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

z00m128 / sjasmplus / 1451

31 Dec 2024 06:13PM UTC coverage: 96.28% (+0.001%) from 96.279%
1451

Pull #254

cirrus-ci

ped7g
c++17: replacing custom code with std::filesystem[::path] where feasible

Related #240, should fix "check include paths" feature for windows, and
simplify somewhat code base (and get rid of home-made filename patching
functions, they seem robust enough and well tested, but I assume in the
long term having C++ standard library implementation is better, even if
it involves slightly more machine code executed here and there).

This is not thorough refactoring of whole code base, working on it bit
by bit, luckily the std::filesystem API is flexible enough to
connect/disconnect it to rest of code through char[] fields, so I can
replace the code partially and check test results.

Commit v2 (replacing lot more variables and code than first proof of
concept).
Pull Request #254: migrating some of the file stuff to std::filesystem, in the naive hope of getting better cross-platform compatibility

77 of 85 new or added lines in 7 files covered. (90.59%)

38 existing lines in 6 files now uncovered.

9680 of 10054 relevant lines covered (96.28%)

168519.82 hits per line

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

97.53
/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) {
248,671✔
34
}
248,671✔
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) {
660,427✔
44
        if (endsWithColon && 0 == colEnd) colEnd = 1;        // first segment of "colonized" line (do +1,+1)
660,427✔
45
        colBegin = colEnd;
660,427✔
46
        if (colBegin <= 1) ++line;                // first segment of any line, increment also line number
660,427✔
47
        if (endsWithColon)        colEnd += advanceColumns;
660,427✔
48
        else                                colEnd = 0;
649,558✔
49
}
660,427✔
50

51
char* PreviousIsLabel = nullptr;
52

53
// since v1.18.0:
54
// The ignore invalid char after feature disconnected from "setNameSpace" to "ignoreCharAfter"
55
// (it's for evaluating labels straight from the expressions, without copying them out first)
56
// The prefix "!" is now recognized as "do not set main label" for following local labels
57
// since v1.18.3:
58
// Inside macro prefix "@." will create non-macro local label instead of macro's instance
59
char* ValidateLabel(const char* naam, bool setNameSpace, bool ignoreCharAfter) {
1,122,547✔
60
        if (nullptr == naam) {
1,122,547✔
61
                Error("Invalid labelname");
2✔
62
                return nullptr;
2✔
63
        }
64
        if ('!' == *naam) {
1,122,545✔
65
                setNameSpace = false;
47✔
66
                ++naam;
47✔
67
        }
68
        // check if local label defined inside macro wants to become non-macro local label
69
        const bool escMacro = setNameSpace && macrolabp && ('@' == naam[0]) && ('.' == naam[1]);
1,122,545✔
70
        if (escMacro) ++naam;                        // such extra "@" is consumed right here and only '.' is left
1,122,545✔
71
        // regular single prefix case in other use cases
72
        const bool global = '@' == *naam;
1,122,545✔
73
        const bool local = '.' == *naam;
1,122,545✔
74
        if (!isLabelStart(naam)) {                // isLabelStart assures that only single modifier exist
1,122,545✔
75
                if (global || local) ++naam;// single modifier is parsed (even when invalid name)
66✔
76
                Error("Invalid labelname", naam);
66✔
77
                return nullptr;
66✔
78
        }
79
        if (global || local) ++naam;        // single modifier is parsed
1,122,479✔
80
        const bool inMacro = !escMacro && local && macrolabp;
1,122,479✔
81
        const bool inModule = !inMacro && !global && ModuleName[0];
1,122,479✔
82
        // check all chars of label
83
        const char* np = naam;
1,122,479✔
84
        while (islabchar(*np)) ++np;
5,089,853✔
85
        if ('[' == *np) return nullptr;        // this is DEFARRAY name, do not process it as label (silent exit)
1,122,479✔
86
        if (*np && !ignoreCharAfter) {
1,122,329✔
87
                // if this is supposed to be new label, there shoulnd't be anything else after it
88
                Error("Invalid labelname", naam);
15✔
89
                return nullptr;
15✔
90
        }
91
        // calculate expected length of fully qualified label name
92
        int labelLen = (np - naam), truncateAt = LABMAX;
1,122,314✔
93
        if (LABMAX < labelLen) Error("Label too long", naam, IF_FIRST);        // non-fatal error, will truncate it
1,122,314✔
94
        if (inMacro) labelLen += 1 + strlen(macrolabp);
1,122,314✔
95
        else if (local) labelLen += 1 + strlen(vorlabp);
1,114,367✔
96
        if (inModule) labelLen += 1 + strlen(ModuleName);
1,122,314✔
97
        // build fully qualified label name (in newly allocated memory buffer, with precise length)
98
        char* const label = new char[1+labelLen];
1,122,314✔
99
        if (nullptr == label) ErrorOOM();
1,122,314✔
100
        label[0] = 0;
1,122,314✔
101
        if (inModule) {
1,122,314✔
102
                STRCAT(label, labelLen, ModuleName);        STRCAT(label, 2, ".");
1,631✔
103
        }
104
        if (inMacro) {
1,122,314✔
105
                STRCAT(label, labelLen, macrolabp);                STRCAT(label, 2, ">");
7,947✔
106
        } else if (local) {
1,114,367✔
107
                STRCAT(label, labelLen, vorlabp);                STRCAT(label, 2, ".");
1,999✔
108
        }
109
        char* lp = label + strlen(label), * newVorlabP = nullptr;
1,122,314✔
110
        if (setNameSpace && !local) newVorlabP = lp;        // here will start new non-local label prefix
1,122,314✔
111
        while (truncateAt-- && islabchar(*naam)) *lp++ = *naam++;        // add the new label (truncated if needed)
5,082,488✔
112
        *lp = 0;
1,122,314✔
113
        if (labelLen < lp - label) Error("internal error", nullptr, FATAL);                // should never happen :)
1,122,314✔
114
        if (newVorlabP) {
1,122,314✔
115
                free(vorlabp);
361,032✔
116
                vorlabp = STRDUP(newVorlabP);
361,032✔
117
                if (vorlabp == NULL) ErrorOOM();
361,032✔
118
        }
119
        return label;
1,122,314✔
120
}
121

122
static char sldLabelExport[2*LINEMAX];
123

124
char* ExportLabelToSld(const char* naam, const SLabelTableEntry* label) {
220✔
125
        // does re-parse the original source line again similarly to ValidateLabel
126
        // but prepares SLD 'L'-type line, with module/main/local comma separated + usage traits info
127
        assert(nullptr != label);
220✔
128
        assert(isLabelStart(naam));                // this should be called only when ValidateLabel did succeed
220✔
129
        const bool global = '@' == *naam;
220✔
130
        const bool local = '.' == *naam;
220✔
131
        if (global || local) ++naam;        // single modifier is parsed
220✔
132
        const bool inMacro = local && macrolabp;
220✔
133
        const bool inModule = !inMacro && !global && ModuleName[0];
220✔
134
        const bool isStructLabel = (label->traits & (LABEL_IS_STRUCT_D|LABEL_IS_STRUCT_E));
220✔
135
        // build fully qualified SLD info
136
        sldLabelExport[0] = 0;
220✔
137
        // module part
138
        if (inModule) STRCAT(sldLabelExport, LINEMAX, ModuleName);
220✔
139
        STRCAT(sldLabelExport, 2, ",");
220✔
140
        // main label part (the `vorlabp` is already the current label, if it was main label)
141
        // except for structure labels: the inner ones don't "set namespace" == vorlabp, use "naam" then
142
        // (but only if the main label of structure itself is not local, if it's local, use vorlabp)
143
        STRCAT(sldLabelExport, LABMAX, isStructLabel && !local ? naam : inMacro ? macrolabp : vorlabp);
220✔
144
        STRCAT(sldLabelExport, 2, ",");
220✔
145
        // local part
146
        if (local) STRCAT(sldLabelExport, LABMAX, naam);
220✔
147
        // usage traits
148
        if (label->traits&LABEL_IS_EQU) STRCAT(sldLabelExport, 20, ",+equ");
220✔
149
        if (inMacro) STRCAT(sldLabelExport, 20, ",+macro");
220✔
150
        if (label->traits&LABEL_IS_SMC) STRCAT(sldLabelExport, 20, ",+smc");
220✔
151
        if (Relocation::REGULAR == label->isRelocatable) STRCAT(sldLabelExport, 20, ",+reloc");
220✔
152
        if (Relocation::HIGH == label->isRelocatable) STRCAT(sldLabelExport, 20, ",+reloc_high");
220✔
153
        if (label->used) STRCAT(sldLabelExport, 20, ",+used");
220✔
154
        if (label->traits&LABEL_IS_STRUCT_D) STRCAT(sldLabelExport, 20, ",+struct_def");
220✔
155
        if (label->traits&LABEL_IS_STRUCT_E) STRCAT(sldLabelExport, 20, ",+struct_data");
220✔
156
        return sldLabelExport;
220✔
157
}
158

159
char* ExportModuleToSld(bool endModule) {
8✔
160
        assert(ModuleName[0]);
8✔
161
        STRNCPY(sldLabelExport, 2*LINEMAX, ModuleName, LINEMAX);
8✔
162
        STRCAT(sldLabelExport, LINEMAX-1, endModule ? ",,,+endmod" : ",,,+module");
8✔
163
        return sldLabelExport;
8✔
164
}
165

166
static bool getLabel_invalidName = false;
167

