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

z00m128 / sjasmplus / 1487

10 Mar 2025 02:05AM UTC coverage: 96.445% (+0.005%) from 96.44%
1487

push

cirrus-ci

ped7g
SLD: fix labels export in special cases

Some of the new prefix control chars were not handled by sld export.
Not sure if this is fixing 100% of possible combinations, but certainly
supports more than before.

6 of 6 new or added lines in 1 file covered. (100.0%)

40 existing lines in 2 files now uncovered.

9603 of 9957 relevant lines covered (96.44%)

340238.26 hits per line

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

97.55
/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) {
496,818✔
34
}
496,818✔
35

36
void TextFilePos::newFile(const char* fileNamePtr) {
736✔
37
        filename = fileNamePtr;
736✔
38
        line = colBegin = colEnd = 0;
736✔
39
}
736✔
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) {
1,323,392✔
44
        if (endsWithColon && 0 == colEnd) colEnd = 1;        // first segment of "colonized" line (do +1,+1)
1,323,392✔
45
        colBegin = colEnd;
1,323,392✔
46
        if (colBegin <= 1) ++line;                // first segment of any line, increment also line number
1,323,392✔
47
        if (endsWithColon)        colEnd += advanceColumns;
1,323,392✔
48
        else                                colEnd = 0;
1,301,642✔
49
}
1,323,392✔
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) {
2,245,208✔
60
        if (nullptr == naam) {
2,245,208✔
61
                Error("Invalid labelname");
4✔
62
                return nullptr;
4✔
63
        }
64
        if ('!' == *naam) {
2,245,204✔
65
                setNameSpace = false;
100✔
66
                ++naam;
100✔
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]);
2,245,204✔
70
        if (escMacro) ++naam;                        // such extra "@" is consumed right here and only '.' is left
2,245,204✔
71
        // regular single prefix case in other use cases
72
        const bool global = '@' == *naam;
2,245,204✔
73
        const bool local = '.' == *naam;
2,245,204✔
74
        if (!isLabelStart(naam)) {                // isLabelStart assures that only single modifier exist
2,245,204✔
75
                if (global || local) ++naam;// single modifier is parsed (even when invalid name)
132✔
76
                Error("Invalid labelname", naam);
132✔
77
                return nullptr;
132✔
78
        }
79
        if (global || local) ++naam;        // single modifier is parsed
2,245,072✔
80
        const bool inMacro = !escMacro && local && macrolabp;
2,245,072✔
81
        const bool inModule = !inMacro && !global && !local && ModuleName[0];
2,245,072✔
82
        // check all chars of label
83
        const char* np = naam;
2,245,072✔
84
        while (islabchar(*np)) ++np;
10,180,630✔
85
        if ('[' == *np) return nullptr;        // this is DEFARRAY name, do not process it as label (silent exit)
2,245,072✔
86
        if (*np && !ignoreCharAfter) {
2,244,772✔
87
                // if this is supposed to be new label, there shoulnd't be anything else after it
88
                Error("Invalid labelname", naam);
30✔
89
                return nullptr;
30✔
90
        }
91
        // calculate expected length of fully qualified label name
92
        int labelLen = (np - naam), truncateAt = LABMAX;
2,244,742✔
93
        if (LABMAX < labelLen) Error("Label too long", naam, IF_FIRST);        // non-fatal error, will truncate it
2,244,742✔
94
        if (inMacro) labelLen += 1 + strlen(macrolabp);
2,244,742✔
95
        else if (local) labelLen += 1 + strlen(vorlabp);
2,228,848✔
96
        if (inModule) labelLen += 1 + strlen(ModuleName);
2,244,742✔
97
        // build fully qualified label name (in newly allocated memory buffer, with precise length)
98
        char* const label = new char[1+labelLen];
2,244,742✔
99
        if (nullptr == label) ErrorOOM();
2,244,742✔
100
        label[0] = 0;
2,244,742✔
101
        if (inModule) {
2,244,742✔
102
                STRCAT(label, labelLen, ModuleName);        STRCAT(label, 2, ".");
2,674✔
103
        }
104
        if (inMacro) {
2,244,742✔
105
                STRCAT(label, labelLen, macrolabp);                STRCAT(label, 2, ">");
15,894✔
106
        } else if (local) {
2,228,848✔
107
                STRCAT(label, labelLen, vorlabp);                STRCAT(label, 2, ".");
4,034✔
108
        }
109
        char* lp = label + strlen(label);
2,244,742✔
110
        while (truncateAt-- && islabchar(*naam)) *lp++ = *naam++;        // add the new label (truncated if needed)
10,165,900✔
111
        *lp = 0;
2,244,742✔
112
        if (labelLen < lp - label) Error("internal error", nullptr, FATAL);                // should never happen :)
2,244,742✔
113
        if (setNameSpace && !local) {
2,244,742✔
114
                free(vorlabp);
722,094✔
115
                vorlabp = STRDUP(label);
722,094✔
116
                if (vorlabp == NULL) ErrorOOM();
722,094✔
117
        }
118
        return label;
2,244,742✔
119
}
120

121
static char sldLabelExport[2*LINEMAX];
122

123
char* ExportLabelToSld(const char* naam, const SLabelTableEntry* label) {
454✔
124
        // does re-parse the original source line again similarly to ValidateLabel
125
        // but prepares SLD 'L'-type line, with module/main/local comma separated + usage traits info
126
        assert(nullptr != label);
454✔
127
        // check if this is setting namespace
128
        bool setNameSpace = ('!' != *naam);
454✔
129
        if (!setNameSpace) ++naam;
454✔
130
        // check if local label defined inside macro wants to become non-macro local label
131
        const bool escMacro = setNameSpace && macrolabp && ('@' == naam[0]) && ('.' == naam[1]);
454✔
132
        if (escMacro) ++naam;                        // such extra "@" is consumed right here and only '.' is left
454✔
133
        assert(isLabelStart(naam));                // this should be called only when ValidateLabel did succeed
454✔
134
        const bool global = '@' == *naam;
454✔
135
        const bool local = '.' == *naam;
454✔
136
        if (global || local) ++naam;        // single modifier is parsed
454✔
137
        const bool inMacro = !escMacro && local && macrolabp;
454✔
138
        const bool inModule = !inMacro && !global && ModuleName[0];
454✔
139
        const bool isStructLabel = (label->traits & (LABEL_IS_STRUCT_D|LABEL_IS_STRUCT_E));
454✔
140
        // build fully qualified SLD info
141
        sldLabelExport[0] = 0;
454✔
142
        // module part
143
        if (inModule) STRCAT(sldLabelExport, LINEMAX, ModuleName);
454✔
144
        STRCAT(sldLabelExport, 2, ",");
454✔
145
        // main label part (the `vorlabp` is already the current label, if it was main label)
146
        // except for structure labels: the inner ones don't "set namespace" == vorlabp, use "naam" then
147
        // (but only if the main label of structure itself is not local, if it's local, use vorlabp)
148
        const char* mainLabel = isStructLabel && !local ? naam : inMacro ? macrolabp : vorlabp;
454✔
149
        if (!setNameSpace) mainLabel = naam;
454✔
150
        if (vorlabp == mainLabel && ModuleName[0]) {        // vorlabp now contains also module part, skip it
454✔
151
                auto modNameSz = strlen(ModuleName);
60✔
152
                if (0 == strncmp(ModuleName, mainLabel, modNameSz)) mainLabel += modNameSz + 1;
60✔
153
        }
154
        STRCAT(sldLabelExport, LABMAX, mainLabel);
454✔
155
        STRCAT(sldLabelExport, 2, ",");
454✔
156
        // local part
157
        if (local) STRCAT(sldLabelExport, LABMAX, naam);
454✔
158
        // usage traits
159
        if (label->traits&LABEL_IS_EQU) STRCAT(sldLabelExport, 20, ",+equ");
454✔
160
        if (inMacro) STRCAT(sldLabelExport, 20, ",+macro");
454✔
161
        if (label->traits&LABEL_IS_SMC) STRCAT(sldLabelExport, 20, ",+smc");
454✔
162
        if (Relocation::REGULAR == label->isRelocatable) STRCAT(sldLabelExport, 20, ",+reloc");
454✔
163
        if (Relocation::HIGH == label->isRelocatable) STRCAT(sldLabelExport, 20, ",+reloc_high");
454✔
164
        if (label->used) STRCAT(sldLabelExport, 20, ",+used");
454✔
165
        if (label->traits&LABEL_IS_STRUCT_D) STRCAT(sldLabelExport, 20, ",+struct_def");
454✔
166
        if (label->traits&LABEL_IS_STRUCT_E) STRCAT(sldLabelExport, 20, ",+struct_data");
454✔
167
        return sldLabelExport;
454✔
168
}
169

170
char* ExportModuleToSld(bool endModule) {
16✔
171
        assert(ModuleName[0]);
16✔
172
        STRNCPY(sldLabelExport, 2*LINEMAX, ModuleName, LINEMAX);
16✔
173
        STRCAT(sldLabelExport, LINEMAX-1, endModule ? ",,,+endmod" : ",,,+module");
16✔
174
        return sldLabelExport;
16✔
175
}
176

177
static bool getLabel_invalidName = false;
178

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

