Why is Lex/Yacc throwing a syntax error while parsing?

Viewed 47

I'm new to Lex and Yacc and learning it for myself. I want to build a parser for Python code and am currently just trying to get Yacc under my fingers by getting it to fully parse the following code inputted as a text file (titled config.in).

def bubblesort(list):
    for i in range(len(list)):
        for j in range(i+1,len(list)):
            if list[i] > list[j]:
                t = list[i]
                list[i] = list[j]
                list[j] = t

    print(list)

list = [34,45,14,24,19]
bubblesort(list)

The problem is that Yacc throws a syntax error once it encounters text beyond for in the second line.

Here's my Lex program:

%{
    #include "y.tab.h"
%}

%option nounput yylineno

%%

"+"                 { return '+';       }
"-"                 { return '-';       }
"*"                 { return '*';       }
"/"                 { return '/';       }
"%"                 { return '%';       }
"["                 { return LBRACE;    }
"]"                 { return RBRACE;    }
"("                 { return LPAREN;    }
")"                 { return RPAREN;    }
","                 { return COMMA;     }
"."                 { return PERIOD;    }
":"                 { return COLON;     }
":="                { return WALRUS;    }
"="                 { return ASSIGN;    }
"=="                { return EQL;       }
"!="                { return NEQ;       }
"<"                 { return LSS;       }
">"                 { return GTR;       }
"<="                { return LEQ;       }
">="                { return GEQ;       }
"#"                 { return COMMENT1;  }
\"{3}               { return COMMENT2;  }

"True"              { return TRUE;      }             
"False"             { return FALSE;     }
"class"             { return CLASS;     }
"def"               { return DEF;       }
"return"            { return RETURN;    }
"if"                { return IF;        }
"elif"              { return ELIF;      }
"else"              { return ELSE;      }
"try"               { return TRY;       }
"except"            { return EXCEPT;    }
"raise"             { return RAISE;     }
"finally"           { return FINALLY;   }
"for"               { return FOR;       }
"in"                { return IN;        }
"is"                { return IS;        }
"not"               { return NOT;       }
"from"              { return FROM;      }
"import"            { return IMPORT;    }
"global"            { return GLOBAL;    }
"lambda"            { return LAMBDA;    }
"nonlocal"          { return NONLOCAL;  }
"pass"              { return PASS;      }
"while"             { return WHILE;     }
"break"             { return BREAK;     }
"continue"          { return CONTINUE;  } 
"and"               { return AND;       }
"with"              { return WITH;      }
"as"                { return AS;        }
"yield"             { return YIELD;     }
"del"               { return DEL;       }
"or"                { return OR;        }
"assert"            { return ASSERT;    }
"None"              { return NONE;      }

"print"             { return PRINT;     }
"abs"               { return ABS;       }
"all"               { return ALL;       }
"any"               { return ANY;       }
"range"             { return RANGE;     }
"len"               { return LEN;       }

[\n]+               { ; }
[\t]+               { return TAB;       }
[ ]                 { ; }
.                   { printf("UnexpChar\n"); }
            
[a-zA-Z][_a-zA-Z0-9]*   { yylval.id = yytext[0]; return IDENTIFIER; }
[0-9]+               { yylval.num = atoi(yytext); return INTEGER;  }

%%

int yywrap(void)
{
    return 1;
}

Here's my Yacc program:

%{
    #include <stdio.h>

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

%union {
    int num; 
    char id;
} 

%left '+' '-' '*' '/' '%'

%token <id> TRUE
%token <id> FALSE
%token <id> CLASS
%token <id> DEF
%token <id> RETURN
%token <id> IF
%token <id> ELIF
%token <id> ELSE
%token <id> TRY
%token <id> EXCEPT
%token <id> RAISE
%token <id> FINALLY
%token <id> FOR
%token <id> IN
%token <id> IS
%token <id> NOT
%token <id> FROM
%token <id> IMPORT
%token <id> GLOBAL
%token <id> LAMBDA
%token <id> NONLOCAL
%token <id> PASS
%token <id> WHILE
%token <id> BREAK
%token <id> CONTINUE
%token <id> AND
%token <id> WITH
%token <id> AS
%token <id> YIELD
%token <id> DEL
%token <id> OR
%token <id> ASSERT
%token <id> NONE

%token <id> LBRACE
%token <id> RBRACE
%token <id> LPAREN
%token <id> RPAREN
%token <id> COMMA
%token <id> WALRUS
%token <id> EQL
%token <id> NEQ
%token <id> LSS
%token <id> GTR
%token <id> LEQ
%token <id> GEQ
%token <id> ASSIGN

%token <id> COLON
%token <id> TAB
%token <id> NEWLINE
%token <id> PERIOD
%token <id> COMMENT1
%token <id> COMMENT2

%token <id> PRINT
%token <id> ABS
%token <id> ALL
%token <id> ANY
%token <id> RANGE
%token <id> LEN

%token <num> INTEGER
%token <id> IDENTIFIER

%type <id> funcDef
%type <id> parameter
%type <id> BIFunc //Built-In Function
%type <id> rangeFunc lenFunc
%type <id> forLoopDef forLoopBody

%%

code        : funcDef
            | forLoopDef
            | forLoopBody
            | BIFunc
            ;
funcDef     : DEF IDENTIFIER LPAREN parameter RPAREN COLON
            ;
forLoopDef  : FOR IDENTIFIER IN rangeFunc LPAREN parameter RPAREN COLON 
            ;
forLoopBody : forLoopDef code
            ;
parameter   : IDENTIFIER
            | BIFunc
            ;
BIFunc      : rangeFunc
            | lenFunc
            ;
rangeFunc   : RANGE LPAREN parameter RPAREN COLON //stop
            | RANGE LPAREN parameter COMMA parameter RPAREN COLON //start, stop
            | RANGE LPAREN parameter COMMA parameter COMMA parameter RPAREN COLON //start, stop, step
            ;
lenFunc     : LEN LPAREN parameter RPAREN
            ;
            
%%

int main(void)
{
    yyparse();
}

I've done the following to see Yacc's process (I've also looked at the state machine but that didn't help):

lex -d lexer.l

yacc --debug --verbose parser.y

gcc -ll lex.yy.c y.tab.c

./a.out <config.in

Which gives:

--(end of buffer or a NUL)
--accepting rule at line 36 ("def")
--accepting rule at line 76 (" ")
--accepting rule at line 79 ("bubblesort")
--accepting rule at line 17 ("(")
--accepting rule at line 79 ("list")
--accepting rule at line 18 (")")
--accepting rule at line 21 (":")
--accepting rule at line 74 ("
")
def bubblesort(list):
--accepting rule at line 76 (" ")
--accepting rule at line 76 (" ")
--accepting rule at line 76 (" ")
--accepting rule at line 76 (" ")
--accepting rule at line 45 ("for")
syntax error
    for%   

I can't figure out why Lex/Yacc is throwing the syntax error. I assume the issue is with the identifier i but I'm just not sure how to fix it. i should just get returned by Lex as an IDENTIFIER, just as list did. I'm also aware of the multitude of unused tokens being returned—I wrote them in since I plan on eventually using them.

I appreciate any help I can get.

0 Answers
Related