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

使用lex/yacc开发编译器时如何实现类似Array[2]的内存数组直接访问?

基于lex/yacc实现通用数组下标访问的方案

词法分析层配置

lex侧仅需新增括号的匹配规则,原有标识符、常量匹配逻辑无需调整:

"["    { return LBRACK; }
"]"    { return RBRACK; }
/* 保留原有基础词法规则 */
[a-zA-Z_][a-zA-Z0-9_]*  { yylval.sym = lookup_symbol(yytext); return IDENT; }
[0-9]+   { yylval.int_val = atoi(yytext); return INT_CONST; }

语法分析层规则定义

yacc侧新增数组访问的语法产生式,同时兼容左值(可被赋值)和右值(可参与运算)场景:
首先在声明段新增相关token和类型定义:

%token <sym> IDENT
%token <int_val> INT_CONST
%token LBRACK RBRACK
%type <expr_node> array_access expr

然后新增语法规则与语义动作:

array_access: IDENT LBRACK expr RBRACK {
    $$ = build_array_access_node($1, $3);
}
;

expr: array_access 
    | /* 原有其他表达式规则,如常量、二元运算、函数调用等 */
    ;

/* 赋值规则天然支持数组左值,无需额外适配 */
assign_stmt: expr '=' expr ';' {
    generate_assign_code($1, $3);
}
;

多数据类型兼容的核心语义实现

这是适配全类型的核心逻辑,无需为每种数据类型单独写访问规则:

  • 符号表统一存储每个数组的元数据:基础元素类型、单元素字节长度、数组总长度等信息
  • 偏移量计算做通用抽象:下标值 × 单元素字节长度,计算逻辑完全和元素类型解耦
    示例语义处理函数伪代码:
struct expr_node* build_array_access_node(struct symbol* arr_sym, struct expr_node* index) {
    // 前置类型校验
    if (!arr_sym->is_array) {
        compile_error("cannot apply index access to non-array type");
    }
    struct expr_node* node = alloc_expr_node(EXPR_ARRAY_ACCESS);
    node->base_addr = arr_sym->mem_addr;
    // 通用偏移计算,和元素类型无关
    node->offset = build_binary_expr(OP_MUL, index, build_int_const(arr_sym->elem_size));
    // 继承元素类型,供后续类型检查用
    node->value_type = arr_sym->elem_type;
    node->type_size = arr_sym->elem_size;
    return node;
}
  • 生成目标代码时,直接按基址 + 偏移量得到的内存地址执行读写,仅需根据节点存储的type_size控制读写的字节数即可,无需为不同类型单独实现访问逻辑。

扩展支持

如果需要实现多维数组,递归套用上述规则即可:Arr[i][j]的第一层访问结果为第二维数组的首地址,再用相同逻辑计算第二维的偏移量。如果需要运行时下标越界检查,可在语义处理阶段插入越界判断的代码片段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 18:15:05