%{ #include "StdH.h" #include #include #include "ParsingSymbols.h" #include #include %} %{ #define YYERROR_VERBOSE 1 // if error occurs in parsing void yyerror(char *str) { // just report the string _pShell->ErrorF("%s", str); }; static BOOL _bExecNextElse = FALSE; FLOAT fDummy = -666.0f; static INDEX _iStack = 0; static UBYTE _ubStack[1024]; INDEX PushExpression(value &v) { if (v.sttType==STT_FLOAT) { FLOAT f = v.fFloat; memcpy(_ubStack+_iStack, &f, sizeof(f)); _iStack+=sizeof(f); return sizeof(f); } else if (v.sttType==STT_INDEX) { INDEX i = v.iIndex; memcpy(_ubStack+_iStack, &i, sizeof(i)); _iStack+=sizeof(i); return sizeof(i); } else if (v.sttType==STT_STRING) { CTString &str = _shell_astrTempStrings.Push(); str = v.strString; CTString *pstr = &str; memcpy(_ubStack+_iStack, &pstr, sizeof(pstr)); _iStack+=sizeof(pstr); return sizeof(pstr); } else { return 0; } } BOOL MatchTypes(value &v1, value &v2) { if (v1.sttType==STT_FLOAT && v2.sttType==STT_FLOAT) { return TRUE; } else if (v1.sttType==STT_STRING && v2.sttType==STT_STRING) { return TRUE; } else if (v1.sttType==STT_INDEX && v2.sttType==STT_INDEX) { return TRUE; } else { v1.sttType = STT_ILLEGAL; v2.sttType = STT_ILLEGAL; _pShell->ErrorF("Type mismatch"); return FALSE; } } void Declaration( ULONG ulQualifiers, INDEX istType, CShellSymbol &ssNew, INDEX (*pPreFunc)(INDEX), void (*pPostFunc)(INDEX)) { // if external if (ulQualifiers&SSF_EXTERNAL) { // get it a new value if (_shell_ast[istType].st_sttType==STT_INDEX ||_shell_ast[istType].st_sttType==STT_FLOAT) { _pvNextToDeclare = &_shell_afExtFloats.Push(); } else if (_shell_ast[istType].st_sttType==STT_STRING) { _pvNextToDeclare = &_shell_astrExtStrings.Push(); } else { NOTHING; } } // if not parsing an external declaration if (_pvNextToDeclare==NULL) { // error _pShell->ErrorF("Only external declarations are supported"); return; } // if the symbol is declared already if (ssNew.IsDeclared()) { // if the declaration is not identical if (!ShellTypeIsSame(ssNew.ss_istType, istType) || ((ssNew.ss_ulFlags&SSF_CONSTANT)!=(ulQualifiers&SSF_CONSTANT))) { // error _pShell->ErrorF("Symbol '%s' is already declared diferrently", ssNew.ss_strName); return; } // copy its value if (_shell_ast[ssNew.ss_istType].st_sttType==STT_INDEX) { *(INDEX*)_pvNextToDeclare = *(INDEX*)ssNew.ss_pvValue; } else if (_shell_ast[ssNew.ss_istType].st_sttType==STT_FLOAT) { *(FLOAT*)_pvNextToDeclare = *(FLOAT*)ssNew.ss_pvValue; } else if (_shell_ast[ssNew.ss_istType].st_sttType==STT_STRING) { *(CTString*)_pvNextToDeclare = *(CTString*)ssNew.ss_pvValue; } else if (_shell_ast[ssNew.ss_istType].st_sttType==STT_ARRAY) { NOTHING; // array values are not retained } else if (_shell_ast[ssNew.ss_istType].st_sttType==STT_FUNCTION) { NOTHING; // function values are not retained } else { // error _pShell->ErrorF("'%s': old value couldn't be retained", ssNew.ss_strName); return; } } // set the type to given type if (!ssNew.IsDeclared()) { ssNew.ss_istType = ShellTypeMakeDuplicate(istType); } // set the value for the external symbol if not already set if (ssNew.ss_pvValue==NULL || !(ulQualifiers&SSF_EXTERNAL)) { ssNew.ss_pvValue = _pvNextToDeclare; } // remember qualifiers (if already predeclared - keep old flags) ssNew.ss_ulFlags |= ulQualifiers; // remember pre and post functions if (ssNew.ss_pPreFunc==NULL) { ssNew.ss_pPreFunc = (BOOL (*)(void *))pPreFunc; } if (ssNew.ss_pPostFunc==NULL) { ssNew.ss_pPostFunc = (void (*)(void *))pPostFunc; } } void DoComparison(value &vRes, value &v0, value &v1, int token) { MatchTypes(v0, v1); vRes.sttType = STT_INDEX; if (v0.sttType == STT_FLOAT) { switch (token) { case '<': vRes.iIndex = v0.fFloat ': vRes.iIndex = v0.fFloat >v1.fFloat; break; case '=': vRes.iIndex = v0.fFloat==v1.fFloat; break; case '!': vRes.iIndex = v0.fFloat!=v1.fFloat; break; case '}': vRes.iIndex = v0.fFloat>=v1.fFloat; break; case '{': vRes.iIndex = v0.fFloat<=v1.fFloat; break; default: ASSERT(FALSE); vRes.sttType = STT_INDEX; vRes.iIndex = 0; } } else if (v0.sttType == STT_INDEX) { switch (token) { case '<': vRes.iIndex = v0.iIndex ': vRes.iIndex = v0.iIndex >v1.iIndex; break; case '=': vRes.iIndex = v0.iIndex==v1.iIndex; break; case '!': vRes.iIndex = v0.iIndex!=v1.iIndex; break; case '}': vRes.iIndex = v0.iIndex>=v1.iIndex; break; case '{': vRes.iIndex = v0.iIndex<=v1.iIndex; break; default: ASSERT(FALSE); vRes.sttType = STT_INDEX; vRes.iIndex = 0; } } else if (v0.sttType == STT_STRING) { switch (token) { case '<': vRes.iIndex = stricmp(v0.strString, v1.strString) < 0; break; case '>': vRes.iIndex = stricmp(v0.strString, v1.strString) > 0; break; case '=': vRes.iIndex = stricmp(v0.strString, v1.strString) == 0; break; case '!': vRes.iIndex = stricmp(v0.strString, v1.strString) != 0; break; case '}': vRes.iIndex = stricmp(v0.strString, v1.strString) >= 0; break; case '{': vRes.iIndex = stricmp(v0.strString, v1.strString) <= 0; break; default: ASSERT(FALSE); vRes.sttType = STT_INDEX; vRes.iIndex = 0; } } else { vRes.sttType = STT_INDEX; vRes.iIndex = 0; } } %} /* BISON Declarations */ // we need to be reentrant! %pure_parser %union { value val; // for constants and expressions arguments arg; // for function input arguments ULONG ulFlags; // for declaration qualifiers INDEX istType; // for types CShellSymbol *pssSymbol; // for symbols struct LValue lvLValue; INDEX (*pPreFunc)(INDEX); // pre-set function for a variable void (*pPostFunc)(INDEX); // post-set function for a variable } %{ extern int yylex(YYSTYPE *lvalp); %} %token c_float %token c_int %token c_string %token c_char %token identifier %token k_INDEX %token k_FLOAT %token k_CTString %token k_void %token k_const %token k_user %token k_persistent %token k_extern %token k_pre %token k_post %token k_help %token k_if %token k_else %token k_else_if %token SHL %token SHR %token EQ %token NEQ %token GEQ %token LEQ %token LOGAND %token LOGOR %token block_beg %token block_end %type lvalue %type expression %type declaration_qualifiers %type opt_string %type type_specifier %type parameter_list %type parameter_list_opt %type pre_func_opt %type post_func_opt %type argument_expression_list_opt %type argument_expression_list %right '=' %left LOGAND LOGOR %left '&' '^' '|' %left '<' '>' EQ NEQ LEQ GEQ %left SHL %left SHR %left '-' '+' %left '*' '/' '%' %left TYPECAST %left SIGN '!' %start program %% /*///////////////////////////////////////////////////////// * Global structure of the source file. */ program : declaration | statements ; block : block_beg statements block_end | block_beg statements block_end ; statements : /* null */ | statement statements ; declaration_qualifiers : /* nothing */ { $$ = 0; } | declaration_qualifiers k_const { $$ = $1 | SSF_CONSTANT; } | declaration_qualifiers k_user { $$ = $1 | SSF_USER; } | declaration_qualifiers k_persistent { $$ = $1 | SSF_PERSISTENT; } | declaration_qualifiers k_extern { $$ = $1 | SSF_EXTERNAL; } opt_string : /* nothing */ { $$.strString = ""; } | c_string { // !!!! remove this option //_pShell->ErrorF("Warning: symbol comments are not supported"); $$.strString = $1.strString; } type_specifier : k_FLOAT { $$ = ShellTypeNewFloat(); } | k_INDEX { $$ = ShellTypeNewIndex(); } | k_CTString { $$ = ShellTypeNewString(); } | k_void { $$ = ShellTypeNewVoid(); } pre_func_opt : { $$ = NULL; } | k_pre ':' identifier { if (_shell_ast[$3->ss_istType].st_sttType!=STT_FUNCTION ||_shell_ast[_shell_ast[$3->ss_istType].st_istBaseType].st_sttType!=STT_INDEX ||_shell_ast[$3->ss_istType].st_istFirstArgument!=_shell_ast[$3->ss_istType].st_istLastArgument ||_shell_ast[_shell_ast[$3->ss_istType].st_istFirstArgument].st_sttType!=STT_INDEX) { _pShell->ErrorF("'%s' must return 'INDEX' and take 'INDEX' as input", $3->ss_strName); } else { void *pv = $3->ss_pvValue; $$ = (INDEX(*)(INDEX))$3->ss_pvValue; } } post_func_opt : { $$ = NULL; } | k_post ':' identifier { if (_shell_ast[$3->ss_istType].st_sttType!=STT_FUNCTION ||_shell_ast[_shell_ast[$3->ss_istType].st_istBaseType].st_sttType!=STT_VOID ||_shell_ast[$3->ss_istType].st_istFirstArgument!=_shell_ast[$3->ss_istType].st_istLastArgument ||_shell_ast[_shell_ast[$3->ss_istType].st_istFirstArgument].st_sttType!=STT_INDEX) { _pShell->ErrorF("'%s' must return 'void' and take 'INDEX' as input", $3->ss_strName); } else { $$ = (void(*)(INDEX))$3->ss_pvValue; } } ; parameter_list_opt : /* nothing */ { $$ = ShellTypeNewFunction(0); ShellTypeAddFunctionArgument($$, ShellTypeNewVoid()); } | parameter_list { $$ = $1; } ; parameter_list : type_specifier { $$ = ShellTypeNewFunction(0); ShellTypeAddFunctionArgument($$, $1); } /*| identifier type_specifier { $$ = ShellTypeNewFunction(0); ShellTypeAddFunctionArgument($$, $2); }*/ | parameter_list ',' type_specifier { $$ = $1; ShellTypeAddFunctionArgument($$, $3); } /*| parameter_list ',' identifier type_specifier { $$ = $1; ShellTypeAddFunctionArgument($$, $4); } */ ; declaration : declaration_qualifiers type_specifier identifier pre_func_opt post_func_opt opt_string ';' { Declaration($1, $2, *$3, $4, $5); ShellTypeDelete($2); } | declaration_qualifiers type_specifier identifier '(' parameter_list_opt ')' opt_string ';' { // take function from the parameter list and set its return type _shell_ast[$5].st_istBaseType = $2; $2 = $5; // declare it Declaration($1, $2, *$3, NULL, NULL); // free the type (declaration will make a copy) ShellTypeDelete($2); } | declaration_qualifiers type_specifier identifier '[' expression ']' pre_func_opt post_func_opt opt_string ';' { if ($5.sttType!=STT_INDEX) { _pShell->ErrorF("Array size is not integral"); } $2 = ShellTypeNewArray($2, $5.iIndex); Declaration($1, $2, *$3, NULL, NULL); ShellTypeDelete($2); } statement : ';' { // dummy } | block { // dummy } | expression ';' { // print its value if ($1.sttType == STT_VOID) { NOTHING; } else if ($1.sttType == STT_FLOAT) { CPrintF("%g\n", $1.fFloat); } else if ($1.sttType == STT_STRING) { CPrintF("\"%s\"\n", $1.strString); } else if ($1.sttType == STT_INDEX) { CPrintF("%d(0x%08X)\n", $1.iIndex, $1.iIndex); } else { _pShell->ErrorF("Expression cannot be printed"); } } | lvalue '=' expression ';' { // if it is constant if ($1.lv_pssSymbol->ss_ulFlags&SSF_CONSTANT) { _pShell->ErrorF("Symbol '%s' is a constant", $1.lv_pssSymbol->ss_strName); // if it is not constant } else { // if it can be changed if ($1.lv_pssSymbol->ss_pPreFunc==NULL || $1.lv_pssSymbol->ss_pPreFunc($1.lv_pvAddress)) { // if floats if ($1.lv_sttType == STT_FLOAT && $3.sttType==STT_FLOAT) { // assign value *(FLOAT*)$1.lv_pvAddress = $3.fFloat; // if indices } else if ($1.lv_sttType == STT_INDEX && $3.sttType==STT_INDEX) { // assign value *(INDEX*)$1.lv_pvAddress = $3.iIndex; // if strings } else if ($1.lv_sttType == STT_STRING && $3.sttType==STT_STRING) { // assign value *(CTString*)$1.lv_pvAddress = $3.strString; // if assigning index to float } else if ($1.lv_sttType == STT_FLOAT && $3.sttType==STT_INDEX) { *(FLOAT*)$1.lv_pvAddress = $3.iIndex; // otherwise } else { // error _pShell->ErrorF("Cannot assign: different types"); } // call post-change function if ($1.lv_pssSymbol->ss_pPostFunc!=NULL) { $1.lv_pssSymbol->ss_pPostFunc($1.lv_pvAddress); } } } } | declaration_qualifiers type_specifier identifier '=' expression ';' { Declaration($1, $2, *$3, NULL, NULL); ShellTypeDelete($2); CShellSymbol &ssSymbol = *$3; // if it is constant if (ssSymbol.ss_ulFlags&SSF_CONSTANT) { // error _pShell->ErrorF("Symbol '%s' is a constant", ssSymbol.ss_strName); } // get symbol type ShellTypeType stt = _shell_ast[$2].st_sttType; // if floats if (stt == STT_FLOAT && $5.sttType==STT_FLOAT) { // assign value *(FLOAT*)ssSymbol.ss_pvValue = $5.fFloat; // if indices } else if (stt == STT_INDEX && $5.sttType==STT_INDEX) { // assign value *(INDEX*)ssSymbol.ss_pvValue = $5.iIndex; // if strings } else if (stt == STT_STRING && $5.sttType==STT_STRING) { // assign value *(CTString*)ssSymbol.ss_pvValue = $5.strString; // !!!! remove this conversion } else if (stt == STT_FLOAT && $5.sttType==STT_INDEX) { _pShell->ErrorF("Warning: assigning INDEX to FLOAT!"); *(FLOAT*)ssSymbol.ss_pvValue = $5.iIndex; } else { _pShell->ErrorF("Symbol '%s' and its initializer have different types", ssSymbol.ss_strName); } } | k_help identifier { extern void PrintShellSymbolHelp(const CTString &strSymbol); PrintShellSymbolHelp($2->ss_strName); } | k_help identifier '(' ')' { extern void PrintShellSymbolHelp(const CTString &strSymbol); PrintShellSymbolHelp($2->ss_strName); } | k_help identifier '[' ']' { extern void PrintShellSymbolHelp(const CTString &strSymbol); PrintShellSymbolHelp($2->ss_strName); } | k_if '(' expression ')' { _bExecNextBlock = FALSE; if ($3.sttType == STT_INDEX) { _bExecNextBlock = $3.iIndex!=0; } else if ($3.sttType == STT_FLOAT) { _bExecNextBlock = $3.fFloat!=0; } else { _pShell->ErrorF("If expression is not integral"); } $1 = _bExecNextBlock; } block { _bExecNextElse = !$1; _bExecNextBlock = TRUE; } opt_else ; opt_else : /* nothing */ | k_else_if '(' expression ')' { if (_bExecNextElse) { _bExecNextBlock = FALSE; if ($3.sttType == STT_INDEX) { _bExecNextBlock = $3.iIndex!=0; } else if ($3.sttType == STT_FLOAT) { _bExecNextBlock = $3.fFloat!=0; } else { _pShell->ErrorF("If expression is not integral"); } $1 = _bExecNextBlock; } else { _bExecNextBlock = FALSE; _bExecNextElse = FALSE; $1 = TRUE; } } block { _bExecNextElse = !$1; _bExecNextBlock = TRUE; } opt_else | k_else { _bExecNextBlock = _bExecNextElse; } block { _bExecNextBlock = TRUE; } ; lvalue : identifier { CShellSymbol &ssSymbol = *$1; const ShellType &stType = _shell_ast[ssSymbol.ss_istType]; $$.lv_pssSymbol = &ssSymbol; if (!ssSymbol.IsDeclared()) { // error _pShell->ErrorF("Identifier '%s' is not declared", $1->ss_strName); fDummy = -666; $$.lv_sttType = STT_VOID; $$.lv_pvAddress = &fDummy; // if the identifier is a float, int or string } else if (stType.st_sttType==STT_FLOAT || stType.st_sttType==STT_INDEX || stType.st_sttType==STT_STRING) { // get its value and type $$.lv_sttType = stType.st_sttType; $$.lv_pvAddress = ssSymbol.ss_pvValue; // if the identifier is something else } else { // error _pShell->ErrorF("'%s' doesn't have a value", $1->ss_strName); fDummy = -666.0f; $$.lv_sttType = STT_VOID; $$.lv_pvAddress = &fDummy; } } | identifier '[' expression ']' { CShellSymbol &ssSymbol = *$1; const ShellType &stType = _shell_ast[ssSymbol.ss_istType]; $$.lv_pssSymbol = &ssSymbol; int iIndex = 0; // if subscript is index if ($3.sttType==STT_INDEX) { // get the index iIndex = $3.iIndex; // if subscript is not index } else { // error _pShell->ErrorF("Array subscript is not integral"); } // if the symbol is array if (stType.st_sttType==STT_ARRAY) { const ShellType &stBase = _shell_ast[stType.st_istBaseType]; // if it is float or int array if (stBase.st_sttType==STT_FLOAT || stBase.st_sttType==STT_INDEX) { // if the index is out of range if (iIndex<0 || iIndex>=stType.st_ctArraySize) { _pShell->ErrorF("Array member out of range"); fDummy = -666.0f; $$.lv_pvAddress = &fDummy; } else { // get its value and type $$.lv_sttType = stBase.st_sttType; $$.lv_pvAddress = (FLOAT*)ssSymbol.ss_pvValue+iIndex; } } } else { _pShell->ErrorF("'%s[]' doesn't have a value", $1->ss_strName); fDummy = -666.0f; $$.lv_pvAddress = &fDummy; } } ; argument_expression_list_opt : /* nothing */ { $$.istType = ShellTypeNewFunction(ShellTypeNewVoid()); ShellTypeAddFunctionArgument($$.istType, ShellTypeNewVoid()); $$.ctBytes = 0; } | argument_expression_list { $$ = $1; } ; argument_expression_list : expression { $$.istType = ShellTypeNewFunction(ShellTypeNewVoid()); ShellTypeAddFunctionArgument($$.istType, ShellTypeNewByType($1.sttType)); $$.ctBytes = PushExpression($1); } | argument_expression_list ',' expression { $$ = $1; ShellTypeAddFunctionArgument($$.istType, ShellTypeNewByType($3.sttType)); $$.ctBytes += PushExpression($3); } expression : c_float { $$.sttType = STT_FLOAT; $$.fFloat = $1.fFloat; } | c_int { $$.sttType = STT_INDEX; $$.iIndex = $1.iIndex; } | c_string { $$.sttType = STT_STRING; $$.strString = $1.strString; } | lvalue { // get its value $$.sttType = $1.lv_sttType; if ($1.lv_sttType==STT_VOID) { NOTHING; } else if ($1.lv_sttType==STT_FLOAT) { $$.fFloat = *(FLOAT*)$1.lv_pvAddress; } else if ($1.lv_sttType==STT_INDEX) { $$.iIndex = *(INDEX*)$1.lv_pvAddress; } else if ($1.lv_sttType==STT_STRING) { $$.strString = (const char*)*(CTString*)$1.lv_pvAddress; } else { $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; _pShell->ErrorF("'%s' is of wrong type", $1.lv_pssSymbol->ss_strName); } } /* shift */ | expression SHL expression { MatchTypes($1, $3); $$.sttType = $1.sttType; if ($1.sttType == STT_INDEX) { $$.iIndex = $1.iIndex<<$3.iIndex; } else { _pShell->ErrorF("Wrong arguments for '<<'"); $$.sttType = STT_INDEX; $$.iIndex = -666; } } | expression SHR expression { MatchTypes($1, $3); $$.sttType = $1.sttType; if ($1.sttType == STT_INDEX) { $$.iIndex = $1.iIndex>>$3.iIndex; } else { _pShell->ErrorF("Wrong arguments for '>>'"); $$.sttType = STT_INDEX; $$.iIndex = -666; } } /* bitwise operators */ | expression '&' expression { MatchTypes($1, $3); $$.sttType = $1.sttType; if ($1.sttType == STT_FLOAT) { _pShell->ErrorF("'&' is illegal for FLOAT values"); } else if ($1.sttType == STT_INDEX) { $$.iIndex = $1.iIndex&$3.iIndex; } else { $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; } } | expression '|' expression { MatchTypes($1, $3); $$.sttType = $1.sttType; if ($1.sttType == STT_FLOAT) { _pShell->ErrorF("'|' is illegal for FLOAT values"); } else if ($1.sttType == STT_INDEX) { $$.iIndex = $1.iIndex|$3.iIndex; } else { $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; } } | expression '^' expression { MatchTypes($1, $3); $$.sttType = $1.sttType; if ($1.sttType == STT_FLOAT) { _pShell->ErrorF("'^' is illegal for FLOAT values"); } else if ($1.sttType == STT_INDEX) { $$.iIndex = $1.iIndex^$3.iIndex; } else { $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; } } /* logical operators */ | expression LOGAND expression { MatchTypes($1, $3); $$.sttType = $1.sttType; if ($1.sttType == STT_FLOAT) { _pShell->ErrorF("'&&' is illegal for FLOAT values"); } else if ($1.sttType == STT_INDEX) { $$.iIndex = $1.iIndex&&$3.iIndex; } else { $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; } } | expression LOGOR expression { MatchTypes($1, $3); $$.sttType = $1.sttType; if ($1.sttType == STT_FLOAT) { _pShell->ErrorF("'||' is illegal for FLOAT values"); } else if ($1.sttType == STT_INDEX) { $$.iIndex = $1.iIndex||$3.iIndex; } else { $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; } } /* addition */ | expression '+' expression { MatchTypes($1, $3); $$.sttType = $1.sttType; if ($1.sttType == STT_FLOAT) { $$.fFloat = $1.fFloat+$3.fFloat; } else if ($1.sttType == STT_INDEX) { $$.iIndex = $1.iIndex+$3.iIndex; } else if ($1.sttType == STT_STRING) { CTString &strNew = _shell_astrTempStrings.Push(); strNew = CTString($1.strString)+$3.strString; $$.strString = (const char*)strNew; } else { $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; } } /* substraction */ | expression '-' expression { MatchTypes($1, $3); $$.sttType = $1.sttType; if ($1.sttType == STT_FLOAT) { $$.fFloat = $1.fFloat-$3.fFloat; } else if ($1.sttType == STT_INDEX) { $$.iIndex = $1.iIndex-$3.iIndex; } else { $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; } } /* multiplication */ | expression '*' expression { MatchTypes($1, $3); $$.sttType = $1.sttType; if ($1.sttType == STT_FLOAT) { $$.fFloat = $1.fFloat*$3.fFloat; } else if ($1.sttType == STT_INDEX) { $$.iIndex = $1.iIndex*$3.iIndex; } else { $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; } } /* division */ | expression '/' expression { MatchTypes($1, $3); $$.sttType = $1.sttType; if ($1.sttType == STT_FLOAT) { $$.fFloat = $1.fFloat/$3.fFloat; } else if ($1.sttType == STT_INDEX) { if ($3.iIndex==0) { _pShell->ErrorF("Division by zero!\n"); $$.iIndex = 0; } else { $$.iIndex = $1.iIndex/$3.iIndex; } } else { $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; } } /* modulo */ | expression '%' expression { MatchTypes($1, $3); $$.sttType = $1.sttType; if ($1.sttType == STT_FLOAT) { _pShell->ErrorF("'%' is illegal for FLOAT values"); } else if ($1.sttType == STT_INDEX) { $$.iIndex = $1.iIndex%$3.iIndex; } else { $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; } } /* comparisons */ | expression '<' expression { DoComparison($$, $1, $3, '<'); } | expression '>' expression { DoComparison($$, $1, $3, '>'); } | expression EQ expression { DoComparison($$, $1, $3, '='); } | expression NEQ expression { DoComparison($$, $1, $3, '!'); } | expression GEQ expression { DoComparison($$, $1, $3, '}'); } | expression LEQ expression { DoComparison($$, $1, $3, '{'); } // unary minus | '-' expression %prec SIGN { $$.sttType = $2.sttType; if ($2.sttType == STT_FLOAT) { $$.fFloat = -$2.fFloat; } else if ($2.sttType == STT_INDEX) { $$.iIndex = -$2.iIndex; } else { $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; } } // unary plus | '+' expression %prec SIGN { $$.sttType = $2.sttType; if ($2.sttType == STT_FLOAT) { $$.fFloat = $2.fFloat; } else if ($2.sttType == STT_INDEX) { $$.iIndex = $2.iIndex; } else { $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; } } | '!' expression %prec SIGN { $$.sttType = $2.sttType; if ($2.sttType == STT_FLOAT) { _pShell->ErrorF("'!' is illegal for FLOAT values"); $$.fFloat = $2.fFloat; } else if ($2.sttType == STT_INDEX) { $$.iIndex = !$2.iIndex; } else { $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; } } | '(' k_FLOAT ')' expression %prec TYPECAST { $$.sttType = STT_FLOAT; if ($4.sttType == STT_FLOAT) { $$.fFloat = $4.fFloat; } else if ($4.sttType == STT_INDEX) { $$.fFloat = FLOAT($4.iIndex); } else if ($4.sttType == STT_STRING) { $$.fFloat = atof($4.strString); } else { _pShell->ErrorF("Cannot convert to FLOAT"); $$.sttType = STT_VOID; } } | '(' k_INDEX ')' expression %prec TYPECAST { $$.sttType = STT_INDEX; if ($4.sttType == STT_FLOAT) { $$.iIndex = INDEX($4.fFloat); } else if ($4.sttType == STT_INDEX) { $$.iIndex = $4.iIndex; } else if ($4.sttType == STT_STRING) { $$.iIndex = atol($4.strString); } else { _pShell->ErrorF("Cannot convert to INDEX"); $$.sttType = STT_VOID; } } | '(' k_CTString ')' expression %prec TYPECAST { CTString &strNew = _shell_astrTempStrings.Push(); $$.sttType = STT_STRING; if ($4.sttType == STT_FLOAT) { strNew.PrintF("%g", $4.fFloat); } else if ($4.sttType == STT_INDEX) { strNew.PrintF("%d", $4.iIndex); } else if ($4.sttType == STT_STRING) { strNew = $4.strString; } else { _pShell->ErrorF("Cannot convert to CTString"); $$.sttType = STT_VOID; } $$.strString = (const char*)strNew; } // function call | identifier '(' argument_expression_list_opt ')' { // if the identifier is not declared if (!$1->IsDeclared()) { // error _pShell->ErrorF("Identifier '%s' is not declared", $1->ss_strName); // if the identifier is declared } else { // get its type ShellType &stFunc = _shell_ast[$1->ss_istType]; // if the identifier is a function if (stFunc.st_sttType==STT_FUNCTION) { // determine result type ShellType &stResult = _shell_ast[stFunc.st_istBaseType]; // match argument list result to that result _shell_ast[_shell_ast[$3.istType].st_istBaseType].st_sttType = stResult.st_sttType; // if types are same if (ShellTypeIsSame($3.istType, $1->ss_istType)) { #define PUSHPARAMS \ memcpy(_alloca($3.ctBytes), _ubStack+_iStack-$3.ctBytes, $3.ctBytes); // if void if (stResult.st_sttType==STT_VOID) { // just call the function $$.sttType = STT_VOID; //PUSHPARAMS; ((void (*)(void*))$1->ss_pvValue)(_ubStack+_iStack-$3.ctBytes); // if index } else if (stResult.st_sttType==STT_INDEX) { // call the function and return result $$.sttType = STT_INDEX; PUSHPARAMS; $$.iIndex = ((INDEX (*)(void))$1->ss_pvValue)(); // if float } else if (stResult.st_sttType==STT_FLOAT) { // call the function and return result $$.sttType = STT_FLOAT; PUSHPARAMS; $$.fFloat = ((FLOAT (*)(void))$1->ss_pvValue)(); // if string } else if (stResult.st_sttType==STT_STRING) { // call the function and return result $$.sttType = STT_STRING; CTString &strNew = _shell_astrTempStrings.Push(); PUSHPARAMS; strNew = ((CTString (*)(void))$1->ss_pvValue)(); $$.strString = (const char*)strNew; } else { ASSERT(FALSE); $$.sttType = STT_FLOAT; $$.fFloat = -666.0f; } // if types are different } else { // error $$.sttType = STT_VOID; _pShell->ErrorF("Wrong parameters for '%s'", $1->ss_strName); } // if the identifier is something else } else { // error $$.sttType = STT_VOID; _pShell->ErrorF("Can't call '%s'", $1->ss_strName); } } // pop arguments and free type info _iStack-=$3.ctBytes; ShellTypeDelete($3.istType); } // brackets | '(' expression ')' { $$ = $2; } ; %%