दिलचस्प पोस्ट
अद्वितीय फ़ील्ड जो Django में नल की अनुमति देते हैं JavaFX में स्वत: पूर्ण कॉम्बो बॉक्स एसक्यूएल – कोयला और ISNULL के बीच का अंतर? सी ++ और बूस्ट: एनकोड / डीकोड यूटीएफ -8 WAMP / XAMPP स्थानीयहोस्ट पर बहुत धीमा जवाब दे रहा है दो देशांतर / अक्षांश अंक के साथ दिशा (कंपास) प्राप्त करें सीएसएस के साथ वर्तमान पृष्ठ का लिंक रंग बदलें IPhone पर मेरे ऐप से आधिकारिक * सेटिंग * ऐप को कॉल करें कैसे ठीक करें "लिखने में असमर्थ '' यादृच्छिक राज्य '' openssl में एंड्रॉइड: बटन क्लिक किए जाने पर कैमरा स्विच करें वेब अनुप्रयोग समस्याएं (वेब। कॉन्फ़िगर त्रुटियां) HTTP 500.19 IIS7.5 और asp.NET v2 के साथ Mysql स्तंभों को कैसे पुनर्व्यवस्थित करें? सूची के अलावा अन्य प्रकार के लिए एक गुना क्या है? GitHub एक पृष्ठ को पुनः लोड किए बिना यूआरएल कैसे बदलता है? Angular2 में templateUrl को परिभाषित करने के लिए चर का उपयोग कैसे करें

ANTLR4 के साथ एएसटी कैसे बनाएं?

मैं इस बारे में बहुत कुछ खोज रहा हूं और मुझे कुछ भी उपयोगी नहीं मिल सका जो वास्तव में मुझे एएसटी बनाने में मदद करता है। मुझे पहले से ही पता है कि एएनटीएलआर 4 एएसटीएलआर 3 जैसी एएसटी का निर्माण नहीं करता है। हर कोई कहता है: "अरे, आगंतुकों का उपयोग करें!", लेकिन मुझे इस पर कोई उदाहरण या अधिक विस्तृत व्याख्या नहीं मिल पाई है …

मेरे पास एक व्याकरण सी होना चाहिए, लेकिन पुर्तगाली (पोर्तुगा प्रोग्रामिंग भाषा) में लिखे हर आज्ञा के साथ। मैं एएनटीएलआर 4 का इस्तेमाल करते हुए आसानी से पेर्स ट्री उत्पन्न कर सकता हूं। मेरा प्रश्न यह है कि अब एक एएसटी बनाने के लिए मुझे क्या करना है?

BTW, मैं जावा और IntelliJ का उपयोग कर रहा हूँ …

EDIT1: निकटतम मैं प्राप्त कर सकता था इस विषय के उत्तर का उपयोग कर रहा था: जावा स्रोत कोड से एएसटी बनाने और तरीकों, चर और टिप्पणियों को निकालने के लिए एन्टीएलआर 4 का इस्तेमाल करने का कोई आसान उदाहरण है? लेकिन यह केवल विज़िट किए गए विधियों का नाम प्रिंट करता है ..

चूंकि मुझे उम्मीद थी कि पहले प्रयास मेरे लिए काम नहीं कर रहा था, इसलिए मैंने ट्यूटोरियल को एएनटीएलआर 3 से इस्तेमाल करने की कोशिश की, लेकिन मुझे पता नहीं था कि एसटी के बजाय स्ट्रिंगटैमलेट का उपयोग कैसे करें …

द डेफिनेविटी एएनटीएलआर 4 रेफरेंस को पढ़ना मैं भी एएसटीएस से संबंधित कुछ भी नहीं मिल सका।

EDIT2: अब मेरे पास डीओटी फ़ाइल बनाने के लिए एक क्लास है, मुझे विज़िटर को ठीक से उपयोग करने के तरीके का पता लगाने की आवश्यकता है

Solutions Collecting From Web of "ANTLR4 के साथ एएसटी कैसे बनाएं?"

ठीक है, चलो एक सरल गणित उदाहरण का निर्माण करते हैं। एएसटी का निर्माण ऐसे कार्य के लिए पूरी तरह से अधिक है, लेकिन यह सिद्धांत को दिखाने का एक अच्छा तरीका है।

मैं इसे सी # में करूँगा लेकिन जावा संस्करण बहुत ही समान होगा।

व्याकरण

सबसे पहले, चलो एक बहुत ही बुनियादी गणित व्याकरण के साथ काम करने के लिए लिखते हैं:

