考虑到这个g4语法:
grammar smaller;
root
: ( componentDefinition )* EOF;
componentDefinition
: Addr
Id?
Lbrace
Rbrace
Semi
;
ExprElem
: Num
| Id
;
Addr : 'addr' {System.out.println("addr");};
Lbrace : '{' ;
Rbrace : '}' ;
Semi : ';' ;
Id : [a-zA-z0-9_]+ {System.out.println("id");};
Num : [0-9]+;
//------------------------------------------------
// Whitespace and Comments
//------------------------------------------------
Wspace : [ \t]+ -> skip;
Newline : ('\r' '\n'?
| '\n'
) -> skip;
和要解析的文件
addr basic {
};
这个cmdline:
rm *.class *.java ; java -Xmx500M org.antlr.v4.Tool smaller.g4 ; javac *.java ; cat basic | java org.antlr.v4.runtime.misc.TestRig smaller root -tree
我收到此错误:
line 2:0 mismatched input 'addr' expecting {<EOF>, 'addr'}
(root addr basic { } ;)
如果我删除ExprElem(语法中没有其他地方使用),解析器可以工作:
addr
id
(root (componentDefinition addr basic { } ;) <EOF>)
为什么呢?请注意,这是语法的大大减少版本。通常,ExprElem确实有目的。
Addr是一个文字,所以它不应该像其他问题那样与Id冲突。
答案 0 :(得分:1)
您的规则ExprElem
是词法分析器规则,而不是解析器规则(以upercase开头)并屏蔽Addr
规则,因此,没有Addr
:(
此外,由于ExprElem
是词法分析器规则,它依赖于Id
或Num
规则。因此,当找到Id
时,ANTLR词法分析器会为其提供ExprElem
令牌类型而不是Id
令牌类型。
所以,有两件事,您可以将ExprElem
规则重写为exprElem
(假设您需要解析器规则):
exprElem : Num | Id;
或者您可以在Id
中使用ExprElem
令牌作为规则的一部分,但您需要能够区分ExprElem
和Id
的内容(以下示例,但我确实如此)认为你想要一个解析器规则):
Addr : 'addr' {System.out.println("addr");};
ExprElem
: Sharp Num // This token use others but defines its own 'pattern'
| Sharp Id
;
Lbrace : '{' ;
Rbrace : '}' ;
Semi : ';' ;
Id : [a-zA-z0-9_]+ {System.out.println("id");};
Num : [0-9]+;
Sharp : '#';
从我的想法来看,这绝对不是你想要的,但我只是把它放在这里来说明lexer规则如何重用其他规则。
如果您对令牌的行为有疑问,请不要犹豫,显示识别令牌。这是我经常使用的Java代码片段(在这种情况下我将你的语法命名为test
):
public class Main {
public static void main(String[] args) throws InterruptedException {
String txt =
"addr Basic {\n"
+ "\n"
+ "};";
TestLexer lexer = new TestLexer(new ANTLRInputStream(txt));
CommonTokenStream tokens = new CommonTokenStream(lexer);
TestParser parser = new TestParser(tokens);
parser.root();
for (Token t : tokens.getTokens()) {
System.out.println(t);
}
}
}
注意:顺便说一下,Num
永远不会被识别为Id
规则可以匹配相同的内容。试试这个:
Id : Letter (Letter | [0-9])*;
Num : [0-9]+;
fragment Letter : [a-zA-z_];