ANTLR and Groovy

Mixing ANTLR with Groovy can give you the best of both worlds.

Consider the following grammar snippet:

additiveExpression
    : multiplicativeExpression
    | additiveExpression ('+'|'-') additiveExpression;

Handling this within Java is quite tedious.  In this example we share a stack of type object across contexts.  The following code shows how we support addition and subtraction of numerical values as well as string concatenation.

public class TMIListenerImpl extends TMIBaseListener
{
  private List<TMINode>  stack = new ArrayList<TMINode>();
  private Map<String, Object>   = new HashMap<String, Object>();


  public TMIListenerImpl()
  {
  }

...

  public void exitAdditiveExpression(AdditiveExpressionContext ctx)
  {
    if (ctx.getChildCount() == 3)
    {
      Object obj2 = getValue(stack.remove(stack.size() - 1));
      Object obj1 = getValue(stack.remove(stack.size() - 1));
      Object result = null;
      String op = ctx.getChild(1).getText();

      if (op.equals("+"))
      {
        if (obj1.getClass() == Double.class)
        {
          if (obj2.getClass() == Double.class)
          {
            result = new Double((Double) obj1 + (Double) obj2);
          }
          else if (obj2.getClass() == Integer.class)
          {
            result = new Double((Double) obj1 + (Integer) obj2);
          }
        }
        else if (obj1.getClass() == Integer.class)
        {
          if (obj2.getClass() == Double.class)
          {
            result = new Double((Integer) obj1 + (Double) obj2);
          }
          else if (obj2.getClass() == Integer.class)
          {
            result = new Integer((Integer) obj1 + (Integer) obj2);
          }
        }

        if (result == null)
        {
          result = obj1.toString() + obj2.toString();
        }
      }
      else if (op.equals("-"))
      {
        if (obj1.getClass() == Double.class)
        {
          if (obj2.getClass() == Double.class)
          {
            result = new Double((Double) obj1 - (Double) obj2);
          }
          else if (obj2.getClass() == Integer.class)
          {
            result = new Double((Double) obj1 - (Integer) obj2);
          }
        }
        else if (obj1.getClass() == Integer.class)
        {
          if (obj2.getClass() == Double.class)
          {
            result = new Double((Integer) obj1 - (Double) obj2);
          }
          else if (obj2.getClass() == Integer.class)
          {
            result = new Integer((Integer) obj1 - (Integer) obj2);
          }
        }
      }

      if (result != null)
      {
        stack.add(result);
      }
    }
  }

That is repetitive and lots of busywork programming.

Now, let’s add a groovy nature to our eclipse project and replace the listener with a groovy listener:

class TMIGroovyListener extends TMIBaseListener
{
  def stack = []
  def sym   = [:]

  def TMIGroovyListener()
  {
  }
...
  public void exitAdditiveExpression(AdditiveExpressionContext ctx)
  {
    if (ctx.getChildCount() == 3)
    {
      Object obj2 = getValue(stack.pop());
      Object obj1 = getValue(stack.pop());
      String op = ctx.getChild(1).getText();

      if (op.equals("+"))
      {
        stack.add(obj1 + obj2)
      }
      else if (op.equals("-"))
      {
       stack.add(obj1 - obj2)
      }
    }
  }

We simply piggyback off of Groovy’s inherent object promotional model which greatly simplifies our code.  Additionally, all of the benefits of Groovy are also at our disposal.

Advertisements

About patmartin

I am a coder and Data Visualization/Machine Learning enthusiast.
This entry was posted in General and tagged , , . Bookmark the permalink.

2 Responses to ANTLR and Groovy

  1. Rüdiger says:

    Yes, Groovy saves you a lot of typing – I love it for this! But the ifs/elses in your code are still bothering. You could get rid of them with a hash table which maps the operation codes to the corresponding handlers (such a hash could even be defined on the fly). This way, the code would further gain in readability.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s