Files
BlitzNext/compiler/lib/assem_x86/operand.cpp
T

227 lines
4.1 KiB
C++
Raw Normal View History

2019-01-19 18:28:07 +01:00
#include "operand.hpp"
#include "../ex.hpp"
#include "insts.hpp"
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
static const char* regs[] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", "ax", "cx", "dx", "bx",
"sp", "bp", "si", "di", "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"};
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
static void opError()
{
2019-01-19 18:28:07 +01:00
throw BlitzException("error in operand");
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
static void sizeError()
{
2019-01-19 18:28:07 +01:00
throw BlitzException("illegal operand size");
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
Operand::Operand() : mode(NONE), reg(-1), imm(0), offset(0), baseReg(-1), indexReg(-1), shift(0) {}
2019-01-19 18:28:07 +01:00
Operand::Operand(const std::string& s)
: mode(NONE), reg(-1), imm(0), offset(0), baseReg(-1), indexReg(-1), shift(0), s(s)
{}
2019-01-18 17:04:57 +01:00
bool Operand::parseSize(int* sz)
{
if (!s.size())
return false;
if (s.find("byte ") == 0) {
*sz = 1;
s = s.substr(5);
} else if (s.find("word ") == 0) {
*sz = 2;
s = s.substr(5);
} else if (s.find("dword ") == 0) {
*sz = 4;
s = s.substr(6);
} else
return false;
2014-01-31 08:23:00 +13:00
return true;
}
2019-01-18 17:04:57 +01:00
bool Operand::parseChar(char c)
{
if (!s.size() || s[0] != c)
return false;
s = s.substr(1);
return true;
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
bool Operand::parseReg(int* reg)
{
2014-01-31 08:23:00 +13:00
int i;
2019-01-18 17:04:57 +01:00
for (i = 0; i < s.size() && isalpha(s[i]); ++i) {
}
if (!i)
return false;
2019-01-19 18:28:07 +01:00
std::string t = s.substr(0, i);
2019-01-18 17:04:57 +01:00
for (int j = 0; j < 24; ++j) {
if (t == regs[j]) {
*reg = j;
s = s.substr(i);
return true;
}
2014-01-31 08:23:00 +13:00
}
return false;
}
2019-01-18 17:04:57 +01:00
bool Operand::parseFPReg(int* reg)
{
2014-01-31 08:23:00 +13:00
//eg: st(0)
2019-01-18 17:04:57 +01:00
if (s.size() < 5)
return false;
if (s[0] != 's' || s[1] != 't' || s[2] != '(' || s[4] != ')')
return false;
if (s[3] < '0' || s[3] > '7')
return false;
*reg = s[3] - '0';
s = s.substr(5);
return true;
2014-01-31 08:23:00 +13:00
}
2019-01-19 18:28:07 +01:00
bool Operand::parseLabel(std::string* label)
2019-01-18 17:04:57 +01:00
{
if (!s.size() || (!isalpha(s[0]) && s[0] != '_'))
return false;
2014-01-31 08:23:00 +13:00
int i;
2019-01-18 17:04:57 +01:00
for (i = 1; i < s.size() && (isalnum(s[i]) || s[i] == '_'); ++i) {
}
*label = s.substr(0, i);
s = s.substr(i);
return true;
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
bool Operand::parseConst(int* iconst)
{
int i, sgn = s.size() && (s[0] == '-' || s[0] == '+');
for (i = sgn; i < s.size() && isdigit(s[i]); ++i) {
}
if (i == sgn)
return false;
int n = atoi(s.c_str());
*iconst = n;
s = s.substr(i);
return true;
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
void Operand::parse()
{
if (!s.size())
return;
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
int sz;
if (!parseSize(&sz))
sz = 0;
2014-01-31 08:23:00 +13:00
2019-01-18 17:04:57 +01:00
if (s[0] != '[') {
2014-01-31 08:23:00 +13:00
int r;
2019-01-18 17:04:57 +01:00
if (parseReg(&r)) {
mode = REG | R_M;
if (r < 8) {
if (sz && sz != 1)
sizeError();
mode |= REG8 | R_M8;
if (r == 0)
mode |= AL;
else if (r == 1)
mode |= CL;
} else if (r < 16) {
if (sz && sz != 2)
sizeError();
mode |= REG16 | R_M16;
if (r == 8)
mode |= AX;
else if (r == 9)
mode |= CX;
} else {
if (sz && sz != 4)
sizeError();
mode |= REG32 | R_M32;
if (r == 16)
mode |= EAX;
else if (r == 17)
mode |= ECX;
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
reg = r & 7;
} else if (parseFPReg(&r)) {
mode = FPUREG;
if (!r)
mode |= ST0;
reg = r;
} else if (parseLabel(&immLabel)) {
if (sz && sz != 4)
sizeError();
mode = IMM | IMM32;
} else if (parseConst(&imm)) {
mode = IMM;
if (sz == 1)
mode |= IMM8;
else if (sz == 2)
mode |= IMM16;
else
mode |= IMM32;
} else
opError();
if (s.size())
opError();
2014-01-31 08:23:00 +13:00
return;
}
2019-01-18 17:04:57 +01:00
if (s[s.size() - 1] != ']')
opError();
s = s.substr(1, s.size() - 2);
mode = MEM | R_M;
if (sz == 1)
mode |= MEM8 | R_M8;
else if (sz == 2)
mode |= MEM16 | R_M16;
else
mode |= MEM32 | R_M32;
for (;;) {
2019-01-19 18:28:07 +01:00
int n;
std::string l;
2019-01-18 17:04:57 +01:00
if (parseReg(&n)) {
if (n < 16)
2019-01-19 18:28:07 +01:00
throw BlitzException("register must be 32 bit");
2019-01-18 17:04:57 +01:00
n &= 7;
if (parseChar('*')) {
if (n == 4)
break; //esp cannot be index reg!
if (indexReg >= 0)
break;
if (parseChar('1'))
shift = 0;
else if (parseChar('2'))
shift = 1;
else if (parseChar('4'))
shift = 2;
else if (parseChar('8'))
shift = 3;
else
break;
indexReg = n;
} else {
if (baseReg < 0)
baseReg = n;
else if (indexReg < 0) {
indexReg = n;
} else
break;
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
} else if (parseLabel(&l)) {
if (baseLabel.size())
opError();
baseLabel = l;
} else if (parseConst(&n)) {
offset += n;
} else
break;
if (!s.size())
return;
2014-01-31 08:23:00 +13:00
}
opError();
}