aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-08-30 13:42:31 +0200
committerhachem <im@hachem.wtf>2026-08-30 13:42:31 +0200
commitdeed096e783fca21b1773fa84c28be139a3c57ad (patch)
tree6ea3743f5d26a130c25c2df1af1d33a0c916348e /src
parent9e979a49b041a9d0e8ba6f8fee50bd11520169af (diff)
add: parse conditional expressions
Diffstat (limited to 'src')
-rw-r--r--src/main.c62
-rw-r--r--src/parser/ast.c16
-rw-r--r--src/parser/ast.h10
-rw-r--r--src/parser/parser.c54
4 files changed, 114 insertions, 28 deletions
diff --git a/src/main.c b/src/main.c
index b40f90e..63f87fd 100644
--- a/src/main.c
+++ b/src/main.c
@@ -25,6 +25,41 @@ static void print_expr(struct Expr* expr)
}
}
+static void print_statement(struct Statement* statement, const char* indent)
+{
+ switch (statement->kind)
+ {
+ case STATEMENT_ASSIGN:
+ {
+ struct AssignStatement assign = statement->assign;
+ printf("%s%s%.*s %.*s ", indent,
+ assign.target_deref ? "^" : "",
+ (int)assign.target.length, assign.target.start,
+ (int)assign.op.length, assign.op.start);
+ print_expr(assign.value);
+ printf("\n");
+ break;
+ }
+ case STATEMENT_LABEL:
+ printf("%s%.*s:\n", indent, (int)statement->label.name.length, statement->label.name.start);
+ break;
+ case STATEMENT_GOTO:
+ printf("%sgoto %.*s\n", indent, (int)statement->jump.label.length, statement->jump.label.start);
+ break;
+ case STATEMENT_SYSCALL:
+ printf("%ssyscall\n", indent);
+ break;
+ case STATEMENT_IF:
+ printf("%sif ", indent);
+ print_expr(statement->branch.left);
+ printf(" %.*s ", (int)statement->branch.comparison.length, statement->branch.comparison.start);
+ print_expr(statement->branch.right);
+ printf("\n");
+ print_statement(statement->branch.body, " ");
+ break;
+ }
+}
+
int main(int argc, char** argv)
{
struct Args args;
@@ -79,32 +114,7 @@ int main(int argc, char** argv)
printf(")\n");
for (size_t s = 0; s < proc.body_count; s += 1)
- {
- struct Statement statement = proc.body[s];
- switch (statement.kind)
- {
- case STATEMENT_ASSIGN:
- {
- struct AssignStatement assign = statement.assign;
- printf(" %s%.*s %.*s ",
- assign.target_deref ? "^" : "",
- (int)assign.target.length, assign.target.start,
- (int)assign.op.length, assign.op.start);
- print_expr(assign.value);
- printf("\n");
- 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;
- }
- }
+ print_statement(&proc.body[s], " ");
}
free_program(&program);
diff --git a/src/parser/ast.c b/src/parser/ast.c
index 97cdb6d..9bdf4d1 100644
--- a/src/parser/ast.c
+++ b/src/parser/ast.c
@@ -25,8 +25,20 @@ void free_expr(struct Expr* expr)
static void free_statement(struct Statement* statement)
{
- if (statement->kind == STATEMENT_ASSIGN)
- free_expr(statement->assign.value);
+ switch (statement->kind)
+ {
+ case STATEMENT_ASSIGN:
+ free_expr(statement->assign.value);
+ break;
+ case STATEMENT_IF:
+ free_expr(statement->branch.left);
+ free_expr(statement->branch.right);
+ free_statement(statement->branch.body);
+ free(statement->branch.body);
+ break;
+ default:
+ break;
+ }
}
void free_proc(struct ProcDecl* proc)
diff --git a/src/parser/ast.h b/src/parser/ast.h
index 199d802..e85e72f 100644
--- a/src/parser/ast.h
+++ b/src/parser/ast.h
@@ -65,6 +65,7 @@ enum StatementKind
STATEMENT_LABEL,
STATEMENT_GOTO,
STATEMENT_SYSCALL,
+ STATEMENT_IF,
};
struct AssignStatement
@@ -85,6 +86,14 @@ struct GotoStatement
struct Token label;
};
+struct IfStatement
+{
+ struct Expr* left;
+ struct Token comparison;
+ struct Expr* right;
+ struct Statement* body;
+};
+
struct Statement
{
enum StatementKind kind;
@@ -93,6 +102,7 @@ struct Statement
struct AssignStatement assign;
struct LabelStatement label;
struct GotoStatement jump;
+ struct IfStatement branch;
};
};
diff --git a/src/parser/parser.c b/src/parser/parser.c
index 5431bfd..2ae52f2 100644
--- a/src/parser/parser.c
+++ b/src/parser/parser.c
@@ -206,8 +206,62 @@ static struct Expr* parse_expression(struct Parser* parser)
return parse_binary(parser, parse_multiplicative, TOKEN_PLUS, TOKEN_MINUS);
}
+static bool is_compare_op(enum TokenType type)
+{
+ return type == TOKEN_EQUAL_EQUAL
+ || type == TOKEN_BANG_EQUAL
+ || type == TOKEN_LESS
+ || type == TOKEN_LESS_EQUAL
+ || type == TOKEN_GREATER
+ || type == TOKEN_GREATER_EQUAL;
+}
+
+static bool parse_statement(struct Parser* parser, struct Statement* out);
+
+static bool parse_if(struct Parser* parser, struct Statement* out)
+{
+ struct Expr* left = parse_expression(parser);
+ if (left == NULL)
+ return false;
+
+ if (!is_compare_op(parser->current.type))
+ {
+ error_at(parser, parser->current, "expected a comparison operator");
+ free_expr(left);
+ return false;
+ }
+ advance_parser(parser);
+ struct Token comparison = parser->previous;
+
+ struct Expr* right = parse_expression(parser);
+ if (right == NULL)
+ {
+ free_expr(left);
+ return false;
+ }
+
+ struct Statement* body = malloc(sizeof(struct Statement));
+ if (!parse_statement(parser, body))
+ {
+ free(body);
+ free_expr(left);
+ free_expr(right);
+ return false;
+ }
+
+ out->kind = STATEMENT_IF;
+ out->branch.left = left;
+ out->branch.comparison = comparison;
+ out->branch.right = right;
+ out->branch.body = body;
+ return true;
+}
+
static bool parse_statement(struct Parser* parser, struct Statement* out)
{
+ if (match_token(parser, TOKEN_IF))
+ return parse_if(parser, out);
+
if (match_token(parser, TOKEN_SYSCALL))
{
out->kind = STATEMENT_SYSCALL;