168
// does parse + consume input source at "p" (and stores result into "fullName")
169
//  ^^^ may report invalid label name error
170
// does search (and only search) LabelTable for various variants of label based on "fullName"
171
// No refresh of "used", no inserting into table when not found, no other errrors reported
172
// Leaves canonical name in "temp" global variable, if this is inside macro
173
// returns table entry, preferring the one with "page defined", if multiple entries are found
174
static SLabelTableEntry* SearchLabel(char*& p, bool setUsed, /*out*/ std::unique_ptr<char[]>& fullName) {
751,077✔
175
        getLabel_invalidName = true;
751,077✔
176
        fullName.reset(ValidateLabel(p, false, true));
751,077✔
177
        if (!fullName) return nullptr;
751,077✔
178
        getLabel_invalidName = false;
750,910✔
179
        const bool global = '@' == *p;
750,910✔
180
        const bool local = '.' == *p;
750,910✔
181
        while (islabchar(*p)) ++p;                // advance pointer beyond the parsed label
3,386,755✔
182
        // find the label entry in the label table (for local macro labels it has to try all sub-parts!)
183
        // then regular full label has to be tried
184
        // and if it's regular non-local in module, then variant w/o current module has to be tried
185
        bool inMacro = local && macrolabp;                // not just inside macro, but should be prefixed
750,910✔
186
        const int modNameLen = strlen(ModuleName);
750,910✔
187
        const char *findName = fullName.get();
750,910✔
188
        SLabelTableEntry* undefinedLabelEntry = nullptr;
750,910✔
189
        SLabelTableEntry* labelEntry = nullptr;
750,910✔
190
        temp[0] = 0;
750,910✔
191
        do {
192
                labelEntry = LabelTable.Find(findName);
751,125✔
193
                if (labelEntry) {
751,125✔
194
                        if (setUsed && pass < LASTPASS) labelEntry->used = true;
747,299✔
195
                        if (LABEL_PAGE_UNDEFINED != labelEntry->page) return labelEntry;        // found
747,299✔
196
                        // if found, but "undefined" one, remember it as fall-back result
197
                        undefinedLabelEntry = labelEntry;
3,650✔
198
                        labelEntry = nullptr;
3,650✔
199
                }
200
                // not found (the defined one, try more variants)
201
                if (inMacro) {                                // try outer macro (if there is one)
7,476✔
202
                        while ('>' != *findName && '.' != *findName) ++findName;
100✔
203
                        // if no more outer macros, try module+non-local prefix with the original local label
204
                        if ('>' == *findName++) {
48✔
205
                                inMacro = false;
38✔
206
                                if (modNameLen) {
38✔
207
                                        #pragma GCC diagnostic push        // disable gcc8 warning about truncation - that's intended behaviour
208
                                        #if 8 <= __GNUC__
209
                                                #pragma GCC diagnostic ignored "-Wstringop-truncation"
210
                                        #endif
211
                                        STRCAT(temp, LINEMAX-2, ModuleName); STRCAT(temp, 2, ".");
×
212
                                        #pragma GCC diagnostic pop
213
                                }
214
                                STRCAT(temp, LABMAX-1, vorlabp); STRCAT(temp, 2, ".");
38✔
215
                                STRCAT(temp, LABMAX-1, findName);
38✔
216
                                findName = temp;
38✔
217
                        }
218
                } else {
219
                        if (!global && !local && fullName.get() == findName && modNameLen) {
7,428✔
220
                                // this still may be global label without current module (but author didn't use "@")
221
                                findName = fullName.get() + modNameLen + 1;
167✔
222
                        } else {
223
                                findName = nullptr;        // all options exhausted
7,261✔
224
                        }
225
                }
226
        } while (findName);
7,476✔
227
        return undefinedLabelEntry;
7,261✔
228
}
229

230
static SLabelTableEntry* GetLabel(char*& p) {
750,918✔
231
        std::unique_ptr<char[]> fullName;
750,918✔
232
        SLabelTableEntry* labelEntry = SearchLabel(p, true, fullName);
750,918✔
233
        if (getLabel_invalidName) return nullptr;
750,918✔
234
        if (!labelEntry || LABEL_PAGE_UNDEFINED == labelEntry->page) {
750,760✔
235
                IsLabelNotFound = true;
7,218✔
236
                // don't insert labels or report errors during substitution phase
237
                if (IsSubstituting) return nullptr;
7,218✔
238
                // regular parsing/assembling, track new labels and report "not found" error
239
                char* findName = temp[0] ? temp : fullName.get();
7,152✔
240
                if (!labelEntry) {
7,152✔
241
                        LabelTable.Insert(findName, 0, LABEL_IS_UNDEFINED);
3,526✔
242
                }
243
                Error("Label not found", findName, IF_FIRST);
7,152✔
244
                return nullptr;
7,152✔
245
        } else {
246
                return labelEntry;
743,542✔
247
        }
248
}
750,918✔
249

250
bool LabelExist(char*& p, aint& val) {
159✔
251
        std::unique_ptr<char[]> fullName;
159✔
252
        SLabelTableEntry* labelEntry = SearchLabel(p, false, fullName);
159✔
253
        val = (labelEntry && LABEL_PAGE_UNDEFINED != labelEntry->page) ? -1 : 0;
159✔
254
        return !getLabel_invalidName;
159✔
255
}
159✔
256

257
bool GetLabelPage(char*& p, aint& val) {
114✔
258
        SLabelTableEntry* labelEntry = GetLabel(p);
114✔
259
        val = labelEntry ? labelEntry->page : LABEL_PAGE_UNDEFINED;
114✔
260
        // true even when not found, but valid label name (neeed for expression-eval logic)
261
        return !getLabel_invalidName;
114✔
262
}
263

264
bool GetLabelValue(char*& p, aint& val) {
750,804✔
265
        SLabelTableEntry* labelEntry = GetLabel(p);
750,804✔
266
        if (labelEntry) {
750,804✔
267
                val = labelEntry->value;
743,439✔
268
                if (Relocation::areLabelsOffset) {
743,439✔
269
                        switch (labelEntry->isRelocatable) {
6,850✔
270
                                case Relocation::REGULAR:        val += Relocation::alternative_offset;                        break;
5,699✔
271
                                case Relocation::HIGH:                val += Relocation::alternative_offset >> 8;                break;
51✔
272
                                default:                                        ;
6,850✔
273
                        }
274
                }
275
        } else {
276
                val = 0;
7,365✔
277
        }
278
        // true even when not found, but valid label name (needed for expression-eval logic)
279
        return !getLabel_invalidName;
750,804✔
280
}
281

282
int GetTemporaryLabelValue(char*& op, aint& val, bool requireUnderscore) {
730,979✔
283
        char* p = op;
730,979✔
284
        if (SkipBlanks(p) || !isdigit((byte)*p)) return 0;
730,979✔
285
        char* const numberB = p;
711,941✔
286
        while (isdigit((byte)*p)) ++p;
2,987,700✔
287
        const bool hasUnderscore = ('_' == *p);
711,941✔
288
        if (requireUnderscore && !hasUnderscore) return 0;
711,941✔
289
        // convert suffix [bB] => 'b', [fF] => 'f' and ignore underscore
290
        const char type = (hasUnderscore ? p[1] : p[0]) | 0x20;        // should be 'b' or 'f'
949✔
291
        const char following = hasUnderscore ? p[2] : p[1];                // should be non-label char
949✔
292
        if ('b' != type && 'f' != type) return 0;        // local label must have "b" or "f" after number
949✔
293
        if (islabchar(following)) return 0;                        // that suffix didn't end correctly
766✔
294
        // numberB -> p are digits to be parsed as integer
295
        if (!GetNumericValue_IntBased(op = numberB, p, val, 10)) return 0;
763✔
296
        if ('_' == *op) ++op;
763✔
297
        ++op;
763✔
298
        // ^^ advance main parsing pointer op beyond the local label (here it *is* local label)
299
        auto label = ('b' == type) ? TemporaryLabelTable.seekBack(val) : TemporaryLabelTable.seekForward(val);
763✔
300
        if (label) {
763✔
301
                val = label->value;
490✔
302
                if (requireUnderscore) {                                // part of full expression, do relocation by +offset
490✔
303
                        if (label->isRelocatable && Relocation::areLabelsOffset) {
120✔
304
                                val += Relocation::alternative_offset;
28✔
305
                        }
306
                } else {                                                                // single-label-only in jump/call instructions
307
                        Relocation::isResultAffected = label->isRelocatable;
370✔
308
                        Relocation::deltaType = label->isRelocatable ? Relocation::REGULAR : Relocation::OFF;
370✔
309
                }
310
        } else {
311
                if (LASTPASS == pass) Error("Temporary label not found", numberB, SUPPRESS);
273✔
312
                val = 0L;
273✔
313
        }
314
        return 1;
763✔
315
}
316

317
static short getAddressPageNumber(const aint address, bool forceRecalculateByAddress) {
361,181✔
318
        // everything is "ROM" based when device is NONE
319
        if (!DeviceID) return LABEL_PAGE_ROM;
361,181✔
320
        // fast-shortcut for regular labels in current slot (if they fit into it)
321
        auto slot = Device->GetCurrentSlot();
332,548✔
322
        assert(Page && slot);
332,548✔
323
        if (!forceRecalculateByAddress && DISP_NONE == PseudoORG) {
332,548✔
324
                if (slot->Address <= address && address < slot->Address + slot->Size) {
4,510✔
325
                        return Page->Number;
164✔
326
                }
327
        }
328
        // enforce explicit request of fake DISP page
329
        if (DISP_NONE != PseudoORG && LABEL_PAGE_UNDEFINED != dispPageNum) {
332,384✔
330
                return dispPageNum;
12✔
331
        }
332
        // in other case (implicit DISP, out-of-slot-bounds or forceRecalculateByAddress)
333
        // track down the page num from current memory mapping
334
        const short page = Device->GetPageOfA16(address);
332,372✔
335
        if (LABEL_PAGE_UNDEFINED == page) return LABEL_PAGE_OUT_OF_BOUNDS;
332,372✔
336
        return page;
228,910✔
337
}
338

