بيسون تحول بدلا من تقليل. مع تقليل/تقليل الأخطاء

StackOverflow https://stackoverflow.com/questions/1763243

سؤال

في لغتي يمكنني الكتابة

a = 1

b = 2
if true { } else { }
if true { } **Here is the problem**
else {}

لا يدعم بلدي grammer الخطوط الجديدة بين العبارات. لا يمكن استخدامها إلا مع IF. عندما أضيف اختياري في قاعدتي

IfExpr:
  IF rval optionalNL codeBlock optionalNL ELSE codeBlock
| IF rval optionalNL codeBlock

الاختياري قبل أن يسبب 3 تقليل/تقليل. السبب هو أنه يمكن أن يقلل من استخدام القاعدة الثانية في IFEXPR أو تقليل النطاق حيث يتيح العديد من الخطوط الجديدة بين التعبيرات.

بغض النظر عن ما أقوم به (حاولت كتابة ٪ prect قبل اختياري وإلا) ، فإنه يقلل دائمًا من النمو إلى الحالات التي تعطيني خطأً في Synax. كيف يمكنني أن أخبر بيسون أن يتحول في هذه المرحلة (إلى اختياري آخر) بدلاً من التقليل؟ (إلى Exprolop مما تسبب في أن يكون آخر خطأ).

مثال ملف للاختبار مع

%%
program:
      exprLoop;
exprLoop:
      exprLoop2 expr
    | exprLoop2
exprLoop2:
    | exprLoop2 expr EOS
    | exprLoop2 EOS
    ;   
expr:
      'i' Var optEOS '{' '}'
    | 'i' Var optEOS '{' '}' optEOS 'e' '{' '}'
EOS: '\n'   ;
Var: 'v';
optEOS: | optEOS EOS

%%

//this can be added to the lex file
[iev]                   { return *yytext; }

y.output http://www.pastie.org/707448

بديل. نعم والإخراج. يمكنك أن ترى أنه يتطلع إلى الأمام لرؤية n ولا يعرفون تقليل القاعدة أو الاستمرار. أقوم بتغيير ترتيب القواعد للحصول على نتائج مختلفة. لكنه إما أنه يتوقع دائمًا n أو يتوقع دائمًا أن يتم تجاهل قاعدة واحدة دائمًا. الدولة 15

    9 expr: 'i' Var optEOS '{' '}' .  [$end, '\n']
   10     | 'i' Var optEOS '{' '}' . 'e' '{' '}'
   11     | 'i' Var optEOS '{' '}' . '\n' 'e' '{' '}'

    'e'   shift, and go to state 16
    '\n'  shift, and go to state 17

    '\n'      [reduce using rule 9 (expr)]
    $default  reduce using rule 9 (expr)

بفضل كينوبيكو ل إجابته

لقد غيرت رمزه لعدم وجود صراعات ثم عملت على جعلها أكثر مرونة. هيريس هي ملفاتي

اختبار

%{
#include <stdio.h>
%}

%%

program: expr                                   { printf ("First expr\n"); }
       | program expr                           { printf ("Another expr\n"); }

expr:
      if optEOS                                 { printf ("IF only\n"); }
    | if optEOS else optEOS                     { printf ("IF/ELSE\n"); }

if:   'i' Var optEOS '{' optEOS '}'
else: 'e' optEOS     '{' optEOS '}'
EOS:  '\n'
Var:  'v'
optEOS:
          | EOS optEOS                          { ;}//printf ("many EOS\n"); }
%%

int main(int argc, char **argv)
{
    int i;

    printf("starting\n");

    if(argc < 2) {
        printf("Reading from stdin\n");
        yyparse();
        return 0;
    }
    for(i = 1; i < argc; i++) {
        FILE *f;
        char fn[260];
        sprintf(fn, "./%s", argv[i]);
        f = fopen(fn, "r");
        if(!f) {
            perror(argv[i]);
            return (1);
        }
        printf("Running '%s'\n", argv[i]);
        yyrestart(f);
        yyparse();
        fclose(f);
        printf("done\n");
    }
    return 0;
}

اختبار

