Pegjs: إضافة القدرة على تتبع موضع العقدة

تم إنشاؤها على ١٣ أغسطس ٢٠١١  ·  15تعليقات  ·  مصدر: pegjs/pegjs

لا تتعقب أجهزة التحليل اللغوي التي تم إنشاؤها بواسطة PEG.js حاليًا الموضع (خط وعمود). أرغب في إضافة هذه الميزة لأنها ستكون مفيدة للغاية.

إحدى الطرق هي إضافة خصائص line و column لكل عنصر يتم إرجاعه كنتيجة مطابقة:

start = "a" b:"b" { return [b.line, b.column]; } // Returns [1, 2] on the input "ab".

هناك طريقة أخرى تتمثل في إنشاء متغيرات خاصة line و column متوفرة داخل الإجراءات / المسندات ، بالإشارة إلى موضع بداية القاعدة الحالية:

start = "a" "b" { return [line, column]; } // Returns [1, 1] on the input "ab".

الطريقة الأولى أكثر مرونة ، لكن هذه المرونة قد لا تكون ضرورية في الواقع. لست متأكدًا من الطريقة التي سأنفذها بعد.

كلا الطريقتين سيؤذي الأداء. لمنع هذا في الحالات التي لا يكون فيها تتبع الموقع مطلوبًا ، يجب تمكين التتبع فقط إذا تم تمرير الخيار trackPosition بقيمة صادقة إلى PEG.buildParser عند إنشاء المحلل اللغوي.

feature

التعليق الأكثر فائدة

tomitrescak ، يبدو أن هذه الميزة قد تغيرت عدة مرات في الماضي. ألق نظرة على سجل التغيير لمزيد من المعلومات. tl ؛ dr هو أنك تحتاج إلى استخدام الدالة location() في القواعد الخاصة بك

ال 15 كومينتر

سيكون أي من الخيارين رائعين. لسطر احتياجاتي ببساطة ، سيكون العمود على ما يرام.

أنا أيضًا أبحث عن حل لهذا. حاليًا ، لقد اخترقت شيئًا سريعًا بناءً على computeErrorPosition () ، لكن به العديد من مكامن الخلل فيه.

على السطح ، يبدو الأسلوب الأول أكثر سهولة من الثاني.

أنا أحب النهج الأول بشكل أفضل أيضًا.

تتمثل إحدى الكفاءة الممكنة في جعل name.position دالة ، بحيث يمكن حسابها بشكل كسول. يمكن أن يؤدي هذا بعد ذلك إلى إرجاع صفيف مكون من عنصرين من السطر والعمود. مجرد فكرة لأولئك الذين لا يريدون حساب الموضع لكل عنصر على حدة.

بعد فوات الأوان ، يبدو أنه من الأفضل توفير مواضع حرف البداية والنهاية ، ثم توفير وظيفة مساعدة في المكتبة تقوم بتحويل الموضع إلى سطر / عمود. نظرًا لأنه في الحالة العامة ، لا تحتاج إلى سطر / عمود ما لم يكن هناك خطأ ، وبمجرد وصولك إلى خطأ ، فإنك تحتاجه عادةً مرة واحدة فقط.

أفعل ذلك حاليًا بطريقة متطرفة من خلال إساءة استخدام المتغيرات startPos0 و pos ، والتي تبدو وكأنها اختراق ، لكنها تعمل في الوقت الحالي.

إلى أن يكون هناك إصلاح رسمي ، أقوم بتضمين هذه الوظيفة (نسخة تقريبية من computeErrorPosition ) في الجزء العلوي من القواعد النحوية الخاصة بي. على الأقل سيعطيني الموضع _current_ (على الرغم من أنه ليس موضع العقد الفردية):

  function computeCurrentPos() {
    /*
     * The first idea was to use |String.split| to break the input up to the
     * error position along newlines and derive the line and column from
     * there. However IE's |split| implementation is so broken that it was
     * enough to prevent it.
     */

    var line = 1;
    var column = 1;
    var seenCR = false;

    for (var i = 0; i < pos; i++) {
      var ch = input.charAt(i);
      if (ch === '\n') {
        if (!seenCR) { line++; }
        column = 1;
        seenCR = false;
      } else if (ch === '\r' | ch === '\u2028' || ch === '\u2029') {
        line++;
        column = 1;
        seenCR = true;
      } else {
        column++;
        seenCR = false;
      }
    }

    return { line: line, column: column, pos: pos };
  }

تم إصلاح هذه المشكلة من خلال سلسلة من الالتزامات .

يمكنك الآن تمرير الخيار trackLineAndColumn إلى الوظيفة PEG.buildParser :

var parser = PEG.buildParser(myGrammar, { trackLineAndColumn: true});

يؤدي تعيين trackLineAndColumn إلى true إلى ظهور متغيرين جديدين في الإجراءات والمسندات - line و column . بالنسبة للإجراءات ، تشير هذه المتغيرات إلى موضع البدء لتعبير الإجراء بينما تشير في المسندات إلى الموضع الحالي. السلوك المختلف قليلاً يحفزه الاستخدام المتوقع.