241
static SLabelTableEntry* GetLabel(char*& p) {
1,501,878✔
242
        std::unique_ptr<char[]> fullName;
1,501,878✔
243
        SLabelTableEntry* labelEntry = SearchLabel(p, true, fullName);
1,501,878✔
244
        if (getLabel_invalidName) return nullptr;
1,501,878✔
245
        if (!labelEntry || LABEL_PAGE_UNDEFINED == labelEntry->page) {
1,501,562✔
246
                IsLabelNotFound = true;
14,448✔
247
                // don't insert labels or report errors during substitution phase
248
                if (IsSubstituting) return nullptr;
14,448✔
249
                // regular parsing/assembling, track new labels and report "not found" error
250
                char* findName = temp[0] ? temp : fullName.get();
14,316✔
251
                if (!labelEntry) {
14,316✔
252
                        LabelTable.Insert(findName, 0, LABEL_IS_UNDEFINED);
7,054✔
253
                }
254
                Error("Label not found", findName, IF_FIRST);
14,316✔
255
                return nullptr;
14,316✔
256
        } else {
257
                return labelEntry;
1,487,114✔
258
        }
259
}
1,501,878✔
260

261
bool LabelExist(char*& p, aint& val) {
318✔
262
        std::unique_ptr<char[]> fullName;
318✔
263
        SLabelTableEntry* labelEntry = SearchLabel(p, false, fullName);
318✔
264
        val = (labelEntry && LABEL_PAGE_UNDEFINED != labelEntry->page) ? -1 : 0;
318✔
265
        return !getLabel_invalidName;
318✔
266
}
318✔
267

268
bool GetLabelPage(char*& p, aint& val) {
228✔
269
        SLabelTableEntry* labelEntry = GetLabel(p);
228✔
270
        val = labelEntry ? labelEntry->page : LABEL_PAGE_UNDEFINED;
228✔
271
        // true even when not found, but valid label name (neeed for expression-eval logic)
272
        return !getLabel_invalidName;
228✔
273
}
274

275
bool GetLabelValue(char*& p, aint& val) {
1,501,650✔
276
        SLabelTableEntry* labelEntry = GetLabel(p);
1,501,650✔
277
        if (labelEntry) {
1,501,650✔
278
                val = labelEntry->value;
1,486,908✔
279
                if (Relocation::areLabelsOffset) {
1,486,908✔
280
                        switch (labelEntry->isRelocatable) {
13,700✔
281
                                case Relocation::REGULAR:        val += Relocation::alternative_offset;                        break;
11,398✔
282
                                case Relocation::HIGH:                val += Relocation::alternative_offset >> 8;                break;
102✔
283
                                default:                                        ;
13,700✔
284
                        }
285
                }
286
        } else {
287
                val = 0;
14,742✔
288
        }
289
        // true even when not found, but valid label name (needed for expression-eval logic)
290
        return !getLabel_invalidName;
1,501,650✔
291
}
292

293
int GetTemporaryLabelValue(char*& op, aint& val, bool requireUnderscore) {
1,462,292✔
294
        char* p = op;
1,462,292✔
295
        if (SkipBlanks(p) || !isdigit((byte)*p)) return 0;
1,462,292✔
296
        char* const numberB = p;
1,424,216✔
297
        while (isdigit((byte)*p)) ++p;
5,976,180✔
298
        const bool hasUnderscore = ('_' == *p);
1,424,216✔
299
        if (requireUnderscore && !hasUnderscore) return 0;
1,424,216✔
300
        // convert suffix [bB] => 'b', [fF] => 'f' and ignore underscore
301
        const char type = (hasUnderscore ? p[1] : p[0]) | 0x20;        // should be 'b' or 'f'
1,898✔
302
        const char following = hasUnderscore ? p[2] : p[1];                // should be non-label char
1,898✔
303
        if ('b' != type && 'f' != type) return 0;        // local label must have "b" or "f" after number
1,898✔
304
        if (islabchar(following)) return 0;                        // that suffix didn't end correctly
1,532✔
305
        // numberB -> p are digits to be parsed as integer
306
        if (!GetNumericValue_IntBased(op = numberB, p, val, 10)) return 0;
1,526✔
307
        if ('_' == *op) ++op;
1,526✔
308
        ++op;
1,526✔
309
        // ^^ advance main parsing pointer op beyond the local label (here it *is* local label)
310
        auto label = ('b' == type) ? TemporaryLabelTable.seekBack(val) : TemporaryLabelTable.seekForward(val);
1,526✔
311
        if (label) {
1,526✔
312
                val = label->value;
980✔
313
                if (requireUnderscore) {                                // part of full expression, do relocation by +offset
980✔
314
                        if (label->isRelocatable && Relocation::areLabelsOffset) {
240✔
315
                                val += Relocation::alternative_offset;
56✔
316
                        }
317
                } else {                                                                // single-label-only in jump/call instructions
318
                        Relocation::isResultAffected = label->isRelocatable;
740✔
319
                        Relocation::deltaType = label->isRelocatable ? Relocation::REGULAR : Relocation::OFF;
740✔
320
                }
321
        } else {
322
                if (LASTPASS == pass) Error("Temporary label not found", numberB, SUPPRESS);
546✔
323
                val = 0L;
546✔
324
        }
325
        return 1;
1,526✔
326
}
327

328
static short getAddressPageNumber(const aint address, bool forceRecalculateByAddress) {
722,414✔
329
        // everything is "ROM" based when device is NONE
330
        if (!DeviceID) return LABEL_PAGE_ROM;
722,414✔
331
        // fast-shortcut for regular labels in current slot (if they fit into it)
332
        auto slot = Device->GetCurrentSlot();
665,130✔
333
        assert(Page && slot);
665,130✔
334
        if (!forceRecalculateByAddress && DISP_NONE == PseudoORG) {
665,130✔
335
                if (slot->Address <= address && address < slot->Address + slot->Size) {
9,048✔
336
                        return Page->Number;
328✔
337
                }
338
        }
339
        // enforce explicit request of fake DISP page
340
        if (DISP_NONE != PseudoORG && LABEL_PAGE_UNDEFINED != dispPageNum) {
664,802✔
341
                return dispPageNum;
24✔
342
        }
343
        // in other case (implicit DISP, out-of-slot-bounds or forceRecalculateByAddress)
344
        // track down the page num from current memory mapping
345
        const short page = Device->GetPageOfA16(address);
664,778✔
346
        if (LABEL_PAGE_UNDEFINED == page) return LABEL_PAGE_OUT_OF_BOUNDS;
664,778✔
347
        return page;
457,854✔
348
}
349

350
int CLabelTable::Insert(const char* nname, aint nvalue, unsigned traits, short equPageNum) {
741,988✔
351
        const bool IsUndefined = !!(traits & LABEL_IS_UNDEFINED);
741,988✔
352

353
        // the EQU/DEFL is relocatable when the expression itself is relocatable
354
        // the regular label is relocatable when relocation is active
355
        const Relocation::EType deltaType = \
741,988✔
356
                        (traits&LABEL_HAS_RELOC_TRAIT) ? \
1,474,388✔
357
                                (traits & LABEL_IS_RELOC ? Relocation::REGULAR : Relocation::OFF) : \
9,588✔
358
                                (traits & (LABEL_IS_DEFL|LABEL_IS_EQU)) ? \
777,498✔
359
                                        Relocation::deltaType : \
360
                                        Relocation::type && DISP_INSIDE_RELOCATE != PseudoORG ? \
45,098✔
361
                                                Relocation::REGULAR : Relocation::OFF;
362
        // Find label in label table
363
        symbol_map_t::iterator labelIt = symbols.find(nname);
1,483,976✔
364
        if (symbols.end() != labelIt) {
741,988✔
365
                //if label already added (as used, or in previous pass), just refresh values
366
                auto& label = labelIt->second;
708,216✔
367
                if (label.traits&LABEL_IS_KEYWORD) WarningById(W_OPKEYWORD, nname, W_EARLY);
708,216✔
368
                bool needsUpdate = label.traits&LABEL_IS_DEFL || label.page == LABEL_PAGE_UNDEFINED || label.updatePass < pass;
708,216✔
369
                if (needsUpdate) {
708,216✔
370
                        label.value = nvalue;
708,120✔
371
                        if ((traits & LABEL_IS_EQU) && LABEL_PAGE_UNDEFINED != equPageNum) {
708,120✔
372
                                label.page = equPageNum;
8✔
373
                        } else {
374
                                label.page = getAddressPageNumber(nvalue, traits & (LABEL_IS_DEFL|LABEL_IS_EQU));
708,112✔
375
                        }
376
                        label.traits = traits;
708,120✔
377
                        label.isRelocatable = deltaType;
708,120✔
378
                        label.updatePass = pass;
708,120✔
379
                }
380
                return needsUpdate;
708,216✔
381
        }
382
        auto& label = symbols[nname];
67,544✔
383
        label.traits = traits;
33,772✔
384
        label.updatePass = pass;
33,772✔
385
        label.value = nvalue;
33,772✔
386
        label.used = IsUndefined;
33,772✔
387
        if ((traits & LABEL_IS_EQU) && LABEL_PAGE_UNDEFINED != equPageNum) {
33,772✔
388
                label.page = equPageNum;
8✔
389
        } else {
390
                label.page = IsUndefined ? LABEL_PAGE_UNDEFINED : getAddressPageNumber(nvalue, traits & (LABEL_IS_DEFL|LABEL_IS_EQU));
33,764✔
391
        }
392
        label.isRelocatable = IsUndefined ? Relocation::OFF : deltaType;        // ignore "relocatable" for "undefined"
33,772✔
393
        return 1;
33,772✔
394
}
395

