Flex/Bison实现C-程序时出现语法错误求助
问题:Flex+Bison实现C-语言时词法分析器未向语法分析器返回Token导致语法错误
编译课程项目中用Flex和Bison实现C-语言,编译通过但输入int a;这类简单代码时始终报语法错误,仅输出declaration_list,排查发现词法分析器未向语法分析器返回Token,求解决建议。
lab1.fl 代码
%{ #include "lab1.tab.h" int line = 1; // 当前代码行号 char filename[20]; int comment = 0; int yywrap(void) { return 1; } %} ID [a-zA-Z_][a-zA-Z0-9_]* NUM [0-9]+ %% "\n" {return 0;} "//"(.*)"\n" {} "/*" { comment=1; printf("multiline comment\n");} "*/" {comment=0;} "int" { if (!comment) return INT; } "void" { if (!comment) return VOID; } "if" { if (!comment) return IF; } "else" { if (!comment) return ELSE; } "while" { if (!comment) return WHILE; } "return" { if (!comment) return RETURN; } {ID} { yylval.strval = strdup(yytext); if (!comment) return ID; } {NUM} { if (!comment) return NUM; } "==" { if (!comment) return EQ; } "!=" { if (!comment) return NE; } "<=" { if (!comment) return LE; } ">=" { if (!comment) return GE; } "<" { if (!comment) return LT; } ">" { if (!comment) return GT; } "+" { if (!comment) return ADD; } "-" { if (!comment) return SUB; } "*" { if (!comment) return MUL; } "/" { if (!comment) return DIV; } "(" { if (!comment) return LPAREN; } ")" { if (!comment) return RPAREN; } "[" { if (!comment) return LBRACKET; } "]" { if (!comment) return RBRACKET; } "{" { if (!comment) return LBRACE; } "}" { if (!comment) return RBRACE; } "," { if (!comment) return COMMA; } ";" { if (!comment) return SEMICOLON; } "=" { if (!comment) return ASSIGN; } [\t| \r | \f | \v] {} <<EOF>> {return 0;} %% int main (int argc, char *argv[]){ if (argc==2) yyin = fopen(argv[1], "rt"); else { printf("No file-Exit\n"); exit(1); } strcpy(filename,argv[1]); yylex(); yyparse(); fclose(yyin); }
lab1.y 代码
%{ #include <stdio.h> #include <stdlib.h> #include <string.h> int yylex(); void yyerror(char *s); #define YYSTYPE_IS_DECLARED #define YYSTYPE_IS_TRIVIAL 1 typedef struct { int numval; // 存储NUM的数值 char *strval; // 存储ID的字符串 } YYSTYPE; #include "lab1.tab.h" %} %token INT VOID IF ELSE WHILE RETURN %token <strval> ID %token <numval> NUM %token EQ NE LT LE GT GE ADD SUB MUL DIV %token LPAREN RPAREN LBRACKET RBRACKET LBRACE RBRACE COMMA SEMICOLON ASSIGN %union { char *strval; // 定义语义值的类型 } %type <strval> type_specifier %type <strval> var %type <strval> call %type <strval> args %type <strval> arg_list %nonassoc LOWER_THAN_ELSE %left ADD SUB %left MUL DIV %nonassoc EQ NE %nonassoc LT LE GT GE %start program %% program: {printf("Program \n declaration_list\n");} declaration_list declaration_list: declaration_list declaration {printf("declaration_list\n");} | declaration {printf("declaration ");} ; declaration: var_declaration {printf("var declaration\n");} | fun_declaration {printf("fun declaration\n");} var_declaration: type_specifier ID SEMICOLON {printf("variable_declaration(INT)");} | type_specifier ID ASSIGN NUM SEMICOLON {printf("type_specifier(INT)\n"); printf("variable_declaration\n");} type_specifier: INT {printf("type_specifier(INT)\n");} | VOID {printf("type_specifier(VOID)\n");} fun_declaration: type_specifier ID LPAREN params RPAREN compound_stmt {printf("fun_definition");} params: param_list | VOID {printf("params(VOID)\n");} param_list: param_list COMMA param {printf("tparams list\n");} | param {printf("params list");} param: type_specifier ID {printf("params(%s)\n",$2);} | type_specifier ID LBRACE RBRACE {printf("params{$s [])\n",$2);} compound_stmt: LPAREN local_declarations statement_list RPAREN {printf("compound_stmt\n");} local_declarations: local_declarations var_declaration {printf("local declaration\n");} | /* empty */ statement_list: statement_list statement {printf("statement list\n");} | /* empty */ statement: expression_stmt {printf("expression statement\n");} | compound_stmt {printf("compound statement\n");} | selection_stmt {printf("selection statement\n");} | iteration_stmt {printf("iteration statement\n");} | return_stmt {printf("return statement\n");} expression_stmt: expression SEMICOLON | SEMICOLON selection_stmt: IF LPAREN expression RPAREN statement %prec LOWER_THAN_ELSE | IF LPAREN expression RPAREN statement ELSE statement iteration_stmt: WHILE LPAREN expression RPAREN statement return_stmt: RETURN SEMICOLON | RETURN expression SEMICOLON expression: var ASSIGN expression {printf("expression \n");}| simple_expression {printf("simple expression\n");} var: ID {printf("var(%s)\n",$1);} | ID expression {printf("var(%s)\n",$1);} simple_expression: additive_expression relop additive_expression {printf("additive expression\n");} | additive_expression {printf("additive expression\n");} relop: EQ | NE | LE | GE | LT | GT additive_expression: additive_expression addop term | term addop: ADD | SUB term: term mulop factor {printf("term\n");} | factor {printf("term\n");} mulop: MUL | DIV factor: var | call | NUM call: ID LPAREN args RPAREN args: arg_list {printf("args list\n");} | /* empty */ {$$ = NULL;} arg_list: arg_list COMMA expression | expression {$$ = NULL;} | /* empty */ {$$ = NULL;} %% void yyerror(char *s) { printf("%s",s); }
核心问题排查与修复建议
1. Flex代码的致命错误:提前终止词法分析
Flex规则中的"\n" {return 0;}会在遇到第一个换行符时就返回EOF(0),直接终止词法分析,后续的int、a、;等Token根本无法被识别。必须删除这条规则,换行符应归为空白字符,和其他空白符一起忽略。
2. 多行注释处理逻辑漏洞
当前多行注释仅匹配/*和*/,但注释内的字符(包括换行)会触发其他规则,导致Token识别混乱。需修改为状态化处理:
- 在Flex定义部分添加状态声明:
%x comment - 替换注释规则:
"/*" { comment = 1; BEGIN(comment); } <comment>"*/" { comment = 0; BEGIN(INITIAL); } <comment>. { /* 忽略注释内所有字符 */ } <comment>\n { line++; /* 注释内换行也要更新行号 */ }
3. main函数中多余的yylex()调用
Flex的main函数中先调用yylex()消耗了输入的Token,导致yyparse()无法获取所需Token。删除单独的yylex()调用,yyparse()会自动调用yylex()获取Token。
4. Bison中YYSTYPE定义冲突
手动定义的YYSTYPE结构体和%union冲突,正确做法是用%union统一定义语义值类型:
- 删除
#define YYSTYPE_IS_DECLARED、#define YYSTYPE_IS_TRIVIAL 1和手动的YYSTYPE结构体 - 修改
%union:
%union { int numval; char *strval; }
5. Bison语法规则的语法错误
- 复合语句
compound_stmt错误使用小括号LPAREN/RPAREN,应改为大括号LBRACE/RBRACE - 参数规则
param中的数组参数错误使用大括号,应改为方括号LBRACKET/RBRACKET
6. 调试建议
在Flex规则中添加Token输出,确认Token是否正确返回:
"int" { if (!comment) { printf("[LEX] Token: INT\n"); return INT; } } {ID} { yylval.strval = strdup(yytext); if (!comment) { printf("[LEX] Token: ID(%s)\n", yytext); return ID; } } ";" { if (!comment) { printf("[LEX] Token: SEMICOLON\n"); return SEMICOLON; } }
内容的提问来源于stack exchange,提问作者Gabriel Vasile
相关产品推荐
相关产品推荐

