From eeff5e273f22aa28e81ab080e9ffdce85ac394b8 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Fri, 22 Oct 2021 09:59:31 +0200 Subject: Prepare skeleton for bytecode interpreter --- src/treewalk/parser.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 src/treewalk/parser.c (limited to 'src/treewalk/parser.c') diff --git a/src/treewalk/parser.c b/src/treewalk/parser.c new file mode 100644 index 0000000..a2f0f71 --- /dev/null +++ b/src/treewalk/parser.c @@ -0,0 +1,139 @@ +#include "parser.h" + +Token +peek_token(const Visitor *visitor) { + return visitor->tokens[visitor->current]; +} + +Token +next_token(Visitor *visitor) { + return visitor->tokens[visitor->current++]; +} + +bool +has_next_token(const Visitor *visitor) { + return visitor->current < array_size(visitor->tokens); +} + +Object * +parse_fixnum(Token tok) { + ssize_t num = 0; + int sign = 1; + for (size_t i = 0; i < tok.value.n; i++) { + char c = tok.value.start[i]; + if (c == '-') { + sign = -1; + continue; + } + num = num * 10 + (c - '0'); + } + + Object *obj = make_fixnum(num * sign); + push_root(obj); + return obj; +} + +Object * +parse_list(Visitor *vs) { + Token tok = peek_token(vs); + if (tok.type == TOKEN_EOF) { + return obj_err; + } + Object *root = make_pair(obj_nil, obj_nil); + push_root(root); + Object *next_obj = parse_tree(vs); + if (next_obj == obj_err) { + return obj_err; + } + root->car = next_obj; + Object *list = root; + while (has_next_token(vs)) { + Token tok = peek_token(vs); + if (tok.type == TOKEN_RPAREN) { + next_token(vs); + break; + } + if (tok.type == TOKEN_EOF) { + return obj_err; + } + next_obj = parse_tree(vs); + if (next_obj == obj_err) { + return obj_err; + } + list->cdr = make_pair(next_obj, obj_nil); + list = list->cdr; + } + return root; +} + +Object * +parse_tree(Visitor *vs) { + Token tok = next_token(vs); + switch (tok.type) { + case TOKEN_FIXNUM: { + return parse_fixnum(tok); + } break; + case TOKEN_TRUE: { + return obj_true; + } break; + case TOKEN_FALSE: { + return obj_false; + } break; + case TOKEN_RPAREN: { + error_push((Error){ + .type = ERR_TYPE_PARSER, + .value = ERR_UNBALANCED_PAREN, + .line = tok.line, + .col = tok.column, + }); + return obj_err; + } break; + case TOKEN_QUOTE: { + Object *base = make_pair(obj_quote, obj_nil); + base->cdr = make_pair(obj_nil, obj_nil); + push_root(base); + Object *next_obj = parse_tree(vs); + if (next_obj == obj_err) { + return obj_err; + } + base->cdr->car = next_obj; + return base; + } break; + case TOKEN_LPAREN: { + Object *obj = parse_list(vs); + if (obj == obj_err) { + error_push((Error){ + .type = ERR_TYPE_PARSER, + .value = ERR_UNBALANCED_PAREN, + .line = tok.line, + .col = tok.column, + }); + } + return obj; + } break; + case TOKEN_STRING: { + Object *obj = make_string(); + push_root(obj); + append_string(obj, tok.value); + return obj; + } break; + case TOKEN_SYMBOL: { + Object *obj = make_symbol(tok.value); + push_root(obj); + return obj; + } break; + case TOKEN_NIL: { + return obj_nil; + } break; + default: { + break; + } break; + } + error_push((Error){ + .type = ERR_TYPE_PARSER, + .value = ERR_EOF_REACHED, + .line = tok.line, + .col = tok.column, + }); + return obj_err; +} -- cgit v1.2.1