ANTLR解析MismatchedTokenException

时间:2011-06-15 15:04:12

标签: python antlr parser-generator antlrworks

我正在尝试为我正在编写的更简单的语言编写一个简单的解析器。它由后缀表达式组成。截至目前,我遇到了解析器的问题。当我在输入2 2 * test >>上运行它时,我得到一个MismatchedTokenException。

另外,我将如何实现递归后缀解析器?

这是我的代码:

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;}
    ;

2 个答案:

答案 0 :(得分:4)

有些事情是不正确的:

1

您已将WS令牌放在HIDDEN频道上,这使得它们无法用于解析器规则。因此,WS规则中的所有body令牌都不正确。

2

_(您的最新编辑删除了左递归问题,但我仍然会指出它抱歉,您的 other question 左侧递归规则(expr),所以我将这里留下这些信息)_

ANTLR是一个LL parser - 生成器,因此您无法创建左递归语法。以下是递归的:

expr
  :  term term operator
  ;

term
  :  INT
  |  ID
  |  expr
  ;

因为term规则中的第一个expr可能与expr规则本身匹配。与任何LL解析器一样,ANTLR生成的解析器无法处理左递归。

3

如果您解决了WS问题,您的body规则将产生以下错误消息:

(1/7) Decision can match input such as "INT" using multiple alternatives

这意味着解析器无法“看到”INT令牌所属的规则。这是因为您的所有body替代品都可以重复零次或多次,exprnested也会重复。所有这些都可以匹配INT,这是ANTLR所抱怨的。如果您删除*,请执行以下操作:

body
    :   nested
    |   var
    |   get
    ;

// ...

expr
    :   term (term operator)
    ;

nested
    :   expr (expr operator)
    ;

错误会消失(尽管这仍然不会导致您的输入被正确解析!)。

我意识到这可能仍然含糊不清,但解释(或理解你是否对这一切都不熟悉)并非易事。

4

要正确考虑expr内的递归expr,您需要保持清除左递归,正如我在#2 中所解释的那样。你可以这样做:

expr
  :  term (expr operator | term operator)*
  ;

仍然含糊不清,但是在使用LL语法描述后缀表达式的情况下,这是不可避免的AFAIK。要解决此问题,您可以在语法的options { ... }部分内启用全局回溯:

options {
  language=Python;
  output=AST;
  backtrack=true;
}

演示

如何解析递归表达式的小演示可能如下所示:

grammar star;

options {
  language=Python;
  output=AST;
  backtrack=true;
}

parse
  :  expr EOF -> expr
  ;

expr
  :  (term -> term) ( expr2 operator -> ^(operator $expr expr2) 
                    | term operator  -> ^(operator term term)
                    )*
  ;

expr2 
  :  expr
  ;

term
  :  INT
  |  ID
  ;

operator 
  :  ('*' | '+' | '/' | '%' | '-')
  ;

ID
  :  ('a'..'z' | 'A'..'Z') ('a..z' | '0'..'9' | 'A'..'Z')*
  ;

INT
  :  '0'..'9'+
  ;

WS
  :  (' ' | '\n' | '\t' | '\r') {$channel=HIDDEN;}
  ;

测试脚本:

#!/usr/bin/env python
import antlr3
from antlr3 import *
from antlr3.tree import *
from starLexer import *
from starParser import *

def print_level_order(tree, indent):
  print '{0}{1}'.format('   '*indent, tree.text)
  for child in tree.getChildren():
    print_level_order(child, indent+1)

input = "5 1 2 + 4 * + 3 -"
char_stream = antlr3.ANTLRStringStream(input)
lexer = starLexer(char_stream)
tokens = antlr3.CommonTokenStream(lexer)
parser = starParser(tokens)
tree = parser.parse().tree 
print_level_order(tree, 0)

产生以下输出:

-
   +
      5
      *
         +
            1
            2
         4
   3

对应于以下AST:

enter image description here

答案 1 :(得分:-1)

问题是你的身体规则永远不会终止,因为它可以不匹配。我没有启动ANTLR,我真的不喜欢弄乱它,而是用C ++重写了你的语法(使用AX解析器生成器),添加了print语句来跟踪匹配并从解析{{1}获得了以下结果}}:

"2 2 * test >>"

如果您对调试此测试用例感兴趣,则AX语法如下所示,在打印时设置断点以逐步执行解析器:

parsed term: 2
parsed expr: 2
parsed nested: 2
parsed term: 2
parsed expr: 2
parsed nested: 2
parsed body: 2 2
parsed body:
parsed body: ... here goes your infinite loop