Ваша основная проблема в том, что вы пытаетесь включить свой лексер в свой парсер. То, что вы (по крайней мере, обычно) хотите сделать, - это чтобы yacc (bison, если вам нужно) генерировал заголовок (y.tab.h), используя yacc -d
, и включал его в свой лексер.
Начало лексера:
%{
#include "y.tab.h"
int yylinenu= 1;
int yycolno= 1;
%}
// ...
Поскольку ваш синтаксический анализатор ссылается на переменные, определенные выше, вы затем объявите, чем в исходном файле вашего синтаксического анализатора:
extern int yylinenu;
extern int yycolno;
Ваши main()
и error()
также были немного беспорядочными (ваш main()
выглядит так, как будто вы, вероятно, играли, пытаясь выяснить, что происходит ...).
void yyerror(char *msg)
{
printf("Line: %d , Column: %d : %s \n", yylinenu, yycolno, msg);
}
int main(int argc, char *argv[])
{
return yyparse();
}
Кроме этого, в вашей грамматике есть мелкая деталь или две, которые, я уверен, не совсем то, что вы действительно хотели. Например:
|WHILE LINKEKLAMMER Cond RECHTEKLAMMER Stmt
{puts("\t\tStmt : 'PRINTF' Expr ';'");}
|PRINTF Expr SEMIKOLON
{puts("\t\tStmt : 'PRINTF' Expr ';'");}
Предположительно, когда вы выбрали "while", которое хотите распечатать "while", а не "printf":
|WHILE LINKEKLAMMER Cond RECHTEKLAMMER Stmt
{puts("\t\tStmt : 'WHILE' Expr ';'");}
Аналогично, в:
|IF LINKEKLAMMER Cond RECHTEKLAMMER Stmt
{puts("\t\tStmt : '(' Cond ')' Stmt");}
|IF LINKEKLAMMER Cond RECHTEKLAMMER Stmt ELSE Stmt
{puts("\t\tStmt : '(' Cond ')' Stmt 'ELSE' Stmt");}
Полагаю, вы, возможно, захотите распечатать в начале каждого слова "если":
|IF LINKEKLAMMER Cond RECHTEKLAMMER Stmt
{puts("\t\tStmt : 'IF' '(' Cond ')' Stmt");}
|IF LINKEKLAMMER Cond RECHTEKLAMMER Stmt ELSE Stmt
{puts("\t\tStmt : 'IF' '(' Cond ')' Stmt 'ELSE' Stmt");}
В качестве заключительного замечания я бы предложил некоторые отступы и пустые строки, чтобы ваши правила грамматики были изложены примерно так:
Term:Factor {puts("\t\tTerm : Factor");}
| Factor MAL Term {puts("\t\tTerm : Factor '*' Term");}
| Factor SLASH Term {puts("\t\tTerm : Factor '/' Term");}
;
Factor:SimpleExpr {puts("\t\tFactor : SimpleExpr");}
| MINUS SimpleExpr {puts("\t\tFactor : '-' SimpleExpr");}
;
Конечно, вы можете изменять это, например, помещать действия в отдельные строки (особенно если они длинные), но общая идея остается прежней. Вы не должны действительно нуждаться в комментариях, чтобы сказать, где заканчивается одно правило и начинается другое - форматирование может сделать это очевидным.
Редактировать: я забыл упомянуть еще один момент: при использовании синтаксического анализатора снизу вверх (например, bison / yacc / byacc generate) рекурсия слева предпочтительнее, чем рекурсия вправо, поэтому вы обычно предпочитаете изменить это:
Stmts : Stmt {puts("\t\tStmts : Stmt");}
| Stmt Stmts {puts("\t\tStmts : Stmt Stmts");}
;
Кому:
Stmts : Stmt {puts("\t\tStmts : Stmt");}
| Stmts Stmt {puts("\t\tStmts : Stmts Stmt");}
;