diff options
| author | hachem <im@hachem.wtf> | 2026-08-30 03:32:51 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-08-30 03:32:51 +0200 |
| commit | 5767110816ca9452ef77d15245d1a747bfdd896b (patch) | |
| tree | 1f7e5dec5f1fb4fe7a53c1c81f94043ba7db5676 /src | |
| parent | 6a6e79cb233e795b78c9ec750dbae9d26bd51654 (diff) | |
add: top level parser
Diffstat (limited to 'src')
| -rw-r--r-- | src/lexer/lexer.c | 1 | ||||
| -rw-r--r-- | src/main.c | 22 | ||||
| -rw-r--r-- | src/parser/ast.c | 33 | ||||
| -rw-r--r-- | src/parser/ast.h | 22 | ||||
| -rw-r--r-- | src/parser/parser.c | 86 | ||||
| -rw-r--r-- | src/parser/parser.h | 8 |
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"; } + @@ -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); |
