我正试图在Antlr4的帮助下用Java编写代码转换器,并且到目前为止在语法部分取得了很大的成功。然而,现在我正在把我的脑袋撞到围绕解析树数据结构的墙上,我需要在解析输入后进行处理。
我正在尝试使用访问者模板来查看我的解析树。我将举例说明我的困惑。
我的语法:
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\r\n\u000C]+ -> skip
;
COMMENT
: '/*' .*? '*/' -> skip
;
LINE_COMMENT
: '//' ~[\r\n]* -> 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
;
现在让我们解析以下字符串:
double x: x >= c_expr
视觉上我会得到这棵树:
假设我的访问者在遇到分支Qexpr(x bin_op_query)时处于visitQexpr(@NotNull pqlcParser.QexprContext ctx)
例程中。
我的问题是,如何判断左边的孩子(树中的“x”)是终端节点,还是更具体地说是“IDENTIFIER”?终端节点没有访问规则,因为它们不是规则。
ctx.getChild(0)
没有RuleIndex。我想我可以用它来检查我是否在终端,但是如果我在IDENTIFIER或其他类型的终端令牌,那仍然不会告诉我。我需要以某种方式区分它。
我有更多的问题,但是在我写这篇解释的时候我忘了它们:&lt; 提前谢谢。
答案 0 :(得分:3)
您可以为令牌添加标签并访问它们/检查它们是否存在于周围环境中:
id :
c_type labelA = IDENTIFIER
| labelB = IDENTIFIER
;
你也可以这样做来创建不同的访问:
id :
c_type IDENTIFIER #idType1 //choose more appropriate names!
| IDENTIFIER #idType2
;
这将为这两个选项创建不同的访问者,我想(即尚未验证)id
的访问者将不会被调用。
我更喜欢以下方法:
id :
typeDef
| otherId
;
typeDef: c_type IDENTIFIER;
otherId : IDENTIFIER ;
这是一个更加严格的系统。但是你可以非常专门地访问节点。我使用的一些经验法则:
|
。otherId
)给予他们&#34;更多含义&#34;。;
),那么可以混合解析器规则和令牌,因此在解析树中不需要。