java – 如何在ANTLR3树解析器@init动作中获取行号
在ANTLR版本3中,如何在高级树解析器规则的@init操作中获取行号?
例如,在下面的@init操作中,我想将行号与句子文本一起推送. sentence @init { myNodeVisitor.pushScriptContext( new MyScriptContext( $sentence.text )); } : assignCommand | actionCommand; finally { m_nodeVisitor.popScriptContext(); } 我需要在执行与规则中的符号相关联的操作之前推送上下文. 有些事情不起作用: >使用$sentence.line – 它没有定义,即使$sentence.text是. 似乎我可以很容易地在@init规则中获得匹配的文本和第一个匹配的令牌,因此应该有一种简单的方法来获取行号. 解决方法
您可以使用以下内容在树语法的令牌/树流中向前看1步:CommonTree ahead =(CommonTree)input.LT(1),您可以将其放在@init部分中.
每个CommonTree(ANTLR中的默认Tree实现)都有一个getToken()方法,该方法返回与此树关联的Token.并且每个令牌都有一个getLine()方法,毫不奇怪,它返回此令牌的行号. 因此,如果您执行以下操作: sentence @init { CommonTree ahead = (CommonTree)input.LT(1); int line = ahead.getToken().getLine(); System.out.println("line=" + line); } : assignCommand | actionCommand ; 您应该能够看到正在打印的正确行号.我说一些,因为在所有情况下都不会按计划进行.让我演示使用一个简单的示例语法: grammar ASTDemo; options { output=AST; } tokens { ROOT; ACTION; } parse : sentence+ EOF -> ^(ROOT sentence+) ; sentence : assignCommand | actionCommand ; assignCommand : ID ASSIGN NUMBER -> ^(ASSIGN ID NUMBER) ; actionCommand : action ID -> ^(ACTION action ID) ; action : START | STOP ; ASSIGN : '='; START : 'start'; STOP : 'stop'; ID : ('a'..'z' | 'A'..'Z')+; NUMBER : '0'..'9'+; SPACE : (' ' | 't' | 'r' | 'n')+ {skip();}; 其树语法如下: tree grammar ASTDemoWalker; options { output=AST; tokenVocab=ASTDemo; ASTLabelType=CommonTree; } walk : ^(ROOT sentence+) ; sentence @init { CommonTree ahead = (CommonTree)input.LT(1); int line = ahead.getToken().getLine(); System.out.println("line=" + line); } : assignCommand | actionCommand ; assignCommand : ^(ASSIGN ID NUMBER) ; actionCommand : ^(ACTION action ID) ; action : START | STOP ; 如果您运行以下测试类: import org.antlr.runtime.*; import org.antlr.runtime.tree.*; public class Main { public static void main(String[] args) throws Exception { String src = "nnnABC = 123nnstart ABC"; ASTDemoLexer lexer = new ASTDemoLexer(new ANTLRStringStream(src)); ASTDemoParser parser = new ASTDemoParser(new CommonTokenStream(lexer)); CommonTree root = (CommonTree)parser.parse().getTree(); ASTDemoWalker walker = new ASTDemoWalker(new CommonTreeNodeStream(root)); walker.walk(); } } 你会看到以下内容被打印出来: line=4 line=0 如您所见,“ABC = 123”产生预期输出(第4行),但“启动ABC”没有产生(第0行).这是因为操作规则的根是一个ACTION标记,并且该标记永远不会在词法分析器中定义,只能在标记{…}块中定义.并且因为输入中并不存在,所以默认情况下会将0行附加到输入中.如果要更改行号,则需要提供一个“引用”标记作为此所谓的虚构ACTION标记的参数,该标记用于将属性复制到自身中. 因此,如果您将组合语法中的actionCommand规则更改为: actionCommand : ref=action ID -> ^(ACTION[$ref.start] action ID) ; 行号将如预期的那样(第6行). 请注意,每个解析器规则都有一个start和end属性,分别是对第一个和最后一个令牌的引用.如果action是lexer规则(比如FOO),那么你可以省略它的.start: actionCommand : ref=FOO ID -> ^(ACTION[$ref] action ID) ; 现在,ACTION令牌已经复制了$ref指向的所有属性,除了令牌的类型,当然是int ACTION.但这也意味着它复制了text属性,因此在我的例子中,由ref = action ID创建的AST – > ^(ACTION [$ref.start]动作ID)可能如下所示: [text=START,type=ACTION] / / / [text=START,type=START] [text=ABC,type=ID] 当然,它是一个合适的AST,因为节点的类型是唯一的,但它使调试混乱,因为ACTION和START共享相同的.text属性. 您可以通过提供第二个字符串参数将所有属性复制到除.text和.type之外的虚构标记,如下所示: actionCommand : ref=action ID -> ^(ACTION[$ref.start,"Action"] action ID) ; 如果您现在再次运行相同的测试类,您将看到以下内容: line=4 line=6 如果你检查生成的树,它将如下所示: [type=ROOT,text='ROOT'] [type=ASSIGN,text='='] [type=ID,text='ABC'] [type=NUMBER,text='123'] [type=ACTION,text='Action'] [type=START,text='start'] [type=ID,text='ABC'] (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |