From ea1947ffcc606d757357398b24e74a3f4ecefa07 Mon Sep 17 00:00:00 2001 From: neonloop Date: Wed, 20 Oct 2021 14:54:27 +0000 Subject: Initial commit from steward-fu release --- core/bgdc/src/c_code.c | 4164 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4164 insertions(+) create mode 100644 core/bgdc/src/c_code.c (limited to 'core/bgdc/src/c_code.c') diff --git a/core/bgdc/src/c_code.c b/core/bgdc/src/c_code.c new file mode 100644 index 0000000..2e4ca1e --- /dev/null +++ b/core/bgdc/src/c_code.c @@ -0,0 +1,4164 @@ +/* + * 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 ; + } +} + -- cgit v1.2.3