Pegjs: دعم تحليل اللغات القائمة على المسافة البادئة

تم إنشاؤها على ١٦ أكتوبر ٢٠١٣  ·  34تعليقات  ·  مصدر: pegjs/pegjs

كنت أستخدم مجموعة من اللغات القائمة على المسافة البادئة ، مثل CoffeeScript و Jade وأريد إنشاء DSL بنفسي.
أجد بعض الحيل للحفاظ على المسافات البادئة في pegjs من خلال البحث ، كنت أتساءل عما إذا كان هناك حل ثابت:
http://stackoverflow.com/questions/11659095/parse-indentation-level-with-peg-js
http://stackoverflow.com/questions/4205442/peg-for-python-style-indentation
https://gist.github.com/jakubkulhan/3192844
https://groups.google.com/forum/#!searchin/pegjs/indent/pegjs/RkbAB4rPlfU/xxafrY5wGCEJ
ولكن هل ستدعم pegjs هذه الميزة؟

feature

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

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

هذا ما أفعله الآن ، وأوصيك بالقيام بذلك: المعالجة المسبقة لملف الإدخال وإدخال الرموز المميزة الخاصة بك مسافة بادئة / قديمة. أنا أستخدم {{{{و}}}} على التوالي. إذن ، تصبح القواعد النحوية خالية من السياق ويمكن تحليلها بشكل طبيعي. قد يؤدي ذلك إلى إفساد قيم السطر / العمود ، ولكن يمكنك تصحيح تلك الموجودة في المعالج اللاحق.

ال 34 كومينتر

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

هذا ما أفعله الآن ، وأوصيك بالقيام بذلك: المعالجة المسبقة لملف الإدخال وإدخال الرموز المميزة الخاصة بك مسافة بادئة / قديمة. أنا أستخدم {{{{و}}}} على التوالي. إذن ، تصبح القواعد النحوية خالية من السياق ويمكن تحليلها بشكل طبيعي. قد يؤدي ذلك إلى إفساد قيم السطر / العمود ، ولكن يمكنك تصحيح تلك الموجودة في المعالج اللاحق.

إذا لم تكن بحاجة إلى استهداف جافا سكريبت ، فإن Pegasus ، استنساخ pegjs الخاص بي لـ C # ، لديه دعم لحالة الدفع / الفرقعة. إليك مقالة wiki حول كيفية القيام بما تريده بالضبط: https://github.com/otac0n/Pegasus/wiki/Significant-Whitespace-Parsing

أود أن أقترح أن تستخدم pegjs بناء الجملة الخاص بي كنقطة انطلاق للتحليل المستند إلى الحالة.

القدرة على الدفع بأمان والدولة البوب ​​أمر جيد. سأستخدم ذلك إذا كان يعتمد على جافا سكريبت. فقط لا يستحق الأمر دمج CLR للتحليل فقط.

هذا ما كنت أحسبه. أعتقد ، في هذه الحالة ، أنه من المحتمل أن أحاول دعم تحسيناتي في pegjs.

ومع ذلك ، لا أرغب بالضرورة في القيام بذلك دون إجراء محادثة معdmajda.

@ otac0n هذا جميل. أنا لا أكتب C #. JavaScript هو أفضل بكثير بالنسبة لي.

اللغات القائمة على المسافة البادئة مهمة. أريد أن أنظر في تبسيط التحليل بعد 1.0.0.

أعتقد أنه من الأفضل حل هذه المشكلة من خلال السماح بالحالة بشكل عام ، تمامًا كما يفعل Pegasus وكما هو مقترح في # 285. إليك فكرة (ما يلي هو ترجمة قواعد المسافات البيضاء الهامة في Pegasus إلى pegjs مع إضافة فكرة بناء الجملة الخاصة بي):

{var indentation = 0}

program
  = s:statements eof { return s }

statements
  = line+

line
  = INDENTATION s:statement { return s }

statement
  = s:simpleStatement eol { return s }
  / "if" _ n:name _? ":" eol INDENT !"bar " s:statements UNDENT {
      return { condition: n, statements: s }
    }
  / "def" _ n:name _? ":" eol INDENT s:statements UNDENT {
      return { name: n, statements: s }
    }

simpleStatement
  = a:name _? "=" _? b:name { return { lValue: a, expression: b } }

name
  = [a-zA-Z] [a-zA-Z0-9]* { return text() }

_ = [ \t]+

eol = _? comment? ("\r\n" / "\n\r" / "\r" / "\n" / eof)

comment = "//" [^\r\n]*

eof = !.

INDENTATION
  = spaces:" "* &{ return spaces.length == indentation }

INDENT
  = #STATE{indentation}{ indentation += 4 }

UNDENT
  = #STATE{indentation}{ indentation -= 4 }

لاحظ الكتل #STATE{indentation} بالقرب من الجزء السفلي (من الواضح أنها مستوحاة من Pegasus). أسمي تلك الدولة كتل. الفكرة هي السماح للدولة بالحظر قبل الأفعال. فيما يلي كتلة حالة أكثر تعقيدًا:

#STATE{a, b, arr: {arr.slice()}, obj: {shallowCopy(obj)}, c}

إنه اختصار لـ:

#STATE{a: {a}, b: {b}, arr: {arr.slice()}, obj: {shallowCopy(obj)}, c: {c}}

بمعنى آخر ، بعد تطبيق توسيع الاختزال ، تكون محتويات كتلة الحالة عبارة عن قائمة identifier ":" "{" code "}" . إضافة كتلة حالة قبل إجراء يخبر pegjs أن هذا الإجراء سيعدل المعرفات المدرجة ، وإذا تم إرجاع القاعدة إلى الوراء ، فيجب إعادة تعيين هذه المعرفات إلى الكود بين الأقواس.

فيما يلي الوظائف المترجمة لـ INDENT و UNDENT من القواعد النحوية أعلاه ، مع إعادة تعيين المتغير indentation تمت إضافته:

    function peg$parseINDENT() {
      var s0, s1, t0;

      s0 = peg$currPos;
      t0 = indentation;
      s1 = [];
      if (s1 !== peg$FAILED) {
        peg$reportedPos = s0;
        s1 = peg$c41();
      } else {
        indentation = t0;
      }
      s0 = s1;

      return s0;
    }

    function peg$parseUNDENT() {
      var s0, s1, t0;

      s0 = peg$currPos;
      t0 = indentation;
      s1 = [];
      if (s1 !== peg$FAILED) {
        peg$reportedPos = s0;
        s1 = peg$c42();
      } else {
        indentation = t0;
      }
      s0 = s1;

      return s0;
    }

وإليك بعضًا من كيفية تجميع "كتلة الحالة المعقدة" من الأعلى:

s0 = peg$currPos;
t0 = a;
t1 = b;
t2 = arr.slice();
t3 = shallowCopy(obj);
t4 = c;
// ...
if (s1 !== peg$FAILED) {
  // ...
} else {
  peg$currPos = s0;
  a = t0;
  b = t1;
  arr = t2;
  obj = t3;
  c = t4;
}

ما رأيك في فكرة القدرة على:

  • أخبر pegjs عن المتغيرات ذات الحالة التي سيتم تعديلها من خلال إجراء ما.
  • قم بتوفير الكود المطلوب لتخزين هذه المتغيرات إذا كانت بحاجة إلى إعادة التعيين. (بما في ذلك بناء الجملة المختصرة للحالة البسيطة حيث يكون المتغير قيمة أولية.)

وما رأيك في النحو؟

تحرير: إليك قواعد النحو المقترحة (للمتعة فقط):

diff --git a/src/parser.pegjs b/src/parser.pegjs
index 08f6c4f..09e079f 100644
--- a/src/parser.pegjs
+++ b/src/parser.pegjs
@@ -116,12 +116,31 @@ ChoiceExpression
     }

 ActionExpression
