我需要为以下搜索条件定义语言解析器:
CRITERIA_1=<values-set-#1> AND/OR CRITERIA_2=<values-set-#2>;
其中<values-set-#1>
可以包含1-50和<values-set-#2>
的值,可以来自以下集合(5,A,B,C) - 这里的情况并不重要。
我已经决定在C#(CSharp3)中使用带有输出的ANTLR3(v3.4),到目前为止它的工作非常流畅。问题是当我从两个数据集(即本例中为'5')提供值时,它无法解析字符串。例如,如果我提供以下字符串
CRITERIA_1=5;
它返回以下错误,其中值节点应为:
<unexpected: [@1,11:11='5',<27>,1:11], resync=5>
语法定义文件如下:
grammar ZeGrammar;
options {
language=CSharp3;
TokenLabelType=CommonToken;
output=AST;
ASTLabelType=CommonTree;
k=3;
}
tokens
{
ROOT;
CRITERIA_1;
CRITERIA_2;
OR = 'OR';
AND = 'AND';
EOF = ';';
LPAREN = '(';
RPAREN = ')';
}
public
start
: expr EOF -> ^(ROOT expr)
;
expr
: subexpr ((AND|OR)^ subexpr)*
;
subexpr
: grouppedsubexpr
| 'CRITERIA_1=' rangeval1_expr -> ^(CRITERIA_1 rangeval1_expr)
| 'CRITERIA_2=' rangeval2_expr -> ^(CRITERIA_2 rangeval2_expr)
;
grouppedsubexpr
: LPAREN! expr RPAREN!
;
rangeval1_expr
: rangeval1_subexpr
| RANGE1_VALUES
;
rangeval1_subexpr
: LPAREN! rangeval1_expr (OR^ rangeval1_expr)* RPAREN!
;
RANGE1_VALUES
: (('0'..'4')? ('0'..'9') | '5''0')
;
rangeval2_expr
: rangeval2_subexpr
| RANGE2_VALUES
;
rangeval2_subexpr
: LPAREN! rangeval2_expr (OR^ rangeval2_expr)* RPAREN!
;
RANGE2_VALUES
: '5' | ('a'|'A') | ('b'|'B') | ('c'|'C')
;
如果我从RANGE2_VALUES
删除值'5',它就可以了。任何人都可以暗示我做错了吗?
答案 0 :(得分:3)
您必须意识到词法分析器不根据解析器尝试匹配的内容生成令牌。因此,在您的情况下,输入"5"
将始终标记为RANGE1_VALUES
,而不是RANGE2_VALUES
,因为RANGE1_VALUES
和RANGE2_VALUES
都可以匹配此输入但RANGE1_VALUES
首先出现(因此RANGE1_VALUES
优先于RANGE2_VALUES
)。
可能的解决方法是删除RANGE1_VALUES
和RANGE2_VALUES
规则,并使用以下词法规则替换它们:
D0_4
: '0'..'4'
;
D5
: '5'
;
D6_50
: '6'..'9' // 6-9
| '1'..'4' '0'..'9' // 10-49
| '50' // 50
;
A_B_C
: ('a'|'A')
| ('b'|'B')
| ('c'|'C')
;
并介绍这些新的解析器规则:
range1_values
: D0_4
| D5
| D6_50
;
range2_values
: A_B_C
| D5
;
并分别使用RANGE1_VALUES
和RANGE2_VALUES
更改解析器规则中的所有range1_values
和range2_values
次调用。
您可以简单地匹配任何整数值,而不是尝试在 lexer-level 中解决此问题,如果值是正确的(或正确的范围),则使用< EM> semantic predicate :
range1_values
: INT {Integer.valueOf($INT.text) <= 50}?
;
range2_values
: A_B_C
| INT {Integer.valueOf($INT.text) == 5}?
;
INT
: '0'..'9'+
;
A_B_C
: 'a'..'c'
| 'A'..'C'
;