339
int CLabelTable::Insert(const char* nname, aint nvalue, unsigned traits, short equPageNum) {
370,823✔
340
        const bool IsUndefined = !!(traits & LABEL_IS_UNDEFINED);
370,823✔
341

342
        // the EQU/DEFL is relocatable when the expression itself is relocatable
343
        // the regular label is relocatable when relocation is active
344
        const Relocation::EType deltaType = \
370,823✔
345
                        (traits&LABEL_HAS_RELOC_TRAIT) ? \
736,852✔
346
                                (traits & LABEL_IS_RELOC ? Relocation::REGULAR : Relocation::OFF) : \
4,794✔
347
                                (traits & (LABEL_IS_DEFL|LABEL_IS_EQU)) ? \
388,401✔
348
                                        Relocation::deltaType : \
349
                                        Relocation::type && DISP_INSIDE_RELOCATE != PseudoORG ? \
22,372✔
350
                                                Relocation::REGULAR : Relocation::OFF;
351
        // Find label in label table
352
        symbol_map_t::iterator labelIt = symbols.find(nname);
741,646✔
353
        if (symbols.end() != labelIt) {
370,823✔
354
                //if label already added (as used, or in previous pass), just refresh values
355
                auto& label = labelIt->second;
354,093✔
356
                if (label.traits&LABEL_IS_KEYWORD) WarningById(W_OPKEYWORD, nname, W_EARLY);
354,093✔
357
                bool needsUpdate = label.traits&LABEL_IS_DEFL || label.page == LABEL_PAGE_UNDEFINED || label.updatePass < pass;
354,093✔
358
                if (needsUpdate) {
354,093✔
359
                        label.value = nvalue;
354,045✔
360
                        if ((traits & LABEL_IS_EQU) && LABEL_PAGE_UNDEFINED != equPageNum) {
354,045✔
361
                                label.page = equPageNum;
4✔
362
                        } else {
363
                                label.page = getAddressPageNumber(nvalue, traits & (LABEL_IS_DEFL|LABEL_IS_EQU));
354,041✔
364
                        }
365
                        label.traits = traits;
354,045✔
366
                        label.isRelocatable = deltaType;
354,045✔
367
                        label.updatePass = pass;
354,045✔
368
                }
369
                return needsUpdate;
354,093✔
370
        }
371
        auto& label = symbols[nname];
33,460✔
372
        label.traits = traits;
16,730✔
373
        label.updatePass = pass;
16,730✔
374
        label.value = nvalue;
16,730✔
375
        label.used = IsUndefined;
16,730✔
376
        if ((traits & LABEL_IS_EQU) && LABEL_PAGE_UNDEFINED != equPageNum) {
16,730✔
377
                label.page = equPageNum;
4✔
378
        } else {
379
                label.page = IsUndefined ? LABEL_PAGE_UNDEFINED : getAddressPageNumber(nvalue, traits & (LABEL_IS_DEFL|LABEL_IS_EQU));
16,726✔
380
        }
381
        label.isRelocatable = IsUndefined ? Relocation::OFF : deltaType;        // ignore "relocatable" for "undefined"
16,730✔
382
        return 1;
16,730✔
383
}
384

385
int CLabelTable::Update(char* name, aint value) {
30✔
386
        auto labelIt = symbols.find(name);
60✔
387
        if (symbols.end() != labelIt) labelIt->second.value = value;
30✔
388
        return (symbols.end() != labelIt);
30✔
389
}
390

391
SLabelTableEntry* CLabelTable::Find(const char* name, bool onlyDefined) {
872,511✔
392
        symbol_map_t::iterator labelIt = symbols.find(name);
1,745,022✔
393
        if (symbols.end() == labelIt) return nullptr;
872,511✔
394
        return (onlyDefined && LABEL_PAGE_UNDEFINED == labelIt->second.page) ? nullptr : &labelIt->second;
868,557✔
395
}
396

397
bool CLabelTable::IsUsed(const char* name) {
99✔
398
        auto labelIt = symbols.find(name);
198✔
399
        return (symbols.end() != labelIt) ? labelIt->second.used : false;
99✔
400
}
401

402
bool CLabelTable::Remove(const char* name) {
×
403
        return symbols.erase(name);
×
404
}
405

406
void CLabelTable::RemoveAll() {
508✔
407
        symbols.clear();
508✔
408
}
508✔
409

410
static const std::vector<symbol_map_t::key_type> getDumpOrder(const symbol_map_t& table) {
363✔
411
        std::vector<symbol_map_t::key_type> order;
363✔
412
        order.reserve(table.size());
363✔
413
        for (const auto& it : table) order.emplace_back(it.first);
9,253✔
414
        if (Options::SortSymbols) {
363✔
415
                std::sort(
363✔
416
                        order.begin(), order.end(),
417
                        [&](const symbol_map_t::key_type& a, const symbol_map_t::key_type& b) {
52,381✔
418
                                // if case insenstive are same, do case sensitive too!
419
                                int caseres = strcasecmp(a.c_str(), b.c_str());
52,381✔
420
                                if (0 == caseres) return a < b;
52,381✔
421
                                return caseres < 0;
52,152✔
422
                        }
423
                );
424
        }
425
        return order;
363✔
426
}
×
427

428
void CLabelTable::Dump() {
474✔
429
        FILE* listFile = GetListingFile();
474✔
430
        if (NULL == listFile) return;                // listing file must be already opened here
474✔
431

432
        const auto order = getDumpOrder(symbols);
335✔
433

434
        char line[LINEMAX], *ep;
435
        fputs("\nValue    Label\n", listFile);
335✔
436
        fputs("------ - -----------------------------------------------------------\n", listFile);
335✔
437
        for (const symbol_map_t::key_type& name: order) {
8,478✔
438
                const symbol_map_t::mapped_type& symbol = symbols.at(name);
8,143✔
439
                if (LABEL_PAGE_UNDEFINED == symbol.page) continue;
8,143✔
440
                ep = line;
4,023✔
441
                *(ep) = 0;
4,023✔
442
                *(ep++) = '0';
4,023✔
443
                *(ep++) = 'x';
4,023✔
444
                PrintHexAlt(ep, symbol.value);
4,023✔
445
                *(ep++) = ' ';
4,023✔
446
                *(ep++) = symbol.used ? ' ' : 'X';
4,023✔
447
                *(ep++) = ' ';
4,023✔
448
                STRNCPY(ep, LINEMAX, name.c_str(), LINEMAX - (ep - line) - 2);
4,023✔
449
                STRNCAT(ep, LINEMAX, "\n", 2);
4,023✔
450
                fputs(line, listFile);
4,023✔
451
        }
452
}
335✔
453

454
void CLabelTable::DumpForUnreal() {
10✔
455
        char ln[LINEMAX], * ep;
456
        FILE* FP_UnrealList;
457
        if (!FOPEN_ISOK(FP_UnrealList, Options::UnrealLabelListFName, "w")) {
10✔
NEW
458
                Error("opening file for write", Options::UnrealLabelListFName.string().c_str(), FATAL);
×
459
        }
460
        const int PAGE_MASK = DeviceID ? Device->GetPage(0)->Size - 1 : 0x3FFF;
10✔
461
        const int ADR_MASK = Options::EmitVirtualLabels ? 0xFFFF : PAGE_MASK;
10✔
462
        const auto order = getDumpOrder(symbols);
10✔
463
        for (const symbol_map_t::key_type& name: order) {
244✔
464
                const symbol_map_t::mapped_type& symbol = symbols.at(name);
234✔
465
                if (LABEL_PAGE_UNDEFINED == symbol.page) continue;
234✔
466
                int page = Options::EmitVirtualLabels ? LABEL_PAGE_OUT_OF_BOUNDS : symbol.page;
114✔
467
                if (!strcmp(DeviceID, "ZXSPECTRUM48") && page < 4) {        //TODO fix this properly?
114✔
468
                        // convert pages {0, 1, 2, 3} of ZX48 into ZX128-like {ROM, 5, 2, 0}
469
                        // this can be fooled when there were multiple devices used, Label doesn't know into
470
                        // which device it does belong, so even ZX128 labels will be converted.
471
                        const int fakeZx128Pages[] = {LABEL_PAGE_ROM, 5, 2, 0};
1✔
472
                        page = fakeZx128Pages[page];
1✔
473
                }
474
                int lvalue = symbol.value & ADR_MASK;
114✔
475
                ep = ln;
114✔
476

477
                if (page < LABEL_PAGE_ROM) ep += sprintf(ep, "%02d", page&255);
114✔
478
                *(ep++) = ':';
114✔
479
                PrintHexAlt(ep, lvalue);
114✔
480

481
                *(ep++) = ' ';
114✔
482
                STRCPY(ep, LINEMAX-(ep-ln), name.c_str());
114✔
483
                STRCAT(ep, LINEMAX, "\n");
114✔
484
                fputs(ln, FP_UnrealList);
114✔
485
        }
486
        fclose(FP_UnrealList);
10✔
487
}
10✔
488