-  = expression:SequenceExpression code:(__ CodeBlock)? {
+  = expression:SequenceExpression code:((__ StateBlock)? __ CodeBlock)? {
       return code !== null
-        ? { type: "action", expression: expression, code: code[1] }
+        ? {
+            type:       "action",
+            expression: expression,
+            code:       code[2],
+            stateVars:  (code[0] !== null ? code[0][1] : [])
+          }
         : expression;
     }

+StateBlock "state block"
+  = "#STATE{" __ first:StateBlockItem rest:(__ "," __ StateBlockItem)* __ "}" {
+      return buildList(first, rest, 3);
+    }
+
+StateBlockItem
+  = varName:Identifier expression:(__ ":" __ CodeBlock)? {
+      return {
+        type:       "stateVar",
+        name:       varName,
+        expression: expression !== null ? expression[3] : varName
+      };
+    }
+
 SequenceExpression
   = first:LabeledExpression rest:(__ LabeledExpression)* {
       return rest.length > 0

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

hoho أنا لا لتحليل المسافات البادئة باستخدام المحلل اللغوي مثل الحلول وقد نجح. وأعتقد أن المسافة البادئة الأصلية لتحليل المسافات البادئة باستخدام PEG.js قد اختفت.

أعني أن هناك حلولاً لتحليل المسافة البادئة ، لكن التعليقات تقول أن هذه الحلول ستفشل في بعض الحالات.

دعني أوضح الموقف: من الممكن تحليل اللغات القائمة على المسافة البادئة في PEG.js. هناك العديد من الحلول المذكورة أعلاه ، ولقد قمت للتو بإنشاء حل آخر حيث حاولت الحصول على "إحساس" لهذا (إنها قواعد للغة بسيطة مع عبارتين ، يمكن أن تحتوي إحداهما على عبارات فرعية ذات مسافة بادئة - على سبيل المثال if في بايثون).

شيء واحد مشترك بين جميع الحلول هو أنها تحتاج إلى تتبع حالة المسافة البادئة يدويًا (لأن PEG.js لا يمكنها القيام بذلك). هذا يعني أن هناك نوعان من القيود:

  1. لا يمكنك ترجمة القواعد باستخدام التخزين المؤقت بأمان (لأن المحلل اللغوي يمكنه استخدام النتائج المخزنة مؤقتًا بدلاً من تنفيذ التعليمات البرمجية لمعالجة الحالة).
  2. لا يمكنك التراجع عبر مستويات المسافة البادئة (لأنه لا توجد حاليًا طريقة لفك الحالة عند التراجع). بعبارة أخرى ، لا يمكنك تحليل لغة يوجد بها بنائين صالحين يمكن إزالتهما فقط بعد تغيير مستوى السطر والمسافة البادئة.

يمكن أن يتسبب التقييد 1 في حدوث مشكلات في الأداء في بعض الحالات ، لكنني لا أعتقد أن هناك العديد من اللغات التي قد يمثل الحد 2 مشكلة فيها.

أنا موافق مع هذه الحالة حتى 1.0.0 وأخطط للعودة إلى هذا الموضوع في وقت ما بعد ذلك. يمكن أن يكون المستوى الأول من التحسين هو التخلص من القيد 2 باستخدام تتبع حالة أكثر وضوحًا (كما هو مقترح أعلاه) أو عن طريق توفير خطاف رجعي (بحيث يمكن للفرد أن يفتح الحالة بشكل صحيح). يمكن أن يكون المستوى الثاني هو التخلص من الحاجة إلى تتبع حالة المسافة البادئة يدويًا من خلال توفير طريقة تعريفية للقيام بذلك. هذا يمكن أن يساعد في التقييد 1.

H ، لقد كتبت تصحيحًا (صغيرًا ، هاكًا) لـ PEG.js يدعم التراجع الصحيح ، كما أوضحت هنا: https://github.com/pegjs/pegjs/issues/45

آسف على النتوء 😜

كنت أبحث للتو في إنشاء محلل CSON و YAML للغة أقوم بتصميمها ، وأثناء البحث عن طرق لإنشاء محلل قائم على المسافة البادئة باستخدام PEG.js ، توصلت إلى طريقة بسيطة:

1) لا تعتمد على حالة الدفع / البوب
2) تأكيد مستويات المسافة البادئة عبر رمز ضمن الإجراءات

لقد خطر لي أن أيًا من الحلين المذكورين أعلاه يضيف بالفعل مشاكل أداء إلى المحلل اللغوي الذي تم إنشاؤه. بالإضافة إلى ذلك في رأيي:

1) الاعتماد على الحالة لا يضيف فقط بناء جملة قبيح PEG.js ولكن يمكن أن يؤثر أيضًا على نوع المحللات التي يمكن إنشاؤها لأنها ستحتاج إلى دعم تسليم الحالة القائم على الإجراء.
2) تؤدي إضافة بعض التعليمات البرمجية في الإجراءات أحيانًا إلى قاعدة تعتمد على اللغة ، وهذا يعني بالنسبة لبعض المطورين أنه لا يمكنهم استخدام المكون الإضافي لإنشاء محللات للغات أخرى مثل C أو PHP دون اللجوء إلى المزيد من المكونات الإضافية للتعامل مع الإجراءات المتعلقة بالقواعد ، والتي فقط يعني نظام بناء أكبر فقط لدعم تغيير واحد أو اثنين.

