diff options
Diffstat (limited to 'src/parser.c')
-rw-r--r-- | src/parser.c | 258 |
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; +} + |