aboutsummaryrefslogtreecommitdiff
path: root/core/bgdc/src/token.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/bgdc/src/token.c')
-rw-r--r--core/bgdc/src/token.c1424
1 files changed, 1424 insertions, 0 deletions
diff --git a/core/bgdc/src/token.c b/core/bgdc/src/token.c
new file mode 100644
index 0000000..5d47b98
--- /dev/null
+++ b/core/bgdc/src/token.c
@@ -0,0 +1,1424 @@
+/*
+ * Copyright © 2006-2016 SplinterGU (Fenix/Bennugd)
+ * Copyright © 2002-2006 Fenix Team (Fenix)
+ * Copyright © 1999-2002 José Luis Cebrián Pagüe (Fenix)
+ *
+ * This file is part of Bennu - Game Development
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ *
+ */
+
+/* Pending: no newline at end of file */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "bgdc.h"
+
+
+/* ---------------------------------------------------------------------- */
+/* Tokenizador. La función token_next, ampliamente utilizada, recoge el */
+/* siguiente token (identificador, operador, etc) del código fuente, y */
+/* rellena la estructura global "token" con los datos del mismo. */
+/* ---------------------------------------------------------------------- */
+
+int line_count = 0 ; /* Se pone a 0, ya que lo incremente con cada \n, y hasta no obtener un \n no se procesa la linea (Splinter) */
+int current_file = 0 ;
+
+static int prepro_sp = 0 ;
+static int prepro_stack[1024] ;
+
+static int disable_prepro = 0 ;
+static int disable_expand_defines = 0 ;
+static int identifiers_as_strings = 0 ;
+
+struct _token token ;
+struct _token token_prev ;
+struct _token token_saved ;
+static int use_saved = 0 ;
+
+typedef struct _define
+{
+ int code;
+ char * text;
+ int param_count;
+ int param_id[MAX_MACRO_PARAMS];
+}
+DEFINE;
+
+static const char * source_ptr;
+static char * source_start;
+static const char * old_sources[MAX_SOURCES];
+static char * old_sources_start[MAX_SOURCES];
+static int old_line_counts[MAX_SOURCES];
+static int old_current_file[MAX_SOURCES];
+static int sources = 0;
+static DEFINE * defines = NULL;
+static int defines_allocated = 0;
+static int defines_count = 0;
+static int id_define;
+static int id_undef;
+static int id_ifdef;
+static int id_ifndef;
+static int id_endif;
+static int id_else;
+static int id_if;
+
+/* --------------------------------------------------------------------------- */
+
+static int token_endfile();
+
+/* ---------------------------------------------------------------------- */
+
+#define SKIP_C89_COMMENTS \
+ if (*source_ptr && *source_ptr == '/' && *(source_ptr + 1) == '*') { \
+ * ((char *) source_ptr++) = ' '; * ((char *) source_ptr++) = ' '; \
+ while (*source_ptr && (*source_ptr != '*' || *(source_ptr + 1) != '/')) { \
+ if (*source_ptr == '\n') { line_count++; * ((char *) source_ptr++) = ' '; continue ;} \
+ * ((char *) source_ptr++) = ' '; \
+ } \
+ if (*source_ptr == '*' && *(source_ptr + 1) == '/') { \
+ * ((char *) source_ptr++) = ' '; * ((char *) source_ptr++) = ' '; \
+ } \
+ continue;\
+ }
+
+
+#define SKIP_C99_COMMENTS \
+ if (*source_ptr && *source_ptr == '/' && *(source_ptr + 1) == '/') { \
+ * ((char *) source_ptr++) = ' '; * ((char *) source_ptr++) = ' '; \
+ while (*source_ptr && *source_ptr != '\n') { \
+ if (*source_ptr == '\\' && *(source_ptr + 1) == '\n') { line_count++; * ((char *) source_ptr++) = ' ';} \
+ * ((char *) source_ptr++) = ' '; \
+ } \
+ continue; \
+ }
+
+
+#define SKIP_COMMENTS \
+ SKIP_C89_COMMENTS \
+ SKIP_C99_COMMENTS
+
+#define SKIP_COMMENTS2 \
+ while(1) { \
+ SKIP_C89_COMMENTS \
+ SKIP_C99_COMMENTS \
+ break; \
+ }
+
+
+#define SKIP_SPACES \
+ SKIP_COMMENTS2;\
+ while (ISSPACE(*source_ptr) || (*source_ptr == '\\' && *(source_ptr + 1) == '\n')) { \
+ if (*source_ptr == '\\' && *(source_ptr + 1) == '\n') { source_ptr += 2; line_count++; continue; } \
+ if (*source_ptr == '\n') { line_count++; source_ptr++; continue; } \
+ SKIP_COMMENTS;\
+ source_ptr++; \
+ }
+
+
+#define SKIP_SPACES_UNTIL_LF \
+ SKIP_COMMENTS2;\
+ while (ISSPACE(*source_ptr) || (*source_ptr == '\\' && *(source_ptr + 1) == '\n')) { \
+ if (*source_ptr == '\\' && *(source_ptr + 1) == '\n') { source_ptr += 2; continue; } \
+ if (*source_ptr == '\n') break; \
+ SKIP_COMMENTS;\
+ source_ptr++; \
+ }
+
+
+#define SKIP_SPACES_UNTIL_LF_AND_COUNT_LINES \
+ SKIP_COMMENTS2;\
+ while (ISSPACE(*source_ptr) || (*source_ptr == '\\' && *(source_ptr + 1) == '\n')) { \
+ if (*source_ptr == '\\' && *(source_ptr + 1) == '\n') { source_ptr += 2; line_count++; continue; } \
+ if (*source_ptr == '\n') { line_count++; break; } \
+ SKIP_COMMENTS;\
+ source_ptr++; \
+ }
+
+
+#define SKIP_ALL_UNTIL_LF \
+ SKIP_COMMENTS2;\
+ while (*source_ptr || (*source_ptr == '\\' && *(source_ptr + 1) == '\n')) { \
+ if (*source_ptr == '\\' && *(source_ptr + 1) == '\n') { source_ptr += 2; continue; } \
+ if (*source_ptr == '\n') break; \
+ SKIP_COMMENTS;\
+ source_ptr++; \
+ }
+
+
+#define SKIP_ALL_UNTIL_LF_AND_COUNT_LINES \
+ SKIP_COMMENTS2;\
+ while (*source_ptr || (*source_ptr == '\\' && *(source_ptr + 1) == '\n')) { \
+ if (*source_ptr == '\\' && *(source_ptr + 1) == '\n') { source_ptr += 2; line_count++; continue; } \
+ if (*source_ptr == '\n') { line_count++; break; } \
+ SKIP_COMMENTS;\
+ source_ptr++; \
+ }
+
+
+#define GET_NEXT_TOKEN_IN_TMPBUFFER \
+ buffer_ptr = buffer; \
+ while (ISWORDCHAR(*source_ptr)) \
+ { \
+ if (buffer_ptr == buffer+1023) compile_error (MSG_IDENTIFIER_TOO_LONG); \
+ *buffer_ptr++ = TOUPPER(*source_ptr++); \
+ } \
+ *buffer_ptr++ = 0; \
+ token.code = identifier_search_or_add(buffer); \
+ token.type = IDENTIFIER;
+
+/* ---------------------------------------------------------------------- */
+
+int n_files = 0; /* Includes */
+char files[MAX_SOURCES][__MAX_PATH]; /* Includes */
+char *source_data[MAX_SOURCES]; /* Includes */
+
+/* ---------------------------------------------------------------------- */
+
+int load_file( char * filename )
+{
+ long size;
+ file * fp = file_open( filename, "rb0" );
+ int n;
+
+ for( n = 0; n < n_files; n++ ) if ( !strcmp( files[n], filename ) ) break;
+
+ if ( n >= n_files )
+ {
+ if ( n_files == MAX_SOURCES ) compile_error( MSG_TOO_MANY_FILES );
+ strcpy( files[n_files], filename );
+ if ( !fp ) compile_error( MSG_FILE_NOT_FOUND, filename );
+ size = file_size( fp );
+ source_data[n_files] = ( char * ) calloc( size + 1, sizeof( char ) );
+ if ( !source_data[n_files] ) compile_error( MSG_FILE_TOO_BIG, filename );
+ if ( size == 0 ) compile_error( MSG_FILE_EMPTY, filename );
+ if ( !file_read( fp, source_data[n_files], size ) ) compile_error( MSG_READ_ERROR, filename );
+
+ source_data[n_files][size] = 0;
+ file_close( fp );
+ n = n_files++;
+ }
+
+ token_init( source_data[n], n );
+ return n;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void include_file( int bprepro )
+{
+ static char buffer[1024];
+ char * buffer_ptr = buffer;
+ int actual_line = line_count;
+
+ SKIP_SPACES_UNTIL_LF_AND_COUNT_LINES;
+ if ( *source_ptr == '"' )
+ {
+ source_ptr++;
+ buffer_ptr = buffer;
+ while ( *source_ptr && *source_ptr != '"' )
+ {
+ if ( buffer_ptr == buffer + 1023 ) compile_error( MSG_IDENTIFIER_TOO_LONG );
+ *buffer_ptr++ = *source_ptr++;
+ }
+ if ( *source_ptr == '"' ) source_ptr++;
+ *buffer_ptr = 0;
+ if ( bprepro )
+ {
+ SKIP_SPACES_UNTIL_LF_AND_COUNT_LINES;
+ if ( *source_ptr == '\n' ) line_count--;
+ }
+ else
+ {
+ SKIP_SPACES;
+ }
+ if ( *source_ptr == ';' )
+ {
+ if ( bprepro )
+ {
+ compile_warning( 0,"extra tokens at end of #include directive" );
+ SKIP_ALL_UNTIL_LF_AND_COUNT_LINES;
+ if ( *source_ptr == '\n' ) line_count--;
+ }
+ else
+ token_next();
+ }
+
+ load_file( buffer );
+ token_next();
+ return;
+ }
+ line_count = actual_line;
+ compile_error( MSG_FILENAME_EXP );
+}
+
+/* ---------------------------------------------------------------------- */
+
+int find_define( int code )
+{
+ int i;
+
+ /* Search for if already defined */
+ for ( i = 0; i < defines_count; i++ ) if ( defines[i].code == code ) return i;
+
+ return -1;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void add_simple_define( char * macro, char *text )
+{
+ int code = identifier_search_or_add( macro );
+
+ if ( find_define( code ) != -1 ) compile_error( MSG_MACRO_ERROR, identifier_name( code ) );
+
+ /* Allocate the macro */
+
+ if ( defines_allocated == defines_count )
+ {
+ defines_allocated += 8;
+ defines = ( DEFINE * ) realloc( defines, sizeof( DEFINE ) * defines_allocated );
+ }
+
+ defines[defines_count].param_count = -1;
+ defines[defines_count].code = code;
+ defines[defines_count].text = strdup( text );
+ defines_count++;
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * FUNCTION : preprocessor_jumpto
+ *
+ * Ignores all of the remaining source file, until
+ * a preprocessor directive with identifier id1
+ * (or id2 if non-zero), and moves the source_ptr
+ * source code pointer just after it.
+ *
+ * This function is used by preprocessor()
+ * with a #ifdef, #ifndef or #if directive.
+ *
+ * PARAMS :
+ * id1 Identifier of ending directive (i.e. id_endif)
+ * id2 Alternative ending directive (i.e. id_else) or 0 if none
+ *
+ * RETURN VALUE :
+ * None
+ */
+
+void preprocessor_jumpto( int id, int id2 )
+{
+ int depth = 1;
+ use_saved = 0;
+
+ disable_prepro = 1;
+
+ while ( depth > 0 && *source_ptr )
+ {
+ SKIP_SPACES_UNTIL_LF_AND_COUNT_LINES;
+ if ( *source_ptr == '\n' )
+ {
+ source_ptr++;
+
+ SKIP_SPACES;
+
+ if ( *source_ptr == '#' )
+ {
+ source_ptr++;
+ SKIP_SPACES_UNTIL_LF_AND_COUNT_LINES;
+ if ( *source_ptr == '\n' ) line_count--;
+
+ token_next();
+ if ( token.type == IDENTIFIER )
+ {
+ if ( token.code == id_endif )
+ {
+ int stck_code = prepro_stack[--prepro_sp];
+
+ if ( prepro_sp < 0 || (
+ stck_code != id_else &&
+ stck_code != id_if &&
+ stck_code != id_ifdef &&
+ stck_code != id_ifndef ) )
+ compile_error( "#endif without #if" );
+ }
+ if ( token.code == id_else )
+ {
+ int stck_code = prepro_stack[--prepro_sp];
+
+ if ( prepro_sp < 0 ||
+ (
+ stck_code != id_if &&
+ stck_code != id_ifdef &&
+ stck_code != id_ifndef
+ )
+ )
+ {
+ if ( stck_code == id_else )
+ {
+ compile_error( "#else after #else" );
+ }
+ else
+ {
+ compile_error( "#else without #if" );
+ }
+ }
+ prepro_stack[prepro_sp++] = token.code;
+ }
+ else if ( token.code == id_ifdef || token.code == id_ifndef || token.code == id_if )
+ {
+ prepro_stack[prepro_sp++] = token.code;
+ }
+
+ if ( token.code == id_endif /*id || (id2 && token.code == id2)*/ )
+ {
+ depth--;
+ }
+ else if ( token.code == id_else )
+ {
+ depth--;
+ if ( !depth ) break;
+ depth++;
+ }
+ else if ( token.code == id_ifdef || token.code == id_ifndef || token.code == id_if )
+ {
+ depth++;
+ }
+ }
+ continue;
+ }
+ }
+ source_ptr++;
+ }
+
+ if ( token.code != id && ( id2 && token.code != id2 ) ) compile_error( "unbalanced #if/#else/#endif" );
+
+ if ( depth > 0 ) compile_error( "unterminate #if" );
+
+ disable_prepro = 0;
+
+}
+
+/*
+ * FUNCTION : preprocessor_expand
+ *
+ * Expands a macro to a malloc'ed text area and moves the
+ * token processing to it using token_init(). This function
+ * is called just after the macro name is read (next token
+ * should be a '(' if any parameters needed)
+ *
+ * PARAMS :
+ * None
+ *
+ * RETURN VALUE :
+ * None
+ */
+
+void preprocessor_expand( DEFINE * def )
+{
+ const char * param_left[MAX_MACRO_PARAMS];
+ const char * param_right[MAX_MACRO_PARAMS];
+ const char * begin = NULL;
+ const char * old_source = NULL;
+ char * text;
+ int i, count, depth, allocated, size, part, actual_line_count;
+
+ /* No params - easy case */
+
+ if ( def->param_count == -1 )
+ {
+ int line = line_count - 1;
+ token_init( def->text, current_file );
+ line_count = line;
+ return;
+ }
+
+ /* Find left parenthesis */
+
+ disable_expand_defines++;
+ token_next();
+ disable_expand_defines--;
+ if ( token.type != IDENTIFIER || token.code != identifier_leftp ) compile_error( MSG_EXPECTED, "(" );
+
+ /* Mark parameters' starting and ending positions */
+
+ if ( def->param_count > 0 )
+ {
+ for ( count = 0; count < def->param_count; count++ )
+ {
+ depth = 0;
+ param_left[count] = source_ptr;
+
+ while ( *source_ptr && ( depth > 0 || ( *source_ptr != ')' && *source_ptr != ',' ) ) )
+ {
+ if ( *source_ptr == '"' || *source_ptr == '\'' )
+ {
+ begin = source_ptr++;
+ while ( *source_ptr && *source_ptr != *begin ) source_ptr++;
+ if ( !*source_ptr ) compile_error( MSG_EXPECTED, "\"" );
+ source_ptr++;
+ continue;
+ }
+ if ( *source_ptr == '(' ) depth++;
+ if ( *source_ptr == ')' ) depth--;
+ source_ptr++;
+ }
+ param_right[count] = source_ptr;
+ if ( !*source_ptr ) compile_error( MSG_EXPECTED, ")" );
+ if ( *source_ptr == ')' ) break;
+ source_ptr++;
+ }
+
+ if ( count != def->param_count - 1 || *source_ptr != ')' )
+ compile_error( MSG_INCORRECT_PARAMC, identifier_name( def->code ), def->param_count - 1 );
+ }
+ else
+ {
+ if ( *source_ptr != ')' )
+ compile_error( MSG_INCORRECT_PARAMC, identifier_name( def->code ), def->param_count );
+ }
+
+ source_ptr++;
+
+ /* Expand the macro */
+
+ allocated = 128;
+ size = 0;
+ text = ( char * )calloc( allocated, sizeof( char ) );
+ old_source = source_ptr;
+ source_ptr = def->text;
+ actual_line_count = line_count;
+
+ while ( *source_ptr )
+ {
+ SKIP_SPACES_UNTIL_LF;
+ if ( *source_ptr == '\n' ) break;
+
+ begin = source_ptr;
+ SKIP_SPACES_UNTIL_LF;
+ if ( *source_ptr )
+ {
+ SKIP_SPACES_UNTIL_LF;
+ if ( !*source_ptr ) break;
+ if ( *source_ptr != '\n' )
+ {
+ disable_expand_defines++;
+ token_next();
+ disable_expand_defines--;
+ if ( token.type == NOTOKEN ) break;
+ if ( token.type == IDENTIFIER )
+ {
+ /* Next token is an identifier. Search for parameter */
+
+ for ( i = 0; i < def->param_count; i++ )
+ if ( def->param_id[i] == token.code ) break;
+
+ if ( i != def->param_count ) /* Parameter found - expand it */
+ {
+
+ part = param_right[i] - param_left[i];
+ if ( size + part + 1 >= allocated )
+ {
+ allocated += (( part + 256 ) & ~ 127 );
+ text = ( char * )realloc( text, allocated );
+ }
+ text[size++] = ' ';
+ memcpy( text + size, param_left[i], part );
+ size += part;
+ continue;
+ }
+ }
+
+ /* No parameter found - copy the token */
+
+ part = source_ptr - begin;
+ if ( size + part + 1 >= allocated )
+ {
+ allocated += (( part + 256 ) & ~127 );
+ text = ( char * )realloc( text, allocated );
+ }
+ memcpy( text + size, begin, part );
+ size += part;
+ }
+ else
+ {
+ line_count++;
+ source_ptr++;
+ }
+ }
+ }
+
+ text[size] = 0;
+ source_ptr = old_source;
+ line_count = actual_line_count;
+
+ /* Now "include" the expanded text "file" */
+
+ token_init( text, current_file );
+ line_count = actual_line_count - 1;
+
+ free( text );
+}
+
+/*
+ * FUNCTION : preprocessor
+ *
+ * Evaluates a preprocessor directive. This function is called
+ * just after a '#' symbol is found after an end-of-line.
+ *
+ * The function moves source_ptr to the next line.
+ *
+ * PARAMS :
+ * None
+ *
+ * RETURN VALUE :
+ * 1 - Include identifier
+ * 0 - Other identifier
+ */
+
+void preprocessor()
+{
+ int i, ifdef;
+ char * ptr;
+ int actual_line_count;
+
+ static int initialized = 0;
+
+ if ( !initialized )
+ {
+ id_define = identifier_search_or_add( "DEFINE" );
+ id_undef = identifier_search_or_add( "UNDEF" );
+ id_ifdef = identifier_search_or_add( "IFDEF" );
+ id_ifndef = identifier_search_or_add( "IFNDEF" );
+ id_else = identifier_search_or_add( "ELSE" );
+ id_endif = identifier_search_or_add( "ENDIF" );
+ id_if = identifier_search_or_add( "IF" );
+ initialized = 1;
+ }
+
+ token_next();
+
+ if ( token.type != IDENTIFIER ) compile_error( MSG_UNKNOWN_PREP );
+
+ /* #define TEXT value */
+
+ if ( token.code == id_define )
+ {
+ disable_expand_defines++;
+
+ token_next();
+ if ( token.type != IDENTIFIER ) compile_error( MSG_INVALID_IDENTIFIER );
+
+ if ( find_define( token.code ) != -1 ) compile_error( MSG_MACRO_ERROR, identifier_name( token.code ) );
+
+ /* Allocate the macro */
+
+ if ( defines_allocated == defines_count )
+ {
+ defines_allocated += 8;
+ defines = ( DEFINE * ) realloc( defines, sizeof( DEFINE ) * defines_allocated );
+ }
+
+ defines[defines_count].code = token.code;
+
+ /* Check for parameters: no space allowed between name and ( */
+
+ if ( *source_ptr == '(' )
+ {
+ source_ptr++;
+ for ( defines[defines_count].param_count = i = 0; *source_ptr != ')'; )
+ {
+ if ( !*source_ptr ) compile_error( MSG_EXPECTED, ")" );
+ if ( i == MAX_MACRO_PARAMS ) compile_error( MSG_TOO_MANY_PARAMS );
+ token_next();
+
+ if ( token.type != IDENTIFIER || token.code < reserved_words ) compile_error( MSG_INVALID_IDENTIFIER );
+
+ defines[defines_count].param_id[i++] = token.code;
+ defines[defines_count].param_count++;
+
+ SKIP_SPACES;
+ if ( *source_ptr == ',' ) source_ptr++;
+ }
+ source_ptr++;
+ }
+ else
+ {
+ /* No parameters and no parenthesis */
+ defines[defines_count].param_count = -1;
+ }
+
+ SKIP_SPACES_UNTIL_LF_AND_COUNT_LINES;
+
+ ptr = ( char * ) source_ptr;
+
+ while ( *ptr && *ptr != '\n' )
+ if ( *ptr == '\\' && *( ptr + 1 ) == '\n' )
+ {
+ *ptr = ' ';
+ ptr++;
+ *ptr = ' ';
+ ptr++;
+ line_count++;
+ }
+ else
+ ptr++;
+
+ while ( ptr > source_ptr && ( !*ptr || ISSPACE( *ptr ) ) ) ptr--;
+
+ defines[defines_count].text = ( char * )calloc( ptr - source_ptr + 2, sizeof( char ) );
+ strncpy( defines[defines_count].text, source_ptr, ptr - source_ptr + 1 );
+ defines[defines_count].text[ptr - source_ptr + 1] = 0;
+
+ defines_count++;
+
+ source_ptr = ptr + 1;
+
+ disable_expand_defines--;
+
+ return;
+ }
+
+ /* #undef TEXT */
+
+ if ( token.code == id_undef )
+ {
+ disable_expand_defines++;
+
+ token_next();
+ if ( token.type != IDENTIFIER ) compile_error( MSG_INVALID_IDENTIFIER );
+
+ if (( i = find_define( token.code ) ) != -1 )
+ {
+ defines_count--;
+ if ( defines[i].text ) free( defines[i].text );
+ memmove( &defines[i], &defines[i+1], ( defines_count - i ) * sizeof( DEFINE ) );
+ }
+
+ disable_expand_defines--;
+
+ return;
+ }
+
+ /* #ifdef CONST / #ifndef CONST*/
+
+ if ( token.code == id_ifdef || token.code == id_ifndef )
+ {
+ ifdef = token.code == id_ifdef;
+
+ prepro_stack[prepro_sp++] = token.code;
+
+ disable_expand_defines++;
+ token_next();
+ disable_expand_defines--;
+
+ if ( token.type != IDENTIFIER ) compile_error( MSG_INVALID_IDENTIFIER );
+
+ SKIP_SPACES_UNTIL_LF_AND_COUNT_LINES;
+ if ( *source_ptr && *source_ptr != '\n' )
+ {
+ if ( ifdef ) compile_warning( 0,"extra tokens at end of #ifdef directive" );
+ else compile_warning( 0,"extra tokens at end of #ifndef directive" );
+ SKIP_ALL_UNTIL_LF_AND_COUNT_LINES;
+ }
+
+ if ( *source_ptr == '\n' ) line_count--;
+
+ for ( i = 0; i < defines_count; i++ )
+ {
+ if ( defines[i].code == token.code )
+ {
+ if ( ifdef ) return;
+ break;
+ }
+ }
+ if ( !ifdef && i == defines_count ) return;
+
+
+ preprocessor_jumpto( id_else, id_endif );
+
+ SKIP_SPACES_UNTIL_LF_AND_COUNT_LINES;
+ if ( *source_ptr && *source_ptr != '\n' )
+ {
+ if ( token.code == id_else ) compile_warning( 0,"extra tokens at end of #else directive" );
+ else if ( token.code == id_endif ) compile_warning( 0,"extra tokens at end of #endif directive" );
+ SKIP_ALL_UNTIL_LF_AND_COUNT_LINES;
+ }
+ if ( *source_ptr == '\n' ) line_count--;
+ return;
+ }
+
+ /* #if */
+
+ if ( token.code == id_if )
+ {
+ int actual_sources;
+ expresion_result res;
+ char c;
+
+ prepro_stack[prepro_sp++] = token.code;
+
+ ptr = ( char * ) source_ptr;
+
+ while ( *ptr && *ptr != '\n' && *ptr != ';' )
+ if ( *ptr == '\\' && *( ptr + 1 ) == '\n' )
+ {
+ *ptr = ' ';
+ ptr++;
+ *ptr = ' ';
+ ptr++;
+ line_count++;
+ }
+ else
+ ptr++;
+
+ c = *ptr;
+ *ptr = '\0';
+
+ actual_line_count = line_count;
+ actual_sources = sources;
+
+ token_init( source_ptr, current_file );
+
+ identifiers_as_strings = 1;
+ res = compile_expresion( 0, 0, 1, TYPE_DWORD );
+ identifiers_as_strings = 0;
+ /*
+ printf ("exp: asignation: [%d] call: [%d] lvalue: [%d] constant: [%d] value: [%d] lvalue: [%f] type: [%d]\n",
+ res.asignation,
+ res.call,
+ res.lvalue,
+ res.constant,
+ res.value,
+ res.fvalue,
+ typedef_base(res.type));
+ */
+ if ( sources != actual_sources ) token_endfile();
+ *ptr = c;
+ source_ptr = ptr;
+ line_count = actual_line_count;
+
+ SKIP_SPACES_UNTIL_LF_AND_COUNT_LINES;
+ if ( *source_ptr && *source_ptr != '\n' )
+ {
+ compile_warning( 0,"extra tokens at end of #if directive" );
+ SKIP_ALL_UNTIL_LF_AND_COUNT_LINES;
+ }
+ if ( *source_ptr == '\n' ) line_count--;
+
+ use_saved = 0;
+ if ( !res.constant ) compile_error( MSG_CONSTANT_EXP );
+ if ( !res.value )
+ {
+ preprocessor_jumpto( id_else, id_endif );
+
+ SKIP_SPACES_UNTIL_LF_AND_COUNT_LINES;
+ if ( *source_ptr && *source_ptr != '\n' )
+ {
+ if ( token.code == id_else ) compile_warning( 0,"extra tokens at end of #else directive" );
+ else if ( token.code == id_endif ) compile_warning( 0,"extra tokens at end of #endif directive" );
+ SKIP_ALL_UNTIL_LF_AND_COUNT_LINES;
+ }
+ if ( *source_ptr == '\n' ) line_count--;
+ }
+
+ return;
+ }
+
+ /* #else */
+
+ if ( token.code == id_else )
+ {
+ if ( !prepro_sp ) compile_error( "#else without #if" );
+
+ int stck_code = prepro_stack[--prepro_sp];
+
+ if ( prepro_sp < 0 ||
+ (
+ stck_code != id_if &&
+ stck_code != id_ifdef &&
+ stck_code != id_ifndef
+ )
+ )
+ {
+ if ( stck_code == id_else )
+ {
+ compile_error( "#else after #else" );
+ }
+ else
+ {
+ compile_error( "#else without #if" );
+ }
+ }
+ prepro_stack[prepro_sp++] = token.code;
+
+ SKIP_SPACES_UNTIL_LF_AND_COUNT_LINES;
+ if ( *source_ptr && *source_ptr != '\n' )
+ {
+ compile_warning( 0,"extra tokens at end of #else directive" );
+ SKIP_ALL_UNTIL_LF_AND_COUNT_LINES;
+ }
+ if ( *source_ptr == '\n' ) line_count--;
+
+ preprocessor_jumpto( id_endif, 0 );
+
+ SKIP_SPACES_UNTIL_LF_AND_COUNT_LINES;
+ if ( *source_ptr && *source_ptr != '\n' )
+ {
+ compile_warning( 0,"extra tokens at end of #endif directive" );
+ SKIP_ALL_UNTIL_LF_AND_COUNT_LINES;
+ }
+ if ( *source_ptr == '\n' ) line_count--;
+ return;
+ }
+
+ /* #endif */
+
+ if ( token.code == id_endif )
+ {
+ int stck_code = prepro_stack[--prepro_sp];
+
+ if ( prepro_sp < 0 || (
+ stck_code != id_else &&
+ stck_code != id_if &&
+ stck_code != id_ifdef &&
+ stck_code != id_ifndef ) ) compile_error( "#endif without #if" );
+
+ SKIP_SPACES_UNTIL_LF_AND_COUNT_LINES;
+ if ( *source_ptr == '\n' ) line_count--;
+ return;
+ }
+
+ /* Unknown preprocessor directive */
+ compile_error( MSG_UNKNOWN_PREP );
+}
+
+void token_init( const char * source, int file )
+{
+ char * ptr;
+ char * clean_source;
+
+ if ( sources == MAX_SOURCES ) compile_error( MSG_TOO_MANY_INCLUDES );
+
+ if ( !source )
+ {
+ fprintf( stdout, "token_init: no source\n" );
+ exit( 1 );
+ }
+
+ /* Perform cleaning of the source file */
+
+ clean_source = ( char * ) calloc( strlen( source ) + 2, sizeof( char ) );
+ ptr = clean_source;
+ *ptr++ = '\n'; /* Adds a blank line to detect first-line # directives */
+ while ( *source )
+ {
+ if ( *source == '\r' && source[1] == '\n' )
+ {
+ source += 2;
+ *ptr++ = '\n';
+ }
+ else
+ {
+ *ptr++ = *source++;
+ }
+ }
+ *ptr = 0;
+
+ /* Store the old source pointer */
+
+ old_line_counts [sources] = line_count;
+ old_current_file [sources] = current_file;
+ old_sources [sources] = source_ptr;
+ old_sources_start [sources] = source_start;
+ sources++;
+
+ /* Use the new source */
+
+ line_count = 0;
+ current_file = file;
+ source_ptr = clean_source;
+ source_start = clean_source;
+
+ use_saved = 0;
+}
+
+int token_endfile()
+{
+ if ( source_start )
+ {
+ free( source_start );
+ source_start = 0;
+ }
+ if ( sources > 0 )
+ {
+ sources--;
+ line_count = old_line_counts[sources];
+ current_file = old_current_file[sources];
+ source_ptr = old_sources[sources];
+ source_start = old_sources_start[sources];
+ use_saved = 0;
+ }
+
+ if ( sources < 1 )
+ {
+ if ( prepro_sp > 0 ) compile_error( "unbalanced #if/#else/#endif" );
+ }
+ return 0;
+}
+
+void token_dump()
+{
+ if ( token.type == NUMBER ) fprintf( stdout, "%d", token.code );
+ else if ( token.type == FLOAT ) fprintf( stdout, "%f", token.value );
+ else if ( token.type == STRING ) fprintf( stdout, "\"%s\"", string_get( token.code ) );
+ else if ( token.type == IDENTIFIER ) fprintf( stdout, "\"%s\"", identifier_name( token.code ) );
+ else if ( token.type == LABEL ) fprintf( stdout, "\"%s\"", identifier_name( token.code ) );
+ else if ( token.type == NOTOKEN ) fprintf( stdout, "EOF" );
+ else fprintf( stdout, "unknown" );
+}
+
+extern int c_type_initialized;
+
+void token_next()
+{
+ static int i, len;
+ static char buffer[1024];
+ char * buffer_ptr = buffer;
+
+ if ( !source_ptr )
+ {
+ token.type = NOTOKEN;
+ return;
+ }
+
+ if ( use_saved )
+ {
+ token = token_saved;
+ line_count = token.line;
+ current_file = token.file;
+ use_saved = 0;
+ return;
+ }
+ token.line = line_count;
+ token.file = current_file;
+ token_prev = token;
+
+ while ( 1 )
+ {
+ SKIP_SPACES;
+
+ if ( !disable_prepro && *source_ptr == '#' )
+ {
+ int line;
+ const char * old_source_ptr;
+
+ identifiers_as_strings = 0;
+
+ /* Comandos de preprocesador */
+ source_ptr++;
+
+ line = line_count;
+
+ SKIP_SPACES_UNTIL_LF_AND_COUNT_LINES;
+
+ if ( *source_ptr == '\n' )
+ {
+ token.code = identifier_search_or_add( "#" );
+ token.type = IDENTIFIER;
+ line_count = line;
+ compile_error( MSG_IDENTIFIER_EXP );
+ }
+
+ old_source_ptr = source_ptr;
+
+ if ( ISWORDFIRST( *source_ptr ) )
+ {
+ GET_NEXT_TOKEN_IN_TMPBUFFER;
+
+ /* #include "file.h" */
+
+ if ( token.code == identifier_include && !use_saved )
+ {
+ include_file( 1 );
+ return;
+ }
+
+ source_ptr = old_source_ptr;
+ }
+
+ preprocessor();
+
+ buffer_ptr = buffer;
+ *buffer_ptr = '\0';
+ continue;
+ }
+
+ if ( !*source_ptr )
+ {
+ /* Casos de bloques manuales */
+ if ( current_file == -1 )
+ {
+ token_endfile();
+ token.type = NOTOKEN;
+ return;
+ }
+
+ while ( !*source_ptr )
+ {
+ if ( sources == 0 )
+ {
+ token.type = NOTOKEN;
+ return;
+ }
+
+ token_endfile();
+
+ if ( !source_ptr )
+ {
+ token.type = NOTOKEN;
+ return;
+ }
+ }
+ continue;
+ }
+
+ /* Ignora comentarios */
+
+ SKIP_COMMENTS;
+ if ( !*source_ptr )
+ {
+ token.type = NOTOKEN;
+ return;
+ }
+
+ /* Cadenas */
+
+ if ( *source_ptr == '"' || *source_ptr == '\'' )
+ {
+ token.type = STRING;
+ token.code = string_compile( &source_ptr );
+ token.line = line_count;
+ token.file = current_file;
+ return;
+ }
+
+ /* Operadores de más de un caracter */
+
+ len = 0;
+
+ if ( *source_ptr == '<' )
+ {
+ if ( source_ptr[1] == '<' )
+ {
+ if ( source_ptr[2] == '=' ) len = 3;
+ else len = 2;
+ }
+ else if ( source_ptr[1] == '>' ) len = 2;
+ else if ( source_ptr[1] == '=' ) len = 2;
+ else len = 1;
+ }
+ else if ( *source_ptr == '>' )
+ {
+ if ( source_ptr[1] == '>' )
+ {
+ if ( source_ptr[2] == '=' ) len = 3;
+ else len = 2;
+ }
+ else if ( source_ptr[1] == '=' ) len = 2;
+ else if ( source_ptr[1] == '>' ) len = 2;
+ else len = 1;
+ }
+ else if ( *source_ptr == '|' )
+ {
+ if ( source_ptr[1] == '|' )
+ {
+ if ( source_ptr[2] == '=' ) len = 3;
+ else len = 2;
+ }
+ else if ( source_ptr[1] == '=' ) len = 2;
+ else len = 1;
+ }
+ else if ( *source_ptr == '=' )
+ {
+ if ( source_ptr[1] == '=' ) len = 2;
+ else if ( source_ptr[1] == '>' ) len = 2;
+ else if ( source_ptr[1] == '<' ) len = 2;
+ else len = 1;
+ }
+ else if ( *source_ptr == '.' )
+ {
+ if ( source_ptr[1] == '.' ) len = 2;
+ else len = 1;
+ }
+ else if ( strchr( "!&^%*+-/", *source_ptr ) )
+ {
+ if ( source_ptr[1] == '=' ) len = 2;
+ else if ( strchr( "+-&^", *source_ptr ) && source_ptr[1] == *source_ptr ) len = 2;
+ else len = 1;
+ }
+
+ if ( len )
+ {
+ strncpy( buffer, source_ptr, len );
+ buffer[len] = 0;
+ source_ptr += len;
+ token.code = identifier_search_or_add( buffer );
+ token.type = IDENTIFIER;
+ token.line = line_count;
+ token.file = current_file;
+ return;
+ }
+
+ /* Numbers */
+
+ if ( ISNUM( *source_ptr ) )
+ {
+ const char * ptr;
+ double num = 0, dec;
+ int base = 10;
+
+ /* Hex/Bin/Octal numbers with the h/b/o sufix */
+ ptr = source_ptr;
+ while ( ISNUM( *ptr ) || ( *ptr >= 'a' && *ptr <= 'f' ) || ( *ptr >= 'A' && *ptr <= 'F' ) ) ptr++;
+
+ if ( *ptr != 'h' && *ptr != 'H' && *ptr != 'o' && *ptr != 'O' && ( ptr[-1] == 'b' || ptr[-1] == 'B' ) ) ptr--;
+
+ if ( *ptr == 'b' || *ptr == 'B' )
+ base = 2;
+ if ( *ptr == 'h' || *ptr == 'H' )
+ base = 16;
+ if ( *ptr == 'o' || *ptr == 'O' )
+ base = 8;
+
+ token.code = 0 ; /* for ints values */
+
+ /* Calculate the number value */
+
+ while ( ISNUM( *source_ptr ) || ( base > 10 && ISALNUM( *source_ptr ) ) )
+ {
+ if ( base == 2 && *source_ptr != '0' && *source_ptr != '1' ) break;
+ if ( base == 8 && ( *source_ptr < '0' || *source_ptr > '7' ) ) break;
+ if ( base == 10 && !ISNUM( *source_ptr ) ) break;
+ if ( base == 16 && !ISNUM( *source_ptr ) && ( TOUPPER( *source_ptr ) < 'A' || TOUPPER( *source_ptr ) > 'F' ) ) break;
+
+ if ( ISNUM( *source_ptr ) )
+ {
+ num = num * base + ( *source_ptr - '0' );
+ token.code = token.code * base + ( *source_ptr - '0' );
+ source_ptr++;
+ continue;
+ }
+ if ( *source_ptr >= 'a' && *source_ptr <= 'f' && base > 10 )
+ {
+ num = num * base + ( *source_ptr - 'a' + 10 );
+ token.code = token.code * base + ( *source_ptr - 'a' + 10 );
+ source_ptr++;
+ continue;
+ }
+ if ( *source_ptr >= 'A' && *source_ptr <= 'F' && base > 10 )
+ {
+ num = num * base + ( *source_ptr - 'A' + 10 );
+ token.code = token.code * base + ( *source_ptr - 'A' + 10 );
+ source_ptr++;
+ continue;
+ }
+ }
+ token.type = NUMBER;
+ token.value = ( float )num;
+
+ /* We have the integer part now - convert to int/float */
+
+ if ( *source_ptr == '.' && base == 10 )
+ {
+ source_ptr++;
+ if ( !ISNUM( *source_ptr ) )
+ source_ptr--;
+ else
+ {
+ dec = 1.0 / ( double )base;
+ while ( ISNUM( *source_ptr ) || ( base > 100 && ISALNUM( *source_ptr ) ) )
+ {
+ if ( ISNUM( *source_ptr ) ) num = num + dec * ( *source_ptr++ - '0' );
+ if ( *source_ptr >= 'a' && *source_ptr <= 'f' && base > 10 ) num = num + dec * ( *source_ptr++ - 'a' + 10 );
+ if ( *source_ptr >= 'A' && *source_ptr <= 'F' && base > 10 ) num = num + dec * ( *source_ptr++ - 'A' + 10 );
+ dec /= ( double )base;
+ }
+ token.type = FLOAT;
+ token.value = ( float )num;
+ }
+ }
+
+ /* Skip the base sufix */
+
+ if ( base == 16 && ( *source_ptr == 'h' || *source_ptr == 'H' ) ) source_ptr++;
+ if ( base == 8 && ( *source_ptr == 'o' || *source_ptr == 'O' ) ) source_ptr++;
+ if ( base == 2 && ( *source_ptr == 'b' || *source_ptr == 'B' ) ) source_ptr++;
+
+ token.line = line_count;
+ token.file = current_file;
+ return;
+ }
+
+ /* Identificadores */
+ if ( ISWORDFIRST( *source_ptr ) )
+ {
+ int maybe_label = source_ptr[-1] == '\n';
+ GET_NEXT_TOKEN_IN_TMPBUFFER;
+
+ token.line = line_count;
+ token.file = current_file;
+
+ if ( maybe_label && *source_ptr == ':' && identifier_search( buffer ) > reserved_words )
+ {
+ source_ptr++;
+ token.code = identifier_search_or_add( buffer );
+ token.type = LABEL;
+ return;
+ }
+
+ /* Search for #define constant inclusion at this point */
+
+ if ( !disable_expand_defines )
+ {
+ if ( !strcmp( buffer, "__FILE__" ) )
+ {
+ token.type = STRING;
+ token.code = string_new(( current_file != -1 && files[current_file] && *files[current_file] ) ? files[current_file] : "N/A" );
+ token.line = line_count;
+ token.file = current_file;
+ return;
+ }
+
+ if ( !strcmp( buffer, "__LINE__" ) )
+ {
+ token.type = NUMBER;
+ token.code = ( int )line_count;
+ token.value = ( float )line_count;
+ token.line = line_count;
+ token.file = current_file;
+ return;
+ }
+
+ for ( i = 0; i < defines_count; i++ )
+ {
+ if ( defines[i].code == token.code )
+ {
+ preprocessor_expand( &defines[i] );
+ token_next();
+ token.line = line_count;
+ token.file = current_file;
+ return;
+ }
+ }
+ }
+
+ /* In a #if, all identifiers are strings */
+
+ if ( identifiers_as_strings )
+ {
+ token.type = STRING;
+ token.code = string_new( buffer );
+ token.line = line_count;
+ token.file = current_file;
+ return;
+ }
+
+ /* Include */
+
+ if ( !disable_prepro && token.code == identifier_include && !use_saved )
+ {
+ include_file( 0 );
+ return;
+ }
+ return;
+ }
+
+ /* 1-char operator or invalid symbol */
+
+ if ( !*source_ptr ) break;
+
+ if ( *source_ptr > 0 && *source_ptr < 32 ) compile_error( MSG_INVALID_CHAR );
+
+ *buffer_ptr++ = *source_ptr++;
+ *buffer_ptr = 0;
+
+ token.code = identifier_search_or_add( buffer );
+ token.type = IDENTIFIER;
+ token.line = line_count;
+ token.file = current_file;
+
+ return;
+ }
+
+ token.type = NOTOKEN;
+ return; /* End-of-file */
+}
+
+void token_back()
+{
+ if ( use_saved )
+ {
+ fprintf( stdout, "Error: two token_back in a row\n" );
+ exit( 1 );
+ }
+
+ token.line = line_count;
+ token.file = current_file;
+ token_saved = token;
+
+ token = token_prev;
+
+ line_count = token.line;
+ current_file = token.file;
+
+ use_saved = 1;
+}
+
+tok_pos token_pos()
+{
+ tok_pos tp;
+
+ tp.use_saved = use_saved;
+ tp.token_saved = token_saved;
+ tp.token = token;
+ tp.line_count = line_count;
+ tp.current_file = current_file;
+ tp.token_prev = token_prev;
+ tp.source_ptr = source_ptr;
+
+ return tp;
+}
+
+void token_set_pos( tok_pos tp )
+{
+ use_saved = tp.use_saved;
+ token_saved = tp.token_saved;
+ token = tp.token;
+ line_count = tp.line_count;
+ current_file = tp.current_file;
+ token_prev = tp.token_prev;
+ source_ptr = tp.source_ptr;
+}
+