OpenCores
URL https://opencores.org/ocsvn/forwardcom/forwardcom/trunk

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [assem1.cpp] - Blame information for rev 67

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 41 Agner
/****************************    assem1.cpp    ********************************
2
* Author:        Agner Fog
3
* Date created:  2017-04-17
4
* Last modified: 2021-07-10
5
* Version:       1.11
6
* Project:       Binary tools for ForwardCom instruction set
7
* Module:        assem.cpp
8
* Description:
9
* Module for assembling ForwardCom .as files. Contains:
10
* pass1(): Split input file into lines and tokens. Remove comments. Find symbol definitions
11
* pass2(): Handle meta code. Classify lines. Identify symbol names, sections, functions
12
*
13
* Copyright 2017-2021 GNU General Public License http://www.gnu.org/licenses
14
******************************************************************************/
15
#include "stdafx.h"
16
 
17
const char * allowedInNames = "_$@";   // characters allowed in symbol names (don't allow characters that are used as operators)
18
const bool allowUTF8 = true;           // UTF-8 characters allowed in symbol names
19
const bool allowNestedComments = true; // allow nested comments: /* /* */ */
20
 
21
                                       // Operator for sorting symbols by name. Used by assembler
22
// List of operators
23
SOperator operatorsList[] = {
24
    // name, id, priority
25
    {"(", '(',      1},
26
    {")", ')',      1},
27
    {"[", '[',      1},
28
    {"]", ']',      1},
29
    {"{", '{',      1},
30
    {"}", '}',      1},
31
    {"'", 39,       1},
32
    {"\"", '"',     1},           // "
33
    {"/*", 'c',     1},           // comment begin
34
    {"*/", 'd',     1},           // comment end
35
    {".", '.',      2},
36
    {"!", '!',      3},
37
    {"~", '~',      3},
38
    {"++", '+'+D2,  3},
39
    {"--", '-'+D2,  3},
40
    {"*", '*',      4},
41
    {"/", '/',      4},
42
    {"%", '%',      4},
43
    {"+", '+',      5},
44
    {"-", '-',      5},
45
    {"<<", '<'+D2,  6},
46
    {">>", '>'+D2,  6},           // signed shift right
47
    {">>>", '>'+D3, 6},           // unsigned shift right
48
    {"<", '<',      7},
49
    {"<=", '<'+EQ,  7},
50
    {">", '>',      7},
51
    {">=", '>'+EQ,  7},
52
    {"==", '='+D2,  8},
53
    {"!=", '!'+EQ,  8},
54
    {"&", '&',      9},
55
    {"^", '^',     10},
56
    {"|", '|',     11},
57
    {"&&", '&'+D2, 12},
58
    {"||", '|'+D2, 13},
59
    {"^^", '^'+D2, 13},           // boolean XOR. non-standard operator
60
    {"?", '?',     14},
61
    {":", ':',     14},
62
    {"=", '=',     15},
63
    {"+=", '+'+EQ, 15},
64
    {"-=", '-'+EQ, 15},
65
    {"*=", '*'+EQ, 15},
66
    {"/=", '/'+EQ, 15},
67
    {"%=", '%'+EQ, 15},
68
    {"<<=", '<'+D2+EQ,  15},
69
    {">>=", '>'+D2+EQ,  15},      // signed shift right
70
    {">>>=", '>'+D3+EQ, 15},      // unsigned shift right
71
    {"&=", '&'+EQ, 15},
72
    {"^=", '^'+EQ, 15},
73
    {"|=", '|'+EQ, 15},
74
    {",", ',',     16},
75
    {"//", '/'+D2, 20},           // comment, end of line
76
    {";", ';',     20}            // comment, end of line
77
};
78
 
79
 
80
// List of keywords
81
SKeyword keywordsList[] = {
82
    // name, id
83
    {"section",        DIR_SECTION},        // TOK_DIR: section, functions directives
84
    {"function",       DIR_FUNCTION},
85
    {"end",            DIR_END},
86
    {"public",         DIR_PUBLIC},
87
    {"extern",         DIR_EXTERN},
88
 
89
    // TOK_ATT: attributes of sections, functions and symbols
90
    {"read",           ATT_READ},           // readable section
91
    {"write",          ATT_WRITE},          // writeable section
92
    {"execute",        ATT_EXEC},           // executable section
93
    {"align",          ATT_ALIGN},          // align section, data, or code
94
    {"weak",           ATT_WEAK},           // weak linking
95
    {"reguse",         ATT_REGUSE},         // register use    
96
    {"constant",       ATT_CONSTANT},       // external constant
97
    {"uninitialized",  ATT_UNINIT},         // uninitialized section (BSS)
98
    {"communal",       ATT_COMDAT},         // communal section. duplicates and unreferenced sections are removed
99
    {"exception_hand", ATT_EXCEPTION},      // exception handler and stack unroll information
100
    {"event_hand",     ATT_EVENT},          // event handler list, including constructors and destructors
101
    {"debug_info",     ATT_DEBUG},          // debug information
102
    {"comment_info",   ATT_COMMENT},        // comments, including copyright and required libraries
103
 
104
    // TOK_TYP: type names
105
    {"int8",           TYP_INT8},
106
    {"uint8",          TYP_INT8+TYP_UNS},
107
    {"int16",          TYP_INT16},
108
    {"uint16",         TYP_INT16+TYP_UNS},
109
    {"int32",          TYP_INT32},
110
    {"uint32",         TYP_INT32+TYP_UNS},
111
    {"int64",          TYP_INT64},
112
    {"uint64",         TYP_INT64+TYP_UNS},
113
    {"int128",         TYP_INT128},
114
    {"uint128",        TYP_INT128+TYP_UNS},
115
    {"int",            TYP_INT32},
116
    {"uint",           TYP_INT32+TYP_UNS},
117
    {"float",          TYP_FLOAT32},
118
    {"double",         TYP_FLOAT64},
119
    {"float16",        TYP_FLOAT16},
120
    {"float32",        TYP_FLOAT32},
121
    {"float64",        TYP_FLOAT64},
122
    {"float128",       TYP_FLOAT128},
123
    {"string",         TYP_STRING},
124
 
125
    // TOK_OPT: options of instructions and operands
126
    {"mask",           OPT_MASK},
127
    {"fallback",       OPT_FALLBACK},
128
    {"length",         OPT_LENGTH},
129
    {"broadcast",      OPT_BROADCAST},
130
    {"limit",          OPT_LIMIT},
131
    {"scalar",         OPT_SCALAR},
132
    {"options",        OPT_OPTIONS},
133
    {"option",         OPT_OPTIONS},  // alias
134
 
135
    // TOK_REG: register names    
136
    {"numcontr",       REG_NUMCONTR},
137
    {"threadp",        REG_THREADP},
138
    {"datap",          REG_DATAP},
139
    {"ip",             REG_IP},
140
    {"sp",             REG_SP},
141
 
142
    // TOK_HLL: high level language keywords
143
    {"if",             HLL_IF},
144
    {"else",           HLL_ELSE},
145
    {"switch",         HLL_SWITCH},         // switch (r1, scratch registers) { case 0: break; ...}
146
    {"case",           HLL_CASE},
147
    {"for",            HLL_FOR},            // for (r1 = 1; r1 <= r2; r1++) {}
148
    {"in",             HLL_IN},             // for (float v1 in [r1-r2], nocheck) // (r2 counts down)
149
    {"while",          HLL_WHILE},          // while (r1 > 0) {}
150
    {"do",             HLL_DO},             // do {} while ()
151
    {"break",          HLL_BREAK},          // break out of switch or loop
152
    {"continue",       HLL_CONTINUE},       // continue loop 
153
    {"true",           HLL_TRUE},           // constant = 1
154
    {"false",          HLL_FALSE},          // constant = 0
155
 
156
    // temporary additions. will be replaced by macros later:
157
    {"push",           HLL_PUSH},           // push registers
158
    {"pop",            HLL_POP},            // pop registers
159
 
160
};
161
 
162
// List of register name prefixes
163
SKeyword registerNames[] = {
164
    // name, id
165
    {"r",            REG_R},
166
    {"v",            REG_V},
167
    {"spec",         REG_SPEC},
168
    {"capab",        REG_CAPAB},
169
    {"perf",         REG_PERF},
170
    {"sys",          REG_SYS}
171
};
172
 
173
 
174
CAssembler::CAssembler() {                                 // Constructor
175
    // Reserve size for buffers
176
    const int estimatedLineLength = 16;
177
    const int estimatedTokensPerLine = 10;
178
    int estimatedNumLines = dataSize() / estimatedLineLength;
179
    lines.setNum(estimatedNumLines);
180
    tokens.setNum(estimatedNumLines * estimatedTokensPerLine);
181
    errors.setOwner(this);
182
    // Initialize and sort lists
183
    initializeWordLists();
184
    ElfFwcShdr nullHeader;         // make first section header empty
185
    zeroAllMembers(nullHeader);
186
    sectionHeaders.push(nullHeader);
187
}
188
 
189
void CAssembler::go() {
190
 
191
    // Write feedback text to console
192
    feedBackText1();
193
 
194
    // Set default options
195
    if (cmd.codeSizeOption == 0) cmd.codeSizeOption = 1 << 24;
196
    if (cmd.dataSizeOption == 0) cmd.dataSizeOption = 1 << 15;
197
    // initialize options
198
    code_size = cmd.codeSizeOption;
199
    data_size = cmd.dataSizeOption;
200
 
201
    do {  // This loop is repeated only once. Just convenient to break out of in case of errors
202
        pass = 1;
203
        // Split input file into lines and tokens. Find symbol definitions
204
        pass1();
205
        if (errors.tooMany()) {err.submit(ERR_TOO_MANY_ERRORS);  break;}
206
 
207
        pass = 2;
208
        // A. Handle metaprogramming directives
209
        // B. Classify lines
210
        // C. Identify symbol names, sections, labels, functions 
211
        pass2();
212
        if (errors.tooMany()) {err.submit(ERR_TOO_MANY_ERRORS);  break;}
213
 
214
        //showTokens();  //!! for debugging only
215
        //showSymbols(); //!! for debugging only        
216
 
217
        pass = 3;
218
        // Interpret lines. Generate code and data
219
        pass3();
220
        if (errors.tooMany()) {err.submit(ERR_TOO_MANY_ERRORS);  break;}
221
 
222
        pass = 4;
223
        // Resolve internal cross references, optimize forward references
224
        pass4();
225
        if (errors.tooMany()) {err.submit(ERR_TOO_MANY_ERRORS);  break;}
226
 
227
        pass = 5;
228
        // Make binary file
229
        pass5();
230
        if (errors.tooMany()) {err.submit(ERR_TOO_MANY_ERRORS);  break;}
231
 
232
    } while (false);
233
 
234
    // output any error messages
235
    errors.outputErrors();
236
    if (errors.numErrors()) cmd.mainReturnValue = 1; // make sure makefile process stops on error
237
 
238
    // output object file
239
    outFile.write(cmd.getFilename(cmd.outputFile));
240
}
241
 
242
 
243
// Character can be the start of a symbol name
244
inline bool nameChar1(char c) {
245
    return ((c | 0x20) >= 'a' && (c | 0x20) <= 'z') || ((c & 0x80) && allowUTF8) || strchr(allowedInNames, c);
246
}
247
 
248
// Character can be the part of a symbol name
249
inline bool nameChar2(char c) {
250
    return nameChar1(c) || (c >= '0' && c <= '9');
251
}
252
 
253
// check if string is a number. Can be decimal, binary, octal, hexadecimal, or floating point
254
// Returns the length of the part of the string that belongs to the number
255
uint32_t isNumber(const char * s, int maxlen, bool * isFloat) {
256
    bool is_float = false;
257
    char c = s[0];
258
    if ((c < '0' || c > '9') && (c != '.' || s[1] < '0' || s[1] > '9')) return 0;
259
    int i = 0;
260
    int state = 0;
261
    // 0: begin
262
    // 1: after 0
263
    // 2: after digits 0-9
264
    // 3: after 0x
265
    // 4: after 0b or 0o
266
    // 5: after .
267
    // 6: after E
268
    // 7: after E09
269
    // 8: after E+-
270
    for (i = 0; i < maxlen; i++) {
271
        c = s[i];
272
        char cl = c | 0x20;   // upper case letter
273
        if (c == '0' && state == 0) {state = 1; continue;}
274
        if (cl == 'x' && state == 1) {state = 3; continue;}
275
        if ((cl == 'b' || cl == 'o') && state == 1) {state = 4; continue;}
276
        if (c == '.' && state <= 2)  {state = 5; is_float = true; continue;}
277
        if (cl == 'e' && (state <= 2 || state == 5)) {state = 6; is_float = true; continue;}
278
        if ((c == '+' || c == '-') && state == 6) {state = 8; continue;}
279
        if (c >= '0' && c <= '9') {
280
            if (state < 2) state = 2;
281
            if (state == 6) state = 7;
282
            continue;
283
        }
284
        if (cl >= 'a' && cl <= 'f' && state == 3) continue;
285
        // Anything else: stop here
286
        break;
287
    }
288
    if (isFloat) *isFloat = is_float;       // return isFloat
289
    return i;                               // return length
290
}
291
 
292
// Check if string is a register name
293
uint32_t isRegister(const char * s, uint32_t len) {
294
    uint32_t i, j, nl, num;
295
    for (i = 0; i < TableSize(registerNames); i++) {
296
        if ((s[0] | 0x20) == registerNames[i].name[0]) {   // first character match, lower case
297
            nl = (uint32_t)strlen(registerNames[i].name);  // length of register name prefix
298
            if (len < nl + 1 || len > nl + 2) continue;    // continue search if length wrong
299
            for (j = 0; j < nl; j++) {                     // check if each character matches
300
                if ((s[j] | 0x20) != registerNames[i].name[j]) { // lower case compare
301
                    j = 0xFFFFFFFF; break;
302
                }
303
            }
304
            if (j == 0xFFFFFFFF) continue;                 // no match
305
            if (s[j] < '0' || s[j] > '9') continue;        // not a number
306
            num = s[j] - '0';                              // get number, first digit
307
            if (len == nl + 2) {                           // two digit number
308
                if (s[j+1] < '0' || s[j+1] > '9') continue;// second digit not a number            
309
                num = num * 10 + (s[j+1] - '0');
310
            }
311
            if (num >= 32) continue;                       // number too high
312
            return num + registerNames[i].id;              // everyting matches
313
        }
314
    }
315
    return 0;       // not found. return 0
316
}
317
 
318
// write feedback text on stdout
319
void CAssembler::feedBackText1() {
320
    if (cmd.verbose) {
321
        // Tell what we are doing:
322
        printf("\nAssembling %s to %s", cmd.getFilename(cmd.inputFile), cmd.getFilename(cmd.outputFile));
323
    }
324
}
325
 
326
 
327
// Split input file into lines and tokens. Handle preprocessing directives. Find symbol definitions
328
void CAssembler::pass1() {
329
    uint32_t n = 0;                // offset into assembly file
330
    uint32_t m;                    // end of current token
331
    int32_t  i, f;                 // temporary
332
    int32_t  comment = 0;          // 0: normal, 1: inside comment to end of line, 2: inside /* */ comment
333
    uint32_t commentStart = 0;     // start position of multiline comment
334
    uint32_t commentStartColumn = 0;// start column of multiline comment
335
    char c;                        // current character or byte
336
    SToken token = {0};            // current token
337
    SKeyword keywSearch;           // record to search for keyword
338
    SOperator opSearch;            // record to search for operator
339
    SInstruction instructSearch;   // record to search for instruction
340
    SLine line = {0,0,0,0,0,0,0};  // line record
341
    lines.push(line);              // empty records for line 0
342
    linei = 1;                     // start at line 1
343
    numSwitch = 0;              // count switch statements
344
    tokens.push(token);            // unused token 0
345
 
346
    if (dataSize() >= 3 && (get<uint32_t>(0) & 0xFFFFFF) == 0xBFBBEF) {
347
        n += 3;                    // skip UTF-8 byte order mark
348
    }
349
 
350
    line.beginPos = n;             // start of line 1
351
    line.firstToken = tokens.numEntries();
352
    line.file = filei;
353
 
354
    // loop through file
355
    while (n < dataSize()) {
356
        c = get<char>(n);              // get character
357
 
358
        // is it space or a control character?
359
        if (uint8_t(c) <= 0x20) {
360
            if (c == ' ' || c == '\t') {   // skip space and tab
361
                n++;
362
                continue;
363
            }
364
            if (c == '\r' || c == '\n') {  // newline
365
                n++;
366
                if (c == '\r' && get<char>(n) == '\n') n++;  // "\r\n" windows newline
367
                if (comment == 1) comment = 0;                  // end comment
368
                if (n <= dataSize()) {
369
                    // finish current line
370
                    line.numTokens = tokens.numEntries() - line.firstToken;
371
                    line.linenum = linei++;
372
                    if (line.numTokens) {  // save line if not empty                  
373
                        lines.push(line);
374
                    }
375
                    // start next line
376
                    line.type = 0;
377
                    line.file = filei;
378
                    line.beginPos = n;
379
                    line.firstToken = tokens.numEntries();
380
                }
381
                continue;
382
            }
383
            // illegal control character
384
            token.type = TOK_ERR;
385
            line.type = LINE_ERROR;
386
            comment = 1;              // ignore rest of line
387
            m = tokens.push(token);     // save error token
388
            errors.report(n, 1, ERR_CONTROL_CHAR);
389
        }
390
        // prepare token of any type
391
        token.pos  = n;
392
        token.stringLength = 1;
393
        token.id   = 0;
394
        //token.column = n - line.beginPos;
395
 
396
        // is it a name?
397
        if (!comment && nameChar1(c)) {
398
            // start of a name
399
            m = n+1;
400
            while (m < dataSize() && nameChar2(get<char>(m))) m++;
401
            // name goes from position n to m-1. make token
402
            token.type = TOK_NAM;
403
            token.pos = n;
404
            token.stringLength = m - n;
405
 
406
            // is it a register name
407
            f = isRegister((char*)buf()+n, token.stringLength);
408
            if (f) {
409
                token.type = TOK_REG;
410
                token.id = f;
411
            }
412
            // is it a keyword?
413
            if (token.type == TOK_NAM && m-n < sizeof(keywSearch.name)) {
414
                memcpy(keywSearch.name, buf()+n, m-n);
415
                keywSearch.name[m-n] = 0;
416
                f = keywords.findFirst(keywSearch);
417
                if (f >= 0) {  // keyword found
418
                    token.id = keywords[f].id;
419
                    token.type = keywords[f].id >> 24;
420
                    if (token.id == HLL_SWITCH) numSwitch++;
421
                }
422
            }
423
            // is it an instruction?
424
            if (token.type == TOK_NAM && m-n < sizeof(instructSearch.name)) {
425
                memcpy(instructSearch.name, buf()+n, m-n);
426
                instructSearch.name[m-n] = 0;
427
                f = instructionlistNm.findFirst(instructSearch);
428
                if (f >= 0) {  // instruction name found
429
                    token.type = TOK_INS;
430
                    token.id = instructionlistNm[f].id;
431
                }
432
            }
433
            n = m;
434
            tokens.push(token);     // save token
435
            continue;
436
        }
437
 
438
        // Is it a number?
439
        if (!comment) {
440
            bool isFloat;
441
            f = isNumber((char*)buf() + n, dataSize() - n, &isFloat);
442
            if (f) {
443
                token.type = TOK_NUM + isFloat;
444
                token.id = n;               // save number as string. The value is extracted later
445
                token.stringLength = f;
446
                n += f;
447
                tokens.push(token);     // save token
448
                continue;
449
            }
450
        }
451
 
452
        // is it an operator?
453
        opSearch.name[0] = c;
454
        opSearch.name[1] = 0;
455
        f = operators.findFirst(opSearch);
456
        if (f >= 0) {
457
            // found single-character operator
458
            // make a greedy search for multi-character operators
459
            i = f;
460
            for (i = f+1; (uint32_t)i < operators.numEntries(); i++) {
461
                if (operators[i].name[0] != c) break;
462
                if (memcmp((char*)buf()+n, operators[i].name, strlen(operators[i].name)) == 0) f = i;
463
            }
464
            token.type = TOK_OPR;
465
            token.id = operators[f].id;
466
            token.priority = operators[f].priority;
467
            token.stringLength = (uint32_t)strlen(operators[f].name);
468
 
469
            // search for operators that need consideration here
470
            switch (token.id) {
471
 
472
            case 39: case '"':  // quoted string in single or double quotes
473
                if (comment) break;
474
                // search for end of string
475
                token.type = token.id == 39 ? TOK_CHA : TOK_STR;
476
                token.pos = n + 1;
477
                m = n;
478
                while (true) {
479
                    if (get<char>(m+1) == '\r' || get<char>(m+1) == '\n' || m == dataSize()) {
480
                        // end of line without matching end quote. multi-line quotes not allowed
481
                        token.type = TOK_ERR;
482
                        errors.report(token.pos-1, 1, ERR_QUOTE_BEGIN);
483
                        comment = 1; // skip rest of line
484
                        break;
485
                    }
486
                    if (get<char>(m+1) == c && get<char>(m) != '\\') {  // matching end quote not preceded by escape backslash
487
                        token.stringLength = m - n;
488
                        n += 2;
489
                        break;
490
                    }
491
                    m++;
492
                }
493
                break;
494
 
495
            case '/'+D2:            // "//". comment to end of line
496
                if (comment == 0) {
497
                    comment = 1;
498
                }
499
                break;
500
            case 'c':                                 // "/*" start of comment
501
                if (comment == 1) {
502
                    n += token.stringLength;         // skip and don't save token
503
                    continue;
504
                }
505
                if (comment == 2) {                     // nested comment
506
                    if (allowNestedComments) {
507
                        comment++;
508
                    }
509
                    else {
510
                        token.type = TOK_ERR;
511
                        errors.report(n, 2, ERR_COMMENT_BEGIN);
512
                    }
513
                    break;
514
                }
515
                comment = 2;
516
                commentStart = n;  commentStartColumn = n - line.beginPos;
517
                break;
518
            case 'd':                                // "*/" end of comment
519
                if (comment == 1) {
520
                    n += token.stringLength;         // skip and don't save token
521
                    continue;
522
                }
523
                if (comment == 2) {
524
                    comment = 0;
525
                    n += token.stringLength;         // skip and don't save token
526
                    continue;
527
                }
528
                else if (comment > 2 && allowNestedComments) {
529
                    comment--;
530
                    n += token.stringLength;         // skip and don't save token
531
                    continue;
532
                }
533
                else {
534
                    token.type = TOK_ERR;           // unmatched end comment
535
                    errors.report(n, 2, ERR_COMMENT_END);
536
                    comment = 1;
537
                }
538
                break;
539
            case ';':
540
                // semicolon starts a new pseudo-line
541
                if (comment) break;
542
                // finish current line
543
                tokens.push(token);     // the ';' token is used only in for(;;) loops. should be ignored at the end of the line otherwise
544
                n += token.stringLength;
545
                line.numTokens = tokens.numEntries() - line.firstToken;
546
                line.linenum = linei;
547
                if (line.numTokens) {  // save line if not empty                  
548
                    lines.push(line);
549
                }
550
                // start next line
551
                line.beginPos = n;
552
                line.firstToken = tokens.numEntries();
553
                continue;  // don't save ';' token twice
554
            case '{':  case '}':
555
                if (comment) break;
556
                // put each bracket in a separate pseudo-line to ease high level language parsing
557
                // finish current line
558
                line.numTokens = tokens.numEntries() - line.firstToken;
559
                line.linenum = linei;
560
                if (line.numTokens) {  // save line if not empty                  
561
                    lines.push(line);
562
                }
563
                // start line with bracket only
564
                line.beginPos = n;
565
                line.firstToken = tokens.numEntries();
566
                tokens.push(token);      // save token
567
                n += token.stringLength;
568
                line.numTokens = 1;
569
                lines.push(line);
570
                // start line after bracket
571
                line.beginPos = n;
572
                line.firstToken = tokens.numEntries();
573
                continue;
574
            }
575
            if (comment == 0 && token.type != TOK_ERR) {
576
                // save token unless we are inside a comment or an error has occurred           
577
                tokens.push(token);     // save token
578
            }
579
            n += token.stringLength;
580
            continue;
581
        }
582
 
583
        if (comment) {
584
            // we are inside a comment. Continue search only for end of line or end of comment
585
            n++;
586
            continue;
587
        }
588
 
589
        // none of the above. Make token for illegal character
590
        token.type = TOK_ERR;
591
        line.type = LINE_ERROR;
592
        errors.report(n, 1, ERR_ILLEGAL_CHAR);
593
        comment = 1;              // ignore rest of line
594
        n++;
595
    }
596
    // finish last line
597
   // tokens.push(token);
598
    line.numTokens = tokens.numEntries() - line.firstToken;
599
    lines.push(line);
600
    // start pseudo line
601
    line.beginPos = n;
602
    line.firstToken = tokens.numEntries();
603
    line.type = 0;
604
 
605
    // check for unmatched comment
606
    if (comment >= 2) {
607
        token.type = TOK_ERR;
608
        errors.report(commentStart, commentStartColumn, ERR_COMMENT_BEGIN);
609
    }
610
    // make EOF token in the end
611
    line.type = 0;
612
    line.beginPos = n;
613
    line.firstToken = tokens.numEntries();
614
    line.numTokens = 1;
615
    lines.push(line);
616
    token.pos   = n;
617
    token.stringLength   = 0;
618
    token.type = TOK_EOF;    // end of file
619
    tokens.push(token);     // save eof token
620
}
621
 
622
 
623
void CAssembler::interpretSectionDirective() {
624
    // Interpret section directive during pass 2 or 3
625
    // pass 2: identify section name and type, and give it a number
626
    // pass 3: make section header
627
 
628
    // to do: nested sections
629
 
630
    uint32_t tok;                                          // token number
631
    ElfFWC_Sym2 sym;                                       // symbol record
632
    int32_t sectionsym = 0;                                // index to symbol record defining current section name
633
    uint32_t state = 0;                                    // 1: after align, 2: after '='
634
    ElfFwcShdr sectionHeader;                             // section header
635
    zeroAllMembers(sym);                                   // reset symbol
636
    zeroAllMembers(sectionHeader);                         // reset section header
637
    sectionHeader.sh_type = SHT_PROGBITS;                  // default section type
638
 
639
    sectionFlags = 0;
640
    for (tok = tokenB + 2; tok < tokenB + tokenN; tok++) { // get section attributes
641
        if (tokens[tok].type == TOK_ATT) {
642
            if (tokens[tok].id == ATT_UNINIT && state != 2) {
643
                sectionHeader.sh_type = SHT_NOBITS;                // uninitialized section (BSS)
644
                sectionFlags |= SHF_READ | SHF_WRITE;
645
            }
646
            else if (tokens[tok].id == ATT_COMDAT && state != 2) {
647
                sectionHeader.sh_type = SHT_COMDAT;                // communal section. duplicates and unreferenced sections are removed
648
            }
649
            else if (tokens[tok].id != ATT_ALIGN && state == 0) {
650
                sectionFlags |= tokens[tok].id & 0xFFFFFF;
651
                if (sectionFlags & SHF_EXEC) sectionFlags |= SHF_IP;  // executable section must be IP based
652
            }
653
            else if (tokens[tok].id == ATT_ALIGN && state == 0) {
654
                state = 1;
655
            }
656
            else {
657
                errors.report(tokens[tok]);  break;
658
            }
659
        }
660
        else if (tokens[tok].type == TOK_REG && tokens[tok].id == REG_IP    && state == 0)   sectionFlags |= SHF_IP;
661
        else if (tokens[tok].type == TOK_REG && tokens[tok].id == REG_DATAP && state == 0)   sectionFlags |= SHF_DATAP;
662
        else if (tokens[tok].type == TOK_REG && tokens[tok].id == REG_THREADP && state == 0) sectionFlags |= SHF_THREADP;
663
        else if (tokens[tok].type == TOK_OPR && tokens[tok].id == '=' && state == 1) state = 2;
664
        else if (tokens[tok].type == TOK_OPR && tokens[tok].id == ',' && state != 2) ; // comma, ignore
665
        else if (tokens[tok].type == TOK_NUM && state == 2) {
666
            if (pass >= 3) {  // alignment value
667
                uint32_t alignm = expression(tok, 1, 0).value.w;
668
                if ((alignm & (alignm - 1)) || alignm > MAX_ALIGN) errors.reportLine(ERR_ALIGNMENT);
669
                else {
670
                    sectionHeader.sh_align = bitScanReverse(alignm);
671
                }
672
            }
673
            state = 0;
674
        }
675
        else {
676
            errors.report(tokens[tok]);  break;
677
        }
678
    }
679
    // find or define symbol with section name
680
    sectionsym = findSymbol((char*)buf() + tokens[tokenB].pos, tokens[tokenB].stringLength);
681
    if (sectionsym <= 0) {
682
        // symbol not previously defined. Define it now
683
        sym.st_type = STT_SECTION;
684
        sym.st_name = symbolNameBuffer.putStringN((char*)buf() + tokens[tokenB].pos, tokens[tokenB].stringLength);
685
        sym.st_bind = sectionFlags;
686
        sectionsym = addSymbol(sym);         // save symbol with section name
687
    }
688
    else {
689
        // symbol already defined. check that it is a section name
690
        if (symbols[sectionsym].st_type != STT_SECTION) {
691
            errors.report(tokens[tokenB].pos, tokens[tokenB].stringLength, ERR_SYMBOL_DEFINED);
692
        }
693
    }
694
    sectionFlags |= SHF_ALLOC;
695
    lines[linei].type = LINE_SECTION;                          // line is section directive
696
    lines[linei].sectionType = sectionFlags;
697
    if (symbols[sectionsym].st_section == 0) {
698
        // new section. make section header
699
        sectionHeader.sh_name = symbols[sectionsym].st_name;
700
        if (sectionFlags & SHF_EXEC) {
701
            sectionHeader.sh_entsize = 4;
702
            if (sectionHeader.sh_align < 2) sectionHeader.sh_align = 2;
703
            sectionFlags |= SHF_IP;
704
        }
705
        else { // data section
706
            if (!(sectionFlags & (SHF_READ | SHF_WRITE))) sectionFlags |= SHF_READ | SHF_WRITE; // read or write attributes not specified, default is both
707
            if (!(sectionFlags & (SHF_IP | SHF_DATAP | SHF_THREADP))) {  // address reference not specified. assume datap if writeable, ip if readonly
708
                if (sectionFlags & SHF_WRITE) sectionFlags |= SHF_DATAP;
709
                else sectionFlags |= SHF_IP;
710
            }
711
        }
712
        sectionHeader.sh_flags = sectionFlags;
713
        section = sectionHeaders.push(sectionHeader);
714
        symbols[sectionsym].st_section = section;
715
    }
716
    else {  // this section is seen before
717
        section = symbols[sectionsym].st_section;
718
        if (sectionHeaders[section].sh_align < sectionHeader.sh_align) sectionHeaders[section].sh_align = sectionHeader.sh_align;
719
        if (sectionFlags && (sectionFlags & ~sectionHeaders[section].sh_flags)) errors.reportLine(ERR_SECTION_DIFFERENT_TYPE);
720
        sectionFlags = (uint32_t)sectionHeaders[section].sh_flags;
721
        if (sectionHeader.sh_align > 2) {
722
            // insert alignment code
723
            SCode code;
724
            zeroAllMembers(code);
725
            code.instruction = II_ALIGN;
726
            code.value.u = (int64_t)1 << sectionHeader.sh_align;
727
            code.sizeUnknown = 0x80;
728
            code.section = section;
729
            codeBuffer.push(code);
730
        }
731
    }
732
}
733
 
734
void CAssembler::interpretFunctionDirective() {
735
    // Interpret function directive during pass 2
736
    uint32_t tok;                     // token number
737
    ElfFWC_Sym2 sym;                  // symbol record
738
    zeroAllMembers(sym);              // reset symbol
739
    int32_t symi;
740
 
741
    symi = findSymbol((char*)buf() + tokens[tokenB].pos, tokens[tokenB].stringLength);
742
    if (symi > 0) {
743
        if (pass == 2) errors.report(tokens[tokenB].pos, tokens[tokenB].stringLength, ERR_SYMBOL_DEFINED);  // symbol already defined
744
    }
745
    else {
746
        // define symbol
747
        sym.st_type = STT_FUNC;
748
        sym.st_other = STV_IP;
749
        sym.st_name = symbolNameBuffer.putStringN((char*)buf() + tokens[tokenB].pos, tokens[tokenB].stringLength);
750
        sym.st_bind = 0;
751
        sym.st_section = section;
752
        for (tok = tokenB + 2; tok < tokenB + tokenN; tok++) { // get function attributes
753
            if (tokens[tok].type == TOK_OPR && tokens[tok].id == ',') continue;
754
            if (tokens[tok].id == ATT_WEAK) sym.st_bind |= STB_WEAK;
755
            if (tokens[tok].id == ATT_REGUSE) {
756
                if (tokens[tok+1].id == '=' && tokens[tok+2].type == TOK_NUM) {
757
                    tok += 2;
758
                    sym.st_reguse1 = expression(tok, 1, 0).value.w;
759
                    sym.st_other |= STV_REGUSE;
760
                    if (tokens[tok+1].id == ',' && tokens[tok+2].type == TOK_NUM) {
761
                        tok += 2;
762
                        sym.st_reguse2 = expression(tok, 1, 0).value.w;
763
                    }
764
                }
765
            }
766
            else if (tokens[tok].type == TOK_DIR && tokens[tok].id == DIR_PUBLIC) sym.st_bind |= STB_GLOBAL;
767
            else {
768
                errors.report(tokens[tok]);  // unexpected token
769
            }
770
        }
771
        symi = addSymbol(sym);          // save symbol with function name
772
    }
773
    lines[linei].type = LINE_FUNCTION;           // line is function directive
774
 
775
    if (pass == 3 && symi) {
776
        // make a label here. The final address will be calculated in pass 4
777
        SCode code;                              // current instruction code
778
        zeroAllMembers(code);                    // reset code structure
779
        code.label = symbols[symi].st_name;
780
        code.section = section;
781
        codeBuffer.push(code);
782
    }
783
}
784
 
785
void CAssembler::interpretEndDirective() {
786
    // Interpret section or function end directive during pass 2
787
    ElfFWC_Sym2 sym;                  // symbol record
788
    zeroAllMembers(sym);              // reset symbol
789
    int32_t symi;
790
    CTextFileBuffer tempBuffer;       // temporary storage of names
791
 
792
    symi = findSymbol((char*)buf() + tokens[tokenB].pos, tokens[tokenB].stringLength);
793
    if (symi <= 0) {
794
        errors.reportLine(ERR_UNMATCHED_END);
795
    }
796
    else {
797
        if (symbols[symi].st_type == STT_SECTION) {
798
            if (symbols[symi].st_section == section) {
799
                // current section ends here
800
                section = 0;  sectionFlags = 0;
801
            }
802
            else {
803
                errors.reportLine(ERR_UNMATCHED_END);
804
            }
805
        }
806
        else if (symbols[symi].st_type == STT_FUNC && pass >= 4) {
807
            symbols[symi].st_unitsize = 4;
808
            // to do: insert size!
809
            //symbols[symi].st_unitsize = ?
810
            // support function(){} syntax. prevent nested functions
811
        }
812
    }
813
    lines[linei].type = LINE_ENDDIR;        // line is end directive
814
}
815
 
816
// Interpret line specifying options
817
void CAssembler::interpretOptionsLine() {
818
 
819
    // Expecting a line of the type:
820
    // "options codesize = 0x10000, datasize = 1 << 20"
821
    uint32_t tok;                      // token number
822
    uint32_t state = 0;                // 0: start, 1: after option name, 2: after equal sign, 3: after expression
823
    const char * optionname = 0;
824
    int option = 0;                    // 1: codesize, 2: datasize
825
    SExpression val;                   // value to be assigned
826
    SCode code;                        // instruction code containing options
827
    for (tok = tokenB + 1; tok < tokenB + tokenN; tok++) {
828
 
829
        switch (state) {
830
        case 0:                        // start. expect name "datasize" or "codesize"
831
            if (tokens[tok].type != TOK_NAM) {
832
                errors.report(tokens[tok]);  return;  // unexpected token
833
            }
834
            optionname = (char*)buf()+tokens[tok].pos; // tokens[tok].stringLength;
835
            if (strncasecmp_(optionname, "codesize", 8) == 0) option = 1;
836
            else if (strncasecmp_(optionname, "datasize", 8) == 0) option = 2;
837
            else {
838
                errors.report(tokens[tok]);  return;  // unexpected name
839
            }
840
            state = 1;
841
            break;
842
 
843
        case 1:  // after name, expecting equal sign
844
            if (tokens[tok].type == TOK_OPR && tokens[tok].id == '=') {
845
                state = 2;
846
            }
847
            else {
848
                errors.report(tokens[tok]);  return;  // unexpected token
849
            }
850
            break;
851
 
852
        case 2:  // expect expression
853
            val = expression(tok, tokenB + tokenN - tok, 0);  // evaluate number or expression
854
            tok += val.tokens - 1;
855
            if (val.etype != XPR_INT) {
856
                errors.reportLine(ERR_MUST_BE_CONSTANT);
857
                return;
858
            }
859
            zeroAllMembers(code);                    // reset code structure
860
            switch (option) {
861
            case 1:  // set codesize
862
                if (val.value.u == 0) code_size = cmd.codeSizeOption;
863
                else code_size = val.value.u;
864
                code.value.u = code_size;
865
                break;
866
            case 2:  // set datasize 
867
                if (val.value.u == 0) data_size = cmd.dataSizeOption;
868
                else data_size = val.value.u;
869
                code.value.u = data_size;
870
                break;
871
            }
872
            // This is called only in pass 3. Save this option for pass 4:
873
            code.instruction = II_OPTIONS;
874
            code.section = section;
875
            code.fitNum = option;
876
            code.sizeUnknown = 1;
877
            codeBuffer.push(code);
878
            state = 3;
879
            break;
880
 
881
        case 3:  // expect comma or nothing
882
            if (tokens[tok].type == TOK_OPR && tokens[tok].id == ',') {
883
                state = 0;    // start over after comma
884
            }
885
            else {
886
                errors.report(tokens[tok]);  return;  // unexpected token
887
            }
888
        }
889
    }
890
}
891
 
892
 
893
// Find symbol by index into symbolNameBuffer. The return value is an index into symbols. 
894
// Symbol indexes may change when new symbols are added to the symbols list, which is sorted by name
895
uint32_t CAssembler::findSymbol(uint32_t namei) {
896
    ElfFWC_Sym2 sym;                                       // temporary symbol record used for searching
897
    sym.st_name = namei;
898
    return symbols.findFirst(sym);                         // find symbol by name
899
}
900
 
901
// Find symbol by name as string. The return value is an index into symbols. 
902
// Symbol indexes may change when new symbols are added to the symbols list, which is sorted by name
903
uint32_t CAssembler::findSymbol(const char * name, uint32_t len) {
904
    uint32_t saveSize = symbolNameBuffer.dataSize();       // save symbolNameBuffer size for later reset
905
    uint32_t namei = symbolNameBuffer.putStringN(name, len); // put name temporarily into symbolNameBuffer
906
    int32_t symi = findSymbol(namei);                      // find symbol by name index
907
    symbolNameBuffer.setSize(saveSize);                    // remove temporary name from symbolNameBuffer
908
    return symi;                                           // return symbol index
909
}
910
 
911
// Add a symbol to symbols list
912
uint32_t CAssembler::addSymbol(ElfFWC_Sym2 & sym) {
913
    int32_t f = symbols.findFirst(sym);
914
    if (f >= 0) {
915
        // error: symbol already defined
916
        return 0;
917
    }
918
    else {
919
        return symbols.addUnique(sym);
920
    }
921
}
922
 
923
// interpret   name: options {, name: options}
924
void CAssembler::interpretExternDirective() {
925
    uint32_t tok;                     // token number
926
    uint32_t nametok = 0;             // last name token
927
    ElfFWC_Sym2 sym;                  // symbol record
928
    zeroAllMembers(sym);              // reset symbol
929
    sym.st_bind = STB_GLOBAL;
930
 
931
    // Example: extern name1: int32 weak, name2: function, name3, name4: read 
932
    uint32_t state = 0;  // 0: after extern or comma, 
933
                         // 1: after name, 
934
                         // 2: after colon
935
 
936
    // loop through tokens on this line
937
    for (tok = tokenB + 1; tok < tokenB + tokenN; tok++) {
938
        switch (state) {
939
        case 0:  // after extern or comma. expecting name
940
            if (tokens[tok].type == TOK_NAM) {
941
                // name encountered
942
                sym.st_name = symbolNameBuffer.putStringN((char*)buf()+tokens[tok].pos, tokens[tok].stringLength);
943
                state = 1;  nametok = tok;
944
            }
945
            else errors.report(tokens[tok]);
946
            break;
947
        case 1: // after name. expecting colon or comma
948
            if (tokens[tok].type == TOK_OPR) {
949
                if (tokens[tok].id == ':') {
950
                    state = 2;
951
                    continue;
952
                }
953
                else if (tokens[tok].id == ',') {
954
                    goto COMMA;
955
                }
956
            }
957
            errors.report(tokens[tok]);
958
            break;
959
        case 2:  // after colon. expecting attribute or comma or end of line
960
            if (tokens[tok].type == TOK_TYP) {
961
                // symbol size given by type token
962
                uint32_t s = tokens[tok].id & 0xF;
963
                if (s > 4) s -= 3;  // float types
964
                sym.st_unitsize = uint32_t(1 << s);
965
                sym.st_unitnum = 1;
966
            }
967
            else if (tokens[tok].type == TOK_ATT || tokens[tok].type == TOK_DIR) {
968
                ATTRIBUTE:
969
                switch (tokens[tok].id) {
970
                case DIR_FUNCTION: case ATT_EXEC: // function or execute
971
                    if (sym.st_type) {
972
                        errors.report(tokens[tok].pos, tokens[tok].stringLength, ERR_CONFLICT_TYPE);
973
                    }
974
                    sym.st_type = STT_FUNC;
975
                    sym.st_other = STV_IP | STV_EXEC;
976
                    break;
977
                case ATT_READ:  // read
978
                    if (sym.st_type == 0) sym.st_other |= STV_READ;
979
                    break;
980
                case ATT_WRITE:  // write
981
                    if (sym.st_type == STT_FUNC) {
982
                        errors.report(tokens[tok].pos, tokens[tok].stringLength, ERR_CONFLICT_TYPE);
983
                    }
984
                    else {
985
                        sym.st_type = STT_OBJECT;
986
                    }
987
                    break;
988
                case ATT_WEAK:   // weak
989
                    sym.st_bind = STB_WEAK;
990
                    break;
991
                case ATT_CONSTANT:  // constant
992
                    sym.st_type = STT_CONSTANT;
993
                    break;
994
                case ATT_REGUSE:
995
                    if (tokens[tok+1].id == '=' && (tokens[tok+2].type == TOK_NUM /*|| tokens[tok+2].type == TOK_OPR)*/)) {
996
                        tok += 2;
997
                        sym.st_reguse1 = expression(tok, 1, 0).value.w;
998
                        sym.st_other |= STV_REGUSE;
999
                        if (tokens[tok+1].id == ',' && tokens[tok+2].type == TOK_NUM) {
1000
                            tok += 2;
1001
                            sym.st_reguse2 = expression(tok, 1, 0).value.w;
1002
                        }
1003
                    }
1004
                    break;
1005
                default:  // error
1006
                    errors.report(tokens[tok]);
1007
                }
1008
            }
1009
            else if (tokens[tok].type == TOK_REG) {
1010
                switch (tokens[tok].id) {
1011
                case REG_IP:
1012
                    sym.st_other |= STV_IP;  break;
1013
                case REG_DATAP:
1014
                    sym.st_other |= STV_DATAP;  break;
1015
                case REG_THREADP:
1016
                    sym.st_other |= STV_THREADP;  break;
1017
                default: errors.report(tokens[tok]);
1018
                }
1019
            }
1020
            else if (tokens[tok].type == TOK_OPR && tokens[tok].id == ',') {
1021
                // end of definition. save symbol
1022
            COMMA:
1023
                if (tok < tokenB + tokenN
1024
                    && (tokens[tok + 1].type == TOK_ATT || tokens[tok + 1].type == TOK_DIR)) {
1025
                    tok++; goto ATTRIBUTE;
1026
                }
1027
                uint32_t symi = addSymbol(sym);          // save symbol with function name
1028
                if (symi == 0) {  // symbol already defined
1029
                    errors.report(tokens[nametok].pos, tokens[nametok].stringLength, ERR_SYMBOL_DEFINED);
1030
                }
1031
                sym.st_name = 0;          // clear record for next symbol
1032
                sym.st_type = 0;
1033
                sym.st_other = 0;
1034
                sym.st_unitsize = 0;
1035
                sym.st_unitnum = 0;
1036
                sym.st_bind = STB_GLOBAL;
1037
                state = 0;
1038
            }
1039
            else {
1040
                errors.report(tokens[tok]);
1041
            }
1042
            break;
1043
        }
1044
    }
1045
    if (state) {  // last extern definition does not end with comma. finish it here
1046
        goto COMMA;
1047
    }
1048
    lines[linei].type = LINE_DATADEF;        // line is data definition
1049
}
1050
 
1051
 
1052
void CAssembler::interpretLabel(uint32_t tok) {
1053
    // line begins with a name. interpret label
1054
    // to do: add type if data. not string type
1055
    ElfFWC_Sym2 sym;   // symbol record
1056
    zeroAllMembers(sym); // reset symbol
1057
 
1058
    // save name
1059
    sym.st_name = symbolNameBuffer.putStringN((char*)buf()+tokens[tok].pos, tokens[tok].stringLength);
1060
    sym.st_section = section;
1061
    // determine if code or data from section type
1062
    if (sectionFlags & SHF_EXEC) {
1063
        sym.st_type = STT_FUNC;
1064
        sym.st_other = STV_EXEC | STV_IP;
1065
    }
1066
    else {
1067
        sym.st_type = STT_OBJECT;
1068
        sym.st_other = sectionFlags & STV_SECT_ATTR;
1069
    }
1070
 
1071
    // look for more exact type information
1072
    if (tokenN > 2) {
1073
        uint32_t t = tok+2;
1074
        if (tokens[t].type == TOK_TYP) {
1075
            uint32_t s = tokens[t].id & 0xF;
1076
            if (s > 4) s -= 3;
1077
            sym.st_unitsize = uint32_t(1 << s);
1078
            sym.st_unitnum = 1;
1079
            if (tokenN > 3) t++;
1080
        }
1081
        if (tokens[t].type == TOK_NUM || tokens[t].type == TOK_FLT) {
1082
            sym.st_type = STT_OBJECT;
1083
            lines[linei].type = LINE_DATADEF;
1084
        }
1085
        else if (tokens[t].type == TOK_REG || tokens[t].type == TOK_INS || tokens[t].id == '[') {
1086
            lines[linei].type = LINE_CODEDEF;
1087
            sym.st_type = STT_FUNC;
1088
        }
1089
    }
1090
    if (section) { // copy type info from section
1091
        sym.st_other = sectionHeaders[section].sh_flags & STV_SECT_ATTR;
1092
    }
1093
 
1094
    if (lines[linei].type == 0) {
1095
        lines[linei].type = (sectionFlags & SHF_EXEC) ? LINE_CODEDEF : LINE_DATADEF;
1096
    }
1097
 
1098
    uint32_t symi = addSymbol(sym);     // add symbol to symbols list
1099
 
1100
    if (section) {
1101
        // symbol address
1102
        symbols[symi].st_value = sectionHeaders[section].sh_size;
1103
    }
1104
    tokens[tok].id = symbols[symi].st_name;         // save symbol name index
1105
    if (symi == 0) errors.report(tokens[tokenB].pos, tokens[tokenB].stringLength, ERR_SYMBOL_DEFINED);
1106
}
1107
 
1108
 
1109
// interpret assembly style variable definition:
1110
// label: type value1, value2
1111
void CAssembler::interpretVariableDefinition1() {
1112
    int state = 0;      // 0: start
1113
                        // 1: after label
1114
                        // 2: after :
1115
                        // 3: after type or ,
1116
                        // 4: after value
1117
    uint32_t tok;                      // token index
1118
    uint32_t type = 0;                 // data type
1119
    uint32_t dsize = 0;                // data size
1120
    uint32_t dsize1;                   // log2(dsize)
1121
    uint32_t dnum = 0;                 // number of data items
1122
    uint32_t stringlen = 0;            // length of string
1123
    uint32_t symi = 0;                 // symbol index
1124
    ElfFWC_Sym2 sym;                   // symbol record
1125
    zeroAllMembers(sym);               // reset symbol
1126
    SExpression exp1;                  // expression when interpreting numeric expression
1127
 
1128
    if (section == 0) {
1129
        errors.reportLine(ERR_DATA_WO_SECTION);
1130
    }
1131
 
1132
    // loop through tokens on this line
1133
    for (tok = tokenB; tok < tokenB + tokenN; tok++) {
1134
        switch (state) {
1135
        case 0:  // start
1136
            if (tokens[tok].type == TOK_NAM) { // name. make symbol
1137
                sym.st_name = symbolNameBuffer.putStringN((char*)buf()+tokens[tok].pos, tokens[tok].stringLength);
1138
                sym.st_type = STT_OBJECT;
1139
                symi = symbols.addUnique(sym);
1140
                tokens[tok].type = TOK_SYM;      // change token type
1141
                tokens[tok].id = symbols[symi].st_name;  // use name offset as unique identifier because symbol index can change
1142
                state = 1;
1143
            }
1144
            else if (tokens[tok].type == TOK_SYM) { // symbol
1145
                symi = findSymbol(tokens[tok].id);
1146
                if (symi > 0) {
1147
                    if (pass == 2) errors.report(tokens[tok].pos, tokens[tok].stringLength, ERR_SYMBOL_DEFINED);  // symbol already defined
1148
                }
1149
                state = 1;
1150
            }
1151
            else if (tokens[tok].type == TOK_TYP) {
1152
                goto TYPE_TOKEN;
1153
            }
1154
            else errors.report(tokens[tok]);
1155
            if (symi && section) {
1156
                symbols[symi].st_value = sectionHeaders[section].sh_size;
1157
            }
1158
            break;
1159
        case 1:  // after label. expect colon
1160
            if (tokens[tok].type == TOK_OPR && tokens[tok].id == ':') {
1161
                state = 2;
1162
            }
1163
            else errors.report(tokens[tok].pos, tokens[tok].stringLength, ERR_EXPECT_COLON);
1164
            break;
1165
        case 2:  // expect type
1166
            if (tokens[tok].type == TOK_TYP) {
1167
                TYPE_TOKEN:
1168
                type = tokens[tok].id & 0xFF;
1169
                dsize1 = type & 0xF;
1170
                if (type & 0x40) dsize1 -= 3;
1171
                dsize = 1 << dsize1;
1172
                state = 3;
1173
                if (section) {  // align data
1174
                    uint32_t addr = (uint32_t)sectionHeaders[section].sh_size;
1175
                    if (sectionHeaders[section].sh_align < dsize1) sectionHeaders[section].sh_align = dsize1;  // update section alignment
1176
                    if (addr & (dsize - 1)) { // needs to insert zeroes
1177
                        uint32_t addr2 = (addr + dsize - 1) & -(int32_t)dsize;
1178
                        sectionHeaders[section].sh_size = addr2;           // update address
1179
                        if (symi) symbols[symi].st_value = addr2;          // update symbol address
1180
                        if (pass >= 3) {
1181
                            dataBuffers[section].align((uint32_t)dsize);   // put zeroes in data buffer
1182
                        }
1183
                    }
1184
                }
1185
            }
1186
            else errors.report(tokens[tok]);
1187
            break;
1188
        case 3:  // after type. expect value. evaluate expression
1189
            exp1 = expression(tok, tokenB + tokenN - tok, pass < 3 ? 0x10 : 0); // pass 3: may contain symbols not defined yet
1190
            tok += exp1.tokens - 1;
1191
            if (exp1.etype & XPR_STRING) {  // string expression: get size
1192
                if ((type & 0x1F) != (TYP_INT8 & 0x1F)) errors.reportLine(ERR_STRING_TYPE);  // string must use type int8
1193
                stringlen = exp1.sym2; // string length
1194
            }
1195
            else stringlen = 0;
1196
            if (pass < 3) {
1197
                if (section) sectionHeaders[section].sh_size += stringlen ? stringlen : dsize;  // update address
1198
            }
1199
            else {
1200
                if (section) {
1201
                    // save data of desired type
1202
                    if (exp1.etype & XPR_FLT) {
1203
                        // floating point number specified
1204
                        if ((type & 0xF0) == (TYP_INT8 & 0xF0)) {  // float specified, integer expected
1205
                            exp1.value.i = int64_t(exp1.value.d);
1206
                            errors.reportLine(ERR_CONFLICT_TYPE);
1207
                        }
1208
                    }
1209
                    else if (exp1.etype & XPR_INT) {
1210
                        if (type & TYP_FLOAT) {  // integer specified, float expected
1211
                            exp1.value.d = double(exp1.value.i);  // convert to float
1212
                        }
1213
                    }
1214
                    int64_t value = exp1.value.i;  //value of expression
1215
                    if (exp1.sym3) {
1216
                        // calculation of symbol value. add relocation if needed
1217
                        uint32_t size = type & 0xF;
1218
                        if (type & 0x40) size -= 3;
1219
                        size = 1 << size;
1220
                        //value = calculateConstantOperand(exp1, dataBuffers[section].dataSize(), size);                            
1221
                        value = calculateConstantOperand(exp1, sectionHeaders[section].sh_size, dsize);
1222
                        if (exp1.etype & XPR_ERROR) {
1223
                            errors.reportLine((uint32_t)value); // report error
1224
                            break;
1225
                        }
1226
                        // check for overflow
1227
                        bool overflow = false;
1228
                        switch (type & 0xFF) {
1229
                        case TYP_INT8 & 0xFF:
1230
                            overflow = value > 0x7F || value < -0x80;
1231
                            break;
1232
                        case TYP_INT16 & 0xFF:
1233
                            overflow = value > 0x7FFF || value < -0x8000;
1234
                            break;
1235
                        case TYP_INT32 & 0xFF:
1236
                            overflow = value > 0x7FFFFFFF || value < int32_t(0x80000000);
1237
                            break;
1238
                        default:;
1239
                        }
1240
                        if (overflow) errors.reportLine(ERR_OVERFLOW); // (symbol1 - symbol2) overflows
1241
                    }
1242
                    if (sectionHeaders[section].sh_type == SHT_NOBITS) {
1243
                        // uninitialized (BSS) section. check that value is zero, but don't store
1244
                        if (value != 0) errors.reportLine(ERR_NONZERO_IN_BSS); // not zero
1245
                    }
1246
                    else {
1247
                        // save data
1248
                        switch (type & 0xFF) {
1249
                        case TYP_INT8 & 0xFF:
1250
                            if (stringlen) {
1251
                                dataBuffers[section].push(stringBuffer.buf() + exp1.value.w, stringlen);
1252
                                break;
1253
                            }
1254
                            dataBuffers[section].push(&value, 1);  break;
1255
                        case TYP_INT16 & 0xFF:
1256
                            dataBuffers[section].push(&value, 2);  break;
1257
                        case TYP_INT32 & 0xFF:
1258
                            dataBuffers[section].push(&value, 4);  break;
1259
                        case TYP_INT64 & 0xFF:
1260
                            dataBuffers[section].push(&value, 8);  break;
1261
                        case TYP_INT128 & 0xFF:
1262
                            dataBuffers[section].push(&value, 8);
1263
                            value = value >> 63;     // sign extend
1264
                            dataBuffers[section].push(&value, 8);
1265
                            break;
1266
                        case TYP_FLOAT16 & 0xFF:  // half precision
1267
                            exp1.value.w = double2half(exp1.value.d);
1268
                            dataBuffers[section].push(&exp1.value.w, 2);  break;
1269
                        case TYP_FLOAT32 & 0xFF: { // single precision
1270
                            float val = float(exp1.value.d);
1271
                            dataBuffers[section].push(&val, 4); }
1272
                            break;
1273
                        case TYP_FLOAT64 & 0xFF:  // double precision
1274
                            dataBuffers[section].push(&exp1.value.d, 8);  break;
1275
                        }
1276
                    }
1277
                    sectionHeaders[section].sh_size += stringlen ? stringlen : dsize;  // update address
1278
                }
1279
            }
1280
            if (!(exp1.etype & (XPR_IMMEDIATE | XPR_STRING | XPR_SYM1 | XPR_UNRESOLV)) || (exp1.etype & (XPR_REG|XPR_OPTION|XPR_MEM|XPR_ERROR))) errors.report(tokens[tok]);
1281
 
1282
            if (stringlen) dnum += stringlen; else dnum += 1;
1283
            state = 4;
1284
            break;
1285
        case 4:  // after value. expect comma or end of line
1286
            if (tokens[tok].type == TOK_OPR && tokens[tok].id == ',') {
1287
                state = 3;
1288
            }
1289
            else errors.report(tokens[tok]);
1290
            break;
1291
        }
1292
        if (lineError) return;
1293
    }
1294
    if (state != 4 && state != 2) errors.report(tokens[tok-1]);
1295
    if (symi) { // save size
1296
        symbols[symi].st_unitsize = dsize;
1297
        symbols[symi].st_unitnum = dnum;
1298
        symbols[symi].st_section = section;
1299
        if ((type & 0xF0) == (TYP_FLOAT32 & 0xF0)) symbols[symi].st_other |= STV_FLOAT;
1300
        if (section) { // copy information from section
1301
            symbols[symi].st_other |= sectionHeaders[section].sh_flags & STV_SECT_ATTR;
1302
        }
1303
    }
1304
}
1305
 