grammar Math; compileUnit : expr EOF ; expr : '(' expr ')' # parensExpr | op=('+'|'-') expr # unaryExpr | left=expr op=('*'|'/') right=expr # infixExpr | left=expr op=('+'|'-') right=expr # infixExpr | func=ID '(' expr ')' # funcExpr | value=NUM # numberExpr ; OP_ADD: '+'; OP_SUB: '-'; OP_MUL: '*'; OP_DIV: '/'; NUM : [0-9]+ ('.' [0-9]+)? ([eE] [+-]? [0-9]+)?; ID : [a-zA-Z]+; WS : [ \t\r\n] -> channel(HIDDEN); 

सुंदर बुनियादी चीजें, हमारे पास एक एकल नियम है जो सब कुछ संभालता है (प्राथमिकता नियम आदि)।

एएसटी नोड्स

उसके बाद, हम कुछ एएसटी नोड्स को परिभाषित करते हैं जो हम प्रयोग करेंगे। ये पूरी तरह से कस्टम हैं और आप उन्हें जिस तरह से करना चाहते हैं, उसे परिभाषित कर सकते हैं।

यहां दिए गए नोड्स हैं जिनका उपयोग हम इस उदाहरण के लिए करेंगे:

 internal abstract class ExpressionNode { } internal abstract class InfixExpressionNode : ExpressionNode { public ExpressionNode Left { get; set; } public ExpressionNode Right { get; set; } } internal class AdditionNode : InfixExpressionNode { } internal class SubtractionNode : InfixExpressionNode { } internal class MultiplicationNode : InfixExpressionNode { } internal class DivisionNode : InfixExpressionNode { } internal class NegateNode : ExpressionNode { public ExpressionNode InnerNode { get; set; } } internal class FunctionNode : ExpressionNode { public Func<double, double> Function { get; set; } public ExpressionNode Argument { get; set; } } internal class NumberNode : ExpressionNode { public double Value { get; set; } } 

सीएसटी को एएसटी में बदलना

MathParser.*Context ने हमारे लिए सीएसटी नोड्स उत्पन्न किए ( MathParser.*Context कक्षाएं) अब हमें इन्हें एएसटी नोड्स में बदलना होगा।

यह आसानी से एक आगंतुक के साथ किया जाता है, और MathBaseVisitor<T> हमें एक MathBaseVisitor<T> वर्ग प्रदान करता है, तो हम उसके साथ काम करते हैं।

 internal class BuildAstVisitor : MathBaseVisitor<ExpressionNode> { public override ExpressionNode VisitCompileUnit(MathParser.CompileUnitContext context) { return Visit(context.expr()); } public override ExpressionNode VisitNumberExpr(MathParser.NumberExprContext context) { return new NumberNode { Value = double.Parse(context.value.Text, NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent) }; } public override ExpressionNode VisitParensExpr(MathParser.ParensExprContext context) { return Visit(context.expr()); } public override ExpressionNode VisitInfixExpr(MathParser.InfixExprContext context) { InfixExpressionNode node; switch (context.op.Type) { case MathLexer.OP_ADD: node = new AdditionNode(); break; case MathLexer.OP_SUB: node = new SubtractionNode(); break; case MathLexer.OP_MUL: node = new MultiplicationNode(); break; case MathLexer.OP_DIV: node = new DivisionNode(); break; default: throw new NotSupportedException(); } node.Left = Visit(context.left); node.Right = Visit(context.right); return node; } public override ExpressionNode VisitUnaryExpr(MathParser.UnaryExprContext context) { switch (context.op.Type) { case MathLexer.OP_ADD: return Visit(context.expr()); case MathLexer.OP_SUB: return new NegateNode { InnerNode = Visit(context.expr()) }; default: throw new NotSupportedException(); } } public override ExpressionNode VisitFuncExpr(MathParser.FuncExprContext context) { var functionName = context.func.Text; var func = typeof(Math) .GetMethods(BindingFlags.Public | BindingFlags.Static) .Where(m => m.ReturnType == typeof(double)) .Where(m => m.GetParameters().Select(p => p.ParameterType).SequenceEqual(new[] { typeof(double) })) .FirstOrDefault(m => m.Name.Equals(functionName, StringComparison.OrdinalIgnoreCase)); if (func == null) throw new NotSupportedException(string.Format("Function {0} is not supported", functionName)); return new FunctionNode { Function = (Func<double, double>)func.CreateDelegate(typeof(Func<double, double>)), Argument = Visit(context.expr()) }; } } 

जैसा कि आप देख सकते हैं, यह सीएसटी नोड से बाहर एक एएसटी नोड बनाने का एक विज़िटर है। कोड बहुत आत्म-व्याख्यात्मक होना चाहिए (अच्छी तरह से, शायद VisitFuncExpr सामग्री को छोड़कर, लेकिन यह सिस्टम के एक उपयुक्त विधि के लिए एक प्रतिनिधि को तार करने का सिर्फ एक त्वरित तरीका है। VisitFuncExpr क्लास)।

