mirror of https://github.com/marketideas/qasm.git
first commit
This commit is contained in:
commit
b7cb4a9afa
|
@ -0,0 +1 @@
|
|||
**/build
|
|
@ -0,0 +1,42 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
set(APPVERSION "1.0.0")
|
||||
set(LIBRARY_NAME pal)
|
||||
|
||||
include(./lib${LIBRARY_NAME}/cmake/CMakeHeader.txt)
|
||||
|
||||
set(SOURCE
|
||||
${PROJECT_ROOT}/${PROJECT_ID}.cpp
|
||||
${PROJECT_ROOT}/asm.cpp
|
||||
${PROJECT_ROOT}/opcodes.cpp
|
||||
${PROJECT_ROOT}/eval.cpp
|
||||
)
|
||||
|
||||
include_directories(BEFORE
|
||||
${PROJECT_ROOT}
|
||||
${PROJECT_ROOT}/lib${LIBRARY_NAME}/include/${LIBRARY_NAME}
|
||||
)
|
||||
|
||||
add_subdirectory(${PROJECT_ROOT}/lib${LIBRARY_NAME})
|
||||
|
||||
include(${PROJECT_ROOT}/lib${LIBRARY_NAME}/cmake/CMakeApp.txt)
|
||||
|
||||
add_executable( ${PROJECT_NAME} ${SOURCE})
|
||||
|
||||
target_link_libraries (
|
||||
${PROJECT_NAME}
|
||||
${LIBRARY_NAME}
|
||||
pthread
|
||||
PocoFoundation
|
||||
PocoNet
|
||||
PocoUtil
|
||||
PocoNetSSL
|
||||
PocoCrypto
|
||||
)
|
||||
|
||||
include(./lib${LIBRARY_NAME}/cmake/CMakeCommands.txt)
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
export CC=/usr/bin/clang
|
||||
export CXX=/usr/bin/clang++
|
||||
|
||||
|
||||
V?=
|
||||
S=
|
||||
ifneq ("$V","")
|
||||
S="VERBOSE=1"
|
||||
else
|
||||
.SILENT:
|
||||
endif
|
||||
|
||||
all:
|
||||
-mkdir -p ./build
|
||||
-cd ./build && cmake .. && $(MAKE) $S
|
||||
|
||||
distclean:
|
||||
rm -rf build app/build sgqlib/build
|
||||
|
||||
clean:
|
||||
-cd ./build && $(MAKE) clean
|
||||
|
||||
depend:
|
||||
-cd ./build && $(MAKE) depend
|
||||
|
||||
rebuild:
|
||||
-cd ./build && $(MAKE) rebuild_cache
|
||||
|
||||
lib:
|
||||
-cd ./build && $(MAKE) sgq
|
||||
|
||||
run:
|
||||
-cd ./build && $(MAKE) run
|
||||
|
||||
install:
|
||||
-cd ./build && cmake -P cmake_install.cmake
|
||||
|
||||
asm:
|
||||
qasm src/testfile.s
|
||||
#cd src/asm && ../qasm main.s
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,920 @@
|
|||
#define ADD_ERROR_STRINGS
|
||||
#include "asm.h"
|
||||
#include "eval.h"
|
||||
|
||||
#define CLASS MerlinLine
|
||||
|
||||
|
||||
CLASS::CLASS()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
CLASS::CLASS(std::string line)
|
||||
{
|
||||
clear();
|
||||
set(line);
|
||||
}
|
||||
|
||||
|
||||
void CLASS::setError(uint32_t ecode)
|
||||
{
|
||||
errorcode = ecode;
|
||||
}
|
||||
|
||||
void CLASS::print(uint32_t lineno)
|
||||
{
|
||||
int i, l;
|
||||
|
||||
|
||||
l = outbytect;
|
||||
if (l > 4)
|
||||
{
|
||||
l = 4;
|
||||
}
|
||||
|
||||
//if ((opflags&OP_STD)!=OP_STD)
|
||||
if ((opcodelower != "inc") && (opcodelower != "ldx") && (opcodelower != "stx"))
|
||||
{
|
||||
//return;
|
||||
}
|
||||
if (errorcode > 0)
|
||||
{
|
||||
if (errorcode >= errFatal)
|
||||
{
|
||||
SetColor(CL_WHITE | CL_BOLD | BG_RED);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetColor(CL_YELLOW | CL_BOLD | BG_NORMAL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetColor(CL_WHITE | CL_BOLD | BG_NORMAL);
|
||||
}
|
||||
bool empty = false;
|
||||
if ((lable == "") && (opcode == "") && (operand == ""))
|
||||
{
|
||||
empty = true;
|
||||
}
|
||||
int b = 4;
|
||||
|
||||
printf("%02X ", addressmode);
|
||||
printf("%6d", lineno + 1);
|
||||
if (!empty)
|
||||
{
|
||||
printf(" %06X:", startpc);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
for (i = 0; i < l; i++)
|
||||
{
|
||||
printf("%02X ", outbytes[i]);
|
||||
}
|
||||
for (i = l; i < b; i++)
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
if (empty)
|
||||
{
|
||||
printf("%s", comment.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%-12s %-8s %-10s ", lable.c_str(), opcode.c_str(), operand.c_str());
|
||||
if (errorcode > 0)
|
||||
{
|
||||
printf(":[Error] %s", errStrings[errorcode].c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s", comment.c_str());
|
||||
}
|
||||
}
|
||||
if (errorcode > 0)
|
||||
{
|
||||
SetColor(CL_NORMAL | BG_NORMAL);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
}
|
||||
|
||||
void CLASS::clear()
|
||||
{
|
||||
syntax = SYNTAX_MERLIN;
|
||||
lable = "";
|
||||
opcode = "";
|
||||
opcodelower = "";
|
||||
operand = "";
|
||||
comment = "";
|
||||
operand_expr = "";
|
||||
addrtext = "";
|
||||
bytect = 0;
|
||||
opflags = 0;
|
||||
pass0bytect = 0;
|
||||
startpc = 0;
|
||||
errorcode = 0;
|
||||
inbytect = 0;
|
||||
outbytect = 0;
|
||||
outbytes.clear();
|
||||
addressmode = 0;
|
||||
expr_value = 0;
|
||||
flags = 0;
|
||||
outbytes.clear();
|
||||
}
|
||||
|
||||
void CLASS::set(std::string line)
|
||||
{
|
||||
int state = 0;
|
||||
int l = line.length();
|
||||
int i = 0;
|
||||
char c,delim;
|
||||
|
||||
clear();
|
||||
|
||||
//printf("line: |%s|\n", line.c_str());
|
||||
while (i < l)
|
||||
{
|
||||
c = line[i++];
|
||||
//printf("state: %d\n",state);
|
||||
switch (state)
|
||||
{
|
||||
case 0: // start of line state
|
||||
if ((c == ';') || (c == '*'))
|
||||
{
|
||||
comment += c;
|
||||
state = 7;
|
||||
}
|
||||
else if (c > ' ')
|
||||
{
|
||||
lable += c;
|
||||
state = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = 2;
|
||||
};
|
||||
break;
|
||||
case 1: // read in entire lable until whitespace
|
||||
if (c > ' ')
|
||||
{
|
||||
lable += c;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = 2;
|
||||
}
|
||||
break;
|
||||
case 2: // read whitespace between label and opcode
|
||||
if (c == ';')
|
||||
{
|
||||
comment += c;
|
||||
state = 7;
|
||||
}
|
||||
else if (c > ' ')
|
||||
{
|
||||
opcode += c;
|
||||
state = 3;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (c > ' ')
|
||||
{
|
||||
opcode += c;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = 4;
|
||||
}
|
||||
break;
|
||||
case 4: // read whitespace between opcode and operand
|
||||
if (c == ';')
|
||||
{
|
||||
comment += c;
|
||||
state = 7;
|
||||
}
|
||||
else if (c > ' ')
|
||||
{
|
||||
operand += c;
|
||||
if (c == '\'')
|
||||
{
|
||||
state = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = 5;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if ((c == '\'') || (c=='"'))
|
||||
{
|
||||
delim=c;
|
||||
operand += c;
|
||||
state = 8;
|
||||
}
|
||||
else if (c > ' ')
|
||||
{
|
||||
operand += c;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = 6;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (c > ' ')
|
||||
{
|
||||
comment += c;
|
||||
state = 7;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
comment += c;
|
||||
break;
|
||||
case 8:
|
||||
if (c == delim)
|
||||
{
|
||||
operand += c;
|
||||
state = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
operand += c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
opcodelower = Poco::toLower(opcode);
|
||||
}
|
||||
|
||||
#undef CLASS
|
||||
#define CLASS TFileProcessor
|
||||
|
||||
CLASS::CLASS()
|
||||
{
|
||||
}
|
||||
|
||||
CLASS::~CLASS()
|
||||
{
|
||||
}
|
||||
|
||||
void CLASS::errorOut(uint16_t code)
|
||||
{
|
||||
printf("error: %d\n", code);
|
||||
}
|
||||
|
||||
void CLASS::init(void)
|
||||
{
|
||||
syntax = SYNTAX_MERLIN;
|
||||
}
|
||||
|
||||
void CLASS::complete(void)
|
||||
{
|
||||
}
|
||||
|
||||
void CLASS::process(void)
|
||||
{
|
||||
|
||||
}
|
||||
int CLASS::doline(int lineno, std::string line)
|
||||
{
|
||||
int res = -1;
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int CLASS::processfile(std::string &p)
|
||||
{
|
||||
//Poco::File fn(p);
|
||||
int c;
|
||||
int res = -1;
|
||||
uint32_t linect;
|
||||
bool done, valid;
|
||||
std::string p1;
|
||||
std::string line, op;
|
||||
|
||||
linect = 0;
|
||||
done = false;
|
||||
|
||||
Poco::Path tp(p);
|
||||
Poco::Path path = tp.makeAbsolute();
|
||||
|
||||
valid = true;
|
||||
p1 = tp.toString();
|
||||
Poco::File fn(p1);
|
||||
if (!fn.exists())
|
||||
{
|
||||
fn = Poco::File(p1 + ".s");
|
||||
if (!fn.exists())
|
||||
{
|
||||
fn = Poco::File(p1 + ".S");
|
||||
if (!fn.exists())
|
||||
{
|
||||
fn = Poco::File(p1 + ".mac");
|
||||
if (!fn.exists())
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
p1 = fn.path();
|
||||
|
||||
if (valid)
|
||||
{
|
||||
std::ifstream f(p1);
|
||||
if (f.is_open())
|
||||
{
|
||||
//printf("file is open\n");
|
||||
line = "";
|
||||
|
||||
while ((!done) && (f.good()) && (!f.eof()))
|
||||
{
|
||||
c = f.get();
|
||||
if (c == 0x8D) // merlin line ending
|
||||
{
|
||||
c = 0x0A; // convert to linux
|
||||
}
|
||||
if (c == 0x8A) // possible merlin line ending
|
||||
{
|
||||
c = 0x00; // ignore
|
||||
}
|
||||
c &= 0x7F;
|
||||
#if 0
|
||||
//printf("%02X ",c&0x7F);
|
||||
|
||||
printf("%c", c);
|
||||
#else
|
||||
int x;
|
||||
switch (c)
|
||||
{
|
||||
case 0x0D:
|
||||
break;
|
||||
case 0x09:
|
||||
line += " ";
|
||||
break;
|
||||
case 0x0A:
|
||||
linect++;
|
||||
x = doline(linect, line);
|
||||
if (x < 0)
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
line = "";
|
||||
break;
|
||||
default:
|
||||
if ((c >= ' ') && (c < 0x7F))
|
||||
{
|
||||
line += c;
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("garbage %08X\n",c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if ( (f.eof()))
|
||||
{
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("file %s does not exist\n", p.c_str());
|
||||
}
|
||||
|
||||
//printf("\n\nfile read result: %d\n", res);
|
||||
return (res);
|
||||
}
|
||||
|
||||
#undef CLASS
|
||||
|
||||
#define CLASS T65816Asm
|
||||
|
||||
CLASS::CLASS()
|
||||
{
|
||||
lines.clear();
|
||||
}
|
||||
|
||||
#define OPHANDLER(ACB) std::bind(ACB, this, std::placeholders::_1, std::placeholders::_2)
|
||||
|
||||
CLASS::~CLASS()
|
||||
{
|
||||
}
|
||||
|
||||
void CLASS::pushopcode(std::string op, uint8_t opcode, uint16_t flags, TOpCallback cb)
|
||||
{
|
||||
TSymbol sym;
|
||||
|
||||
sym.name = op;
|
||||
sym.opcode = opcode;
|
||||
sym.namelc = Poco::toLower(op);
|
||||
sym.stype = flags;
|
||||
sym.value = 0;
|
||||
sym.cb = cb;
|
||||
std::pair<std::string, TSymbol> p(Poco::toUpper(op), sym);
|
||||
|
||||
opcodes.insert(p);
|
||||
}
|
||||
|
||||
|
||||
TSymbol *CLASS::findSymbol(std::string symname)
|
||||
{
|
||||
TSymbol *res = NULL;
|
||||
|
||||
auto itr = symbols.find(Poco::toUpper(symname));
|
||||
if (itr != symbols.end())
|
||||
{
|
||||
res = &itr->second;
|
||||
|
||||
return (res);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
TSymbol *CLASS::addSymbol(std::string sym, uint32_t val, bool replace)
|
||||
{
|
||||
TSymbol *res = NULL;
|
||||
TSymbol *fnd = NULL;
|
||||
|
||||
fnd = findSymbol(sym);
|
||||
|
||||
if ((fnd != NULL) && (!replace))
|
||||
{
|
||||
return (NULL); // it is a duplicate
|
||||
}
|
||||
|
||||
if (fnd != NULL)
|
||||
{
|
||||
fnd->value = val;
|
||||
return (fnd);
|
||||
}
|
||||
|
||||
TSymbol s;
|
||||
s.name = sym;
|
||||
s.opcode = 0;
|
||||
s.namelc = Poco::toLower(sym);
|
||||
s.stype = 0;
|
||||
s.value = val;
|
||||
s.cb = NULL;
|
||||
std::pair<std::string, TSymbol> p(Poco::toUpper(sym), s);
|
||||
symbols.insert(p);
|
||||
res = findSymbol(sym);
|
||||
return (res);
|
||||
}
|
||||
|
||||
void CLASS::showSymbolTable(void)
|
||||
{
|
||||
// Poco::HashTable::Iterator itr;
|
||||
for (auto itr = symbols.begin(); itr != symbols.end(); itr++)
|
||||
{
|
||||
TSymbol ptr = itr->second;
|
||||
printf("Sym: %-24s 0x%08X\n", ptr.name.c_str(), ptr.value);
|
||||
}
|
||||
}
|
||||
|
||||
int CLASS::callOpCode(std::string op, MerlinLine &line)
|
||||
{
|
||||
int res = -1;
|
||||
char c;
|
||||
|
||||
if (op.length() == 4) // check for 4 digit 'L' opcodes
|
||||
{
|
||||
c = op[3];
|
||||
if ((c >= 'a') || (c <= 'z'))
|
||||
{
|
||||
c = c - 0x20;
|
||||
}
|
||||
if (c == 'L')
|
||||
{
|
||||
op = op.substr(0, 3);
|
||||
line.flags |= FLAG_LONGADDR;
|
||||
}
|
||||
|
||||
}
|
||||
//Poco::HashMap<std::string, TSymbol>::ConstIterator ptr;
|
||||
|
||||
auto itr = opcodes.find(Poco::toUpper(op));
|
||||
if (itr != opcodes.end())
|
||||
{
|
||||
TSymbol s = itr->second;
|
||||
if (s.cb != NULL)
|
||||
{
|
||||
if (s.stype & OP_ONEBYTE)
|
||||
{
|
||||
line.inbytes[0] = (s.opcode);
|
||||
line.inbytect = 1;
|
||||
}
|
||||
res = s.cb(line, s);
|
||||
if (res == -1)
|
||||
{
|
||||
res = -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
line.setError(errBadOpcode);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
//imp = <no operand>
|
||||
//imm = #$00
|
||||
//sr = $00,S
|
||||
//dp = $00
|
||||
//dpx = $00,X
|
||||
//dpy = $00,Y
|
||||
//idp = ($00)
|
||||
//idx = ($00,X)
|
||||
//idy = ($00),Y
|
||||
//idl = [$00]
|
||||
//idly = [$00],Y
|
||||
//isy = ($00,S),Y
|
||||
//abs = $0000
|
||||
//abx = $0000,X
|
||||
//aby = $0000,Y
|
||||
//abl = $000000
|
||||
//alx = $000000,X
|
||||
//ind = ($0000)
|
||||
//iax = ($0000,X)
|
||||
//ial = [$000000]
|
||||
//rel = $0000 (8 bits PC-relative)
|
||||
//rell = $0000 (16 bits PC-relative)
|
||||
//bm = $00,$00
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::string regEx;
|
||||
uint16_t addrMode;
|
||||
std::string text;
|
||||
std::string expression;
|
||||
} TaddrMode;
|
||||
|
||||
TaddrMode addrRegEx[] =
|
||||
{
|
||||
{ "^(?'expr'.+)\\,[s,S]{1}$", syn_s, "e,s"}, // expr,s
|
||||
{"^[(]{1}(?'expr'.+)[,]{1}[(S|s)]{1}[)]{1}[,]{1}[(Y|y)]{1}$", syn_sy, "(e,s),y"}, // (expr,s),y
|
||||
{"^#{1}(?'shift'[<,>,^,|]?)(.+)$", syn_imm, "immediate"}, //#expr,#^expr,#|expr,#<expr,#>expr
|
||||
{"^[(]{1}(?'expr'.+)[,]{1}[x,X]{1}\\)$", syn_diix, "(e,x)"}, // (expr,x)
|
||||
{"^[(]{1}(?'expr'.+)[\\)]{1}[\\,][(Y|y]{1}$", syn_diiy, "(e),y"}, //(expr),y
|
||||
{"^[(]{1}(?'expr'.+)[\\)]{1}$", syn_di, "(e)"}, // (expr)
|
||||
{"^\\[{1}(?'expr'.+)\\]{1}[,]{1}[(Y|y)]{1}$", syn_iyl, "[e],x"}, // [expr],y
|
||||
{"^\\[(?'expr'.+)\\]$", syn_dil, "[e]"}, // [expr]
|
||||
{"^(?'expr'.+)[,]{1}[(X|x)]{1}$", syn_absx, "e,x"}, // expr,x
|
||||
{"^(?'expr'.+)[,]{1}[(Y|y)]{1}$", syn_absy, "e,y"}, // expr,y
|
||||
{"^(?'expr'.+)[,]{1}(?'expr2'.+)$", syn_bm, "block"}, // block move expr,expr1
|
||||
{"^(?'expr'.+)$", syn_abs, "absolute"}, // expr (MUST BE LAST)
|
||||
{"", 0, ""}
|
||||
};
|
||||
|
||||
// opcodes that are only 65C02 (27) - also in 65816
|
||||
|
||||
// 0x01 = 6502
|
||||
// 0x02 = 65C02
|
||||
// 0x03 = 65816
|
||||
uint8_t opCodeCompatibility[256] = {
|
||||
0x00,0x00,0x02,0x02,0x01,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x01,0x00,0x00,0x02,
|
||||
0x00,0x00,0x01,0x02,0x01,0x00,0x00,0x02,0x00,0x00,0x01,0x02,0x01,0x00,0x00,0x02,
|
||||
0x00,0x00,0x02,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,
|
||||
0x00,0x00,0x01,0x02,0x01,0x00,0x00,0x02,0x00,0x00,0x01,0x02,0x01,0x00,0x00,0x02,
|
||||
0x00,0x00,0x02,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,
|
||||
0x00,0x00,0x01,0x02,0x02,0x00,0x00,0x02,0x00,0x00,0x01,0x02,0x02,0x00,0x00,0x02,
|
||||
0x00,0x00,0x02,0x02,0x01,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,
|
||||
0x00,0x00,0x01,0x02,0x01,0x00,0x00,0x02,0x00,0x00,0x01,0x02,0x01,0x00,0x00,0x02,
|
||||
0x01,0x00,0x02,0x02,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x02,
|
||||
0x00,0x00,0x01,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x01,0x00,0x01,0x02,
|
||||
0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,
|
||||
0x00,0x00,0x01,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,
|
||||
0x00,0x00,0x02,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,
|
||||
0x00,0x00,0x01,0x02,0x02,0x00,0x00,0x02,0x00,0x00,0x01,0x02,0x02,0x00,0x00,0x02,
|
||||
0x00,0x00,0x02,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,
|
||||
0x00,0x00,0x01,0x02,0x02,0x00,0x00,0x02,0x00,0x00,0x01,0x02,0x02,0x00,0x00,0x02
|
||||
};
|
||||
|
||||
void CLASS::init(void)
|
||||
{
|
||||
TFileProcessor::init();
|
||||
lines.clear();
|
||||
|
||||
insertOpcodes();
|
||||
|
||||
}
|
||||
|
||||
void CLASS::initpass(void)
|
||||
{
|
||||
casesen = true;
|
||||
relocatable = false;
|
||||
listing = true;
|
||||
|
||||
origin = 0;
|
||||
currentpc = 0;
|
||||
cpumode = MODE_65816;
|
||||
mx = 0x00;
|
||||
currentsym = NULL;
|
||||
totalbytes = 0;
|
||||
lineno = 0;
|
||||
passcomplete = false;
|
||||
}
|
||||
|
||||
void CLASS::complete(void)
|
||||
{
|
||||
printf("=== Assembly Complete: %d bytes\n", totalbytes);
|
||||
|
||||
if (listing)
|
||||
{
|
||||
showSymbolTable();
|
||||
}
|
||||
}
|
||||
|
||||
int CLASS::evaluate(std::string expr, int64_t &value)
|
||||
{
|
||||
int res = -1;
|
||||
int64_t result = 0;
|
||||
|
||||
if (expr.length() > 0)
|
||||
{
|
||||
|
||||
TEvaluator eval(*this);
|
||||
|
||||
res = eval.evaluate(expr, result);
|
||||
//printf("res=%d %08lX\n",res,result);
|
||||
if (res == 0)
|
||||
{
|
||||
value = result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = 0;
|
||||
res = 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int CLASS::getAddrMode(MerlinLine &line)
|
||||
{
|
||||
int res = -1;
|
||||
uint16_t mode = syn_none;
|
||||
int idx, x;
|
||||
std::string s, oper;
|
||||
std::vector<std::string> groups;
|
||||
|
||||
oper = line.operand;
|
||||
|
||||
if ((line.opcode.length() == 0) || (line.operand.length() == 0))
|
||||
{
|
||||
return (syn_implied);
|
||||
}
|
||||
|
||||
idx = 0;
|
||||
while (mode == syn_none)
|
||||
{
|
||||
s = addrRegEx[idx].regEx;
|
||||
if (s == "")
|
||||
{
|
||||
mode = syn_err;
|
||||
}
|
||||
else
|
||||
{
|
||||
RegularExpression regex(s, 0, true);
|
||||
groups.clear();
|
||||
x = 0;
|
||||
try
|
||||
{
|
||||
x = regex.split(oper, 0, groups, 0);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
x = 0;
|
||||
}
|
||||
if (x > 0)
|
||||
{
|
||||
mode = addrRegEx[idx].addrMode;
|
||||
line.addrtext = addrRegEx[idx].text;
|
||||
//cout << "mode: " << line.addrtext << endl;
|
||||
for (uint32_t i = 0; i < groups.size(); i++)
|
||||
{
|
||||
s = groups[i];
|
||||
if ((s != "^") && (s != "<") && (s != ">") && (s != "|"))
|
||||
{
|
||||
line.operand_expr = s;
|
||||
//printf("line expression=|%s|\n", s.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// SGQ need to set a flag for a shift and process it after eval
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (mode == syn_none)
|
||||
{
|
||||
mode = syn_err;
|
||||
}
|
||||
res = mode;
|
||||
//printf("syn_mode=%d\n", mode);
|
||||
return (res);
|
||||
}
|
||||
|
||||
int CLASS::parseOperand(MerlinLine &line)
|
||||
{
|
||||
|
||||
int res = -1;
|
||||
|
||||
line.operand_expr = "";
|
||||
int m = getAddrMode(line);
|
||||
if (m >= 0)
|
||||
{
|
||||
res = m;
|
||||
}
|
||||
else
|
||||
{
|
||||
//errorOut(errBadAddressMode);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
void CLASS::process(void)
|
||||
{
|
||||
uint32_t l;
|
||||
int x;
|
||||
char c;
|
||||
std::string op, operand;
|
||||
//uint32_t operand_eval;
|
||||
//uint16_t addrmode;
|
||||
|
||||
MerlinLine *line;
|
||||
pass = 0;
|
||||
while (pass < 2)
|
||||
{
|
||||
initpass();
|
||||
|
||||
l = lines.size();
|
||||
while ((lineno < l) && (!passcomplete))
|
||||
{
|
||||
line = &lines[lineno];
|
||||
|
||||
//printf("lineno: %d %d |%s|\n",lineno,l,line->operand.c_str());
|
||||
|
||||
op = Poco::toLower(line->opcode);
|
||||
operand = Poco::toLower(line->operand);
|
||||
line->startpc = currentpc;
|
||||
line->bytect = 0;
|
||||
|
||||
if ((line->lable != "") && (pass == 0))
|
||||
{
|
||||
c = line->lable[0];
|
||||
switch (c)
|
||||
{
|
||||
case ']':
|
||||
break;
|
||||
case ':':
|
||||
break;
|
||||
default:
|
||||
addSymbol(line->lable, currentpc, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
x = parseOperand(*line);
|
||||
if (x >= 0)
|
||||
{
|
||||
line->addressmode = x;
|
||||
}
|
||||
int64_t value = -1;
|
||||
x=-1;
|
||||
x = evaluate(line->operand_expr, value);
|
||||
if (x == 0)
|
||||
{
|
||||
value &= 0xFFFFFFFF;
|
||||
//printf("OPERAND VALUE=%08X\n",value);
|
||||
line->expr_value = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
line->expr_value = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
x = 0;
|
||||
if (op.length() > 0)
|
||||
{
|
||||
x = callOpCode(op, *line);
|
||||
}
|
||||
if (x > 0)
|
||||
{
|
||||
line->bytect = x;
|
||||
currentpc += x;
|
||||
totalbytes += x;
|
||||
}
|
||||
if (pass == 0)
|
||||
{
|
||||
line->pass0bytect = line->bytect;
|
||||
}
|
||||
|
||||
|
||||
if (pass == 1)
|
||||
{
|
||||
if ((line->pass0bytect != line->bytect) && (line->errorcode == 0))
|
||||
{
|
||||
line->setError(errBadByteCount);
|
||||
}
|
||||
|
||||
bool skip = false;
|
||||
if (op == "lst")
|
||||
{
|
||||
if ((operand == "") || (operand == "on"))
|
||||
{
|
||||
listing = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
skip = true;
|
||||
listing = false;
|
||||
}
|
||||
}
|
||||
if ((!skip) && (listing) && (pass == 1))
|
||||
{
|
||||
line->print(lineno);
|
||||
}
|
||||
}
|
||||
lineno++;
|
||||
}
|
||||
pass++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int CLASS::doline(int lineno, std::string line)
|
||||
{
|
||||
int res = 0;
|
||||
std::string op;
|
||||
|
||||
MerlinLine l(line);
|
||||
|
||||
op = Poco::toLower(l.opcode);
|
||||
if (op == "merlin")
|
||||
{
|
||||
syntax = SYNTAX_MERLIN;
|
||||
}
|
||||
else if (op == "orca")
|
||||
{
|
||||
syntax = SYNTAX_ORCA;
|
||||
}
|
||||
l.syntax = syntax;
|
||||
lines.push_back(l);
|
||||
|
||||
if ((op == "use") || (op == "put"))
|
||||
{
|
||||
//printf("processing % s\n",l.operand.c_str());
|
||||
processfile(l.operand);
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
#undef CLASS
|
||||
|
||||
#define CLASS T65816Link
|
||||
|
||||
CLASS::CLASS()
|
||||
{
|
||||
}
|
||||
|
||||
CLASS::~CLASS()
|
||||
{
|
||||
}
|
||||
|
||||
void CLASS::init(void)
|
||||
{
|
||||
TFileProcessor::init();
|
||||
}
|
||||
|
||||
void CLASS::process(void)
|
||||
{
|
||||
|
||||
}
|
||||
void CLASS::complete(void)
|
||||
{
|
||||
}
|
||||
|
||||
int CLASS::doline(int lineno, std::string line)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
#undef CLASS
|
|
@ -0,0 +1,229 @@
|
|||
#pragma once
|
||||
#include "app.h"
|
||||
|
||||
#define OPHANDLER(ACB) std::bind(ACB, this, std::placeholders::_1, std::placeholders::_2)
|
||||
|
||||
#define MODE_6502 0
|
||||
#define MODE_65C02 1
|
||||
#define MODE_65816 2
|
||||
|
||||
#define SYNTAX_MERLIN 0
|
||||
#define SYNTAX_APW 1
|
||||
#define SYNTAX_ORCA 2
|
||||
|
||||
#define OP_6502 0x01
|
||||
#define OP_65C02 0x02
|
||||
#define OP_65816 0x04
|
||||
#define OP_PSUEDO 0x08
|
||||
#define OP_ONEBYTE 0x10
|
||||
#define OP_SPECIAL 0x20
|
||||
#define OP_CLASS0 0x0000
|
||||
#define OP_CLASS1 0x0100
|
||||
#define OP_CLASS2 0x0200
|
||||
#define OP_CLASS3 0x0300
|
||||
#define OP_CLASS4 0x0400
|
||||
#define OP_STD (0x1000 | OP_CLASS1 | OP_6502)
|
||||
#define OP_ASL (0x2000 | OP_CLASS2 | OP_6502)
|
||||
#define OP_STX (0x3000 | OP_CLASS2 | OP_6502)
|
||||
#define OP_C0 (0x4000 | OP_CLASS0 | OP_6502)
|
||||
|
||||
enum asmErrors
|
||||
{
|
||||
errNone,
|
||||
errWarn,
|
||||
errIncomplete,
|
||||
errFatal,
|
||||
errBadAddressMode,
|
||||
errBadOpcode,
|
||||
errIncompatibleOpcode,
|
||||
errBadByteCount,
|
||||
errMAX
|
||||
};
|
||||
|
||||
#ifdef ADD_ERROR_STRINGS
|
||||
std::string errStrings[errMAX] = {
|
||||
"No Error",
|
||||
"Warning",
|
||||
"Unfinished Opcode",
|
||||
"Fatal",
|
||||
"Unsupported Addressing Mode",
|
||||
"Unknown Opcode",
|
||||
"Opcode not available under CPU selecton",
|
||||
"Byte output differs between passes",
|
||||
};
|
||||
#else
|
||||
extern std::string errStrings[errMAX];
|
||||
extern uint8_t opCodeCompatibility[256];
|
||||
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
syn_err = -1, // error - not recognized
|
||||
syn_none = 0, // should never be returned 0
|
||||
syn_implied, // no operand 1
|
||||
syn_s, // expr,s 2
|
||||
syn_sy, // (expr,s),y 3
|
||||
syn_imm, // #expr 4
|
||||
syn_diix, // (expr,x) 5
|
||||
syn_diiy, // (expr),y 6
|
||||
syn_di, // (expr) 7
|
||||
syn_iyl, // [expr],y 8
|
||||
syn_dil, // [expr] 9
|
||||
syn_absx, // expr,x 10
|
||||
syn_absy, // expr,y 11
|
||||
syn_bm, // block move 12
|
||||
syn_abs, // expr 13
|
||||
|
||||
syn_MAX
|
||||
};
|
||||
|
||||
#define FLAG_LONGADDR 0x01
|
||||
|
||||
class MerlinLine
|
||||
{
|
||||
public:
|
||||
|
||||
uint8_t syntax;
|
||||
std::string lable;
|
||||
std::string opcode;
|
||||
std::string opcodelower;
|
||||
std::string operand;
|
||||
std::string operand_expr;
|
||||
std::string comment;
|
||||
std::string addrtext;
|
||||
uint32_t flags;
|
||||
uint16_t opflags;
|
||||
uint32_t startpc;
|
||||
uint32_t addressmode;
|
||||
uint32_t expr_value;
|
||||
uint32_t errorcode;
|
||||
uint8_t inbytect;
|
||||
uint8_t inbytes[256];
|
||||
|
||||
uint16_t pass0bytect;
|
||||
uint16_t bytect;
|
||||
uint16_t outbytect;
|
||||
std::vector<uint8_t> outbytes;
|
||||
|
||||
public:
|
||||
MerlinLine();
|
||||
MerlinLine(std::string line);
|
||||
void clear();
|
||||
void set(std::string line);
|
||||
void print(uint32_t lineno);
|
||||
void setError(uint32_t ecode);
|
||||
};
|
||||
|
||||
class TFileProcessor
|
||||
{
|
||||
protected:
|
||||
uint8_t syntax;
|
||||
public:
|
||||
|
||||
TFileProcessor();
|
||||
virtual ~TFileProcessor();
|
||||
virtual int processfile(std::string &p);
|
||||
virtual void init(void);
|
||||
virtual int doline(int lineno, std::string line);
|
||||
virtual void process(void);
|
||||
virtual void complete(void);
|
||||
virtual void errorOut(uint16_t code);
|
||||
};
|
||||
|
||||
class TSymbol;
|
||||
typedef int (*TOpCB)(MerlinLine &line, TSymbol &sym);
|
||||
typedef std::function<int (MerlinLine &line, TSymbol &sym)> TOpCallback;
|
||||
|
||||
class TSymbol
|
||||
{
|
||||
public:
|
||||
std::string namelc;
|
||||
std::string name;
|
||||
uint32_t value;
|
||||
uint16_t stype;
|
||||
uint8_t opcode;
|
||||
TOpCallback cb;
|
||||
Poco::HashMap<std::string, TSymbol>locals;
|
||||
|
||||
TSymbol()
|
||||
{
|
||||
locals.clear();
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
class T65816Asm : public TFileProcessor
|
||||
{
|
||||
protected:
|
||||
bool passcomplete;
|
||||
bool casesen;
|
||||
bool relocatable;
|
||||
bool listing;
|
||||
uint32_t totalbytes;
|
||||
uint32_t lineno;
|
||||
uint32_t origin;
|
||||
uint8_t mx;
|
||||
uint8_t cpumode; // 0=6502, 1=65C02, 2=65816
|
||||
TSymbol *currentsym;
|
||||
std::vector<MerlinLine> lines;
|
||||
Poco::HashMap<std::string, TSymbol>opcodes;
|
||||
Poco::HashMap<std::string, TSymbol> macros;
|
||||
Poco::HashMap<std::string, TSymbol> symbols;
|
||||
public:
|
||||
uint16_t pass;
|
||||
uint32_t currentpc;
|
||||
|
||||
T65816Asm();
|
||||
virtual ~T65816Asm();
|
||||
|
||||
virtual void init(void);
|
||||
virtual int doline(int lineno, std::string line);
|
||||
virtual void process(void);
|
||||
virtual void complete(void);
|
||||
|
||||
void insertOpcodes(void);
|
||||
void pushopcode(std::string op, uint8_t opcode, uint16_t flags, TOpCallback cb);
|
||||
|
||||
int callOpCode(std::string op, MerlinLine &line);
|
||||
TSymbol *findSymbol(std::string sym);
|
||||
TSymbol *addSymbol(std::string sym, uint32_t val, bool replace);
|
||||
|
||||
void initpass(void);
|
||||
void showSymbolTable(void);
|
||||
|
||||
int evaluate(std::string expr, int64_t &value);
|
||||
|
||||
int parseOperand(MerlinLine &line);
|
||||
int getAddrMode(MerlinLine &line);
|
||||
void setOpcode(MerlinLine &line, uint8_t op);
|
||||
|
||||
|
||||
int doPSEUDO(MerlinLine &line, TSymbol &sym);
|
||||
int doEND(MerlinLine &line, TSymbol &sym);
|
||||
int doBase6502(MerlinLine &line, TSymbol &sym);
|
||||
int doBRANCH(MerlinLine &line, TSymbol &sym);
|
||||
int doJMP(MerlinLine &line, TSymbol &sym);
|
||||
int doAddress(MerlinLine &line, TSymbol &sym);
|
||||
int doNoPattern(MerlinLine &line, TSymbol &sym);
|
||||
|
||||
int doEQU(MerlinLine &line, TSymbol &sym);
|
||||
int doXC(MerlinLine &line, TSymbol &sym);
|
||||
int doMX(MerlinLine &line, TSymbol &sym);
|
||||
|
||||
int doBYTE(MerlinLine &line, TSymbol &sym);
|
||||
int doUNK(MerlinLine &line, TSymbol &sym);
|
||||
|
||||
};
|
||||
|
||||
class T65816Link : public TFileProcessor
|
||||
{
|
||||
public:
|
||||
T65816Link();
|
||||
virtual ~T65816Link();
|
||||
virtual void init(void);
|
||||
virtual int doline(int lineno, std::string line);
|
||||
virtual void process(void);
|
||||
|
||||
virtual void complete(void);
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
// define application options here
|
||||
#define PAL_APPCLASS TMyCustomApp
|
||||
|
||||
//#define SERVERAPP
|
||||
#define ENABLE_SSL
|
||||
#define USE_LOGGER
|
||||
|
||||
// help text
|
||||
#define HELP_USAGE "<options> filename"
|
||||
#define HELP_PURPOSE "a program that does something"
|
||||
|
||||
|
|
@ -0,0 +1,609 @@
|
|||
#include "asm.h"
|
||||
#include "eval.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define CLASS TEvaluator
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Token& token)
|
||||
{
|
||||
os << token.str;
|
||||
return os;
|
||||
}
|
||||
|
||||
CLASS::CLASS(T65816Asm &_asm) : assembler(_asm)
|
||||
{
|
||||
}
|
||||
|
||||
CLASS::~CLASS()
|
||||
{
|
||||
}
|
||||
|
||||
std::deque<Token> CLASS::exprToTokens(const std::string& expr)
|
||||
{
|
||||
std::deque<Token> tokens;
|
||||
int state = 0;
|
||||
char c;
|
||||
char delim;
|
||||
std::string ident, asc;
|
||||
|
||||
std::string ops = "+-*//^!.&()";
|
||||
std::string c1;
|
||||
char *tokptr;
|
||||
char *tptr;
|
||||
bool numexpect;
|
||||
Token::Type t;
|
||||
|
||||
numexpect = true;
|
||||
for (const auto* p = expr.c_str(); *p; ++p)
|
||||
{
|
||||
c = *p;
|
||||
c1 = c;
|
||||
tptr = (char *)c1.c_str();
|
||||
tokptr = strpbrk(tptr, (const char *)ops.c_str());
|
||||
// printf("state=%d %c %p\n", state, c,tokptr);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
default:
|
||||
printf("bad token state\n");
|
||||
state = 0;
|
||||
break;
|
||||
case 11:
|
||||
if ((c < ' ') || (c == delim))
|
||||
{
|
||||
// SGQ - convert ascii to a number here
|
||||
asc = "0";
|
||||
//printf("ident=|%s|\n",ident.c_str());
|
||||
if (ident.length() > 0)
|
||||
{
|
||||
// SGQ - convert ascii to a number here
|
||||
}
|
||||
t = Token::Type::Number;
|
||||
int pr = 1; // precedence
|
||||
bool ra = false; // rightAssociative
|
||||
tokens.push_back(Token
|
||||
{
|
||||
t, asc, pr, ra
|
||||
});
|
||||
ident = "";
|
||||
state = 0;
|
||||
if (c != delim)
|
||||
{
|
||||
p--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ident += c;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
case 20:
|
||||
if ((c <= ' ') || (tokptr != NULL))
|
||||
{
|
||||
if (ident.length() > 0)
|
||||
{
|
||||
if (state == 20)
|
||||
{
|
||||
t = Token::Type::Symbol;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = Token::Type::Number;
|
||||
}
|
||||
int pr = 1; // precedence
|
||||
bool ra = false; // rightAssociative
|
||||
tokens.push_back(Token
|
||||
{
|
||||
t, ident, pr, ra
|
||||
});
|
||||
ident = "";
|
||||
}
|
||||
state = 0;
|
||||
p--;
|
||||
}
|
||||
else
|
||||
{
|
||||
ident += c;
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
if ((c == '$') && (numexpect))
|
||||
{
|
||||
state = 10;
|
||||
ident += c;
|
||||
numexpect = false;
|
||||
|
||||
}
|
||||
else if ((c == '*') && (numexpect))
|
||||
{
|
||||
numexpect = false;
|
||||
state = 20;
|
||||
ident += c;
|
||||
}
|
||||
else if ((c == '%') && (numexpect))
|
||||
{
|
||||
state = 10;
|
||||
ident += c;
|
||||
numexpect = false;
|
||||
|
||||
}
|
||||
else if ((c == '\'') && (numexpect))
|
||||
{
|
||||
delim = c;
|
||||
state = 11;
|
||||
numexpect = false;
|
||||
}
|
||||
else if ((c == '"') && (numexpect))
|
||||
{
|
||||
delim = c;
|
||||
state = 11;
|
||||
numexpect = false;
|
||||
}
|
||||
else if (((c == '-') || (c == '+')) && (numexpect))
|
||||
{
|
||||
state = 10;
|
||||
ident += c;
|
||||
}
|
||||
else if (isdigit(c))
|
||||
{
|
||||
state = 10;
|
||||
ident += c;
|
||||
numexpect = false;
|
||||
|
||||
}
|
||||
else if ((c >= 'a') && (c <= 'z'))
|
||||
{
|
||||
state = 20;
|
||||
ident += c;
|
||||
numexpect = false;
|
||||
|
||||
}
|
||||
else if ((c >= 'A') && (c <= 'A'))
|
||||
{
|
||||
state = 20;
|
||||
ident += c;
|
||||
numexpect = false;
|
||||
}
|
||||
else if ((tokptr != NULL) && (!numexpect))
|
||||
{
|
||||
t = Token::Type::Unknown;
|
||||
int pr = -1; // precedence
|
||||
bool ra = false; // rightAssociative
|
||||
switch (c)
|
||||
{
|
||||
default: break;
|
||||
case '(': t = Token::Type::LeftParen; break;
|
||||
case ')': t = Token::Type::RightParen; break;
|
||||
case '!': t = Token::Type::Operator; pr = 5; break;
|
||||
case '.': t = Token::Type::Operator; pr = 5; break;
|
||||
case '&': t = Token::Type::Operator; pr = 5; break;
|
||||
case '^': t = Token::Type::Operator; pr = 4; ra = true; break;
|
||||
case '*': t = Token::Type::Operator; pr = 3; break;
|
||||
case '/': t = Token::Type::Operator; pr = 3; break;
|
||||
case '+': t = Token::Type::Operator; pr = 2; break;
|
||||
case '-': t = Token::Type::Operator; pr = 2; break;
|
||||
|
||||
}
|
||||
tokens.push_back(Token
|
||||
{
|
||||
t, std::string(1, c), pr, ra
|
||||
});
|
||||
numexpect = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
|
||||
std::deque<Token> CLASS::shuntingYard(const std::deque<Token>& tokens)
|
||||
{
|
||||
std::deque<Token> queue;
|
||||
std::vector<Token> stack;
|
||||
TSymbol *sym;
|
||||
char buff[128];
|
||||
|
||||
// While there are tokens to be read:
|
||||
for (auto token : tokens)
|
||||
{
|
||||
// Read a token
|
||||
switch (token.type)
|
||||
{
|
||||
case Token::Type::Symbol:
|
||||
token.type = Token::Type::Number;
|
||||
|
||||
if (token.str == "*")
|
||||
{
|
||||
sprintf(buff, "%u", assembler.currentpc);
|
||||
token.str = buff;
|
||||
}
|
||||
else
|
||||
{
|
||||
sym = assembler.findSymbol(token.str);
|
||||
if (sym != NULL)
|
||||
{
|
||||
sprintf(buff, "%u", sym->value);
|
||||
token.str = buff;
|
||||
}
|
||||
else
|
||||
{
|
||||
token.str = "-1";
|
||||
}
|
||||
}
|
||||
queue.push_back(token);
|
||||
break;
|
||||
case Token::Type::Number:
|
||||
// If the token is a number, then add it to the output queue
|
||||
queue.push_back(token);
|
||||
break;
|
||||
|
||||
case Token::Type::Operator:
|
||||
{
|
||||
// If the token is operator, o1, then:
|
||||
const auto o1 = token;
|
||||
|
||||
// while there is an operator token,
|
||||
while (!stack.empty())
|
||||
{
|
||||
// o2, at the top of stack, and
|
||||
const auto o2 = stack.back();
|
||||
|
||||
// either o1 is left-associative and its precedence is
|
||||
// *less than or equal* to that of o2,
|
||||
// or o1 if right associative, and has precedence
|
||||
// *less than* that of o2,
|
||||
if (
|
||||
(! o1.rightAssociative && o1.precedence <= o2.precedence)
|
||||
|| ( o1.rightAssociative && o1.precedence < o2.precedence)
|
||||
)
|
||||
{
|
||||
// then pop o2 off the stack,
|
||||
stack.pop_back();
|
||||
// onto the output queue;
|
||||
queue.push_back(o2);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// @@ otherwise, exit.
|
||||
break;
|
||||
}
|
||||
|
||||
// push o1 onto the stack.
|
||||
stack.push_back(o1);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token::Type::LeftParen:
|
||||
// If token is left parenthesis, then push it onto the stack
|
||||
stack.push_back(token);
|
||||
break;
|
||||
|
||||