1306
// interpret C style variable definition:
1307
// type name1 = value1, name2[num] = {value, value, ..}
1308
void CAssembler::interpretVariableDefinition2() {
1309
    int state = 0;      // 0: start
1310
                        // 1: after type or comma
1311
                        // 2: after name
1312
                        // 3: after [
1313
                        // 4: after [number
1314
                        // 5: after =
1315
                        // 6: after = number
1316
                        // 7: after {
1317
                        // 8: after {number
1318
 
1319
    uint32_t tok;                           // token index
1320
    uint32_t dsize = 0;                     // data element size
1321
    uint32_t dsize1 = 0;                    // data element size = 1 << dsize1
1322
    uint32_t type = 0;                      // data type
1323
    uint32_t arrayNum1 = 1;                 // number of elements indicated in []
1324
    uint32_t arrayNum2 = 0;                 // number of elements in {} list
1325
    uint32_t stringlen = 0;                 // length of string
1326
    uint32_t symi = 0;                      // symbol index
1327
    ElfFWC_Sym2 sym;                        // symbol record
1328
    zeroAllMembers(sym);                    // reset symbol
1329
    SExpression exp1;                       // expression when interpreting numeric expression
1330
 
1331
    if (section == 0) {
1332
        errors.reportLine(ERR_DATA_WO_SECTION);
1333
    }
1334
 
1335
    // loop through tokens on this line
1336
    for (tok = tokenB; tok < tokenB + tokenN; tok++) {
1337
        switch (state) {
1338
        case 0:  // this is a type token
1339
            type  = tokens[tok].id & 0xFF;
1340
            dsize1 = tokens[tok].id & 0xF;
1341
            if ((type & 0x40) > 3) dsize1 -= 3;
1342
            dsize = 1 << dsize1;
1343
            state = 1;
1344
            if (section) {  // align data
1345
                uint32_t addr = (uint32_t)sectionHeaders[section].sh_size;
1346
                if (addr & (dsize - 1)) { // needs to insert zeroes
1347
                    uint32_t addr2 = (addr + dsize - 1) & -(int32_t)dsize;  // calculate aligned address
1348
                    sectionHeaders[section].sh_size = addr2;           // update address
1349
                    if (pass >= 3) {
1350
                        dataBuffers[section].align(dsize);   // put zeroes in data buffer
1351
                    }
1352
                }
1353
                if (sectionHeaders[section].sh_align < dsize1) sectionHeaders[section].sh_align = dsize1;  // update section alignment
1354
            }
1355
            break;
1356
        case 1:  // expecting name token. save name
1357
            if (tokens[tok].type == TOK_NAM) { // name. make symbol
1358
                sym.st_name = symbolNameBuffer.putStringN((char*)buf()+tokens[tok].pos, tokens[tok].stringLength);
1359
                symi = addSymbol(sym);
1360
                if (symi == 0 && pass == 2) {
1361
                    errors.report(tokens[tok].pos, tokens[tok].stringLength, ERR_SYMBOL_DEFINED);  break;
1362
                }
1363
                symbols[symi].st_type = (sectionFlags & SHF_EXEC) ? STT_FUNC : STT_OBJECT;
1364
                tokens[tok].type = TOK_SYM;      // change token type
1365
                tokens[tok].id = symbols[symi].st_name;  // use name offset as unique identifier because symbol index can change
1366
                state = 2;
1367
            }
1368
            else if (tokens[tok].type == TOK_SYM) { // symbol
1369
                symi = findSymbol(tokens[tok].id);
1370
                if (symi > 0 && pass == 2) errors.report(tokens[tok].pos, tokens[tok].stringLength, ERR_SYMBOL_DEFINED);  // symbol already defined
1371
                state = 2;
1372
            }
1373
            else {
1374
                errors.report(tokens[tok]);
1375
            }
1376
            //nametok = tok;
1377
            symbols[symi].st_unitsize = dsize;
1378
            symbols[symi].st_unitnum = 0;
1379
 
1380
            if ((type & 0xF0) == (TYP_FLOAT32 & 0xF0)) symbols[symi].st_other |= STV_FLOAT;
1381
            if (section) { // copy information from section
1382
                symbols[symi].st_value = sectionHeaders[section].sh_size;
1383
                symbols[symi].st_other |= sectionHeaders[section].sh_flags & STV_SECT_ATTR;
1384
            }
1385
            break;
1386
        case 2:  // after name. expect , = [ eol
1387
            if (tokens[tok].type != TOK_OPR) {
1388
                errors.report(tokens[tok]);  break;
1389
            }
1390
            switch (tokens[tok].id) {
1391
            case ',':  // finish this symbol definition
1392
                COMMA:
1393
                    if (arrayNum2 > arrayNum1) { // check if the two array sizes match
1394
                        if (arrayNum1 > 1) {
1395
                            errors.report(tokens[tok-1].pos, tokens[tok-1].stringLength, ERR_CONFLICT_ARRAYSZ);
1396
                        }
1397
                        else arrayNum1 = arrayNum2;
1398
                    }
1399
                    symbols[symi].st_unitsize = dsize;
1400
                    symbols[symi].st_unitnum = arrayNum1;
1401
                    symbols[symi].st_reguse1 = linei;
1402
                    symbols[symi].st_section = section;
1403
 
1404
                    if (arrayNum1 > arrayNum2 && section) {
1405
                        // unspecified elements are zero. calculate extra size
1406
                        uint32_t asize = (arrayNum1 - arrayNum2) * dsize;
1407
                        sectionHeaders[section].sh_size += asize;
1408
                        if (pass >= 3 && sectionHeaders[section].sh_type != SHT_NOBITS) {
1409
                            // store any unspecified elements as zero
1410
                            uint64_t zero = 0;
1411
                            while (asize > 8) {
1412
                                dataBuffers[section].push(&zero, 8);  asize -= 8;
1413
                            }
1414
                            while (asize > 0) {
1415
                                dataBuffers[section].push(&zero, 1);  asize -= 1;
1416
                            }
1417
                        }
1418
                    }
1419
 
1420
                    // get ready for next symbol
1421
                    zeroAllMembers(sym);
1422
                    arrayNum1 = 1;  arrayNum2 = 0;
1423
                    if (state == 99) return;       // finished line
1424
                    state = 1;
1425
                    break;
1426
            case '=':
1427
                state = 5;
1428
                break;
1429
            case '[':
1430
                state = 3;
1431
                break;
1432
            default:
1433
                errors.report(tokens[tok]);
1434
            }
1435
            break;
1436
        case 3:  // after [ . expect number or ]
1437
            if (tokens[tok].id == ']') {
1438
                state = 2; break;
1439
            }
1440
            if (arrayNum1 > 1) {
1441
                errors.report(tokens[tok].pos, tokens[tok].stringLength, ERR_MULTIDIMENSIONAL);  break;            // error. multidimensional array not supported
1442
            }
1443
            // evaluate numeric expression inside []. 
1444
            // it may contain complex expressions that can only be evaluated later, but
1445
            // this will not generate an error message here
1446
            exp1 = expression(tok, tokenB + tokenN - tok, 0x10);
1447
            if (lineError) return;
1448
            tok += exp1.tokens -1;
1449
            if (exp1.etype == 0) errors.report(tokens[tok]);
1450
            if ((exp1.etype & ~XPR_IMMEDIATE) == 0) {
1451
                arrayNum1 = exp1.value.w;
1452
            }
1453
            state = 4;
1454
            break;
1455
        case 4:  // after [number. expect ]
1456
            if (tokens[tok].id != ']') {
1457
                errors.report(tokens[tok]);  break;
1458
            }
1459
            state = 2;
1460
            break;
1461
        case 5:  // after =. expect number or {numbers}
1462
            if (tokens[tok].id == '{') state = 7;
1463
            else {
1464
                state = 6;
1465
                goto SAVE_VALUE;  // interpret value and save it
1466
            }
1467
            break;
1468
        case 6:  // after = number. expect comma or eol
1469
            if (tokens[tok].id != ',') {
1470
                errors.report(tokens[tok]);  break;
1471
            }
1472
            goto COMMA;
1473
        case 7:  // after {. expect number list
1474
            state = 8;
1475
        SAVE_VALUE:
1476
            arrayNum2++;
1477
            if (pass < 3) {
1478
                // may contain symbols not defined yet. just pass expression and count tokens
1479
                exp1 = expression(tok, tokenB + tokenN - tok, 0x10);
1480
                tok += exp1.tokens - 1;
1481
                if (lineError) return;
1482
            }
1483
            else {
1484
                // pass 5. evaluate expression and save value
1485
                exp1 = expression(tok, tokenB + tokenN - tok, 0);
1486
                tok += exp1.tokens - 1;
1487
                if (lineError) return;
1488
                if ((exp1.etype & XPR_SYM1) && exp1.sym3 && pass > 3) {
1489
                    // calculation of symbol value. add relocation if needed
1490
                    exp1.value.i = calculateConstantOperand(exp1, sectionHeaders[section].sh_size, dsize);
1491
                    if (exp1.etype & XPR_ERROR) {
1492
                        errors.reportLine((uint32_t)(exp1.value.i)); // report error
1493
                        break;
1494
                    }
1495
                    // check for overflow
1496
                    bool overflow = false;
1497
                    switch (type & 0xFF) {
1498
                    case TYP_INT8 & 0xFF:
1499
                        overflow = exp1.value.i > 0x7F || exp1.value.i < -0x80;
1500
                        break;
1501
                    case TYP_INT16 & 0xFF:
1502
                        overflow = exp1.value.i > 0x7FFF || exp1.value.i < -0x8000;
1503
                        break;
1504
                    case TYP_INT32 & 0xFF:
1505
                        overflow = exp1.value.i > 0x7FFFFFFF || exp1.value.i < int32_t(0x80000000);
1506
                        break;
1507
                    default:;
1508
                    }
1509
                    if (overflow) errors.reportLine(ERR_OVERFLOW); // (symbol1 - symbol2) overflows
1510
                }
1511
            }
1512
            if (!(exp1.etype & (XPR_IMMEDIATE | XPR_STRING | XPR_UNRESOLV | XPR_SYM1)) || (exp1.etype & (XPR_REG|XPR_OPTION|XPR_MEM|XPR_ERROR))) {
1513
                errors.report(tokens[tok]);
1514
            }
1515
            if (section && section < dataBuffers.numEntries() && pass >= 3) {
1516
                // save data of desired type
1517
                if ((exp1.etype & XPR_IMMEDIATE) == XPR_FLT) {
1518
                    // floating point number specified
1519
                    if ((type & 0xF0) == (TYP_INT8 & 0xF0)) {  // float specified, integer expected
1520
                        exp1.value.i = int64_t(exp1.value.d);
1521
                        errors.reportLine(ERR_CONFLICT_TYPE);
1522
                    }
1523
                }
1524
                else if ((exp1.etype & XPR_IMMEDIATE) == XPR_INT) {
1525
                    if ((type & 0xF0) == (TYP_FLOAT32 & 0xF0)) {  // integer specified, float expected
1526
                        exp1.value.d = double(exp1.value.i);  // convert to float
1527
                    }
1528
                }
1529
                else if (exp1.etype & XPR_STRING) {  // string expression: get size
1530
                    if ((type & 0x1F) != (TYP_INT8 & 0x1F)) errors.reportLine(ERR_STRING_TYPE);  // string must use type int8
1531
                    stringlen = exp1.sym2; // string length
1532
                }
1533
                else stringlen = 0;
1534
 
1535
                if (sectionHeaders[section].sh_type == SHT_NOBITS) {
1536
                    // uninitialized (BSS) section. check that value is zero, but don't store
1537
                    if (exp1.value.i != 0) errors.reportLine(ERR_NONZERO_IN_BSS); // not zero
1538
                }
1539
                else {
1540
                    // save data
1541
                    switch (type & 0xFF) {
1542
                    case TYP_INT8 & 0xFF:
1543
                        if (stringlen) {
1544
                            dataBuffers[section].push(stringBuffer.buf() + exp1.value.w, stringlen);
1545
                            break;
1546
                        }
1547
                        dataBuffers[section].push(&exp1.value.u, 1);  break;
1548
                    case TYP_INT16 & 0xFF:
1549
                        dataBuffers[section].push(&exp1.value.u, 2);  break;
1550
                    case TYP_INT32 & 0xFF:
1551
                        dataBuffers[section].push(&exp1.value.u, 4);  break;
1552
                    case TYP_INT64 & 0xFF:
1553
                        dataBuffers[section].push(&exp1.value.u, 8);  break;
1554
                    case TYP_INT128 & 0xFF:
1555
                        dataBuffers[section].push(&exp1.value.u, 8);
1556
                        exp1.value.i = exp1.value.i >> 63;     // sign extend
1557
                        dataBuffers[section].push(&exp1.value.u, 8);
1558
                        break;
1559
                    case TYP_FLOAT16 & 0xFF:  // half precision
1560
                        exp1.value.w = double2half(exp1.value.d);
1561
                        dataBuffers[section].push(&exp1.value.w, 2);  break;
1562
                    case TYP_FLOAT32 & 0xFF: { // single precision
1563
                        float val = float(exp1.value.d);
1564
                        dataBuffers[section].push(&val, 4); }
1565
                                             break;
1566
                    case TYP_FLOAT64 & 0xFF:  // double precision
1567
                        dataBuffers[section].push(&exp1.value.d, 8);  break;
1568
                    }
1569
                }
1570
            }
1571
            sectionHeaders[section].sh_size += stringlen ? stringlen : dsize;  // update address
1572
            break;
1573
        case 8:  // after {number. expect comma or }
1574
            if (tokens[tok].id == ',') state = 7;
1575
            else if (tokens[tok].id == '}') state = 6;
1576
            else {
1577
                errors.report(tokens[tok]);  break;
1578
            }
1579
        }
1580
        if (tok + 1 == tokenB + tokenN && (state == 5 || state >= 7) && linei + 1 < lines.numEntries()) {
1581
            // no more tokens. statement with {} can span multiple lines
1582
            if (state == 5) {
1583
                // after '='. expect next line to be '{'
1584
                uint32_t tokNext = lines[linei+1].firstToken;
1585
                if (tokens[tokNext].type != TOK_OPR || tokens[tokNext].id != '{') break; // anything else: break out of loop and get error message
1586
            }
1587
            // append next line
1588
            lines[linei].type = LINE_DATADEF;
1589
            linei++;
1590
            tokenN += lines[linei].numTokens;
1591
        }
1592
 
1593
    }
1594
    // no more tokens
1595
    if (state == 2 || state == 6) {
1596
        // finish this definition
1597
        lines[linei].type = LINE_DATADEF;
1598
        state = 99; goto COMMA;
1599
    }
1600
    errors.report(tokens[tok-1].pos, tokens[tok-1].stringLength, ERR_UNFINISHED_VAR);
1601
}
1602
 