396
int CLabelTable::Update(char* name, aint value) {
60✔
397
        auto labelIt = symbols.find(name);
120✔
398
        if (symbols.end() != labelIt) labelIt->second.value = value;
60✔
399
        return (symbols.end() != labelIt);
60✔
400
}
401

402
SLabelTableEntry* CLabelTable::Find(const char* name, bool onlyDefined) {
1,745,094✔
403
        symbol_map_t::iterator labelIt = symbols.find(name);
3,490,188✔
404
        if (symbols.end() == labelIt) return nullptr;
1,745,094✔
405
        return (onlyDefined && LABEL_PAGE_UNDEFINED == labelIt->second.page) ? nullptr : &labelIt->second;
1,737,184✔
406
}
407

408
bool CLabelTable::IsUsed(const char* name) {
198✔
409
        auto labelIt = symbols.find(name);
396✔
410
        return (symbols.end() != labelIt) ? labelIt->second.used : false;
198✔
411
}
412

UNCOV
413
bool CLabelTable::Remove(const char* name) {
×
UNCOV
414
        return symbols.erase(name);
×
415
}
416

417
void CLabelTable::RemoveAll() {
1,040✔
418
        symbols.clear();
1,040✔
419
}
1,040✔
420

421
static const std::vector<symbol_map_t::key_type> getDumpOrder(const symbol_map_t& table) {
744✔
422
        std::vector<symbol_map_t::key_type> order;
744✔
423
        order.reserve(table.size());
744✔
424
        for (const auto& it : table) order.emplace_back(it.first);
18,748✔
425
        if (Options::SortSymbols) {
744✔
426
                std::sort(
744✔
427
                        order.begin(), order.end(),
428
                        [&](const symbol_map_t::key_type& a, const symbol_map_t::key_type& b) {
104,950✔
429
                                // if case insenstive are same, do case sensitive too!
430
                                int caseres = strcasecmp(a.c_str(), b.c_str());
104,950✔
431
                                if (0 == caseres) return a < b;
104,950✔
432
                                return caseres < 0;
104,492✔
433
                        }
434
                );
435
        }
436
        return order;
744✔
UNCOV
437
}
×
438

439
void CLabelTable::Dump() {
972✔
440
        FILE* listFile = GetListingFile();
972✔
441
        if (NULL == listFile) return;                // listing file must be already opened here
972✔
442

443
        const auto order = getDumpOrder(symbols);
688✔
444

445
        char line[LINEMAX], *ep;
446
        fputs("\nValue    Label\n", listFile);
688✔
447
        fputs("------ - -----------------------------------------------------------\n", listFile);
688✔
448
        for (const symbol_map_t::key_type& name: order) {
17,198✔
449
                const symbol_map_t::mapped_type& symbol = symbols.at(name);
16,510✔
450
                if (LABEL_PAGE_UNDEFINED == symbol.page) continue;
16,510✔
451
                ep = line;
8,054✔
452
                *(ep) = 0;
8,054✔
453
                *(ep++) = '0';
8,054✔
454
                *(ep++) = 'x';
8,054✔
455
                PrintHexAlt(ep, symbol.value);
8,054✔
456
                *(ep++) = ' ';
8,054✔
457
                *(ep++) = symbol.used ? ' ' : 'X';
8,054✔
458
                *(ep++) = ' ';
8,054✔
459
                STRNCPY(ep, LINEMAX, name.c_str(), LINEMAX - (ep - line) - 2);
8,054✔
460
                STRNCAT(ep, LINEMAX, "\n", 2);
8,054✔
461
                fputs(line, listFile);
8,054✔
462
        }
463
}
688✔
464

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

488
                if (page < LABEL_PAGE_ROM) ep += SPRINTF1(ep, LINEMAX, "%02d", page&255);
228✔
489
                *(ep++) = ':';
228✔
490
                PrintHexAlt(ep, lvalue);
228✔
491

492
                *(ep++) = ' ';
228✔
493
                STRCPY(ep, LINEMAX-(ep-ln), name.c_str());
228✔
494
                STRCAT(ep, LINEMAX, "\n");
228✔
495
                fputs(ln, FP_UnrealList);
228✔
496
        }
497
        fclose(FP_UnrealList);
20✔
498
}
20✔
499

500
void CLabelTable::DumpForCSpect() {
24✔
501
        FILE* file;
502
        if (!FOPEN_ISOK(file, Options::CSpectMapFName, "w")) {
24✔
UNCOV
503
                Error("opening file for write", Options::CSpectMapFName.string().c_str(), FATAL);
×
504
        }
505
        const int CSD_PAGE_SIZE = Options::CSpectMapPageSize;
24✔
506
        const int CSD_PAGE_MASK = CSD_PAGE_SIZE - 1;
24✔
507
        const auto order = getDumpOrder(symbols);
24✔
508
        for (const symbol_map_t::key_type& name: order) {
784✔
509
                const symbol_map_t::mapped_type& symbol = symbols.at(name);
760✔
510
                if (LABEL_PAGE_UNDEFINED == symbol.page) continue;
760✔
511
                const int labelType =
450✔
512
                        (symbol.traits&LABEL_IS_STRUCT_E) ? 0 :
894✔
513
                        (symbol.traits&LABEL_IS_STRUCT_D) ? 4 :
876✔
514
                        (symbol.traits&LABEL_IS_EQU) ? 1 :
842✔
515
                        (symbol.traits&LABEL_IS_DEFL) ? 2 :
808✔
516
                        (LABEL_PAGE_ROM <= symbol.page) ? 3 : 0;
398✔
517
                const short page = labelType ? 0 : symbol.page;
450✔
518
                        // TODO:
519
                        // page == -1 will put regular EQU like "BLUE" out of reach for disassembly window
520
                        // (otherwise BLUE becomes label for address $C001 with default mapping)
521
                        // BUT then it would be nice to provide real page data for equ which have them explicit
522
                        // BUT I can't distinguish explicit/implicit page number, as there's heuristic to use current mapping
523
                        // instead of using the LABEL_PAGE_OUT_OF_BOUNDS page number...
524
                        // TODO: figure out when/why the implicit page number heuristic happenned and if you can detect
525
                        // only explicit page numbers used in EQU, and export only those
526

527
                const aint longAddress = (CSD_PAGE_MASK & symbol.value) + page * CSD_PAGE_SIZE;
450✔
528
                fprintf(file, "%08X %08X %02X ", 0xFFFF & symbol.value, longAddress, labelType);
450✔
529
                // convert primary+local label to be "@" delimited (not "." delimited)
530
                STRCPY(temp, LINEMAX, name.c_str());
450✔
531
                // look for "primary" label (where the local label starts)
532
                char* localLabelStart = strrchr(temp, '.');
450✔
533
                while (temp < localLabelStart) {        // the dot must be at least second character
688✔
534
                        *localLabelStart = 0;                        // terminate the possible "primary" part
320✔
535
                        if (Find(temp, true)) {
320✔
536
                                *localLabelStart = '@';
82✔
537
                                break;
82✔
538
                        }
539
                        *localLabelStart = '.';                        // "primary" label didn't work, restore dot
238✔
540
                        do {
541
                                --localLabelStart;                        // and look for next dot
586✔
542
                        } while (temp < localLabelStart && '.' != *localLabelStart);
586✔
543
                }
544
                // convert whole label to upper-case, as CSpect search is malfunctioning otherwise.
545
                char* strToUpper = temp;
450✔
546
                while ((*strToUpper = (char) toupper((byte)*strToUpper))) { ++strToUpper; }
5,766✔
547
                fprintf(file, "%s\n", temp);
450✔
548
        }
549
        fclose(file);
24✔
550
}
24✔
551

552
void CLabelTable::DumpSymbols() {
12✔
553
        FILE* symfp;
554
        if (!FOPEN_ISOK(symfp, Options::SymbolListFName, "w")) {
12✔
UNCOV
555
                Error("opening file for write", Options::SymbolListFName.string().c_str(), FATAL);
×
556
        }
557
        const auto order = getDumpOrder(symbols);
12✔
558
        for (const symbol_map_t::key_type& name: order) {
278✔
559
                const symbol_map_t::mapped_type& symbol = symbols.at(name);
266✔
560
                if (isdigit((byte)name[0])) continue;
266✔
561
                if (symbol.traits&LABEL_IS_KEYWORD) continue;
266✔
562
                WriteLabelEquValue(name.c_str(), symbol.value, symfp);
122✔
563
        }
564
        fclose(symfp);
12✔
565
}
12✔
566

567
int CFunctionTable::Insert(const char* name_cstr, function_fn_t nfunp) {
316,614✔
568
        std::string name(name_cstr);
316,614✔
569
        if (!std::get<1>(functions.emplace(name, nfunp))) return 0;
316,614✔
570
        for (auto& c : name) c = toupper(c);
2,010,762✔
571
        return std::get<1>(functions.emplace(name, nfunp));
316,614✔
572
}
316,614✔
573

