diff options
author | Linnnus <[email protected]> | 2025-04-15 14:09:14 +0000 |
---|---|---|
committer | Linnnus <[email protected]> | 2025-04-15 14:09:14 +0000 |
commit | db682a9cea30ba5295fe160012e2c7593c8cee89 (patch) | |
tree | 6c73c9e4517a53ce4b528084a4d8c14ada938c9d | |
parent | f667ae8eff0f0e87130c7b5b934e32c9fdb9f957 (diff) |
-rw-r--r-- | src/core/parser.c | 71 | ||||
-rw-r--r-- | src/core/parser.h | 30 |
2 files changed, 101 insertions, 0 deletions
diff --git a/src/core/parser.c b/src/core/parser.c new file mode 100644 index 0000000..5ebe917 --- /dev/null +++ b/src/core/parser.c @@ -0,0 +1,71 @@ +#include "parser.h" +#include "config.h" +#include "tokenizer.h" + +typedef struct { + SandTokenizer tokenizer; + SandToken previous; + SandToken current; + + SandAllocator *a; + SandState *S; +} Parser; + +// Report an error at the given token and enter panic mode. +static void error_at(Parser *parser, SandToken token, const char *message) { + sand_print_diagnostic(parser->S, token.location, SAND_DIAGNOSTIC_ERROR, ""); +} + + +// Same as `error_at` except using the parser's current token. +static void error_at_current(Parser *parser, const char *message) { + error_at(parser, parser->current, message); +} + +static void advance(Parser *parser) { + parser->previous = parser->current; + + while (true) { + parser->current = sand_get_next_token(&parser->tokenizer); + if (parser->current.kind == SAND_TOKEN_ERROR) { + // `content` is going to be NULL-terminated because it will always point to a C string literal for error tokens. + error_at_current(parser, parser->current.content); + } else { + break; + } + } +} + +static SandToken peek(const Parser *parser) { + return parser->current; +} + +static bool match(Parser *parser, SandTokenKind expected) { + if (peek(parser).kind == expected) { + advance(parser); + return true; + } else { + return false; + } +} + +static void consume(Parser *parser, SandTokenKind expected, const char *error) { + if (!match(parser, expected)) { + error_at_current(parser, error); + } +} + +SandAst *sand_parse(SandState *S, SandAllocator *a, const char *source, size_t source_length, const char *filename) { + Parser parser; + parser.a = a; + parser.S = S; + + parser.tokenizer = sand_create_tokenizer(source, source_length, filename); + advance(&parser); // Prime the pump on the tokenizer. + + // Parse the document. + SandAst *expr = expression(&parser); + consume(&parser, SAND_TOKEN_EOF, "Expected end of expression"); + + return expr; +} diff --git a/src/core/parser.h b/src/core/parser.h new file mode 100644 index 0000000..d514341 --- /dev/null +++ b/src/core/parser.h @@ -0,0 +1,30 @@ +#ifndef SAND_PARSER_H +#define SAND_PARSER_H + +#include "allocator.h" +#include "tokenizer.h" +#include "state.h" + +typedef enum { + SAND_AST_BINARY_OP, + SAND_AST_NUMBER, +} SandAstKind; + +typedef struct { + SandToken op; + struct _SandAst *left; + struct _SandAst *right; +} SandAstBinaryOp; + +typedef struct { + SandToken value; +} SandAstNumber; + +typedef struct _SandAst { + SandAstKind kind; + SandLocation location; +} SandAst; + +SandAst *sand_parse(SandState *, SandAllocator *, const char *source, size_t source_length, const char *filename); + +#endif |