1603
// check if line is code or data
1604
void CAssembler::determineLineType() {
1605
    uint32_t tok;                           // current token
1606
    uint32_t elements = 0;                  // detect type and constant tokens
1607
 
1608
    if (tokens[tokenB].type == TOK_OPT) {
1609
        lines[linei].type = LINE_OPTIONS;  return;
1610
    }
1611
    // loop through tokens on this line
1612
    for (tok = tokenB; tok < tokenB + tokenN; tok++) {
1613
        if (tokens[tok].type == TOK_REG || tokens[tok].type == TOK_INS || tokens[tok].type == TOK_XPR || tokens[tok].type == TOK_HLL) {
1614
            lines[linei].type = LINE_CODEDEF;  return;     // register or instruction found. must be code
1615
        }
1616
        if (tokens[tok].type == TOK_TYP) elements |= 1;
1617
        if (tokens[tok].type == TOK_NUM || tokens[tok].type == TOK_FLT || tokens[tok].type == TOK_CHA || tokens[tok].type == TOK_STR) elements |= 2;
1618
    }
1619
    if (elements == 3)  lines[linei].type = LINE_DATADEF;
1620
    else if (tokens[tokenB].type == TOK_ATT && tokens[tokenB].id == ATT_ALIGN) {  // align directive
1621
        lines[linei].type = (sectionFlags & SHF_EXEC) ? LINE_CODEDEF : LINE_DATADEF;
1622
    }
1623
    else if (tokens[tokenB].type == TOK_EOF) lines[linei].type = 0;   // end of file
1624
    else if (tokenN == 1 && tokens[tokenB].type == TOK_OPR && linei > 1) {
1625
        // {} bracket. same type as previous line
1626
        lines[linei].type = lines[linei-1].type;
1627
    }
1628
    else if (tokens[tokenB].type == TOK_OPR && tokens[tokenB].id == '%') {
1629
        // metaprogramming code
1630
        lines[linei].type = LINE_METADEF;
1631
    }
1632
    else if (linei > 1) {
1633
        // undetermined. This may occur in for(;;) clause. Use same type as previous line
1634
        lines[linei].type = lines[linei-1].type;
1635
    }
1636
    else {
1637
        // error. cannot determine
1638
        errors.report(tokens[tokenB]);
1639
        lines[linei].type = LINE_ERROR;
1640
    }
1641
}
1642
 
1643
// interpret data or code alignment directive
1644
void CAssembler::interpretAlign() {
1645
    if (section) {
1646
        uint32_t addr = (uint32_t)sectionHeaders[section].sh_size;
1647
        SExpression exp1 = expression(tokenB+1, tokenN - 1, pass < 3 ? 0x10 : 0);
1648
        if (exp1.tokens < tokenN - 1) {errors.report(tokens[tokenB+1+exp1.tokens]); return;}
1649
        if ((exp1.etype & XPR_IMMEDIATE) != XPR_INT || (exp1.etype & (XPR_STRING | XPR_REG | XPR_OP | XPR_MEM | XPR_OPTION))) {
1650
            errors.report(tokens[tokenB+1]);  return;
1651
        }
1652
        uint64_t alignm = exp1.value.u;
1653
        if ((alignm & (alignm - 1)) || alignm > MAX_ALIGN) {errors.reportLine(ERR_ALIGNMENT);  return;}
1654
        uint32_t log2ali = bitScanReverse(alignm);
1655
        if (sectionHeaders[section].sh_align < log2ali) {
1656
            sectionHeaders[section].sh_align = log2ali;  // make sure section alignment is not less
1657
        }
1658
        if (addr & ((uint32_t)alignm - 1)) { // needs to insert zeroes
1659
            uint32_t addr2 = (addr + (uint32_t)alignm - 1) & -(int32_t)alignm;
1660
            sectionHeaders[section].sh_size = addr2;           // update address
1661
            if (pass >= 3) {
1662
                dataBuffers[section].align((uint32_t)alignm);  // put zeroes in data buffer
1663
            }
1664
        }
1665
    }
1666
}
1667
 
1668
// Pass 3 does three things. 
1669
// A. Handle metaprogramming directives
1670
// B. Classify lines
1671
// C. Identify symbol names, sections, labels, functions 
1672
// These must be done in parallel because metaprogramming directives can refer to previously 
1673
// defined symbols, and data/code definitions can involve metaprogramming variables and macros
1674
 
