From 6ca377762516888b0488d60c971e0660ae6035f4 Mon Sep 17 00:00:00 2001 From: Camil Staps Date: Fri, 14 Oct 2016 22:17:01 +0200 Subject: token_list using an array for memory efficiency --- interpreter/eval.c | 16 ++- interpreter/fuspel.c | 5 +- interpreter/lex.c | 92 ++++++++-------- interpreter/lex.h | 2 + interpreter/parse.c | 294 +++++++++++++++++++++++++++------------------------ interpreter/print.c | 12 +-- interpreter/syntax.c | 8 +- interpreter/syntax.h | 5 +- 8 files changed, 231 insertions(+), 203 deletions(-) diff --git a/interpreter/eval.c b/interpreter/eval.c index 1997d4e..4387c96 100644 --- a/interpreter/eval.c +++ b/interpreter/eval.c @@ -216,9 +216,6 @@ bool debug_graphs; void eval(struct fuspel *rules, struct node **node, bool to_rnf) { struct fuspel *_rules; bool rerun; -#ifdef _FUSPEL_DEBUG - bool print_graph; -#endif struct replacements *repls; if (!node || !*node) @@ -234,10 +231,10 @@ void eval(struct fuspel *rules, struct node **node, bool to_rnf) { #endif do { - rerun = 0; #ifdef _FUSPEL_DEBUG - print_graph = debug_graphs; + bool print_graph = debug_graphs; #endif + rerun = false; switch ((*node)->kind) { case NODE_INT: @@ -247,7 +244,7 @@ void eval(struct fuspel *rules, struct node **node, bool to_rnf) { case NODE_APP: if (is_code_app(*node)) { eval_code_app(rules, node); - rerun = 1; + rerun = true; break; } @@ -295,7 +292,7 @@ void eval(struct fuspel *rules, struct node **node, bool to_rnf) { _repls = _repls->rest) free_node(_repls->replacement.node, 1, 1); - rerun = 1; + rerun = true; #ifdef _FUSPEL_DEBUG if (is_code_app(*node)) print_graph = false; @@ -327,13 +324,13 @@ void eval(struct fuspel *rules, struct node **node, bool to_rnf) { Code_0 *code_fun = (Code_0*) (*node)->var1; code_fun(node); use_node(*node, 1); - rerun = 1; + rerun = true; } break; case NODE_REDIRECT: remove_redirects(*node); - rerun = 1; + rerun = true; break; } @@ -356,6 +353,7 @@ struct expression *eval_main(struct fuspel *rules struct expression *expr = my_calloc(1, sizeof(struct expression)); #ifdef _FUSPEL_DEBUG + root_node = NULL; debug_graphs = debug_graphs_enabled; #endif diff --git a/interpreter/fuspel.c b/interpreter/fuspel.c index 736a1c3..bfdbda0 100644 --- a/interpreter/fuspel.c +++ b/interpreter/fuspel.c @@ -50,7 +50,6 @@ struct fuspel *import(struct fuspel *already_parsed, char *fname) { pgm = parse(tokens); free_token_list(tokens); - my_free(tokens); concat_fuspel(pgm, already_parsed); @@ -105,6 +104,10 @@ int main(int argc, char *argv[]) { env.printProgram = false; env.program = NULL; +#ifdef _FUSPEL_DEBUG + env.debugGraphs = false; +#endif + argp_parse(&argp, argc, argv, 0, 0, &env); if (!env.program) { diff --git a/interpreter/lex.c b/interpreter/lex.c index 5032bfb..497ee8e 100644 --- a/interpreter/lex.c +++ b/interpreter/lex.c @@ -34,87 +34,89 @@ unsigned char lex_name_length(char *input) { } struct token_list *lex(struct token_list *list, char *input) { - struct token_list *first_list; bool create_new_token; while (*input && is_space_char(*input)) input++; - if (*input == 0) { + if (*input == 0) return list; - } - if (list) { - first_list = list; - while (list->rest) list = list->rest; - list->rest = my_calloc(1, sizeof(struct token_list)); - list = list->rest; - } else { - first_list = list = my_calloc(1, sizeof(struct token_list)); + if (!list) { + list = my_calloc(1, + sizeof(struct token_list) + + INITIAL_TOKEN_LIST_SIZE * sizeof(struct token) + 1); + list->length = INITIAL_TOKEN_LIST_SIZE; + list->index = 0; } - create_new_token = 1; + create_new_token = true; while (*input) { - list->elem.var = NULL; + if (list->index >= list->length) { + list = my_realloc(list, + sizeof(struct token_list) + + 2 * list->length * sizeof(struct token) + 1); + list->length *= 2; + } + + list->elems[list->index].var = NULL; switch (*input) { - case ';': list->elem.kind = TOKEN_SEMICOLON; break; - case ':': list->elem.kind = TOKEN_COLON; break; - case '(': list->elem.kind = TOKEN_OPEN_P; break; - case ')': list->elem.kind = TOKEN_CLOSE_P; break; - case '[': list->elem.kind = TOKEN_OPEN_SQ; break; - case ']': list->elem.kind = TOKEN_CLOSE_SQ; break; - case '=': list->elem.kind = TOKEN_EQUALS; break; - case ',': list->elem.kind = TOKEN_COMMA; break; + case ';': list->elems[list->index].kind = TOKEN_SEMICOLON; break; + case ':': list->elems[list->index].kind = TOKEN_COLON; break; + case '(': list->elems[list->index].kind = TOKEN_OPEN_P; break; + case ')': list->elems[list->index].kind = TOKEN_CLOSE_P; break; + case '[': list->elems[list->index].kind = TOKEN_OPEN_SQ; break; + case ']': list->elems[list->index].kind = TOKEN_CLOSE_SQ; break; + case '=': list->elems[list->index].kind = TOKEN_EQUALS; break; + case ',': list->elems[list->index].kind = TOKEN_COMMA; break; default: if (input[0] == '/' && input[1] == '/') { while (input && input[0] != '\n') input++; + create_new_token = false; break; - } - if (input[0] == 'c' && input[1] == 'o' && input[2] == 'd' && - input[3] == 'e' && is_space_char(input[4])) { - list->elem.kind = TOKEN_CODE; + } else if (input[0] == 'c' && input[1] == 'o' && + input[2] == 'd' && input[3] == 'e' && + is_space_char(input[4])) { + list->elems[list->index].kind = TOKEN_CODE; input += 4; break; - } - if (input[0] == 'i' && input[1] == 'm' && input[2] == 'p' && - input[3] == 'o' && input[4] == 'r' && - input[5] == 't' && is_space_char(input[6])) { - list->elem.kind = TOKEN_IMPORT; + } else if (input[0] == 'i' && input[1] == 'm' && + input[2] == 'p' && input[3] == 'o' && + input[4] == 'r' && input[5] == 't' && + is_space_char(input[6])) { + list->elems[list->index].kind = TOKEN_IMPORT; input += 6; break; - } - if (is_int_char(*input)) { + } else if (is_int_char(*input)) { char *s; unsigned char len = lex_int_length(input); s = my_calloc(1, len + 1); - list->elem.kind = TOKEN_INT; - list->elem.var = my_calloc(1, sizeof(int)); + list->elems[list->index].kind = TOKEN_INT; + list->elems[list->index].var = my_calloc(1, sizeof(int)); strncpy(s, input, len); - *((int*) list->elem.var) = atoi(s); + *((int*) list->elems[list->index].var) = atoi(s); my_free(s); input += len - 1; } else if (is_name_char(*input)) { unsigned char len = lex_name_length(input); - list->elem.kind = TOKEN_NAME; - list->elem.var = my_calloc(1, len + 1); - strncpy(list->elem.var, input, len); + list->elems[list->index].kind = TOKEN_NAME; + list->elems[list->index].var = my_calloc(1, len + 1); + strncpy(list->elems[list->index].var, input, len); input += len - 1; } else if (is_space_char(*input)) { - create_new_token = 0; + create_new_token = false; } else { - free_token_list(first_list); - my_free(first_list); + free_token_list(list); + my_free(list); return NULL; } } do input++; while (*input && is_space_char(*input)); - if (*input && create_new_token) { - list->rest = my_calloc(1, sizeof(struct token_list)); - list = list->rest; - } + if (create_new_token) + list->index++; } - return first_list; + return list; } diff --git a/interpreter/lex.h b/interpreter/lex.h index e6f525b..45a5a3c 100644 --- a/interpreter/lex.h +++ b/interpreter/lex.h @@ -3,6 +3,8 @@ #include "syntax.h" +#define INITIAL_TOKEN_LIST_SIZE 20 + struct token_list *lex(struct token_list*, char*); #endif diff --git a/interpreter/parse.c b/interpreter/parse.c index b949cb1..6c3ed24 100644 --- a/interpreter/parse.c +++ b/interpreter/parse.c @@ -1,5 +1,6 @@ #include "parse.h" +#include #include #include "code.h" @@ -7,54 +8,66 @@ extern struct fuspel *import(struct fuspel *already_parsed, char *name); -struct token_list *parse_name(char **name, struct token_list *list) { - if (list->elem.kind != TOKEN_NAME) - return NULL; +struct parsing_list { + struct token_list *tokens; + unsigned int i; +}; + +bool parse_name(char **name, struct parsing_list *list) { + if (list->tokens->elems[list->i].kind != TOKEN_NAME) + return false; // TODO error handling - *name = my_calloc(1, strlen(list->elem.var) + 1); + *name = my_calloc(1, strlen(list->tokens->elems[list->i].var) + 1); - strcpy(*name, list->elem.var); + strcpy(*name, list->tokens->elems[list->i].var); - return list->rest; + list->i++; + + return true; } -struct token_list *parse_simple_expression(struct expression *expr, struct token_list *list) { +bool parse_simple_expression(struct expression *expr, struct parsing_list *list) { struct expression *_expr; - switch (list->elem.kind) { + switch (list->tokens->elems[list->i].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; + *((int*) expr->var1) = *((int*) list->tokens->elems[list->i].var); + list->i++; + return true; case TOKEN_NAME: expr->kind = EXPR_NAME; - list = parse_name((char**) &expr->var1, list); - return list; + parse_name((char**) &expr->var1, list); + return true; case TOKEN_CODE: - if (list->rest && list->rest->elem.kind == TOKEN_NAME) { + if (list->i < list->tokens->index && + list->tokens->elems[list->i+1].kind == TOKEN_NAME) { char *name; expr->kind = EXPR_CODE; - list = parse_name(&name, list->rest); + list->i++; + parse_name(&name, list); expr->var2 = my_calloc(1, sizeof(unsigned char)); *((unsigned char*) expr->var2) = code_find(name, &expr->var1); my_free(name); - return list; + return true; } else { - return NULL; + return false; // TODO error handling } case TOKEN_OPEN_P: - list = parse_simple_expression(expr, list->rest); - if (!list) - return NULL; + list->i++; + if (!parse_simple_expression(expr, list)) { + list->i--; + return false; + } - switch (list->elem.kind) { + switch (list->tokens->elems[list->i].kind) { case TOKEN_CLOSE_P: - return list->rest; - break; + list->i++; + return true; case TOKEN_COMMA: _expr = my_calloc(1, sizeof(struct expression)); cpy_expression(_expr, expr); @@ -62,82 +75,80 @@ struct token_list *parse_simple_expression(struct expression *expr, struct token expr->kind = EXPR_TUPLE; expr->var1 = _expr; expr->var2 = my_calloc(1, sizeof(struct expression)); - list = parse_simple_expression(expr->var2, list->rest); - if (!list || list->elem.kind != TOKEN_CLOSE_P) { + list->i++; + if (!parse_simple_expression(expr->var2, list) || + list->tokens->elems[list->i].kind != TOKEN_CLOSE_P) { + list->i--; free_expression(_expr); my_free(_expr); - return NULL; + return false; } else { - return list->rest; + list->i++; + return true; } - break; default: - return NULL; + return false; } break; case TOKEN_OPEN_SQ: expr->kind = EXPR_LIST; - list = list->rest; - if (!list) - return NULL; + list->i++; - if (list->elem.kind == TOKEN_CLOSE_SQ) - return list->rest; + if (list->tokens->elems[list->i].kind == TOKEN_CLOSE_SQ) { + list->i++; + return true; + } expr->var1 = my_calloc(1, sizeof(struct expression)); expr->var2 = my_calloc(1, sizeof(struct expression)); - list = parse_simple_expression(expr->var1, list); - - if (!list || list->elem.kind != TOKEN_COLON) { + if (!parse_simple_expression(expr->var1, list) || + list->tokens->elems[list->i].kind != TOKEN_COLON) { free_expression(expr->var1); - return NULL; + return false; } - list = parse_simple_expression(expr->var2, list->rest); - - if (!list || list->elem.kind != TOKEN_CLOSE_SQ) { + list->i++; + if (!parse_simple_expression(expr->var2, list) || + list->tokens->elems[list->i].kind != TOKEN_CLOSE_SQ) { free_expression(expr->var1); my_free(expr->var1); free_expression(expr->var2); my_free(expr->var2); - return NULL; + return false; } - return list->rest; - - break; + list->i++; + return true; default: - return NULL; + return false; } } -struct token_list *parse_arg_list(struct arg_list **args, struct token_list *list) { - if (list->elem.kind == TOKEN_EQUALS) - return list; +bool parse_arg_list(struct arg_list **args, struct parsing_list *list) { + if (list->tokens->elems[list->i].kind == TOKEN_EQUALS) + return true; *args = my_calloc(1, sizeof(struct arg_list)); - list = parse_simple_expression(&(*args)->elem, list); - if (!list) - return NULL; - - list = parse_arg_list(&(*args)->rest, list); + if (!parse_simple_expression(&(*args)->elem, list)) + return false; - return list; + return parse_arg_list(&(*args)->rest, list); } -struct token_list *parse_expression(struct expression*, struct token_list*); +bool parse_expression(struct expression*, struct parsing_list*); -struct token_list *parse_expression_no_app(struct expression *expr, struct token_list *list) { - if (list->elem.kind == TOKEN_OPEN_P) { - struct 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) { +bool parse_expression_no_app(struct expression *expr, struct parsing_list *list) { + if (list->tokens->elems[list->i].kind == TOKEN_OPEN_P) { + list->i++; + if (parse_expression(expr, list)) { + if (list->tokens->elems[list->i].kind == TOKEN_CLOSE_P) { + list->i++; + return true; + } else if (list->tokens->elems[list->i].kind == TOKEN_COMMA) { struct expression *_expr = my_calloc(1, sizeof(struct expression)); cpy_expression(_expr, expr); @@ -147,88 +158,91 @@ struct token_list *parse_expression_no_app(struct expression *expr, struct token expr->var2 = my_calloc(1, sizeof(struct expression)); - _list = parse_expression(expr->var2, _list->rest); - if (_list && _list->elem.kind == TOKEN_CLOSE_P) { - return _list->rest; + list->i++; + if (parse_expression(expr->var2, list) && + list->tokens->elems[list->i].kind == TOKEN_CLOSE_P) { + list->i++; + return true; } } free_expression(expr); } - } else if (list->elem.kind == TOKEN_OPEN_SQ) { - struct token_list *_list; - + } else if (list->tokens->elems[list->i].kind == TOKEN_OPEN_SQ) { expr->kind = EXPR_LIST; - if (list->rest->elem.kind == TOKEN_CLOSE_SQ) { - return list->rest->rest; + if (list->tokens->elems[list->i+1].kind == TOKEN_CLOSE_SQ) { + list->i += 2; + return true; } expr->var1 = my_calloc(1, sizeof(struct expression)); expr->var2 = my_calloc(1, sizeof(struct expression)); - _list = parse_expression(expr->var1, list->rest); - if (!_list || - (_list->elem.kind != TOKEN_COLON && - _list->elem.kind != TOKEN_COMMA && - _list->elem.kind != TOKEN_CLOSE_SQ)) { + list->i++; + if (!parse_expression(expr->var1, list) || + (list->tokens->elems[list->i].kind != TOKEN_COLON && + list->tokens->elems[list->i].kind != TOKEN_COMMA && + list->tokens->elems[list->i].kind != TOKEN_CLOSE_SQ)) { free_expression(expr); - } else if (_list->elem.kind == TOKEN_CLOSE_SQ) { + } else if (list->tokens->elems[list->i].kind == TOKEN_CLOSE_SQ) { ((struct expression *) expr->var2)->kind = EXPR_LIST; ((struct expression *) expr->var2)->var1 = NULL; ((struct expression *) expr->var2)->var2 = NULL; - return _list->rest; - } else if (_list->elem.kind == TOKEN_COMMA) { + list->i++; + return true; + } else if (list->tokens->elems[list->i].kind == TOKEN_COMMA) { struct expression *_expr = expr; - while (_list && _list->elem.kind == TOKEN_COMMA) { + bool loop = true; + while (loop && list->tokens->elems[list->i].kind == TOKEN_COMMA) { _expr = _expr->var2; _expr->kind = EXPR_LIST; _expr->var1 = my_calloc(1, sizeof(struct expression)); _expr->var2 = my_calloc(1, sizeof(struct expression)); - _list = parse_expression(_expr->var1, _list->rest); + list->i++; + loop = parse_expression(_expr->var1, list); } - if (!_list || - (_list->elem.kind != TOKEN_CLOSE_SQ && - _list->elem.kind != TOKEN_COLON)) { + if (list->i >= list->tokens->length || + (list->tokens->elems[list->i].kind != TOKEN_CLOSE_SQ && + list->tokens->elems[list->i].kind != TOKEN_COLON)) { free_expression(expr); - } else if (_list->elem.kind == TOKEN_COLON) { - _list = parse_expression(((struct expression*) expr->var2)->var2, _list->rest); - if (!_list || _list->elem.kind != TOKEN_CLOSE_SQ) { + } else if (list->tokens->elems[list->i].kind == TOKEN_COLON) { + list->i++; + if (!parse_expression(((struct expression*) expr->var2)->var2, list) || + list->tokens->elems[list->i].kind != TOKEN_CLOSE_SQ) free_expression(expr); - } else { - return _list->rest; - } - } else if (_list->elem.kind == TOKEN_CLOSE_SQ) { + else + return list; + } else if (list->tokens->elems[list->i].kind == TOKEN_CLOSE_SQ) { ((struct expression*) _expr->var2)->kind = EXPR_LIST; ((struct expression*) _expr->var2)->var1 = NULL; ((struct expression*) _expr->var2)->var2 = NULL; - return _list->rest; + list->i++; + return list; } - } else if (_list->elem.kind == TOKEN_COLON) { - _list = parse_expression(expr->var2, _list->rest); - if (!_list || _list->elem.kind != TOKEN_CLOSE_SQ) { + } else if (list->tokens->elems[list->i].kind == TOKEN_COLON) { + list->i++; + if (!parse_expression(expr->var2, list) || + list->tokens->elems[list->i].kind != TOKEN_CLOSE_SQ) { free_expression(expr); } else { - return _list->rest; + list->i++; + return list; } } } - list = parse_simple_expression(expr, list); - - return list; + return parse_simple_expression(expr, list); } -struct token_list *parse_expression(struct expression *expr, struct token_list *list) { - list = parse_expression_no_app(expr, list); - if (!list) - return NULL; +bool parse_expression(struct expression *expr, struct parsing_list *list) { + if (!parse_expression_no_app(expr, list)) + return false; - 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) { - + while (list->tokens->elems[list->i].kind != TOKEN_SEMICOLON && + list->tokens->elems[list->i].kind != TOKEN_CLOSE_P && + list->tokens->elems[list->i].kind != TOKEN_CLOSE_SQ && + list->tokens->elems[list->i].kind != TOKEN_COLON && + list->tokens->elems[list->i].kind != TOKEN_COMMA) { struct expression *_expr = my_calloc(1, sizeof(struct expression)); cpy_expression(_expr, expr); @@ -238,69 +252,77 @@ struct token_list *parse_expression(struct expression *expr, struct token_list * expr->var2 = my_calloc(1, sizeof(struct expression)); - list = parse_expression_no_app(expr->var2, list); - if (!list) { + if (!parse_expression_no_app(expr->var2, list)) { free_expression(expr); - return NULL; + return false; } } - return list; + return true; } -struct token_list *parse_rule(struct rewrite_rule *rule, struct token_list *list) { - list = parse_name(&rule->name, list); - if (!list) - return NULL; +bool parse_rule(struct rewrite_rule *rule, struct parsing_list *list) { + if (!parse_name(&rule->name, list)) + return false; - list = parse_arg_list(&rule->args, list); - if (!list) { + if (!parse_arg_list(&rule->args, list)) { my_free(rule->name); - return NULL; + return false; } - if (list->elem.kind != TOKEN_EQUALS) { + if (list->tokens->elems[list->i].kind != TOKEN_EQUALS) { my_free(rule->name); free_arg_list(rule->args); - return NULL; + return false; } - list = parse_expression(&rule->rhs, list->rest); - - return list; + list->i++; + return parse_expression(&rule->rhs, list); } -struct fuspel *parse(struct token_list *list) { +struct fuspel *parse_intern(struct parsing_list *list) { struct fuspel *rules = NULL; struct fuspel *return_rules; - while (list && list->elem.kind == TOKEN_SEMICOLON) - list = list->rest; + while (list->i < list->tokens->index && + list->tokens->elems[list->i].kind == TOKEN_SEMICOLON) + list->i++; - if (!list) + if (list->i >= list->tokens->index) return NULL; - if (list->elem.kind == TOKEN_IMPORT) { - list = list->rest; - if (!list || list->elem.kind != TOKEN_NAME) + if (list->tokens->elems[list->i].kind == TOKEN_IMPORT) { + list->i++; + if (!list || list->tokens->elems[list->i].kind != TOKEN_NAME) return NULL; - rules = import(rules, list->elem.var); + rules = import(rules, list->tokens->elems[list->i].var); if (!rules) return NULL; - list = list->rest->rest; + list->i += 2; return_rules = rules; while (rules->rest) rules = rules->rest; } else { return_rules = rules = my_calloc(1, sizeof(struct fuspel)); - list = parse_rule(&rules->rule, list); - if (!list) + if (!parse_rule(&rules->rule, list)) { + my_free(rules); return NULL; + } } - rules->rest = parse(list); + rules->rest = parse_intern(list); return return_rules; } + +struct fuspel *parse(struct token_list *tk_list) { + struct fuspel *pgm; + struct parsing_list *list = my_calloc(1, sizeof(struct parsing_list)); + list->i = 0; + list->tokens = tk_list; + pgm = parse_intern(list); + my_free(list); + return pgm; +} diff --git a/interpreter/print.c b/interpreter/print.c index 5433fcb..e1ed9ed 100644 --- a/interpreter/print.c +++ b/interpreter/print.c @@ -20,8 +20,8 @@ void print_token(struct token *tk) { case TOKEN_CLOSE_SQ: c = ']'; break; case TOKEN_EQUALS: c = '='; break; case TOKEN_COMMA: c = ','; break; - case TOKEN_CODE: printf("code "); return; - case TOKEN_IMPORT: printf("import "); return; + case TOKEN_CODE: printf("code"); return; + case TOKEN_IMPORT: printf("import"); return; case TOKEN_NAME: printf("%s", (char*) tk->var); return; @@ -34,10 +34,10 @@ void print_token(struct token *tk) { } void print_token_list(struct token_list *list) { - print_token(&list->elem); - if (list->rest) { - printf(list->elem.kind == TOKEN_SEMICOLON ? "\n" : " "); - print_token_list(list->rest); + unsigned int i; + for (i = 0; i < list->index; i++) { + print_token(&list->elems[i]); + printf(list->elems[i].kind == TOKEN_SEMICOLON ? "\n" : " "); } } diff --git a/interpreter/syntax.c b/interpreter/syntax.c index c79d482..015f820 100644 --- a/interpreter/syntax.c +++ b/interpreter/syntax.c @@ -10,10 +10,10 @@ void free_token(struct token *tk) { } void free_token_list(struct token_list *list) { - free_token(&list->elem); - if (list->rest) - free_token_list(list->rest); - my_free(list->rest); + unsigned int i; + for (i = 0; i < list->index; i++) + free_token(&list->elems[i]); + my_free(list); } bool empty_args_list(struct arg_list *list) { diff --git a/interpreter/syntax.h b/interpreter/syntax.h index 09ba3bc..f2043c3 100644 --- a/interpreter/syntax.h +++ b/interpreter/syntax.h @@ -26,8 +26,9 @@ struct token { }; struct token_list { - struct token elem; - struct token_list *rest; + unsigned int length; + unsigned int index; + struct token elems[]; }; void free_token(struct token*); -- cgit v1.2.3