ANTLR Visitor Implementation For ArrayInitVisitorImpl

Tags: , , , ,



I am trying to build a visitor implementation that will convert a string array to unicode.

I am using the following grammar:

grammar ArrayInit;

init : '{' value (',' value)* '}' ;

value : init
      | INT
      ;

INT : [0-9]+ ;  
WS : [ trn]+ -> skip ;

I have gotten as far as this:

public class ArrayInitVisitorImpl extends ArrayInitBaseVisitor<String> {

    @Override
    public String visitInit(ArrayInitParser.InitContext ctx){
        return """;
    }

    @Override
    public String visitValue(ArrayInitParser.ValueContext ctx) {
        int value = Integer.parseInt(ctx.INT().getText());
        return String.format("\u%04x", value);
    }

}

and I’m not sure how to handle the nested visiting. Any assistance is appreciated.

Edit:

Thank to help from Bart, I was able to come up with a final solution for my use case.

public class Driver {

    public static void main(String[] args) {
        String stringArray = "{ 99, {1, 2, 3}, 3, 451 }";

        StringArrayToUnicodeConverter converter = new StringArrayToUnicodeConverter();
        String unicode = converter.convert(stringArray);

        System.out.println(unicode);
    }

}

public class StringArrayToUnicodeConverter {

    public String convert(String source) {
        CodePointCharStream input = CharStreams.fromString(source);
        return compile(input);
    }

    private String compile(CharStream source) {
        ArrayInitLexer lexer = new ArrayInitLexer(source);
        CommonTokenStream tokenStream = new CommonTokenStream(lexer);
        ArrayInitParser parser = new ArrayInitParser(tokenStream);
        ParseTree tree = parser.init();
        ArrayInitVisitorImpl visitor = new ArrayInitVisitorImpl();
        return visitor.visit(tree);
    }

}

public class ArrayInitVisitorImpl extends ArrayInitBaseVisitor<String> {

    @Override
    public String visitInit(ArrayInitParser.InitContext ctx){
        List<String> values = new ArrayList<>();
        for (ArrayInitParser.ValueContext value : ctx.value()) {
            values.add(this.visit(value));
        }
        return """ + String.join(",", values) + """;
    }

    @Override
    public String visitValue(ArrayInitParser.ValueContext ctx) {
        if(ctx.INT() != null){
            int value = Integer.parseInt(ctx.INT().getText());
            return String.format("\u%04x", value);
        }

        return this.visit(ctx.init());
    }

}

Answer

Something like this should do it:

public class Main {
    public static void main(String[] args) throws Exception {
        ArrayInitLexer lexer = new ArrayInitLexer(CharStreams.fromString("{1,2,{33,44,55}}"));
        ArrayInitParser parser = new ArrayInitParser(new CommonTokenStream(lexer));
        Object[] result = (Object[]) new ArrayInitVisitorImpl().visit(parser.init());
        System.out.println(Arrays.deepToString(result));
    }
}

class ArrayInitVisitorImpl extends ArrayInitBaseVisitor<Object> {

    @Override
    public Object visitInit(ArrayInitParser.InitContext ctx){
        List<Object> values = new ArrayList<>();
        for (ArrayInitParser.ValueContext value : ctx.value()) {
            values.add(this.visit(value));
        }
        return values.toArray();
    }

    @Override
    public Object visitValue(ArrayInitParser.ValueContext ctx) {
        if (ctx.INT() != null) {
            int value = Integer.parseInt(ctx.INT().getText());
            return String.format("\u%04x", value);
        }
        else {
            return this.visit(ctx.init());
        }
    }
}

which will print:

[u0001, u0002, [u0021, u002c, u0037]]


Source: stackoverflow