سؤال

أواجه مشكلة في فهم تضارب التحول/التقليل لقواعد النحو التي أعرف أنها لا تحتوي على أي غموض.الحالة هي واحدة من النوع 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

http://compilers.iecc.com/comparch/article/98-01-079

GPPG، المحلل الذي أستخدمه

دليل البيسون

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

المحلول

ولديك حكم 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).

وأنا لم أمضى الوقت في العمل لماذا هذا يجمع خالية من الصراعات وما أشرت في وقت سابق لا. وآمل أن يساعد.

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