سؤال
أواجه مشكلة في فهم تضارب التحول/التقليل لقواعد النحو التي أعرف أنها لا تحتوي على أي غموض.الحالة هي واحدة من النوع if else ولكنها ليست مشكلة "dangling else" نظرًا لأن لدي عبارات END إلزامية تحدد كتل التعليمات البرمجية.
فيما يلي القواعد النحوية لـ gppg (إنه مترجم مترجم مثل Bison ...وما كان ذلك صدى):
%output=program.cs
%start program
%token FOR
%token END
%token THINGS
%token WHILE
%token SET
%token IF
%token ELSEIF
%token ELSE
%%
program : statements
;
statements : /*empty */
| statements stmt
;
stmt : flow
| THINGS
;
flow : '#' IF '(' ')' statements else
;
else : '#' END
| '#' ELSE statements '#' END
| elseifs
;
elseifs : elseifs '#' ELSEIF statements else
| '#' ELSEIF statements else
;
هنا هو إخراج الصراع:
// Parser Conflict Information for grammar file "program.y"
Shift/Reduce conflict on symbol "'#'", parser will shift
Reduce 10: else -> elseifs
Shift "'#'": State-22 -> State-23
Items for From-state State 22
10 else: elseifs .
-lookahead: '#', THINGS, EOF
11 elseifs: elseifs . '#' ELSEIF statements else
Items for Next-state State 23
11 elseifs: elseifs '#' . ELSEIF statements else
// End conflict information for parser
لقد قمت بالفعل بالتبديل حول كل شيء، وأنا أعرف كيفية حلها، ولكن هذا الحل يتضمن التخلي عن العودية اليسرى على "elseif" من أجل العودية الصحيحة.
لقد قمت بمراجعة جميع الوثائق النادرة التي وجدتها على الإنترنت فيما يتعلق بهذه المشكلة (أقوم بنشر بعض الروابط في النهاية) وما زلت لم أجد حلاً أنيقًا.أعرف شيئًا عن ANTLR ولا أريد أن أفكر فيه الآن.يرجى قصر الحل الخاص بك على موزعي Yacc/Bison.
سأكون ممتنًا للحلول الأنيقة، فقد تمكنت من القيام بذلك عن طريق حذف قواعد /* فارغة */ وتكرار كل ما يحتاج إلى قائمة فارغة ولكن في القواعد النحوية الأكبر التي أعمل عليها، ينتهي الأمر مثل "متلازمة قواعد سبارغيتي".
وهنا بعض الروابط:
http://nitsan.org/~maratb/cs164/bison.html
المحلول
ولديك حكم ELSEIF المنقحة لا يوجد لديه علامات لحالة - يجب أن يكون اسميا '(' و ')' وأضاف
والأخطر من ذلك، لديك الآن قاعدة ل
elsebody : else
| elseifs else
;
و
elseifs : /* Nothing */
| elseifs ...something...
;
لا حاجة إلى "لا شيء". انها اتخذت ضمنا الرعاية من قبل "elsebody 'دون' elseifs".
وسأكون يميل جدا للاستخدام "opt_elseifs" قواعد "، opt_else '، و' نهاية ':
flow : '#' IF '(' ')' statements opt_elseifs opt_else end
;
opt_elseifs : /* Nothing */
| opt_elseifs '#' ELSIF '(' ')' statements
;
opt_else : /* Nothing */
| '#' ELSE statements
;
end : '#' END
;
ولقد تقم بتشغيل هذا من خلال مولد محلل، ولكن أجد هذا من السهل نسبيا لفهم.
نصائح أخرى
وأعتقد أن المشكلة هي في بند elseifs.
elseifs : elseifs '#' ELSEIF statements else
| '#' ELSEIF statements else
;
لا أعتقد ذلك مطلوب النسخة الأولى، لأن شرط آخر يشير إلى elseifs على أي حال:
else : '#' END
| '#' ELSE statements '#' END
| elseifs
;
وماذا يحدث إذا قمت بتغيير elseifs:؟
elseifs : '#' ELSEIF statements else
;
والجواب من جوناثان فوق يبدو وكأنه سيكون أفضل، ولكن منذ وليس للعمل معك لدي بعض الاقتراحات التي يمكن أن تحاول أن تساعدك في تصحيح الخطأ.
أولا هل تعتبر صناعة التجزئة / رمز حاد جزء من الرموز نفسها (أي #END، #IF، الخ)؟ بحيث الحصول على اتخاذها من قبل lexer، وهذا يعني أنها لم يكن لديك ليتم تضمينها في المحلل.
وثانيا أود أن أحثكم على إعادة كتابة قواعد دون تكرار أي تيارات رمزية. (جزء من مبدأ لا تكرر نفسك.) لذلك قاعدة " '#' البيانات ELSEIF آخر" يجب أن توجد إلا في مكان واحد في هذا الملف (وليس اثنين كما كان لديك أعلاه).
وأخيرا أقترح عليك أن تنظر في الأسبقية وترابطيات من الرموز / ELSEIF / ELSE IF. وأنا أعلم أنه يجب أن تكون قادرا على كتابة محلل التي لا تتطلب هذا ولكن قد يكون الشيء الذي تحتاجه في هذه الحالة.
ما زلت أقوم بتبديل الأشياء، وكان سؤالي الأصلي يحتوي على بعض الأخطاء منذ com.elseifs كان للتسلسل آخر دائما في النهاية والذي كان خطأ.إليك نظرة أخرى على السؤال، هذه المرة أحصل على تضاربين في التحول/التقليل:
flow : '#' IF '(' ')' statements elsebody
;
elsebody : else
| elseifs else
;
else : '#' ELSE statements '#' END
| '#' END
;
elseifs : /* empty */
| elseifs '#' ELSEIF statements
;
الصراعات الآن هي:
// Parser Conflict Information for grammar file "program.y"
Shift/Reduce conflict on symbol "'#'", parser will shift
Reduce 12: elseifs -> /* empty */
Shift "'#'": State-10 -> State-13
Items for From-state State 10
7 flow: '#' IF '(' ')' statements . elsebody
4 statements: statements . stmt
Items for Next-state State 13
10 else: '#' . ELSE statements '#' END
11 else: '#' . END
7 flow: '#' . IF '(' ')' statements elsebody
Shift/Reduce conflict on symbol "'#'", parser will shift
Reduce 13: elseifs -> elseifs, '#', ELSEIF, statements
Shift "'#'": State-24 -> State-6
Items for From-state State 24
13 elseifs: elseifs '#' ELSEIF statements .
-lookahead: '#'
4 statements: statements . stmt
Items for Next-state State 6
7 flow: '#' . IF '(' ')' statements elsebody
// End conflict information for parser
القواعد الفارغة تؤدي فقط إلى تفاقم gppg وأنا خائف.لكن يبدو أنها طبيعية جدًا للاستخدام، وأستمر في تجربتها.
أعلم بالفعل أن العودية الصحيحة تحل المشكلة 1800 معلومة قال.لكني أبحث عن حل مع العودية اليسرى على ال شرط elseifs.
elsebody : elseifs else
| elseifs
;
elseifs : /* empty */
| elseifs '#' ELSEIF statements
;
else : '#' ELSE statements '#' END
;
وأعتقد أن هذا ينبغي ترك عنة ودائما إنهاء.
وOK - هنا هو نحوي (لا الحد الأدنى) لأنه إذا كتل. أنا حفرت عليه للخروج من بعض الرموز لقد (وتسمى مخصصا، على أساس الغرض من كيرنيغان وPlauger و"إن بيئة البرمجة UNIX"). هذه القواعد مخطط يجمع مع ياك مع أي تعارض.
%token NUMBER IF ELSE
%token ELIF END
%token THEN
%start program
%%
program
: stmtlist
;
stmtlist
: /* Nothing */
| stmtlist stmt
;
stmt
: ifstmt
;
ifstmt
: ifcond endif
| ifcond else begin
| ifcond eliflist begin
;
ifcond
: ifstart cond then stmtlist
;
ifstart
: IF
;
cond
: '(' expr ')'
;
then
: /* Nothing */
| THEN
;
endif
: END IF begin
;
else
: ELSE stmtlist END IF
;
eliflist
: elifblock
| elifcond eliflist begin /* RIGHT RECURSION */
;
elifblock
: elifcond else begin
| elifcond endif
;
elifcond
: elif cond then stmtlist end
;
elif
: ELIF
;
begin
: /* Nothing */
;
end
: /* Nothing */
;
expr
: NUMBER
;
%%
وكنت 'رقم' باعتبارها العنصر وهمية، بدلا من الأشياء، وكنت ELIF بدلا من ELSEIF. ويتضمن ذلك الحين، ولكن هذا هو اختياري. و'تبدأ "، وكانت تستخدم عمليات" نهاية "للاستيلاء على عداد البرنامج في البرنامج ولدت - وبالتالي يجب أن تكون قابلة للنقل من هذا دون أن يؤثر ذلك
.وكان هناك سبب وأعتقد أنني بحاجة إلى استخدام العودية اليمنى بدلا من اليسرى العودية العادية - ولكن أعتقد أنه كان على علاقة مع استراتيجية رمز جيل كنت تستخدم، وليس أي شيء آخر. كانت علامة الاستفهام في التعليق في النص الأصلي. أتذكر لا يجري سعيدة معه. البرنامج ككل لا عمل - هو مشروع وهذا ما كان على الموقد الخلفي على مدى العقد الماضي أو نحو ذلك (هممم ... فعلت بعض العمل في نهاية عام 2004 وبداية عام 2005، وقبل ذلك، كان 1992 و 1993).
وأنا لم أمضى الوقت في العمل لماذا هذا يجمع خالية من الصراعات وما أشرت في وقت سابق لا. وآمل أن يساعد.