117 lines
2.7 KiB
C
117 lines
2.7 KiB
C
#include "ast.h"
|
|
|
|
struct Parser {
|
|
Token* tokens;
|
|
int current;
|
|
}
|
|
|
|
Token peek(Parser* p);
|
|
Token advance(Parser* p);
|
|
bool match(Parser* p, TokenKind kind);
|
|
bool expect(Parser* p, TokenKind kind, const char* error);
|
|
bool is_at_end(Parser* p);
|
|
|
|
List<ASTNode> parse_program(Parser* p) {
|
|
List<ASTNode> nodes;
|
|
|
|
while (!is_at_end(p)) {
|
|
nodes.append(parse_toplevel(p));
|
|
}
|
|
|
|
return nodes;
|
|
}
|
|
|
|
ASTNode parse_toplevel(Parser* p) {
|
|
if (match(p, KW_FN)) return parse_function(p);
|
|
if (match(p, KW_TYPEDEF)) return parse_typedef(p);
|
|
if (match(p, KW_STRUCT)) return parse_struct(p);
|
|
error("Unexpected top-level declaration");
|
|
}
|
|
|
|
ASTNode parse_function(Parser* p) {
|
|
ASTNode node;
|
|
node.kind = NODE_FUNCTION;
|
|
|
|
FunctionNode fn;
|
|
|
|
// Qualifiers (optional)
|
|
while (match(p, KW_STATIC) || match(p, KW_EXPORT) || match(p, KW_INLINE) || match(p, KW_EXTERN) || match(p, KW_ASM)) {
|
|
switch (previous(p).kind) {
|
|
case KW_STATIC: fn.is_static = true; break;
|
|
case KW_EXPORT: fn.is_export = true; break;
|
|
case KW_INLINE: fn.is_inline = true; break;
|
|
case KW_EXTERN: fn.is_extern = true; break;
|
|
case KW_ASM: fn.is_asm = true; break;
|
|
}
|
|
}
|
|
|
|
// Return type
|
|
fn.return_type = expect_identifier(p);
|
|
|
|
// Name
|
|
fn.name = expect_identifier(p);
|
|
|
|
// Parameters
|
|
expect(p, TOKEN_LPAREN, "Expected '(' after function name");
|
|
while (!match(p, TOKEN_RPAREN)) {
|
|
fn.params.append(parse_var_decl(p));
|
|
if (!match(p, TOKEN_RPAREN)) expect(p, TOKEN_COMMA, "Expected ',' between parameters");
|
|
}
|
|
|
|
// Body or semicolon (extern only)
|
|
if (fn.is_extern) {
|
|
expect(p, TOKEN_SEMICOLON, "Expected ';' after extern declaration");
|
|
fn.body = NULL;
|
|
} else {
|
|
fn.body = parse_block(p);
|
|
}
|
|
|
|
node.fn = fn;
|
|
return node;
|
|
}
|
|
|
|
VarDeclNode parse_var_decl(Parser* p) {
|
|
VarDeclNode var;
|
|
var.type = expect_identifier(p);
|
|
var.name = expect_identifier(p);
|
|
|
|
if (match(p, TOKEN_ASSIGN)) {
|
|
var.init = parse_expression(p);
|
|
}
|
|
|
|
return var;
|
|
}
|
|
|
|
ASTNode parse_struct(Parser* p) {
|
|
expect(p, KW_STRUCT, "Expected 'struct'");
|
|
String name = expect_identifier(p);
|
|
|
|
expect(p, TOKEN_LBRACE, "Expected '{' for struct definition");
|
|
|
|
List<VarDeclNode> fields;
|
|
while (!match(p, TOKEN_RBRACE)) {
|
|
fields.append(parse_var_decl(p));
|
|
expect(p, TOKEN_SEMICOLON, "Expected ';' after struct field");
|
|
}
|
|
|
|
StructNode str = { .name = name, .fields = fields };
|
|
ASTNode node = { .kind = NODE_STRUCT, .str = str };
|
|
return node;
|
|
}
|
|
|
|
BlockNode parse_block(Parser* p) {
|
|
BlockNode block;
|
|
|
|
expect(p, TOKEN_LBRACE, "Expected '{'");
|
|
while (!match(p, TOKEN_RBRACE)) {
|
|
block.statements.append(parse_statement(p));
|
|
}
|
|
|
|
return block;
|
|
}
|
|
|
|
ExprNode* parse_expression(Parser* p);
|
|
ExprNode* parse_primary(Parser* p);
|
|
ExprNode* parse_binary(Parser* p, int min_prec);
|
|
ExprNode* parse_call(Parser* p, ExprNode* callee);
|