forked from MirrorRepos/RomWBW
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
977 lines
26 KiB
977 lines
26 KiB
//////////////////////////////////////////////////////////////
|
|
// //
|
|
// 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 <string.h>
|
|
#include <math.h>
|
|
#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. //
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|