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

使用Bison的D解析器接口时,如何连接Flex与Bison?

Flex+Bison D接口问题解决方案

一、实现Lex.yylex()连接解析器与词法分析器

Bison的D接口要求Lexer类返回Symbol类型,而非传统的int,可以通过手动适配或Flex生成适配代码解决:

手动适配方案

在自定义的Lex类中调用Flex生成的yylex()(返回int),将其转换为Symbol对象,同时同步yylval的值:

class Lex : Lexer {
    Symbol yylex() {
        int token = yylex();
        // 同步Flex的yylval到当前Lexer的yylval
        this.yylval.n = yylval.n;
        
        if (token == 0) {
            return new Symbol(SymbolKind.SYM_EOF_); // 处理EOF
        }
        // 将int类型token转为SymbolKind枚举并生成Symbol
        SymbolKind kind = cast(SymbolKind)token;
        return new Symbol(kind);
    }

    void yyerror(string s) {
        stderr.writef("%s\n", s);
    }
}

Flex自动生成适配代码

在Flex词法文件开头添加以下选项,生成D语言的词法分析器:

%option d
%option noyywrap

生成的yylex()默认返回int,直接用上面的手动适配逻辑即可完成对接。

二、不生成yy.tab.h让Flex知晓符号

Bison生成的parser.d中包含SymbolKind枚举,可直接在Flex中引用:

  1. 先运行Bison生成parser.d,里面的SymbolKind枚举包含所有终结符(命名终结符对应SYM_XXX_,字面字符对应SYM_ASCII码_)。
  2. 在Flex文件中引入parser模块,直接使用枚举值:
%{
import parser;
%}

%%
[0-9]+ {
    yylval.n = atoi(yytext);
    return cast(int)SymbolKind.SYM_NUM_;
}

"+" {
    return cast(int)SymbolKind.SYM_43_; // 43是'+'的ASCII码
}
%%

三、解决字面字符映射为SYM_XX_的不直观问题

方法1:在Bison中为字面字符定义别名

在Bison声明部分给字面字符显式命名,让Bison生成可读性更强的枚举值:

%{
%}

%define api.symbol.prefix {SYM_}

%union {
    int n;
}

%token<n> NUM;
%token PLUS '+' // 为'+'定义别名PLUS

%%

S: NUM | S PLUS NUM {} // 使用别名代替字面字符

%%

此时Bison会生成SYM_PLUS_枚举值,Flex中可直接返回cast(int)SymbolKind.SYM_PLUS_。

方法2:在D代码中封装字符映射函数

如果不想修改Bison规则,可在Lex类中添加辅助函数,将字符转为对应的SymbolKind:

class Lex : Lexer {
    private SymbolKind charToSymbolKind(char c) {
        return cast(SymbolKind)("SYM_" ~ cast(string)(cast(ubyte)c) ~ "_").to!SymbolKind;
    }

    Symbol yylex() {
        int token = yylex();
        this.yylval.n = yylval.n;
        
        if (token == 0) {
            return new Symbol(SymbolKind.SYM_EOF_);
        }
        // 处理可打印ASCII字符的映射
        if (token >= 32 && token <= 126) {
            return new Symbol(charToSymbolKind(cast(char)token));
        }
        return new Symbol(cast(SymbolKind)token);
    }

    void yyerror(string s) {
        stderr.writef("%s\n", s);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 13:04:56