10
votes

I'm currently trying to develope a JavaScript Compiler with the help of an Antlr4 Visitor. I've got this already implemented with Java but cannot figure out how to do this in JavaScript. Probably somebody can answer me a few questions?

1: In Java there is a Visitor.visit function. If im right this isn't possibile with Javascript. Is there a work around for this?

2: My Javascript Visitor got all the generated visiting functions but when I use console.log(ctx) the context is undefined. Any idea why?

Extract from the SimpleVisitor.js:

// Visit a parse tree produced by SimpleParser#parse.
SimpleVisitor.prototype.visitParse = function(ctx) {
        console.log(ctx);
};

Main js file:

var antlr4 = require('lib/antlr4/index');
var SimpleLexer = require('antlr4/SimpleLexer');
var SimpleParser = require('antlr4/SimpleParser');
var SimpleVisitor = require('antlr4/SimpleVisitor');    

var input = "double hallo = 1;";
var chars = new antlr4.InputStream(input);
var lexer = new SimpleLexer.SimpleLexer(chars);
var tokens = new antlr4.CommonTokenStream(lexer);
var parser = new SimpleParser.SimpleParser(tokens);
var visitor = new SimpleVisitor.SimpleVisitor();
parser.buildParseTrees = true;
var tree = parser.parse();

visitor.visitParse();

This is probably enough to start with ...

Bruno

Edit:

Probably the context is undefined because I call the function without arguments but where do I get the "starting"-context?

Edit2:

So I think I get the idea how this should work out. One Question remaining how do I determine which rule to call next inside each visitor function?

1
No idea, but maybe you could get an answer on the antlr-discussion google group. Don't forget to add your grammar file and some visitor code you've developed.erosb
You are right, in Java it uses method overloading. Since it is not possible in javascript, it generates visitXXX where XXX is the rule name. You still have a function for every rule, it's the name which distinguishes them, not their parameter type. By the way, you could show some code as well.Katona
Found the solution if somebody is interested he can write me a messageBruno
Post the solution as an answer!thur
Can you please post your solution on how to invoke the visitor function on its children as an answer?ironchefpython

1 Answers

13
votes

The basic idea behind the visitor is that you have to handle all the logic by yourself. To do this I generated the visitor using antlr. My own visitor overrides all functions that I need to implement my logic.

  1. create lexer, tokens, ...

    var antlr4 = require('antlr4/index');
    var SimpleJavaLexer = require('generated/GrammarLexer');
    var SimpleJavaParser = require('generated/GrammarParser');
    var SimpleJavaVisitor = require('generated/GrammarVisitor');
    var Visitor = require('./Visitor');
    
    var input = "TestInput";
    var chars = new antlr4.InputStream(input);
    var lexer = new GrammarLexer.GrammarLexer(chars);
    var tokens = new antlr4.CommonTokenStream(lexer);
    var parser = new GrammarParser.GrammarParser(tokens);
    var visitor = new Visitor.Visitor();
    parser.buildParseTrees = true;
    var tree = parser.parse();
    
  2. and call your entry function

    visitor.visitTest(tree);
    
  3. inside your new visitor you need to implement your new logic to determine which function to call next (the right context as argument is important)

    var GrammarVisitor =     require('generated/GrammarVisitor').GrammarVisitor;
    
    function Visitor () {
      SimpleJavaVisitor.call(this);
      return this;
    };
    
    Visitor.prototype = Object.create(GrammarVisitor.prototype);
    Visitor.prototype.constructor = Visitor;
    Visitor.prototype.visitTest = function(ctx) {
        // implement logic to determine which function to visit
        // then call next function and with the right context
        this.visitBlock(ctx.block());
    };
    

I hope you can understand my basic idea. If anybody got any questions just comment.