1675
void CAssembler::pass2() {
1676
    ElfFWC_Sym2 sym;                  // symbol record
1677
    zeroAllMembers(sym);              // reset symbol
1678
    symbols.push(sym);                // symbol record 0 is empty
1679
    symbolNameBuffer.put((char)0);    // put dummy zero to avoid zero offset at next string
1680
    sectionFlags = 0;
1681
    section = 0;
1682
 
1683
    // lines loop
1684
    for (linei = 1; linei < lines.numEntries(); linei++) {
1685
        lineError = 0;
1686
        tokenB = lines[linei].firstToken;      // first token in line        
1687
        tokenN = lines[linei].numTokens; // number of tokens in line
1688
        if (tokenN == 0) continue;
1689
        replaceKnownNames();                   // replace previously defined names by symbol references
1690
        // check if line begins with '%'
1691
        if (tokens[tokenB].type == TOK_OPR && tokens[tokenB].id == '%') {
1692
            // metaprogramming code
1693
            lines[linei].type = LINE_METADEF;
1694
            interpretMetaDefinition();
1695
            continue;
1696
        }
1697
        // classify other lines
1698
        lines[linei].sectionType = sectionFlags;                    // line is section directive
1699
        if (sectionFlags & ATT_EXEC) lines[linei].type = LINE_CODEDEF;
1700
        else if (sectionFlags & ((ATT_READ | ATT_WRITE))) lines[linei].type = LINE_DATADEF;
1701
 
1702
        if (tokenN > 1) {
1703
            // search for section, function and symbol definitions
1704
            // lines with a single token cannot legally define a symbol name
1705
            if ((tokens[tokenB].type == TOK_NAM || tokens[tokenB].type == TOK_SYM) && tokens[tokenB+1].type == TOK_DIR) {
1706
                switch (tokens[tokenB + 1].id) {
1707
                case DIR_SECTION:   // section starts here
1708
                    interpretSectionDirective();
1709
                    break;
1710
                case DIR_FUNCTION:   // function starts here
1711
                    interpretFunctionDirective();
1712
                    break;
1713
                case DIR_END:    // section or function end
1714
                    interpretEndDirective();
1715
                    break;
1716
                default:
1717
                    errors.report(tokens[tokenB + 1]);
1718
                }
1719
            }
1720
            else if (tokens[tokenB].id == DIR_EXTERN) {
1721
                // extern symbols
1722
                interpretExternDirective();
1723
            }
1724
            else if (tokens[tokenB].id == DIR_PUBLIC) {
1725
                // the interpretation of public symbol declarations is postponed to pass 4 after all 
1726
                // symbols have been defined and got their final value
1727
                lines[linei].type = LINE_PUBLICDEF;
1728
            }
1729
            else if (tokens[tokenB].type == TOK_NAM && tokens[tokenB+1].id == ':') {
1730
                interpretLabel(tokenB);
1731
                if (lines[linei].type == LINE_DATADEF) interpretVariableDefinition1();
1732
            }
1733
            else if (tokens[tokenB].type == TOK_TYP && (tokens[tokenB+1].type == TOK_NAM || tokens[tokenB+1].type == TOK_SYM)) {
1734
                interpretVariableDefinition2();
1735
            }
1736
            else if (tokens[tokenB].type == TOK_ATT && tokens[tokenB].id == ATT_ALIGN) {
1737
                interpretAlign();
1738
            }
1739
            else if (tokens[tokenB].type == TOK_SYM && tokens[tokenB+1].id == ':' && pass == 2) {
1740
                errors.report(tokens[tokenB].pos, tokens[tokenB].stringLength, ERR_SYMBOL_DEFINED);  // symbol already defined
1741
            }
1742
            else {
1743
                determineLineType();  // check if code or data
1744
                if (lines[linei].type == LINE_DATADEF) interpretVariableDefinition1();
1745
            }
1746
        }
1747
        else {
1748
            determineLineType();  // check if code or data (can only be code)
1749
        }
1750
    }
1751
 
1752
    // loop through lines again to replace names that are forward references to symbols defined during pass 2
1753
    for (linei = 1; linei < lines.numEntries(); linei++) {
1754
        tokenB = lines[linei].firstToken;      // first token in line        
1755
        tokenN = lines[linei].numTokens;      // number of tokens in line
1756
        replaceKnownNames();                   // replace previously defined names by symbol references
1757
    }
1758
}
1759
 
1760
 
1761
// Show all symbols. For debugging only
1762
void CAssembler::showSymbols() {
1763
    uint32_t symi;
1764
    ElfFWC_Sym2 sym;
1765
    printf("\n\nSymbol:    name, section, addr, type, size, binding");
1766
    for (symi = 1; symi < symbols.numEntries(); symi++) {
1767
        sym = symbols[symi];
1768
        printf("\n%3i: %10s, %7i, %4X", symi, symbolNameBuffer.buf() + sym.st_name,
1769
            sym.st_section, (uint32_t)sym.st_value);
1770
        if (sym.st_type == STT_CONSTANT || sym.st_type == STT_VARIABLE) {
1771
            if (sym.st_other & STV_FLOAT) {    // floating point constant
1772
                union { uint64_t i; double d; } val;
1773
                val.i = sym.st_value;
1774
                printf(" = %G", val.d);
1775
            }
1776
            else if (sym.st_other & STV_STRING) {   // string
1777
                printf(" = %s", stringBuffer.getString((uint32_t)sym.st_value));
1778
            }
1779
            else {
1780
                // print 64 bit integer constant
1781
                printf(" = 0x");
1782
                if (uint64_t(sym.st_value) >> 32) {
1783
                    printf("%X%08X", uint32_t(sym.st_value >> 32), uint32_t(sym.st_value));
1784
                }
1785
                else {
1786
                    printf("%X", uint32_t(sym.st_value));
1787
                }
1788
                // this method causes warnings:
1789
                // printf(((sizeof(long int) > 4) ? " = 0x%lx" : " = 0x%llx"), sym.st_value); 
1790
            }
1791
        }
1792
        else {
1793
            printf(" %5X, %X*%X, %7X",  // other type
1794
                sym.st_type, sym.st_unitsize, sym.st_unitnum, sym.st_bind);
1795
        }
1796
    }
1797
}
1798
 
1799
// Show all tokens. For debugging only
1800
void CAssembler::showTokens() {
1801
    SKeyword const tokenNames[] = {
1802
        {"name",        TOK_NAM},   // unidentified name        
1803
        {"direc",       TOK_DIR},   // section or function directive
1804
        {"attrib",      TOK_ATT},   // section or function attribute
1805
        {"label",       TOK_LAB},   // code label or function name
1806
        {"datalb",      TOK_VAR},   // data label
1807
        {"secnm",       TOK_SEC},   // section name
1808
        {"type",        TOK_TYP},   // type name
1809
        {"reg",         TOK_REG},   //  register name
1810
        {"instr",       TOK_INS},   // instruction name 
1811
        {"oper",        TOK_OPR},   // operator
1812
        {"option",      TOK_OPT},   // operator
1813
        {"num",         TOK_NUM},   // number
1814
        {"float",       TOK_FLT},   // floating point number
1815
        {"char",        TOK_CHA},   // character or string in single quotes ' '
1816
        {"string",      TOK_STR},   // string in double quotes " "
1817
        {"symbol",      TOK_SYM},   // symbol
1818
        {"expression",  TOK_XPR},   // expression
1819
        {"eof",         TOK_EOF},   // string in double quotes " "
1820
        {"hll",         TOK_HLL}    // string in double quotes " "
1821
                                    //   {"error", TOK_ERR}   // error. illegal character or unmatched quote
1822
    };
1823
 
1824
    uint32_t line, tok, i;
1825
    for (line = 1; line < lines.numEntries(); line++) {
1826
        if (line < lines.numEntries() && lines[line].numTokens) {
1827
            printf("\nline %2i type %X", lines[line].linenum, lines[line].type);
1828
 
1829
            for (tok = lines[line].firstToken; tok < lines[line].firstToken + lines[line].numTokens; tok++) {
1830
                // find name for token type
1831
                const char * nm = 0;
1832
                for (i = 0; i < TableSize(tokenNames); i++) {
1833
                    if (tokenNames[i].id == tokens[tok].type) nm = tokenNames[i].name;
1834
                }
1835
                if (nm) printf("\n%4X  %8s: ", tok, nm);                               // Token type
1836
                else printf("type %4X", tokens[tok].type);
1837
 
1838
                switch (tokens[tok].type) {
1839
                case TOK_DIR: case TOK_ATT: case TOK_TYP: case TOK_OPT: case TOK_HLL:
1840
                    nm = 0;
1841
                    for (i = 0; i < TableSize(keywordsList); i++) {
1842
                        if (keywordsList[i].id == tokens[tok].id) nm = keywordsList[i].name;
1843
                    }
1844
                    if (nm) printf("%s", nm);
1845
                    else printf("%4X %2i", tokens[tok].pos, tokens[tok].stringLength);
1846
                    break;
1847
                case TOK_OPR:
1848
                    nm = 0;
1849
                    for (i = 0; i < TableSize(operatorsList); i++) {
1850
                        if (operatorsList[i].id == tokens[tok].id) nm = operatorsList[i].name;
1851
                    }
1852
                    if (nm) printf("%s", nm);
1853
                    else printf("%4X %2i", tokens[tok].pos, tokens[tok].stringLength);
1854
                    break;
1855
                case TOK_REG: //registerNames
1856
                    nm = 0;
1857
                    for (i = 0; i < TableSize(registerNames); i++) {
1858
                        if (registerNames[i].id == tokens[tok].id) nm = registerNames[i].name;
1859
                    }
1860
                    if (nm) printf("%s%i", nm, tokens[tok].id & 0xFF);
1861
                    else printf("%4X %2i", tokens[tok].pos, tokens[tok].stringLength);
1862
                    break;
1863
                case TOK_NAM: case TOK_NUM: case TOK_FLT: case TOK_LAB: case TOK_VAR: case TOK_SEC:
1864
                case TOK_CHA: case TOK_STR: case TOK_INS: case TOK_SYM:
1865
                    for (i = 0; i < tokens[tok].stringLength; i++) {
1866
                        printf("%c", buf()[tokens[tok].pos + i]);
1867
                    }
1868
                    printf("  id %X, value %X", tokens[tok].id, tokens[tok].value.w);
1869
                    break;
1870
                case TOK_XPR:
1871
                default:
1872
                    printf("0x%X 0x%X 0x%X %2i", tokens[tok].id, tokens[tok].value.w, tokens[tok].pos, tokens[tok].stringLength);
1873
                    break;
1874
                }
1875
            }
1876
        }
1877
    }
1878
}
1879
 
1880
void CAssembler::initializeWordLists() {
1881
    // Operators list
1882
    operators.pushBig(operatorsList, sizeof(operatorsList));
1883
    operators.sort();
1884
    // Keywords list
1885
    keywords.pushBig(keywordsList,sizeof(keywordsList));
1886
    keywords.sort();
1887
    // Read instruction list from file
1888
    CCSVFile instructionListFile;
1889
    instructionListFile.read(cmd.getFilename(cmd.instructionListFile), CMDL_FILE_SEARCH_PATH); // Filename of list of instructions
1890
    instructionListFile.parse();                            // Read and interpret instruction list file
1891
    instructionlist << instructionListFile.instructionlist; // Transfer instruction list to my own container
1892
    instructionlistId.copy(instructionlist);                // copy instruction list
1893
    instructionlistNm.copy(instructionlist);                // copy instruction list
1894
                                                            // sort lists by different criteria, defined by the different operators:
1895
    // operator < (SInstruction const & a, SInstruction const & b)
1896
    // operator < (SInstruction3 const & a, SInstruction3 const & b)
1897
    SInstruction3 nullInstruction;                          // empty record
1898
    zeroAllMembers(nullInstruction);
1899
    instructionlistId.push(nullInstruction);                // Empty record will go to position 0 to avoid an instruction with index 0
1900
    instructionlistNm.sort();                               // Sort instructionlist by name
1901
    instructionlistId.sort();                               // Sort instructionlistId by id
1902
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.