بعد فترة ، بدأت في إنشاء متغير خاص بي من المحلل اللغوي PEG.js وفكرت: لماذا لا تستخدم فقط عوامل بادئة الزيادة ("++") والتناقص ("-") (__ ++ تعبير__ و __ - تعبير__ ) للتعامل مع نتائج تعبيرات المطابقة (__expression * __ أو __expression + __).

ما يلي هو مثال على القواعد النحوية المستندة إلى لغةdmajda 's Simple intentation-based ، والتي أعيد كتابتها لاستخدام التعبير __ ++ الجديد__ و __- التعبير__ بدلاً من __ & {المسند} __:

Start
  = Statements

Statements
  = Statement*

Statement
  = Indent* statement:(S / I) { return statement; }

S
  = "S" EOS {
      return "S";
    }

I
  = "I" EOL ++Indent statements:Statements --Indent { return statements; }
  / "I" EOS { return []; }

Indent "indent"
  = "\t"
 / !__ "  "

__ "white space"
 = " \t"
 / " "

EOS
  = EOL
  / EOF

EOL
  = "\n"

EOF
  = !.

أكثر إرضاء للعين ، أليس كذلك؟ سهل الفهم أيضًا ، لكل من البشر والبرامج.

كيف يعمل؟ بسيط:

1) يخبر Indent* المحلل اللغوي أننا نريد 0 أو أكثر مما يعيده Indent
2) ++Indent يطلب من المحلل اللغوي زيادة الحد الأدنى من المطابقات المطلوبة لـ Indent
3) الآن في أي وقت يكون المحلل اللغوي على وشك إعادة التطابقات لـ Indent ، فإنه يتوقع أولاً أن يكون __1 أكثر__ مطابقًا من قبل ، وإلا سيتم طرح _peg $ SyntaxError_.
4) --Indent يطلب من المحلل اللغوي تقليل الحد الأدنى من المطابقات المطلوبة لـ Indent
5) الآن في أي وقت يبحث المحلل اللغوي عن Indent ويعيد التطابقات فإنه يتوقع __1 أقل__ تطابقًا من قبل ، وإلا سيتم طرح _peg $ SyntaxError_.

هذا الحل هو أفضل طريقة لإضافة دعم لـ "تحليل المسافات البيضاء الهامة" دون إضافة بناء جملة قبيح إلى قواعد النحو في PEG.js أو حظر مولدات الطرف الثالث.

فيما يلي القواعد التي تم تغييرها لإضافة دعم لتحليل هذا في _src / parser.pegjs_:

{
  const OPS_TO_PREFIXED_TYPES = {
    "$": "text",
    "&": "simple_and",
    "!": "simple_not",
    "++": "increment_match",
    "--": "decrement_match"
  };
}

PrefixedOperator
  = "$"
  / "&"
  / "!"
  / "++"
  / "--"

SuffixedOperator
  = "?"
  / "*"
  / "+" !"+"

هل أنا محق في افتراض أنه لدعم جانب المترجم / المولد ، سيتعين علينا:

1) أضف مرور مترجم يضمن استخدام __ ++ تعبير__ أو __ - تعبير__ فقط في __expression * __ أو __expression + __ ، حيث يجب أن يكون __expression__ من الأنواع: اختيار أو تسلسل أو قاعدة_راجع
2) إضافة تحقق يستند إلى ذاكرة التخزين المؤقت في المحلل اللغوي الذي تم إنشاؤه لـ __expression * __ أو __expression + __ الذي يؤكد استيفاء الحد الأدنى المطلوب من المطابقة قبل إعادة المطابقات
3) قم اختياريًا بإضافة طريقة مساعدة للمحللين الذين تم إنشاؤهم لتنفيذ ذلك الذي يُرجع عدد المطابقات المطلوبة لقاعدة معينة ، على سبيل المثال. nMatches( name: String ): Number

