aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.c10
-rw-r--r--src/parser/ast.c5
-rw-r--r--src/parser/ast.h10
-rw-r--r--src/parser/parser.c45
-rw-r--r--tests/parser_test.c23
5 files changed, 93 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c
index 63f87fd..e33734d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -57,6 +57,16 @@ static void print_statement(struct Statement* statement, const char* indent)
printf("\n");
print_statement(statement->branch.body, " ");
break;
+ case STATEMENT_CALL:
+ printf("%s%.*s(", indent, (int)statement->call.name.length, statement->call.name.start);
+ for (size_t i = 0; i < statement->call.arg_count; i += 1)
+ {
+ if (i > 0)
+ printf(", ");
+ print_expr(statement->call.args[i]);
+ }
+ printf(")\n");
+ break;
}
}
diff --git a/src/parser/ast.c b/src/parser/ast.c
index 9bdf4d1..1aa1d38 100644
--- a/src/parser/ast.c
+++ b/src/parser/ast.c
@@ -36,6 +36,11 @@ static void free_statement(struct Statement* statement)
free_statement(statement->branch.body);
free(statement->branch.body);
break;
+ case STATEMENT_CALL:
+ for (size_t i = 0; i < statement->call.arg_count; i += 1)
+ free_expr(statement->call.args[i]);
+ free(statement->call.args);
+ break;
default:
break;
}
diff --git a/src/parser/ast.h b/src/parser/ast.h
index e85e72f..3fa80da 100644
--- a/src/parser/ast.h
+++ b/src/parser/ast.h
@@ -66,6 +66,7 @@ enum StatementKind
STATEMENT_GOTO,
STATEMENT_SYSCALL,
STATEMENT_IF,
+ STATEMENT_CALL,
};
struct AssignStatement
@@ -94,6 +95,14 @@ struct IfStatement
struct Statement* body;
};
+struct CallStatement
+{
+ struct Token name;
+ struct Expr** args;
+ size_t arg_count;
+ size_t arg_capacity;
+};
+
struct Statement
{
enum StatementKind kind;
@@ -103,6 +112,7 @@ struct Statement
struct LabelStatement label;
struct GotoStatement jump;
struct IfStatement branch;
+ struct CallStatement call;
};
};
diff --git a/src/parser/parser.c b/src/parser/parser.c
index 2ae52f2..55203ca 100644
--- a/src/parser/parser.c
+++ b/src/parser/parser.c
@@ -216,6 +216,48 @@ static bool is_compare_op(enum TokenType type)
|| type == TOKEN_GREATER_EQUAL;
}
+static bool parse_call(struct Parser* parser, struct Token name, struct Statement* out)
+{
+ struct Expr** args = NULL;
+ size_t count = 0;
+ size_t capacity = 0;
+
+ if (!check(parser, TOKEN_RIGHT_PAREN))
+ {
+ do
+ {
+ struct Expr* arg = parse_expression(parser);
+ if (arg == NULL)
+ goto error;
+
+ if (count == capacity)
+ {
+ capacity = capacity < 4 ? 4 : capacity * 2;
+ args = realloc(args, capacity * sizeof(struct Expr*));
+ }
+ args[count] = arg;
+ count += 1;
+ }
+ while (match_token(parser, TOKEN_COMMA));
+ }
+
+ if (!consume(parser, TOKEN_RIGHT_PAREN, "expected ')' after arguments"))
+ goto error;
+
+ out->kind = STATEMENT_CALL;
+ out->call.name = name;
+ out->call.args = args;
+ out->call.arg_count = count;
+ out->call.arg_capacity = capacity;
+ return true;
+
+error:
+ for (size_t i = 0; i < count; i += 1)
+ free_expr(args[i]);
+ free(args);
+ return false;
+}
+
static bool parse_statement(struct Parser* parser, struct Statement* out);
static bool parse_if(struct Parser* parser, struct Statement* out)
@@ -284,6 +326,9 @@ static bool parse_statement(struct Parser* parser, struct Statement* out)
return false;
struct Token name = parser->previous;
+ if (!deref && match_token(parser, TOKEN_LEFT_PAREN))
+ return parse_call(parser, name, out);
+
if (!deref && match_token(parser, TOKEN_COLON))
{
out->kind = STATEMENT_LABEL;
diff --git a/tests/parser_test.c b/tests/parser_test.c
index 8856f4c..8e72402 100644
--- a/tests/parser_test.c
+++ b/tests/parser_test.c
@@ -150,6 +150,28 @@ static void test_parse_if(struct TestContext* context)
free_program(&program);
}
+static void test_parse_call(struct TestContext* context)
+{
+ struct Lexer lexer = create_lexer("proc main\n{\nprint_number(r12)\nf(a, b)\n}\n");
+ struct Program program;
+
+ check(context, parse_program(&lexer, &program));
+ check(context, program.procs[0].body_count == 2);
+
+ struct CallStatement first = program.procs[0].body[0].call;
+ check(context, program.procs[0].body[0].kind == STATEMENT_CALL);
+ check(context, text_is(first.name, "print_number"));
+ check(context, first.arg_count == 1);
+ check(context, primary_is(first.args[0], "r12"));
+
+ struct CallStatement second = program.procs[0].body[1].call;
+ check(context, second.arg_count == 2);
+ check(context, primary_is(second.args[0], "a"));
+ check(context, primary_is(second.args[1], "b"));
+
+ free_program(&program);
+}
+
static void test_parse_errors(struct TestContext* context)
{
struct Program program;
@@ -176,5 +198,6 @@ void run_parser_tests(struct TestContext* context)
test_parse_simple_statements(context);
test_parse_expressions(context);
test_parse_if(context);
+ test_parse_call(context);
test_parse_errors(context);
}