489
void CLabelTable::DumpForCSpect() {
12✔
490
        FILE* file;
491
        if (!FOPEN_ISOK(file, Options::CSpectMapFName, "w")) {
12✔
NEW
492
                Error("opening file for write", Options::CSpectMapFName.string().c_str(), FATAL);
×
493
        }
494
        const int CSD_PAGE_SIZE = Options::CSpectMapPageSize;
12✔
495
        const int CSD_PAGE_MASK = CSD_PAGE_SIZE - 1;
12✔
496
        const auto order = getDumpOrder(symbols);
12✔
497
        for (const symbol_map_t::key_type& name: order) {
392✔
498
                const symbol_map_t::mapped_type& symbol = symbols.at(name);
380✔
499
                if (LABEL_PAGE_UNDEFINED == symbol.page) continue;
380✔
500
                const int labelType =
225✔
501
                        (symbol.traits&LABEL_IS_STRUCT_E) ? 0 :
447✔
502
                        (symbol.traits&LABEL_IS_STRUCT_D) ? 4 :
438✔
503
                        (symbol.traits&LABEL_IS_EQU) ? 1 :
421✔
504
                        (symbol.traits&LABEL_IS_DEFL) ? 2 :
404✔
505
                        (LABEL_PAGE_ROM <= symbol.page) ? 3 : 0;
199✔
506
                const short page = labelType ? 0 : symbol.page;
225✔
507
                        // TODO:
508
                        // page == -1 will put regular EQU like "BLUE" out of reach for disassembly window
509
                        // (otherwise BLUE becomes label for address $C001 with default mapping)
510
                        // BUT then it would be nice to provide real page data for equ which have them explicit
511
                        // BUT I can't distinguish explicit/implicit page number, as there's heuristic to use current mapping
512
                        // instead of using the LABEL_PAGE_OUT_OF_BOUNDS page number...
513
                        // TODO: figure out when/why the implicit page number heuristic happenned and if you can detect
514
                        // only explicit page numbers used in EQU, and export only those
515

516
                const aint longAddress = (CSD_PAGE_MASK & symbol.value) + page * CSD_PAGE_SIZE;
225✔
517
                fprintf(file, "%08X %08X %02X ", 0xFFFF & symbol.value, longAddress, labelType);
225✔
518
                // convert primary+local label to be "@" delimited (not "." delimited)
519
                STRCPY(temp, LINEMAX, name.c_str());
225✔
520
                // look for "primary" label (where the local label starts)
521
                char* localLabelStart = strrchr(temp, '.');
225✔
522
                while (temp < localLabelStart) {        // the dot must be at least second character
344✔
523
                        *localLabelStart = 0;                        // terminate the possible "primary" part
160✔
524
                        if (Find(temp, true)) {
160✔
525
                                *localLabelStart = '@';
41✔
526
                                break;
41✔
527
                        }
528
                        *localLabelStart = '.';                        // "primary" label didn't work, restore dot
119✔
529
                        do {
530
                                --localLabelStart;                        // and look for next dot
293✔
531
                        } while (temp < localLabelStart && '.' != *localLabelStart);
293✔
532
                }
533
                // convert whole label to upper-case, as CSpect search is malfunctioning otherwise.
534
                char* strToUpper = temp;
225✔
535
                while ((*strToUpper = (char) toupper((byte)*strToUpper))) { ++strToUpper; }
2,883✔
536
                fprintf(file, "%s\n", temp);
225✔
537
        }
538
        fclose(file);
12✔
539
}
12✔
540

541
void CLabelTable::DumpSymbols() {
6✔
542
        FILE* symfp;
543
        if (!FOPEN_ISOK(symfp, Options::SymbolListFName, "w")) {
6✔
NEW
544
                Error("opening file for write", Options::SymbolListFName.string().c_str(), FATAL);
×
545
        }
546
        const auto order = getDumpOrder(symbols);
6✔
547
        for (const symbol_map_t::key_type& name: order) {
139✔
548
                const symbol_map_t::mapped_type& symbol = symbols.at(name);
133✔
549
                if (isdigit((byte)name[0])) continue;
133✔
550
                if (symbol.traits&LABEL_IS_KEYWORD) continue;
133✔
551
                WriteLabelEquValue(name.c_str(), symbol.value, symfp);
61✔
552
        }
553
        fclose(symfp);
6✔
554
}
6✔
555

556
int CFunctionTable::Insert(const char* name_cstr, function_fn_t nfunp) {
154,539✔
557
        std::string name(name_cstr);
154,539✔
558
        if (!std::get<1>(functions.emplace(name, nfunp))) return 0;
154,539✔
559
        for (auto& c : name) c = toupper(c);
981,429✔
560
        return std::get<1>(functions.emplace(name, nfunp));
154,539✔
561
}
154,539✔
562

563
int CFunctionTable::insertd(const char* name, function_fn_t nfunp) {
58,580✔
564
        if ('.' != name[0]) Error("Directive string must start with dot", NULL, FATAL);
58,580✔
565
        // insert the non-dot variant first, then dot variant
566
        return Insert(name+1, nfunp) && Insert(name, nfunp);
58,580✔
567
}
568

569
int CFunctionTable::zoek(const char* name) {
382,665✔
570
        auto it = functions.find(name);
765,330✔
571
        if (functions.end() == it) return 0;
382,665✔
572
        (*it->second)();
243,535✔
573
        return 1;
243,530✔
574
}
575

576
TemporaryLabel::TemporaryLabel(aint number, aint address)
97✔
577
        : nummer(number), value(address), isRelocatable(bool(Relocation::type)) {}
97✔
578

579
CTemporaryLabelTable::CTemporaryLabelTable() {
517✔
580
        labels.reserve(128);
517✔
581
        refresh = 0;
517✔
582
}
517✔
583

584
void CTemporaryLabelTable::InitPass() {
1,499✔
585
        refresh = 0;                // reset refresh pointer for next pass
1,499✔
586
}
1,499✔
587

588
bool CTemporaryLabelTable::insertImpl(const aint labelNumber) {
97✔
589
        labels.emplace_back(labelNumber, CurAddress);
97✔
590
        return true;
97✔
591
}
592

593
bool CTemporaryLabelTable::refreshImpl(const aint labelNumber) {
197✔
594
        if (labels.size() <= refresh || labels.at(refresh).nummer != labelNumber) return false;
197✔
595
        TemporaryLabel & to_r = labels.at(refresh);
194✔
596
        if (to_r.value != CurAddress) Warning("Temporary label has different address");
194✔
597
        to_r.value = CurAddress;
194✔
598
        ++refresh;
194✔
599
        return true;
194✔
600
}
601

602
bool CTemporaryLabelTable::InsertRefresh(const aint nnummer) {
294✔
603
        return (1 == pass) ? insertImpl(nnummer) : refreshImpl(nnummer);
294✔
604
}
605

606
const TemporaryLabel* CTemporaryLabelTable::seekForward(const aint labelNumber) const {
321✔
607
        if (1 == pass) return nullptr;                                        // just building tables in first pass, no results yet
321✔
608
        temporary_labels_t::size_type i = refresh;                // refresh already points at first "forward" temporary label
214✔
609
        while (i < labels.size() && labelNumber != labels[i].nummer) ++i;
240✔
610
        return (i < labels.size()) ? &labels[i] : nullptr;
214✔
611
}
612

613
const TemporaryLabel* CTemporaryLabelTable::seekBack(const aint labelNumber) const {
442✔
614
        if (1 == pass || refresh <= 0) return nullptr;        // just building tables or no temporary label "backward"
442✔
615
        temporary_labels_t::size_type i = refresh;                // after last "backward" temporary label
282✔
616
        while (i--) if (labelNumber == labels[i].nummer) return &labels[i];
366✔
617
        return nullptr;                                                                        // not found
2✔
618
}
619

620
CStringsList::CStringsList(const char* stringSource, CStringsList* nnext) {
33,941✔
621
        string = STRDUP(stringSource);
33,941✔
622
        next = nnext;
33,941✔
623
        if (!sourcePosStack.empty()) source = sourcePosStack.back();
33,941✔
624
}
33,941✔
625

626
CStringsList::~CStringsList() {
33,932✔
627
        if (string) free(string);
33,932✔
628
        if (next) delete next;
33,932✔
629
}
33,932✔
630

631
bool CStringsList::contains(const CStringsList* strlist, const char* searchString) {
200✔
632
        while (nullptr != strlist) {
372✔
633
                if (!strcmp(searchString, strlist->string)) return true;
173✔
634
                strlist = strlist->next;
172✔
635
        }
636
        return false;
199✔
637
}
638

639
CDefineTableEntry::CDefineTableEntry(const char* nname, const char* nvalue, CStringsList* nnss, CDefineTableEntry* nnext)
28,530✔
640
                : name(NULL), value(NULL) {
28,530✔
641
        name = STRDUP(nname);
28,530✔
642
        value = new char[strlen(nvalue) + 1];
28,530✔
643
        if (NULL == name || NULL == value) ErrorOOM();
28,530✔
644
        char* s1 = value;
28,530✔
645
        while (*nvalue && *nvalue != '\n' && *nvalue != '\r') *s1++ = *nvalue++;
231,111✔
646
        *s1 = 0;
28,530✔
647
        next = nnext;
28,530✔
648
        nss = nnss;
28,530✔
649
}
28,530✔
650

651
CDefineTableEntry::~CDefineTableEntry() {
28,530✔
652
        if (name) free(name);
28,530✔
653
        if (value) delete[] value;
28,530✔
654
        if (nss) delete nss;
28,530✔
655
        if (next) delete next;
28,530✔
656
}
28,530✔
657

658
void CDefineTableEntry::Replace(const char* nvalue) {
21,396✔
659
        if (value) delete[] value;
21,396✔
660
        value = new char[strlen(nvalue) + 1];
21,396✔
661
        strcpy(value, nvalue);
21,396✔
662
}
21,396✔
663

664
CDefineTable::~CDefineTable() {
1,034✔
665
        for (auto def : defs) if (def) delete def;
133,386✔
666
}
1,034✔
667

668
CDefineTable& CDefineTable::operator=(CDefineTable const & defTable) {
1,499✔
669
        RemoveAll();
1,499✔
670
        for (CDefineTableEntry* srcDef : defTable.defs) {
193,371✔
671
                CDefineTableEntry* srcD = srcDef;
191,872✔
672
                while (srcD) {
194,996✔
673
                        Add(srcD->name, srcD->value, srcD->nss);
3,124✔
674
                        srcD = srcD->next;
3,124✔
675
                }
676
        }
677
        return *this;
1,499✔
678
}
679

680
void CDefineTable::Init() {
1,034✔
681
        DefArrayList = NULL;
1,034✔
682
        for (auto & def : defs) def = NULL;
133,386✔
683
}
1,034✔
684