574
int CFunctionTable::insertd(const char* name, function_fn_t nfunp) {
119,944✔
575
        if ('.' != name[0]) Error("Directive string must start with dot", NULL, FATAL);
119,944✔
576
        // insert the non-dot variant first, then dot variant
577
        return Insert(name+1, nfunp) && Insert(name, nfunp);
119,944✔
578
}
579

580
int CFunctionTable::zoek(const char* name) {
766,692✔
581
        auto it = functions.find(name);
1,533,384✔
582
        if (functions.end() == it) return 0;
766,692✔
583
        (*it->second)();
488,252✔
584
        return 1;
488,242✔
585
}
586

587
TemporaryLabel::TemporaryLabel(aint number, aint address)
194✔
588
        : nummer(number), value(address), isRelocatable(bool(Relocation::type)) {}
194✔
589

590
CTemporaryLabelTable::CTemporaryLabelTable() {
1,058✔
591
        labels.reserve(128);
1,058✔
592
        refresh = 0;
1,058✔
593
}
1,058✔
594

595
void CTemporaryLabelTable::InitPass() {
3,070✔
596
        refresh = 0;                // reset refresh pointer for next pass
3,070✔
597
}
3,070✔
598

599
bool CTemporaryLabelTable::insertImpl(const aint labelNumber) {
194✔
600
        labels.emplace_back(labelNumber, CurAddress);
194✔
601
        return true;
194✔
602
}
603

604
bool CTemporaryLabelTable::refreshImpl(const aint labelNumber) {
394✔
605
        if (labels.size() <= refresh || labels.at(refresh).nummer != labelNumber) return false;
394✔
606
        TemporaryLabel & to_r = labels.at(refresh);
388✔
607
        if (to_r.value != CurAddress) Warning("Temporary label has different address");
388✔
608
        to_r.value = CurAddress;
388✔
609
        ++refresh;
388✔
610
        return true;
388✔
611
}
612

613
bool CTemporaryLabelTable::InsertRefresh(const aint nnummer) {
588✔
614
        return (1 == pass) ? insertImpl(nnummer) : refreshImpl(nnummer);
588✔
615
}
616

617
const TemporaryLabel* CTemporaryLabelTable::seekForward(const aint labelNumber) const {
642✔
618
        if (1 == pass) return nullptr;                                        // just building tables in first pass, no results yet
642✔
619
        temporary_labels_t::size_type i = refresh;                // refresh already points at first "forward" temporary label
428✔
620
        while (i < labels.size() && labelNumber != labels[i].nummer) ++i;
480✔
621
        return (i < labels.size()) ? &labels[i] : nullptr;
428✔
622
}
623

624
const TemporaryLabel* CTemporaryLabelTable::seekBack(const aint labelNumber) const {
884✔
625
        if (1 == pass || refresh <= 0) return nullptr;        // just building tables or no temporary label "backward"
884✔
626
        temporary_labels_t::size_type i = refresh;                // after last "backward" temporary label
564✔
627
        while (i--) if (labelNumber == labels[i].nummer) return &labels[i];
732✔
628
        return nullptr;                                                                        // not found
4✔
629
}
630

631
CStringsList::CStringsList(const char* stringSource, CStringsList* nnext) {
66,960✔
632
        string = STRDUP(stringSource);
66,960✔
633
        next = nnext;
66,960✔
634
        if (!sourcePosStack.empty()) source = sourcePosStack.back();
66,960✔
635
}
66,960✔
636

637
CStringsList::~CStringsList() {
66,960✔
638
        if (string) free(string);
66,960✔
639
        if (next) delete next;
66,960✔
640
}
66,960✔
641

642
bool CStringsList::contains(const CStringsList* strlist, const char* searchString) {
410✔
643
        while (nullptr != strlist) {
754✔
644
                if (!strcmp(searchString, strlist->string)) return true;
346✔
645
                strlist = strlist->next;
344✔
646
        }
647
        return false;
408✔
648
}
649

650
CDefineTableEntry::CDefineTableEntry(const char* nname, const char* nvalue, CStringsList* nnss, CDefineTableEntry* nnext)
58,364✔
651
                : name(NULL), value(NULL) {
58,364✔
652
        name = STRDUP(nname);
58,364✔
653
        value = new char[strlen(nvalue) + 1];
58,364✔
654
        if (NULL == name || NULL == value) ErrorOOM();
58,364✔
655
        char* s1 = value;
58,364✔
656
        while (*nvalue && *nvalue != '\n' && *nvalue != '\r') *s1++ = *nvalue++;
472,840✔
657
        *s1 = 0;
58,364✔
658
        next = nnext;
58,364✔
659
        nss = nnss;
58,364✔
660
}
58,364✔
661

662
CDefineTableEntry::~CDefineTableEntry() {
58,364✔
663
        if (name) free(name);
58,364✔
664
        if (value) delete[] value;
58,364✔
665
        if (nss) delete nss;
58,364✔
666
        if (next) delete next;
58,364✔
667
}
58,364✔
668

669
void CDefineTableEntry::Replace(const char* nvalue) {
44,192✔
670
        if (value) delete[] value;
44,192✔
671
        value = new char[strlen(nvalue) + 1];
44,192✔
672
        strcpy(value, nvalue);
44,192✔
673
}
44,192✔
674

675
CDefineTable::~CDefineTable() {
2,116✔
676
        for (auto def : defs) if (def) delete def;
272,964✔
677
}
2,116✔
678

679
CDefineTable& CDefineTable::operator=(CDefineTable const & defTable) {
3,070✔
680
        RemoveAll();
3,070✔
681
        for (CDefineTableEntry* srcDef : defTable.defs) {
396,030✔
682
                CDefineTableEntry* srcD = srcDef;
392,960✔
683
                while (srcD) {
399,352✔
684
                        Add(srcD->name, srcD->value, srcD->nss);
6,392✔
685
                        srcD = srcD->next;
6,392✔
686
                }
687
        }
688
        return *this;
3,070✔
689
}
690

691
void CDefineTable::Init() {
2,116✔
692
        DefArrayList = NULL;
2,116✔
693
        for (auto & def : defs) def = NULL;
272,964✔
694
}
2,116✔
695

696
void CDefineTable::Add(const char* name, const char* value, CStringsList* nss) {
9,512✔
697
        if (FindDuplicate(name)) {
9,512✔
698
                Error("Duplicate define (replacing old value)", name, PASS03);
32✔
699
        }
700
        defs[(*name)&127] = new CDefineTableEntry(name, value, nss, defs[(*name)&127]);
9,512✔
701
}
9,512✔
702

703
static char defineGet__Counter__Buffer[32] = {};
704
static char defineGet__Line__Buffer[32] = {};
705

706
const char* CDefineTable::Get(const char* name) {
3,488,334✔
707
        DefArrayList = nullptr;
3,488,334✔
708
        if (nullptr == name || 0 == name[0]) return nullptr;
3,488,334✔
709
        // the __COUNTER__ and __LINE__ have fully dynamic custom implementation here
710
        if ('_' == name[1]) {
3,488,322✔
711
                if (!strcmp(name, "__COUNTER__")) {
132,172✔
712
                        SPRINTF1(defineGet__Counter__Buffer, 30, "%d", PredefinedCounter);
30,762✔
713
                        ++PredefinedCounter;
30,762✔
714
                        return defineGet__Counter__Buffer;
30,762✔
715
                }
716
                if (!strcmp(name, "__LINE__")) {
101,410✔
717
                        SPRINTF1(defineGet__Line__Buffer, 30, "%d", sourcePosStack.empty() ? 0 : sourcePosStack.back().line);
30✔
718
                        return defineGet__Line__Buffer;
30✔
719
                }
720
        }
721
        CDefineTableEntry* p = defs[(*name)&127];
3,457,530✔
722
        while (p && strcmp(name, p->name)) p = p->next;
4,679,088✔
723
        if (nullptr == p) return nullptr;
3,457,530✔
724
        DefArrayList = p->nss;
33,958✔
725
        return p->value;
33,958✔
726
}
727

728
int CDefineTable::FindDuplicate(const char* name) {
11,756✔
729
        CDefineTableEntry* p = defs[(*name)&127];
11,756✔
730
        while (p) {
24,008✔
731
                if (!strcmp(name, p->name)) {
14,312✔
732
                        return 1;
2,060✔
733
                }
734
                p = p->next;
12,252✔
735
        }
736
        return 0;
9,696✔
737
}
738

739
int CDefineTable::Replace(const char* name, const char* value) {
90,324✔
740
        CDefineTableEntry* p = defs[(*name)&127];
90,324✔
741
        while (p) {
690,762✔
742
                if (!strcmp(name, p->name)) {
644,630✔
743
                        p->Replace(value);
44,192✔
744
                        return 0;
44,192✔
745
                }
746
                p = p->next;
600,438✔
747
        }
748
        defs[(*name)&127] = new CDefineTableEntry(name, value, 0, defs[(*name)&127]);
46,132✔
749
        return 1;
46,132✔
750
}
751

752
int CDefineTable::Replace(const char* name, const int value) {
32,518✔
753
        char newIntValue[24];
754
        SPRINTF1(newIntValue, sizeof(newIntValue), "%d", value);
32,518✔
755
        return Replace(name, newIntValue);
65,036✔
756
}
757

758
int CDefineTable::Remove(const char* name) {
180✔
759
        CDefineTableEntry* p = defs[(*name)&127];
180✔
760
        CDefineTableEntry* p2 = NULL;
180✔
761
        while (p) {
186✔
762
                if (!strcmp(name, p->name)) {
186✔
763
                        // unchain the particular item
764
                        if (NULL == p2) defs[(*name)&127] = p->next;
180✔
765
                        else                        p2->next = p->next;
6✔
766
                        p->next = NULL;
180✔
767
                        // delete it
768
                        delete p;
180✔
769
                        DefArrayList = NULL;                // may be invalid here, so just reset it
180✔
770
                        return 1;
180✔
771
                }
772
                p2 = p;
6✔
773
                p = p->next;
6✔
774
        }
UNCOV
775
        return 0;
×
776
}
777

778
void CDefineTable::RemoveAll() {
4,116✔
779
        DefArrayList = NULL;
4,116✔
780
        for (auto & def : defs) {
530,964✔
781
                if (!def) continue;
526,848✔
782
                delete def;
3,628✔
783
                def = NULL;
3,628✔
784
        }
785
}
4,116✔
786

787
CMacroDefineTable::CMacroDefineTable() : defs(nullptr) {
1,058✔
788
        for (auto & usedX : used) usedX = false;
136,482✔
789
}
1,058✔
790

791
CMacroDefineTable::~CMacroDefineTable() {
1,058✔
792
        if (defs) delete defs;
1,058✔
793
}
1,058✔
794

795
void CMacroDefineTable::ReInit() {
4,970✔
796
        if (defs) delete defs;
4,970✔
797
        defs = nullptr;
4,970✔
798
        for (auto & usedX : used) usedX = false;
641,130✔
799
}
4,970✔
800

801
void CMacroDefineTable::AddMacro(char* naam, char* vervanger) {
2,720✔
802
        CDefineTableEntry* tmpdefs = new CDefineTableEntry(naam, vervanger, 0, defs);
2,720✔
803
        defs = tmpdefs;
2,720✔
804
        used[(*naam)&127] = true;
2,720✔
805
}
2,720✔
806

807
CDefineTableEntry* CMacroDefineTable::getdefs() {
2,956✔
808
        return defs;
2,956✔
809
}
810

811
void CMacroDefineTable::setdefs(CDefineTableEntry* const ndefs) {
2,872✔
812
        if (ndefs == defs) return;                        // the current HEAD of defines is already same as requested one
2,872✔
813
        // traverse through current HEAD until the requested chain is found, unchain the HEAD from it
814
        CDefineTableEntry* entry = defs;
1,366✔
815
        while (entry && ndefs != entry->next) entry = entry->next;
2,660✔
816
        if (entry) entry->next = nullptr;        // if "ndefs" is chained to current HEAD, unchain
1,366✔
817
        if (defs) delete defs;                                // release front part of current chain from memory
1,366✔
818
        defs = ndefs;                                                // the requested chain is new current HEAD
1,366✔
819
}
820

821
const char* CMacroDefineTable::getverv(const char* name) const {
96,396✔
822
        if (nullptr == name) return nullptr;
96,396✔
823
        if (!used[(*name)&127]) return nullptr;
96,396✔
824
        const CDefineTableEntry* p = defs;
17,742✔
825
        while (p && strcmp(name, p->name)) p = p->next;
88,052✔
826
        return p ? p->value : nullptr;
17,742✔
827
}
828

UNCOV
829
int CMacroDefineTable::FindDuplicate(char* name) {
×
830
        CDefineTableEntry* p = defs;
×
831
        if (!used[(*name)&127]) {
×
832
                return 0;
×
833
        }
834
        while (p) {
×
UNCOV
835
                if (!strcmp(name, p->name)) {
×
836
                        return 1;
×
837
                }
UNCOV
838
                p = p->next;
×
839
        }
UNCOV
840
        return 0;
×
841
}
842

843
CMacroTableEntry::CMacroTableEntry(char* nnaam, CMacroTableEntry* nnext)
1,002✔
844
        : naam(nnaam), args(nullptr), body(nullptr), next(nnext) {
1,002✔
845
}
1,002✔
846

847
CMacroTableEntry::~CMacroTableEntry() {
1,002✔
848
        if (naam) free(naam);        // must be of STRDUP origin!
1,002✔
849
        if (args) delete args;
1,002✔
850
        if (body) delete body;
1,002✔
851
        if (next) delete next;
1,002✔
852
}
1,002✔
853

854
CMacroTable::CMacroTable() : macs(nullptr) {
1,058✔
855
        for (auto & usedX : used) usedX = false;
136,482✔
856
}
1,058✔
857

858
CMacroTable::~CMacroTable() {
1,058✔
859
        if (macs) delete macs;
1,058✔
860
}
1,058✔
861

862
void CMacroTable::ReInit() {
3,070✔
863
        if (macs) delete macs;
3,070✔
864
        macs = nullptr;
3,070✔
865
        for (auto & usedX : used) usedX = false;
396,030✔
866
}
3,070✔
867

868
int CMacroTable::FindDuplicate(const char* naam) {
1,014✔
869
        CMacroTableEntry* p = macs;
1,014✔
870
        if (!used[(*naam)&127]) {
1,014✔
871
                return 0;
660✔
872
        }
873
        while (p) {
1,284✔
874
                if (!strcmp(naam, p->naam)) {
942✔
875
                        return 1;
12✔
876
                }
877
                p = p->next;
930✔
878
        }
879
        return 0;
342✔
880
}
881

882
void CMacroTable::Add(const char* nnaam, char*& p) {
1,014✔
883
        if (FindDuplicate(nnaam)) {
1,014✔
884
                Error("Duplicate macroname", nnaam);return;
12✔
885
        }
886
        char* macroname = STRDUP(nnaam);
1,002✔
887
        if (macroname == NULL) ErrorOOM();
1,002✔
888
        macs = new CMacroTableEntry(macroname, macs);
1,002✔
889
        used[(*macroname)&127] = true;
1,002✔
890
        CStringsList* last = nullptr;
1,002✔
891
        do {
892
                char* n = GetID(p);
1,590✔
893
                if (!n) {
1,590✔
894
                        // either EOL when no previous argument, or valid name is required after comma (2nd+ loop)
895
                        if ((1 == pass) && (last || *p)) Error("Illegal argument name", p, EARLY);
360✔
896
                        SkipToEol(p);
360✔
897
                        break;
360✔
898
                }
899
                if ((1 == pass) && CStringsList::contains(macs->args, n)) {
1,230✔
900
                        Error("Duplicate argument name", n, EARLY);
2✔
901
                }
902
                CStringsList* argname = new CStringsList(n);
1,230✔
903
                if (!macs->args) {
1,230✔
904
                        macs->args = argname;        // first argument name, make it head of list
654✔
905
                } else {
906
                        last->next = argname;
576✔
907
                }
908
                last = argname;
1,230✔
909
        } while (anyComma(p));
1,230✔
910
        if ((1 == pass) && *p) {
1,002✔
911
                Error("Unexpected", p, EARLY);
4✔
912
        }
913
        ListFile();
1,002✔
914
        if (!ReadFileToCStringsList(macs->body, "endm")) {
1,002✔
915
                Error("Unexpected end of macro", NULL, EARLY);
6✔
916
        }
917
}
918

919
int CMacroTable::Emit(char* naam, char*& p) {
487,880✔
920
        // search for the desired macro
921
        if (!used[(*naam)&127]) return 0;
487,880✔
922
        CMacroTableEntry* m = macs;
3,974✔
923
        while (m && strcmp(naam, m->naam)) m = m->next;
8,510✔
924
        if (!m) return 0;
3,974✔
925
        // macro found, emit it, prepare temporary instance label base
926
        char* omacrolabp = macrolabp;
2,956✔
927
        char labnr[LINEMAX], ml[LINEMAX];
928
        SPRINTF1(labnr, LINEMAX, "%d", macronummer++);
2,956✔
929
        macrolabp = labnr;
2,956✔
930
        if (omacrolabp) {
2,956✔
931
                STRCAT(macrolabp, LINEMAX-1, "."); STRCAT(macrolabp, LINEMAX-1, omacrolabp);
1,056✔
932
        } else {
933
                MacroDefineTable.ReInit();
1,900✔
934
        }
935
        // parse argument values
936
        CDefineTableEntry* odefs = MacroDefineTable.getdefs();
2,956✔
937
        CStringsList* a = m->args;
2,956✔
938
        while (a) {
5,676✔
939
                char* n = ml;
2,750✔
940
                const bool lastArg = NULL == a->next;
2,750✔
941
                if (!GetMacroArgumentValue(p, n) || (!lastArg && !comma(p))) {
2,750✔
942
                        Error("Not enough arguments for macro", naam, SUPPRESS);
30✔
943
                        macrolabp = omacrolabp;
30✔
944
                        return 1;
30✔
945
                }
946
                MacroDefineTable.AddMacro(a->string, ml);
2,720✔
947
                a = a->next;
2,720✔
948
        }
949
        SkipBlanks(p);
2,926✔
950
        if (*p) {
2,926✔
951
                Error("Too many arguments for macro", naam, SUPPRESS);
54✔
952
                macrolabp = omacrolabp;
54✔
953
                return 1;
54✔
954
        }
955
        // arguments parsed, emit the macro lines and parse them
956
        lp = p;
2,872✔
957
        ListFile();
2,872✔
958
        ++listmacro;
2,872✔
959
        CStringsList* olijstp = lijstp;
2,872✔
960
        lijstp = m->body;
2,872✔
961
        ++lijst;
2,872✔
962
        STRCPY(ml, LINEMAX, line);
2,872✔
963
        sourcePosStack.push_back(TextFilePos());
2,872✔
964
        while (lijstp) {
14,206✔
965
                sourcePosStack.back() = lijstp->source;
11,334✔
966
                STRCPY(line, LINEMAX, lijstp->string);
11,334✔
967
                substitutedLine = line;                // reset substituted listing
11,334✔
968
                eolComment = NULL;                        // reset end of line comment
11,334✔
969
                lijstp = lijstp->next;
11,334✔
970
                ParseLineSafe();
11,334✔
971
        }
972
        sourcePosStack.pop_back();
2,872✔
973
        ++CompiledCurrentLine;
2,872✔
974
        STRCPY(line, LINEMAX, ml);
2,872✔
975
        lijstp = olijstp;
2,872✔
976
        --lijst;
2,872✔
977
        MacroDefineTable.setdefs(odefs);
2,872✔
978
        macrolabp = omacrolabp;
2,872✔
979
        --listmacro; donotlist = 1;
2,872✔
980
        return 2;
2,872✔
981
}
982

983
CStructureEntry1::CStructureEntry1(char* nnaam, aint noffset) {
2,454✔
984
        next = 0;
2,454✔
985
        naam = STRDUP(nnaam);
2,454✔
986
        if (naam == NULL) ErrorOOM();
2,454✔
987
        offset = noffset;
2,454✔
988
}
2,454✔
989

990
CStructureEntry1::~CStructureEntry1() {
2,454✔
991
        free(naam);
2,454✔
992
        if (next) delete next;
2,454✔
993
}
2,454✔
994

995
CStructureEntry2::CStructureEntry2(aint noffset, aint nlen, aint ndef, Relocation::EType ndeltatype, EStructureMembers ntype) :
2,810✔
996
        next(nullptr), text(nullptr), offset(noffset), len(nlen), def(ndef), defDeltaType(ndeltatype), type(ntype)
2,810✔
997
{
998
}
2,810✔
999

1000
CStructureEntry2::CStructureEntry2(aint noffset, aint nlen, byte* textData) :
216✔
1001
        next(nullptr), text(textData), offset(noffset), len(nlen), def(0), defDeltaType(Relocation::OFF), type(SMEMBTEXT)
216✔
1002
{
1003
        assert(1 <= len && len <= TEXT_MAX_SIZE && nullptr != text);
216✔
1004
}
216✔
1005

1006
CStructureEntry2::~CStructureEntry2() {
3,026✔
1007
        if (next) delete next;
3,026✔
1008
        if (text) delete[] text;
3,026✔
1009
}
3,026✔
1010

1011
// Parses source input for types: BYTE, WORD, DWORD, D24
1012
aint CStructureEntry2::ParseValue(char* & p) {
7,950✔
1013
        if (SMEMBBYTE != type && SMEMBWORD != type && SMEMBDWORD != type && SMEMBD24 != type) return def;
7,950✔
1014
        SkipBlanks(p);
7,950✔
1015
        aint val = def;
7,950✔
1016
        bool keepRelocatableFlags = false;        // keep flags from the ParseExpressionNoSyntaxError?
7,950✔
1017
        // check for unexpected {
1018
        if ('{' != *p) {
7,950✔
1019
                if (!(keepRelocatableFlags = ParseExpressionNoSyntaxError(p, val))) {
6,582✔
1020
                        val = def;
3,966✔
1021
                }
1022
                switch (type) {
6,582✔
1023
                        case SMEMBBYTE:
4,518✔
1024
                                check8(val);
4,518✔
1025
                                val &= 0xFF;
4,518✔
1026
                                break;
4,518✔
1027
                        case SMEMBWORD:
1,482✔
1028
                                check16(val);
1,482✔
1029
                                val &= 0xFFFF;
1,482✔
1030
                                break;
1,482✔
1031
                        case SMEMBD24:
270✔
1032
                                check24(val);
270✔
1033
                                val &= 0xFFFFFF;
270✔
1034
                                break;
270✔
1035
                        case SMEMBDWORD:
312✔
1036
                                break;
312✔
UNCOV
1037
                        default:
×
UNCOV
1038
                                break;
×
1039
                }
1040
        }
1041
        if (!Relocation::type) return val;
7,950✔
1042
        if (SMEMBBYTE == type && Relocation::HIGH == Relocation::type) {
870✔
1043
                if (!keepRelocatableFlags) {        // override flags, if parse expression was not successful
48✔
1044
                        Relocation::isResultAffected |= bool(defDeltaType);
24✔
1045
                        Relocation::deltaType = defDeltaType;
24✔
1046
                }
1047
                Relocation::resolveRelocationAffected(0, Relocation::HIGH);
48✔
1048
        } else if (SMEMBWORD == type) {
822✔
1049
                if (!keepRelocatableFlags) {        // override flags, if parse expression was not successful
468✔
1050
                        Relocation::isResultAffected |= bool(defDeltaType);
336✔
1051
                        Relocation::deltaType = defDeltaType;
336✔
1052
                }
1053
                Relocation::resolveRelocationAffected(0);
468✔
1054
        }
1055
        Relocation::checkAndWarn();
870✔
1056
        return val;
870✔
1057
}
1058

1059
CStructure::CStructure(const char* nnaam, char* nid, int no, int ngl, CStructure* p) {
474✔
1060
        mnf = mnl = NULL; mbf = mbl = NULL;
474✔
1061
        naam = STRDUP(nnaam);
474✔
1062
        if (naam == NULL) ErrorOOM();
474✔
1063
        id = STRDUP(nid);
474✔
1064
        if (id == NULL) ErrorOOM();
474✔
1065
        next = p; noffset = no; global = ngl;
474✔
1066
        maxAlignment = 0;
474✔
1067
}
474✔
1068

1069
CStructure::~CStructure() {
474✔
1070
        free(naam);
474✔
1071
        free(id);
474✔
1072
        if (mnf) delete mnf;
474✔
1073
        if (mbf) delete mbf;
474✔
1074
        if (next) delete next;
474✔
1075
}
474✔
1076

1077
void CStructure::AddLabel(char* nnaam) {
1,968✔
1078
        CopyLabel(nnaam, 0);
1,968✔
1079
}
1,968✔
1080

1081
void CStructure::AddMember(CStructureEntry2* n) {
3,026✔
1082
        if (!mbf)        mbf = n;
3,026✔
1083
        else                 mbl->next = n;
2,570✔
1084
        mbl = n;
3,026✔
1085
        noffset += n->len;
3,026✔
1086
}
3,026✔
1087

1088
void CStructure::CopyLabel(char* nnaam, aint offset) {
2,454✔
1089
        CStructureEntry1* n = new CStructureEntry1(nnaam, noffset + offset);
2,454✔
1090
        if (!mnf)        mnf = n;
2,454✔
1091
        else                mnl->next = n;
1,998✔
1092
        mnl = n;
2,454✔
1093
}
2,454✔
1094

1095
void CStructure::CopyLabels(CStructure* st) {
162✔
1096
        CStructureEntry1* np = st->mnf;
162✔
1097
        if (!np || !PreviousIsLabel) return;
162✔
1098
        char str[LINEMAX];
1099
        STRCPY(str, LINEMAX-1, PreviousIsLabel);
162✔
1100
        STRCAT(str, LINEMAX-1, ".");
162✔
1101
        char * const stw = str + strlen(str);
162✔
1102
        while (np) {
648✔
1103
                STRCPY(stw, LINEMAX, np->naam);        // overwrite the second part of label
486✔
1104
                CopyLabel(str, np->offset);
486✔
1105
                np = np->next;
486✔
1106
        }
1107
}
1108

1109
void CStructure::CopyMember(CStructureEntry2* item, aint newDefault, Relocation::EType newDeltaType) {
666✔
1110
        AddMember(new CStructureEntry2(noffset, item->len, newDefault, newDeltaType, item->type));
666✔
1111
}
666✔
1112

