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