我在这里有一个非常基本的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,没有太多的经验,所以我很欣赏!
提前感谢!卡尔
发布于 2011-06-16 01:41:06
首先,考虑到您以前从未使用过ANTLR,您做得很好。
您可以省略默认值language=Java
和ASTLabelType=CommonTree
。所以你可以这样做:
options {
output=AST;
}
而且,您不必为每个运算符单独指定根节点。所以你不需要这样做:
(ADD^ | SUB^)
但以下内容:
(ADD | SUB)^
就足够了。只有两个运算符,没有太大区别,但在实现关系运算符(>=
、<=
、>
和<
)时,后者更容易一些。
现在,对于AST:您可能想要创建一棵二叉树:这样,所有内部节点都是运算符,而leafs将是操作数,这使得表达式的实际计算变得更容易。要获得二叉树,您必须稍微更改atom
规则:
atom
: INTEGER
| (
OPARN expression CPARN -> expression
)
(
OPARN e=expression CPARN -> ^(MUL $atom $e)
)*
;
在给定输入"(2-3)(4+5)(6*7)"
的情况下,它会生成以下AST
(图片出自:)
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);
}
}
https://stackoverflow.com/questions/6360621
复制相似问题