futagoza ، هذا نظيف وذكي. أحبها. أنا أعمل على محلل يتعامل مع الحالة ، لكن الحالة الوحيدة التي نحتاجها حقًا هي مستويات المسافة البادئة. قد أستخدم هذه الفكرة وأمنحك الفضل في ذلك. لا يزال تتبع مستوى المسافة البادئة يتطلب دفع / تفرقع بشكل فعال وبالتالي قد لا يزال يمنع بعض التحسينات ولكن دلالات هذا لطيفة للغاية.

إذا كنت تضيف عوامل تشغيل إلى القواعد النحوية ، فإنني أوصي بإضافة عامل التشغيل @ البادئة أيضًا. الغرض منه هو استخراج نتيجة قاعدة واحدة من تسلسل. باستخدام ذلك يصبح نموذج القواعد أكثر نظافة. لا مزيد من الإجراءات التافهة {إرجاع x}.

Start
  = Statements

Statements
  = Statement*

Statement
  = Indent* @(S / I)

S
  = "S" EOS {
      return "S";
    }

I
  = "I" EOL ++Indent <strong i="8">@Statements</strong> --Indent
  / "I" EOS { return []; }

Indent "indent"
  = "\t"
 / !__ "  "

__ "white space"
 = " \t"
 / " "

EOS
  = EOL
  / EOF

EOL
  = "\n"

EOF
  = !.

kodyjking ما رأيك في هذا؟

futagoza هل لديك شوكة / فرع مع تصحيح المسافة البادئة

أنا أعمل على هذه المسافة البادئة للشوكة / الفرع

krinye "أوصي بإضافة عامل تشغيل البادئة @ أيضًا. والغرض منه هو ببساطة استخراج نتيجة قاعدة واحدة من تسلسل"

هل يمكن لشخص منكم إلقاء نظرة وإبداء تعليق أو العلاقات العامة مع الإصلاح. شكرا :)

الملف التمهيدي: التغييرات الشوكة

آه ، لم ألاحظ التحذير:

هل أنا محق في افتراض أنه لدعم جانب المترجم / المولد ، سيتعين علينا:

  • إضافة مرور مترجم يضمن استخدام تعبير ++ أو - تعبير فقط في التعبير * أو التعبير + ، حيث يجب أن يكون التعبير من الأنواع: اختيار أو تسلسل أو rule_ref
  • إضافة فحص مستند إلى ذاكرة التخزين المؤقت في المحلل اللغوي الذي تم إنشاؤه للتعبير * أو التعبير + الذي يؤكد استيفاء الحد الأدنى المطلوب من المطابقة قبل إرجاع المطابقات
  • قم اختياريًا بإضافة طريقة مساعدة للمحللات التي تم إنشاؤها لتنفيذها والتي تُرجع عدد المطابقات المطلوبة لقاعدة معينة ، على سبيل المثال. التطابقات n (الاسم: سلسلة): الرقم

فقط للركلات ، حاولت إضافة هذا بـ visitor.js

      increment_match: visitExpression,
      decrement_match: visitExpression,

أحصل الآن على Invalid opcode: undefined.

@ kristianmandrup بخصوص عامل التشغيل @ لاستخراج قيم مفردة من التسلسلات ، لديّ مفترق مع هذه الميزة المضافة إلى PegJS المتاحة هنا:

https://github.com/krisnye/pegjs

إنها إضافة بسيطة جدًا.

@ krisnye +1 للتنفيذ القائم على القواعد ، لطيف وبسيط. إذا كنت لا تمانع ، فسأضيف هذا إلى البديل الخاص بي من PEG.js 😄

@ kristianmandrup أراك تلتزم باقتراحي

تضمين التغريدة

كنت أناقش منطق المسافة البادئة مع زميل في العمل ونقترح العناصر النحوية التالية

// يزيد متغير الحالة المسماة
المعرف ++
// ينقص متغير الحالة المسماة
المعرف--

// كرر المبلغ الثابت أو متغير الحالة (مع صفر افتراضي إذا لم يزداد المتغير بعد)
القاعدة {عدد صحيح | معرّف}
// كرر min / max باستخدام الثوابت أو متغيرات الحالة
القاعدة {عدد صحيح | المعرف ، عدد صحيح | معرّف}

المحلل اللغوي الذي نعمل عليه يمكنه التعامل مع الحالة التعسفية ، ولكن بصراحة ، ما سبق هو كل ما هو مطلوب لتحليل المسافة البادئة.

