Beispiel #1
0
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++;
}
Beispiel #2
0
int main( int argc, char *argv[] )
{
    time_t curtime;
    struct tm *loctime;
    int value, code;
    char * d, *d1;

    char * sourcefile = 0;
    char basepathname[__MAX_PATH] = "";
    char dcbname[__MAX_PATH] = "";
    char stubname[__MAX_PATH] = "";
    char importname[__MAX_PATH] = "";
    char compilerimport[__MAX_PATH] = "";
    int i, j;
    char *ptr;

    /* get my executable name */
    ptr = argv[0] + strlen( argv[0] );
    while ( ptr > argv[0] && ptr[-1] != '\\' && ptr[-1] != '/' ) ptr-- ;
    appexename = strdup( ptr );

    /* get executable full pathname  */
    appexefullpath = getfullpath( argv[0] );
    if ( ( !strchr( argv[0], '\\' ) && !strchr( argv[0], '/' ) ) && !file_exists( appexefullpath ) )
    {
        char *p = whereis( appexename );
        if ( p )
        {
            char * tmp = calloc( 1, strlen( p ) + strlen( appexename ) + 2 );
            free( appexefullpath );
            sprintf( tmp, "%s/%s", p, appexename );
            appexefullpath = getfullpath( tmp );
            free( tmp );
        }
    }

    /* get pathname of executable */
    ptr = strstr( appexefullpath, appexename );
    appexepath = calloc( 1, ptr - appexefullpath + 1 );
    strncpy( appexepath, appexefullpath, ptr - appexefullpath );

    printf( BGDC_VERSION "\n"
            "Bennu Game Development Compiler\n"
            "\n"
            "Copyright (c) 2006-2016 SplinterGU (Fenix/BennuGD)\n"
            "Copyright (c) 2002-2006 Fenix Team (Fenix)\n"
            "Copyright (c) 1999-2002 José Luis Cebrián Pagüe (Fenix)\n"
            "\n" );

    /* Default lang to EN */
    strcpy( langinfo, "EN" );
    /* LANG detect */
#ifdef WIN32
    GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_SABBREVCTRYNAME, langinfo, 64 );
    strlwr( langinfo );
#else
    if ( getenv( "LANG" ) != NULL && strlen( getenv( "LANG" ) ) >= 2 )
        strcpy( langinfo, getenv( "LANG" ) );
#endif
    langinfo[2] = 0;

    srand( time( NULL ) );

    /* build error messages list */
    err_buildErrorTable();

    init_c_type();
    identifier_init();
    constants_init();
    string_init();
    compile_init();

    mainproc = procdef_new( procdef_getid(), identifier_search_or_add( "MAIN" ) ) ;

    /* Init vars */

    char tmp_version[ 32 ];
    sprintf( tmp_version, "\"%s\"", VERSION );
    add_simple_define( "COMPILER_VERSION", tmp_version );
    add_simple_define( "__VERSION__", tmp_version );

    curtime = time( NULL ); /* Get the current time. */
    loctime = localtime( &curtime ); /* Convert it to local time representation. */

    strftime( timebuff, sizeof( timebuff ), "%Y/%m/%d", loctime );
    value = string_new( timebuff );
    code = identifier_search_or_add( "__DATE__" ) ;
    constants_add( code, typedef_new( TYPE_STRING ), value ) ;

    strftime( timebuff, sizeof( timebuff ), "%H:%M:%S", loctime );
    value = string_new( timebuff );
    code = identifier_search_or_add( "__TIME__" ) ;
    constants_add( code, typedef_new( TYPE_STRING ), value ) ;
/*
    value = string_new( VERSION );
    code = identifier_search_or_add( "__VERSION__" ) ;
    constants_add( code, typedef_new( TYPE_STRING ), value ) ;
    code = identifier_search_or_add( "COMPILER_VERSION" ) ;
    constants_add( code, typedef_new( TYPE_STRING ), value ) ;
*/
    strcpy( _tmp, VERSION );
                d = strchr( _tmp, '.' ); *d = '\0'; add_simple_define( "__BGD__", _tmp );
    d1 = d + 1; d = strchr(   d1, '.' ); *d = '\0'; add_simple_define( "__BGD_MINOR__", d1 );
    d1 = d + 1;                                     add_simple_define( "__BGD_PATCHLEVEL__", d1 );

    memset( &dcb, 0, sizeof( dcb ) );

    core_init();
    sysproc_init();

    /* Get command line parameters */

    for ( i = 1 ; i < argc ; i++ )
    {
        if ( argv[i][0] == '-' )
        {
            if ( !strcmp( argv[i], "--pedantic" ) )
            {
                autodeclare = 0 ;
                continue;
            }

            if ( !strcmp( argv[i], "--libmode" ) )
            {
                libmode = 1 ;
                continue;
            }

            j = 1;
            while ( argv[i][j] )
            {
                if ( argv[i][j] == 'd' )
                {
                    if ( argv[i][j + 1] >= '0' && argv[i][j + 1] <= '9' )
                    {
                        debug = atoi( &argv[i][j + 1] );
                    }
                    else
                    {
                        debug = 1;
                    }
                }

                if ( argv[i][j] == 'o' )
                {
                    if ( argv[i][j + 1] )
                        strncpy( dcbname, &argv[i][j + 1], sizeof( dcbname ) );
                    else if ( argv[i + 1] && argv[i + 1][0] != '-' )
                        strncpy( dcbname, argv[++i], sizeof( dcbname ) );
                    break;
                }

                if ( argv[i][j] == 'c' ) dos_chars = 1;

                if ( argv[i][j] == 'a' ) autoinclude = 1;

                if ( argv[i][j] == 'g' ) dcb_options |= DCB_DEBUG;

                if ( argv[i][j] == 'p' ) autodeclare = 0 ;

                if ( argv[i][j] == 's' )
                {
                    /* -s "stub": Use a stub */

                    if ( argv[i][j + 1] )
                        strncpy( stubname, &argv[i][j + 1], __MAX_PATH );
                    else if ( argv[i + 1] && argv[i + 1][0] != '-' )
                        strncpy( stubname, argv[++i], __MAX_PATH );
                    break;
                }

                if ( argv[i][j] == 'f' )
                {
                    /* -f "file": Embed a file to the DCB */

                    if ( argv[i][j + 1] )
                        dcb_add_file( &argv[i][j + 1] );
                    else while ( argv[i + 1] )
                        {
                            if ( argv[i + 1][0] == '-' ) break;
                            dcb_add_file( argv[i + 1] );
                            i++;
                        }
                    break;
                }

                if ( argv[i][j] == 'i' )
                {
                    /* -i "path": add a file to the path for include files */

                    if ( argv[i][j + 1] == 0 )
                    {
                        if ( i == argc - 1 )
                        {
                            printf( MSG_DIRECTORY_MISSING "\n" );
                            exit( 1 );
                        }
                        file_addp( argv[i + 1] );
                        i++;
                        break;
                    }
                    file_addp( &argv[i][j + 1] );
                    break;
                }

                if ( argv[i][j] == 'l' )
                {
                    /* -lLANG:  Set the language for errors and messages */

                    if ( argv[i][j + 1] == 0 )
                    {
                        if ( i != argc - 1 )
                        {
                            strcpy( langinfo, argv[i + 1] );
                        }
                        i++;
                        break;
                    }
                    strcpy( langinfo, &argv[i][j + 1] );
                    break;
                }

                if ( argv[i][j] == 'D' )
                {
                    char * macro = NULL ;
                    char * text = NULL ;

                    /* -D<macro>=<text> */

                    if ( argv[i][j + 1] )
                    {
                        macro = strdup( &argv[i][j + 1] );
                    }
                    else
                    {
                        if ( argv[i + 1][0] == '-' ) break;
                        macro = strdup( argv[i + 1] );
                        i++;
                    }

                    if (( text = strchr( macro, '=' ) ) )
                    {
                        * text = '\0';
                        text++;
                    }
                    else
                    {
                        text = "";
                    }

                    add_simple_define( macro, text );
                    free( macro );
                    break;
                }

                if ( argv[i][j] == 'C' )
                {
                    if ( argv[i][j + 1] == 'a' ) autodeclare = 1 ;
                    break;
                }

                if ( argv[i][j] == 'L' )
                {
                    int r = 1;
                    char * f;
                    if ( argv[i][j + 1] )
                        r = dcb_load_lib( ( f = &argv[i][j + 1] ) );
                    else if ( argv[i + 1] && argv[i + 1][0] != '-' )
                    {
                        r = dcb_load_lib( ( f = argv[i + 1] ) );
                        i++;
                    }

                    switch ( r )
                    {
                        case    0:
                                printf( "ERROR: %s doesn't exist or isn't version DCB compatible\n", f ) ;
                                exit( -1 );

                        case    -1:
                                printf( "ERROR: %s isn't 7.10 DCB version, you need a 7.10 version or greater for use this feature\n", f ) ;
                                exit( -1 );
                    }
                    break;
                }

                j++;
            }
        }
        else
        {
/*
            if ( sourcefile )
            {
                printf( MSG_TOO_MANY_FILES "\n" );
                return 0;
            }
*/
            char * p, * pathend = NULL;

            sourcefile = argv[i];
            p = main_path = strdup( argv[i] );
            while ( p && *p )
            {
                if ( *p == ':' || *p == '\\' || *p == '/' ) pathend = p;
                p++;
            }
            if ( pathend )
            {
                *( pathend + 1 ) = '\0';
                file_addp( main_path );
            }
            else
            {
                free( main_path );
                main_path = getcwd(malloc(__MAX_PATH), __MAX_PATH);
                strcat(main_path, PATH_SEP);
            }

            /* Files names */

            strcpy( basepathname, sourcefile );
            REMOVE_EXT( basepathname );

            /* Default compiler imports */
            strcpy( compilerimport, argv[0] );
#ifdef WIN32
            REMOVE_EXT( compilerimport );
#endif
            strcat( compilerimport, ".imp" );
            import_files( compilerimport );
            strcat( compilerimport, "ort" ); /* name.import */
            import_files( compilerimport );

            /* Project imports */
            strcpy( importname, basepathname ); strcat( importname, ".imp" );
            import_files( importname );

            strcat( importname, "ort" ); /* name.import */
            import_files( importname );

            /* Load Main Source File */
            load_file( sourcefile );

            if ( !dcbname[0] )
            {
                strcpy( dcbname, basepathname ); strcat( dcbname, !libmode ? ".dcb" : ".dcl" );
            }
        }
    }

    if ( !sourcefile )
    {
        printf( MSG_USING
                MSG_OPTION_D
                MSG_OPTIONS
                MSG_LICENSE, argv[0] );
        return 0;
    }

    compile_program();

    if ( stubname[0] != 0 )
    {
        if ( !file_exists( stubname ) )
        {
#ifdef WIN32
            char exepath[__MAX_PATH];

            GetModuleFileName( NULL, exepath, sizeof( exepath ) );
            PathRemoveFileSpec( exepath );
            strcat( exepath, "\\" );
            memmove( stubname + strlen( exepath ), stubname, strlen( stubname ) + 1 );
            memcpy( stubname, exepath, strlen( exepath ) );
#else
            const char * ptr = argv[0] + strlen( argv[0] );
            while ( ptr > argv[0] && *ptr != '\\' && *ptr != '/' ) ptr--;
            if ( *ptr == '\\' || *ptr == '/' ) ptr++;
            if ( ptr > argv[0] )
            {
                memmove( stubname + ( ptr - argv[0] ), stubname, strlen( stubname ) + 1 );
                memcpy( stubname, argv[0], ptr - argv[0] );
            }
#endif
            if ( !file_exists( stubname ) )
            {
#ifdef WIN32
                strcat( stubname, ".exe" );
                if ( !file_exists( stubname ) )
                {
#endif
                    compile_error( "Can't open stub file %s", stubname );
#ifdef WIN32
                    return -1;
                }
#endif

            }
        }

        REMOVE_EXT( dcbname );
#ifdef WIN32
        strcat( dcbname, ".exe" );
#endif
        dcb_save( dcbname, dcb_options, stubname );
    }
    else
    {
        dcb_save( dcbname, dcb_options, NULL );
    }

    /* destroy error messages list */
    err_destroyErrorTable();

    return 1;
}
Beispiel #3
0
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 */
}
Beispiel #4
0
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 );
}