我有一种语言,基本上是将列映射到数组中的新结构.该语言旨在让产品经理定义映射,而无需了解大量编程细节.我相信这里有很多改进,但这就是我所拥有的.
这种语言主要起作用.我遇到的问题是条件语句.
我的解析器有以下规则:
conditionalexpr : IF^ LPAREN! (statement) RPAREN! THEN! LCURLY! statement RCURLY! (ELSE! LCURLY! statement RCURLY!)?;
这适用于生成有三个孩子的树.
我的问题是如果条件不允许,则避免评估语句.
天真地我做了:
conditionalexpr returns[Object o]: ^(IF a=statement b=statement (c=statement)?) { $o = (Boolean)$a.o ? $b.o : $c.o != null ? $c.o : ""; } ;
显然这不起作用.
我一直在玩语法谓词,但我不能让它们正常工作.
语句当前返回一个对象.主要是语言处理字符串,但我需要支持布尔值和数字(整数和小数).
如果我添加{$a.o}?=>之类的内容我在生成的代码中得到$a.
我查看了antlr-interest列表,但这个问题并没有得到很好的回答,很可能是因为它对他们来说似乎很明显.
我愿意发布完整的语法但是已经把它留下来保持这个简短.
解决方法
如果您不希望评估某些子树,则需要让树规则返回节点而不是实际值.您可以扩展CommonTree并提供自定义TreeAdaptor来帮助构建自己的节点,但就个人而言,我发现最简单的方法是创建自定义节点类(或类)并使用它们.一个演示澄清:
T.G
grammar T; options { output=AST; } tokens { ASSIGNMENT; } parse : statement+ EOF -> statement+ ; statement : ifStatement | assignment ; ifStatement : IF a=expression THEN b=expression (ELSE c=expression)? -> ^(IF $a $b $c?) ; assignment : ID '=' expression -> ^(ASSIGNMENT ID expression) ; expression : orExpression ; orExpression : andExpression (OR^ andExpression)* ; andExpression : equalityExpression (AND^ equalityExpression)* ; equalityExpression : relationalExpression (('==' | '!=')^ relationalExpression)* ; relationalExpression : atom (('<=' | '<' | '>=' | '>')^ atom)* ; atom : BOOLEAN | NUMBER | ID | '(' expression ')' -> expression ; IF : 'if'; THEN : 'then'; ELSE : 'else'; OR : 'or'; AND : 'and'; BOOLEAN : 'true' | 'false'; ID : ('a'..'z' | 'A'..'Z')+; NUMBER : '0'..'9'+ ('.' '0'..'9'+)?; SPACE : (' ' | '\t' | '\r' | '\n') {skip();};
Main.java
我创建了一个具有eval():Object方法的Node接口,还创建了一个实现Node的抽象类BinaryNode,并且总是有2个子节点.正如您在这些Java类之后的树语法中所看到的,所有规则现在都返回一个Node.
import org.antlr.runtime.*; import org.antlr.runtime.tree.*; public class Main { public static void main(String[] args) throws Exception { String source = "a = 3 b = 4 if b > a then b==b else c==c"; TLexer lexer = new TLexer(new ANTLRStringStream(source)); TParser parser = new TParser(new CommonTokenStream(lexer)); TWalker walker = new TWalker(new CommonTreeNodeStream(parser.parse().getTree())); Node root = walker.walk(); System.out.println(root.eval()); } } interface Node { Object eval(); } abstract class BinaryNode implements Node { protected Node left; protected Node right; public BinaryNode(Node l,Node r) { left = l; right = r; } } class AtomNode implements Node { private Object value; public AtomNode(Object v) { value = v; } @Override public Object eval() { return value; } } class OrNode extends BinaryNode { public OrNode(Node left,Node right) { super(left,right); } @Override public Object eval() { return (Boolean)super.left.eval() || (Boolean)super.right.eval(); } } class AndNode extends BinaryNode { public AndNode(Node left,right); } @Override public Object eval() { return (Boolean)super.left.eval() && (Boolean)super.right.eval(); } } class LTNode extends BinaryNode { public LTNode(Node left,right); } @Override public Object eval() { return (Double)super.left.eval() < (Double)super.right.eval(); } } class LTEqNode extends BinaryNode { public LTEqNode(Node left,right); } @Override public Object eval() { return (Double)super.left.eval() <= (Double)super.right.eval(); } } class GTNode extends BinaryNode { public GTNode(Node left,right); } @Override public Object eval() { return (Double)super.left.eval() > (Double)super.right.eval(); } } class GTEqNode extends BinaryNode { public GTEqNode(Node left,right); } @Override public Object eval() { return (Double)super.left.eval() >= (Double)super.right.eval(); } } class EqNode extends BinaryNode { public EqNode(Node left,right); } @Override public Object eval() { return super.left.eval().equals(super.right.eval()); } } class NEqNode extends BinaryNode { public NEqNode(Node left,right); } @Override public Object eval() { return !super.left.eval().equals(super.right.eval()); } } class VarNode implements Node { private java.util.Map<String,Object> memory; private String var; VarNode(java.util.Map<String,Object> m,String v) { memory = m; var = v; } @Override public Object eval() { Object value = memory.get(var); if(value == null) { throw new RuntimeException("Unknown variable: " + var); } return value; } } class IfNode implements Node { private Node test; private Node ifTrue; private Node ifFalse; public IfNode(Node a,Node b,Node c) { test = a; ifTrue = b; ifFalse = c; } @Override public Object eval() { return (Boolean)test.eval() ? ifTrue.eval() : ifFalse.eval(); } }
TWalker.g
tree grammar TWalker; options { tokenVocab=T; ASTLabelType=CommonTree; } @members { private java.util.Map<String,Object> memory = new java.util.HashMap<String,Object>(); } walk returns [Node n] : (statement {$n = $statement.n;})+ ; statement returns [Node n] : ifStatement {$n = $ifStatement.n;} | assignment {$n = null;} ; assignment : ^(ASSIGNMENT ID expression) {memory.put($ID.text,$expression.n.eval());} ; ifStatement returns [Node n] : ^(IF a=expression b=expression c=expression?) {$n = new IfNode($a.n,$b.n,$c.n);} ; expression returns [Node n] : ^(OR a=expression b=expression) {$n = new OrNode($a.n,$b.n);} | ^(AND a=expression b=expression) {$n = new AndNode($a.n,$b.n);} | ^('==' a=expression b=expression) {$n = new EqNode($a.n,$b.n);} | ^('!=' a=expression b=expression) {$n = new NEqNode($a.n,$b.n);} | ^('<=' a=expression b=expression) {$n = new LTEqNode($a.n,$b.n);} | ^('<' a=expression b=expression) {$n = new LTNode($a.n,$b.n);} | ^('>=' a=expression b=expression) {$n = new GTEqNode($a.n,$b.n);} | ^('>' a=expression b=expression) {$n = new GTNode($a.n,$b.n);} | BOOLEAN {$n = new AtomNode(Boolean.valueOf($BOOLEAN.text));} | NUMBER {$n = new AtomNode(Double.valueOf($NUMBER.text));} | ID {$n = new VarNode(memory,$ID.text);} ;
如果您现在运行主类,并评估:
a = 3 b = 4 if b > a then b==b else c==c
正在打印到控制台:
bart@hades:~/Programming/ANTLR/Demos/T$java -cp antlr-3.3.jar org.antlr.Tool T.g bart@hades:~/Programming/ANTLR/Demos/T$java -cp antlr-3.3.jar org.antlr.Tool TWalker.g bart@hades:~/Programming/ANTLR/Demos/T$javac -cp antlr-3.3.jar *.java bart@hades:~/Programming/ANTLR/Demos/T$java -cp .:antlr-3.3.jar Main true
但是,如果你检查b< a,导致执行else,你会看到以下内容:
Exception in thread "main" java.lang.RuntimeException: Unknown variable: c at VarNode.eval(Main.java:140) at EqNode.eval(Main.java:112) at IfNode.eval(Main.java:160) at Main.main(Main.java:11)
有关更复杂的语言结构(范围,函数等)的实现,请参阅my blog.
祝好运!