diff options
Diffstat (limited to 'interpreter/parse.c')
-rw-r--r-- | interpreter/parse.c | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/interpreter/parse.c b/interpreter/parse.c new file mode 100644 index 0000000..a9fc345 --- /dev/null +++ b/interpreter/parse.c @@ -0,0 +1,251 @@ +#include "parse.h" + +#include <string.h> + +#include "log.h" +#include "mem.h" + +token_list* parse_name(char** name, token_list* list) { + if (list->elem.kind != TOKEN_NAME) + return NULL; + + *name = my_calloc(1, strlen(list->elem.var) + 1); + + strcpy(*name, list->elem.var); + + return list->rest; +} + +token_list* parse_simple_expression(expression* expr, token_list* list) { + expression* _expr; + switch (list->elem.kind) { + case TOKEN_INT: + expr->kind = EXPR_INT; + expr->var1 = my_calloc(1, sizeof(int)); + *((int*) expr->var1) = *((int*) list->elem.var); + return list->rest; + + case TOKEN_NAME: + expr->kind = EXPR_NAME; + list = parse_name((char**) &expr->var1, list); + return list; + + case TOKEN_OPEN_P: + list = parse_simple_expression(expr, list->rest); + if (!list) + return NULL; + + switch (list->elem.kind) { + case TOKEN_CLOSE_P: + return list->rest; + break; + case TOKEN_COMMA: + _expr = my_calloc(1, sizeof(expression)); + cpy_expression(_expr, expr); + free_expression(expr); + expr->kind = EXPR_TUPLE; + expr->var1 = _expr; + expr->var2 = my_calloc(1, sizeof(expression)); + list = parse_simple_expression(expr->var2, list->rest); + if (!list || list->elem.kind != TOKEN_CLOSE_P) { + free_expression(_expr); + my_free(_expr); + return NULL; + } else { + return list->rest; + } + break; + default: + return NULL; + } + break; + + case TOKEN_OPEN_SQ: + expr->kind = EXPR_LIST; + list = list->rest; + if (!list) + return NULL; + + if (list->elem.kind == TOKEN_CLOSE_SQ) + return list->rest; + + expr->var1 = my_calloc(1, sizeof(expression)); + expr->var2 = my_calloc(1, sizeof(expression)); + + list = parse_simple_expression(expr->var1, list); + + if (!list || list->elem.kind != TOKEN_COLON) { + free_expression(expr->var1); + return NULL; + } + + list = parse_simple_expression(expr->var2, list->rest); + + if (!list || list->elem.kind != TOKEN_CLOSE_SQ) { + free_expression(expr->var1); + my_free(expr->var1); + free_expression(expr->var2); + my_free(expr->var2); + return NULL; + } + + return list->rest; + + break; + + default: + return NULL; + } +} + +token_list* parse_arg_list(arg_list** args, token_list* list) { + if (list->elem.kind == TOKEN_EQUALS) + return list; + + *args = my_calloc(1, sizeof(arg_list)); + + list = parse_simple_expression(&(*args)->elem, list); + if (!list) + return NULL; + + list = parse_arg_list(&(*args)->rest, list); + + return list; +} + +token_list* parse_expression(expression*, token_list*); + +token_list* parse_expression_no_app(expression* expr, token_list* list) { + if (list->elem.kind == TOKEN_OPEN_P) { + token_list* _list = parse_expression(expr, list->rest); + if (_list) { + if (_list->elem.kind == TOKEN_CLOSE_P) { + return _list->rest; + } else if (_list->elem.kind == TOKEN_COMMA) { + expression* _expr = my_calloc(1, sizeof(expression)); + + cpy_expression(_expr, expr); + free_expression(expr); + expr->kind = EXPR_TUPLE; + expr->var1 = _expr; + + expr->var2 = my_calloc(1, sizeof(expression)); + + _list = parse_expression(expr->var2, _list->rest); + if (_list && _list->elem.kind == TOKEN_CLOSE_P) { + return _list->rest; + } + } + free_expression(expr); + } + } else if (list->elem.kind == TOKEN_OPEN_SQ) { + expression *expr1, *expr2; + token_list* _list; + + expr->kind = EXPR_LIST; + + if (list->rest->elem.kind == TOKEN_CLOSE_SQ) { + return list->rest->rest; + } + + expr1 = my_calloc(1, sizeof(expression)); + expr2 = my_calloc(1, sizeof(expression)); + + _list = parse_expression(expr1, list->rest); + if (!_list || _list->elem.kind != TOKEN_COLON) { + free_expression(expr1); + my_free(expr1); + my_free(expr2); + } else { + _list = parse_expression(expr2, _list->rest); + if (!_list || _list->elem.kind != TOKEN_CLOSE_SQ) { + free_expression(expr1); + free_expression(expr2); + my_free(expr1); + my_free(expr2); + } else { + expr->var1 = expr1; + expr->var2 = expr2; + return _list->rest; + } + } + } + + list = parse_simple_expression(expr, list); + + return list; +} + +token_list* parse_expression(expression* expr, token_list* list) { + list = parse_expression_no_app(expr, list); + if (!list) + return NULL; + + while (list->elem.kind != TOKEN_SEMICOLON && + list->elem.kind != TOKEN_CLOSE_P && + list->elem.kind != TOKEN_CLOSE_SQ && + list->elem.kind != TOKEN_COLON && + list->elem.kind != TOKEN_COMMA) { + + expression* _expr = my_calloc(1, sizeof(expression)); + + cpy_expression(_expr, expr); + free_expression(expr); + expr->kind = EXPR_APP; + expr->var1 = _expr; + + expr->var2 = my_calloc(1, sizeof(expression)); + + list = parse_expression_no_app(expr->var2, list); + if (!list) { + free_expression(expr); + return NULL; + } + } + + return list; +} + +token_list* parse_rule(rewrite_rule* rule, token_list* list) { + list = parse_name(&rule->name, list); + if (!list) + return NULL; + + list = parse_arg_list(&rule->args, list); + if (!list) { + log_debug("parse_rule: error in arg_list"); + my_free(rule->name); + return NULL; + } + + if (list->elem.kind != TOKEN_EQUALS) { + log_debug("parse_rule: no ="); + my_free(rule->name); + free_arg_list(rule->args); + return NULL; + } + + list = parse_expression(&rule->rhs, list->rest); + + return list; +} + +fuspel* parse(token_list* list) { + fuspel* rules; + + while (list && list->elem.kind == TOKEN_SEMICOLON) + list = list->rest; + + if (!list) + return NULL; + + rules = my_calloc(1, sizeof(fuspel)); + + list = parse_rule(&rules->rule, list); + if (!list) + return NULL; + + rules->rest = parse(list); + + return rules; +} |