我想为以下字符串创建一个使用 antlr 的解析器:
“1 AND (2 OR (3 AND 4)) AND 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(); };
编辑2: 我刚刚发现我的语法有另一个问题:当我输入像“1 AND 2 OR 3”这样的输入时,语法被解析得很好,但它应该失败,因为“1 AND 2”需要在括号内或“ 2 或 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);
}
我可以更改任何内容以便解析器从一开始就正确生成吗?