Question

Dans ma langue, je peux écrire

a = 1

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

Mon Grammer ne marche pas entre les déclarations de soutien des sauts de ligne. Un autre ne peut être utilisé avec un si. Quand j'ajoute optionalNL dans ma règle

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

Le optionalNL avant les causes 3 autres réduire / réduire. La raison est qu'il peut réduire l'utilisation de la 2ème règle IfExpr ou réduire à exprLoop où il permet à plusieurs nouvelles lignes entre les expressions.

Peu importe ce que je fais (j'ai essayé d'écrire% prec avant optionalNL et ELSE) il réduit toujours exprLoop quels cas bisons pour me donner une erreur SYNAX sur autre. Comment puis-je dire le bison de passer à ce point (à optionalNL autre) au lieu de réduire? (À exprLoop causant autre à une erreur).

fichier exemple pour tester avec

%%
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; }

http://www.pastie.org/707448

.y et de sortie alternative. Vous pouvez le voir en regardant voir avant un \ n et ne marche pas savoir pour réduire la règle ou continuer. Je change de modifier l'ordre des règles pour obtenir des résultats différents. Mais il attend toujours soit un \ n ou attend toujours une autre ainsi une règle finissent toujours par être ignorer.     état 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)

Merci à Kinopiko pour sa réponse

Je changé son code à aucun conflit alors travaillé à le rendre plus flexible. Heres mes fichiers

test.y

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

test.y

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

un fichier de test automatique a couru après la compilation

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 
{ }
Était-ce utile?

La solution

Je ne comprends pas très bien votre problème, alors j'ai commencé à partir de zéro:

Ceci est ma grammaire:

%{
#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") }
%%

Voici le 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 ();
}

Voici quelques entrées de test:

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

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

Voici la sortie:

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

Il y a un / réduire les conflits restants.

Autres conseils

Selon Lex & Yacc la résolution par défaut de la réduire / réduire est la première règle définie, de sorte que vous dites la exprLoop gagne, alors je suppose qu'il se définit d'abord.

Mais la commutation de l'ordre ne peut pas résoudre le problème que vous attendez.

Pour en savoir plus (page 237), il semble que vous avez besoin de plus regarder vers l'avenir, ce qui est pas une option pour yacc / bison standard. Mais Bison a un GLR Mode , ce qui peut être utile.

Une chose que vous pouvez faire est d'analyser à l'aide d'une complètement nouvelles lignes règle de la lex pour eux. De cette façon, peu importe où les nouvelles lignes sont. C'est ce que C / C ++ ne ... nouvelles lignes sont largement ignorées.

Le problème est que:

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

nécessite deux jetons préanalyse après la codeblock pour voir le « autre » après le saut de ligne si c'est ce qu'il y a. Vous pouvez éviter cela en dupliquant le optionalNL dans les deux cas des règles:

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

Maintenant, l'analyseur ne doit pas décider entre les deux règles jusqu'à ce que le optionalNL est analysé, laissant voir le ELSE (ou son absence) dans le préanalyse un jeton.

Un inconvénient potentiel est que la deuxième règle si (mais pas la première) va maintenant absorber les sauts de lignes, donc si votre grammaire pour les programmes nécessite une nouvelle ligne entre chaque déclaration, il ne trouvera pas un après ifs sans elses et son déjà été consommée.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top