%{
#include <stdio.h>
#include "y.tab.h"
%}    
%option noyywrap
%%
[ \t]               { }
\n                  { return *yytext; }
.                   { return *yytext; }
%%
int yyerror ()
{
    printf ("syntax error\n");
    exit (1);
}

ملف اختبار يديره تلقائيًا بعد التجميع

i v { } 
i v { }
e { }
i v { }

e { }
i v { 
} e {
 }
i v { }


i v { } i v { } e { }

i v
{ } i v { } e { } i v { } e { 
} i v {
 } e 
{ }
هل كانت مفيدة؟

المحلول

لا أفهم مشكلتك جيدًا ، لذلك بدأت من الصفر:

هذه هي قواعدتي:

%{
#include <stdio.h>
%}

%%

program: expr                                   { printf ("First expr\n") }
       | program EOS                            { printf ("Ate an EOS\n") }
       | program expr                           { printf ("Another expr\n") }

expr:
      ifeos                                     { printf ("IF only\n"); }
    | ifelse                                    { printf ("IF/ELSE\n"); }

ifelse: ifeos else
      | if else

ifeos: if EOS
     | ifeos EOS

if:   'i' Var optEOS '{' '}'
else: 'e' '{' '}'
EOS:  '\n'
Var:  'v'
optEOS:
          | EOS optEOS                          { printf ("many EOS\n") }
%%

هنا هو lexer:

%{
#include <stdio.h>
#include "1763243.tab.h"
%}    
%option noyywrap
%%
[iev\{\}\n]                  { return *yytext; }
\x20                         { }
%%
int yyerror ()
{
    printf ("syntax error\n");
    exit (1);
}
int main () {
    yyparse ();
}

هنا بعض إدخال الاختبار:

i v { } 
i v { }
e { }
i v { }

e { }
i v { } e { }
i v { }

ها هو الإخراج:

IF only
First expr
IF/ELSE
Another expr
Ate an EOS
IF/ELSE
Another expr
Ate an EOS
IF/ELSE
Another expr
Ate an EOS
IF only
Another expr

هناك تحول/تقليل الصراع متبقي.

نصائح أخرى

وفقًا لـ "LEX & YACC" ، فإن الدقة الافتراضية لتقليل/تقليل هي القاعدة المحددة الأولى ، لذلك كما تقول إن Exproplop يفوز ، لذلك سأفترض أنه يتم تعريفه أولاً.

لكن تبديل الطلب قد لا يحل المشكلة التي تتوقعها.

مزيد من القراءة (صفحة 237) يبدو أنك بحاجة إلى مزيد من البحث ، وهو ليس خيارًا لـ YACC/Bison القياسي. لكن بيسون لديه ملف GLR الوضع, والتي قد تكون مفيدة.

شيء واحد يمكنك القيام به هو تحليل الخطوط الجديدة تمامًا باستخدام قاعدة LEX لهم. بهذه الطريقة ، لا يهم أين توجد الخطوط الجديدة. هذا ما يفعله C/C ++ ... يتم تجاهل الخطوط الجديدة إلى حد كبير.

المشكلة هي:

IfExpr:
  IF rval optionalNL codeBlock optionalNL ELSE codeBlock
| IF rval optionalNL codeBlock

يتطلب lookahead اثنين بعد أن يرى CodeBlock "آخر" بعد السطر الجديد إذا كان هذا هو ما هو موجود. يمكنك تجنب ذلك عن طريق تكرار الاختياري في كلا القاعدتين:

IfExpr:
  IF rval optionalNL codeBlock optionalNL ELSE codeBlock
| IF rval optionalNL codeBlock optionalNL

الآن ، لا يتعين على المحلل أن يقرر بين القاعدتين حتى بعد تحليل الاختياري ، مما يتيح له رؤية آخر (أو عدم وجوده) في Lookahead الواحد.

عيب محتمل هنا هو أن القاعدة الثانية (ولكن ليس الأولى) ستستوعب الآن أي خطوط جديدة متأخرة ، لذلك إذا كانت القواعد الخاصة بك للبرامج تتطلب خطًا جديدًا بين كل عبارة ، فلن يجد واحدة بعد IFS بدون Elses و It بالفعل مستهلك.

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