0

I'm trying to use my_toy_compiler of lsegal https://github.com/lsegal/my_toy_compiler but I get 48 shift/reduce errors errors when I try to "compile" it.

I resolve 24 shift/reduce errors adding this line to the parser.y file:

%left TCEQ TCNE TCLT TCLE TCGT TCGE

But I still get 24 error and I didn't realice how to solve it.

%{
#include "node.h"
    #include <cstdio>
    #include <cstdlib>
NBlock *programBlock; /* the top level root node of our final AST */

extern int yylex();
void yyerror(const char *s) { std::printf("Error: %s\n", s);std::exit(1); }
%}

/* Represents the many different ways we can access our data */
%union {
    Node *node;
    NBlock *block;
    NExpression *expr;
    NStatement *stmt;
    NIdentifier *ident;
    NVariableDeclaration *var_decl;
    std::vector<NVariableDeclaration*> *varvec;
    std::vector<NExpression*> *exprvec;
    std::string *string;
    int token;
}

/* Define our terminal symbols (tokens). This should
   match our tokens.l lex file. We also define the node type
   they represent.
 */
%token <string> TIDENTIFIER TINTEGER TDOUBLE
%token <token> TCEQ TCNE TCLT TCLE TCGT TCGE TEQUAL
%token <token> TLPAREN TRPAREN TLBRACE TRBRACE TCOMMA TDOT
%token <token> TPLUS TMINUS TMUL TDIV
%token <token> TRETURN TEXTERN

/* Define the type of node our nonterminal symbols represent.
   The types refer to the %union declaration above. Ex: when
   we call an ident (defined by union type ident) we are really
   calling an (NIdentifier*). It makes the compiler happy.
 */
%type <ident> ident
%type <expr> numeric expr 
%type <varvec> func_decl_args
%type <exprvec> call_args
%type <block> program stmts block
%type <stmt> stmt var_decl func_decl extern_decl
%type <token> comparison

/* Operator precedence for mathematical operators */
%left TPLUS TMINUS
%left TMUL TDIV
%left TCEQ TCNE TCLT TCLE TCGT TCGE

%start program

%%

program : stmts { programBlock = $1; }
        ;

stmts : stmt { $$ = new NBlock(); $$->statements.push_back($<stmt>1); }
      | stmts stmt { $1->statements.push_back($<stmt>2); }
      ;

stmt : var_decl 
     | func_decl 
     | extern_decl
     | expr { $$ = new NExpressionStatement(*$1); }
     | TRETURN expr { $$ = new NReturnStatement(*$2); }
     ;

block : TLBRACE stmts TRBRACE { $$ = $2; }
      | TLBRACE TRBRACE { $$ = new NBlock(); }
      ;

var_decl : ident ident { $$ = new NVariableDeclaration(*$1, *$2); }
         | ident ident TEQUAL expr { $$ = new NVariableDeclaration(*$1, *$2, $4); }
         ;

extern_decl : TEXTERN ident ident TLPAREN func_decl_args TRPAREN
                { $$ = new NExternDeclaration(*$2, *$3, *$5); delete $5; }
            ;

func_decl : ident ident TLPAREN func_decl_args TRPAREN block 
            { $$ = new NFunctionDeclaration(*$1, *$2, *$4, *$6); delete $4; }
          ;

func_decl_args : /*blank*/  { $$ = new VariableList(); }
          | var_decl { $$ = new VariableList(); $$->push_back($<var_decl>1); }
          | func_decl_args TCOMMA var_decl { $1->push_back($<var_decl>3); }
          ;

ident : TIDENTIFIER { $$ = new NIdentifier(*$1); delete $1; }
      ;

numeric : TINTEGER { $$ = new NInteger(atol($1->c_str())); delete $1; }
        | TDOUBLE { $$ = new NDouble(atof($1->c_str())); delete $1; }
        ;

expr : ident TEQUAL expr { $$ = new NAssignment(*$<ident>1, *$3); }
     | ident TLPAREN call_args TRPAREN { $$ = new NMethodCall(*$1, *$3); delete $3; }
     | ident { $<ident>$ = $1; }
     | numeric
     | expr TMUL expr { $$ = new NBinaryOperator(*$1, $2, *$3); }
     | expr TDIV expr { $$ = new NBinaryOperator(*$1, $2, *$3); }
     | expr TPLUS expr { $$ = new NBinaryOperator(*$1, $2, *$3); }
     | expr TMINUS expr { $$ = new NBinaryOperator(*$1, $2, *$3); }
     | expr comparison expr { $$ = new NBinaryOperator(*$1, $2, *$3); }
     | TLPAREN expr TRPAREN { $$ = $2; }
     ;

call_args : /*blank*/  { $$ = new ExpressionList(); }
          | expr { $$ = new ExpressionList(); $$->push_back($1); }
          | call_args TCOMMA expr  { $1->push_back($3); }
          ;

comparison : TCEQ | TCNE | TCLT | TCLE | TCGT | TCGE;

%%

Hope you can help me!

Brian
  • 3,850
  • 3
  • 21
  • 37
agurodriguez
  • 480
  • 2
  • 6
  • 19
  • That seems like a question you should direct at the author of that code. Although you might be better off seeking a tutorial by someonw who knows how to write grammars. – rici Oct 28 '15 at 00:37

1 Answers1

1

Use the -v option to bison to get a y.output file that summarizes the grammar and all the conflicts. In your case, the conflicts are in a bunch of places, but you can look at each of them in turn. For example, you see:

State 13

   11 var_decl: ident . ident
   12         | ident . ident TEQUAL expr
   14 func_decl: ident . ident TLPAREN func_decl_args TRPAREN block
   21 expr: ident . TEQUAL expr
   22     | ident . TLPAREN call_args TRPAREN
   23     | ident .

    TIDENTIFIER  shift, and go to state 1
    TEQUAL       shift, and go to state 22
    TLPAREN      shift, and go to state 23

    TIDENTIFIER  [reduce using rule 23 (expr)]
    TLPAREN      [reduce using rule 23 (expr)]
    $default     reduce using rule 23 (expr)

    ident  go to state 24

which tells you that when it sees an identifier followed by a TIDENTIFIER or a TLPAREN it doesn't know whether to continue parsing as an expression or a declaration.

In this specific case, its actually an ambiguity caused by the fact that there is no separator in the grammar between stmts in a stmts -- so two consecutive identifiers can be either a var_decl or two exprs. The default resolution of shift will cause it to try to parse it as a declaration, which might be incorrect.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226