我在这里为ANTLR提供了一个非常基本的数学表达式语法,感兴趣的是在括号之间处理隐含的*
运算符,例如: (2-3)(4+5)(6*7)
实际应该是(2-3)*(4+5)*(6*7)
。
鉴于输入(2-3)(4+5)(6*7)
我正在尝试在解析时将缺少的*
运算符添加到AST树中,在下面的语法中我认为我已经设法实现了这一点,但我想知道如果这是正确的,最优雅的方式?
grammar G;
options {
language = Java;
output=AST;
ASTLabelType=CommonTree;
}
tokens {
ADD = '+' ;
SUB = '-' ;
MUL = '*' ;
DIV = '/' ;
OPARN = '(' ;
CPARN = ')' ;
}
start
: expression EOF!
;
expression
: mult (( ADD^ | SUB^ ) mult)*
;
mult
: atom (( MUL^ | DIV^) atom)*
;
atom
: INTEGER
| (
OPARN expression CPARN -> expression
)
(
OPARN expression CPARN -> ^(MUL expression)+
)*
;
INTEGER : ('0'..'9')+ ;
WS : (' ' | '\t' | '\n' | '\r' | '\f')+ {$channel = HIDDEN;};
这个语法似乎在ANTLRworks中输出正确的AST树:
我只是刚刚开始掌握解析和ANTLR,没有太多经验所以反馈真的很感激!
提前致谢!卡尔
答案 0 :(得分:3)
首先,鉴于你以前从未使用过ANTLR,你做得很好。
您可以省略language=Java
和ASTLabelType=CommonTree
,这是默认值。所以你可以这样做:
options {
output=AST;
}
此外,您不必单独为每个运算符指定根节点。所以你不必这样做:
(ADD^ | SUB^)
但以下内容:
(ADD | SUB)^
就足够了。只有两个运算符,没有太大区别,但在实现关系运算符(>=
,<=
,>
和<
)时,后者更容易一些。
现在,对你来说AST:你可能想要创建一个二叉树:这样,所有内部节点都是运算符,而叶子将是操作数,这使得对表达式的实际评估更加容易。要获取二叉树,您必须稍微更改atom
规则:
atom
: INTEGER
| (
OPARN expression CPARN -> expression
)
(
OPARN e=expression CPARN -> ^(MUL $atom $e)
)*
;
在输入"(2-3)(4+5)(6*7)"
:
(由graphviz-dev.appspot.com生成的图片)
使用以下测试类生成DOT文件:
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
public class Main {
public static void main(String[] args) throws Exception {
GLexer lexer = new GLexer(new ANTLRStringStream("(2-3)(4+5)(6*7)"));
GParser parser = new GParser(new CommonTokenStream(lexer));
CommonTree tree = (CommonTree)parser.start().getTree();
DOTTreeGenerator gen = new DOTTreeGenerator();
StringTemplate st = gen.toDOT(tree);
System.out.println(st);
}
}