Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

can't make work multiple assignments in bison/flex

Hi everyone I'm trying to learn bison. I found on github an simple working expression parser, that can do the following:

  • assignments (like a = 34; b = a;)

  • printing (like print a;)

  • exiting (type exit; and it will terminate)

I think to understand how the the basic rules work. So I've tried to modify the rules to make possible doing multiple assignments (like this one : a = b = c = 5;).

To do so, I add a new line rule that works like this:

line    : assegn ';'        {;}
            | exit_command ';'      {exit(EXIT_SUCCESS);}
            | print exp ';'         {printf("Printing %d\n", $2);}
          | line assignment ';' {;}
            | line print exp ';'    {printf("Printing %d\n", $3);}
            | line exit_command ';' {exit(EXIT_SUCCESS);}
          ;

then I added the following new rules

assegn : assignment {;}
        | identifiers {;}
            ;

identifiers : assignment {$$=$1;}
        | identifier '=' identifiers {updateSymbolVal($1,$3);}
            ;

and assignment works like this

assignment : identifier '=' exp  {$$=$3; updateSymbolVal($1,$3); }
                ;

In the end I was able to compile files generate by bison and flex, but when I try to make multiple assignment it returns me syntax error.

Can somebody explain me,where I commit an error, please? This is the original example I started from. https://github.com/jengelsma/yacc-tutorial.git

This is the code of my bison file:

%{
void yyerror (char *s);
#include <stdio.h>     /* C declarations used in actions */
#include <stdlib.h>
int symbols[52];
int symbolVal(char symbol);
void updateSymbolVal(char symbol, int val);
int val;
%}

%union {int num; char id;}         /* Yacc definitions */
%start line
%token print
%token exit_command
%token <num> number
%token <id> identifier
%type <num> line exp term
%type <id> assignment
%type <num> identifiers

%%
/*the original line was line : assignment ';'  {;}*/
line    : assegn ';'        {;}
        | exit_command ';'      {exit(EXIT_SUCCESS);}
        | print exp ';'         {printf("Printing %d\n", $2);}
      | line assignment ';' {;}
        | line print exp ';'    {printf("Printing %d\n", $3);}
        | line exit_command ';' {exit(EXIT_SUCCESS);}
      ;

assegn : assignment {;}
        | identifiers {;}
            ;

identifiers : assignment {$$=$1;}
        | identifier '=' identifiers {updateSymbolVal($1,$3);}
            ;


assignment : identifier '=' exp  {$$=$3; updateSymbolVal($1,$3); }
            ;
exp     : term                  {$$ = $1;}
        | exp '+' term          {$$ = $1 + $3;}
        | exp '-' term          {$$ = $1 - $3;}
        ;
term    : number                {$$ = $1;}
        | identifier            {$$ = symbolVal($1);}
      ;

%%                     /* C code */

int computeSymbolIndex(char token)
{
    int idx = -1;
    if(islower(token)) {
        idx = token - 'a' + 26;
    } else if(isupper(token)) {
        idx = token - 'A';
    }
    return idx;
}

/* returns the value of a given symbol */
int symbolVal(char symbol)
{
    int bucket = computeSymbolIndex(symbol);
    return symbols[bucket];
}

/* updates the value of a given symbol */
void updateSymbolVal(char symbol, int val)
{
    int bucket = computeSymbolIndex(symbol);
    symbols[bucket] = val;
}

int main (void) {
    /* init symbol table */
    int i;
    for(i=0; i<52; i++) {
        symbols[i] = 0;
    }

    return yyparse ( );
}

void yyerror (char *s) {fprintf (stderr, "%s\n", s);}

this is my flex file:

%{
#include "exppars.tab.h"
%}
%%
"print"                            {return print;}
"exit"                             {return exit_command;}
[a-zA-Z]                           {yylval.id = yytext[0]; return identifier;}
[0-9]+                 {yylval.num = atoi(yytext); return number;}
[ \t\n]                ;
[-+=;]                     {return yytext[0];}
.                      {ECHO; yyerror ("unexpected character");}

%%
int yywrap (void) {return 1;}
like image 653
Kostyuk Rostyslav Avatar asked Jan 21 '26 12:01

Kostyuk Rostyslav


1 Answers

Ok it looks like I have found a kind of answer.

  • I notice that the syntax error appears only when I'm trying to do multiple assignment in the after the first input.

to solve this one I added a new rule. Now rules block looks like this:

line    : assegn ';'        {;}
    | exit_command ';'      {exit(EXIT_SUCCESS);}
    | print exp ';'         {printf("Printing %d\n", $2);}
    | line assegn ';'   {;}
    | line print exp ';'    {printf("Printing %d\n", $3);}
    | line exit_command ';' {exit(EXIT_SUCCESS);}
  ;
  • the next problem appeared when I tried to do long multiple assignment, like this one for example : a = b = c = d = 5;. I just assign the value to c and d, not to the others. It seems like the code { $$ = $1} didn't work as I have expected. So I add a new int variable to store the value of last assignment. The production rules now look like this:

    identifiers : assignment { val = $1;}
        | identifier '=' identifiers {updateSymbolVal($1,val);}
        ;
    assignment : identifier '=' exp  {$$=$3; updateSymbolVal($1,$3);}
        ;
    exp     : term                  { $$ = $1; @1;}
        | exp '+' term          { $$ = $1 + $3; }
        | exp '-' term          { $$ = $1 - $3; }
        ;
    term    : number                {$$ = $1;}
        | identifier            {$$ = symbolVal($1);}
      ;
    

Now it's work.

like image 186
Kostyuk Rostyslav Avatar answered Jan 23 '26 02:01

Kostyuk Rostyslav



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!