كنت أستخدم مجموعة من اللغات القائمة على المسافة البادئة ، مثل 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 هذه الميزة؟
من الخطير جدًا الاعتماد على الآثار الجانبية التي تضيفها في معالجات مخصصة لتحليل القواعد النحوية القائمة على المسافة البادئة. فقط لا تفعل ذلك. يجب أن تضيف 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;
}
ما رأيك في فكرة القدرة على:
وما رأيك في النحو؟
تحرير: إليك قواعد النحو المقترحة (للمتعة فقط):
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.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 "أوصي بإضافة عامل تشغيل البادئة @
أيضًا. والغرض منه هو ببساطة استخراج نتيجة قاعدة واحدة من تسلسل"
هل يمكن لشخص منكم إلقاء نظرة وإبداء تعليق أو العلاقات العامة مع الإصلاح. شكرا :)
لقد تم تصحيحه ... لم يتم العثور على increment_match
آه ، لم ألاحظ التحذير:
هل أنا محق في افتراض أنه لدعم جانب المترجم / المولد ، سيتعين علينا:
فقط للركلات ، حاولت إضافة هذا بـ 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 باستخدام الثوابت أو متغيرات الحالة
القاعدة {عدد صحيح | المعرف ، عدد صحيح | معرّف}
المحلل اللغوي الذي نعمل عليه يمكنه التعامل مع الحالة التعسفية ، ولكن بصراحة ، ما سبق هو كل ما هو مطلوب لتحليل المسافة البادئة.
شكرا جزيلا يا أصدقاء! إذا كان من السهل جدًا القيام بذلك ، فلماذا لا تصنع مفترقًا "مخصصًا" حيث الأشياء التي تذكرها "تعمل فقط" ؛)
هتافات!
تضمين التغريدة
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
min..
__ ، __ min..max
__ ، __ ..max
__ أو __ exact
__أنا لا أستخدم متغيرات الحالة لأن ذلك سيكون محيرًا فقط مع معرفات القواعد.
باستخدام مزيج من __range__، __ ++ __، __ - __ __ أو__ أنا على أمل لإنشاء ملفات قواعد PEG التي تعتمد أقل على قواعد __action__ عن نتائجها، والتي ينبغي زيادة الوقت اللازم لتطوير من بيضاء (على سبيل المثال المسافة البادئة -اللغات المستندة إلى فن ASCII ، إلخ) مثل مصممي اللغة و / أو المنفذين لا داعي للقلق بشأن محاولة تأكيد ما إذا كان قد تم تحليل المقدار الصحيح للمسافات البيضاء.
يجب أن يسمح هذا أيضًا لمطوري المكونات الإضافية بإنشاء مولدات محلل يمكنها التحسين بدون خوف من ماهية لغة __action __ (افتراضيًا ، يمكن لـ JavaScript ، ولكن مع المكون الإضافي يمكن تغييرها إلى CoffeeScript و PHP وما إلى ذلك).
لذلك يبدو أنه لا يزال من غير الممكن اليوم تحليل Python باستخدام PEG.js خارج الصندوق ، هل هذا صحيح؟
إذا لم يكن كذلك ، فهل هذا شيء سيأتي قريبًا؟ هل هناك مجموعة من المهام المطلوبة لإنجاز هذا العمل والتي يمكن أن يساهم بها الناس؟
لدي مشروع حيث أود أن أتمكن من الحصول على Python AST في JS ، وتعديله ثم تحويله مرة أخرى إلى كود المصدر بنفس التنسيق ، لذلك سأكون مهتمًا بتحقيق ذلك إذا كان هناك واضح خريطة الطريق.
mindjuice ليس بعد ، من المخطط نشره بعد 1.0.
إذا كنت لا تستطيع الانتظار ، فقد قمت أنا وابن أخي بإنشاء محلل مكتوب بلغة TypeScript يستخدم نفس بناء الجملة ويتعامل مع المسافة البادئة. لم يتم توثيقها بعد ، لكنها بسيطة جدًا. لا يزال هناك عمل مستمر حيث نستخدمه كمحلل لتصميم لغة جديد.
يمكنك أيضًا تجربة مولد محلل آخر مع دعم مثل 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
التعليق الأكثر فائدة
من الخطير جدًا الاعتماد على الآثار الجانبية التي تضيفها في معالجات مخصصة لتحليل القواعد النحوية القائمة على المسافة البادئة. فقط لا تفعل ذلك. يجب أن تضيف Pegjs بعض القدرة على الدفع وإخراج الحالة الشرطية من أجل جعل المسافات البادئة للتحليل (وغيرها من القواعد النحوية الحساسة للسياق) آمنة.
هذا ما أفعله الآن ، وأوصيك بالقيام بذلك: المعالجة المسبقة لملف الإدخال وإدخال الرموز المميزة الخاصة بك مسافة بادئة / قديمة. أنا أستخدم {{{{و}}}} على التوالي. إذن ، تصبح القواعد النحوية خالية من السياق ويمكن تحليلها بشكل طبيعي. قد يؤدي ذلك إلى إفساد قيم السطر / العمود ، ولكن يمكنك تصحيح تلك الموجودة في المعالج اللاحق.