aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lexer/lexer.c1
-rw-r--r--src/main.c22
-rw-r--r--src/parser/ast.c33
-rw-r--r--src/parser/ast.h22
-rw-r--r--src/parser/parser.c86
-rw-r--r--src/parser/parser.h8
6 files changed, 166 insertions, 6 deletions
diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c
index 59a71d8..ca51bb8 100644
--- a/src/lexer/lexer.c
+++ b/src/lexer/lexer.c
@@ -234,3 +234,4 @@ const char* token_type_name(enum TokenType type)
return "unknown";
}
+
diff --git a/src/main.c b/src/main.c
index 9a9dae4..3196013 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,8 +1,10 @@
#include <stdio.h>
+#include <stddef.h>
#include "io/file.h"
#include "cli/args.h"
#include "lexer/lexer.h"
+#include "parser/parser.h"
int main(int argc, char** argv)
{
@@ -20,14 +22,22 @@ int main(int argc, char** argv)
struct Lexer lexer = create_lexer(source.data);
- for (;;)
+ struct Program program;
+ if (!parse_program(&lexer, &program))
{
- struct Token token = scan_token(&lexer);
- printf("%4u %-14s %.*s\n", token.line, token_type_name(token.type), (int)token.length, token.start);
- if (token.type == TOKEN_EOF)
- break;
+ free_program(&program);
+ free_file(&source);
+ return 1;
+ }
+
+ for (size_t i = 0; i < program.const_count; i += 1)
+ {
+ struct ConstDecl decl = program.consts[i];
+ printf("const %.*s = %.*s\n",
+ (int)decl.name.length, decl.name.start,
+ (int)decl.value.length, decl.value.start);
}
+ free_program(&program);
free_file(&source);
- return 0;
}
diff --git a/src/parser/ast.c b/src/parser/ast.c
new file mode 100644
index 0000000..979dff0
--- /dev/null
+++ b/src/parser/ast.c
@@ -0,0 +1,33 @@
+#include <stdlib.h>
+
+#include "parser/ast.h"
+
+struct Program create_program(void)
+{
+ struct Program program;
+ program.consts = NULL;
+ program.const_count = 0;
+ program.const_capacity = 0;
+ return program;
+}
+
+void free_program(struct Program* program)
+{
+ free(program->consts);
+ program->consts = NULL;
+ program->const_count = 0;
+ program->const_capacity = 0;
+}
+
+void add_const(struct Program* program, struct ConstDecl decl)
+{
+ if (program->const_count == program->const_capacity)
+ {
+ size_t capacity = program->const_capacity < 8 ? 8 : program->const_capacity * 2;
+ program->consts = realloc(program->consts, capacity * sizeof(struct ConstDecl));
+ program->const_capacity = capacity;
+ }
+
+ program->consts[program->const_count] = decl;
+ program->const_count += 1;
+}
diff --git a/src/parser/ast.h b/src/parser/ast.h
new file mode 100644
index 0000000..7079305
--- /dev/null
+++ b/src/parser/ast.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <stddef.h>
+
+#include "lexer/lexer.h"
+
+struct ConstDecl
+{
+ struct Token name;
+ struct Token value;
+};
+
+struct Program
+{
+ struct ConstDecl* consts;
+ size_t const_count;
+ size_t const_capacity;
+};
+
+struct Program create_program(void);
+void free_program(struct Program* program);
+void add_const(struct Program* program, struct ConstDecl decl);
diff --git a/src/parser/parser.c b/src/parser/parser.c
new file mode 100644
index 0000000..5845ad4
--- /dev/null
+++ b/src/parser/parser.c
@@ -0,0 +1,86 @@
+#include <stdio.h>
+
+#include "parser/parser.h"
+
+struct Parser
+{
+ struct Lexer* lexer;
+ struct Token current;
+ struct Token previous;
+ bool had_error;
+};
+
+static void advance_parser(struct Parser* parser)
+{
+ parser->previous = parser->current;
+ parser->current = scan_token(parser->lexer);
+}
+
+static bool check(struct Parser* parser, enum TokenType type)
+{
+ return parser->current.type == type;
+}
+
+static void error_at(struct Parser* parser, struct Token token, const char* message)
+{
+ fprintf(stderr, "error: line %u: %s\n", token.line, message);
+ parser->had_error = true;
+}
+
+static bool consume(struct Parser* parser, enum TokenType type, const char* message)
+{
+ if (check(parser, type))
+ {
+ advance_parser(parser);
+ return true;
+ }
+
+ error_at(parser, parser->current, message);
+ return false;
+}
+
+static bool parse_const(struct Parser* parser, struct Program* program)
+{
+ struct ConstDecl decl;
+
+ if (!consume(parser, TOKEN_IDENTIFIER, "expected constant name after 'const'"))
+ return false;
+ decl.name = parser->previous;
+
+ if (!consume(parser, TOKEN_EQUAL, "expected '=' after constant name"))
+ return false;
+
+ if (!consume(parser, TOKEN_INTEGER, "expected integer value after '='"))
+ return false;
+ decl.value = parser->previous;
+
+ add_const(program, decl);
+ return true;
+}
+
+bool parse_program(struct Lexer* lexer, struct Program* out)
+{
+ struct Parser parser;
+ parser.lexer = lexer;
+ parser.had_error = false;
+ advance_parser(&parser);
+
+ *out = create_program();
+
+ while (!check(&parser, TOKEN_EOF))
+ {
+ if (check(&parser, TOKEN_CONST))
+ {
+ advance_parser(&parser);
+ if (!parse_const(&parser, out))
+ return false;
+ }
+ else
+ {
+ error_at(&parser, parser.current, "expected a top-level declaration");
+ return false;
+ }
+ }
+
+ return !parser.had_error;
+}
diff --git a/src/parser/parser.h b/src/parser/parser.h
new file mode 100644
index 0000000..82d306a
--- /dev/null
+++ b/src/parser/parser.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <stdbool.h>
+
+#include "lexer/lexer.h"
+#include "parser/ast.h"
+
+bool parse_program(struct Lexer* lexer, struct Program* out);