685
void CDefineTable::Add(const char* name, const char* value, CStringsList* nss) {
4,645✔
686
        if (FindDuplicate(name)) {
4,645✔
687
                Error("Duplicate define (replacing old value)", name, PASS03);
16✔
688
        }
689
        defs[(*name)&127] = new CDefineTableEntry(name, value, nss, defs[(*name)&127]);
4,645✔
690
}
4,645✔
691

692
static char defineGet__Counter__Buffer[32] = {};
693
static char defineGet__Line__Buffer[32] = {};
694

695
const char* CDefineTable::Get(const char* name) {
1,742,649✔
696
        DefArrayList = nullptr;
1,742,649✔
697
        if (nullptr == name || 0 == name[0]) return nullptr;
1,742,649✔
698
        // the __COUNTER__ and __LINE__ have fully dynamic custom implementation here
699
        if ('_' == name[1]) {
1,742,643✔
700
                if (!strcmp(name, "__COUNTER__")) {
65,816✔
701
                        SPRINTF1(defineGet__Counter__Buffer, 30, "%d", PredefinedCounter);
15,381✔
702
                        ++PredefinedCounter;
15,381✔
703
                        return defineGet__Counter__Buffer;
15,381✔
704
                }
705
                if (!strcmp(name, "__LINE__")) {
50,435✔
706
                        SPRINTF1(defineGet__Line__Buffer, 30, "%d", sourcePosStack.empty() ? 0 : sourcePosStack.back().line);
15✔
707
                        return defineGet__Line__Buffer;
15✔
708
                }
709
        }
710
        CDefineTableEntry* p = defs[(*name)&127];
1,727,247✔
711
        while (p && strcmp(name, p->name)) p = p->next;
2,334,126✔
712
        if (nullptr == p) return nullptr;
1,727,247✔
713
        DefArrayList = p->nss;
16,925✔
714
        return p->value;
16,925✔
715
}
716

717
int CDefineTable::FindDuplicate(const char* name) {
5,752✔
718
        CDefineTableEntry* p = defs[(*name)&127];
5,752✔
719
        while (p) {
11,830✔
720
                if (!strcmp(name, p->name)) {
7,108✔
721
                        return 1;
1,030✔
722
                }
723
                p = p->next;
6,078✔
724
        }
725
        return 0;
4,722✔
726
}
727

728
int CDefineTable::Replace(const char* name, const char* value) {
43,921✔
729
        CDefineTableEntry* p = defs[(*name)&127];
43,921✔
730
        while (p) {
337,028✔
731
                if (!strcmp(name, p->name)) {
314,503✔
732
                        p->Replace(value);
21,396✔
733
                        return 0;
21,396✔
734
                }
735
                p = p->next;
293,107✔
736
        }
737
        defs[(*name)&127] = new CDefineTableEntry(name, value, 0, defs[(*name)&127]);
22,525✔
738
        return 1;
22,525✔
739
}
740

741
int CDefineTable::Replace(const char* name, const int value) {
15,816✔
742
        char newIntValue[24];
743
        SPRINTF1(newIntValue, sizeof(newIntValue), "%d", value);
15,816✔
744
        return Replace(name, newIntValue);
31,632✔
745
}
746

747
int CDefineTable::Remove(const char* name) {
90✔
748
        CDefineTableEntry* p = defs[(*name)&127];
90✔
749
        CDefineTableEntry* p2 = NULL;
90✔
750
        while (p) {
93✔
751
                if (!strcmp(name, p->name)) {
93✔
752
                        // unchain the particular item
753
                        if (NULL == p2) defs[(*name)&127] = p->next;
90✔
754
                        else                        p2->next = p->next;
3✔
755
                        p->next = NULL;
90✔
756
                        // delete it
757
                        delete p;
90✔
758
                        DefArrayList = NULL;                // may be invalid here, so just reset it
90✔
759
                        return 1;
90✔
760
                }
761
                p2 = p;
3✔
762
                p = p->next;
3✔
763
        }
764
        return 0;
×
765
}
766

767
void CDefineTable::RemoveAll() {
2,010✔
768
        DefArrayList = NULL;
2,010✔
769
        for (auto & def : defs) {
259,290✔
770
                if (!def) continue;
257,280✔
771
                delete def;
1,762✔
772
                def = NULL;
1,762✔
773
        }
774
}
2,010✔
775

776
CMacroDefineTable::CMacroDefineTable() : defs(nullptr) {
517✔
777
        for (auto & usedX : used) usedX = false;
66,693✔
778
}
517✔
779

780
CMacroDefineTable::~CMacroDefineTable() {
517✔
781
        if (defs) delete defs;
517✔
782
}
517✔
783

784
void CMacroDefineTable::ReInit() {
2,443✔
785
        if (defs) delete defs;
2,443✔
786
        defs = nullptr;
2,443✔
787
        for (auto & usedX : used) usedX = false;
315,147✔
788
}
2,443✔
789

790
void CMacroDefineTable::AddMacro(char* naam, char* vervanger) {
1,360✔
791
        CDefineTableEntry* tmpdefs = new CDefineTableEntry(naam, vervanger, 0, defs);
1,360✔
792
        defs = tmpdefs;
1,360✔
793
        used[(*naam)&127] = true;
1,360✔
794
}
1,360✔
795

796
CDefineTableEntry* CMacroDefineTable::getdefs() {
1,472✔
797
        return defs;
1,472✔
798
}
799

800
void CMacroDefineTable::setdefs(CDefineTableEntry* const ndefs) {
1,430✔
801
        if (ndefs == defs) return;                        // the current HEAD of defines is already same as requested one
1,430✔
802
        // traverse through current HEAD until the requested chain is found, unchain the HEAD from it
803
        CDefineTableEntry* entry = defs;
683✔
804
        while (entry && ndefs != entry->next) entry = entry->next;
1,330✔
805
        if (entry) entry->next = nullptr;        // if "ndefs" is chained to current HEAD, unchain
683✔
806
        if (defs) delete defs;                                // release front part of current chain from memory
683✔
807
        defs = ndefs;                                                // the requested chain is new current HEAD
683✔
808
}
809

810
const char* CMacroDefineTable::getverv(const char* name) const {
48,076✔
811
        if (nullptr == name) return nullptr;
48,076✔
812
        if (!used[(*name)&127]) return nullptr;
48,076✔
813
        const CDefineTableEntry* p = defs;
8,859✔
814
        while (p && strcmp(name, p->name)) p = p->next;
44,014✔
815
        return p ? p->value : nullptr;
8,859✔
816
}
817

818
int CMacroDefineTable::FindDuplicate(char* name) {
×
819
        CDefineTableEntry* p = defs;
×
820
        if (!used[(*name)&127]) {
×
821
                return 0;
×
822
        }
823
        while (p) {
×
824
                if (!strcmp(name, p->name)) {
×
825
                        return 1;
×
826
                }
827
                p = p->next;
×
828
        }
829
        return 0;
×
830
}
831

832
CMacroTableEntry::CMacroTableEntry(char* nnaam, CMacroTableEntry* nnext)
480✔
833
        : naam(nnaam), args(nullptr), body(nullptr), next(nnext) {
480✔
834
}
480✔
835

836
CMacroTableEntry::~CMacroTableEntry() {
480✔
837
        if (naam) free(naam);        // must be of STRDUP origin!
480✔
838
        if (args) delete args;
480✔
839
        if (body) delete body;
480✔
840
        if (next) delete next;
480✔
841
}
480✔
842

843
CMacroTable::CMacroTable() : macs(nullptr) {
517✔
844
        for (auto & usedX : used) usedX = false;
66,693✔
845
}
517✔
846

847
CMacroTable::~CMacroTable() {
517✔
848
        if (macs) delete macs;
517✔
849
}
517✔
850

851
void CMacroTable::ReInit() {
1,499✔
852
        if (macs) delete macs;
1,499✔
853
        macs = nullptr;
1,499✔
854
        for (auto & usedX : used) usedX = false;
193,371✔
855
}
1,499✔
856

857
int CMacroTable::FindDuplicate(const char* naam) {
486✔
858
        CMacroTableEntry* p = macs;
486✔
859
        if (!used[(*naam)&127]) {
486✔
860
                return 0;
312✔
861
        }
862
        while (p) {
636✔
863
                if (!strcmp(naam, p->naam)) {
468✔
864
                        return 1;
6✔
865
                }
866
                p = p->next;
462✔
867
        }
868
        return 0;
168✔
869
}
870

871
void CMacroTable::Add(const char* nnaam, char*& p) {
486✔
872
        if (FindDuplicate(nnaam)) {
486✔
873
                Error("Duplicate macroname", nnaam);return;
6✔
874
        }
875
        char* macroname = STRDUP(nnaam);
480✔
876
        if (macroname == NULL) ErrorOOM();
480✔
877
        macs = new CMacroTableEntry(macroname, macs);
480✔
878
        used[(*macroname)&127] = true;
480✔
879
        CStringsList* last = nullptr;
480✔
880
        do {
881
                char* n = GetID(p);
774✔
882
                if (!n) {
774✔
883
                        // either EOL when no previous argument, or valid name is required after comma (2nd+ loop)
884
                        if ((1 == pass) && (last || *p)) Error("Illegal argument name", p, EARLY);
174✔
885
                        SkipToEol(p);
174✔
886
                        break;
174✔
887
                }
888
                if ((1 == pass) && CStringsList::contains(macs->args, n)) {
600✔
889
                        Error("Duplicate argument name", n, EARLY);
1✔
890
                }
891
                CStringsList* argname = new CStringsList(n);
600✔
892
                if (!macs->args) {
600✔
893
                        macs->args = argname;        // first argument name, make it head of list
312✔
894
                } else {
895
                        last->next = argname;
288✔
896
                }
897
                last = argname;
600✔
898
        } while (anyComma(p));
600✔
899
        if ((1 == pass) && *p) {
480✔
900
                Error("Unexpected", p, EARLY);
2✔
901
        }
902
        ListFile();
480✔
903
        if (!ReadFileToCStringsList(macs->body, "endm")) {
480✔
904
                Error("Unexpected end of macro", NULL, EARLY);
3✔
905
        }
906
}
907

