我想使用antlr为以下字符串创建一个解析器:
“1 AND(2 OR(3 AND 4))和5” - >所以我想要解析成功后应该导致树的AND和OR操作。这应该导致以下树:
AND
- 1
- OR
- 2
- AND
-3
-4
- 5
我还想避免像“1 AND 2 OR 3”这样的输入不清楚,因为不清楚如何从中构造树。并且它似乎解析器“接受”输入带有诸如“1 AND 2asdf”之类的尾随歌曲。
到目前为止我所做的是(没有按预期工作):
grammar code;
options {
language=CSharp3;
output=AST;
ASTLabelType=CommonTree;
//backtrack=true;
}
tokens {
ROOT;
}
@rulecatch {
catch {
throw;
}
}
@parser::namespace { Web.DealerNet.Areas.QueryBuilder.Parser }
@lexer::namespace { Web.DealerNet.Areas.QueryBuilder.Parser }
@lexer::members {
public override void ReportError(RecognitionException e) {
throw e;
}
}
public parse : exp EOF -> ^(ROOT exp);
exp
: atom
( And^ atom (And! atom)*
| Or^ atom (Or! atom)*
)?
;
atom
: Number
| '(' exp ')' -> exp
;
Number
: ('0'..'9')+
;
And
: 'AND' | 'and'
;
Or
: 'OR' | 'or'
;
WS : (' '|'\t'|'\f'|'\n'|'\r')+{ Skip(); };
希望你们中的某些人可以帮助我走上正轨!
编辑,我怎样才能达到“1 AND 2 AND 3”的结果
AND
1
2
3
而不是
AND
AND
1
2
3
修改
感谢伟大的解决方案,它的作用就像一个魅力,除了一件事:当我在下面的术语“1 AND(2 OR(1 AND 3)AND 4”(关闭括号丢失)上调用parse()方法时)解析器仍然接受输入为有效。
到目前为止这是我的代码: 语法代码;
options {
language=CSharp3;
output=AST;
ASTLabelType=CommonTree;
}
tokens {
ROOT;
}
@rulecatch {
catch {
throw;
}
}
@lexer::members {
public override void ReportError(RecognitionException e) {
throw e;
}
}
public parse
: exp -> ^(ROOT exp)
;
exp
: atom
( And^ atom (And! atom)*
| Or^ atom (Or! atom)*
)?
;
atom
: Number
| '(' exp ')' -> exp
;
Number
: ('0'..'9')+
;
And
: 'AND' | 'and'
;
Or
: 'OR' | 'or'
;
WS : (' '|'\t'|'\f'|'\n'|'\r')+{ Skip(); };
EDIT2: 我刚发现我的语法有另一个问题: 当我输入像“1 AND 2 OR 3”时,语法被解析得很好,但它应该失败,因为“1 AND 2”需要在括号内或“2 OR 3”部分。 我不明白为什么解析器会运行,因为在我看来这个语法应该真的涵盖了这种情况。 是否有任何类型的在线测试环境左右才能找到问题? (我试过antlrWorks,但那里给出的错误并没有把我带到任何地方......)
EDIT3: 更新代码以表示建议的新语法。
我仍然遇到以下语法相同的问题:
public parse : exp EOF -> ^(ROOT exp);
没有解析到最后..生成的c#源似乎只是忽略了EOF ...你能否就如何解决这个问题提供进一步的指导?
edit4 我仍然有以下语法相同的问题:
公共解析:exp EOF - > ^(ROOT exp);
没有解析到最后..生成的c#源似乎只是忽略了EOF ...你能否就如何解决这个问题提供进一步的指导?
问题似乎出现在代码的这一部分:
EOF2=(IToken)Match(input,EOF,Follow._EOF_in_parse97);
stream_EOF.Add(EOF2);
当我添加以下代码(只是一个黑客)时,它可以工作......
if (EOF2.Text == "<missing EOF>") {
throw new Exception(EOF2.Text);
}
我可以更改任何内容,以便解析器从一开始就生成correclty吗?
答案 0 :(得分:1)
此规则将禁止包含AND
和OR
且不带括号的表达式。它还将构造您描述的解析树,方法是将第一个AND
或OR
标记作为AST的根,然后隐藏AND
或OR
标记的其余部分来自同一个表达。
exp
: atom
( 'AND'^ atom ('AND'! atom)*
| 'OR'^ atom ('OR'! atom)*
)?
;
编辑:第二个问题与此无关。如果您没有通过在一个解析器规则中包含明确的EOF
符号来指示ANTLR使用所有输入,则允许仅使用一部分输入以尝试成功匹配某些内容
原始parse
规则说“匹配某些输入为exp
”。对parse
规则的以下修改说“将整个输入与exp
匹配”。
public parse : exp EOF -> ^(ROOT exp);