summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/parser.c71
-rw-r--r--src/core/parser.h30
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