feat: 复合赋值 += -= *= /= + CHANGELOG 更新

- lexer: 4 个复合赋值 Token (解析时优先于单字符)
- parser: desugar x+=expr → x=x+expr(零 sema/codegen 改动)
- 新增集成测试 09_compound_assign.l (15 12 24 6)
- CHANGELOG 新增 v0.2.0 条目
This commit is contained in:
2026-06-05 02:40:05 +08:00
parent 9e41b09318
commit d5a94d45cb
6 changed files with 71 additions and 2 deletions
+31
View File
@@ -277,6 +277,37 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) {
value, name->line, name->col);
}
// 复合赋值: ident += expr → ident = ident + expr
if (t->kind == TOK_IDENT) {
TokenKind next_kind = (t + 1)->kind;
if (next_kind >= TOK_PLUS_EQ && next_kind <= TOK_SLASH_EQ) {
const Token* name = advance(p); // 消费标识符
TokenKind comp_op = advance(p)->kind;
BinaryOp binop;
switch (comp_op) {
case TOK_PLUS_EQ: binop = OP_ADD; break;
case TOK_MINUS_EQ: binop = OP_SUB; break;
case TOK_STAR_EQ: binop = OP_MUL; break;
case TOK_SLASH_EQ: binop = OP_DIV; break;
default: break;
}
AstNode* rhs = parse_expr(p, error);
if (!rhs) return NULL;
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
AstNode* lhs_ident = ast_make_ident(p->arena,
arena_strdup_impl(p->arena, name->start, name->length),
name->line, name->col);
AstNode* bin_expr = ast_make_binary(p->arena, binop, lhs_ident, rhs,
name->line, name->col);
return ast_make_assign(p->arena,
arena_strdup_impl(p->arena, name->start, name->length),
bin_expr, name->line, name->col);
}
}
// 表达式语句
AstNode* expr = parse_expr(p, error);
if (!expr) return NULL;