908
int CMacroTable::Emit(char* naam, char*& p) {
243,343✔
909
        // search for the desired macro
910
        if (!used[(*naam)&127]) return 0;
243,343✔
911
        CMacroTableEntry* m = macs;
1,966✔
912
        while (m && strcmp(naam, m->naam)) m = m->next;
3,985✔
913
        if (!m) return 0;
1,966✔
914
        // macro found, emit it, prepare temporary instance label base
915
        char* omacrolabp = macrolabp;
1,472✔
916
        char labnr[LINEMAX], ml[LINEMAX];
917
        SPRINTF1(labnr, LINEMAX, "%d", macronummer++);
1,472✔
918
        macrolabp = labnr;
1,472✔
919
        if (omacrolabp) {
1,472✔
920
                STRCAT(macrolabp, LINEMAX-1, "."); STRCAT(macrolabp, LINEMAX-1, omacrolabp);
528✔
921
        } else {
922
                MacroDefineTable.ReInit();
944✔
923
        }
924
        // parse argument values
925
        CDefineTableEntry* odefs = MacroDefineTable.getdefs();
1,472✔
926
        CStringsList* a = m->args;
1,472✔
927
        while (a) {
2,832✔
928
                char* n = ml;
1,375✔
929
                const bool lastArg = NULL == a->next;
1,375✔
930
                if (!GetMacroArgumentValue(p, n) || (!lastArg && !comma(p))) {
1,375✔
931
                        Error("Not enough arguments for macro", naam, SUPPRESS);
15✔
932
                        macrolabp = omacrolabp;
15✔
933
                        return 1;
15✔
934
                }
935
                MacroDefineTable.AddMacro(a->string, ml);
1,360✔
936
                a = a->next;
1,360✔
937
        }
938
        SkipBlanks(p);
1,457✔
939
        if (*p) {
1,457✔
940
                Error("Too many arguments for macro", naam, SUPPRESS);
27✔
941
                macrolabp = omacrolabp;
27✔
942
                return 1;
27✔
943
        }
944
        // arguments parsed, emit the macro lines and parse them
945
        lp = p;
1,430✔
946
        ListFile();
1,430✔
947
        ++listmacro;
1,430✔
948
        CStringsList* olijstp = lijstp;
1,430✔
949
        lijstp = m->body;
1,430✔
950
        ++lijst;
1,430✔
951
        STRCPY(ml, LINEMAX, line);
1,430✔
952
        sourcePosStack.push_back(TextFilePos());
1,430✔
953
        while (lijstp) {
7,091✔
954
                sourcePosStack.back() = lijstp->source;
5,661✔
955
                STRCPY(line, LINEMAX, lijstp->string);
5,661✔
956
                substitutedLine = line;                // reset substituted listing
5,661✔
957
                eolComment = NULL;                        // reset end of line comment
5,661✔
958
                lijstp = lijstp->next;
5,661✔
959
                ParseLineSafe();
5,661✔
960
        }
961
        sourcePosStack.pop_back();
1,430✔
962
        ++CompiledCurrentLine;
1,430✔
963
        STRCPY(line, LINEMAX, ml);
1,430✔
964
        lijstp = olijstp;
1,430✔
965
        --lijst;
1,430✔
966
        MacroDefineTable.setdefs(odefs);
1,430✔
967
        macrolabp = omacrolabp;
1,430✔
968
        --listmacro; donotlist = 1;
1,430✔
969
        return 2;
1,430✔
970
}
971

972
CStructureEntry1::CStructureEntry1(char* nnaam, aint noffset) {
1,227✔
973
        next = 0;
1,227✔
974
        naam = STRDUP(nnaam);
1,227✔
975
        if (naam == NULL) ErrorOOM();
1,227✔
976
        offset = noffset;
1,227✔
977
}
1,227✔
978

979
CStructureEntry1::~CStructureEntry1() {
1,227✔
980
        free(naam);
1,227✔
981
        if (next) delete next;
1,227✔
982
}
1,227✔
983

984
CStructureEntry2::CStructureEntry2(aint noffset, aint nlen, aint ndef, Relocation::EType ndeltatype, EStructureMembers ntype) :
1,405✔
985
        next(nullptr), text(nullptr), offset(noffset), len(nlen), def(ndef), defDeltaType(ndeltatype), type(ntype)
1,405✔
986
{
987
}
1,405✔
988

989
CStructureEntry2::CStructureEntry2(aint noffset, aint nlen, byte* textData) :
108✔
990
        next(nullptr), text(textData), offset(noffset), len(nlen), def(0), defDeltaType(Relocation::OFF), type(SMEMBTEXT)
108✔
991
{
992
        assert(1 <= len && len <= TEXT_MAX_SIZE && nullptr != text);
108✔
993
}
108✔
994

995
CStructureEntry2::~CStructureEntry2() {
1,513✔
996
        if (next) delete next;
1,513✔
997
        if (text) delete[] text;
1,513✔
998
}
1,513✔
999

1000
// Parses source input for types: BYTE, WORD, DWORD, D24
1001
aint CStructureEntry2::ParseValue(char* & p) {
3,975✔
1002
        if (SMEMBBYTE != type && SMEMBWORD != type && SMEMBDWORD != type && SMEMBD24 != type) return def;
3,975✔
1003
        SkipBlanks(p);
3,975✔
1004
        aint val = def;
3,975✔
1005
        bool keepRelocatableFlags = false;        // keep flags from the ParseExpressionNoSyntaxError?
3,975✔
1006
        // check for unexpected {
1007
        if ('{' != *p) {
3,975✔
1008
                if (!(keepRelocatableFlags = ParseExpressionNoSyntaxError(p, val))) {
3,291✔
1009
                        val = def;
1,983✔
1010
                }
1011
                switch (type) {
3,291✔
1012
                        case SMEMBBYTE:
2,259✔
1013
                                check8(val);
2,259✔
1014
                                val &= 0xFF;
2,259✔
1015
                                break;
2,259✔
1016
                        case SMEMBWORD:
741✔
1017
                                check16(val);
741✔
1018
                                val &= 0xFFFF;
741✔
1019
                                break;
741✔
1020
                        case SMEMBD24:
135✔
1021
                                check24(val);
135✔
1022
                                val &= 0xFFFFFF;
135✔
1023
                                break;
135✔
1024
                        case SMEMBDWORD:
156✔
1025
                                break;
156✔
1026
                        default:
×
1027
                                break;
×
1028
                }
1029
        }
1030
        if (!Relocation::type) return val;
3,975✔
1031
        if (SMEMBBYTE == type && Relocation::HIGH == Relocation::type) {
435✔
1032
                if (!keepRelocatableFlags) {        // override flags, if parse expression was not successful
24✔
1033
                        Relocation::isResultAffected |= bool(defDeltaType);
12✔
1034
                        Relocation::deltaType = defDeltaType;
12✔
1035
                }
1036
                Relocation::resolveRelocationAffected(0, Relocation::HIGH);
24✔
1037
        } else if (SMEMBWORD == type) {
411✔
1038
                if (!keepRelocatableFlags) {        // override flags, if parse expression was not successful
234✔
1039
                        Relocation::isResultAffected |= bool(defDeltaType);
168✔
1040
                        Relocation::deltaType = defDeltaType;
168✔
1041
                }
1042
                Relocation::resolveRelocationAffected(0);
234✔
1043
        }
1044
        Relocation::checkAndWarn();
435✔
1045
        return val;
435✔
1046
}
1047

1048
CStructure::CStructure(const char* nnaam, char* nid, int no, int ngl, CStructure* p) {
237✔
1049
        mnf = mnl = NULL; mbf = mbl = NULL;
237✔
1050
        naam = STRDUP(nnaam);
237✔
1051
        if (naam == NULL) ErrorOOM();
237✔
1052
        id = STRDUP(nid);
237✔
1053
        if (id == NULL) ErrorOOM();
237✔
1054
        next = p; noffset = no; global = ngl;
237✔
1055
        maxAlignment = 0;
237✔
1056
}
237✔
1057

1058
CStructure::~CStructure() {
237✔
1059
        free(naam);
237✔
1060
        free(id);
237✔
1061
        if (mnf) delete mnf;
237✔
1062
        if (mbf) delete mbf;
237✔
1063
        if (next) delete next;
237✔
1064
}
237✔
1065

1066
void CStructure::AddLabel(char* nnaam) {
984✔
1067
        CopyLabel(nnaam, 0);
984✔
1068
}
984✔
1069

1070
void CStructure::AddMember(CStructureEntry2* n) {
1,513✔
1071
        if (!mbf)        mbf = n;
1,513✔
1072
        else                 mbl->next = n;
1,285✔
1073
        mbl = n;
1,513✔
1074
        noffset += n->len;
1,513✔
1075
}
1,513✔
1076

1077
void CStructure::CopyLabel(char* nnaam, aint offset) {
1,227✔
1078
        CStructureEntry1* n = new CStructureEntry1(nnaam, noffset + offset);
1,227✔
1079
        if (!mnf)        mnf = n;
1,227✔
1080
        else                mnl->next = n;
999✔
1081
        mnl = n;
1,227✔
1082
}
1,227✔
1083

1084
void CStructure::CopyLabels(CStructure* st) {
81✔
1085
        CStructureEntry1* np = st->mnf;
81✔
1086
        if (!np || !PreviousIsLabel) return;
81✔
1087
        char str[LINEMAX];
1088
        STRCPY(str, LINEMAX-1, PreviousIsLabel);
81✔
1089
        STRCAT(str, LINEMAX-1, ".");
81✔
1090
        char * const stw = str + strlen(str);
81✔
1091
        while (np) {
324✔
1092
                STRCPY(stw, LINEMAX, np->naam);        // overwrite the second part of label
243✔
1093
                CopyLabel(str, np->offset);
243✔
1094
                np = np->next;
243✔
1095
        }
1096
}
1097

