java – if then else条件评估

我有一种语言,基本上是将列映射到数组中的新结构.该语言旨在让产品经理定义映射,而无需了解大量编程细节.我相信这里有很多改进,但这就是我所拥有的.

这种语言主要起作用.我遇到的问题是条件语句.

我的解析器有以下规则:

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.

祝好运!

相关文章

最近看了一下学习资料,感觉进制转换其实还是挺有意思的,尤...
/*HashSet 基本操作 * --set:元素是无序的,存入和取出顺序不...
/*list 基本操作 * * List a=new List(); * 增 * a.add(inde...
/* * 内部类 * */ 1 class OutClass{ 2 //定义外部类的成员变...
集合的操作Iterator、Collection、Set和HashSet关系Iterator...
接口中常量的修饰关键字:public,static,final(常量)函数...