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( "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 compile_array_data( VARSPACE * n, segment * data, int size, int subsize, BASETYPE *t ) { int block, count = 0, base, remaining = size ; int base_offset, total_length ; expresion_result res ; for ( ;; ) { if ( !remaining && size ) { token_back(); break; // compile_error( MSG_TOO_MANY_INIT ) ; } token_next() ; /* if (*t == TYPE_UNDEFINED && token.type == STRING) { *t = typedef_base(typedef_new(TYPE_STRING)) ; } */ if ( token.type == STRING && *t == TYPE_CHAR ) { const char * str = string_get( token.code ) ; int subcount = 0 ; if ( subsize == 0 ) subsize = strlen( str ) + 1; if (( int )strlen( str ) > subsize ) compile_error( MSG_TOO_MANY_INIT ) ; while ( *str ) { segment_add_as( data, *str++, *t ) ; subcount++ ; } while ( subcount++ < subsize ) segment_add_as( data, 0, *t ) ; count += subsize ; remaining -= subsize ; } else if ( token.type == IDENTIFIER && ( token.code == identifier_rightp || token.code == identifier_semicolon ) ) { token_back() ; break ; } else if ( token.type == IDENTIFIER && token.code == identifier_leftp ) { block = compile_array_data( n, data, remaining, remaining, t ) ; remaining -= block ; count += block ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightp ) compile_error( MSG_EXPECTED, ")" ) ; } else { token_back() ; res = compile_expresion( 1, 0, 0, *t ) ; if ( *t == TYPE_UNDEFINED ) { *t = typedef_base( res.type ) ; if ( *t == TYPE_UNDEFINED ) { compile_error( MSG_INCOMP_TYPE ) ; } } base = res.value ; if ( *t == TYPE_FLOAT ) base = *( int * ) & res.fvalue ; token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_dup ) { token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_leftp ) compile_error( MSG_EXPECTED, "(" ) ; base_offset = data->current ; block = compile_array_data( n, data, remaining, remaining, t ) ; total_length = data->current - base_offset ; if ( size && block * base > remaining ) { break; /* MSG_TOO_MANY_INIT */ } count += block * base ; if ( size ) remaining -= block * base ; while ( base-- > 1 ) { segment_copy( data, base_offset, total_length ) ; base_offset += total_length ; } token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightp ) compile_error( MSG_EXPECTED, ")" ) ; } else { token_back() ; if ( *t == TYPE_STRING ) varspace_varstring( n, data->current ) ; segment_add_as( data, base, *t ) ; count ++ ; if ( size ) remaining -- ; } } token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_comma ) { if ( !size && *t == TYPE_CHAR ) compile_error( MSG_TOO_MANY_INIT ); continue ; } token_back() ; break ; } return count ; }
int compile_varspace( VARSPACE * n, segment * data, int additive, int copies, int padding, VARSPACE ** collision, int alignment, int duplicateignore ) { int i, j, total_count, last_count = 0 ; int base_offset = data->current ; int total_length ; int size, count ; int code ; expresion_result res ; VARIABLE * var ; int unsigned_prefix = 0; int signed_prefix = 0; BASETYPE basetype = TYPE_UNDEFINED ; TYPEDEF type, typeaux; segment * segm = NULL ; PROCDEF * proc = NULL; /* Backup vars */ BASETYPE basetypeb = TYPE_UNDEFINED ; TYPEDEF typeb; segment * segmb = NULL ; /* Initialize some stuffs */ type = typedef_new( TYPE_UNDEFINED ) ; typeb = typedef_new( TYPE_UNDEFINED ) ; for ( ;; ) { if ( n->reserved == n->count ) varspace_alloc( n, 16 ) ; if ( alignment && ( n->size % alignment ) > 0 ) { int extra = alignment - ( n->size % alignment ); if ( n->reserved <= n->count + extra ) { varspace_alloc( n, extra + 16 ); } if ( data->reserved <= data->current + extra ) { segment_alloc( data, extra + 16 ); } n->size += extra; data->current += extra; } token_next() ; /* Se salta comas y puntos y coma */ if ( token.type == NOTOKEN ) break ; if ( token.type != IDENTIFIER ) compile_error( MSG_INCOMP_TYPE ) ; if ( token.code == identifier_comma ) { basetype = basetypeb ; type = typeb ; segm = segmb ; continue ; } else if ( token.code == identifier_semicolon ) { basetype = TYPE_UNDEFINED ; set_type( &type, TYPE_UNDEFINED ) ; basetypeb = basetype ; typeb = type ; segm = NULL ; proc = NULL ; continue ; } else if ( token.code == identifier_end ) { break ; } /* "Unsigned" */ if ( token.code == identifier_unsigned ) { unsigned_prefix = 1; token_next(); } else if ( token.code == identifier_signed ) { signed_prefix = 1; token_next(); } /* Tipos de datos básicos */ if ( token.code == identifier_dword ) { basetype = signed_prefix ? TYPE_INT : TYPE_DWORD ; signed_prefix = unsigned_prefix = 0; token_next() ; } else if ( token.code == identifier_word ) { basetype = signed_prefix ? TYPE_SHORT : TYPE_WORD ; signed_prefix = unsigned_prefix = 0; token_next() ; } else if ( token.code == identifier_byte ) { basetype = signed_prefix ? TYPE_SBYTE : TYPE_BYTE ; signed_prefix = unsigned_prefix = 0; token_next() ; } else if ( token.code == identifier_int ) { basetype = unsigned_prefix ? TYPE_DWORD : TYPE_INT; signed_prefix = unsigned_prefix = 0; token_next() ; } else if ( token.code == identifier_short ) { basetype = unsigned_prefix ? TYPE_WORD : TYPE_SHORT; signed_prefix = unsigned_prefix = 0; token_next() ; } else if ( token.code == identifier_char ) { basetype = TYPE_CHAR ; token_next() ; } else if ( token.code == identifier_float ) { basetype = TYPE_FLOAT ; token_next() ; } else if ( token.code == identifier_string ) { basetype = TYPE_STRING ; token_next() ; } else { if ( !proc && ( proc = procdef_search( token.code ) ) ) /* Variables tipo proceso, Splinter */ { basetype = TYPE_INT ; token_next(); } else { if ( token.type == IDENTIFIER && token.code >= reserved_words && !segment_by_name( token.code ) ) { int code = token.code; token_next(); if ( token.type == IDENTIFIER && token.code >= reserved_words ) { proc = procdef_new( procdef_getid(), code ); basetype = TYPE_INT ; } else { token_back(); } } } } if ( signed_prefix || unsigned_prefix ) compile_error( MSG_INVALID_TYPE ); if ( basetype != TYPE_STRUCT ) type = typedef_new( basetype ) ; if ( basetype == TYPE_UNDEFINED ) type = typedef_new( TYPE_INT ) ; /* Tipos de datos definidos por el usuario */ if ( basetype != TYPE_STRUCT && ( segm = segment_by_name( token.code ) ) ) { basetype = TYPE_STRUCT ; type = * typedef_by_name( token.code ) ; token_next() ; } if ( token.type == IDENTIFIER && token.code == identifier_struct ) { type.chunk[0].type = TYPE_STRUCT ; type.chunk[0].count = 1 ; type.depth = 1 ; token_next() ; segm = 0 ; } basetypeb = basetype ; typeb = type ; segmb = segm ; /* Tipos de datos derivados */ while ( token.type == IDENTIFIER && ( token.code == identifier_pointer || token.code == identifier_multiply ) ) { type = typedef_enlarge( type ) ; type.chunk[0].type = TYPE_POINTER ; basetype = TYPE_POINTER ; segm = NULL ; token_next() ; } /* Nombre del dato */ if ( token.type != IDENTIFIER ) compile_error( MSG_IDENTIFIER_EXP ) ; if ( token.code < reserved_words ) { if ( proc ) compile_error( MSG_VARIABLE_ERROR ); token_back() ; break ; } if (( var = varspace_search( n, token.code ) ) ) { if ( duplicateignore ) { int skip_all_until_semicolon = 0; int skip_equal = 0; if ( debug ) compile_warning( 0, MSG_VARIABLE_REDECLARE ) ; for ( ;; ) { token_next() ; /* Se salta todo hasta el puntos y coma o en el end o la coma si no hay asignacion */ if ( token.type == NOTOKEN ) break ; if ( token.type == IDENTIFIER ) { if ( !skip_equal && token.code == identifier_equal ) { skip_all_until_semicolon = 1; continue; } if ( !skip_all_until_semicolon && token.code == identifier_comma ) break; if ( token.code == identifier_semicolon ) break ; if ( token.code == identifier_end ) break ; } } token_back(); continue; } else compile_error( MSG_VARIABLE_REDECLARE ) ; } /* (2006/11/19 19:34 GMT-03:00, Splinter - [email protected]) */ if ( collision ) for ( i = 0; collision[i];i++ ) if ( varspace_search( collision[i], token.code ) ) compile_error( MSG_VARIABLE_REDECLARE ) ; /* (2006/11/19 19:34 GMT-03:00, Splinter - [email protected]) */ if ( constants_search( token.code ) ) compile_error( MSG_CONSTANT_REDECLARED_AS_VARIABLE ) ; code = token.code ; n->vars[n->count].code = token.code ; n->vars[n->count].offset = data->current; /* Non-additive STRUCT; use zero-based member offsets */ if ( !additive ) n->vars[n->count].offset -= base_offset; token_next() ; /* Compila una estructura no predefinida */ if ( !segm && typedef_is_struct( type ) ) { VARSPACE * members ; type.chunk[0].count = 1 ; count = 1 ; while ( token.type == IDENTIFIER && token.code == identifier_leftb ) { res = compile_expresion( 1, 0, 0, TYPE_INT ) ; if ( !typedef_is_integer( res.type ) ) compile_error( MSG_INTEGER_REQUIRED ) ; count *= res.value + 1 ; type = typedef_enlarge( type ) ; type.chunk[0].type = TYPE_ARRAY ; type.chunk[0].count = res.value + 1 ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightb ) compile_error( MSG_EXPECTED, "]" ) ; token_next() ; } token_back() ; /* Da la vuelta a los índices [10][5] -> [5][10] */ for ( i = 0 ; i < type.depth ; i++ ) if ( type.chunk[i].type != TYPE_ARRAY ) break ; i--; for ( j = 0 ; j <= i ; j++ ) typeaux.chunk[ j ] = type.chunk[ i - j ]; for ( j = 0 ; j <= i ; j++ ) type.chunk[ j ] = typeaux.chunk[ j ]; members = ( VARSPACE * )calloc( 1, sizeof( VARSPACE ) ) ; if ( !members ) { fprintf( stdout, "compile_varspace: out of memory\n" ) ; exit( 1 ) ; } varspace_init( members ) ; size = compile_varspace( members, data, 0, count, 0, NULL, 0, duplicateignore ) ; type.varspace = members ; token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_equal ) { i = data->current ; data->current = n->vars[n->count].offset ; compile_struct_data( members, data, count, 0 ); data->current = i ; } else { token_back() ; } for ( i = 0 ; i < members->stringvar_count ; i++ ) varspace_varstring( n, members->stringvars[i] ) ; n->size += typedef_size( type ) ; n->vars[n->count].type = type ; n->count++ ; continue ; /* No ; */ } else if ( token.type == IDENTIFIER && token.code == identifier_leftb ) /* Compila un array */ { total_count = 1 ; while ( token.type == IDENTIFIER && token.code == identifier_leftb ) { if ( type.depth == MAX_TYPECHUNKS ) compile_error( MSG_TOO_MANY_AL ) ; type = typedef_enlarge( type ) ; type.chunk[0].type = TYPE_ARRAY ; token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_rightb ) { type.chunk[0].count = 0 ; if ( total_count != 1 ) compile_error( MSG_VTA ) ; total_count = 0 ; last_count = 0 ; } else { token_back() ; res = compile_expresion( 1, 0, 0, TYPE_DWORD ) ; if ( !total_count ) compile_error( MSG_VTA ) ; total_count *= res.value + 1 ; last_count = res.value + 1 ; type.chunk[0].count = res.value + 1 ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightb ) compile_error( MSG_EXPECTED, "]" ) ; } token_next() ; } /* Da la vuelta a los índices [10][5] -> [5][10] */ for ( i = 0 ; i < type.depth ; i++ ) if ( type.chunk[i].type != TYPE_ARRAY ) break ; i--; for ( j = 0 ; j <= i ; j++ ) typeaux.chunk[ j ] = type.chunk[ i - j ]; for ( j = 0 ; j <= i ; j++ ) type.chunk[ j ] = typeaux.chunk[ j ]; if ( segm && token.type == IDENTIFIER && token.code == identifier_equal ) { for ( i = 0 ; i < total_count ; i++ ) segment_add_from( data, segm ) ; i = data->current ; data->current = n->vars[n->count].offset ; compile_struct_data( type.varspace, data, typedef_count( type ), 0 ); if ( !type.chunk[0].count ) type.chunk[0].count = ( data->current - i ) / typedef_size( typeb ); else data->current = i; /* Solo si ya habia sido alocada */ } else if ( token.type == IDENTIFIER && token.code == identifier_equal ) { /* if (basetype == TYPE_UNDEFINED) basetype = TYPE_INT; */ i = compile_array_data( n, data, total_count, last_count, &basetype ) ; assert( basetype != TYPE_UNDEFINED ) ; set_type( &type, basetype ) ; if ( total_count == 0 ) { type.chunk[0].count = i; } else if ( i < total_count ) { for ( ; i < total_count; i++ ) { if ( basetype == TYPE_STRING ) varspace_varstring( n, data->current ) ; segment_add_as( data, 0, basetype ) ; } } } else if ( segm ) { int string_offset = 0, j; if ( total_count == 0 ) compile_error( MSG_EXPECTED, "=" ) ; for ( i = 0; i < total_count; i++ ) { segment_add_from( data, segm ) ; for ( j = 0; j < type.varspace->stringvar_count; j++ ) varspace_varstring( n, type.varspace->stringvars[j] + string_offset ); string_offset += type.varspace->size; } token_back() ; } else { if ( basetype == TYPE_UNDEFINED ) { basetype = TYPE_INT; set_type( &type, basetype ) ; } if ( type.chunk[0].count == 0 ) compile_error( MSG_EXPECTED, "=" ) ; for ( i = 0; i < total_count; i++ ) { if ( basetype == TYPE_STRING ) varspace_varstring( n, data->current ) ; segment_add_as( data, 0, basetype ) ; } token_back() ; } } else if ( segm && token.type == IDENTIFIER && token.code == identifier_equal ) /* Compila una asignación de valores por defecto */ { segment_add_from( data, segm ) ; i = data->current ; data->current = n->vars[n->count].offset ; if ( !additive ) data->current += base_offset; compile_struct_data( type.varspace, data, 1, 0 ); data->current = i ; } else if ( token.type == IDENTIFIER && token.code == identifier_equal ) { res = compile_expresion( 1, 0, 0, basetype ) ; if ( basetype == TYPE_UNDEFINED ) { basetype = typedef_base( res.type ) ; if ( basetype == TYPE_UNDEFINED ) compile_error( MSG_INCOMP_TYPE ) ; set_type( &type, basetype ) ; } if ( basetype == TYPE_FLOAT ) { segment_add_as( data, *( int * )&res.fvalue, basetype ) ; } else { if ( basetype == TYPE_STRING ) varspace_varstring( n, data->current ) ; segment_add_as( data, res.value, basetype ) ; } } else if ( !segm ) /* Asigna valores por defecto (0) */ { if ( basetype == TYPE_UNDEFINED ) { basetype = TYPE_INT; set_type( &type, basetype ) ; } if ( basetype == TYPE_STRING ) varspace_varstring( n, data->current ) ; segment_add_as( data, 0, basetype ) ; token_back() ; } else { if ( typedef_is_struct( type ) ) for ( i = 0 ; i < type.varspace->stringvar_count ; i++ ) varspace_varstring( n, type.varspace->stringvars[i] + n->size ); segment_add_from( data, segm ) ; token_back() ; } n->size += typedef_size( type ) ; n->vars[n->count].type = type ; /* Variables tipo proceso, asigno varspace al tipo. Splinter */ if ( proc ) n->vars[n->count].type.varspace = proc->pubvars; n->count++ ; token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_comma ) { token_back() ; continue ; } if ( token.type == IDENTIFIER && token.code == identifier_semicolon ) { token_back() ; continue ; } compile_error( MSG_EXPECTED, ";" ) ; token_back() ; break ; } if ( padding && ( data->current % padding ) > 0 ) { padding -= data->current % padding; data->current += padding; n->size += padding; if ( data->reserved <= data->current ) segment_alloc( data, data->reserved - data->current + 32 ); } n->last_offset = data->current ; total_length = data->current - base_offset ; /* n->size *= copies ; */ while ( copies-- > 1 ) { int i ; for ( i = 0 ; i < n->stringvar_count ; i++ ) { if ( n->stringvars[i] >= base_offset && n->stringvars[i] < base_offset + total_length ) { varspace_varstring( n, n->stringvars[i] - base_offset + data->current ) ; } } segment_copy( data, base_offset, total_length ) ; base_offset += total_length ; } return total_length ; }
int compile_struct_data( VARSPACE * n, segment * data, int size, int sub ) { int elements = 0 ; int position = 0 ; expresion_result res ; for ( ;; ) { token_next() ; /* Allow parenthized struct initialization */ if ( token.type == IDENTIFIER && token.code == identifier_leftp ) { if (( elements % n->count ) != 0 ) compile_error( MSG_NOT_ENOUGH_INIT ); /* Note - don't ignore a trailing comma! */ elements = compile_struct_data( n, data, size, 0 ) ; if ( elements >= n->count ) size -= ( elements / n->count ); token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightp ) compile_error( MSG_EXPECTED, ")" ) ; token_next() ; if (( elements % n->count ) == 0 && size > 0 && token.type == IDENTIFIER && token.code == identifier_comma ) continue; token_back() ; return elements ; } /* Allow empty initialization */ if ( token.type == IDENTIFIER && token.code == identifier_semicolon ) return 0 ; token_back() ; for ( ;; ) { TYPEDEF next_type = n->vars[position].type ; /* Next variable is a pointer */ if ( typedef_is_pointer( next_type ) ) { res = compile_expresion( 1, 0, 0, TYPE_DWORD ) ; if ( !res.constant ) compile_error( MSG_INCORRECT_PTR_INIT ); segment_add_as( data, 0, TYPE_POINTER ) ; } else if ( typedef_is_array( next_type ) ) /* Next variable is an array */ { int elements = typedef_tcount( next_type ) ; BASETYPE base; /* Get the array base type */ while ( typedef_is_array( next_type ) ) next_type = typedef_reduce( next_type ); base = typedef_base( next_type ); /* Special case: array of structs */ if ( base == TYPE_STRUCT ) { compile_struct_data( next_type.varspace, data, elements, 1 ); } else { token_next(); /* Special case: intializing char[] strings */ if ( token.type == STRING && next_type.chunk[1].type == TYPE_CHAR ) { const char * str = string_get( token.code ) ; int subcount = 0 ; if (( int )strlen( str ) > typedef_count( next_type ) - 1 ) compile_error( MSG_TOO_MANY_INIT ) ; while ( *str ) { segment_add_as( data, *str++, TYPE_CHAR ) ; subcount++ ; } while ( subcount++ < typedef_count( next_type ) ) segment_add_as( data, 0, TYPE_CHAR ) ; } else /* Initializing normal arrays */ { int has_parents = 1; if ( token.type != IDENTIFIER || token.code != identifier_leftp ) { has_parents = 0; token_back(); } compile_array_data( n, data, elements, elements, &base ) ; if ( has_parents ) { token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightp ) compile_error( MSG_EXPECTED, ")" ) ; } } } } else if ( typedef_is_struct( next_type ) ) /* Next variable is another struct */ { compile_struct_data( next_type.varspace, data, 1, 1 ) ; } else /* Next variable is a single type */ { res = compile_expresion( 1, 0, 0, typedef_base( next_type ) ) ; if ( !res.constant ) compile_error( MSG_CONSTANT_EXP ); segment_add_as( data, typedef_base( next_type ) == TYPE_FLOAT ? *( int* )&res.fvalue : res.value, typedef_base( next_type ) ) ; } position++ ; elements++ ; if ( position == n->count && size < 2 && sub ) break ; /* A comma should be here */ token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_semicolon ) { token_back(); break ; } if ( token.type == IDENTIFIER && token.code == identifier_rightp ) { token_back() ; break ; } if ( token.type != IDENTIFIER || token.code != identifier_comma ) compile_error( MSG_EXPECTED, "," ) ; /* Wrap around for the next struct */ if ( position == n->count ) { if ( size == 1 && !sub ) compile_error( MSG_TOO_MANY_INIT ) ; size--; position = 0; } } break; } return elements ; }
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 == ':' ) { 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 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( "extra tokens at end of #ifdef directive" ); else compile_warning( "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( "extra tokens at end of #else directive" ); else if ( token.code == id_endif ) compile_warning( "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( "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( "extra tokens at end of #else directive" ); else if ( token.code == id_endif ) compile_warning( "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( "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( "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 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 ); }
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; }