يعد تعقب الخط والأعمدة اختياريًا لأنه يضر بالأداء (يجعل المحلل اللغوي حوالي 3-4 × أبطأ). قد أكون قادرًا على تحسين هذا إلى حد ما في المستقبل (حاولت أن أجعله يعمل أولاً).

في وصف المشكلة ، كنت أذكر طريقة مختلفة لهذه المشكلة: إضافة خصائص line و column لكل نتيجة مطابقة. بينما كان هذا الحل أنظف ومفضلًا من قبل المستخدمين ، أدركت أنه لا يمكن تعيين خصائص على قيم أولية مثل السلاسل أو الأرقام أو القيم المنطقية (والتي يتم إرجاعها غالبًا كنتائج مطابقة). قد يكون إرجاع مثيلات التفاف العناصر (على سبيل المثال ، String ، Number أو Boolean ) حلاً ممكنًا ، لكنه قد يؤدي إلى أخطاء دقيقة في المحلل اللغوي الذي أنشأه المستخدمون ، لأن تتصرف هذه الأغلفة بشكل مختلف قليلاً عن الأوليات. وهكذا قررت تنفيذ الاقتراح البديل.

هل سيتم تحديث صفحة الاختبار عبر الإنترنت لدعم هذه الميزة؟

paulftw يستخدم المحرر عبر الإنترنت دائمًا أحدث إصدار ثابت من PEG.js (حاليًا 0.6.2). سوف أقوم بتحديثه بمجرد إصدار PEG.js 0.7.0 (والذي سيتضمن هذه الميزة). ما لم يظهر شيء غير متوقع ، سيحدث هذا في النصف الثاني من أبريل.

لاحظ أن الكود المصدري لموقع الويب متاح في GitHub ، لذلك إذا كنت لا تتحلى بالصبر ، فيمكنك تشغيله وتعديله بنفسك.

أدركت للتو أن جميع الصفوف والأعمدة تستند إلى 1 ، بينما تستخدم مصفوفات JS بالإضافة إلى جميع اللغات والمكتبات الحديثة تقريبًا الفهرسة المستندة إلى 0.

أي فرصة للتراجع عن قرار التصميم هذا؟

paulftw هل يمكنك إعطاء مثال لمولد محلل يُبلغ عن الأسطر والأعمدة على أنها 0؟

الفكرة من قراري هي أنه من المرجح أن يتم عرض هذه الأرقام للمستخدمين (في رسائل الخطأ ، ومواضع العقدة ، وما إلى ذلك) ، لذا فإن الفهرسة القائمة على 1 تكون أكثر منطقية من الفهرسة المستندة إلى 0. بالنسبة إلى معالجة الآلة ، من المحتمل أن يتم استخدام المتغير offset في أغلب الأحيان ، حيث يعتمد المتغير على 0.

أي فرصة للتراجع عن قرار التصميم هذا؟

نعم ، إذا اقتنعت :-)

أستخدم peg.js لإبراز النص في محرر Ace. من الطبيعي جدًا أن تستند أرقام خطوط Ace إلى 0.
ومع ذلك ، يبدو أن مواقع Bison تعتمد على 1.
http://git.savannah.gnu.org/cgit/bison.git/tree/src/location.c#n73

إذا كان هذا هو الحال بالفعل ، فعندئذ يجب أن أتوقف عن الجدل.

لست متأكدًا من نوع المثال الذي تريد رؤيته.
في الوقت الحالي ، أستخدم الكود التالي للعثور على اسم رمز:

الآسر
= "" {إرجاع الموضع الجديد (السطر - 1 ، العمود - 1) ؛ }

رمز
= start: captor name: IDENT end: captor S * {return new Symbol (name، new Range (start، end))؛ }

paulftw لقد قسمت هذه المشكلة إلى إصدار منفصل . سأنتظر حتى يتبنى المستخدمون 0.7.0 وأرى ما هو الاستخدام السائد ليقرر.

أعلم أن هذا مغلق منذ فترة طويلة ، لكن كيف يمكنني أن أجعل هذا يعمل؟ أنا مستجد تماما في هذا. قمت بتجميع القواعد النحوية الخاصة بي باستخدام علامة "trackLineAndColumn ': true" ، لكن العقد ما زالت لا تحتوي على أسطر وأعمدة. ما هو المطلوب؟

ذكرت ما يلي ، أنا فقط لا أعرف كيفية استخدامه ، هل هو موثق في مكان ما من فضلك؟

يؤدي تعيين trackLineAndColumn إلى القيمة true إلى ظهور متغيرين جديدين في الإجراءات والمسندات - الخط والعمود. بالنسبة للإجراءات ، تشير هذه المتغيرات إلى موضع البدء لتعبير الإجراء بينما تشير في المسندات إلى الموضع الحالي. السلوك المختلف قليلاً يحفزه الاستخدام المتوقع.

tomitrescak ، يبدو أن هذه الميزة قد تغيرت عدة مرات في الماضي. ألق نظرة على سجل التغيير لمزيد من المعلومات. tl ؛ dr هو أنك تحتاج إلى استخدام الدالة location() في القواعد الخاصة بك

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات