• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

z00m128 / sjasmplus / 26128377223

19 May 2026 10:10PM UTC coverage: 97.798% (+0.5%) from 97.312%
26128377223

push

github

ped7g
CI: try switch to lcov for coverage

10128 of 10356 relevant lines covered (97.8%)

172537.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.75
/sjasm/tables.cpp
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 "sjdefs.h"
32

33
TextFilePos::TextFilePos(const char* fileNamePtr, uint32_t line) : filename(fileNamePtr), line(line), colBegin(0), colEnd(0) {
249,113✔
34
}
249,113✔
35

36
void TextFilePos::newFile(const char* fileNamePtr) {
368✔
37
        filename = fileNamePtr;
368✔
38
        line = colBegin = colEnd = 0;
368✔
39
}
368✔
40

41
// advanceColumns are valid only when true == endsWithColon (else advanceColumns == 0)
42
// default arguments are basically "next line"
43
void TextFilePos::nextSegment(bool endsWithColon, size_t advanceColumns) {
666,587✔
44
        if (endsWithColon && 0 == colEnd) colEnd = 1;        // first segment of "colonized" line (do +1,+1)
666,587✔
45
        colBegin = colEnd;
666,587✔
46
        if (colBegin <= 1) ++line;                // first segment of any line, increment also line number
666,587✔
47
        if (endsWithColon)        colEnd += advanceColumns;
666,587✔
48
        else                                colEnd = 0;
655,463✔
49
}
666,587✔
50

51
std::string vorlab;
52

53
void InitVorlab() {
2,081✔
54
        if (ModuleName[0]) {
2,081✔
55
                vorlab = ModuleName; vorlab += "._";
273✔
56
        } else {
57
                vorlab = "_";
1,808✔
58
        }
59
}
2,081✔
60

61
char* PreviousIsLabel = nullptr;
62

63
// since v1.18.0:
64
// The ignore invalid char after feature disconnected from "setNameSpace" to "ignoreCharAfter"
65
// (it's for evaluating labels straight from the expressions, without copying them out first)
66
// The prefix "!" is now recognized as "do not set main label" for following local labels
67
// since v1.18.3:
68
// Inside macro prefix "@." will create non-macro local label instead of macro's instance
69
char* ValidateLabel(bool & local, const char* naam, bool setNameSpace, bool ignoreCharAfter) {
1,123,087✔
70
        local = false;
1,123,087✔
71
        if (nullptr == naam || 0 == *naam || White(naam[0])) {
1,123,087✔
72
                Error("Invalid (blank) labelname");
19✔
73
                return nullptr;
19✔
74
        }
75
        if ('!' == *naam) {
1,123,068✔
76
                setNameSpace = false;
65✔
77
                ++naam;
65✔
78
        }
79
        // check if local label defined inside macro wants to become non-macro local label
80
        const bool escMacro = setNameSpace && macrolabp && ('@' == naam[0]) && ('.' == naam[1]);
1,123,068✔
81
        if (escMacro) ++naam;                        // such extra "@" is consumed right here and only '.' is left
1,123,068✔
82
        // regular single prefix case in other use cases
83
        const bool global = ('@' == *naam);
1,123,068✔
84
        local = ('.' == *naam);
1,123,068✔
85
        if (!isLabelStart(naam)) {                // isLabelStart assures that only single modifier exist
1,123,068✔
86
                if (global || local) ++naam;// single modifier is parsed (even when invalid name)
86✔
87
                Error("Invalid character at start of labelname", naam, SUPPRESS);
86✔
88
                return nullptr;
86✔
89
        }
90
        if (global || local) ++naam;        // single modifier is parsed
1,122,982✔
91
        const bool inMacro = !escMacro && local && macrolabp;
1,122,982✔
92
        const bool inModule = !inMacro && !global && !local && ModuleName[0];
1,122,982✔
93
        // check all chars of label
94
        const char* np = naam;
1,122,982✔
95
        while (islabchar(*np)) ++np;
5,088,143✔
96
        if ('[' == *np) return nullptr;        // this is DEFARRAY name, do not process it as label (silent exit)
1,122,982✔
97
        if (*np && !ignoreCharAfter) {
1,122,832✔
98
                // if this is supposed to be new label, there shoulnd't be anything else after it
99
                Error("Invalid character after labelname", naam, SUPPRESS);
15✔
100
                return nullptr;
15✔
101
        }
102
        // calculate expected length of fully qualified label name
103
        int labelLen = (np - naam), truncateAt = LABMAX;
1,122,817✔
104
        if (LABMAX < labelLen) Error("Label too long", naam, IF_FIRST);        // non-fatal error, will truncate it
1,122,817✔
105
        if (inMacro) labelLen += 1 + strlen(macrolabp);
1,122,817✔
106
        else if (local) labelLen += 1 + vorlab.size();
1,114,823✔
107
        if (inModule) labelLen += 1 + strlen(ModuleName);
1,122,817✔
108
        // build fully qualified label name (in newly allocated memory buffer, with precise length)
109
        char* const label = new char[1+labelLen];
1,122,817✔
110
        if (nullptr == label) ErrorOOM();
1,122,817✔
111
        label[0] = 0;
1,122,817✔
112
        if (inModule) {                // false when `local` so doesn't double with vorlab content
1,122,817✔
113
                STRCAT(label, labelLen, ModuleName);                STRCAT(label, 2, ".");
1,587✔
114
        }
115
        if (inMacro) {
1,122,817✔
116
                STRCAT(label, labelLen, macrolabp);                        STRCAT(label, 2, ">");
7,994✔
117
        } else if (local) {
1,114,823✔
118
                STRCAT(label, labelLen, vorlab.c_str());        STRCAT(label, 2, ".");
2,164✔
119
        }
120
        char* lp = label + strlen(label);
1,122,817✔
121
        while (truncateAt-- && islabchar(*naam)) *lp++ = *naam++;        // add the new label (truncated if needed)
5,080,778✔
122
        *lp = 0;
1,122,817✔
123
        if (labelLen < lp - label) Error("internal error", nullptr, FATAL);                // should never happen :)
1,122,817✔
124
        if (setNameSpace && !local) vorlab = label;
1,122,817✔
125
        return label;
1,122,817✔
126
}
127

128
char* ValidateLabel(const char* naam, bool setNameSpace, bool ignoreCharAfter) {
753,090✔
129
        bool discardIsLocal;
130
        return ValidateLabel(discardIsLocal, naam, setNameSpace, ignoreCharAfter);
1,506,180✔
131
}
132

133
static char sldLabelExport[2*LINEMAX];
134

135
char* ExportLabelToSld(const char* naam, const SLabelTableEntry* label) {
292✔
136
        // does re-parse the original source line again similarly to ValidateLabel
137
        // but prepares SLD 'L'-type line, with module/main/local comma separated + usage traits info
138
        assert(nullptr != label);
292✔
139
        // check if this is setting namespace
140
        bool setNameSpace = ('!' != *naam);
292✔
141
        if (!setNameSpace) ++naam;
292✔
142
        // check if local label defined inside macro wants to become non-macro local label
143
        const bool escMacro = setNameSpace && macrolabp && ('@' == naam[0]) && ('.' == naam[1]);
292✔
144
        if (escMacro) ++naam;                        // such extra "@" is consumed right here and only '.' is left
292✔
145
        assert(isLabelStart(naam));                // this should be called only when ValidateLabel did succeed
292✔
146
        const bool global = '@' == *naam;
292✔
147
        const bool local = '.' == *naam;
292✔
148
        if (global || local) ++naam;        // single modifier is parsed
292✔
149
        const auto modNameSz = strlen(ModuleName);
292✔
150
        const bool inMacro = !escMacro && local && macrolabp;
292✔
151
        // struct def full name "@" global marker is not part of "naam" here, deduct it from matching against ModuleName (if any)
152
        const bool globalStructDef = (label->traits & LABEL_IS_STRUCT_D) && (strncmp(ModuleName, naam, modNameSz) || ('.' != naam[modNameSz]));
292✔
153
        const bool inModule = !inMacro && !global && modNameSz && !globalStructDef;
292✔
154
        const bool isStructLabel = (label->traits & (LABEL_IS_STRUCT_D|LABEL_IS_STRUCT_E));
292✔
155
        // build fully qualified SLD info
156
        sldLabelExport[0] = 0;
292✔
157
        // module part
158
        if (inModule) STRCAT(sldLabelExport, LINEMAX, ModuleName);
292✔
159
        STRCAT(sldLabelExport, 2, ",");
292✔
160
        // main label part (the `vorlab` is already the current label, if it was main label)
161
        // except for structure labels: the inner ones don't "set namespace" == vorlab, use "naam" then
162
        // (but only if the main label of structure itself is not local, if it's local, use vorlab)
163
        const char* mainLabel = isStructLabel && !local ? naam : inMacro ? macrolabp : vorlab.data();
292✔
164
        if (!setNameSpace) mainLabel = naam;
292✔
165
        if ((vorlab.data() == mainLabel || isStructLabel) && modNameSz) {        // vorlab may contain module part, skip it then
292✔
166
                if (0 == strncmp(ModuleName, mainLabel, modNameSz)) mainLabel += modNameSz + 1;
87✔
167
        }
168
        STRCAT(sldLabelExport, LABMAX, mainLabel);
292✔
169
        STRCAT(sldLabelExport, 2, ",");
292✔
170
        // local part
171
        if (local) STRCAT(sldLabelExport, LABMAX, naam);
292✔
172
        assert(local == !!(label->traits&LABEL_IS_LOCAL));
292✔
173
        // usage traits
174
        if (label->traits&LABEL_IS_LOCAL) STRCAT(sldLabelExport, 20, ",+local");
292✔
175
        if (label->traits&LABEL_IS_EQU) STRCAT(sldLabelExport, 20, ",+equ");
292✔
176
        if (inMacro) STRCAT(sldLabelExport, 20, ",+macro");
292✔
177
        if (label->traits&LABEL_IS_SMC) STRCAT(sldLabelExport, 20, ",+smc");
292✔
178
        if (Relocation::REGULAR == label->isRelocatable) STRCAT(sldLabelExport, 20, ",+reloc");
292✔
179
        if (Relocation::HIGH == label->isRelocatable) STRCAT(sldLabelExport, 20, ",+reloc_high");
292✔
180
        if (label->used) STRCAT(sldLabelExport, 20, ",+used");
292✔
181
        if (label->traits&LABEL_IS_STRUCT_D) STRCAT(sldLabelExport, 20, ",+struct_def");
292✔
182
        if (label->traits&LABEL_IS_STRUCT_E) STRCAT(sldLabelExport, 20, ",+struct_data");
292✔
183
        if (label->traits&LABEL_HAS_SIZE) STRCAT(sldLabelExport, 20, ",+sizeof");
292✔
184
        return sldLabelExport;
292✔
185
}
186

