我对antlr 的理解停留在非常基础的层面。浏览 Parr 博士的“权威 ANTLR 4 参考”。在第 4.2 节“使用访问者构建计算器”中列出了以下语法:
\n\ngrammar LabeledExpr; // rename to distinguish from Expr.g4\n\nprog: stat+ ;\n\nstat: expr NEWLINE # printExpr\n | ID \'=\' expr NEWLINE # assign\n | NEWLINE # blank\n ;\n\nexpr: expr op=(\'*\'|\'/\') expr # MulDiv\n | expr op=(\'+\'|\'-\') expr # AddSub\n | INT # int\n | ID # id\n | \'(\' expr \')\' # parens\n ;\n\nMUL : \'*\' ; // assigns token name to \'*\' used above in grammar\nDIV : \'/\' ;\nADD : \'+\' ;\nSUB : \'-\' ;\nID : [a-zA-Z]+ ; // match identifiers\nINT : [0-9]+ ; // match integers\nNEWLINE:\'\\r\'? \'\\n\' ; // return newlines to parser (is end-statement signal)\nWS : [ \\t]+ -> skip ; // toss out whitespace\n
Run Code Online (Sandbox Code Playgroud)\n\n我试图clear
在书中添加以下声明:
在继续之前,您可能需要花一些时间尝试通过添加语句来扩展此表达式语言clear
。该clear
命令应该清除memory
地图,并且您\xe2\x80\x99将需要规则中的新替代方案stat
来识别它。标记替代方案# clear
,然后运行ANTLR
语法以获得增强的访问者界面。
这是我的尝试:
\n\ngrammar LabeledExpr;\n\nprog: stat+ ;\n\nstat: expr NEWLINE # printExpr\n | ID \'=\' expr NEWLINE # assign\n | clear NEWLINE # clearMem\n | NEWLINE # blank\n ;\n\nexpr: expr op=(\'*\'|\'/\') expr # MulDiv\n | expr op=(\'+\'|\'-\') expr # AddSub\n | INT # int\n | ID # id\n | \'(\' expr \')\' # parens\n ;\n\nclear: CLEAR \n ;\n\nMUL: \'*\' ; // assigns token name to \'*\' used above in grammar\nDIV: \'/\' ;\nADD: \'+\' ;\nSUB: \'-\' ;\n\nID : [a-zA-Z]+ ;\nINT : [0-9]+ ;\nNEWLINE: \'\\r\'?\'\\n\' ;\nWS : [ \\t]+ -> skip ;\nCLEAR: \'clear\';\n
Run Code Online (Sandbox Code Playgroud)\n\n然而,visitClearMem
永远不会被调用:
@Override\npublic Integer visitClearMem(LabeledExprParser.ClearMemContext ctx) {\n String text = ctx.getText();\n if (text.equalsIgnoreCase("clear")) {\n memory.clear();\n }\n return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n
问题在于规则CLEAR
在词法分析器中的位置。由于输入clear
同时匹配规则ID
和CLEAR
,ANTLR 选择语法中第一个出现的规则。在这种情况下,输入clear
变为ID
.
一般来说,您希望将您语言的所有关键字放置在其他标识符的规则之前,以确保它们正确匹配。