/*
 *  Fenix - Videogame compiler/interpreter
 *  Current release       : FENIX - PROJECT 1.0 - R 0.84
 *  Last stable release   :
 *  Project documentation : http://fenix.divsite.net
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 *  Copyright © 1999 José Luis Cebrián Pagüe
 *  Copyright © 2002 Fenix Team
 *
 */

#include <stdio.h>
#ifdef TARGET_BEOS
#include <posix/assert.h>
#else
#include <assert.h>
#endif
#include <string.h>
#include <stdlib.h>

#include "fxc.h"
#include "messages.c"

/* ---------------------------------------------------------------------- */
/* Este módulo contiene las funciones que compilan definiciones de datos: */
/* declaraciones de variables e inicialziación de las mismas              */
/* ---------------------------------------------------------------------- */

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-1)
                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, *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;
                    //compile_error (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){
            continue ;
        }
        token_back() ;
        break ;
    }

    return count ;
}

static BASETYPE get_basetype (VARSPACE * v)
{
    TYPEDEF t ;
    BASETYPE type = TYPE_UNDEFINED, newtype ;
    int n ;

    for (n = 0 ; n < v->count ; n++) {
        t = v->vars[n].type ;
        while (typedef_is_array(t)) {
            t = typedef_reduce(t) ;
        }

        if (typedef_is_struct(t)) {
            newtype = get_basetype (typedef_members(t))  ;
        } else {
            newtype = typedef_base(t) ;
        }

        if (type != TYPE_UNDEFINED && type != newtype) {
            return TYPE_UNDEFINED ;
        }

        type = newtype ;
    }
    return type ;
}

/*
 *  FUNCTION : compile_struct_data
 *
 *  Compile the values of an struct initialization
 *  Does not suppor parenthized sections or the DUP operator
 *
 *  PARAMS:
 *      n       Current variable space
 *      data    Current data segment
 *      size    Size (total number of variables) of the array
 *              including all dimensions (1 for single struct)
 *      sub     1 if the struct we'are initializing is part of
 *              another one (the function will then ignore
 *              a trailing comma)
 *
 *  RETURN VALUE:
 *      Number of structs initialized
 */

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, 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 != token.type != 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, 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 ;
}

static void set_type (TYPEDEF * t, BASETYPE type)
{
#if 0
    int n ;

    for (n = 0 ; n < t->depth ; n++)
        if (t->chunk[n].type == TYPE_UNDEFINED)
        {
            t->chunk[n].type = type ;
            break ;
        }
    return ;
#endif

    t->chunk[t->depth-1].type = type ;
    return ;
}

/*
 *  FUNCTION : compile_varspace
 *
 *  Compile a variable space (a LOCAL, PRIVATE or GLOBAL section,
 *  or part of a STRUCT data)
 *
 *  PARAMS :
 *      n               Pointer to the VARSPACE object (already initialized)
 *      data            Pointer to the data segment. All variables are added at end.
 *      additive        1 if the compiling is additive (the struct members have
 *                          non-local offset; GLOBAL case) or not (STRUCT case)
 *      copies          Number of data copies (if the STRUCT is part of an array)
 *      collision       Check this varspace array for name collisions (NULL = end of array), if nonzero
 *                      (2006/11/19 19:34 GMT-03:00, Splinter - jj_arg@yahoo.com)
 *      alignment       Byte size for member alignment. Empty data will be added
 *                      to the varspace if its size is not multiple of this value.
 *
 *  In any case, nested varspaces (structs) will have an alignment of 0.
 *
 *  RETURN VALUE :
 *      None
 *
 */

int compile_varspace (VARSPACE * n, segment * data, int additive, int copies, int padding, VARSPACE ** collision, int alignment)
{
    int i, j, total_count, last_count = 0 ;
    int base_offset = data->current ;
    int total_length ;
    int size, count ;
    int code ;
    int is_pointer = 0 ;
    BASETYPE basetype = TYPE_UNDEFINED ;
    BASETYPE basetypeb = TYPE_UNDEFINED ;
    TYPEDEF type ;
    TYPEDEF typeb ;
    expresion_result res ;
    segment * s = 0 ;
    VARSPACE * v = 0 ;
    int unsigned_prefix = 0;
    int signed_prefix = 0;
    PROCDEF * proc = NULL;

    for (;;) {

        basetype = basetypeb ;
        type = typeb ;
        is_pointer = 0;

        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 ;
            continue ;
        }

        if (token.code == identifier_semicolon) {
            basetype = TYPE_UNDEFINED ;
            basetypeb = TYPE_UNDEFINED ;
            is_pointer = 0 ;
            s = 0 ;
            v = 0 ;
            continue ;
        }

        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 = 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) == 0)
                {
                    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 && (s = segment_by_name(token.code)) != 0) {
            basetype = TYPE_STRUCT ;
            type = *typedef_by_name(token.code) ;
            token_next() ;
        }

        /* Tipos de datos derivados */
        while (token.type == IDENTIFIER && (token.code == identifier_pointer || token.code == identifier_multiply)) {
            is_pointer++ ;
            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() ;
            s = 0 ;
        }

        basetypeb = basetype ;
        typeb = type ;

        while (is_pointer) {
            type = typedef_enlarge(type) ;
            type.chunk[0].type = TYPE_POINTER ;
            basetype = TYPE_POINTER ;
            is_pointer-- ;
            s = 0 ;
            v = 0 ;
        }

        /* 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 (varspace_search (n, token.code)) {
            compile_error (MSG_VARIABLE_ALREADY) ;
        }

        /* (2006/11/19 19:34 GMT-03:00, Splinter - jj_arg@yahoo.com) */
        if ( collision ) {
            for (i=0; collision[i];i++) {
                if (varspace_search (collision[i], token.code)) {
                    compile_error (MSG_VARIABLE_ALREADY) ;
                }
            }
        }
        /* (2006/11/19 19:34 GMT-03:00, Splinter - jj_arg@yahoo.com) */

        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 (!s && 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, 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 ([3][2] -> [2][3])

            for (i = 0 ; i < type.depth ; i++) {
                if (type.chunk[i].type != TYPE_ARRAY) {
                    break ;
                }
            }

            for (j = --i ; j > i-j ; j--) {
                TYPECHUNK n ;
                n = type.chunk[j] ;
                type.chunk[j] = type.chunk[i-j] ;
                type.chunk[i-j] = n ;
            }

            members = (VARSPACE *)malloc (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) ;

            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 ;
                } else {
                    token_back() ;
                    res = compile_expresion(1,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 ;
                }
            }

            for (j = --i ; j > i-j ; j--) {
                TYPECHUNK n ;
                n = type.chunk[j] ;
                type.chunk[j] = type.chunk[i-j] ;
                type.chunk[i-j] = n ;
            }

            if (s && token.type == IDENTIFIER && token.code == identifier_equal) {
                int ii = 1;
                for (i = 0 ; i < total_count ; i++) {
                    segment_add_from (data, s) ;
                }
                i = data->current ;
                data->current = n->vars[n->count].offset ;
                ii = compile_struct_data (type.varspace, data, typedef_count(type), 0);
                type.chunk[0].count = ii / typedef_members(typeb)->count;
/* Comentado para poder inicializar arrays de structs sin dimension */
//                data->current = i;

            } 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 (s) {
                int string_offset = 0, j;

                if (total_count == 0) {
                    compile_error (MSG_EXPECTED, "=") ;
                }

                for (i = 0 ; i < total_count ; i++) {
                    segment_add_from (data, s) ;
                    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 (s && token.type == IDENTIFIER && token.code == identifier_equal) { /* Compila una asignación de valores por defecto */
            segment_add_from (data, s) ;
            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,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 (!s) { /* 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, s) ;
            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) {
            continue ;
        }

        if (token.type == IDENTIFIER && token.code == identifier_semicolon) {
            basetype = TYPE_UNDEFINED;
            basetypeb = basetype;
            is_pointer = 0 ;
            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 ;
}