187
char* ExportModuleToSld(bool endModule) {
10✔
188
        assert(ModuleName[0]);
10✔
189
        STRNCPY(sldLabelExport, 2*LINEMAX, ModuleName, LINEMAX);
10✔
190
        STRCAT(sldLabelExport, LINEMAX-1, endModule ? ",,,+endmod" : ",,,+module");
10✔
191
        return sldLabelExport;
10✔
192
}
193

194
static bool getLabel_invalidName = false;
195

196
// does parse + consume input source at "p" (and stores result into "fullName")
197
//  ^^^ may report invalid label name error
198
// does search (and only search) LabelTable for various variants of label based on "fullName"
199
// No refresh of "used", no inserting into table when not found, no other errrors reported
200
// Leaves canonical name in "temp" global variable, if this is inside macro
201
// returns table entry, preferring the one with "page defined", if multiple entries are found
202
static SLabelTableEntry* SearchLabel(char*& p, bool setUsed, /*out*/ std::unique_ptr<char[]>& fullName) {
751,953✔
203
        getLabel_invalidName = true;
751,953✔
204
        fullName.reset(ValidateLabel(p, false, true));
751,953✔
205
        if (!fullName) return nullptr;
751,953✔
206
        getLabel_invalidName = false;
751,779✔
207
        const bool global = '@' == *p;
751,779✔
208
        const bool local = '.' == *p;
751,779✔
209
        while (islabchar(*p)) ++p;                // advance pointer beyond the parsed label
3,394,889✔
210
        // find the label entry in the label table (for local macro labels it has to try all sub-parts!)
211
        // then regular full label has to be tried
212
        // and if it's regular non-local in module, then variant w/o current module has to be tried
213
        bool inMacro = local && macrolabp;                // not just inside macro, but should be prefixed
751,779✔
214
        const int modNameLen = strlen(ModuleName);
751,779✔
215
        const char *findName = fullName.get();
751,779✔
216
        SLabelTableEntry* undefinedLabelEntry = nullptr;
751,779✔
217
        SLabelTableEntry* labelEntry = nullptr;
751,779✔
218
        temp[0] = 0;
751,779✔
219
        do {
220
                labelEntry = LabelTable.Find(findName);
752,086✔
221
                if (labelEntry) {
752,086✔
222
                        if (setUsed && pass < LASTPASS) labelEntry->used = true;
748,161✔
223
                        if (LABEL_PAGE_UNDEFINED != labelEntry->page) return labelEntry;        // found
748,161✔
224
                        // if found, but "undefined" one, remember it as fall-back result
225
                        undefinedLabelEntry = labelEntry;
3,661✔
226
                        labelEntry = nullptr;
3,661✔
227
                }
228
                // not found (the defined one, try more variants)
229
                if (inMacro) {                                // try outer macro (if there is one)
7,586✔
230
                        while ('>' != *findName && '.' != *findName) ++findName;
104✔
231
                        // if no more outer macros, try module+non-local prefix with the original local label
232
                        if ('>' == *findName++) {
50✔
233
                                inMacro = false;
40✔
234
                                STRCAT(temp, LABMAX-1, vorlab.c_str()); STRCAT(temp, 2, ".");
40✔
235
                                STRCAT(temp, LABMAX-1, findName);
40✔
236
                                findName = temp;
40✔
237
                        }
238
                } else {
239
                        if (!global && !local && fullName.get() == findName && modNameLen) {
7,536✔
240
                                // this still may be global label without current module (but author didn't use "@")
241
                                findName = fullName.get() + modNameLen + 1;
257✔
242
                        } else {
243
                                findName = nullptr;        // all options exhausted
7,279✔
244
                        }
245
                }
246
        } while (findName);
7,586✔
247
        return undefinedLabelEntry;
7,279✔
248
}
249

250
static SLabelTableEntry* GetLabel(char*& p, uint16_t setExtraTraits = 0) {
751,782✔
251
        std::unique_ptr<char[]> fullName;
751,782✔
252
        SLabelTableEntry* labelEntry = SearchLabel(p, true, fullName);
751,782✔
253
        if (getLabel_invalidName) return nullptr;
751,782✔
254
        if (labelEntry) labelEntry->traits |= setExtraTraits;
751,617✔
255
        if (!labelEntry || LABEL_PAGE_UNDEFINED == labelEntry->page) {
751,617✔
256
                IsLabelNotFound = true;
7,236✔
257
                // don't insert labels or report errors during substitution phase
258
                if (IsSubstituting) return nullptr;
7,236✔
259
                // regular parsing/assembling, track new labels and report "not found" error
260
                char* findName = temp[0] ? temp : fullName.get();
7,170✔
261
                if (!labelEntry) {
7,170✔
262
                        LabelTable.Insert(findName, 0, (LABEL_IS_UNDEFINED | setExtraTraits));
3,533✔
263
                }
264
                Error("Label not found", findName, IF_FIRST);
7,170✔
265
                return nullptr;
7,170✔
266
        } else {
267
                return labelEntry;
744,381✔
268
        }
269
}
751,782✔
270

271
bool LabelExist(char*& p, aint& val) {
171✔
272
        std::unique_ptr<char[]> fullName;
171✔
273
        SLabelTableEntry* labelEntry = SearchLabel(p, false, fullName);
171✔
274
        val = (labelEntry && LABEL_PAGE_UNDEFINED != labelEntry->page) ? -1 : 0;
171✔
275
        return !getLabel_invalidName;
171✔
276
}
171✔
277

278
bool GetLabelPage(char*& p, aint& val) {
168✔
279
        SLabelTableEntry* labelEntry = GetLabel(p);
168✔
280
        val = labelEntry ? labelEntry->page : LABEL_PAGE_UNDEFINED;
168✔
281
        // true even when not found, but valid label name (neeed for expression-eval logic)
282
        return !getLabel_invalidName;
168✔
283
}
284

285
bool GetLabelValue(char*& p, aint& val) {
751,266✔
286
        SLabelTableEntry* labelEntry = GetLabel(p);
751,266✔
287
        if (labelEntry) {
751,266✔
288
                val = labelEntry->value;
743,887✔
289
                if (Relocation::areLabelsOffset) {
743,887✔
290
                        switch (labelEntry->isRelocatable) {
6,839✔
291
                                case Relocation::REGULAR:        val += Relocation::alternative_offset;                        break;
5,694✔
292
                                case Relocation::HIGH:                val += Relocation::alternative_offset >> 8;                break;
51✔
293
                                default:                                        ;
6,839✔
294
                        }
295
                }
296
        } else {
297
                val = 0;
7,379✔
298
        }
299
        // true even when not found, but valid label name (needed for expression-eval logic)
300
        return !getLabel_invalidName;
751,266✔
301
}
302

303
bool GetLabelPhPage(char*& p, aint& val) {
69✔
304
        SLabelTableEntry* labelEntry = GetLabel(p);
69✔
305
        val = labelEntry ? labelEntry->ph_page : LABEL_PAGE_UNDEFINED;
69✔
306
        return !getLabel_invalidName;                // true even when not found, but valid label name
69✔
307
}
308

309
bool GetLabelPhValue(char*& p, aint& val) {
72✔
310
        SLabelTableEntry* labelEntry = GetLabel(p);
72✔
311
        val = labelEntry ? labelEntry->ph_value : 0;        // no relocation logic for ph_value
72✔
312
        return !getLabel_invalidName;                // true even when not found, but valid label name
72✔
313
}
314

315
bool GetLabelSize(char*& p, aint& val) {
207✔
316
        // if symbol is found, add "sizeof" trait, if not found, insert placeholder with "sizeof" trait
317
        SLabelTableEntry* labelEntry = GetLabel(p, LABEL_HAS_SIZE);
207✔
318
        val = labelEntry ? labelEntry->size : 0;                // get symbol's size as return value
207✔
319
        // true even when not found, but valid label name (needed for expression-eval logic)
320
        return !getLabel_invalidName;
207✔
321
}
322

323
int GetTemporaryLabelValue(char*& op, aint& val, bool requireUnderscore) {
732,319✔
324
        char* p = op;
732,319✔
325
        if (SkipBlanks(p) || !isdigit((byte)*p)) return 0;
732,319✔
326
        char* const numberB = p;
713,263✔
327
        while (isdigit((byte)*p)) ++p;
2,990,964✔
328
        const bool hasUnderscore = ('_' == *p);
713,263✔
329
        if (requireUnderscore && !hasUnderscore) return 0;
713,263✔
330
        // convert suffix [bB] => 'b', [fF] => 'f' and ignore underscore
331
        const char type = (hasUnderscore ? p[1] : p[0]) | 0x20;        // should be 'b' or 'f'
1,045✔
332
        const char following = hasUnderscore ? p[2] : p[1];                // should be non-label char
1,045✔
333
        if ('b' != type && 'f' != type) return 0;        // local label must have "b" or "f" after number
1,045✔
334
        if (islabchar(following)) return 0;                        // that suffix didn't end correctly
799✔
335
        // numberB -> p are digits to be parsed as integer
336
        if (!GetNumericValue_IntBased(op = numberB, p, val, 10)) return 0;
796✔
337
        if ('_' == *op) ++op;
796✔
338
        ++op;
796✔
339
        // ^^ advance main parsing pointer op beyond the local label (here it *is* local label)
340
        auto label = ('b' == type) ? TemporaryLabelTable.seekBack(val) : TemporaryLabelTable.seekForward(val);
796✔
341
        if (label) {
796✔
342
                val = label->value;
655✔
343
                if (requireUnderscore) {                                // part of full expression, do relocation by +offset
655✔
344
                        if (label->isRelocatable && Relocation::areLabelsOffset) {
164✔
345
                                val += Relocation::alternative_offset;
35✔
346
                        }
347
                } else {                                                                // single-label-only in jump/call instructions
348
                        Relocation::isResultAffected = label->isRelocatable;
491✔
349
                        Relocation::deltaType = label->isRelocatable ? Relocation::REGULAR : Relocation::OFF;
491✔
350
                }
351
        } else {
352
                if (LASTPASS == pass) Error("Temporary label not found", numberB, SUPPRESS);
141✔
353
                val = 0L;
141✔
354
        }
355
        return 1;
796✔
356
}
357

358
static page_t getAddressPageNumber(const aint address, bool forceRecalculateByAddress) {
361,784✔
359
        // everything is "ROM" based when device is NONE
360
        if (!DeviceID) return LABEL_PAGE_ROM;
361,784✔
361
        // fast-shortcut for regular labels in current slot (if they fit into it)
362
        auto slot = Device->GetCurrentSlot();
332,745✔
363
        assert(Page && slot);
332,745✔
364
        if (!forceRecalculateByAddress && DISP_NONE == PseudoORG) {
332,745✔
365
                if (slot->Address <= address && address < slot->Address + slot->Size) {
4,685✔
366
                        return Page->Number;
174✔
367
                }
368
        }
369
        // enforce explicit request of fake DISP page
370
        if (DISP_NONE != PseudoORG && LABEL_PAGE_UNDEFINED != dispPageNum) {
332,571✔
371
                return dispPageNum;
28✔
372
        }
373
        // in other case (implicit DISP, out-of-slot-bounds or forceRecalculateByAddress)
374
        // track down the page num from current memory mapping
375
        const page_t page = Device->GetPageOfA16(address);
332,543✔
376
        if (LABEL_PAGE_UNDEFINED == page) return LABEL_PAGE_OUT_OF_BOUNDS;
332,543✔
377
        return page;
332,543✔
378
}
379

380
// requires label.page and label.ph_value to be already up-to-date
381
static void updatePhAddressPageNumber(SLabelTableEntry & label) {
379,553✔
382
        page_t page = LABEL_PAGE_OUT_OF_BOUNDS;
379,553✔
383
        if (LABEL_PAGE_UNDEFINED != label.page) {
379,553✔
384
                page = DeviceID ? Device->GetPageOfA16(label.ph_value) : LABEL_PAGE_ROM;
361,798✔
385
        }
386
        label.ph_page = page;
379,553✔
387
}
379,553✔
388

389
int CLabelTable::Insert(const char* nname, aint nvalue, uint16_t traits, page_t equPageNum) {
379,591✔
390
        const bool IsUndefined = !!(traits & LABEL_IS_UNDEFINED);
379,591✔
391

392
        // the EQU/DEFL is relocatable when the expression itself is relocatable
393
        // the regular label is relocatable when relocation is active
394
        const Relocation::EType deltaType = \
379,591✔
395
                        (traits&LABEL_HAS_RELOC_TRAIT) ? \
754,178✔
396
                                (traits & LABEL_IS_RELOC ? Relocation::REGULAR : Relocation::OFF) : \
5,004✔
397
                                (traits & (LABEL_IS_DEFL|LABEL_IS_EQU)) ? \
405,466✔
398
                                        Relocation::deltaType : \
399
                                        Relocation::type && DISP_INSIDE_RELOCATE != PseudoORG ? \
30,879✔
400
                                                Relocation::REGULAR : Relocation::OFF;
401
        // Find label in label table
402
        symbol_map_t::iterator labelIt = symbols.find(nname);
759,182✔
403
        if (symbols.end() != labelIt) {
379,591✔
404
                //if label already added (as used, or in previous pass), just refresh values
405
                auto& label = labelIt->second;
354,417✔
406
                if (label.traits&LABEL_IS_KEYWORD) WarningById(W_OPKEYWORD, nname, W_EARLY);
354,417✔
407
                bool needsUpdate = label.traits&LABEL_IS_DEFL || label.page == LABEL_PAGE_UNDEFINED || label.updatePass < pass;
354,417✔
408
                if (needsUpdate) {
354,417✔
409
                        label.value = nvalue;
354,356✔
410
                        label.ph_value = (DISP_NONE != PseudoORG) ? adrdisp : CurAddress;
354,356✔
411
                        if ((traits & LABEL_IS_EQU) && LABEL_PAGE_UNDEFINED != equPageNum) {
354,356✔
412
                                label.page = equPageNum;
7✔
413
                        } else {
414
                                label.page = getAddressPageNumber(nvalue, traits & (LABEL_IS_DEFL|LABEL_IS_EQU));
354,349✔
415
                        }
416
                        updatePhAddressPageNumber(label);
354,356✔
417
                        label.traits &= LABEL_HAS_SIZE;                        // preserve some
354,356✔
418
                        label.traits |= traits;
354,356✔
419
                        label.isRelocatable = deltaType;
354,356✔
420
                        label.updatePass = pass;
354,356✔
421
                }
422
                return needsUpdate;
354,417✔
423
        }
424
        auto& label = symbols[nname];
50,348✔
425
        label.traits = traits;
25,174✔
426
        label.updatePass = pass;
25,174✔
427
        label.value = nvalue;
25,174✔
428
        label.ph_value = (DISP_NONE != PseudoORG) ? adrdisp : CurAddress;        // in case of expression using undefined label, ph_value is "address" ahead of expression
25,174✔
429
        label.used = IsUndefined;
25,174✔
430
        if ((traits & LABEL_IS_EQU) && LABEL_PAGE_UNDEFINED != equPageNum) {
25,174✔
431
                label.page = equPageNum;
7✔
432
        } else {
433
                label.page = IsUndefined ? LABEL_PAGE_UNDEFINED : getAddressPageNumber(nvalue, traits & (LABEL_IS_DEFL|LABEL_IS_EQU));
25,167✔
434
        }
435
        updatePhAddressPageNumber(label);
25,174✔
436
        label.isRelocatable = IsUndefined ? Relocation::OFF : deltaType;        // ignore "relocatable" for "undefined"
25,174✔
437
        return 1;
25,174✔
438
}
439

440
int CLabelTable::Update(char* name, aint value) {
30✔
441
        // this may happen in early passes with duplicate labels (ie. the result is wrong anyway and source needs fixing)
442
        // or in third pass even when single label drifts from second pass, in such case full update to have correct values
443
        // at least for rest of the pass 3 is needed
444
        auto labelIt = symbols.find(name);
60✔
445
        if (symbols.end() == labelIt) return 0;
30✔
446
        auto& label = labelIt->second;
30✔
447
        label.value = value;
30✔
448
        label.ph_value = (DISP_NONE != PseudoORG) ? adrdisp : CurAddress;
30✔
449
        if (0 == (label.traits & (LABEL_IS_EQU|LABEL_IS_DEFL|LABEL_IS_STRUCT_D))) {
30✔
450
                if (LABEL_PAGE_UNDEFINED != label.page) {        // regular label with some page, refresh it
23✔
451
                        label.page = getAddressPageNumber(value, false);
23✔
452
                }
453
                updatePhAddressPageNumber(label);
23✔
454
        }
455
        return 1;
30✔
456
}
457

458
SLabelTableEntry* CLabelTable::Find(const char* name, bool onlyDefined) {
1,238,403✔
459
        symbol_map_t::iterator labelIt = symbols.find(name);
2,476,806✔
460
        if (symbols.end() == labelIt) return nullptr;
1,238,403✔
461
        return (onlyDefined && LABEL_PAGE_UNDEFINED == labelIt->second.page) ? nullptr : &labelIt->second;
1,234,179✔
462
}
463

464
bool CLabelTable::IsUsed(const char* name) {
102✔
465
        auto labelIt = symbols.find(name);
204✔
466
        return (symbols.end() != labelIt) ? labelIt->second.used : false;
102✔
467
}
468

469
bool CLabelTable::Remove(const char* name) {
×
470
        return symbols.erase(name);
×
471
}
472

473
void CLabelTable::RemoveAll() {
550✔
474
        symbols.clear();
550✔
475
}
550✔
476

477
static const std::vector<symbol_map_t::key_type> getDumpOrder(const symbol_map_t& table) {
392✔
478
        std::vector<symbol_map_t::key_type> order;
392✔
479
        order.reserve(table.size());
392✔
480
        for (const auto& it : table) order.emplace_back(it.first);
15,348✔
481
        if (Options::SortSymbols) {
392✔
482
                std::sort(
392✔
483
                        order.begin(), order.end(),
484
                        [&](const symbol_map_t::key_type& a, const symbol_map_t::key_type& b) {
116,120✔
485
                                // if case insenstive are same, do case sensitive too!
486
                                int caseres = strcasecmp(a.c_str(), b.c_str());
116,120✔
487
                                if (0 == caseres) return a < b;
116,120✔
488
                                return caseres < 0;
109,182✔
489
                        }
490
                );
491
        }
492
        return order;
392✔
493
}
×
494

495
void CLabelTable::Dump() {
515✔
496
        FILE* listFile = GetListingFile();
515✔
497
        if (NULL == listFile) return;                // listing file must be already opened here
515✔
498

499
        const auto order = getDumpOrder(symbols);
364✔
500

501
        char line[LINEMAX], *ep;
502
        fputs("\nValue    Label\n", listFile);
364✔
503
        fputs("------ - -----------------------------------------------------------\n", listFile);
364✔
504
        for (const symbol_map_t::key_type& name: order) {
14,180✔
505
                const symbol_map_t::mapped_type& symbol = symbols.at(name);
13,816✔
506
                if (LABEL_PAGE_UNDEFINED == symbol.page) continue;
13,816✔
507
                ep = line;
4,254✔
508
                *(ep) = 0;
4,254✔
509
                *(ep++) = '0';
4,254✔
510
                *(ep++) = 'x';
4,254✔
511
                PrintHexAlt(ep, symbol.value);
4,254✔
512
                *(ep++) = ' ';
4,254✔
513
                *(ep++) = symbol.used ? ' ' : 'X';
4,254✔
514
                *(ep++) = ' ';
4,254✔
515
                STRNCPY(ep, LINEMAX, name.c_str(), LINEMAX - (ep - line) - 2);
4,254✔
516
                STRNCAT(ep, LINEMAX, "\n", 2);
4,254✔
517
                fputs(line, listFile);
4,254✔
518
        }
519
}
364✔
520

521
void CLabelTable::DumpForUnreal() {
10✔
522
        char ln[LINEMAX], * ep;
523
        FILE* FP_UnrealList;
524
        if (!FOPEN_ISOK(FP_UnrealList, Options::UnrealLabelListFName, "w")) {
10✔
525
                Error("opening file for write", Options::UnrealLabelListFName.string().c_str(), FATAL);
×
526
        }
527
        // not adding to --cleanonerror, this is not binary output file
528
        const int PAGE_MASK = DeviceID ? Device->GetPage(0)->Size - 1 : 0x3FFF;
10✔
529
        const int ADR_MASK = Options::EmitVirtualLabels ? 0xFFFF : PAGE_MASK;
10✔
530
        const auto order = getDumpOrder(symbols);
10✔
531
        for (const symbol_map_t::key_type& name: order) {
384✔
532
                const symbol_map_t::mapped_type& symbol = symbols.at(name);
374✔
533
                if (LABEL_PAGE_UNDEFINED == symbol.page) continue;
374✔
534
                int page = Options::EmitVirtualLabels ? LABEL_PAGE_OUT_OF_BOUNDS : symbol.page;
114✔
535
                if (!strcmp(DeviceID, "ZXSPECTRUM48") && page < 4) {        //TODO fix this properly?
114✔
536
                        // convert pages {0, 1, 2, 3} of ZX48 into ZX128-like {ROM, 5, 2, 0}
537
                        // this can be fooled when there were multiple devices used, Label doesn't know into
538
                        // which device it does belong, so even ZX128 labels will be converted.
539
                        const int fakeZx128Pages[] = {LABEL_PAGE_ROM, 5, 2, 0};
1✔
540
                        page = fakeZx128Pages[page];
1✔
541
                }
542
                int lvalue = symbol.value & ADR_MASK;
114✔
543
                ep = ln;
114✔
544

545
                if (page < LABEL_PAGE_ROM) ep += SPRINTF1(ep, LINEMAX, "%02d", page&255);
114✔
546
                *(ep++) = ':';
114✔
547
                PrintHexAlt(ep, lvalue);
114✔
548

549
                *(ep++) = ' ';
114✔
550
                STRCPY(ep, LINEMAX-(ep-ln), name.c_str());
114✔
551
                STRCAT(ep, LINEMAX, "\n");
114✔
552
                fputs(ln, FP_UnrealList);
114✔
553
        }
554
        fclose(FP_UnrealList);
10✔
555
}
10✔
556

557
void CLabelTable::DumpForCSpect() {
12✔
558
        FILE* file;
559
        if (!FOPEN_ISOK(file, Options::CSpectMapFName, "w")) {
12✔
560
                Error("opening file for write", Options::CSpectMapFName.string().c_str(), FATAL);
×
561
        }
562
        // not adding to --cleanonerror, this is not binary output file
563
        const int CSD_PAGE_SIZE = Options::CSpectMapPageSize;
12✔
564
        const int CSD_PAGE_MASK = CSD_PAGE_SIZE - 1;
12✔
565
        const auto order = getDumpOrder(symbols);
12✔
566
        for (const symbol_map_t::key_type& name: order) {
561✔
567
                const symbol_map_t::mapped_type& symbol = symbols.at(name);
549✔
568
                if (LABEL_PAGE_UNDEFINED == symbol.page) continue;
549✔
569
                const int labelType =
226✔
570
                        (symbol.traits&LABEL_IS_STRUCT_E) ? 0 :
449✔
571
                        (symbol.traits&LABEL_IS_STRUCT_D) ? 4 :
440✔
572
                        (symbol.traits&LABEL_IS_EQU) ? 1 :
422✔
573
                        (symbol.traits&LABEL_IS_DEFL) ? 2 :
404✔
574
                        (LABEL_PAGE_ROM <= symbol.page) ? 3 : 0;
199✔
575
                const short page = labelType ? 0 : symbol.page;
226✔
576
                        // TODO:
577
                        // page == -1 will put regular EQU like "BLUE" out of reach for disassembly window
578
                        // (otherwise BLUE becomes label for address $C001 with default mapping)
579
                        // BUT then it would be nice to provide real page data for equ which have them explicit
580
                        // BUT I can't distinguish explicit/implicit page number, as there's heuristic to use current mapping
581
                        // instead of using the LABEL_PAGE_OUT_OF_BOUNDS page number...
582
                        // TODO: figure out when/why the implicit page number heuristic happenned and if you can detect
583
                        // only explicit page numbers used in EQU, and export only those
584

585
                const aint longAddress = (CSD_PAGE_MASK & symbol.value) + page * CSD_PAGE_SIZE;
226✔
586
                fprintf(file, "%08X %08X %02X ", 0xFFFF & symbol.value, longAddress, labelType);
226✔
587
                // convert primary+local label to be "@" delimited (not "." delimited)
588
                STRCPY(temp, LINEMAX, name.c_str());
226✔
589
                // look for "primary" label (where the local label starts)
590
                char* localLabelStart = strrchr(temp, '.');
226✔
591
                while (temp < localLabelStart) {        // the dot must be at least second character
345✔
592
                        *localLabelStart = 0;                        // terminate the possible "primary" part
160✔
593
                        if (Find(temp, true)) {
160✔
594
                                *localLabelStart = '@';
41✔
595
                                break;
41✔
596
                        }
597
                        *localLabelStart = '.';                        // "primary" label didn't work, restore dot
119✔
598
                        do {
599
                                --localLabelStart;                        // and look for next dot
293✔
600
                        } while (temp < localLabelStart && '.' != *localLabelStart);
293✔
601
                }
602
                // convert whole label to upper-case, as CSpect search is malfunctioning otherwise.
603
                char* strToUpper = temp;
226✔
604
                while ((*strToUpper = (char) toupper((byte)*strToUpper))) { ++strToUpper; }
2,903✔
605
                fprintf(file, "%s\n", temp);
226✔
606
        }
607
        fclose(file);
12✔
608
}
12✔
609

610
void CLabelTable::DumpSymbols() {
6✔
611
        FILE* symfp;
612
        if (!FOPEN_ISOK(symfp, Options::SymbolListFName, "w")) {
6✔
613
                Error("opening file for write", Options::SymbolListFName.string().c_str(), FATAL);
×
614
        }
615
        // not adding to --cleanonerror, this is not binary output file
616
        const auto order = getDumpOrder(symbols);
6✔
617
        for (const symbol_map_t::key_type& name: order) {
223✔
618
                const symbol_map_t::mapped_type& symbol = symbols.at(name);
217✔
619
                if (isdigit((byte)name[0])) continue;
217✔
620
                if (symbol.traits&LABEL_IS_KEYWORD) continue;
217✔
621
                WriteLabelEquValue(name.c_str(), symbol.value, symfp);
61✔
622
        }
623
        fclose(symfp);
6✔
624
}
6✔
625

626
void CLabelTable::TrackForSize(SLabelTableEntry *label) {
117✔
627
        assert(label);
117✔
628
        if ((LABEL_IS_EQU|LABEL_IS_DEFL|LABEL_IS_SMC) & label->traits) {                                // skip size counting for certain types of labels
117✔
629
                Warning("SIZEOF(...) this type of label is invalid, size is zero");
6✔
630
                return;
6✔
631
        }
632
        const aint myLevel = sourceBlockLevel + (!!(LABEL_IS_LOCAL & label->traits));        // local labels are +1 level
111✔
633
        sizeofStack.emplace_back(label, myLevel);
111✔
634
}
635

636
void CLabelTable::SizeBoundary(BoundaryLevel boundaryLevel) {
374,430✔
637
        if (sizeofStack.empty()) return;
374,430✔
638
        if (BOUNDARY_FLOW == boundaryLevel) {
141✔
639
                Warning("SIZEOF-tracking does not work across wrap-around. Stopping count here.");
2✔
640
        }
641
        // soft boundary, process all stacked labels with current sourceBlockLevel (nesting of source text)
642
        aint myLevel = sourceBlockLevel + (BOUNDARY_LOCAL == boundaryLevel);        // local labels are +1 level
141✔
643
        while (myLevel <= sizeofStack.back().srcLevel) {
187✔
644
                auto & label = *sizeofStack.back().label;
105✔
645
                label.size = ((DISP_NONE != PseudoORG) ? adrdisp : CurAddress) - label.ph_value;
105✔
646
                // printf("boundary: %p, updatePass %d, ph_value %X, size %X, adrdisp %X, CurAddress %X\n", &label, label.updatePass, label.ph_value, label.size, adrdisp, CurAddress);
647
                sizeofStack.pop_back();
105✔
648
                if (sizeofStack.empty()) return;
105✔
649
        }
650
        if (BOUNDARY_FLOW != boundaryLevel && BOUNDARY_ALL != boundaryLevel) return;
82✔
651
        // process *all* stacked labels, even with lower boundary level, but warn about them
652
        // but I don't have names of them! So general warning about "Labels" ... :shrug:
653
        assert(!sizeofStack.empty());
6✔
654
        if (BOUNDARY_ALL == boundaryLevel) {
6✔
655
                Warning("There are labels in parent scope being SIZEOF-tracked at this point. Stopping their count here.");
6✔
656
        }
657
        do {
658
                auto & label = *sizeofStack.back().label;
6✔
659
                label.size = ((DISP_NONE != PseudoORG) ? adrdisp : CurAddress) - label.ph_value;
6✔
660
                // printf("boundary: %p, updatePass %d, ph_value %X, size %X, adrdisp %X, CurAddress %X\n", &label, label.updatePass, label.ph_value, label.size, adrdisp, CurAddress);
661
                sizeofStack.pop_back();
6✔
662
        } while (!sizeofStack.empty());
6✔
663
}
664

665
int CFunctionTable::Insert(const char* name_cstr, function_fn_t nfunp) {
173,053✔
666
        std::string name(name_cstr);
173,053✔
667
        if (!std::get<1>(functions.emplace(name, nfunp))) return 0;
173,053✔
668
        for (auto& c : name) c = toupper(c);
1,099,716✔
669
        return std::get<1>(functions.emplace(name, nfunp));
173,053✔
670
}
173,053✔
671

672
int CFunctionTable::insertd(const char* name, function_fn_t nfunp) {
66,187✔
673
        if ('.' != name[0]) Error("Directive string must start with dot", NULL, FATAL);
66,187✔
674
        // insert the non-dot variant first, then dot variant
675
        return Insert(name+1, nfunp) && Insert(name, nfunp);
66,187✔
676
}
677

678
int CFunctionTable::zoek(const char* name) {
386,274✔
679
        auto it = functions.find(name);
772,548✔
680
        if (functions.end() == it) return 0;
386,274✔
681
        (*it->second)();
246,495✔
682
        return 1;
246,489✔
683
}
684

685
TemporaryLabel::TemporaryLabel(aint number, aint address)
361✔
686
        : nummer(number), value(address), isRelocatable(bool(Relocation::type)) {}
361✔
687

688
void CTemporaryLabelTable::InitPass() {
1,625✔
689
        labels = std::move(nextPassLabels);                                // use labels collected in previous pass
1,625✔
690
        nextPassLabels.reserve(128U + labels.size());        // reserve similar memory for next pass
1,625✔
691
}
1,625✔
692

693
bool CTemporaryLabelTable::InsertRefresh(const aint labelNumber) {
361✔
694
        temporary_labels_t::size_type refresh = nextPassLabels.size();
361✔
695
        nextPassLabels.emplace_back(labelNumber, CurAddress);
361✔
696
        if (labels.size() <= refresh || labels.at(refresh).nummer != labelNumber) return false;
361✔
697
        TemporaryLabel & to_r = labels.at(refresh);
233✔
698
        if (to_r.value != CurAddress) Warning("Temporary label has different address");
233✔
699
        return true;
233✔
700
}
701

702
const TemporaryLabel* CTemporaryLabelTable::seekForward(const aint labelNumber) const {
366✔
703
        // has to search through previous pass "labels", so data may be outdated a bit (last pass should match penultimate pass!)
704
        temporary_labels_t::size_type i = nextPassLabels.size();        // points at first "forward" temporary label
366✔
705
        while (i < labels.size() && labelNumber != labels[i].nummer) ++i;
393✔
706
        return (i < labels.size()) ? &labels[i] : nullptr;
366✔
707
}
708

709
const TemporaryLabel* CTemporaryLabelTable::seekBack(const aint labelNumber) const {
466✔
710
        // will search through nextPassLabels, so data are "fresh" from current pass
711
        temporary_labels_t::size_type i = nextPassLabels.size();        // points after last "backward" temporary label
466✔
712
        while (i-- && labelNumber != nextPassLabels[i].nummer) ;        // empty while statement, condition does all work
607✔
713
        return (i < nextPassLabels.size()) ? &nextPassLabels[i] : nullptr;
466✔
714
}
715

716
CStringsList::CStringsList(const char* stringSource, CStringsList* nnext) {
33,744✔
717
        string = STRDUP(stringSource);
33,744✔
718
        next = nnext;
33,744✔
719
        if (!sourcePosStack.empty()) source = sourcePosStack.back();
33,744✔
720
}
33,744✔
721

722
CStringsList::~CStringsList() {
33,744✔
723
        if (string) free(string);
33,744✔
724
        if (next) delete next;
33,744✔
725
}
33,744✔
726

727
bool CStringsList::contains(const CStringsList* strlist, const char* searchString) {
212✔
728
        while (nullptr != strlist) {
386✔
729
                if (!strcmp(searchString, strlist->string)) return true;
175✔
730
                strlist = strlist->next;
174✔
731
        }
732
        return false;
211✔
733
}
734

735
CDefineTableEntry::CDefineTableEntry(const char* nname, const char* nvalue, CStringsList* nnss, CDefineTableEntry* nnext)
30,817✔
736
                : name(NULL), value(NULL) {
30,817✔
737
        name = STRDUP(nname);
30,817✔
738
        value = new char[strlen(nvalue) + 1];
30,817✔
739
        if (NULL == name || NULL == value) ErrorOOM();
30,817✔
740
        char* s1 = value;
30,817✔
741
        while (*nvalue && *nvalue != '\n' && *nvalue != '\r') *s1++ = *nvalue++;
250,008✔
742
        *s1 = 0;
30,817✔
743
        next = nnext;
30,817✔
744
        nss = nnss;
30,817✔
745
}
30,817✔
746

747
CDefineTableEntry::~CDefineTableEntry() {
30,817✔
748
        if (name) free(name);
30,817✔
749
        if (value) delete[] value;
30,817✔
750
        if (nss) delete nss;
30,817✔
751
        if (next) delete next;
30,817✔
752
}
30,817✔
753

754
void CDefineTableEntry::Replace(const char* nvalue) {
22,824✔
755
        if (value) delete[] value;
22,824✔
756
        value = new char[strlen(nvalue) + 1];
22,824✔
757
        strcpy(value, nvalue);
22,824✔
758
}
22,824✔
759

760
CDefineTable::~CDefineTable() {
1,120✔
761
        for (auto def : defs) if (def) delete def;
144,480✔
762
}
1,120✔
763

764
CDefineTable& CDefineTable::operator=(CDefineTable const & defTable) {
1,625✔
765
        RemoveAll();
1,625✔
766
        for (CDefineTableEntry* srcDef : defTable.defs) {
209,625✔
767
                CDefineTableEntry* srcD = srcDef;
208,000✔
768
                while (srcD) {
211,376✔
769
                        Add(srcD->name, srcD->value, srcD->nss);
3,376✔
770
                        srcD = srcD->next;
3,376✔
771
                }
772
        }
773
        return *this;
1,625✔
774
}
775

776
void CDefineTable::Init() {
1,120✔
777
        DefArrayList = NULL;
1,120✔
778
        for (auto & def : defs) def = NULL;
144,480✔
779
}
1,120✔
780

781
void CDefineTable::Add(const char* name, const char* value, CStringsList* nss) {
5,022✔
782
        if (FindDuplicate(name)) {
5,022✔
783
                Error("Duplicate define (replacing old value)", name, PASS03);
16✔
784
        }
785
        defs[(*name)&127] = new CDefineTableEntry(name, value, nss, defs[(*name)&127]);
5,022✔
786
}
5,022✔
787

788
static char defineGet__Counter__Buffer[32] = {};
789
static char defineGet__Line__Buffer[32] = {};
790

791
const char* CDefineTable::Get(const char* name) {
1,753,816✔
792
        DefArrayList = nullptr;
1,753,816✔
793
        if (nullptr == name || 0 == name[0]) return nullptr;
1,753,816✔
794
        // the __COUNTER__ and __LINE__ have fully dynamic custom implementation here
795
        if ('_' == name[1]) {
1,753,810✔
796
                if (!strcmp(name, "__COUNTER__")) {
67,025✔
797
                        SPRINTF1(defineGet__Counter__Buffer, 30, "%d", PredefinedCounter);
15,390✔
798
                        ++PredefinedCounter;
15,390✔
799
                        return defineGet__Counter__Buffer;
15,390✔
800
                }
801
                if (!strcmp(name, "__LINE__")) {
51,635✔
802
                        SPRINTF1(defineGet__Line__Buffer, 30, "%d", sourcePosStack.empty() ? 0 : sourcePosStack.back().line);
15✔
803
                        return defineGet__Line__Buffer;
15✔
804
                }
805
        }
806
        CDefineTableEntry* p = defs[(*name)&127];
1,738,405✔
807
        while (p && strcmp(name, p->name)) p = p->next;
2,363,263✔
808
        if (nullptr == p) return nullptr;
1,738,405✔
809
        DefArrayList = p->nss;
17,150✔
810
        return p->value;
17,150✔
811
}
812

813
int CDefineTable::FindDuplicate(const char* name) {
6,150✔
814
        CDefineTableEntry* p = defs[(*name)&127];
6,150✔
815
        while (p) {
12,400✔
816
                if (!strcmp(name, p->name)) {
7,280✔
817
                        return 1;
1,030✔
818
                }
819
                p = p->next;
6,250✔
820
        }
821
        return 0;
5,120✔
822
}
823

824
int CDefineTable::Replace(const char* name, const char* value) {
47,240✔
825
        CDefineTableEntry* p = defs[(*name)&127];
47,240✔
826
        while (p) {
362,360✔
827
                if (!strcmp(name, p->name)) {
337,944✔
828
                        p->Replace(value);
22,824✔
829
                        return 0;
22,824✔
830
                }
831
                p = p->next;
315,120✔
832
        }
833
        defs[(*name)&127] = new CDefineTableEntry(name, value, 0, defs[(*name)&127]);
24,416✔
834
        return 1;
24,416✔
835
}
836

837
int CDefineTable::Replace(const char* name, const int value) {
16,881✔
838
        char newIntValue[24];
839
        SPRINTF1(newIntValue, sizeof(newIntValue), "%d", value);
16,881✔
840
        return Replace(name, newIntValue);
33,762✔
841
}
842

843
int CDefineTable::Remove(const char* name) {
90✔
844
        CDefineTableEntry* p = defs[(*name)&127];
90✔
845
        CDefineTableEntry* p2 = NULL;
90✔
846
        while (p) {
93✔
847
                if (!strcmp(name, p->name)) {
93✔
848
                        // unchain the particular item
849
                        if (NULL == p2) defs[(*name)&127] = p->next;
90✔
850
                        else                        p2->next = p->next;
3✔
851
                        p->next = NULL;
90✔
852
                        // delete it
853
                        delete p;
90✔
854
                        DefArrayList = NULL;                // may be invalid here, so just reset it
90✔
855
                        return 1;
90✔
856
                }
857
                p2 = p;
3✔
858
                p = p->next;
3✔
859
        }
860
        return 0;
×
861
}
862

863
void CDefineTable::RemoveAll() {
2,178✔
864
        DefArrayList = NULL;
2,178✔
865
        for (auto & def : defs) {
280,962✔
866
                if (!def) continue;
278,784✔
867
                delete def;
1,925✔
868
                def = NULL;
1,925✔
869
        }
870
}
2,178✔
871

872
CMacroDefineTable::CMacroDefineTable() : defs(nullptr) {
560✔
873
        for (auto & usedX : used) usedX = false;
72,240✔
874
}
560✔
875

876
CMacroDefineTable::~CMacroDefineTable() {
560✔
877
        if (defs) delete defs;
560✔
878
}
560✔
879

880
void CMacroDefineTable::ReInit() {
2,664✔
881
        if (defs) delete defs;
2,664✔
882
        defs = nullptr;
2,664✔
883
        for (auto & usedX : used) usedX = false;
343,656✔
884
}
2,664✔
885

886
void CMacroDefineTable::AddMacro(char* naam, char* vervanger) {
1,379✔
887
        CDefineTableEntry* tmpdefs = new CDefineTableEntry(naam, vervanger, 0, defs);
1,379✔
888
        defs = tmpdefs;
1,379✔
889
        used[(*naam)&127] = true;
1,379✔
890
}
1,379✔
891

892
CDefineTableEntry* CMacroDefineTable::getdefs() {
1,573✔
893
        return defs;
1,573✔
894
}
895

896
void CMacroDefineTable::setdefs(CDefineTableEntry* const ndefs) {
1,530✔
897
        if (ndefs == defs) return;                        // the current HEAD of defines is already same as requested one
1,530✔
898
        // traverse through current HEAD until the requested chain is found, unchain the HEAD from it
899
        CDefineTableEntry* entry = defs;
696✔
900
        while (entry && ndefs != entry->next) entry = entry->next;
1,348✔
901
        if (entry) entry->next = nullptr;        // if "ndefs" is chained to current HEAD, unchain
696✔
902
        if (defs) delete defs;                                // release front part of current chain from memory
696✔
903
        defs = ndefs;                                                // the requested chain is new current HEAD
696✔
904
}
905

906
const char* CMacroDefineTable::getverv(const char* name) const {
49,364✔
907
        if (nullptr == name) return nullptr;
49,364✔
908
        if (!used[(*name)&127]) return nullptr;
49,364✔
909
        const CDefineTableEntry* p = defs;
9,103✔
910
        while (p && strcmp(name, p->name)) p = p->next;
44,770✔
911
        return p ? p->value : nullptr;
9,103✔
912
}
913

914
void CMacroTable::ReInit() {
1,625✔
915
        used.assign(128, false);
1,625✔
916
        macs.clear();
1,625✔
917
}
1,625✔
918

919
void CMacroTable::Add(const char* nnaam, char*& p) {
573✔
920
        auto [add_it, is_new] = macs.try_emplace(nnaam, CMacroTableEntry());
1,719✔
921
        if (!is_new) {
573✔
922
                Error("Duplicate macroname", nnaam);
6✔
923
                return;
6✔
924
        }
925
        used[nnaam[0] & 127] = true;
567✔
926
        CStringsList* last = nullptr;
567✔
927
        do {
928
                char* n = GetID(p);
867✔
929
                if (!n) {
867✔
930
                        // either EOL when no previous argument, or valid name is required after comma (2nd+ loop)
931
                        if ((1 == pass) && (last || *p)) Error("Illegal argument name", p, EARLY);
231✔
932
                        SkipToEol(p);
231✔
933
                        break;
231✔
934
                }
935
                if ((1 == pass) && CStringsList::contains(add_it->second.args, n)) {
636✔
936
                        Error("Duplicate argument name", n, EARLY);
1✔
937
                }
938
                CStringsList* argname = new CStringsList(n);
636✔
939
                if (!add_it->second.args) {
636✔
940
                        add_it->second.args = argname;        // first argument name, make it head of list
342✔
941
                } else {
942
                        last->next = argname;
294✔
943
                }
944
                last = argname;
636✔
945
        } while (anyComma(p));
636✔
946
        if ((1 == pass) && *p) {
567✔
947
                Error("Unexpected", p, EARLY);
2✔
948
        }
949
        ListFile();
567✔
950
        if (!ReadFileToCStringsList(add_it->second.body, "endm")) {
567✔
951
                Error("Unexpected end of macro", NULL, EARLY);
3✔
952
        }
953
}
954

955
int CMacroTable::Emit(char* naam, char*& p) {
246,436✔
956
        // search for the desired macro
957
        if (!used[naam[0] & 127]) return 0;
246,436✔
958
        auto mac_it = macs.find(naam);
4,398✔
959
        if (macs.end() == mac_it) return 0;
2,199✔
960
        // macro found, emit it, prepare temporary instance label base
961
        char* omacrolabp = macrolabp;
1,573✔
962
        char labnr[LINEMAX], ml[LINEMAX];
963
        SPRINTF1(labnr, LINEMAX, "%d", macronummer++);
1,573✔
964
        macrolabp = labnr;
1,573✔
965
        if (omacrolabp) {
1,573✔
966
                STRCAT(macrolabp, LINEMAX-1, "."); STRCAT(macrolabp, LINEMAX-1, omacrolabp);
534✔
967
        } else {
968
                MacroDefineTable.ReInit();
1,039✔
969
        }
970
        // parse argument values
971
        CDefineTableEntry* odefs = MacroDefineTable.getdefs();
1,573✔
972
        CStringsList* a = mac_it->second.args;
1,573✔
973
        while (a) {
2,952✔
974
                char* n = ml;
1,394✔
975
                const bool lastArg = NULL == a->next;
1,394✔
976
                if (!GetMacroArgumentValue(p, n) || (!lastArg && !comma(p))) {
1,394✔
977
                        Error("Not enough arguments for macro", naam, SUPPRESS);
15✔
978
                        macrolabp = omacrolabp;
15✔
979
                        return 1;
15✔
980
                }
981
                MacroDefineTable.AddMacro(a->string, ml);
1,379✔
982
                a = a->next;
1,379✔
983
        }
984
        SkipBlanks(p);
1,558✔
985
        if (*p) {
1,558✔
986
                Error("Too many arguments for macro", naam, SUPPRESS);
27✔
987
                macrolabp = omacrolabp;
27✔
988
                return 1;
27✔
989
        }
990
        // arguments parsed, emit the macro lines and parse them
991
        lp = p;
1,531✔
992
        ListFile();
1,531✔
993
        sourceBlockLevel += 2;
1,531✔
994
        ++listmacro;
1,531✔
995
        CStringsList* olijstp = lijstp;
1,531✔
996
        lijstp = mac_it->second.body;
1,531✔
997
        ++lijst;
1,531✔
998
        STRCPY(ml, LINEMAX, line);
1,531✔
999
        sourcePosStack.push_back(TextFilePos());
1,531✔
1000
        const aint osldSwapSrcPos = sldSwapSrcPos;
1,531✔
1001
        while (lijstp) {
7,509✔
1002
                sourcePosStack.back() = lijstp->source;
5,979✔
1003
                STRCPY(line, LINEMAX, lijstp->string);
5,979✔
1004
                substitutedLine = line;                // reset substituted listing
5,979✔
1005
                eolComment = NULL;                        // reset end of line comment
5,979✔
1006
                lijstp = lijstp->next;
5,979✔
1007
                ParseLineSafe();
5,979✔
1008
        }
1009
        LabelTable.SizeBoundary(CLabelTable::BOUNDARY_MAIN);
1,530✔
1010
        sourceBlockLevel -= 2;
1,530✔
1011
        if (osldSwapSrcPos != sldSwapSrcPos) WarningById(W_SLD_SWAP, mac_it->first.c_str());
1,530✔
1012
        sourcePosStack.pop_back();
1,530✔
1013
        ++CompiledCurrentLine;
1,530✔
1014
        STRCPY(line, LINEMAX, ml);
1,530✔
1015
        lijstp = olijstp;
1,530✔
1016
        --lijst;
1,530✔
1017
        MacroDefineTable.setdefs(odefs);
1,530✔
1018
        macrolabp = omacrolabp;
1,530✔
1019
        --listmacro; donotlist = 1;
1,530✔
1020
        return 2;
1,530✔
1021
}
1022

1023
CStructureEntry1::CStructureEntry1(char* nnaam, aint noffset) {
1,314✔
1024
        next = 0;
1,314✔
1025
        naam = STRDUP(nnaam);
1,314✔
1026
        if (naam == NULL) ErrorOOM();
1,314✔
1027
        offset = noffset;
1,314✔
1028
}
1,314✔
1029

1030
CStructureEntry1::~CStructureEntry1() {
1,314✔
1031
        free(naam);
1,314✔
1032
        if (next) delete next;
1,314✔
1033
}
1,314✔
1034

1035
CStructureEntry2::CStructureEntry2(aint noffset, aint nlen, aint ndef, Relocation::EType ndeltatype, EStructureMembers ntype) :
1,480✔
1036
        next(nullptr), text(nullptr), offset(noffset), len(nlen), def(ndef), defDeltaType(ndeltatype), type(ntype)
1,480✔
1037
{
1038
}
1,480✔
1039

1040
CStructureEntry2::CStructureEntry2(aint noffset, aint nlen, byte* textData) :
114✔
1041
        next(nullptr), text(textData), offset(noffset), len(nlen), def(0), defDeltaType(Relocation::OFF), type(SMEMBTEXT)
114✔
1042
{
1043
        assert(1 <= len && len <= TEXT_MAX_SIZE && nullptr != text);
114✔
1044
}
114✔
1045

1046
CStructureEntry2::~CStructureEntry2() {
1,594✔
1047
        if (next) delete next;
1,594✔
1048
        if (text) delete[] text;
1,594✔
1049
}
1,594✔
1050

1051
// Parses source input for types: BYTE, WORD, DWORD, D24
1052
aint CStructureEntry2::ParseValue(char* & p) {
4,065✔
1053
        if (SMEMBBYTE != type && SMEMBWORD != type && SMEMBDWORD != type && SMEMBD24 != type) return def;
4,065✔
1054
        SkipBlanks(p);
4,065✔
1055
        aint val = def;
4,065✔
1056
        bool keepRelocatableFlags = false;        // keep flags from the ParseExpressionNoSyntaxError?
4,065✔
1057
        // check for unexpected {
1058
        if ('{' != *p) {
4,065✔
1059
                if (!(keepRelocatableFlags = ParseExpressionNoSyntaxError(p, val))) {
3,381✔
1060
                        val = def;
2,001✔
1061
                }
1062
                switch (type) {
3,381✔
1063
                        case SMEMBBYTE:
2,340✔
1064
                                check8(val);
2,340✔
1065
                                val &= 0xFF;
2,340✔
1066
                                break;
2,340✔
1067
                        case SMEMBWORD:
750✔
1068
                                check16(val);
750✔
1069
                                val &= 0xFFFF;
750✔
1070
                                break;
750✔
1071
                        case SMEMBD24:
135✔
1072
                                check24(val);
135✔
1073
                                val &= 0xFFFFFF;
135✔
1074
                                break;
135✔
1075
                        case SMEMBDWORD:
156✔
1076
                                break;
156✔
1077
                        default:
×
1078
                                break;
×
1079
                }
1080
        }
1081
        if (!Relocation::type) return val;
4,065✔
1082
        if (SMEMBBYTE == type && Relocation::HIGH == Relocation::type) {
435✔
1083
                if (!keepRelocatableFlags) {        // override flags, if parse expression was not successful
24✔
1084
                        Relocation::isResultAffected |= bool(defDeltaType);
12✔
1085
                        Relocation::deltaType = defDeltaType;
12✔
1086
                }
1087
                Relocation::resolveRelocationAffected(0, Relocation::HIGH);
24✔
1088
        } else if (SMEMBWORD == type) {
411✔
1089
                if (!keepRelocatableFlags) {        // override flags, if parse expression was not successful
234✔
1090
                        Relocation::isResultAffected |= bool(defDeltaType);
168✔
1091
                        Relocation::deltaType = defDeltaType;
168✔
1092
                }
1093
                Relocation::resolveRelocationAffected(0);
234✔
1094
        }
1095
        Relocation::checkAndWarn();
435✔
1096
        return val;
435✔
1097
}
1098

1099
CStructure::CStructure(const char* nnaam, int no, CStructure* p) {
279✔
1100
        mnf = mnl = NULL; mbf = mbl = NULL;
279✔
1101
        naam = STRDUP(nnaam);
279✔
1102
        if (naam == NULL) ErrorOOM();
279✔
1103
        next = p; noffset = no;
279✔
1104
        maxAlignment = 0;
279✔
1105
}
279✔
1106

1107
CStructure::~CStructure() {
279✔
1108
        free(naam);
279✔
1109
        if (mnf) delete mnf;
279✔
1110
        if (mbf) delete mbf;
279✔
1111
        if (next) delete next;
279✔
1112
}
279✔
1113

1114
void CStructure::AddLabel(char* nnaam) {
1,062✔
1115
        CopyLabel(nnaam, 0);
1,062✔
1116
}
1,062✔
1117

1118
void CStructure::AddMember(CStructureEntry2* n) {
1,594✔
1119
        if (!mbf)        mbf = n;
1,594✔
1120
        else                 mbl->next = n;
1,321✔
1121
        mbl = n;
1,594✔
1122
        noffset += n->len;
1,594✔
1123
}
1,594✔
1124

1125
void CStructure::CopyLabel(char* nnaam, aint offset) {
1,314✔
1126
        CStructureEntry1* n = new CStructureEntry1(nnaam, noffset + offset);
1,314✔
1127
        if (!mnf)        mnf = n;
1,314✔
1128
        else                mnl->next = n;
1,041✔
1129
        mnl = n;
1,314✔
1130
}
1,314✔
1131

1132
void CStructure::CopyLabels(CStructure* st) {
84✔
1133
        CStructureEntry1* np = st->mnf;
84✔
1134
        if (!np || !PreviousIsLabel) return;
84✔
1135
        char str[LINEMAX];
1136
        STRCPY(str, LINEMAX-1, PreviousIsLabel);
84✔
1137
        STRCAT(str, LINEMAX-1, ".");
84✔
1138
        char * const stw = str + strlen(str);
84✔
1139
        while (np) {
336✔
1140
                STRCPY(stw, LINEMAX, np->naam);        // overwrite the second part of label
252✔
1141
                CopyLabel(str, np->offset);
252✔
1142
                np = np->next;
252✔
1143
        }
1144
}
1145

1146
void CStructure::CopyMember(CStructureEntry2* item, aint newDefault, Relocation::EType newDeltaType) {
342✔
1147
        AddMember(new CStructureEntry2(noffset, item->len, newDefault, newDeltaType, item->type));
342✔
1148
}
342✔
1149

1150
void CStructure::CopyMembers(CStructure* st, char*& lp) {
84✔
1151
        aint val;
1152
        int haakjes = 0;
84✔
1153
        AddMember(new CStructureEntry2(noffset, 0, 0, Relocation::OFF, SMEMBPARENOPEN));
84✔
1154
        SkipBlanks(lp);
84✔
1155
        if (*lp == '{') {
84✔
1156
                ++haakjes; ++lp;
48✔
1157
        }
1158
        CStructureEntry2* ip = st->mbf;
84✔
1159
        while (ip || 0 < haakjes) {
504✔
1160
                Relocation::isResultAffected = false;
423✔
1161
                // check if inside curly braces block, and input seems to be empty -> fetch next line
1162
                if (0 < haakjes && !PrepareNonBlankMultiLine(lp)) break;
423✔
1163
                if (nullptr == ip) {        // no more struct members expected, looking for closing '}'
423✔
1164
                        assert(0 < haakjes);
48✔
1165
                        if (!need(lp, '}')) break;
48✔
1166
                        --haakjes;
45✔
1167
                        continue;
45✔
1168
                }
1169
                assert(ip);
375✔
1170
                switch (ip->type) {
375✔
1171
                case SMEMBBLOCK:
24✔
1172
                        CopyMember(ip, ip->def, Relocation::OFF);
24✔
1173
                        break;
24✔
1174
                case SMEMBBYTE:
270✔
1175
                case SMEMBWORD:
1176
                case SMEMBD24:
1177
                case SMEMBDWORD:
1178
                        {
1179
                                Relocation::EType isRelocatable = Relocation::OFF;
270✔
1180
                                if (ParseExpressionNoSyntaxError(lp, val)) {
270✔
1181
                                        isRelocatable = (Relocation::isResultAffected && (SMEMBWORD == ip->type || SMEMBBYTE == ip->type))
168✔
1182
                                                                                ? Relocation::deltaType : Relocation::OFF;
168✔
1183
                                } else {
1184
                                        val = ip->def;
108✔
1185
                                        isRelocatable = ip->defDeltaType;
108✔
1186
                                }
1187
                                CopyMember(ip, val, isRelocatable);
270✔
1188
                                if (SMEMBWORD == ip->type) {
270✔
1189
                                        Relocation::resolveRelocationAffected(INT_MAX);        // clear flags + warn when can't be relocated
54✔
1190
                                } else if (SMEMBBYTE == ip->type) {
216✔
1191
                                        Relocation::resolveRelocationAffected(INT_MAX, Relocation::HIGH);        // clear flags + warn when can't be relocated
204✔
1192
                                }
1193
                                if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(lp);
270✔
1194
                        }
1195
                        break;
270✔
1196
                case SMEMBTEXT:
33✔
1197
                        {
1198
                                byte* textData = new byte[ip->len]();        // zero initialized for stable binary results
174✔
1199
                                if (nullptr == textData) ErrorOOM();
33✔
1200
                                GetStructText(lp, ip->len, textData, ip->text);
33✔
1201
                                AddMember(new CStructureEntry2(noffset, ip->len, textData));
33✔
1202
                                if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(lp);
33✔
1203
                        }
1204
                        break;
33✔
1205
                case SMEMBPARENOPEN:
24✔
1206
                        SkipBlanks(lp);
24✔
1207
                        if (*lp == '{') {
24✔
1208
                                ++haakjes; ++lp;
6✔
1209
                        }
1210
                        CopyMember(ip, 0, Relocation::OFF);
24✔
1211
                        break;
24✔
1212
                case SMEMBPARENCLOSE:
24✔
1213
                        SkipBlanks(lp);
24✔
1214
                        if (haakjes && *lp == '}') {
24✔
1215
                                --haakjes; ++lp;
6✔
1216
                                if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(lp);
6✔
1217
                        }
1218
                        CopyMember(ip, 0, Relocation::OFF);
24✔
1219
                        break;
24✔
1220
                default:
×
1221
                        Error("internalerror CStructure::CopyMembers", NULL, FATAL);
×
1222
                }
1223
                Relocation::checkAndWarn();
375✔
1224
                ip = ip->next;
375✔
1225
        }
1226
        if (haakjes) {
84✔
1227
                Error("closing } missing");
3✔
1228
        }
1229
        AddMember(new CStructureEntry2(noffset, 0, 0, Relocation::OFF, SMEMBPARENCLOSE));
84✔
1230
}
84✔
1231

1232
static void InsertSingleStructLabel(const bool setNameSpace, char *name, const bool isRelocatable, const aint value, const bool isDefine = true) {
7,519✔
1233
        // "isDefine" case already has namespaced-full-name, don't add namespace twice by ValidateLabel
1234
        bool isLocal = false;
7,519✔
1235
        std::unique_ptr<char[]> tempFullName(isDefine ? nullptr : ValidateLabel(isLocal, name, setNameSpace));
7,519✔
1236
        if (!isDefine && !tempFullName) return;                // invalid labelname reported by ValidateLabel
7,519✔
1237
        char *fullName = isDefine ? name : tempFullName.get();
7,504✔
1238
        if (pass == LASTPASS) {
7,504✔
1239
                aint oval;
1240
                char *lp = name;        // not full name, full name fails in GetLabelValue for local macro labels (trying to full-name it second time)
2,500✔
1241
                if (!GetLabelValue(lp, oval)) {
2,500✔
1242
                        Error("Internal error. InsertSingleStructLabel()", fullName, FATAL);
1✔
1243
                }
1244
                if (value != oval) {
2,499✔
1245
                        Error("Label has different value in pass 2", fullName);
6✔
1246
                }
1247
                if (IsSldExportActive()) {                // SLD (Source Level Debugging) tracing-data logging
2,499✔
1248
                        SLabelTableEntry* symbol = LabelTable.Find(fullName, true);
118✔
1249
                        assert(symbol);        // should have been already defined before last pass
118✔
1250
                        if (symbol) {
118✔
1251
                                WriteToSldFile(isDefine ? -1 : symbol->page, value, 'L', ExportLabelToSld(name, symbol));
118✔
1252
                        }
1253
                }
1254
        } else {
1255
                Relocation::isResultAffected = isRelocatable;
5,004✔
1256
                Relocation::deltaType = isRelocatable ? Relocation::REGULAR : Relocation::OFF;
5,004✔
1257
                assert(!isDefine || Relocation::OFF == Relocation::deltaType);        // definition labels are always nonrel
5,004✔
1258
                unsigned traits = LABEL_HAS_RELOC_TRAIT \
5,004✔
1259
                                                | (isLocal ? LABEL_IS_LOCAL : 0) \
5,004✔
1260
                                                | (isDefine ? LABEL_IS_STRUCT_D : LABEL_IS_STRUCT_E) \
5,004✔
1261
                                                | (isRelocatable ? LABEL_IS_RELOC : 0);
5,004✔
1262
                if (!LabelTable.Insert(fullName, value, traits)) {
5,004✔
1263
                        // while main struct name shouldn't be possible to dupe, item names may compound into clash, caught as late as here
1264
                        Error("Duplicate label", fullName, EARLY);
4✔
1265
                } else if (isDefine && setNameSpace) {        // this is name of structure defined, make it's SIZEOF also set
5,000✔
1266
                        SLabelTableEntry* structLabel = LabelTable.Find(fullName, true);
184✔
1267
                        assert(structLabel);
184✔
1268
                        structLabel->size = value;
184✔
1269
                }
1270
        }
1271
}
7,518✔
1272

1273
static void InsertStructSubLabels(const char* mainName, const bool isRelocatable, const CStructureEntry1* members, const aint address = 0, const bool isDefine = true) {
860✔
1274
        char ln[LINEMAX+1];
1275
        size_t mainNameSz = std::min(strlen(mainName), size_t(LINEMAX-2));
860✔
1276
        memcpy(ln, mainName, mainNameSz);
860✔
1277
        ln[mainNameSz++] = '.';
860✔
1278
        ln[mainNameSz] = 0;
860✔
1279
        char * const lnsubw = ln + mainNameSz;
860✔
1280
        while (members) {
7,518✔
1281
                STRCPY(lnsubw, LINEMAX-strlen(ln), members->naam);                // overwrite sub-label part
6,658✔
1282
                InsertSingleStructLabel(false, ln, isRelocatable, members->offset + address, isDefine);
6,658✔
1283
                members = members->next;
6,658✔
1284
        }
1285
}
860✔
1286

1287
void CStructure::deflab() {
279✔
1288
        InsertSingleStructLabel(true, naam, false, noffset);
279✔
1289
        InsertStructSubLabels(naam, false, mnf);
278✔
1290
}
278✔
1291

1292
void CStructure::emitlab(char* iid, aint address, const bool isRelocatable) {
582✔
1293
        const aint misalignment = maxAlignment ? ((-address) & (maxAlignment - 1)) : 0;
582✔
1294
        if (misalignment) {
582✔
1295
                // emitting in misaligned position (considering the ALIGN used to define this struct)
1296
                char warnTxt[LINEMAX];
1297
                SPRINTF3(warnTxt, LINEMAX,
13✔
1298
                                        "Struct %s did use ALIGN %d in definition, but here it is misaligned by %d bytes",
1299
                                        naam, maxAlignment, misalignment);
1300
                Warning(warnTxt);
13✔
1301
        }
1302
        char sn[LINEMAX] { 0 };
582✔
1303
        STRCPY(sn, LINEMAX-1, iid);
582✔
1304
        InsertSingleStructLabel(true, sn, isRelocatable, address, false);
582✔
1305
        InsertStructSubLabels(sn, isRelocatable, mnf, address, false);
582✔
1306
        SLabelTableEntry* structLabel = LabelTable.Find(sn, true);                // set SIZEOF of emitted structure label
582✔
1307
        if (structLabel) structLabel->size = noffset;
582✔
1308
}
582✔
1309

1310
void CStructure::emitmembs(char*& p) {
699✔
1311
        byte* emitTextBuffer = nullptr;
699✔
1312
        aint val;
1313
        int haakjes = 0;
699✔
1314
        SkipBlanks(p);
699✔
1315
        if (*p == '{') {
699✔
1316
                ++haakjes; ++p;
372✔
1317
        }
1318
        CStructureEntry2* ip = mbf;
699✔
1319
        Relocation::isResultAffected = false;
699✔
1320
        while (ip || 0 < haakjes) {
8,105✔
1321
                // check if inside curly braces block, and input seems to be empty -> fetch next line
1322
                if (0 < haakjes && !PrepareNonBlankMultiLine(p)) break;
7,433✔
1323
                if (nullptr == ip) {        // no more struct members expected, looking for closing '}'
7,424✔
1324
                        assert(0 < haakjes);
303✔
1325
                        if (!need(p, '}')) break;
303✔
1326
                        --haakjes;
285✔
1327
                        continue;
285✔
1328
                }
1329
                assert(ip);
7,121✔
1330
                switch (ip->type) {
7,121✔
1331
                case SMEMBBLOCK:
821✔
1332
                        EmitBlock(ip->def != -1 ? ip->def : 0, ip->len, ip->def == -1, 8);
821✔
1333
                        if (8 < ip->len) ListFile();        // "..." elipsis happened in listing, force listing
821✔
1334
                        break;
821✔
1335
                case SMEMBBYTE:
2,547✔
1336
                        EmitByte(ip->ParseValue(p));
2,547✔
1337
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
2,547✔
1338
                        break;
2,547✔
1339
                case SMEMBWORD:
951✔
1340
                        // ParseValue will also add relocation data if needed (so the "ParseValue" name is misleading)
1341
                        EmitWord(ip->ParseValue(p));
951✔
1342
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
951✔
1343
                        break;
951✔
1344
                case SMEMBD24:
204✔
1345
                        val = ip->ParseValue(p);
204✔
1346
                        EmitByte(val & 0xFF);
204✔
1347
                        EmitWord((val>>8) & 0xFFFF);
204✔
1348
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
204✔
1349
                        break;
204✔
1350
                case SMEMBDWORD:
363✔
1351
                        val = ip->ParseValue(p);
363✔
1352
                        EmitWord(val & 0xFFFF);
363✔
1353
                        EmitWord((val>>16) & 0xFFFF);
363✔
1354
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
363✔
1355
                        break;
363✔
1356
                case SMEMBTEXT:
573✔
1357
                        {
1358
                                if (nullptr == emitTextBuffer) {
573✔
1359
                                        emitTextBuffer = new byte[CStructureEntry2::TEXT_MAX_SIZE+2];
138✔
1360
                                        if (nullptr == emitTextBuffer) ErrorOOM();
138✔
1361
                                }
1362
                                memset(emitTextBuffer, 0, ip->len);
573✔
1363
                                GetStructText(p, ip->len, emitTextBuffer, ip->text);
573✔
1364
                                for (aint ii = 0; ii < ip->len; ++ii) EmitByte(emitTextBuffer[ii]);
4,194✔
1365
                        }
1366
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
573✔
1367
                        break;
573✔
1368
                case SMEMBPARENOPEN:
831✔
1369
                        SkipBlanks(p);
831✔
1370
                        if (*p == '{') { ++haakjes; ++p; }
831✔
1371
                        break;
831✔
1372
                case SMEMBPARENCLOSE:
831✔
1373
                        SkipBlanks(p);
831✔
1374
                        if (haakjes && *p == '}') {
831✔
1375
                                --haakjes; ++p;
417✔
1376
                        }
1377
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
831✔
1378
                        break;
831✔
1379
                default:
×
1380
                        ErrorInt("Internal Error CStructure::emitmembs", ip->type, FATAL);
×
1381
                }
1382
                ip = ip->next;
7,121✔
1383
        }
1384
        if (haakjes) {
699✔
1385
                Error("closing } missing");
27✔
1386
        }
1387
        if (!SkipBlanks(p)) Error("[STRUCT] Syntax error - too many arguments?");
699✔
1388
        Relocation::checkAndWarn();
699✔
1389
        if (nullptr != emitTextBuffer) delete[] emitTextBuffer;
699✔
1390
}
699✔
1391

1392
CStructureTable::CStructureTable() {
560✔
1393
        for (auto & structPtr : strs) structPtr = nullptr;
72,240✔
1394
}
560✔
1395

1396
CStructureTable::~CStructureTable() {
560✔
1397
        for (auto structPtr : strs) if (structPtr) delete structPtr;
72,240✔
1398
}
560✔
1399

1400
void CStructureTable::ReInit() {
1,625✔
1401
        for (auto & structPtr : strs) {
209,625✔
1402
                if (structPtr) delete structPtr;
208,000✔
1403
                structPtr = nullptr;
208,000✔
1404
        }
1405
}
1,625✔
1406

1407
CStructure* CStructureTable::Add(const char* naam, int offset) {
288✔
1408
        if (FindDuplicate(naam)) {
288✔
1409
                Error("[STRUCT] Structure already exist", naam);
9✔
1410
                return nullptr;
9✔
1411
        }
1412
        CStructure** strsN = strs + (naam[0] & 127);
279✔
1413
        *strsN = new CStructure(naam, 0, *strsN);
279✔
1414
        if (offset) {
279✔
1415
                (*strsN)->AddMember(new CStructureEntry2(0, offset, -1, Relocation::OFF, SMEMBBLOCK));
37✔
1416
        }
1417
        return *strsN;
279✔
1418
}
1419

1420
CStructure* CStructureTable::zoek(const char* naam, int gl) {
262,170✔
1421
        char sn[LINEMAX], * sp;
1422
        sn[0] = 0;
262,170✔
1423
        const char* prependNS = gl ? nullptr : ('.' == naam[0]) ? vorlab.c_str() : ModuleName[0] ? ModuleName : nullptr;
262,170✔
1424
        if (prependNS) {
262,170✔
1425
                STRCPY(sn, LINEMAX-2, prependNS);
4,769✔
1426
                if ('.' != naam[0]) STRCAT(sn, 2, ".");
4,769✔
1427
        }
1428
        STRCAT(sn, LINEMAX-1, naam);
262,170✔
1429
        sp = sn;
262,170✔
1430
        CStructure* p = strs[(*sp)&127];
262,170✔
1431
        while (p) {
262,878✔
1432
                if (!strcmp(sp, p->naam)) return p;
1,515✔
1433
                p = p->next;
708✔
1434
        }
1435
        if (gl || ! *ModuleName) return NULL;
261,363✔
1436
        sp += 1 + strlen(ModuleName); p = strs[(*sp)&127];
4,173✔
1437
        while (p) {
4,197✔
1438
                if (!strcmp(sp, p->naam)) return p;
69✔
1439
                p = p->next;
24✔
1440
        }
1441
        return NULL;
4,128✔
1442
}
1443

1444
int CStructureTable::FindDuplicate(const char* naam) {
288✔
1445
        CStructure* p = strs[(*naam)&127];
288✔
1446
        while (p) {
480✔
1447
                if (!strcmp(naam, p->naam)) return 1;
201✔
1448
                p = p->next;
192✔
1449
        }
1450
        return 0;
279✔
1451
}
1452

1453
aint CStructureTable::ParseDesignedAddress(char* &p) {
756✔
1454
        if (!SkipBlanks(p) && ('=' == *p)) {
756✔
1455
                char* adrP = ++p;
57✔
1456
                aint resultAdr;
1457
                if (ParseExpressionNoSyntaxError(p, resultAdr)) return resultAdr;
57✔
1458
                Error("[STRUCT] Syntax error in designed address", adrP, SUPPRESS);
3✔
1459
                return 0;
3✔
1460
        }
1461
        return INT_MAX;                // no "designed address" provided, emit structure bytes
699✔
1462
}
1463

1464
int CStructureTable::Emit(char* naam, char* l, char*& p, int gl) {
262,005✔
1465
        CStructure* st = zoek(naam, gl);
262,005✔
1466
        if (!st) return 0;
262,005✔
1467
        // create new labels corresponding to current/designed address
1468
        aint address = CStructureTable::ParseDesignedAddress(p);
756✔
1469
        if (l) {
756✔
1470
                const Relocation::EType relocatable =
582✔
1471
                        (INT_MAX == address) ?
1,164✔
1472
                                (Relocation::type ? Relocation::REGULAR : Relocation::OFF)
528✔
1473
                                : Relocation::isResultAffected ? Relocation::deltaType : Relocation::OFF;
54✔
1474
                st->emitlab(l, (INT_MAX == address) ? CurAddress : address, relocatable == Relocation::REGULAR);
582✔
1475
        }
1476
        if (INT_MAX == address) st->emitmembs(p);        // address was not designed, emit also bytes
756✔
1477
        else if (!l) Warning("[STRUCT] designed address without label = no effect");
57✔
1478
        return 1;
756✔
1479
}
1480

1481
SRepeatStack::SRepeatStack(aint count, CStringsList* condition, CStringsList* firstLine)
4,223✔
1482
        : RepeatCount(count), RepeatCondition(condition), Lines(firstLine), Pointer(firstLine), IsInWork(false), Level(0)
4,223✔
1483
{
1484
        assert(!sourcePosStack.empty());
4,223✔
1485
        sourcePos = sourcePosStack.back();
4,223✔
1486
}
4,223✔
1487

1488
SRepeatStack::~SRepeatStack() {
4,223✔
1489
        if (RepeatCondition) delete RepeatCondition;
4,223✔
1490
        if (Lines) delete Lines;
4,223✔
1491
}
4,223✔
1492

1493
//eof tables.cpp
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc