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.