1098
void CStructure::CopyMember(CStructureEntry2* item, aint newDefault, Relocation::EType newDeltaType) {
333✔
1099
        AddMember(new CStructureEntry2(noffset, item->len, newDefault, newDeltaType, item->type));
333✔
1100
}
333✔
1101

1102
void CStructure::CopyMembers(CStructure* st, char*& lp) {
81✔
1103
        aint val;
1104
        int haakjes = 0;
81✔
1105
        AddMember(new CStructureEntry2(noffset, 0, 0, Relocation::OFF, SMEMBPARENOPEN));
81✔
1106
        SkipBlanks(lp);
81✔
1107
        if (*lp == '{') {
81✔
1108
                ++haakjes; ++lp;
45✔
1109
        }
1110
        CStructureEntry2* ip = st->mbf;
81✔
1111
        while (ip || 0 < haakjes) {
492✔
1112
                Relocation::isResultAffected = false;
411✔
1113
                // check if inside curly braces block, and input seems to be empty -> fetch next line
1114
                if (0 < haakjes && !PrepareNonBlankMultiLine(lp)) break;
411✔
1115
                if (nullptr == ip) {        // no more struct members expected, looking for closing '}'
411✔
1116
                        assert(0 < haakjes);
45✔
1117
                        if (!need(lp, '}')) break;
45✔
1118
                        --haakjes;
45✔
1119
                        continue;
45✔
1120
                }
1121
                assert(ip);
366✔
1122
                switch (ip->type) {
366✔
1123
                case SMEMBBLOCK:
24✔
1124
                        CopyMember(ip, ip->def, Relocation::OFF);
24✔
1125
                        break;
24✔
1126
                case SMEMBBYTE:
261✔
1127
                case SMEMBWORD:
1128
                case SMEMBD24:
1129
                case SMEMBDWORD:
1130
                        {
1131
                                Relocation::EType isRelocatable = Relocation::OFF;
261✔
1132
                                if (ParseExpressionNoSyntaxError(lp, val)) {
261✔
1133
                                        isRelocatable = (Relocation::isResultAffected && (SMEMBWORD == ip->type || SMEMBBYTE == ip->type))
159✔
1134
                                                                                ? Relocation::deltaType : Relocation::OFF;
159✔
1135
                                } else {
1136
                                        val = ip->def;
108✔
1137
                                        isRelocatable = ip->defDeltaType;
108✔
1138
                                }
1139
                                CopyMember(ip, val, isRelocatable);
261✔
1140
                                if (SMEMBWORD == ip->type) {
261✔
1141
                                        Relocation::resolveRelocationAffected(INT_MAX);        // clear flags + warn when can't be relocated
54✔
1142
                                } else if (SMEMBBYTE == ip->type) {
207✔
1143
                                        Relocation::resolveRelocationAffected(INT_MAX, Relocation::HIGH);        // clear flags + warn when can't be relocated
195✔
1144
                                }
1145
                                if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(lp);
261✔
1146
                        }
1147
                        break;
261✔
1148
                case SMEMBTEXT:
33✔
1149
                        {
1150
                                byte* textData = new byte[ip->len]();        // zero initialized for stable binary results
174✔
1151
                                if (nullptr == textData) ErrorOOM();
33✔
1152
                                GetStructText(lp, ip->len, textData, ip->text);
33✔
1153
                                AddMember(new CStructureEntry2(noffset, ip->len, textData));
33✔
1154
                                if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(lp);
33✔
1155
                        }
1156
                        break;
33✔
1157
                case SMEMBPARENOPEN:
24✔
1158
                        SkipBlanks(lp);
24✔
1159
                        if (*lp == '{') {
24✔
1160
                                ++haakjes; ++lp;
6✔
1161
                        }
1162
                        CopyMember(ip, 0, Relocation::OFF);
24✔
1163
                        break;
24✔
1164
                case SMEMBPARENCLOSE:
24✔
1165
                        SkipBlanks(lp);
24✔
1166
                        if (haakjes && *lp == '}') {
24✔
1167
                                --haakjes; ++lp;
6✔
1168
                                if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(lp);
6✔
1169
                        }
1170
                        CopyMember(ip, 0, Relocation::OFF);
24✔
1171
                        break;
24✔
1172
                default:
×
1173
                        Error("internalerror CStructure::CopyMembers", NULL, FATAL);
×
1174
                }
1175
                Relocation::checkAndWarn();
366✔
1176
                ip = ip->next;
366✔
1177
        }
1178
        if (haakjes) {
81✔
1179
                Error("closing } missing");
×
1180
        }
1181
        AddMember(new CStructureEntry2(noffset, 0, 0, Relocation::OFF, SMEMBPARENCLOSE));
81✔
1182
}
81✔
1183

1184
static void InsertSingleStructLabel(const bool setNameSpace, char *name, const bool isRelocatable, const aint value, const bool isDefine = true) {
7,194✔
1185
        char *op = name;
7,194✔
1186
        std::unique_ptr<char[]> p(ValidateLabel(op, setNameSpace));
7,194✔
1187
        if (!p) {
7,194✔
1188
                Error("Illegal labelname", op, EARLY);
3✔
1189
                return;
3✔
1190
        }
1191
        if (pass == LASTPASS) {
7,191✔
1192
                aint oval;
1193
                if (!GetLabelValue(op, oval)) {
2,397✔
1194
                        Error("Internal error. ParseLabel()", op, FATAL);
×
1195
                }
1196
                if (value != oval) {
2,397✔
1197
                        Error("Label has different value in pass 2", p.get());
5✔
1198
                }
1199
                if (IsSldExportActive()) {                // SLD (Source Level Debugging) tracing-data logging
2,397✔
1200
                        SLabelTableEntry* symbol = LabelTable.Find(p.get(), true);
62✔
1201
                        assert(symbol);        // should have been already defined before last pass
62✔
1202
                        if (symbol) {
62✔
1203
                                WriteToSldFile(isDefine ? -1 : symbol->page, value, 'L', ExportLabelToSld(name, symbol));
62✔
1204
                        }
1205
                }
1206
        } else {
1207
                Relocation::isResultAffected = isRelocatable;
4,794✔
1208
                Relocation::deltaType = isRelocatable ? Relocation::REGULAR : Relocation::OFF;
4,794✔
1209
                assert(!isDefine || Relocation::OFF == Relocation::deltaType);        // definition labels are always nonrel
4,794✔
1210
                unsigned traits = LABEL_HAS_RELOC_TRAIT \
4,794✔
1211
                                                | (isDefine ? LABEL_IS_STRUCT_D : LABEL_IS_STRUCT_E) \
4,794✔
1212
                                                | (isRelocatable ? LABEL_IS_RELOC : 0);
4,794✔
1213
                if (!LabelTable.Insert(p.get(), value, traits)) Error("Duplicate label", p.get(), EARLY);
4,794✔
1214
        }
1215
}
7,194✔
1216

1217
static void InsertStructSubLabels(const char* mainName, const bool isRelocatable, const CStructureEntry1* members, const aint address = 0, const bool isDefine = true) {
756✔
1218
        char ln[LINEMAX+1];
1219
        STRCPY(ln, LINEMAX, mainName);
756✔
1220
        char * const lnsubw = ln + strlen(ln);
756✔
1221
        while (members) {
7,194✔
1222
                STRCPY(lnsubw, LINEMAX-strlen(ln), members->naam);                // overwrite sub-label part
6,438✔
1223
                InsertSingleStructLabel(false, ln, isRelocatable, members->offset + address, isDefine);
6,438✔
1224
                members = members->next;
6,438✔
1225
        }
1226
}
756✔
1227

1228
void CStructure::deflab() {
237✔
1229
        const size_t moduleNameLength = strlen(ModuleName);
237✔
1230
        char sn[LINEMAX] = { '@', 0 };
237✔
1231
        if (moduleNameLength && (0 == strncmp(id, ModuleName, moduleNameLength)) \
237✔
1232
                && ('.' == id[moduleNameLength]) && (id[moduleNameLength+1]))
21✔
1233
        {
1234
                // looks like the structure name starts with current module name, use non-global way then
1235
                STRCPY(sn, LINEMAX-1, id + moduleNameLength + 1);
21✔
1236
        } else {
1237
                // the structure name does not match current module, use the global "@id" way to define it
1238
                STRCPY(sn+1, LINEMAX-1, id);
216✔
1239
        }
1240
        InsertSingleStructLabel(true, sn, false, noffset);
237✔
1241
        STRCAT(sn, LINEMAX-1, ".");
237✔
1242
        InsertStructSubLabels(sn, false, mnf);
237✔
1243
}
237✔
1244

1245
void CStructure::emitlab(char* iid, aint address, const bool isRelocatable) {
519✔
1246
        const aint misalignment = maxAlignment ? ((-address) & (maxAlignment - 1)) : 0;
519✔
1247
        if (misalignment) {
519✔
1248
                // emitting in misaligned position (considering the ALIGN used to define this struct)
1249
                char warnTxt[LINEMAX];
1250
                SPRINTF3(warnTxt, LINEMAX,
13✔
1251
                                        "Struct %s did use ALIGN %d in definition, but here it is misaligned by %d bytes",
1252
                                        naam, maxAlignment, misalignment);
1253
                Warning(warnTxt);
13✔
1254
        }
1255
        char sn[LINEMAX] { 0 };
519✔
1256
        STRCPY(sn, LINEMAX-1, iid);
519✔
1257
        InsertSingleStructLabel(true, sn, isRelocatable, address, false);
519✔
1258
        STRCAT(sn, LINEMAX-1, ".");
519✔
1259
        InsertStructSubLabels(sn, isRelocatable, mnf, address, false);
519✔
1260
}
519✔
1261

