在我刚写的一个小测试范围内,我遇到了一个奇怪的问题,我不太了解。
将其剥离为显示问题的最小示例,让我们从以下语法开始:
testing.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 : [ trn]+ -> skip;
使用输入
z = x + y;
一切都很好,我们得到了一个解析树,该树从cscript到statement_list,statement,spectment_statement,id和expression。太好了!
现在,如果我添加了声明变量的可能性,所有这些都会下降:
这是语法的变化:
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)
突然之间,相同的测试输入被错误地分解为两个语句_lists,每个语句继续带有"缺失';'"警告,第一个将转到" z ="的不完整sizhtment_statement_ statement_statement_statement_stater。到不完整的sigsment_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的评论之后:
用显式声明替换所有隐式Lexer规则后,突然间,输入" z = x y"工作了。(大拇指)
我接下来要做的就是恢复更多我想到的原始示例,并添加新的输入行
int x = 22;
输入(以前有效,但没有将其归入最小示例)。现在,线路失败。这是测试钻机的输出输出:
[@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 '='
由于问题似乎在变量_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;"one_answers" x = 22;"作品。叹气
在2016-12-26上进行编辑,在Mike的下一个评论之后:
仔细检查,一切都是Lexer规则。尽管如此," ='and'='之间的不匹配(不幸的是,我再也无法重建)给了我检查令牌类型的想法。当前状态是:
(缩短语法)
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的输出 - 是sistizent_operator,而预期相等的是13。
。这可能是问题吗?
好的,似乎主要的收入是:考虑您的定义以及如何定义它们。为您的文字创建明确的Lexer规则,而不是在解析器规则中隐式定义它们。如果解析器给您奇怪的错误,请检查您从Lexer获得的令牌值,因为它们必须首先是正确的,否则您的解析没有机会完成工作。