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

C语言AST项目类型识别错误与段错误排查求助

编译器AST项目的类型错误与段错误排查

一、编译错误:AST_comm/AST_prog未知类型的原因与解决

问题成因

C语言要求使用类型前必须先声明或定义,你的代码存在两个关键问题:

  1. AST_comm未提前声明:定义struct _prog_tree时,编译器还不知道AST_comm的类型定义。
  2. 循环依赖的typedef:struct _prog_tree中直接使用了AST_prog,但AST_prog的typedef语句在结构体定义之后,编译器处理结构体时无法识别该类型。

解决方法

添加前向声明,先告知编译器这些类型的存在,再定义结构体:

// 前向声明AST_comm(假设AST_comm对应struct _AST_comm)
struct _AST_comm;
typedef struct _AST_comm AST_comm;

// 前向声明_prog_tree的指针类型
struct _prog_tree;
typedef struct _prog_tree* AST_prog;

// 现在可正常定义结构体
struct _prog_tree {
    AST_comm commande;
    AST_prog programme;
};

如果AST_comm本身是指针类型,只需调整前向声明的对应类型即可,核心是让编译器在处理结构体前知晓所有用到的类型标识。


二、运行时段错误的成因与解决

核心问题1:Parser规则中的未初始化值

你的program规则包含空分支,但未对$$赋值:

program : 
            { /* 无任何赋值操作 */ }
        | commande program
        ;

当解析空程序(或{}中的空内容)时,$$会保留未初始化的垃圾值,后续commande规则中$$ = $2会将这个非法值赋值给当前节点,访问节点成员(如->rule)时直接触发段错误。

解决:给空program分支明确赋值合法值:

program : 
            { $$ = NULL; }  // 空程序返回空指针
        | commande program
            { /* 这里需实现commande与program的链接逻辑,比如构建_prog_tree节点 */ }
        ;

同步调整{ program }的处理逻辑:

| '{' program '}'
           {
    $$ = $2;  // 此时$2要么是NULL要么是合法节点
          }

核心问题2:内存管理逻辑混乱

你在expression ';'分支中,将new_command返回的指针直接赋值给结构体数组:

(*rez)[i-1] = new_command($1, NULL, NULL, NULL);

但从parser.y的%union和%type定义来看,AST_comm是结构体类型,而new_command返回的是指针(你后续用了$$->rule访问成员),这相当于把指针地址直接拷贝到结构体中,导致内存布局完全错误,后续访问结构体成员时会触发非法内存访问。

解决:

  1. 调整内存分配逻辑,改为存储指针数组:
// 替换原结构体数组分配逻辑为指针数组分配
if (*rez == NULL) {
    *rez = (AST_comm**)malloc(sizeof(AST_comm*));
} else {
    AST_comm **tmp = (AST_comm**)realloc(*rez, sizeof(AST_comm*) * i);
    if (tmp == NULL) {
        // 错误处理:释放已分配的指针和数组
        for (int j=0; j<i-1; j++) free((*rez)[j]);
        free(*rez);
        return 0;
    }
    *rez = tmp;
}
(*rez)[i-1] = new_command($1, NULL, NULL, NULL);
*size = ++i;
  1. 确保new_command返回AST_comm*类型,且AST_comm结构体的定义包含rule、expr1等所需成员。

核心问题3:全局变量i的风险

全局变量i在多次解析或错误回溯时会导致数组大小与实际元素数量不匹配,比如解析出错回溯时,i的值不会回滚,后续分配的数组大小会大于实际需要的空间,甚至引发越界。

解决:用size参数跟踪当前元素数量,去掉全局变量:

// 初始调用时*size需设为0
int current_size = *size;
AST_comm **tmp = (AST_comm**)realloc(*rez, sizeof(AST_comm*) * (current_size + 1));
if (tmp == NULL) {
    // 错误处理
    for (int j=0; j<current_size; j++) free((*rez)[j]);
    free(*rez);
    return 0;
}
*rez = tmp;
(*rez)[current_size] = new_command($1, NULL, NULL, NULL);
*size = current_size + 1;

额外检查点

  • 确认AST.h中AST_comm、AST_prog的定义在所有文件中保持一致,避免重复定义或类型不匹配。
  • 检查new_command、new_binary_expr等函数的实现,确保它们正确分配内存并初始化成员,不会返回空指针或未初始化的指针。
  • 检查lexer中strdup分配的内存是否会被正确释放,避免内存泄漏(虽不是段错误直接原因,但会引发其他问题)。

内容的提问来源于stack exchange,提问作者10969_ shirazu_

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 14:37:31