开发者

Working with expression ASTs

开发者 https://www.devze.com 2022-12-26 06:56 出处:网络
Is there any best practice when working with ASTs? I have a parsed expression AST. Cons开发者_Python百科tantExpression, BinaryExpression etc.

Is there any best practice when working with ASTs? I have a parsed expression AST. Cons开发者_Python百科tantExpression, BinaryExpression etc. I want to populate a GUI-dialog with information from the AST, and it's here where I get kinda confused because my code gets pretty messy.

Example:

expression = "Var1 > 10 AND Var2 < 20"

I want to populate two textboxes with value 10 resp. 20 from the AST. What I'm doing now is a recursive method that checks for correct child expression-types (with .Net Is-operator) and acts accordingly and the code is really "smelly" :)

Is there any design pattern, like Visitor or such, that makes this somewhat easier/more readable/maintainable ?


Best practices for working with ASTs are:

  • Get good parsers to help you build the ASTs from some kind of grammar description
  • Get a good library to help you walk the AST to collect/modify the AST

For serious work with ASTs, this is best done by using a package designed to generate and manipulate ASTs. Often such packages include a lot of additional support, such as pattern matching and/or AST rewriting using source-to-source transformations.

Here are several:

  • ANTLR
  • DMS Software Reengineering Toolkit (my product)
  • TXL

This example shows how to build and manipulate ASTs using only BNF, patterns, and source-to-source transformations.


Most compilers solve this problem by using either

  • Method overriding
  • Visitor

Here are is how you'd go about collecting all constant value (literals) that appears in your expression into a List of integers. Calling code can then populate textboxes with values from this list.

Method overriding

The top-most AST class defines an abstract method which is overridden at subclasses.

class AstNode {
  .. // Some stuff
  public abstract void collectValues(List<Integer> ints);
}

class ConstantExpression : AstNode {
  private int value;
  .. // Some stuff
  public override void collectValues(List<Integer> ints) { ints.Add(value); }
}

 class BinaryExpression : AstNode {
   private AstNode left;
   private AstNode right;
   .. // Some stuff
   public override void collectValues(List<Integer> ints) { 
      left.collectValues(ints); 
      right.collectValues(ints); 
   }
}

class Identifier : AstNode {
  .. // Some stuff
  public override void collectValues(List<Integer> ints) { 
     // do nothing!
  }
}

Visitor

Same program but written using Visitors.

class Visitor {
   public abstract void visit(ConstantExpression e);
   public abstract void visit(BinaryExpression e);
   public abstract void visit(Identifier e);
}

class AstNode {
  .. // Some stuff
  public abstract void accept(Visitor v);
}

class ConstantExpression : AstNode {
  public int value;
  .. // Some stuff
  public override void accept(Visitor v) { v.visit(this); }
}

 class BinaryExpression : AstNode {
   private AstNode left;
   private AstNode right;
   .. // Some stuff
  public override void accept(Visitor v) { 
     left.accept(v); 
     right.accept(v); 
     v.visit(this); 
  }
}

class Identifier : AstNode {
  .. // Some stuff
  public override void accept(Visitor v) { v.visit(this); }
}


class ValueCollector : Visitor {
  public List<Integer> ints = ...;

   public void visit(ConstantExpression e) { ints.Add(e.value); }
   public void visit(BinaryExpression e) { }
   public void visit(Identifier e) { }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消