From 9e979a49b041a9d0e8ba6f8fee50bd11520169af Mon Sep 17 00:00:00 2001 From: hachem Date: Sun, 30 Aug 2026 13:24:29 +0200 Subject: add: parse expressions --- src/parser/ast.c | 41 ++++++++++++++++++++--- src/parser/ast.h | 41 ++++++++++++++++++++++- src/parser/parser.c | 96 +++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 160 insertions(+), 18 deletions(-) (limited to 'src/parser') diff --git a/src/parser/ast.c b/src/parser/ast.c index 4f10915..97cdb6d 100644 --- a/src/parser/ast.c +++ b/src/parser/ast.c @@ -2,6 +2,42 @@ #include "parser/ast.h" +void free_expr(struct Expr* expr) +{ + if (expr == NULL) + return; + + switch (expr->kind) + { + case EXPR_PRIMARY: + break; + case EXPR_BINARY: + free_expr(expr->binary.left); + free_expr(expr->binary.right); + break; + case EXPR_MEMBER: + free_expr(expr->member.object); + break; + } + + free(expr); +} + +static void free_statement(struct Statement* statement) +{ + if (statement->kind == STATEMENT_ASSIGN) + free_expr(statement->assign.value); +} + +void free_proc(struct ProcDecl* proc) +{ + free(proc->params); + + for (size_t i = 0; i < proc->body_count; i += 1) + free_statement(&proc->body[i]); + free(proc->body); +} + struct Program create_program(void) { struct Program program; @@ -23,10 +59,7 @@ void free_program(struct Program* program) free(program->data_decls); for (size_t i = 0; i < program->proc_count; i += 1) - { - free(program->procs[i].params); - free(program->procs[i].body); - } + free_proc(&program->procs[i]); free(program->procs); program->consts = NULL; diff --git a/src/parser/ast.h b/src/parser/ast.h index 4604e1a..199d802 100644 --- a/src/parser/ast.h +++ b/src/parser/ast.h @@ -23,6 +23,42 @@ struct Param struct Token reg; }; +enum ExprKind +{ + EXPR_PRIMARY, + EXPR_BINARY, + EXPR_MEMBER, +}; + +struct PrimaryExpr +{ + struct Token token; +}; + +struct BinaryExpr +{ + struct Expr* left; + struct Token op; + struct Expr* right; +}; + +struct MemberExpr +{ + struct Expr* object; + struct Token member; +}; + +struct Expr +{ + enum ExprKind kind; + union + { + struct PrimaryExpr primary; + struct BinaryExpr binary; + struct MemberExpr member; + }; +}; + enum StatementKind { STATEMENT_ASSIGN, @@ -36,7 +72,7 @@ struct AssignStatement bool target_deref; struct Token target; struct Token op; - struct Token value; + struct Expr* value; }; struct LabelStatement @@ -93,6 +129,9 @@ void add_const(struct Program* program, struct ConstDecl decl); void add_data(struct Program* program, struct DataDecl decl); struct ProcDecl create_proc(void); +void free_proc(struct ProcDecl* proc); void add_param(struct ProcDecl* proc, struct Param param); void add_statement(struct ProcDecl* proc, struct Statement statement); void add_proc(struct Program* program, struct ProcDecl decl); + +void free_expr(struct Expr* expr); diff --git a/src/parser/parser.c b/src/parser/parser.c index a125b7d..5431bfd 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -123,17 +123,87 @@ static bool is_assign_op(enum TokenType type) || type == TOKEN_SLASH_EQUAL; } -static bool parse_value(struct Parser* parser, struct Token* out) +static struct Expr* alloc_expr(enum ExprKind kind) +{ + struct Expr* expr = malloc(sizeof(struct Expr)); + expr->kind = kind; + return expr; +} + +static struct Expr* parse_primary(struct Parser* parser) { if (check(parser, TOKEN_IDENTIFIER) || check(parser, TOKEN_INTEGER) || check(parser, TOKEN_CHAR)) { advance_parser(parser); - *out = parser->previous; - return true; + + struct Expr* expr = alloc_expr(EXPR_PRIMARY); + expr->primary.token = parser->previous; + return expr; } - error_at(parser, parser->current, "expected a value"); - return false; + error_at(parser, parser->current, "expected an expression"); + return NULL; +} + +static struct Expr* parse_postfix(struct Parser* parser) +{ + struct Expr* expr = parse_primary(parser); + if (expr == NULL) + return NULL; + + while (match_token(parser, TOKEN_DOT)) + { + if (!consume(parser, TOKEN_IDENTIFIER, "expected member name after '.'")) + { + free_expr(expr); + return NULL; + } + + struct Expr* member = alloc_expr(EXPR_MEMBER); + member->member.object = expr; + member->member.member = parser->previous; + expr = member; + } + + return expr; +} + +static struct Expr* parse_binary(struct Parser* parser, struct Expr* (*operand)(struct Parser*), enum TokenType a, enum TokenType b) +{ + struct Expr* left = operand(parser); + if (left == NULL) + return NULL; + + while (check(parser, a) || check(parser, b)) + { + advance_parser(parser); + struct Token op = parser->previous; + + struct Expr* right = operand(parser); + if (right == NULL) + { + free_expr(left); + return NULL; + } + + struct Expr* binary = alloc_expr(EXPR_BINARY); + binary->binary.left = left; + binary->binary.op = op; + binary->binary.right = right; + left = binary; + } + + return left; +} + +static struct Expr* parse_multiplicative(struct Parser* parser) +{ + return parse_binary(parser, parse_postfix, TOKEN_STAR, TOKEN_SLASH); +} + +static struct Expr* parse_expression(struct Parser* parser) +{ + return parse_binary(parser, parse_multiplicative, TOKEN_PLUS, TOKEN_MINUS); } static bool parse_statement(struct Parser* parser, struct Statement* out) @@ -173,17 +243,18 @@ static bool parse_statement(struct Parser* parser, struct Statement* out) return false; } - struct AssignStatement assign; - assign.target_deref = deref; - assign.target = name; advance_parser(parser); - assign.op = parser->previous; + struct Token op = parser->previous; - if (!parse_value(parser, &assign.value)) + struct Expr* value = parse_expression(parser); + if (value == NULL) return false; out->kind = STATEMENT_ASSIGN; - out->assign = assign; + out->assign.target_deref = deref; + out->assign.target = name; + out->assign.op = op; + out->assign.value = value; return true; } @@ -226,8 +297,7 @@ static bool parse_proc(struct Parser* parser, struct Program* program) return true; error: - free(decl.params); - free(decl.body); + free_proc(&decl); return false; } -- cgit v1.3