aboutsummaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c258
1 files changed, 258 insertions, 0 deletions
diff --git a/src/parser.c b/src/parser.c
new file mode 100644
index 0000000..c4e37bd
--- /dev/null
+++ b/src/parser.c
@@ -0,0 +1,258 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "common.h"
+#include "parser.h"
+
+// TODO: Do all the todos
+
+// adds another child of type type to the sexp sexp
+// returns the index of the added type and < 0 on fail
+static size_t sexp_add(struct sexp *sexp, enum ast_type type);
+
+// self-explanatory
+static void sexp_init(struct sexp *sexp);
+static void sexp_print(struct sexp *sexp, int indent);
+static void sexp_free(struct sexp *sexp);
+static void ast_free(struct ast *ast);
+
+static void quote_stack_push(struct quote_node **head, struct sexp *cur_sexp);
+static struct sexp *quote_stack_pop(struct quote_node **head, int peak);
+
+// returns 0 on success
+static int on_paren(parser_t parser, int paren_type); // 0 is open, 1 is close
+static int on_quote(parser_t parent);
+static int on_value(parser_t parent, value_t value);
+
+#define TOKEN_CALLBACK_TBL(X, parser, token) \
+/* X(test, execute on succes) */ \
+ X(TOKEN_PARENTHS_OPEN, on_paren(parser, 0)) \
+ X(TOKEN_PARENTHS_CLOSE, on_paren(parser, 1)) \
+ X(TOKEN_SPECIAL_QUOTE, on_quote(parser)) \
+ X(TOKEN_VALUE, on_value(parser, token->value))
+
+#define FN(fn, arg) "%s", fn(arg, buf, buf_sz)
+
+#define MANAGE_AST_TBL(X, ast) \
+ X(AST_SEXP, sexp_free(&ast->sexp), "|") \
+ X(AST_VALUE, value_destroy(ast->value), FN(value_string, ast->value)) \
+
+// ---------- Exported Functions ---------- //
+
+#define CASE_TYPE(type, callback) \
+ case type: \
+ if(callback) { \
+ err(#callback ": failed"); \
+ return -1; \
+ } break;
+
+int parser_parse_lexer(parser_t parser, lexer_t lexer)
+{
+ for(size_t i = 0; i < lexer->ntokens; i++) {
+ struct token *token = &lexer->tokens[i];
+
+ switch(token->type) {
+ TOKEN_CALLBACK_TBL(CASE_TYPE, parser, token);
+ default:
+ err("parser_parse_lexer: Unknown token type given");
+ break;
+ }
+
+ if((token->type != TOKEN_SPECIAL_QUOTE) &&
+ (parser->cur_sexp == quote_stack_pop(&parser->quote_head, 1))) {
+ if(on_paren(parser, 1));
+ quote_stack_pop(&parser->quote_head, 0);
+ }
+ }
+
+ if(&parser->root == parser->cur_sexp) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+parser_t parser_create()
+{
+ parser_t parser = xmalloc(sizeof(struct parser));
+
+#define VALUE_CREATE(str) \
+ value_create(VALUE_SYMBOL, str, &ret); \
+ if(ret) { \
+ err("value_create: failed"); \
+ return NULL; \
+ }
+
+ int ret = 0;
+ parser->begin_symbol_value = VALUE_CREATE("begin");
+ parser->quote_symbol_value = VALUE_CREATE("quote");
+
+ parser->root.nchildren = 0;
+ parser->quote_head = NULL;
+ parser_reset(parser);
+
+ return parser;
+}
+
+void parser_destroy(parser_t parser)
+{
+ if(!parser) return;
+
+ value_destroy(parser->begin_symbol_value);
+ value_destroy(parser->quote_symbol_value);
+
+ sexp_free(&parser->root);
+ free(parser);
+}
+
+void parser_reset(parser_t parser)
+{
+ struct sexp *root = &parser->root;
+
+ for(size_t i = 0; i < root->nchildren; i++) {
+ ast_free(&root->children[i]);
+ }
+
+ sexp_init(root);
+ size_t index = sexp_add(root, AST_VALUE);
+
+ root->children[index].value = value_copy(parser->begin_symbol_value);
+ parser->cur_sexp = &parser->root;
+
+ while(quote_stack_pop(&parser->quote_head, 0) != NULL);
+}
+
+
+void parser_print_ast(parser_t parser)
+{
+ sexp_print(&parser->root, 0);
+}
+
+// ---------- Callback Functions ---------- //
+
+static int on_paren(parser_t parser, int paren_type)
+{
+ if(paren_type) { // !0 closing paren
+ parser->cur_sexp = parser->cur_sexp->prev;
+ } else { // 0 opening paren
+ size_t index = sexp_add(parser->cur_sexp, AST_SEXP);
+
+ struct sexp *prev = parser->cur_sexp;
+ struct sexp *new = &prev->children[index].sexp;
+
+ sexp_init(new);
+
+ parser->cur_sexp = new;
+ parser->cur_sexp->prev = prev;
+ }
+
+ return 0;
+}
+
+static int on_quote(parser_t parser)
+{
+ // new sexp
+ on_paren(parser, 0);
+
+ // add symbol to the sexp
+ on_value(parser, parser->quote_symbol_value);
+
+ // save the current quote sexp
+ quote_stack_push(&parser->quote_head, parser->cur_sexp);
+ return 0;
+}
+
+static int on_value(parser_t parser, value_t value)
+{
+ size_t index = sexp_add(parser->cur_sexp, AST_VALUE);
+
+ value_t copied = value_copy(value);
+
+ parser->cur_sexp->children[index].value = copied;
+ return 0;
+}
+
+// ---------- Parser Functions ---------- //
+
+static size_t sexp_add(struct sexp *sexp, enum ast_type type)
+{
+ sexp->children = xrealloc(sexp->children, sizeof(struct ast) * (sexp->nchildren+1));
+
+ sexp->children[sexp->nchildren].type = type;
+ return sexp->nchildren++;
+}
+
+static void sexp_init(struct sexp *sexp)
+{
+ sexp->children = NULL;
+ sexp->nchildren = 0;
+ sexp->prev = NULL;
+}
+
+static void sexp_print(struct sexp *sexp, int indent)
+{
+ for(size_t i = 0; i < sexp->nchildren; i++) {
+ struct ast *child = &sexp->children[i];
+
+ if(child->type == AST_SEXP) {
+ sexp_print(&child->sexp, indent + 2);
+ continue;
+ }
+
+ char buf[LEXER_IDEN_CAP];
+ size_t buf_sz = LEXER_IDEN_CAP;
+
+ info("%d %s", indent, value_string(child->value, buf, buf_sz));
+ }
+}
+
+static void sexp_free(struct sexp *sexp)
+{
+ for(size_t i = 0; i < sexp->nchildren; i++){
+ ast_free(&sexp->children[i]);
+ }
+ free(sexp->children);
+}
+
+#define CASE_FREE(type, free_func, print_func) \
+ case type: free_func; return;
+
+static void ast_free(struct ast *ast)
+{
+ if(!ast) return;
+
+ switch(ast->type) {
+ MANAGE_AST_TBL(CASE_FREE, ast)
+ default:
+ err("ast_free: Unknown ast type given");
+ break;
+ }
+}
+
+static void quote_stack_push(struct quote_node **head, struct sexp *cur_sexp)
+{
+ struct quote_node *node = xmalloc(sizeof(struct quote_node));
+
+ node->prev = *head;
+ node->cur_sexp = cur_sexp;
+ *head = node;
+}
+
+static struct sexp *quote_stack_pop(struct quote_node **head, int peak)
+{
+ if(*head == NULL) {
+ return NULL;
+ }
+
+ struct sexp *sexp = (*head)->cur_sexp;
+
+ if(!peak) {
+ struct quote_node *prev = (*head)->prev;
+ free(*head);
+ *head = prev;
+ }
+
+ return sexp;
+}
+