سؤال

هل أي شخص يدرك البرامج التعليمية للمشي asts التي تم إنشاؤها من antlr في C #؟ الأقرب كنت قادرا على العثور عليه هو هذه, ، لكنها ليست مفيدة بشكل فظيع.

هدفي هو المشي من خلال الأشجار التي أقوم بتوليدها بناء على لغة خاصة بالمجال تعمل عليها، واستخدام الأشجار لإخراج رمز C # الناتج.

سيكون البرنامج التعليمي القائم على جافا مفيدا أيضا - أي شيء يوفر أمثلة واضحة حول كيفية اجتياز ATLR ASTS.

هل كانت مفيدة؟

المحلول

تمكنت من معرفة ذلك عن طريق تكييف المثال في نهاية مقال مانويل عبادي.

إليك الإصدار الخاص بي، الذي صادفته لاستخدامه لتحويل التعليمات البرمجية المحورة إلى C #. هذه هي الخطوات:

  1. إنشاء مثيل antlrstringstream أو الفئة الفرعية مع المدخلات الخاصة بك (يمكن أن يكون ملف أو سلسلة).
  2. إرساء Lexer الذي تم إنشاؤه، يمر في تيار السلسلة.
  3. إنشاء مثيل رمز رمزية مع Lexer.
  4. إرساء محللك مع تيار الرمز المميز.
  5. احصل على قيمة المستوى الأعلى من المحلل المحلل الخاص بك، وتحويلها إلى CommonTree.
  6. اجتياز الشجرة:

للحصول على النص الحرفي لعقدة، استخدم node.Textوبعد للحصول على اسم الرمز المميز لعقدة، استخدم node.Token.Text.

لاحظ أن node.Token.Text سوف تعطيك فقط الاسم الفعلي لرمزتك إذا كان رمزا وهمي بدون سلسلة مقابلة. إذا كان رمزا حقيقي، ثم node.Token.Text سوف ترجع سلسلةها.

على سبيل المثال، إذا كان لديك ما يلي في قواعد اللغة الخاصة بك:

tokens { PROGRAM, FUNCDEC }

EQUALS : '==';
ASSIGN : '=';

ثم سوف تحصل على "PROGRAM", "FUNCDEC", "==", ، و "=" من الوصول المقابل لل node.Token.Text.

يمكنك أن ترى جزءا من مثالي أدناه، أو يمكنك تصفح النسخة الكاملة.


public static string Convert(string input)
{
    ANTLRStringStream sStream = new ANTLRStringStream(input);
    MyGrammarLexer lexer = new MyGrammarLexer(sStream);

    CommonTokenStream tStream = new CommonTokenStream(lexer);

    MyGrammarParser parser = new MyGrammarParser (tStream);
    MyGrammarParser.program_return parserResult = parser.program();

    CommonTree ast = (CommonTree)parserResult.Tree;

    Print(ast);
    string output = header + body + footer;

    return output;
}

public static void PrintChildren(CT ast)
{
    PrintChildren(ast, " ", true);
}

public static void PrintChildren(CT ast, string delim, bool final)
{
    if (ast.Children == null)
    {
        return;
    }

    int num = ast.Children.Count;

    for (int i = 0; i < num; ++i)
    {
        CT d = (CT)(ast.Children[i]);
        Print(d);
        if (final || i < num - 1)
        {
            body += delim;
        }
    }
}

public static void Print(CommonTree ast)
{
    switch (ast.Token.Text)
    {
        case "PROGRAM":
            //body += header;
            PrintChildren(ast);
            //body += footer;
            break;
        case "GLOBALS":
            body += "\r\n\r\n// GLOBALS\r\n";
            PrintChildren(ast);
            break;
        case "GLOBAL":
            body += "public static ";
            PrintChildren(ast);
            body += ";\r\n";
            break;

      ....
    }
}

نصائح أخرى

عادة ما تمشي asts مع العودية، وأداء إجراءات مختلفة بناء على نوع العقدة. إذا كنت تستخدم العقد شجرة متعددة الأشجار (أي فئات فئة فرعية مختلفة لعقد مختلفة في الشجرة)، فقد يكون الإرسال المزدوج في نمط الزائر مناسب؛ ومع ذلك، هذا عادة غير مناسب جدا مع Antlr.

في Pseudocode، عادة ما تبدو المشي عادة إلى حد ما:

func processTree(t)
    case t.Type of
        FOO: processFoo t
        BAR: processBar t
    end

// a post-order process
func processFoo(foo)
    // visit children
    for (i = 0; i < foo.ChildCount; ++i)
        processTree(foo.GetChild(i))
    // visit node
    do_stuff(foo.getText())

// a pre-order process
func processBoo(bar)
    // visit node
    do_stuff(bar.getText())
    // visit children
    for (i = 0; i < foo.ChildCount; ++i)
        processTree(foo.GetChild(i))

أنواع المعالجة تعتمد اعتمادا كبيرا على دلالات اللغة. على سبيل المثال، التعامل مع IF بيان، مع الهيكل (IF <predicate> <if-true> [<if-false>]), ، عند إنشاء رمز لآلة كومة مثل JVM أو CLR، قد تبدو إلى حد ما مثل هذا:

func processIf(n)
    predicate = n.GetChild(0)
    processExpr(predicate) // get predicate value on stack
    falseLabel = createLabel()
    genCode(JUMP_IF_FALSE, falseLabel) // JUMP_IF_FALSE is called brfalse in CLR,
                                       // ifeq in JVM
    if_true = n.GetChild(1)
    processStmt(if_true)
    if_false = n.ChildCount > 2 ? n.GetChild(2) : null
    if (if_false != null)
        doneLabel = createLabel()
        genCode(JUMP, doneLabel)
    markLabel(falseLabel)
    if (if_false != null)
        processStmt(if_false) // if-false branch
        markLabel(doneLabel)

بشكل عام يتم كل شيء بشكل متكرر اعتمادا على نوع العقدة الحالية، إلخ.

يجب أن تنظر في كتابة TreeParser؛ يمكن أن تجعل مهمة تفسير الشجرة أكثر بساطة.

ل antlr 2.x انظر http://www.antlr2.org/doc/sor.html.ل antlr 3.x انظر http://www.antlr.org/wiki/display/tlr3/tree+construe (جافا قائم على المحلل ومحافظة شجرة مثال)

لقد فعلت شيئا مشابها (ولكن ليس حقا) وانتهى بي الأمر مع TreeParser.

أقترح أيضا شراء دفتر Antlr. لقد وجدت أنه أكثر قيمة من أي مورد ويب. قد لا يكون لها كل الإجابات ولكن من المؤكد أنه يساعد في الأساسيات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top