2004-08-06 12:46:59 +04:00
|
|
|
/* AMX Assembler
|
|
|
|
* Copyright (C)2004 David "BAILOPAN" Anderson
|
|
|
|
*
|
|
|
|
* This software is provided 'as-is', without any express or implied
|
|
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
|
|
* arising from the use of this software.
|
|
|
|
*
|
|
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
|
|
* including commercial applications, and to alter it and redistribute it
|
|
|
|
* freely, subject to the following restrictions:
|
|
|
|
*
|
|
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
|
|
* claim that you wrote the original software. If you use this software
|
|
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
|
|
* appreciated but is not required.
|
|
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
|
|
* misrepresented as being the original software.
|
|
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
|
|
*
|
|
|
|
* Version: $Id$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include "amxasm.h"
|
|
|
|
|
|
|
|
CExpr::CExpr()
|
|
|
|
{
|
|
|
|
numVal = 0;
|
|
|
|
type = Val_None;
|
|
|
|
block = 0;
|
2004-08-11 12:14:54 +04:00
|
|
|
bDone = false;
|
2004-08-06 12:46:59 +04:00
|
|
|
CError = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
CExpr::CExpr(ErrorMngr *e)
|
|
|
|
{
|
|
|
|
numVal = 0;
|
|
|
|
type = Val_None;
|
|
|
|
block = 0;
|
2004-08-11 12:14:54 +04:00
|
|
|
bDone = false;
|
2004-08-06 12:46:59 +04:00
|
|
|
CError = e;
|
|
|
|
}
|
|
|
|
|
|
|
|
CExpr::CExpr(ErrorMngr *e, std::string &text)
|
|
|
|
{
|
|
|
|
numVal = 0;
|
|
|
|
type = Val_None;
|
|
|
|
block = 0;
|
|
|
|
CError = e;
|
2004-08-11 12:14:54 +04:00
|
|
|
bDone = false;
|
2004-08-06 12:46:59 +04:00
|
|
|
data.assign(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CExpr::Clear()
|
|
|
|
{
|
|
|
|
if (type == Val_Block && block)
|
|
|
|
delete [] block;
|
|
|
|
numVal = 0;
|
|
|
|
type = Val_None;
|
|
|
|
block = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
CExpr::~CExpr()
|
|
|
|
{
|
2004-08-11 12:14:54 +04:00
|
|
|
if (block && type == Val_Block)
|
2004-08-06 12:46:59 +04:00
|
|
|
delete [] block;
|
|
|
|
}
|
|
|
|
|
|
|
|
char CExpr::IsLiteral(char c)
|
|
|
|
{
|
|
|
|
if (c == '"')
|
|
|
|
return '"';
|
|
|
|
if (c == '\'')
|
|
|
|
return '\'';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char CExpr::IsHex(char c)
|
|
|
|
{
|
|
|
|
if (c >= '0' && c <= '9')
|
|
|
|
return c;
|
|
|
|
if (c >= 'A' && c <= 'F')
|
|
|
|
return c;
|
|
|
|
if (c >= 'a' && c <= 'f')
|
|
|
|
return c;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
cExprType CExpr::GetType()
|
|
|
|
{
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CExpr::Set(std::string &text)
|
|
|
|
{
|
|
|
|
data.assign(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
int CExpr::DeHex(std::string blk)
|
|
|
|
{
|
2004-08-21 10:20:27 +04:00
|
|
|
size_t pos = 0, xc = 0, xpos = 0, ms = 0;
|
2004-08-06 12:46:59 +04:00
|
|
|
/* run through the characters */
|
|
|
|
for (pos = 0; pos < blk.size(); pos++)
|
|
|
|
{
|
|
|
|
if (blk[pos] == 'x')
|
|
|
|
{
|
|
|
|
xc++;
|
|
|
|
if (xc > 1)
|
|
|
|
break;
|
|
|
|
xpos = pos;
|
2004-08-21 10:20:27 +04:00
|
|
|
} else if (blk[pos] == '-') {
|
|
|
|
if (pos != 0)
|
|
|
|
ms = 1;
|
2004-08-06 12:46:59 +04:00
|
|
|
} else if (blk[pos] != ' '
|
|
|
|
&& (blk[pos] < '0' || blk[pos] > '9')
|
|
|
|
&& (!xc || (xc && !IsHex(blk[pos])))) {
|
|
|
|
CError->ErrorMsg(Err_Unexpected_Char, blk[pos]);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (xc > 1)
|
|
|
|
{
|
|
|
|
CError->ErrorMsg(Err_Unexpected_Char, 'x');
|
|
|
|
return 0;
|
|
|
|
}
|
2004-08-21 10:20:27 +04:00
|
|
|
if (ms)
|
|
|
|
{
|
|
|
|
CError->ErrorMsg(Err_Unexpected_Char, '-');
|
|
|
|
return 0;
|
|
|
|
}
|
2004-08-06 12:46:59 +04:00
|
|
|
if (xc)
|
|
|
|
{
|
|
|
|
if (xpos == 0 || blk[xpos-1] != '0')
|
|
|
|
{
|
|
|
|
if (CError)
|
|
|
|
CError->ErrorMsg(Warning_Hex_Start);
|
|
|
|
}
|
|
|
|
blk.erase(0, xpos+1);
|
|
|
|
pos = 0;
|
|
|
|
int j = 0;
|
|
|
|
while (blk[pos])
|
|
|
|
{
|
|
|
|
blk[pos] -= 48;
|
|
|
|
if (blk[pos] > 16)
|
|
|
|
blk[pos] -= 7;
|
|
|
|
if (blk[pos] >= 16)
|
|
|
|
blk[pos] -= 32;
|
|
|
|
if (blk[pos] >= 16 || blk[pos] < 0)
|
|
|
|
{
|
|
|
|
if (CError)
|
2004-08-21 10:20:27 +04:00
|
|
|
{
|
2004-08-06 12:46:59 +04:00
|
|
|
CError->ErrorMsg(Err_Unexpected_Char, blk[pos]);
|
2004-08-21 10:20:27 +04:00
|
|
|
}
|
2004-08-06 12:46:59 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
j *= 16;
|
|
|
|
j += blk[pos];
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return j;
|
|
|
|
}
|
|
|
|
|
|
|
|
return atoi(blk.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
int CExpr::Size()
|
|
|
|
{
|
|
|
|
if (type == Val_String || type == Val_Block)
|
|
|
|
return numVal;
|
|
|
|
if (type == Val_Number)
|
|
|
|
return (SMALL_CELL_SIZE/8);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *CExpr::GetString(int *d)
|
|
|
|
{
|
|
|
|
const char *ret = 0;
|
|
|
|
|
|
|
|
if (type == Val_String)
|
|
|
|
{
|
|
|
|
ret = data.c_str();
|
|
|
|
if (d != NULL)
|
|
|
|
*d = numVal;
|
|
|
|
} else if (type == Val_Block) {
|
|
|
|
ret = block;
|
|
|
|
if (d != NULL)
|
|
|
|
*d = numVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CExpr::GetNumber()
|
|
|
|
{
|
2004-08-11 12:14:54 +04:00
|
|
|
if (type == Val_Float)
|
|
|
|
{
|
|
|
|
memcpy((void*)&numVal, (void*)&fData, sizeof(float));
|
|
|
|
}
|
2004-08-06 12:46:59 +04:00
|
|
|
return numVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns true if the expr can be evaluated */
|
|
|
|
int CExpr::Analyze()
|
|
|
|
{
|
2004-08-11 12:14:54 +04:00
|
|
|
size_t pos = 0, xc = 0, xpos = 0, fd = 0;
|
2004-08-06 12:46:59 +04:00
|
|
|
/* run through the characters */
|
2004-08-09 12:43:27 +04:00
|
|
|
if (data.compare("$") == 0)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
2004-08-06 12:46:59 +04:00
|
|
|
for (pos = 0; pos < data.size(); pos++)
|
|
|
|
{
|
2004-08-11 12:14:54 +04:00
|
|
|
if (data[pos] == '.')
|
2004-08-06 12:46:59 +04:00
|
|
|
{
|
2004-08-11 12:14:54 +04:00
|
|
|
fd++;
|
|
|
|
if (fd > 1 || xc)
|
|
|
|
return 0;
|
|
|
|
} else if (data[pos] == 'x') {
|
2004-08-06 12:46:59 +04:00
|
|
|
xc++;
|
2004-08-11 12:14:54 +04:00
|
|
|
if (xc > 1 || fd)
|
2004-08-06 12:46:59 +04:00
|
|
|
return 0;
|
|
|
|
xpos = pos;
|
|
|
|
} else if (data[pos] != ' '
|
|
|
|
&& (data[pos] < '0' || data[pos] > '9')
|
|
|
|
&& (!xc || (xc && !IsHex(data[pos])))) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2004-08-11 12:14:54 +04:00
|
|
|
cExprType CExpr::Evaluate(int symNum)
|
2004-08-06 12:46:59 +04:00
|
|
|
{
|
2004-08-11 14:01:56 +04:00
|
|
|
size_t i = 0;
|
|
|
|
char litc = 0, c = 0;
|
2004-08-06 12:46:59 +04:00
|
|
|
cExprType t = Val_None;
|
|
|
|
std::string num;
|
|
|
|
|
|
|
|
block = new char[2];
|
2004-08-11 12:14:54 +04:00
|
|
|
bDone = true;
|
2004-08-06 12:46:59 +04:00
|
|
|
|
2004-08-09 12:43:27 +04:00
|
|
|
if (data.compare("$") == 0)
|
|
|
|
{
|
2004-08-11 12:14:54 +04:00
|
|
|
type = Val_Number;
|
2004-08-09 12:43:27 +04:00
|
|
|
numVal = CError->CurCip();
|
2004-08-11 12:14:54 +04:00
|
|
|
Update();
|
|
|
|
return t;
|
|
|
|
} else {
|
2004-08-12 20:31:50 +04:00
|
|
|
if (CError->IsSymbol(data)
|
|
|
|
|| (IsValidSymbol(data) && symNum == Sym_Label || symNum == Sym_Proc))
|
2004-08-11 12:14:54 +04:00
|
|
|
{
|
|
|
|
type = Val_Number;
|
|
|
|
numVal = CError->DerefSymbol(data, symNum);
|
|
|
|
Update();
|
|
|
|
return t;
|
|
|
|
}
|
2004-08-09 12:43:27 +04:00
|
|
|
}
|
|
|
|
|
2004-08-06 12:46:59 +04:00
|
|
|
if (data.find('\'', 0) != std::string::npos || data.find('"', 0) != std::string::npos)
|
|
|
|
{
|
|
|
|
/* STRESS TEST */
|
|
|
|
for (i=0; i<data.size(); i++)
|
|
|
|
{
|
|
|
|
c = data[i];
|
2004-08-09 12:43:27 +04:00
|
|
|
if (c == '\\')
|
|
|
|
{
|
|
|
|
if (i == data.size() - 1)
|
|
|
|
{
|
|
|
|
if (CError)
|
|
|
|
CError->ErrorMsg(Err_String_Terminate);
|
|
|
|
t = Val_Error;
|
|
|
|
} else {
|
|
|
|
char cp = data[i+1];
|
|
|
|
char *nc = 0;
|
|
|
|
if (cp == 't')
|
|
|
|
nc = "\t";
|
|
|
|
else if (cp == 'n')
|
|
|
|
nc = "\n";
|
|
|
|
else if (cp == '\\')
|
|
|
|
nc = "\\";
|
|
|
|
else if (cp == '"')
|
|
|
|
nc = "\"";
|
|
|
|
else if (cp == '\'')
|
|
|
|
nc = "'";
|
|
|
|
if (nc)
|
|
|
|
{
|
|
|
|
data.replace(i, 2, nc);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-08-06 12:46:59 +04:00
|
|
|
if (IsLiteral(c) != 0)
|
|
|
|
{
|
|
|
|
if (litc == IsLiteral(c))
|
|
|
|
{
|
|
|
|
litc = 0;
|
|
|
|
/* The literal has terminated. Expect no more. */
|
|
|
|
if (i != data.size() - 1)
|
|
|
|
{
|
|
|
|
t = Val_Error;
|
|
|
|
if (CError)
|
|
|
|
CError->ErrorMsg(Err_String_Extra, data[i+1]);
|
|
|
|
} else {
|
|
|
|
/* STRING DISCOVERED */
|
|
|
|
t = Val_String;
|
2004-08-08 14:15:08 +04:00
|
|
|
/* Erase literals */
|
|
|
|
data.erase(0, 1);
|
|
|
|
data.erase(data.size()-1, 1);
|
2004-08-06 12:46:59 +04:00
|
|
|
numVal = (int)(data.size()+1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
litc = IsLiteral(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (data.find(' ', 0) != std::string::npos) {
|
|
|
|
/* Build a mem block from values, store length in numVal */
|
|
|
|
t = Val_Block;
|
|
|
|
size_t pos = 0, npos = 0;
|
|
|
|
numVal = 0;
|
|
|
|
pos = data.find(' ', 0);
|
|
|
|
block[numVal++] = DeHex(data.substr(0, pos));
|
|
|
|
while ((pos = data.find(' ', pos)) != std::string::npos)
|
|
|
|
{
|
|
|
|
npos = data.find(' ', pos+1);
|
|
|
|
block = (char *)realloc(block, numVal+2);
|
|
|
|
if (npos != std::string::npos)
|
|
|
|
{
|
|
|
|
block[numVal] = (char)DeHex(data.substr(pos, npos-pos));
|
|
|
|
} else {
|
|
|
|
block[numVal] = (char)DeHex(data.substr(pos));
|
|
|
|
}
|
|
|
|
pos++;
|
|
|
|
numVal++;
|
|
|
|
}
|
|
|
|
} else {
|
2004-08-11 12:14:54 +04:00
|
|
|
if (data.find('.', 0) != std::string::npos)
|
|
|
|
{
|
|
|
|
/* Get as a float */
|
|
|
|
fData = (float)atof(data.c_str());
|
|
|
|
t = Val_Float;
|
|
|
|
memcpy((void*)&numVal, (void*)&fData, sizeof(float));
|
|
|
|
} else {
|
|
|
|
/* Just get the number */
|
|
|
|
t = Val_Number;
|
|
|
|
numVal = DeHex(data);
|
|
|
|
char buf[32];
|
|
|
|
sprintf(buf, "%d", numVal);
|
|
|
|
data.assign(buf);
|
|
|
|
}
|
2004-08-06 12:46:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (litc)
|
|
|
|
{
|
|
|
|
if (CError)
|
|
|
|
CError->ErrorMsg(Err_String_Terminate);
|
|
|
|
}
|
|
|
|
|
|
|
|
type = t;
|
|
|
|
|
|
|
|
return t;
|
|
|
|
}
|
2004-08-11 12:14:54 +04:00
|
|
|
|
|
|
|
void CExpr::Not()
|
|
|
|
{
|
|
|
|
if (type != Val_Number)
|
|
|
|
{
|
|
|
|
if (CError)
|
|
|
|
CError->ErrorMsg(Err_Bad_Not);
|
|
|
|
}
|
|
|
|
numVal = ~numVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CExpr::Oper(OpToken op, CExpr &e)
|
|
|
|
{
|
|
|
|
switch (op)
|
|
|
|
{
|
|
|
|
case Token_Xor:
|
|
|
|
{
|
|
|
|
if (e.GetType() != Val_Number)
|
|
|
|
{
|
|
|
|
if (CError)
|
|
|
|
CError->ErrorMsg(Err_Invalid_Operator);
|
|
|
|
}
|
|
|
|
numVal = numVal ^ e.GetNumber();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token_Shr:
|
|
|
|
{
|
|
|
|
if (e.GetType() != Val_Number)
|
|
|
|
{
|
|
|
|
if (CError)
|
|
|
|
CError->ErrorMsg(Err_Invalid_Operator);
|
|
|
|
}
|
|
|
|
numVal >>= e.GetNumber();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token_Sub:
|
|
|
|
{
|
|
|
|
if (GetType() == Val_Number)
|
|
|
|
{
|
|
|
|
if (e.GetType() == Val_Number)
|
|
|
|
{
|
|
|
|
numVal -= e.GetNumber();
|
|
|
|
} else if (e.GetType() == Val_Float) {
|
|
|
|
numVal -= (int)e.GetFloat();
|
|
|
|
}
|
|
|
|
} else if (GetType() == Val_Float) {
|
|
|
|
if (e.GetType() == Val_Number)
|
|
|
|
{
|
|
|
|
fData -= (float)e.GetNumber();
|
|
|
|
} else if (e.GetType() == Val_Float) {
|
|
|
|
fData -= e.GetFloat();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token_Mod:
|
|
|
|
{
|
|
|
|
if (e.GetType() != Val_Number)
|
|
|
|
{
|
|
|
|
if (CError)
|
|
|
|
CError->ErrorMsg(Err_Invalid_Operator);
|
|
|
|
}
|
|
|
|
numVal = numVal % e.GetNumber();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token_Mul:
|
|
|
|
{
|
|
|
|
if (GetType() == Val_Number)
|
|
|
|
{
|
|
|
|
if (e.GetType() == Val_Number)
|
|
|
|
{
|
|
|
|
numVal *= e.GetNumber();
|
|
|
|
} else if (e.GetType() == Val_Float) {
|
|
|
|
numVal *= (int)e.GetFloat();
|
|
|
|
}
|
|
|
|
} else if (GetType() == Val_Float) {
|
|
|
|
if (e.GetType() == Val_Number)
|
|
|
|
{
|
|
|
|
fData *= (float)e.GetNumber();
|
|
|
|
} else if (e.GetType() == Val_Float) {
|
|
|
|
fData *= e.GetFloat();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token_Div:
|
|
|
|
{
|
|
|
|
if (GetType() == Val_Number)
|
|
|
|
{
|
|
|
|
if (e.GetType() == Val_Number)
|
|
|
|
{
|
|
|
|
numVal /= e.GetNumber();
|
|
|
|
} else if (e.GetType() == Val_Float) {
|
|
|
|
numVal /= (int)e.GetFloat();
|
|
|
|
}
|
|
|
|
} else if (GetType() == Val_Float) {
|
|
|
|
if (e.GetType() == Val_Number)
|
|
|
|
{
|
|
|
|
fData /= (float)e.GetNumber();
|
|
|
|
} else if (e.GetType() == Val_Float) {
|
|
|
|
fData /= e.GetFloat();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token_Shl:
|
|
|
|
{
|
|
|
|
if (e.GetType() != Val_Number)
|
|
|
|
{
|
|
|
|
if (CError)
|
|
|
|
CError->ErrorMsg(Err_Invalid_Operator);
|
|
|
|
}
|
|
|
|
numVal <<= e.GetNumber();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token_And:
|
|
|
|
{
|
|
|
|
if (e.GetType() != Val_Number)
|
|
|
|
{
|
|
|
|
if (CError)
|
|
|
|
CError->ErrorMsg(Err_Invalid_Operator);
|
|
|
|
}
|
|
|
|
numVal &= e.GetNumber();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token_Or:
|
|
|
|
{
|
|
|
|
if (e.GetType() != Val_Number)
|
|
|
|
{
|
|
|
|
if (CError)
|
|
|
|
CError->ErrorMsg(Err_Invalid_Operator);
|
|
|
|
}
|
|
|
|
numVal |= e.GetNumber();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token_Add:
|
|
|
|
{
|
|
|
|
if (GetType() == Val_Number)
|
|
|
|
{
|
|
|
|
if (e.GetType() == Val_Number)
|
|
|
|
{
|
|
|
|
numVal += e.GetNumber();
|
|
|
|
} else if (e.GetType() == Val_Float) {
|
|
|
|
numVal += (int)e.GetFloat();
|
|
|
|
}
|
|
|
|
} else if (GetType() == Val_Float) {
|
|
|
|
if (e.GetType() == Val_Number)
|
|
|
|
{
|
|
|
|
fData += (float)e.GetNumber();
|
|
|
|
} else if (e.GetType() == Val_Float) {
|
|
|
|
fData += e.GetFloat();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
numVal = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CExpr::Update()
|
|
|
|
{
|
|
|
|
if (type == Val_Float)
|
|
|
|
{
|
|
|
|
numVal = (int)fData;
|
|
|
|
} else if (type == Val_Number) {
|
|
|
|
fData = (float)numVal;
|
|
|
|
}
|
|
|
|
if (type != Val_String && type != Val_Block)
|
|
|
|
{
|
|
|
|
char buf[24];
|
|
|
|
sprintf(buf, "%d", numVal);
|
|
|
|
data.assign(buf);
|
|
|
|
}
|
2004-08-11 14:01:56 +04:00
|
|
|
}
|