我试图在lex和yacc的帮助下制作一个迷你c编译器
以下是yacc / bison代码:
%{
#include <stdio.h>
#include <stdlib.h>
extern FILE *fp;
extern int line;
extern int yylex();
int yyerror(char *);
%}
%token FOR WHILE IF ELSE PRINTF NUM ID STR ROP LOG INC RETURN STRUCT INT FLOAT CHAR DOUBLE VOID LT GT LE GE NE EQ
%right '='
%left LOG
%left AND OR
%left LT GT LE GE NE EQ
%left '+' '-'
%left '*' '/' '%'
%left INC
%nonassoc XYZ
%nonassoc ELSE
%%
start: Function start
| Declaration start
|
;
Declaration: Type Ass ';'
| Ass ';'
| Type Arr ';'
| Arr ';'
| StructStmt ';'
| FunctionCall ';'
;
Ass: ID1 '=' Ass
| ID1 '=' FunctionCall
| ID1 '=' Arr
| Arr '=' Ass
| ID1 ',' Ass
| NUM ',' Ass
| ID1 '+' Ass
| ID1 '-' Ass
| ID1 '*' Ass
| ID1 '/' Ass
| ID1 '%' Ass
| NUM '+' Ass
| NUM '-' Ass
| NUM '*' Ass
| NUM '/' Ass
| NUM '%' Ass
| RETURN Ass
| '\'' Ass '\''
| '\"' Ass '\"'
| '(' Ass ')'
| '-' ID1
| '-' NUM
| INC ID1
| ID1 INC
| INC NUM
| NUM INC
| ID1
| NUM
;
ID1: ID
;
FunctionCall: ID1 '(' Ass ')'
| ID1 '(' ')'
;
Function: Type ID1 '(' ArgListOpt ')' Stmt
;
ArgListOpt: ArgList Arg
|
;
ArgList: ArgList ',' Arg
| Arg
;
Arg: Type ID1
;
CompoundStmt: '{' StmtList '}'
;
StmtList: StmtList Stmt
|
;
Stmt: WhileStmt
| ForStmt
| IfStmt
| CompoundStmt
| Declaration
| PrintFunc
| ';'
;
PrintFunc: PRINTF '(' STR ',' Ass ')' ';'
| PRINTF '(' STR ')' ';'
;
WhileStmt: WHILE '(' Expr ')' Stmt
;
ForStmt: FOR '(' Expr1 ';' Expr1 ';' Expr1 ')' Stmt
;
Expr1: Expr
|
;
IfStmt: IF '(' Expr ')' Stmt %prec XYZ
| IF '(' Expr ')' Stmt ELSE Stmt
;
StructStmt: STRUCT ID1 '{' Type Ass '}'
;
Expr: Expr LE Expr
| Expr GE Expr
| Expr NE Expr
| Expr EQ Expr
| Expr GT Expr
| Expr LT Expr
| Expr LOG Expr
| Ass
| Arr
;
Arr: Type ID1 '[' Ass ']'
;
Type: INT
| FLOAT
| CHAR
| DOUBLE
| VOID
;
%%
#include <ctype.h>
#include "lex.yy.c"
int main(int argc, char *argv[])
{
yyin = fopen("tests/test1.c", "r");
if (!yyparse())
{
printf("Success\n");
}
else
{
printf("Error\n");
}
return 0;
}
int yyerror (char *s)
{
printf("%d : %s %s\n", line, s, yytext);
return 0;
}
以下是我用来收集令牌的lex文件
%{
#include <stdio.h>
int line = 1;
%}
L [a-zA-Z_]
D [0-9]
%x mcomment
%x slcomment
%%
"/*" BEGIN(mcomment);
"//" BEGIN(slcomment);
<mcomment>"/*" printf("Error Mcomment");
<mcomment>. ;
<mcomment>\n line++;
<mcomment>"*/" BEGIN(INITIAL);
<slcomment>. ;
<slcomment>\n {line++; BEGIN(INITIAL);}
"printf" return PRINTF;
"for" return FOR;
"while" return WHILE;
"if" return IF;
"else" return ELSE;
"return" return RETURN;
"struct" return STRUCT;
"int" return INT;
"float" return FLOAT;
"char" return CHAR;
"double" return DOUBLE;
"void" return VOID;
{L}({L}|{D})* {return ID;}
{D}+([^{L};])* {return NUM;}
"+"|"-"|"*"|"/"|"%" {;}
"=" {;}
"<=" return LE;
">=" return GE;
"==" return EQ;
"!=" return NE;
">" return GT;
"<" return LT;
"!" ;
"&&"|"||" {return LOG;}
"++"|"--" {return INC;}
\"(\\.|[^\\"])*\" {return STR;}
^"#include ".+ ;
^"#include".+ ;
"("|")"|"["|"]"|"{"|"}" {;}
[ \t] return yytext[0];
";" ;
\n {line++;}
. return yytext[0];
%%
无论我输入哪个文件作为输入,它总是在第1行显示语法错误。它仅在我提供空白输入文件时显示成功解析,这是无用的。 语法有问题吗? 或者是lex代码错了吗?
答案 0 :(得分:1)
你的词法分析器会返回所有空格字符,除了它吃掉的换行符(不返回)。
您的语法接受否空格字符。因此,如果输入流中有空格,则会出现语法错误。
您的语法通常需要使用分号终结符,但您的词法分析器会使用分号(不会返回分号)。因此,如果您有任何必须以分号结尾的作品,那么此处也会出现语法错误。
答案 1 :(得分:1)
您的语法期望忽略空格,并将分号作为';'
标记发送。你的词霸,另一方面:
[ \t] return yytext[0]; // Send every soace and tab as a token
";" ; // Ignore semicolons
您也忽略算术运算符。毫无疑问,还有其他问题。
建议:因为这是你的第一个bison / flex项目,所以从更简单的东西开始,一次完成一个完整的语法。广泛使用flex的跟踪工具(只需将-d
添加到处理lex文件的命令行。)