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

Flex-Bison开发Python解析器:Bison无法识别令牌显示$undefined

问题:Flex-Bison开发Python解析器时,解析器无法识别词法分析器返回的Token ID

我用Flex-Bison编写Python解析器,词法分析器已完成,能正确识别import/from等关键字,但解析器始终无法识别对应的Token ID,报错提示unexpected $undefined。

词法分析器代码(python.l)

%{
#include <stdio.h>

// 大量宏定义
#define TOKEN_IDENTIFIER 259
// 大量宏定义
#define TOKEN_WHITE 294
// 大量宏定义
#define TOKEN_KEYWORD_FROM 306
// 大量宏定义
#define TOKEN_KEYWORD_IMPORT 311
// 大量宏定义

int displayToken(int);
void yyerror(char *sp);

numbers         ((0|[1-9][0-9]*)(\.[0-9]+)?)
identifiers     ([a-zA-Z\_][0-9a-zA-Z\_]*)
identation      (^\t+)
whites          (\ |\t|\r|\n)+

// 大量代码行
"from"          { return displayToken(TOKEN_KEYWORD_FROM); }
// 大量代码行
"import"        { return displayToken(TOKEN_KEYWORD_IMPORT); }
// 大量代码行

{identifiers}   { return displayToken(TOKEN_IDENTIFIER); }
{identation}    { return displayToken(TOKEN_IDENTATION); }
{whites}        { return displayToken(TOKEN_WHITE); }

// 大量代码行
.               { yyerror("Unknown token!!!"); }
%%

int displayToken(int token) {

#ifdef DEBUG

// 调试逻辑

#endif

    return token;
}

解析器代码(python.y)

%{
    #pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
    #include <stdio.h>
    #include <stdlib.h>

    int yylex();
%}

%define parse.error verbose

%token TOKEN_KEYWORD_IMPORT TOKEN_KEYWORD_FROM TOKEN_IDENTIFIER TOKEN_WHITE
%start input

%%
input: import_def
     | from_def TOKEN_WHITE import_def
;

import_def: import TOKEN_WHITE identifier;

from_def: from TOKEN_WHITE identifier;

import: TOKEN_KEYWORD_IMPORT {
    printf("found import\n");
};

from: TOKEN_KEYWORD_FROM {
    printf("found from\n");
};

identifier: TOKEN_IDENTIFIER {
    printf("found an identifier\n");
};

%%

int main (int argc, char **argv) {
    #ifdef YYDEBUG
    yydebug = 1;
    #endif
    yyparse();
}

int yywrap(void)
{
   return 1;
}

int yyerror(char *s) {
    fprintf(stderr, "error: %s\n", s);
    exit(1);
}

编译运行命令

flex python.l
bison python.y --debug
gcc lex.yy.c python.tab.c -lfl
./a.out

错误输出

输入from math import sqrt后得到:

Starting
Starting parse
Entering state 0
Reading a token: from math import sqrt
Token ID 306 (TOKEN_KEYWORD_FROM)
Next token is token $undefined ()
error: syntax error, unexpected $undefined, expecting TOKEN_KEYWORD_IMPORT or TOKEN_KEYWORD_FROM

我确认词法分析器能正确识别Token,但解析器无法匹配对应的ID,试过引入lex.yy.c、复制宏定义都没用,求解决办法。


解决方案

问题核心是Flex和Bison的Token ID不匹配:你在Flex中手动定义了Token数值(如TOKEN_KEYWORD_FROM 306),但Bison会自动为%token声明的符号分配独立ID,两者数值不一致导致解析器无法识别Flex返回的Token。

正确解决步骤:

  1. 让Bison生成统一的Token宏定义
    在Bison文件(python.y)中添加%defines选项,Bison会生成python.tab.h头文件,包含所有Token的正确ID定义:

    %{
        #pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
        #include <stdio.h>
        #include <stdlib.h>
    
        int yylex();
    %}
    
    %define parse.error verbose
    %defines  // 添加此行,生成Token定义头文件
    
  2. Flex引入Bison生成的头文件
    在Flex的python.l文件中,删除所有手动定义的TOKEN_*宏,引入Bison生成的python.tab.h:

    %{
    #include <stdio.h>
    #include "python.tab.h"  // 引入Bison生成的Token定义
    
    int displayToken(int);
    void yyerror(char *sp);
    
    // 删除所有手动定义的TOKEN_*宏
    
  3. 保持Flex返回Token的一致性
    Flex中直接使用Bison头文件里的宏返回Token,现有代码无需修改(只要宏名一致即可):

    "from"          { return displayToken(TOKEN_KEYWORD_FROM); }
    "import"        { return displayToken(TOKEN_KEYWORD_IMPORT); }
    
  4. 重新编译
    按原命令重新编译,Bison会自动生成python.tab.h:

    bison python.y --debug
    flex python.l
    gcc lex.yy.c python.tab.c -lfl
    ./a.out
    

额外注意事项:

  • 禁止手动定义Token数值,始终由Bison统一管理,避免ID冲突。
  • 词法分析器中identation对应的TOKEN_IDENTATION未在解析器中声明,若无需在语法中处理缩进,可直接跳过(不返回该Token);若需要则在Bison中添加%token TOKEN_IDENTATION。
  • 空白字符(TOKEN_WHITE)若无需在语法规则中显式处理,可在Flex中直接跳过(将动作改为{ /* skip whitespace */ }),简化语法规则。

内容的提问来源于stack exchange,提问作者Havarem

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 00:36:27