зубров сдвинуть вместо сокращения.С ошибками уменьшения/сокращения

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

Вопрос

На моем языке я могу написать

a = 1

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

Мой грамматик не поддерживает переводы строк между операторами.else можно использовать только с if.Когда я добавляю optionNL в свое правило

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

НеобязательныйNL перед else вызывает 3 сокращения/сокращения.Причина в том, что его можно сократить, используя второе правило в IfExpr, или сократить до exprLoop, где допускается использование большого количества новых строк между выражениями.

Независимо от того, что я делаю (я пытался написать %prec перед опциональнымNL и ELSE), это всегда сводится к exprLoop, в котором bison выдает мне ошибку Synax в else.Как мне сказать Bison, чтобы он переключился в этот момент (на optionNL else) вместо уменьшения?(чтобы exprLoop вызвал ошибку else).

пример файла для тестирования

%%
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.выход http://www.pastie.org/707448

Альтернативный .y и вывод.Вы можете видеть, что он смотрит вперед, видит и не знает, нужно ли уменьшить правило или продолжать.Я меняю порядок правил, чтобы получить разные результаты.Но он либо всегда ожидает , либо всегда ожидает else, поэтому одно правило всегда игнорируется.штат 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") }
%%

Вот лексер:

%{
#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

Eсть сдвиг/уменьшение конфликта оставшийся.

Другие советы

Согласно «Lex & Yacc», разрешение сокращения/сокращения по умолчанию является первым определенным правилом, поэтому, как вы говорите, побеждает exprLoop, поэтому я предполагаю, что оно определено первым.

Но изменение порядка может не решить проблему так, как вы ожидаете.

При дальнейшем чтении (стр. 237) оказывается, что вам нужно больше смотреть вперед, что невозможно для стандартного yacc/bison.Но у Бизона есть ГЛР режим, что может пригодиться.

Единственное, что вы можете сделать, — это полностью проанализировать символы новой строки, используя для них правило lex.Таким образом, не имеет значения, где находятся новые строки.Это то, что делает C/C++...символы новой строки в основном игнорируются.

Проблема в том, что:

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

требует просмотра двух токенов после кодового блока, чтобы увидеть «еще» после новой строки, если это то, что есть.Этого можно избежать, продублировав опциональныйNL в обоих правилах if:

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

Теперь анализатору не нужно выбирать между двумя правилами до тех пор, пока не будет проанализирован необязательныйNL, что позволит ему увидеть ELSE (или его отсутствие) в предпросмотре с одним токеном.

Потенциальным недостатком здесь является то, что второе правило if (но не первое) теперь будет поглощать любые конечные символы новой строки, поэтому, если ваша грамматика для программ требует новой строки между каждым оператором, она не найдет ни одной после if без elses, и она уже была. потребляется.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top