英文:
ANTLR to get symbolicNames when walking the parser tree
问题
我正在按照https://blog.gopheracademy.com/advent-2017/parsing-with-antlr4-and-go/的指导进行操作,并且我正在查看https://github.com/bramp/goadvent-antlr/blob/master/example2.go,但是它没有输出。现在,我想使用EnterEveryRule
来输出遇到的每个符号及其符号名称。我该如何做到这一点?
也就是说,如何在任何特定阶段访问symbolicNames
切片,以了解我正在处理哪个符号名称。
英文:
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.
答案1
得分: 1
我对Go并不是很精通,但是这个例子包含了以下几行代码:
// 最后解析表达式(通过遍历树)
antlr.ParseTreeWalkerDefault.Walk(&calcListener{}, p.Start())
这有点误导人。这个语句中的p.Start()
实际上是进行解析的(调用p.Start()
应该会返回一个ANTLR解析树)。在这一点上,你已经完成了解析。
antlr.ParseTreeWalkerDefault.Walk()
是用来遍历解析树并在传递给它的listener
上调用方法的。你可能想将它存储在一个临时变量中,然后将其传递给遍历器(可以在调试器中检查它,或者它应该有一个类似toStringTree(...)
的函数,可以给你一个解析树的字符串表示)。
看起来calcListener
只是一个对parser.BaseCalcListener
的引用。ANTLR生成的Base*Listener
是“空实现”监听器,它只提供了所有监听器需要实现的方法的空实现。
你需要对calcListener
做一些处理,以“覆盖”EnterEveryRule
函数,并对传递给它的*Context
对象进行一些操作。
英文:
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*Listener
s 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.
答案2
得分: 1
我正在为**@kaby76**回答,他引导我到了https://play.golang.org/p/R8Sik7sdZaz,所以我能够继续前进到https://play.golang.org/p/uZqfUhHE0mt。
以下是完整的代码:
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() {
// 设置输入
is := antlr.NewInputStream("1 + 2 * 3")
// 创建词法分析器
lexer := parser.NewCalcLexer(is)
stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)
// 创建语法分析器
p := parser.NewCalcParser(stream)
// 最后解析表达式(通过遍历树)
listener := calcListener{}
listener.parser = p
antlr.ParseTreeWalkerDefault.Walk(&listener, p.Start())
}
执行结果:
NUMBER 1
NUMBER 2
NUMBER 3
MUL 2*3
ADD 1+2*3
英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论