और यहां आपके पास एएसटी निर्माण सामग्री है यही सब कुछ जरूरी है बस सीएसटी से संबंधित जानकारी निकालें और उसे एएसटी में रखें।

AST आगंतुक

अब, एएसटी के साथ थोड़ा सा खेलते हैं। हमें इसके लिए एएसटी आगंतुक बेस क्लास का निर्माण करना होगा। चलिए बस AbstractParseTreeVisitor<T> विजिटर के समान कुछ करें AbstractParseTreeVisitor<T> एएनटीएलआर द्वारा प्रदान किया गया।

 internal abstract class AstVisitor<T> { public abstract T Visit(AdditionNode node); public abstract T Visit(SubtractionNode node); public abstract T Visit(MultiplicationNode node); public abstract T Visit(DivisionNode node); public abstract T Visit(NegateNode node); public abstract T Visit(FunctionNode node); public abstract T Visit(NumberNode node); public T Visit(ExpressionNode node) { return Visit((dynamic)node); } } 

यहां, मैंने सी # के dynamic कीवर्ड का लाभ उठाया है ताकि कोड की एक पंक्ति में डबल-प्रेषण किया जा सके। जावा में, आपको इस तरह से बयान if एक अनुक्रम के साथ तारों को खुद करना होगा:

 if (node is AdditionNode) { return Visit((AdditionNode)node); } else if (node is SubtractionNode) { return Visit((SubtractionNode)node); } else if ... 

लेकिन मैं सिर्फ इस उदाहरण के लिए शॉर्टकट के लिए गया था।

एएसटी के साथ कार्य करें

तो, हम गणित अभिव्यक्ति के पेड़ के साथ क्या कर सकते हैं? यह निश्चित रूप से मूल्यांकन करें! चलो एक अभिव्यक्ति मूल्यांकनकर्ता लागू करें:

 internal class EvaluateExpressionVisitor : AstVisitor<double> { public override double Visit(AdditionNode node) { return Visit(node.Left) + Visit(node.Right); } public override double Visit(SubtractionNode node) { return Visit(node.Left) - Visit(node.Right); } public override double Visit(MultiplicationNode node) { return Visit(node.Left) * Visit(node.Right); } public override double Visit(DivisionNode node) { return Visit(node.Left) / Visit(node.Right); } public override double Visit(NegateNode node) { return -Visit(node.InnerNode); } public override double Visit(FunctionNode node) { return node.Function(Visit(node.Argument)); } public override double Visit(NumberNode node) { return node.Value; } } 

एक बार जब हमारे पास एएसटी होती है तो बहुत आसान है, है ना?

यह सब एक साथ डालें

अंतिम लेकिन कम से कम, हमें वास्तव में मुख्य कार्यक्रम लिखना होगा:

 internal class Program { private static void Main() { while (true) { Console.Write("> "); var exprText = Console.ReadLine(); if (string.IsNullOrWhiteSpace(exprText)) break; var inputStream = new AntlrInputStream(new StringReader(exprText)); var lexer = new MathLexer(inputStream); var tokenStream = new CommonTokenStream(lexer); var parser = new MathParser(tokenStream); try { var cst = parser.compileUnit(); var ast = new BuildAstVisitor().VisitCompileUnit(cst); var value = new EvaluateExpressionVisitor().Visit(ast); Console.WriteLine("= {0}", value); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.WriteLine(); } } } 

और अब हम अंततः इसके साथ खेल सकते हैं:

यहां छवि विवरण दर्ज करें

मैंने एक छोटा जावा प्रोजेक्ट बनाया है जो आपको एएनटीएलआर इन-मेमोरी द्वारा उत्पन्न लेक्सर और पार्सर संकलित करके तुरन्त अपने एएनटीएलआर व्याकरण का परीक्षण करने की अनुमति देता है। आप इसे पार्स करने के लिए केवल एक स्ट्रिंग पार्स कर सकते हैं, और यह स्वचालित रूप से एक एएसटी उत्पन्न करेगा जो तब आपके आवेदन में उपयोग किया जा सकता है।

एएसटी के आकार को कम करने के उद्देश्य से, आप एक नोडफ़िल्टर का उपयोग कर सकते हैं, जिसमें आप एएसटी के निर्माण के दौरान गैर-टर्मिनलों के उत्पादन-नियम नाम जोड़ सकते हैं।

कोड और कुछ कोड उदाहरण https://github.com/julianthome/inmemantlr पर पाये जा सकते हैं

आशा है कि टूल उपयोगी है 😉