شكرا جزيلا يا أصدقاء! إذا كان من السهل جدًا القيام بذلك ، فلماذا لا تصنع مفترقًا "مخصصًا" حيث الأشياء التي تذكرها "تعمل فقط" ؛)
هتافات!

تضمين التغريدة

  1. يمكن أن يتسبب استخدام __identifier ++ __ في حدوث خطأ فوضوي بسهولة إذا كان المطور يقصد __ Identifier + __ ، ولهذا اخترت استخدام __ ++ معرف__ وللتناسق __-- المعرف__
  2. كما هو مذكور في قضية مختلفة حول النطاقات ، يمكن الخلط بين rule{ STATE_REPEAT / RANGE } rule{ ACTION } ، خاصة إذا كنت تقوم ببناء تمييز بناء الجملة لـ PEG.js ، لذلك تم رفض هذا الأسلوب من قبل dmajda

@ kristianmandrup _ (OFF TOPIC) _ أنا جيد في تصميم الميزات ، وفي بعض الأحيان تنفيذ التطبيقات ، لكنني

futagoza شكرًا

وجهني شخص آخر من هذه القائمة إلى حلول أخرى منشئ / منشئ محلل قد أنظر إليها أيضًا. أبقني على اطلاع بالمستجدات! هتافات!

@ kristianmandrup لم يتم تضمينه بقدر ما أستطيع أن أقول ، لكن dmajda قال منذ 3 سنوات إنه سينظر في الأمر بعد إصدار PEG.js v1 ، ولكن مما يمكنني قوله لن يكون لمدة عامين آخرين ، ما لم يخطط لذلك قم بإصدار المزيد من الإصدارات الثانوية من PEG.js v0 (_0.12_، _0.13_، _etc_)

قصدت ما إذا كنت قد أدرجت دعم المسافة البادئة في ePEG بالفعل أو في خارطة الطريق؟

@ kristianmandrup أوه 😆 ، إنها على خريطة الطريق. لم أقم بتحديث repo ePEG.js لفترة من الوقت ، وقررت مؤخرًا تحويله إلى إعادة كتابة كاملة لـ PEG.js بدلاً من مكون إضافي.

وافق futagoza على ++ / -

وبالتالي

++identifier
--identifier
rule[integer | identifier]
rule[integer | identifier, integer | identifier]

يتم استخدامkrisnye [ ... ] لفئات الشخصيات ، راجع https://github.com/pegjs/pegjs#characters

ما أفعله في ePEG.js هو إضافة نطاقات (أيضًا على خريطة الطريق) لتحقيق ما أعتقد أنه تصفه:

space = [ \t]*
rule = range|expression
  • يمكن أن يكون __expression__ أيًا مما يلي: __ ++ مسافة__ ، __- مسافة__ أو __فضاء__
  • __range__ يمكن أن يكون __ min.. __ ، __ min..max __ ، __ ..max __ أو __ exact __
  • __ min__ ، __max__ أو __exact__ يمكن أن يكون فقط __عددًا صحيحًا بدون إشارة__
  • يمكن أن يسمح لنا استخدام __range__ مع __expression__ (على سبيل المثال 2 | تعبير) بتعيين المبلغ الإجمالي لـ __expression__ المطلوب لـ __القاعدة__ للتحليل بنجاح.
  • استخدام النطاق __exact__ مع __ ++ تعبير__ أو __- تعبير__ (على سبيل المثال 3 | ++ تعبير) يمكن أن يسمح لنا بتعيين مبلغ __ صحيح__ لـ __ ++ __ أو __ - __ ، وهو افتراضي __1__
  • يؤدي استخدام النطاق __ min__ أو __max__ مع تعبير __ ++__ أو __- التعبير__ إلى ظهور خطأ في بناء الجملة.

أنا لا أستخدم متغيرات الحالة لأن ذلك سيكون محيرًا فقط مع معرفات القواعد.

