深入解析DoctorWkt/acwj项目中结构体成员访问的实现
acwj A Compiler Writing Journey 项目地址: https://gitcode.com/gh_mirrors/ac/acwj
在编译器开发过程中,实现结构体成员访问是一个重要的里程碑。本文将详细解析DoctorWkt/acwj项目中如何实现结构体成员的访问机制,包括直接访问(.)和指针访问(->)两种方式。
结构体成员访问的基本原理
结构体成员访问的核心思想与数组元素访问非常相似,但存在一些关键差异:
- 数组访问:通过基地址加上索引乘以元素大小的偏移量来定位元素
- 结构体访问:通过基地址加上预定义的成员偏移量来定位成员
例如,对于数组访问:
int arr[5];
y = arr[3]; // 计算地址:基地址 + 3 * sizeof(int)
而对于结构体访问:
struct example { int a; char b; };
struct example var;
char c = var.b; // 计算地址:基地址 + b的偏移量
新增的语法标记
项目新增了两个重要的标记(Token)来支持结构体访问:
- T_DOT:对应
.
操作符,用于直接访问结构体成员 - 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) # 存储值
当前实现的限制
虽然基本功能已经实现,但当前版本仍有一些限制:
- 多级指针访问:无法处理
ptr->next->next
这样的多级访问 - 类型系统不完整:尚未支持联合体(union)的成员访问
- 错误处理简单:目前的错误检查较为基础
未来发展方向
项目后续可能会关注以下改进:
- 支持联合体(union)的成员访问
- 实现多级指针访问功能
- 增强类型系统和错误处理
- 优化生成的代码质量
结构体成员访问的实现是编译器开发中的重要一步,为后续更复杂的数据结构支持奠定了基础。通过理解这一实现过程,开发者可以更好地掌握编译器如何处理复合数据类型。
acwj A Compiler Writing Journey 项目地址: https://gitcode.com/gh_mirrors/ac/acwj
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考