कैसे एक antlr4 आगंतुक लिखने के लिए
मैं एक साधारण antlr4 व्याकरण के लिए एक आगंतुक लिखने की कोशिश कर रहा हूं - मैं पुस्तक से निम्नलिखित उदाहरण से आकर्षित कर रहा हूं:
* directory tour
* example: LabeledExpr.g4, EvalVisitor.java, Calc.java
जावा कोड के आधार पर, मैंने निम्नलिखित गो कोड लिखा है:
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 गलती मिली।
आपके संदर्भ के लिए, मैं मूल जावा कोड नीचे दिखा रहा हूं:
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 पर कुछ नकारात्मक टिप्पणियां कीं , और यह भी एंटीवायरल मुद्दों पर पोस्ट किया गया है। उस प्रश्न का एक उत्तर है जो अपूर्ण है और संकलन नहीं करता है। तो, क्या आगंतुक antlr4 के लक्ष्य में सभी काम करते हैं? और क्या इसके लिए एक नमूना कोड उपलब्ध है?
जवाब
मैंने थोड़ा सा Googled, और निम्नलिखित Go आगंतुक को एक साथ हैक किया:
फ़ाइल :/antlr4demo/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 JAR को डाउनलोड करें, पार्सर और विजिटर को जनरेट करें और उन्हें 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
यदि आप अब निम्नलिखित गो स्क्रिप्ट चलाते हैं:
फाइल: ./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]
ध्यान दें कि मैंने कभी भी गो में कुछ भी प्रोग्राम नहीं किया है: मुझे यकीन है कि कोड एक गड़बड़ है, लेकिन हे, "यह काम करता है"।