diff options
Diffstat (limited to 'src/parser')
| -rw-r--r-- | src/parser/ast.c | 46 | ||||
| -rw-r--r-- | src/parser/ast.h | 22 | ||||
| -rw-r--r-- | src/parser/parser.c | 86 |
3 files changed, 154 insertions, 0 deletions
diff --git a/src/parser/ast.c b/src/parser/ast.c index 3f360cc..b002ff2 100644 --- a/src/parser/ast.c +++ b/src/parser/ast.c @@ -11,6 +11,9 @@ struct Program create_program(void) program.data_decls = NULL; program.data_count = 0; program.data_capacity = 0; + program.procs = NULL; + program.proc_count = 0; + program.proc_capacity = 0; return program; } @@ -18,12 +21,20 @@ void free_program(struct Program* program) { free(program->consts); free(program->data_decls); + + for (size_t i = 0; i < program->proc_count; i += 1) + free(program->procs[i].params); + free(program->procs); + program->consts = NULL; program->const_count = 0; program->const_capacity = 0; program->data_decls = NULL; program->data_count = 0; program->data_capacity = 0; + program->procs = NULL; + program->proc_count = 0; + program->proc_capacity = 0; } // TODO: generalize this growable-array boilerplate once a third list appears @@ -52,3 +63,38 @@ void add_data(struct Program* program, struct DataDecl decl) program->data_decls[program->data_count] = decl; program->data_count += 1; } + +struct ProcDecl create_proc(void) +{ + struct ProcDecl proc; + proc.params = NULL; + proc.param_count = 0; + proc.param_capacity = 0; + return proc; +} + +void add_param(struct ProcDecl* proc, struct Param param) +{ + if (proc->param_count == proc->param_capacity) + { + size_t capacity = proc->param_capacity < 4 ? 4 : proc->param_capacity * 2; + proc->params = realloc(proc->params, capacity * sizeof(struct Param)); + proc->param_capacity = capacity; + } + + proc->params[proc->param_count] = param; + proc->param_count += 1; +} + +void add_proc(struct Program* program, struct ProcDecl decl) +{ + if (program->proc_count == program->proc_capacity) + { + size_t capacity = program->proc_capacity < 8 ? 8 : program->proc_capacity * 2; + program->procs = realloc(program->procs, capacity * sizeof(struct ProcDecl)); + program->proc_capacity = capacity; + } + + program->procs[program->proc_count] = decl; + program->proc_count += 1; +} diff --git a/src/parser/ast.h b/src/parser/ast.h index 30dd1e7..665bfd2 100644 --- a/src/parser/ast.h +++ b/src/parser/ast.h @@ -16,6 +16,20 @@ struct DataDecl struct Token value; }; +struct Param +{ + struct Token name; + struct Token reg; +}; + +struct ProcDecl +{ + struct Token name; + struct Param* params; + size_t param_count; + size_t param_capacity; +}; + struct Program { struct ConstDecl* consts; @@ -25,9 +39,17 @@ struct Program struct DataDecl* data_decls; size_t data_count; size_t data_capacity; + + struct ProcDecl* procs; + size_t proc_count; + size_t proc_capacity; }; struct Program create_program(void); void free_program(struct Program* program); void add_const(struct Program* program, struct ConstDecl decl); void add_data(struct Program* program, struct DataDecl decl); + +struct ProcDecl create_proc(void); +void add_param(struct ProcDecl* proc, struct Param param); +void add_proc(struct Program* program, struct ProcDecl decl); diff --git a/src/parser/parser.c b/src/parser/parser.c index 4fb85ef..acd4b7a 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -1,4 +1,5 @@ #include <stdio.h> +#include <stdlib.h> #include "parser/parser.h" @@ -27,6 +28,15 @@ static void error_at(struct Parser* parser, struct Token token, const char* mess parser->had_error = true; } +static bool match_token(struct Parser* parser, enum TokenType type) +{ + if (!check(parser, type)) + return false; + + advance_parser(parser); + return true; +} + static bool consume(struct Parser* parser, enum TokenType type, const char* message) { if (check(parser, type)) @@ -77,6 +87,76 @@ static bool parse_data(struct Parser* parser, struct Program* program) return true; } +static bool parse_params(struct Parser* parser, struct ProcDecl* proc) +{ + if (check(parser, TOKEN_RIGHT_PAREN)) + return true; + + do + { + struct Param param; + + if (!consume(parser, TOKEN_IDENTIFIER, "expected parameter name")) + return false; + param.name = parser->previous; + + if (!consume(parser, TOKEN_COLON, "expected ':' after parameter name")) + return false; + + if (!consume(parser, TOKEN_IDENTIFIER, "expected register after ':'")) + return false; + param.reg = parser->previous; + + add_param(proc, param); + } + while (match_token(parser, TOKEN_COMMA)); + + return true; +} + +static bool parse_proc(struct Parser* parser, struct Program* program) +{ + struct ProcDecl decl = create_proc(); + + if (!consume(parser, TOKEN_IDENTIFIER, "expected procedure name after 'proc'")) + goto error; + decl.name = parser->previous; + + if (match_token(parser, TOKEN_LEFT_PAREN)) + { + if (!parse_params(parser, &decl)) + goto error; + if (!consume(parser, TOKEN_RIGHT_PAREN, "expected ')' after parameters")) + goto error; + } + + if (!consume(parser, TOKEN_LEFT_BRACE, "expected '{' to begin procedure body")) + goto error; + + // TODO: parse body statements; for now skip the braced block + int depth = 1; + while (depth > 0) + { + if (check(parser, TOKEN_EOF)) + { + error_at(parser, parser->current, "unterminated procedure body"); + goto error; + } + if (check(parser, TOKEN_LEFT_BRACE)) + depth += 1; + else if (check(parser, TOKEN_RIGHT_BRACE)) + depth -= 1; + advance_parser(parser); + } + + add_proc(program, decl); + return true; + +error: + free(decl.params); + return false; +} + bool parse_program(struct Lexer* lexer, struct Program* out) { struct Parser parser; @@ -100,6 +180,12 @@ bool parse_program(struct Lexer* lexer, struct Program* out) if (!parse_data(&parser, out)) return false; } + else if (check(&parser, TOKEN_PROC)) + { + advance_parser(&parser); + if (!parse_proc(&parser, out)) + return false; + } else { error_at(&parser, parser.current, "expected a top-level declaration"); |
