Python ANTLR解析不匹配的TokenException
我正在尝试为我正在编写的更简单的语言编写一个简单的解析器。它由后缀表达式组成。到目前为止,我对解析器有问题。当我在输入Python ANTLR解析不匹配的TokenException,python,antlr,parser-generator,antlrworks,Python,Antlr,Parser Generator,Antlrworks,我正在尝试为我正在编写的更简单的语言编写一个简单的解析器。它由后缀表达式组成。到目前为止,我对解析器有问题。当我在输入2*test>上运行它时,我得到一个不匹配的TokenException 另外,我将如何实现递归后缀解析器 这是我的密码: grammar star; options { language=Python; output=AST; ASTLabelType=CommonTree; } tokens {DECL;} //start // : decl
2*test>
上运行它时,我得到一个不匹配的TokenException
另外,我将如何实现递归后缀解析器
这是我的密码:
grammar star;
options {
language=Python;
output=AST;
ASTLabelType=CommonTree;
}
tokens {DECL;}
//start
// : decl ;
//decl
// : type ID -> ^(DECL type ID)
// ;
program
: (body)+
;
body : (nested WS)*
| (var WS)*
| (get WS)*
;
var
: nested ID '>>'
;
get
: ID '<<'
;
//expressions
term
: INT
;
expr
: term (term operator)*
;
nested
: expr (expr operator)*
;
operator
: ('*' | '+' | '/' | '%' | '-')
;
ID
: ('a'..'z' | 'A'..'Z') ('a..z' | '0'..'9' | 'A'..'Z')*
;
INT
: '0'..'9'+
;
WS
: (' ' | '\n' | '\t' | '\r') {$channel=HIDDEN;}
;
语法之星;
选择权{
语言=Python;
输出=AST;
ASTLabelType=CommonTree;
}
代币{DECL;}
//开始
//:十二月;
//十二月
//:类型ID->^(DECL类型ID)
// ;
程序
:(正文)+
;
正文:(嵌套WS)*
|(var WS)*
|(获取WS)*
;
变量
:嵌套ID“>>”
;
得到
:ID'问题是您的主体规则永远不会终止,因为它不允许匹配任何内容。我没有触发ANTLR,我真的不喜欢弄乱它,而是我改写了C++中的语法(使用AXE语法分析器生成器),添加了打印语句来跟踪匹配,得到了以下解析结果:代码< > 2×2测试> < <代码>: 如果您对调试此测试用例感兴趣,AXE语法如下所示,请在打印处设置断点以逐步完成解析器:
using namespace axe;
typedef std::string::iterator It;
auto space = r_any(" \t\n\r");
auto int_rule = r_numstr();
auto id = r_ident();
auto op = r_any("*+/%-");
auto term = int_rule
>> e_ref([](It i1, It i2)
{
std::cout << "\nparsed term: " << std::string(i1, i2);
});
auto expr = (term & *(term & op))
>> e_ref([](It i1, It i2)
{
std::cout << "\nparsed expr: " << std::string(i1, i2);
});
auto nested = (expr & *(expr & op))
>> e_ref([](It i1, It i2)
{
std::cout << "\nparsed nested: " << std::string(i1, i2);
});
auto get = (id & "<<")
>> e_ref([](It i1, It i2)
{
std::cout << "\nparsed get: " << std::string(i1, i2);
});
auto var = (nested & id & ">>")
>> e_ref([](It i1, It i2)
{
std::cout << "\nparsed var: " << std::string(i1, i2);
});
auto body = (*(nested & space) | *(var & space) | *(get & space))
>> e_ref([](It i1, It i2)
{
std::cout << "\nparsed body: " << std::string(i1, i2);
});
auto program = +(body)
| r_fail([](It i1, It i2)
{
std::cout << "\nparsing failed, parsed portion: "
<< std::string(i1, i2);
});
// test parser
std::ostringstream text;
text << "2 2 * test >>";
std::string str = text.str();
program(str.begin(), str.end());
使用名称空间axe;
typedef std::string::迭代器;
自动空格=r_any(“\t\n\r”);
auto int_rule=r_numstr();
自动标识=r_ident();
auto op=r_any(“*+/%-”);
自动术语=整数规则
>>e_ref([](It i1,It i2)
{
标准::cout e_ref([](It i1,It i2)
{
标准::cout e_ref([](It i1,It i2)
{
标准::cout e_ref([](It i1,It i2)
{
标准::cout>e_ref([](It i1,It i2)
{
标准::cout e_ref([](It i1,It i2)
{
有两件事是不正确的:
1.
您已将WS
标记放在隐藏的通道上,这使得解析器规则无法使用这些标记。因此WS
标记在正文中都是不正确的
2.
_(您最近的编辑删除了左递归问题,但我仍然要强调这一点。很抱歉,您有一个左递归规则(expr
),因此我将此信息留在这里)_
ANTLR是一个-生成器,因此您不能创建左递归语法。以下是左递归语法:
expr
: term term operator
;
term
: INT
| ID
| expr
;
因为expr
规则中的第一个术语
可能与expr
规则本身匹配。与任何LL解析器一样,ANTLR生成的解析器无法处理左递归
3.
如果您修复了WS
问题,您的body
规则将生成以下错误消息:
(1/7) Decision can match input such as "INT" using multiple alternatives
错误将消失(尽管这仍然不会导致正确解析您的输入!)
我意识到这听起来可能仍然很模糊,但要解释(或者理解,如果你对这一切都不熟悉的话)
4.
要正确解释expr
内部的递归expr
,您需要远离左递归,如我在#2中所述。您可以这样做:
body
: nested
| var
| get
;
// ...
expr
: term (term operator)
;
nested
: expr (expr operator)
;
expr
: term (expr operator | term operator)*
;
这仍然是不明确的,但这是在使用LL语法描述后缀表达式的情况下,不可避免的AFAIK。要解决此问题,可以在语法的options{…}
部分中启用全局回溯:
options {
language=Python;
output=AST;
backtrack=true;
}
演示
关于如何解析递归表达式的一个小演示如下所示:
语法之星;
选择权{
语言=Python;
输出=AST;
回溯=真;
}
作语法分析
:expr EOF->expr
;
expr
:(术语->术语)(expr2运算符->^(运算符$expr expr2)
|术语运算符->^(运算符术语)
)*
;
expr2
:expr
;
学期
:INT
|身份证
;
操作人员
: ('*' | '+' | '/' | '%' | '-')
;
身份证件
:('a''z''a''z')('a''z''0''9''a''z'))*
;
国际的
: '0'..'9'+
;
WS
:(“”|’\n’|’\t’|’\r’{$channel=HIDDEN;}
;
测试脚本:
!/usr/bin/env python
进口antlr3
从antlr3导入*
从antlr3.tree导入*
从starLexer导入*
从starParser导入*
def打印级别顺序(树、缩进):
打印“{0}{1}”。格式(“”*缩进,tree.text)
对于树中的子级。getChildren()
打印级别顺序(子级,缩进+1)
输入=“5 1 2+4*+3”
char_stream=antlr3.ANTLRStringStream(输入)
lexer=starLexer(字符流)
tokens=antlr3.CommonTokenStream(lexer)
parser=starParser(令牌)
tree=parser.parse().tree
打印级别顺序(树,0)
生成以下输出:
-
+
5
*
+
1
2
4
3
-
+
5.
*
+
1.
2.
4.
3.
对应于以下AST:
它无法处理3 4*2 3+/
,这意味着它无法将表达式作为术语。您如何运行测试?使用AntlWorks?您使用什么规则解析2 2*test>
?启动或程序
?我在AntlWorks解释器中运行了它,是的,我还使用程序
解析了它关于多个选项的一些警告
您发布的语法有很多错误。今晚晚些时候我会尝试解释(如果其他人没有在我之前解释)。这是一个问题(它永远不会终止)“但问题不是OP报告的问题。而且,问题显然是关于ANTLR和Python,而不是C++和Axe。”Bart Kiers:这太粗鲁了。我把问题的两个识别和解决问题的更好方法结合在一起。对不起,我不是故意粗鲁的(我们也必须有不同的定义“粗鲁”,BTW)。.但你错了:OP指出的问题(a不匹配的TokenException
)不是因为身体规则永远不会终止。正如我已经提到的:OP清楚地询问了Python和ANTLR,而不是关于C++和AXE。如果OP遇到了问题,因为身体规则永远不会终止,那么某种溢出异常就会被抛出,而不是<代码> MistMatChuttoKutExp< <代码>。就像我说的:事实。body
匹配零个或多个空字符串确实是一个问题,但不是O
-
+
5
*
+
1
2
4
3