xpt
xpt

Reputation: 23032

ANTLR to get symbolicNames when walking the parser tree

I'm following https://blog.gopheracademy.com/advent-2017/parsing-with-antlr4-and-go/, and
I'm looking at https://github.com/bramp/goadvent-antlr/blob/master/example2.go, which has no output. Now,

I want to use the EnterEveryRule to output each symbol encountered, with their symbolicNames. How can I do that?

I.e., how to somehow access to the symbolicNames slice at any specific stage, to know which SymbolicName I'm dealing with.

Upvotes: 0

Views: 594

Answers (2)

xpt
xpt

Reputation: 23032

I'm answering it for @kaby76 actually, who had led me to https://play.golang.org/p/R8Sik7sdZaz, so that I am able to move on to https://play.golang.org/p/uZqfUhHE0mt

Here is the full code:

package main

import (
    "fmt"

    "github.com/antlr/antlr4/runtime/Go/antlr"

    "github.com/bramp/goadvent-antlr/parser"
)

type calcListener struct {
    *parser.BaseCalcListener
    parser *parser.CalcParser
}

// ExitEveryRule is called when any rule is exited.
func (l *calcListener) ExitEveryRule(ctx antlr.ParserRuleContext) {
    count := ctx.GetChildCount()
    // count == 1, NUMBER
    ch := ctx.GetChild(0)
    if count == 3 {
        // operation
        ch = ctx.GetChild(1)
    }
    q := ch.(antlr.Tree)
    t, ok := q.(antlr.TerminalNode)
    if ok {
        s := t.GetSymbol()
        x := s.GetTokenType()
        y := l.parser.GetSymbolicNames()
        fmt.Println(y[x], ctx.GetText())
    }
}

func main() {
    // Setup the input
    is := antlr.NewInputStream("1 + 2 * 3")

    // Create the Lexer
    lexer := parser.NewCalcLexer(is)
    stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)

    // Create the Parser
    p := parser.NewCalcParser(stream)

    // Finally parse the expression (by walking the tree)
    listener := calcListener{}
    listener.parser = p
    antlr.ParseTreeWalkerDefault.Walk(&listener, p.Start())
}

Execution result:

NUMBER 1
NUMBER 2
NUMBER 3
MUL 2*3
ADD 1+2*3

Upvotes: 1

Mike Cargal
Mike Cargal

Reputation: 6785

I'm certainly no expert with Go, but that example contains the following lines:

    // Finally parse the expression (by walking the tree)
    antlr.ParseTreeWalkerDefault.Walk(&calcListener{}, p.Start())

This is a bit misleading. The p.Start() part of that statement actually does the parsing (calling p.Start() should return an ANTLR parse tree. At that point, you've done the parsing.

antlr.ParseTreeWalkerDefault.Walk() is how you walk a parse tree invoking methods on the listener that is passed in along with the parse Tree you got from the p.start() call. You may want to store it in a temporary variable before passing it to the walker (maybe inspect it in a debugger to understand it, or, it should have something like a toStringTree(...) function that will give you a string representation of the parse tree.)

it appears that calcListener just has a reference to a parser.BaseCalcListener. The ANTLR-generated Base*Listeners are "do-nothing" listeners that just provide empty implementations of all the methods a listener needs to have implemented.

You'll need to do something with the calcListener to "override" the EnterEveryRule function, and do something with the *Context object passed to it.

Upvotes: 1

Related Questions