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