diff --git a/asm.cpp b/asm.cpp index 2930ba8..9a010b5 100644 --- a/asm.cpp +++ b/asm.cpp @@ -2,6 +2,9 @@ #include "asm.h" #include "eval.h" #include "psuedo.h" +#include +#include + #define CLASS MerlinLine @@ -99,7 +102,7 @@ void CLASS::print(uint32_t lineno) } } bool empty = false; - if ((printlable == "") && (opcode == "") && (operand == "")) + if ((printlable == "") && (opcode == "") && (printoperand == "")) { empty = true; } @@ -174,7 +177,7 @@ void CLASS::print(uint32_t lineno) { pcol += printf("%c", comment[cc]); comct++; - if ((comment[cc] <= ' ') && (pcol >= (commentcol + savpcol + 10))) + if ((comment[cc] <= ' ') && (pcol >= (commentcol + savpcol + 20))) { printf("\n"); pcol = 0; @@ -202,7 +205,14 @@ void CLASS::print(uint32_t lineno) { pcol += printf(" "); } - pcol += printf("%s ", operand.c_str()); + if (isDebug() > 2) + { + pcol += printf("%s ", operand.c_str()); + } + else + { + pcol += printf("%s ", printoperand.c_str()); + } //pcol += printf("%-12s %-8s %-10s ", printlable.c_str(), opcode.c_str(), operand.c_str()); } if ((errorcode > 0) && (!merlinerrors)) @@ -287,6 +297,7 @@ void CLASS::clear() opcode = ""; opcodelower = ""; operand = ""; + printoperand = ""; comment = ""; operand_expr = ""; operand_expr2 = ""; @@ -416,6 +427,11 @@ void CLASS::set(std::string line) restofline = Poco::trim(tline.substr(i, tline.length())) + " "; //printf("ROL: |%s|\n",restofline.c_str()); + if (restofline == "") + { + i = l; + break; + } strs.clear(); x = 0; try @@ -478,9 +494,7 @@ void CLASS::set(std::string line) i = l; if (!match) { - opcode = ":::"; // let assembler figure out this is a bad opcode - // SGQ maybe error here - //printf("---No Match %s\n", restofline.c_str()); + // if you are here, there probably isn't an operand and/or comment after opcode } } break; @@ -490,15 +504,16 @@ void CLASS::set(std::string line) x = lable.length(); if (x > 1) { - // SGQ M32 syntax -#if 0 - while ((x > 1) && (lable[x - 1] == ':')) + // M32 syntax allows a colon after lable, and it is not part of the lable + if ((syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) { - lable = lable.substr(0, x - 1); - x--; + while ((x > 1) && (lable[x - 1] == ':')) + { + lable = lable.substr(0, x - 1); + x--; + } + //printf("linelable: |%s|\n", lable.c_str()); } - //printf("linelable: |%s|\n", lable.c_str()); -#endif } opcodelower = Poco::toLower(opcode); @@ -509,7 +524,20 @@ void CLASS::set(std::string line) CLASS::CLASS() { + int x; errorct = 0; + + win_columns = -1; + win_rows = -1; + struct winsize w; + x = ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + if (x == 0) + { + win_columns = w.ws_col; + win_rows = w.ws_row; + } + //printf("cols=%d rows=%d\n",win_columns,win_rows); + } CLASS::~CLASS() @@ -529,9 +557,24 @@ void CLASS::init(void) filenames.clear(); starttime = GetTickCount(); initialdir = Poco::Path::current(); - syntax = 0; + syntax = SYNTAX_MERLIN; filecount = 0; + s = getConfig("option.syntax", "merlin16"); + s = Poco::toUpper(Poco::trim(s)); + if ((s == "MERLIN") || (s == "MERLIN16")) + { + syntax = SYNTAX_MERLIN; + } + else if (s == "MERLIN32") + { + syntax = SYNTAX_MERLIN32; + } + else if (s == "QASM") + { + syntax = SYNTAX_QASM; + } + std::string tabstr = getConfig("reformat.tabs", "8,16,32"); tabstr = Poco::trim(tabstr); @@ -1139,7 +1182,7 @@ TSymbol * CLASS::addVariable(std::string symname, std::string val, bool replace) if (fnd != NULL) { //printf("replacing symbol: %s %08X\n",sym.c_str(),val); - fnd->text = val; + fnd->var_text = val; return (fnd); } @@ -1149,7 +1192,7 @@ TSymbol * CLASS::addVariable(std::string symname, std::string val, bool replace) s.namelc = Poco::toLower(sym); s.stype = 0; s.value = 0; - s.text = val; + s.var_text = val; s.used = false; s.cb = NULL; @@ -1166,7 +1209,7 @@ TSymbol * CLASS::findVariable(std::string symname) TSymbol *res = NULL; //printf("finding: %s\n",symname.c_str()); - auto itr = variables.find(Poco::toUpper(symname)); + auto itr = variables.find(symname); if (itr != variables.end()) { //printf("Found: %s 0x%08X\n",itr->second.name.c_str(),itr->second.value); @@ -1185,7 +1228,7 @@ void CLASS::showVariables(void) for (auto itr = variables.begin(); itr != variables.end(); ++itr) { - printf("%-16s %s\n", itr->first.c_str(), itr->second.text.c_str()); + printf("%-16s %s\n", itr->first.c_str(), itr->second.var_text.c_str()); } printf("\n"); } @@ -1291,12 +1334,23 @@ int CLASS::callOpCode(std::string op, MerlinLine &line) case '>': line.expr_value >>= 8; line.expr_value &= 0xFFFF; + if ((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) + { + line.flags |= FLAG_FORCEABS; + } break; case '^': line.expr_value = (line.expr_value >> 16) & 0xFFFF; + if ((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) + { + line.flags |= FLAG_FORCEABS; + } break; case '|': - line.flags |= FLAG_FORCELONG; + if ((line.syntax & SYNTAX_MERLIN32) != SYNTAX_MERLIN32) + { + line.flags |= FLAG_FORCELONG; + } break; } if (line.expr_value >= 0x100) @@ -1419,7 +1473,22 @@ void CLASS::initpass(void) merlinerrors = getBool("asm.merlinerrors", true); trackrep = getBool("asm.trackrep", false); - merlincompat = getBool("asm.merlincompatible", true); + if (syntax == SYNTAX_MERLIN32) + { + trackrep = true; // can't turn this off in M32 + } + else if (syntax == SYNTAX_MERLIN) + { + trackrep = false; // can't turn this ON in M16 + } + else if (syntax == SYNTAX_QASM) + { + // we will allow this to be settable default off + trackrep = false; + trackrep = getBool("asm.trackrep", trackrep); + + } + //merlincompat = getBool("asm.merlincompatible", true); allowdup = getBool("asm.allowduplicate", true); skiplist = false; @@ -1461,7 +1530,12 @@ void CLASS::initpass(void) lastcarry = false; relocatable = false; - currentsym = &topSymbol; // this is the default symbol for :locals without a global above; + currentsym = NULL; + if ((syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) + { + // M32 allows locals that don't have a global above. this is the catchall for that + currentsym = &topSymbol; // this is the default symbol for :locals without a global above; + } currentsymstr = ""; lineno = 0; errorct = 0; @@ -1665,18 +1739,17 @@ int CLASS::getAddrMode(MerlinLine & line) // symbol is defined later, we will generate different // bytes on the next pass - if (Poco::toUpper(oper) == "A") // check the whole operand, not just the expression + if ((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) { - // SGQ - // Merlin32 supports the 'A" operand for immediate - // mode for opcodes like "ROR A". Problem is, Merlin16 - // does not, and 'A' could be a lable. - TSymbol *sym = findSymbol("A"); - if (sym == NULL) + if (Poco::toUpper(oper) == "A") // check the whole operand, not just the expression { - line.flags |= FLAG_FORCEIMPLIED; - mode = syn_implied; // if the label hasn't been defined yet, assume Immediate addressing - goto out; + TSymbol *sym = findSymbol("A"); + if (sym == NULL) + { + line.flags |= FLAG_FORCEIMPLIED; + mode = syn_implied; // if the label hasn't been defined yet, assume Immediate addressing + goto out; + } } } } @@ -1742,63 +1815,93 @@ int CLASS::parseOperand(MerlinLine & line) return (res); } -int CLASS::substituteVariables(MerlinLine & line) +int CLASS::substituteVariables(MerlinLine & line, std::string &outop) { - int res = -1; + int res = 0; int x; std::string::size_type offset, slen; std::string oper = line.operand; std::string s; + std::string operin; TSymbol *sym; uint32_t len, off, ct; - slen = oper.length(); - if (slen > 0) + bool done = false; + operin = oper; + ct = 0; +restart: + while (!done) { - std::vector groups; - offset = 0; - RegularExpression varEx(varExpression, Poco::RegularExpression::RE_EXTRA, true); - Poco::RegularExpression::MatchVec mVec; - - //printf("|%s|%s|\n", varExpression.c_str(), oper.c_str()); - groups.clear(); - ct = 0; - while (offset < slen) + slen = oper.length(); + if (slen > 0) { - try - { - varEx.match(oper, offset, mVec, 0); - } - catch (...) - { - offset = slen; - } + std::vector groups; - x = mVec.size(); - if (x > 0) + offset = 0; + RegularExpression varEx(varExpression, 0, true); + Poco::RegularExpression::MatchVec mVec; + + //printf("|%s|%s|\n", varExpression.c_str(), oper.c_str()); + groups.clear(); + while (offset < slen) { - res = 0; - off = mVec[0].offset; - len = mVec[0].length; - s = oper.substr(off, len); - sym = findVariable(s); - if (sym != NULL) + try { - ct++; - if (pass > 0) - { - //printf("%d |%s|\n", ct, s.c_str()); - } + varEx.match(oper, offset, mVec, 0); + } + catch (...) + { + offset = slen; } - offset += len; - } - else - { - offset = slen; - } - } + x = mVec.size(); + if (x > 0) + { + res = 0; + off = mVec[0].offset; + len = mVec[0].length; + s = oper.substr(off, len); + sym = findVariable(s); + if (sym != NULL) + { + //printf("match |%s|\n",sym->var_text.c_str()); + + if (sym->var_text != "") + { + oper = oper.replace(off, len, sym->var_text); + ct++; + if (pass > 0) + { + //printf("%d |%s|\n", ct, s.c_str()); + } + goto restart; + } + } + else + { + done = true; + } + offset += len; + } + else + { + offset = slen; + done = true; + } + } + + } + else + { + done = true; + } + } + //printf("inoper=|%s| outoper=|%s|\n",operin.c_str(),oper.c_str()); + if (ct > 0) + { + outop = oper; + res = ct; } return (res); } @@ -1858,6 +1961,7 @@ void CLASS::process(void) line.linemx = mx; line.bytect = 0; line.showmx = showmx; + line.syntax = syntax; line.merlinerrors = merlinerrors; if ((line.lable != "")) @@ -1872,7 +1976,7 @@ void CLASS::process(void) sprintf(buff, "$%X", PC.currentpc); ls = buff; sym = addVariable(line.lable, ls, true); - if (sym == NULL) { dupsym = true; } + //if (sym == NULL) { dupsym = true; } break; case ':': @@ -1898,7 +2002,16 @@ void CLASS::process(void) line.setError(errDupSymbol); } } - x = substituteVariables(line); + std::string outop; + if (pass == 0) + { + line.printoperand = line.operand; + } + x = substituteVariables(line, outop); + if (x > 0) + { + line.operand = outop; + } x = parseOperand(line); if (x >= 0) { diff --git a/asm.h b/asm.h index cae8a1e..aa0e88e 100644 --- a/asm.h +++ b/asm.h @@ -8,8 +8,18 @@ #define MODE_65816 2 #define SYNTAX_MERLIN 0 -#define SYNTAX_APW 1 -#define SYNTAX_ORCA 2 +#define SYNTAX_MERLIN32 0x01 +#define SYNTAX_APW 0x02 +#define SYNTAX_ORCA 0x04 +#define SYNTAX_QASM (0x08 | SYNTAX_MERLIN32) +#define OPTION_ALLOW_A_OPERAND 0x0100 +#define OPTION_ALLOW_LOCAL 0x0200 +#define OPTION_ALLOW_COLON 0x0400 +#define OPTION_FORCE_REPSEP 0x0800 +#define OPTION_NO_REPSEP 0x1000 +#define OPTION_CFG_REPSEP 0x2000 +#define OPTION_M32_VARS 0x4000 + #define FLAG_FORCELONG 0x01 #define FLAG_FORCEABS 0x02 @@ -68,6 +78,7 @@ enum asmErrors errBadLUPOperand, errBadLabel, errBadOperand, + errErrOpcode, errMAX }; @@ -102,6 +113,7 @@ const std::string errStrings[errMAX + 1] = "LUP value must be 0 < VAL <= $8000", "Unknown label", "Bad operand", + "Break", "" }; @@ -177,9 +189,10 @@ class MerlinLine { public: - uint8_t syntax; + uint32_t syntax; std::string lable; std::string printlable; + std::string printoperand; std::string opcode; std::string opcodelower; std::string operand; @@ -222,9 +235,11 @@ public: class TFileProcessor { protected: + int win_columns; + int win_rows; std::string initialdir; std::vector filenames; - uint8_t syntax; + uint32_t syntax; uint64_t starttime; uint8_t tabs[16]; @@ -301,7 +316,8 @@ class TSymbol public: std::string namelc; std::string name; - std::string text; + //std::string text; + std::string var_text; uint32_t value; uint16_t stype; uint8_t opcode; @@ -317,7 +333,8 @@ public: { value = 0; used = false; - text = ""; + //text = ""; + var_text=""; name = ""; namelc = ""; stype = 0; @@ -335,7 +352,6 @@ public: bool casesen; bool showmx; bool trackrep; - bool merlincompat; bool merlinerrors; bool allowdup; uint8_t mx; @@ -398,7 +414,8 @@ public: void showVariables(void); int evaluate(MerlinLine &line, std::string expr, int64_t &value); - int substituteVariables(MerlinLine & line); + int substituteVariables(MerlinLine & line, std::string &outop); + bool codeSkipped(void); int parseOperand(MerlinLine &line); diff --git a/opcodes.cpp b/opcodes.cpp index 58afdbd..d603a99 100644 --- a/opcodes.cpp +++ b/opcodes.cpp @@ -94,7 +94,18 @@ int CLASS::doEQU(MerlinLine &line, TSymbol &sym) else if (isvar) { res = -1; - s = addVariable(line.lable, line.operand, true); + + if (syntax==SYNTAX_MERLIN) + { + char buff[32]; + sprintf(buff,"$%08X",line.expr_value); + std::string s1=buff; + s = addVariable(line.lable, s1, true); + } + else + { + s = addVariable(line.lable, line.operand, true); + } if (s != NULL) { res = 0; @@ -849,7 +860,7 @@ void CLASS::insertOpcodes(void) pushopcode("IF", P_DO, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("FIN", P_DO, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("CHK", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); - pushopcode("ERR", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); + pushopcode("ERR", P_ERR, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("KBD", 0x00, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("LUP", P_LUP, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); pushopcode("--^", P_LUP, OP_PSUEDO, OPHANDLER(&CLASS::doPSEUDO)); diff --git a/psuedo.cpp b/psuedo.cpp index fdfa6a8..d42e7a8 100644 --- a/psuedo.cpp +++ b/psuedo.cpp @@ -844,6 +844,17 @@ int CLASS::ProcessOpcode(T65816Asm &a, MerlinLine &line, TSymbol &opinfo) case P_SAV: a.savepath = a.processFilename(line.operand, Poco::Path::current(), 0); break; + case P_ERR: + if (a.pass>0) + { + if ((line.expr_value!=0) || (line.eval_result<0)) + { + line.setError(errErrOpcode); + //a.passcomplete=true; // terminate assembly + } + } + res=0; + break; case P_LST: res = doLST(a, line, opinfo); break; diff --git a/psuedo.h b/psuedo.h index 1270e00..5d86908 100644 --- a/psuedo.h +++ b/psuedo.h @@ -19,6 +19,7 @@ enum P_DO, P_TR, P_ASC, + P_ERR, P_MAX }; diff --git a/qasm.cpp b/qasm.cpp index 8c06b3f..c065ecd 100644 --- a/qasm.cpp +++ b/qasm.cpp @@ -18,9 +18,11 @@ programOption PAL::appOptions[] = #ifdef DEBUG { "debug", "d", "enable debug info (repeat for more verbosity)", "", false, true}, #endif - //{ "config", "f", "load configuration data from a ", " ", false, false}, - { "exec", "x", "execute a command [asm, link, reformat] default=asm", " ", false, false}, - { "objfile", "o", "write output to file", " ", false, false}, + //{ "config", "f", "load configuration data from a ", "", false, false}, + { "exec", "x", "execute a command [asm, link, reformat] default=asm", "", false, false}, + { "objfile", "o", "write output to file", "", false, false}, + { "syntax", "s", "enforce syntax of other assembler [merlin16, merlin32]", "", false, false}, + { "", "", "", "", false, false} }; diff --git a/qasm.ini b/qasm.ini index 2aad0ca..9769696 100644 --- a/qasm.ini +++ b/qasm.ini @@ -6,6 +6,7 @@ logfile=mylog.log [option] debug=1 nocolor=false +;syntax=merlin32 ;debug must be an integer. Code can use this as a level [application] @@ -28,8 +29,7 @@ lst=true cpu=M65816 trackrep=true allowduplicate=true -merlinerrors=false -merlincompatible=true +merlinerrors=true symcolumns=3 [reformat] diff --git a/runtests.sh b/runtests.sh index 8cbb574..6e4ae83 100755 --- a/runtests.sh +++ b/runtests.sh @@ -29,7 +29,7 @@ for S in $SRC ; do BASE=${BASE/.s/} #./qasm -o 0/$OUTDIR/$S1 ./testdata/$S - ./qasm -o 0/$OUTDIR/$S1 ./testdata/$S >> $TMPFILE + ./qasm --syntax merlin32 -o 0/$OUTDIR/$S1 ./testdata/$S >> $TMPFILE R=?$ #echo $S " " $S1 diff --git a/src/main.s b/src/main.s index b64d017..b27f9ab 100644 --- a/src/main.s +++ b/src/main.s @@ -307,7 +307,7 @@ myQuit sbc ^$012345 sbc |$012345 - asll $1234 + ;asll $1234 lda <$fff0+24 ;zp lda >$fff0+24 ;ABS (lo word) @@ -411,8 +411,8 @@ L00BC bit L00BC asc 02,15,?123456? asc 02,15,>123456> asc 02,15,<123456< - asc 02,15,5,"123456" - asc 02,15,"123456 + asc 02,15,05,"123456" + asc 02,15,"123456" asc 0215"1234"1502 @@ -423,7 +423,7 @@ lup_start: --^ - lst off + ;lst off //]XCODEEND ; Keep this at the end and put your code above this ;lst off diff --git a/testdata/2019-local-variables.S b/testdata/2019-local-variables.S index 1687a46..db1922b 100644 --- a/testdata/2019-local-variables.S +++ b/testdata/2019-local-variables.S @@ -155,5 +155,5 @@ LOCAL1 lda #$2c ;EDIT: format as ASCII beq LOCAL1 LOCAL2 lda $2c ;EDIT: format as ASCII ldx $5678 ;put empty variable table here - ;beq LOCAL2 + beq LOCAL2 rts diff --git a/todo.txt b/todo.txt index 51a6fe3..7752725 100644 --- a/todo.txt +++ b/todo.txt @@ -1,13 +1,12 @@ (0) 2019-11-17 - BRK does not detect a lable that can't be evaluated (0) 2019-11-17 - ASCII parsing in both eval and for ASC type commands (0) 2019-11-17 - IF processing for character compare mode - (0) 2019-11-17 - Note (syntax) Merlin doesn't allow 'A' implied addressing (0) 2019-11-17 - Note (syntax): Merlin doesn't allow local labels without a previous global (0) 2019-11-17 - Note (syntax): Merlin doesn't allow local colons after label which is ignored (0) 2019-11-17 - Note (syntax): Merlin doesn't allow for 'rep/sep/xce' tracking (0) 2019-11-17 - Bug (evaluation routine puts ascii bytes in reverse order (#"AB") - (0) 2019-11-17 - - (0) 2019-11-17 - + (0) 2019-11-17 - want to wrap comments based on current terminal width, and don't if printing to non-terminal + (0) 2019-11-17 - syntax options - check OPTION bits, not syntax type (OPTION_ALLOW_LOCAL) (0) 2019-11-17 - (0) 2019-11-17 - (0) 2019-11-17 -