1113
void CStructure::CopyMembers(CStructure* st, char*& lp) {
162✔
1114
        aint val;
1115
        int haakjes = 0;
162✔
1116
        AddMember(new CStructureEntry2(noffset, 0, 0, Relocation::OFF, SMEMBPARENOPEN));
162✔
1117
        SkipBlanks(lp);
162✔
1118
        if (*lp == '{') {
162✔
1119
                ++haakjes; ++lp;
90✔
1120
        }
1121
        CStructureEntry2* ip = st->mbf;
162✔
1122
        while (ip || 0 < haakjes) {
984✔
1123
                Relocation::isResultAffected = false;
822✔
1124
                // check if inside curly braces block, and input seems to be empty -> fetch next line
1125
                if (0 < haakjes && !PrepareNonBlankMultiLine(lp)) break;
822✔
1126
                if (nullptr == ip) {        // no more struct members expected, looking for closing '}'
822✔
1127
                        assert(0 < haakjes);
90✔
1128
                        if (!need(lp, '}')) break;
90✔
1129
                        --haakjes;
90✔
1130
                        continue;
90✔
1131
                }
1132
                assert(ip);
732✔
1133
                switch (ip->type) {
732✔
1134
                case SMEMBBLOCK:
48✔
1135
                        CopyMember(ip, ip->def, Relocation::OFF);
48✔
1136
                        break;
48✔
1137
                case SMEMBBYTE:
522✔
1138
                case SMEMBWORD:
1139
                case SMEMBD24:
1140
                case SMEMBDWORD:
1141
                        {
1142
                                Relocation::EType isRelocatable = Relocation::OFF;
522✔
1143
                                if (ParseExpressionNoSyntaxError(lp, val)) {
522✔
1144
                                        isRelocatable = (Relocation::isResultAffected && (SMEMBWORD == ip->type || SMEMBBYTE == ip->type))
318✔
1145
                                                                                ? Relocation::deltaType : Relocation::OFF;
318✔
1146
                                } else {
1147
                                        val = ip->def;
216✔
1148
                                        isRelocatable = ip->defDeltaType;
216✔
1149
                                }
1150
                                CopyMember(ip, val, isRelocatable);
522✔
1151
                                if (SMEMBWORD == ip->type) {
522✔
1152
                                        Relocation::resolveRelocationAffected(INT_MAX);        // clear flags + warn when can't be relocated
108✔
1153
                                } else if (SMEMBBYTE == ip->type) {
414✔
1154
                                        Relocation::resolveRelocationAffected(INT_MAX, Relocation::HIGH);        // clear flags + warn when can't be relocated
390✔
1155
                                }
1156
                                if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(lp);
522✔
1157
                        }
1158
                        break;
522✔
1159
                case SMEMBTEXT:
66✔
1160
                        {
1161
                                byte* textData = new byte[ip->len]();        // zero initialized for stable binary results
348✔
1162
                                if (nullptr == textData) ErrorOOM();
66✔
1163
                                GetStructText(lp, ip->len, textData, ip->text);
66✔
1164
                                AddMember(new CStructureEntry2(noffset, ip->len, textData));
66✔
1165
                                if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(lp);
66✔
1166
                        }
1167
                        break;
66✔
1168
                case SMEMBPARENOPEN:
48✔
1169
                        SkipBlanks(lp);
48✔
1170
                        if (*lp == '{') {
48✔
1171
                                ++haakjes; ++lp;
12✔
1172
                        }
1173
                        CopyMember(ip, 0, Relocation::OFF);
48✔
1174
                        break;
48✔
1175
                case SMEMBPARENCLOSE:
48✔
1176
                        SkipBlanks(lp);
48✔
1177
                        if (haakjes && *lp == '}') {
48✔
1178
                                --haakjes; ++lp;
12✔
1179
                                if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(lp);
12✔
1180
                        }
1181
                        CopyMember(ip, 0, Relocation::OFF);
48✔
1182
                        break;
48✔
UNCOV
1183
                default:
×
UNCOV
1184
                        Error("internalerror CStructure::CopyMembers", NULL, FATAL);
×
1185
                }
1186
                Relocation::checkAndWarn();
732✔
1187
                ip = ip->next;
732✔
1188
        }
1189
        if (haakjes) {
162✔
UNCOV
1190
                Error("closing } missing");
×
1191
        }
1192
        AddMember(new CStructureEntry2(noffset, 0, 0, Relocation::OFF, SMEMBPARENCLOSE));
162✔
1193
}
162✔
1194

1195
static void InsertSingleStructLabel(const bool setNameSpace, char *name, const bool isRelocatable, const aint value, const bool isDefine = true) {
14,388✔
1196
        char *op = name;
14,388✔
1197
        std::unique_ptr<char[]> p(ValidateLabel(op, setNameSpace));
14,388✔
1198
        if (!p) {
14,388✔
1199
                Error("Illegal labelname", op, EARLY);
6✔
1200
                return;
6✔
1201
        }
1202
        if (pass == LASTPASS) {
14,382✔
1203
                aint oval;
1204
                if (!GetLabelValue(op, oval)) {
4,794✔
UNCOV
1205
                        Error("Internal error. ParseLabel()", op, FATAL);
×
1206
                }
1207
                if (value != oval) {
4,794✔
1208
                        Error("Label has different value in pass 2", p.get());
10✔
1209
                }
1210
                if (IsSldExportActive()) {                // SLD (Source Level Debugging) tracing-data logging
4,794✔
1211
                        SLabelTableEntry* symbol = LabelTable.Find(p.get(), true);
124✔
1212
                        assert(symbol);        // should have been already defined before last pass
124✔
1213
                        if (symbol) {
124✔
1214
                                WriteToSldFile(isDefine ? -1 : symbol->page, value, 'L', ExportLabelToSld(name, symbol));
124✔
1215
                        }
1216
                }
1217
        } else {
1218
                Relocation::isResultAffected = isRelocatable;
9,588✔
1219
                Relocation::deltaType = isRelocatable ? Relocation::REGULAR : Relocation::OFF;
9,588✔
1220
                assert(!isDefine || Relocation::OFF == Relocation::deltaType);        // definition labels are always nonrel
9,588✔
1221
                unsigned traits = LABEL_HAS_RELOC_TRAIT \
9,588✔
1222
                                                | (isDefine ? LABEL_IS_STRUCT_D : LABEL_IS_STRUCT_E) \
9,588✔
1223
                                                | (isRelocatable ? LABEL_IS_RELOC : 0);
9,588✔
1224
                if (!LabelTable.Insert(p.get(), value, traits)) Error("Duplicate label", p.get(), EARLY);
9,588✔
1225
        }
1226
}
14,388✔
1227

1228
static void InsertStructSubLabels(const char* mainName, const bool isRelocatable, const CStructureEntry1* members, const aint address = 0, const bool isDefine = true) {
1,512✔
1229
        char ln[LINEMAX+1];
1230
        STRCPY(ln, LINEMAX, mainName);
1,512✔
1231
        char * const lnsubw = ln + strlen(ln);
1,512✔
1232
        while (members) {
14,388✔
1233
                STRCPY(lnsubw, LINEMAX-strlen(ln), members->naam);                // overwrite sub-label part
12,876✔
1234
                InsertSingleStructLabel(false, ln, isRelocatable, members->offset + address, isDefine);
12,876✔
1235
                members = members->next;
12,876✔
1236
        }
1237
}
1,512✔
1238

1239
void CStructure::deflab() {
474✔
1240
        const size_t moduleNameLength = strlen(ModuleName);
474✔
1241
        char sn[LINEMAX] = { '@', 0 };
474✔
1242
        if (moduleNameLength && (0 == strncmp(id, ModuleName, moduleNameLength)) \
474✔
1243
                && ('.' == id[moduleNameLength]) && (id[moduleNameLength+1]))
42✔
1244
        {
1245
                // looks like the structure name starts with current module name, use non-global way then
1246
                STRCPY(sn, LINEMAX-1, id + moduleNameLength + 1);
42✔
1247
        } else {
1248
                // the structure name does not match current module, use the global "@id" way to define it
1249
                STRCPY(sn+1, LINEMAX-1, id);
432✔
1250
        }
1251
        InsertSingleStructLabel(true, sn, false, noffset);
474✔
1252
        STRCAT(sn, LINEMAX-1, ".");
474✔
1253
        InsertStructSubLabels(sn, false, mnf);
474✔
1254
}
474✔
1255

1256
void CStructure::emitlab(char* iid, aint address, const bool isRelocatable) {
1,038✔
1257
        const aint misalignment = maxAlignment ? ((-address) & (maxAlignment - 1)) : 0;
1,038✔
1258
        if (misalignment) {
1,038✔
1259
                // emitting in misaligned position (considering the ALIGN used to define this struct)
1260
                char warnTxt[LINEMAX];
1261
                SPRINTF3(warnTxt, LINEMAX,
26✔
1262
                                        "Struct %s did use ALIGN %d in definition, but here it is misaligned by %d bytes",
1263
                                        naam, maxAlignment, misalignment);
1264
                Warning(warnTxt);
26✔
1265
        }
1266
        char sn[LINEMAX] { 0 };
1,038✔
1267
        STRCPY(sn, LINEMAX-1, iid);
1,038✔
1268
        InsertSingleStructLabel(true, sn, isRelocatable, address, false);
1,038✔
1269
        STRCAT(sn, LINEMAX-1, ".");
1,038✔
1270
        InsertStructSubLabels(sn, isRelocatable, mnf, address, false);
1,038✔
1271
}
1,038✔
1272

1273
void CStructure::emitmembs(char*& p) {
1,272✔
1274
        byte* emitTextBuffer = nullptr;
1,272✔
1275
        aint val;
1276
        int haakjes = 0;
1,272✔
1277
        SkipBlanks(p);
1,272✔
1278
        if (*p == '{') {
1,272✔
1279
                ++haakjes; ++p;
654✔
1280
        }
1281
        CStructureEntry2* ip = mbf;
1,272✔
1282
        Relocation::isResultAffected = false;
1,272✔
1283
        while (ip || 0 < haakjes) {
15,796✔
1284
                // check if inside curly braces block, and input seems to be empty -> fetch next line
1285
                if (0 < haakjes && !PrepareNonBlankMultiLine(p)) break;
14,578✔
1286
                if (nullptr == ip) {        // no more struct members expected, looking for closing '}'
14,560✔
1287
                        assert(0 < haakjes);
516✔
1288
                        if (!need(p, '}')) break;
516✔
1289
                        --haakjes;
480✔
1290
                        continue;
480✔
1291
                }
1292
                assert(ip);
14,044✔
1293
                switch (ip->type) {
14,044✔
1294
                case SMEMBBLOCK:
1,642✔
1295
                        EmitBlock(ip->def != -1 ? ip->def : 0, ip->len, ip->def == -1, 8);
1,642✔
1296
                        if (8 < ip->len) ListFile();        // "..." elipsis happened in listing, force listing
1,642✔
1297
                        break;
1,642✔
1298
                case SMEMBBYTE:
4,932✔
1299
                        EmitByte(ip->ParseValue(p));
4,932✔
1300
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
4,932✔
1301
                        break;
4,932✔
1302
                case SMEMBWORD:
1,884✔
1303
                        // ParseValue will also add relocation data if needed (so the "ParseValue" name is misleading)
1304
                        EmitWord(ip->ParseValue(p));
1,884✔
1305
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
1,884✔
1306
                        break;
1,884✔
1307
                case SMEMBD24:
408✔
1308
                        val = ip->ParseValue(p);
408✔
1309
                        EmitByte(val & 0xFF);
408✔
1310
                        EmitWord((val>>8) & 0xFFFF);
408✔
1311
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
408✔
1312
                        break;
408✔
1313
                case SMEMBDWORD:
726✔
1314
                        val = ip->ParseValue(p);
726✔
1315
                        EmitWord(val & 0xFFFF);
726✔
1316
                        EmitWord((val>>16) & 0xFFFF);
726✔
1317
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
726✔
1318
                        break;
726✔
1319
                case SMEMBTEXT:
1,128✔
1320
                        {
1321
                                if (nullptr == emitTextBuffer) {
1,128✔
1322
                                        emitTextBuffer = new byte[CStructureEntry2::TEXT_MAX_SIZE+2];
258✔
1323
                                        if (nullptr == emitTextBuffer) ErrorOOM();
258✔
1324
                                }
1325
                                memset(emitTextBuffer, 0, ip->len);
1,128✔
1326
                                GetStructText(p, ip->len, emitTextBuffer, ip->text);
1,128✔
1327
                                for (aint ii = 0; ii < ip->len; ++ii) EmitByte(emitTextBuffer[ii]);
8,238✔
1328
                        }
1329
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
1,128✔
1330
                        break;
1,128✔
1331
                case SMEMBPARENOPEN:
1,662✔
1332
                        SkipBlanks(p);
1,662✔
1333
                        if (*p == '{') { ++haakjes; ++p; }
1,662✔
1334
                        break;
1,662✔
1335
                case SMEMBPARENCLOSE:
1,662✔
1336
                        SkipBlanks(p);
1,662✔
1337
                        if (haakjes && *p == '}') {
1,662✔
1338
                                --haakjes; ++p;
834✔
1339
                        }
1340
                        if (ip->next && SMEMBPARENCLOSE != ip->next->type) anyComma(p);
1,662✔
1341
                        break;
1,662✔
UNCOV
1342
                default:
×
UNCOV
1343
                        ErrorInt("Internal Error CStructure::emitmembs", ip->type, FATAL);
×
1344
                }
1345
                ip = ip->next;
14,044✔
1346
        }
1347
        if (haakjes) {
1,272✔
1348
                Error("closing } missing");
54✔
1349
        }
1350
        if (!SkipBlanks(p)) Error("[STRUCT] Syntax error - too many arguments?");
1,272✔
1351
        Relocation::checkAndWarn();
1,272✔
1352
        if (nullptr != emitTextBuffer) delete[] emitTextBuffer;
1,272✔
1353
}
1,272✔
1354

1355
CStructureTable::CStructureTable() {
1,058✔
1356
        for (auto & structPtr : strs) structPtr = nullptr;
136,482✔
1357
}
1,058✔
1358

1359
CStructureTable::~CStructureTable() {
1,058✔
1360
        for (auto structPtr : strs) if (structPtr) delete structPtr;
136,482✔
1361
}
1,058✔
1362

1363
void CStructureTable::ReInit() {
3,070✔
1364
        for (auto & structPtr : strs) {
396,030✔
1365
                if (structPtr) delete structPtr;
392,960✔
1366
                structPtr = nullptr;
392,960✔
1367
        }
1368
}
3,070✔
1369

1370
CStructure* CStructureTable::Add(char* naam, int no, int gl) {
480✔
1371
        char sn[LINEMAX], * sp;
1372
        sn[0] = 0;
480✔
1373
        if (!gl && *ModuleName) {
480✔
1374
                STRCPY(sn, LINEMAX-2, ModuleName);
42✔
1375
                STRCAT(sn, 2, ".");
42✔
1376
        }
1377
        STRCAT(sn, LINEMAX-1, naam);
480✔
1378
        sp = sn;
480✔
1379
        if (FindDuplicate(sp)) {
480✔
1380
                Error("[STRUCT] Structure already exist", naam);
6✔
1381
                return nullptr;
6✔
1382
        }
1383
        strs[(*sp)&127] = new CStructure(naam, sp, 0, gl, strs[(*sp)&127]);
474✔
1384
        if (no) {
474✔
1385
                strs[(*sp)&127]->AddMember(new CStructureEntry2(0, no, -1, Relocation::OFF, SMEMBBLOCK));
74✔
1386
        }
1387
        return strs[(*sp)&127];
474✔
1388
}
1389

1390
CStructure* CStructureTable::zoek(const char* naam, int gl) {
518,898✔
1391
        char sn[LINEMAX], * sp;
1392
        sn[0] = 0;
518,898✔
1393
        if (!gl && *ModuleName) {
518,898✔
1394
                STRCPY(sn, LINEMAX-2, ModuleName);
7,932✔
1395
                STRCAT(sn, 2, ".");
7,932✔
1396
        }
1397
        STRCAT(sn, LINEMAX-1, naam);
518,898✔
1398
        sp = sn;
518,898✔
1399
        CStructure* p = strs[(*sp)&127];
518,898✔
1400
        while (p) {
519,918✔
1401
                if (!strcmp(sp, p->id)) return p;
2,508✔
1402
                p = p->next;
1,020✔
1403
        }
1404
        if (gl || ! *ModuleName) return NULL;
517,410✔
1405
        sp += 1 + strlen(ModuleName); p = strs[(*sp)&127];
7,878✔
1406
        while (p) {
7,926✔
1407
                if (!strcmp(sp, p->id)) return p;
114✔
1408
                p = p->next;
48✔
1409
        }
1410
        return NULL;
7,812✔
1411
}
1412

1413
int CStructureTable::FindDuplicate(char* naam) {
480✔
1414
        CStructure* p = strs[(*naam)&127];
480✔
1415
        while (p) {
786✔
1416
                if (!strcmp(naam, p->naam)) return 1;
312✔
1417
                p = p->next;
306✔
1418
        }
1419
        return 0;
474✔
1420
}
1421

1422
aint CStructureTable::ParseDesignedAddress(char* &p) {
1,386✔
1423
        if (!SkipBlanks(p) && ('=' == *p)) {
1,386✔
1424
                char* adrP = ++p;
114✔
1425
                aint resultAdr;
1426
                if (ParseExpressionNoSyntaxError(p, resultAdr)) return resultAdr;
114✔
1427
                Error("[STRUCT] Syntax error in designed address", adrP, SUPPRESS);
6✔
1428
                return 0;
6✔
1429
        }
1430
        return INT_MAX;                // no "designed address" provided, emit structure bytes
1,272✔
1431
}
1432

1433
int CStructureTable::Emit(char* naam, char* l, char*& p, int gl) {
518,592✔
1434
        CStructure* st = zoek(naam, gl);
518,592✔
1435
        if (!st) return 0;
518,592✔
1436
        // create new labels corresponding to current/designed address
1437
        aint address = CStructureTable::ParseDesignedAddress(p);
1,386✔
1438
        if (l) {
1,386✔
1439
                const Relocation::EType relocatable =
1,038✔
1440
                        (INT_MAX == address) ?
2,076✔
1441
                                (Relocation::type ? Relocation::REGULAR : Relocation::OFF)
930✔
1442
                                : Relocation::isResultAffected ? Relocation::deltaType : Relocation::OFF;
108✔
1443
                st->emitlab(l, (INT_MAX == address) ? CurAddress : address, relocatable == Relocation::REGULAR);
1,038✔
1444
        }
1445
        if (INT_MAX == address) st->emitmembs(p);        // address was not designed, emit also bytes
1,386✔
1446
        else if (!l) Warning("[STRUCT] designed address without label = no effect");
114✔
1447
        return 1;
1,386✔
1448
}
1449

1450
SRepeatStack::SRepeatStack(aint count, CStringsList* condition, CStringsList* firstLine)
8,440✔
1451
        : RepeatCount(count), RepeatCondition(condition), Lines(firstLine), Pointer(firstLine), IsInWork(false), Level(0)
8,440✔
1452
{
1453
        assert(!sourcePosStack.empty());
8,440✔
1454
        sourcePos = sourcePosStack.back();
8,440✔
1455
}
8,440✔
1456

1457
SRepeatStack::~SRepeatStack() {
8,440✔
1458
        if (RepeatCondition) delete RepeatCondition;
8,440✔
1459
        if (Lines) delete Lines;
8,440✔
1460
}
8,440✔
1461

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