C#实现LALR(1)解析器的生成器

news/2025/1/5 16:32:44/文章来源:https://www.cnblogs.com/bitzhuwei/p/18649990

Yet Another Compiler

参考lex和yacc的输入格式,参考虎书《现代编译原理-C语言描述》的算法,大力整合优化,实现了LALR(1)的C#生成器(暂命名为bitParser)。

词法分析器

  • 根据DFA和最小化DFA分别生成词法分析器代码(状态转换表、保留字、Token类型等)

  • 支持全Unicode字符。支持int.MaxValue个词法状态。

  • 正则表达式支持/后缀,便于识别id = refId这类情况。

  • 正则表达式支持<'Vt'>单个前缀,便于识别struct type_name这类情况。

  • 正则表达式支持<signal1, signal2, ..>多个状态信号作为前缀,便于识别<Comment>[^*\n]*这样的情况。类似lex,但不完全相同。

  • 无须单独列示Token或状态信号,即无须lex中的%s NUM ID ..,也无须%x Comment End Text ..

  • 无须显式书写保留字,即无须lex中的[(] { return ('('); }

  • 无须手动编写语义代码,即无须lex中的#[0-9]+ { CreateNewText(YYText(),YYLeng()); return(token::IDENT); },但仍可在自动生成后手动修改。

  • 注释详尽。每个状态的每个条件分支上都在注释中说明其正则表达式、关联的Token类型等。

  • 生成ε-NFA、NFA、DFA、最小化DFA的状态图(mermaid格式)的文档,便于学习和调试。

  • 生成每个Token类型的状态图(mermaid格式)的文档。

语法分析器

  • 根据LL(1)、LR(0)、SLR(1)、LALR(1)、LR(1)分别生成语法分析器代码(分析表、规则列表、语法树结点类型等)。

  • 支持关联指令%nonassoc%left%right、优先级指令%prec,自动解决Shift/Reduce、Reduce/Reduce冲突,并在分析表代码的注释中列示之。

  • 注释详尽。在注释中列示:冲突数量、已解决数量、未解决数量;每个状态的LR项和lookahead等。

  • 生成LL(1)、LR(0)、SLR(1)、LALR(1)、LR(1)的状态图(mermaid格式)和状态表(md文件中的Table)的文档,便于学习和调试。

  • 生成nullable、FIRST集、FOLLOW集的文档。

其他

  • 支持多行注释指令%blockComment on/off和单行注释指令%inlineComment on/off,默认格式同C语言的/**///,可自定义其格式。

  • 支持Scope范围指令%validScopeChars和全局范围指令%validGlobalChars,默认范围均为[\u0001-\uFFFF](即除'\0'外的全部Unicode字符),可自定义其范围。

  • 生成语法结点的class类型框架和遍历语法树的框架,提供适用各种语言的格式化算法。可用于格式化、进一步生成中间代码。

  • 大力优化,例如生成ANSI C语言的全部代码+文档只需3秒,生成GLGL4.60.8的全部代码+文档只需9秒。

举例-Calc.st

能够处理加减乘除运算的解析器,其文法如下:

input file: Calc.st

Exp    : Exp '+' Term| Exp '-' Term| Term ;
Term   : Term '*' Factor| Term '/' Factor| Factor ;
Factor : '(' Exp ')'| 'number' ;%%[0-9]+%% 'number' // 示例只处理非负整数的四则运算
点击查看生成的终结点Vt和非终结点Vn代码
/// <summary>
/// Vt types are used both for lexical analyzing and syntax parse.
/// <para>Vt is quoted in ''.</para>
/// <para>Vn types are only for syntax parse.</para>
/// <para>Vn is not quoted in ''.</para>
/// </summary>
public static class st {// fixed st from template file./// <summary>/// 多行注释 multiple line comment /* xxx *//// </summary>public const string blockComment = "'blockComment'";/// <summary>/// 单行注释 single line comment // xxx/// </summary>public const string inlineComment = "'inlineComment'";/// <summary>/// Something wrong within the source code./// </summary>public const string Error = "'×'";// Vt/// <summary>/// '+'/// </summary>public const string @Plus符 = "'+'";/// <summary>/// '-'/// </summary>public const string @Dash符 = "'-'";/// <summary>/// '*'/// </summary>public const string @Asterisk符 = "'*'";/// <summary>/// '/'/// </summary>public const string @Slash符 = "'/'";/// <summary>/// '('/// </summary>public const string @LeftParenthesis符 = "'('";/// <summary>/// ')'/// </summary>public const string @RightParenthesis符 = "')'";/// <summary>/// 'number'/// </summary>public const string @number = "'number'";/// <summary>/// end of token list./// </summary>public const string @终 = "'¥'";// Vn/// <summary>/// Exp/// </summary>public const string @vnExp = "Exp";/// <summary>/// Term/// </summary>public const string @vnTerm = "Term";/// <summary>/// Factor/// </summary>public const string @vnFactor = "Factor";}

生成的词法分析器状态图如下:

flowchart classDef c0001 color:#FF0000; classDef c0010 stroke-dasharray: 10 10; classDef c0011 stroke-dasharray: 10 10,color:#FF0000; classDef c0100 fill:#BB66EE; classDef c0101 fill:#BB66EE,color:#FF0000; classDef c0110 fill:#BB66EE,stroke-dasharray: 10 10; classDef c0111 fill:#BB66EE,stroke-dasharray: 10 10,color:#FF0000; classDef c1000 stroke:#333,stroke-width:4px; classDef c1001 stroke:#333,stroke-width:4px,color:#FF0000; classDef c1010 stroke:#333,stroke-width:4px,stroke-dasharray: 10 10; classDef c1011 stroke:#333,stroke-width:4px,stroke-dasharray: 10 10,color:#FF0000; classDef c1100 stroke:#333,stroke-width:4px,fill:#BB66EE; classDef c1101 stroke:#333,stroke-width:4px,fill:#BB66EE,color:#FF0000; classDef c1110 stroke:#333,stroke-width:4px,fill:#BB66EE,stroke-dasharray: 10 10; classDef c1111 stroke:#333,stroke-width:4px,fill:#BB66EE,stroke-dasharray: 10 10,color:#FF0000; miniDFA0(["miniDFA0 1 DFA States"]) class miniDFA0 c1000; miniDFA1(["miniDFA1 1 DFA States AcceptToken 'number'"]) class miniDFA1 c0001; miniDFA2(["miniDFA2 1 DFA States AcceptToken ')'"]) class miniDFA2 c0001; miniDFA3(["miniDFA3 1 DFA States AcceptToken '('"]) class miniDFA3 c0001; miniDFA4(["miniDFA4 1 DFA States AcceptToken '/'"]) class miniDFA4 c0001; miniDFA5(["miniDFA5 1 DFA States AcceptToken '*'"]) class miniDFA5 c0001; miniDFA6(["miniDFA6 1 DFA States AcceptToken '-'"]) class miniDFA6 c0001; miniDFA7(["miniDFA7 1 DFA States AcceptToken '+'"]) class miniDFA7 c0001; miniDFA0 -->|"[0-9] BeginToken 'number'"|miniDFA1 miniDFA0 -->|"#92;) BeginToken ')'"|miniDFA2 miniDFA0 -->|"#92;( BeginToken '('"|miniDFA3 miniDFA0 -->|"#92;/ BeginToken '/'"|miniDFA4 miniDFA0 -->|"#92;#42; BeginToken '#42;'"|miniDFA5 miniDFA0 -->|"- BeginToken '-'"|miniDFA6 miniDFA0 -->|"#92;+ BeginToken '+'"|miniDFA7 miniDFA1 -->|"[0-9]"|miniDFA1
点击查看生成的保留字相代码
public static class reservedWord {/// <summary>/// +/// </summary>public const string @Plus符 = "+";/// <summary>/// -/// </summary>public const string @Dash符 = "-";/// <summary>/// */// </summary>public const string @Asterisk符 = "*";/// <summary>/// //// </summary>public const string @Slash符 = "/";/// <summary>/// (/// </summary>public const string @LeftParenthesis符 = "(";/// <summary>/// )/// </summary>public const string @RightParenthesis符 = ")";
}/// <summary>
/// if <paramref name="token"/> is a reserved word, assign correspond type and return true.
/// <para>otherwise, return false.</para>
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
private static bool CheckReservedWord(AnalyzingToken token) {bool isReservedWord = true;switch (token.value) {//case reservedWord.@emptyReservedWord: token.type = st.@empty; break;case reservedWord.@Plus符: token.type = st.@Plus符; break;case reservedWord.@Dash符: token.type = st.@Dash符; break;case reservedWord.@Asterisk符: token.type = st.@Asterisk符; break;case reservedWord.@Slash符: token.type = st.@Slash符; break;case reservedWord.@LeftParenthesis符: token.type = st.@LeftParenthesis符; break;case reservedWord.@RightParenthesis符: token.type = st.@RightParenthesis符; break;default: isReservedWord = false; break;}return isReservedWord;
}
点击查看生成的lexi状态0相关代码
/// <summary>
/// lexicalState0
/// <para>CompilerExp.Lexical●[1 DFA States]</para>
/// </summary>
private static readonly Action<LexicalContext, char> lexicalState0 =
static (context, c) => {if (false) { /* for simpler code generation purpose. */ }/* user-input condition code *//* [0-9] */else if (/* possible Vt : 'number' *//* no possible signal *//* [xxx] scope */'0'/*'\u0030'(48)*/ <= c && c <= '9'/*'\u0039'(57)*/) {BeginToken(context);context.currentState = lexicalState1;}/* user-input condition code *//* \) */else if (/* possible Vt : ')' *//* no possible signal *//* single char */c == ')'/*'\u0029'(41)*/) {BeginToken(context);context.currentState = lexicalState2;}/* user-input condition code *//* \( */else if (/* possible Vt : '(' *//* no possible signal *//* single char */c == '('/*'\u0028'(40)*/) {BeginToken(context);context.currentState = lexicalState3;}/* user-input condition code *//* \/ */else if (/* possible Vt : '/' *//* no possible signal *//* single char */c == '/'/*'\u002F'(47)*/) {BeginToken(context);context.currentState = lexicalState4;}/* user-input condition code *//* \* */else if (/* possible Vt : '*' *//* no possible signal *//* single char */c == '*'/*'\u002A'(42)*/) {BeginToken(context);context.currentState = lexicalState5;}/* user-input condition code *//* - */else if (/* possible Vt : '-' *//* no possible signal *//* single char */c == '-'/*'\u002D'(45)*/) {BeginToken(context);context.currentState = lexicalState6;}/* user-input condition code *//* \+ */else if (/* possible Vt : '+' *//* no possible signal *//* single char */c == '+'/*'\u002B'(43)*/) {BeginToken(context);context.currentState = lexicalState7;}/* deal with everything else. */else if (c == ' ' || c == '\r' || c == '\n' || c == '\t' || c == '\0') {context.currentState = lexicalState0; // skip them.}else { // unexpected char.BeginToken(context);context.tokenEnd = context.cursor; // ExtendToken(context);AcceptToken(st.Error, context);context.currentState = lexicalState0;}
};
点击查看nullable、FIRST集、FOLLOW集
nullable:
[0]: nullable( Exp' ) = False
[1]: nullable( Exp ) = False
[2]: nullable( Term ) = False
[3]: nullable( Factor ) = False
[4]: nullable( '¥' ) = False
[5]: nullable( '+' ) = False
[6]: nullable( '-' ) = False
[7]: nullable( '*' ) = False
[8]: nullable( '/' ) = False
[9]: nullable( '(' ) = False
[10]: nullable( ')' ) = False
[11]: nullable( 'number' ) = FalseFIRST集:
[0]: FIRST( Exp' ) = { '(' 'number' }
[1]: FIRST( Exp ) = { '(' 'number' }
[2]: FIRST( Term ) = { '(' 'number' }
[3]: FIRST( Factor ) = { '(' 'number' }
[4]: FIRST( '¥' ) = { '¥' }
[5]: FIRST( '+' ) = { '+' }
[6]: FIRST( '-' ) = { '-' }
[7]: FIRST( '*' ) = { '*' }
[8]: FIRST( '/' ) = { '/' }
[9]: FIRST( '(' ) = { '(' }
[10]: FIRST( ')' ) = { ')' }
[11]: FIRST( 'number' ) = { 'number' }
[12]: FIRST( Exp '+' Term ) = { '(' 'number' }
[13]: FIRST( Exp '-' Term ) = { '(' 'number' }
[14]: FIRST( Term '*' Factor ) = { '(' 'number' }
[15]: FIRST( Term '/' Factor ) = { '(' 'number' }
[16]: FIRST( '(' Exp ')' ) = { '(' }FOLLOW集:
[0]: FOLLOW( Exp' ) = { '¥' }
[1]: FOLLOW( Exp ) = { '-' ')' '+' '¥' }
[2]: FOLLOW( Term ) = { '-' ')' '*' '/' '+' '¥' }
[3]: FOLLOW( Factor ) = { '-' ')' '*' '/' '+' '¥' }

生成的语法分析器LALR(1)状态图和状态表如下:

flowchart classDef default fill:#C7EDCC,stroke:#993399,stroke-width:0px,text-align:left; classDef titlebarStyle fill:gold; titlebar>"LALR(1) syntax states"] class titlebar titlebarStyle syntaxState0("syntaxState0 [-1]=Exp' : ⏳ Exp ;☕ '¥' [0]=Exp : ⏳ Exp '+' Term ;☕ '-' '+' '¥' [1]=Exp : ⏳ Exp '-' Term ;☕ '-' '+' '¥' ...") syntaxState1("syntaxState1 [-1]=Exp' : Exp ⏳ ;☕ '¥' [0]=Exp : Exp ⏳ '+' Term ;☕ '-' '+' '¥' [1]=Exp : Exp ⏳ '-' Term ;☕ '-' '+' '¥' ") syntaxState2("syntaxState2 [2]=Exp : Term ⏳ ;☕ '-' ')' '+' ... [3]=Term : Term ⏳ '#42;' Factor ;☕ '-' ')' '#42;' ... [4]=Term : Term ⏳ '/' Factor ;☕ '-' ')' '#42;' ...") syntaxState3("syntaxState3 [5]=Term : Factor ⏳ ;☕ '-' ')' '#42;' ...") syntaxState4("syntaxState4 [6]=Factor : '(' ⏳ Exp ')' ;☕ '-' ')' '#42;' ... [0]=Exp : ⏳ Exp '+' Term ;☕ '-' ')' '+' [1]=Exp : ⏳ Exp '-' Term ;☕ '-' ')' '+' ...") syntaxState5("syntaxState5 [7]=Factor : 'number' ⏳ ;☕ '-' ')' '#42;' ...") syntaxState6("syntaxState6 [0]=Exp : Exp '+' ⏳ Term ;☕ '-' ')' '+' ... [3]=Term : ⏳ Term '#42;' Factor ;☕ '-' ')' '#42;' ... [4]=Term : ⏳ Term '/' Factor ;☕ '-' ')' '#42;' ... ...") syntaxState7("syntaxState7 [1]=Exp : Exp '-' ⏳ Term ;☕ '-' ')' '+' ... [3]=Term : ⏳ Term '#42;' Factor ;☕ '-' ')' '#42;' ... [4]=Term : ⏳ Term '/' Factor ;☕ '-' ')' '#42;' ... ...") syntaxState8("syntaxState8 [3]=Term : Term '#42;' ⏳ Factor ;☕ '-' ')' '#42;' ... [6]=Factor : ⏳ '(' Exp ')' ;☕ '-' ')' '#42;' ... [7]=Factor : ⏳ 'number' ;☕ '-' ')' '#42;' ...") syntaxState9("syntaxState9 [4]=Term : Term '/' ⏳ Factor ;☕ '-' ')' '#42;' ... [6]=Factor : ⏳ '(' Exp ')' ;☕ '-' ')' '#42;' ... [7]=Factor : ⏳ 'number' ;☕ '-' ')' '#42;' ...") syntaxState10("syntaxState10 [6]=Factor : '(' Exp ⏳ ')' ;☕ '-' ')' '#42;' ... [0]=Exp : Exp ⏳ '+' Term ;☕ '-' ')' '+' [1]=Exp : Exp ⏳ '-' Term ;☕ '-' ')' '+' ") syntaxState11("syntaxState11 [0]=Exp : Exp '+' Term ⏳ ;☕ '-' ')' '+' ... [3]=Term : Term ⏳ '#42;' Factor ;☕ '-' ')' '#42;' ... [4]=Term : Term ⏳ '/' Factor ;☕ '-' ')' '#42;' ...") syntaxState12("syntaxState12 [1]=Exp : Exp '-' Term ⏳ ;☕ '-' ')' '+' ... [3]=Term : Term ⏳ '#42;' Factor ;☕ '-' ')' '#42;' ... [4]=Term : Term ⏳ '/' Factor ;☕ '-' ')' '#42;' ...") syntaxState13("syntaxState13 [3]=Term : Term '#42;' Factor ⏳ ;☕ '-' ')' '#42;' ...") syntaxState14("syntaxState14 [4]=Term : Term '/' Factor ⏳ ;☕ '-' ')' '#42;' ...") syntaxState15("syntaxState15 [6]=Factor : '(' Exp ')' ⏳ ;☕ '-' ')' '#42;' ...") syntaxState0 -.-> |"Exp"| syntaxState1 syntaxState0 -.-> |"Term"| syntaxState2 syntaxState0 -.-> |"Factor"| syntaxState3 syntaxState0 --> |"'('"| syntaxState4 syntaxState0 --> |"'number'"| syntaxState5 syntaxState1 --> |"'+'"| syntaxState6 syntaxState1 --> |"'-'"| syntaxState7 syntaxState1 o--o |"'¥'"| syntaxState1 syntaxState2 --> |"'#42;'"| syntaxState8 syntaxState2 --> |"'/'"| syntaxState9 syntaxState4 -.-> |"Exp"| syntaxState10 syntaxState4 -.-> |"Term"| syntaxState2 syntaxState4 -.-> |"Factor"| syntaxState3 syntaxState4 --> |"'('"| syntaxState4 syntaxState4 --> |"'number'"| syntaxState5 syntaxState6 -.-> |"Term"| syntaxState11 syntaxState6 -.-> |"Factor"| syntaxState3 syntaxState6 --> |"'('"| syntaxState4 syntaxState6 --> |"'number'"| syntaxState5 syntaxState7 -.-> |"Term"| syntaxState12 syntaxState7 -.-> |"Factor"| syntaxState3 syntaxState7 --> |"'('"| syntaxState4 syntaxState7 --> |"'number'"| syntaxState5 syntaxState8 -.-> |"Factor"| syntaxState13 syntaxState8 --> |"'('"| syntaxState4 syntaxState8 --> |"'number'"| syntaxState5 syntaxState9 -.-> |"Factor"| syntaxState14 syntaxState9 --> |"'('"| syntaxState4 syntaxState9 --> |"'number'"| syntaxState5 syntaxState10 --> |"')'"| syntaxState15 syntaxState10 --> |"'+'"| syntaxState6 syntaxState10 --> |"'-'"| syntaxState7 syntaxState11 --> |"'#42;'"| syntaxState8 syntaxState11 --> |"'/'"| syntaxState9 syntaxState12 --> |"'#42;'"| syntaxState8 syntaxState12 --> |"'/'"| syntaxState9 syntaxState2 x==x |"'-' ')' '+' ... R[2]= Exp : Term ;"| syntaxState2 syntaxState3 x==x |"'-' ')' '#42;' ... R[5]= Term : Factor ;"| syntaxState3 syntaxState5 x==x |"'-' ')' '#42;' ... R[7]= Factor : 'number' ;"| syntaxState5 syntaxState11 x==x |"'-' ')' '+' ... R[0]= Exp : Exp '+' Term ;"| syntaxState11 syntaxState12 x==x |"'-' ')' '+' ... R[1]= Exp : Exp '-' Term ;"| syntaxState12 syntaxState13 x==x |"'-' ')' '#42;' ... R[3]= Term : Term '*' Factor ;"| syntaxState13 syntaxState14 x==x |"'-' ')' '#42;' ... R[4]= Term : Term '/' Factor ;"| syntaxState14 syntaxState15 x==x |"'-' ')' '#42;' ... R[6]= Factor : '(' Exp ')' ;"| syntaxState15
状态 '+' '-' '*' '/' '(' ')' 'number' '¥' Exp Term Factor
0 S4 S5 G1 G2 G3
1 S6 S7
2 R[2] R[2] S8 S9 R[2] R[2]
3 R[5] R[5] R[5] R[5] R[5] R[5]
4 S4 S5 G10 G2 G3
5 R[7] R[7] R[7] R[7] R[7] R[7]
6 S4 S5 G11 G3
7 S4 S5 G12 G3
8 S4 S5 G13
9 S4 S5 G14
10 S6 S7 S15
11 R[0] R[0] S8 S9 R[0] R[0]
12 R[1] R[1] S8 S9 R[1] R[1]
13 R[3] R[3] R[3] R[3] R[3] R[3]
14 R[4] R[4] R[4] R[4] R[4] R[4]
15 R[6] R[6] R[6] R[6] R[6] R[6]
点击查看生成的遍历语法树提取结点信息的代码
/// <summary>
/// <see cref="LRNode.type"/> -&gt; <see cref="Action{LRNode, TContext{Exp}}"/>
/// </summary>
private static readonly Dictionary<string/*LRNode.type*/,Action<LRNode, TContext<Exp>>> @expExtractorDict = new();private static readonly Action<LRNode, TContext<Exp>> VtHandler =
(node, context) => {var token = node.start;context.objStack.Push(token);
};/// <summary>
/// initialize dict for extractor.
/// </summary>
private static void InitializeExtractorDict() {var extractorDict = @expExtractorDict;extractorDict.Add(st.@Plus符, VtHandler);extractorDict.Add(st.@Dash符, VtHandler);extractorDict.Add(st.@Asterisk符, VtHandler);extractorDict.Add(st.@Slash符, VtHandler);extractorDict.Add(st.@LeftParenthesis符, VtHandler);extractorDict.Add(st.@RightParenthesis符, VtHandler);extractorDict.Add(st.@number, VtHandler);extractorDict.Add(st.@终,static (node, context) => {// [-1]=Exp' : Exp ;// dumped by ExternalExtractorvar @final = (VnExp?)context.objStack.Pop();var left = new Exp(@final);context.result = left; // final step, no need to push into stack.}); // end of extractorDict.Add(st.@终, (node, context) => { ... });extractorDict.Add(st.@vnExp,static (node, context) => {switch (node.regulation.index) {case 0: { // [0]=Exp : Exp '+' Term ;// dumped by ListExtractor 2var r0 = (VnTerm?)context.objStack.Pop();var r1 = (Token?)context.objStack.Pop();var r2 = (VnExp?)context.objStack.Pop();var left = r2;left.Add(r1, r0);context.objStack.Push(left);}break;case 1: { // [1]=Exp : Exp '-' Term ;// dumped by ListExtractor 2var r0 = (VnTerm?)context.objStack.Pop();var r1 = (Token?)context.objStack.Pop();var r2 = (VnExp?)context.objStack.Pop();var left = r2;left.Add(r1, r0);context.objStack.Push(left);}break;case 2: { // [2]=Exp : Term ;// dumped by ListExtractor 1var r0 = (VnTerm?)context.objStack.Pop();var left = new VnExp(r0);context.objStack.Push(left);}break;default: throw new NotImplementedException();}}); // end of extractorDict.Add(st.@vnExp, (node, context) => { ... });extractorDict.Add(st.@vnTerm,static (node, context) => {switch (node.regulation.index) {case 3: { // [3]=Term : Term '*' Factor ;// dumped by ListExtractor 2var r0 = (VnFactor?)context.objStack.Pop();var r1 = (Token?)context.objStack.Pop();var r2 = (VnTerm?)context.objStack.Pop();var left = r2;left.Add(r1, r0);context.objStack.Push(left);}break;case 4: { // [4]=Term : Term '/' Factor ;// dumped by ListExtractor 2var r0 = (VnFactor?)context.objStack.Pop();var r1 = (Token?)context.objStack.Pop();var r2 = (VnTerm?)context.objStack.Pop();var left = r2;left.Add(r1, r0);context.objStack.Push(left);}break;case 5: { // [5]=Term : Factor ;// dumped by ListExtractor 1var r0 = (VnFactor?)context.objStack.Pop();var left = new VnTerm(r0);context.objStack.Push(left);}break;default: throw new NotImplementedException();}}); // end of extractorDict.Add(st.@vnTerm, (node, context) => { ... });extractorDict.Add(st.@vnFactor,static (node, context) => {switch (node.regulation.index) {case 6: { // [6]=Factor : '(' Exp ')' ;// dumped by DefaultExtractorvar r0 = (Token?)context.objStack.Pop();var r1 = (VnExp?)context.objStack.Pop();var r2 = (Token?)context.objStack.Pop();var left = new VnFactor(r2, r1, r0);context.objStack.Push(left);}break;case 7: { // [7]=Factor : 'number' ;// dumped by DefaultExtractorvar r0 = (Token?)context.objStack.Pop();var left = new VnFactor(r0);context.objStack.Push(left);}break;default: throw new NotImplementedException();}}); // end of extractorDict.Add(st.@vnFactor, (node, context) => { ... });
}

关于通用的格式化算法,可参考我的另一篇文章(一个GLSL Shader的格式化算法(LALR解析器))。

End

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/863357.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【新兴产业】量子信息

产业链 量子信息主要包括量子计算、量子通信和量子测量三大领域,在提升计算困难问题运算处理能力、加强信息安全保护能力、提高传感测量精度等方面,具备超越经典信息技术的潜力。 量子信息产业链从上游到下游主要包含基础光电元器件、量子通信 核心元器件、量子通信传输干线、…

【新兴产业】元宇宙

产业链 •顶层设计:政府从宏观角度为元宇宙的发展做出顶层设计,尤其在金融交易体系、社会治理制度方面给出明确定调和指明方向。 • 市场培育:地方政府因地制宜制定符合当地产业特色的元宇宙发展规划,并出台产业扶持政策、落地措施,制定未来执行计划。 • 产业联盟:建立与…

回首2024,展望2025,新年新“鲸”象~

回首 2024 年,数字孪生领域蓬勃发展,技术创新层出不穷,应用场景不断拓展。在这充满机遇与挑战的一年里,山海鲸可视化凭借国产自研的零代码数字孪生平台,为众多企业和政府机构提供了一站式的数字化解决方案,助力各行各业在数字化转型的道路上稳步前行。 1. 回首2024年 (一…

CICD Day2、基于jenkins Gitlab 的CICD web-demo配置

1、 代码提交 1.1 在服务器上创建一个web-demo的目录,用户web前端项目的开发目录 mkdir web-demo # 在web-demo目录下 编辑一个index.html的文件 cat index.html <!DOCTYPE html> <html> <head><meta charset="utf-8"><title>实例<…

CPU-Z处理器检测工具 v2.13.0中文绿色单文件

点击上方蓝字关注我 前言 CPU-Z是一个非常厉害的CPU检测小帮手。它能识别很多种类的CPU,而且打开和检测的速度都很快。这个工具能清楚地告诉我们关于CPU、主板、内存、显卡等硬件的详细信息,比如是哪个厂家生产的、处理器的名字、是怎么做出来的、封装技术怎么样,还有它们的…

uniapp(Hbuilderx)

目录微信开发者工具下载新建项目运行 微信开发者工具下载新建项目注意点 如果要打包安卓,需要勾上:运行微信小程序 1: 找到.exe路径,粘贴进去2:打开微信小程序“服务端口”

商品个性化推荐

商品个性化推荐 任务要求:二.原理讲解: 本项目的基于 用户的购买历史 和 商品之间的相似性 进行商品推荐。它主要包括两个核心部分:用户-商品矩阵 和 商品相似度计算。下面我会结合算法的原理和实际示例为你讲解这个推荐系统的工作原理。 2.1用户-商品矩阵(User-Product M…

探索新路径:金融行业如何借助内部知识库实现智能转型

引言 在数字化转型的浪潮中,金融行业正经历着前所未有的变革。随着大数据、人工智能等技术的飞速发展,金融机构不仅需要提升服务效率,更要优化内部管理,以创新驱动业务增长。内部知识库作为信息管理与知识分享的核心平台,正逐渐成为金融行业智能转型的关键驱动力。本文将探…

Listary 6.3.1.85 Windows文件管理:高效文件管理工具

点击上方蓝字关注我 前言 Listary是一个非常实用的Windows文件管理小帮手,它能让找文件和管理文件变得更快更容易。用了它,你可以更快地搜索到想要的文件或程序,还能通过一些快捷操作快速到达文件所在的位置。更重要的是,Listary能和Windows自带的文件管理器以及其他常用的…

断点输出大法快速定位编程错误

断点&输出大法快速定位编程错误 1、断点法 点红框位置就可以加每行代码的断点 再按F5进行debug断点&输出大法快速定位编程错误 1、断点法 点红框位置就可以加每行代码的断点再按F5进行debug操作,在下面的窗口看各函数的值 这种方法经常用在循环出现问题时进行处理 举个…

Nginx的referer参数的用法和原理

​ Nginx的referer参数是用于控制HTTP请求中的Referer字段的相关配置。这个参数的主要作用是限制或允许特定来源网站的访问,以加强安全性或控制流量。 用法:限制特定来源网站的访问: 可以使用referer参数来配置Nginx,使其只允许来自指定来源网站的请求。这有助于防止盗链或…

.Net程序员机会来了,微软官方新推出一个面向Windows开发者本地运行AI模型的开源工具

想要开发AI产品的.Net程序员机会来了,这个项目应该好好研究。 虽然说大模型基本都有提供网络API,但肯定没有直接使用本地模型速度快。 最近微软官方新推出AI Dev Gallery开源项目,可以帮助Windows开发人员学习如何将具有本地模型和API的AI添加到Windows应用程序中。01 项目简…