深入解析DoctorWkt/acwj项目中结构体成员访问的实现

深入解析DoctorWkt/acwj项目中结构体成员访问的实现

acwj A Compiler Writing Journey acwj 项目地址: https://gitcode.com/gh_mirrors/ac/acwj

在编译器开发过程中,实现结构体成员访问是一个重要的里程碑。本文将详细解析DoctorWkt/acwj项目中如何实现结构体成员的访问机制,包括直接访问(.)和指针访问(->)两种方式。

结构体成员访问的基本原理

结构体成员访问的核心思想与数组元素访问非常相似,但存在一些关键差异:

  1. 数组访问:通过基地址加上索引乘以元素大小的偏移量来定位元素
  2. 结构体访问:通过基地址加上预定义的成员偏移量来定位成员

例如,对于数组访问:

int arr[5];
y = arr[3];  // 计算地址:基地址 + 3 * sizeof(int)

而对于结构体访问:

struct example { int a; char b; };
struct example var;
char c = var.b;  // 计算地址:基地址 + b的偏移量

新增的语法标记

项目新增了两个重要的标记(Token)来支持结构体访问:

  1. T_DOT:对应.操作符,用于直接访问结构体成员
  2. T_ARROW:对应->操作符,用于通过指针访问结构体成员

这些标记在词法分析阶段被识别并添加到标记流中。

解析过程详解

成员访问被实现为后缀操作符,类似于数组访问的[]操作符。解析逻辑位于postfix()函数中:

static struct ASTnode *postfix(void) {
  // ...
  if (Token.token == T_DOT)
    return (member_access(0));  // 直接访问
  if (Token.token == T_ARROW)
    return (member_access(1));  // 指针访问
  // ...
}

member_access()函数是核心实现,其工作流程如下:

1. 变量声明检查

首先验证标识符是否已声明为结构体或结构体指针:

if ((compvar = findsymbol(Text)) == NULL)
  fatals("Undeclared variable", Text);
if (withpointer && compvar->type != pointer_to(P_STRUCT))
  fatals("Undeclared variable", Text);
if (!withpointer && compvar->type != P_STRUCT)
  fatals("Undeclared variable", Text);

2. 获取基地址

根据访问方式生成不同的AST节点:

if (withpointer) {
  // 指针访问:加载指针值
  left = mkastleaf(A_IDENT, pointer_to(P_STRUCT), compvar, 0);
} else {
  // 直接访问:获取结构体地址
  left = mkastleaf(A_ADDR, compvar->type, compvar, 0);
}
left->rvalue = 1;

3. 查找成员

跳过操作符标记后,查找匹配的成员名:

typeptr = compvar->ctype;  // 获取结构体类型信息
scan(&Token);             // 跳过.或->
ident();                  // 获取成员名

// 遍历成员列表查找匹配项
for (m = typeptr->member; m != NULL; m = m->next)
  if (!strcmp(m->name, Text))
    break;
if (m == NULL)
  fatals("No member found in struct/union: ", Text);

4. 生成访问代码

最终生成计算成员地址并解引用的AST节点:

right = mkastleaf(A_INTLIT, P_INT, NULL, m->posn);  // 成员偏移量
left = mkastnode(A_ADD, pointer_to(m->type), left, NULL, right, NULL, 0);
left = mkastunary(A_DEREF, m->type, left, NULL, 0);  // 解引用

生成的汇编代码分析

var2.y = 'c'为例,生成的汇编代码展示了实际的访问过程:

movq    $99, %r10               # 'c'的ASCII值
leaq    var2(%rip), %r11        # 获取var2基地址
movq    $4, %r12                # y成员的偏移量
addq    %r11, %r12              # 计算实际地址
movb    %r10b, (%r12)           # 存储值

当前实现的限制

虽然基本功能已经实现,但当前版本仍有一些限制:

  1. 多级指针访问:无法处理ptr->next->next这样的多级访问
  2. 类型系统不完整:尚未支持联合体(union)的成员访问
  3. 错误处理简单:目前的错误检查较为基础

未来发展方向

项目后续可能会关注以下改进:

  1. 支持联合体(union)的成员访问
  2. 实现多级指针访问功能
  3. 增强类型系统和错误处理
  4. 优化生成的代码质量

结构体成员访问的实现是编译器开发中的重要一步,为后续更复杂的数据结构支持奠定了基础。通过理解这一实现过程,开发者可以更好地掌握编译器如何处理复合数据类型。

acwj A Compiler Writing Journey acwj 项目地址: https://gitcode.com/gh_mirrors/ac/acwj

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孟振优Harvester

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值