You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 12:27:06