Antlr4解析不一致
Antlr4 parsing inconsistency
在我刚刚写的一个小测试解析器中,我遇到了一个奇怪的问题,我不太明白。
将其分解为显示问题的最小示例,让我们从以下语法开始:
测试.g4:
grammar Testing;
cscript // This is the construct I shortened
: (statement_list)* ;
statement_list
: statement ';' statement_list?
| block
;
statement
: assignment_statement
;
block : '{' statement_list? '}' ;
expression
: left=expression op=('*'|'/') right=expression # arithmeticExpression
| left=expression op=('+'|'-') right=expression # arithmeticExpression
| left=expression op=Comparison_operator right=expression # comparisonExpression
| ID # variableValueExpression
| constant # ignore // will be executed with the rule name
;
assignment_statement
: ID op=Assignment_operator expression
;
constant
: INT
| REAL;
Assignment_operator : ('=' | '+=' | '-=') ;
Comparison_operator : ('<' | '>' | '==' | '!=') ;
Comment : '//' .*? '\n' -> skip;
fragment NUM : [0-9];
INT : NUM+;
REAL
: NUM* '.' NUM+
| '.' NUM+
| INT
;
ID : [a-zA-Z_] [a-zA-Z_0-9]*;
WS : [ \t\r\n]+ -> skip;
使用输入
z = x + y;
一切都很好,我们得到了一个从 cscript 到 statement_list、语句、assignment_statement、id 和表达式的解析树。太棒了!
现在,如果我添加声明变量的可能性,一切都会付诸东流:
这是对语法的更改:
cscript
: (statement_list | variable_declaration ';')* ;
variable_declaration
: type ID ('=' expression)?
;
type
: 'int'
| 'real'
;
statement_list
: statement ';' statement_list?
| block
;
statement
: assignment_statement
;
// (continue as before)
突然间,相同的测试输入被错误地分解为两个 statement_lists,每个继续到带有 "missing ';'" 警告的语句,第一个进入不完整的 assignment_statement 的 "z =" 和第二个不完整的 assignment_statement "x +".
我尝试以文本形式显示解析树:
cscript
statement_list
statement
assignment_statement
'z'
'=' [marked as error]
[warning: missing ';']
statement_list
statement
assignment_statement
'x'
'+' [marked as error]
'y' [marked as error]
';'
谁能告诉我问题出在哪里? (以及如何修复它?;-))
编辑于 2016-12-26,在 Mike 的评论后:
用显式声明替换所有隐式词法分析器规则后,突然之间,输入 "z = x + y" 起作用了。 (点赞)
我接下来要做的是恢复更多我想到的原始示例,并添加一个新的输入行
int x = 22;
到输入(以前有效,但没有进入最小示例)。现在,that 行失败了。这是测试装置的 -token 输出:
[@0,0:2='int',<4>,1:0]
[@1,4:4='x',<22>,1:4]
[@2,6:6='=',<1>,1:6]
[@3,8:9='22',<20>,1:8]
[@4,10:10=';',<12>,1:10]
[@5,13:13='z',<22>,2:0]
[@6,15:15='=',<1>,2:2]
[@7,17:17='x',<22>,2:4]
[@8,19:19='+',<18>,2:6]
[@9,21:21='y',<22>,2:8]
[@10,22:22=';',<12>,2:9]
[@11,25:24='<EOF>',<-1>,3:0]
line 1:6 mismatched input '=' expecting '='
由于问题似乎出在 variable_declaration 部分,我什至尝试将其分成两个解析规则,如下所示:
cscript
: (statement_list | variable_declaration_and_assignment SEMICOLON | variable_declaration SEMICOLON)* ;
variable_declaration_and_assignment
: type ID EQUAL expression
;
variable_declaration
: type ID
;
结果:
line 1:6 no viable alternative at input 'intx='
仍然卡住了:-(
顺便说一句:将 "int x = 22;" 拆分为 "int x;" 和 "x = 22;" 是可行的。 感叹
编辑于 2016-12-26,在 Mike 的下一条评论之后:
仔细检查,一切都是词法分析器规则。尽管如此,'=' 和 '=' 之间的不匹配(遗憾的是我无法再重建)让我产生了检查令牌类型的想法。当前状态是:
(简化语法)
cscript
: (statement_list | variable_declaration)* ;
...
variable_declaration
: type ID (EQUAL expression)? SEMICOLON
;
...
Assignment_operator : (EQUAL | PLUS_EQ | MINUS_EQ) ;
// among others
PLUS_EQ : '+=';
MINUS_EQ : '-=';
EQUAL: '=';
...
缩短输出:
[@0,0:2='int',<4>,1:0]
[@1,4:4='x',<22>,1:4]
[@2,6:6='=',<1>,1:6]
...
line 1:6 mismatched input '=' expecting ';'
这里,如果我理解正确,“=”被解析为标记类型 1,根据 lexer.tokens 输出,它是 Assignment_Operator,而预期的 EQUAL 将是 13 .
这可能是问题所在吗?
好的,看来这里的主要收获是:考虑您的定义以及定义它们的方式。为文字创建明确的词法分析器规则,而不是在解析器规则中隐式定义它们。如果解析器给你奇怪的错误,请检查你从词法分析器获得的标记值,因为它们首先必须是正确的,否则你的解析器就没有机会完成它的工作。
在我刚刚写的一个小测试解析器中,我遇到了一个奇怪的问题,我不太明白。
将其分解为显示问题的最小示例,让我们从以下语法开始:
测试.g4:
grammar Testing;
cscript // This is the construct I shortened
: (statement_list)* ;
statement_list
: statement ';' statement_list?
| block
;
statement
: assignment_statement
;
block : '{' statement_list? '}' ;
expression
: left=expression op=('*'|'/') right=expression # arithmeticExpression
| left=expression op=('+'|'-') right=expression # arithmeticExpression
| left=expression op=Comparison_operator right=expression # comparisonExpression
| ID # variableValueExpression
| constant # ignore // will be executed with the rule name
;
assignment_statement
: ID op=Assignment_operator expression
;
constant
: INT
| REAL;
Assignment_operator : ('=' | '+=' | '-=') ;
Comparison_operator : ('<' | '>' | '==' | '!=') ;
Comment : '//' .*? '\n' -> skip;
fragment NUM : [0-9];
INT : NUM+;
REAL
: NUM* '.' NUM+
| '.' NUM+
| INT
;
ID : [a-zA-Z_] [a-zA-Z_0-9]*;
WS : [ \t\r\n]+ -> skip;
使用输入
z = x + y;
一切都很好,我们得到了一个从 cscript 到 statement_list、语句、assignment_statement、id 和表达式的解析树。太棒了!
现在,如果我添加声明变量的可能性,一切都会付诸东流:
这是对语法的更改:
cscript
: (statement_list | variable_declaration ';')* ;
variable_declaration
: type ID ('=' expression)?
;
type
: 'int'
| 'real'
;
statement_list
: statement ';' statement_list?
| block
;
statement
: assignment_statement
;
// (continue as before)
突然间,相同的测试输入被错误地分解为两个 statement_lists,每个继续到带有 "missing ';'" 警告的语句,第一个进入不完整的 assignment_statement 的 "z =" 和第二个不完整的 assignment_statement "x +".
我尝试以文本形式显示解析树:
cscript
statement_list
statement
assignment_statement
'z'
'=' [marked as error]
[warning: missing ';']
statement_list
statement
assignment_statement
'x'
'+' [marked as error]
'y' [marked as error]
';'
谁能告诉我问题出在哪里? (以及如何修复它?;-))
编辑于 2016-12-26,在 Mike 的评论后:
用显式声明替换所有隐式词法分析器规则后,突然之间,输入 "z = x + y" 起作用了。 (点赞)
我接下来要做的是恢复更多我想到的原始示例,并添加一个新的输入行
int x = 22;
到输入(以前有效,但没有进入最小示例)。现在,that 行失败了。这是测试装置的 -token 输出:
[@0,0:2='int',<4>,1:0]
[@1,4:4='x',<22>,1:4]
[@2,6:6='=',<1>,1:6]
[@3,8:9='22',<20>,1:8]
[@4,10:10=';',<12>,1:10]
[@5,13:13='z',<22>,2:0]
[@6,15:15='=',<1>,2:2]
[@7,17:17='x',<22>,2:4]
[@8,19:19='+',<18>,2:6]
[@9,21:21='y',<22>,2:8]
[@10,22:22=';',<12>,2:9]
[@11,25:24='<EOF>',<-1>,3:0]
line 1:6 mismatched input '=' expecting '='
由于问题似乎出在 variable_declaration 部分,我什至尝试将其分成两个解析规则,如下所示:
cscript
: (statement_list | variable_declaration_and_assignment SEMICOLON | variable_declaration SEMICOLON)* ;
variable_declaration_and_assignment
: type ID EQUAL expression
;
variable_declaration
: type ID
;
结果:
line 1:6 no viable alternative at input 'intx='
仍然卡住了:-( 顺便说一句:将 "int x = 22;" 拆分为 "int x;" 和 "x = 22;" 是可行的。 感叹
编辑于 2016-12-26,在 Mike 的下一条评论之后:
仔细检查,一切都是词法分析器规则。尽管如此,'=' 和 '=' 之间的不匹配(遗憾的是我无法再重建)让我产生了检查令牌类型的想法。当前状态是:
(简化语法)
cscript
: (statement_list | variable_declaration)* ;
...
variable_declaration
: type ID (EQUAL expression)? SEMICOLON
;
...
Assignment_operator : (EQUAL | PLUS_EQ | MINUS_EQ) ;
// among others
PLUS_EQ : '+=';
MINUS_EQ : '-=';
EQUAL: '=';
...
缩短输出:
[@0,0:2='int',<4>,1:0]
[@1,4:4='x',<22>,1:4]
[@2,6:6='=',<1>,1:6]
...
line 1:6 mismatched input '=' expecting ';'
这里,如果我理解正确,“=”被解析为标记类型 1,根据 lexer.tokens 输出,它是 Assignment_Operator,而预期的 EQUAL 将是 13 .
这可能是问题所在吗?
好的,看来这里的主要收获是:考虑您的定义以及定义它们的方式。为文字创建明确的词法分析器规则,而不是在解析器规则中隐式定义它们。如果解析器给你奇怪的错误,请检查你从词法分析器获得的标记值,因为它们首先必须是正确的,否则你的解析器就没有机会完成它的工作。