diff options
Diffstat (limited to 'project/src/lib-parser.c')
| -rw-r--r-- | project/src/lib-parser.c | 7617 |
1 files changed, 7617 insertions, 0 deletions
diff --git a/project/src/lib-parser.c b/project/src/lib-parser.c new file mode 100644 index 0000000..094a1ee --- /dev/null +++ b/project/src/lib-parser.c @@ -0,0 +1,7617 @@ + +/*************************************************************************** + * _______ _______ _______ * + * | ___ |____ | ___ | * + * | | |_| / /| | |_| * + * | |_____ / / | |_____ * + * |_____ | / / |_____ | * + * _ | | / / _ | | * + * | |___| |/ /____| |___| | * + * |_______|_______|_______| * + * * + * Wiimms SZS Tools * + * https://szs.wiimm.de/ * + * * + *************************************************************************** + * * + * This file is part of the SZS project. * + * Visit https://szs.wiimm.de/ for project details and sources. * + * * + * Copyright (c) 2011-2020 by Dirk Clemens <wiimm@wiimm.de> * + * * + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt * + * * + ***************************************************************************/ + +#include "lib-std.h" +#include <math.h> +#include <stddef.h> + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// conversion helpers /////////////// +/////////////////////////////////////////////////////////////////////////////// + +Var_t var_unset = {0}; + +/////////////////////////////////////////////////////////////////////////////// + +bool GetBoolV ( const Var_t * var ) +{ + if (var) + switch(var->mode) + { + case VAR_UNSET: + return false; + + case VAR_INT: + return var->i != 0; + + case VAR_DOUBLE: + return var->d != 0.0; + + case VAR_VECTOR: + return var->x || var->y || var->z; + + case VAR_STRING: + return var->str_len > 0; + } + return false; +} + +////////////////////////////////////////////////////////////////////////////// + +int GetIntV ( const Var_t * var ) +{ + if (var) + switch(var->mode) + { + case VAR_UNSET: + return 0; + + case VAR_INT: + return var->i; + + case VAR_DOUBLE: + case VAR_VECTOR: + { + const double d = floor ( var->d + 0.5 ); + return d < INT_MIN ? INT_MIN : d > INT_MAX ? INT_MAX : d; + } + + case VAR_STRING: + return str2l(var->str,0,10); + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +double GetDoubleV ( const Var_t * var ) +{ + if (var) + switch(var->mode) + { + case VAR_UNSET: + return 0.0; + + case VAR_INT: + return var->i; + + case VAR_DOUBLE: + case VAR_VECTOR: + return var->d; + + case VAR_STRING: + return var->str_len ? strtod_comma(var->str,0) : 0.0; + } + return 0.0; +} + +/////////////////////////////////////////////////////////////////////////////// + +double GetXDoubleV ( const Var_t * var ) +{ + if (var) + switch(var->mode) + { + case VAR_UNSET: + return 0.0; + + case VAR_INT: + return var->i; + + case VAR_DOUBLE: + return var->d; + + case VAR_VECTOR: + return var->x; + + case VAR_STRING: + return var->str_len ? strtod_comma(var->str,0) : 0.0; + } + return 0.0; +} + +/////////////////////////////////////////////////////////////////////////////// + +double GetYDoubleV ( const Var_t * var ) +{ + if (var) + switch(var->mode) + { + case VAR_UNSET: + return 0.0; + + case VAR_INT: + return var->i; + + case VAR_DOUBLE: + return var->d; + + case VAR_VECTOR: + return var->y; + + case VAR_STRING: + return var->str_len ? strtod_comma(var->str,0) : 0.0; + } + return 0.0; +} + +/////////////////////////////////////////////////////////////////////////////// + +double GetZDoubleV ( const Var_t * var ) +{ + if (var) + switch(var->mode) + { + case VAR_UNSET: + return 0.0; + + case VAR_INT: + return var->i; + + case VAR_DOUBLE: + return var->d; + + case VAR_VECTOR: + return var->z; + + case VAR_STRING: + return var->str_len ? strtod_comma(var->str,0) : 0.0; + } + return 0.0; +} + +/////////////////////////////////////////////////////////////////////////////// + +double3 GetVectorV ( const Var_t * var ) +{ + double3 d; + if (!var) + d.x = d.y = d.z = 0.0; + else + switch(var->mode) + { + case VAR_UNSET: + d.x = d.y = d.z = 0.0; + break; + + case VAR_INT: + d.x = d.y = d.z = var->i; + break; + + case VAR_DOUBLE: + d.x = d.y = d.z = var->d; + break; + + case VAR_VECTOR: + return var->d3; + + case VAR_STRING: + { + DEFINE_VAR(temp); + ScanVectorExpr(var->str,var->name,&temp); + DASSERT( temp.mode == VAR_VECTOR ); + return temp.d3; + } + } + return d; +} + +/////////////////////////////////////////////////////////////////////////////// + +float3 GetVectorFV ( const Var_t * var ) +{ + float3 f; + if (!var) + f.x = f.y = f.z = 0.0; + else + switch(var->mode) + { + case VAR_UNSET: + f.x = f.y = f.z = 0.0; + break; + + case VAR_INT: + f.x = f.y = f.z = var->i; + break; + + case VAR_DOUBLE: + f.x = f.y = f.z = var->d; + break; + + case VAR_VECTOR: + f.x = var->x; + f.y = var->y; + f.z = var->z; + break; + + case VAR_STRING: + { + DEFINE_VAR(temp); + ScanVectorExpr(var->str,var->name,&temp); + DASSERT( temp.mode == VAR_VECTOR ); + f.x = temp.x; + f.y = temp.y; + f.z = temp.z; + } + } + return f; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// move content; src can be NULL or ==dest + +void MoveDataV ( Var_t *dest, Var_t * src ) +{ + DASSERT(dest); + FreeV(dest); + + if (!src) + dest->mode = VAR_UNSET; + else if ( src != dest ) + { + memcpy( &dest->mode, &src->mode, sizeof(*dest)-offsetof(Var_t,mode) ); + src->mode = VAR_UNSET; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void MoveDataInitV ( Var_t *dest, Var_t * src ) +{ + DASSERT(dest); + + if (!src) + dest->mode = VAR_UNSET; + else if ( src != dest ) + { + memcpy( &dest->mode, &src->mode, sizeof(*dest)-offsetof(Var_t,mode) ); + src->mode = VAR_UNSET; + } +} + +/////////////////////////////////////////////////////////////////////////////// +void MoveAllV ( Var_t *dest, Var_t * src ) +{ + DASSERT(dest); + FreeV(dest); + + if (!src) + dest->mode = VAR_UNSET; + else if ( src != dest ) + { + memcpy(dest,src,sizeof(*dest)); + src->name = 0; + src->mode = VAR_UNSET; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void MoveAllInitV ( Var_t *dest, Var_t * src ) +{ + DASSERT(dest); + + if (!src) + dest->mode = VAR_UNSET; + else if ( src != dest ) + { + memcpy(dest,src,sizeof(*dest)); + src->name = 0; + src->mode = VAR_UNSET; + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// assign strings + +uint AssignStringVV ( Var_t * var, const Var_t * src ) +{ + DASSERT(var); + + DEFINE_VAR(temp); + Var_t *res = GetStringV(src,&temp); + DASSERT( res && res->mode == VAR_STRING ); + AssignStringVS(var,res->str,res->str_len); + FreeV(&temp); + return var->str_len; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint AppendStringVV ( Var_t * var, const Var_t * src ) +{ + DASSERT(var); + + DEFINE_VAR(temp); + Var_t *res = GetStringV(src,&temp); + DASSERT( res && res->mode == VAR_STRING ); + AppendStringVS(var,res->str,res->str_len); + FreeV(&temp); + return var->str_len; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint AssignStringVS ( Var_t * var, ccp str, int len ) +{ + DASSERT(var); + + SetModeStringV(var); + var->str_len = 0; + + if (str) + { + if ( len < 0 ) + len = strlen(str); + if ( len > 0 ) + { + char *old = 0; + if ( len > var->str_size ) + { + old = var->str; + var->str_size = len; + var->str = MALLOC(var->str_size+1); + } + DASSERT( len <= var->str_size); + memcpy(var->str,str,len); + var->str[len] = 0; + var->str_len = len; + if (old) + FREE(old); + } + } + return var->str_len; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint AssignStringVS2 ( Var_t * var, ccp str1, int len1, ccp str2, int len2 ) +{ + DASSERT(var); + + if ( !str1 || !len1 ) return AssignStringVS(var,str2,len2); + if ( !str2 || !len2 ) return AssignStringVS(var,str1,len1); + + SetModeStringV(var); + var->str_len = 0; + + if ( len1 < 0 ) len1 = strlen(str1); + if ( len2 < 0 ) len2 = strlen(str2); + const int total = len1 + len2; + + if ( total > 0 ) + { + char *old = 0; + if ( total > var->str_size ) + { + old = var->str; + var->str_size = total; + var->str = MALLOC(var->str_size+1); + } + DASSERT( total <= var->str_size); + memcpy(var->str,str1,len1); + memcpy(var->str+len1,str2,len2); + var->str[total] = 0; + var->str_len = total; + if (old) + FREE(old); + } + + return var->str_len; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint AppendStringVS ( Var_t * var, ccp str, int len ) +{ + DASSERT(var); + + if ( var->mode != VAR_STRING ) + return AssignStringVS(var,str,len); + + if (str) + { + if ( len < 0 ) + len = strlen(str); + if ( len > 0 ) + { + char *old = 0; + const uint total = var->str_len + len; + if ( total > var->str_size ) + { + old = var->str; + var->str_size = total + 20; + var->str = MALLOC(var->str_size+1); + memcpy(var->str,old,var->str_len); + } + DASSERT( total <= var->str_size); + memcpy(var->str+var->str_len,str,len); + var->str_len = total; + var->str[total] = 0; + if (old) + FREE(old); + } + } + return var->str_len; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint AppendStringVC ( Var_t * var, char ch, int repeat ) +{ + DASSERT(var); + + SetModeStringV(var); + if ( repeat > 0 ) + { + const uint total = var->str_len + repeat; + if ( total > var->str_size ) + { + var->str_size = total + 20; + var->str = REALLOC(var->str,var->str_size+1); + } + DASSERT( total <= var->str_size); + char *dest = var->str+var->str_len; + while ( repeat-- > 0 ) + *dest++ = ch; + *dest = 0; + var->str_len = total; + DASSERT( dest - var->str == var->str_len ); + } + return var->str_len; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * GetStringV ( const Var_t * var, Var_t * temp ) +{ + DASSERT(temp); + + if (!var) + { + SetModeStringV(temp); + temp->str_len = 0; + return temp; + } + + if ( var->mode == VAR_STRING ) + return (Var_t*)var; + + int len = 0; + char buf[100]; + + switch (var->mode) + { + case VAR_INT: + len = snprintf(buf,sizeof(buf),"%lld",var->i); + break; + + case VAR_DOUBLE: + len = snprintf(buf,sizeof(buf),"%5.3f",var->d); + break; + + case VAR_VECTOR: + len = snprintf(buf,sizeof(buf),"%5.3f,%5.3f,%5.3f", + var->x, var->y, var->z ); + break; + + case VAR_STRING: // VAR_STRING will not happen + ASSERT(0); + case VAR_UNSET: + break; + } + + AssignStringVS(temp,buf,len); + return temp; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +Var_t * ToNoneV ( Var_t * var ) +{ + DASSERT(var); + FreeV(var); + return var; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * ToBoolV ( Var_t * var ) +{ + DASSERT(var); + const bool i = GetBoolV(var); + FreeV(var); + var->i = i; + var->mode = VAR_INT; + return var; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * ToIntV ( Var_t * var ) +{ + DASSERT(var); + if ( var->mode != VAR_INT ) + { + const int i = GetIntV(var); + FreeV(var); + var->i = i; + var->mode = VAR_INT; + } + return var; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * ToDoubleV ( Var_t * var ) +{ + DASSERT(var); + if ( var->mode != VAR_DOUBLE ) + { + const double d = GetDoubleV(var); + FreeV(var); + var->d = d; + var->mode = VAR_DOUBLE; + } + return var; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * ToXDoubleV ( Var_t * var ) +{ + DASSERT(var); + if ( var->mode != VAR_DOUBLE ) + { + const double d = GetXDoubleV(var); + FreeV(var); + var->d = d; + var->mode = VAR_DOUBLE; + } + return var; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * ToYDoubleV ( Var_t * var ) +{ + DASSERT(var); + if ( var->mode != VAR_DOUBLE ) + { + const double d = GetYDoubleV(var); + FreeV(var); + var->d = d; + var->mode = VAR_DOUBLE; + } + return var; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * ToZDoubleV ( Var_t * var ) +{ + DASSERT(var); + if ( var->mode != VAR_DOUBLE ) + { + const double d = GetZDoubleV(var); + FreeV(var); + var->d = d; + var->mode = VAR_DOUBLE; + } + return var; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * ToVectorV ( Var_t * var ) +{ + switch(var->mode) + { + case VAR_UNSET: + var->x = var->y = var->z = 0.0; + break; + + case VAR_INT: + var->x = var->y = var->z = (double)var->i; + break; + + case VAR_DOUBLE: + DASSERT( &var->x == &var->d ); + var->y = var->z = var->x; + break; + + case VAR_VECTOR: + return var; + + case VAR_STRING: + { + DEFINE_VAR(temp); + ScanVectorExpr(var->str,var->name,&temp); + DASSERT( temp.mode == VAR_VECTOR ); + var->x = temp.x; + var->y = temp.y; + var->z = temp.z; + } + break; + } + var->mode = VAR_VECTOR; + return var; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * ToVectorXV ( Var_t * var ) +{ + switch(var->mode) + { + case VAR_UNSET: + var->x = var->y = var->z = 0.0; + break; + + case VAR_INT: + var->x = (double)var->i; + var->y = var->z = 0.0; + break; + + case VAR_DOUBLE: + DASSERT( &var->x == &var->d ); + var->y = var->z = 0.0; + break; + + case VAR_VECTOR: + return var; + + case VAR_STRING: + { + const double d = var->str_len ? strtod_comma(var->str,0) : 0.0; + FreeV(var); + var->x = d; + var->y = var->z = 0.0; + } + break; + } + var->mode = VAR_VECTOR; + return var; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * ToVectorYV ( Var_t * var ) +{ + switch(var->mode) + { + case VAR_UNSET: + var->x = var->y = var->z = 0.0; + break; + + case VAR_INT: + var->y = (double)var->i; + var->x = var->z = 0.0; + break; + + case VAR_DOUBLE: + var->y = var->d; + var->x = var->z = 0.0; + break; + + case VAR_VECTOR: + return var; + + case VAR_STRING: + { + const double d = var->str_len ? strtod_comma(var->str,0) : 0.0; + FreeV(var); + var->y = d; + var->x = var->z = 0.0; + } + break; + } + var->mode = VAR_VECTOR; + return var; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * ToVectorZV ( Var_t * var ) +{ + switch(var->mode) + { + case VAR_UNSET: + var->x = var->y = var->z = 0.0; + break; + + case VAR_INT: + var->z = (double)var->i; + var->x = var->y = 0.0; + break; + + case VAR_DOUBLE: + var->z = var->d; + var->x = var->y = 0.0; + break; + + case VAR_VECTOR: + return var; + + case VAR_STRING: + { + const double d = var->str_len ? strtod_comma(var->str,0) : 0.0; + FreeV(var); + var->z = d; + var->x = var->y = 0.0; + } + break; + } + var->mode = VAR_VECTOR; + return var; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * ToStringV ( Var_t * var ) +{ + DASSERT(var); + if ( var->mode != VAR_STRING ) + GetStringV(var,var); + return var; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * ToVarMode ( Var_t * var, TextCommand_t mode ) +{ + DASSERT(var); + noPRINT("ToVarMode(%u)\n",mode); + + switch (mode) + { + case TCMD_PDEF_I: + case TCMD_LDEF_I: + case TCMD_GDEF_I: + return ToIntV(var); + + case TCMD_PDEF_F: + case TCMD_LDEF_F: + case TCMD_GDEF_F: + return ToDoubleV(var); + + case TCMD_PDEF_S: + case TCMD_LDEF_S: + case TCMD_GDEF_S: + return ToStringV(var); + + case TCMD_PDEF_V: + case TCMD_LDEF_V: + case TCMD_GDEF_V: + return ToVectorV(var); + + case TCMD_PDEF_X: + case TCMD_LDEF_X: + case TCMD_GDEF_X: + return ToXDoubleV(var); + + case TCMD_PDEF_Y: + case TCMD_LDEF_Y: + case TCMD_GDEF_Y: + return ToYDoubleV(var); + + case TCMD_PDEF_Z: + case TCMD_LDEF_Z: + case TCMD_GDEF_Z: + return ToZDoubleV(var); + + default: + return var; + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +void AssignIntV ( Var_t * var, int val ) +{ + DASSERT(var); + FreeV(var); + var->i = val; + var->mode = VAR_INT; +} + +/////////////////////////////////////////////////////////////////////////////// + +void AssignDoubleV ( Var_t * var, double val ) +{ + DASSERT(var); + FreeV(var); + var->d = val; + var->mode = VAR_DOUBLE; +} + +/////////////////////////////////////////////////////////////////////////////// + +void AssignXDoubleV ( Var_t * var, double val ) +{ + DASSERT(var); + FreeV(var); + if ( var->mode != VAR_VECTOR ) + { + var->mode = VAR_VECTOR; + var->y = var->z = 0.0; + } + var->x = val; +} + +/////////////////////////////////////////////////////////////////////////////// + +void AssignYDoubleV ( Var_t * var, double val ) +{ + DASSERT(var); + FreeV(var); + if ( var->mode != VAR_VECTOR ) + { + var->mode = VAR_VECTOR; + var->x = var->z = 0.0; + } + var->y = val; +} + +/////////////////////////////////////////////////////////////////////////////// + +void AssignZDoubleV ( Var_t * var, double val ) +{ + DASSERT(var); + FreeV(var); + if ( var->mode != VAR_VECTOR ) + { + var->mode = VAR_VECTOR; + var->x = var->y = 0.0; + } + var->z = val; +} + +/////////////////////////////////////////////////////////////////////////////// + +void AssignVectorV ( Var_t * var, const double3 * val ) +{ + DASSERT(var); + DASSERT(val); + FreeV(var); + memcpy(&var->d3,val,sizeof(var->d3)); + var->mode = VAR_VECTOR; +} + +/////////////////////////////////////////////////////////////////////////////// + +void AssignVectorV3 ( Var_t * var, double x, double y, double z ) +{ + DASSERT(var); + FreeV(var); + var->x = x; + var->y = y; + var->z = z; + var->mode = VAR_VECTOR; +} + +/////////////////////////////////////////////////////////////////////////////// + +void AssignVar +( + Var_t * dest, // valid destination var + const Var_t * src // NULL or valid source var +) +{ + // assertions needed for memcpy() below + DASSERT( (u8*)&dest->name == (u8*)dest ); + DASSERT( (u8*)&dest->name + sizeof(dest->name) == (u8*)&dest->mode ); + + if (src) + { + if ( src->mode == VAR_STRING ) + AssignStringVV(dest,src); + else + memcpy(&dest->mode,&src->mode,sizeof(*dest)-offsetof(Var_t,mode)); + } + else + FreeV(dest); +} + +/////////////////////////////////////////////////////////////////////////////// + +void AssignVarMode ( Var_t * dest, const Var_t * src, TextCommand_t mode ) +{ + DASSERT(dest); + noPRINT("AssignVarMode(%u) name=%s src_mode=%d\n", + mode, dest->name, src ? src->mode : -1 ); + + // assertions needed for memcpy() below + DASSERT( (u8*)&dest->name == (u8*)dest ); + DASSERT( (u8*)&dest->name + sizeof(dest->name) == (u8*)&dest->mode ); + + switch (mode) + { + case TCMD_PDEF_I: + case TCMD_LDEF_I: + case TCMD_GDEF_I: + dest->i = GetIntV(src); + dest->mode = VAR_INT; + break; + + case TCMD_PDEF_F: + case TCMD_LDEF_F: + case TCMD_GDEF_F: + dest->d = GetDoubleV(src); + dest->mode = VAR_DOUBLE; + break; + + case TCMD_PDEF_S: + case TCMD_LDEF_S: + case TCMD_GDEF_S: + AssignStringVV(dest,src); + break; + + case TCMD_PDEF_V: + case TCMD_LDEF_V: + case TCMD_GDEF_V: + dest->d3 = GetVectorV(src); + dest->mode = VAR_VECTOR; + break; + + case TCMD_PDEF_X: + case TCMD_LDEF_X: + case TCMD_GDEF_X: + if ( dest->mode == VAR_VECTOR ) + dest->x = GetXDoubleV(src); + else + { + dest->x = GetXDoubleV(src); + dest->y = dest->z = 0.0; + dest->mode = VAR_VECTOR; + } + break; + + case TCMD_PDEF_Y: + case TCMD_LDEF_Y: + case TCMD_GDEF_Y: + if ( dest->mode == VAR_VECTOR ) + dest->y = GetYDoubleV(src); + else + { + dest->y = GetYDoubleV(src); + dest->x = dest->z = 0.0; + dest->mode = VAR_VECTOR; + } + break; + + case TCMD_PDEF_Z: + case TCMD_LDEF_Z: + case TCMD_GDEF_Z: + if ( dest->mode == VAR_VECTOR ) + dest->z = GetZDoubleV(src); + else + { + dest->z = GetYDoubleV(src); + dest->x = dest->y = 0.0; + dest->mode = VAR_VECTOR; + } + break; + + default: + if (src) + memcpy( &dest->mode, &src->mode, sizeof(*dest)-sizeof(dest->name) ); + else + { + dest->mode = VAR_UNSET; + dest = 0; + } + break; + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanValueV ( Var_t * dest, const Var_t * src, ccp name ) +{ + Var_t temp; + if ( src && src->mode == VAR_STRING ) + { + if (!name) + name = src->name; + + ScanInfo_t si; + InitializeSI(&si,src->str,src->str_len,name,0); + if (!name) + si.no_warn++; + + InitializeV(&temp); + enumError err = ScanValueSI(&si,&temp); + if (!err) + CheckEolSI(&si); + ResetSI(&si); + src = &temp; + } + + FreeV(dest); + if (src) + memcpy(&dest->mode,&src->mode,sizeof(*dest)-offsetof(Var_t,mode)); + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanExprV ( Var_t * dest, const Var_t * src, ccp name ) +{ + Var_t temp; + if ( src && src->mode == VAR_STRING ) + { + if (!name) + name = src->name; + + ScanInfo_t si; + InitializeSI(&si,src->str,src->str_len,name,0); + if (!name) + si.no_warn++; + + InitializeV(&temp); + enumError err = ScanExprSI(&si,&temp); + if (!err) + CheckEolSI(&si); + ResetSI(&si); + src = &temp; + } + + FreeV(dest); + if (src) + memcpy(&dest->mode,&src->mode,sizeof(*dest)-offsetof(Var_t,mode)); + return ERR_OK; +} +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ResultFloat +( + Var_t * dest, // valid destination var + const float * val, // pointer to N floats + uint n_val // number of floats in 'n' +) +{ + FreeV(dest); + switch (n_val) + { + case 0: + dest->i = 0; + dest->mode = VAR_UNSET; + break; + + case 1: + dest->d = *val; + dest->mode = VAR_DOUBLE; + break; + + case 2: + dest->x = val[0]; + dest->y = 0.0; + dest->z = val[1]; + dest->mode = VAR_VECTOR; + break; + + default: + dest->x = val[0]; + dest->y = val[1]; + dest->z = val[2]; + dest->mode = VAR_VECTOR; + break; + } + return ERR_OK; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// variables & maps: interface /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static bool IsNum ( char ch, int hex_mode ) +{ + return ch >= '0' && ch <= '9' + || ch == '-' + || ch == '+' + || ch == '.' + || hex_mode > 0 && ( ch >= 'a' && ch <= 'f' || ch >= 'A' && ch <= 'F' ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void InitializeVarMap +( + VarMap_t * vm // data structure to initialize +) +{ + DASSERT(vm); + memset(vm,0,sizeof(*vm)); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ResetVarMap +( + VarMap_t * vm // data structure to resewt +) +{ + DASSERT(vm); + ClearVarMap(vm); + FREE(vm->list); + memset(vm,0,sizeof(*vm)); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ClearVarMap +( + VarMap_t * vm // data structure to resewt +) +{ + DASSERT(vm); + if (vm->used) + { + uint count = vm->used; + Var_t * v = vm->list; + while ( count-- > 0 ) + { + FreeV(v); + FreeString(v->name); + v++; + } + vm->used = 0; + // not needed: memset(vm->list,0,sizeof(*vm->list)*vm->size); + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +void CopyVarMap +( + VarMap_t * dest, // destination var map + bool init_dest, // true: initialialize 'dest' first + const VarMap_t * src // source var map +) +{ + DASSERT(dest); + DASSERT(src); + + if (init_dest) + InitializeVarMap(dest); + + if (src->used) + { + Var_t * vsrc = src->list; + // assertions needed for memcpy() below + DASSERT( (u8*)&vsrc->name == (u8*)vsrc ); + DASSERT( (u8*)&vsrc->name + sizeof(vsrc->name) == (u8*)&vsrc->mode ); + + uint count; + for ( count = src->used; count > 0; count--, vsrc++ ) + { + Var_t * vdest = InsertVarMap( dest, vsrc->name, false, 0, 0 ); + DASSERT(vdest); + if ( vsrc->mode == VAR_STRING ) + AssignStringVV(vdest,vsrc); + else + memcpy(&vdest->mode,&vsrc->mode,sizeof(*vdest)-offsetof(Var_t,mode)); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void MoveVarMap +( + VarMap_t * dest, // destination var map + bool init_dest, // true: initialialize 'dest' first + VarMap_t * src // source var map -> will be resetted +) +{ + DASSERT(dest); + DASSERT(src); + + if (!init_dest) + ResetVarMap(dest); + memcpy(dest,src,sizeof(*dest)); + InitializeVarMap(src); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static uint FindVarMapHelper ( const VarMap_t * vm, bool * p_found, ccp name ) +{ + ASSERT(vm); + + int beg = 0; + if ( vm && name ) + { + int end = vm->used - 1; + while ( beg <= end ) + { + uint idx = (beg+end)/2; + int stat = strcmp(name,vm->list[idx].name); + if ( stat < 0 ) + end = idx - 1 ; + else if ( stat > 0 ) + beg = idx + 1; + else + { + TRACE("FindVarMapHelper(%s) FOUND=%d/%d/%d\n", + name, idx, vm->used, vm->size ); + if (p_found) + *p_found = true; + return idx; + } + } + } + + TRACE("FindVarMapHelper(%s) failed=%d/%d/%d\n", + name, beg, vm->used, vm->size ); + + if (p_found) + *p_found = false; + return beg; +} + +/////////////////////////////////////////////////////////////////////////////// + +int FindVarMapIndex +( + const VarMap_t * vm, // valid variable map + ccp varname, // variable name + int not_found_value // return value if not found +) +{ + bool found; + const int idx = FindVarMapHelper(vm,&found,varname); + return found ? idx : not_found_value; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool RemoveVarMap +( + // returns 'true' if var deleted + + VarMap_t * vm, // valid variable map + ccp varname // variable name +) +{ + bool found; + uint idx = FindVarMapHelper(vm,&found,varname); + if (found) + { + vm->used--; + ASSERT( idx <= vm->used ); + Var_t *dest = vm->list + idx; + FreeV(dest); + FREE((char*)dest->name); + memmove(dest,dest+1,(vm->used-idx)*sizeof(*dest)); + } + return found; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * InsertVarMap +( + VarMap_t * vm, // valid variable map + ccp varname, // varname to insert + bool move_varname, // true: move 'varname', false: strdup() + ScanInfo_t * si, // not null: print "already defined" message + bool * found // not null: store found status +) +{ + DASSERT(vm); + DASSERT( vm->used <= vm->size ); + + if (!varname) + { + if (found) + *found = false; + return 0; + } + + bool my_found; + const int idx = FindVarMapHelper(vm,&my_found,varname); + if (found) + *found = my_found; + + Var_t * var; + if (my_found) + { + var = vm->list + idx; + if (move_varname) + FreeString(varname); + + if ( si && si->no_warn <= 0 ) + { + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "Variable '%s' already defined [%s @%u]: %.*s\n", + varname, sf->name, sf->line, + (int)(eol - sf->prev_ptr), sf->prev_ptr ); + } + } + else + { + if ( vm->used == vm->size ) + { + vm->size = 3*vm->size/2 + 100; + vm->list = REALLOC(vm->list,vm->size*sizeof(*vm->list)); + } + + DASSERT( idx <= vm->used ); + var = vm->list + idx; + memmove(var+1,var,(vm->used-idx)*sizeof(*var)); + vm->used++; + + var->name = move_varname ? varname : STRDUP(varname); + var->mode = VAR_UNSET; + } + + return var; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool DefineIntVar +( + VarMap_t * vm, // valid variable map + ccp varname, // name of variable + int value // value to assign +) +{ + DASSERT(vm); + DASSERT(varname); + + bool found; + Var_t * var = InsertVarMap( vm, varname, false, 0, &found ); + DASSERT(var); + FreeV(var); + var->mode = VAR_INT; + var->i = value; + return found; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool DefineDoubleVar +( + VarMap_t * vm, // valid variable map + ccp varname, // name of variable + double value // value to assign +) +{ + DASSERT(vm); + DASSERT(varname); + + bool found; + Var_t * var = InsertVarMap( vm, varname, false, 0, &found ); + DASSERT(var); + FreeV(var); + var->mode = VAR_DOUBLE; + var->d = value; + return found; +} + +/////////////////////////////////////////////////////////////////////////////// + +void PrintV +( + FILE * f, // destination file + const Var_t * v, // variable to print + int str_mode // 0:-, 1:limit+escape, 2:limit+escape+quote +) +{ + DASSERT(f); + DASSERT(v); + + const uint max_str = 100; + char strbuf[5*max_str+100]; + + switch(v->mode) + { + case VAR_UNSET: + fputs("$NONE",f); + break; + + case VAR_INT: + fprintf(f,"%19lld = %#16llx", v->i, v->i ); + if (v->int_mode) + fprintf(f," [%s]",GetIntModeName(v->int_mode)); + break; + + case VAR_DOUBLE: + if ( fabs(v->d) < 1e10 ) + fprintf(f,"%15.3f = %14.7e", v->d, v->d ); + else + fprintf(f," %14.7e", v->d ); + break; + + case VAR_VECTOR: + if ( fabs(v->x) < 1e10 ) + fprintf(f,"v( %14.3f,", v->x ); + else + fprintf(f,"v( %14.7e,", v->x ); + + if ( fabs(v->y) < 1e10 ) + fprintf(f," %14.3f,",v->y); + else + fprintf(f," %14.7e,",v->y); + + if ( fabs(v->z) < 1e10 ) + fprintf(f," %14.3f )",v->z); + else + fprintf(f," %14.7e )",v->z); + break; + + case VAR_STRING: + if (!str_mode) + fwrite(v->str,v->str_len,1,f); + else + { + ccp quote = str_mode > 1 ? "\"" : ""; + PrintEscapedString( strbuf, sizeof(strbuf), + v->str, v->str_len < max_str ? v->str_len : max_str, + CHMD__ALL, *quote, 0 ); + if ( v->str_len > max_str ) + fprintf(f,"[%u/%u] %s%s%s...",max_str,v->str_len,quote,strbuf,quote); + else + fprintf(f,"[%u] %s%s%s",v->str_len,quote,strbuf,quote); + } + break; + + default: + fputs("?",f); + break; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void DumpVarMap +( + FILE * f, // destination file + uint indent, // indention + const VarMap_t * vm, // valid variable map + bool print_header // print table header +) +{ + DASSERT(f); + DASSERT(indent<100); + DASSERT(vm); + + if (!vm->used) + return; + + uint maxlen = 4; + Var_t *v, *vend = vm->list + vm->used; + for ( v = vm->list; v < vend; v++ ) + { + const uint len = strlen(v->name); + if ( maxlen < len ) + maxlen = len; + } + + char last_name1 = 0; + if (print_header) + { + fprintf(f,"%*s%-*s = value = value\n" + "%*s%.*s\n", + indent,"", maxlen, "name", + indent,"", maxlen+36, Minus300 ); + last_name1 = vm->list->name[0]; + } + + for ( v = vm->list; v < vend; v++ ) + { + if ( print_header && last_name1 != v->name[0] ) + { + last_name1 = v->name[0]; + fputc('\n',f); + } + + fprintf(f,"%*s%-*s = ", indent,"", maxlen, v->name ); + PrintV(f,v,2); + fputc('\n',f); + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// SI var access /////////////// +/////////////////////////////////////////////////////////////////////////////// + +const Var_t * FindConst +( + ccp varname // variable name +) +{ + bool found; + const int idx = FindVarMapHelper(&const_map,&found,varname); + return found ? const_map.list + idx : 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +const Var_t * FindVarMap +( + const VarMap_t * vm, // NULL or variable map + ccp varname, // variable name + ScanInfo_t * si // not null: print "not found" message +) +{ + if (vm) + { + bool found; + const int idx = FindVarMapHelper(vm,&found,varname); + if (found) + return vm->list + idx; + } + + if ( si && si->no_warn <= 0 ) + { + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "Variable '%s' not found [%s @%u]: %.*s\n", + varname, sf->name, sf->line, + (int)(eol - sf->prev_ptr), sf->prev_ptr ); + } + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +const Var_t * FindVarSI +( + ScanInfo_t * si, // not NULL: use var maps + ccp varname, // variable name + bool print_warning // true && 'si': print 'not found' warning +) +{ + if (si) + { + bool found; + DASSERT(si->cur_file); + int idx = FindVarMapHelper(&si->cur_file->pvar,&found,varname); + if (found) + return si->cur_file->pvar.list + idx; + + if (si->param) + { + idx = FindVarMapHelper(si->param,&found,varname); + if (found) + return si->param->list + idx; + } + + idx = FindVarMapHelper(&si->lvar,&found,varname); + if (found) + return si->lvar.list + idx; + + idx = FindVarMapHelper(&si->gvar,&found,varname); + if (found) + return si->gvar.list + idx; + + if (si->predef) + { + idx = FindVarMapHelper(si->predef,&found,varname); + if (found) + return si->predef->list + idx; + } + } + + const Var_t *res = FindConst(varname); + if (res) + return res; + + if (print_warning) + FindVarMap(0,varname,si); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +Var_t * OverwriteVarSI +( + // returns always not NULL + + ScanInfo_t * si, // not NULL: use var maps for search + VarMap_t * vm_insert, // valid variable map, insert search failed + ccp varname, // varname to insert + int * xyz, // not NULL: enable .X/Y/Z support + // input: <0: not a X/Y/Z + // 0..2: is a X/Y/Z + // >2: unknown + // output: store corrected value + bool * found // not null: store found status (false=NEW) +) +{ + DASSERT(vm_insert); + DASSERT( vm_insert->used <= vm_insert->size ); + noPRINT("OverwriteVarSI(xyz=%d) %s\n",xyz?*xyz:-999,varname); + + Var_t *var = (Var_t*)FindVarSI(si,varname,false); + if (var) + { + if (xyz) + *xyz = -1; + if (found) + *found = true; + return var; + } + + if ( xyz && *xyz >= 0 ) + { + uint namelen = strlen(varname); + if ( *xyz > 2 ) + { + *xyz = namelen > 2 + && varname[namelen-2] == '.' + && varname[namelen-1] >= 'X' + && varname[namelen-1] <= 'Z' + ? varname[namelen-1] - 'X' : -1; + } + + if ( *xyz >= 0 && namelen > 2 && namelen <= VARNAME_SIZE ) + { + char basename[VARNAME_SIZE+1]; + memcpy(basename,varname,namelen-2); + basename[namelen-2] = 0; + var = (Var_t*)FindVarSI(si,basename,0); + if ( var && var->mode == VAR_VECTOR ) + { + if (found) + *found = true; + return var; + } + *xyz = -1; + } + } + + return InsertVarMap(vm_insert,varname,false,0,0); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// options /////////////// +/////////////////////////////////////////////////////////////////////////////// + +VarMap_t const_map = {0}; + +/////////////////////////////////////////////////////////////////////////////// + +void SetupConst() +{ + if (!const_map.used) + { + InsertVarMap(&const_map,"$NONE",false,0,0); + InsertVarMap(&const_map,"$NULL",false,0,0); + + struct inttab_t { ccp name; int val; }; + static const struct inttab_t inttab[] = + { + { "$N", 0 }, + {0,0} + }; + + const struct inttab_t * ip; + for ( ip = inttab; ip->name; ip++ ) + DefineIntVar(&const_map,ip->name,ip->val); + + struct dbltab_t { ccp name; double val; }; + static const struct dbltab_t dbltab[] = + { + { "INF", INFINITY }, + { "NAN", NAN }, + {0,0} + }; + + const struct dbltab_t * dp; + for ( dp = dbltab; dp->name; dp++ ) + DefineDoubleVar(&const_map,dp->name,dp->val); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptConst ( ccp arg ) +{ + SetupConst(); + if (!arg) + return 0; + + ScanInfo_t si; + InitializeSI(&si,arg,strlen(arg),"Option --const",0); + ScanFile_t *sf = si.cur_file; + DASSERT(sf); + sf->disable_comma++; + for(;;) + { + while ( *sf->ptr > 0 && *sf->ptr <= ' ' || *sf->ptr == ',' ) + sf->ptr++; + if (!*sf->ptr) + break; + + char varname[VARNAME_SIZE+1]; + const uint namelen = ScanNameSI(&si,varname,sizeof(varname),false,true,0); + if (!namelen) + { + ERROR0(ERR_SYNTAX,"Option --const: Missing name: %s\n",sf->prev_ptr); + goto abort; + } + + if ( NextCharSI(&si,false) != '=' ) + { + ERROR0(ERR_SYNTAX, + "Option --const: Missing '=' behind name: %s\n", + sf->prev_ptr); + goto abort; + } + sf->ptr++; + + Var_t * vdest = InsertVarMap( &const_map, varname, false, 0, 0 ); + DASSERT(vdest); + if (ScanExprSI(&si,vdest)) + goto abort; + } + + ResetSI(&si); + return 0; + + abort: + ResetSI(&si); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////// scan text /////////////// +/////////////////////////////////////////////////////////////////////////////// + +ScanFile_t empty_scan_file = {0}; // used as last file in ScanInfo_t + +/////////////////////////////////////////////////////////////////////////////// + +static void InitializeSM +( + ScanMacro_t * sm // data structure to setup +) +{ + DASSERT(sm); + memset(sm,0,sizeof(*sm)); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void ResetSM +( + ScanMacro_t * sm // data structure to reset +) +{ + DASSERT(sm); + if (sm->data_alloced) + FREE((void*)sm->data); + FreeString(sm->src_name); + memset(sm,0,sizeof(*sm)); +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void InitializeSF +( + ScanFile_t * sf, // data structure to setup + ScanInfo_t * si, // NULL or base scan info + ccp data, // data to scan + uint data_size, // size of data + ccp name, // NULL or name for warnings + int revision, // revision number + VarMap_t * varmap // NULL or new varmap (moved) +) +{ + DASSERT(sf); + memset(sf,0,sizeof(*sf)); + + sf->data = data; + sf->ptr = data + GetTextBOMLen(data,data_size); + sf->prev_ptr = sf->ptr; + sf->end = data + data_size; + sf->line = 1; + sf->line_err = 0; + sf->name = name ? name : "?"; + sf->revision = revision; + + if (si) + { + sf->next = si->cur_file; + si->cur_file = sf; + si->n_files++; + #if HAVE_PRINT + si->debug = 0; + #endif + } + + if (varmap) + MoveVarMap(&sf->pvar,true,varmap); + else + { + InitializeVarMap(&sf->pvar); + Var_t *var = InsertVarMap(&sf->pvar,"$N",false,0,0); + DASSERT(var); + AssignIntV(var,0); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +ScanFile_t * AddSF +( + ScanInfo_t * si, // base scan info + ccp data, // data to scan + uint data_size, // size of data + ccp name, // NULL or name for warnings + int revision, // revision number + VarMap_t * varmap // NULL or new varmap (moved) +) +{ + DASSERT(si); + noPRINT("AddSF(rev=%u)\n",revision); + + if ( si->n_files > MAX_SOURCE_DEPTH ) + { + si->total_err++; + ScanFile_t * sf = si->cur_file; + DASSERT(sf); + ERROR0(ERR_WARNING, + "To many open source files and/or macros (max=%u) [%s @%u]\n", + MAX_SOURCE_DEPTH, sf->name, sf->line ); + return 0; + } + + ScanFile_t * sf = MALLOC(sizeof(*sf)); + InitializeSF(sf,si,data,data_size,name,revision,varmap); + noPRINT("AddSF() %p,%p, rev=%u\n",sf,sf->next,sf->revision); + return sf; +} + +/////////////////////////////////////////////////////////////////////////////// + +static void ResetSF +( + ScanFile_t * sf // data structure to reset +) +{ + DASSERT(sf); + + int i; + for ( i = 0; i < MAX_LOOP_DEPTH; i++ ) + FreeString(sf->loop[i].varname); + + if (sf->data_alloced) + FREE((void*)sf->data); + + if (sf->name_alloced) + FreeString(sf->name); + + ResetVarMap(&sf->pvar); + memset(sf,0,sizeof(*sf)); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool DropSF +( + ScanInfo_t * si // data structure +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + + if ( !sf || sf == &empty_scan_file ) + return false; + + si->n_files--; + si->cur_file = sf->next; + ResetSF(sf); + FREE(sf); + DASSERT(si->cur_file); + noPRINT("DROPSF() -> |%.20s|\n",si->cur_file->ptr); + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +void InitializeSI +( + ScanInfo_t * si, // data structure to setup + ccp data, // data to scan + uint data_size, // size of data + ccp name, // NULL or name for warnings + int revision // revision number +) +{ + DASSERT(si); + DASSERT(data); + memset(si,0,sizeof(*si)); + + si->init_data = data; + si->init_data_size = data_size; + si->init_name = name; + si->init_revision = revision; + + InitializeSF(&empty_scan_file,0,0,0,EmptyString,0,0); + si->cur_file = &empty_scan_file; + empty_scan_file.revision = REVISION_NUM; + AddSF(si,data,data_size,name,revision,0); + + InitializeVarMap(&si->macro); + InitializeVarMap(&si->lvar); + InitializeVarMap(&si->gvar); + + DefineIntVar(&si->gvar,"REVISION$SETUP",revision); + DefineIntVar(&si->gvar,"REVISION$ACTIVE",revision); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ResetHelperSI +( + ScanInfo_t * si // data structure to reset +) +{ + DASSERT(si); + + //--- close all files + + while (DropSF(si)) + ; + + //--- drop all macros + + if (si->macro.used) + { + uint count = si->macro.used; + Var_t * v = si->macro.list; + while ( count-- > 0 ) + { + ScanMacro_t *sm = v->macro; + if (sm) + { + v->macro = 0; + ResetSM(sm); + FREE(sm); + } + v++; + } + } + ResetVarMap(&si->macro); + + //--- clear variables + + ResetVarMap(&si->lvar); + si->cur_file = &empty_scan_file; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ResetSI +( + ScanInfo_t * si // data structure to reset +) +{ + DASSERT(si); + + ResetHelperSI(si); + ResetVarMap(&si->gvar); + + memset(si,0,sizeof(*si)); + si->cur_file = &empty_scan_file; +} + +/////////////////////////////////////////////////////////////////////////////// + +void RestartSI +( + ScanInfo_t * si // data structure to setup +) +{ + ResetHelperSI(si); + AddSF(si,si->init_data,si->init_data_size,si->init_name,si->init_revision,0); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ResetLocalVarsSI +( + ScanInfo_t * si, // data structure to setup + int revision // revision number +) +{ + DASSERT(si); + ResetVarMap(&si->lvar); + + ScanFile_t *sf ; + for ( sf = si->cur_file; sf && sf != &empty_scan_file; sf = sf->next ) + sf->revision = revision; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static bool TestContLineSI +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + ccp ptr = sf->ptr; + ccp end = sf->end; + uint lines = 0; + + uchar ch = 0; + for(;;) + { + if ( ptr == end ) + { + ch = 0; + break; + } + + ch = *ptr; + if ( ch == '#' ) + { + while ( ptr < end && *ptr != '\n' ) + ptr++; + continue; + } + + if ( ch == '\n' ) + lines++; + + if ( ch > ' ' ) + break; + ptr++; + } + + if ( ch != '>' ) + return false; + + sf->ptr = ptr; + if (lines) + { + sf->line += lines; + sf->line_err = 0; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +char NextCharSI +( + ScanInfo_t * si, // valid data + bool skip_lines // true: skip empty lines +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + ccp ptr = sf->ptr; + ccp end = sf->end; + + for(;;) + { + if ( ptr == end ) + { + sf->ptr = ptr; + if (!skip_lines) + { + CheckLevelSI(si); + return 0; + } + + if (!NextLineSI(si,false,true)) + return 0; + + sf = si->cur_file; + DASSERT(sf); + ptr = sf->ptr; + end = sf->end; + noPRINT("CHAR [%zu] |%.20s|\n",end-ptr,ptr); + continue; + } + + const uchar ch = *ptr++; + if ( ch == '#' ) + { + while ( ptr < end && *ptr != '\n' ) + ptr++; + continue; + } + + if ( ch == '@' && skip_lines ) + { + sf->ptr = ptr; + const TextCommand_t tcmd = ScanTextCommand(si); + if (tcmd) + { + ExecTextCommand(si,tcmd); + sf = si->cur_file; + DASSERT(sf); + ptr = sf->ptr; + end = sf->end; + continue; + } + } + + if ( ch > ' ' ) + { + sf->ptr = ptr - 1; + return ch; + } + + if ( ch == '\n' ) + { + sf->ptr = sf->prev_ptr = ptr - 1; + if (TestContLineSI(si)) + ptr = sf->ptr+1; + else + return skip_lines ? NextLineSI(si,true,true) : 0; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +char SkipCharSI +( + // return next non skipped character + + ScanInfo_t * si, // valid data + char ch // character to skip +) +{ + DASSERT(si); + const char next_ch = NextCharSI(si,false); + if ( next_ch == ch ) + { + DASSERT(si->cur_file); + si->cur_file->ptr++; + return NextCharSI(si,false); + } + return next_ch; +} + +/////////////////////////////////////////////////////////////////////////////// + +char NextLineSI +( + ScanInfo_t * si, // valid data + bool skip_cont, // true: skip continuation lines + bool allow_tcmd // true: scan and execute text commands +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + char cont_ch = skip_cont ? '>' : '#'; + ccp ptr = sf->ptr; + ccp end = sf->end; + + for(;;) + { + //--- find beginning of next line first (skip current line) + + while ( ptr < end ) + if ( *ptr++ == '\n' ) + { + sf->line++; + sf->line_err = 0; + break; + } + + //--- now find next relevant line + + for(;;) + { + if ( ptr == end ) + { + sf->ptr = sf->prev_ptr = ptr; + CheckLevelSI(si); + + if ( sf != &empty_scan_file ) + si->last_result.mode = VAR_UNSET; + if ( !allow_tcmd || !DropSF(si) ) + return 0; + + sf = si->cur_file; + DASSERT(sf); + ptr = sf->ptr; + end = sf->end; + cont_ch = '#'; + continue; + } + + // skip blanks and controls at beginning of line + + while ( ptr < end && (uchar)*ptr <= ' ' ) + { + if ( *ptr == '\n' ) + { + sf->line++; + sf->line_err = 0; + } + ptr++; + } + + if ( ptr == end ) + continue; + + if ( *ptr == '@' && allow_tcmd ) + { + sf->ptr = ptr; + const TextCommand_t tcmd = ScanTextCommand(si); + if (tcmd) + { + ExecTextCommand(si,tcmd); + sf = si->cur_file; + DASSERT(sf); + ptr = sf->ptr; + end = sf->end; + continue; + } + } + + if ( *ptr != '#' && *ptr != cont_ch ) + { + // neither comment nor continuation line + sf->ptr = sf->prev_ptr = ptr; + return *ptr; + } + break; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError CheckLevelSI +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + DASSERT(sf->if_level >= 0); + + enumError stat = ERR_OK; + + if ( sf->if_level > 0 ) + { + if ( si->no_warn <= 0 ) + { + si->total_err++; + ERROR0(ERR_WARNING, + "End of text/section within @IF..@ENDIF level #%u [%s @%u]\n", + sf->if_level, sf->name, sf->line ); + } + sf->if_level = 0; + stat = ERR_WARNING; + } + + if ( sf->loop_level > 0 ) + { + if ( si->no_warn <= 0 ) + { + si->total_err++; + ERROR0(ERR_WARNING, + "End of text/section within loop level #%u [%s @%u]\n", + sf->loop_level, sf->name, sf->line ); + } + sf->loop_level = 0; + stat = ERR_WARNING; + } + + return stat; +} + +/////////////////////////////////////////////////////////////////////////////// + +void GotoEolSI +( + ScanInfo_t * si // valid data +) +{ + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + sf->prev_ptr = sf->ptr; + while (NextCharSI(si,false)) + { + ccp ptr = sf->ptr; + while ( ptr < sf->end && *ptr != '\n' ) + ptr++; + sf->ptr = ptr; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError CheckEolSI +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + sf->prev_ptr = sf->ptr; + if (!NextCharSI(si,false)) + return ERR_OK; + + if ( si->no_warn <= 0 ) + { + si->total_err++; + if (!sf->line_err) + { + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "End of line expected [%s @%u]: %.*s\n", + sf->name, sf->line, (int)(eol - sf->ptr), sf->ptr ); + } + } + GotoEolSI(si); + return ERR_WARNING; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError CheckWarnSI +( + ScanInfo_t * si, // valid data + char ch, // char to test + enumError err // previous error level +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + if ( NextCharSI(si,false) == ch ) + sf->ptr++; + else + { + if ( err < ERR_WARNING ) + err = ERR_WARNING; + + si->total_err++; + if ( si->no_warn <= 0 ) + { + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "Character '%c' expected [%s @%u]: %.*s\n", + ch, sf->name, sf->line, (int)(eol - sf->ptr), sf->ptr ); + } + } + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError WarnIgnoreSI +( + ScanInfo_t * si, // valid data + ccp format, // NULL or format of text before 'line ignored' + ... // arguments for 'format' +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + si->total_err++; + if ( si->no_warn <= 0 ) + { + char buf[1000]; + *buf = 0; + + if (format) + { + va_list arg; + va_start(arg,format); + vsnprintf(buf,sizeof(buf),format,arg); + va_end(arg); + } + + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "%sLine ignored [%s @%u]:\n%.*s\n", + buf, sf->name, sf->line, (int)(eol - sf->ptr), sf->ptr ); + } + + GotoEolSI(si); + return ERR_WARNING; +} + +/////////////////////////////////////////////////////////////////////////////// + +ccp FindEndOfLineSI +( + ScanInfo_t * si, // valid data + ccp ptr // start search here +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + while ( ptr < sf->end && *ptr != '\n' && *ptr != '\r' && *ptr ) + ptr++; + + return ptr; +} + +/////////////////////////////////////////////////////////////////////////////// + +ccp FindLineFeedSI +( + ScanInfo_t * si, // valid data + ccp ptr, // start search here + bool mark_error // true: increment error counter +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + if (mark_error) + { + sf->line_err++; + si->total_err++; + } + + while ( ptr < sf->end && *ptr != '\n' ) + ptr++; + + return ptr; +} + +/////////////////////////////////////////////////////////////////////////////// + +ccp FindNextLineFeedSI +( + ScanInfo_t * si, // valid data + bool mark_error // true: increment error counter +) +{ + DASSERT(si); + DASSERT(si->cur_file); + return FindLineFeedSI(si,si->cur_file->ptr,mark_error); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +uint ScanNameSI +( + // return length of name + + ScanInfo_t * si, // valid data + char * name_buf, // destination buffer + uint buf_size, // size of 'name_buf' + bool allow_minus, // true: allow '-' in names + bool to_upper, // true: convert letters to upper case + int * xyz // not null: store vector index + // -1: no index, 0=x, 1=y, 2=z +) +{ + DASSERT(si); + DASSERT(name_buf); + DASSERT(buf_size>1); + NextCharSI(si,false); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + sf->prev_ptr = sf->ptr; + char *dest = name_buf, *end = name_buf + buf_size - 1; + + for(;;) + { + ccp src = sf->ptr; + while ( src < sf->end ) + { + char ch = *src; + if ( ch >= 'A' && ch <= 'Z' + || ch >= '0' && ch <= '9' + || ch == '_' + || ch == '.' + || ch == '$' + || ch == '-' && allow_minus + ) + { + // nothing to do + } + else if ( ch >= 'a' && ch <= 'z' ) + { + if (to_upper) + ch += 'A' - 'a'; + } + else + break; + + src++; + if ( dest < end ) + *dest++ = ch; + } + sf->ptr = src; + + if ( dest == name_buf || NextCharSI(si,false) != '[' ) + break; + + sf->ptr++; + DEFINE_VAR(val); + CheckWarnSI(si,']',ScanExprSI(si,&val)); + char buf[20]; + snprintf(buf,sizeof(buf),"[%d]",GetIntV(&val)); + dest = StringCopyE(dest,end,buf); + } + memset(dest,0,name_buf+buf_size-dest); + + if (xyz) + { + *xyz = dest > name_buf+2 && dest[-2] == '.' && dest[-1] >= 'X' && dest[-1] <= 'Z' + ? dest[-1] - 'X' : -1; + noPRINT("NAME=%s XYZ=%d\n",name_buf,*xyz); + } + + return dest - name_buf; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ConcatStringsSI +( + ScanInfo_t * si, // valid data + char ** dest_str, // store string here, use FREE + MALLOC + uint * ret_len // not NULL: store length of return string here +) +{ + DASSERT(si); + + if (dest_str) + { + FreeString(*dest_str); + *dest_str = 0; + } + if (ret_len) + *ret_len = 0; + +// [[var-string-]] support of dynamic buffer + char buf[5000]; + char *buf_end = buf + sizeof(buf) - 1; + char *dest = buf, *dest_end = buf_end - 50; + + enumError err = ERR_OK; + while ( dest < dest_end ) + { + char ch = NextCharSI(si,false); + if ( !ch || ch == ',' || ch == ';' ) + break; + + if ( ch == '"' || ch == '\'' ) + { + DEFINE_VAR(temp); + err = ScanStringSI(si,&temp); + dest = StringCopyEM(dest,dest_end,temp.str,temp.str_len); + continue; + } + +// [[var-string-]] optimize? + DEFINE_VAR(var); + err = ScanExprSI(si,&var); + if (err) + break; + + switch (var.mode) + { + case VAR_INT: + dest += snprintf(dest,buf_end-dest,"%lld",var.i); + break; + + case VAR_DOUBLE: + dest += snprintf(dest,buf_end-dest,"%5.3f",var.d); + break; + + case VAR_VECTOR: + dest += snprintf(dest,buf_end-dest,"%5.3f,%5.3f,%5.3f", + var.x, var.y, var.z ); + break; + + case VAR_STRING: // [[var-string+]] NULL support missed! + dest = StringCopyE(dest,buf_end,var.str); + break; + + case VAR_UNSET: + break; + } + } + + const uint len = dest - buf; + if (ret_len) + *ret_len = len; + if (dest_str) + { + *dest_str = MEMDUP(buf,len); + noPRINT("STRING: |%s|\n",*dest_str); + } + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanStringSI +( + ScanInfo_t * si, // valid data + Var_t * var // store result here (already initialized) +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + DASSERT(var); + + DEFINE_VAR(temp); + temp.mode = VAR_STRING; + + enumError err = ERR_OK; + for(;;) + { + const char sep = NextCharSI(si,false); + if ( sep != '\'' && sep != '"' ) + break; + + ccp ptr = ++sf->ptr; + ccp eol = FindEndOfLineSI(si,ptr); + ccp start = ptr; + + while ( ptr < eol && *ptr != sep ) + { + const char ch = *ptr++; + if ( ch == '\\' && ptr < eol ) + ptr++; + } + + char buf[5000]; + const uint len + = ScanEscapedString( buf, sizeof(buf), start, ptr-start, true, 0, 0 ); + AppendStringVS(&temp,buf,len); + + if ( *ptr == sep ) + sf->ptr = ptr + 1; + else + { + sf->ptr = ptr; + err = ERROR0(ERR_WARNING, + "Unterminated string [%s @%u]\n", sf->name, sf->line ); + } + } + + MoveDataV(var,&temp); + return err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +char last_index_name[VARNAME_SIZE+1] = {0}; + +//----------------------------------------------------------------------------- + +int ScanIndexSI +( + ScanInfo_t * si, // valid data + enumError * err, // return value: error code + int index, // index to define if name + IndexList_t * il, // NULL or index list + int insert_mode // 0: don't insert + // 1: insert into global namespace + // 2: '1' + print "already defined" error +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + enumError local_err; + if (!err) + err = &local_err; + + char ch = NextCharSI(si,false); + if (IsNum(ch,0)) + { + u32 num; + *err = ScanU32SI(si,&num,1,0); + if (il) + DefineIL(il,index,0,0); + return num; + } + + *err = ERR_OK; + + const uint name_len + = ScanNameSI(si,last_index_name,sizeof(last_index_name),false,false,0); + if (!name_len) + { + *err = ERR_WARNING; + if (il) + DefineIL(il,index,0,0); + } + else if ( name_len > 1 || *last_index_name != '_' ) + { + if (il) + { + DefineIL(il,index,last_index_name,false); + noPRINT("DEFINE: %3u = %s\n",index,last_index_name); + } + + char *ptr = last_index_name; + while ( *ptr = toupper((int)*ptr) ) + ptr++; + + if ( insert_mode > 0 ) + { + bool found; + Var_t * var = InsertVarMap( &si->gvar, last_index_name, false, 0, &found ); + + if (found) + { + if ( insert_mode > 1 + && si->no_warn <= 0 + && ( var->mode != VAR_INT || var->i != index) ) + { + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "Variable '%s' already defined [%s @%u]: %.*s\n", + last_index_name, sf->name, sf->line, + (int)(eol - sf->prev_ptr), sf->prev_ptr ); + } + //*err = ERR_WARNING; + } + else + { + var->mode = VAR_INT; + var->i = index; + } + } + } + else + { + *last_index_name = 0; + if (il) + DefineIL(il,index,0,0); + } + + return index; +} + +//----------------------------------------------------------------------------- + +void SetIndexName ( ccp name ) +{ + if (!name) + name = ""; + char *dest = last_index_name; + char *end = dest + sizeof(last_index_name) -1 ; + while ( dest < end && *name ) + *dest++ = toupper((int)*name++); + *dest = 0; +} + +//----------------------------------------------------------------------------- + +bool DefineIndexInt +( + // returns true, if inserted + + ScanInfo_t * si, // valid data + ccp suffix, // name suffix + int value // value to assign +) +{ + if ( *last_index_name ) + { + char name[2*VARNAME_SIZE]; + snprintf(name,sizeof(name),"%s.%s",last_index_name,suffix); + + bool found; + Var_t * var = InsertVarMap( &si->gvar, name, false, 0, &found ); + noPRINT("DEFINE %s = %d\n",name,value); + var->mode = VAR_INT; + var->i = value; + return true; + } + return false; +} + +//----------------------------------------------------------------------------- + +bool DefineIndexDouble +( + // returns true, if inserted + + ScanInfo_t * si, // valid data + ccp suffix, // name suffix + double value // value to assign +) +{ + if ( *last_index_name ) + { + char name[2*VARNAME_SIZE]; + snprintf(name,sizeof(name),"%s.%s",last_index_name,suffix); + + bool found; + Var_t * var = InsertVarMap( &si->gvar, name, false, 0, &found ); + noPRINT("DEFINE %s = %g\n",name,value); + var->mode = VAR_DOUBLE; + var->d = value; + return true; + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanU8SI +( + ScanInfo_t * si, // valid data + u8 * dest, // destination list + int n, // number of elements in 'dest' + int force_hex // >0: force hex for non prefixed integers +) +{ + DASSERT(si); + DASSERT(dest); + DASSERT(n>0); + + while ( n-- > 0 ) + { + long num; + if (!ScanUValueSI(si,&num,force_hex)) + *dest++ = num; + else + { + while ( n-- >= 0 ) + *dest++ = 0; + return ERR_WARNING; + } + } + + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanU16SI +( + ScanInfo_t * si, // valid data + u16 * dest, // destination list + int n, // number of elements in 'dest' + int force_hex // >0: force hex for non prefixed integers +) +{ + DASSERT(si); + DASSERT(dest); + DASSERT(n>0); + + while ( n-- > 0 ) + { + long num; + if (!ScanUValueSI(si,&num,force_hex)) + *dest++ = num; + else + { + while ( n-- >= 0 ) + *dest++ = 0; + return ERR_WARNING; + } + } + + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanU32SI +( + ScanInfo_t * si, // valid data + u32 * dest, // destination list + int n, // number of elements in 'dest' + int force_hex // >0: force hex for non prefixed integers +) +{ + DASSERT(si); + DASSERT(dest); + DASSERT(n>0); + + while ( n-- > 0 ) + { + long num; + if (!ScanUValueSI(si,&num,force_hex)) + *dest++ = num; + else + { + while ( n-- >= 0 ) + *dest++ = 0; + return ERR_WARNING; + } + } + + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanBE16SI +( + ScanInfo_t * si, // valid data + u16 * dest, // destination list + int n, // number of elements in 'dest' + int force_hex // >0: force hex for non prefixed integers +) +{ + DASSERT(si); + DASSERT(dest); + DASSERT(n>0); + + while ( n-- > 0 ) + { + long num; + if (!ScanUValueSI(si,&num,force_hex)) + write_be16(dest++,num); + else + { + while ( n-- >= 0 ) + write_be16(dest++,0); + return ERR_WARNING; + } + } + + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanBE32SI +( + ScanInfo_t * si, // valid data + u32 * dest, // destination list + int n, // number of elements in 'dest' + int force_hex // >0: force hex for non prefixed integers +) +{ + DASSERT(si); + DASSERT(dest); + DASSERT(n>0); + + while ( n-- > 0 ) + { + long num; + if (!ScanUValueSI(si,&num,force_hex)) + write_be32(dest++,num); + else + { + while ( n-- >= 0 ) + write_be32(dest++,0); + return ERR_WARNING; + } + } + + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanBE32SI_swap +( + ScanInfo_t * si, // valid data + u32 * dest, // destination list + int n, // number of elements in 'dest' + int force_hex // >0: force hex for non prefixed integers +) +{ + DASSERT(si); + DASSERT(dest); + DASSERT(n>0); + + while ( n-- > 0 ) + { + long num; + if (!ScanUValueSI(si,&num,force_hex)) + { + u16 temp[2]; + write_be32(temp,num); + ((u16*)dest)[0] = be16(temp); + ((u16*)dest)[1] = be16(temp+1); + dest++; + } + else + { + while ( n-- >= 0 ) + write_be32(dest++,0); + return ERR_WARNING; + } + } + + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanFloatSI +( + ScanInfo_t * si, // valid data + float * dest, // destination list + int n // number of elements in 'dest' +) +{ + DASSERT(si); + DASSERT(dest); + DASSERT(n>0); + + while ( n-- > 0 ) + { + double num; + if (!ScanDValueSI(si,&num)) + *dest++ = num; + else + { + while ( n-- >= 0 ) + *dest++ = 0; + return ERR_WARNING; + } + } + + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanFloatV2SI +( + ScanInfo_t * si, // valid data + float * dest, // destination list + int n // number of 2d vectors in 'dest' +) +{ + DASSERT(si); + DASSERT(dest); + DASSERT(n>0); + + float *end = dest + 2*n; + + enumError err = ERR_OK; + while ( n-- > 0 ) + { + DEFINE_VAR(var); + err = ScanValueSI(si,&var); + if (err) + break; + *dest++ = GetXDoubleV(&var); + SkipCharSI(si,','); + + if ( var.mode == VAR_VECTOR ) + *dest++ = GetZDoubleV(&var); + else + { + err = ScanValueSI(si,&var); + if (err) + break; + *dest++ = GetZDoubleV(&var); + SkipCharSI(si,','); + } + } + + while ( dest < end ) + *dest++ = 0.0; + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanFloatV3SI +( + ScanInfo_t * si, // valid data + float * dest, // destination list + int n // number of 3d vectors in 'dest' +) +{ + DASSERT(si); + DASSERT(dest); + DASSERT(n>0); + + float *end = dest + 3*n; + + enumError err = ERR_OK; + while ( n-- > 0 ) + { + DEFINE_VAR(var); + err = ScanValueSI(si,&var); + if (err) + break; + *dest++ = GetXDoubleV(&var); + SkipCharSI(si,','); + + if ( var.mode == VAR_VECTOR ) + { + *dest++ = GetYDoubleV(&var); + *dest++ = GetZDoubleV(&var); + } + else + { + err = ScanValueSI(si,&var); + if (err) + break; + *dest++ = GetYDoubleV(&var); + SkipCharSI(si,','); + + err = ScanValueSI(si,&var); + if (err) + break; + *dest++ = GetZDoubleV(&var); + SkipCharSI(si,','); + } + } + + while ( dest < end ) + *dest++ = 0.0; + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanDoubleSI +( + ScanInfo_t * si, // valid data + double * dest, // destination list + int n // number of elements in 'dest' +) +{ + DASSERT(si); + DASSERT(dest); + DASSERT(n>0); + + while ( n-- > 0 ) + { + double num; + if (!ScanDValueSI(si,&num)) + *dest++ = num; + else + { + while ( n-- >= 0 ) + *dest++ = 0; + return ERR_WARNING; + } + } + + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanDoubleV3SI +( + ScanInfo_t * si, // valid data + double * dest, // destination list + int n // number of 3d vectors in 'dest' +) +{ + DASSERT(si); + DASSERT(dest); + DASSERT(n>0); + + double *end = dest + 3*n; + + enumError err = ERR_OK; + while ( n-- > 0 ) + { + DEFINE_VAR(var); + err = ScanValueSI(si,&var); + if (err) + break; + *dest++ = GetXDoubleV(&var); + SkipCharSI(si,','); + + if ( var.mode == VAR_VECTOR ) + { + *dest++ = GetYDoubleV(&var); + *dest++ = GetZDoubleV(&var); + } + else + { + err = ScanValueSI(si,&var); + if (err) + break; + *dest++ = GetYDoubleV(&var); + SkipCharSI(si,','); + + err = ScanValueSI(si,&var); + if (err) + break; + *dest++ = GetZDoubleV(&var); + SkipCharSI(si,','); + } + } + + while ( dest < end ) + *dest++ = 0.0; + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SetVarSI +( + ScanInfo_t * si, // valid data + VarMap_t * vm, // valid varmap + TextCommand_t mode // TCMD_DEF* +) +{ + DASSERT(si); + DASSERT(vm); + + enum EnumMode { EM_OFF, EM_ENUM, EM_SHIFT } enum_mode; + switch (mode) + { + case TCMD_PDEF_ENUM: enum_mode = EM_ENUM; mode = TCMD_PDEF; break; + case TCMD_PDEF_SHIFT: enum_mode = EM_SHIFT; mode = TCMD_PDEF; break; + case TCMD_LDEF_ENUM: enum_mode = EM_ENUM; mode = TCMD_LDEF; break; + case TCMD_LDEF_SHIFT: enum_mode = EM_SHIFT; mode = TCMD_LDEF; break; + case TCMD_GDEF_ENUM: enum_mode = EM_ENUM; mode = TCMD_GDEF; break; + case TCMD_GDEF_SHIFT: enum_mode = EM_SHIFT; mode = TCMD_GDEF; break; + default: enum_mode = EM_OFF; break; + } + + DEFINE_VAR(next_val); + AssignIntV( &next_val, enum_mode == EM_SHIFT ); + + restart:; + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + int xyz; + char name[VARNAME_SIZE+1]; + if (!ScanNameSI(si,name,sizeof(name),false,true,&xyz)) + { + if ( si->no_warn <= 0 ) + { + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "Missing name [%s @%u]: %.*s\n", + sf->name, sf->line, + (int)(eol - sf->prev_ptr), sf->prev_ptr ); + } + return ERR_WARNING; + } + if ( mode != TCMD_PDEF && mode != TCMD_LDEF && mode != TCMD_GDEF ) + xyz = -2; + + char ch = NextCharSI(si,false); + bool have_param = ch && ch != ','; + bool overwrite = have_param || enum_mode != EM_OFF; + if ( ch == '?' ) + { + sf->ptr++; + overwrite = false; + } + + DEFINE_VAR(val); + if (have_param) + { + if ( NextCharSI(si,false) != '=' ) + { + if ( si->no_warn <= 0 ) + { + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "Missing '=' [%s @%u]: %.*s\n", + sf->name, sf->line, + (int)(eol - sf->prev_ptr), sf->prev_ptr ); + } + return ERR_WARNING; + } + sf->ptr++; + + enumError err = ScanExprSI(si,&val); + if (err) + return err; + } + else if ( enum_mode != EM_OFF ) + { + AssignVar(&val,&next_val); + have_param = true; + noPRINT_IF( val.mode == VAR_INT, "NEXT: %s = %d\n",name,GetIntV(&val)); + noPRINT_IF( val.mode == VAR_DOUBLE, "NEXT: %s ~ %g\n",name,GetDoubleV(&val)); + } + else + val.mode = VAR_UNSET; + + switch (enum_mode) + { + case EM_ENUM: + if ( val.mode >= VAR_DOUBLE ) + AssignDoubleV(&next_val,GetDoubleV(&val)+1); + else + AssignIntV(&next_val,GetIntV(&val)+1); + break; + + case EM_SHIFT: + if ( val.mode >= VAR_DOUBLE ) + AssignDoubleV(&next_val, GetDoubleV(&val) * 2 ); + else + AssignIntV(&next_val, GetIntV(&val) << 1 ); + break; + + default: + break; + } + + bool found; + Var_t *var = OverwriteVarSI( 0, vm, name, &xyz, &found ); + + DASSERT(var); + if ( overwrite || !found ) + { + if ( xyz >= 0 ) + { + DASSERT( xyz <= 2 ); + DASSERT( var->mode == VAR_VECTOR ); + var->v[xyz] = GetDoubleV(&val); + } + else + AssignVarMode(var,&val,mode); + } + else if (!have_param) + ToVarMode(var,mode); + + if ( NextCharSI(si,false) == ',' ) + { + sf->ptr++; + goto restart; + } + + return CheckEolSI(si); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanAssignIntSI +( + ScanInfo_t * si, // valid data + int * value // result: scanned value +) +{ + DASSERT(si); + DASSERT(si->cur_file); + DASSERT(value); + + if ( NextCharSI(si,false) == '=' ) + si->cur_file->ptr++; + + DEFINE_VAR(val); + enumError err = ScanExprSI(si,&val); + *value = GetIntV(&val); + return err ? err : CheckEolSI(si); +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanAssignDoubleSI +( + ScanInfo_t * si, // valid data + double * value // result: scanned value +) +{ + DASSERT(si); + DASSERT(si->cur_file); + DASSERT(value); + + if ( NextCharSI(si,false) == '=' ) + si->cur_file->ptr++; + + DEFINE_VAR(val); + enumError err = ScanExprSI(si,&val); + *value = GetDoubleV(&val); + return err ? err : CheckEolSI(si); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanParamSI +( + ScanInfo_t * si, // valid data + const ScanParam_t * sp // NULL or scan parameter + // list ends with sp->name==NULL +) +{ + DASSERT(si); + + static const ScanParam_t ptab[] = {{0}}; + if (!sp) + sp = ptab; + + #if HAVE_PRINT0 + const ScanParam_t *sp0 = sp; + #endif + + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + char ch = NextCharSI(si,false); + if ( ch == '@' ) + { + sf->ptr++; + ch = NextCharSI(si,false); + } + + char name[VARNAME_SIZE+1]; + if (!ScanNameSI(si,name,sizeof(name),true,true,0)) + { + if ( si->no_warn <= 0 ) + { + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "Missing name [%s @%u]: %.*s\n", + sf->name, sf->line, + (int)(eol - sf->prev_ptr), sf->prev_ptr ); + } + return ERR_WARNING; + } + + for ( ; sp->name; sp++ ) + if (!strcmp(name,sp->name)) + break; + + if (!sp->name) + { + if ( si->no_warn <= 0 ) + { + #if HAVE_PRINT0 + PRINT(">>> SEARCH: |%s|\n",name); + for ( ; sp0->name; sp0++ ) + PRINT(">>> HAVE NAME: |%s| => %d\n",sp0->name,!strcmp(name,sp0->name)); + #endif + + sf->line_err++; + si->total_err++; + ERROR0(ERR_WARNING, + "Unknown key [%s @%u]: %s\n", + sf->name, sf->line, name ); + } + + GotoEolSI(si); + return ERR_WARNING; + } + + if ( sp->mode == SPM_INC ) + { + // special case; increment value + if (sp->result) + ((int*)sp->result)[0]++; + if (sp->n_result) + *sp->n_result = 0; + + CheckEolSI(si); + return ERR_OK; + } + + if ( NextCharSI(si,false) == '=' ) + sf->ptr++; + + if ( sp->mode == SPM_STRING ) // special case: STRING + return ConcatStringsSI(si,(char**)sp->result,0); + + sf->disable_comma++; + + enumError max_err = ERR_OK; + const uint min = sp->min > 0 ? sp->min : 1; + const uint max = sp->max > min ? sp->max : min; + uint i, n_result = 0, skip = 0; + for ( i = 0; i < max; i++ ) + { + if ( i && NextCharSI(si,false) == ',' ) + sf->ptr++; + + if ( i >= min && !NextCharSI(si,false) ) + skip++; + + DEFINE_VAR(val); + if (skip) + val.mode = VAR_UNSET; + else + { + enumError err = ScanExprSI(si,&val); + if ( err > ERR_WARNING ) + skip++; + else + n_result++; + if ( max_err < err ) + max_err = err; + } + + if (sp->result) + switch(sp->mode) + { + case SPM_NONE: + case SPM_INC: + break; + + case SPM_BOOL: + ((bool*)sp->result)[i] = GetBoolV(&val); + break; + + case SPM_U8: + case SPM_S8: + ((u8*)sp->result)[i] = GetIntV(&val); + break; + + case SPM_U16: + case SPM_S16: + ((u16*)sp->result)[i] = GetIntV(&val); + break; + + case SPM_U32: + case SPM_S32: + ((u32*)sp->result)[i] = GetIntV(&val); + break; + + case SPM_U16_BE: + case SPM_S16_BE: + ((u16*)sp->result)[i] = htons(GetIntV(&val)); + break; + + case SPM_U32_BE: + case SPM_S32_BE: + ((u32*)sp->result)[i] = htonl(GetIntV(&val)); + break; + + case SPM_INT: + case SPM_UINT: + ((uint*)sp->result)[i] = GetIntV(&val); + break; + + case SPM_FLOAT: + ((float*)sp->result)[i] = GetDoubleV(&val); + break; + + case SPM_FLOAT_BE: + write_bef4( ((float*)sp->result)+i, GetDoubleV(&val) ); + break; + + case SPM_DOUBLE: + ((double*)sp->result)[i] = GetDoubleV(&val); + break; + + case SPM_DOUBLE_X: + ((double*)sp->result)[i] = GetXDoubleV(&val); + break; + + case SPM_DOUBLE_Y: + ((double*)sp->result)[i] = GetYDoubleV(&val); + break; + + case SPM_DOUBLE_Z: + ((double*)sp->result)[i] = GetZDoubleV(&val); + break; + + case SPM_FLOAT3: + ((float3*)sp->result)[i] = GetVectorFV(&val); + break; + + case SPM_FLOAT3_BE: + { + float3 src = GetVectorFV(&val); + float3 *dest = ((float3*)sp->result)+i; + write_bef4(&dest->x,src.x); + write_bef4(&dest->y,src.y); + write_bef4(&dest->z,src.z); + } + break; + + case SPM_VAR: + AssignVar(((Var_t*)sp->result)+i,&val); + break; + + case SPM_STRING: + ASSERT(0); + break; + } + } + if (sp->n_result) + *sp->n_result = n_result; + + sf->disable_comma--; + CheckEolSI(si); + return max_err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanHexlineSI +( + ScanInfo_t * si, // valid data + FastBuf_t * dest, // valid, append scanned data here + bool skip_addr // true: line may start with address field +) +{ + DASSERT(si); + DASSERT(dest); + + NextCharSI(si,false); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + //--- skip address field + + if (skip_addr) + { + ccp ptr = sf->ptr; + while (isalnum((int)*ptr)) + ptr++; + if ( ptr > sf->ptr && *ptr == ':' ) + sf->ptr = ptr + 1; + } + + Var_t val; + InitializeV(&val); + + enumError err = ERR_OK; + for(;;) + { + char ch = NextCharSI(si,false); + if (!ch) + break; + + if ( ch == ':' || ch == '/' || ch == '#' ) + { + GotoEolSI(si); + break; + } + + if ( ch == '(' ) + { + sf->ptr++; + err = ScanExprSI(si,&val); + err = CheckWarnSI(si,')',err); + if (err) + break; + + switch (val.mode) + { + case VAR_UNSET: + // nothing to do + break; + + case VAR_INT: + AppendInt64FastBuf( dest, val.i, val.int_mode ? val.int_mode : IMD_BE4 ); + break; + + case VAR_DOUBLE: + { + float f = val.d; + AppendBE32FastBuf(dest,*(u32*)&f); + } + break; + + case VAR_VECTOR: + { + float f = val.x; + AppendBE32FastBuf(dest,*(u32*)&f); + f = val.y; + AppendBE32FastBuf(dest,*(u32*)&f); + f = val.z; + AppendBE32FastBuf(dest,*(u32*)&f); + } + break; + + case VAR_STRING: + AppendFastBuf(dest,val.str,val.str_len); + break; + } + } + else + { + u8 data; + err = ScanU8SI(si,&data,1,true); + if (err) + break; + + AppendCharFastBuf(dest,data); + } + } + + CheckEolSI(si); + ResetV(&val); + return err; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// text commands /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_SkipToENDIF +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + DASSERT(si->cur_file); + + const int start_level = si->cur_file->if_level; + for(;;) + { + const char ch = NextLineSI(si,true,false); // don't use 'sf' + if (!ch) + return ERR_WARNING; + if ( ch != '@' ) + continue; + + const TextCommand_t tcmd = ScanTextCommand(si); + if ( tcmd == TCMD_IF ) + si->cur_file->if_level++; + else if ( tcmd == TCMD_ENDIF && --si->cur_file->if_level < start_level ) + return ERR_OK; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_IF +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + DASSERT(si->cur_file); + TRACE("### IF ###\n"); + si->cur_file->if_level++; + + DEFINE_VAR(cond); + enumError err = ScanExprSI(si,&cond); + if (err) + return err; + + err = CheckEolSI(si); + if (err) + return err; + + while (!GetBoolV(&cond)) + { + const char ch = NextLineSI(si,true,false); + DASSERT(si->cur_file); + if (!ch) + return ERR_WARNING; + if ( ch != '@' ) + continue; + + const TextCommand_t tcmd = ScanTextCommand(si); + switch (tcmd) + { + case TCMD_IF: + si->cur_file->if_level++; + SI_SkipToENDIF(si); + break; + + case TCMD_ELIF: + err = ScanExprSI(si,&cond); + if (err) + return err; + + err = CheckEolSI(si); + if (err) + return err; + break; + + case TCMD_ELSE: + return CheckEolSI(si); + + case TCMD_ENDIF: + si->cur_file->if_level--; + return CheckEolSI(si); + + default: + break; + } + } + + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_ELSE +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + DASSERT(si->cur_file); + TRACE("### ELSE/ELIF ###\n"); + + if ( si->cur_file->if_level <= 0 ) + { + if ( si->no_warn <= 0 ) + { + si->total_err++; + ERROR0(ERR_WARNING, + "Illegal '@ELSE' or '@ELIF' -> ignored [%s @%u]\n", + si->cur_file->name, si->cur_file->line ); + } + return ERR_WARNING; + } + + return SI_SkipToENDIF(si); +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_ENDIF +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + TRACE("### ENDIF ###\n"); + + CheckEolSI(si); + if ( sf->if_level <= 0 ) + { + if ( si->no_warn <= 0 ) + { + si->total_err++; + ERROR0(ERR_WARNING, + "Illegal '@ENDIF' -> ignored [%s @%u]\n", + sf->name, sf->line ); + } + return ERR_WARNING; + } + + sf->if_level--; + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_DOIF +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + noPRINT("### DOIF ###\n"); + + enumError err = CheckWarnSI(si,'(',ERR_OK); + if (!err) + { + DEFINE_VAR(cond); + err = ScanExprSI(si,&cond); + err = CheckWarnSI(si,')',err); + if ( err || !GetBoolV(&cond) ) + GotoEolSI(si); + } + return err; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// loop helpers + +static ccp loop_name[] = // same order as TCMD_LOOP... & TCMD_ENDLOOP... +{ + "LOOP", + "REPEAT", + "FOR", + "FOREACH", + "WHILE" +}; + +//----------------------------------------------------------------------------- + +static ccp GetLoopName ( TextCommand_t tcmd_end ) +{ + return tcmd_end >= TCMD_LOOP && tcmd_end <= TCMD_WHILE + ? loop_name[tcmd_end-TCMD_LOOP] + : tcmd_end >= TCMD_ENDLOOP && tcmd_end <= TCMD_ENDWHILE + ? loop_name[tcmd_end-TCMD_ENDLOOP] + : "?"; +} + +//----------------------------------------------------------------------------- + +static ccp GetLoopNameL ( const ScanLoop_t * loop ) +{ + return loop ? GetLoopName(loop->tcmd_end) : "-"; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static ScanLoop_t * SI_CheckLoop +( + ScanInfo_t * si, // valid data + TextCommand_t tcmd_end, // loop termiantion command + enumError * return_stat // store return status (never NULL) +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + DASSERT( sf->loop_level >= 0 && sf->loop_level <= MAX_LOOP_DEPTH ); + DASSERT( tcmd_end >= TCMD_ENDLOOP && tcmd_end <= TCMD_ENDWHILE ); + DASSERT(return_stat); + + noPRINT("##%s## SI_CheckLoop() line=%u, loop_level=%d\n", + GetLoopName(tcmd_end), sf->line, sf->loop_level ); + + if ( sf->loop_level < MAX_LOOP_DEPTH ) + { + ScanLoop_t * loop = sf->loop + sf->loop_level++; + + loop->tcmd_end = tcmd_end; + loop->ptr = sf->ptr; + loop->line = sf->line; + loop->if_level = sf->if_level; + + loop->count_val = 0; + loop->end_val = 1; + loop->step_val = 1; + + FreeString(loop->varname); + loop->varname = 0; + loop->expr_ptr = 0; + loop->expr_line = 0; + + *return_stat = ERR_OK; + return loop; + } + + if ( si->no_warn <= 0 ) + { + si->total_err++; + ERROR0(ERR_WARNING, + "To many nested loops (max=%u) [%s @%u]\n", + MAX_LOOP_DEPTH, sf->name, sf->line ); + } + + *return_stat = ERR_WARNING; + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static ScanLoop_t * SI_CheckEndLoop +( + ScanInfo_t * si, // valid data + TextCommand_t tcmd_end, // loop termiantion command + enumError * return_stat // store return status (never NULL) +) +{ + DASSERT( si ); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + DASSERT( sf->loop_level >= 0 && sf->loop_level <= MAX_LOOP_DEPTH ); + DASSERT( !tcmd_end || tcmd_end >= TCMD_ENDLOOP && tcmd_end <= TCMD_ENDWHILE ); + DASSERT( return_stat ); + noPRINT("##%s## SI_CheckEndLoop() line=%u, loop_level=%d\n", + GetLoopName(tcmd_end), sf->line, sf->loop_level ); + + enumError err = CheckEolSI(si); + const int loop_level = sf->loop_level; + DASSERT( loop_level >= 0 && loop_level <= MAX_LOOP_DEPTH ); + if (loop_level) + { + ScanLoop_t * loop = sf->loop + loop_level - 1; + if ( !tcmd_end || loop->tcmd_end == tcmd_end ) + { + loop->count_val += loop->step_val; + *return_stat = err; + return loop; + } + } + + if ( si->no_warn <= 0 && tcmd_end ) + { + si->total_err++; + if (loop_level) + { + ScanLoop_t * loop = sf->loop + loop_level - 1; + ERROR0(ERR_WARNING, + "End of loop command '@END%s' does not match current '%s' loop [%s @%u]\n", + GetLoopName(tcmd_end), GetLoopName(loop->tcmd_end), + sf->name, sf->line ); + } + else + { + ERROR0(ERR_WARNING, + "End of loop command 'END%s' not allowed outside a loop [%s @%u]\n", + GetLoopName(tcmd_end), sf->name, sf->line ); + } + } + + *return_stat = ERR_WARNING; + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void SI_RestartLoop +( + ScanInfo_t * si, // valid data + ScanLoop_t * loop // valid loop pointer +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + DASSERT(loop); + DASSERT( loop == sf->loop + sf->loop_level - 1 ); + noPRINT("##%s## SI_RestartLoop()\n", GetLoopName(loop->tcmd_end) ); + + sf->ptr = loop->ptr; + sf->line = loop->line; + sf->if_level = loop->if_level; +} + +/////////////////////////////////////////////////////////////////////////////// + +static void SI_ExitLoop +( + ScanInfo_t * si, // valid data + ScanLoop_t * loop // valid loop pointer +) +{ + // exit loop at end-loop-command + + DASSERT(si); + noPRINT("##%s## SI_ExitLoop()\n", GetLoopNameL(loop) ); + + if (loop) + { + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + DASSERT( loop == sf->loop + sf->loop_level - 1 ); + + sf->if_level = loop->if_level; + if ( --sf->loop_level > 0 ) + { + loop--; + if ( loop >= sf->loop && loop->varname ) + { + Var_t *var = InsertVarMap(&si->lvar,loop->varname,false,0,0); + var->mode = VAR_INT; + var->i = loop->count_val; + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static void SI_TerminateLoop +( + ScanInfo_t * si, // valid data + ScanLoop_t * loop // valid loop pointer +) +{ + DASSERT(si); + DASSERT(si->cur_file); + DASSERT(loop); + DASSERT( loop == si->cur_file->loop + si->cur_file->loop_level - 1 ); + noPRINT("##%s## SI_TerminateLoop()\n", GetLoopName(loop->tcmd_end) ); + + const TextCommand_t tcmd_beg = TCMD_LOOP - TCMD_ENDLOOP + loop->tcmd_end; + int level = 1; + for(;;) + { + const char ch = NextLineSI(si,true,false); + DASSERT(si->cur_file); + if (!ch) + return; + if ( ch != '@' ) + continue; + + const TextCommand_t tcmd = ScanTextCommand(si); + if ( tcmd == tcmd_beg ) + level++; + else if ( tcmd == loop->tcmd_end && !--level ) + break; + } + + CheckEolSI(si); + SI_ExitLoop(si,loop); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// loop commands /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_LOOP +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + noPRINT("##LOOP(BEGIN)##\n"); + + enumError err; + ScanLoop_t * loop = SI_CheckLoop(si,TCMD_ENDLOOP,&err); + if (loop) + { + if (err) + GotoEolSI(si); + else + CheckEolSI(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + loop->ptr = sf->ptr; + loop->line = sf->line; + } + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_ENDLOOP +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + noPRINT("##LOOP(END)##\n"); + + enumError err; + ScanLoop_t * loop = SI_CheckEndLoop(si,TCMD_ENDLOOP,&err); + if (loop) + SI_RestartLoop(si,loop); + else + SI_ExitLoop(si,loop); + return err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_REPEAT +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + noPRINT("##REPEAT(BEGIN)##\n"); + + enumError err; + ScanLoop_t * loop = SI_CheckLoop(si,TCMD_ENDREPEAT,&err); + if (loop) + { + DEFINE_VAR(val); + err = ScanExprSI(si,&val); + loop->end_val = GetIntV(&val); + noPRINT("-> count=%d/%d +%d\n",loop->count_val,loop->end_val,loop->step_val); + + if (err) + GotoEolSI(si); + else + CheckEolSI(si); + + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + loop->ptr = sf->ptr; + loop->line = sf->line; + + if ( loop->count_val >= loop->end_val ) + SI_TerminateLoop(si,loop); + } + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_ENDREPEAT +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + noPRINT("##REPEAT(END)##\n"); + + enumError err; + ScanLoop_t * loop = SI_CheckEndLoop(si,TCMD_ENDREPEAT,&err); + if ( loop && loop->count_val < loop->end_val ) + SI_RestartLoop(si,loop); + else + SI_ExitLoop(si,loop); + return err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static enumError scan_for_varname +( + ScanInfo_t * si, // valid data + ScanLoop_t * loop // valid loop pointer +) +{ + DASSERT(si); + DASSERT(loop); + + char name[VARNAME_SIZE+1]; + if (!ScanNameSI(si,name,sizeof(name),false,true,0)) + { + if ( si->no_warn <= 0 ) + { + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "Missing name [%s @%u]: %.*s\n", + sf->name, sf->line, + (int)(eol - sf->prev_ptr), sf->prev_ptr ); + } + return ERR_WARNING; + } + + loop->varname = STRDUP(name); + return CheckWarnSI(si,'=',0); +} + +//----------------------------------------------------------------------------- + +static enumError SI_FOR +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + noPRINT("##FOR(BEGIN)##\n"); + + enumError err; + ScanLoop_t * loop = SI_CheckLoop(si,TCMD_ENDFOR,&err); + if (loop) + { + err = scan_for_varname(si,loop); + if (err) + goto abort; + + DEFINE_VAR(val); + err = ScanExprSI(si,&val); + if (err) + goto abort; + loop->count_val = GetIntV(&val); + + err = CheckWarnSI(si,';',err); + if (err) + goto abort; + err = ScanExprSI(si,&val); + if (err) + goto abort; + loop->end_val = GetIntV(&val); + + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + if ( NextCharSI(si,false) == ';' ) + { + sf->ptr++; + err = ScanExprSI(si,&val); + if (err) + goto abort; + loop->step_val = GetIntV(&val); + } + + if (err) + GotoEolSI(si); + else + CheckEolSI(si); + loop->ptr = sf->ptr; + loop->line = sf->line; + + noPRINT("-> FOR %s = %d -> %d, step = %d\n", + loop->varname, loop->count_val, loop->end_val, loop->step_val ); + + Var_t *var = InsertVarMap(&sf->pvar,loop->varname,false,0,0); + var->mode = VAR_INT; + var->i = loop->count_val; + + if ( loop->step_val > 0 && loop->count_val > loop->end_val + || loop->step_val < 0 && loop->count_val < loop->end_val ) + goto abort; + } + return err; + + abort: + GotoEolSI(si); + if (loop) + SI_TerminateLoop(si,loop); + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_ENDFOR +( + ScanInfo_t * si, // valid data + ScanLoop_t * loop // not NULL: SI_CheckEndLoop() already done + // + call TermLoop() instead of ExitLoop() +) +{ + DASSERT(si); + noPRINT("##FOR(END)##\n"); + + enumError err = ERR_OK; + bool use_term = loop != 0; + if (!loop) + loop = SI_CheckEndLoop(si,TCMD_ENDFOR,&err); + + if (loop) + { + if ( loop->step_val > 0 && loop->count_val > loop->end_val + || loop->step_val < 0 && loop->count_val < loop->end_val ) + { + if (use_term) + SI_TerminateLoop(si,loop); + else + SI_ExitLoop(si,loop); + } + else + { + DASSERT(si->cur_file); + Var_t *var = InsertVarMap(&si->cur_file->pvar,loop->varname,false,0,0); + var->mode = VAR_INT; + var->i = loop->count_val; + SI_RestartLoop(si,loop); + } + } + return err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_FOREACH +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + noPRINT("##WHILE(BEGIN)##\n"); + + enumError err; + ScanLoop_t * loop = SI_CheckLoop(si,TCMD_ENDFOREACH,&err); + if (loop) + { + err = scan_for_varname(si,loop); + if (err) + { + GotoEolSI(si); + SI_TerminateLoop(si,loop); + return err; + } + + if (!NextCharSI(si,false)) + SI_TerminateLoop(si,loop); + else + { + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + Var_t *var = InsertVarMap(&sf->pvar,loop->varname,false,0,0); + err = ScanExprSI(si,var); + + loop->expr_ptr = sf->ptr; + loop->expr_line = sf->line; + + GotoEolSI(si); + loop->ptr = sf->ptr; + loop->line = sf->line; + } + } + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_ENDFOREACH +( + ScanInfo_t * si, // valid data + ScanLoop_t * loop // not NULL: SI_CheckEndLoop() already done + // + call TermLoop() instead of ExitLoop() +) +{ + DASSERT(si); + noPRINT("##WHILE(END)##\n"); + + enumError err = ERR_OK; + bool use_term = loop != 0; + if (!loop) + loop = SI_CheckEndLoop(si,TCMD_ENDFOREACH,&err); + + if (loop) + { + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + DASSERT(loop->expr_ptr); + ccp saved_ptr = sf->ptr; + uint saved_line = sf->line; + sf->ptr = loop->expr_ptr; + sf->line = loop->expr_line; + + if ( NextCharSI(si,false) == ';' ) + sf->ptr++; + + if (NextCharSI(si,false)) + { + Var_t *var = InsertVarMap(&sf->pvar,loop->varname,false,0,0); + ccp saved_ptr = sf->ptr; + err = ScanExprSI(si,var); + if ( sf->ptr > saved_ptr ) + { + loop->expr_ptr = sf->ptr; + loop->expr_line = sf->line; + SI_RestartLoop(si,loop); + return err; + } + } + + sf->ptr = saved_ptr; + sf->line = saved_line; + } + + if (use_term) + SI_TerminateLoop(si,loop); + else + SI_ExitLoop(si,loop); + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_WHILE +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + noPRINT("##WHILE(BEGIN)##\n"); + + enumError err; + ScanLoop_t * loop = SI_CheckLoop(si,TCMD_ENDWHILE,&err); + if (loop) + { + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + loop->expr_ptr = sf->ptr; + loop->expr_line = sf->line; + + DEFINE_VAR(val); + err = ScanExprSI(si,&val); + + if (err) + GotoEolSI(si); + else + CheckEolSI(si); + loop->ptr = sf->ptr; + loop->line = sf->line; + + if (!GetBoolV(&val)) + SI_TerminateLoop(si,loop); + } + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_ENDWHILE +( + ScanInfo_t * si, // valid data + ScanLoop_t * loop // not NULL: SI_CheckEndLoop() already done + // + call TermLoop() instead of ExitLoop() +) +{ + DASSERT(si); + noPRINT("##WHILE(END)##\n"); + + enumError err = ERR_OK; + bool use_term = loop != 0; + if (!loop) + loop = SI_CheckEndLoop(si,TCMD_ENDWHILE,&err); + + if (loop) + { + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + DASSERT(loop->expr_ptr); + ccp saved_ptr = sf->ptr; + uint saved_line = sf->line; + sf->ptr = loop->expr_ptr; + sf->line = loop->expr_line; + + DEFINE_VAR(val); + err = ScanExprSI(si,&val); + if ( !err && GetBoolV(&val) ) + { + SI_RestartLoop(si,loop); + return ERR_OK; + } + + sf->ptr = saved_ptr; + sf->line = saved_line; + } + + if (use_term) + SI_TerminateLoop(si,loop); + else + SI_ExitLoop(si,loop); + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_BreakLoop +( + ScanInfo_t * si, // valid data + bool is_continue // true: is @CONTINUE +) +{ + DASSERT(si); + + ccp tcmd_name = is_continue ? "CONTINUE" : "BREAK"; + noPRINT("##%s##\n",tcmd_name); + + enumError err = ERR_OK; + char ch = NextCharSI(si,false); + int level = 1; + if ( ch && ch != '@' ) + { + DEFINE_VAR(val); + err = ScanExprSI(si,&val); + level = GetIntV(&val); + if ( level < 1 ) + level = 1; + ch = NextCharSI(si,false); + } + + bool cond = true; + if ( ch == '@' ) + { + const TextCommand_t tcmd = ScanTextCommand(si); + if ( tcmd != TCMD_IF ) + { + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + ERROR0(ERR_WARNING, + "Commandline '@%s ... @IF ...' expected [%s @%u]\n", + tcmd_name, sf->name, sf->line ); + } + else + { + DEFINE_VAR(val); + err = ScanExprSI(si,&val); + if (!err) + cond = GetBoolV(&val); + } + } + CheckEolSI(si); + noPRINT(""##%s##\n" -> cond = %d, level = %d\n",cond,level); + if (!cond) + return err; + + while ( level-- > 0 ) + { + ScanLoop_t * loop = SI_CheckEndLoop(si,0,&err); + if (!loop) + break; + + if ( !is_continue || level > 0 ) + SI_TerminateLoop(si,loop); + else + { + // CONTINUE + switch(loop->tcmd_end) + { + case TCMD_ENDLOOP: + SI_RestartLoop(si,loop); + break; + + case TCMD_ENDREPEAT: + if ( loop->count_val < loop->end_val ) + SI_RestartLoop(si,loop); + else + SI_TerminateLoop(si,loop); + break; + + case TCMD_ENDFOR: + SI_ENDFOR(si,loop); + break; + + case TCMD_ENDFOREACH: + SI_ENDFOREACH(si,loop); + break; + + case TCMD_ENDWHILE: + SI_ENDWHILE(si,loop); + break; + } + } + } + + return err; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// exec, include and macros + +static enumError SI_EXEC +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + char *str = 0; + uint len = 0; + enumError err = ConcatStringsSI(si,&str,&len); + + if (!err) + { + sf = AddSF(si,str,len,"@EXEC",si->init_revision,0); + if (sf) + { + sf->data_alloced = true; + NextCharSI(si,true); + } + } + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_INCLUDE +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + const bool have_quote = NextCharSI(si,false) == '"'; + sf->prev_ptr = sf->ptr; + + ccp start, ptr; + if (have_quote) + { + start = ptr = sf->ptr + 1; + while ( ptr < sf->end && *ptr && *ptr != '"' ) + ptr++; + + if ( *ptr == '"' ) + sf->ptr = ptr + 1; + else + { + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "Missing '\"' [%s @%u]: %.*s\n", + sf->name, sf->line, + (int)(eol - sf->prev_ptr), sf->prev_ptr ); + sf->ptr = ptr; + } + } + else + { + start = ptr = sf->ptr; + while ( ptr < sf->end && (u8)*ptr > ' ' ) + ptr++; + sf->ptr = ptr; + } + CheckEolSI(si); + + char path[PATH_MAX]; + ccp slash = strrchr(sf->name,'/'); + uint len1 = slash ? slash+1 - sf->name : 0; + if ( len1 > sizeof(path) - 1 ) + len1 = sizeof(path) - 1; + memcpy(path,sf->name,len1); + + uint len2 = ptr - start; + if ( len2 > sizeof(path) - len1 - 1 ) + len2 = sizeof(path) - len1 - 1; + memcpy(path+len1,start,len2); + path[len1+len2] = 0; + + PRINT("SI_INCLUDE(%s) quote=%d\n",path,have_quote); + + u8 *data; + uint size; + ccp fname; + enumError err = OpenReadFILE(path,0,false,&data,&size,&fname,0); + if (err) + { + FREE(data); + FreeString(fname); + } + else + { + sf = AddSF(si,(ccp)data,size,fname,si->init_revision,0); + if (sf) + { + sf->data_alloced = sf->name_alloced = true; + noPRINT(" -> %.30s\n",sf->ptr); + NextCharSI(si,true); + } + } + + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_RETURN +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + noPRINT("SI_RETURN()\n"); + + si->last_result.mode = VAR_UNSET; + enumError err = ERR_OK; + if (NextCharSI(si,false)) + { + err = ScanExprSI(si,&si->last_result); + CheckEolSI(si); + } + + DropSF(si); + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_EXIT +( + ScanInfo_t * si, // valid data + bool is_assert // true: @ASSERT +) +{ + DASSERT(si); + PRINT("SI_RETURN()\n"); + + enumError err = ERR_OK; + if (is_assert) + { + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + ccp prev = sf->ptr; + + DEFINE_VAR(cond); + ScanExprSI(si,&cond); + if (GetBoolV(&cond)) + { + CheckEolSI(si); + return ERR_OK; + } + + //ccp eol = FindNextLineFeedSI(si,true); + err = ERROR0(ERR_ERROR, + "Assertion failed [%s @%u]: %.*s\n", + sf->name, sf->line, + (int)(sf->ptr - prev), prev ); + GotoEolSI(si); + } + + CheckEolSI(si); + while (DropSF(si)) + ; + return err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_MACRO +( + ScanInfo_t * si, // valid data + TextCommand_t tcmd_beg // command to execute +) +{ + DASSERT(si); + + char mname[VARNAME_SIZE+1]; + bool valid = ScanNameSI(si,mname,sizeof(mname),false,true,0) > 0; + CheckEolSI(si); + + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + ccp macro_begin = sf->ptr; + ccp macro_end = macro_begin; + uint macro_line = sf->line; + + //--- skip macro body + + const TextCommand_t tcmd_end = TCMD_ENDMACRO - TCMD_MACRO + tcmd_beg; + int level = 1; + for(;;) + { + const char ch = NextLineSI(si,true,false); + DASSERT(si->cur_file); + if (!ch) + { + ERROR0(ERR_WARNING, + "End of source reached, but %s '%s' not terminated [%s @%u]\n", + tcmd_beg == TCMD_FUNCTION ? "function" : "macro", + mname, sf->name, macro_line ); + macro_end = sf->ptr; + valid = false; + break; + } + if ( ch != '@' ) + continue; + + macro_end = sf->ptr; + const TextCommand_t tcmd = ScanTextCommand(si); + if ( tcmd == tcmd_beg ) + level++; + else if ( tcmd == tcmd_end && !--level ) + break; + } + + if (valid) + { + bool found; + Var_t * mvar = InsertVarMap(&si->macro,mname,false,0,&found); + DASSERT(mvar); + ScanMacro_t *macro; + if (found) + { + macro = mvar->macro; + DASSERT(macro); + ResetSM(macro); + } + else + { + //DASSERT(!mvar->macro); + macro = MALLOC(sizeof(*macro)); + DASSERT(macro); + InitializeSM(macro); + mvar->macro = macro; + } + + DASSERT( sf == si->cur_file ); + DASSERT( sf->ptr > macro_begin ); + const uint macro_size = macro_end - macro_begin; + macro->data = MEMDUP(macro_begin,macro_size); + DASSERT(macro->data); + macro->data_size = macro_size; + macro->data_alloced = true; + macro->line0 = macro_line; + macro->map = mvar; + macro->src_name = STRDUP(sf->name); + macro->is_function = tcmd_beg == TCMD_FUNCTION; + + PRINT("DEFINE %s '%s' : line=%u, size=%u\n", + macro->is_function ? "FUNCTION" : "MACRO", mname, + macro_line, macro_size ); + } + + return valid ? ERR_OK : ERR_WARNING; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_ENDMACRO +( + ScanInfo_t * si, // valid data + TextCommand_t tcmd // command to execute +) +{ + DASSERT(si); + PRINT("SI_ENDMACRO(%u) func=%d\n",tcmd,tcmd==TCMD_ENDFUNCTION); + CheckEolSI(si); + + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + if (!sf->active_macro) + { + if ( si->no_warn <= 0 ) + { + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "No active %s, END%s command ignored [%s @%u]: %.*s\n", + tcmd==TCMD_ENDFUNCTION ? "function" : "macro", + tcmd==TCMD_ENDFUNCTION ? "FUNCTION" : "MACRO", + sf->name, sf->line, + (int)(eol - sf->prev_ptr), sf->prev_ptr ); + } + return ERR_WARNING; + } + + si->last_result.mode = VAR_UNSET; + DropSF(si); + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static const ScanMacro_t *ScanMacroNameSI +( + ScanInfo_t * si, // valid data + char * mname, // pointer to name buffer + uint mname_size // size of 'mname' +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + DASSERT(mname); + DASSERT(mname_size>1); + + //--- scan macro name + + if (!ScanNameSI(si,mname,mname_size,false,true,0)) + { + if ( si->no_warn <= 0 ) + { + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "Missing macro name [%s @%u]: %.*s\n", + sf->name, sf->line, + (int)(eol - sf->prev_ptr), sf->prev_ptr ); + } + GotoEolSI(si); + return 0; + } + + + //--- find macro name + + const Var_t * mvar = FindVarMap(&si->macro,mname,0); + if (!mvar) + { + if ( si->no_warn <= 0 ) + { + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "Macro '%s' not found [%s @%u]: %.*s\n", + mname, sf->name, sf->line, + (int)(eol - sf->prev_ptr), sf->prev_ptr ); + } + GotoEolSI(si); + return 0; + } + + DASSERT(mvar->macro); + return mvar->macro; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_CALL +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + noPRINT("SI_CALL()\n"); + + //--- scan macro name + + char mname[VARNAME_SIZE+1]; + const ScanMacro_t *macro = ScanMacroNameSI(si,mname,sizeof(mname)); + if (!macro) + return ERR_WARNING; + + + //--- evaluate parameters + + uint n_param = 0; + enumError err = ERR_OK; + VarMap_t pvar; + InitializeVarMap(&pvar); + + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + if ( NextCharSI(si,false) == '(' ) + { + sf->ptr++; + if ( NextCharSI(si,false) != ')' ) + { + sf->disable_comma++; + for(;;) + { + char pname[20]; + snprintf(pname,sizeof(pname),"$%u",++n_param); + Var_t *param = InsertVarMap(&pvar,pname,false,0,0); + DASSERT(param); + enumError err1 = ScanExprSI(si,param); + if ( err < err1 ) + err = err1; + if ( NextCharSI(si,false) != ',' ) + break; + sf->ptr++; + } + sf->disable_comma--; + } + err = CheckWarnSI(si,')',err); + } + Var_t *var = InsertVarMap(&pvar,"$N",false,0,0); + DASSERT(var); + AssignIntV(var,n_param); + CheckEolSI(si); + + + //--- call macro + + sf = AddSF(si,macro->data,macro->data_size,macro->src_name,sf->revision,&pvar); + if (sf) + { + DASSERT(!pvar.used); + DASSERT(!pvar.list); + sf->active_macro = macro; + sf->line = macro->line0; + } + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SI_PARAMETERS +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + noPRINT("SI_PARAMETERS()\n"); + + enumError err = ERR_OK; + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + const Var_t *var = FindVarMap(&sf->pvar,"$N",0); + const int n = var && var->mode != VAR_UNSET ? GetIntV(var) : 0; + + int i; + for ( i = 1;; i++ ) + { + while ( NextCharSI(si,false) == ',' ) + sf->ptr++; + + if (!NextCharSI(si,false)) + break; + + char varname[VARNAME_SIZE+1]; + int xyz; + const uint namelen + = ScanNameSI(si,varname,sizeof(varname),false,true,&xyz); + if (!namelen) + { + ccp eol = FindNextLineFeedSI(si,true); + err = ERROR0(ERR_WARNING, + "Missing name [%s @%u]: %.*s\n", + sf->name, sf->line, + (int)(eol - sf->prev_ptr), sf->prev_ptr ); + GotoEolSI(si); + break; + } + + Var_t *dest = OverwriteVarSI(0,&sf->pvar,varname,&xyz,0); + DASSERT(dest); + dest->mode = VAR_UNSET; + noPRINT("DEST#%u/%u: %p |%s|\n",i,n,dest,varname); + + if ( i <= n ) + { + char pname[20]; + snprintf(pname,sizeof(pname),"$%u",i); + const Var_t *src = FindVarMap(&sf->pvar,pname,0); + noPRINT("SRC#%u/%u: %p |%s|\n",i,n,src,pname); + if (src) + AssignVar(dest,src); + } + } + + return err; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +TextCommand_t GetTextCommand +( + ccp name // name to scan, upper case is assumed +) +{ + static FormatField_t cmdtab = {0}; + if (!cmdtab.used) + { + struct tcmdtab_t { ccp name; int id; }; + static const struct tcmdtab_t def_tab[] = + { + //--- messages + + { "ECHO", TCMD_ECHO }, + { "WARN", TCMD_WARN }, + + //--- reset var maps + + { "RESET-PRIVATE", TCMD_RESET_PRIVATE }, + { "RESET-LOCAL", TCMD_RESET_LOCAL }, + { "RESET-GLOBAL", TCMD_RESET_GLOBAL }, + + //--- dump var maps + + { "DUMP-VAR", TCMD_DUMP_VAR }, + { "DUMP-PRIVATE", TCMD_DUMP_PRIVATE }, + { "DUMP-LOCAL", TCMD_DUMP_LOCAL }, + { "DUMP-GLOBAL", TCMD_DUMP_GLOBAL }, + { "DUMP-CONST", TCMD_DUMP_CONST }, + { "DUMP-PREDEF", TCMD_DUMP_PREDEF }, + + //--- settings + + { "REVISION", TCMD_REVISION }, + { "SZS-MODIFIER", TCMD_SZS_MODIFIER }, + { "SMOD", TCMD_SZS_MODIFIER }, + { "SETUP-RANDOM", TCMD_SETUP_RANDOM }, + + //--- define variables + + { "DEF", TCMD_LDEF }, + { "DEF.I", TCMD_LDEF_I }, + { "DEF.F", TCMD_LDEF_F }, + { "DEF.S", TCMD_LDEF_S }, + { "DEF.V", TCMD_LDEF_V }, + { "DEF.X", TCMD_LDEF_X }, + { "DEF.Y", TCMD_LDEF_Y }, + { "DEF.Z", TCMD_LDEF_Z }, + { "DEF.ENUM", TCMD_LDEF_ENUM }, + { "DEF.SHIFT", TCMD_LDEF_SHIFT }, + + { "PDEF", TCMD_PDEF }, + { "PDEF.I", TCMD_PDEF_I }, + { "PDEF.F", TCMD_PDEF_F }, + { "PDEF.S", TCMD_PDEF_S }, + { "PDEF.V", TCMD_PDEF_V }, + { "PDEF.X", TCMD_PDEF_X }, + { "PDEF.Y", TCMD_PDEF_Y }, + { "PDEF.Z", TCMD_PDEF_Z }, + { "PDEF.ENUM", TCMD_PDEF_ENUM }, + { "PDEF.SHIFT", TCMD_PDEF_SHIFT }, + + { "LDEF", TCMD_LDEF }, + { "LDEF.I", TCMD_LDEF_I }, + { "LDEF.F", TCMD_LDEF_F }, + { "LDEF.S", TCMD_LDEF_S }, + { "LDEF.V", TCMD_LDEF_V }, + { "LDEF.X", TCMD_LDEF_X }, + { "LDEF.Y", TCMD_LDEF_Y }, + { "LDEF.Z", TCMD_LDEF_Z }, + { "LDEF.ENUM", TCMD_LDEF_ENUM }, + { "LDEF.SHIFT", TCMD_LDEF_SHIFT }, + + { "GDEF", TCMD_GDEF }, + { "GDEF.I", TCMD_GDEF_I }, + { "GDEF.F", TCMD_GDEF_F }, + { "GDEF.S", TCMD_GDEF_S }, + { "GDEF.V", TCMD_GDEF_V }, + { "GDEF.X", TCMD_GDEF_X }, + { "GDEF.Y", TCMD_GDEF_Y }, + { "GDEF.Z", TCMD_GDEF_Z }, + { "GDEF.ENUM", TCMD_GDEF_ENUM }, + { "GDEF.SHIFT", TCMD_GDEF_SHIFT }, + + //--- define variables (old names) + + { "NUM", TCMD_LDEF }, + { "GNUM", TCMD_GDEF }, + { "INT", TCMD_LDEF_I }, + { "GINT", TCMD_GDEF_I }, + { "FLOAT", TCMD_LDEF_F }, + { "GFLOAT", TCMD_GDEF_F }, + + //--- if then else + + { "IF", TCMD_IF }, + { "ELIF", TCMD_ELIF }, + { "ELSEIF", TCMD_ELIF }, + { "ELSE", TCMD_ELSE }, + { "ENDIF", TCMD_ENDIF }, + { "FI", TCMD_ENDIF }, + + { "DOIF", TCMD_DOIF }, + + //--- loops + + { "LOOP", TCMD_LOOP }, + { "REPEAT", TCMD_REPEAT }, + { "FOR", TCMD_FOR }, + { "FOREACH", TCMD_FOREACH }, + { "WHILE", TCMD_WHILE }, + + { "ENDLOOP", TCMD_ENDLOOP }, + { "ENDREPEAT", TCMD_ENDREPEAT }, + { "ENDFOR", TCMD_ENDFOR }, + { "ENDFOREACH", TCMD_ENDFOREACH }, + { "ENDEACH", TCMD_ENDFOREACH }, + { "ENDWHILE", TCMD_ENDWHILE }, + + { "BREAK", TCMD_BREAK }, + { "CONTINUE", TCMD_CONTINUE }, + + //--- include & return + + { "EXEC", TCMD_EXEC }, + { "INCLUDE", TCMD_INCLUDE }, + { "RETURN", TCMD_RETURN }, + { "EXIT", TCMD_EXIT }, + { "ASSERT", TCMD_ASSERT }, + + //--- macros and functions + + { "MACRO", TCMD_MACRO }, + { "ENDMACRO", TCMD_ENDMACRO }, + { "FUNCTION", TCMD_FUNCTION }, + { "ENDFUNCTION", TCMD_ENDFUNCTION }, + + { "CALL", TCMD_CALL }, + { "PARAMETERS", TCMD_PARAMETERS }, + { "PARAM", TCMD_PARAMETERS }, + + {0,0} + }; + + const struct tcmdtab_t * cp; + for ( cp = def_tab; cp->name; cp++ ) + InsertFormatField(&cmdtab,cp->name,0,0,0)->num = cp->id; + } + + FormatFieldItem_t * item = FindFormatField(&cmdtab,name); + return item ? item->num : TCMD_NONE; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanTextCommand +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + if ( si->fast_scan <= 0 ) + { + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + ScanFile_t saved_sf; + memcpy(&saved_sf,sf,sizeof(saved_sf)); + if ( NextCharSI(si,false) == '@' ) + sf->ptr++; + + char name[VARNAME_SIZE+1]; + if (ScanNameSI(si,name,sizeof(name),true,true,0)) + { + const TextCommand_t tcmd = GetTextCommand(name); + //if ( tcmd && ( sf->no_if <= 0 || tcmd < TCMD_IF || tcmd > TCMD_ENDIF )) + if (tcmd) + { + noPRINT("CMD FOUND @ line %u: %u %s |%.10s|\n", + sf->line, tcmd, name, sf->ptr ); + return tcmd; + } + } + + switch(NextCharSI(si,false)) + { + case ':': + sf->ptr++; + return TCMD_CALL; + + case '>': + sf->ptr++; + return TCMD_EXEC; + } + + memcpy(sf,&saved_sf,sizeof(*sf)); + } + return TCMD_NONE; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ExecTextCommand +( + ScanInfo_t * si, // valid data + TextCommand_t tcmd // command to execute +) +{ + DASSERT(si); + DASSERT(si->cur_file); + TRACE("ExecTextCommand(%u)\n",tcmd); + + switch (tcmd) + { + case TCMD_ECHO: + { + char * str = 0; + enumError err = ConcatStringsSI(si,&str,0); + if ( si->fast_scan || si->no_warn ) + err = ERR_OK; + else if ( str && !opt_no_echo ) + fprintf(stdlog,"%s\n",str); + FreeString(str); + return err; + } + + case TCMD_WARN: + { + char * str = 0; + enumError err = ConcatStringsSI(si,&str,0); + if ( si->fast_scan || si->no_warn ) + err = ERR_OK; + else if ( !err && str ) + err = ERROR0(ERR_WARNING,"%s",str); + FreeString(str); + return err; + } + + case TCMD_RESET_PRIVATE: + ResetVarMap(&si->cur_file->pvar); + return ERR_OK; + + case TCMD_RESET_LOCAL: + ResetVarMap(&si->lvar); + return ERR_OK; + + case TCMD_RESET_GLOBAL: + ResetVarMap(&si->gvar); + return ERR_OK; + + case TCMD_DUMP_VAR: + case TCMD_DUMP_PRIVATE: + case TCMD_DUMP_LOCAL: + case TCMD_DUMP_GLOBAL: + case TCMD_DUMP_CONST: + case TCMD_DUMP_PREDEF: + { + if (NextCharSI(si,false)) + { + DEFINE_VAR(var); + if ( ScanExprSI(si,&var) || !GetBoolV(&var) ) + return ERR_OK; + } + else if (si->no_warn) + return ERR_OK; + + if (si->fast_scan) + return ERR_OK; + + if ( tcmd == TCMD_DUMP_VAR || tcmd == TCMD_DUMP_PRIVATE ) + { + fprintf(stdlog,"VAR DUMP/PRIVATE:\n"); + DumpVarMap(stdlog,3,&si->cur_file->pvar,false); + } + if ( tcmd == TCMD_DUMP_VAR || tcmd == TCMD_DUMP_LOCAL ) + { + fprintf(stdlog,"VAR DUMP/LOCAL:\n"); + DumpVarMap(stdlog,3,&si->lvar,false); + } + if ( tcmd == TCMD_DUMP_VAR || tcmd == TCMD_DUMP_GLOBAL ) + { + fprintf(stdlog,"VAR DUMP/GLOBAL:\n"); + DumpVarMap(stdlog,3,&si->gvar,false); + } + if ( tcmd == TCMD_DUMP_VAR || tcmd == TCMD_DUMP_CONST ) + { + fprintf(stdlog,"VAR DUMP/CONST:\n"); + DumpVarMap(stdlog,3,&const_map,false); + } + if ( tcmd == TCMD_DUMP_PREDEF ) + { + fprintf(stdlog,"VAR DUMP/PREDEF:\n"); + if (si->predef) + DumpVarMap(stdlog,3,si->predef,false); + } + return ERR_OK; + } + + + case TCMD_REVISION: + { + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + enumError err = ScanAssignIntSI(si,&sf->revision); + DefineIntVar(&si->gvar,"REVISION$ACTIVE",sf->revision); + return err; + } + + case TCMD_SZS_MODIFIER: + return ScanAssignIntSI(si,&si->cur_file->szs_modifier); + + case TCMD_SETUP_RANDOM: + { + int num; + enumError err = ScanAssignIntSI(si,&num); + MySeed(num); + return err; + } + + case TCMD_PDEF: + case TCMD_PDEF_I: + case TCMD_PDEF_F: + case TCMD_PDEF_S: + case TCMD_PDEF_V: + case TCMD_PDEF_X: + case TCMD_PDEF_Y: + case TCMD_PDEF_Z: + case TCMD_PDEF_ENUM: + case TCMD_PDEF_SHIFT: return SetVarSI(si,&si->cur_file->pvar,tcmd); + + case TCMD_LDEF: + case TCMD_LDEF_I: + case TCMD_LDEF_F: + case TCMD_LDEF_S: + case TCMD_LDEF_V: + case TCMD_LDEF_X: + case TCMD_LDEF_Y: + case TCMD_LDEF_Z: + case TCMD_LDEF_ENUM: + case TCMD_LDEF_SHIFT: return SetVarSI(si,&si->lvar,tcmd); + + case TCMD_GDEF: + case TCMD_GDEF_I: + case TCMD_GDEF_F: + case TCMD_GDEF_S: + case TCMD_GDEF_V: + case TCMD_GDEF_X: + case TCMD_GDEF_Y: + case TCMD_GDEF_Z: + case TCMD_GDEF_ENUM: + case TCMD_GDEF_SHIFT: return SetVarSI(si,&si->gvar,tcmd); + + case TCMD_IF: return SI_IF(si); + case TCMD_ELIF: + case TCMD_ELSE: return SI_ELSE(si); + case TCMD_ENDIF: return SI_ENDIF(si); + + case TCMD_DOIF: return SI_DOIF(si); + + case TCMD_LOOP: return SI_LOOP(si); + case TCMD_REPEAT: return SI_REPEAT(si); + case TCMD_FOR: return SI_FOR(si); + case TCMD_FOREACH: return SI_FOREACH(si); + case TCMD_WHILE: return SI_WHILE(si); + + case TCMD_ENDLOOP: return SI_ENDLOOP(si); + case TCMD_ENDREPEAT: return SI_ENDREPEAT(si); + case TCMD_ENDFOR: return SI_ENDFOR(si,0); + case TCMD_ENDFOREACH: return SI_ENDFOREACH(si,0); + case TCMD_ENDWHILE: return SI_ENDWHILE(si,0); + + case TCMD_BREAK: return SI_BreakLoop(si,false); + case TCMD_CONTINUE: return SI_BreakLoop(si,true); + + case TCMD_EXEC: return SI_EXEC(si); + case TCMD_INCLUDE: return SI_INCLUDE(si); + case TCMD_RETURN: return SI_RETURN(si); + case TCMD_EXIT: return SI_EXIT(si,false); + case TCMD_ASSERT: return SI_EXIT(si,true); + + case TCMD_MACRO: + case TCMD_FUNCTION: return SI_MACRO(si,tcmd); + case TCMD_ENDMACRO: + case TCMD_ENDFUNCTION: return SI_ENDMACRO(si,tcmd); + + case TCMD_CALL: return SI_CALL(si); + case TCMD_PARAMETERS: return SI_PARAMETERS(si); + + default: + DASSERT(0); + return ERR_WARNING; + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// expressions: definitions /////////////// +/////////////////////////////////////////////////////////////////////////////// +// [[OpCounter_t]] created by work/scripts/create-db/optab.gen + +typedef enum OpCounter_t +{ + OP_MAX_LEN = 3, + OP_CHARMAP_SIZE = 128, + OP_CHARIDX_SIZE = 15, + OP_TAB_SIZE = 29 + +} OpCounter_t; + +//----------------------------------------------------------------------------- +// [[OpPrio_t]] created by work/scripts/create-db/optab.gen + +typedef enum OpPrio_t +{ + OPP_NONE, // 3* + OPP_JOIN, // 1* + OPP_LOR, // 1* + OPP_LEOR, // 2* + OPP_LAND, // 1* + OPP_OR, // 1* + OPP_EOR, // 2* + OPP_AND, // 1* + OPP_EQ, // 5* + OPP_CMP, // 4* + OPP_SHIFT, // 2* + OPP_ADD, // 2* + OPP_MULT, // 3* + OPP_POW, // 1* + + OPP__N // = 14 + +} OpPrio_t; + +//----------------------------------------------------------------------------- +// [[OpMode_t]] created by work/scripts/create-db/optab.gen + +typedef enum OpMode_t +{ + OPM_0, // 27* + OPM_AND, // 1* + OPM_OR, // 1* + +} OpMode_t; + +/////////////////////////////////////////////////////////////////////////////// +// [[Operator_t]] // created by work/scripts/create-db/optab.gen + +typedef struct Operator_t +{ + OpId_t id; + OpPrio_t prio; + OpMode_t mode; + int op_len; + const char op_name[OP_MAX_LEN+1]; + const u8 sub_index[OP_CHARIDX_SIZE]; + +} Operator_t; + +/////////////////////////////////////////////////////////////////////////////// +// [[op_tab]] // created by work/scripts/create-db/optab.gen + +static const Operator_t op_tab[OP_TAB_SIZE] = // OP_TAB_SIZE := 29 +{ + { OPI_NONE, OPP_NONE, OPM_0, 0,"", {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14} }, + + { OPI_NONE, OPP_NONE, OPM_0, 1,"!", {0,0,0,0,0,0,0,0,0,15,0,0,0,0,0} }, + { OPI_MOD, OPP_MULT, OPM_0, 1,"%", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_AND, OPP_AND, OPM_0, 1,"&", {0,0,0,16,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_MULT, OPP_MULT, OPM_0, 1,"*", {0,0,0,0,17,0,0,0,0,0,0,0,0,0,0} }, + { OPI_ADD, OPP_ADD, OPM_0, 1,"+", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_SUB, OPP_ADD, OPM_0, 1,"-", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_DIV, OPP_MULT, OPM_0, 1,"/", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_LT, OPP_CMP, OPM_0, 1,"<", {0,0,0,0,0,0,0,0,18,19,20,0,0,0,0} }, + { OPI_NONE, OPP_NONE, OPM_0, 1,"=", {0,0,0,0,0,0,0,0,0,21,0,0,0,0,0} }, + { OPI_GT, OPP_CMP, OPM_0, 1,">", {0,0,0,0,0,0,0,0,0,22,23,0,0,0,0} }, + { OPI_JOIN, OPP_JOIN, OPM_0, 1,"@", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_EOR, OPP_EOR, OPM_0, 1,"^", {0,0,0,0,0,0,0,0,0,0,0,0,24,0,0} }, + { OPI_OR, OPP_OR, OPM_0, 1,"|", {0,0,0,0,0,0,0,0,0,0,0,0,0,25,0} }, + { OPI_EOR, OPP_EOR, OPM_0, 1,"~", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,26} }, + + { OPI_NEQ, OPP_EQ, OPM_0, 2,"!=", {0,0,0,0,0,0,0,0,0,27,0,0,0,0,0} }, + { OPI_LAND, OPP_LAND, OPM_AND, 2,"&&", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_POW, OPP_POW, OPM_0, 2,"**", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_LSHIFT, OPP_SHIFT, OPM_0, 2,"<<", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_LE, OPP_CMP, OPM_0, 2,"<=", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_NEQ, OPP_EQ, OPM_0, 2,"<>", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_EQ, OPP_EQ, OPM_0, 2,"==", {0,0,0,0,0,0,0,0,0,28,0,0,0,0,0} }, + { OPI_GE, OPP_CMP, OPM_0, 2,">=", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_RSHIFT, OPP_SHIFT, OPM_0, 2,">>", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_LEOR, OPP_LEOR, OPM_0, 2,"^^", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_LOR, OPP_LOR, OPM_OR, 2,"||", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_LEOR, OPP_LEOR, OPM_0, 2,"~~", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + + { OPI_NEQNEQ, OPP_EQ, OPM_0, 3,"!==", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, + { OPI_EQEQ, OPP_EQ, OPM_0, 3,"===", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }, +}; + +/////////////////////////////////////////////////////////////////////////////// +// created by work/scripts/create-db/optab.gen + +static const u8 op_charmap[OP_CHARMAP_SIZE] = // OP_CHARMAP_SIZE := 128 +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 4, 5, 0, 6, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 0, + 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 14, 0, +}; + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// expressions: helpers /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static const Operator_t * FindOperator +( + ScanInfo_t * si // valid data +) +{ + DASSERT(si); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + const Operator_t *op = op_tab, *found = op_tab; + + NextCharSI(si,false); + ccp ptr = sf->prev_ptr = sf->ptr; + while ( ptr < sf->end && (uchar)*ptr < OP_CHARMAP_SIZE ) + { + const uint ch_idx = op_charmap[(uchar)*ptr]; + DASSERT( ch_idx < OP_CHARIDX_SIZE ); + const uint op_idx = op->sub_index[ch_idx]; + if (!op_idx) + break; + ptr++; + DASSERT( op_idx < OP_TAB_SIZE ); + op = op_tab + op_idx; + if (op->id) + { + found = op; + sf->ptr = ptr; + } + // else: a temporary step + } + noPRINT("FindOperator(%.*s) %zu\n", + (int)(sf->ptr - sf->prev_ptr), sf->prev_ptr, found - op_tab ); + return found; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void ShiftLeftV ( Var_t *val, int shift ) +{ + #undef MAXBIT + #define MAXBIT ((int)(CHAR_BIT*sizeof(val->i))) + + DASSERT(val); + switch(val->mode) + { + case VAR_UNSET: + break; + + case VAR_INT: + if ( shift >= MAXBIT ) val->i = 0; + else if ( shift >= 0 ) val->i <<= shift; + else if ( shift > -MAXBIT ) val->i >>= -shift; + else if ( val->i < 0 ) val->i = -1; + else val->i = 0; + break; + + case VAR_DOUBLE: + val->d = ldexp(val->d,shift); + break; + + case VAR_VECTOR: + val->x = ldexp(val->x,shift); + val->y = ldexp(val->y,shift); + val->z = ldexp(val->z,shift); + break; + + case VAR_STRING: + // ignored! + break; + } + + #undef MAXBIT +} + +/////////////////////////////////////////////////////////////////////////////// + +void CalcExpr +( + Var_t * dest, // first source and destination + const Var_t * src2, // second source + OpId_t op_id, // operator id + ScanInfo_t * si // not NULL: Use for warnings +) +{ + DASSERT(dest); + DASSERT(src2); + DASSERT( op_id > OPI_NONE && op_id < OPI__N ); + + noPRINT("%%%%%% CalcExpr() %p,%d,%p %s %p,%d,%p\n", + dest,dest->mode,dest->str, op_tab[op_id].op_name, + src2,src2->mode,src2->str ); + + dest->int_mode = IMD_UNSET; + + + //--- if one unset: assign only! + + if ( src2->mode == VAR_UNSET ) + return; + + if ( dest->mode == VAR_UNSET ) + { + AssignVar(dest,src2); + return; + } + + //--- OPI_JOIN is the only force-string operator + + DEFINE_VAR(temp); + + if ( op_id == OPI_JOIN ) + { + op_join:; + AssignStringVV(&temp,dest); + AppendStringVV(&temp,src2); + MoveDataV(dest,&temp); + return; + } + + + //--- string operations + + if ( dest->mode == VAR_STRING || src2->mode == VAR_STRING ) + { + if ( dest->mode == VAR_STRING && src2->mode == VAR_STRING ) + { + str_cmp:; + int res = 0; + switch (op_id) + { + case OPI_LT: // SxS + res = CmpMem( MemByS(dest->str,dest->str_len), + MemByS(src2->str,src2->str_len)) < 0; + break; + + case OPI_LE: // SxS + res = CmpMem( MemByS(dest->str,dest->str_len), + MemByS(src2->str,src2->str_len)) <= 0; + break; + + case OPI_GT: // SxS + res = CmpMem( MemByS(dest->str,dest->str_len), + MemByS(src2->str,src2->str_len)) > 0; + break; + + case OPI_GE: // SxS + res = CmpMem( MemByS(dest->str,dest->str_len), + MemByS(src2->str,src2->str_len)) >= 0; + break; + + case OPI_EQ: // SxS + case OPI_EQEQ: // SxS + res = dest->str_len == src2->str_len + && !memcmp(dest->str,src2->str,dest->str_len); + break; + + case OPI_NEQ: // SxS + case OPI_NEQNEQ: // SxS + res = dest->str_len != src2->str_len + || memcmp(dest->str,src2->str,dest->str_len); + break; + + case OPI_ADD: // SxS + goto op_join; + + case OPI_LAND: // SxS + res = dest->str_len > 0 && src2->str_len > 0; + break; + + case OPI_LOR: // SxS + res = dest->str_len > 0 || src2->str_len > 0; + break; + + case OPI_LEOR: // SxS + res = dest->str_len > 0 != src2->str_len > 0; + break; + + case OPI_POW: // SxS + case OPI_MULT: // SxS + case OPI_DIV: // SxS + case OPI_MOD: // SxS + case OPI_SUB: // SxS + case OPI_LSHIFT: // SxS + case OPI_RSHIFT: // SxS + case OPI_AND: // SxS + case OPI_OR: // SxS + case OPI_EOR: // SxS + ResetV(dest); + return; + + case OPI_JOIN: // SxS + case OPI_NONE: // SxS + case OPI__N: // SxS + DASSERT(0); // never executed + ResetV(dest); + return; + } + + FreeV(dest); + dest->mode = VAR_INT; + dest->i = res; + return; + } + else // one param is not string + { + DASSERT( ( dest->mode == VAR_STRING ) != ( src2->mode == VAR_STRING ) ); + switch (op_id) + { + case OPI_LAND: // S + case OPI_LOR: // S + case OPI_LEOR: // S + if ( dest->mode == VAR_STRING ) + ToBoolV(dest); + else if ( src2->mode == VAR_STRING ) + { + temp.mode = VAR_INT; + temp.i = src2->str_len > 0; + src2 = &temp; + } + // continue like numeric values + break; + + case OPI_EQEQ: // S + case OPI_NEQNEQ: // S + FreeV(dest); + dest->mode = VAR_INT; + dest->i = op_id == OPI_NEQNEQ; + return; + + case OPI_EQ: // S + case OPI_NEQ: // S + case OPI_LT: // S + case OPI_LE: // S + case OPI_GT: // S + case OPI_GE: // S + if ( dest->mode == VAR_STRING ) + { + AssignStringVV(&temp,src2); + src2 = &temp; + } + else + ToStringV(dest); + goto str_cmp; + + default: + ResetV(dest); + return; + } + } + } + + DASSERT( dest->mode != VAR_STRING ); + DASSERT( src2->mode != VAR_STRING ); + + + if ( dest->mode == VAR_VECTOR ) + { + if ( src2->mode == VAR_VECTOR ) + { + // both vectors + switch (op_id) + { + case OPI_POW: // VxV + dest->x = pow(dest->x,src2->x); + dest->y = pow(dest->y,src2->y); + dest->z = pow(dest->z,src2->z); + return; + + case OPI_MULT: // VxV + dest->x *= src2->x; + dest->y *= src2->y; + dest->z *= src2->z; + return; + + case OPI_DIV: // VxV + dest->x /= src2->x; + dest->y /= src2->y; + dest->z /= src2->z; + return; + + case OPI_MOD: // VxV + dest->x = fmod(dest->x,src2->x); + dest->y = fmod(dest->y,src2->y); + dest->z = fmod(dest->z,src2->z); + return; + + case OPI_ADD: // VxV + dest->x += src2->x; + dest->y += src2->y; + dest->z += src2->z; + return; + + case OPI_SUB: // VxV + dest->x -= src2->x; + dest->y -= src2->y; + dest->z -= src2->z; + return; + + case OPI_LSHIFT: // VxV + dest->x = ldexp(dest->x,(int)src2->x); + dest->y = ldexp(dest->y,(int)src2->y); + dest->z = ldexp(dest->z,(int)src2->z); + return; + + case OPI_RSHIFT: // VxV + dest->x = ldexp(dest->x,(int)-src2->x); + dest->y = ldexp(dest->y,(int)-src2->y); + dest->z = ldexp(dest->z,(int)-src2->z); + return; + + case OPI_LT: // VxV + if ( dest->x != src2->x ) + dest->i = dest->x < src2->x; + else if ( dest->y != src2->y ) + dest->i = dest->y < src2->y; + else if ( dest->z != src2->z ) + dest->i = dest->z < src2->z; + else + dest->i = 0; + dest->mode = VAR_INT; + return; + + case OPI_LE: // VxV + if ( dest->x != src2->x ) + dest->i = dest->x <= src2->x; + else if ( dest->y != src2->y ) + dest->i = dest->y <= src2->y; + else if ( dest->z != src2->z ) + dest->i = dest->z <= src2->z; + else + dest->i = 1; + dest->mode = VAR_INT; + return; + + case OPI_GT: // VxV + if ( dest->x != src2->x ) + dest->i = dest->x > src2->x; + else if ( dest->y != src2->y ) + dest->i = dest->y > src2->y; + else if ( dest->z != src2->z ) + dest->i = dest->z > src2->z; + else + dest->i = 0; + dest->mode = VAR_INT; + return; + + case OPI_GE: // VxV + if ( dest->x != src2->x ) + dest->i = dest->x >= src2->x; + else if ( dest->y != src2->y ) + dest->i = dest->y >= src2->y; + else if ( dest->z != src2->z ) + dest->i = dest->z >= src2->z; + else + dest->i = 1; + dest->mode = VAR_INT; + return; + + case OPI_EQ: // VxV + case OPI_EQEQ: // VxV + dest->i = dest->x == src2->x && dest->y == src2->y && dest->z == src2->z; + dest->mode = VAR_INT; + return; + + case OPI_NEQ: // VxV + case OPI_NEQNEQ: // VxV + dest->i = dest->x != src2->x || dest->y != src2->y || dest->z == src2->z; + dest->mode = VAR_INT; + return; + + case OPI_AND: // VxV + case OPI_OR: // VxV + case OPI_EOR: // VxV + dest->mode = VAR_UNSET; + return; + + case OPI_LAND: // VxV + dest->i = ( dest->x || dest->y || dest->z ) + && ( src2->x || src2->y || src2->z ); + dest->mode = VAR_INT; + return; + + case OPI_LOR: // VxV + dest->i = ( dest->x || dest->y || dest->z ) + || ( src2->x || src2->y || src2->z ); + dest->mode = VAR_INT; + return; + + case OPI_LEOR: // VxV + dest->i = ( dest->x || dest->y || dest->z ) + != ( src2->x || src2->y || src2->z ); + dest->mode = VAR_INT; + return; + + case OPI_JOIN: // VxV + case OPI_NONE: // VxV + case OPI__N: // VxV + DASSERT(0); + return; + } + } + else + { + // only dest is vector + double d = GetDoubleV(src2); + switch (op_id) + { + case OPI_POW: // VxD + dest->x = pow(dest->x,d); + dest->y = pow(dest->y,d); + dest->z = pow(dest->z,d); + return; + + case OPI_MULT: // VxD + dest->x *= d; + dest->y *= d; + dest->z *= d; + return; + + case OPI_DIV: // VxD + dest->x /= d; + dest->y /= d; + dest->z /= d; + return; + + case OPI_MOD: // VxD + dest->x = fmod(dest->x,d); + dest->y = fmod(dest->y,d); + dest->z = fmod(dest->z,d); + return; + + case OPI_ADD: // VxD + dest->x += d; + dest->y += d; + dest->z += d; + return; + + case OPI_SUB: // VxD + dest->x -= d; + dest->y -= d; + dest->z -= d; + return; + + case OPI_LSHIFT: // VxD + { + int shift = (int)floor(d+0.5); + dest->x = ldexp(dest->x,shift); + dest->y = ldexp(dest->y,shift); + dest->z = ldexp(dest->z,shift); + } + return; + + case OPI_RSHIFT: // VxD + { + int shift = -(int)floor(d+0.5); + dest->x = ldexp(dest->x,shift); + dest->y = ldexp(dest->y,shift); + dest->z = ldexp(dest->z,shift); + } + return; + + case OPI_LT: // VxD + dest->i = dest->x < d; + dest->mode = VAR_INT; + return; + + case OPI_LE: // VxD + dest->i = dest->x <= d; + dest->mode = VAR_INT; + return; + + case OPI_GT: // VxD + dest->i = dest->x > d; + dest->mode = VAR_INT; + return; + + case OPI_GE: // VxD + dest->i = dest->x >= d; + dest->mode = VAR_INT; + return; + + case OPI_EQ: // VxD + dest->i = dest->x == d; + dest->mode = VAR_INT; + return; + + case OPI_EQEQ: // VxD + dest->i = 0; + dest->mode = VAR_INT; + return; + + case OPI_NEQ: // VxD + dest->i = dest->x != d; + dest->mode = VAR_INT; + return; + + case OPI_NEQNEQ: // VxD + dest->i = 1; + dest->mode = VAR_INT; + return; + + case OPI_AND: // VxD + case OPI_OR: // VxD + case OPI_EOR: // VxD + dest->mode = VAR_UNSET; + return; + + case OPI_LAND: // VxD + dest->i = ( dest->x || dest->y || dest->z ) && d; + dest->mode = VAR_INT; + return; + + case OPI_LOR: // VxD + dest->i = ( dest->x || dest->y || dest->z ) || d; + dest->mode = VAR_INT; + return; + + case OPI_LEOR: // VxD + dest->i = ( dest->x || dest->y || dest->z ) == !d; + dest->mode = VAR_INT; + return; + + case OPI_JOIN: // VxD + case OPI_NONE: // VxD + case OPI__N: // VxD + DASSERT(0); + return; + } + } + } + else if ( src2->mode == VAR_VECTOR ) + { + // only src2 is vector + double d = GetDoubleV(dest); + MARK_USED(d); + switch (op_id) + { + case OPI_POW: // DxV + dest->x = pow(d,src2->x); + dest->y = pow(d,src2->y); + dest->z = pow(d,src2->z); + dest->mode = VAR_VECTOR; + return; + + case OPI_MULT: // DxV + dest->x = d * src2->x; + dest->y = d * src2->y; + dest->z = d * src2->z; + dest->mode = VAR_VECTOR; + return; + + case OPI_DIV: // DxV + dest->x = d / src2->x; + dest->y = d / src2->y; + dest->z = d / src2->z; + dest->mode = VAR_VECTOR; + return; + + case OPI_MOD: // DxV + dest->x = fmod(d,src2->x); + dest->y = fmod(d,src2->y); + dest->z = fmod(d,src2->z); + dest->mode = VAR_VECTOR; + return; + + case OPI_ADD: // DxV + dest->x = d + src2->x; + dest->y = d + src2->y; + dest->z = d + src2->z; + dest->mode = VAR_VECTOR; + return; + + case OPI_SUB: // DxV + dest->x = d - src2->x; + dest->y = d - src2->y; + dest->z = d - src2->z; + dest->mode = VAR_VECTOR; + return; + + case OPI_LSHIFT: // DxV + dest->x = ldexp(d,(int)src2->x); + dest->y = ldexp(d,(int)src2->y); + dest->z = ldexp(d,(int)src2->z); + return; + + case OPI_RSHIFT: // DxV + dest->x = ldexp(d,(int)-src2->x); + dest->y = ldexp(d,(int)-src2->y); + dest->z = ldexp(d,(int)-src2->z); + return; + + case OPI_LT: // DxV + dest->i = dest->x < d; + dest->mode = VAR_INT; + return; + + case OPI_LE: // DxV + dest->i = dest->x <= d; + dest->mode = VAR_INT; + return; + + case OPI_GT: // DxV + dest->i = dest->x > d; + dest->mode = VAR_INT; + return; + + case OPI_GE: // DxV + dest->i = dest->x >= d; + dest->mode = VAR_INT; + return; + + case OPI_EQ: // DxV + dest->i = dest->x == d; + dest->mode = VAR_INT; + return; + + case OPI_EQEQ: // DxV + dest->i = 0; + dest->mode = VAR_INT; + return; + + case OPI_NEQ: // DxV + dest->i = dest->x != d; + dest->mode = VAR_INT; + return; + + case OPI_NEQNEQ: // DxV + dest->i = 1; + dest->mode = VAR_INT; + return; + + case OPI_AND: // DxV + case OPI_OR: // DxV + case OPI_EOR: // DxV + dest->mode = VAR_UNSET; + return; + + case OPI_LAND: // DxV + dest->i = ( dest->x || dest->y || dest->z ) && d; + dest->mode = VAR_INT; + return; + + case OPI_LOR: // DxV + dest->i = ( dest->x || dest->y || dest->z ) || d; + dest->mode = VAR_INT; + return; + + case OPI_LEOR: // DxV + dest->i = ( dest->x || dest->y || dest->z ) == !d; + dest->mode = VAR_INT; + return; + + case OPI_JOIN: // DxV + case OPI_NONE: // DxV + case OPI__N: // DxV + DASSERT(0); + return; + } + } + else if ( dest->mode == VAR_DOUBLE || src2->mode == VAR_DOUBLE ) + { + switch (op_id) + { + case OPI_POW: // DxD | DxI | IxD + dest->d = pow( dest->mode == VAR_DOUBLE ? dest->d : dest->i, + src2->mode == VAR_DOUBLE ? src2->d : src2->i ); + break; + + case OPI_MULT: // DxD | DxI | IxD + dest->d = ( dest->mode == VAR_DOUBLE ? dest->d : dest->i ) + * ( src2->mode == VAR_DOUBLE ? src2->d : src2->i ); + break; + + case OPI_DIV: // DxD | DxI | IxD + dest->d = ( dest->mode == VAR_DOUBLE ? dest->d : dest->i ) + / ( src2->mode == VAR_DOUBLE ? src2->d : src2->i ); + break; + + case OPI_MOD: // DxD | DxI | IxD + dest->d = fmod( dest->mode == VAR_DOUBLE ? dest->d : dest->i, + src2->mode == VAR_DOUBLE ? src2->d : src2->i ); + break; + + case OPI_ADD: // DxD | DxI | IxD + dest->d = ( dest->mode == VAR_DOUBLE ? dest->d : dest->i ) + + ( src2->mode == VAR_DOUBLE ? src2->d : src2->i ); + break; + + case OPI_SUB: // DxD | DxI | IxD + dest->d = ( dest->mode == VAR_DOUBLE ? dest->d : dest->i ) + - ( src2->mode == VAR_DOUBLE ? src2->d : src2->i ); + break; + + case OPI_LSHIFT: // DxD | DxI | IxD + ShiftLeftV(dest, GetIntV(src2)); + break; + + case OPI_RSHIFT: // DxD | DxI | IxD + ShiftLeftV(dest,-GetIntV(src2)); + break; + + case OPI_LT: // DxD | DxI | IxD + dest->i = ( dest->mode == VAR_DOUBLE ? dest->d : dest->i ) + < ( src2->mode == VAR_DOUBLE ? src2->d : src2->i ); + dest->mode = VAR_INT; + return; + + case OPI_LE: // DxD | DxI | IxD + dest->i = ( dest->mode == VAR_DOUBLE ? dest->d : dest->i ) + <= ( src2->mode == VAR_DOUBLE ? src2->d : src2->i ); + dest->mode = VAR_INT; + return; + + case OPI_GT: // DxD | DxI | IxD + dest->i = ( dest->mode == VAR_DOUBLE ? dest->d : dest->i ) + > ( src2->mode == VAR_DOUBLE ? src2->d : src2->i ); + dest->mode = VAR_INT; + return; + + case OPI_GE: // DxD | DxI | IxD + dest->i = ( dest->mode == VAR_DOUBLE ? dest->d : dest->i ) + >= ( src2->mode == VAR_DOUBLE ? src2->d : src2->i ); + dest->mode = VAR_INT; + return; + + case OPI_EQ: // DxD | DxI | IxD + dest->i = ( dest->mode == VAR_DOUBLE ? dest->d : dest->i ) + == ( src2->mode == VAR_DOUBLE ? src2->d : src2->i ); + dest->mode = VAR_INT; + return; + + case OPI_NEQ: // DxD | DxI | IxD + dest->i = ( dest->mode == VAR_DOUBLE ? dest->d : dest->i ) + != ( src2->mode == VAR_DOUBLE ? src2->d : src2->i ); + dest->mode = VAR_INT; + return; + + case OPI_EQEQ: // DxD | DxI | IxD + dest->i = dest->mode == src2->mode && dest->d == src2->d; + dest->mode = VAR_INT; + return; + + case OPI_NEQNEQ: // DxD | DxI | IxD + dest->i = dest->mode != src2->mode || dest->d != src2->d; + dest->mode = VAR_INT; + return; + + case OPI_AND: // DxD | DxI | IxD + dest->i = GetIntV(dest) & GetIntV(src2); + dest->mode = VAR_INT; + return; + + case OPI_OR: // DxD | DxI | IxD + dest->i = GetIntV(dest) | GetIntV(src2); + dest->mode = VAR_INT; + return; + + case OPI_EOR: // DxD | DxI | IxD + dest->i = GetIntV(dest) ^ GetIntV(src2); + dest->mode = VAR_INT; + return; + + case OPI_LAND: // DxD | DxI | IxD + dest->i = GetBoolV(dest) && GetBoolV(src2); + dest->mode = VAR_INT; + return; + + case OPI_LOR: // DxD | DxI | IxD + dest->i = GetBoolV(dest) || GetBoolV(src2); + dest->mode = VAR_INT; + return; + + case OPI_LEOR: // DxD | DxI | IxD + dest->i = GetBoolV(dest) != GetBoolV(src2); + dest->mode = VAR_INT; + return; + + case OPI_JOIN: // DxD | DxI | IxD + case OPI_NONE: // DxD | DxI | IxD + case OPI__N: // DxD | DxI | IxD + DASSERT(0); + break; + } + dest->mode = VAR_DOUBLE; + } + else + { + DASSERT( dest->mode == VAR_INT ); + DASSERT( src2->mode == VAR_INT ); + + switch (op_id) + { + case OPI_POW: // IxI + if ( src2->i >= 0 ) + { + // try integer calculation first, double is fall back on overflow + int n = src2->i, res = 1, err = 0; + while ( n-- > 0 ) + { + int new_res = res * dest->i; + if ( abs(new_res) <= abs(res) ) + { + err++; + break; + } + res = new_res; + } + if (!err) + { + dest->i = res; + break; + } + } + dest->d = pow(dest->i,src2->i); + dest->mode = VAR_DOUBLE; + break; + + case OPI_DIV: // IxI + if (src2->i) + { + if ( si->float_div > 0 ) + { + dest->d = (double)dest->i / (double)src2->i; + dest->mode = VAR_DOUBLE; + } + else + dest->i /= src2->i; + } + else if ( si && si->no_warn <= 0 ) + { + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + sf->line_err++; + si->total_err++; + ERROR0(ERR_WARNING,"Division by 0 [%s @%u]\n",sf->name,sf->line); + } + break; + + case OPI_MOD: // IxI + if (src2->i) + dest->i %= src2->i; + else if ( si && si->no_warn <= 0 ) + { + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + sf->line_err++; + si->total_err++; + ERROR0(ERR_WARNING,"Modulo by 0 [%s @%u]\n",sf->name,sf->line); + } + break; + + // IxI + case OPI_MULT: dest->i *= src2->i; break; + case OPI_ADD: dest->i += src2->i; break; + case OPI_SUB: dest->i -= src2->i; break; + + case OPI_LSHIFT: ShiftLeftV(dest, src2->i); break; + case OPI_RSHIFT: ShiftLeftV(dest,-src2->i); break; + + case OPI_LT: dest->i = dest->i < src2->i; break; + case OPI_LE: dest->i = dest->i <= src2->i; break; + case OPI_GT: dest->i = dest->i > src2->i; break; + case OPI_GE: dest->i = dest->i >= src2->i; break; + case OPI_EQ: + case OPI_EQEQ: dest->i = dest->i == src2->i; break; + case OPI_NEQ: + case OPI_NEQNEQ: dest->i = dest->i != src2->i; break; + + case OPI_AND: dest->i &= src2->i; break; + case OPI_OR: dest->i |= src2->i; break; + case OPI_EOR: dest->i ^= src2->i; break; + break; + + case OPI_LAND: dest->i = dest->i && src2->i; break; + case OPI_LOR: dest->i = dest->i || src2->i; break; + case OPI_LEOR: dest->i = !dest->i != !src2->i; break; + + case OPI_JOIN: // IxI + case OPI_NONE: // IxI + case OPI__N: // IxI + DASSERT(0); + break; + } + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// expressions: functions /////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanExprSI +( + ScanInfo_t * si, // valid data + Var_t * var // result: store value here +) +{ + DASSERT(si); + DASSERT(var); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + sf->expr_depth++; + noPRINT("ENTER ScanExprSI(), depth=%d, nowarn=%d, nocalc=%d\n", + sf->expr_depth++, si->no_warn, si->no_calc ); + + struct PARMS + { + const Operator_t * op; + Var_t val; + int no_calc; + + } parm[OPP__N]; + const Operator_t *cur_op = parm->op = op_tab; + struct PARMS *p = parm; + p->val.mode = VAR_UNSET; + + //enum { M_VALUE, M_ALT, M_ALT1, M_ALT2 } mode = M_VALUE; + + enumError maxerr = ERR_OK; + do + { + p++; + DASSERT( p < parm + OPP__N ); + p->op = cur_op; + p->no_calc = si->no_calc; + p->val.mode = VAR_UNSET; + p->val.int_mode = IMD_UNSET; + enumError err = ScanValueSI(si,&p->val); + if ( maxerr < err ) + maxerr = err; + cur_op = FindOperator(si); + + while ( p > parm+1 && cur_op->prio <= p->op->prio ) + { + // calc operations with higher and same priority + + PRINT("%s: %g %s %g [%d,%d,%d] nocalc=%d,%d mode=%dx%d imode=%dx%d\n", + p->no_calc <= 0 ? "CALC" : "SKIP", + GetDoubleV(&p[-1].val), + p->op->op_name, + GetDoubleV(&p->val), + p->op->id, p->op->prio, p->op->mode, + p[-1].no_calc, p->no_calc, + p[-1].val.mode, p->val.mode, + p[-1].val.int_mode, p->val.int_mode ); + if ( p->no_calc <= 0 ) + CalcExpr(&p[-1].val,&p->val,p->op->id,si); + FreeV(&p->val); + p--; + si->no_calc = p->no_calc; + } + + #if HAVE_PRINT + if ( cur_op->id == OPI_LAND || cur_op->id == OPI_LOR ) + PRINT(">>OP=%u '%g %s ...'\n", + cur_op->id, GetDoubleV(&p->val), cur_op->op_name ); + #endif + + if ( cur_op->id == OPI_LAND && !GetBoolV(&p->val) ) + { + PRINT("NO-CALC++ [%d->%d] (AND)\n",si->no_calc,si->no_calc+1); + FreeV(&p->val); + p->val.mode = VAR_INT; + p->val.i = 0; + si->no_calc++; + } + else if ( cur_op->id == OPI_LOR && GetBoolV(&p->val) ) + { + PRINT("NO-CALC++ [%d->%d] (OR)\n",si->no_calc,si->no_calc+1); + FreeV(&p->val); + p->val.mode = VAR_INT; + p->val.i = 1; + si->no_calc++; + } + + } while ( cur_op->prio > OPP_NONE ); + + if ( NextCharSI(si,false) == '?' ) + { + sf->ptr++; + noPRINT("NO-WARN = %d, \n",si->no_warn); + if (GetBoolV(&p->val)) + { + enumError err = ScanExprSI(si,var); + if ( maxerr < err ) + maxerr = err; + + err = CheckWarnSI(si,':',ERR_OK); + if (!err) + { + noPRINT("NO-CALC++ [%d->%d] (1?:)\n",si->no_calc,si->no_calc+1); + si->no_calc++; + ScanExprSI(si,&p->val); + noPRINT("NO-CALC-- [%d->%d] (1?:)\n",si->no_calc,si->no_calc-1); + si->no_calc--; + } + else if ( maxerr < err ) + maxerr = err; + } + else + { + noPRINT("NO-CALC++ [%d->%d] (0?:)\n",si->no_calc,si->no_calc+1); + si->no_calc++; + ScanExprSI(si,var); + noPRINT("NO-CALC-- [%d->%d] (0?:)\n",si->no_calc,si->no_calc-1); + si->no_calc--; + + enumError err = CheckWarnSI(si,':',ERR_OK); + if (!err) + err = ScanExprSI(si,var); + if ( maxerr < err ) + maxerr = err; + } + } + else + AssignVar(var,&p->val); + + noPRINT("LEAVE ScanExprSI(), depth=%d, nowarn=%d, nocalc=%d\n", + sf->expr_depth++, si->no_warn, si->no_calc ); + sf->expr_depth--; + return maxerr; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanVectorExprSI +( + // scans: v | a,b | x,y,z + + ScanInfo_t * si, // valid data + Var_t * var, // result: store value here + double ab_default, // used for 'a,b' format + uint xyz // for ab default: 0:yz, 1:xz, 2:xy +) +{ + DASSERT(si); + DASSERT(var); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + sf->disable_comma++; + enumError err = ScanExprSI(si,var); + ToVectorV(var); + + if ( NextCharSI(si,false) == ',' ) + sf->ptr++; + if (*sf->ptr) + { + DEFINE_VAR(temp); + err = ScanExprSI(si,&temp); + if (!err) + { + if ( NextCharSI(si,false) == ',' ) + sf->ptr++; + if (*sf->ptr) + { + var->y = GetYDoubleV(&temp); + err = ScanExprSI(si,&temp); + var->z = GetZDoubleV(&temp); + } + else if ( xyz == 0 ) + { + var->y = var->x; + var->x = ab_default; + var->z = GetZDoubleV(&temp); + } + else if ( xyz == 2 ) + { + var->y = GetYDoubleV(&temp); + var->z = ab_default; + } + else // xyz == 1 + { + var->y = ab_default; + var->z = GetZDoubleV(&temp); + } + } + } + + sf->disable_comma--; + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanVectorExpr +( + // scans: v | x,z | x,y,z + + ccp arg, // string to scan + ccp name, // NULL or name for error messages + Var_t * var // result: store value here +) +{ + DASSERT(var); + + if (!arg) + arg = ""; + + ScanInfo_t si; + InitializeSI(&si,arg,strlen(arg),name,0); + if (!name) + si.no_warn++; + const enumError err = ScanVectorExprSI(&si,var,0.0,1); + CheckEolSI(&si); + ResetSI(&si); + return err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanMinMaxExprSI +( + // scans: val (min=-val,max=+val) | val1,val2 + + ScanInfo_t *si, // valid data + Var_t *min, // result: store min vector here + Var_t *max // result: store max vector here +) +{ + DASSERT(si); + DASSERT(min); + DASSERT(max); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + sf->disable_comma++; + enumError err = ScanExprSI(si,min); + ToVectorV(min); + + if ( err || NextCharSI(si,false) != ',' ) + { + max->x = fabs(min->x); min->x = -max->x; + max->y = fabs(min->y); min->y = -max->y; + max->z = fabs(min->z); min->z = -max->z; + max->mode = VAR_VECTOR; + } + else + { + sf->ptr++; + err = ScanExprSI(si,max); + ToVectorV(max); + + if ( min->x > max->x ) { double d = min->x; min->x = max->x; max->x = d; } + if ( min->y > max->y ) { double d = min->y; min->y = max->y; max->y = d; } + if ( min->z > max->z ) { double d = min->z; min->z = max->z; max->z = d; } + } + + sf->disable_comma--; + return err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanValueSI +( + ScanInfo_t * si, // valid data + Var_t * var // result: store value here +) +{ + DASSERT(si); + DASSERT(var); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + FreeV(var); + var->mode = VAR_UNSET; + var->int_mode = IMD_UNSET; + var->i = 0; + + enumError err = ERR_OK; + int sign = 0, neg = 0, invert = 0; + char ch = NextCharSI(si,false); + + + //--- arithmetic negation -> delayed + + for(;;) + { + if ( ch == '+' ) + ; + else if ( ch == '-' ) + sign++; + else + break; + sf->ptr++; + ch = NextCharSI(si,false); + } + + + //--- logical negation + + for(;;) + { + if ( ch == '+' ) + ; + else if ( ch == '!' ) + neg++; + else + break; + sf->ptr++; + ch = NextCharSI(si,false); + } + + if (neg) + { + err = ScanValueSI(si,var); + switch (var->mode) + { + case VAR_UNSET: + break; + + case VAR_INT: + var->i = var->i != 0; + break; + + case VAR_DOUBLE: + var->i = var->d != 0; + break; + + case VAR_VECTOR: + var->i = var->x || var->y || var->z; + break; + + case VAR_STRING: + { + const int i = var->str_len > 0; + FREE(var->str); + var->i = i; + } + break; + } + if (neg&1) + var->i = !var->i; + var->mode = VAR_INT; + goto value_ok; + } + + + //--- invertion + + for(;;) + { + if ( ch == '+' ) + ; + else if ( ch == '~' || ch == '^' ) + invert++; + else + break; + sf->ptr++; + ch = NextCharSI(si,false); + } + + if (invert) + { + err = ScanValueSI(si,var); + switch (var->mode) + { + case VAR_UNSET: + break; + + case VAR_INT: + if (invert&1) + var->i = ~var->i; + break; + + case VAR_DOUBLE: + var->i = ~(int)floor(var->d+0.5); + var->mode = VAR_INT; + break; + + case VAR_VECTOR: + var->mode = VAR_UNSET; + break; + + case VAR_STRING: + ResetV(var); + break; + } + goto value_ok; + } + + + //--- analye operand + + switch(ch) + { + case '*': + sf->ptr++; + var->mode = VAR_INT; + var->i = INT_MAX; + goto value_ok; + + case '!': + case '~': + case '^': + err = ScanValueSI(si,var); + goto value_ok; + + case '"': + case '\'': + err = ScanStringSI(si,var); + goto value_ok; + + case '(': + sf->ptr++; + err = CheckWarnSI(si,')',ScanExprSI(si,var)); + goto value_ok; + + case '<': + sf->ptr++; + err = CheckWarnSI(si,'>',ScanBitfieldSI(si,var)); + goto value_ok; + } + + if ( si->force_hex > 0 && IsNum(ch,1) ) + { + char *end; + var->i = strtoul( sf->ptr, &end, 16 ); + var->mode = VAR_INT; + if ( end == sf->ptr ) + { + ccp eol = FindNextLineFeedSI(si,true); + err = ERROR0(ERR_WARNING, + "Can't scan a hex number [%s @%u]: %.*s\n", + sf->name, sf->line, (int)(eol - sf->ptr), sf->ptr ); + } + sf->ptr = end; + } + else if (IsNum(ch,0)) + { + ccp ptr = sf->ptr; + if ( ptr[0] != '0' || ptr[1] != 'x' ) + { + // int or float + + if ( sf->disable_comma <= 0 ) + { + // is this a floating point with a comma? + + ccp src = ptr; + char buf[60], *dest = buf; + char *dest_end = buf + sizeof(buf)/2; + while ( *src >= '0' && *src <= '9' && dest < dest_end ) + *dest++ = *src++; + if ( *src == ',' && src[1] >= '0' && src[1] <= '9' ) + { + src++; + *dest++ = '.'; + dest_end = buf + sizeof(buf); + while ( *src >= '0' && *src <= '9' && dest < dest_end ) + *dest++ = *src++; + if ( dest < dest_end ) + { + *dest = 0; + var->mode = VAR_DOUBLE; + var->d = strtod(buf,0); + sf->ptr = src; + goto value_ok; + } + } + } + + char * end; + double d = strtod(ptr,&end); + + for ( ; ptr < end; ptr++ ) + if ( *ptr < '0' || *ptr > '9' ) + { + // number is float + var->mode = VAR_DOUBLE; + var->d = d; + sf->ptr = end; + goto value_ok; + } + } + + // number is integer + + const uint base = sf->ptr[1] < '0' || sf->ptr[1] > '9' ? 0 : 10; + ccp start = sf->ptr; + var->i = strtoul( sf->ptr, (char**)&sf->ptr, base ); + var->mode = VAR_INT; + if ( sf->ptr == start && *start == '.' && si->point_is_null > 0 ) + sf->ptr++; + } + else + { + char varname[VARNAME_SIZE+1]; + int xyz; + const uint name_len + = ScanNameSI(si,varname,sizeof(varname),false,true,&xyz); + if (!name_len) + { + if ( si->no_warn <= 0 ) + { + ccp eol = FindNextLineFeedSI(si,true); + if ( sf->line_err < 2 ) + { + si->total_err++; + ERROR0(ERR_WARNING, + "Neither name nor number [%s @%u]: %.*s\n", + sf->name, sf->line, + (int)( eol - sf->prev_ptr ), sf->prev_ptr ); + } + } + return ERR_WARNING; + } + + // outside an expression no spaces are allowed between name and '(' + // because of ambiguous meaning with space separated parameter lists + // like: name1 (expression2) + if ( *sf->ptr == '(' || sf->expr_depth && NextCharSI(si,false) == '(' ) + { + //--- we have a function call + + const uint saved_line = sf->line; + const ccp saved_ptr = sf->prev_ptr; + + FuncParam_t temppar; + const FuncParam_t *fpar = si->no_calc > 0 + ? &FuncDollar + : GetParserFunc(varname,si,&temppar); + DASSERT(fpar); + noPRINT("FUNC %s(%u..%u)\n",varname,fpar->min_param,fpar->max_param); + + sf->disable_comma++; + sf->ptr++; + int n_param = 0; + if ( NextCharSI(si,false) != ')' ) + { + while ( sf->param_used < STACK_SIZE ) + { + Var_t * dest = sf->param + sf->param_used++; + if ( !n_param++ && fpar->need_name ) + { + char vname[VARNAME_SIZE+1]; + ScanNameSI(si,vname,sizeof(vname),false,true,0); + dest->name = vname; + } + else + { + enumError err1 = ScanExprSI(si,dest); + if ( err < err1 ) + err = err1; + } + if ( NextCharSI(si,false) != ',' ) + break; + sf->ptr++; + } + } + + if ( si->no_warn <= 0 ) + { + if ( sf->param_used >= STACK_SIZE ) + { + ccp eol = FindNextLineFeedSI(si,true); + ERROR0(ERR_WARNING, + "Stack overflow [%s @%u]: %.*s\n", + sf->name, sf->line, + (int)(eol - sf->prev_ptr), sf->prev_ptr ); + } + else if ( n_param < fpar->min_param || n_param > fpar->max_param ) + { + ccp eol = FindLineFeedSI(si,saved_ptr,true); + ccp attrib = n_param < fpar->min_param ? "few" : "many"; + if ( fpar->min_param == fpar->max_param ) + ERROR0(ERR_WARNING, + "To %s parameters for %s(), have %u, need %u [%s @%u]: %.*s\n", + attrib, varname, n_param, fpar->min_param, + sf->name, saved_line, + (int)(eol - saved_ptr), saved_ptr ); + else + ERROR0(ERR_WARNING, + "To %s parameters for %s(), have %u, need %u..%u [%s @%u]: %.*s\n", + attrib, varname, n_param, fpar->min_param, fpar->max_param, + sf->name, sf->line, + (int)(eol - sf->prev_ptr), sf->prev_ptr ); + } + } + + err = CheckWarnSI(si,')',err); + sf->disable_comma--; + + if ( n_param < fpar->min_param ) + fpar = &FuncDollar; + + ResetV(var); + sf->param_used -= n_param; + enumError err1 = fpar->func(var,sf->param+sf->param_used,n_param,si,fpar); + if ( err < err1 ) + err = err1; + goto value_ok; + } + + if (si->no_calc) + { + // don't search the variable + FreeV(var); + goto value_ok; + } + + if ( xyz >= 0 ) + { + DASSERT( xyz >= 0 && xyz <= 2 ); + const Var_t *svar = FindVarSI(si,varname,false); + if (svar) + { + AssignVar(var,svar); + goto value_ok; + } + + varname[name_len-2] = 0; + svar = FindVarSI(si,varname,false); + if ( svar && svar->mode == VAR_VECTOR ) + { + var->d = svar->v[xyz]; + var->mode = VAR_DOUBLE; + goto value_ok; + } + varname[name_len-2] = '.'; + } + + const Var_t *svar = FindVarSI(si,varname,true); + AssignVar(var,svar); + } + + value_ok: + + if (sign&1) + { + switch (var->mode) + { + case VAR_UNSET: + break; + + case VAR_INT: + var->i = -var->i; + break; + + case VAR_DOUBLE: + var->d = -var->d; + break; + + case VAR_VECTOR: + var->x = -var->x; + var->y = -var->y; + var->z = -var->z; + break; + + case VAR_STRING: + ResetV(var); + break; + } + } + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanUValueSI +( + ScanInfo_t * si, // valid data + long * num, // return value + int force_hex // >0: force hex for non prefixed integers +) +{ + DASSERT(si); + DASSERT(num); + + const int old_force_hex = si->force_hex; + si->force_hex = force_hex; + + DEFINE_VAR(var); + enumError err = ScanValueSI(si,&var); + si->force_hex = old_force_hex; + SkipCharSI(si,','); + + switch(var.mode) + { + case VAR_UNSET: + *num = 0; + return err; + + case VAR_INT: + *num = var.i; + return err; + + case VAR_DOUBLE: + case VAR_VECTOR: + *num = floor( var.d + 0.5 ); + return err; + + case VAR_STRING: + *num = str2l(var.str,0,10); + break; + } + + // only needed to avoid compiler warnings + *num = 0; + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanDValueSI +( + ScanInfo_t * si, // valid data + double * num // return value +) +{ + DASSERT(si); + DASSERT(num); + + DEFINE_VAR(var); + enumError err = ScanValueSI(si,&var); + SkipCharSI(si,','); + + switch(var.mode) + { + case VAR_UNSET: + *num = 0.0; + return err; + + case VAR_INT: + *num = var.i; + return err; + + case VAR_DOUBLE: + case VAR_VECTOR: + *num = var.d; + return err; + + case VAR_STRING: + *num = var.str_len ? strtod(var.str,0) : 0.0; + break; + } + + // only needed to avoid compiler warnings + *num = 0.0; + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanBitfieldSI +( + ScanInfo_t * si, // valid data + Var_t * var // result: store value here +) +{ + DASSERT(si); + DASSERT(var); + ScanFile_t *sf = si->cur_file; + DASSERT(sf); + + uint val = 0; + sf->disable_comma++; + + DEFINE_VAR(temp); + enumError err = ERR_OK; + for(;;) + { + char ch = NextCharSI(si,false); + if ( !ch || ch == '>' ) + break; + + err = ScanValueSI(si,&temp); + if (err) + break; + + int n1 = GetIntV(&temp), n2 = n1; + if ( NextCharSI(si,false) == ':' ) + { + sf->ptr++; + err = ScanValueSI(si,&temp); + if (err) + break; + + n2 = GetIntV(&temp); + } + + if ( n1 < 0 ) + n1 = 0; + if ( n2 > CHAR_BIT * sizeof(uint) - 1 ) + n2 = CHAR_BIT * sizeof(uint) - 1; + PRINT("BITFIELD: %u..%u => %x\n",n1,n2,val); + while ( n1 <= n2 ) + val |= 1u << n1++; + + if ( NextCharSI(si,false) != ',' ) + break; + sf->ptr++; + } + + FreeV(&temp); + sf->disable_comma--; + var->mode = VAR_INT; + var->i = val; + return err; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// struct Line_t /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void InitializeLine ( Line_t * lin ) +{ + DASSERT(lin); + memset(lin,0,sizeof(*lin)); + lin->n = 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError ScanLine +( + Line_t * lin, // valid line data + ScanInfo_t * si, // scanning source + uint n_dim, // number of elements in each vector (<=3) + int mode // user defined mode, stored in 'lin->mode' +) +{ + DASSERT(lin); + DASSERT(si); + DASSERT( n_dim > 0 ); + DASSERT( n_dim <= MAX_LINE_DIMEN ); + + InitializeLine(lin); + lin->line_mode = mode; + if (!NextCharSI(si,false)) + return ERR_OK; + + long n; + enumError err = ScanUValueSI(si,&n,false); + if (err) + return err; + lin->n = ( n < 0 ? 0 : n ) + 1; + + DEFINE_VAR(var); + while ( lin->n_pt < MAX_LINE_HELPER && NextCharSI(si,false) ) + { + err = ScanValueSI(si,&var); + if (err) + goto err; + + double *dest = lin->pt[lin->n_pt]; + *dest++ = GetXDoubleV(&var); + SkipCharSI(si,','); + + if ( var.mode == VAR_VECTOR ) + { + if ( n_dim > 1 ) + { + if ( n_dim > 2 ) + *dest++ = GetYDoubleV(&var); + *dest++ = GetZDoubleV(&var); + } + } + else if ( n_dim > 1 ) + { + if ( n_dim > 2 ) + { + err = ScanValueSI(si,&var); + if (err) + goto err; + *dest++ = GetYDoubleV(&var); + SkipCharSI(si,','); + } + + err = ScanValueSI(si,&var); + SkipCharSI(si,','); + if (err) + goto err; + *dest++ = GetZDoubleV(&var); + } + lin->n_pt++; + } + FreeV(&var); + return CheckEolSI(si); + + err: + FreeV(&var); + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +void CalcLine +( + Line_t * lin, // valid line data + float * dest, // destination vector + const float * p1, // source vector P1 + const float * p2, // source vector P2 + uint n_dim, // number of elements in each vector, n>3 possible + uint step // value between 0 and lin->n inclusive +) +{ + DASSERT(lin); + DASSERT(dest); + + if ( lin->n <= 0 ) + lin->n = 0; + + if ( step == lin->n ) + { + // a little optimization for the most common case + // Important: This case do not access 'p1' + + DASSERT(p2); + memcpy(dest,p2,sizeof(*dest)*n_dim); + return; + } + + if (!step) + { + // a little optimization for the most common case + // Important: This case do not access 'p2' + + DASSERT(p1); + memcpy(dest,p1,sizeof(*dest)*n_dim); + return; + } + + DASSERT(p1); + DASSERT(p2); + // http://en.wikipedia.org/wiki/B%C3%A9zier_curve + + uint dim = 0; + + if ( lin->n_pt == 2 ) + { + // Cubic bezier + // B(t) = (1-t)^3*P1 + 3*(1-t)^2*t*Pa + 3*(1-t)*t^2*Pb + t^3*P2 + + const double t1 = (double)step / (double)lin->n; + const double t2 = 1.0 - t1; + double *pa = lin->pt[0]; + double *pb = lin->pt[1]; + + uint max_dim = n_dim < MAX_LINE_DIMEN ? n_dim : MAX_LINE_DIMEN; + for ( ; dim < max_dim; dim++ ) + { + *dest++ = t2 * t2 * t2 * *p1++ + + 3* t1 * t2 * t2 * *pa++ + + 3* t1 * t1 * t2 * *pb++ + + t1 * t1 * t1 * *p2++; + } + } + else if ( lin->n_pt == 1 ) + { + // Quadratic bezier + // B(t) = (1-t)^2*P1 + 2*(1-t)*t*Pa + t^2*P2 + + const double t1 = (double)step / (double)lin->n; + const double t2 = 1.0 - t1; + double *pa = lin->pt[0]; + + uint max_dim = n_dim < MAX_LINE_DIMEN ? n_dim : MAX_LINE_DIMEN; + for ( ; dim < max_dim; dim++ ) + { + *dest++ = t2 * t2 * *p1++ + + 2* t1 * t2 * *pa++ + + t1 * t1 * *p2++; + } + } + + // all other points are calculated linear: B(t) = (1-t)*P1 + t*P2 + + while ( dim++ < n_dim ) + { + *dest++ = step * ( *p2 - *p1 ) / lin->n + *p1; + p1++; + p2++; + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// END /////////////// +/////////////////////////////////////////////////////////////////////////////// + |
