为什么这个语法无法解析这个输入?
Why does this grammar fail to parse this input?
我正在为一种小型语言和 Antlr4 定义语法。这个想法是在那种语言中,有一个关键字 "function" 可用于定义函数或在定义参数时用作类型说明符。我希望能够做这样的事情:
function aFunctionHere(int a, function callback) ....
但是,Antlr 似乎不喜欢我在两个不同的地方使用 "function"。据我所知,语法甚至没有歧义。
在下面的语法中,如果我删除第 1 行,生成的解析器将毫无问题地解析样本输入。此外,如果我更改第 2 行或第 3 行中的标记字符串,使它们不相等,解析器就会工作。
我按原样使用语法时遇到的错误:
line 1:0 mismatched input 'function' expecting <INVALID>
"expecting <INVALID>" 是什么意思?
(精简)语法:
grammar test;
begin : function ;
function: FUNCTION IDENTIFIER '(' parameterlist? ')' ;
parameterlist: parameter (',' parameter)+ ;
parameter: BaseParamType IDENTIFIER ;
// Lexer stuff
BaseParamType:
INT_TYPE
| FUNCTION_TYPE // <---- LINE 1
;
FUNCTION : 'function'; // <---- LINE 2
INT_TYPE : 'int';
FUNCTION_TYPE : 'function'; // <---- LINE 3
IDENTIFIER : [a-zA-Z_$]+[a-zA-Z_[=11=]-9]*;
WS : [ \t\r\n]+ -> skip ;
我正在使用的输入:
function abc(int c, int d, int a)
测试生成解析器的程序:
from antlr4 import *
from testLexer import testLexer as Lexer
from testParser import testParser as Parser
from antlr4.tree.Trees import Trees
def main(argv):
input = FileStream(argv[1] if len(argv)>1 else "test.in")
lexer = Lexer(input)
tokens = CommonTokenStream(lexer)
parser = Parser(tokens)
tree = parser.begin()
print Trees.toStringTree(tree, None, parser)
if __name__ == '__main__':
import sys
main(sys.argv)
只需为令牌使用一个名称 function
。
令牌只是令牌。孤立地看function
,无法判断它是FUNCTION
还是FUNCTION_TYPE
。由于 FUNCTION
在文件中排在第一位,因此词法分析器使用了它。这使得无法匹配 FUNCTION_TYPE
,从而成为无效的标记类型。
解析器将找出令牌的句法角色function
。因此,即使可能,也没有必要对同一个标记使用两个不同的词法描述符。
OP中的文法中,BaseParamType
也是词法类型,会吸收token的所有用法function
,防止FUNCTION
在产生式中被识别为function
。将其名称更改为 baseParamType
,这实际上将其更改为解析器 non-terminal,将允许解析器工作,尽管我认为它可能会以不希望的方式改变解析树。
鉴于 Antlr 的预测解析策略的性质,我理解解析器 "should know" 哪些词法标记在上下文中是可能的反对意见。我远不是 Antlr 专家,所以我不会假装解释为什么它似乎不起作用,但是对于大多数解析器生成器——以及我常用的所有解析器生成器——词法分析作为之前传递给解析,因此文本输入到标记流的转换是在解析器建立上下文之前完成的。 (大多数词法生成器,包括 Antlr,都有用户可以用来构建词法上下文的机制,但恕我直言,这些机制会降低语法可读性,只有在绝对必要时才应使用。)
这是我测试的语法文件:
grammar test;
begin : function ;
function: FUNCTION IDENTIFIER '(' parameterlist? ')' ;
parameterlist: parameter (',' parameter)+ ;
parameter: baseParamType IDENTIFIER ;
// Lexer stuff
baseParamType:
INT_TYPE
| FUNCTION //
;
FUNCTION : 'function';
INT_TYPE : 'int';
IDENTIFIER : [a-zA-Z_$]+[a-zA-Z_[=10=]-9]*;
WS : [ \t\r\n]+ -> skip ;
我正在为一种小型语言和 Antlr4 定义语法。这个想法是在那种语言中,有一个关键字 "function" 可用于定义函数或在定义参数时用作类型说明符。我希望能够做这样的事情:
function aFunctionHere(int a, function callback) ....
但是,Antlr 似乎不喜欢我在两个不同的地方使用 "function"。据我所知,语法甚至没有歧义。
在下面的语法中,如果我删除第 1 行,生成的解析器将毫无问题地解析样本输入。此外,如果我更改第 2 行或第 3 行中的标记字符串,使它们不相等,解析器就会工作。
我按原样使用语法时遇到的错误:
line 1:0 mismatched input 'function' expecting <INVALID>
"expecting <INVALID>" 是什么意思?
(精简)语法:
grammar test;
begin : function ;
function: FUNCTION IDENTIFIER '(' parameterlist? ')' ;
parameterlist: parameter (',' parameter)+ ;
parameter: BaseParamType IDENTIFIER ;
// Lexer stuff
BaseParamType:
INT_TYPE
| FUNCTION_TYPE // <---- LINE 1
;
FUNCTION : 'function'; // <---- LINE 2
INT_TYPE : 'int';
FUNCTION_TYPE : 'function'; // <---- LINE 3
IDENTIFIER : [a-zA-Z_$]+[a-zA-Z_[=11=]-9]*;
WS : [ \t\r\n]+ -> skip ;
我正在使用的输入:
function abc(int c, int d, int a)
测试生成解析器的程序:
from antlr4 import *
from testLexer import testLexer as Lexer
from testParser import testParser as Parser
from antlr4.tree.Trees import Trees
def main(argv):
input = FileStream(argv[1] if len(argv)>1 else "test.in")
lexer = Lexer(input)
tokens = CommonTokenStream(lexer)
parser = Parser(tokens)
tree = parser.begin()
print Trees.toStringTree(tree, None, parser)
if __name__ == '__main__':
import sys
main(sys.argv)
只需为令牌使用一个名称 function
。
令牌只是令牌。孤立地看function
,无法判断它是FUNCTION
还是FUNCTION_TYPE
。由于 FUNCTION
在文件中排在第一位,因此词法分析器使用了它。这使得无法匹配 FUNCTION_TYPE
,从而成为无效的标记类型。
解析器将找出令牌的句法角色function
。因此,即使可能,也没有必要对同一个标记使用两个不同的词法描述符。
OP中的文法中,BaseParamType
也是词法类型,会吸收token的所有用法function
,防止FUNCTION
在产生式中被识别为function
。将其名称更改为 baseParamType
,这实际上将其更改为解析器 non-terminal,将允许解析器工作,尽管我认为它可能会以不希望的方式改变解析树。
鉴于 Antlr 的预测解析策略的性质,我理解解析器 "should know" 哪些词法标记在上下文中是可能的反对意见。我远不是 Antlr 专家,所以我不会假装解释为什么它似乎不起作用,但是对于大多数解析器生成器——以及我常用的所有解析器生成器——词法分析作为之前传递给解析,因此文本输入到标记流的转换是在解析器建立上下文之前完成的。 (大多数词法生成器,包括 Antlr,都有用户可以用来构建词法上下文的机制,但恕我直言,这些机制会降低语法可读性,只有在绝对必要时才应使用。)
这是我测试的语法文件:
grammar test;
begin : function ;
function: FUNCTION IDENTIFIER '(' parameterlist? ')' ;
parameterlist: parameter (',' parameter)+ ;
parameter: baseParamType IDENTIFIER ;
// Lexer stuff
baseParamType:
INT_TYPE
| FUNCTION //
;
FUNCTION : 'function';
INT_TYPE : 'int';
IDENTIFIER : [a-zA-Z_$]+[a-zA-Z_[=10=]-9]*;
WS : [ \t\r\n]+ -> skip ;