ANTLR 4 无法解析一个类似于另一个的规则
ANTLR 4 can't parse one rule similar to another
我正在为 C# 编写一个基于 ANTLR 4 的规则引擎(我使用的是 Sam Harwell alternative),但我无法正确解析关于两个非常相似的规则的输入的语法。
可能还有其他几个错误,但我暂时坚持这个。另外,我是 ANTLR 的新手(除了我在学校的旧时光 ^^),所以不要犹豫给我一些 tips/explanations :)。
我的目标是解释二进制和数字赋值,例如:
Fact := Fact1 OR Fact2
在幕后,我希望它符合 bin_assign
规则。
Fact := 8 * 4
在幕后,我希望它符合 num_assign
规则。
但是我的解析器总是匹配 num_assign
并且匹配运算符失败(因为它期望 NUM_OP 或 EOF)。
您会看到这两条规则以相同的方式以 FACT 令牌开始。但我的直觉告诉我这不是问题的原因(正如我所说,我是 ANTLR 的新手,这只是我的直觉)。我写这两条规则是为了避免 Fact := 1 + true
成为正确的陈述。
这是我的语法:
常用词法分析器规则:
lexer grammar Common;
/*
* Lexer Rules
*/
FACT: [a-zA-Z](([a-zA-Z0-9] | '.' | '_')*[a-zA-Z0-9])?;
ASSIGN: ':=';
LITERAL: '\'' .*? '\'' | '"' .*? '"';
WS : [ \t\r\n]+ -> skip;
数值语法:
grammar NumericGrammar;
import Common;
/*
* Parser Rules
*/
num_stat: num_stat NUM_OP num_stat # ArithmeticStat
| '(' num_stat ')' # ArithmeticBrakedStat
| DIGIT # DigitStat
| FACT # ArithmeticFactStat
;
num_assign:
FACT NUM_ASSIGN num_stat # ArithmeticAssign
;
/*
* Lexer Rules
*/
DIGIT: INT | FLOAT;
INT: ([1-9][0-9]*)?[0-9];
FLOAT: INT(','|'.')[0-9]+;
NUM_OP: MULT | DIV | ADD | SUB;
MULT: '*';
DIV: '/';
ADD: '+';
SUB: '-';
NUM_ASSIGN: MULT_ASSIGN | DIV_ASSIGN | ADD_ASSIGN | SUB_ASSIGN | ASSIGN;
MULT_ASSIGN: '*=';
DIV_ASSIGN: '\=';
ADD_ASSIGN: '+=';
SUB_ASSIGN: '-=';
二进制语法:
grammar BinaryGrammar;
import NumericGrammar;
/*
* Parser Rules
*/
bin_stat: bin_stat BIN_OP bin_stat # BinaryStat
| '(' bin_stat ')' # BinaryBrakedStat
| NOT bin_stat # NegateStat
| num_stat COMPARE_OP num_stat # CompareStat
| FACT EQUALITY_OP (LITERAL | DIGIT) # LiteralComparisonStat
| num_stat IN SET # IntervalComparisonStat
| BOOL # BoolStat
| FACT # BinaryFactStat
;
bin_assign:
FACT ASSIGN bin_stat # BinAssign
;
/*
* Lexer Rules
*/
BOOL: TRUE | FALSE;
TRUE: '1' | 'true' | 'True' | 'YES' | 'Yes' | 'yes';
FALSE: '0' | 'false' | 'False' | 'NO' | 'No' | 'no';
BIN_OP: AND | OR | EQUALITY_OP;
COMPARE_OP: EQUALITY_OP | GT | GTE | LT | LTE;
AND: 'AND' | 'And' | 'and' | '&' | '&&';
OR: 'OR' | 'Or' | 'or' | '|' | '||';
EQUALITY_OP: EQUALITY | UNEQUALITY;
EQUALITY: '=' | '==';
UNEQUALITY: '<>' | '!=' | '=/=' | '=\=';
GT: '>';
GTE: '>=';
LT: '<';
LTE: '<=';
NOT: '!' | 'NOT' | 'not';
IN: 'IN' | 'in';
SET: ('[' | ']') (INT | FLOAT) ';' (INT | FLOAT) ('[' | ']');
最终语法:
grammar Test;
import BinaryGrammar;
/*
* Parser Rules
*/
r: (IF bin_stat THEN)? assign EOF;
assign: bin_assign | num_assign;
/*
* Lexer Rules
*/
IF: 'if' | 'IF' | 'If';
THEN: 'then' | 'THEN' | 'Then';
如果需要,这里是执行的屏幕截图:
FACT
词法分析器规则将不匹配 Fact1
FACT: [a-zA-Z](([a-zA-Z0-9] | '.' | '_')*[a-zA-Z0-9])?;
中间的 kleene star 名义上是一个贪心算子。因此,将捕获所有终端号码,不留下任何内容来完成规则。
让它成为非贪婪的:
FACT: [a-zA-Z](([a-zA-Z0-9] | '.' | '_')*?[a-zA-Z0-9])?;
使用不一致的标记命名会使您更难分析规则(parser/lexer 不会介意)。因此,这只是关于更容易(手动)阅读规则的建议——当我阅读我的语法时,当我看到两条带有不同标记的规则都在大写(终端)中时,我确信它们在这一点上是不同的。在您的情况下,您必须检查该令牌是否真的是终端,如果不是,它如何展开。
我正在为 C# 编写一个基于 ANTLR 4 的规则引擎(我使用的是 Sam Harwell alternative),但我无法正确解析关于两个非常相似的规则的输入的语法。
可能还有其他几个错误,但我暂时坚持这个。另外,我是 ANTLR 的新手(除了我在学校的旧时光 ^^),所以不要犹豫给我一些 tips/explanations :)。
我的目标是解释二进制和数字赋值,例如:
Fact := Fact1 OR Fact2
在幕后,我希望它符合 bin_assign
规则。
Fact := 8 * 4
在幕后,我希望它符合 num_assign
规则。
但是我的解析器总是匹配 num_assign
并且匹配运算符失败(因为它期望 NUM_OP 或 EOF)。
您会看到这两条规则以相同的方式以 FACT 令牌开始。但我的直觉告诉我这不是问题的原因(正如我所说,我是 ANTLR 的新手,这只是我的直觉)。我写这两条规则是为了避免 Fact := 1 + true
成为正确的陈述。
这是我的语法:
常用词法分析器规则:
lexer grammar Common; /* * Lexer Rules */ FACT: [a-zA-Z](([a-zA-Z0-9] | '.' | '_')*[a-zA-Z0-9])?; ASSIGN: ':='; LITERAL: '\'' .*? '\'' | '"' .*? '"'; WS : [ \t\r\n]+ -> skip;
数值语法:
grammar NumericGrammar; import Common; /* * Parser Rules */ num_stat: num_stat NUM_OP num_stat # ArithmeticStat | '(' num_stat ')' # ArithmeticBrakedStat | DIGIT # DigitStat | FACT # ArithmeticFactStat ; num_assign: FACT NUM_ASSIGN num_stat # ArithmeticAssign ; /* * Lexer Rules */ DIGIT: INT | FLOAT; INT: ([1-9][0-9]*)?[0-9]; FLOAT: INT(','|'.')[0-9]+; NUM_OP: MULT | DIV | ADD | SUB; MULT: '*'; DIV: '/'; ADD: '+'; SUB: '-'; NUM_ASSIGN: MULT_ASSIGN | DIV_ASSIGN | ADD_ASSIGN | SUB_ASSIGN | ASSIGN; MULT_ASSIGN: '*='; DIV_ASSIGN: '\='; ADD_ASSIGN: '+='; SUB_ASSIGN: '-=';
二进制语法:
grammar BinaryGrammar; import NumericGrammar; /* * Parser Rules */ bin_stat: bin_stat BIN_OP bin_stat # BinaryStat | '(' bin_stat ')' # BinaryBrakedStat | NOT bin_stat # NegateStat | num_stat COMPARE_OP num_stat # CompareStat | FACT EQUALITY_OP (LITERAL | DIGIT) # LiteralComparisonStat | num_stat IN SET # IntervalComparisonStat | BOOL # BoolStat | FACT # BinaryFactStat ; bin_assign: FACT ASSIGN bin_stat # BinAssign ; /* * Lexer Rules */ BOOL: TRUE | FALSE; TRUE: '1' | 'true' | 'True' | 'YES' | 'Yes' | 'yes'; FALSE: '0' | 'false' | 'False' | 'NO' | 'No' | 'no'; BIN_OP: AND | OR | EQUALITY_OP; COMPARE_OP: EQUALITY_OP | GT | GTE | LT | LTE; AND: 'AND' | 'And' | 'and' | '&' | '&&'; OR: 'OR' | 'Or' | 'or' | '|' | '||'; EQUALITY_OP: EQUALITY | UNEQUALITY; EQUALITY: '=' | '=='; UNEQUALITY: '<>' | '!=' | '=/=' | '=\='; GT: '>'; GTE: '>='; LT: '<'; LTE: '<='; NOT: '!' | 'NOT' | 'not'; IN: 'IN' | 'in'; SET: ('[' | ']') (INT | FLOAT) ';' (INT | FLOAT) ('[' | ']');
最终语法:
grammar Test; import BinaryGrammar; /* * Parser Rules */ r: (IF bin_stat THEN)? assign EOF; assign: bin_assign | num_assign; /* * Lexer Rules */ IF: 'if' | 'IF' | 'If'; THEN: 'then' | 'THEN' | 'Then';
如果需要,这里是执行的屏幕截图:
FACT
词法分析器规则将不匹配 Fact1
FACT: [a-zA-Z](([a-zA-Z0-9] | '.' | '_')*[a-zA-Z0-9])?;
中间的 kleene star 名义上是一个贪心算子。因此,将捕获所有终端号码,不留下任何内容来完成规则。
让它成为非贪婪的:
FACT: [a-zA-Z](([a-zA-Z0-9] | '.' | '_')*?[a-zA-Z0-9])?;
使用不一致的标记命名会使您更难分析规则(parser/lexer 不会介意)。因此,这只是关于更容易(手动)阅读规则的建议——当我阅读我的语法时,当我看到两条带有不同标记的规则都在大写(终端)中时,我确信它们在这一点上是不同的。在您的情况下,您必须检查该令牌是否真的是终端,如果不是,它如何展开。