?login_element?

Subversion Repositories NedoOS

Rev

Rev 622 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download

  1. /*
  2.  
  3.   SjASMPlus Z80 Cross Compiler
  4.  
  5.   This is modified sources of SjASM by Aprisobal - aprisobal@tut.by
  6.  
  7.   Copyright (c) 2006 Sjoerd Mastijn
  8.  
  9.   This software is provided 'as-is', without any express or implied warranty.
  10.   In no event will the authors be held liable for any damages arising from the
  11.   use of this software.
  12.  
  13.   Permission is granted to anyone to use this software for any purpose,
  14.   including commercial applications, and to alter it and redistribute it freely,
  15.   subject to the following restrictions:
  16.  
  17.   1. The origin of this software must not be misrepresented; you must not claim
  18.          that you wrote the original software. If you use this software in a product,
  19.          an acknowledgment in the product documentation would be appreciated but is
  20.          not required.
  21.  
  22.   2. Altered source versions must be plainly marked as such, and must not be
  23.          misrepresented as being the original software.
  24.  
  25.   3. This notice may not be removed or altered from any source distribution.
  26.  
  27. */
  28.  
  29. // tables.cpp
  30.  
  31. #include <assert.h>
  32. #include "sjdefs.h"
  33.  
  34. TextFilePos::TextFilePos() : filename(nullptr), line(0), colBegin(0), colEnd(0) {
  35. }
  36.  
  37. void TextFilePos::newFile(const char* fileNamePtr) {
  38.         filename = fileNamePtr;
  39.         line = colBegin = colEnd = 0;
  40. }
  41.  
  42. // advanceColumns are valid only when true == endsWithColon (else advanceColumns == 0)
  43. // default arguments are basically "next line"
  44. void TextFilePos::nextSegment(bool endsWithColon, size_t advanceColumns) {
  45.         if (endsWithColon && 0 == colEnd) colEnd = 1;   // first segment of "colonized" line (do +1,+1)
  46.         colBegin = colEnd;
  47.         if (colBegin <= 1) ++line;              // first segment of any line, increment also line number
  48.         if (endsWithColon)      colEnd += advanceColumns;
  49.         else                            colEnd = 0;
  50. }
  51.  
  52. char* PreviousIsLabel = nullptr;
  53.  
  54. // since v1.14.2:
  55. // When "setNameSpace == true" the naam is parsed as whole, reporting invalid labelname error
  56. // When "setNameSpace == false" the naam is parsed only through valid label chars (early exit)
  57. // => the labels can be evaluated straight from the expression string without copying them out!
  58. char* ValidateLabel(const char* naam, bool setNameSpace) {
  59.         const bool global = '@' == *naam;
  60.         const bool local = '.' == *naam;
  61.         if (!isLabelStart(naam)) {              // isLabelStart assures that only single modifier exist
  62.                 if (global || local) ++naam;// single modifier is parsed (even when invalid name)
  63.                 Error("Invalid labelname", naam);
  64.                 return nullptr;
  65.         }
  66.         if (global || local) ++naam;    // single modifier is parsed
  67.         const bool inMacro = local && macrolabp;
  68.         const bool inModule = !inMacro && !global && ModuleName[0];
  69.         // check all chars of label
  70.         const char* np = naam;
  71.         while (islabchar(*np)) ++np;
  72.         if ('[' == *np) return nullptr; // this is DEFARRAY name, do not process it as label (silent exit)
  73.         if (setNameSpace && *np) {
  74.                 // if this is supposed to be new label, there shoulnd't be anything else after it
  75.                 Error("Invalid labelname", naam);
  76.                 return nullptr;
  77.         }
  78.         // calculate expected length of fully qualified label name
  79.         int labelLen = (np - naam), truncateAt = LABMAX;
  80.         if (LABMAX < labelLen) Error("Label too long", naam, IF_FIRST); // non-fatal error, will truncate it
  81.         if (inMacro) labelLen += 1 + strlen(macrolabp);
  82.         else if (local) labelLen += 1 + strlen(vorlabp);
  83.         if (inModule) labelLen += 1 + strlen(ModuleName);
  84.         // build fully qualified label name (in newly allocated memory buffer, with precise length)
  85.         char* label = new char[1+labelLen];
  86.         if (nullptr == label) ErrorOOM();
  87.         label[0] = 0;
  88.         if (inModule) {
  89.                 STRCAT(label, labelLen, ModuleName);    STRCAT(label, 2, ".");
  90.         }
  91.         if (inMacro) {
  92.                 STRCAT(label, labelLen, macrolabp);             STRCAT(label, 2, ">");
  93.         } else if (local) {
  94.                 STRCAT(label, labelLen, vorlabp);               STRCAT(label, 2, ".");
  95.         }
  96.         char* lp = label + strlen(label), * newVorlabP = nullptr;
  97.         if (setNameSpace && !local) newVorlabP = lp;    // here will start new non-local label prefix
  98.         while (truncateAt-- && islabchar(*naam)) *lp++ = *naam++;       // add the new label (truncated if needed)
  99.         *lp = 0;
  100.         if (labelLen < lp - label) Error("internal error", nullptr, FATAL);             // should never happen :)
  101.         if (newVorlabP) {
  102.                 free(vorlabp);
  103.                 vorlabp = STRDUP(newVorlabP);
  104.                 if (vorlabp == NULL) ErrorOOM();
  105.         }
  106.         return label;
  107. }
  108.  
  109. static bool getLabel_invalidName = false;
  110.  
  111. static CLabelTableEntry* GetLabel(char*& p) {
  112.         getLabel_invalidName = true;
  113.         char* fullName = ValidateLabel(p, false);
  114.         if (nullptr == fullName) return nullptr;
  115.         getLabel_invalidName = false;
  116.         const bool global = '@' == *p;
  117.         const bool local = '.' == *p;
  118.         bool inMacro = local && macrolabp;              // not just inside macro, but should be prefixed
  119.         while (islabchar(*p)) ++p;              // advance pointer beyond the parsed label
  120.         const int modNameLen = strlen(ModuleName);
  121.         // find the label entry in the label table (for local macro labels it has to try all sub-parts!)
  122.         // then regular full label has to be tried
  123.         // and if it's regular non-local in module, then variant w/o current module has to be tried
  124.         char *findName = fullName;
  125.         bool inTableAlready = false;
  126.         CLabelTableEntry* labelEntry = nullptr;
  127.         temp[0] = 0;
  128.         do {
  129.                 labelEntry = LabelTable.Find(findName);
  130.                 if (labelEntry) {
  131.                         inTableAlready = true;
  132.                         if (LASTPASS != pass) labelEntry->used = true;
  133.                         if (LABEL_PAGE_UNDEFINED != labelEntry->page) break;
  134.                         labelEntry = nullptr;
  135.                         IsLabelNotFound = 2;
  136.                 }
  137.                 // not found (the defined one, try more variants)
  138.                 if (inMacro) {                          // try outer macro (if there is one)
  139.                         while ('>' != *findName && '.' != *findName) ++findName;
  140.                         // if no more outer macros, try module+non-local prefix with the original local label
  141.                         if ('>' == *findName++) {
  142.                                 inMacro = false;
  143.                                 if (modNameLen) {
  144.                                         STRCAT(temp, LINEMAX-2, ModuleName); STRCAT(temp, 2, ".");
  145.                                 }
  146.                                 STRCAT(temp, LABMAX-1, vorlabp); STRCAT(temp, 2, ".");
  147.                                 STRCAT(temp, LABMAX-1, findName);
  148.                                 findName = temp;
  149.                         }
  150.                 } else {
  151.                         if (!global && !local && fullName == findName && modNameLen) {
  152.                                 // this still may be global label without current module (but author didn't use "@")
  153.                                 findName = fullName + modNameLen + 1;
  154.                         } else {
  155.                                 findName = nullptr;     // all options exhausted
  156.                         }
  157.                 }
  158.         } while (findName);
  159.         if (nullptr == findName) {              // not found, check if it needs to be inserted into table
  160.                 // canonical name is either in "temp" (when in-macro) or in "fullName" (outside macro)
  161.                 findName = temp[0] ? temp : fullName;
  162.                 if (!inTableAlready) {
  163.                         LabelTable.Insert(findName, 0, true);
  164.                         IsLabelNotFound = 1;
  165.                 }
  166.                 Error("Label not found", findName);
  167.         }
  168.         delete[] fullName;
  169.         return labelEntry;
  170. }
  171.  
  172.  
  173. bool GetLabelPage(char*& p, aint& val) {
  174.         CLabelTableEntry* labelEntry = GetLabel(p);
  175.         val = labelEntry ? labelEntry->page : LABEL_PAGE_UNDEFINED;
  176.         // true even when not found, but valid label name (neeed for expression-eval logic)
  177.         return !getLabel_invalidName;
  178. }
  179.  
  180. bool GetLabelValue(char*& p, aint& val) {
  181.         CLabelTableEntry* labelEntry = GetLabel(p);
  182.         val = labelEntry ? labelEntry->value : 0;
  183.         // true even when not found, but valid label name (neeed for expression-eval logic)
  184.         return !getLabel_invalidName;
  185. }
  186.  
  187. int GetLocalLabelValue(char*& op, aint& val) {
  188.         char* p = op;
  189.         if (SkipBlanks(p) || !isdigit((byte)*p)) return 0;
  190.         char* const numberB = p;
  191.         while (isdigit((byte)*p)) ++p;
  192.         const char type = *p|0x20;              // [bB] => 'b', [fF] => 'f'
  193.         if ('b' != type && 'f' != type) return 0;       // local label must have "b" or "f" after number
  194.         const char following = p[1];    // should be EOL, colon or whitespace
  195.         if (0 != following && ':' != following && !White(following)) return 0;
  196.         // numberB -> p are digits to be parsed as integer
  197.         if (!GetNumericValue_IntBased(op = numberB, p, val, 10)) return 0;
  198.         ++op;
  199.         // ^^ advance main parsing pointer op beyond the local label (here it *is* local label)
  200.         val = ('b' == type) ? LocalLabelTable.seekBack(val) : LocalLabelTable.seekForward(val);
  201.         if (-1L == val) {
  202.                 Error("Local label not found", numberB, SUPPRESS);
  203.                 val = 0L;
  204.                 return 1;
  205.         }
  206.         return 1;
  207. }
  208.  
  209. void CLabelTableEntry::ClearData() {
  210.         if (name) free(name);
  211.         name = NULL;
  212.         value = 0;
  213.         updatePass = 0;
  214.         page = LABEL_PAGE_UNDEFINED;
  215.         IsDEFL = IsEQU = used = false;
  216. }
  217.  
  218. CLabelTableEntry::CLabelTableEntry() : name(NULL) {
  219.         ClearData();
  220. }
  221.  
  222. CLabelTable::CLabelTable() {
  223.         NextLocation = 1;
  224. }
  225.  
  226. static short getAddressPageNumber(const aint address, bool forceRecalculateByAddress) {
  227.         // everything is "ROM" based when device is NONE
  228.         if (!DeviceID) return LABEL_PAGE_ROM;
  229.         // fast-shortcut for regular labels in current slot (if they fit into it)
  230.         auto slot = Device->GetCurrentSlot();
  231.         assert(Page && slot);
  232.         if (!forceRecalculateByAddress && !PseudoORG) {
  233.                 if (slot->Address <= address && address < slot->Address + slot->Size) {
  234.                         return Page->Number;
  235.                 }
  236.         }
  237.         // enforce explicit request of fake DISP page
  238.         if (PseudoORG && LABEL_PAGE_UNDEFINED != dispPageNum) {
  239.                 return dispPageNum;
  240.         }
  241.         // in other case (implicit DISP, out-of-slot-bounds or forceRecalculateByAddress)
  242.         // track down the page num from current memory mapping
  243.         const short page = Device->GetPageOfA16(address);
  244.         if (LABEL_PAGE_UNDEFINED == page) return LABEL_PAGE_OUT_OF_BOUNDS;
  245.         return page;
  246. }
  247.  
  248. int CLabelTable::Insert(const char* nname, aint nvalue, bool undefined, bool IsDEFL, bool IsEQU) {
  249.         if (NextLocation >= LABTABSIZE * 2 / 3) {
  250.                 Error("Label table full", NULL, FATAL);
  251.         }
  252.  
  253.         // Find label in label table
  254.         CLabelTableEntry* label = Find(nname);
  255.         if (label) {
  256.                 if (!label->IsDEFL && label->page != LABEL_PAGE_UNDEFINED && label->updatePass == pass) {
  257.                         return 0;
  258.                 } else {
  259.                         //if label already added (as used, or in previous pass), just refresh values
  260.                         label->value = nvalue;
  261.                         label->page = getAddressPageNumber(nvalue, IsDEFL|IsEQU);
  262.                         label->IsDEFL = IsDEFL;
  263.                         label->IsEQU = IsEQU;
  264.                         label->updatePass = pass;
  265.                         return 1;
  266.                 }
  267.         }
  268.         int tr = Hash(nname);
  269.         while (HashTable[tr]) {
  270.                 if (++tr >= LABTABSIZE) tr = 0;
  271.         }
  272.         HashTable[tr] = NextLocation;
  273.         label = LabelTable + NextLocation++;
  274.         label->name = STRDUP(nname);
  275.         if (label->name == NULL) ErrorOOM();
  276.         label->IsDEFL = IsDEFL;
  277.         label->IsEQU = IsEQU;
  278.         label->updatePass = pass;
  279.         label->value = nvalue;
  280.         label->used = undefined;
  281.         label->page = undefined ? LABEL_PAGE_UNDEFINED : getAddressPageNumber(nvalue, IsDEFL|IsEQU);
  282.         return 1;
  283. }
  284.  
  285. int CLabelTable::Update(char* nname, aint nvalue) {
  286.         CLabelTableEntry* label = Find(nname);
  287.         if (label) label->value = nvalue;
  288.         return NULL != label;
  289. }
  290.  
  291. CLabelTableEntry* CLabelTable::Find(const char* name, bool onlyDefined)
  292. {
  293.         //FIXME get rid of this manual hash table implementation (seems still bugged for edge cases)
  294.         int tr, htr, otr;
  295.         otr = tr = Hash(name);
  296.         while ((htr = HashTable[tr])) {
  297.                 if (LabelTable[htr].name && !strcmp(LabelTable[htr].name, name)) {
  298.                         if (onlyDefined && LABEL_PAGE_UNDEFINED == LabelTable[htr].page) return NULL;
  299.                         return LabelTable+htr;
  300.                 }
  301.                 if (LABTABSIZE <= ++tr) tr = 0;
  302.                 if (tr == otr) break;
  303.         }
  304.         return NULL;
  305. }
  306.  
  307. bool CLabelTable::IsUsed(const char* name) {
  308.         CLabelTableEntry* label = Find(name);
  309.         return label ? label->used : false;
  310. }
  311.  
  312. bool CLabelTable::Remove(const char* name) {
  313.         CLabelTableEntry* label = Find(name);
  314.         if (label) label->ClearData();
  315.         return NULL != label;
  316. }
  317.  
  318. void CLabelTable::RemoveAll() {
  319.         for (int i = 1; i < NextLocation; ++i) LabelTable[i].ClearData();
  320.         NextLocation = 1;
  321. }
  322.  
  323. int CLabelTable::Hash(const char* s) {
  324.         const char* ss = s;
  325.         unsigned int h = 0,g;
  326.         for (; *ss != '\0'; ss++) {
  327.                 h = (h << 4) + *ss;
  328.                 if ((g = h & 0xf0000000)) {
  329.                         h ^= g >> 24; h ^= g;
  330.                 }
  331.         }
  332.         return h % LABTABSIZE;
  333. }
  334.  
  335. void CLabelTable::Dump() {
  336.         FILE* listFile = GetListingFile();
  337.         if (NULL == listFile) return;           // listing file must be already opened here
  338.  
  339.         char line[LINEMAX], *ep;
  340.         fputs("\nValue    Label\n", listFile);
  341.         fputs("------ - -----------------------------------------------------------\n", listFile);
  342.         for (int i = 1; i < NextLocation; ++i) {
  343.                 if (LABEL_PAGE_UNDEFINED != LabelTable[i].page) {
  344.                         ep = line;
  345.                         *(ep) = 0;
  346.                         *(ep++) = '0';
  347.                         *(ep++) = 'x';
  348.                         PrintHexAlt(ep, LabelTable[i].value);
  349.                         *(ep++) = ' ';
  350.                         *(ep++) = LabelTable[i].used ? ' ' : 'X';
  351.                         *(ep++) = ' ';
  352.                         STRCPY(ep, LINEMAX - (ep - line), LabelTable[i].name);
  353.                         ep += strlen(LabelTable[i].name);
  354.                         *(ep++) = '\n';
  355.                         *(ep) = 0;
  356.                         fputs(line, listFile);
  357.                 }
  358.         }
  359. }
  360.  
  361. void CLabelTable::DumpForUnreal() {
  362.         char ln[LINEMAX], * ep;
  363.         FILE* FP_UnrealList;
  364.         if (!FOPEN_ISOK(FP_UnrealList, Options::UnrealLabelListFName, "w")) {
  365.                 Error("Error opening file", Options::UnrealLabelListFName, FATAL);
  366.         }
  367.         const int PAGE_MASK = DeviceID ? Device->GetPage(0)->Size - 1 : 0x3FFF;
  368.         for (int i = 1; i < NextLocation; ++i) {
  369.                 if (LABEL_PAGE_UNDEFINED == LabelTable[i].page) continue;
  370.                 int page = LabelTable[i].page;
  371.                 if (!strcmp(DeviceID, "ZXSPECTRUM48") && page < 4) {    //TODO fix this properly?
  372.                         // convert pages {0, 1, 2, 3} of ZX48 into ZX128-like {ROM, 5, 2, 0}
  373.                         // this can be fooled when there were multiple devices used, Label doesn't know into
  374.                         // which device it does belong, so even ZX128 labels will be converted.
  375.                         const int fakeZx128Pages[] = {LABEL_PAGE_ROM, 5, 2, 0};
  376.                         page = fakeZx128Pages[page];
  377.                 }
  378.                 int lvalue = LabelTable[i].value & PAGE_MASK;
  379.                 ep = ln;
  380.  
  381.                 if (!Options::EmitVirtualLabels) {
  382.                         if (page < LABEL_PAGE_ROM) ep += sprintf(ep, "%02d", page&255);
  383.                         *(ep++) = ':';
  384.                         PrintHexAlt(ep, lvalue);
  385.                 }
  386.                 else {
  387.                         *(ep++) = ':';
  388.                         PrintHexAlt(ep, LabelTable[i].value & 0xFFFF);
  389.                 }
  390.  
  391.                 *(ep++) = ' ';
  392.                 STRCPY(ep, LINEMAX-(ep-ln), LabelTable[i].name);
  393.                 STRCAT(ep, LINEMAX, "\n");
  394.                 fputs(ln, FP_UnrealList);
  395.         }
  396.         fclose(FP_UnrealList);
  397. }
  398.  
  399. void CLabelTable::DumpForCSpect() {
  400.         FILE* file;
  401.         if (!FOPEN_ISOK(file, Options::CSpectMapFName, "w")) {
  402.                 Error("Error opening file", Options::CSpectMapFName, FATAL);
  403.         }
  404.         const int PAGE_SIZE = Options::CSpectMapPageSize;
  405.         const int PAGE_MASK = PAGE_SIZE - 1;
  406.         for (int i = 1; i < NextLocation; ++i) {
  407.                 if (LABEL_PAGE_UNDEFINED == LabelTable[i].page) continue;
  408.                 const int labelType =
  409.                         LabelTable[i].IsEQU ? 1 :
  410.                         LabelTable[i].IsDEFL ? 2 :
  411.                         (LABEL_PAGE_ROM <= LabelTable[i].page) ? 3 : 0;
  412.                 const short page = labelType ? 0 : LabelTable[i].page;
  413.                 const aint longAddress = (PAGE_MASK & LabelTable[i].value) + page * PAGE_SIZE;
  414.                 fprintf(file, "%08X %08X %02X ", 0xFFFF & LabelTable[i].value, longAddress, labelType);
  415.                 // convert primary+local label to be "@" delimited (not "." delimited)
  416.                 STRCPY(temp, LINEMAX, LabelTable[i].name);
  417.                 // look for "primary" label (where the local label starts)
  418.                 char* localLabelStart = strrchr(temp, '.');
  419.                 while (temp < localLabelStart) {        // the dot must be at least second character
  420.                         *localLabelStart = 0;                   // terminate the possible "primary" part
  421.                         CLabelTableEntry* label = Find(temp, true);
  422.                         if (label) {
  423.                                 *localLabelStart = '@';         // "primary" label exists, modify delimiter '.' -> '@'
  424.                                 break;
  425.                         }
  426.                         *localLabelStart = '.';                 // "primary" label didn't work, restore dot
  427.                         do {
  428.                                 --localLabelStart;                      // and look for next dot
  429.                         } while (temp < localLabelStart && '.' != *localLabelStart);
  430.                 }
  431.                 fprintf(file, "%s\n", temp);
  432.         }
  433.         fclose(file);
  434. }
  435.  
  436. void CLabelTable::DumpSymbols() {
  437.         FILE* symfp;
  438.         if (!FOPEN_ISOK(symfp, Options::SymbolListFName, "w")) {
  439.                 Error("Error opening file", Options::SymbolListFName, FATAL);
  440.         }
  441.         for (int i = 1; i < NextLocation; ++i) {
  442.                 if (LabelTable[i].name && isalpha((byte)LabelTable[i].name[0])) {
  443.                         STRCPY(ErrorLine, LINEMAX, LabelTable[i].name);
  444.                         STRCAT(ErrorLine, LINEMAX2-1, ": equ ");
  445.                         STRCAT(ErrorLine, LINEMAX2-1, "0x");
  446.                         char lnrs[16], * l = lnrs;
  447.                         PrintHex32(l, LabelTable[i].value);
  448.                         *l = 0;
  449.                         STRCAT(ErrorLine, LINEMAX2-1, lnrs);
  450.                         STRCAT(ErrorLine, LINEMAX2-1, "\n");
  451.                         fputs(ErrorLine, symfp);
  452.                 }
  453.         }
  454.         fclose(symfp);
  455. }
  456.  
  457. CFunctionTable::CFunctionTable() {
  458.         NextLocation = 1;
  459. }
  460.  
  461. int CFunctionTable::Insert(const char* nname, void(*nfunp) (void)) {
  462.         char* p;
  463.         if (NextLocation >= FUNTABSIZE * 2 / 3) {
  464.                 Error("Functions Table is full", NULL, FATAL);
  465.         }
  466.         int tr, htr;
  467.         tr = Hash(nname);
  468.         while ((htr = HashTable[tr])) {
  469.                 if (!strcmp((funtab[htr].name), nname)) {
  470.                         return 0;
  471.                 } else if (++tr >= FUNTABSIZE) {
  472.                         tr = 0;
  473.                 }
  474.         }
  475.         HashTable[tr] = NextLocation;
  476.         funtab[NextLocation].name = STRDUP(nname);
  477.         if (funtab[NextLocation].name == NULL) ErrorOOM();
  478.         funtab[NextLocation].funp = nfunp;
  479.         ++NextLocation;
  480.  
  481.         STRCPY(p = temp, LINEMAX, nname);
  482.         while ((*p = (char) toupper((byte)*p))) { ++p; }
  483.  
  484.         if (NextLocation >= FUNTABSIZE * 2 / 3) {
  485.                 Error("Functions Table is full", NULL, FATAL);
  486.         }
  487.         tr = Hash(temp);
  488.         while ((htr = HashTable[tr])) {
  489.                 if (!strcmp((funtab[htr].name), temp)) {
  490.                         return 0;
  491.                 } else if (++tr >= FUNTABSIZE) {
  492.                         tr = 0;
  493.                 }
  494.         }
  495.         HashTable[tr] = NextLocation;
  496.         funtab[NextLocation].name = STRDUP(temp);
  497.         if (funtab[NextLocation].name == NULL) ErrorOOM();
  498.         funtab[NextLocation].funp = nfunp;
  499.         ++NextLocation;
  500.  
  501.         return 1;
  502. }
  503.  
  504. int CFunctionTable::insertd(const char* name, void(*nfunp) (void)) {
  505.         if ('.' != name[0]) Error("Directive string must start with dot", NULL, FATAL);
  506.         // insert the non-dot variant first, then dot variant
  507.         return Insert(name+1, nfunp) && Insert(name, nfunp);
  508. }
  509.  
  510. int CFunctionTable::zoek(const char* nname) {
  511.         int tr, htr, otr;
  512.         otr = tr = Hash(nname);
  513.         while ((htr = HashTable[tr])) {
  514.                 if (!strcmp((funtab[htr].name), nname)) {
  515.                         (*funtab[htr].funp)();
  516.                         return 1;
  517.                 }
  518.                 if (++tr >= FUNTABSIZE) tr = 0;
  519.                 if (tr == otr) break;
  520.         }
  521.         return 0;
  522. }
  523.  
  524. int CFunctionTable::Find(char* nname) {
  525.         int tr, htr, otr;
  526.         otr = tr = Hash(nname);
  527.         while ((htr = HashTable[tr])) {
  528.                 if (!strcmp((funtab[htr].name), nname)) {
  529.                         return 1;
  530.                 }
  531.                 if (++tr >= FUNTABSIZE) {
  532.                         tr = 0;
  533.                 }
  534.                 if (tr == otr) {
  535.                         break;
  536.                 }
  537.         }
  538.         return 0;
  539. }
  540.  
  541. int CFunctionTable::Hash(const char* s) {
  542.         const char* ss = s;
  543.         unsigned int h = 0;
  544.         for (; *ss != '\0'; ss++) {
  545.                 h = (h << 3) + *ss;
  546.         }
  547.         return h % FUNTABSIZE;
  548. }
  549.  
  550. CLocalLabelTableEntry::CLocalLabelTableEntry(aint number, aint address, CLocalLabelTableEntry* previous) {
  551.         nummer = number;
  552.         value = address;
  553.         prev = previous; next = NULL;
  554.         if (previous) previous->next = this;
  555. }
  556.  
  557. CLocalLabelTable::CLocalLabelTable() {
  558.         first = last = refresh = NULL;
  559. }
  560.  
  561. CLocalLabelTable::~CLocalLabelTable() {
  562.         while (last) {          // release all local labels
  563.                 refresh = last->prev;
  564.                 delete last;
  565.                 last = refresh;
  566.         }
  567. }
  568.  
  569. void CLocalLabelTable::InitPass() {
  570.         // reset refresh pointer for next pass
  571.         refresh = first;
  572. }
  573.  
  574. bool CLocalLabelTable::insertImpl(const aint labelNumber) {
  575.         last = new CLocalLabelTableEntry(labelNumber, CurAddress, last);
  576.         if (!first) first = last;
  577.         return true;
  578. }
  579.  
  580. bool CLocalLabelTable::refreshImpl(const aint labelNumber) {
  581.         if (!refresh || refresh->nummer != labelNumber) return false;
  582.         if (refresh->value != CurAddress) Warning("Local label has different address");
  583.         refresh->value = CurAddress;
  584.         refresh = refresh->next;
  585.         return true;
  586. }
  587.  
  588. bool CLocalLabelTable::InsertRefresh(const aint nnummer) {
  589.         return (1 == pass) ? insertImpl(nnummer) : refreshImpl(nnummer);
  590. }
  591.  
  592. aint CLocalLabelTable::seekForward(const aint labelNumber) const {
  593.         if (1 == pass) return 0;                        // just building tables in first pass, no results yet
  594.         CLocalLabelTableEntry* l = refresh;     // already points on first "forward" local label
  595.         while (l && l->nummer != labelNumber) l = l->next;
  596.         return l ? l->value : -1L;
  597. }
  598.  
  599. aint CLocalLabelTable::seekBack(const aint labelNumber) const {
  600.         if (1 == pass) return 0;                        // just building tables in first pass, no results yet
  601.         CLocalLabelTableEntry* l = refresh ? refresh->prev : last;
  602.         while (l && l->nummer != labelNumber) l = l->prev;
  603.         return l ? l->value : -1L;
  604. }
  605.  
  606. CStringsList::CStringsList() : string(NULL), next(NULL)
  607. {
  608.         // all initialized already
  609. }
  610.  
  611. CStringsList::~CStringsList() {
  612.         if (string) free(string);
  613.         if (next) delete next;
  614. }
  615.  
  616.  
  617. CDefineTableEntry::CDefineTableEntry(const char* nname, const char* nvalue, CStringsList* nnss, CDefineTableEntry* nnext)
  618.                 : name(NULL), value(NULL) {
  619.         name = STRDUP(nname);
  620.         value = new char[strlen(nvalue) + 1];
  621.         if (NULL == name || NULL == value) ErrorOOM();
  622.         char* s1 = value;
  623.         while (White(*nvalue)) ++nvalue;
  624.         while (*nvalue && *nvalue != '\n' && *nvalue != '\r') *s1++ = *nvalue++;
  625.         *s1 = 0;
  626.         next = nnext;
  627.         nss = nnss;
  628. }
  629.  
  630. CDefineTableEntry::~CDefineTableEntry() {
  631.         if (name) free(name);
  632.         if (value) delete[] value;
  633.         if (nss) delete nss;
  634.         if (next) delete next;
  635. }
  636.  
  637. CDefineTable::~CDefineTable() {
  638.         for (auto def : defs) if (def) delete def;
  639. }
  640.  
  641. CDefineTable& CDefineTable::operator=(CDefineTable const & defTable) {
  642.         RemoveAll();
  643.         for (CDefineTableEntry* srcDef : defTable.defs) {
  644.                 CDefineTableEntry* srcD = srcDef;
  645.                 while (srcD) {
  646.                         Add(srcD->name, srcD->value, srcD->nss);
  647.                         srcD = srcD->next;
  648.                 }
  649.         }
  650.         return *this;
  651. }
  652.  
  653. void CDefineTable::Init() {
  654.         DefArrayList = NULL;
  655.         for (auto & def : defs) def = NULL;
  656. }
  657.  
  658. void CDefineTable::Add(const char* name, const char* value, CStringsList* nss) {
  659.         if (FindDuplicate(name)) {
  660.                 Error("Duplicate define (replacing old value)", name);
  661.         }
  662.         defs[(*name)&127] = new CDefineTableEntry(name, value, nss, defs[(*name)&127]);
  663. }
  664.  
  665. static char defineGet__Counter__Buffer[32] = {};
  666. static char defineGet__Line__Buffer[32] = {};
  667.  
  668. char* CDefineTable::Get(const char* name) {
  669.         if (NULL != name) {
  670.                 // the __COUNTER__ and __LINE__ have fully dynamic custom implementation here
  671.                 if ('_' == name[1]) {
  672.                         if (!strcmp(name, "__COUNTER__")) {
  673.                                 SPRINTF1(defineGet__Counter__Buffer, 30, "%d", PredefinedCounter);
  674.                                 ++PredefinedCounter;
  675.                                 return defineGet__Counter__Buffer;
  676.                         }
  677.                         if (!strcmp(name, "__LINE__")) {
  678.                                 SPRINTF1(defineGet__Line__Buffer, 30, "%d", CurSourcePos.line);
  679.                                 return defineGet__Line__Buffer;
  680.                         }
  681.                 }
  682.                 CDefineTableEntry* p = defs[(*name)&127];
  683.                 while (p) {
  684.                         if (!strcmp(name, p->name)) {
  685.                                 DefArrayList = p->nss;
  686.                                 return p->value;
  687.                         }
  688.                         p = p->next;
  689.                 }
  690.         }
  691.         DefArrayList = NULL;
  692.         return NULL;
  693. }
  694.  
  695. int CDefineTable::FindDuplicate(const char* name) {
  696.         CDefineTableEntry* p = defs[(*name)&127];
  697.         while (p) {
  698.                 if (!strcmp(name, p->name)) {
  699.                         return 1;
  700.                 }
  701.                 p = p->next;
  702.         }
  703.         return 0;
  704. }
  705.  
  706. int CDefineTable::Replace(const char* name, const char* value) {
  707.         CDefineTableEntry* p = defs[(*name)&127];
  708.         while (p) {
  709.                 if (!strcmp(name, p->name)) {
  710.                         delete[](p->value);
  711.                         p->value = new char[strlen(value)+1];
  712.                         strcpy(p->value,value);
  713.                         return 0;
  714.                 }
  715.                 p = p->next;
  716.         }
  717.         defs[(*name)&127] = new CDefineTableEntry(name, value, 0, defs[(*name)&127]);
  718.         return 1;
  719. }
  720.  
  721. int CDefineTable::Replace(const char* name, const int value) {
  722.         char newIntValue[24];
  723.         SPRINTF1(newIntValue, sizeof(newIntValue), "%d", value);
  724.         return Replace(name, newIntValue);
  725. }
  726.  
  727. int CDefineTable::Remove(const char* name) {
  728.         CDefineTableEntry* p = defs[(*name)&127];
  729.         CDefineTableEntry* p2 = NULL;
  730.         while (p) {
  731.                 if (!strcmp(name, p->name)) {
  732.                         // unchain the particular item
  733.                         if (NULL == p2) defs[(*name)&127] = p->next;
  734.                         else                    p2->next = p->next;
  735.                         p->next = NULL;
  736.                         // delete it
  737.                         delete p;
  738.                         DefArrayList = NULL;            // may be invalid here, so just reset it
  739.                         return 1;
  740.                 }
  741.                 p2 = p;
  742.                 p = p->next;
  743.         }
  744.         return 0;
  745. }
  746.  
  747. void CDefineTable::RemoveAll() {
  748.         DefArrayList = NULL;
  749.         for (auto & def : defs) {
  750.                 if (!def) continue;
  751.                 delete def;
  752.                 def = NULL;
  753.         }
  754. }
  755.  
  756. CMacroDefineTable::CMacroDefineTable() : defs(nullptr) {
  757.         for (auto & usedX : used) usedX = false;
  758. }
  759.  
  760. CMacroDefineTable::~CMacroDefineTable() {
  761.         if (defs) delete defs;
  762. }
  763.  
  764. void CMacroDefineTable::ReInit() {
  765.         if (defs) delete defs;
  766.         defs = nullptr;
  767.         for (auto & usedX : used) usedX = false;
  768. }
  769.  
  770. void CMacroDefineTable::AddMacro(char* naam, char* vervanger) {
  771.         CDefineTableEntry* tmpdefs = new CDefineTableEntry(naam, vervanger, 0, defs);
  772.         defs = tmpdefs;
  773.         used[(*naam)&127] = true;
  774. }
  775.  
  776. CDefineTableEntry* CMacroDefineTable::getdefs() {
  777.         return defs;
  778. }
  779.  
  780. void CMacroDefineTable::setdefs(CDefineTableEntry* const ndefs) {
  781.         if (ndefs == defs) return;                      // the current HEAD of defines is already same as requested one
  782.         // traverse through current HEAD until the requested chain is found, unchain the HEAD from it
  783.         CDefineTableEntry* entry = defs;
  784.         while (entry && ndefs != entry->next) entry = entry->next;
  785.         if (entry) entry->next = nullptr;       // if "ndefs" is chained to current HEAD, unchain
  786.         if (defs) delete defs;                          // release front part of current chain from memory
  787.         defs = ndefs;                                           // the requested chain is new current HEAD
  788. }
  789.  
  790. char* CMacroDefineTable::getverv(char* name) {
  791.         CDefineTableEntry* p = defs;
  792.         if (!used[(*name)&127]) return NULL;
  793.         while (p) {
  794.                 if (!strcmp(name, p->name)) return p->value;
  795.                 p = p->next;
  796.         }
  797.         return NULL;
  798. }
  799.  
  800. int CMacroDefineTable::FindDuplicate(char* name) {
  801.         CDefineTableEntry* p = defs;
  802.         if (!used[(*name)&127]) {
  803.                 return 0;
  804.         }
  805.         while (p) {
  806.                 if (!strcmp(name, p->name)) {
  807.                         return 1;
  808.                 }
  809.                 p = p->next;
  810.         }
  811.         return 0;
  812. }
  813.  
  814. CStringsList::CStringsList(const char* stringSource, CStringsList* nnext) {
  815.         string = STRDUP(stringSource);
  816.         next = nnext;
  817.         source = CurSourcePos;
  818.         definition = DefinitionPos.line ? DefinitionPos : CurSourcePos;
  819. }
  820.  
  821. CMacroTableEntry::CMacroTableEntry(char* nnaam, CMacroTableEntry* nnext) {
  822.         naam = nnaam; next = nnext; args = body = NULL;
  823. }
  824.  
  825. CMacroTableEntry::~CMacroTableEntry() {
  826.         if (naam) free(naam);   // must be of STRDUP origin!
  827.         if (args) delete args;
  828.         if (body) delete body;
  829.         if (next) delete next;
  830. }
  831.  
  832. CMacroTable::CMacroTable() : macs(nullptr) {
  833.         for (auto & usedX : used) usedX = false;
  834. }
  835.  
  836. CMacroTable::~CMacroTable() {
  837.         if (macs) delete macs;
  838. }
  839.  
  840. void CMacroTable::ReInit() {
  841.         if (macs) delete macs;
  842.         macs = nullptr;
  843.         for (auto & usedX : used) usedX = false;
  844. }
  845.  
  846. int CMacroTable::FindDuplicate(char* naam) {
  847.         CMacroTableEntry* p = macs;
  848.         if (!used[(*naam)&127]) {
  849.                 return 0;
  850.         }
  851.         while (p) {
  852.                 if (!strcmp(naam, p->naam)) {
  853.                         return 1;
  854.                 }
  855.                 p = p->next;
  856.         }
  857.         return 0;
  858. }
  859.  
  860. void CMacroTable::Add(char* nnaam, char*& p) {
  861.         char* n;
  862.         CStringsList* s,* l = NULL,* f = NULL;
  863.         if (FindDuplicate(nnaam)) {
  864.                 Error("Duplicate macroname", nnaam);return;
  865.         }
  866.         char* macroname = STRDUP(nnaam);
  867.         if (macroname == NULL) ErrorOOM();
  868.         macs = new CMacroTableEntry(macroname, macs);
  869.         used[(*macroname)&127] = true;
  870.         SkipBlanks(p);
  871.         while (*p) {
  872.                 if (!(n = GetID(p))) {
  873.                         Error("Illegal macro argument", p, EARLY); break;
  874.                 }
  875.                 s = new CStringsList(n); if (!f) {
  876.                                                                                 f = s;
  877.                                                                           } if (l) {
  878.                                                                                         l->next = s;
  879.                                                                                 } l = s;
  880.                 SkipBlanks(p); if (*p == ',') {
  881.                                                 ++p;
  882.                                            } else {
  883.                                                 break;
  884.                                            }
  885.         }
  886.         macs->args = f;
  887.         if (*p) {
  888.                 Error("Unexpected", p, EARLY);
  889.         }
  890.         ListFile();
  891.         if (!ReadFileToCStringsList(macs->body, "endm")) {
  892.                 Error("Unexpected end of macro", NULL, EARLY);
  893.         }
  894. }
  895.  
  896. int CMacroTable::Emit(char* naam, char*& p) {
  897.         // search for the desired macro
  898.         if (!used[(*naam)&127]) return 0;
  899.         CMacroTableEntry* m = macs;
  900.         while (m && strcmp(naam, m->naam)) m = m->next;
  901.         if (!m) return 0;
  902.         // macro found, emit it, prepare temporary instance label base
  903.         char* omacrolabp = macrolabp;
  904.         char labnr[LINEMAX], ml[LINEMAX];
  905.         SPRINTF1(labnr, LINEMAX, "%d", macronummer++);
  906.         macrolabp = labnr;
  907.         if (omacrolabp) {
  908.                 STRCAT(macrolabp, LINEMAX-1, "."); STRCAT(macrolabp, LINEMAX-1, omacrolabp);
  909.         } else {
  910.                 MacroDefineTable.ReInit();
  911.         }
  912.         // parse argument values
  913.         CDefineTableEntry* odefs = MacroDefineTable.getdefs();
  914.         CStringsList* a = m->args;
  915.         while (a) {
  916.                 char* n = ml;
  917.                 const bool lastArg = NULL == a->next;
  918.                 if (!GetMacroArgumentValue(p, n) || (!lastArg && !comma(p))) {
  919.                         Error("Not enough arguments for macro", naam, SUPPRESS);
  920.                         macrolabp = 0;
  921.                         return 1;
  922.                 }
  923.                 MacroDefineTable.AddMacro(a->string, ml);
  924.                 a = a->next;
  925.         }
  926.         SkipBlanks(p);
  927.         if (*p) {
  928.                 Error("Too many arguments for macro", naam, SUPPRESS);
  929.                 macrolabp = 0;
  930.                 return 1;
  931.         }
  932.         // arguments parsed, emit the macro lines and parse them
  933.         lp = p;
  934.         ListFile();
  935.         ++listmacro;
  936.         CStringsList* olijstp = lijstp;
  937.         lijstp = m->body;
  938.         ++lijst;
  939.         STRCPY(ml, LINEMAX, line);
  940.         while (lijstp) {
  941.                 DefinitionPos = lijstp->definition;
  942.                 STRCPY(line, LINEMAX, lijstp->string);
  943.                 substitutedLine = line;         // reset substituted listing
  944.                 eolComment = NULL;                      // reset end of line comment
  945.                 lijstp = lijstp->next;
  946.                 ParseLineSafe();
  947.         }
  948.         DefinitionPos = TextFilePos();
  949.         STRCPY(line, LINEMAX, ml);
  950.         lijstp = olijstp;
  951.         --lijst;
  952.         MacroDefineTable.setdefs(odefs);
  953.         macrolabp = omacrolabp;
  954.         --listmacro; donotlist = 1;
  955.         return 2;
  956. }
  957.  
  958. CStructureEntry1::CStructureEntry1(char* nnaam, aint noffset) {
  959.         next = 0;
  960.         naam = STRDUP(nnaam);
  961.         if (naam == NULL) ErrorOOM();
  962.         offset = noffset;
  963. }
  964.  
  965. CStructureEntry1::~CStructureEntry1() {
  966.         free(naam);
  967.         if (next) delete next;
  968. }
  969.  
  970.  
  971. CStructureEntry2::CStructureEntry2(aint noffset, aint nlen, aint ndef, EStructureMembers ntype) {
  972.         next = 0; offset = noffset; len = nlen; def = ndef; type = ntype;
  973. }
  974.  
  975. CStructureEntry2::~CStructureEntry2() {
  976.         if (next) delete next;
  977. }
  978.  
  979. // Parses source input for types: BYTE, WORD, DWORD, D24
  980. aint CStructureEntry2::ParseValue(char* & p) {
  981.         if (SMEMBBYTE != type && SMEMBWORD != type && SMEMBDWORD != type && SMEMBD24 != type) return def;
  982.         SkipBlanks(p);
  983.         if ('{' == *p) return def;      // unexpected {
  984.         aint val;
  985.         if (!ParseExpressionNoSyntaxError(p, val)) val = def;
  986.         switch (type) {
  987.                 case SMEMBBYTE:
  988.                         check8(val);
  989.                         return(val & 0xFF);
  990.                 case SMEMBWORD:
  991.                         check16(val);
  992.                         return(val & 0xFFFF);
  993.                 case SMEMBD24:
  994.                         check24(val);
  995.                         return(val & 0xFFFFFF);
  996.                 case SMEMBDWORD:
  997.                         return val;
  998.                 default:
  999.                         return def;
  1000.         }
  1001. }
  1002.  
  1003. CStructure::CStructure(const char* nnaam, char* nid, int no, int ngl, CStructure* p) {
  1004.         mnf = mnl = NULL; mbf = mbl = NULL;
  1005.         naam = STRDUP(nnaam);
  1006.         if (naam == NULL) ErrorOOM();
  1007.         id = STRDUP(nid);
  1008.         if (id == NULL) ErrorOOM();
  1009.         next = p; noffset = no; global = ngl;
  1010.         maxAlignment = 0;
  1011. }
  1012.  
  1013. CStructure::~CStructure() {
  1014.         free(naam);
  1015.         free(id);
  1016.         if (mnf) delete mnf;
  1017.         if (mbf) delete mbf;
  1018.         if (next) delete next;
  1019. }
  1020.  
  1021. void CStructure::AddLabel(char* nnaam) {
  1022.         CopyLabel(nnaam, 0);
  1023. }
  1024.  
  1025. void CStructure::AddMember(CStructureEntry2* n) {
  1026.         if (!mbf)       mbf = n;
  1027.         else            mbl->next = n;
  1028.         mbl = n;
  1029.         noffset += n->len;
  1030. }
  1031.  
  1032. void CStructure::CopyLabel(char* nnaam, aint offset) {
  1033.         CStructureEntry1* n = new CStructureEntry1(nnaam, noffset + offset);
  1034.         if (!mnf)       mnf = n;
  1035.         else            mnl->next = n;
  1036.         mnl = n;
  1037. }
  1038.  
  1039. void CStructure::CopyLabels(CStructure* st) {
  1040.         CStructureEntry1* np = st->mnf;
  1041.         if (!np || !PreviousIsLabel) return;
  1042.         char str[LINEMAX];
  1043.         STRCPY(str, LINEMAX-1, PreviousIsLabel);
  1044.         STRCAT(str, LINEMAX-1, ".");
  1045.         char * const stw = str + strlen(str);
  1046.         while (np) {
  1047.                 STRCPY(stw, LINEMAX, np->naam); // overwrite the second part of label
  1048.                 CopyLabel(str, np->offset);
  1049.                 np = np->next;
  1050.         }
  1051. }
  1052.  
  1053. void CStructure::CopyMember(CStructureEntry2* ni, aint ndef) {
  1054.         AddMember(new CStructureEntry2(noffset, ni->len, ndef, ni->type));
  1055. }
  1056.  
  1057. void CStructure::CopyMembers(CStructure* st, char*& lp) {
  1058.         aint val;
  1059.         int haakjes = 0;
  1060.         AddMember(new CStructureEntry2(noffset, 0, 0, SMEMBPARENOPEN));
  1061.         SkipBlanks(lp);
  1062.         if (*lp == '{') {
  1063.                 ++haakjes; ++lp;
  1064.         }
  1065.         CStructureEntry2* ip = st->mbf;
  1066.         while (ip) {
  1067.                 switch (ip->type) {
  1068.                 case SMEMBBLOCK:
  1069.                         CopyMember(ip, ip->def);
  1070.                         break;
  1071.                 case SMEMBBYTE:
  1072.                 case SMEMBWORD:
  1073.                 case SMEMBD24:
  1074.                 case SMEMBDWORD:
  1075.                         if (!ParseExpressionNoSyntaxError(lp, val)) val = ip->def;
  1076.                         CopyMember(ip, val);
  1077.                         if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(lp);
  1078.                         break;
  1079.                 case SMEMBPARENOPEN:
  1080.                         SkipBlanks(lp);
  1081.                         if (*lp == '{') {
  1082.                                 ++haakjes; ++lp;
  1083.                         }
  1084.                         CopyMember(ip, 0);
  1085.                         break;
  1086.                 case SMEMBPARENCLOSE:
  1087.                         SkipBlanks(lp);
  1088.                         if (haakjes && *lp == '}') {
  1089.                                 --haakjes; ++lp;
  1090.                                 if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(lp);
  1091.                         }
  1092.                         CopyMember(ip, 0);
  1093.                         break;
  1094.                 default:
  1095.                         Error("internalerror CStructure::CopyMembers", NULL, FATAL);
  1096.                 }
  1097.                 ip = ip->next;
  1098.         }
  1099.         while (haakjes--) {
  1100.                 if (!need(lp, '}')) Error("closing } missing");
  1101.         }
  1102.         AddMember(new CStructureEntry2(noffset, 0, 0, SMEMBPARENCLOSE));
  1103. }
  1104.  
  1105. static void InsertSingleStructLabel(char *name, const aint value) {
  1106.         char *op = name, *p;
  1107.         if (!(p = ValidateLabel(op, true))) {
  1108.                 Error("Illegal labelname", op, EARLY);
  1109.                 return;
  1110.         }
  1111.         if (pass == LASTPASS) {
  1112.                 aint oval;
  1113.                 if (!GetLabelValue(op, oval)) {
  1114.                         Error("Internal error. ParseLabel()", op, FATAL);
  1115.                 }
  1116.                 if (value != oval) {
  1117.                         Error("Label has different value in pass 2", p);
  1118.                 }
  1119.         } else {
  1120.                 if (!LabelTable.Insert(p, value, false, false, true)) Error("Duplicate label", p, EARLY);
  1121.         }
  1122.         delete[] p;
  1123. }
  1124.  
  1125. static void InsertStructSubLabels(const char* mainName, const CStructureEntry1* members, const aint address = 0) {
  1126.         char ln[LINEMAX+1];
  1127.         STRCPY(ln, LINEMAX, mainName);
  1128.         char * const lnsubw = ln + strlen(ln);
  1129.         while (members) {
  1130.                 STRCPY(lnsubw, LINEMAX-strlen(ln), members->naam);              // overwrite sub-label part
  1131.                 InsertSingleStructLabel(ln, members->offset + address);
  1132.                 members = members->next;
  1133.         }
  1134. }
  1135.  
  1136. void CStructure::deflab() {
  1137.         char sn[LINEMAX] = { '@' };
  1138.         STRCPY(sn+1, LINEMAX-1, id);
  1139.         InsertSingleStructLabel(sn, noffset);
  1140.         STRCAT(sn, LINEMAX-1, ".");
  1141.         InsertStructSubLabels(sn, mnf);
  1142. }
  1143.  
  1144. void CStructure::emitlab(char* iid, aint address) {
  1145.         const aint misalignment = maxAlignment ? ((-address) & (maxAlignment - 1)) : 0;
  1146.         if (misalignment) {
  1147.                 // emitting in misaligned position (considering the ALIGN used to define this struct)
  1148.                 char warnTxt[LINEMAX];
  1149.                 SPRINTF3(warnTxt, LINEMAX,
  1150.                                         "Struct %s did use ALIGN %d in definition, but here it is misaligned by %d bytes",
  1151.                                         naam, maxAlignment, misalignment);
  1152.                 Warning(warnTxt);
  1153.         }
  1154.         char sn[LINEMAX];
  1155.         STRCPY(sn, LINEMAX-1, iid);
  1156.         InsertSingleStructLabel(sn, address);
  1157.         STRCAT(sn, LINEMAX-1, ".");
  1158.         InsertStructSubLabels(sn, mnf, address);
  1159. }
  1160.  
  1161. void CStructure::emitmembs(char*& p) {
  1162.         aint val;
  1163.         int haakjes = 0;
  1164.         SkipBlanks(p);
  1165.         if (*p == '{') {
  1166.                 ++haakjes; ++p;
  1167.         }
  1168.         CStructureEntry2* ip = mbf;
  1169.         while (ip) {
  1170.                 switch (ip->type) {
  1171.                 case SMEMBBLOCK:
  1172.                         EmitBlock(ip->def != -1 ? ip->def : 0, ip->len, ip->def == -1, 8);
  1173.                         break;
  1174.                 case SMEMBBYTE:
  1175.                         EmitByte(ip->ParseValue(p));
  1176.                         if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
  1177.                         break;
  1178.                 case SMEMBWORD:
  1179.                         EmitWord(ip->ParseValue(p));
  1180.                         if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
  1181.                         break;
  1182.                 case SMEMBD24:
  1183.                         val = ip->ParseValue(p);
  1184.                         EmitByte(val & 0xFF);
  1185.                         EmitWord((val>>8) & 0xFFFF);
  1186.                         if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
  1187.                         break;
  1188.                 case SMEMBDWORD:
  1189.                         val = ip->ParseValue(p);
  1190.                         EmitWord(val & 0xFFFF);
  1191.                         EmitWord((val>>16) & 0xFFFF);
  1192.                         if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
  1193.                         break;
  1194.                 case SMEMBPARENOPEN:
  1195.                         SkipBlanks(p);
  1196.                         if (*p == '{') { ++haakjes; ++p; }
  1197.                         break;
  1198.                 case SMEMBPARENCLOSE:
  1199.                         SkipBlanks(p);
  1200.                         if (haakjes && *p == '}') {
  1201.                                 --haakjes; ++p;
  1202.                         }
  1203.                         if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
  1204.                         break;
  1205.                 default:
  1206.                         ErrorInt("Internal Error CStructure::emitmembs", ip->type, FATAL);
  1207.                 }
  1208.                 ip = ip->next;
  1209.         }
  1210.         while (haakjes--) {
  1211.                 if (!need(p, '}')) Error("closing } missing");
  1212.         }
  1213.         if (!SkipBlanks(p)) Error("[STRUCT] Syntax error - too many arguments?");
  1214. }
  1215.  
  1216. CStructureTable::CStructureTable() {
  1217.         for (auto & structPtr : strs) structPtr = nullptr;
  1218. }
  1219.  
  1220. CStructureTable::~CStructureTable() {
  1221.         for (auto structPtr : strs) if (structPtr) delete structPtr;
  1222. }
  1223.  
  1224. void CStructureTable::ReInit() {
  1225.         for (auto & structPtr : strs) {
  1226.                 if (structPtr) delete structPtr;
  1227.                 structPtr = nullptr;
  1228.         }
  1229. }
  1230.  
  1231. CStructure* CStructureTable::Add(char* naam, int no, int gl) {
  1232.         char sn[LINEMAX], * sp;
  1233.         sn[0] = 0;
  1234.         if (!gl && *ModuleName) {
  1235.                 STRCPY(sn, LINEMAX-2, ModuleName);
  1236.                 STRCAT(sn, 2, ".");
  1237.         }
  1238.         STRCAT(sn, LINEMAX-1, naam);
  1239.         sp = sn;
  1240.         if (FindDuplicate(sp)) {
  1241.                 Error("Duplicate structure name", naam, EARLY);
  1242.         }
  1243.         strs[(*sp)&127] = new CStructure(naam, sp, 0, gl, strs[(*sp)&127]);
  1244.         if (no) {
  1245.                 strs[(*sp)&127]->AddMember(new CStructureEntry2(0, no, -1, SMEMBBLOCK));
  1246.         }
  1247.         return strs[(*sp)&127];
  1248. }
  1249.  
  1250. CStructure* CStructureTable::zoek(const char* naam, int gl) {
  1251.         char sn[LINEMAX], * sp;
  1252.         sn[0] = 0;
  1253.         if (!gl && *ModuleName) {
  1254.                 STRCPY(sn, LINEMAX-2, ModuleName);
  1255.                 STRCAT(sn, 2, ".");
  1256.         }
  1257.         STRCAT(sn, LINEMAX-1, naam);
  1258.         sp = sn;
  1259.         CStructure* p = strs[(*sp)&127];
  1260.         while (p) {
  1261.                 if (!strcmp(sp, p->id)) return p;
  1262.                 p = p->next;
  1263.         }
  1264.         if (gl || ! *ModuleName) return NULL;
  1265.         sp += 1 + strlen(ModuleName); p = strs[(*sp)&127];
  1266.         while (p) {
  1267.                 if (!strcmp(sp, p->id)) return p;
  1268.                 p = p->next;
  1269.         }
  1270.         return NULL;
  1271. }
  1272.  
  1273. int CStructureTable::FindDuplicate(char* naam) {
  1274.         CStructure* p = strs[(*naam)&127];
  1275.         while (p) {
  1276.                 if (!strcmp(naam, p->naam)) return 1;
  1277.                 p = p->next;
  1278.         }
  1279.         return 0;
  1280. }
  1281.  
  1282. aint CStructureTable::ParseDesignedAddress(char* &p) {
  1283.         if (!SkipBlanks(p) && ('=' == *p)) {
  1284.                 char* adrP = ++p;
  1285.                 aint resultAdr;
  1286.                 if (ParseExpressionNoSyntaxError(p, resultAdr)) return resultAdr;
  1287.                 Error("[STRUCT] Syntax error in designed address", adrP, SUPPRESS);
  1288.                 return 0;
  1289.         }
  1290.         return INT_MAX;         // no "designed address" provided, emit structure bytes
  1291. }
  1292.  
  1293. int CStructureTable::Emit(char* naam, char* l, char*& p, int gl) {
  1294.         CStructure* st = zoek(naam, gl);
  1295.         if (!st) return 0;
  1296.         // create new labels corresponding to current/designed address
  1297.         aint address = CStructureTable::ParseDesignedAddress(p);
  1298.         if (l) st->emitlab(l, (INT_MAX == address) ? CurAddress : address);
  1299.         if (INT_MAX == address) st->emitmembs(p);       // address was not designed, emit also bytes
  1300.         else if (!l) Warning("[STRUCT] designed address without label = no effect");
  1301.         return 1;
  1302. }
  1303.  
  1304. int LuaGetLabel(char *name) {
  1305.         //TODO v2.0: deprecated, use default "calculate" feature to get identical results as asm line
  1306.         aint val;
  1307.         if (!GetLabelValue(name, val)) val = -1;
  1308.         return val;
  1309. }
  1310.  
  1311. //eof tables.cpp
  1312.