aboutsummaryrefslogtreecommitdiffhomepage
path: root/parse.c
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-07-21 10:09:00 +0900
committernsfisis <nsfisis@gmail.com>2025-08-15 10:04:28 +0900
commit6daa56323634e1142f2d22a756a77a74382cf3a7 (patch)
tree85355ad1ad0cf5dca837f8b4cd7e6b09eaa7bd9d /parse.c
parent16bbc2e0d72f94f8061ba294d1776edfe5bf8a55 (diff)
downloadducc-6daa56323634e1142f2d22a756a77a74382cf3a7.tar.gz
ducc-6daa56323634e1142f2d22a756a77a74382cf3a7.tar.zst
ducc-6daa56323634e1142f2d22a756a77a74382cf3a7.zip
feat: separate main.c
Diffstat (limited to 'parse.c')
-rw-r--r--parse.c1009
1 files changed, 1009 insertions, 0 deletions
diff --git a/parse.c b/parse.c
new file mode 100644
index 0000000..b056077
--- /dev/null
+++ b/parse.c
@@ -0,0 +1,1009 @@
+#define LVAR_MAX 32
+
+struct LocalVar {
+ String name;
+ Type* ty;
+};
+typedef struct LocalVar LocalVar;
+
+struct GlobalVar {
+ String name;
+ Type* ty;
+};
+typedef struct GlobalVar GlobalVar;
+
+struct Func {
+ String name;
+ Type* ty;
+};
+typedef struct Func Func;
+
+struct Parser {
+ Token* tokens;
+ int pos;
+ LocalVar* lvars;
+ int n_lvars;
+ GlobalVar* gvars;
+ int n_gvars;
+ Func* funcs;
+ int n_funcs;
+ AstNode* structs;
+ int n_structs;
+ AstNode* enums;
+ int n_enums;
+ AstNode* typedefs;
+ int n_typedefs;
+ char** str_literals;
+ int n_str_literals;
+};
+typedef struct Parser Parser;
+
+Parser* parser_new(Token* tokens) {
+ Parser* p = calloc(1, sizeof(Parser));
+ p->tokens = tokens;
+ p->gvars = calloc(128, sizeof(GlobalVar));
+ p->funcs = calloc(256, sizeof(Func));
+ p->structs = calloc(64, sizeof(AstNode));
+ p->enums = calloc(16, sizeof(AstNode));
+ p->typedefs = calloc(64, sizeof(AstNode));
+ p->str_literals = calloc(1024, sizeof(char*));
+ return p;
+}
+
+Token* peek_token(Parser* p) {
+ return p->tokens + p->pos;
+}
+
+Token* next_token(Parser* p) {
+ ++p->pos;
+ return p->tokens + p->pos - 1;
+}
+
+int eof(Parser* p) {
+ return peek_token(p)->kind != TokenKind_eof;
+}
+
+Token* expect(Parser* p, int expected) {
+ Token* t = next_token(p);
+ if (t->kind == expected) {
+ return t;
+ }
+
+ char* buf = calloc(1024, sizeof(char));
+ sprintf(buf, "expected '%s', but got '%s'", token_kind_stringify(expected), token_stringify(t));
+ fatal_error(buf);
+}
+
+int find_lvar(Parser* p, const String* name) {
+ int i;
+ for (i = 0; i < p->n_lvars; ++i) {
+ if (string_equals(&p->lvars[i].name, name)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int find_gvar(Parser* p, const String* name) {
+ int i;
+ for (i = 0; i < p->n_gvars; ++i) {
+ if (string_equals(&p->gvars[i].name, name)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int find_func(Parser* p, const String* name) {
+ int i;
+ for (i = 0; i < p->n_funcs; ++i) {
+ if (string_equals(&p->funcs[i].name, name)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int find_struct(Parser* p, const String* name) {
+ int i;
+ for (i = 0; i < p->n_structs; ++i) {
+ if (string_equals(&p->structs[i].name, name)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int find_enum(Parser* p, const String* name) {
+ int i;
+ for (i = 0; i < p->n_enums; ++i) {
+ if (string_equals(&p->enums[i].name, name)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int find_enum_member(Parser* p, const String* name) {
+ int i;
+ int j;
+ for (i = 0; i < p->n_enums; ++i) {
+ for (j = 0; j < p->enums[i].node_members->node_len; ++j) {
+ if (string_equals(&p->enums[i].node_members->node_items[j].name, name)) {
+ return i * 1000 + j;
+ }
+ }
+ }
+ return -1;
+}
+
+int find_typedef(Parser* p, const String* name) {
+ int i;
+ for (i = 0; i < p->n_typedefs; ++i) {
+ if (string_equals(&p->typedefs[i].name, name)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+AstNode* parse_expr(Parser* p);
+AstNode* parse_stmt(Parser* p);
+
+String* parse_ident(Parser* p) {
+ return &expect(p, TokenKind_ident)->raw;
+}
+
+int register_str_literal(Parser* p, char* s) {
+ p->str_literals[p->n_str_literals] = s;
+ ++p->n_str_literals;
+ return p->n_str_literals;
+}
+
+AstNode* parse_primary_expr(Parser* p) {
+ Token* t = next_token(p);
+ AstNode* e;
+ char* buf;
+ if (t->kind == TokenKind_literal_int) {
+ return ast_new_int(atoi(string_to_cstr(&t->raw)));
+ } else if (t->kind == TokenKind_literal_str) {
+ e = ast_new(AstNodeKind_str_expr);
+ e->node_idx = register_str_literal(p, string_to_cstr(&t->raw));
+ return e;
+ } else if (t->kind == TokenKind_paren_l) {
+ e = parse_expr(p);
+ expect(p, TokenKind_paren_r);
+ return e;
+ } else if (t->kind == TokenKind_ident) {
+ String* name = &t->raw;
+
+ if (peek_token(p)->kind == TokenKind_paren_l) {
+ e = ast_new(AstNodeKind_func_call);
+ int func_idx = find_func(p, name);
+ if (func_idx == -1) {
+ buf = calloc(1024, sizeof(char));
+ sprintf(buf, "undefined function: %.*s", name->len, name->data);
+ fatal_error(buf);
+ }
+ e->name.data = name->data;
+ e->name.len = name->len;
+ e->ty = p->funcs[func_idx].ty;
+ return e;
+ }
+
+ int lvar_idx = find_lvar(p, name);
+ if (lvar_idx == -1) {
+ int gvar_idx = find_gvar(p, name);
+ if (gvar_idx == -1) {
+ int enum_member_idx = find_enum_member(p, name);
+ if (enum_member_idx == -1) {
+ buf = calloc(1024, sizeof(char));
+ sprintf(buf, "undefined variable: %.*s", name->len, name->data);
+ fatal_error(buf);
+ }
+ int enum_idx = enum_member_idx / 1000;
+ int n = enum_member_idx % 1000;
+ e = ast_new_int(p->enums[enum_idx].node_members->node_items[n].node_int_value);
+ e->ty = type_new(TypeKind_enum);
+ e->ty->def = p->enums + enum_idx;
+ return e;
+ }
+ e = ast_new(AstNodeKind_gvar);
+ e->name.data = name->data;
+ e->name.len = name->len;
+ e->ty = p->gvars[gvar_idx].ty;
+ return e;
+ }
+
+ e = ast_new(AstNodeKind_lvar);
+ e->name.data = name->data;
+ e->name.len = name->len;
+ e->node_idx = lvar_idx;
+ e->ty = p->lvars[lvar_idx].ty;
+ return e;
+ } else {
+ buf = calloc(1024, sizeof(char));
+ sprintf(buf, "expected primary expression, but got '%s'", token_stringify(t));
+ fatal_error(buf);
+ }
+}
+
+AstNode* parse_arg_list(Parser* p) {
+ AstNode* list = ast_new_list(6);
+ while (peek_token(p)->kind != TokenKind_paren_r) {
+ AstNode* arg = parse_expr(p);
+ ast_append(list, arg);
+ if (peek_token(p)->kind == TokenKind_comma) {
+ next_token(p);
+ } else {
+ break;
+ }
+ }
+ if (list->node_len > 6) {
+ fatal_error("too many arguments");
+ }
+ return list;
+}
+
+AstNode* parse_postfix_expr(Parser* p) {
+ AstNode* ret = parse_primary_expr(p);
+ String* name;
+ while (1) {
+ TokenKind tk = peek_token(p)->kind;
+ if (tk == TokenKind_paren_l) {
+ next_token(p);
+ AstNode* args = parse_arg_list(p);
+ expect(p, TokenKind_paren_r);
+ ret->node_args = args;
+ } else if (tk == TokenKind_bracket_l) {
+ next_token(p);
+ AstNode* idx = parse_expr(p);
+ expect(p, TokenKind_bracket_r);
+ idx = ast_new_binary_expr(TokenKind_star, idx, ast_new_int(type_sizeof(ret->ty->to)));
+ ret = ast_new_deref_expr(ast_new_binary_expr(TokenKind_plus, ret, idx));
+ } else if (tk == TokenKind_dot) {
+ next_token(p);
+ name = parse_ident(p);
+ ret = ast_new_member_access_expr(ast_new_ref_expr(ret), name);
+ } else if (tk == TokenKind_arrow) {
+ next_token(p);
+ name = parse_ident(p);
+ ret = ast_new_member_access_expr(ret, name);
+ } else {
+ break;
+ }
+ }
+ return ret;
+}
+
+int is_type_token(Parser* p, Token* token) {
+ if (token->kind == TokenKind_keyword_int || token->kind == TokenKind_keyword_long ||
+ token->kind == TokenKind_keyword_char || token->kind == TokenKind_keyword_void ||
+ token->kind == TokenKind_keyword_enum || token->kind == TokenKind_keyword_struct ||
+ token->kind == TokenKind_keyword_const) {
+ return 1;
+ }
+ if (token->kind != TokenKind_ident) {
+ return 0;
+ }
+ return find_typedef(p, &token->raw) != -1;
+}
+
+Type* parse_type(Parser* p) {
+ Token* t = next_token(p);
+ char* buf;
+ String* name;
+ if (t->kind == TokenKind_keyword_const) {
+ t = next_token(p);
+ }
+ if (!is_type_token(p, t)) {
+ buf = calloc(1024, sizeof(char));
+ sprintf(buf, "parse_type: expected type, but got '%s'", token_stringify(t));
+ fatal_error(buf);
+ }
+ Type* ty;
+ if (t->kind == TokenKind_ident) {
+ int typedef_idx = find_typedef(p, &t->raw);
+ if (typedef_idx == -1) {
+ buf = calloc(1024, sizeof(char));
+ sprintf(buf, "parse_type: unknown typedef, %.*s", t->raw.len, t->raw.data);
+ fatal_error(buf);
+ }
+ ty = p->typedefs[typedef_idx].ty;
+ } else {
+ ty = type_new(TypeKind_unknown);
+ if (t->kind == TokenKind_keyword_int) {
+ ty->kind = TypeKind_int;
+ } else if (t->kind == TokenKind_keyword_long) {
+ ty->kind = TypeKind_long;
+ } else if (t->kind == TokenKind_keyword_char) {
+ ty->kind = TypeKind_char;
+ } else if (t->kind == TokenKind_keyword_void) {
+ ty->kind = TypeKind_void;
+ } else if (t->kind == TokenKind_keyword_enum) {
+ ty->kind = TypeKind_enum;
+ name = parse_ident(p);
+ int enum_idx = find_enum(p, name);
+ if (enum_idx == -1) {
+ buf = calloc(1024, sizeof(char));
+ sprintf(buf, "parse_type: unknown enum, %.*s", name->len, name->data);
+ fatal_error(buf);
+ }
+ ty->def = p->enums + enum_idx;
+ } else if (t->kind == TokenKind_keyword_struct) {
+ ty->kind = TypeKind_struct;
+ name = parse_ident(p);
+ int struct_idx = find_struct(p, name);
+ if (struct_idx == -1) {
+ buf = calloc(1024, sizeof(char));
+ sprintf(buf, "parse_type: unknown struct, %.*s", name->len, name->data);
+ fatal_error(buf);
+ }
+ ty->def = p->structs + struct_idx;
+ } else {
+ unreachable();
+ }
+ }
+ while (1) {
+ if (peek_token(p)->kind == TokenKind_star) {
+ next_token(p);
+ ty = type_new_ptr(ty);
+ } else {
+ break;
+ }
+ }
+ return ty;
+}
+
+AstNode* parse_prefix_expr(Parser* p) {
+ AstNode* operand;
+ TokenKind op = peek_token(p)->kind;
+ if (op == TokenKind_minus) {
+ next_token(p);
+ operand = parse_prefix_expr(p);
+ return ast_new_binary_expr(op, ast_new_int(0), operand);
+ } else if (op == TokenKind_not) {
+ next_token(p);
+ operand = parse_prefix_expr(p);
+ return ast_new_unary_expr(op, operand);
+ } else if (op == TokenKind_and) {
+ next_token(p);
+ operand = parse_prefix_expr(p);
+ return ast_new_ref_expr(operand);
+ } else if (op == TokenKind_star) {
+ next_token(p);
+ operand = parse_prefix_expr(p);
+ return ast_new_deref_expr(operand);
+ } else if (op == TokenKind_plusplus) {
+ next_token(p);
+ operand = parse_prefix_expr(p);
+ return ast_new_assign_add_expr(operand, ast_new_int(1));
+ } else if (op == TokenKind_minusminus) {
+ next_token(p);
+ operand = parse_prefix_expr(p);
+ return ast_new_assign_sub_expr(operand, ast_new_int(1));
+ } else if (op == TokenKind_keyword_sizeof) {
+ next_token(p);
+ expect(p, TokenKind_paren_l);
+ Type* ty = parse_type(p);
+ expect(p, TokenKind_paren_r);
+ return ast_new_int(type_sizeof(ty));
+ }
+ return parse_postfix_expr(p);
+}
+
+AstNode* parse_multiplicative_expr(Parser* p) {
+ AstNode* lhs = parse_prefix_expr(p);
+ while (1) {
+ TokenKind op = peek_token(p)->kind;
+ if (op == TokenKind_star || op == TokenKind_slash || op == TokenKind_percent) {
+ next_token(p);
+ AstNode* rhs = parse_prefix_expr(p);
+ lhs = ast_new_binary_expr(op, lhs, rhs);
+ } else {
+ break;
+ }
+ }
+ return lhs;
+}
+
+AstNode* parse_additive_expr(Parser* p) {
+ AstNode* lhs = parse_multiplicative_expr(p);
+ AstNode* rhs;
+ while (1) {
+ TokenKind op = peek_token(p)->kind;
+ if (op == TokenKind_plus) {
+ next_token(p);
+ rhs = parse_multiplicative_expr(p);
+ if (lhs->ty->kind == TypeKind_ptr) {
+ lhs = ast_new_binary_expr(
+ op, lhs, ast_new_binary_expr(TokenKind_star, rhs, ast_new_int(type_sizeof(lhs->ty->to))));
+ } else if (rhs->ty->kind == TypeKind_ptr) {
+ lhs = ast_new_binary_expr(
+ op, ast_new_binary_expr(TokenKind_star, lhs, ast_new_int(type_sizeof(rhs->ty->to))), rhs);
+ } else {
+ lhs = ast_new_binary_expr(op, lhs, rhs);
+ }
+ } else if (op == TokenKind_minus) {
+ next_token(p);
+ rhs = parse_multiplicative_expr(p);
+ if (lhs->ty->kind == TypeKind_ptr) {
+ if (rhs->ty->kind == TypeKind_ptr) {
+ // (a - b) / sizeof(a)
+ lhs = ast_new_binary_expr(TokenKind_slash, ast_new_binary_expr(op, lhs, rhs),
+ ast_new_int(type_sizeof(lhs->ty->to)));
+ } else {
+ // a - b*sizeof(a)
+ lhs = ast_new_binary_expr(
+ op, lhs, ast_new_binary_expr(TokenKind_star, rhs, ast_new_int(type_sizeof(lhs->ty->to))));
+ }
+ } else {
+ lhs = ast_new_binary_expr(op, lhs, rhs);
+ }
+ } else {
+ break;
+ }
+ }
+ return lhs;
+}
+
+AstNode* parse_relational_expr(Parser* p) {
+ AstNode* lhs = parse_additive_expr(p);
+ AstNode* rhs;
+ while (1) {
+ TokenKind op = peek_token(p)->kind;
+ if (op == TokenKind_lt || op == TokenKind_le) {
+ next_token(p);
+ rhs = parse_additive_expr(p);
+ lhs = ast_new_binary_expr(op, lhs, rhs);
+ } else if (op == TokenKind_gt) {
+ next_token(p);
+ rhs = parse_additive_expr(p);
+ lhs = ast_new_binary_expr(TokenKind_lt, rhs, lhs);
+ } else if (op == TokenKind_ge) {
+ next_token(p);
+ rhs = parse_additive_expr(p);
+ lhs = ast_new_binary_expr(TokenKind_le, rhs, lhs);
+ } else {
+ break;
+ }
+ }
+ return lhs;
+}
+
+AstNode* parse_equality_expr(Parser* p) {
+ AstNode* lhs = parse_relational_expr(p);
+ while (1) {
+ TokenKind op = peek_token(p)->kind;
+ if (op == TokenKind_eq || op == TokenKind_ne) {
+ next_token(p);
+ AstNode* rhs = parse_relational_expr(p);
+ lhs = ast_new_binary_expr(op, lhs, rhs);
+ } else {
+ break;
+ }
+ }
+ return lhs;
+}
+
+AstNode* parse_logical_and_expr(Parser* p) {
+ AstNode* lhs = parse_equality_expr(p);
+ while (1) {
+ TokenKind op = peek_token(p)->kind;
+ if (op == TokenKind_andand) {
+ next_token(p);
+ AstNode* rhs = parse_equality_expr(p);
+ AstNode* e = ast_new(AstNodeKind_logical_expr);
+ e->node_op = op;
+ e->node_lhs = lhs;
+ e->node_rhs = rhs;
+ e->ty = type_new(TypeKind_int);
+ lhs = e;
+ } else {
+ break;
+ }
+ }
+ return lhs;
+}
+
+AstNode* parse_logical_or_expr(Parser* p) {
+ AstNode* lhs = parse_logical_and_expr(p);
+ while (1) {
+ TokenKind op = peek_token(p)->kind;
+ if (op == TokenKind_oror) {
+ next_token(p);
+ AstNode* rhs = parse_logical_and_expr(p);
+ AstNode* e = ast_new(AstNodeKind_logical_expr);
+ e->node_op = op;
+ e->node_lhs = lhs;
+ e->node_rhs = rhs;
+ e->ty = type_new(TypeKind_int);
+ lhs = e;
+ } else {
+ break;
+ }
+ }
+ return lhs;
+}
+
+AstNode* parse_assignment_expr(Parser* p) {
+ AstNode* lhs = parse_logical_or_expr(p);
+ AstNode* rhs;
+ while (1) {
+ TokenKind op = peek_token(p)->kind;
+ if (op == TokenKind_assign) {
+ next_token(p);
+ rhs = parse_logical_or_expr(p);
+ lhs = ast_new_assign_expr(op, lhs, rhs);
+ } else if (op == TokenKind_assign_add) {
+ next_token(p);
+ rhs = parse_logical_or_expr(p);
+ lhs = ast_new_assign_add_expr(lhs, rhs);
+ } else if (op == TokenKind_assign_sub) {
+ next_token(p);
+ rhs = parse_logical_or_expr(p);
+ lhs = ast_new_assign_sub_expr(lhs, rhs);
+ } else {
+ break;
+ }
+ }
+ return lhs;
+}
+
+AstNode* parse_expr(Parser* p) {
+ return parse_assignment_expr(p);
+}
+
+AstNode* parse_return_stmt(Parser* p) {
+ expect(p, TokenKind_keyword_return);
+ if (peek_token(p)->kind == TokenKind_semicolon) {
+ next_token(p);
+ return ast_new(AstNodeKind_return_stmt);
+ }
+
+ AstNode* expr = parse_expr(p);
+ expect(p, TokenKind_semicolon);
+
+ AstNode* ret = ast_new(AstNodeKind_return_stmt);
+ ret->node_expr = expr;
+ return ret;
+}
+
+AstNode* parse_if_stmt(Parser* p) {
+ expect(p, TokenKind_keyword_if);
+ expect(p, TokenKind_paren_l);
+ AstNode* cond = parse_expr(p);
+ expect(p, TokenKind_paren_r);
+ AstNode* then_body = parse_stmt(p);
+ AstNode* else_body = NULL;
+ if (peek_token(p)->kind == TokenKind_keyword_else) {
+ next_token(p);
+ else_body = parse_stmt(p);
+ }
+
+ AstNode* stmt = ast_new(AstNodeKind_if_stmt);
+ stmt->node_cond = cond;
+ stmt->node_then = then_body;
+ stmt->node_else = else_body;
+ return stmt;
+}
+
+AstNode* parse_for_stmt(Parser* p) {
+ expect(p, TokenKind_keyword_for);
+ expect(p, TokenKind_paren_l);
+ AstNode* init = NULL;
+ AstNode* cond = NULL;
+ AstNode* update = NULL;
+ if (peek_token(p)->kind != TokenKind_semicolon) {
+ init = parse_expr(p);
+ }
+ expect(p, TokenKind_semicolon);
+ if (peek_token(p)->kind != TokenKind_semicolon) {
+ cond = parse_expr(p);
+ } else {
+ cond = ast_new_int(1);
+ }
+ expect(p, TokenKind_semicolon);
+ if (peek_token(p)->kind != TokenKind_paren_r) {
+ update = parse_expr(p);
+ }
+ expect(p, TokenKind_paren_r);
+ AstNode* body = parse_stmt(p);
+
+ AstNode* stmt = ast_new(AstNodeKind_for_stmt);
+ stmt->node_cond = cond;
+ stmt->node_init = init;
+ stmt->node_update = update;
+ stmt->node_body = body;
+ return stmt;
+}
+
+AstNode* parse_while_stmt(Parser* p) {
+ expect(p, TokenKind_keyword_while);
+ expect(p, TokenKind_paren_l);
+ AstNode* cond = parse_expr(p);
+ expect(p, TokenKind_paren_r);
+ AstNode* body = parse_stmt(p);
+
+ AstNode* stmt = ast_new(AstNodeKind_for_stmt);
+ stmt->node_cond = cond;
+ stmt->node_body = body;
+ return stmt;
+}
+
+AstNode* parse_do_while_stmt(Parser* p) {
+ expect(p, TokenKind_keyword_do);
+ AstNode* body = parse_stmt(p);
+ expect(p, TokenKind_keyword_while);
+ expect(p, TokenKind_paren_l);
+ AstNode* cond = parse_expr(p);
+ expect(p, TokenKind_paren_r);
+ expect(p, TokenKind_semicolon);
+
+ AstNode* stmt = ast_new(AstNodeKind_do_while_stmt);
+ stmt->node_cond = cond;
+ stmt->node_body = body;
+ return stmt;
+}
+
+AstNode* parse_break_stmt(Parser* p) {
+ expect(p, TokenKind_keyword_break);
+ expect(p, TokenKind_semicolon);
+ return ast_new(AstNodeKind_break_stmt);
+}
+
+AstNode* parse_continue_stmt(Parser* p) {
+ expect(p, TokenKind_keyword_continue);
+ expect(p, TokenKind_semicolon);
+ return ast_new(AstNodeKind_continue_stmt);
+}
+
+AstNode* parse_var_decl(Parser* p) {
+ Type* ty = parse_type(p);
+ if (!type_is_unsized(ty)) {
+ fatal_error("parse_var_decl: invalid type for variable");
+ }
+ String* name = parse_ident(p);
+
+ AstNode* init = NULL;
+ if (peek_token(p)->kind == TokenKind_assign) {
+ next_token(p);
+ init = parse_expr(p);
+ }
+ expect(p, TokenKind_semicolon);
+
+ if (find_lvar(p, name) != -1 || find_gvar(p, name) != -1) {
+ char* buf = calloc(1024, sizeof(char));
+ sprintf(buf, "parse_var_decl: %.*s redeclared", name->len, name->data);
+ fatal_error(buf);
+ }
+ p->lvars[p->n_lvars].name.data = name->data;
+ p->lvars[p->n_lvars].name.len = name->len;
+ p->lvars[p->n_lvars].ty = ty;
+ ++p->n_lvars;
+
+ AstNode* ret;
+ if (init) {
+ AstNode* lhs = ast_new(AstNodeKind_lvar);
+ lhs->name.data = name->data;
+ lhs->name.len = name->len;
+ lhs->node_idx = p->n_lvars - 1;
+ lhs->ty = ty;
+ AstNode* assign = ast_new_assign_expr(TokenKind_assign, lhs, init);
+ ret = ast_new(AstNodeKind_expr_stmt);
+ ret->node_expr = assign;
+ } else {
+ ret = ast_new(AstNodeKind_lvar_decl);
+ }
+ return ret;
+}
+
+AstNode* parse_expr_stmt(Parser* p) {
+ AstNode* e = parse_expr(p);
+ expect(p, TokenKind_semicolon);
+ AstNode* stmt = ast_new(AstNodeKind_expr_stmt);
+ stmt->node_expr = e;
+ return stmt;
+}
+
+AstNode* parse_block_stmt(Parser* p) {
+ AstNode* list = ast_new_list(1024);
+ expect(p, TokenKind_brace_l);
+ while (peek_token(p)->kind != TokenKind_brace_r) {
+ AstNode* stmt = parse_stmt(p);
+ ast_append(list, stmt);
+ }
+ expect(p, TokenKind_brace_r);
+ return list;
+}
+
+AstNode* parse_stmt(Parser* p) {
+ Token* t = peek_token(p);
+ if (t->kind == TokenKind_keyword_return) {
+ return parse_return_stmt(p);
+ } else if (t->kind == TokenKind_keyword_if) {
+ return parse_if_stmt(p);
+ } else if (t->kind == TokenKind_keyword_for) {
+ return parse_for_stmt(p);
+ } else if (t->kind == TokenKind_keyword_while) {
+ return parse_while_stmt(p);
+ } else if (t->kind == TokenKind_keyword_do) {
+ return parse_do_while_stmt(p);
+ } else if (t->kind == TokenKind_keyword_break) {
+ return parse_break_stmt(p);
+ } else if (t->kind == TokenKind_keyword_continue) {
+ return parse_continue_stmt(p);
+ } else if (t->kind == TokenKind_brace_l) {
+ return parse_block_stmt(p);
+ } else if (is_type_token(p, t)) {
+ return parse_var_decl(p);
+ } else {
+ return parse_expr_stmt(p);
+ }
+}
+
+void enter_func(Parser* p) {
+ p->lvars = calloc(LVAR_MAX, sizeof(LocalVar));
+ p->n_lvars = 0;
+}
+
+void register_params(Parser* p, AstNode* params) {
+ int i;
+ for (i = 0; i < params->node_len; ++i) {
+ AstNode* param = params->node_items + i;
+ p->lvars[p->n_lvars].name.data = param->name.data;
+ p->lvars[p->n_lvars].name.len = param->name.len;
+ p->lvars[p->n_lvars].ty = param->ty;
+ ++p->n_lvars;
+ }
+}
+
+void register_func(Parser* p, const String* name, Type* ty) {
+ p->funcs[p->n_funcs].name.data = name->data;
+ p->funcs[p->n_funcs].name.len = name->len;
+ p->funcs[p->n_funcs].ty = ty;
+ ++p->n_funcs;
+}
+
+AstNode* parse_param(Parser* p) {
+ Type* ty = parse_type(p);
+ String* name = NULL;
+ TokenKind tk = peek_token(p)->kind;
+ if (tk != TokenKind_comma && tk != TokenKind_paren_r) {
+ name = parse_ident(p);
+ }
+ AstNode* param = ast_new(AstNodeKind_param);
+ param->ty = ty;
+ if (name) {
+ param->name.data = name->data;
+ param->name.len = name->len;
+ }
+ return param;
+}
+
+AstNode* parse_param_list(Parser* p) {
+ int has_void = 0;
+ AstNode* list = ast_new_list(6);
+ while (peek_token(p)->kind != TokenKind_paren_r) {
+ if (peek_token(p)->kind == TokenKind_ellipsis) {
+ next_token(p);
+ break;
+ }
+ AstNode* param = parse_param(p);
+ has_void = has_void || param->ty->kind == TypeKind_void;
+ ast_append(list, param);
+ if (peek_token(p)->kind == TokenKind_comma) {
+ next_token(p);
+ } else {
+ break;
+ }
+ }
+ if (list->node_len > 6) {
+ fatal_error("too many parameters");
+ }
+ if (has_void) {
+ if (list->node_len != 1) {
+ fatal_error("invalid use of void param");
+ }
+ list->node_len = 0;
+ }
+ return list;
+}
+
+AstNode* parse_func_decl_or_def(Parser* p) {
+ Type* ty = parse_type(p);
+ String* name = parse_ident(p);
+ register_func(p, name, ty);
+ expect(p, TokenKind_paren_l);
+ AstNode* params = parse_param_list(p);
+ expect(p, TokenKind_paren_r);
+ if (peek_token(p)->kind == TokenKind_semicolon) {
+ next_token(p);
+ return ast_new(AstNodeKind_func_decl);
+ }
+ enter_func(p);
+ register_params(p, params);
+ AstNode* body = parse_block_stmt(p);
+ AstNode* func = ast_new(AstNodeKind_func_def);
+ func->ty = ty;
+ func->name.data = name->data;
+ func->name.len = name->len;
+ func->node_params = params;
+ func->node_body = body;
+ return func;
+}
+
+AstNode* parse_struct_member(Parser* p) {
+ Type* ty = parse_type(p);
+ String* name = parse_ident(p);
+ expect(p, TokenKind_semicolon);
+ AstNode* member = ast_new(AstNodeKind_struct_member);
+ member->name.data = name->data;
+ member->name.len = name->len;
+ member->ty = ty;
+ return member;
+}
+
+AstNode* parse_struct_members(Parser* p) {
+ AstNode* list = ast_new_list(16);
+ while (peek_token(p)->kind != TokenKind_brace_r) {
+ AstNode* member = parse_struct_member(p);
+ ast_append(list, member);
+ }
+ return list;
+}
+
+AstNode* parse_struct_decl_or_def(Parser* p) {
+ expect(p, TokenKind_keyword_struct);
+ String* name = parse_ident(p);
+
+ if (peek_token(p)->kind != TokenKind_semicolon && peek_token(p)->kind != TokenKind_brace_l) {
+ p->pos = p->pos - 2;
+ return parse_func_decl_or_def(p);
+ }
+
+ int struct_idx = find_struct(p, name);
+ if (struct_idx == -1) {
+ struct_idx = p->n_structs;
+ p->structs[struct_idx].kind = AstNodeKind_struct_def;
+ p->structs[struct_idx].name.data = name->data;
+ p->structs[struct_idx].name.len = name->len;
+ ++p->n_structs;
+ }
+ if (peek_token(p)->kind == TokenKind_semicolon) {
+ next_token(p);
+ return ast_new(AstNodeKind_struct_decl);
+ }
+ if (p->structs[struct_idx].node_members) {
+ char* buf = calloc(1024, sizeof(char));
+ sprintf(buf, "parse_struct_decl_or_def: struct %.*s redefined", name->len, name->data);
+ fatal_error(buf);
+ }
+ expect(p, TokenKind_brace_l);
+ AstNode* members = parse_struct_members(p);
+ expect(p, TokenKind_brace_r);
+ expect(p, TokenKind_semicolon);
+ p->structs[struct_idx].node_members = members;
+ return p->structs + struct_idx;
+}
+
+AstNode* parse_enum_member(Parser* p) {
+ String* name = parse_ident(p);
+ AstNode* member = ast_new(AstNodeKind_enum_member);
+ member->name.data = name->data;
+ member->name.len = name->len;
+ return member;
+}
+
+AstNode* parse_enum_members(Parser* p) {
+ int next_value = 0;
+ AstNode* list = ast_new_list(256);
+ while (peek_token(p)->kind != TokenKind_brace_r) {
+ AstNode* member = parse_enum_member(p);
+ member->node_int_value = next_value;
+ ++next_value;
+ ast_append(list, member);
+ if (peek_token(p)->kind != TokenKind_comma) {
+ break;
+ }
+ next_token(p);
+ }
+ return list;
+}
+
+AstNode* parse_enum_def(Parser* p) {
+ expect(p, TokenKind_keyword_enum);
+ String* name = parse_ident(p);
+
+ if (peek_token(p)->kind != TokenKind_brace_l) {
+ p->pos = p->pos - 2;
+ return parse_func_decl_or_def(p);
+ }
+
+ int enum_idx = find_enum(p, name);
+ if (enum_idx == -1) {
+ enum_idx = p->n_enums;
+ p->enums[enum_idx].kind = AstNodeKind_enum_def;
+ p->enums[enum_idx].name.data = name->data;
+ p->enums[enum_idx].name.len = name->len;
+ ++p->n_enums;
+ } else {
+ char* buf = calloc(1024, sizeof(char));
+ sprintf(buf, "parse_enum_def: enum %.*s redefined", name->len, name->data);
+ fatal_error(buf);
+ }
+ expect(p, TokenKind_brace_l);
+ AstNode* members = parse_enum_members(p);
+ expect(p, TokenKind_brace_r);
+ expect(p, TokenKind_semicolon);
+ p->enums[enum_idx].node_members = members;
+ return p->enums + enum_idx;
+}
+
+AstNode* parse_typedef_decl(Parser* p) {
+ expect(p, TokenKind_keyword_typeof);
+ Type* ty = parse_type(p);
+ String* name = parse_ident(p);
+ expect(p, TokenKind_semicolon);
+ AstNode* decl = ast_new(AstNodeKind_typedef_decl);
+ decl->name.data = name->data;
+ decl->name.len = name->len;
+ decl->ty = ty;
+ p->typedefs[p->n_typedefs].name.data = name->data;
+ p->typedefs[p->n_typedefs].name.len = name->len;
+ p->typedefs[p->n_typedefs].ty = ty;
+ ++p->n_typedefs;
+ return decl;
+}
+
+AstNode* parse_extern_var_decl(Parser* p) {
+ expect(p, TokenKind_keyword_extern);
+ Type* ty = parse_type(p);
+ if (!type_is_unsized(ty)) {
+ fatal_error("parse_extern_var_decl: invalid type for variable");
+ }
+ String* name = parse_ident(p);
+ expect(p, TokenKind_semicolon);
+
+ if (find_lvar(p, name) != -1 || find_gvar(p, name) != -1) {
+ char* buf = calloc(1024, sizeof(char));
+ sprintf(buf, "parse_extern_var_decl: %.*s redeclared", name->len, name->data);
+ fatal_error(buf);
+ }
+ p->gvars[p->n_gvars].name.data = name->data;
+ p->gvars[p->n_gvars].name.len = name->len;
+ p->gvars[p->n_gvars].ty = ty;
+ ++p->n_gvars;
+
+ return ast_new(AstNodeKind_gvar_decl);
+}
+
+AstNode* parse_toplevel(Parser* p) {
+ TokenKind tk = peek_token(p)->kind;
+ if (tk == TokenKind_keyword_struct) {
+ return parse_struct_decl_or_def(p);
+ } else if (tk == TokenKind_keyword_enum) {
+ return parse_enum_def(p);
+ } else if (tk == TokenKind_keyword_typeof) {
+ return parse_typedef_decl(p);
+ } else if (tk == TokenKind_keyword_extern) {
+ return parse_extern_var_decl(p);
+ } else {
+ return parse_func_decl_or_def(p);
+ }
+}
+
+Program* parse(Token* tokens) {
+ Parser* p = parser_new(tokens);
+ AstNode* funcs = ast_new_list(1024);
+ while (eof(p)) {
+ AstNode* n = parse_toplevel(p);
+ if (n->kind == AstNodeKind_func_def) {
+ ast_append(funcs, n);
+ }
+ }
+ Program* prog = calloc(1, sizeof(Program));
+ prog->funcs = funcs;
+ prog->str_literals = p->str_literals;
+ return prog;
+}