aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-08-30 04:11:27 +0200
committerhachem <im@hachem.wtf>2026-08-30 04:11:27 +0200
commitaffa20ab497911353babc9ed6c580c8a12b2bf15 (patch)
tree6d7c8d2164cbf1403819991baf62d8201049b778
parent2e7cab34d22a0174909030942671e95d5a3c769f (diff)
add: parse proc declarations
-rw-r--r--src/lexer/lexer.c4
-rw-r--r--src/main.c14
-rw-r--r--src/parser/ast.c46
-rw-r--r--src/parser/ast.h22
-rw-r--r--src/parser/parser.c86
5 files changed, 170 insertions, 2 deletions
diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c
index ca51bb8..6018fab 100644
--- a/src/lexer/lexer.c
+++ b/src/lexer/lexer.c
@@ -22,8 +22,8 @@ static enum TokenType identifier_type(const char* start, size_t length)
const char* text;
size_t length;
enum TokenType type;
- }
- keywords[] = {
+ } keywords[] =
+ {
{ "const", 5, TOKEN_CONST },
{ "data", 4, TOKEN_DATA },
{ "proc", 4, TOKEN_PROC },
diff --git a/src/main.c b/src/main.c
index b351bd8..e65362c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -46,6 +46,20 @@ int main(int argc, char** argv)
(int)decl.value.length, decl.value.start);
}
+ for (size_t i = 0; i < program.proc_count; i += 1)
+ {
+ struct ProcDecl proc = program.procs[i];
+ printf("proc %.*s(", (int)proc.name.length, proc.name.start);
+ for (size_t p = 0; p < proc.param_count; p += 1)
+ {
+ struct Param param = proc.params[p];
+ printf("%s%.*s: %.*s", p == 0 ? "" : ", ",
+ (int)param.name.length, param.name.start,
+ (int)param.reg.length, param.reg.start);
+ }
+ printf(")\n");
+ }
+
free_program(&program);
free_file(&source);
}
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");