Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Visitor or Listener with ANTLR4 when returning objects of different types

Tags:

java

antlr

antlr4

I translate one language into another with ANTLR4. For example when I read numerical literals I can return an Integer or Double.

@Override
public Integer visitIntegerValue(Parser.IntegerValueContext ctx) {
    return Integer.valueOf(ctx.getText());
}

@Override
public Double visitDoubleValue(Parser.DoubleValueContext ctx) {
    return Double.valueOf(ctx.getText());
}

Ultimately if you extend this approach further and introduce other constructs like strings and conditions, the only reasonable type for the visitor is class Visitor extends BaseVisitor<Object>, but it leads to a code heavily spiced with instanceof. For example

@Override
public CollectionQuery visitCondition(Parser.ConditionContext ctx) {
    Property property = (Property) visit(ctx.property());
    String operator = (String) visit(ctx.operator());
    Object value = visit(ctx.amount());
    Object condition;
    if (value instanceof String && operator.equals("$regex")) {
        condition = Pattern.compile((String) value, Pattern.CASE_INSENSITIVE);
    }
    ...
}

While I don't mind this kind of 'dynamism', I would like to know if this is a maintainable way to proceed or are there other techniques that I should use instead, like creating proper hierarchy of target language constructs.

like image 743
vasily Avatar asked Apr 13 '15 07:04

vasily


2 Answers

One suggestion is to have a visitor per return type:

public class IntegerVisitor extends BaseListener<Integer> {
  @Override
  public Integer visitIntegerValue(Parser.IntegerValueContext ctx) {
    return Integer.valueOf(ctx.getText());
  }
}

public class DoubleVisitor extends BaseListener<Double> {
  @Override
  public Double visitDoubleValue(Parser.DoubleValueContext ctx) {
    return Integer.valueOf(ctx.getText());
  }
}

This makes more sense when you're visiting vastly different things (for example if you were parsing using a java grammar you might have a MethodVisitor and a ClassVisitor etc. See an example here: See an example here

like image 170
Matthew Avatar answered Oct 26 '22 15:10

Matthew


To get an impression how a custom post-processing could look like.

some ANTLR code

topMostRule : childRule+ EOL;
childRule : variantOne | variantTwo;
variantOne : 'A';
variantTwo : '1';
...

Pseudo code for a custom postprocessing (more C# like than Java / not the real method names ANTLR uses):

public class MyCustomPostprocessor
{
    private IntermediateResults lookupTable; // use private fields for lookup tables etc.

    public ResultType process(Parser.TopMostRuleContext ctx)
    {
        // inspect the children
        var children = new List<object>();
        foreach (var rule in ctx.ChildRules)
        {
            switch (rule.Type)
            {
            case typeof (Parser.ChildRuleContext):
                var result = process(rule);
                children.Add(result);
            else
                throw new NotImplementedException("Don't know what to do with " + rule.Type.ToString());
            }

            // use the information gathered so far to form the result
            return new ResultType (children);
        }
    }


    public object process (Parser.ChildRuleContext)
    {
        foreach (var rule in ctx.ChildRules)
        {
            switch (rule.Type)
            {
            case typeof (Parser.VariantOneContext):
                var result = process(rule);
                return result;
            case typeof (Parser.VariantTwoContext):
                var result = process(rule);
                return result;
            else
                throw new NotImplementedException("Don't know what to do with " + rule.Type.ToString());
            }

        }
    }

    public string process (Parser.VariantOneContext ctx)
    {
        return ctx.GetText();
    }

    public int process (Parser.VariantTwoContext ctx)
    {
        return Int.Parse(ctx.GetText());
    }


}
like image 35
Onur Avatar answered Oct 26 '22 15:10

Onur