diff options
Diffstat (limited to 'dimension/tokenize.c')
-rw-r--r-- | dimension/tokenize.c | 1098 |
1 files changed, 0 insertions, 1098 deletions
diff --git a/dimension/tokenize.c b/dimension/tokenize.c deleted file mode 100644 index ced6fe5..0000000 --- a/dimension/tokenize.c +++ /dev/null @@ -1,1098 +0,0 @@ -/************************************************************************* - * Copyright (C) 2010 Tavian Barnes <tavianator@tavianator.com> * - * * - * This file is part of Dimension. * - * * - * Dimension is free software; you can redistribute it and/or modify it * - * under the terms of the GNU General Public License as published by the * - * Free Software Foundation; either version 3 of the License, or (at * - * your option) any later version. * - * * - * Dimension is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - *************************************************************************/ - -#include "tokenize.h" -#include "directives.h" -#include "utility.h" -#include <libgen.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> - -typedef struct dmnsn_buffered_token { - dmnsn_token_type type; - dmnsn_parse_item lval; - dmnsn_parse_location lloc; -} dmnsn_buffered_token; - -typedef struct dmnsn_token_buffer { - dmnsn_token_type type; - /* To indicate that the first token should be returned as-is */ - #define DMNSN_T_LEX_VERBATIM DMNSN_T_EOF - - /* Whether to automatically delete this buffer if we reach its end */ - bool auto_delete; - - dmnsn_parse_location lloc; - dmnsn_array *buffered; - size_t i; - - struct dmnsn_token_buffer *prev; - - const char *filename; - void *ptr; -} dmnsn_token_buffer; - -static dmnsn_token_buffer * -dmnsn_new_token_buffer(dmnsn_parse_location lloc, dmnsn_token_type type, - dmnsn_token_buffer *prev, const char *filename) -{ - dmnsn_token_buffer *tbuffer = dmnsn_malloc(sizeof(dmnsn_token_buffer)); - tbuffer->type = type; - tbuffer->auto_delete = true; - tbuffer->lloc = lloc; - tbuffer->buffered = dmnsn_new_array(sizeof(dmnsn_buffered_token)); - tbuffer->i = 0; - tbuffer->prev = prev; - tbuffer->filename = filename; - tbuffer->ptr = NULL; - return tbuffer; -} - -static void -dmnsn_delete_token_buffer(void *ptr) -{ - dmnsn_token_buffer *tbuffer = ptr; - if (tbuffer) { - DMNSN_ARRAY_FOREACH (dmnsn_buffered_token *, buffered, tbuffer->buffered) { - dmnsn_free(buffered->lval.value); - } - - dmnsn_delete_array(tbuffer->buffered); - dmnsn_free(tbuffer); - } -} - -static int -dmnsn_yylex_wrapper(dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, - const char *filename, dmnsn_symbol_table *symtable, - void *yyscanner); -int dmnsn_ld_yyparse(const char *filename, void *yyscanner, - dmnsn_symbol_table *symtable); - -static int -dmnsn_buffer_balanced(dmnsn_token_buffer *tbuffer, bool recursive, - dmnsn_token_type left, dmnsn_token_type right, - const char *filename, dmnsn_symbol_table *symtable, - void *yyscanner) -{ - dmnsn_buffered_token buffered; - - if (tbuffer->prev) - tbuffer->prev->auto_delete = false; - - int nesting = -1; - while (1) { - if (recursive) { - buffered.type = dmnsn_yylex(&buffered.lval, &buffered.lloc, - filename, symtable, yyscanner); - } else { - buffered.type = dmnsn_yylex_wrapper(&buffered.lval, &buffered.lloc, - filename, symtable, yyscanner); - } - - if (buffered.type == DMNSN_T_EOF) { - dmnsn_diagnostic(buffered.lloc, "syntax error, unexpected end-of-file"); - return 1; - } else if (buffered.type == DMNSN_T_LEX_ERROR) { - return 1; - } - - dmnsn_array_push(tbuffer->buffered, &buffered); - - if (buffered.type == left) { - if (nesting < 0) - nesting = 1; - else - ++nesting; - } else if (buffered.type == right) { - --nesting; - if (nesting == 0) { - break; - } - } - } - - if (tbuffer->prev) - tbuffer->prev->auto_delete = true; - - return 0; -} - -static int -dmnsn_buffer_strexp(dmnsn_token_buffer *tbuffer, bool recursive, - const char *filename, dmnsn_symbol_table *symtable, - void *yyscanner) -{ - dmnsn_buffered_token buffered; - - if (tbuffer->prev) - tbuffer->prev->auto_delete = false; - - if (recursive) { - buffered.type = dmnsn_yylex(&buffered.lval, &buffered.lloc, - filename, symtable, yyscanner); - } else { - buffered.type = dmnsn_yylex_wrapper(&buffered.lval, &buffered.lloc, - filename, symtable, yyscanner); - } - - if (buffered.type == DMNSN_T_EOF) { - dmnsn_diagnostic(buffered.lloc, "syntax error, unexpected end-of-file"); - return 1; - } else if (buffered.type == DMNSN_T_LEX_ERROR) { - return 1; - } - /* Buffer the first token */ - dmnsn_array_push(tbuffer->buffered, &buffered); - - bool is_strexp = buffered.type != DMNSN_T_STRING; - if (buffered.type == DMNSN_T_IDENTIFIER) { - /* Check if it's a string identifier or a macro */ - dmnsn_astnode *inode = dmnsn_find_symbol(symtable, buffered.lval.value); - if (!inode || inode->type == DMNSN_AST_STRING) { - is_strexp = false; - } - } - - if (is_strexp) { - /* Grab all the tokens belonging to the string expression */ - return dmnsn_buffer_balanced(tbuffer, recursive, - DMNSN_T_LPAREN, DMNSN_T_RPAREN, - filename, symtable, yyscanner); - } - - if (tbuffer->prev) - tbuffer->prev->auto_delete = true; - - return 0; -} - -static dmnsn_token_buffer * -dmnsn_include_buffer(int token, dmnsn_token_buffer *prev, - dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, - const char *filename, dmnsn_symbol_table *symtable, - void *yyscanner) -{ - dmnsn_token_buffer *include_buffer - = dmnsn_new_token_buffer(*llocp, DMNSN_T_LEX_VERBATIM, prev, filename); - - /* Buffer the current token */ - dmnsn_buffered_token buffered = { - .type = token, - .lval = *lvalp, - .lloc = *llocp - }; - dmnsn_array_push(include_buffer->buffered, &buffered); - - /* Buffer the following string expression */ - if (dmnsn_buffer_strexp(include_buffer, true, filename, symtable, yyscanner) - != 0) - { - dmnsn_delete_token_buffer(include_buffer); - return NULL; - } - - /* Fake EOF */ - buffered.type = DMNSN_T_EOF; - buffered.lval.value = NULL; - dmnsn_array_push(include_buffer->buffered, &buffered); - - dmnsn_yyset_extra(include_buffer, yyscanner); - if (dmnsn_ld_yyparse(filename, yyscanner, symtable) != 0) { - dmnsn_yyset_extra(include_buffer->prev, yyscanner); - dmnsn_delete_token_buffer(include_buffer); - return NULL; - } - - dmnsn_yyset_extra(include_buffer->prev, yyscanner); - dmnsn_delete_token_buffer(include_buffer); - - dmnsn_token_buffer *tbuffer - = dmnsn_new_token_buffer(*llocp, token, prev, filename); - - dmnsn_astnode *inode = dmnsn_find_symbol(symtable, "$include"); - dmnsn_assert(inode, "$include unset."); - dmnsn_assert(inode->type == DMNSN_AST_STRING, "$include has wrong type."); - - const char *include = inode->ptr; - char *filename_copy = dmnsn_strdup(filename); - char *localdir = dirname(filename_copy); - char *local_include = dmnsn_malloc(strlen(localdir) + strlen(include) + 2); - strcpy(local_include, localdir); - strcat(local_include, "/"); - strcat(local_include, include); - dmnsn_free(filename_copy); - - FILE *file = fopen(local_include, "r"); - if (!file) { - dmnsn_diagnostic(*llocp, "Couldn't open include file '%s'", include); - dmnsn_undef_symbol(symtable, "$include"); - dmnsn_free(local_include); - dmnsn_delete_token_buffer(tbuffer); - return NULL; - } - tbuffer->ptr = file; - - void *buffer = dmnsn_yy_make_buffer(file, yyscanner); - if (!buffer) { - dmnsn_diagnostic(*llocp, "Couldn't allocate buffer for include file '%s'", - include); - dmnsn_undef_symbol(symtable, "$include"); - fclose(file); - dmnsn_free(local_include); - dmnsn_delete_token_buffer(tbuffer); - return NULL; - } - dmnsn_yy_push_buffer(buffer, yyscanner); - - /* Stuff the filename in the symbol table to persist it */ - dmnsn_astnode *includes = dmnsn_find_symbol(symtable, "$includes"); - if (!includes) { - dmnsn_declare_symbol(symtable, "$includes", dmnsn_new_ast_array()); - includes = dmnsn_find_symbol(symtable, "$includes"); - } - dmnsn_assert(includes, "$includes unset."); - dmnsn_assert(includes->type == DMNSN_AST_ARRAY, - "$includes has wrong type."); - - dmnsn_astnode fnode = dmnsn_new_ast_string(local_include); - dmnsn_free(local_include); - tbuffer->filename = fnode.ptr; - dmnsn_array_push(includes->children, &fnode); - - dmnsn_push_scope(symtable); - - dmnsn_undef_symbol(symtable, "$include"); - return tbuffer; -} - -static dmnsn_token_buffer * -dmnsn_declaration_buffer(int token, dmnsn_token_buffer *prev, - dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, - const char *filename, dmnsn_symbol_table *symtable, - void *yyscanner) -{ - dmnsn_token_buffer *tbuffer - = dmnsn_new_token_buffer(*llocp, DMNSN_T_LEX_VERBATIM, prev, filename); - - /* Buffer the current token */ - dmnsn_buffered_token buffered = { - .type = token, - .lval = *lvalp, - .lloc = *llocp - }; - dmnsn_array_push(tbuffer->buffered, &buffered); - - if (prev) - prev->auto_delete = false; - - /* Grab all the tokens belonging to the #declare/#local, i.e. until the braces - balance or we hit a semicolon */ - int bracelevel = -1; - while (1) { - /* Recursive call -- permit other directives inside the declaration */ - buffered.type = dmnsn_yylex(&buffered.lval, &buffered.lloc, - filename, symtable, yyscanner); - - if (buffered.type == DMNSN_T_EOF) { - dmnsn_diagnostic(buffered.lloc, "syntax error, unexpected end-of-file"); - dmnsn_delete_token_buffer(tbuffer); - return NULL; - } else if (buffered.type == DMNSN_T_LEX_ERROR) { - dmnsn_delete_token_buffer(tbuffer); - return NULL; - } - - dmnsn_array_push(tbuffer->buffered, &buffered); - - if (buffered.type == DMNSN_T_LBRACE) { - if (bracelevel < 0) - bracelevel = 1; - else - ++bracelevel; - } else if (buffered.type == DMNSN_T_RBRACE) { - --bracelevel; - if (bracelevel == 0) { - break; - } - } else if (buffered.type == DMNSN_T_SEMICOLON) { - break; - } - } - - if (prev) - prev->auto_delete = true; - - /* Fake EOF */ - buffered.type = DMNSN_T_EOF; - buffered.lval.value = NULL; - dmnsn_array_push(tbuffer->buffered, &buffered); - - return tbuffer; -} - -static dmnsn_token_buffer * -dmnsn_undef_buffer(int token, dmnsn_token_buffer *prev, - dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, - const char *filename, dmnsn_symbol_table *symtable, - void *yyscanner) -{ - dmnsn_token_buffer *tbuffer - = dmnsn_new_token_buffer(*llocp, DMNSN_T_LEX_VERBATIM, prev, filename); - - /* Buffer the current token */ - dmnsn_buffered_token buffered = { - .type = token, - .lval = *lvalp, - .lloc = *llocp - }; - dmnsn_array_push(tbuffer->buffered, &buffered); - - if (prev) - prev->auto_delete = false; - /* Recursive call */ - buffered.type = dmnsn_yylex(&buffered.lval, &buffered.lloc, - filename, symtable, yyscanner); - if (prev) - prev->auto_delete = true; - - if (buffered.type == DMNSN_T_EOF) { - dmnsn_diagnostic(buffered.lloc, "syntax error, unexpected end-of-file"); - dmnsn_delete_token_buffer(tbuffer); - return NULL; - } else if (buffered.type == DMNSN_T_LEX_ERROR) { - dmnsn_delete_token_buffer(tbuffer); - return NULL; - } - /* Buffer the next token */ - dmnsn_array_push(tbuffer->buffered, &buffered); - - /* Fake EOF */ - buffered.type = DMNSN_T_EOF; - buffered.lval.value = NULL; - dmnsn_array_push(tbuffer->buffered, &buffered); - - return tbuffer; -} - -static dmnsn_token_buffer * -dmnsn_if_buffer(int token, dmnsn_token_buffer *prev, - dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, - const char *filename, dmnsn_symbol_table *symtable, - void *yyscanner) -{ - dmnsn_token_buffer *cond_buffer - = dmnsn_new_token_buffer(*llocp, DMNSN_T_LEX_VERBATIM, prev, filename); - - /* Buffer the current token */ - dmnsn_buffered_token buffered = { - .type = token, - .lval = *lvalp, - .lloc = *llocp - }; - dmnsn_array_push(cond_buffer->buffered, &buffered); - - /* Grab all the tokens belonging to the #if (...) */ - if (dmnsn_buffer_balanced(cond_buffer, true, DMNSN_T_LPAREN, DMNSN_T_RPAREN, - filename, symtable, yyscanner) - != 0) - { - dmnsn_delete_token_buffer(cond_buffer); - return NULL; - } - - /* Fake EOF */ - buffered.type = DMNSN_T_EOF; - buffered.lval.value = NULL; - dmnsn_array_push(cond_buffer->buffered, &buffered); - - dmnsn_yyset_extra(cond_buffer, yyscanner); - if (dmnsn_ld_yyparse(filename, yyscanner, symtable) != 0) { - dmnsn_yyset_extra(cond_buffer->prev, yyscanner); - dmnsn_delete_token_buffer(cond_buffer); - return NULL; - } - - dmnsn_yyset_extra(cond_buffer->prev, yyscanner); - dmnsn_delete_token_buffer(cond_buffer); - - dmnsn_token_buffer *tbuffer - = dmnsn_new_token_buffer(*llocp, token, prev, filename); - - dmnsn_astnode *cnode = dmnsn_find_symbol(symtable, "$cond"); - dmnsn_assert(cnode, "$cond unset."); - - bool cond = false; - if (cnode->type == DMNSN_AST_INTEGER) { - cond = (*(long *)cnode->ptr) ? true : false; - } else if (cnode->type == DMNSN_AST_FLOAT) { - cond = (*(double *)cnode->ptr) ? true : false; - } else { - dmnsn_assert(false, "$cond has wrong type."); - } - - dmnsn_undef_symbol(symtable, "$cond"); - - if (prev) - prev->auto_delete = false; - - int nesting = 1, else_seen = 0; - while (1) { - /* Non-recursive call */ - buffered.type = dmnsn_yylex_wrapper(&buffered.lval, &buffered.lloc, - filename, symtable, yyscanner); - - if (buffered.type == DMNSN_T_EOF) { - dmnsn_diagnostic(buffered.lloc, "syntax error, unexpected end-of-file"); - dmnsn_delete_token_buffer(tbuffer); - return NULL; - } - - switch (buffered.type) { - case DMNSN_T_IF: - case DMNSN_T_IFDEF: - case DMNSN_T_IFNDEF: - case DMNSN_T_MACRO: - case DMNSN_T_SWITCH: - case DMNSN_T_WHILE: - ++nesting; - break; - - case DMNSN_T_END: - --nesting; - break; - - default: - break; - } - - if (nesting == 0) { - break; - } else if (nesting == 1 && buffered.type == DMNSN_T_ELSE) { - if (else_seen - || (tbuffer->prev && tbuffer->prev->type == DMNSN_T_WHILE)) - { - dmnsn_diagnostic(buffered.lloc, "syntax error, unexpected #else"); - dmnsn_delete_token_buffer(tbuffer); - return NULL; - } else { - cond = !cond; - else_seen = 1; - continue; - } - } - - if (cond) { - dmnsn_array_push(tbuffer->buffered, &buffered); - } else { - dmnsn_free(buffered.lval.value); - } - } - - if (prev) - prev->auto_delete = true; - - return tbuffer; -} - -static dmnsn_token_buffer * -dmnsn_while_buffer(int token, dmnsn_token_buffer *prev, - dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, - const char *filename, dmnsn_symbol_table *symtable, - void *yyscanner) -{ - dmnsn_token_buffer *tbuffer - = dmnsn_new_token_buffer(*llocp, token, prev, filename); - - /* Pretend to be an if */ - dmnsn_buffered_token buffered = { - .type = DMNSN_T_IF, - .lval = *lvalp, - .lloc = *llocp - }; - dmnsn_array_push(tbuffer->buffered, &buffered); - - if (prev) - prev->auto_delete = false; - - /* Grab all the tokens belonging to the #while ... #end */ - int nesting = 1; - while (1) { - /* Non-recursive call */ - buffered.type = dmnsn_yylex_wrapper(&buffered.lval, &buffered.lloc, - filename, symtable, yyscanner); - - if (buffered.type == DMNSN_T_EOF) { - dmnsn_diagnostic(buffered.lloc, "syntax error, unexpected end-of-file"); - dmnsn_delete_token_buffer(tbuffer); - return NULL; - } - - dmnsn_array_push(tbuffer->buffered, &buffered); - - switch (buffered.type) { - case DMNSN_T_IF: - case DMNSN_T_IFDEF: - case DMNSN_T_IFNDEF: - case DMNSN_T_MACRO: - case DMNSN_T_SWITCH: - case DMNSN_T_WHILE: - ++nesting; - break; - - case DMNSN_T_END: - --nesting; - break; - - default: - break; - } - - if (nesting == 0) { - break; - } - } - - if (prev) - prev->auto_delete = true; - - return tbuffer; -} - -static dmnsn_token_buffer * -dmnsn_version_buffer(int token, dmnsn_token_buffer *prev, - dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, - const char *filename, dmnsn_symbol_table *symtable, - void *yyscanner) -{ - dmnsn_token_buffer *tbuffer - = dmnsn_new_token_buffer(*llocp, DMNSN_T_LEX_VERBATIM, prev, filename); - - /* Buffer the current token */ - dmnsn_buffered_token buffered = { - .type = token, - .lval = *lvalp, - .lloc = *llocp - }; - dmnsn_array_push(tbuffer->buffered, &buffered); - - if (prev) - prev->auto_delete = false; - - while (buffered.type != DMNSN_T_SEMICOLON) { - /* Recursive call */ - buffered.type = dmnsn_yylex(&buffered.lval, &buffered.lloc, - filename, symtable, yyscanner); - - if (buffered.type == DMNSN_T_EOF) { - dmnsn_diagnostic(buffered.lloc, "syntax error, unexpected end-of-file"); - dmnsn_delete_token_buffer(tbuffer); - return NULL; - } else if (buffered.type == DMNSN_T_LEX_ERROR) { - dmnsn_delete_token_buffer(tbuffer); - return NULL; - } - - dmnsn_array_push(tbuffer->buffered, &buffered); - } - - if (prev) - prev->auto_delete = true; - - /* Fake EOF */ - buffered.type = DMNSN_T_EOF; - buffered.lval.value = NULL; - dmnsn_array_push(tbuffer->buffered, &buffered); - - return tbuffer; -} - -static dmnsn_token_buffer * -dmnsn_stream_buffer(int token, dmnsn_token_buffer *prev, - dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, - const char *filename, dmnsn_symbol_table *symtable, - void *yyscanner) -{ - dmnsn_token_buffer *tbuffer - = dmnsn_new_token_buffer(*llocp, DMNSN_T_LEX_VERBATIM, prev, filename); - - /* Buffer the current token */ - dmnsn_buffered_token buffered = { - .type = token, - .lval = *lvalp, - .lloc = *llocp - }; - dmnsn_array_push(tbuffer->buffered, &buffered); - - /* Buffer the following string expression */ - if (dmnsn_buffer_strexp(tbuffer, true, filename, symtable, yyscanner) - != 0) - { - dmnsn_delete_token_buffer(tbuffer); - return NULL; - } - - /* Fake EOF */ - buffered.type = DMNSN_T_EOF; - buffered.lval.value = NULL; - dmnsn_array_push(tbuffer->buffered, &buffered); - - return tbuffer; -} - -static bool -dmnsn_declare_macro(int token, dmnsn_token_buffer *prev, - dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, - const char *filename, dmnsn_symbol_table *symtable, - void *yyscanner) -{ - dmnsn_token_buffer *decl_buffer - = dmnsn_new_token_buffer(*llocp, DMNSN_T_LEX_VERBATIM, prev, filename); - - /* Buffer the current token */ - dmnsn_buffered_token buffered = { - .type = token, - .lval = *lvalp, - .lloc = *llocp - }; - dmnsn_array_push(decl_buffer->buffered, &buffered); - - /* Grab all the tokens belonging to the #macro ID (...) */ - if (dmnsn_buffer_balanced(decl_buffer, true, DMNSN_T_LPAREN, DMNSN_T_RPAREN, - filename, symtable, yyscanner) - != 0) - { - dmnsn_delete_token_buffer(decl_buffer); - return false; - } - - /* Fake EOF */ - buffered.type = DMNSN_T_EOF; - buffered.lval.value = NULL; - dmnsn_array_push(decl_buffer->buffered, &buffered); - - dmnsn_yyset_extra(decl_buffer, yyscanner); - if (dmnsn_ld_yyparse(filename, yyscanner, symtable) != 0) { - dmnsn_yyset_extra(decl_buffer->prev, yyscanner); - dmnsn_delete_token_buffer(decl_buffer); - return false; - } - - dmnsn_yyset_extra(decl_buffer->prev, yyscanner); - dmnsn_delete_token_buffer(decl_buffer); - - dmnsn_token_buffer *tbuffer - = dmnsn_new_token_buffer(*llocp, token, NULL, filename); - - dmnsn_astnode *mname = dmnsn_find_symbol(symtable, "$macro"); - dmnsn_assert(mname, "$macro unset."); - dmnsn_assert(mname->type == DMNSN_AST_STRING, "$macro has wrong type."); - dmnsn_astnode *mnode = dmnsn_find_symbol(symtable, mname->ptr); - dmnsn_assert(mnode, "#macro unset."); - dmnsn_assert(mnode->type == DMNSN_AST_MACRO, "#macro has wrong type."); - dmnsn_undef_symbol(symtable, "$macro"); - - if (prev) - prev->auto_delete = false; - - int nesting = 1; - while (1) { - /* Non-recursive call */ - buffered.type = dmnsn_yylex_wrapper(&buffered.lval, &buffered.lloc, - filename, symtable, yyscanner); - - if (buffered.type == DMNSN_T_EOF) { - dmnsn_diagnostic(buffered.lloc, "syntax error, unexpected end-of-file"); - dmnsn_delete_token_buffer(tbuffer); - return false; - } - - switch (buffered.type) { - case DMNSN_T_IF: - case DMNSN_T_IFDEF: - case DMNSN_T_IFNDEF: - case DMNSN_T_MACRO: - case DMNSN_T_SWITCH: - case DMNSN_T_WHILE: - ++nesting; - break; - - case DMNSN_T_END: - --nesting; - break; - - default: - break; - } - - if (nesting == 0) - break; - - dmnsn_array_push(tbuffer->buffered, &buffered); - } - - if (prev) - prev->auto_delete = true; - - mnode->ptr = tbuffer; - mnode->free_fn = dmnsn_delete_token_buffer; - return true; -} - -static dmnsn_token_buffer * -dmnsn_macro_buffer(int token, dmnsn_astnode *mnode, dmnsn_token_buffer *prev, - dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, - const char *filename, dmnsn_symbol_table *symtable, - void *yyscanner) -{ - dmnsn_token_buffer *invoke_buffer - = dmnsn_new_token_buffer(*llocp, DMNSN_T_LEX_VERBATIM, prev, filename); - - /* Buffer the current token */ - dmnsn_buffered_token buffered = { - .type = token, - .lval = *lvalp, - .lloc = *llocp - }; - dmnsn_array_push(invoke_buffer->buffered, &buffered); - - /* Grab all the tokens belonging to the #macro ID (...) */ - if (dmnsn_buffer_balanced(invoke_buffer, true, DMNSN_T_LPAREN, DMNSN_T_RPAREN, - filename, symtable, yyscanner) - != 0) - { - dmnsn_delete_token_buffer(invoke_buffer); - return NULL; - } - - /* Fake EOF */ - buffered.type = DMNSN_T_EOF; - buffered.lval.value = NULL; - dmnsn_array_push(invoke_buffer->buffered, &buffered); - - dmnsn_yyset_extra(invoke_buffer, yyscanner); - dmnsn_push_scope(symtable); - if (dmnsn_ld_yyparse(filename, yyscanner, symtable) != 0) { - dmnsn_yyset_extra(invoke_buffer->prev, yyscanner); - dmnsn_delete_token_buffer(invoke_buffer); - return NULL; - } - - dmnsn_yyset_extra(invoke_buffer->prev, yyscanner); - dmnsn_delete_token_buffer(invoke_buffer); - - dmnsn_token_buffer *tbuffer = mnode->ptr; - tbuffer->lloc = *llocp; - tbuffer->i = 0; - tbuffer->prev = prev; - return tbuffer; -} - -int dmnsn_yylex_impl(dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, - const char *filename, void *yyscanner); - -static int -dmnsn_yylex_wrapper(dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, - const char *filename, dmnsn_symbol_table *symtable, - void *yyscanner) -{ - dmnsn_token_buffer *tbuffer = dmnsn_yyget_extra(yyscanner); - - while (tbuffer && tbuffer->type != DMNSN_T_INCLUDE - && tbuffer->i >= dmnsn_array_size(tbuffer->buffered)) - { - if (tbuffer->type == DMNSN_T_WHILE) { - tbuffer->i = 0; - } else { - if (!tbuffer->auto_delete) { - return DMNSN_T_EOF; - } - - if (dmnsn_array_size(tbuffer->buffered) == 0 - && tbuffer->prev && tbuffer->prev->type == DMNSN_T_WHILE) - { - dmnsn_yyset_extra(tbuffer->prev, yyscanner); - dmnsn_delete_token_buffer(tbuffer); - tbuffer = dmnsn_yyget_extra(yyscanner); - } - - dmnsn_yyset_extra(tbuffer->prev, yyscanner); - if (tbuffer->type == DMNSN_T_MACRO) { - dmnsn_pop_scope(symtable); - } else { - dmnsn_delete_token_buffer(tbuffer); - } - tbuffer = dmnsn_yyget_extra(yyscanner); - } - } - - int token; - - if (tbuffer && tbuffer->type != DMNSN_T_INCLUDE) { - /* Return buffered tokens */ - dmnsn_buffered_token buffered; - - dmnsn_array_get(tbuffer->buffered, tbuffer->i, &buffered); - token = buffered.type; - - if (buffered.lval.value) { - lvalp->value = dmnsn_strdup(buffered.lval.value); - } else { - lvalp->value = NULL; - } - - *llocp = buffered.lloc; - if (tbuffer->type == DMNSN_T_MACRO) - llocp->parent = &tbuffer->lloc; - ++tbuffer->i; - } else { - const char *real_filename = tbuffer ? tbuffer->filename : filename; - token = dmnsn_yylex_impl(lvalp, llocp, real_filename, yyscanner); - - if (tbuffer && tbuffer->type == DMNSN_T_INCLUDE) { - if (token == DMNSN_T_EOF) { - dmnsn_yy_pop_buffer(yyscanner); - fclose(tbuffer->ptr); - dmnsn_pop_scope(symtable); - dmnsn_yyset_extra(tbuffer->prev, yyscanner); - dmnsn_delete_token_buffer(tbuffer); - return dmnsn_yylex_wrapper(lvalp, llocp, filename, symtable, - yyscanner); - } else { - llocp->parent = &tbuffer->lloc; - } - } - } - - return token; -} - -int -dmnsn_yylex(dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, - const char *filename, dmnsn_symbol_table *symtable, void *yyscanner) -{ - /* - * So... this is kind of ugly. POV-Ray's language directives are not parsable - * by any reasonable bison grammar, since some require skipping arbitrary - * amounts of tokens, or repeatedly parsing tokens. Instead, they are - * implemented transparently by the lexer. The lexing function calls a - * separate parser to handle language directives as they arrise, and returns - * only non-directive tokens. - * - * Ideally we'd use a push parser for the language directives, but bison - * doesn't support GLR push parsers. Instead, we buffer all the appropriate - * tokens and call a pull parser, then discard the buffer and continue. - */ - - while (1) { - int token = dmnsn_yylex_wrapper( - lvalp, llocp, filename, symtable, yyscanner - ); - dmnsn_token_buffer *tbuffer = dmnsn_yyget_extra(yyscanner); - - if (tbuffer && tbuffer->type == DMNSN_T_LEX_VERBATIM && tbuffer->i == 1) { - return token; - } - - switch (token) { - case DMNSN_T_INCLUDE: - { - dmnsn_token_buffer *tb = dmnsn_include_buffer( - token, tbuffer, lvalp, llocp, filename, symtable, yyscanner - ); - if (!tb) { - return DMNSN_T_LEX_ERROR; - } - - dmnsn_yyset_extra(tb, yyscanner); - break; - } - - case DMNSN_T_DECLARE: - case DMNSN_T_LOCAL: - { - dmnsn_token_buffer *tb = dmnsn_declaration_buffer( - token, tbuffer, lvalp, llocp, filename, symtable, yyscanner - ); - if (!tb) { - return DMNSN_T_LEX_ERROR; - } - - dmnsn_yyset_extra(tb, yyscanner); - if (dmnsn_ld_yyparse(filename, yyscanner, symtable) != 0) { - dmnsn_yyset_extra(tb->prev, yyscanner); - dmnsn_delete_token_buffer(tb); - return DMNSN_T_LEX_ERROR; - } - - /* Restore the previous extra pointer */ - dmnsn_yyset_extra(tb->prev, yyscanner); - dmnsn_delete_token_buffer(tb); - break; - } - - case DMNSN_T_UNDEF: - { - dmnsn_token_buffer *tb = dmnsn_undef_buffer( - token, tbuffer, lvalp, llocp, filename, symtable, yyscanner - ); - if (!tb) { - return DMNSN_T_LEX_ERROR; - } - - dmnsn_yyset_extra(tb, yyscanner); - if (dmnsn_ld_yyparse(filename, yyscanner, symtable) != 0) { - dmnsn_yyset_extra(tb->prev, yyscanner); - dmnsn_delete_token_buffer(tb); - return DMNSN_T_LEX_ERROR; - } - - /* Restore the previous extra pointer */ - dmnsn_yyset_extra(tb->prev, yyscanner); - dmnsn_delete_token_buffer(tb); - break; - } - - case DMNSN_T_IF: - case DMNSN_T_IFDEF: - case DMNSN_T_IFNDEF: - { - dmnsn_token_buffer *tb = dmnsn_if_buffer( - token, tbuffer, lvalp, llocp, filename, symtable, yyscanner - ); - if (!tb) { - return DMNSN_T_LEX_ERROR; - } - - dmnsn_yyset_extra(tb, yyscanner); - break; - } - - case DMNSN_T_WHILE: - { - dmnsn_token_buffer *tb = dmnsn_while_buffer( - token, tbuffer, lvalp, llocp, filename, symtable, yyscanner - ); - if (!tb) { - return DMNSN_T_LEX_ERROR; - } - - dmnsn_yyset_extra(tb, yyscanner); - break; - } - - case DMNSN_T_VERSION: - { - dmnsn_token_buffer *tb = dmnsn_version_buffer( - token, tbuffer, lvalp, llocp, filename, symtable, yyscanner - ); - if (!tb) { - return DMNSN_T_LEX_ERROR; - } - - dmnsn_yyset_extra(tb, yyscanner); - if (dmnsn_ld_yyparse(filename, yyscanner, symtable) != 0) { - dmnsn_yyset_extra(tb->prev, yyscanner); - dmnsn_delete_token_buffer(tb); - return DMNSN_T_LEX_ERROR; - } - - /* Restore the previous extra pointer */ - dmnsn_yyset_extra(tb->prev, yyscanner); - dmnsn_delete_token_buffer(tb); - break; - } - - case DMNSN_T_DEBUG: - case DMNSN_T_ERROR: - case DMNSN_T_WARNING: - { - dmnsn_token_buffer *tb = dmnsn_stream_buffer( - token, tbuffer, lvalp, llocp, filename, symtable, yyscanner - ); - if (!tb) { - return DMNSN_T_LEX_ERROR; - } - - dmnsn_yyset_extra(tb, yyscanner); - if (dmnsn_ld_yyparse(filename, yyscanner, symtable) != 0) { - dmnsn_yyset_extra(tb->prev, yyscanner); - dmnsn_delete_token_buffer(tb); - return DMNSN_T_LEX_ERROR; - } - - /* Restore the previous extra pointer */ - dmnsn_yyset_extra(tb->prev, yyscanner); - dmnsn_delete_token_buffer(tb); - break; - } - - case DMNSN_T_MACRO: - { - bool status = dmnsn_declare_macro( - token, tbuffer, lvalp, llocp, filename, symtable, yyscanner - ); - if (!status) { - return DMNSN_T_LEX_ERROR; - } - break; - } - - case DMNSN_T_IDENTIFIER: - { - dmnsn_astnode *symbol = dmnsn_find_symbol(symtable, lvalp->value); - if (symbol && symbol->type == DMNSN_AST_MACRO) { - dmnsn_token_buffer *tb = dmnsn_macro_buffer( - token, symbol, tbuffer, lvalp, llocp, filename, symtable, yyscanner - ); - if (!tb) { - return DMNSN_T_LEX_ERROR; - } - - dmnsn_yyset_extra(tb, yyscanner); - break; - } else { - return token; - } - } - - default: - return token; - } - } -} - -void -dmnsn_yylex_cleanup(void *yyscanner) -{ - dmnsn_token_buffer *tbuffer = dmnsn_yyget_extra(yyscanner); - while (tbuffer) { - if (tbuffer->type == DMNSN_T_INCLUDE) { - dmnsn_yy_pop_buffer(yyscanner); - fclose(tbuffer->ptr); - } - - dmnsn_token_buffer *prev = tbuffer->prev; - if (tbuffer->type != DMNSN_T_MACRO) - dmnsn_delete_token_buffer(tbuffer); - tbuffer = prev; - } - dmnsn_yyset_extra(NULL, yyscanner); -} |