Understanding the context data structure in Antlr4
我正尝试在Antlr4的帮助下用Java编写代码转换器,到目前为止,在语法部分上取得了巨大的成功。但是,我现在将头撞在墙上,这使我的脑袋围绕解析树数据结构,在解析输入后我需要进行处理。
我正在尝试使用访问者模板遍历我的解析树。我将向您展示一个例子来说明我的困惑点。
我的语法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | grammar pqlc; // Lexer //Schlüsselw?rter EXISTS: 'exists'; REDUCE: 'reduce'; QUERY: 'query'; INT: 'int'; DOUBLE: 'double'; CONST: 'const'; STDVECTOR: 'std::vector'; STDMAP: 'std::map'; STDSET: 'std::set'; C_EXPR: 'c_expr'; INTEGER_LITERAL : (DIGIT)+ ; fragment DIGIT: '0'..'9'; DOUBLE_LITERAL : DIGIT '.' DIGIT+; LPAREN : '('; RPAREN : ')'; LBRACK : '['; RBRACK : ']'; DOT : '.'; EQUAL : '=='; LE : '<='; GE : '>='; GT : '>'; LT : '<'; ADD : '+'; MUL : '*'; AND : '&&'; COLON : ':'; IDENTIFIER : JavaLetter JavaLetterOrDigit*; fragment JavaLetter : [a-zA-Z$_]; // these are the"java letters" below 0xFF fragment JavaLetterOrDigit : [a-zA-Z0-9$_]; // these are the"java letters or digits" below 0xFF WS : [ \\t\ \ \\u000C]+ -> skip ; COMMENT : '/*' .*? '*/' -> skip ; LINE_COMMENT : '//' ~[\ \ ]* -> skip ; // Parser //start_rule: query; query : quant_expr | qexpr+ | IDENTIFIER // order IDENTIFIER and qexpr+? | numeral | c_expr //TODO ; c_type : INT | DOUBLE | CONST; bin_op: AND | ADD | MUL | EQUAL | LT | GT | LE| GE; qexpr: LPAREN query RPAREN bin_op_query? // query bin_op query | IDENTIFIER bin_op_query? // copied from query to resolve left recursion problem | numeral bin_op_query? // ^ | quant_expr bin_op_query? // ^ |c_expr bin_op_query? // query.find(query) | IDENTIFIER find_query? // copied from query to resolve left recursion problem | numeral find_query? // ^ | quant_expr find_query? |c_expr find_query? // query[query] | IDENTIFIER array_query? // copied from query to resolve left recursion problem | numeral array_query? // ^ | quant_expr array_query? |c_expr array_query? // | qexpr bin_op_query // bad, resolved by quexpr+ in query ; bin_op_query: bin_op query bin_op_query?; // resolve left recursion of query bin_op query find_query: '.''find' LPAREN query RPAREN; array_query: LBRACK query RBRACK; quant_expr: quant id ':' query | QUERY LPAREN match RPAREN ':' query | REDUCE LPAREN IDENTIFIER RPAREN id ':' query ; match: STDVECTOR LBRACK id RBRACK EQUAL cm | STDMAP '.''find' LPAREN cm RPAREN EQUAL cm | STDSET '.''find' LPAREN cm RPAREN ; cm: IDENTIFIER | numeral | c_expr //TODO ; quant : EXISTS; id : c_type IDENTIFIER | IDENTIFIER // Nach Seite 2 aber nicht der übersicht. Laut übersicht id -> aber dann w?re Regel 1 ohne + ; numeral : INTEGER_LITERAL | DOUBLE_LITERAL ; c_expr: C_EXPR ; |
现在,让我们分析以下字符串:
1 | double x: x >= c_expr |
视觉上,我会得到这棵树:
假设我的访问者访问分支Qexpr(x bin_op_query)时,它在
我的问题是,如何确定左边的孩子(树中的" x")是终端节点,或更具体地说是" IDENTIFIER"?终端节点没有访问规则,因为它们不是规则。
我还有更多问题,但是在写我的解释的时间上我忘了他们:< 提前致谢。
您可以为标记添加标签并访问它们/检查它们是否存在于周围环境中:
1 2 3 4 | id : c_type labelA = IDENTIFIER | labelB = IDENTIFIER ; |
您也可以这样做来创建不同的访问:
1 2 3 4 | id : c_type IDENTIFIER #idType1 //choose more appropriate names! | IDENTIFIER #idType2 ; |
这将为两种选择创建不同的访问者,我想(即尚未验证)不会调用
我更喜欢以下方法:
1 2 3 4 5 6 | id : typeDef | otherId ; typeDef: c_type IDENTIFIER; otherId : IDENTIFIER ; |
这是一个类型较多的系统。 但是您可以非常具体地访问节点。 我使用的一些经验法则: