/* * Copyright © 2006-2016 SplinterGU (Fenix/Bennugd) * Copyright © 2002-2006 Fenix Team (Fenix) * Copyright © 1999-2002 José Luis Cebrián Pagüe (Fenix) * * This file is part of Bennu - Game Development * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source * distribution. * */ #include #include #include #include "bgdc.h" extern int autodeclare ; int reduce_arrays = 1; /* ---------------------------------------------------------------------- */ /* Compilador de expresiones y sentencias. En este módulo están todas las */ /* funciones de compilado que generan código efectivo. */ /* ---------------------------------------------------------------------- */ PROCDEF * proc ; CODEBLOCK * code ; /* Comprueba que los parámetros de una expresión binaria sean datos * numéricos. Devuelve el tipo de operación(MN_FLOAT o MN_DWORD) */ static int check_integer_type( expresion_result *exp ) { if ( typedef_is_pointer( exp->type ) || typedef_base( exp->type ) == TYPE_CHAR ) { /* codeblock_add(code, MN_POINTER2BOL, 0) ; */ exp->type = typedef_new( TYPE_DWORD ) ; } if ( typedef_is_integer( exp->type ) ) { BASETYPE t = typedef_base( exp->type ) ; switch (t) { case TYPE_SHORT : case TYPE_WORD : return MN_WORD ; case TYPE_SBYTE : case TYPE_BYTE : return MN_BYTE ; case TYPE_UNDEFINED : case TYPE_INT : case TYPE_DWORD : case TYPE_CHAR : case TYPE_FLOAT : case TYPE_STRING : case TYPE_ARRAY : case TYPE_STRUCT : case TYPE_POINTER : break; } return MN_DWORD ; } compile_error( MSG_INTEGER_REQUIRED ) ; return 0; } static int check_integer_types( expresion_result *left, expresion_result *right ) { if ( typedef_is_pointer( left->type ) || typedef_base( left->type ) == TYPE_CHAR ) { /* codeblock_add(code, MN_POINTER2BOL, 1) ; */ left->type = typedef_new( TYPE_DWORD ) ; } if ( typedef_is_pointer( right->type ) || typedef_base( right->type ) == TYPE_CHAR ) { /* codeblock_add(code, MN_POINTER2BOL, 0) ; */ right->type = typedef_new( TYPE_DWORD ) ; } if ( typedef_is_integer( left->type ) ) { if ( typedef_is_integer( right->type ) ) { if ( typedef_base( left->type ) == typedef_base( right->type ) ) { BASETYPE t = typedef_base( left->type ) ; switch (t) { case TYPE_SHORT : case TYPE_WORD : return MN_WORD ; case TYPE_SBYTE : case TYPE_BYTE : return MN_BYTE ; case TYPE_UNDEFINED : case TYPE_INT : case TYPE_DWORD : case TYPE_CHAR : case TYPE_FLOAT : case TYPE_STRING : case TYPE_ARRAY : case TYPE_STRUCT : case TYPE_POINTER : break; } } return MN_DWORD ; } } compile_error( MSG_INTEGER_REQUIRED ) ; return 0; } static int check_numeric_types( expresion_result *left, expresion_result *right ) { if ( typedef_base( left->type ) == TYPE_FLOAT ) { if ( typedef_base( right->type ) == TYPE_FLOAT ) return MN_FLOAT ; if ( typedef_is_integer( right->type ) ) { codeblock_add( code, MN_INT2FLOAT | mntype( right->type, 0 ), 0 ) ; right->fvalue = ( float )right->value ; return MN_FLOAT ; } } if ( typedef_is_integer( left->type ) || typedef_is_pointer( left->type ) ) { if ( typedef_is_integer( right->type ) || typedef_is_pointer( right->type ) ) { if ( typedef_base( left->type ) == typedef_base( right->type ) ) return mntype( left->type, 0 ); if ( typedef_base( left->type ) < typedef_base( right->type ) ) return mntype( left->type, 0 ) ; return mntype( right->type, 0 ) ; } if ( typedef_base( right->type ) == TYPE_FLOAT ) { codeblock_add( code, MN_INT2FLOAT, 1 ) ; left->fvalue = ( float )left->value ; return MN_FLOAT ; } } if ( typedef_base( left->type ) == TYPE_CHAR ) { if ( typedef_base( right->type ) == TYPE_STRING ) { codeblock_add( code, MN_STR2CHR, 0 ); if ( right->constant == 1 ) right->value = ( unsigned char ) * ( string_get( right->value ) ); right->type = typedef_new( TYPE_CHAR ); return MN_BYTE; } if ( typedef_base( right->type ) == TYPE_CHAR || typedef_is_integer( right->type ) ) return MN_BYTE; } if ( typedef_base( right->type ) == TYPE_CHAR ) { if ( typedef_base( left->type ) == TYPE_STRING ) { codeblock_add( code, MN_STR2CHR, 1 ); if ( left->constant == 1 ) left->value = ( unsigned char ) * ( string_get( left->value ) ); left->type = typedef_new( TYPE_CHAR ); return MN_BYTE; } if ( typedef_base( left->type ) == TYPE_CHAR || typedef_is_integer( left->type ) ) return MN_BYTE; } compile_error( MSG_INCOMP_TYPES ) ; return 0 ; } /* Comprueba que los parámetros de una expresión binaria sean cadenas * o datos numéricos. Devuelve MN_STRING o el tipo de dato numérico */ static int check_numeric_or_string_types( expresion_result * left, expresion_result * right ) { if ( typedef_is_array( left->type ) && left->type.chunk[1].type == TYPE_CHAR && typedef_is_string( right->type ) ) { left->type = typedef_new( TYPE_STRING ); left->lvalue = 0; codeblock_add( code, MN_A2STR, 1 ) ; return MN_STRING; } if ( typedef_is_array( right->type ) && right->type.chunk[1].type == TYPE_CHAR && typedef_is_string( left->type ) ) { right->type = typedef_new( TYPE_STRING ); right->lvalue = 0; codeblock_add( code, MN_A2STR, 0 ) ; return MN_STRING; } if ( typedef_is_array( right->type ) && right->type.chunk[1].type == TYPE_CHAR && typedef_is_array( left->type ) && left->type.chunk[1].type == TYPE_CHAR ) { left->type = typedef_new( TYPE_STRING ); right->type = typedef_new( TYPE_STRING ); left->lvalue = 0; right->lvalue = 0; codeblock_add( code, MN_A2STR, 0 ) ; codeblock_add( code, MN_A2STR, 1 ) ; return MN_STRING; } if ( typedef_base( left->type ) == TYPE_CHAR && typedef_base( right->type ) == TYPE_STRING ) { codeblock_add( code, MN_CHR2STR, 1 ); left->lvalue = 0; left->type = typedef_new( TYPE_STRING ); return MN_STRING; } if ( typedef_base( right->type ) == TYPE_CHAR && typedef_base( left->type ) == TYPE_STRING ) { codeblock_add( code, MN_CHR2STR, 0 ); right->lvalue = 0; right->type = typedef_new( TYPE_STRING ); return MN_STRING; } if ( typedef_is_string( left->type ) && typedef_is_string( right->type ) ) return MN_STRING ; if ( typedef_is_string( left->type ) || typedef_is_string( right->type ) ) compile_error( MSG_INCOMP_TYPES ) ; return check_numeric_types( left, right ) ; } /* Devuelve el código que hay que adjuntar a un mnemónico para producir * una variante del mismo, adecuada al tipo de dato concreto */ int mntype( TYPEDEF type, int accept_structs ) { BASETYPE t ; while ( typedef_is_array( type ) ) type = typedef_reduce( type ) ; t = typedef_base( type ) ; switch (t) { case TYPE_DWORD : return MN_DWORD | MN_UNSIGNED; case TYPE_INT : return MN_DWORD; case TYPE_WORD : return MN_WORD | MN_UNSIGNED; case TYPE_SHORT : return MN_WORD ; case TYPE_BYTE : return MN_BYTE | MN_UNSIGNED; case TYPE_SBYTE : return MN_BYTE ; case TYPE_CHAR : return MN_BYTE ; case TYPE_FLOAT : return MN_FLOAT ; case TYPE_STRING : return MN_STRING; case TYPE_POINTER : return MN_DWORD ; case TYPE_UNDEFINED : case TYPE_ARRAY : case TYPE_STRUCT : break; } if ( t == TYPE_STRUCT && accept_structs ) return 0; compile_error( MSG_INCOMP_TYPE ) ; return 0; } /* Compila el acceso a una VARIABLE global, local, privada o publica */ expresion_result compile_sublvalue( VARSPACE * from, int base_offset, VARSPACE * remote ) { VARIABLE * var = NULL ; VARSPACE * here = from ; VARSPACE * privars = ( proc ? proc->privars : NULL ) ; VARSPACE * pubvars = ( proc ? proc->pubvars : NULL ) ; expresion_result res, ind ; if ( here ) token_next() ; if ( token.type != IDENTIFIER ) compile_error( MSG_IDENTIFIER_EXP ) ; if ( !here && !remote ) { /* Splinter, se agrega localidad... */ if ( proc ) { here = privars ; var = varspace_search( here, token.code ) ; if ( !var ) { here = pubvars ; var = varspace_search( here, token.code ) ; } } if ( !var ) { here = &local ; var = varspace_search( here, token.code ) ; } if ( !var ) { here = &global ; var = varspace_search( here, token.code ) ; } } else { if ( remote ) { here = remote ; var = varspace_search( here, token.code ) ; } if ( !var ) { here = from; var = varspace_search( here, token.code ) ; } } if ( !var ) compile_error( MSG_UNKNOWN_IDENTIFIER ) ; if ( var->offset - base_offset != 0 || here == &global || here == &local || ( privars && ( here == privars ) ) || ( pubvars && ( here == pubvars ) ) || ( remote && ( here == remote ) ) ) { codeblock_add( code, ( ( remote && ( here == remote ) ) ? MN_REMOTE_PUBLIC : here == &global ? MN_GLOBAL : (( here == &local ) && ( here == from ) ) ? MN_REMOTE : here == &local ? MN_LOCAL : ( privars && ( here == privars ) ) ? MN_PRIVATE : ( pubvars && ( here == pubvars ) ) ? MN_PUBLIC : MN_INDEX ) | mntype( var->type, 1 ), var->offset - base_offset ) ; if (( pubvars && ( here == pubvars ) ) || ( remote && ( here == remote ) ) ) /* Tambien las locales remotas ? */ { proc->flags |= PROC_USES_PUBLICS; } if ( here == &local ) { proc->flags |= PROC_USES_LOCALS; } } token_next() ; res.type = var->type ; res.lvalue = 1 ; res.asignation = 0 ; res.constant = 0 ; res.call = 0 ; res.value = 0 ; res.count = 1 ; /* Indexado vía [...] */ while ( token.type == IDENTIFIER && token.code == identifier_leftb ) /* "[" */ { /* De estructuras o arrays */ if ( typedef_is_struct( res.type ) && typedef_count( res.type ) == 1 ) compile_error( MSG_NOT_AN_ARRAY ) ; /* Cadenas y punteros se indexan en otro nivel */ if ( typedef_is_pointer( res.type ) || typedef_is_string( res.type ) ) break ; if ( !typedef_is_struct( res.type ) && !typedef_is_array( res.type ) ) compile_error( MSG_NOT_AN_ARRAY ) ; ind = compile_expresion( 0, 0, 0, TYPE_DWORD ) ; if ( ind.lvalue ) codeblock_add( code, MN_PTR | mntype( ind.type, 0 ), 0 ) ; if ( ind.constant && ( ind.value < 0 || ind.value >= typedef_count( res.type ) ) ) compile_error( MSG_BOUND ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightb ) compile_error( MSG_EXPECTED, "]" ) ; /* "]" */ if ( typedef_is_array( res.type ) ) { res.type = typedef_reduce( res.type ) ; codeblock_add( code, MN_ARRAY, typedef_size( res.type ) ) ; } else /* estructura */ { codeblock_add( code, MN_ARRAY, typedef_size( res.type ) / typedef_count( res.type ) ) ; } token_next() ; } /* Un acceso a un array es un acceso a su primer elemento */ /* res.count = 1; if ( reduce_arrays == 1 && typedef_is_array( res.type ) ) { if ( res.type.chunk[1].type != TYPE_CHAR ) { while ( typedef_is_array( res.type ) ) { res.count *= ( typedef_count( res.type ) ? typedef_count( res.type ) : 1 ); res.type = typedef_reduce( res.type ) ; } } } */ token_back() ; return res ; } /* Compila el tamaño de una VARIABLE o estructura local, global, privada o publica */ #define MAX_EXPR_LEVEL 256 int compile_sizeof( VARSPACE * here, int * content_size, char * content_type, int * parent_count ) { VARIABLE * var = NULL ; expresion_result ind ; int base = 0 ; TYPEDEF type, * usertype ; int _content_size = 0; char * _content_type = NULL; int _parent_count = 0; int check_datatype = 0; int tcode; int index_pointer = 0; if ( !content_size ) content_size = &_content_size; if ( !content_type ) content_type = _content_type = (char *)calloc( MAX_EXPR_LEVEL, sizeof( int ) ); if ( !parent_count ) parent_count = &_parent_count; /* Basics datatypes */ token_next() ; if ( token.type != IDENTIFIER && ( token.code == identifier_unsigned || token.code == identifier_signed ) ) /* "UNSIGNED" or "SIGNED" */ { check_datatype = 1; token_next(); } if ( token.type != IDENTIFIER ) compile_error( MSG_INCOMP_TYPE ) ; /* Base datatypes */ if ( token.code == identifier_dword ) base = 4 ; else if ( token.code == identifier_int ) base = 4 ; else if ( token.code == identifier_string ) base = 4 ; else if ( token.code == identifier_float ) base = 4 ; else if ( token.code == identifier_short ) base = 2 ; else if ( token.code == identifier_word ) base = 2 ; else if ( token.code == identifier_char ) base = 1 ; else if ( token.code == identifier_byte ) base = 1 ; else { usertype = typedef_by_name( token.code ) ; if ( usertype ) base = typedef_size( *usertype ) ; } if ( base ) { token_next() ; if ( token.type == IDENTIFIER && token.code != identifier_point ) { token_back() ; for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER && ( token.code == identifier_pointer || token.code == identifier_multiply ) ) /* "POINTER" */ { base = 4 ; continue ; } token_back() ; break ; } return base ; } token_back() ; } if ( check_datatype ) compile_error( MSG_INVALID_TYPE ) ; /* Expressions datatypes */ /* Count "*" or "[" */ while ( token.type == IDENTIFIER && ( token.code == identifier_multiply || token.code == identifier_leftb || token.code == identifier_leftp ) ) { if ( *content_size == MAX_EXPR_LEVEL ) compile_error( MSG_TOO_COMPLEX ); if ( token.code == identifier_leftp )( *parent_count )++; content_type[( *content_size )++] = token.code; token_next() ; } if ( !here ) { /* Splinter, se agrega localidad... */ here = proc->privars ; var = varspace_search( here, token.code ) ; if ( !var ) { here = proc->pubvars ; var = varspace_search( here, token.code ) ; } if ( !var ) { here = &local ; var = varspace_search( here, token.code ) ; } if ( !var ) { here = &global ; var = varspace_search( here, token.code ) ; } } else { var = varspace_search( here, token.code ) ; } if ( !var ) compile_error( MSG_UNKNOWN_IDENTIFIER ) ; type = var->type; token_next() ; /* Indexado de arrays */ while ( token.type == IDENTIFIER && token.code == identifier_leftb ) /* "[" */ { CODEBLOCK_POS p = codeblock_pos( code ); /* Cadenas y punteros se indexan en otro nivel */ if ( typedef_is_pointer( type ) || typedef_is_string( type ) ) break ; /* De estructuras o arrays */ if ( typedef_is_struct( type ) && typedef_count( type ) == 1 ) compile_error( MSG_NOT_AN_ARRAY ) ; if ( !typedef_is_struct( type ) && !typedef_is_array( type ) ) compile_error( MSG_NOT_AN_ARRAY ) ; ind = compile_expresion( 0, 0, 0, TYPE_DWORD ) ; if ( !ind.constant || ( ind.value < 0 || ind.value >= typedef_count( type ) ) ) compile_error( MSG_BOUND ) ; codeblock_setpos( code, p ); token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightb ) compile_error( MSG_EXPECTED, "]" ) ; /* "]" */ if ( typedef_is_array( type ) ) type = typedef_reduce( type ) ; else break ; token_next() ; } if ( token.type == IDENTIFIER && token.code == identifier_leftb && ( typedef_is_pointer( type ) || typedef_is_string( type ) ) ) /* Indexado de punteros ptr[0] o cadenas */ { /* Ningun array entra por aca */ CODEBLOCK_POS p = codeblock_pos( code ); ind = compile_subexpresion() ; if ( !typedef_is_integer( ind.type ) ) compile_error( MSG_INTEGER_REQUIRED ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightb ) compile_error( MSG_EXPECTED, "]" ) ; /* "]" */ codeblock_setpos( code, p ); if ( typedef_is_pointer( type ) ) { type = typedef_reduce( type ); token_next(); index_pointer = 1; } else if ( typedef_is_string( type ) ) return 1; /* Indexado de cadenas */ } /* Check for pointer by ']' or ')' */ while ( token.type == IDENTIFIER && ( token.code == identifier_rightb || token.code == identifier_rightp ) ) { if ( token.code == identifier_rightp ) /* ')' */ { if ( !*content_size || !*parent_count ) break; while (( *content_size ) && content_type[( *content_size )-1] == identifier_multiply ) /* only '*', '[]' must be already process */ { if ( !typedef_is_pointer( type ) ) compile_error( MSG_NOT_A_POINTER ) ; type = typedef_reduce( type ); ( *content_size )--; } if ( content_type[--( *content_size )] != identifier_leftp ) compile_error( MSG_INVALID_EXP ); ( *parent_count )--; token_next() ; } else { if ( !*content_size ) compile_error( MSG_EXTRA_CHAR ); while ( *content_size && ( ( tcode = content_type[( *content_size )-1] ) == identifier_leftb || tcode == identifier_multiply ) ) { /* '[' or '*' */ if ( !typedef_is_pointer( type ) ) compile_error( MSG_NOT_A_POINTER ) ; type = typedef_reduce( type ); ( *content_size )--; if ( tcode == identifier_leftb ) { token_next() ; break ; } } } } if ( index_pointer && ( token.type != IDENTIFIER || token.code != identifier_point ) ) /* "." */ { token_back(); return typedef_size( type ); /* Indexado de punteros ptr[0] */ } if ( token.type == IDENTIFIER && token.code == identifier_point ) /* "." */ { if ( typedef_is_pointer( type ) ) type = typedef_reduce( type ) ; if ( !typedef_is_struct( type ) && typedef_base( type ) != TYPE_DWORD && typedef_base( type ) != TYPE_INT /* Soporte de process type para publicas */ ) compile_error( MSG_STRUCT_REQUIRED ) ; if ( typedef_is_struct( type ) || typedef_is_pointer( type ) || typedef_base( type ) == TYPE_DWORD || typedef_base( type ) == TYPE_INT ) return compile_sizeof( typedef_members( type ), content_size, content_type, parent_count ) ; return compile_sizeof( &local, content_size, content_type, parent_count ) ; } /* Process "*ptr|**ptr|***ptr|..." */ while (( *content_size )-- ) { if ( content_type[*content_size] != identifier_multiply ) compile_error( MSG_INVALID_EXP ); if ( !typedef_is_pointer( type ) ) compile_error( MSG_NOT_A_POINTER ) ; type = typedef_reduce( type ); } if ( _content_type ) free( _content_type ); token_back() ; return typedef_size( type ) ; } /* Static utility function for compile_bestproc */ static void strdelchars( char * str, char * chars ) { while ( *str ) { if ( strchr( chars, *str ) ) strcpy( str, str + 1 ) ; else str++ ; } } /* * FUNCTION : compile_bestproc * * Compile a system call, given a list of system functions * with the same name * * PARAMS: * procs List of system functions * * RETURN VALUE: * Identifier code allocated for the function */ SYSPROC * compile_bestproc( SYSPROC ** procs ) { int n, proc_count = 0 ; expresion_result res ; int count = 0 ; char validtypes[32] ; char type = -1 ; int min_params = 0 ; const char * proc_name = procs[0]->name ; int param_diff, params = 0; CODEBLOCK_POS code_pos_code; tok_pos token_save; /* --------------------------------------------------- */ while ( procs[proc_count] ) proc_count++ ; /* Get the minimum number of parameters */ for ( n = 0 ; n < proc_count ; n++ ) if ( procs[n]->params > min_params ) min_params = procs[n]->params ; /* --------------------------------------------------- */ /* count function params */ code_pos_code = codeblock_pos( code ); token_save = token_pos(); params = 0; for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_rightp ) /* ")" */ { token_back() ; break ; } token_back() ; params++ ; res = compile_expresion( 0, 0, 0, TYPE_UNDEFINED ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_comma ) /* "," */ { token_back() ; break ; } } codeblock_setpos(code, code_pos_code); token_set_pos(token_save); /* Eliminate any process that has not as many parameters */ param_diff = 0; for ( n = 0 ; n < proc_count ; n++ ) { char * p = procs[n]->paramtypes; param_diff = 0; while( ( *p ) ) if ( *(p++) == '+' ) param_diff++; if ( procs[n]->params - param_diff != params ) { memmove( &procs[n], &procs[n+1], sizeof( SYSPROC* ) *( proc_count - n ) ) ; proc_count-- ; n-- ; } } count = 0; for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_rightp ) /* ")" */ { token_back() ; break ; } token_back() ; count++ ; /* Eliminate any process that has not as many parameters */ /* for ( n = 0 ; n < proc_count ; n++ ) { if ( procs[n]->params < count ) { memmove( &procs[n], &procs[n+1], sizeof( SYSPROC* ) *( proc_count - n ) ) ; proc_count-- ; n-- ; } } */ if ( proc_count == 0 ) compile_error( MSG_INCORRECT_PARAMC, proc_name, min_params ) ; /* Find all the available types */ validtypes[0] = 0 ; for ( n = 0 ; n < proc_count ; n++ ) { if ( !strchr( validtypes, procs[n]->paramtypes[count-1] ) ) { validtypes[strlen( validtypes )+1] = 0 ; validtypes[strlen( validtypes )] = procs[n]->paramtypes[count-1]; } } if ( strlen( validtypes ) == 1 ) { /* Same type for any function variant */ if ( validtypes[0] == 'V' ) { /* Function will receive a varspace struct */ reduce_arrays = 0; res = compile_expresion( 0, 1, 0, TYPE_UNDEFINED ); reduce_arrays = 1; /* while ( typedef_is_pointer( res.type ) ) { codeblock_add( code, MN_PTR, 0 ); res.type = typedef_reduce( res.type ); } */ if ( typedef_is_struct( res.type ) ) { int size = res.type.varspace->count * sizeof( DCB_TYPEDEF ); int nvar; segment_alloc( globaldata, size ); codeblock_add( code, MN_GLOBAL, globaldata->current ) ; for ( nvar = 0 ; nvar < res.type.varspace->count ; nvar++ ) { DCB_TYPEDEF type; dcb_settype( &type, &res.type.varspace->vars[nvar].type ); memcpy(( uint8_t* )globaldata->bytes + globaldata->current, &type, sizeof( DCB_TYPEDEF ) ); globaldata->current += sizeof( DCB_TYPEDEF ); } codeblock_add( code, MN_PUSH, res.type.varspace->count ); count += 2; } else { DCB_TYPEDEF type; dcb_settype( &type, &res.type ); segment_alloc( globaldata, sizeof( TYPEDEF ) ); codeblock_add( code, MN_GLOBAL, globaldata->current ) ; memcpy(( uint8_t* )globaldata->bytes + globaldata->current, &type, sizeof( DCB_TYPEDEF ) ); globaldata->current += sizeof( DCB_TYPEDEF ); codeblock_add( code, MN_PUSH, 1 ); count += 2; } } else { switch ( validtypes[0] ) { case 'I': type = TYPE_DWORD ; break ; case 'B': type = TYPE_BYTE ; break ; case 'W': type = TYPE_WORD ; break ; case 'S': type = TYPE_STRING ; break ; case 'P': type = TYPE_POINTER ; break ; case 'F': type = TYPE_FLOAT ; break ; default: compile_error( MSG_INVALID_PARAMT ) ; } res = compile_expresion( 0, 0, 0, (BASETYPE)type ) ; if ( res.lvalue ) codeblock_add( code, mntype( res.type, 0 ) | MN_PTR, 0 ) ; } } else { /* Different types availables */ res = compile_expresion( 0, 0, 0, TYPE_UNDEFINED ) ; if ( res.lvalue ) codeblock_add( code, mntype( res.type, 0 ) | MN_PTR, 0 ) ; /* Eliminate any incompatible data type, but allow some * conversions if no exact match is available */ switch ( typedef_base( res.type ) ) { case TYPE_DWORD: case TYPE_SHORT: case TYPE_BYTE: case TYPE_SBYTE: case TYPE_WORD: case TYPE_INT: strdelchars( validtypes, "SFP" ) ; break ; case TYPE_FLOAT: if ( strchr( validtypes, 'F' ) ) strdelchars( validtypes, "SPIWB" ) ; else strdelchars( validtypes, "SP" ) ; break ; case TYPE_STRING: if ( strchr( validtypes, 'S' ) ) strdelchars( validtypes, "FPIWB" ) ; else strdelchars( validtypes, "P" ) ; break ; case TYPE_POINTER: strdelchars( validtypes, "SFIWB" ) ; break ; default: break ; } if ( strlen( validtypes ) != 1 ) compile_error( MSG_INVALID_PARAMT ) ; /* Eliminate all functions that are not selected */ for ( n = 0 ; n < proc_count ; n++ ) { if ( procs[n]->paramtypes[count-1] != validtypes[0] ) { memmove( &procs[n], &procs[n+1], sizeof( SYSPROC* ) *( proc_count - n ) ) ; proc_count-- ; n-- ; } } if ( strlen( validtypes ) > 1 ) continue ; /* Convert the result to the appropiate type, if needed */ switch ( validtypes[0] ) { case 'I': type = TYPE_DWORD ; break ; case 'B': type = TYPE_BYTE ; break ; case 'W': type = TYPE_WORD ; break ; case 'S': type = TYPE_STRING ; break ; case 'P': type = TYPE_POINTER ; break ; case 'F': type = TYPE_FLOAT ; break ; default: compile_error( MSG_INVALID_PARAMT ) ; } res = convert_result_type( res, (BASETYPE)type ) ; } token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_comma ) /* "," */ { token_back() ; break ; } } /* Eliminate any process that has too many parameters */ for ( n = 0 ; n < proc_count ; n++ ) { if ( procs[n]->params != count ) { memmove( &procs[n], &procs[n+1], sizeof( SYSPROC* ) *( proc_count - n ) ) ; proc_count-- ; n-- ; } } if ( proc_count > 1 ) compile_error( MSG_MULTIPLE_PROCS_FOUND, proc_name ); if ( proc_count == 0 ) compile_error( MSG_INCORRECT_PARAMC, proc_name, min_params ) ; codeblock_add( code, MN_SYSCALL, procs[0]->code ) ; return procs[0] ; } /* Compila una lista de parámetros */ int compile_paramlist( BASETYPE * types, const char * paramtypes ) { expresion_result res ; int count = 0, type ; for ( ;; ) { type = types ? *types : TYPE_UNDEFINED ; if ( paramtypes ) { switch ( *paramtypes++ ) { case 'I': type = TYPE_DWORD ; break ; case 'B': type = TYPE_BYTE ; break ; case 'W': type = TYPE_WORD ; break ; case 'S': type = TYPE_STRING ; break ; case 'P': type = TYPE_POINTER ; break ; case 'F': type = TYPE_FLOAT ; break ; default: compile_error( MSG_INVALID_PARAMT ) ; } } res = compile_expresion( 0, 0, 0, (BASETYPE)type ) ; if ( types ) { if ( *types == TYPE_UNDEFINED ) *types = typedef_base( res.type ) ; types++ ; } if ( res.lvalue ) codeblock_add( code, mntype( res.type, 0 ) | MN_PTR, 0 ) ; count++ ; token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_comma ) continue ; /* "," */ token_back() ; break ; } return count ; } /* * FUNCTION : compile_cast * * Compiles a cast operator(c-like type conversion:([type])value) * * PARAMS : * None * * RETURN VALUE : * Returns the expression result * */ expresion_result compile_cast() { TYPEDEF type; BASETYPE basetype = TYPE_INT; int tokens = 0; int signed_prefix = 0; int unsigned_prefix = 0; expresion_result res; token_next(); /* Check for signed/unsigned prefix */ if ( token.type == IDENTIFIER ) { if ( token.code == identifier_signed ) { signed_prefix = 1; tokens++; token_next(); } else if ( token.code == identifier_unsigned ) { unsigned_prefix = 1; tokens++; token_next(); } } /* Create the data type definition */ if ( token.type == IDENTIFIER ) { if ( token.code == identifier_dword ) { basetype = signed_prefix ? TYPE_INT : TYPE_DWORD; signed_prefix = unsigned_prefix = 0; tokens++; token_next() ; } else if ( token.code == identifier_word ) { basetype = signed_prefix ? TYPE_SHORT : TYPE_WORD; signed_prefix = unsigned_prefix = 0; tokens++; token_next() ; } else if ( token.code == identifier_byte ) { basetype = signed_prefix ? TYPE_SBYTE : TYPE_BYTE; signed_prefix = unsigned_prefix = 0; tokens++; token_next() ; } else if ( token.code == identifier_int ) { basetype = unsigned_prefix ? TYPE_DWORD : TYPE_INT; signed_prefix = unsigned_prefix = 0; tokens++; token_next() ; } else if ( token.code == identifier_short ) { basetype = unsigned_prefix ? TYPE_WORD : TYPE_SHORT; signed_prefix = unsigned_prefix = 0; tokens++; token_next() ; } else if ( token.code == identifier_char ) { basetype = TYPE_CHAR; tokens++; token_next() ; } else if ( token.code == identifier_float ) { basetype = TYPE_FLOAT ; tokens++; token_next() ; } else if ( token.code == identifier_string ) { basetype = TYPE_STRING ; tokens++; token_next() ; } } /* Don't allow a signed/unsigned prefix in non-integer types */ if ( signed_prefix || unsigned_prefix ) compile_error( MSG_INVALID_TYPE ); /* If type is not a basic one: check for user-defined types */ if ( tokens == 0 ) { TYPEDEF * typep = typedef_by_name( token.code ); if ( typep == NULL ) { /* type = typedef_new(TYPE_INT); */ compile_error( MSG_INVALID_TYPE ); } type = *typep; token_next(); } else type = typedef_new( basetype ); /* Check for pointers to defined types */ while ( token.type == IDENTIFIER && ( token.code == identifier_pointer || token.code == identifier_multiply ) ) /* "POINTER" or "*" */ { type = typedef_pointer( type ); /* tokens++; */ token_next() ; } /* Check for the right parent */ if ( token.type != IDENTIFIER || token.code != identifier_rightp ) compile_error( MSG_EXPECTED, ")" ); /* ")" */ /* Do the cast */ res = compile_value(); if ( typedef_is_equal( res.type, type ) ) return res; if ( typedef_is_pointer( type ) ) { /* Conversion of pointer to pointer of another type */ if ( typedef_is_pointer( res.type ) || typedef_is_integer( res.type ) ) { res.type = type; return res; } else if ( typedef_is_float( res.type ) ) { codeblock_add( code, MN_FLOAT2INT, 0 ); res.type = type; return res; } compile_error( MSG_PTR_CONVERSION ); } else if ( typedef_is_float( type ) ) { /* Conversion of integer to float */ if ( typedef_is_integer( res.type ) ) { if ( res.lvalue ) { codeblock_add( code, mntype( res.type, 0 ) | MN_PTR, 0 ); res.lvalue = 0; } codeblock_add( code, MN_INT2FLOAT, 0 ); res.type = type; } else compile_error( MSG_CONVERSION ); } else if ( typedef_base( type ) == TYPE_CHAR ) { if ( typedef_is_string( res.type ) ) { if ( res.lvalue ) { codeblock_add( code, MN_PTR | MN_STRING, 0 ); res.lvalue = 0; } /* codeblock_add(code, MN_STR2INT, 0); res.type = typedef_new(TYPE_INT); */ codeblock_add( code, MN_STR2CHR, 0 ); res.type = typedef_new( TYPE_CHAR ); } else if ( typedef_is_array( res.type ) && res.type.chunk[1].type == TYPE_CHAR ) { codeblock_add( code, MN_A2STR, 0 ); codeblock_add( code, MN_STR2CHR, 0 ); res.type = typedef_new( TYPE_CHAR ); } else { compile_error( MSG_CONVERSION ); } } else if ( typedef_is_integer( type ) ) { /* Conversion of float, string or integer to integer */ if ( typedef_is_float( res.type ) ) { if ( res.lvalue ) { codeblock_add( code, MN_PTR | MN_FLOAT, 0 ); res.lvalue = 0; } codeblock_add( code, MN_FLOAT2INT, 0 ); res.type = typedef_new( TYPE_INT ); } else if ( typedef_is_string( res.type ) ) { if ( res.lvalue ) { codeblock_add( code, MN_PTR | MN_STRING, 0 ); res.lvalue = 0; } codeblock_add( code, MN_STR2INT, 0 ); res.type = typedef_new( TYPE_INT ); } else if ( typedef_is_array( res.type ) && res.type.chunk[1].type == TYPE_CHAR ) { codeblock_add( code, MN_A2STR, 0 ); codeblock_add( code, MN_STR2INT, 0 ); res.type = typedef_new( TYPE_INT ); } else if ( typedef_is_integer( res.type ) || typedef_is_pointer( res.type ) || typedef_base( res.type ) == TYPE_CHAR ) { if ( res.lvalue ) { codeblock_add( code, mntype( res.type, 0 ) | MN_PTR, 0 ); res.lvalue = 0; } } else { compile_error( MSG_CONVERSION ); } if ( type.chunk[0].type == TYPE_BYTE && typedef_is_integer( res.type ) ) { codeblock_add( code, MN_INT2BYTE, 0 ); res.type = type; } else if ( type.chunk[0].type == TYPE_SBYTE && typedef_is_integer( res.type ) ) { codeblock_add( code, MN_INT2BYTE, 0 ); res.type = type; } else if ( type.chunk[0].type == TYPE_WORD && typedef_is_integer( res.type ) ) { codeblock_add( code, MN_INT2WORD, 0 ); res.type = type; } else if ( type.chunk[0].type == TYPE_SHORT && typedef_is_integer( res.type ) ) { codeblock_add( code, MN_INT2WORD, 0 ); res.type = type; } } else if ( typedef_is_string( type ) ) { /* Conversión de puntero, float, entero o cadena de ancho fijo a cadena */ if ( typedef_is_array( res.type ) && res.type.chunk[1].type == TYPE_CHAR ) { codeblock_add( code, MN_A2STR, 0 ); res.type = typedef_new( TYPE_STRING ); } else if ( typedef_is_pointer( res.type ) ) { if ( res.lvalue ) { codeblock_add( code, mntype( res.type, 0 ) | MN_PTR, 0 ); res.lvalue = 0; } codeblock_add( code, MN_A2STR, 0 ); res.type = typedef_new( TYPE_STRING ); } else if ( res.type.chunk[0].type == TYPE_CHAR ) { if ( res.lvalue ) { codeblock_add( code, mntype( res.type, 0 ) | MN_PTR, 0 ); res.lvalue = 0; } codeblock_add( code, MN_CHR2STR, 0 ); res.type = typedef_new( TYPE_STRING ); } else if ( typedef_is_integer( res.type ) ) { if ( res.lvalue ) { codeblock_add( code, mntype( res.type, 0 ) | MN_PTR, 0 ); res.lvalue = 0; } codeblock_add( code, MN_INT2STR | mntype( res.type, 0 ), 0 ); res.type = typedef_new( TYPE_STRING ); } else if ( typedef_is_float( res.type ) ) { if ( res.lvalue ) { codeblock_add( code, MN_PTR, 0 ); res.lvalue = 0; } codeblock_add( code, MN_FLOAT2STR, 0 ); res.type = typedef_new( TYPE_STRING ); } else compile_error( MSG_CONVERSION ); } else if ( typedef_is_struct( type ) ) { res.type = type; } else compile_error( MSG_CONVERSION ); return res; } /* Compila un valor (elemento más pequeño del lenguaje) */ expresion_result compile_value() { CONSTANT * c ; SYSPROC * sysproc ; PROCDEF * cproc ; int param_count, id ; expresion_result res ; token_next() ; /* ( ... ) */ if ( token.type == IDENTIFIER ) { if ( token.code == identifier_leftp ) /* "(" */ { /* Check for cast-type expressions */ token_next(); if ( token.type == IDENTIFIER && identifier_is_type( token.code ) ) { token_back(); return compile_cast(); } token_back(); res = compile_subexpresion() ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightp ) compile_error( MSG_EXPECTED, ")" ) ; /* ")" */ return res ; } if ( token.code == identifier_type ) /* "TYPE" */ { token_next( ); /* "TYPE mouse" */ if ( token.type == IDENTIFIER && token.code == identifier_mouse ) /* "MOUSE" - Hack */ { codeblock_add( code, MN_PUSH, -1 ) ; res.value = -1 ; res.fvalue = 0.0 ; res.lvalue = 0 ; res.constant = 1 ; res.asignation = 0 ; res.call = 0 ; res.type = typedef_new( TYPE_INT ) ; return res ; } if ( token.type != IDENTIFIER || token.code < reserved_words ) compile_error( MSG_PROCESS_NAME_EXP ) ; codeblock_add( code, MN_TYPE, token.code ) ; res.fvalue = 0.0 ; res.value = 0 ; res.lvalue = 0 ; res.constant = 0 ; res.asignation = 0 ; res.call = 0 ; res.type = typedef_new( TYPE_INT ) ; return res ; } if ( token.code == identifier_offset || token.code == identifier_bandoffset ) /* "OFFSET" or "&" */ { res = compile_factor() ; /* Para permitir &a.b */ if ( !res.lvalue ) compile_error( MSG_NOT_AN_LVALUE ) ; res.lvalue = 0 ; res.type = typedef_pointer( res.type ) ; return res ; } if ( token.code == identifier_leftb ) /* "[" */ /* POINTER */ { res = compile_subexpresion() ; if ( !typedef_is_pointer( res.type ) ) compile_error( MSG_NOT_A_POINTER ) ; if ( res.lvalue ) codeblock_add( code, mntype( res.type, 0 ) | MN_PTR, 0 ) ; res.type = typedef_reduce( res.type ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightb ) compile_error( MSG_EXPECTED, "]" ) ; /* "]" */ res.lvalue = 1 ; return res ; } if ( token.code == identifier_multiply ) /* "*" */ { res = compile_factor() ; /* Para aceptar *ptr++ */ if ( !typedef_is_pointer( res.type ) ) compile_error( MSG_NOT_A_POINTER ) ; if ( res.lvalue ) codeblock_add( code, mntype( res.type, 0 ) | MN_PTR, 0 ) ; res.type = typedef_reduce( res.type ) ; res.lvalue = 1 ; return res ; } /* SIZEOF */ if ( token.code == identifier_sizeof ) /* "SIZEOF" */ { token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_leftp ) compile_error( MSG_EXPECTED, "(" ) ; /* "(" */ res.value = compile_sizeof( 0, NULL, NULL, NULL ) ; res.fvalue = 0.0 ; res.lvalue = 0 ; res.constant = 1 ; res.asignation = 0 ; res.call = 0 ; res.type = typedef_new( TYPE_DWORD ) ; codeblock_add( code, MN_PUSH, res.value ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightp ) compile_error( MSG_EXPECTED, ")" ) ; /* ")" */ return res ; } } switch ( token.type ) { case NUMBER: /* Numbers */ codeblock_add( code, MN_PUSH, token.code ) ; res.fvalue = 0.0 ; res.lvalue = 0 ; res.asignation = 0 ; res.constant = 1 ; res.call = 0 ; res.value = token.code ; res.type = typedef_new( TYPE_INT ) ; return res ; case FLOAT: codeblock_add( code, MN_PUSH, *( int * )&token.value ) ; res.value = 0 ; res.lvalue = 0 ; res.asignation = 0 ; res.constant = 1 ; res.call = 0 ; res.fvalue = token.value ; res.type = typedef_new( TYPE_FLOAT ) ; return res ; case STRING: /* Strings */ codeblock_add( code, MN_PUSH | MN_STRING, token.code ) ; res.fvalue = 0.0 ; res.lvalue = 0 ; res.asignation = 0 ; res.constant = 1 ; res.call = 0 ; res.value = token.code ; res.type = typedef_new( TYPE_STRING ) ; return res ; case IDENTIFIER: /* Constants */ c = constants_search( token.code ) ; if ( c ) { if ( typedef_is_string( c->type ) ) codeblock_add( code, MN_PUSH | MN_STRING, c->value ) ; else codeblock_add( code, MN_PUSH, c->value ) ; res.lvalue = 0 ; res.asignation = 0 ; res.constant = 1 ; res.call = 0 ; res.value = c->value ; res.fvalue = *( float * ) & c->value; res.type = c->type ; return res ; } break; default: compile_error( MSG_UNKNOWN_IDENTIFIER ) ; break; } /* Llamada a un procedimiento o función del sistema */ id = token.code ; token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_leftp ) /* "(" */ { SYSPROC ** sysproc_list = sysproc_getall( id ) ; if ( sysproc_list ) { sysproc = compile_bestproc( sysproc_list ); free( sysproc_list ); token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightp ) compile_error( MSG_EXPECTED, ")" ) ; /* ")" */ res.fvalue = 0.0 ; res.lvalue = 0 ; res.asignation = 0 ; res.constant = 0 ; res.call = 1 ; res.value = 0 ; res.type = typedef_new( sysproc->type ) ; return res ; } /* Llama a un procedimiento del usuario */ cproc = procdef_search( id ) ; if ( !cproc ) { if ( autodeclare ) cproc = procdef_new( procdef_getid(), id ) ; else { token_back() ; compile_error( MSG_UNDEFINED_PROC ) ; } } token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightp ) /* ")" */ { token_back() ; param_count = compile_paramlist( cproc->paramtype, 0 ) ; token_next() ; } else { param_count = 0 ; } if ( token.type != IDENTIFIER || token.code != identifier_rightp ) compile_error( MSG_EXPECTED, ")" ) ; /* ")" */ if ( cproc->params == -1 ) { cproc->params = param_count ; } else if ( cproc->params != param_count ) { compile_error( MSG_INCORRECT_PARAMC, identifier_name( cproc->identifier ), cproc->params ) ; } codeblock_add( code, MN_CALL, id ) ; res.fvalue = 0.0 ; res.lvalue = 0 ; res.asignation = 0 ; res.constant = 0 ; res.call = 1 ; res.value = 0 ; res.type = typedef_new( cproc->type ) ; return res ; } token_back() ; /* Valor asignable */ return compile_sublvalue( 0, 0, NULL ) ; } expresion_result compile_factor() { expresion_result res, part ; token_next() ; res.value = 0 ; res.fvalue = 0 ; res.lvalue = 0 ; res.call = 0 ; res.constant = 0 ; res.asignation = 0 ; /* "+2" (Positivo) */ if ( token.type == IDENTIFIER && token.code == identifier_plus ) token_next() ; /* "+" */ if ( token.type == IDENTIFIER ) { if ( token.code == identifier_minus ) /* "-" */ /* "-2" (Negativo) */ { part = compile_factor() ; if ( part.lvalue ) codeblock_add( code, mntype( part.type, 0 ) | MN_PTR, 0 ) ; codeblock_add( code, ( mntype( part.type, 0 ) == MN_FLOAT ? MN_FLOAT : 0 ) | MN_NEG, 0 ) ; res.type = part.type ; if ( typedef_is_numeric( part.type ) ) { res.constant = part.constant ; res.value = -part.value ; res.fvalue = -part.fvalue ; return res ; } compile_error( MSG_NUMBER_REQUIRED ) ; } else if ( token.code == identifier_not ) /* "NOT" or "!" */ { part = compile_factor() ; if ( part.lvalue ) codeblock_add( code, mntype( part.type, 0 ) | MN_PTR, 0 ) ; if ( typedef_is_pointer( part.type ) ) { /* codeblock_add (code, mntype(part.type, 0) | MN_POINTER2BOL, 0) ; */ part.type = typedef_new( TYPE_DWORD ) ; } codeblock_add( code, ( mntype( part.type, 0 ) == MN_FLOAT ? MN_FLOAT : 0 ) | MN_NOT, 0 ) ; if ( typedef_is_numeric( part.type ) || typedef_is_pointer( part.type ) ) { res.constant = part.constant ; res.value = !part.value ; res.fvalue = ( float )!part.fvalue ; res.type = part.type ; return res ; } compile_error( MSG_NUMBER_REQUIRED ) ; return res ; } else if ( token.code == identifier_bnot ) /* "BNOT" or "~" */ { part = compile_factor() ; if ( part.lvalue ) codeblock_add( code, mntype( part.type, 0 ) | MN_PTR, 0 ) ; if ( typedef_is_pointer( part.type ) ) { /* codeblock_add (code, mntype(part.type, 0) | MN_POINTER2BOL, 0) ; */ part.type = typedef_new( TYPE_DWORD ) ; } if ( mntype( part.type, 0 ) == MN_FLOAT ) compile_error( MSG_INTEGER_REQUIRED ); codeblock_add( code, mntype( part.type, 0 ) | MN_BNOT, 0 ) ; if ( typedef_is_numeric( part.type ) ) { res.constant = part.constant ; res.value = ~part.value ; res.type = part.type /*typedef_new( TYPE_INT )*/ ; return res ; } compile_error( MSG_NUMBER_REQUIRED ) ; return res ; } else if ( token.type == IDENTIFIER && token.code == identifier_plusplus ) /* "++" */ { part = compile_factor() ; if ( !part.lvalue ) compile_error( MSG_VARIABLE_REQUIRED ) ; if ( typedef_is_string( part.type ) ) compile_error( MSG_INCOMP_TYPE ) ; if ( typedef_is_pointer( part.type ) ) codeblock_add( code, MN_INC, typedef_size( typedef_reduce( part.type ) ) ) ; else codeblock_add( code, mntype( part.type, 0 ) | MN_INC, 1 ) ; res.asignation = 1 ; res.lvalue = 1 ; res.type = part.type ; return res ; } else if ( token.type == IDENTIFIER && token.code == identifier_minusminus ) /* "--" */ { part = compile_factor() ; if ( !part.lvalue ) compile_error( MSG_VARIABLE_REQUIRED ) ; if ( typedef_is_string( part.type ) ) compile_error( MSG_INCOMP_TYPE ) ; if ( typedef_is_pointer( part.type ) ) codeblock_add( code, MN_DEC, typedef_size( typedef_reduce( part.type ) ) ) ; else codeblock_add( code, mntype( part.type, 0 ) | MN_DEC, 1 ) ; res.asignation = 1 ; res.lvalue = 1 ; res.type = part.type ; return res ; } } token_back() ; part = compile_value() ; /* Sufijos (operadores ., [], etc) */ for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER ) { if ( token.code == identifier_point ) /* "." */ /* Operador "." */ { if ( typedef_is_array( part.type ) ) { while ( typedef_is_array ( part.type = typedef_reduce( part.type ) ) ) ; } if ( typedef_is_pointer( part.type ) ) { part.type = typedef_reduce( part.type ) ; if ( !typedef_is_struct( part.type ) ) compile_error( MSG_STRUCT_REQUIRED ) ; codeblock_add( code, MN_PTR, 0 ) ; } if ( typedef_is_struct( part.type ) ) { VARSPACE * v = typedef_members( part.type ) ; if ( !v->vars ) compile_error( MSG_STRUCT_REQUIRED ) ; part = compile_sublvalue( v, v->vars[0].offset, NULL ) ; } else { VARSPACE * v = typedef_members( part.type ) ; if ( typedef_base( part.type ) != TYPE_DWORD && typedef_base( part.type ) != TYPE_INT ) compile_error( MSG_INTEGER_REQUIRED ) ; if ( part.lvalue ) codeblock_add( code, mntype( part.type, 0 ) | MN_PTR, 0 ) ; part = compile_sublvalue( &local, 0, v ) ; /* referenciada REMOTA por proceso (Splinter) */ } continue ; } else if ( token.code == identifier_plusplus ) /* Operador ++ posterior */ { if ( !part.lvalue ) compile_error( MSG_VARIABLE_REQUIRED ) ; if ( typedef_is_string( part.type ) ) compile_error( MSG_INCOMP_TYPE ) ; if ( typedef_is_pointer( part.type ) ) codeblock_add( code, MN_POSTINC, typedef_size( typedef_reduce( part.type ) ) ) ; else codeblock_add( code, mntype( part.type, 0 ) | MN_POSTINC, 1 ) ; part.asignation = 1 ; part.lvalue = 0 ; continue ; } else if ( token.code == identifier_minusminus ) /* Operador -- posterior */ { if ( !part.lvalue ) compile_error( MSG_VARIABLE_REQUIRED ) ; if ( typedef_is_string( part.type ) ) compile_error( MSG_INCOMP_TYPE ) ; if ( typedef_is_pointer( part.type ) ) codeblock_add( code, MN_POSTDEC, typedef_size( typedef_reduce( part.type ) ) ) ; else codeblock_add( code, mntype( part.type, 0 ) | MN_POSTDEC, 1 ) ; part.asignation = 1 ; part.lvalue = 0 ; continue ; } } /* Indexado vía [...] */ if ( token.type == IDENTIFIER && token.code == identifier_leftb ) /* "[" */ { if ( typedef_is_pointer( part.type ) ) /* De punteros */ { if ( part.lvalue ) codeblock_add( code, mntype( part.type, 0 ) | MN_PTR, 0 ) ; part.type = typedef_reduce( part.type ) ; res = compile_subexpresion() ; if ( !typedef_is_integer( res.type ) ) compile_error( MSG_INTEGER_REQUIRED ) ; if ( res.lvalue ) codeblock_add( code, mntype( res.type, 0 ) | MN_PTR, 0 ) ; codeblock_add( code, MN_ARRAY, typedef_size( part.type ) ) ; part.lvalue = 1 ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightb ) compile_error( MSG_EXPECTED, "]" ) ; /* "]" */ continue ; } if ( typedef_is_string( part.type ) ) /* De cadenas */ { if ( part.lvalue ) codeblock_add( code, MN_STRING | MN_PTR, 0 ) ; res = compile_subexpresion() ; if ( !typedef_is_integer( res.type ) ) compile_error( MSG_INTEGER_REQUIRED ) ; if ( res.lvalue ) codeblock_add( code, mntype( res.type, 0 ) | MN_PTR, 0 ) ; codeblock_add( code, MN_STRI2CHR, 0 ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightb ) compile_error( MSG_EXPECTED, "]" ) ; /* "]" */ /* part.type = typedef_new( TYPE_STRING ) ; */ part.type = typedef_new( TYPE_CHAR ) ; part.lvalue = 0 ; } continue ; } break ; } token_back() ; return part ; } /* Paso 7 */ expresion_result compile_operand() { expresion_result left = compile_factor(), right, res ; int op, t ; for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_multiply ) /* "*" */ { if ( left.lvalue ) codeblock_add( code, mntype( left.type, 0 ) | MN_PTR, 0 ) ; right = compile_factor(); if ( right.lvalue ) codeblock_add( code, mntype( right.type, 0 ) | MN_PTR, 0 ) ; t = check_numeric_types( &left, &right ) ; codeblock_add( code, MN_MUL | t, 0 ) ; res.constant = ( right.constant && left.constant ) ; if ( t == MN_FLOAT ) { res.value = 0 ; res.fvalue = left.fvalue * right.fvalue ; res.type = typedef_new( TYPE_FLOAT ) ; } else { res.fvalue = 0.0 ; res.type = typedef_new( TYPE_INT ) ; res.value = left.value * right.value ; } res.lvalue = 0 ; res.asignation = 0 ; res.call = 0 ; left = res ; continue ; } else if ( token.type == IDENTIFIER && ( token.code == identifier_divide || token.code == identifier_mod ) ) /* "/" or "%" */ { op = token.code == identifier_mod ? MN_MOD : MN_DIV ; if ( op == MN_MOD && typedef_base( left.type ) == TYPE_FLOAT ) compile_error( MSG_INTEGER_REQUIRED ) ; if ( left.lvalue ) codeblock_add( code, mntype( left.type, 0 ) | MN_PTR, 0 ) ; right = compile_factor(); if ( op == MN_MOD && typedef_base( right.type ) == TYPE_FLOAT ) compile_error( MSG_INTEGER_REQUIRED ) ; if ( right.lvalue ) codeblock_add( code, mntype( right.type, 0 ) | MN_PTR, 0 ) ; t = check_numeric_types( &left, &right ) ; codeblock_add( code, op | t, 0 ) ; res.constant = ( right.constant && left.constant ) ; res.value = 0 ; res.fvalue = 0.0 ; res.lvalue = 0 ; res.asignation = 0 ; res.call = 0 ; res.type = typedef_new( t == MN_FLOAT ? TYPE_FLOAT : TYPE_INT ) ; if ( res.constant ) { if ( t == MN_FLOAT ) { if ( op == MN_MOD ) compile_error( MSG_NUMBER_REQUIRED ) ; res.fvalue = left.fvalue / right.fvalue ; res.type = typedef_new( TYPE_FLOAT ) ; res.value = 0 ; } else { if ( right.value == 0 ) compile_error( MSG_DIVIDE_BY_ZERO ) ; res.value = op == MN_MOD ? left.value % right.value : left.value / right.value ; res.type = typedef_new( TYPE_INT ) ; res.fvalue = 0.0 ; } } left = res ; continue ; } token_back() ; break ; } return left ; } /* Paso 6 */ expresion_result compile_operation() { expresion_result left = compile_operand(), right, res ; int op, t ; for ( ;; ) { token_next() ; /* Suma(o resta) de un entero a un puntero */ if ( typedef_is_pointer( left.type ) && token.type == IDENTIFIER && ( token.code == identifier_plus || token.code == identifier_minus ) ) /* "+" o "-" */ { TYPEDEF ptr_t = typedef_reduce( left.type ) ; op = token.code == identifier_plus ? MN_ADD : MN_SUB ; if ( left.lvalue ) codeblock_add( code, mntype( left.type, 0 ) | MN_PTR, 0 ) ; right = compile_operand() ; if ( right.lvalue ) codeblock_add( code, mntype( right.type, 0 ) | MN_PTR, 0 ) ; if ( !typedef_is_integer( right.type ) && !typedef_is_pointer( right.type )) compile_error( MSG_INCOMP_TYPES ) ; if ( typedef_size( ptr_t ) > 1 ) codeblock_add( code, MN_ARRAY, ( op == MN_ADD ? 1 : -1 ) * typedef_size( ptr_t ) ) ; else codeblock_add( code, op, 0 ) ; res.value = 0 ; res.fvalue = 0.0 ; res.constant = 0 ; res.lvalue = 0 ; res.asignation = 0 ; res.call = 0 ; res.type = left.type ; left = res ; continue ; } /* Suma de cadenas */ if ( typedef_is_array( left.type ) && left.lvalue && token.type == IDENTIFIER && token.code == identifier_plus && left.type.chunk[1].type == TYPE_CHAR ) /* "+" */ { codeblock_add( code, MN_A2STR, 0 ) ; left.lvalue = 0 ; left.type = typedef_new( TYPE_STRING ) ; } /* Suma/resta de valores numéricos */ if ( token.type == IDENTIFIER && ( token.code == identifier_plus || token.code == identifier_minus ) ) /* "+" or "-" */ { op = token.code == identifier_plus ? MN_ADD : MN_SUB ; if ( left.lvalue ) codeblock_add( code, mntype( left.type, 0 ) | MN_PTR, 0 ) ; right = compile_operand() ; /* Concatenación de cadenas */ if (( typedef_is_string( left.type ) || typedef_is_string( right.type ) ) && op == MN_ADD ) { if ( typedef_is_array( right.type ) && right.lvalue && right.type.chunk[1].type == TYPE_CHAR ) { codeblock_add( code, MN_A2STR, 0 ) ; right.type = typedef_new( TYPE_STRING ) ; right.lvalue = 0 ; } if ( right.lvalue ) codeblock_add( code, mntype( right.type, 0 ) | MN_PTR, 0 ) ; if ( typedef_is_integer( right.type ) ) codeblock_add( code, MN_INT2STR | mntype( right.type, 0 ), 0 ) ; else if ( typedef_is_float( right.type ) ) codeblock_add( code, MN_FLOAT2STR, 0 ) ; else if ( typedef_is_pointer( right.type ) ) codeblock_add( code, MN_POINTER2STR, 0 ) ; else if ( typedef_base( right.type ) == TYPE_CHAR ) codeblock_add( code, MN_CHR2STR, 0 ); else if ( !typedef_is_string( right.type ) ) compile_error( MSG_INCOMP_TYPES ) ; if ( typedef_is_integer( left.type ) ) codeblock_add( code, MN_INT2STR | mntype( left.type, 0 ), 1 ) ; else if ( typedef_is_float( left.type ) ) codeblock_add( code, MN_FLOAT2STR, 1 ) ; else if ( typedef_is_pointer( left.type ) ) codeblock_add( code, MN_POINTER2STR, 1 ) ; else if ( typedef_base( left.type ) == TYPE_CHAR ) codeblock_add( code, MN_CHR2STR, 1 ); else if ( !typedef_is_string( left.type ) ) compile_error( MSG_INCOMP_TYPES ) ; codeblock_add( code, MN_STRING | MN_ADD, 0 ) ; res.fvalue = 0.0 ; res.value = 0 ; res.constant = 0 ; res.lvalue = 0 ; res.asignation = 0 ; res.call = 0 ; res.type = typedef_new( TYPE_STRING ) ; left = res ; continue ; } if ( right.lvalue ) codeblock_add( code, mntype( right.type, 0 ) | MN_PTR, 0 ) ; t = check_numeric_types( &left, &right ) ; if ( t != MN_FLOAT ) t = MN_DWORD ; codeblock_add( code, op | t, 0 ) ; res.constant = ( right.constant && left.constant ) ; res.lvalue = 0 ; res.asignation = 0 ; res.call = 0 ; if ( t == MN_FLOAT ) { res.value = 0.0 ; res.type = typedef_new( TYPE_FLOAT ) ; res.fvalue = op == MN_ADD ? left.fvalue + right.fvalue : left.fvalue - right.fvalue ; } else { res.fvalue = 0.0 ; res.type = left.type /*typedef_new( TYPE_INT )*/ ; res.value = op == MN_ADD ? left.value + right.value : left.value - right.value ; } left = res ; continue ; } token_back() ; break ; } return left ; } /* Paso 5 */ expresion_result compile_rotation() { expresion_result left = compile_operation(), right, res ; int op ; BASETYPE t ; for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER && ( token.code == identifier_ror || token.code == identifier_rol ) ) /* ">>" or "<<" */ { op = token.code == identifier_ror ? MN_ROR : MN_ROL ; if ( left.lvalue ) codeblock_add( code, mntype( left.type, 0 ) | MN_PTR, 0 ) ; right = compile_operation() ; if ( right.lvalue ) codeblock_add( code, mntype( right.type, 0 ) | MN_PTR, 0 ) ; t = check_numeric_types( &left, &right ) ; codeblock_add( code, op | mntype( left.type, 0 ), 0 ) ; res.constant = ( right.constant && left.constant ) ; if ( t == MN_FLOAT ) compile_error( MSG_INTEGER_REQUIRED ) ; res.type = left.type /*typedef_new( TYPE_DWORD ) */; res.value = ( op == MN_ROR ? ( left.value >> right.value ) : ( left.value << right.value ) ) ; res.lvalue = 0 ; res.asignation = 0 ; res.call = 0 ; left = res ; continue ; } token_back() ; break; } return left ; } /* Paso 4 */ expresion_result compile_comparison_1() { expresion_result left = compile_rotation(), right, res ; int op, t ; for ( ;; ) { token_next() ; if (token.type == IDENTIFIER && ( token.code == identifier_gt || /* ">" */ token.code == identifier_lt || /* "<" */ token.code == identifier_gte || /* ">=" or "=>" */ token.code == identifier_lte ) ) /* "<=" or "=<" */ { int is_unsigned = 0; op = token.code ; if ( left.lvalue && ( left.type.chunk[0].type != TYPE_ARRAY || left.type.chunk[1].type != TYPE_CHAR ) ) codeblock_add( code, mntype( left.type, 0 ) | MN_PTR, 0 ) ; right = compile_rotation() ; if ( right.lvalue && ( right.type.chunk[0].type != TYPE_ARRAY || right.type.chunk[1].type != TYPE_CHAR ) ) codeblock_add( code, mntype( right.type, 0 ) | MN_PTR, 0 ) ; t = check_numeric_or_string_types( &left, &right ) ; if ( t != MN_FLOAT && t != MN_STRING ) t = MN_DWORD ; if ( ( typedef_is_unsigned( left.type ) || typedef_is_unsigned( right.type ) ) && ( typedef_is_integer( left.type ) && typedef_is_integer( right.type ) ) ) is_unsigned = MN_UNSIGNED; res.value = 0 ; if ( op == identifier_gt ) /* ">" */ { codeblock_add( code, t | MN_GT | is_unsigned, 0 ) ; if ( left.constant && right.constant ) { if ( t == MN_DWORD ) res.value = left.value > right.value; else if ( t == MN_FLOAT ) res.value = ( left.fvalue > right.fvalue ); else res.value = strcmp( string_get( left.value ), string_get( right.value ) ) > 0; } } else if ( op == identifier_lt ) /* "<" */ { codeblock_add( code, t | MN_LT | is_unsigned, 0 ) ; if ( left.constant && right.constant ) { if ( t == MN_DWORD ) res.value = left.value < right.value; else if ( t == MN_FLOAT ) res.value = ( left.fvalue < right.fvalue ); else res.value = strcmp( string_get( left.value ), string_get( right.value ) ) < 0; } } else if ( op == identifier_gte ) /* ">=" or "=>" */ { codeblock_add( code, t | MN_GTE | is_unsigned, 0 ) ; if ( left.constant && right.constant ) { if ( t == MN_DWORD ) res.value = left.value >= right.value; else if ( t == MN_FLOAT ) res.value = ( left.fvalue >= right.fvalue ); else res.value = strcmp( string_get( left.value ), string_get( right.value ) ) >= 0; } } else if ( op == identifier_lte ) /* "<=" or "=<" */ { codeblock_add( code, t | MN_LTE | is_unsigned, 0 ) ; if ( left.constant && right.constant ) { if ( t == MN_DWORD ) res.value = left.value <= right.value; else if ( t == MN_FLOAT ) res.value = ( left.fvalue <= right.fvalue ); else res.value = strcmp( string_get( left.value ), string_get( right.value ) ) <= 0; } } res.lvalue = 0 ; res.asignation = 0 ; res.call = 0 ; res.constant = ( right.constant && left.constant ) ; res.type = typedef_new( TYPE_INT ) ; left = res; continue; } token_back() ; break; } return left ; } expresion_result compile_comparison_2() { expresion_result left = compile_comparison_1(), right, res ; int op, t ; for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER && ( token.code == identifier_eq || /* "==" */ token.code == identifier_ne ) ) /* "!=" or "<>" */ { int is_unsigned = 0; op = token.code ; if ( left.lvalue && ( left.type.chunk[0].type != TYPE_ARRAY || left.type.chunk[1].type != TYPE_CHAR ) ) codeblock_add( code, mntype( left.type, 0 ) | MN_PTR, 0 ) ; right = compile_comparison_1(); if ( right.lvalue && ( right.type.chunk[0].type != TYPE_ARRAY || right.type.chunk[1].type != TYPE_CHAR ) ) codeblock_add( code, mntype( right.type, 0 ) | MN_PTR, 0 ) ; t = check_numeric_or_string_types( &left, &right ) ; if ( t != MN_FLOAT && t != MN_STRING ) t = MN_DWORD ; if ( typedef_is_unsigned( left.type ) && typedef_is_unsigned( right.type ) ) is_unsigned = MN_UNSIGNED; res.value = 0 ; if ( op == identifier_eq ) /* "==" */ { codeblock_add( code, t | MN_EQ, 0 ) ; if ( left.constant && right.constant ) { if ( t == MN_DWORD ) res.value = left.value == right.value; else if ( t == MN_FLOAT ) res.value = ( left.fvalue == right.fvalue ); else res.value = strcmp( string_get( left.value ), string_get( right.value ) ) == 0; } } else if ( op == identifier_ne ) /* "!=" or "<>" */ { codeblock_add( code, t | MN_NE, 0 ) ; if ( left.constant && right.constant ) { if ( t == MN_DWORD ) res.value = left.value != right.value; else if ( t == MN_FLOAT ) res.value = ( left.fvalue != right.fvalue ); else res.value = strcmp( string_get( left.value ), string_get( right.value ) ) != 0; } } res.lvalue = 0 ; res.asignation = 0 ; res.call = 0 ; res.constant = ( right.constant && left.constant ) ; res.type = typedef_new( TYPE_INT ) ; left = res ; continue; } token_back() ; break; } return left ; } expresion_result compile_bitwise_and() { expresion_result left = compile_comparison_2(), right, res ; for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER && ( token.code == identifier_band || token.code == identifier_bandoffset ) ) /* "BAND" or "&" */ { if ( left.lvalue ) codeblock_add( code, mntype( left.type, 0 ) | MN_PTR, 0 ) ; right = compile_comparison_2() ; if ( right.lvalue ) codeblock_add( code, mntype( right.type, 0 ) | MN_PTR, 0 ) ; check_integer_types( &left, &right ) ; codeblock_add( code, MN_BAND, 0 ) ; res.lvalue = 0 ; res.asignation = 0 ; res.call = 0 ; res.constant = ( right.constant && left.constant ) ; res.value = ( left.value & right.value ) ; res.type = left.type /* typedef_new( TYPE_INT )*/ ; left = res ; continue ; } token_back() ; break; } return left ; } expresion_result compile_bitwise_xor() { expresion_result left = compile_bitwise_and(), right, res ; for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_bxor ) /* "BXOR" or "^" */ { if ( left.lvalue ) codeblock_add( code, mntype( left.type, 0 ) | MN_PTR, 0 ) ; right = compile_bitwise_and() ; if ( right.lvalue ) codeblock_add( code, mntype( right.type, 0 ) | MN_PTR, 0 ) ; check_integer_types( &left, &right ) ; codeblock_add( code, MN_BXOR, 0 ) ; res.lvalue = 0 ; res.asignation = 0 ; res.call = 0 ; res.constant = ( right.constant && left.constant ) ; res.value = ( left.value ^ right.value ) ; res.type = left.type /* typedef_new( TYPE_INT )*/ ; left = res ; continue ; } token_back() ; break; } return left ; } /* Paso 3 */ expresion_result compile_bitwise_or() { expresion_result left = compile_bitwise_xor(), right, res ; for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_bor ) /* "BOR" or "|" */ { if ( left.lvalue ) codeblock_add( code, mntype( left.type, 0 ) | MN_PTR, 0 ) ; right = compile_bitwise_xor() ; if ( right.lvalue ) codeblock_add( code, mntype( right.type, 0 ) | MN_PTR, 0 ) ; check_integer_types( &left, &right ) ; codeblock_add( code, MN_BOR, 0 ) ; res.lvalue = 0 ; res.asignation = 0 ; res.call = 0 ; res.constant = ( right.constant && left.constant ) ; res.value = ( left.value | right.value ) ; res.type = left.type /*typedef_new( TYPE_INT )*/ ; left = res ; continue ; } token_back() ; break; } return left ; } /* Paso 2 */ expresion_result compile_logical_and() { expresion_result left = compile_bitwise_or(), right, res ; int et1; for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_and ) /* "AND" or "&&" */ { et1 = codeblock_label_add( code, -1 ); if ( left.lvalue ) codeblock_add( code, MN_PTR | mntype( left.type, 0 ), 0 ) ; check_integer_type( &left ) ; codeblock_add( code, MN_JTFALSE, et1 ) ; right = compile_bitwise_or() ; if ( right.lvalue ) codeblock_add( code, MN_PTR | mntype( right.type, 0 ), 0 ) ; check_integer_type( &right ) ; codeblock_add( code, MN_AND, 0 ) ; codeblock_label_set( code, et1, code->current ) ; res.lvalue = 0 ; res.asignation = 0 ; res.call = 0 ; res.constant = ( right.constant && left.constant ) ; res.value = ( left.value && right.value ) ; res.type = typedef_new( TYPE_INT ) ; left = res ; continue ; } token_back() ; break; } return left ; } /* Paso 2 */ expresion_result compile_logical_xor() { expresion_result left = compile_logical_and(), right, res ; for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_xor ) /* "XOR" or "^^" */ { if ( left.lvalue ) codeblock_add( code, mntype( left.type, 0 ) | MN_PTR, 0 ) ; right = compile_logical_and() ; if ( right.lvalue ) codeblock_add( code, mntype( right.type, 0 ) | MN_PTR, 0 ) ; check_integer_types( &left, &right ) ; codeblock_add( code, MN_XOR, 0 ) ; res.lvalue = 0 ; res.asignation = 0 ; res.call = 0 ; res.constant = ( right.constant && left.constant ) ; res.value = (( left.value != 0 ) ^( right.value != 0 ) ) ; res.type = typedef_new( TYPE_INT ) ; left = res ; continue ; } token_back() ; break; } return left ; } /* Paso 2 */ expresion_result compile_logical_or() { expresion_result left = compile_logical_xor(), right, res ; int et1; int et2; for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_or ) /* "OR" or "||" */ { et1 = codeblock_label_add( code, -1 ); et2 = codeblock_label_add( code, -1 ); if ( left.lvalue ) codeblock_add( code, mntype( left.type, 0 ) | MN_PTR, 0 ) ; check_integer_type( &left ) ; codeblock_add( code, MN_JTFALSE, et1 ) ; codeblock_add( code, MN_POP, 0 ); codeblock_add( code, MN_PUSH, 1 ); codeblock_add( code, MN_JUMP, et2 ); codeblock_label_set( code, et1, code->current ) ; right = compile_logical_xor() ; if ( right.lvalue ) codeblock_add( code, mntype( right.type, 0 ) | MN_PTR, 0 ) ; check_integer_type( &right ) ; codeblock_add( code, MN_OR, 0 ) ; codeblock_label_set( code, et2, code->current ) ; res.lvalue = 0 ; res.asignation = 0 ; res.call = 0 ; res.constant = ( right.constant && left.constant ) ; res.value = ( left.value || right.value ) ; res.type = typedef_new( TYPE_INT ) ; left = res ; continue; } token_back() ; break ; } return left ; } /* Paso 1 */ expresion_result compile_ternarycond() { CODEBLOCK_POS pos ; if ( code ) pos = codeblock_pos( code ); expresion_result base = compile_logical_or(), right, res ; int et1, et2 ; token_next() ; /* Operador EXPR ? TRUE : FALSE */ if ( token.type == IDENTIFIER && token.code == identifier_question ) /* "?" */ { if ( base.lvalue ) codeblock_add( code, mntype( base.type, 0 ) | MN_PTR, 0 ) ; if ( base.constant ) { codeblock_setpos( code, pos ); if ( ( typedef_is_integer( base.type ) && base.value ) || ( typedef_is_float( base.type ) && base.fvalue ) ) { right = compile_expresion( 0, 0, 0, TYPE_UNDEFINED ); if ( code ) pos = codeblock_pos( code ); token_next(); if ( token.type != IDENTIFIER || token.code != identifier_colon ) compile_error( MSG_EXPECTED, ":" ); /* ":" */ res = compile_expresion( 0, 0, 0, right.type.chunk[0].type ); codeblock_setpos( code, pos ); } else { if ( code ) pos = codeblock_pos( code ); right = compile_expresion( 0, 0, 0, TYPE_UNDEFINED ); codeblock_setpos( code, pos ); token_next(); if ( token.type != IDENTIFIER || token.code != identifier_colon ) compile_error( MSG_EXPECTED, ":" ); /* ":" */ res = compile_expresion( 0, 0, 0, right.type.chunk[0].type ); } } else { et1 = codeblock_label_add( code, -1 ); et2 = codeblock_label_add( code, -1 ); codeblock_add( code, MN_JFALSE, et1 ); right = compile_expresion( 0, 0, 0, TYPE_UNDEFINED ); codeblock_add( code, MN_JUMP, et2 ); codeblock_label_set( code, et1, code->current ); token_next(); if ( token.type != IDENTIFIER || token.code != identifier_colon ) compile_error( MSG_EXPECTED, ":" ); /* ":" */ res = compile_expresion( 0, 0, 0, right.type.chunk[0].type ); codeblock_label_set( code, et2, code->current ); } if ( base.constant && res.constant && right.constant ) { if ( typedef_is_integer( base.type ) ) { return base.value ? right : res; } else if ( typedef_is_float( base.type ) ) { return base.fvalue ? right : res; } } res.constant = 0; res.lvalue = ( right.lvalue && res.lvalue ); return res; } token_back() ; return base; } /* Paso 1 */ expresion_result compile_subexpresion() { expresion_result base = compile_ternarycond(), right, res ; int op, type ; token_next() ; if ( token.type == IDENTIFIER ) { /* Asignaciones */ if ( token.code == identifier_equal ) /* "=" */ { if ( typedef_is_array( base.type ) && base.lvalue && base.type.chunk[1].type == TYPE_CHAR ) /* Asignaciones a cadenas de ancho fijo */ { right = compile_expresion( 0, 0, 0, TYPE_UNDEFINED ) ; if ( typedef_is_integer( right.type ) ) { compile_warning( 1, "implicit conversion (INTEGER to CHAR[])" ); codeblock_add( code, MN_INT2STR | mntype( right.type, 0 ), 0 ) ; } else if ( typedef_is_float( right.type ) ) { compile_warning( 1, "implicit conversion (FLOAT to CHAR[])" ); codeblock_add( code, MN_FLOAT2STR, 0 ) ; } else if ( !typedef_is_string( right.type ) ) { compile_error( MSG_INCOMP_TYPE ) ; } codeblock_add( code, MN_STR2A, base.type.chunk[0].count - 1 ) ; right.asignation = 1 ; return right ; } if ( typedef_is_pointer( base.type ) ) /* Asignaciones a punteros */ { TYPEDEF pointer_type ; pointer_type = typedef_reduce( base.type ) ; if ( !base.lvalue ) compile_error( MSG_VARIABLE_REQUIRED ) ; right = compile_expresion( 0, 0, 0, TYPE_UNDEFINED ) ; if (( typedef_base( right.type ) == TYPE_DWORD || typedef_base( right.type ) == TYPE_INT ) && right.constant && right.value == 0 ) { right.type = base.type ; } if ( typedef_base( right.type ) == TYPE_FLOAT ) { compile_warning( 1, "implicit conversion (FLOAT to POINTER)" ); codeblock_add( code, MN_FLOAT2INT, 0 ); right.type = base.type; } /* Un puntero "void" puede asignarse a otro cualquiera */ right.type = typedef_pointer( pointer_type ) ; if ( typedef_base( typedef_reduce( right.type ) ) != typedef_base( pointer_type ) ) compile_error( MSG_TYPES_NOT_THE_SAME ) ; codeblock_add( code, MN_DWORD | MN_LET, 0 ) ; res.lvalue = 1 ; res.asignation = 1 ; res.call = 0 ; res.constant = 0 ; res.value = 0 ; res.type = base.type ; return res ; } if ( typedef_base( base.type ) == TYPE_CHAR ) /* Asignaciones a chars */ { if ( !base.lvalue ) compile_error( MSG_VARIABLE_REQUIRED ) ; right = compile_expresion( 0, 0, 0, TYPE_UNDEFINED ) ; if ( typedef_is_string( right.type ) ) { compile_warning( 1, "implicit conversion (STRING to CHAR)" ); codeblock_add( code, MN_STR2CHR, 0 ) ; } else if ( typedef_base( right.type ) == TYPE_FLOAT ) { compile_warning( 1, "implicit conversion (FLOAT to CHAR)" ); codeblock_add( code, MN_FLOAT2INT, 0 ) ; } else if ( !typedef_is_numeric( right.type ) ) { compile_error( MSG_INCOMP_TYPE ) ; } codeblock_add( code, MN_LET | MN_BYTE, 0 ) ; res.lvalue = 1 ; res.asignation = 1 ; res.call = 0 ; res.constant = 0 ; res.value = 0 ; res.type = typedef_new( TYPE_CHAR ) ; return res ; } if ( typedef_is_string( base.type ) ) /* Asignaciones a cadenas */ { if ( !base.lvalue ) compile_error( MSG_VARIABLE_REQUIRED ) ; right = compile_expresion( 0, 0, 0, TYPE_UNDEFINED ) ; if ( typedef_base( right.type ) == TYPE_CHAR ) { compile_warning( 1, "implicit conversion (CHAR to STRING)" ); codeblock_add( code, MN_CHR2STR, 0 ) ; } else if ( typedef_is_integer( right.type ) ) { compile_warning( 1, "implicit conversion (INTEGER to STRING)" ); codeblock_add( code, MN_INT2STR | mntype( right.type, 0 ), 0 ) ; } else if ( typedef_is_float( right.type ) ) { compile_warning( 1, "implicit conversion (FLOAT to STRING)" ); codeblock_add( code, MN_FLOAT2STR, 0 ) ; } else if ( typedef_is_pointer( right.type ) ) { compile_warning( 1, "implicit conversion (POINTER to STRING)" ); codeblock_add( code, MN_POINTER2STR, 0 ) ; } else if ( !typedef_is_string( right.type ) ) { compile_error( MSG_INCOMP_TYPE ) ; } codeblock_add( code, MN_STRING | MN_LET, 0 ) ; res.lvalue = 1 ; res.asignation = 1 ; res.call = 0 ; res.constant = 0 ; res.value = 0 ; res.type = typedef_new( TYPE_STRING ) ; return res ; } } /* Puntero += entero */ if ( typedef_is_pointer( base.type ) && ( token.code == identifier_plusequal || token.code == identifier_minusequal ) ) /* "+=" or "-=" */ { TYPEDEF pointer_type ; op = ( token.code == identifier_plusequal ? MN_VARADD : MN_VARSUB ) ; pointer_type = typedef_reduce( base.type ) ; if ( !base.lvalue ) compile_error( MSG_VARIABLE_REQUIRED ) ; right = compile_expresion( 0, 0, 0, TYPE_UNDEFINED ) ; if ( !typedef_is_integer( right.type ) ) compile_error( MSG_INCOMP_TYPES ) ; if ( typedef_size( pointer_type ) > 1 ) codeblock_add( code, MN_ARRAY, ( op == MN_VARADD ? 1 : -1 ) * typedef_size( pointer_type ) ) ; else codeblock_add( code, op, 0 ) ; res.lvalue = 1 ; res.asignation = 1 ; res.call = 0 ; res.constant = 0 ; res.value = 0 ; res.type = typedef_new( TYPE_STRING ) ; return res ; } /* Increment and assign */ if ( token.code == identifier_plusequal ) /* "+=" */ { if ( typedef_is_array( base.type ) && base.lvalue && base.type.chunk[1].type == TYPE_CHAR ) /* Cadena += cadena fija */ { right = compile_expresion( 0, 0, 0, TYPE_UNDEFINED ) ; if ( typedef_is_integer( right.type ) ) { compile_warning( 1, "implicit conversion (INTEGER to CHAR[])" ); codeblock_add( code, MN_INT2STR | mntype( right.type, 0 ), 0 ) ; } else if ( typedef_is_float( right.type ) ) { compile_warning( 1, "implicit conversion (FLOAT to CHAR[])" ); codeblock_add( code, MN_FLOAT2STR, 0 ) ; } else if ( typedef_base( right.type ) == TYPE_CHAR ) { compile_warning( 1, "implicit conversion (CHAR to CHAR[])" ); codeblock_add( code, MN_CHR2STR, 0 ); } else if ( !typedef_is_string( right.type ) ) { compile_error( MSG_INCOMP_TYPE ) ; } codeblock_add( code, MN_STRACAT, base.type.chunk[0].count ) ; right.asignation = 1 ; return right ; } if ( typedef_is_string( base.type ) ) { if ( !base.lvalue ) compile_error( MSG_VARIABLE_REQUIRED ) ; right = compile_expresion( 0, 0, 0, TYPE_UNDEFINED ) ; if ( typedef_is_integer( right.type ) ) { compile_warning( 1, "implicit conversion (INTEGER to STRING)" ); codeblock_add( code, MN_INT2STR | mntype( right.type, 0 ), 0 ) ; } else if ( typedef_is_float( right.type ) ) { compile_warning( 1, "implicit conversion (FLOAT to STRING)" ); codeblock_add( code, MN_FLOAT2STR, 0 ) ; } else if ( typedef_base( right.type ) == TYPE_CHAR ) { compile_warning( 1, "implicit conversion (CHAR to STRING)" ); codeblock_add( code, MN_CHR2STR, 0 ); } else if ( !typedef_is_string( right.type ) ) { compile_error( MSG_INCOMP_TYPE ) ; } codeblock_add( code, MN_STRING | MN_VARADD, 0 ) ; res.lvalue = 1 ; res.asignation = 1 ; res.call = 0 ; res.constant = 0 ; res.value = 0 ; res.type = typedef_new( TYPE_STRING ) ; return res ; } } /* Otra posible combinación(for not string/char[]/pointers) */ if ( token.code == identifier_plusequal /* "+=" */ || token.code == identifier_minusequal /* "-=" */ || token.code == identifier_multequal /* "*=" */ || token.code == identifier_divequal /* "/=" */ || token.code == identifier_modequal /* "%=" */ || token.code == identifier_andequal /* "&=" */ || token.code == identifier_xorequal /* "^=" */ || token.code == identifier_orequal /* "|=" */ || token.code == identifier_rolequal /* "<<=" */ || token.code == identifier_rorequal /* ">>=" */ || token.code == identifier_equal ) /* "=" */ { SYSPROC * proc_copy = sysproc_get( identifier_search_or_add( "#COPY#" ) ); SYSPROC * proc_memcopy = sysproc_get( identifier_search_or_add( "#MEMCOPY#" ) ); SYSPROC * proc_copy_string_array = sysproc_get( identifier_search_or_add( "#COPYSTRA#" ) ); int size, nvar; op = token.code ; /* Assignation to struct: struct copy */ if ( typedef_is_struct( base.type ) ) { if ( token.code != identifier_equal ) compile_error( MSG_EXPECTED, "=" ) ; /* "=" */ right = compile_expresion( 0, 0, 0, TYPE_UNDEFINED ); while ( typedef_is_array( right.type ) ) right.type = typedef_reduce( right.type ); if ( typedef_base( right.type ) != TYPE_POINTER ) compile_error( MSG_STRUCT_REQUIRED ); if ( !typedef_is_struct( typedef_reduce( right.type ) ) ) { compile_error( MSG_STRUCT_REQUIRED ); } else if ( right.type.varspace != base.type.varspace ) { compile_error( MSG_TYPES_NOT_THE_SAME ); } else { /* * Struct copy operator */ while ( typedef_is_pointer( base.type ) ) { codeblock_add( code, MN_PTR, 0 ); res.type = typedef_reduce( base.type ); } if ( typedef_base( base.type ) != TYPE_STRUCT ) compile_error( MSG_STRUCT_REQUIRED ); else { size = right.type.varspace->count * sizeof( DCB_TYPEDEF ); if ( right.type.varspace->stringvar_count > 0 ) { /* True struct copy version */ segment_alloc( globaldata, size ); codeblock_add( code, MN_GLOBAL, globaldata->current ) ; for ( nvar = 0 ; nvar < right.type.varspace->count ; nvar++ ) { DCB_TYPEDEF type; dcb_settype( &type, &right.type.varspace->vars[nvar].type ); memcpy(( uint8_t* )globaldata->bytes + globaldata->current, &type, sizeof( DCB_TYPEDEF ) ); globaldata->current += sizeof( DCB_TYPEDEF ); } codeblock_add( code, MN_PUSH, right.type.varspace->count ); codeblock_add( code, MN_PUSH, right.count ? right.count : 1 ); codeblock_add( code, MN_SYSCALL, proc_copy->code ); } else { /* Optimized fast memcopy version */ codeblock_add( code, MN_PUSH, right.type.varspace->size*( right.count ? right.count : 1 ) ); codeblock_add( code, MN_SYSCALL, proc_memcopy->code ); } } base.type = right.type; base.constant = 0; base.lvalue = 0; base.call = 1; } return base; } if ( op != identifier_equal && typedef_is_array( base.type ) ) compile_error( MSG_EXPECTED, "[" ) ; if ( !base.lvalue ) compile_error( MSG_VARIABLE_REQUIRED ) ; right = compile_expresion( 0, 0, 0, typedef_base( base.type ) ) ; /* Array copy */ if ( op == identifier_equal && typedef_is_array( base.type ) && typedef_is_array( right.type ) ) { int size; if ( !typedef_is_equal( base.type, right.type ) ) compile_error( MSG_TYPES_NOT_THE_SAME ); size = typedef_size( base.type ); while ( typedef_is_array( base.type ) ) { base.type = typedef_reduce( base.type ) ; right.type = typedef_reduce( right.type ) ; } /* Optimized fast memcopy version */ if ( typedef_is_string( base.type ) ) { codeblock_add( code, MN_PUSH, size / sizeof( int ) ); codeblock_add( code, MN_SYSCALL, proc_copy_string_array->code ); } else { codeblock_add( code, MN_PUSH, size ); codeblock_add( code, MN_SYSCALL, proc_memcopy->code ); } base.type = right.type; base.constant = 0; base.lvalue = 0; base.call = 1; return base; } if ( right.lvalue ) codeblock_add( code, mntype( right.type, 0 ) | MN_PTR, 0 ) ; type = check_numeric_types( &base, &right ) ; if ( op == identifier_plusequal ) /* "+=" */ codeblock_add( code, type | MN_VARADD, 0 ) ; else if ( op == identifier_minusequal ) /* "-=" */ codeblock_add( code, type | MN_VARSUB, 0 ) ; else if ( op == identifier_multequal ) /* "*=" */ codeblock_add( code, type | MN_VARMUL, 0 ) ; else if ( op == identifier_divequal ) /* "/=" */ codeblock_add( code, type | MN_VARDIV, 0 ) ; else if ( op == identifier_modequal ) /* "%=" */ codeblock_add( code, type | MN_VARMOD, 0 ) ; else if ( op == identifier_orequal ) /* "|=" */ codeblock_add( code, type | MN_VAROR, 0 ) ; else if ( op == identifier_andequal ) /* "&=" */ codeblock_add( code, type | MN_VARAND, 0 ) ; else if ( op == identifier_xorequal ) /* "^=" */ codeblock_add( code, type | MN_VARXOR, 0 ) ; else if ( op == identifier_rorequal ) /* ">>=" */ codeblock_add( code, type | MN_VARROR, 0 ) ; else if ( op == identifier_rolequal ) /* "<<=" */ codeblock_add( code, type | MN_VARROL, 0 ) ; else if ( op == identifier_equal ) /* "=" */ codeblock_add( code, type | MN_LET, 0 ) ; res.lvalue = 1 ; res.asignation = 1 ; res.call = 0 ; res.constant = 0 ; res.value = 0 ; res.type = right.type ; return res ; } else { token_back() ; } } else { token_back() ; } return base ; } expresion_result compile_expresion( int need_constant, int need_lvalue, int discart_code, BASETYPE t ) { expresion_result res ; CODEBLOCK_POS pos ; if ( code ) pos = codeblock_pos( code ); res = compile_subexpresion() ; /* Interpreta una estructura tal cual como un puntero a la misma */ if ( res.lvalue && typedef_base( res.type ) == TYPE_STRUCT && !need_lvalue ) { res.type = typedef_pointer( res.type ) ; res.lvalue = 0 ; res.constant = 0 ; } /* Interpretar arrays de byte como cadenas */ if ( typedef_base( res.type ) == TYPE_ARRAY && res.type.chunk[1].type == TYPE_CHAR && res.lvalue && !need_lvalue ) { codeblock_add( code, MN_A2STR, 0 ) ; res.type = typedef_new( TYPE_STRING ) ; /* Array 2 String */ res.lvalue = 0 ; } /* Quita los lvalue */ if ( !need_lvalue && res.lvalue && !typedef_is_array( res.type ) ) { res.lvalue = 0 ; codeblock_add( code, mntype( res.type, 0 ) | MN_PTR, 0 ) ; } /* Conversiones de tipo */ if ( t != TYPE_UNDEFINED ) res = convert_result_type( res, t ) ; /* Optimización de datos constantes */ if ( res.constant ) { if ( code ) codeblock_setpos( code, pos ); if ( typedef_base( res.type ) == TYPE_FLOAT ) codeblock_add( code, MN_PUSH, *( int * )&res.fvalue ) ; else if ( typedef_base( res.type ) == TYPE_STRING ) codeblock_add( code, MN_PUSH | MN_STRING, res.value ) ; else codeblock_add( code, MN_PUSH, res.value ) ; } if ( need_lvalue && !res.lvalue ) compile_error( MSG_VARIABLE_REQUIRED ) ; if ( need_constant && !res.constant ) compile_error( MSG_CONSTANT_EXP ) ; if ( discart_code && code ) codeblock_setpos( code, pos ); return res ; } /* * FUNCTION : convert_result_type * * Given an expresion result in the current context, convert it * if possible to the basic type given(and emit the necessary code) * * PARAMS: * res Result of expression at current context * t Basic type required * * RETURN VALUE: * The converted type result */ expresion_result convert_result_type( expresion_result res, BASETYPE t ) { /* Conversiones de tipo */ if ( t < 9 && typedef_is_integer( res.type ) ) { res.type = typedef_new( t ); } else if ( typedef_base( res.type ) == TYPE_POINTER && t == TYPE_STRING ) { codeblock_add( code, MN_POINTER2STR, 0 ) ; res.type = typedef_new( t ) ; /* Pointer 2 String */ } else if ( typedef_is_integer( res.type ) /*&& res.constant && res.value == 0*/ && t == TYPE_POINTER ) { res.type = typedef_new( t ) ; /* pointer */ } else if ( typedef_base( res.type ) == TYPE_POINTER && t < 8 ) { res.type = typedef_new( t ) ; /* Pointer 2 Int */ } else if ( typedef_base( res.type ) == TYPE_FLOAT && t < 8 ) { codeblock_add( code, MN_FLOAT2INT, 0 ) ; res.type = typedef_new( t ) ; res.value = ( int )res.fvalue ; } else if ( t == TYPE_FLOAT && typedef_is_integer( res.type ) ) { codeblock_add( code, MN_INT2FLOAT, 0 ) ; res.type = typedef_new( TYPE_FLOAT ) ; res.fvalue = ( float )res.value ; } else if (( t == TYPE_BYTE || t == TYPE_WORD || t == TYPE_DWORD ) && typedef_is_integer( res.type ) ) { res.type = typedef_new( t ) ; } else if ( t == TYPE_STRING && typedef_is_integer( res.type ) ) { codeblock_add( code, MN_INT2STR | mntype( res.type, 0 ), 0 ) ; if ( res.constant ) { char buffer[32] ; switch ( res.type.chunk[0].type ) { case TYPE_INT: sprintf( buffer, "%d", res.value ) ; break; case TYPE_WORD: sprintf( buffer, "%d", ( uint16_t )res.value ) ; break; case TYPE_BYTE: sprintf( buffer, "%d", ( uint8_t )res.value ) ; break; case TYPE_SHORT: sprintf( buffer, "%d", ( int16_t )res.value ) ; break; case TYPE_SBYTE: sprintf( buffer, "%d", ( int8_t )res.value ) ; break; case TYPE_DWORD: sprintf( buffer, "%u", ( int32_t )res.value ) ; break; case TYPE_UNDEFINED : case TYPE_CHAR : case TYPE_FLOAT : case TYPE_STRING : case TYPE_ARRAY : case TYPE_STRUCT : case TYPE_POINTER : break; } res.value = string_new( buffer ) ; } res.type = typedef_new( t ) ; } else if ( t == TYPE_STRING && typedef_base( res.type ) == TYPE_CHAR ) { codeblock_add( code, MN_CHR2STR, 0 ) ; if ( res.constant ) { char buffer[2] ; buffer[0] = res.value; buffer[1] = 0; res.value = string_new( buffer ) ; } res.type = typedef_new( t ) ; } else if ( t != TYPE_UNDEFINED && typedef_base( res.type ) != t ) { switch ( t ) { case TYPE_CHAR: /* Allow string-to-char conversions */ if ( typedef_is_string( res.type ) ) { codeblock_add( code, MN_STR2CHR, 0 ) ; if ( res.constant == 1 ) res.value = ( unsigned char ) * ( string_get( res.value ) ); } else compile_error( MSG_INTEGER_REQUIRED ) ; break ; case TYPE_DWORD: case TYPE_INT: case TYPE_WORD: case TYPE_SHORT: case TYPE_BYTE: case TYPE_SBYTE: if ( typedef_is_array( res.type ) && res.lvalue && res.type.chunk[1].type == TYPE_CHAR ) { codeblock_add( code, MN_A2STR, 0 ) ; codeblock_add( code, MN_STR2INT, 0 ) ; res.lvalue = 0 ; res.constant = 0; } else if ( typedef_is_string( res.type ) ) { codeblock_add( code, MN_STR2INT, 0 ) ; if ( res.constant == 1 ) res.value = atoi( string_get( res.value ) ); } else if ( typedef_base( res.type ) == TYPE_CHAR ) { res.type = typedef_new( t ); } else compile_error( MSG_INTEGER_REQUIRED ) ; break ; case TYPE_FLOAT: if ( typedef_is_string( res.type ) ) { codeblock_add( code, MN_STR2FLOAT, 0 ) ; if ( res.constant == 1 ) res.fvalue = ( float )atof( string_get( res.value ) ); } else compile_error( MSG_NUMBER_REQUIRED ) ; break ; case TYPE_STRING: if ( typedef_is_array( res.type ) && res.lvalue && res.type.chunk[1].type == TYPE_CHAR ) { codeblock_add( code, MN_A2STR, 0 ) ; res.lvalue = 0 ; } else if ( typedef_is_integer( res.type ) ) { codeblock_add( code, MN_INT2STR | mntype( res.type, 0 ), 0 ) ; if ( res.constant ) { char buffer[32] ; sprintf( buffer, "%d", res.value ) ; res.value = string_new( buffer ) ; } } else if ( typedef_is_float( res.type ) ) { codeblock_add( code, MN_FLOAT2STR, 0 ) ; if ( res.constant ) { char buffer[32] ; sprintf( buffer, "%g", res.fvalue ) ; res.value = string_new( buffer ) ; } } else compile_error( MSG_STRING_EXP ) ; break ; default: compile_error( MSG_INCOMP_TYPE ) ; } res.type = typedef_new( t ) ; } return res ; } int compile_sentence_end() { token_next() ; if ( token.type == NOTOKEN ) return 1; if ( token.type == IDENTIFIER && token.code == identifier_semicolon ) return 0 ; /* ";" */ /* if (token.type == IDENTIFIER && token.code == identifier_end) { token_back() ; return 1 ; } */ compile_error( MSG_EXPECTED, ";" ) ; return 0; } extern int dcb_options ; void basetype_describe( char * buffer, BASETYPE t ) { switch ( t ) { case TYPE_INT: sprintf( buffer, "INT" ) ; return ; case TYPE_DWORD: sprintf( buffer, "DWORD" ) ; return ; case TYPE_SHORT: sprintf( buffer, "SHORT" ) ; return ; case TYPE_WORD: sprintf( buffer, "WORD" ) ; return ; case TYPE_BYTE: sprintf( buffer, "BYTE" ) ; return ; case TYPE_CHAR: sprintf( buffer, "CHAR" ) ; return ; case TYPE_SBYTE: sprintf( buffer, "SIGNED BYTE" ) ; return ; case TYPE_STRING: sprintf( buffer, "STRING" ) ; return ; case TYPE_FLOAT: sprintf( buffer, "FLOAT" ) ; return ; case TYPE_STRUCT: sprintf( buffer, "STRUCT" ) ; case TYPE_ARRAY: sprintf( buffer, "ARRAY" ) ; return ; case TYPE_POINTER: sprintf( buffer, "POINTER" ) ; return ; case TYPE_UNDEFINED: default: sprintf( buffer, "" ) ; return ; } } void compile_block( PROCDEF * p ) { int loop, last_loop, et1, et2 ; expresion_result res, from, to ; int codelabel; proc = p ; code = &p->code ; for ( ;; ) { token_next() ; if ( token.type == NOTOKEN ) break ; if ( token.type == IDENTIFIER ) { if ( token.code == identifier_end || /* "END" */ token.code == identifier_until || /* "UNTIL" */ token.code == identifier_else || /* "ELSE" */ token.code == identifier_elseif ) /* "ELSEIF" */ break ; if ( token.code == identifier_semicolon ) /* ";" */ continue ; if ( token.code == identifier_colon ) /* ":" */ continue ; if ( token.code == identifier_continue ) /* "CONTINUE" */ { if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; if ( !code->loop_active ) compile_error( MSG_NO_LOOP ) ; codeblock_add( code, MN_REPEAT, code->loop_active ) ; compile_sentence_end() ; continue ; } if ( token.code == identifier_break ) /* "BREAK" */ { if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; if ( !code->loop_active ) compile_error( MSG_NO_LOOP ) ; codeblock_add( code, MN_BREAK, code->loop_active ) ; compile_sentence_end() ; continue ; } if ( token.code == identifier_frame || token.code == identifier_yield ) /* "FRAME or YIELD " */ { if ( proc->type != TYPE_INT && proc->type != TYPE_DWORD ) if ( !( proc->flags & PROC_FUNCTION ) ) compile_error( MSG_FRAME_REQUIRES_INT ); if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_semicolon ) /* ";" */ { token_back() ; compile_expresion( 0, 0, 0, TYPE_DWORD ) ; codeblock_add( code, MN_FRAME, 0 ) ; compile_sentence_end() ; } else { codeblock_add( code, MN_PUSH, 100 ) ; codeblock_add( code, MN_FRAME, 0 ) ; } proc->flags |= PROC_USES_FRAME; continue ; } if ( token.code == identifier_debug ) /* "DEBUG" */ { if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; codeblock_add( code, MN_DEBUG, 0 ) ; compile_sentence_end() ; continue ; } if ( token.code == identifier_return ) /* "RETURN" */ { if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_semicolon ) /* ";" */ { token_back() ; compile_expresion( 0, 0, 0, p->type ) ; codeblock_add( code, MN_RETURN, 0 ) ; compile_sentence_end() ; } else { codeblock_add( code, MN_END, 0 ) ; } continue ; } if ( token.code == identifier_clone ) /* "CLONE" */ { if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; et1 = codeblock_label_add( code, -1 ) ; codeblock_add( code, MN_CLONE, et1 ) ; compile_block( p ) ; codeblock_label_set( code, et1, code->current ) ; proc->flags |= PROC_USES_FRAME; continue ; } if ( token.code == identifier_if ) /* "IF" */ { /* Label at the end of a IF/ELSEIF/ELSEIF/ELSE chain */ int end_of_chain = -1; if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; for ( ;; ) { token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_leftp ) /* "(" */ { token_back() ; compile_expresion( 0, 0, 0, TYPE_DWORD ); token_next() ; if ( token.type != IDENTIFIER || ( token.code != identifier_semicolon && token.code != identifier_colon ) ) /* ";" or ":" */ compile_error( MSG_EXPECTED, ";" MSG_OR ":" ) ; } else { compile_expresion( 0, 0, 0, TYPE_DWORD ); token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightp ) /* ")" */ compile_error( MSG_EXPECTED, ")" ) ; } et1 = codeblock_label_add( code, -1 ) ; codeblock_add( code, MN_JFALSE, et1 ) ; compile_block( p ) ; if ( token.type == IDENTIFIER && token.code == identifier_else ) /* "ELSE" */ { et2 = codeblock_label_add( code, -1 ) ; codeblock_add( code, MN_JUMP, et2 ) ; codeblock_label_set( code, et1, code->current ) ; compile_block( p ) ; codeblock_label_set( code, et2, code->current ) ; break; } else if ( token.type == IDENTIFIER && token.code == identifier_elseif ) /* "ELSEIF" */ { if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; if ( end_of_chain == -1 ) end_of_chain = codeblock_label_add( code, -1 ) ; codeblock_add( code, MN_JUMP, end_of_chain ); codeblock_label_set( code, et1, code->current ) ; continue; } else { codeblock_label_set( code, et1, code->current ) ; break; } } if ( end_of_chain != -1 ) codeblock_label_set( code, end_of_chain, code->current ) ; continue ; } if ( token.code == identifier_for ) /* "FOR" */ { if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; loop = codeblock_loop_add( code ) ; et1 = codeblock_label_add( code, -1 ) ; et2 = codeblock_label_add( code, -1 ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_leftp ) /* "(" */ compile_error( MSG_EXPECTED, "(" ) ; /* Inicializadores */ token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_semicolon ) /* ";" */ { token_back() ; do { compile_expresion( 0, 0, 0, TYPE_DWORD ) ; codeblock_add( code, MN_POP, 0 ) ; token_next() ; } while ( token.type == IDENTIFIER && token.code == identifier_comma ) ; /* "," */ } if ( token.type != IDENTIFIER || token.code != identifier_semicolon ) /* ";" */ compile_error( MSG_EXPECTED, ";" ) ; codeblock_label_set( code, et1, code->current ) ; /* Condiciones */ token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_semicolon ) /* ";" */ { if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; token_back() ; do { compile_expresion( 0, 0, 0, TYPE_DWORD ) ; codeblock_add( code, MN_BRFALSE, loop ) ; token_next() ; } while ( token.type == IDENTIFIER && token.code == identifier_comma ) ; /* "," */ } if ( token.type != IDENTIFIER || token.code != identifier_semicolon ) /* ";" */ compile_error( MSG_EXPECTED, ";" ) ; codeblock_add( code, MN_JUMP, et2 ) ; /* Incrementos */ codeblock_loop_start( code, loop, code->current ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightp ) /* ")" */ { if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; token_back() ; do { compile_expresion( 0, 0, 0, TYPE_DWORD ) ; codeblock_add( code, MN_POP, 0 ) ; token_next() ; } while ( token.type == IDENTIFIER && token.code == identifier_comma ) ; /* "," */ } if ( token.type != IDENTIFIER || token.code != identifier_rightp ) /* ")" */ compile_error( MSG_EXPECTED, ")" ) ; codeblock_add( code, MN_JUMP, et1 ) ; /* Bloque */ codeblock_label_set( code, et2, code->current ) ; last_loop = code->loop_active ; code->loop_active = loop ; compile_block( p ) ; code->loop_active = last_loop ; if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; codeblock_add( code, MN_REPEAT, loop ) ; codeblock_loop_end( code, loop, code->current ) ; continue ; } if ( token.code == identifier_switch ) /* "SWITCH" */ { BASETYPE switch_type = TYPE_UNDEFINED; expresion_result switch_exp ; if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_leftp ) /* "(" */ compile_error( MSG_EXPECTED, "(" ) ; switch_exp = compile_expresion( 0, 0, 0, TYPE_UNDEFINED ) ; switch_type = typedef_base( switch_exp.type ); if ( switch_type == TYPE_ARRAY && switch_exp.type.chunk[0].type == TYPE_CHAR ) { codeblock_add( code, MN_A2STR, 0 ) ; switch_type = TYPE_STRING; } else if ( typedef_is_integer( switch_exp.type ) ) { switch_exp = convert_result_type( switch_exp, TYPE_INT ); switch_type = TYPE_INT; } token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightp ) /* ")" */ compile_error( MSG_EXPECTED, ")" ); token_next() ; if ( token.type != IDENTIFIER || ( token.code != identifier_semicolon && token.code != identifier_colon ) ) /* ";" or ":" */ token_back() ; if ( switch_type == TYPE_STRING ) codeblock_add( code, MN_SWITCH | MN_STRING, 0 ) ; else codeblock_add( code, MN_SWITCH, 0 ) ; et1 = codeblock_label_add( code, -1 ) ; for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_case ) /* "CASE" */ { if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; for ( ;; ) { token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_colon ) /* ":" */ break ; if ( token.type == IDENTIFIER && token.code == identifier_comma ) /* "," */ continue ; token_back() ; compile_expresion( 0, 0, 0, switch_type ) ; token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_twopoints ) /* ".." */ { compile_expresion( 0, 0, 0, switch_type ) ; if ( switch_type == TYPE_STRING ) { codeblock_add( code, MN_CASE_R | MN_STRING, 0 ) ; } else { codeblock_add( code, MN_CASE_R, 0 ) ; } token_next() ; } else { if ( switch_type == TYPE_STRING ) { codeblock_add( code, MN_CASE | MN_STRING, 0 ) ; } else { codeblock_add( code, MN_CASE, 0 ) ; } } if ( token.type == IDENTIFIER && token.code == identifier_colon ) /* ":" */ break ; if ( token.type != IDENTIFIER || token.code != identifier_comma ) /* "," */ compile_error( MSG_EXPECTED, "," ) ; } et2 = codeblock_label_add( code, -1 ) ; codeblock_add( code, MN_JNOCASE, et2 ) ; compile_block( p ) ; codeblock_add( code, MN_JUMP, et1 ) ; codeblock_label_set( code, et2, code->current ) ; } else if ( token.type == IDENTIFIER && token.code == identifier_default ) /* "DEFAULT" */ { if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_colon ) /* ":" */ compile_error( MSG_EXPECTED, ":" ) ; compile_block( p ) ; } else if ( token.type == IDENTIFIER && token.code == identifier_semicolon ) /* ";" */ continue ; else if ( token.type == IDENTIFIER && token.code == identifier_end ) /* "END" */ break ; else compile_error( MSG_EXPECTED, "CASE" ); } codeblock_label_set( code, et1, code->current ) ; continue ; } if ( token.code == identifier_loop ) /* "LOOP" */ { loop = codeblock_loop_add( code ) ; codeblock_loop_start( code, loop, code->current ) ; if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; last_loop = code->loop_active ; code->loop_active = loop ; compile_block( p ) ; code->loop_active = last_loop ; if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; codeblock_add( code, MN_REPEAT, loop ) ; codeblock_loop_end( code, loop, code->current ) ; continue ; } /* FROM ... TO */ if ( token.code == identifier_from ) /* "FROM" */ { int inc = 1 ; CODEBLOCK_POS var_pos; CODEBLOCK_POS var_end; int is_unsigned = 0; int is_float = 0; BASETYPE res_type = TYPE_UNDEFINED; et1 = codeblock_label_add( code, -1 ) ; /* Compile the variable access */ loop = codeblock_loop_add( code ) ; if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; var_pos = codeblock_pos( code ); res = compile_value() ; res_type = typedef_base( res.type ); if ( typedef_is_unsigned( res.type ) ) is_unsigned = MN_UNSIGNED; if ( typedef_is_float( res.type ) ) is_float = MN_FLOAT; var_end = codeblock_pos( code ); if ( !res.lvalue ) compile_error( MSG_VARIABLE_REQUIRED ) ; if ( !typedef_is_numeric( res.type ) ) compile_error( MSG_NUMBER_REQUIRED ); /* Compile the assignation of first value */ token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_equal ) /* "=" */ compile_error( MSG_EXPECTED, "=" ) ; from = compile_expresion( 0, 0, 0, res_type ); codeblock_add( code, MN_LETNP | mntype( res.type, 0 ), 0 ); /* Compile the loop termination check */ codeblock_label_set( code, et1, code->current ) ; codeblock_add_block( code, var_pos, var_end ); codeblock_add( code, MN_PTR | mntype( res.type, 0 ), 0 ); token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_to ) /* "TO" */ compile_error( MSG_EXPECTED, "TO" ) ; to = compile_expresion( 0, 0, 0, res_type ) ; token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_step ) /* "STEP" */ { CODEBLOCK_POS p = codeblock_pos( code ); expresion_result r = compile_expresion( 1, 0, 0, res_type ) ; if ( !r.constant ) compile_error( MSG_CONSTANT_EXP ); if ( !typedef_is_numeric( r.type ) ) compile_error( MSG_NUMBER_REQUIRED ); if ( res_type == TYPE_FLOAT ) { if ( r.fvalue == 0.0 ) compile_error( MSG_INVALID_STEP ) ; inc = *( int * ) & r.fvalue; } else { if ( r.value == 0 ) compile_error( MSG_INVALID_STEP ) ; inc = r.value; } codeblock_setpos( code, p ); if (( res_type == TYPE_FLOAT && r.fvalue > 0 ) || ( res_type != TYPE_FLOAT && r.value > 0 ) ) codeblock_add( code, MN_LTE | is_float | is_unsigned, 0 ) ; else codeblock_add( code, MN_GTE | is_float | is_unsigned, 0 ) ; } else { if ( from.constant && to.constant ) { int dec = 0; if ( res_type == TYPE_FLOAT && from.fvalue > to.fvalue ) { float v = -1; inc = *(( int * ) & v ); dec = 1; } else if ( from.value > to.value ) { inc = -1; dec = 1; } codeblock_add( code, ( dec ? MN_GTE : MN_LTE ) | is_float | is_unsigned, 0 ) ; } else codeblock_add( code, MN_LTE | is_float | is_unsigned, 0 ) ; token_back() ; } token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_semicolon ) /* ";" */ compile_error( MSG_EXPECTED, ";" ) ; if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; codeblock_add( code, MN_BRFALSE, loop ) ; /* Compile the loop block contents */ last_loop = code->loop_active ; code->loop_active = loop ; compile_block( p ) ; code->loop_active = last_loop ; /* Compile the increment and looping code */ codeblock_loop_start( code, loop, code->current ) ; codeblock_add_block( code, var_pos, var_end ); if ( inc == 1 ) codeblock_add( code, MN_INC | mntype( res.type, 0 ), 1 ) ; else if ( inc == -1 ) codeblock_add( code, MN_DEC | mntype( res.type, 0 ), 1 ) ; else { codeblock_add( code, MN_PUSH, inc ) ; codeblock_add( code, MN_VARADD | mntype( res.type, 0 ), 0 ) ; } codeblock_add( code, MN_POP, 0 ) ; codeblock_add( code, MN_JUMP, et1 ) ; codeblock_loop_end( code, loop, code->current ) ; continue ; } /* REPEAT ... UNTIL */ if ( token.code == identifier_repeat ) /* "REPEAT" */ { et1 = codeblock_label_add( code, -1 ) ; et2 = codeblock_label_add( code, -1 ) ; loop = codeblock_loop_add( code ) ; codeblock_add( code, MN_JUMP, et1 ) ; codeblock_loop_start( code, loop, code->current ) ; codeblock_add( code, MN_JUMP, et2 ) ; codeblock_label_set( code, et1, code->current ) ; if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; last_loop = code->loop_active ; code->loop_active = loop ; compile_block( p ) ; code->loop_active = last_loop ; codeblock_label_set( code, et2, code->current ) ; if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; if ( token.type != IDENTIFIER || token.code != identifier_until ) /* "UNTIL" */ compile_error( MSG_EXPECTED, "UNTIL" ) ; token_next() ; if ( token.type == IDENTIFIER && token.code == identifier_leftp ) /* "(" */ { compile_expresion( 0, 0, 0, TYPE_DWORD ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightp ) /* ")" */ compile_error( MSG_EXPECTED, ")" ) ; } else { token_back() ; compile_expresion( 0, 0, 0, TYPE_DWORD ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_semicolon ) /* ";" */ compile_error( MSG_EXPECTED, ";" ) ; } codeblock_add( code, MN_JFALSE, et1 ) ; codeblock_loop_end( code, loop, code->current ) ; continue ; } /* WHILE ... END */ if ( token.code == identifier_while ) /* "WHILE" */ { token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_leftp ) /* "(" */ { token_back() ; loop = codeblock_loop_add( code ) ; codeblock_loop_start( code, loop, code->current ) ; if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; compile_expresion( 0, 0, 0, TYPE_DWORD ) ; token_next() ; if ( token.type != IDENTIFIER || ( token.code != identifier_semicolon && token.code != identifier_colon ) ) /* ";" or ":" */ compile_error( MSG_EXPECTED, ";" MSG_OR ":" ) ; } else { loop = codeblock_loop_add( code ) ; codeblock_loop_start( code, loop, code->current ) ; if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; compile_expresion( 0, 0, 0, TYPE_DWORD ) ; token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_rightp ) /* ")" */ compile_error( MSG_EXPECTED, ")" ) ; } codeblock_add( code, MN_BRFALSE, loop ) ; last_loop = code->loop_active ; code->loop_active = loop ; compile_block( p ) ; code->loop_active = last_loop ; if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; codeblock_add( code, MN_REPEAT, loop ) ; codeblock_loop_end( code, loop, code->current ) ; continue ; } if ( token.code == identifier_jmp ) /* JMP */ { if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; token_next(); if ( token.type != IDENTIFIER ) compile_error( MSG_INVALID_PARAM ); if (( codelabel = codeblock_label_get_id_by_name( code, token.code ) ) == -1 ) codelabel = codeblock_label_add( code, token.code ); codeblock_add( code, MN_JUMP, codelabel ); token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_semicolon ) compile_error( MSG_EXPECTED, ";" ) ; continue; } if ( token.code == identifier_call ) /* CALL */ { if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; token_next(); if ( token.type != IDENTIFIER ) compile_error( MSG_INVALID_PARAM ); if (( codelabel = codeblock_label_get_id_by_name( code, token.code ) ) == -1 ) codelabel = codeblock_label_add( code, token.code ); codeblock_add( code, MN_NCALL, codelabel ); token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_semicolon ) compile_error( MSG_EXPECTED, ";" ) ; continue; } if ( token.code == identifier_on ) /* ON EXIT/ON ERROR */ { int on_req = 0; if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; token_next(); if ( token.type != IDENTIFIER || ( token.code != identifier_exit && token.code != identifier_error ) ) compile_error( MSG_ON_PARAM_ERR ); on_req = token.code; token_next(); if ( token.type != IDENTIFIER || token.code != identifier_jmp ) compile_error( MSG_GOTO_EXP ); token_next(); if ( token.type == NUMBER && token.code == 0 ) codelabel = -1; else if (( codelabel = codeblock_label_get_id_by_name( code, token.code ) ) == -1 ) codelabel = codeblock_label_add( code, token.code ); codeblock_add( code, on_req == identifier_exit ? MN_EXITHNDLR : MN_ERRHNDLR, codelabel ); token_next() ; if ( token.type != IDENTIFIER || token.code != identifier_semicolon ) compile_error( MSG_EXPECTED, ";" ) ; continue; } } if ( token.type == LABEL || /* Label */ ( token.type == IDENTIFIER && ( token.code == identifier_onexit || token.code == identifier_onerror ) ) /* ONEXIT or ONERROR */ ) { if ( token.code == identifier_onexit ) /* "ONEXIT" */ { /* Finalizo el bloque actual y todo el codigo a continuacion es onexit */ codeblock_add( code, MN_END, 0 ) ; p->exitcode = code->current; } if ( token.code == identifier_onerror ) /* "ONERROR" */ { /* Finalizo el bloque actual y todo el codigo a continuacion es onerror */ codeblock_add( code, MN_END, 0 ) ; p->errorcode = code->current; } if (( codelabel = codeblock_label_get_id_by_name( code, token.code ) ) != -1 ) { if ( codeblock_label_get( code, codelabel ) != -1 ) compile_error( "Label already defined" ); } else { codelabel = codeblock_label_add( code, token.code ); } codeblock_label_set( code, codelabel, code->current ) ; continue; } if ( token.type != IDENTIFIER ) /* || token.code < reserved_words) */ compile_error( MSG_INVALID_SENTENCE ) ; if ( dcb_options & DCB_DEBUG ) codeblock_add( code, MN_SENTENCE, line_count + ( current_file << 20 ) ) ; token_back() ; /* Asignation */ res = compile_subexpresion() ; if ( !res.asignation && !res.call ) compile_error( MSG_INVALID_SENTENCE ) ; if ( typedef_is_string( res.type ) && !res.lvalue ) codeblock_add( code, MN_POP | MN_STRING, 0 ) ; else codeblock_add( code, MN_POP, 0 ) ; if ( compile_sentence_end() ) break ; } }