我正在尝试为我正在编写的更简单的语言编写一个简单的解析器。它由后缀表达式组成。截至目前,我遇到了解析器的问题。当我在输入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;}
;
答案 0 :(得分:4)
有些事情是不正确的:
您已将WS
令牌放在HIDDEN
频道上,这使得它们无法用于解析器规则。因此,WS
规则中的所有body
令牌都不正确。
_(您的最新编辑删除了左递归问题,但我仍然会指出它抱歉,您的 other question 左侧递归规则(expr
),所以我将这里留下这些信息)_
ANTLR是一个LL parser - 生成器,因此您无法创建左递归语法。以下是递归的:
expr
: term term operator
;
term
: INT
| ID
| expr
;
因为term
规则中的第一个expr
可能与expr
规则本身匹配。与任何LL解析器一样,ANTLR生成的解析器无法处理左递归。
如果您解决了WS
问题,您的body
规则将产生以下错误消息:
(1/7) Decision can match input such as "INT" using multiple alternatives
这意味着解析器无法“看到”INT
令牌所属的规则。这是因为您的所有body
替代品都可以重复零次或多次,expr
和nested
也会重复。所有这些都可以匹配INT
,这是ANTLR所抱怨的。如果您删除*
,请执行以下操作:
body
: nested
| var
| get
;
// ...
expr
: term (term operator)
;
nested
: expr (expr operator)
;
错误会消失(尽管这仍然不会导致您的输入被正确解析!)。
我意识到这可能仍然含糊不清,但解释(或理解你是否对这一切都不熟悉)并非易事。
要正确考虑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:
答案 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