aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-08-30 12:14:04 +0200
committerhachem <im@hachem.wtf>2026-08-30 12:14:04 +0200
commit53946c982cb3290a25f7c8529ef1399f0635ef37 (patch)
tree969bc78c304e13d733b794ffc98d44bf44b53621
parent6532b074e5c1db4a1c32298cc338a1a533208641 (diff)
add: parse labels and syscalls
-rw-r--r--src/main.c27
-rw-r--r--src/parser/ast.h15
-rw-r--r--src/parser/parser.c27
-rw-r--r--tests/parser_test.c22
4 files changed, 82 insertions, 9 deletions
diff --git a/src/main.c b/src/main.c
index 2f5f4d1..a44350e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -62,14 +62,27 @@ int main(int argc, char** argv)
for (size_t s = 0; s < proc.body_count; s += 1)
{
struct Statement statement = proc.body[s];
- if (statement.kind == STATEMENT_ASSIGN)
+ switch (statement.kind)
{
- struct AssignStatement assign = statement.assign;
- printf(" %s%.*s %.*s %.*s\n",
- assign.target_deref ? "^" : "",
- (int)assign.target.length, assign.target.start,
- (int)assign.op.length, assign.op.start,
- (int)assign.value.length, assign.value.start);
+ case STATEMENT_ASSIGN:
+ {
+ struct AssignStatement assign = statement.assign;
+ printf(" %s%.*s %.*s %.*s\n",
+ assign.target_deref ? "^" : "",
+ (int)assign.target.length, assign.target.start,
+ (int)assign.op.length, assign.op.start,
+ (int)assign.value.length, assign.value.start);
+ break;
+ }
+ case STATEMENT_LABEL:
+ printf(" %.*s:\n", (int)statement.label.name.length, statement.label.name.start);
+ break;
+ case STATEMENT_GOTO:
+ printf(" goto %.*s\n", (int)statement.jump.label.length, statement.jump.label.start);
+ break;
+ case STATEMENT_SYSCALL:
+ printf(" syscall\n");
+ break;
}
}
}
diff --git a/src/parser/ast.h b/src/parser/ast.h
index 83483e9..4604e1a 100644
--- a/src/parser/ast.h
+++ b/src/parser/ast.h
@@ -26,6 +26,9 @@ struct Param
enum StatementKind
{
STATEMENT_ASSIGN,
+ STATEMENT_LABEL,
+ STATEMENT_GOTO,
+ STATEMENT_SYSCALL,
};
struct AssignStatement
@@ -36,12 +39,24 @@ struct AssignStatement
struct Token value;
};
+struct LabelStatement
+{
+ struct Token name;
+};
+
+struct GotoStatement
+{
+ struct Token label;
+};
+
struct Statement
{
enum StatementKind kind;
union
{
struct AssignStatement assign;
+ struct LabelStatement label;
+ struct GotoStatement jump;
};
};
diff --git a/src/parser/parser.c b/src/parser/parser.c
index d86502f..a125b7d 100644
--- a/src/parser/parser.c
+++ b/src/parser/parser.c
@@ -138,11 +138,34 @@ static bool parse_value(struct Parser* parser, struct Token* out)
static bool parse_statement(struct Parser* parser, struct Statement* out)
{
+ if (match_token(parser, TOKEN_SYSCALL))
+ {
+ out->kind = STATEMENT_SYSCALL;
+ return true;
+ }
+
+ if (match_token(parser, TOKEN_GOTO))
+ {
+ if (!consume(parser, TOKEN_IDENTIFIER, "expected label after 'goto'"))
+ return false;
+
+ out->kind = STATEMENT_GOTO;
+ out->jump.label = parser->previous;
+ return true;
+ }
+
bool deref = match_token(parser, TOKEN_CARET);
if (!consume(parser, TOKEN_IDENTIFIER, "expected a statement"))
return false;
- struct Token target = parser->previous;
+ struct Token name = parser->previous;
+
+ if (!deref && match_token(parser, TOKEN_COLON))
+ {
+ out->kind = STATEMENT_LABEL;
+ out->label.name = name;
+ return true;
+ }
if (!is_assign_op(parser->current.type))
{
@@ -152,7 +175,7 @@ static bool parse_statement(struct Parser* parser, struct Statement* out)
struct AssignStatement assign;
assign.target_deref = deref;
- assign.target = target;
+ assign.target = name;
advance_parser(parser);
assign.op = parser->previous;
diff --git a/tests/parser_test.c b/tests/parser_test.c
index 85626a0..ea18add 100644
--- a/tests/parser_test.c
+++ b/tests/parser_test.c
@@ -83,6 +83,27 @@ static void test_parse_proc_body(struct TestContext* context)
free_program(&program);
}
+static void test_parse_simple_statements(struct TestContext* context)
+{
+ struct Lexer lexer = create_lexer("proc main\n{\nloop:\nsyscall\ngoto loop\n}\n");
+ struct Program program;
+
+ check(context, parse_program(&lexer, &program));
+ check(context, program.procs[0].body_count == 3);
+
+ struct Statement label = program.procs[0].body[0];
+ check(context, label.kind == STATEMENT_LABEL);
+ check(context, text_is(label.label.name, "loop"));
+
+ check(context, program.procs[0].body[1].kind == STATEMENT_SYSCALL);
+
+ struct Statement jump = program.procs[0].body[2];
+ check(context, jump.kind == STATEMENT_GOTO);
+ check(context, text_is(jump.jump.label, "loop"));
+
+ free_program(&program);
+}
+
static void test_parse_errors(struct TestContext* context)
{
struct Program program;
@@ -106,5 +127,6 @@ void run_parser_tests(struct TestContext* context)
test_parse_data(context);
test_parse_proc_params(context);
test_parse_proc_body(context);
+ test_parse_simple_statements(context);
test_parse_errors(context);
}