////////////////////////////////////////////////////////////// // // // Propeller Spin/PASM Compiler // // (c)2012-2016 Parallax Inc. DBA Parallax Semiconductor. // // Adapted from Chip Gracey's x86 asm code by Roy Eltham // // See end of file for terms of use. // // // ////////////////////////////////////////////////////////////// // // ExpressionResolver.cpp // #include #include #include "Utilities.h" #include "PropellerCompilerInternal.h" #include "SymbolEngine.h" #include "Elementizer.h" #include "ErrorStrings.h" //bool GetTryValue(bool bMustResolve, bool bInteger, bool bOperandMode = false); // declared in Utilities.h ////////////////////////////////////////// // declarations of internal functions // void ResolveExpression(); void ResolveSubExpression(int precedence); void GetTerm(int& precedence); bool CheckUndefined(bool& bUndefined); bool CheckDat(); bool CheckConstant(bool& bConstant); bool GetObjSymbol(int type, char id); bool PreviewOp(); bool PerformPush(); bool PerformBinary(); bool PerformOp(); ////////////////////////////////////////// // exported functions // // only valid after calling GetTryValue() with bMustResolve set to true and it returned true int GetResult() { return g_pCompilerData->mathStack[g_pCompilerData->mathCurrent - 1]; } // if this succeeds and bMustResolve it true then, the result is in g_pCompilerData->mathStack[g_pCompilerData->mathCurrent-1] bool GetTryValue(bool bMustResolve, bool bInteger, bool bOperandMode) { g_pCompilerData->intMode = bInteger ? 1 : 0; g_pCompilerData->bMustResolve = bMustResolve; g_pCompilerData->bOperandMode = bOperandMode; g_pCompilerData->mathCurrent = 0; g_pCompilerData->bUndefined = false; g_pCompilerData->currentOp = 0; bool bEof = false; if (!g_pElementizer->GetNext(bEof)) { return false; } int save_start = g_pCompilerData->source_start; g_pElementizer->Backup(); // results are put into g_pCompilerData ResolveExpression(); if (g_pCompilerData->error) { return false; } g_pElementizer->Backup(); if (!g_pElementizer->GetNext(bEof)) { return false; } g_pCompilerData->source_start = save_start; return true; } ////////////////////////////////////////// // internal function definitions // void ResolveExpression() { g_pCompilerData->precedence = 11; ResolveSubExpression(g_pCompilerData->precedence - 1); } void ResolveSubExpression(int precedence) { if (precedence < 0) { GetTerm(precedence); } else { ResolveSubExpression(precedence - 1); } if (g_pCompilerData->error) { return; } bool bEof = false; while (!bEof) { if (!g_pElementizer->GetNext(bEof)) { return; } if (g_pElementizer->GetType() != type_binary) { g_pElementizer->Backup(); return; } if (!PreviewOp()) { return; } if (precedence != g_pElementizer->GetValue()) { g_pElementizer->Backup(); return; } g_pCompilerData->savedOp[g_pCompilerData->currentOp] = g_pElementizer->GetOpType(); g_pCompilerData->currentOp++; int save_start = g_pCompilerData->source_start; int save_finish = g_pCompilerData->source_finish; ResolveSubExpression(precedence - 1); if (g_pCompilerData->error) { return; } g_pCompilerData->source_start = save_start; g_pCompilerData->source_finish = save_finish; if (!PerformBinary()) { return; } g_pCompilerData->currentOp--; } } void GetTerm(int& precedence) { bool bEof = false; // skip over any leading +'s do { g_pElementizer->GetNext(bEof); if (g_pElementizer->GetType() == type_binary && g_pElementizer->GetOpType() == op_add) { continue; } break; } while (!bEof); bool bConstant = false; if (!CheckConstant(bConstant)) { if (g_pCompilerData->error) { return; } } if (bConstant) { PerformPush(); return; } if (g_pElementizer->SubToNeg()) { precedence = 0; } if (g_pElementizer->GetType() == type_unary) { if (!PreviewOp()) { return; } precedence = g_pElementizer->GetValue(); // for unary types, value = precedence int save_start = g_pCompilerData->source_start; int save_finish = g_pCompilerData->source_finish; g_pCompilerData->savedOp[g_pCompilerData->currentOp] = g_pElementizer->GetOpType(); g_pCompilerData->currentOp++; ResolveSubExpression(precedence - 1); if (g_pCompilerData->error) { return; } g_pCompilerData->source_start = save_start; g_pCompilerData->source_finish = save_finish; if (!PerformOp()) { return; } g_pCompilerData->currentOp--; } else if (g_pElementizer->GetType() == type_left) { ResolveExpression(); if (!g_pElementizer->GetElement(type_right)) { return; } } else if (g_pCompilerData->bMustResolve) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_eacuool]; // when we return from here, the calling code will return due to error = true } } bool CheckUndefined(bool& bUndefined) { if (g_pElementizer->GetType() == type_undefined) { g_pCompilerData->bUndefined = bUndefined = true; int save_start = g_pCompilerData->source_start; int save_finish = g_pCompilerData->source_finish; if(g_pElementizer->CheckElement(type_pound)) { int length = 0; if (!GetSymbol(&length)) { return false; } if (length == 0) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_eacn]; return false; } } g_pCompilerData->source_start = save_start; g_pCompilerData->source_finish = save_finish; if (g_pCompilerData->bMustResolve) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_us]; return false; } } else { bUndefined = false; } return true; } bool CheckDat() { if (g_pCompilerData->bOperandMode) { g_pElementizer->DatResToLong(); } if ((g_pElementizer->GetType() == type_dat_byte) || (g_pElementizer->GetType() == type_dat_word) || (g_pElementizer->GetType() == type_dat_long)) { return true; } return false; } bool CheckConstant(bool& bConstant) { bConstant = true; if (g_pElementizer->GetType() == type_con) { if (g_pCompilerData->intMode == 2) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_fpnaiie]; return false; } else { g_pCompilerData->intMode = 1; } g_pCompilerData->intermediateResult = g_pElementizer->GetValue(); return true; } else if (g_pElementizer->GetType() == type_con_float) { if (g_pCompilerData->intMode == 1) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_inaifpe]; return false; } else { g_pCompilerData->intMode = 2; } g_pCompilerData->intermediateResult = g_pElementizer->GetValue(); return true; } else if (g_pElementizer->GetType() == type_float) { if (g_pCompilerData->intMode == 1) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_inaifpe]; return false; } else { g_pCompilerData->intMode = 2; } if (!g_pElementizer->GetElement(type_left)) { return false; } g_pCompilerData->intMode = 1; ResolveExpression(); // integer mode g_pCompilerData->intMode = 2; if (!g_pElementizer->GetElement(type_right)) { return false; } int value = g_pCompilerData->mathStack[g_pCompilerData->mathCurrent - 1]; g_pCompilerData->mathCurrent--; float fValue = (float)(value); g_pCompilerData->intermediateResult = *(int*)(&fValue); return true; } else if (g_pElementizer->GetType() == type_round) { if (g_pCompilerData->intMode == 2) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_fpnaiie]; return false; } else { g_pCompilerData->intMode = 1; } if (!g_pElementizer->GetElement(type_left)) { return false; } g_pCompilerData->intMode = 2; ResolveExpression(); // float mode g_pCompilerData->intMode = 1; if (!g_pElementizer->GetElement(type_right)) { return false; } // convert float to rounded integer int value = g_pCompilerData->mathStack[g_pCompilerData->mathCurrent - 1]; g_pCompilerData->mathCurrent--; float fValue = *(float*)(&value); g_pCompilerData->intermediateResult = (int)(fValue + 0.5f); return true; } else if (g_pElementizer->GetType() == type_trunc) { if (g_pCompilerData->intMode == 2) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_fpnaiie]; return false; } else { g_pCompilerData->intMode = 1; } if (!g_pElementizer->GetElement(type_left)) { return false; } g_pCompilerData->intMode = 2; ResolveExpression(); // float mode g_pCompilerData->intMode = 1; if (!g_pElementizer->GetElement(type_right)) { return false; } // convert float to truncated integer int value = g_pCompilerData->mathStack[g_pCompilerData->mathCurrent - 1]; g_pCompilerData->mathCurrent--; float fValue = *(float*)(&value); g_pCompilerData->intermediateResult = (int)(fValue); return true; } if (g_pCompilerData->bOperandMode) { bool bLocal = false; if (!CheckLocal(bLocal)) { return false; } } bool bUndefined = false; if (!CheckUndefined(bUndefined)) { return false; } if (bUndefined) { if (!g_pCompilerData->bMustResolve) { g_pCompilerData->intermediateResult = 0; } return true; } else if (g_pElementizer->GetType() == type_asm_org) { if (g_pCompilerData->bOperandMode) { g_pCompilerData->intermediateResult = g_pCompilerData->cog_org >> 2; return true; } else { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_oinah]; return false; } } else if (g_pElementizer->GetType() == type_reg) { if (g_pCompilerData->bOperandMode) { if (g_pCompilerData->intMode == 2) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_fpnaiie]; return false; } else { g_pCompilerData->intMode = 1; } g_pCompilerData->intermediateResult = g_pElementizer->GetValue(); g_pCompilerData->intermediateResult |= 0x1E0; return true; } else { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_rinah]; return false; } } else if (g_pElementizer->GetType() == type_obj) { if (!g_pElementizer->GetElement(type_pound)) { return false; } char id = (g_pElementizer->GetValue() & 0x0000FF00) >> 8; if (!GetObjSymbol(type_objcon, id)) { return false; } return CheckConstant(bConstant); } else if (g_pElementizer->GetType() == type_at) { if (g_pCompilerData->intMode == 2) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_fpnaiie]; return false; } else { g_pCompilerData->intMode = 1; } bool bEof = false; if (!g_pElementizer->GetNext(bEof)) { return false; } if (CheckDat()) { g_pCompilerData->intermediateResult = g_pElementizer->GetValue(); return true; } bool bUndefinedCheck = false; if (!CheckUndefined(bUndefinedCheck)) { return false; } if (bUndefinedCheck) { if (!g_pCompilerData->bMustResolve) { g_pCompilerData->intermediateResult = 0; } bConstant = false; return true; } else { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_eads]; return false; } } else if (CheckDat()) { if (g_pCompilerData->intMode == 2) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_fpnaiie]; return false; } else { g_pCompilerData->intMode = 1; } if (g_pCompilerData->bOperandMode) { // use org address in value 2 g_pCompilerData->intermediateResult = g_pElementizer->GetValue2(); // check for valid long address if ((g_pCompilerData->intermediateResult & 0x03) != 0) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_ainl]; return false; } // convert to long index g_pCompilerData->intermediateResult >>= 2; if (g_pCompilerData->intermediateResult >= 0x1F0) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_aioor]; return false; } } else { g_pCompilerData->intermediateResult = g_pElementizer->GetValue(); } return true; } bConstant = false; return true; } bool PreviewOp() { int i = g_pElementizer->GetOpType(); int check = 0x00AACD8F; // 00000000 10101010 11001101 10001111 check >>= i; if (check & 1) { if (g_pCompilerData->intMode == 2) { // integer only op while in float mode g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_ionaifpe]; return false; } // force integer mode g_pCompilerData->intMode = 1; } return true; } bool PerformPush() { if (g_pCompilerData->mathCurrent > 9) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_eitc]; return false; } g_pCompilerData->mathStack[g_pCompilerData->mathCurrent] = g_pCompilerData->intermediateResult; g_pCompilerData->mathCurrent++; return true; } bool PerformBinary() { g_pCompilerData->mathCurrent--; return PerformOp(); } bool PerformOp() { if (g_pCompilerData->bUndefined) { g_pCompilerData->mathStack[g_pCompilerData->mathCurrent-1] = 0; return true; } int value1 = g_pCompilerData->mathStack[g_pCompilerData->mathCurrent - 1]; int value2 = g_pCompilerData->mathStack[g_pCompilerData->mathCurrent]; float fValue1 = *((float*)(&value1)); float fValue2 = *((float*)(&value2)); int result = 0; float fResult = 0.0f; switch(g_pCompilerData->savedOp[g_pCompilerData->currentOp-1]) { case op_ror: result = ror(value1, (value2 & 0xFF)); break; case op_rol: result = rol(value1, (value2 & 0xFF)); break; case op_shr: result = (unsigned int)value1 >> (value2 & 0xFF); break; case op_shl: result = value1 << (value2 & 0xFF); break; case op_min: // limit minimum if (g_pCompilerData->intMode == 2) { fResult = (fValue1 < fValue2) ? fValue2 : fValue1; } else { result = (value1 < value2) ? value2 : value1; } break; case op_max: // limit maximum if (g_pCompilerData->intMode == 2) { fResult = (fValue1 > fValue2) ? fValue2 : fValue1; } else { result = (value1 > value2) ? value2 : value1; } break; case op_neg: if (g_pCompilerData->intMode == 2) { // float neg (using xor) fResult = -fValue1; } else { result = -value1; } break; case op_not: result = ~value1; break; case op_and: result = value1 & value2; break; case op_abs: if (g_pCompilerData->intMode == 2) { // float abs fResult = (float)fabs(fValue1); } else { result = (value1 < 0) ? -value1 : value1; } break; case op_or: result = value1 | value2; break; case op_xor: result = value1 ^ value2; break; case op_add: if (g_pCompilerData->intMode == 2) { // float add fResult = fValue1 + fValue2; } else { result = value1 + value2; } break; case op_sub: if (g_pCompilerData->intMode == 2) { // float sub fResult = fValue1 - fValue2; } else { result = value1 - value2; } break; case op_sar: result = value1 >> (value2 & 0xFF); break; case op_rev: value2 &= 0xFF; result = 0; for (int i = 0; i < value2; i++) { result <<= 1; result |= (value1 & 0x01); value1 >>= 1; } break; case op_log_and: if (value1 != 0) { value1 = 0xFFFFFFFF; } if (value2 != 0) { value2 = 0xFFFFFFFF; } result = value1 & value2; if (g_pCompilerData->intMode == 2) { if (result != 0) { fResult = 1.0f; } else { fResult = 0.0f; } } break; case op_ncd: result = 32; while(!(value1 & 0x80000000) && result > 0) { result--; value1 <<= 1; } break; case op_log_or: if (value1 != 0) { value1 = 0xFFFFFFFF; } if (value2 != 0) { value2 = 0xFFFFFFFF; } result = value1 | value2; if (g_pCompilerData->intMode == 2) { if (result != 0) { fResult = 1.0f; } else { fResult = 0.0f; } } break; case op_dcd: result = 1; result <<= (value1 & 0xFF); break; case op_mul: if (g_pCompilerData->intMode == 2) { // float mul fResult = fValue1 * fValue2; } else { result = value1 * value2; } break; case op_scl: { // calculate the upper 32bits of the 64bit result of multiplying two 32bit numbers // I did it this way to avoid using compiler specific stuff. int a = (value1 >> 16) & 0xffff; int b = value1 & 0xffff; int c = (value2 >> 16) & 0xffff; int d = value2 & 0xffff; int x = a * d + c * b; int y = (((b * d) >> 16) & 0xffff) + x; result = (y >> 16) & 0xffff; result += a * c; } break; case op_div: if (g_pCompilerData->intMode == 2) { // float div fResult = fValue1 / fValue2; } else { result = value1 / value2; } break; case op_rem: // remainder (mod) result = value1 % value2; break; case op_sqr: // sqrt if (g_pCompilerData->intMode == 2) { // float sqrt if (fValue1 < 0.0f) { g_pCompilerData->error = true; g_pCompilerData->error_msg = g_pErrorStrings[error_ccsronfp]; return false; } fResult = (float)sqrt(fValue1); } else { for (result = 0; value1 >= (2*result)+1; value1 -= (2*result++)+1); } break; case op_cmp_b: case op_cmp_a: case op_cmp_ne: case op_cmp_e: case op_cmp_be: case op_cmp_ae: if (g_pCompilerData->intMode == 2) { // float cmp if (fValue1 < fValue2) { result = 1; } else if (fValue1 > fValue2) { result = 2; } else { result = 4; } result &= g_pCompilerData->savedOp[g_pCompilerData->currentOp-1]; if (result != 0) { fResult = 1.0f; } else { fResult = 0.0f; } } else { if (value1 < value2) { result = 1; } else if (value1 > value2) { result = 2; } else { result = 4; } result &= g_pCompilerData->savedOp[g_pCompilerData->currentOp-1]; if (result != 0) { result = 0xFFFFFFFF; } } break; case op_log_not: result = !value1; if (g_pCompilerData->intMode == 2) { if (result != 0) { fResult = 1.0f; } else { fResult = 0.0f; } } else { if (result != 0) { result = 0xFFFFFFFF; } } break; } if (g_pCompilerData->intMode == 2) { result = *(int*)(&fResult); } g_pCompilerData->mathStack[g_pCompilerData->mathCurrent - 1] = result; return true; } /////////////////////////////////////////////////////////////////////////////////////////// // TERMS OF USE: MIT License // /////////////////////////////////////////////////////////////////////////////////////////// // Permission is hereby granted, free of charge, to any person obtaining a copy of this // // software and associated documentation files (the "Software"), to deal in the Software // // without restriction, including without limitation the rights to use, copy, modify, // // merge, publish, distribute, sublicense, and/or sell copies of the Software, and to // // permit persons to whom the Software is furnished to do so, subject to the following // // conditions: // // // // The above copyright notice and this permission notice shall be included in all copies // // or substantial portions of the Software. // // // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A // // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ///////////////////////////////////////////////////////////////////////////////////////////