1262
void CStructure::emitmembs(char*& p) {
636✔
1263
        byte* emitTextBuffer = nullptr;
636✔
1264
        aint val;
1265
        int haakjes = 0;
636✔
1266
        SkipBlanks(p);
636✔
1267
        if (*p == '{') {
636✔
1268
                ++haakjes; ++p;
327✔
1269
        }
1270
        CStructureEntry2* ip = mbf;
636✔
1271
        Relocation::isResultAffected = false;
636✔
1272
        while (ip || 0 < haakjes) {
7,898✔
1273
                // check if inside curly braces block, and input seems to be empty -> fetch next line
1274
                if (0 < haakjes && !PrepareNonBlankMultiLine(p)) break;
7,289✔
1275
                if (nullptr == ip) {        // no more struct members expected, looking for closing '}'
7,280✔
1276
                        assert(0 < haakjes);
258✔
1277
                        if (!need(p, '}')) break;
258✔
1278
                        --haakjes;
240✔
1279
                        continue;
240✔
1280
                }
1281
                assert(ip);
7,022✔
1282
                switch (ip->type) {
7,022✔
1283
                case SMEMBBLOCK:
821✔
1284
                        EmitBlock(ip->def != -1 ? ip->def : 0, ip->len, ip->def == -1, 8);
821✔
1285
                        if (8 < ip->len) ListFile();        // "..." elipsis happened in listing, force listing
821✔
1286
                        break;
821✔
1287
                case SMEMBBYTE:
2,466✔
1288
                        EmitByte(ip->ParseValue(p));
2,466✔
1289
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
2,466✔
1290
                        break;
2,466✔
1291
                case SMEMBWORD:
942✔
1292
                        // ParseValue will also add relocation data if needed (so the "ParseValue" name is misleading)
1293
                        EmitWord(ip->ParseValue(p));
942✔
1294
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
942✔
1295
                        break;
942✔
1296
                case SMEMBD24:
204✔
1297
                        val = ip->ParseValue(p);
204✔
1298
                        EmitByte(val & 0xFF);
204✔
1299
                        EmitWord((val>>8) & 0xFFFF);
204✔
1300
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
204✔
1301
                        break;
204✔
1302
                case SMEMBDWORD:
363✔
1303
                        val = ip->ParseValue(p);
363✔
1304
                        EmitWord(val & 0xFFFF);
363✔
1305
                        EmitWord((val>>16) & 0xFFFF);
363✔
1306
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
363✔
1307
                        break;
363✔
1308
                case SMEMBTEXT:
564✔
1309
                        {
1310
                                if (nullptr == emitTextBuffer) {
564✔
1311
                                        emitTextBuffer = new byte[CStructureEntry2::TEXT_MAX_SIZE+2];
129✔
1312
                                        if (nullptr == emitTextBuffer) ErrorOOM();
129✔
1313
                                }
1314
                                memset(emitTextBuffer, 0, ip->len);
564✔
1315
                                GetStructText(p, ip->len, emitTextBuffer, ip->text);
564✔
1316
                                for (aint ii = 0; ii < ip->len; ++ii) EmitByte(emitTextBuffer[ii]);
4,119✔
1317
                        }
1318
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
564✔
1319
                        break;
564✔
1320
                case SMEMBPARENOPEN:
831✔
1321
                        SkipBlanks(p);
831✔
1322
                        if (*p == '{') { ++haakjes; ++p; }
831✔
1323
                        break;
831✔
1324
                case SMEMBPARENCLOSE:
831✔
1325
                        SkipBlanks(p);
831✔
1326
                        if (haakjes && *p == '}') {
831✔
1327
                                --haakjes; ++p;
417✔
1328
                        }
1329
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
831✔
1330
                        break;
831✔
1331
                default:
×
1332
                        ErrorInt("Internal Error CStructure::emitmembs", ip->type, FATAL);
×
1333
                }
1334
                ip = ip->next;
7,022✔
1335
        }
1336
        if (haakjes) {
636✔
1337
                Error("closing } missing");
27✔
1338
        }
1339
        if (!SkipBlanks(p)) Error("[STRUCT] Syntax error - too many arguments?");
636✔
1340
        Relocation::checkAndWarn();
636✔
1341
        if (nullptr != emitTextBuffer) delete[] emitTextBuffer;
636✔
1342
}
636✔
1343

1344
CStructureTable::CStructureTable() {
517✔
1345
        for (auto & structPtr : strs) structPtr = nullptr;
66,693✔
1346
}
517✔
1347

1348
CStructureTable::~CStructureTable() {
517✔
1349
        for (auto structPtr : strs) if (structPtr) delete structPtr;
66,693✔
1350
}
517✔
1351

1352
void CStructureTable::ReInit() {
1,499✔
1353
        for (auto & structPtr : strs) {
193,371✔
1354
                if (structPtr) delete structPtr;
191,872✔
1355
                structPtr = nullptr;
191,872✔
1356
        }
1357
}
1,499✔
1358

1359
CStructure* CStructureTable::Add(char* naam, int no, int gl) {
240✔
1360
        char sn[LINEMAX], * sp;
1361
        sn[0] = 0;
240✔
1362
        if (!gl && *ModuleName) {
240✔
1363
                STRCPY(sn, LINEMAX-2, ModuleName);
21✔
1364
                STRCAT(sn, 2, ".");
21✔
1365
        }
1366
        STRCAT(sn, LINEMAX-1, naam);
240✔
1367
        sp = sn;
240✔
1368
        if (FindDuplicate(sp)) {
240✔
1369
                Error("[STRUCT] Structure already exist", naam);
3✔
1370
                return nullptr;
3✔
1371
        }
1372
        strs[(*sp)&127] = new CStructure(naam, sp, 0, gl, strs[(*sp)&127]);
237✔
1373
        if (no) {
237✔
1374
                strs[(*sp)&127]->AddMember(new CStructureEntry2(0, no, -1, Relocation::OFF, SMEMBBLOCK));
37✔
1375
        }
1376
        return strs[(*sp)&127];
237✔
1377
}
1378

1379
CStructure* CStructureTable::zoek(const char* naam, int gl) {
258,819✔
1380
        char sn[LINEMAX], * sp;
1381
        sn[0] = 0;
258,819✔
1382
        if (!gl && *ModuleName) {
258,819✔
1383
                STRCPY(sn, LINEMAX-2, ModuleName);
3,933✔
1384
                STRCAT(sn, 2, ".");
3,933✔
1385
        }
1386
        STRCAT(sn, LINEMAX-1, naam);
258,819✔
1387
        sp = sn;
258,819✔
1388
        CStructure* p = strs[(*sp)&127];
258,819✔
1389
        while (p) {
259,329✔
1390
                if (!strcmp(sp, p->id)) return p;
1,254✔
1391
                p = p->next;
510✔
1392
        }
1393
        if (gl || ! *ModuleName) return NULL;
258,075✔
1394
        sp += 1 + strlen(ModuleName); p = strs[(*sp)&127];
3,906✔
1395
        while (p) {
3,930✔
1396
                if (!strcmp(sp, p->id)) return p;
57✔
1397
                p = p->next;
24✔
1398
        }
1399
        return NULL;
3,873✔
1400
}
1401

1402
int CStructureTable::FindDuplicate(char* naam) {
240✔
1403
        CStructure* p = strs[(*naam)&127];
240✔
1404
        while (p) {
393✔
1405
                if (!strcmp(naam, p->naam)) return 1;
156✔
1406
                p = p->next;
153✔
1407
        }
1408
        return 0;
237✔
1409
}
1410

1411
aint CStructureTable::ParseDesignedAddress(char* &p) {
693✔
1412
        if (!SkipBlanks(p) && ('=' == *p)) {
693✔
1413
                char* adrP = ++p;
57✔
1414
                aint resultAdr;
1415
                if (ParseExpressionNoSyntaxError(p, resultAdr)) return resultAdr;
57✔
1416
                Error("[STRUCT] Syntax error in designed address", adrP, SUPPRESS);
3✔
1417
                return 0;
3✔
1418
        }
1419
        return INT_MAX;                // no "designed address" provided, emit structure bytes
636✔
1420
}
1421

1422
int CStructureTable::Emit(char* naam, char* l, char*& p, int gl) {
258,666✔
1423
        CStructure* st = zoek(naam, gl);
258,666✔
1424
        if (!st) return 0;
258,666✔
1425
        // create new labels corresponding to current/designed address
1426
        aint address = CStructureTable::ParseDesignedAddress(p);
693✔
1427
        if (l) {
693✔
1428
                const Relocation::EType relocatable =
519✔
1429
                        (INT_MAX == address) ?
1,038✔
1430
                                (Relocation::type ? Relocation::REGULAR : Relocation::OFF)
465✔
1431
                                : Relocation::isResultAffected ? Relocation::deltaType : Relocation::OFF;
54✔
1432
                st->emitlab(l, (INT_MAX == address) ? CurAddress : address, relocatable == Relocation::REGULAR);
519✔
1433
        }
1434
        if (INT_MAX == address) st->emitmembs(p);        // address was not designed, emit also bytes
693✔
1435
        else if (!l) Warning("[STRUCT] designed address without label = no effect");
57✔
1436
        return 1;
693✔
1437
}
1438

1439
SRepeatStack::SRepeatStack(aint count, CStringsList* condition, CStringsList* firstLine)
4,220✔
1440
        : RepeatCount(count), RepeatCondition(condition), Lines(firstLine), Pointer(firstLine), IsInWork(false), Level(0)
4,220✔
1441
{
1442
        assert(!sourcePosStack.empty());
4,220✔
1443
        sourcePos = sourcePosStack.back();
4,220✔
1444
}
4,220✔
1445

1446
SRepeatStack::~SRepeatStack() {
4,220✔
1447
        if (RepeatCondition) delete RepeatCondition;
4,220✔
1448
        if (Lines) delete Lines;
4,220✔
1449
}
4,220✔
1450

1451
//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