#define ADD_ERROR_STRINGS #include "asm.h" #include "eval.h" #include "psuedo.h" #include #include #include #define CLASS MerlinLine CLASS::CLASS(ConfigOptions &opt) : options(&opt) { clear(); } CLASS::CLASS(std::string line, ConfigOptions &opt) : options(&opt) { clear(); set(line); } void CLASS::setError(uint32_t ecode) { errorcode = ecode; } void CLASS::print(uint32_t lineno) { uint32_t l, i, savpcol, pcol; bool commentprinted = false; uint8_t commentcol = tabs[2]; bool force=false; uint32_t b = 4; // how many bytes show on the first line if (datafillct > 0) { l = datafillct; } else { l = outbytect; } if (l > b) { l = b; } if (errorcode > 0) { if (merlinerrors) { //printf("errorcode=%d\n",errorcode); printf("\n%s in line: %d", errStrings[errorcode].c_str(), lineno + 1); if (errorText != "") { printf(" (%s)", errorText.c_str()); } printf("\n"); } force=true; flags &= (~FLAG_NOLINEPRINT); } bool np=(flags & FLAG_NOLINEPRINT)?true:false; if (options->isQuiet()) { np=true; } if (options->isList()) { np=false; } if (force) { np=false; } if (np) { return; } if (options->useColor()) { 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 ((printlable == "") && (opcode == "") && (printoperand == "")) { empty = true; } pcol = 0; bool saddr = flags & FLAG_FORCEADDRPRINT; saddr = (outbytect > 0) ? true : saddr; saddr = (printlable != "") ? true : saddr; if (saddr) { pcol += printf("%02X/%04X:", (startpc >> 16), startpc & 0xFFFF); } else { pcol += printf(" "); } for (i = 0; i < l; i++) { uint8_t a = datafillbyte; if (datafillct == 0) { a = outbytes[i]; } pcol += printf("%02X ", a); } for (i = l; i < b; i++) { pcol += printf(" "); } pcol += printf("%6d ", lineno + 1); if (showmx) { if ((outbytect + datafillct) > 0) { pcol += printf("%%%c%c ", linemx & 02 ? '1' : '0', linemx & 01 ? '1' : '0'); } else { pcol += printf(" "); } string addrmode=options->addrModeEnglish(addressmode).c_str(); pcol+=printf("%s ",addrmode.c_str()); pcol+=printf("/%04X ",flags); while(pcol<50) { pcol+=printf(" "); } char sc=shiftchar; if (sc==0) { sc=' '; } pcol+=printf("%c |",sc); } if (isDebug() > 1) { //pcol += printf("%02X ", addressmode & 0xFF); pcol += printf(" %s ", addrtext.c_str()); } savpcol = pcol; // this is how many bytes are in the side margin pcol = 0; // reset pcol here because this is where source code starts if (empty) { if (comment.length() > 0) { if (comment[0] == ';') { while (pcol < commentcol) { pcol += printf(" "); } } //else { int comct = 0; for (uint32_t cc = 0; cc < comment.length(); cc++) { pcol += printf("%c", comment[cc]); comct++; if ((comment[cc] <= ' ') && (pcol >= (commentcol + savpcol + 20))) { printf("\n"); pcol = 0; while (pcol < (commentcol + savpcol)) { pcol += printf(" "); } } } //pcol += printf("%s", comment.c_str()); } commentprinted = true; } } else { pcol += printf("%s ", printlable.c_str()); while (pcol < tabs[0]) { pcol += printf(" "); } pcol += printf("%s ", opcode.c_str()); while (pcol < tabs[1]) { pcol += printf(" "); } if (isDebug() > 1) { pcol += printf("%s ", operand.c_str()); } else { if (printoperand.length() > 0) { pcol += printf("%s ", printoperand.c_str()); //pcol += printf("%s ", orig_operand.c_str()); } else { pcol += printf("%s ", printoperand.c_str()); //pcol += printf("%s ", orig_operand.c_str()); } } //pcol += printf("%-12s %-8s %-10s ", printlable.c_str(), opcode.c_str(), operand.c_str()); } //printf("merlinerrors=%d\n",merlinerrors); //merlinerrors=false; if ((errorcode > 0) && (!merlinerrors)) { while (pcol < commentcol) { pcol += printf(" "); } pcol += printf(":[Error] %s", errStrings[errorcode].c_str()); if (errorText.length() > 0) { pcol += printf(" (%s)", errorText.c_str()); } } else if (!commentprinted) { while (pcol < commentcol) { pcol += printf(" "); } pcol += printf("%s", comment.c_str()); } //printf("\n"); if ((options->useColor()) && (errorcode > 0)) { SetColor(CL_NORMAL); } uint32_t obc = datafillct; if (obc == 0) { obc = outbytect; } uint32_t ct = 1; if ((obc > b) && ((truncdata & 0x01) == 0)) { ct = 0; uint8_t db; uint32_t t = b; char *s = (char *)" "; b = 8; //printf("t=%d ct=%d\n",t,outbytect); printf("\n"); while (t < obc) { db = datafillbyte; if (datafillct == 0) { db = outbytes[t]; } if (ct == 0) { printf("%s", s); } printf("%02X ", db); t++; ct++; if (ct >= b) { printf("\n"); ct = 0; } } } if (ct > 0) { printf("\n"); } } void CLASS::clear() { shiftchar=0; wholetext = ""; lable = ""; printlable = ""; opcode = ""; opcodelower = ""; operand = ""; printoperand = ""; orig_operand=""; strippedoperand=""; comment = ""; operand_expr = ""; operand_expr2 = ""; addrtext = ""; merlinerrors = false; linemx = 0; bytect = 0; opflags = 0; pass0bytect = 0; startpc = 0; errorcode = 0; errorText = ""; datafillct = 0; datafillbyte = 0; lineno = 0; addressmode = 0; expr_value = 0; eval_result = 0; flags = 0; outbytes.clear(); outbytect = 0; } std::string operEx[] = { "^(\\S*)(#?)([<>\\^|]?)([\"\'])(.*)(\\4)([\\S]*)", // catches the normal delims "^(\\s*)([!-~])([!-~]*?)([^;]*)\\2(\\S*)", // catches the unusual delims "^(\\s*)(\\S+)", // captures everything else "" }; std::string commentEx = "^(\\s*)((;|\\/{2}))+(.*)"; void CLASS::set(std::string line) { int state = 0; int l = (int)line.length(); int i = 0; int x; char c; //char delim; //bool isascii; std::string opupper, s; std::string restofline; std::string tline = line; clear(); wholetext = line; // isascii = false; //delim = 0; while (i < l) { c = tline[i++]; switch (state) { case 7: if (c >= ' ') { comment += c; } else { i = l; } break; case 0: // start of line state if ((c == ';') || (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 == '*') || (c == '/')) && (lable.length() == 0)) { comment += c; state = 7; } else if (c > ' ') { opcode += c; state = 3; } break; case 3: { if (c > ' ') { opcode += c; } else { i--; state = 4; } } break; case 4: // read whitespace between opcode and operand { std::vector strs; std::string s; Poco::RegularExpression comEx(commentEx, 0, true); 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 { x = comEx.split(restofline, strs, 0); } catch (Poco::Exception &e) { x = 0; if (isDebug() > 3) { cout << e.displayText() << endl; } } if (x > 0) { // if the comment detector above is true, then the rest of line is comment; operand = ""; comment = strs[0]; //printf("comment=%s\n", comment.c_str()); i = l; break; } int ct = 0; int x = 0; bool match = false; s = operEx[ct]; while (s != "") { RegularExpression regex(s, 0, true); strs.clear(); x = 0; try { x = regex.split(restofline, strs, 0); } catch (Poco::Exception &e) { x = 0; if (isDebug() > 3) { cout << e.displayText() << endl; } } if (x > 0) { //printf("%d regex %d match |%s|\n", ct, x, restofline.c_str()); operand = strs[0]; orig_operand=operand; //printf("which=%d operand=|%s|\n",ct,operand.c_str()); i = (int)operand.length(); restofline = restofline.substr(i, restofline.length()); comment = Poco::trim(restofline); match = true; break; } ct++; s = operEx[ct]; } i = l; if (!match) { // if you are here, there probably isn't an operand and/or comment after opcode } } break; } } printlable = lable; x = (int)lable.length(); if (x > 1) { // M32 syntax allows a colon after lable, and it is not part of the lable //if ((syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) if (options->isMerlin32()) { while ((x > 1) && (lable[x - 1] == ':')) { lable = lable.substr(0, x - 1); x--; } //printf("linelable: |%s|\n", lable.c_str()); } } opcodelower = Poco::toLower(opcode); } #undef CLASS #define CLASS TFileProcessor CLASS::CLASS(ConfigOptions &opt) : options(opt) { int x; errorct = 0; //syntax=SYNTAX_QASM; 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() { } void CLASS::setLanguage(string lang,bool force) { options.setLanguage(lang,force); } void CLASS::errorOut(uint16_t code) { printf("error: %d\n", code); } void CLASS::init(void) { int ts, tabpos; std::string s; filenames.clear(); starttime = GetTickCount(); initialdir = Poco::Path::current(); filecount = 0; //syntax = SYNTAX_QASM; //std::string tabstr = getConfig("reformat.tabs", "8,16,32"); std::string tabstr = getConfig("reformat.tabs", "12,24,40,70"); tabstr = Poco::trim(tabstr); memset(tabs, 0x00, sizeof(tabs)); Poco::StringTokenizer t(tabstr, ",;", 0); tabpos = 0; for (auto itr = t.begin(); itr != t.end(); ++itr) { s = Poco::trim(*itr); try { ts = Poco::NumberParser::parse(s); } catch (...) { ts = 0; } if ((ts >= 0) && (ts < 240)) { tabs[tabpos++] = ts; } } } void CLASS::complete(void) { uint64_t n = GetTickCount(); //if (isDebug()) { //cout << "Processing Time: " << n - starttime << "ms" << endl; uint64_t x = n - starttime; uint32_t x1 = x & 0xFFFFFFFF; //if ((!getBool("option.quiet",false)) && (isDebug()>0)) { printf("Elapsed time: %u ms\n", x1); } } } void CLASS::process(void) { } int CLASS::doline(int lineno, std::string line) { UNUSED(lineno); UNUSED(line); int res = -1; return (res); } std::string CLASS::processFilename(std::string fn, std::string curDir, int level) { std::string res = fn; std::string s, s1; Path p = Poco::Path(fn); try { int n = p.depth(); //LOG_DEBUG << "n=" << n << " " << fn << endl; if (n == 0) { res = curDir + fn; } if (n > 0) { std::string d1 = p[0]; uint32_t v = 100; try { v = Poco::NumberParser::parseUnsigned(d1); } catch (...) { v = 99; } if (v < 10) { Poco::Path p1 = p.popFrontDirectory(); s = p1.toString(); s1 = "global.path" + Poco::NumberFormatter::format(v); switch (v) { case 0: s = initialdir + s; break; default: s = getConfig(s1, ".") + "/" + s; if (level < 5) { s = processFilename(s, curDir, level + 1); } break; } p = s; p.makeAbsolute(); } res = p.toString(); } } catch (Poco::Exception &e) { if (isDebug() > 2) { cout << "exception: " << e.displayText() << endl; } } catch (std::exception &e) { if (isDebug() > 2) { cout << e.what() << endl; } } p = res; p.makeAbsolute(); res = p.toString(); char buff[PATH_MAX + 1]; memset(buff, 0x00, sizeof(buff)); char *rp = realpath(res.c_str(), buff); if (rp != NULL) { //printf("realpath: %s\n", buff); res = rp; } p = res; p.makeAbsolute(); res = p.toString(); //LOG_DEBUG << "convert: |" << res << "|" << endl; return (res); } int CLASS::processfile(std::string p, std::string &newfilename) { //Poco::File fn(p); int c,c1; int res = -1; uint32_t linect; bool done, valid; std::string currentdir; std::string p1; std::string line, op; linect = 0; done = false; p = Poco::trim(p); currentdir = Poco::Path::current(); if (filecount == 0) { initialdir = currentdir; //printf("initialdir=%s\n",initialdir.c_str()); } //printf("currentdir=%s initialdir=%s\n", currentdir.c_str(), initialdir.c_str()); //LOG_DEBUG << "initial file name: " << p << endl; p = processFilename(p, (filecount == 0) ? currentdir : currentdir, 0); //LOG_DEBUG << "Converted filename: " << p << endl; Poco::Path tp(p); Poco::Path path = tp.makeAbsolute(); Poco::Path parent = path.parent(); std::string dir = parent.toString(); try { if (filecount == 0) { // is this the first file in the compilation, or a PUT/USE? // if first, change CWD to location of file //LOG_DEBUG << "Changing directory to: " << dir << endl; if (chdir(dir.c_str())) {} // change directory to where the file is } p1 = path.toString(); newfilename = p1; //LOG_DEBUG << "initial file name: " << p1 << endl; valid = true; 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()) { fn = Poco::File(p1); valid = false; } } } } p1 = fn.path(); //LOG_DEBUG << "File name: " << p1 << endl; int ecode = -3; valid = false; if (fn.exists()) { ecode = -2; valid = true; //LOG_DEBUG << "File exists: " << p1 << endl; if (fn.isLink()) { //LOG_DEBUG << "File is a link: " << p1 << endl; } if ((fn.isDirectory()) || (!fn.canRead())) { LOG_DEBUG << "File is a directory or can not read: " << p1 << endl; valid = false; } } else { printf("file does not exist |%s|\n", p1.c_str()); } newfilename = p1; if (!valid) { //fprintf(stderr, "Unable to access file: %s\n", p1.c_str()); errorct = 1; return (ecode); } if (valid) { if (filecount == 0) { } else { for (auto itr = filenames.begin(); itr != filenames.end(); ++itr) { if (*itr == p1) { return (-9); } } } filecount++; filenames.push_back(p1); std::ifstream f(p1); if (f.is_open()) { //printf("file is open\n"); line = ""; while ((!done) && (f.good()) && (!f.eof())) { c = f.get(); c1 = c & 0x7F; if (c == 0x8D) // merlin line ending { c = 0x0A; // convert to linux } else if (c == 0x8A) // possible merlin line ending { c = 0x0D; // ignore } else if ((c1<0x20) || (c1==127)) // see if it might be a control character { if ((c1==0x0D) || (c1==0x0A) || (c1==0x09)) { } else { c=0x00; } } c &= 0x7F; int x; switch (c) { case 0x00: case 0x0D: break; case 0x09: line += " "; break; case 0x0A: linect++; line=Poco::trimRight(line); //get rid of any space at end of line 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; } } if ( (f.eof())) { res = 0; } } } else { fprintf(stderr, "File <%s> does not exist.\n\n", p.c_str()); } } catch (...) { } return (res); } #if 1 #undef CLASS #define CLASS TMerlinConverter CLASS::CLASS(ConfigOptions &opt) : TFileProcessor(opt) { format_flags=CONVERT_TEST; //options=new ConfigOptions(); } CLASS::~CLASS() { } void CLASS::init(void) { TFileProcessor::init(); std::string s; lines.clear(); } int CLASS::doline(int lineno, std::string line) { UNUSED(lineno); MerlinLine l(line, options); lines.push_back(l); return 0; } void CLASS::process(void) { char buff[128*1024]; uint32_t ct = (uint32_t)lines.size(); uint8_t orval=0x00; uint32_t flags; string s; int llen,oplen,operlen,comlen; string lable,opcode,operand,comment; uint32_t len, tlen,t, pos,i; tlen=0; flags=format_flags; for (uint32_t lineno = 0; lineno < ct; lineno++) { MerlinLine line = lines.at(lineno); //printf("line: |%s|\n",line.wholetext.c_str()); orval=0x00; if (flags&CONVERT_HIGH) { orval=0x80; } len=0; pos = 0; lable=Poco::trimRight(line.printlable); llen=lable.length(); opcode=Poco::trimRight(line.opcode); oplen=opcode.length(); operand=Poco::trimRight(line.operand); operlen=operand.length(); comment=Poco::trimRight(line.comment); comlen=comment.length(); if ((llen+oplen+operlen)==0) { if (comlen > 0) { char c = comment[0]; if ((c == '*') || (c == '/')) { len+=sprintf(&buff[len+tlen],"%s", comment.c_str()); } else { t = tabs[2]; if (flags&CONVERT_COMPRESS) { if (flags&CONVERT_TABS) { len += sprintf(&buff[len+tlen],"\t\t\t\t"); } else { len += sprintf(&buff[len+tlen]," "); } } else { while (len < t) { len += sprintf(&buff[len+tlen]," "); } } len+=sprintf(&buff[len+tlen],"%s", comment.c_str()); } } } else { t = tabs[pos++]; len += sprintf(&buff[len+tlen],"%s", lable.c_str()); if ((oplen+operlen+comlen)>0) { if (flags&CONVERT_COMPRESS) { if (flags&CONVERT_TABS) { len += sprintf(&buff[len+tlen],"\t\t\t"); } else { len += sprintf(&buff[len+tlen]," "); } } else { while (len < t) { len += sprintf(&buff[len+tlen]," "); } } } t = tabs[pos++]; len += sprintf(&buff[len+tlen],"%s", opcode.c_str()); if ((operlen+comlen)>0) { if (flags&CONVERT_COMPRESS) { if (flags&CONVERT_TABS) { len += sprintf(&buff[len+tlen],"\t\t\t"); } else { len += sprintf(&buff[len+tlen]," "); } } else { while (len < t) { len += sprintf(&buff[len+tlen]," "); } } } t = tabs[pos++]; len += sprintf(&buff[len+tlen],"%s", operand.c_str()); if ((comlen)>0) { if (flags&CONVERT_COMPRESS) { if (flags&CONVERT_TABS) { len += sprintf(&buff[len+tlen],"\t\t\t"); } else { len += sprintf(&buff[len+tlen]," "); } } else { while (len < t) { len += sprintf(&buff[len+tlen]," "); } } } len += sprintf(&buff[len+tlen],"%s", comment.c_str()); } if (flags&CONVERT_CRLF) { len+=sprintf(&buff[len+tlen],"\r\n"); } else if (flags&CONVERT_LF) { len+=sprintf(&buff[len+tlen],"\n"); } else { len+=sprintf(&buff[len+tlen],"\r"); } tlen+=len; } //printf("tlen=%d\n",tlen); if (tlen>0) { int tct=0; int idx=0; for (i=0; i p(Poco::toUpper(op), sym); opcodes.insert(p); } TSymbol * CLASS::addSymbol(std::string symname, uint32_t val, bool replace) { TSymbol *res = NULL; TSymbol *fnd = NULL; std::string sym = symname; if (!casesen) { sym = Poco::toUpper(sym); } //printf("addSymbol: |%s|\n",sym.c_str()); if (sym.length() > 0) { TSymbol s; s.name = sym; s.opcode = 0; s.namelc = Poco::toLower(sym); s.stype = 0; s.value = val; s.used = false; s.cb = NULL; std::pair p(sym, s); if (sym[0] == ':') { //local symbol if (currentsym == NULL) { goto out; } else { fnd = findSymbol(sym); if ((fnd != NULL) && (!replace)) { goto out; } if (fnd != NULL) { fnd->value = val; res = fnd; goto out; } if (currentsym != NULL) { currentsym->locals.insert(p); } res = findSymbol(sym); goto out; } } else { fnd = findSymbol(sym); if ((fnd != NULL) && (!replace)) { goto out; } if (fnd != NULL) { //printf("replacing symbol: %s %08X\n",sym.c_str(),val); fnd->value = val; res = fnd; goto out; } symbols.insert(p); res = findSymbol(sym); } } out: return (res); } TMacro * CLASS::findMacro(std::string symname) { TMacro *res = NULL; std::string sym = symname; if (!casesen) { sym = Poco::toUpper(sym); } if (symname.length() > 0) { //printf("finding: %s\n",symname.c_str()); auto itr = macros.find(sym); if (itr != macros.end()) { res = &itr->second; } } return (res); } TSymbol * CLASS::findSymbol(std::string symname) { TSymbol *res = NULL; std::string sym = symname; if (!casesen) { sym = Poco::toUpper(sym); } if (symname.length() > 0) { if (symname[0] == ']') { //printf("finding symbol: |%s|\n",symname.c_str()); res = findVariable(symname, variables); if (res!=NULL) { //printf("symbol found: |%s| |%s|\n",symname.c_str(),res->var_text.c_str()); TEvaluator eval(*this); int64_t er_val=0; uint8_t shift=0; int er; er = eval.evaluate(res->var_text, er_val, shift); if (er == 0) { res->value=er_val; } } } else if (symname[0] == ':') { if (currentsym == NULL) { goto out; } else { auto itr = currentsym->locals.find(sym); if (itr != currentsym->locals.end()) { res = &itr->second; goto out; } } } else { //printf("finding: %s\n",symname.c_str()); auto itr = symbols.find(sym); if (itr != symbols.end()) { //printf("Found: %s 0x%08X\n",itr->second.name.c_str(),itr->second.value); res = &itr->second; goto out; } } } out: return (res); } TSymbol * CLASS::addVariable(std::string symname, std::string val, TVariable &vars, bool replace) { TSymbol *res = NULL; TSymbol *fnd = NULL; std::string sym = symname; if (!casesen) { sym = Poco::toUpper(sym); } //printf("addvariable\n"); fnd = findVariable(sym, vars); if ((fnd != NULL) && (!replace)) { return (NULL); // it is a duplicate } if (fnd != NULL) { //printf("replacing symbol: %s %s\n",sym.c_str(),val.c_str()); fnd->var_text = val; return (fnd); } TSymbol s; s.name = sym; s.opcode = 0; s.namelc = Poco::toLower(sym); s.stype = 0; s.value = 0; s.var_text = val; s.used = false; s.cb = NULL; //printf("addvariable: %s %s\n", s.name.c_str(), s.var_text.c_str()); std::pair p(sym, s); vars.vars.insert(p); res = findVariable(sym, vars); return (res); } TSymbol * CLASS::findVariable(std::string symname, TVariable &vars) { TSymbol *res = NULL; if (!casesen) { symname = Poco::toUpper(symname); } if ((expand_macrostack.size() > 0) && (vars.id != expand_macro.variables.id)) { res = findVariable(symname, expand_macro.variables); if (res != NULL) { return (res); } } //printf("finding: %s\n",symname.c_str()); auto itr = vars.vars.find(symname); if (itr != vars.vars.end()) { //printf("Found: %s 0x%08X\n",itr->second.name.c_str(),itr->second.value); res = &itr->second; return (res); } return (res); } void CLASS::showVariables(TVariable &vars) { if (vars.vars.size() > 0) { printf("\nVariables:\n"); for (auto itr = vars.vars.begin(); itr != vars.vars.end(); ++itr) { printf("%-16s %s\n", itr->first.c_str(), itr->second.var_text.c_str()); } printf("\n"); } } // set alpha to true to print table sorted by name or // false to print by value; void CLASS::showSymbolTable(bool alpha) { if (symbols.size() > 0) { std::map alphamap; std::map nummap; int columns = getInt("asm.symcolumns", 3); int column = columns; for (auto itr = symbols.begin(); itr != symbols.end(); itr++) { TSymbol ptr = itr->second; alphamap.insert(pair(ptr.name, ptr.value)); nummap.insert(pair(ptr.value, ptr.name)); } if (alpha) { printf("\n\nSymbol table sorted alphabetically:\n\n"); for (auto itr = alphamap.begin(); itr != alphamap.end(); ++itr) { printf("%-16s 0x%08X ", itr->first.c_str(), itr->second); if ( !--column ) { printf("\n"); column = columns; } } } else { printf("\n\nSymbol table sorted numerically:\n\n"); for (auto itr = nummap.begin(); itr != nummap.end(); ++itr) { printf("0x%08X %-16s ", itr->first, itr->second.c_str()); if ( !--column ) { printf("\n"); column = columns; } } } if (column > 0) { printf("\n"); } } } // set alpha to true to print table sorted by name or // false to print by value; void CLASS::showMacros(bool alpha) { if (macros.size() > 0) { std::map alphamap; int columns = getInt("asm.symcolumns", 3); int column = columns; for (auto itr = macros.begin(); itr != macros.end(); itr++) { TMacro ptr = itr->second; alphamap.insert(pair(ptr.name, 0)); } if (alpha) { printf("\n\nmacros sorted alphabetically:\n\n"); for (auto itr = alphamap.begin(); itr != alphamap.end(); ++itr) { printf("%-16s 0x%08X ", itr->first.c_str(), itr->second); if ( !--column ) { printf("\n"); column = columns; } } } if (column > 0) { printf("\n"); } } } int CLASS::callOpCode(std::string op, MerlinLine &line) { int res = -1; char c; std::string s; // 'op' is always lowercase here // during MACRO definition no opcodes are called (except for MAC, EOM, <<) if (macrostack.size() > 0) { // if something on the macro stack, then a macro is being defined if (!((op == "mac") || (op == "eom") || (op == "<<<"))) { return 0; } } if (op.length() == 4) // check for 4 digit 'L' opcodes { c = op[3] & 0x7F; if ((c >= 'a') && (c <= 'z')) { c = c - 0x20; } switch (c) { case 'L': op = op.substr(0, 3); line.flags |= FLAG_FORCELONG; // 3 byte address break; default: // any char but 'L' as in Merlin 16+ s = Poco::toUpper(op); if ((s == "ELSE") || (s == "DEND")) { break; } if (c != 'D') { op = op.substr(0, 3); line.flags |= FLAG_FORCEABS; // 2 byte address } break; case 'Z': op = op.substr(0, 3); line.flags |= FLAG_FORCEDP; // one byte address break; } } if (line.addressmode == syn_imm) //page 83 merlin16 manual { //printf("immediate mode\n"); switch (line.shiftchar) { case '<': //line.expr_value &= 0xFF; break; case '>': //line.expr_value >>= 8; //line.expr_value &= 0xFFFF; break; case '^': //line.expr_value = (line.expr_value >> 16); //line.expr_value = (line.expr_value >> 16) & 0xFFFF; break; case '|': // should never get here, handled in getAddrMode //if (syntax == SYNTAX_MERLIN) if (options.isMerlin()) { line.setError(errBadOperand); line.expr_value = 0; } //line.shiftchar=0; break; } } else { switch (line.shiftchar) // page 84 Merlin16 manual { case '<': if (options.isMerlin32()) { line.flags |= FLAG_DP; line.expr_value &= 0xFF; } break; case '>': if (options.isMerlin32()) { // bug in M32 or not, do what it does //line.flags |= FLAG_FORCEABS; line.flags |= FLAG_FORCELONG; } else { // Merlin16+ uses this to force long addressing // need to check Merlin16 if (!options.isMerlin()) // not merlin8 { line.flags |= FLAG_FORCELONG; } } break; case '|': if ((!options.isMerlin32()) && (options.isMerlinCompat())) { line.flags |= FLAG_FORCEABS; //line.shiftchar=0; } break; case '^': if (options.isMerlin32()) { line.flags |= FLAG_DP; line.expr_value >>= 16; } break; } } if (line.expr_value >= 0x100) { line.flags |= FLAG_FORCEABS; } auto itr = opcodes.find(Poco::toUpper(op)); if (itr != opcodes.end()) { TSymbol s = itr->second; if (s.cb != NULL) { res = s.cb(line, s); if (res == -1) { res = -2; } } } else { line.setError(errBadOpcode); } return (res); } typedef struct { std::string regEx; uint16_t addrMode; std::string text; //std::string expression; } TaddrMode; // these are the regular expressions that determine the addressing mode // and extract the 'expr' part of the addr-mode const 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}(.+)$", syn_imm, "immediate"}, //#expr,#^expr,#|expr,#expr {"^[(]{1}(?'expr'.+)[,]{1}[x,X]{1}\\)$", syn_diix, "(dp,x)"}, // (expr,x) {"^[(]{1}(?'expr'.+)[\\)]{1}[\\,][(Y|y]{1}$", syn_diiy, "(dp),y"}, //(expr),y {"^[(]{1}(?'expr'.+)[\\)]{1}$", syn_di, "(dp)"}, // (expr) {"^\\[{1}(?'expr'.+)\\]{1}[,]{1}[(Y|y)]{1}$", syn_iyl, "[laddr],y"}, // [expr],y {"^\\[(?'expr'.+)\\]$", syn_dil, "[e]"}, // [expr] {"^(?'expr'.+)[,]{1}[(X|x)]{1}$", syn_absx, "addr,x"}, // expr,x {"^(?'expr'.+)[,]{1}[(Y|y)]{1}$", syn_absy, "addr,y"}, // expr,y {"^(?'expr'.+)[,]{1}(?'expr2'.+)$", syn_bm, "block"}, // block move expr,expr1 {"^(?'expr'.+)$", syn_abs, "absolute"}, // expr (MUST BE LAST) {"", 0, ""} }; // one or more of any character except ][,(); //const std::string valExpression = "^([^\\]\\[,();]+)$"; const std::string valExpression = "^([^\\[,();]+)$"; // this one looks for ]variables const std::string varExpression = "([]]{1}[:0-9A-Z_a-z]{1}[0-9A-Z_a-z]*)"; const std::string macExpression = "([]]{1}[:0-9]{1}[0-9]*)"; // opcode check. emitted opcodes are compared against this // table, and if the XC status doesn't meet the requirements // an error is thrown // 0x00 = 6502 // 0x01 = 65C02 // 0x02 = 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) { uint8_t b = opCodeCompatibility[0]; if (b) { } TFileProcessor::init(); lines.clear(); insertOpcodes(); } void CLASS::initpass(void) { std::string s; casesen = getBool("asm.casesen", true); listing = getBool("asm.lst", true); showmx = getBool("asm.showmx", true); merlinerrors = getBool("asm.merlinerrors", true); outputbytes.clear(); trackrep = getBool("asm.trackrep", false); if (options.isMerlin32()) { trackrep = true; // can't turn this off in M32 } else if (options.isMerlin()) { trackrep = false; // can't turn this ON in M16 } else if (options.isNative()) { // 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; PC.origin = 0x8000; PC.currentpc = PC.origin; PC.totalbytes = 0; PC.orgsave = PC.origin; s = getConfig("asm.cpu", "M6502"); s = Poco::trim(Poco::toUpper(s)); s=PAL::getString("option.instruction",""); if (s!="") { //printf("CPU command line %s\n",s.c_str()); cpumode = MODE_65816; mx = 0x03; if (s == "M65816") { cpumode = MODE_65816; mx = 0x03; } else if (s == "M65C02") { cpumode = MODE_65C02; mx = 0x03; } else if (s == "M6502") { cpumode = MODE_6502; mx = 0x03; } else { printf("Unknown CPU type in .ini\n"); mx = 0x03; } } mx = getInt("asm.startmx", mx);; savepath = getConfig("option.objfile", ""); //printf("savepath: %s\n",savepath.c_str()); lastcarry = false; relocatable = false; currentsym = NULL; if (options.isMerlin32()) { // 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; passcomplete = false; dumstartaddr = 0; dumstart = 0; truncdata = 0; variables.vars.clear(); // clear the variables for each pass while (!macrostack.empty()) { macrostack.pop(); } while (!expand_macrostack.empty()) { expand_macrostack.pop(); } while (!LUPstack.empty()) { LUPstack.pop(); } while (!DOstack.empty()) { DOstack.pop(); } while (!LSTstack.empty()) { LSTstack.pop(); } while (!PCstack.empty()) { PCstack.pop(); } currentmacro.clear(); expand_macro.clear(); curLUP.clear(); curDO.clear(); } void CLASS::complete(void) { bool writeerr=false; if (savepath != "") { if (errorct == 0) { std::string currentdir = Poco::Path::current(); //savepath = processFilename(savepath, currentdir, 0); savepath=options.formatPath(savepath); if (!options.isQuiet()) { printf("saving to file: %s\n", savepath.c_str()); } //std::ofstream f(savepath, std::ios::out|std::ios::trunc); std::ofstream f(savepath, std::ios::out); if (f.is_open()) { for (unsigned int i=0; i 0) { TEvaluator eval(*this); line.eval_result = 0; res = eval.evaluate(expr, result, line.expr_shift); if (res != 0) { if (isDebug() > 2) { int c; if (options.useColor()) { c = SetColor(CL_RED); } uint32_t rr = result & 0xFFFFFFFF; printf("eval Error=%d %08X |%s|\n", res, rr, eval.badsymbol.c_str()); if (options.useColor()) { SetColor(c); } } } if (res == 0) { uint64_t v1 = (uint64_t) result; value = result; if ((listing) && (pass > 0) && (isDebug() > 2)) { uint32_t rr = v1 & 0xFFFFFFFF; printf("EV1=%08X '%c'\n", rr, line.expr_shift); } if (v1 >= 0x10000) { line.flags |= FLAG_BIGNUM; } if (v1 < 0x100) { line.flags |= FLAG_DP; } } } else { value = 0; res = 0; } if (isDebug() >= 3) { uint32_t rr = value & 0xFFFFFFFF; printf("Eval Result: %08X (status=%d)\n", rr, res); } return (res); } int CLASS::getAddrMode(MerlinLine & line) { int res = -1; uint16_t mode = syn_none; int idx, x; std::string s, oper; std::vector groups; char shiftchar; oper = line.operand; int l=oper.length(); int ol=line.opcode.length(); if ((ol == 0) || (l <= 0)) { if (ol>0) { return (syn_implied); } else { return(syn_none); } } bool supportbar=false; bool modified=false; shiftchar=oper[0]; if (shiftchar=='#') { shiftchar=0; if (l>1) { shiftchar=oper[1]; //oper=oper.substr(1); //oper="#"+oper; } } if (shiftchar=='^') { if (options.isMerlin()) { return(syn_err); //shiftchar=0x00; // merlin8 does not support the bank addr } } if (shiftchar=='|') { if (options.isMerlinCompat()) { if ((options.isMerlin() || options.isMerlin16())) // merlin8 and merlin16 do not support the bar { return(syn_err); } else { supportbar=true; } } } if ((shiftchar=='^') || (shiftchar=='<') || (shiftchar=='>') || (supportbar && (shiftchar=='|'))) { modified=true; } if (modified) { line.shiftchar=shiftchar; if (oper[0]=='#') { oper=oper.substr(2); oper="#"+oper; l=oper.length(); } else if (shiftchar!=0) { oper=oper.substr(1); l=oper.length(); } if (isDebug()>1) { printf("old: |%s| new: |%s|\n",line.operand.c_str(),oper.c_str()); } line.strippedoperand=oper; } if (supportbar && shiftchar=='|') { //if ((options.isMerlin32()) || (options.isNative())) if (options.isMerlin32()) { // regular Merlin16/16+ seems to accept this character, but does NOT force long (bank) addressing line.flags|=FLAG_FORCELONG; } //shiftchar=0; // don't process this as a shift because we only needed to set a flag to force long addressing } idx = 0; RegularExpression valEx(valExpression, 0, true); while (mode == syn_none) { s = addrRegEx[idx].regEx; if (s == "") { mode = syn_err; // no more RegX left (nothing matched) } else { RegularExpression regex(s, 0, true); groups.clear(); x = 0; try { //printf("oper: |%s|\n",oper.c_str()); 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; int ct = 0; for (uint32_t i = 0; i < groups.size(); i++) { s = groups[i]; //printf("ct=%zu idx=%d group: |%s|\n", groups.size(), i, s.c_str()); if (s != "") { //if ((s != "^") && (s != "<") && (s != ">") && (s != "|")) { bool v = true; if (mode == syn_abs) { if (i > 0) { v = valEx.match(s, 0, 0); if (v) { if (pass == 0) { // can only check on pass 0, because if the A" // symbol is defined later, we will generate different // bytes on the next pass if (options.isMerlin32()) //if ((line.syntax & SYNTAX_MERLIN32) == SYNTAX_MERLIN32) { if (Poco::toUpper(oper) == "A") // check the whole operand, not just the expression { 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; } } } } else if (line.flags & FLAG_FORCEIMPLIED) { mode = syn_implied; goto out; } } } } if (!v) { //printf("invalid expression |%s|\n", s.c_str()); mode = syn_none; } else if (ct == 1) { line.operand_expr = s; } else if (ct == 2) { line.operand_expr2 = s; } ct++; //printf("line expression=|%s|\n", s.c_str()); } //else { // SGQ need to set a flag for a shift and process it after eval } } } } } idx++; } out: 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); } if (isDebug()>1) { printf("addressmode=%d %s\n",res,options.addrModeEnglish(res).c_str()); } return (res); } int CLASS::substituteVariables(MerlinLine & line, std::string &outop) { int res = 0; int x,x1; std::string::size_type offset, slen; std::string oper = line.operand; std::string s; std::string operin; TSymbol *sym; uint32_t len, off, ct; bool done = false; operin = oper; ct = 0; bool mac_var; restart: while (!done) { mac_var=false; slen = oper.length(); if (slen > 0) { std::vector groups; 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) { try { varEx.match(oper, offset, mVec, 0); } catch (...) { offset = slen; } x = (int)mVec.size(); if (x > 0) { res = 0; off = (uint32_t)mVec[0].offset; len = (uint32_t)mVec[0].length; s = oper.substr(off, len); slen = s.length(); sym = NULL; if (expand_macrostack.size() > 0) { mac_var=true; sym = findVariable(s, expand_macro.variables); if (sym!=NULL) { RegularExpression varEx1(macExpression, 0, true); Poco::RegularExpression::MatchVec mVec1; try { varEx1.match(oper, 0, mVec1, 0); x1 = (int)mVec1.size(); if (x1>0) { mac_var=true; //printf("Found MACvar: |%s| |%s|\n",sym->name.c_str(),sym->var_text.c_str()); } } catch(...) { } } } else { //mac_var=true; } if (sym == NULL) { sym = findVariable(s, variables); } if ((expand_macrostack.size() == 0) && (!mac_var)) { //mac_var=true; } if ((sym != NULL) && (mac_var)) { //printf("match |%s|\n",sym->var_text.c_str()); if (sym->var_text != "") { oper = oper.replace(off, len, sym->var_text); slen = oper.length(); 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); } bool CLASS::doOFF(void) { bool res = curDO.doskip; std::stack tmpstack; TDOstruct doitem; uint32_t ct = (uint32_t)DOstack.size(); if (ct > 0) { tmpstack = DOstack; } while (ct > 0) { doitem = tmpstack.top(); tmpstack.pop(); if (doitem.doskip) { res = true; } ct--; } //printf("DOOFF: %d\n",res); return (res); } // this function determines if code generation is turned off (IF,DO,LUP,MAC, etc bool CLASS::codeSkipped(void) { bool res = false; res = (curLUP.lupskip) ? true : res; res = doOFF() ? true : res; res = currentmacro.running ? true : res; //printf("codeskip: %d\n",res); return (res); } void CLASS::process(void) { #if 0 uint32_t ct = lines.size(); for (uint32_t lineno = 0; lineno < ct; lineno++) { //MerlinLine &line = lines.at(lineno); //printf("|%s| |%s| |%s| |%s|\n", line.lable.c_str() // , line.opcode.c_str(), line.operand.c_str(), line.comment.c_str()); } #else uint32_t l; int x;; char c; char buff[256]; MerlinLine errLine(options); std::string op, realop, operand, ls; pass = 0; while (pass < 2) { initpass(); l = (uint32_t)lines.size(); bool passdone = false; while ((!passdone) && (!passcomplete)) { MerlinLine *ml = NULL; bool srcline = true; if (expand_macro.running) { srcline = false; if (expand_macro.currentline >= expand_macro.len) { // macro is complete lineno = expand_macro.sourceline + 1; if (expand_macrostack.size() > 0) { expand_macro = expand_macrostack.top(); expand_macrostack.pop(); } else { expand_macro.clear(); } srcline = true; } else { ml = &expand_macro.lines[expand_macro.currentline]; lineno = expand_macro.sourceline; expand_macro.currentline++; } } if (srcline) { if (lineno >= l) { passdone = true; goto passout; } else { ml = &lines[lineno]; } } MerlinLine &line = *ml; //printf("lineno=%u %s\n", lineno, line.wholetext.c_str()); line.eval_result = 0; line.lineno = lineno + 1; line.truncdata = truncdata; memcpy(line.tabs, tabs, sizeof(tabs)); //printf("lineno: %d %d |%s|\n",lineno,l,line.operand.c_str()); op = Poco::toLower(line.opcode); realop = line.opcode; operand = Poco::toLower(line.operand); line.startpc = PC.currentpc; line.linemx = mx; line.bytect = 0; line.showmx = showmx; //line.syntax = syntax; line.merlinerrors = merlinerrors; if ((line.lable != "") && (op != "mac")) { std::string lable = Poco::trim(line.lable); TSymbol *sym = NULL; bool dupsym = false; c = line.lable[0]; switch (c) { case ']': sprintf(buff, "$%X", PC.currentpc); ls = buff; sym = addVariable(line.lable, ls, variables, true); //if (sym == NULL) { dupsym = true; } break; case ':': default: if (pass == 0) { sym = addSymbol(line.lable, PC.currentpc, false); if (sym == NULL) { dupsym = true; line.setError(errDupSymbol); } } if (c != ':') { currentsym = findSymbol(line.lable); currentsymstr = line.lable; } break; } if (dupsym) { line.setError(errDupSymbol); } } std::string outop; line.printoperand = line.operand; //printf("\nprintoperand: |%s|\n",line.printoperand.c_str()); //printf("\noperand: |%s|\n",operand.c_str()); x = 0; if (macrostack.size() == 0) { x = substituteVariables(line, outop); } if (x > 0) { line.printoperand = outop; line.operand = outop; } x = parseOperand(line); //if (x >= 0) //{ line.addressmode = x; //} int64_t value = -1; x = evaluate(line, line.operand_expr, value); line.eval_result = x; if (x == 0) { value &= 0xFFFFFFFF; line.expr_value = (uint32_t)value; } else { line.expr_value = 0; } x = 0; if (op.length() > 0) { bool skipop = false; if (doOFF()) { skipop = true; if ((op == "fin") || (op == "else") || (op == "do") || (op == "if")) { skipop = false; } } if (!skipop) { TMacro *mac = NULL; bool inoperand = false; if (macrostack.size() == 0) { mac = findMacro(realop); if (mac == NULL) { if (op == ">>>") // specal merlin way of calling a macro { Poco::StringTokenizer tok(operand, ", ", Poco::StringTokenizer::TOK_TRIM | Poco::StringTokenizer::TOK_IGNORE_EMPTY); std::string s = ""; if (tok.count() > 0) { s = tok[0]; } mac = findMacro(s); inoperand = true; } } } if (mac == NULL) { x = callOpCode(op, line); } if (mac != NULL) { expand_macrostack.push(expand_macro); expand_macro = *mac; expand_macro.lines.clear(); //printf("mac start=%u end=%u\n", expand_macro.start, expand_macro.end); for (uint32_t lc = expand_macro.start; lc < expand_macro.end; lc++) { //printf("pushing %s\n", lines[lc].wholetext.c_str()); MerlinLine nl(lines[lc].wholetext,options); // create a new clean line (without errors,data) expand_macro.lines.push_back(nl); } expand_macro.running = true; expand_macro.sourceline = lineno; expand_macro.variables.vars.clear(); // set the variables for the macro here SGQ std::string parms = line.operand; if (inoperand) { Poco::StringTokenizer tok(parms, ", ", Poco::StringTokenizer::TOK_TRIM | Poco::StringTokenizer::TOK_IGNORE_EMPTY); parms = ""; if (tok.count() > 1) { parms = tok[1]; } } Poco::StringTokenizer tok(parms, ",;", Poco::StringTokenizer::TOK_TRIM | Poco::StringTokenizer::TOK_IGNORE_EMPTY); uint32_t ct = 0; for (auto itr = tok.begin(); itr != tok.end(); ++itr) { //evaluate each of these strings, check for errors on pass 2 std::string expr = *itr; std::string v = "]" + Poco::NumberFormatter::format(ct + 1); //printf("var: %s %s\n", v.c_str(), expr.c_str()); addVariable(v, expr, expand_macro.variables, true); ct++; } x = 0; expand_macro.currentline = 0; } } } if ((x > 0) && (codeSkipped())) // has a psuedo-op turned off code generation? (LUP, IF, etc) { x = 0; line.outbytect = 0; } if (x > 0) { if (!PCstack.empty()) // are we inside a DUM section? { line.flags |= FLAG_INDUM; } if ((line.eval_result != 0) && (pass > 0)) { line.setError(errBadOperand); line.errorText = line.operand_expr; } line.bytect = x; if (pass>0) { if ((line.flags & FLAG_INDUM) == 0) // don't write bytes if inside DUM section { for (unsigned int i=0; i0) { for (int i=0; i 0) // starting a dummy section { PCstack.push(PC); PC.origin = dumstartaddr; PC.currentpc = PC.origin; dumstart = 0; dumstartaddr = 0; } if (dumstart < 0) { PC = PCstack.top(); PCstack.pop(); dumstart = 0; dumstartaddr = 0; } if (pass == 1) { if ((line.pass0bytect != line.bytect) && (line.errorcode == 0)) { if (expand_macrostack.size() == 0) // if macro expanding, you can't make this check { line.setError(errBadByteCount); } } if (line.errorcode != 0) { errorct++; } if (((!skiplist) && (listing) && (pass == 1)) || (line.errorcode != 0) || (options.isList())) { line.print(lineno); } skiplist = false; line.outbytes.clear(); // clear the outbytes on the line so LUP works correctly line.outbytect=0; } lineno++; } passout: // end of file reached here, do some final checks #if 0 if (LUPstack.size() > 0) { errLine.clear(); errLine.setError(errUnexpectedEOF); errLine.print(lineno); pass = 2; } #endif pass++; } #endif } int CLASS::doline(int lineno, std::string line) { int res = 0; int x; std::string op; UNUSED(lineno); MerlinLine l(line,options); op = Poco::toLower(l.opcode); lines.push_back(l); if ((op == "use") || (op == "put")) { std::string fn; x = processfile(l.operand, fn); //printf("processfile : %d\n",x); if (x < 0) { switch (x) { case -9: l.setError(errDuplicateFile); break; case -3: l.setError(errFileNotFound); break; case -2: l.setError(errFileNoAccess); break; default: l.setError(errFileNotFound); break; } l.operand = fn; l.print(0); errorct++; res = -1; } } return (res); } #undef CLASS #define CLASS T65816Link CLASS::CLASS(ConfigOptions &opt) : TFileProcessor(opt) { } CLASS::~CLASS() { } void CLASS::init(void) { TFileProcessor::init(); } void CLASS::process(void) { } void CLASS::complete(void) { } int CLASS::doline(int lineno, std::string line) { UNUSED(lineno); UNUSED(line); int res = 0; return (res); } #undef CLASS