ANTLR4のgolangでvisitorパターンで実装するサンプルが無かったので試しに作ってみました。
以下、golangで実装する場合の備忘録
これに従ってantlr4をインストール
goのruntimeをインストール$ go get github.com/antlr/antlr4/runtime/Go/antlr
grammerファイルからパーサを生成(今回はformulaというpackage名で作ります)
$ antlr4 -Dlanguage=Go -visitor formula.g4
コマンドを実行するとこんな感じなファイルが生成される↓
formula.tokens
formulaLexer.interp
formula_lexer.go
formulaLexer.tokens
formula_listener.go
formula.g4
formula_base_listener.go
formula_parser.go
formula.interp
formula_base_visitor.go
formula_visitor.go
visitorを使うのでformula_base_visitor.goに定義されているBaseformulaVisitorを埋め込む形で構造体を作っていく。
// Code generated from formula.g4 by ANTLR 4.7.1. DO NOT EDIT.
package parser // formula
import "github.com/antlr/antlr4/runtime/Go/antlr"
type AstBuilder struct {
*BaseformulaVisitor
}
func (v *AstBuilder) VisitCompilationUnit(ctx *CompilationUnitContext) interface{} {
return ctx.Expression().Accept(v)
}
func (v *AstBuilder) VisitPrimaryExpression(ctx *PrimaryExpressionContext) interface{} {
return ctx.Primary().Accept(v)
}
func (v *AstBuilder) VisitBinaryExpression(ctx *BinaryExpressionContext) interface{} {
left := ctx.Expression(0).Accept(v)
right := ctx.Expression(1).Accept(v)
op := ctx.GetOp().GetText()
return &BinaryNode{
Left: left,
Right: right,
Op: op,
}
}
書き方は他のターゲットと同じくctxに対してルールのメソッドを呼び出してAcceptしていきます。配列の場合は引数にインデックスを入れるか、Allのprefixがついたメソッドを呼ぶと配列が返ってくるのでそれを使います。終端ノードはGetText()でトークンの文字列を取得できます。
あとは定義した構造体をこういう感じで使っていけばOK。
package main
import (
"os"
"github.com/tzmfreedom/go-salesforce-formula-parser"
)
func main() {
input, err := antlr.NewFileStream(os.Argv[1]) // ファイル名を指定する場合
// input := antlr.NewInputStream("1+2*3") // 文字列を指定する場合
lexer := NewformulaLexer(input)
stream := antlr.NewCommonTokenStream(lexer, 0)
p := NewformulaParser(stream)
p.AddErrorListener(antlr.NewDiagnosticErrorListener(true))
p.BuildParseTrees = true
tree := p.CompilationUnit() // ルートのルール名のメソッドを指定
tree.Accept(&AstBuilder{}) // 定義した構造体はここで使う
}