باستخدام مزيج من __range__، __ ++ __، __ - __ __ أو__ أنا على أمل لإنشاء ملفات قواعد PEG التي تعتمد أقل على قواعد __action__ عن نتائجها، والتي ينبغي زيادة الوقت اللازم لتطوير من بيضاء (على سبيل المثال المسافة البادئة -اللغات المستندة إلى فن ASCII ، إلخ) مثل مصممي اللغة و / أو المنفذين لا داعي للقلق بشأن محاولة تأكيد ما إذا كان قد تم تحليل المقدار الصحيح للمسافات البيضاء.
يجب أن يسمح هذا أيضًا لمطوري المكونات الإضافية بإنشاء مولدات محلل يمكنها التحسين بدون خوف من ماهية لغة __action __ (افتراضيًا ، يمكن لـ JavaScript ، ولكن مع المكون الإضافي يمكن تغييرها إلى CoffeeScript و PHP وما إلى ذلك).

لذلك يبدو أنه لا يزال من غير الممكن اليوم تحليل Python باستخدام PEG.js خارج الصندوق ، هل هذا صحيح؟

إذا لم يكن كذلك ، فهل هذا شيء سيأتي قريبًا؟ هل هناك مجموعة من المهام المطلوبة لإنجاز هذا العمل والتي يمكن أن يساهم بها الناس؟

لدي مشروع حيث أود أن أتمكن من الحصول على Python AST في JS ، وتعديله ثم تحويله مرة أخرى إلى كود المصدر بنفس التنسيق ، لذلك سأكون مهتمًا بتحقيق ذلك إذا كان هناك واضح خريطة الطريق.

mindjuice ليس بعد ، من المخطط نشره بعد 1.0.

إذا كنت لا تستطيع الانتظار ، فقد قمت أنا وابن أخي بإنشاء محلل مكتوب بلغة TypeScript يستخدم نفس بناء الجملة ويتعامل مع المسافة البادئة. لم يتم توثيقها بعد ، لكنها بسيطة جدًا. لا يزال هناك عمل مستمر حيث نستخدمه كمحلل لتصميم لغة جديد.

https://github.com/krisnye/pegs

يمكنك أيضًا تجربة مولد محلل آخر مع دعم مثل chevrotain

مثال على المسافة البادئة بيثون

أعتقد أنه من الممكن جدًا تحليل المسافة البادئة التي تشبه الثعبان باستخدام PEGjs.
يستخدم المثال أدناه المسافة البادئة القائمة على أربع مسافات فقط ، ولكن يمكن تمديدها لتغطية علامات التبويب ذات المسافات العشوائية وأحرف المسافات البيضاء الأخرى.
في الواقع ، للغة التي أعمل عليها قصة مسافة بادئة أكثر تعقيدًا من قصة بايثون وهذه القواعد تعمل بشكل جيد معها.

{
    let prevIndentCount = 0;
    function print(...s) { console.log(...s); }
}

Indent 'indent'
    = i:("    "+) { 
        let currentIndentCount = i.toString().replace(/,/g, "").length;
        if (currentIndentCount === prevIndentCount + 4) { 
            // DEBUG //
            print("=== Indent ===");
            print("    current:"+currentIndentCount); 
            print("    previous:"+prevIndentCount);
            print("    lineNumber:"+location().start.line); 
            // DEBUG //
            prevIndentCount += 4;
            return "[indent]";
        }
        error("error: expected a 4-space indentation here!")
    } // 4 spaces 

Samedent 'samedent'
    = s:("    "+ / "") &{
        let currentIndentCount = s.toString().replace(/,/g, "").length;
        if (currentIndentCount === prevIndentCount) {
            print("=== Samedent ===");
            return true;
        }
        return false;
    }

Dedent 'dedent'
    = d:("    "+ / "") {
        let currentIndentCount = d.toString().replace(/,/g, "").length;
        if (currentIndentCount < prevIndentCount) {
            // DEBUG //
            print("=== Dedent ===");
            print("    current:"+currentIndentCount); 
            print("    previous:"+prevIndentCount);
            print("    lineNumber:"+location().start.line); 
            // DEBUG //
            prevIndentCount -= 4;
            return "[dedent]";
        }
        error("error: expected a 4-space dedentation here!");
    }

باستخدام القواعد النحوية أعلاه ، يمكنك إنشاء قاعدة كتلة ذات مسافة بادئة مثل هذا:

FunctionDeclaration 
    = 'function' _ Identifier _ FunctionParameterSection _ ":" _ FunctionBody

FunctionBody
    = Newline Indent FunctionSourceCode (Newline Samedent FunctionSourceCode)* Dedent 
هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات