Go语言 如何写一个antlr4访问者

kadbb459  于 2023-09-28  发布在  Go
关注(0)|答案(2)|浏览(126)

我正在尝试为一个简单的antlr 4语法编写一个访问者-我正在改编书中的以下示例:

* directory tour
* example: LabeledExpr.g4, EvalVisitor.java, Calc.java

基于java代码,我写了下面的go代码:

package main
import (
    "os"
    "./parser"
    "github.com/antlr/antlr4/runtime/Go/antlr"
)

type evalVisitor struct {
    *parser.BaseLabeledExprVisitor
}

func (v *evalVisitor) VisitAddSub(c *parser.AddSubContext) int {
    left := v.Visit(c.Expr(0))
    right := v.Visit(c.Expr(1))
    if(c.GetOp().GetTokenType() == parser.LabeledExprParserADD) {
        return left + right //error: invalid operation: left + right (operator + not defined on interface)
    } else {
        return  left - right
    }
}

func main() {
    input, _ := antlr.NewFileStream(os.Args[1])
    lexer := parser.NewLabeledExprLexer(input)
    stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)
    p := parser.NewLabeledExprParser(stream)
    tree := p.Prog()
    var visitor evalVisitor
    visitor.Visit(tree)
}

我在上面显示了一个访问者,其他访问者也会写类似的内容。我得到了一些编译错误,如上面的评论所示。如何修复此错误?
在访问者的顶层调用中似乎也有一个错误,因为当我注解掉“左+右”行时,我得到了一个SIGSEGV错误。
下面是原始的java代码,供大家参考:

public Integer visitAddSub(LabeledExprParser.AddSubContext ctx) {
    int left = visit(ctx.expr(0));  // get value of left subexpression
    int right = visit(ctx.expr(1)); // get value of right subexpression
    if ( ctx.op.getType() == LabeledExprParser.ADD ) return left + right;
    return left - right; // must be SUB
}

另外,语法是这样的:

grammar LabeledExpr;
prog:   stat+ ;

stat:   expr NEWLINE                # printExpr
    |   ID '=' expr NEWLINE         # assign
    |   NEWLINE                     # blank
    ;

expr:   expr op=('*'|'/') expr      # MulDiv
    |   expr op=('+'|'-') expr      # AddSub
    |   INT                         # int
    |   ID                          # id
    |   '(' expr ')'                # parens
    ;

MUL :   '*' ; // assigns token name to '*' used above in grammar
DIV :   '/' ;
ADD :   '+' ;
SUB :   '-' ;
ID  :   [a-zA-Z]+ ;      // match identifiers
INT :   [0-9]+ ;         // match integers
NEWLINE:'\r'? '\n' ;     // return newlines to parser (is end-statement signal)
WS  :   [ \t]+ -> skip ; // toss out whitespace

注意:我到处寻找一个示例访问者代码,但我在54992660上遇到了一些负面评论,这也是在antlr问题上发布的。这个问题有一个不完整的答案,不能编译。那么,访问者在antlr 4的Go目标中工作吗?是否有一个示例代码可供使用?

5rgfhyps

5rgfhyps1#

我在谷歌上搜索了一下,并一起破解了以下Go访问者:

文件:./antlr 4demo/eval_visitor.go

package antlr4demo

import (
    "strconv"

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

type EvalVisitor struct {
    BaseExpressionVisitor
    Results map[int]float64
}

func (v *EvalVisitor) Visit(tree antlr.ParseTree) float64 {
    switch val := tree.(type) {
    case *ParseContext:
        return v.VisitParse(val)
    case *MultDivExprContext:
        return v.VisitMultDivExpr(val)
    case *NumberExprContext:
        return v.VisitNumberExpr(val)
    case *PlusSubExprContext:
        return v.VisitPlusSubExpr(val)
    case *NestedExprContext:
        return v.VisitNestedExpr(val)
    case *UnaryExprContext:
        return v.VisitUnaryExpr(val)
    default:
        panic("Unknown context")
    }
}

func (v *EvalVisitor) VisitParse(ctx *ParseContext) float64 {
    for index, expr := range ctx.expr_list {
        v.Results[index] = v.Visit(expr)
    }
    return v.Results[len(v.Results)-1]
}

func (v *EvalVisitor) VisitMultDivExpr(ctx *MultDivExprContext) float64 {
    lhs := v.Visit(ctx.lhs)
    rhs := v.Visit(ctx.rhs)

    if ctx.op.GetTokenType() == ExpressionLexerMULT {
        return lhs * rhs
    } else {
        return lhs / rhs
    }
}

func (v *EvalVisitor) VisitPlusSubExpr(ctx *PlusSubExprContext) float64 {
    lhs := v.Visit(ctx.lhs)
    rhs := v.Visit(ctx.rhs)

    if ctx.op.GetTokenType() == ExpressionLexerPLUS {
        return lhs + rhs
    } else {
        return lhs - rhs
    }
}

func (v *EvalVisitor) VisitNumberExpr(ctx *NumberExprContext) float64 {
    val, _ := strconv.ParseFloat(ctx.NUMBER().GetText(), 10)
    return val
}

func (v *EvalVisitor) VisitNestedExpr(ctx *NestedExprContext) float64 {
    return v.Visit(ctx.Expr())
}

func (v *EvalVisitor) VisitUnaryExpr(ctx *UnaryExprContext) float64 {
    return -v.Visit(ctx.Expr())
}

文件:./Expression.g4

grammar Expression;

parse
 : expr_list+=expr+ EOF
 ;

expr
 : '(' expr ')'                        #NestedExpr
 | SUB expr                            #UnaryExpr
 | lhs=expr op=( MULT | DIV ) rhs=expr #MultDivExpr
 | lhs=expr op=( PLUS | SUB ) rhs=expr #PlusSubExpr
 | NUMBER                              #NumberExpr
 ;

MULT : '*';
DIV  : '/';
PLUS : '+';
SUB  : '-';

NUMBER
 : ( D* '.' )? D+
 ;

SPACES
 : [ \t\r\n] -> skip
 ;

fragment D : [0-9];

首先下载ANTLR 4.9编译器,生成解析器和访问者Go文件,并将它们移动到antlr4demo文件夹:

wget https://www.antlr.org/download/antlr-4.9-complete.jar
java -cp antlr-4.9-complete.jar org.antlr.v4.Tool -Dlanguage=Go -o antlr4demo -package antlr4demo -visitor -no-listener Expression.g4

如果你现在运行下面的Go脚本:

文件:./main.go

package main

import (
    "fmt"

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

func main() {
    expression := "1000 25/5 (1 + 2) * -3.14159265"
    input := antlr.NewInputStream(expression)
    lexer := antlr4demo.NewExpressionLexer(input)
    stream := antlr.NewCommonTokenStream(lexer, 0)
    parser := antlr4demo.NewExpressionParser(stream)
    parser.BuildParseTrees = true
    tree := parser.Parse()

    visitor := antlr4demo.EvalVisitor{
        Results: make(map[int]float64),
    }

    var result = visitor.Visit(tree)

    fmt.Println(expression, "=", result)
    fmt.Println("All results: ", visitor.Results)
}

你会看到输出:

$ go run main.go
1000 25/5 (1 + 2) * -3.14159265 = -9.424777950000001
All results:  map[0:1000 1:5 2:-9.424777950000001]

请注意,我从来没有在Go中编程过任何东西:我肯定代码是一团糟,但嘿,“它工作”。

wfveoks0

wfveoks02#

而不是

func (v *EvalVisitor) Visit(tree antlr.ParseTree) float64 {
    switch val := tree.(type) {
    case *ParseContext:
        return v.VisitParse(val)
    case *MultDivExprContext:
        return v.VisitMultDivExpr(val)
    case *NumberExprContext:
        return v.VisitNumberExpr(val)
    case *PlusSubExprContext:
        return v.VisitPlusSubExpr(val)
    case *NestedExprContext:
        return v.VisitNestedExpr(val)
    case *UnaryExprContext:
        return v.VisitUnaryExpr(val)
    default:
        panic("Unknown context")
    }
}

。你就写:

func (v *EvalVisitor) Visit(tree antlr.ParseTree) float64 {
    return tree.Accept(v)
}

相关问题