为什么我得到 "mismatched input 'addr' expecting {<EOF>, 'addr'}"
Why am I getting "mismatched input 'addr' expecting {<EOF>, 'addr'}"
鉴于此 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 {
};
此命令行:
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 冲突。
你的规则 ExprElem
是词法分析器规则,而不是解析器规则(它以大写字母开头)并且屏蔽了 Addr
规则,所以,没有 Addr
:(
此外,因为 ExprElem
是词法分析器规则,它依赖于 Id
或 Num
规则。因此,当找到 Id
时,ANTLR 词法分析器将其赋予 ExprElem
标记类型而不是 Id
标记类型。
所以,有两件事,您可以将 ExprElem
规则重写为 exprElem
(假设您需要解析器规则):
exprElem : Num | Id;
或者您可以在 ExprElem
中使用 Id
标记作为规则的一部分,但您需要一些可以区分 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 : '#';
据我推测,这绝对不是你想要的,但我只是把它放在这里来说明词法分析器规则如何重用其他规则。
当您对令牌的用途有疑问时,请毫不犹豫地显示识别令牌。这是我经常使用的 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_];
鉴于此 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 {
};
此命令行:
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 冲突。
你的规则 ExprElem
是词法分析器规则,而不是解析器规则(它以大写字母开头)并且屏蔽了 Addr
规则,所以,没有 Addr
:(
此外,因为 ExprElem
是词法分析器规则,它依赖于 Id
或 Num
规则。因此,当找到 Id
时,ANTLR 词法分析器将其赋予 ExprElem
标记类型而不是 Id
标记类型。
所以,有两件事,您可以将 ExprElem
规则重写为 exprElem
(假设您需要解析器规则):
exprElem : Num | Id;
或者您可以在 ExprElem
中使用 Id
标记作为规则的一部分,但您需要一些可以区分 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 : '#';
据我推测,这绝对不是你想要的,但我只是把它放在这里来说明词法分析器规则如何重用其他规则。
当您对令牌的用途有疑问时,请毫不犹豫地显示识别令牌。这是我经常使用的 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_];