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

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [assem5.cpp] - Blame information for rev 130

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

Line No. Rev Author Line
1 45 Agner
/****************************    assem5.cpp    ********************************
2
* Author:        Agner Fog
3
* Date created:  2017-09-19
4
* Last modified: 2021-05-21
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.
10
* This module contains functions for interpreting high level language constructs:
11
* functions, branches, and loops
12
*
13
* Copyright 2017-2021 GNU General Public License http://www.gnu.org/licenses
14
******************************************************************************/
15
#include "stdafx.h"
16
 
17
// Define high level block types
18
const int HL_SECTION     =  1;  // section
19
const int HL_FUNC        =  2;  // function
20
const int HL_IF          =  3;  // if branch
21
const int HL_ELSE        =  4;  // else branch
22
const int HL_SWITCH      =  5;  // switch-case branch
23
const int HL_FOR         =  6;  // for loop
24
const int HL_FOR_IN      =  7;  // vector loop. for (v1 in [r2-r3]) {}
25
const int HL_WHILE       =  8;  // while loop
26
const int HL_DO_WHILE    =  9;  // do-while loop
27
 
28
// invert condition code for branch instruction
29
void invertCondition(SCode & code) {
30
    code.instruction ^= II_JUMP_INVERT;  // invert condition code
31
    if ((code.dtype & TYP_FLOAT)
32
        && (code.instruction & 0xFF) == II_COMPARE
33
        && (code.instruction & 0x7F00) - 0x1000 < 0x2000) {
34
        // floating point compare instructions, except jump_ordered, must invert the unordered bit
35
        code.instruction ^= II_JUMP_UNORDERED; // inverse condition is unordered
36
    }
37
}
38
 
39
// if, else, switch, for, do, while statements
40
void CAssembler::interpretHighLevelStatement() {
41
    //uint32_t label = 0;
42
    if (tokenN > 2 && tokens[tokenB].type == TOK_SYM && tokens[tokenB+1].id == ':') {
43
        // line starts with a label. insert label
44
        // (this will prevent merging of jump instruction. merging is not allowed when there is a label between the two instructions)
45
        SCode codeL;
46
        zeroAllMembers(codeL);
47
        //codeL.label = tokens[tokenB].value.w; //?
48
        codeL.label = tokens[tokenB].id;
49
        codeL.section = section;
50
        codeBuffer.push(codeL);
51
        // interpret directive after label
52
        tokenB += 2;
53
        tokenN -= 2;
54
    }
55
    uint32_t tok = tokenB;
56
    if (tokenN > 1 && tokens[tok].type == TOK_TYP) {
57
        tok++;  // skip type keyword
58
        if (tok+1 < tokenB+tokenN && tokens[tok].type == TOK_OPR && tokens[tok].id == '+') tok++;  // skip '+' after type
59
    }
60
    // expect HLL keyword here. dispatch to the corresponding function
61
    switch (tokens[tok].id) {
62
    case HLL_IF:
63
        codeIf();  break;
64
    case HLL_SWITCH:
65
        codeSwitch();  break;
66
    case HLL_CASE:
67
        codeCase();  break;
68
    case HLL_FOR:
69
        codeFor();  break;
70
    case HLL_WHILE:
71
        codeWhile();  break;
72
    case HLL_DO:
73
        codeDo();  break;
74
    case HLL_BREAK: case HLL_CONTINUE:
75
        if (tok != tokenB) {
76
            errors.report(tokens[tok]);   // cannot have type token before break or continue
77
            break;
78
        }
79
        codeBreak();  break;
80
    case HLL_PUSH:                        // may be replaced by macro later
81
        codePush();  break;
82
    case HLL_POP:                         // may be replaced by macro later
83
        codePop();  break;
84
    default:
85
        errors.report(tokens[tok]);
86
    }
87
}
88
 
89
 
90
// finish {} block
91
void CAssembler::interpretEndBracket() {
92
    uint32_t n = hllBlocks.numEntries();
93
    if (n == 0) {
94
        errors.reportLine(ERR_BRACKET_END);  // unmatched end bracket
95
        return;
96
    }
97
    // dispatch depending on type of block
98
    switch (hllBlocks[n-1].blockType) {
99
    case HL_FUNC: // function
100
        break;
101
    case HL_IF: case HL_ELSE: // if branch
102
        codeIf2();
103
        break;
104
    case HL_FOR: // for loop
105
        codeFor2();
106
        break;
107
    case HL_FOR_IN: // vector loop. for (v1 in [r2-r3]) {}
108
        codeForIn2();
109
        break;
110
    case HL_WHILE:    // while loop
111
        codeWhile2();
112
        break;
113
    case HL_DO_WHILE: // do-while loop
114
        codeDo2();
115
        break;
116
    case HL_SWITCH: // switch-case branch
117
        break;
118
    default:
119
        errors.reportLine(ERR_BRACKET_END);  // should not occur
120
    }
121
}
122
 
123
 
124
// Interpret if statement in assembly code
125
void CAssembler::codeIf() {
126
    uint32_t state = 0;                // 0: start, 1: after type, 2: after if, 3: after (, 4: after (type, 
127
                                       // 5: after expression, 6: after ')', 7: after {
128
    uint32_t tok;                      // current token index
129
    SBlock block;                      // block descriptor to save
130
    zeroAllMembers(block);             // reset
131
    block.blockType = HL_IF;           // if block
132
    SToken token;                      // current token
133
    SExpression expr;                  // expression in ()
134
    SCode code;                        // instruction code
135
    zeroAllMembers(code);              // reset
136
 
137
    // interpret line by state machine looping through tokens
138
    for (tok = tokenB; tok < tokenB + tokenN; tok++) {
139
        if (lineError) break;
140
        token = tokens[tok];
141
 
142
        switch (state) {
143
        case 0:  // start. expect type or 'if'
144
            if (token.type == TOK_TYP) {
145
                code.dtype = dataType = token.id & 0xFF;
146
                state = 1;
147
            }
148
            else if (token.id == HLL_IF) state = 2;
149
            else errors.report(token);
150
            break;
151
        case 1:  // after type. expect '+' or 'if'
152
            if (token.type == TOK_OPR && token.id == '+') {
153
                code.dtype |= TYP_PLUS;
154
            }
155
            else if (token.id == HLL_IF) state = 2;
156
            else errors.report(token);
157
            break;
158
        case 2: // after if. expect '('
159
            if (token.type == TOK_OPR && token.id == '(') state = 3;
160
            else errors.report(token.pos, token.stringLength, ERR_EXPECT_PARENTHESIS);
161
            break;
162
        case 3: // after '('. expect type or logical expression
163
            if (token.type == TOK_TYP && !code.dtype) {
164
                code.dtype = dataType = token.id & 0xFF;
165
                state = 4;
166
                break;
167
            }
168
            EXPRESSION:
169
            expr = expression(tok, tokenB + tokenN-tok, (code.dtype & TYP_UNS) != 0);
170
            if (lineError) return;
171
 
172
            // insert logical expression into block
173
            insertAll(code, expr);
174
            tok += expr.tokens - 1;
175
            state = 5;
176
            break;
177
        case 4: // after "if (type". expect '+' or expression
178
            if (token.type == TOK_OPR && token.id == '+') {
179
                code.dtype |= TYP_PLUS;
180
                break;
181
            }
182
            // not a '+'. expect expression
183
            goto EXPRESSION;
184
        case 5: // after expression. expect ')'
185
            if (token.type == TOK_OPR && token.id == ')') state = 6;
186
            else {
187
                errors.report(token);  return;
188
            }
189
            break;
190
        }
191
    }
192
    // should end at state 6 because '{' should be on next pseudo-line
193
    if (state != 6) errors.report(token);
194
    if (lineError) return;
195
 
196
    if (linei == lines.numEntries()-1) {  // no more lines
197
        errors.reportLine(ERR_UNFINISHED_INSTRUCTION);
198
        return;
199
    }
200
 
201
    // get next line
202
    if (linei == lines.numEntries()-1) {    // no more lines
203
        errors.reportLine(ERR_UNFINISHED_INSTRUCTION);
204
        return;
205
    }
206
    linei++;
207
    tokenB = lines[linei].firstToken;       // first token in line        
208
    tokenN = lines[linei].numTokens;        // number of tokens in line
209
    lineError = false;
210
 
211
    // expect '{'
212
    if (tokens[tokenB].id != '{') {
213
        errors.reportLine(ERR_EXPECT_BRACKET);
214
        return;
215
    }
216
    // interpret the condition expression
217
    linei--;                                // make any error message apply to previous line
218
    interpretCondition(code);
219
    linei++;
220
    // make instruction code
221
    code.etype |= XPR_JUMPOS | XPR_SYM1;
222
    code.section = section;
223
 
224
    // check if {} contains a jump only
225
    uint32_t target2 = hasJump(linei+1);
226
    if (target2) {
227
        if (linei + 2 < lines.numEntries() && lines[linei+2].numTokens == 1) {
228
            tok = lines[linei+2].firstToken;
229
            if (tokens[tok].type == TOK_OPR && tokens[tok].id == '}') {
230
                // the {} block contains a jump and nothing else
231
                // make conditional jump to target2 instead
232
                code.sym5 = target2;
233
                linei += 2;                          // finished processing these two lines
234
                // check if it can be merged with previous instruction
235
                mergeJump(code);
236
                // finish code and fit it
237
                checkCode1(code);
238
                if (lineError) return;
239
                fitCode(code);       // find an instruction variant that fits
240
                if (lineError) return;
241
                codeBuffer.push(code);// save code structure
242
 
243
                // check if there is an 'else' after if(){}
244
                if (linei + 2 < lines.numEntries() && lines[linei+1].numTokens == 1 && lines[linei+2].numTokens == 1) {
245
                    tok = lines[linei+1].firstToken;
246
                    if (tokens[tok].type == TOK_HLL && tokens[tok].id == HLL_ELSE) {
247
                        tok = lines[linei+2].firstToken;
248
                        if (tokens[tok].type == TOK_OPR && tokens[tok].id == '{') {
249
                            // make the 'else' ignored
250
                            linei += 2;
251
                            // make block record with no label
252
                            block.blockNumber = ++iIf;
253
                            block.startBracket = tok;
254
                            block.jumpLabel = 0;
255
                            // store block in hllBlocks stack. will be retrieved at matching '}'
256
                            hllBlocks.push(block);
257
                        }
258
                    }
259
                }
260
                return;
261
            }
262
        }
263
    }
264
    invertCondition(code);  // invert condition. jump to else block if logical expression false
265
 
266
    if (code.instruction == (II_JUMP | II_JUMP_INVERT)) {
267
        // constant: don't jump
268
        code.instruction = 0;
269
    }
270
    // make block record with label name
271
    block.blockNumber = ++iIf;
272
    block.startBracket = tokenB;
273
    char name[32];
274
    sprintf(name, "@if_%u_a", iIf);
275
    uint32_t symi = makeLabelSymbol(name);
276
    block.jumpLabel = symbols[symi].st_name;
277
 
278
    // store block in hllBlocks stack. will be retrieved at matching '}'
279
    hllBlocks.push(block);
280
 
281
    // store jump instruction
282
    code.sym5 = block.jumpLabel;
283
 
284
    // check if it can be merged with previous instruction
285
    mergeJump(code);
286
 
287
    // finish code and fit it
288
    checkCode1(code);
289
    if (lineError) return;
290
    fitCode(code);       // find an instruction variant that fits
291
    if (lineError) return;
292
    codeBuffer.push(code);// save code structure
293
}
294
 
295
 
296
// Finish if statement at end bracket
297
void CAssembler::codeIf2() {
298
    SCode code;                             // code record for jump label
299
    zeroAllMembers(code);                   // reset
300
    SBlock block = hllBlocks.pop();         // pop the stack of {} blocks
301
    uint32_t labelA = block.jumpLabel;      // jump target label to place here
302
    // check if there is an 'else' following the if(){}
303
    if (block.blockType == HL_IF && linei+2 < lines.numEntries() && tokens[lines[linei+1].firstToken].id == HLL_ELSE) {
304
        // there is an else. get next line with the else
305
        linei++;
306
        if (lines[linei].numTokens > 1) errors.report(tokens[lines[linei].firstToken+1]);  // something other than '{' after else
307
        // check if there is a '{' following the 'else'
308
        linei++;
309
        uint32_t tokenB = lines[linei].firstToken;
310
        if (lines[linei].numTokens > 1 || tokens[tokenB].type != TOK_OPR || tokens[tokenB].id != '{') {
311
            errors.reportLine(ERR_EXPECT_BRACKET); // expecting '{'
312
            return;
313
        }
314
        // make block record for jump to label b
315
        block.blockType = HL_ELSE;           // if-else block
316
        block.startBracket = tokenB;
317
        // make label name
318
        char name[32];
319
        sprintf(name, "@if_%u_b", block.blockNumber);
320
        uint32_t symi = makeLabelSymbol(name);
321
        block.jumpLabel = symbols[symi].st_name;
322
        hllBlocks.push(block);     // store block in hllBlocks stack. will be retrieved at matching '}'
323
 
324
        // make jump instruction
325
        code.section = section;
326
        code.instruction = II_JUMP;
327
        code.etype = XPR_JUMPOS | XPR_SYM1;
328
        code.sym5 = block.jumpLabel;
329
 
330
        // check if it can be merged with previous instruction
331
        mergeJump(code);
332
 
333
        // finish code and save it
334
        checkCode1(code);
335
        if (lineError) return;
336
        fitCode(code);       // find an instruction variant that fits
337
        if (lineError) return;
338
        codeBuffer.push(code);// save code structure
339
    }
340
    // make target label here
341
    if (labelA) {
342
        zeroAllMembers(code);
343
        code.section = section;
344
        code.label = labelA;       // jump target label
345
        codeBuffer.push(code);    // save code structure
346
    }
347
}
348
 
349
 
350
// Interpret while loop in assembly code
351
void CAssembler::codeWhile() {
352
    uint32_t state = 0;                // 0: start, 1: after type, 2: after while, 3: after (, 4: after (type, 
353
                                       // 5: after expression, 6: after ')', 7: after {
354
    uint32_t tok;                      // current token index
355
    SBlock block;                      // block descriptor to save
356
    zeroAllMembers(block);             // reset
357
    SToken token;                      // current token
358
    SExpression expr;                  // expression in ()
359
    SCode code;                        // instruction code
360
    zeroAllMembers(code);              // reset
361
 
362
    // interpret line by state machine looping through tokens (same as for codeIf)
363
    for (tok = tokenB; tok < tokenB + tokenN; tok++) {
364
        if (lineError) break;
365
        token = tokens[tok];
366
 
367
        switch (state) {
368
        case 0:  // start. expect type or 'while'
369
            if (token.type == TOK_TYP) {
370
                code.dtype = dataType = token.id & 0xFF;
371
                state = 1;
372
            }
373
            else if (token.id == HLL_WHILE) state = 2;
374
            else errors.report(token);
375
            break;
376
        case 1:  // after type. expect '+' or 'while'
377
            if (token.type == TOK_OPR && token.id == '+') {
378
                code.dtype |= TYP_PLUS;
379
            }
380
            else if (token.id == HLL_WHILE) state = 2;
381
            else errors.report(token);
382
            break;
383
        case 2: // after if. expect '('
384
            if (token.type == TOK_OPR && token.id == '(') state = 3;
385
            else errors.report(token.pos, token.stringLength, ERR_EXPECT_PARENTHESIS);
386
            break;
387
        case 3: // after '('. expect type or logical expression
388
            if (token.type == TOK_TYP && !code.dtype) {
389
                code.dtype = dataType = token.id & 0xFF;
390
                state = 4;
391
                break;
392
            }
393
        EXPRESSION:
394
            expr = expression(tok, tokenB + tokenN-tok, (code.dtype & TYP_UNS) != 0);
395
            if (lineError) return;
396
 
397
            // insert logical expression into block
398
            insertAll(code, expr);
399
            tok += expr.tokens - 1;
400
            state = 5;
401
            break;
402
        case 4: // after "while (type". expect '+' or expression
403
            if (token.type == TOK_OPR && token.id == '+') {
404
                code.dtype |= TYP_PLUS;
405
                break;
406
            }
407
            // not a '+'. expect expression
408
            goto EXPRESSION;
409
        case 5: // after expression. expect ')'
410
            if (token.type == TOK_OPR && token.id == ')') state = 6;
411
            else {
412
                errors.report(token);  return;
413
            }
414
            break;
415
        }
416
    }
417
    // should end at state 6 because '{' should be on next pseudo-line
418
    if (state != 6) errors.report(token);
419
    if (lineError) return;
420
 
421
    if (linei == lines.numEntries()-1) {  // no more lines
422
        errors.reportLine(ERR_UNFINISHED_INSTRUCTION);
423
        return;
424
    }
425
 
426
    // get next line
427
    // get next line
428
    if (linei == lines.numEntries()-1) {    // no more lines
429
        errors.reportLine(ERR_UNFINISHED_INSTRUCTION);
430
        return;
431
    }
432
    linei++;
433
    tokenB = lines[linei].firstToken;       // first token in line        
434
    tokenN = lines[linei].numTokens;        // number of tokens in line
435
    lineError = false;
436
 
437
    // expect '{'
438
    if (tokens[tokenB].id != '{') {
439
        errors.reportLine(ERR_EXPECT_BRACKET);
440
        return;
441
    }
442
 
443
    // interpret the condition expression
444
    linei--;                                // make any error message apply to previous line
445
    interpretCondition(code);
446
    linei++;
447
 
448
    // make instruction code
449
    code.etype |= XPR_JUMPOS | XPR_SYM1;
450
    code.section = section;
451
 
452
    // make block record with label names
453
    block.blockType = HL_WHILE;        // while-block
454
    block.blockNumber = ++iLoop;
455
    block.startBracket = tokenB;
456
    char name[32];
457
    sprintf(name, "@while_%u_a", iLoop);
458
    uint32_t symi1 = makeLabelSymbol(name);
459
    block.jumpLabel = symbols[symi1].st_name;  // label to jump back to
460
    sprintf(name, "@while_%u_b", iLoop);
461
    uint32_t symi2 = makeLabelSymbol(name);
462
    block.breakLabel = symbols[symi2].st_name;  // label after loop. used if condition is false first time and for break statements
463
    block.continueLabel = 0xFFFFFFFF;          // this label will only be made if there is a continue statement
464
 
465
    // make code to check condition before first iteration
466
    SCode code1 = code;
467
    invertCondition(code1); // invert condition to jump if false
468
 
469
    if (code1.instruction == (II_JUMP | II_JUMP_INVERT)) {
470
        // constant: don't jump
471
        code1.instruction = 0;
472
    }
473
    code1.sym5 = block.breakLabel;
474
    // check if it can be merged with previous instruction
475
    mergeJump(code1);
476
    // finish code and store it
477
    checkCode1(code1);
478
    if (lineError) return;
479
    fitCode(code1);       // find an instruction variant that fits
480
    if (lineError) return;
481
    codeBuffer.push(code1);// save code structure
482
 
483
    // make loop label
484
    zeroAllMembers(code1);
485
    code1.label = block.jumpLabel;
486
    code1.section = section;
487
    codeBuffer.push(code1);// save code structure
488
 
489
    // make instruction to place at end of loop
490
    code.sym5 = block.jumpLabel;
491
    checkCode1(code);
492
    // store in codeBuffer2 for later insertion at the end of the loop
493
    block.codeBuffer2index = codeBuffer2.push(code);
494
    block.codeBuffer2num = 1;
495
 
496
    // store block in hllBlocks stack. will be retrieved at matching '}'
497
    hllBlocks.push(block);
498
}
499
 
500
// Finish while-loop at end bracket
501
void CAssembler::codeWhile2() {
502
    SCode code;                            // code record for jump back
503
    SBlock block = hllBlocks.pop();        // pop the stack of {} blocks
504
    if (block.continueLabel != 0xFFFFFFFF) {
505
        // place label here as jump target for continue statements
506
        zeroAllMembers(code);
507
        code.label = block.continueLabel;
508
        code.section = section;
509
        codeBuffer.push(code);
510
    }
511
 
512
    uint32_t codebuf2num = codeBuffer2.numEntries();
513
    if (block.codeBuffer2num && block.codeBuffer2index < codebuf2num) {
514
        // retrieve jumpback instruction
515
        code = codeBuffer2[block.codeBuffer2index];
516
 
517
        if (code.instruction == (II_JUMP | II_JUMP_INVERT)) {
518
            // constant: don't jump
519
            code.instruction = 0;
520
        }
521
        // check if it can be merged with previous instruction
522
        mergeJump(code);
523
        // finish code and store it
524
        checkCode1(code);
525
        if (lineError) return;
526
        fitCode(code);       // find an instruction variant that fits
527
        if (lineError) return;
528
        codeBuffer.push(code);  // save code
529
        // remove from temporary buffer
530
        if (block.codeBuffer2index + 1 == codebuf2num) codeBuffer2.pop();
531
        // place label for breaking out
532
        zeroAllMembers(code);
533
        code.label = block.breakLabel;
534
        code.section = section;
535
        codeBuffer.push(code);  // save label
536
        return;
537
    }
538
}
539
 
540
// Interpret do-while loop in assembly code
541
void CAssembler::codeDo() {
542
    SBlock block;                          // block record
543
    SCode code;                            // code record for label
544
    zeroAllMembers(block);
545
    zeroAllMembers(code);
546
 
547
    // make block record with label names
548
    block.blockType = HL_DO_WHILE;        // do-while-block
549
    block.blockNumber = ++iLoop;
550
    char name[32];
551
    sprintf(name, "@do_%u_a", iLoop);
552
    uint32_t symi1 = makeLabelSymbol(name);
553
    block.jumpLabel = symbols[symi1].st_name;  // label to jump back to
554
    block.breakLabel = 0xFFFFFFFF;             // this label will only be made if there is a break statement
555
    block.continueLabel = 0xFFFFFFFF;          // this label will only be made if there is a continue statement
556
    // make loop label
557
    code.label = block.jumpLabel;
558
    code.section = section;
559
    codeBuffer.push(code);                     // save label
560
 
561
    // get next line with '{'
562
    if (linei == lines.numEntries()-1) {    // no more lines
563
        errors.reportLine(ERR_UNFINISHED_INSTRUCTION);
564
        return;
565
    }
566
    linei++;
567
    tokenB = lines[linei].firstToken;       // first token in line        
568
    tokenN = lines[linei].numTokens;        // number of tokens in line
569
    lineError = false;
570
    // expect '{'
571
    if (tokens[tokenB].id != '{') {
572
        errors.report(tokens[tokenB]);
573
        return;
574
    }
575
    block.startBracket = tokenB;
576
    hllBlocks.push(block);                     // store block in hllBlocks stack. will be retrieved at matching '}'
577
}
578
 
579
// Finish do-while loop at end bracket
580
void CAssembler::codeDo2() {
581
    SCode code;                            // code record 
582
 
583
    SBlock block = hllBlocks.pop();        // pop the stack of {} blocks
584
    if (block.continueLabel != 0xFFFFFFFF) {
585
        // place label here as jump target for continue statements
586
        zeroAllMembers(code);
587
        code.label = block.continueLabel;
588
        code.section = section;
589
        codeBuffer.push(code);
590
    }
591
    // find 'while' keyword in next pseudo-line after '}'
592
    if (linei+1 >= lines.numEntries()) {                  // no more lines
593
        errors.reportLine(ERR_WHILE_EXPECTED); return;
594
    }
595
    linei++;
596
    tokenB = lines[linei].firstToken;       // first token in line        
597
    tokenN = lines[linei].numTokens;        // number of tokens in line
598
    lineError = false;
599
 
600
    // expect "while (expression)"
601
    uint32_t state = 0;                // 0: start, 1: after type, 2: after 'while', 3: after (, 4: after (type, 
602
                                       // 5: after expression, 6: after ')'
603
    uint32_t tok;                      // current token index
604
    SToken token;                      // current token
605
    SExpression expr;                  // expression in ()
606
    zeroAllMembers(code);              // reset code
607
 
608
    // interpret line by state machine looping through tokens
609
    for (tok = tokenB; tok < tokenB + tokenN; tok++) {
610
        if (lineError) return;
611
        token = tokens[tok];
612
 
613
        switch (state) {
614
        case 0:  // start. expect type or 'while'
615
            if (token.type == TOK_TYP) {
616
                code.dtype = dataType = token.id & 0xFF;
617
                state = 1;
618
            }
619
            else if (token.id == HLL_WHILE) state = 2;
620
            else errors.reportLine(ERR_WHILE_EXPECTED);
621
            break;
622
        case 1:  // after type. expect '+' or 'while'
623
            if (token.type == TOK_OPR && token.id == '+') {
624
                code.dtype |= TYP_PLUS;
625
            }
626
            else if (token.id == HLL_WHILE) state = 2;
627
            else errors.report(token);
628
            break;
629
        case 2: // after 'while'. expect '('
630
            if (token.type == TOK_OPR && token.id == '(') state = 3;
631
            else errors.report(token.pos, token.stringLength, ERR_EXPECT_PARENTHESIS);
632
            break;
633
        case 3: // after '('. expect type or logical expression
634
            if (token.type == TOK_TYP && !code.dtype) {
635
                code.dtype = dataType = token.id & 0xFF;
636
                state = 4;
637
                break;
638
            }
639
        EXPRESSION:
640
            expr = expression(tok, tokenB + tokenN - tok, (code.dtype & TYP_UNS) != 0);
641
            if (lineError) return;
642
 
643
            // insert logical expression into block
644
            insertAll(code, expr);
645
            tok += expr.tokens - 1;
646
            state = 5;
647
            break;
648
        case 4: // after "while (type". expect '+' or expression
649
            if (token.type == TOK_OPR && token.id == '+') {
650
                code.dtype |= TYP_PLUS;
651
                break;
652
            }
653
            // not a '+'. expect expression
654
            goto EXPRESSION;
655
        case 5: // after expression. expect ')'
656
            if (token.type == TOK_OPR && token.id == ')') state = 6;
657
            else {
658
                errors.report(token);  return;
659
            }
660
            break;
661
        }
662
    }
663
    // should end at state 6
664
    if (state != 6) errors.report(token);
665
    if (lineError) return;
666
 
667
    // make instruction with condition
668
    interpretCondition(code);
669
    code.etype |= XPR_JUMPOS | XPR_SYM1;
670
    code.section = section;
671
    code.sym5 = block.jumpLabel;
672
 
673
    if (code.instruction == (II_JUMP | II_JUMP_INVERT)) {
674
        // constant: don't jump
675
        code.instruction = 0;
676
    }
677
    // check if it can be merged with previous instruction
678
    mergeJump(code);
679
    // finish code and fit it
680
    checkCode1(code);
681
    if (lineError) return;
682
    fitCode(code);       // find an instruction variant that fits
683
    if (lineError) return;
684
    codeBuffer.push(code);// save code structure
685
 
686
    if (block.breakLabel != 0xFFFFFFFF) {
687
        // place label here as jump target for break statements
688
        zeroAllMembers(code);
689
        code.label = block.breakLabel;
690
        code.section = section;
691
        codeBuffer.push(code);
692
    }
693
}
694
 
695
// Interpret for-loop in assembly code
696
void CAssembler::codeFor() {
697
    uint32_t tok;                                 // token number
698
 
699
    // search for 'in' keyword
700
    for (tok = tokenB; tok < tokenB + tokenN; tok++) {
701
        if (tokens[tok].type == TOK_HLL && tokens[tok].id == HLL_IN) {
702
            // this is a for-in vector loop
703
            codeForIn();
704
            return;
705
        }
706
    }
707
 
708
    // this is a traditional for(;;) loop
709
    uint32_t state = 0;                // state while interpreting line
710
                                       // 0: start, 1: after type, 2: after 'for', 3: after (, 4: after (type, 
711
    SBlock block;                      // block descriptor to save
712
    zeroAllMembers(block);             // reset
713
    block.blockType = HL_FOR;          // 'for' block
714
    block.breakLabel = block.jumpLabel = block.continueLabel = 0xFFFFFFFF;
715
    SToken token;                      // current token
716
    SToken typeToken;                  // token defining type
717
    // uint32_t type = 0;                 // operand type for all three expressions in for(;;)
718
    dataType = 0;                      // operand type for all three expressions in for(;;)
719
    uint32_t symi = 0;                 // symbol index
720
    char name[48];                     // symbol name
721
    int conditionFirst = 0;            // evaluation of the condition before first iteration:
722
                                       // 0: condition must be checked before first iteration
723
                                       // 2: condition is false before first iteration. zero iterations
724
                                       // 3: condition is true before first iteration. no initial check needed
725
 
726
    // interpret line by state machine looping through tokens
727
    for (tok = tokenB; tok < tokenB + tokenN; tok++) {
728
        if (lineError) break;
729
        token = tokens[tok];
730
 
731
        if (state == 0) { // start. expect type or 'for'
732
            if (token.type == TOK_TYP) {
733
                dataType = token.id & 0xFF;
734
                typeToken = token;
735
                state = 1;
736
            }
737
            else if (token.id == HLL_FOR) state = 2;
738
            else errors.report(token);
739
        }
740
        else if (state == 1) { // after type. expect '+' or 'for'
741
            if (token.type == TOK_OPR && token.id == '+') {
742
                dataType |= TYP_PLUS;
743
            }
744
            else if (token.id == HLL_FOR) state = 2;
745
            else errors.report(token);
746
        }
747
        else if (state == 2) { // after 'for'. expect '('
748
            if (token.type == TOK_OPR && token.id == '(') state = 3;
749
            else errors.report(token.pos, token.stringLength, ERR_EXPECT_PARENTHESIS);
750
        }
751
        else if (state == 3) { // after '('. expect type or initialization
752
            if (token.type == TOK_TYP && !dataType) {
753
                dataType = token.id & 0xFF;
754
                typeToken = token;
755
                tok++;
756
                if (tok < tokenB + tokenN && tokens[tok].type == TOK_OPR && tokens[tok].id == '+') {
757
                    // '+' after type
758
                    dataType |= TYP_PLUS;
759
                    tok++;
760
                }
761
            }
762
            state = 4;
763
            break;  // end tok loop here            
764
        }
765
    }
766
    if (state != 4) {
767
        errors.report(token);
768
        return;
769
    }
770
    if (lineError) return;
771
 
772
    // check type
773
    if (dataType == 0) {
774
        errors.reportLine(ERR_TYPE_MISSING);  return;
775
    }
776
    // extend type to int32 if allowed. this allows various optimizations
777
    // (unsigned types not allowed, even if start and end values are known to be positive, because loop counter may become negative inside loop in rare cases)
778
    if ((dataType & TYP_PLUS) && ((dataType & 0xFF) < (TYP_INT32 & 0xFF))) dataType = TYP_INT32;
779
 
780
    // remake token sequence for generating initial instruction
781
    uint32_t tokensRestorePoint = tokens.numEntries();
782
    typeToken.id = dataType;
783
    tokens.push(typeToken);
784
    uint32_t tokenFirst = tok;
785
    if (tokens[tokenFirst].type == TOK_TYP) tokenFirst++; // skip type token. it has already been inserted
786
    for (; tok < tokenB + tokenN; tok++) {  // insert remaining tokens
787
        token = tokens[tok];
788
        if (token.type == TOK_OPR && token.id == ';') break;
789
        tokens.push(tokens[tok]);
790
    }
791
    // make an instruction out of this sequence
792
    tokenB = tokensRestorePoint;
793
    tokenN = tokens.numEntries() - tokensRestorePoint;
794
    uint32_t codePoint = codeBuffer.numEntries();
795
    SCode initializationCode;
796
    zeroAllMembers(initializationCode);
797
    if (tokenN > 1) {   // skip if there is no code
798
        interpretCodeLine();
799
        if (codeBuffer.numEntries() == codePoint + 1) {
800
            // remember initialization code
801
            initializationCode = codeBuffer[codePoint];
802
        }
803
    }
804
    // remove temporary token sequence
805
    tokens.setNum(tokensRestorePoint);
806
    if (lineError) return;
807
 
808
    // get next line containing loop condition
809
    SCode conditionCode;
810
    zeroAllMembers(conditionCode);
811
    conditionCode.section = section;
812
    if (linei+2 >= lines.numEntries()) {  // no more lines
813
        errors.reportLine(ERR_UNFINISHED_INSTRUCTION);
814
        return;
815
    }
816
    linei++;
817
    tokenB = lines[linei].firstToken;       // first token in line        
818
    tokenN = lines[linei].numTokens;        // number of tokens in line
819
    if (tokenN == 1 && tokens[tokenB].type == TOK_OPR && tokens[tokenB].id == ';') {
820
        // no condition specified. infinite loop
821
        conditionFirst = 3;
822
        conditionCode.instruction = II_JUMP;
823
        conditionCode.etype = XPR_JUMPOS;
824
    }
825
    else {
826
        SExpression expr = expression(tokenB, tokenN, (dataType & TYP_UNS) != 0);
827
        if (lineError) return;
828
        insertAll(conditionCode, expr);  // insert logical expression into block
829
        conditionCode.dtype = dataType;
830
        interpretCondition(conditionCode);  // convert expression to conditional jump
831
        if (conditionCode.etype == XPR_INT) { // always true or always false
832
            conditionFirst = 2 + (conditionCode.value.w & 1);
833
            conditionCode.instruction = II_JUMP;
834
            conditionCode.etype = XPR_JUMPOS;
835
            conditionCode.value.i = 0;
836
            conditionCode.dtype = 0;
837
        }
838
        else {
839
            conditionCode.etype |= XPR_JUMPOS | XPR_SYM1;
840
            conditionCode.section = section;
841
            tok = tokenB + expr.tokens;       // expect ';' after expression
842
            if (tokens[tok].type != TOK_OPR || tokens[tok].id != ';') {
843
                errors.report(tokens[tok]);
844
            }
845
            //uint32_t counterRegister = 0;
846
            uint64_t counterStart = 0;
847
            // are start and end values known constants?
848
            if (initializationCode.instruction == II_MOVE && (initializationCode.etype & XPR_INT) && initializationCode.dest
849
                && !(initializationCode.etype & (XPR_REG1 | XPR_MEM | XPR_OPTION))) {
850
                //counterRegister = initializationCode.dest;
851
                counterStart = initializationCode.value.i;
852
                if ((expr.etype & XPR_INT) && (expr.etype & XPR_REG1) && !(expr.etype & (XPR_REG2 | XPR_MEM | XPR_OPTION))) {
853
                    // start and end values are integer constants
854
                    if ((expr.instruction & 0xFF) == II_COMPARE) {
855
                        // compare instruction. condition is in option bits
856
                        switch ((expr.optionbits >> 1) & 3) {
857
                        case 0:  // ==
858
                            conditionFirst = 2 + (counterStart == expr.value.u);  break;
859
                        case 1:  // <
860
                            if (dataType & TYP_UNS) conditionFirst = 2 + (counterStart < expr.value.u);
861
                            else conditionFirst = 2 + ((int64_t)counterStart < expr.value.i);
862
                            break;
863
                        case 2:  // >
864
                            if (dataType & TYP_UNS) conditionFirst = 2 + (counterStart > expr.value.u);
865
                            else conditionFirst = 2 + ((int64_t)counterStart > expr.value.i);
866
                            break;
867
                        }
868
                        if (expr.optionbits & 1) conditionFirst ^= 1; // invert if bit 0    
869
                    }
870
                    else if ((expr.instruction & 0xFF) == II_AND) {
871
                        // bit test. if (r1 & 1 << n)
872
                        conditionFirst = 2 + ((counterStart & ((uint64_t)1 << expr.value.u)) != 0);
873
                    }
874
                }
875
            }
876
        }
877
    }
878
 
879
    // make block record with label name
880
    block.blockNumber = ++iLoop;
881
 
882
    if (conditionFirst == 0) {
883
        // condition must be checked before first iteration
884
        invertCondition(conditionCode);          // invert condition
885
        sprintf(name, "@for_%u_b", iLoop);
886
        symi = makeLabelSymbol(name);
887
        block.breakLabel = symbols[symi].st_name;
888
        conditionCode.sym5 = block.breakLabel;
889
        // check if it can be merged with previous instruction
890
        mergeJump(conditionCode);
891
        checkCode1(conditionCode);               // finish code and fit it
892
        if (lineError) return;
893
        fitCode(conditionCode);                  // find an instruction variant that fits
894
        if (lineError) return;
895
        codeBuffer.push(conditionCode);          // save code structure
896
        invertCondition(conditionCode);          // invert condition back again
897
    }
898
    else if (conditionFirst == 2) {
899
        // condition is known to be false. loop goes zero times
900
        SCode jumpAlways;
901
        zeroAllMembers(jumpAlways);
902
        jumpAlways.instruction = II_JUMP;        // jump past loop
903
        jumpAlways.section = section;
904
        jumpAlways.etype = XPR_JUMPOS;
905
        sprintf(name, "@for_%u_goes_zero_times", iLoop);
906
        symi = makeLabelSymbol(name);
907
        block.breakLabel = symbols[symi].st_name;
908
        jumpAlways.sym5 = block.breakLabel;
909
        // check if it can be merged with previous instruction
910
        mergeJump(jumpAlways);
911
        checkCode1(jumpAlways);                  // finish code and fit it
912
        if (lineError) return;
913
        fitCode(jumpAlways);                     // find an instruction variant that fits
914
        if (lineError) return;
915
        codeBuffer.push(jumpAlways);             // save code structure
916
    }
917
    // make label for loop back
918
    if (conditionCode.instruction != II_JUMP) {
919
        sprintf(name, "@for_%u_a", iLoop);
920
    }
921
    else {
922
        sprintf(name, "@infinite_loop_%u_a", iLoop);
923
    }
924
    symi = makeLabelSymbol(name);
925
    block.jumpLabel = symbols[symi].st_name;
926
    conditionCode.sym5 = block.jumpLabel;
927
    SCode codeLabel;
928
    zeroAllMembers(codeLabel);
929
    codeLabel.label = block.jumpLabel;
930
    codeLabel.section = section;
931
    codeBuffer.push(codeLabel);
932
 
933
    // get next line containing increment
934
    linei++;
935
    tokenB = lines[linei].firstToken;            // first token in line        
936
    tokenN = lines[linei].numTokens;             // number of tokens in line
937
    // line must end with ')'
938
    if (tokenN < 1) {
939
        errors.reportLine(ERR_UNFINISHED_INSTRUCTION);
940
        return;
941
    }
942
    if (tokens[tokenB+tokenN-1].type != TOK_OPR || tokens[tokenB+tokenN-1].id != ')') {
943
        errors.report(tokens[tokenB+tokenN-1]);  // expecting ')'
944
        return;
945
    }
946
 
947
    // make instruction for loop counter increment
948
    tokens.push(typeToken);
949
    for (tok = tokenB; tok < tokenB + tokenN - 1; tok++) { // insert remaining tokens
950
        tokens.push(tokens[tok]);
951
    }
952
    // make an instruction out of this sequence
953
    tokenB = tokensRestorePoint;
954
    tokenN = tokens.numEntries() - tokensRestorePoint;
955
    SCode incrementCode;
956
    zeroAllMembers(incrementCode);
957
    codePoint = codeBuffer.numEntries();
958
    if (tokenN > 1) {
959
        interpretCodeLine();
960
        if (codeBuffer.numEntries() == codePoint + 1) {
961
            incrementCode = codeBuffer[codePoint];
962
            incrementCode.section = section;
963
        }
964
    }
965
    // remove temporary token sequence
966
    tokens.setNum(tokensRestorePoint);
967
    // remove temporary incrementation code. it has to be inserted after the loop
968
    codeBuffer.setNum(codePoint);
969
    if (lineError) return;
970
 
971
    // save instructions in block
972
    block.codeBuffer2index = codeBuffer2.push(incrementCode);
973
    codeBuffer2.push(conditionCode);
974
    block.codeBuffer2num = 2;
975
 
976
    // get next line containing '{'
977
    linei++;
978
    tokenB = lines[linei].firstToken;            // first token in line        
979
    tokenN = lines[linei].numTokens;             // number of tokens in line
980
    // line must contain '{'
981
    if (tokenN != 1 || tokens[tokenB].type != TOK_OPR || tokens[tokenB].id != '{') {
982
        errors.reportLine(ERR_EXPECT_BRACKET);
983
        return;
984
    }
985
    block.startBracket = tokenB;
986
 
987
    // save block to be recalled at end bracket
988
    hllBlocks.push(block);
989
 
990
}
991
 
992
// Finish for-loop at end bracket
993
void CAssembler::codeFor2() {
994
    SCode incrementCode;                         // code record for incrementing loop counter
995
    SCode conditionCode;                         // code record for conditional jump back
996
    SCode labelCode;                             // code record for label
997
    SBlock block = hllBlocks.pop();              // pop the stack of {} blocks
998
    if (block.continueLabel != 0xFFFFFFFF) {
999
        // place label here as jump target for continue statements
1000
        zeroAllMembers(labelCode);
1001
        labelCode.label = block.continueLabel;
1002
        labelCode.section = section;
1003
        codeBuffer.push(labelCode);
1004
    }
1005
 
1006
    uint32_t codebuf2num = codeBuffer2.numEntries();
1007
    if (block.codeBuffer2num == 2 && block.codeBuffer2index < codebuf2num) {
1008
        // retrieve prepared instruction
1009
        incrementCode = codeBuffer2[block.codeBuffer2index];
1010
        conditionCode = codeBuffer2[block.codeBuffer2index+1];
1011
 
1012
        // finish increment code and store it
1013
        if (incrementCode.instruction) {
1014
            checkCode1(incrementCode);
1015
            if (lineError) return;
1016
            fitCode(incrementCode);              // find an instruction variant that fits
1017
            if (lineError) return;
1018
            codeBuffer.push(incrementCode);      // save code
1019
        }
1020
 
1021
        // finish condition code and store it
1022
        // check if it can be merged with previous instruction
1023
        mergeJump(conditionCode);
1024
        checkCode1(conditionCode);
1025
        if (lineError) return;
1026
        fitCode(conditionCode);                  // find an instruction variant that fits
1027
        if (lineError) return;
1028
        codeBuffer.push(conditionCode);          // save code
1029
 
1030
        // remove from temporary buffer
1031
        if (block.codeBuffer2index + 2 == codebuf2num) {
1032
            codeBuffer2.pop(); codeBuffer2.pop();
1033
        }
1034
        // place label for breaking out
1035
        if (block.breakLabel != 0xFFFFFFFF) {
1036
            zeroAllMembers(labelCode);
1037
            labelCode.label = block.breakLabel;
1038
            labelCode.section = section;
1039
            codeBuffer.push(labelCode);          // save label
1040
        }
1041
    }
1042
}
1043
 
1044
// Interpret for-in vector loop in assembly code
1045
// for (float v1 in [r1-r2]) {}
1046
void CAssembler::codeForIn() {
1047
    uint32_t state = 0;                // state while interpreting line
1048
                                       // 0: start, 1: after type, 2: after 'for', 3: after (, 4: after (type,
1049
                                       // 5: after vector register, 6: after 'in', 7: after '['
1050
                                       // 8: after base register, 9: after '-', 10: after index register
1051
                                       // 11: after ']', 12: after ')'
1052
    SBlock block;                      // block descriptor to save
1053
    zeroAllMembers(block);             // reset
1054
    block.blockType = HL_FOR_IN;       // 'for-in' block
1055
    block.breakLabel = block.jumpLabel = block.continueLabel = 0xFFFFFFFF;
1056
    block.blockNumber = ++iLoop;       // number to use in labels
1057
    //uint32_t baseReg;                // base register
1058
    uint32_t indexReg = 0;             // index register
1059
    uint32_t tok;                      // token number
1060
    SToken token;                      // current token
1061
    uint32_t type = 0;                 // vector element type
1062
    uint32_t symi;                     // symbol index
1063
    char name[32];                     // symbol name
1064
 
1065
    // interpret line by state machine looping through tokens
1066
    for (tok = tokenB; tok < tokenB + tokenN; tok++) {
1067
        if (lineError) break;
1068
        token = tokens[tok];
1069
 
1070
        switch (state) {
1071
        case 0:  // start. expect type or 'for'
1072
            if (token.type == TOK_TYP) {
1073
                type = token.id & 0xFF;
1074
                state = 1;
1075
            }
1076
            else if (token.type == TOK_HLL && token.id == HLL_FOR) {
1077
                state = 2;
1078
            }
1079
            else errors.report(token);
1080
            break;
1081
        case 1:  // after type. expect 'for' ('+' not allowed after type)
1082
            if (token.type == TOK_HLL && token.id == HLL_FOR) {
1083
                state = 2;
1084
            }
1085
            else errors.report(token);
1086
            break;
1087
        case 2:  // after 'for'. expect '('
1088
            if (token.type == TOK_OPR && token.id == '(') {
1089
                state = 3;
1090
            }
1091
            else errors.report(token);
1092
            break;
1093
        case 3:  // after '('. expect type or vector register
1094
            if (token.type == TOK_TYP && !type) {
1095
                type = token.id & 0xFF;
1096
                state = 4;
1097
            }
1098
            else if (token.type == TOK_REG) {
1099
                // must be vector register
1100
                if (!(token.id & REG_V)) errors.report(token.pos, token.stringLength, ERR_WRONG_REG_TYPE);
1101
                state = 5;
1102
            }
1103
            else errors.report(token);
1104
            break;
1105
        case 4:  // after type. expect vector register         
1106
            if (token.type == TOK_REG) {
1107
                // must be vector register
1108
                if (!(token.id & REG_V)) errors.report(token.pos, token.stringLength, ERR_WRONG_REG_TYPE);
1109
                state = 5;
1110
            }
1111
            else errors.report(token);
1112
            break;
1113
        case 5:  // after vector register. expect 'in'
1114
            if (token.type == TOK_HLL && token.id == HLL_IN) {
1115
                state = 6;
1116
            }
1117
            else errors.report(token);
1118
            break;
1119
        case 6:  // after 'in'. expect '['
1120
            if (token.type == TOK_OPR && token.id == '[') {
1121
                state = 7;
1122
            }
1123
            else errors.report(token);
1124
            break;
1125
        case 7:  // after '['. expect base register
1126
            if (token.type == TOK_REG) {
1127
                // must be general purpose register
1128
                if (!(token.id & REG_R)) errors.report(token.pos, token.stringLength, ERR_WRONG_REG_TYPE);
1129
                //baseReg = token.id;
1130
                state = 8;
1131
            }
1132
            else errors.report(token);
1133
            break;
1134
        case 8:  // after base register. expect '-'
1135
            if (token.type == TOK_OPR && token.id == '-') {
1136
                state = 9;
1137
            }
1138
            else errors.report(token);
1139
            break;
1140
        case 9:  // after '-'. expect index register
1141
            if (token.type == TOK_REG) {
1142
                // must be general purpose register, except r31
1143
                if (!(token.id & REG_R) || token.id == (REG_R|31)) errors.report(token.pos, token.stringLength, ERR_WRONG_REG_TYPE);
1144
                indexReg = token.id;
1145
                state = 10;
1146
            }
1147
            else errors.report(token);
1148
            break;
1149
        case 10:  // after index register. expect ']'
1150
            if (token.type == TOK_OPR && token.id == ']') {
1151
                state = 11;
1152
            }
1153
            else errors.report(token);
1154
            break;
1155
        case 11:  // after ']'. expect ')'
1156
            if (token.type == TOK_OPR && token.id == ')') {
1157
                state = 12;
1158
            }
1159
            else errors.report(token);
1160
            break;
1161
        default:
1162
            errors.report(token);
1163
        }
1164
    }
1165
    // get next line and expect '{'
1166
    if (linei == lines.numEntries()-1) {    // no more lines
1167
        errors.reportLine(ERR_UNFINISHED_INSTRUCTION);
1168
        return;
1169
    }
1170
    linei++;
1171
    tokenB = lines[linei].firstToken;       // first token in line        
1172
    tokenN = lines[linei].numTokens;        // number of tokens in line
1173
    lineError = false;
1174
 
1175
    // expect '{'
1176
    if (tokens[tokenB].id != '{') {
1177
        errors.reportLine(ERR_EXPECT_BRACKET);
1178
        return;
1179
    }
1180
    block.startBracket = tokenB;
1181
 
1182
    // look at preceding instruction to see if value of index register is known to be positive
1183
    bool startCheckNeeded = true;
1184
    SCode previousInstruction;
1185
    if (codeBuffer.numEntries()) {
1186
        previousInstruction = codeBuffer[codeBuffer.numEntries()-1];  // recall previous instruction
1187
        if (previousInstruction.section == section && previousInstruction.instruction == II_MOVE
1188
            && (previousInstruction.etype & XPR_INT) && previousInstruction.dest == indexReg
1189
            && !(previousInstruction.etype & (XPR_REG1 | XPR_MEM | XPR_OPTION))
1190
            && previousInstruction.value.i > 0) {
1191
            startCheckNeeded = false;
1192
        }
1193
    }
1194
    if (startCheckNeeded) {
1195
        // make label name for break
1196
        sprintf(name, "@for_%u_b", iLoop);
1197
        symi = makeLabelSymbol(name);
1198
        block.breakLabel = symbols[symi].st_name; // label to jump back to
1199
        // make conditional jump if index not positive
1200
        SCode startCheck;
1201
        zeroAllMembers(startCheck);
1202
        startCheck.section = section;
1203
        startCheck.instruction = II_COMPARE | II_JUMP_POSITIVE | II_JUMP_INVERT;
1204
        startCheck.reg1 = indexReg;
1205
        startCheck.sym5 = block.breakLabel;
1206
        startCheck.etype = XPR_INT | XPR_REG | XPR_REG1 | XPR_JUMPOS;
1207
        startCheck.line = linei;
1208
        startCheck.dtype = TYP_INT64;
1209
        mergeJump(startCheck);                   // check if it can be merged with previous instruction
1210
        checkCode1(startCheck);
1211
        fitCode(startCheck);                     // find an instruction variant that fits
1212
        if (lineError) return;
1213
        codeBuffer.push(startCheck);             // save instruction
1214
    }
1215
    // make label name for loop
1216
    sprintf(name, "@for_%u_a", iLoop);
1217
    symi = makeLabelSymbol(name);
1218
    block.jumpLabel = symbols[symi].st_name;     // label to jump back to
1219
    SCode labelCode;
1220
    zeroAllMembers(labelCode);
1221
    labelCode.section = section;
1222
    labelCode.label = block.jumpLabel;
1223
    codeBuffer.push(labelCode);                  // save label
1224
 
1225
    // save index registr and type in block
1226
    block.codeBuffer2num = indexReg;
1227
    block.codeBuffer2index = type;
1228
 
1229
    // save block to be recalled at '}'
1230
    hllBlocks.push(block);
1231
}
1232
 
1233
// Finish for-in vector loop in assembly code
1234
void CAssembler::codeForIn2() {
1235
    SCode code;                                  // code record for jump back
1236
    SBlock block = hllBlocks.pop();              // pop the stack of {} blocks
1237
    if (block.continueLabel != 0xFFFFFFFF) {
1238
        // place label here as jump target for continue statements
1239
        zeroAllMembers(code);
1240
        code.label = block.continueLabel;
1241
        code.section = section;
1242
        codeBuffer.push(code);
1243
    }
1244
    // make loop instruction
1245
    zeroAllMembers(code);
1246
    code.section = section;
1247
    code.line = linei;
1248
    code.instruction = II_SUB_MAXLEN | II_JUMP_POSITIVE;
1249
    code.reg1 = code.dest = block.codeBuffer2num;
1250
    code.value.u = block.codeBuffer2index & 0xF;  // element type in vector
1251
    code.dtype = TYP_INT64;
1252
    code.sym5 = block.jumpLabel;
1253
    code.etype = XPR_INT | XPR_REG | XPR_REG1 | XPR_JUMPOS;
1254
    // fit code and save it
1255
    checkCode1(code);
1256
    fitCode(code);
1257
    if (lineError) return;
1258
    codeBuffer.push(code);  // save instruction
1259
    // make break label
1260
    if (block.breakLabel != 0xFFFFFFFF) {
1261
        zeroAllMembers(code);
1262
        code.section = section;
1263
        code.label = block.breakLabel;
1264
        codeBuffer.push(code);   // save label
1265
    }
1266
}
1267
 
1268
 
1269
// Interpret switch statement in assembly code
1270
void CAssembler::codeSwitch() {
1271
    /*
1272
    CMetaBuffer<CDynamicArray<SCcaseLabel> > caseLabels;
1273
    CDynamicArray<SCode> extraCode;
1274
    if (caseLabels.numEntries() == 0) caseLabels.setNum(switchNumber);
1275
    */
1276
 
1277
 
1278
}
1279
 
1280
// Interpret switch case label in assembly code
1281
void CAssembler::codeCase() {}
1282
 
1283
// Finish switch statement at end bracket
1284
void CAssembler::codeSwitch2() {
1285
}
1286
 
1287
// Interpret break or continue statement in assembly code
1288
void CAssembler::codeBreak() {
1289
    uint32_t symi = findBreakTarget(tokens[tokenB].id);
1290
    if (symi == 0) {
1291
        errors.report(tokens[tokenB].pos, tokens[tokenB].stringLength, tokens[tokenB].id == HLL_BREAK ? ERR_MISPLACED_BREAK : ERR_MISPLACED_CONTINUE);
1292
        return;
1293
    }
1294
    // make jump to symi
1295
    SCode code;
1296
    zeroAllMembers(code);
1297
    code.section = section;
1298
    code.instruction = II_JUMP;
1299
    code.etype = XPR_JUMPOS | XPR_SYM1;
1300
    code.sym5 = symi;
1301
 
1302
    // check if it can be merged with previous instruction
1303
    mergeJump(code);
1304
 
1305
    // finish code and save it
1306
    checkCode1(code);
1307
    if (lineError) return;
1308
    fitCode(code);       // find an instruction variant that fits
1309
    if (lineError) return;
1310
    codeBuffer.push(code);// save code structure
1311
}
1312
 
1313
 
1314
// Find or make the target symbol of a break or continue statement
1315
uint32_t CAssembler::findBreakTarget(uint32_t k) {
1316
    // k is HLL_BREAK or HLL_CONTINUE
1317
    int32_t blocki;        // block index
1318
    uint32_t symi;         // symbol id
1319
    bool found = false;    // target found
1320
    // search backwords through blocks to find the first block that can have break/continue
1321
    for (blocki = (int32_t)hllBlocks.numEntries() - 1; blocki >= 0; blocki--) {
1322
        switch (hllBlocks[blocki].blockType) {
1323
        case HL_FOR: case HL_FOR_IN: case HL_WHILE: case HL_DO_WHILE:
1324
            // can have break and continue
1325
            found = true;
1326
            break;
1327
        case HL_SWITCH:
1328
            // can have break, but not continue
1329
            if (k == HLL_BREAK) found = true;
1330
            break;
1331
        case HL_FUNC: case HL_SECTION:
1332
            // stop search and fail
1333
            return 0;
1334
        }
1335
        if (found) break;
1336
    }
1337
    if (!found) return 0;  // not found
1338
    char prefix;
1339
    // find symbol in block
1340
    if (k == HLL_BREAK) {
1341
        symi = hllBlocks[blocki].breakLabel;
1342
        prefix = 'b';
1343
    }
1344
    else {
1345
        symi = hllBlocks[blocki].continueLabel;
1346
        prefix = 'c';
1347
    }
1348
    if (symi != 0xFFFFFFFF) return symi;  // symbol has already been assigned
1349
 
1350
    // symbol has not been assigned yet. give it a name
1351
    const char * blockName = 0;
1352
    switch (hllBlocks[blocki].blockType) {
1353
    case HL_FOR: case HL_FOR_IN:
1354
        blockName = "for";  break;
1355
    case HL_WHILE:
1356
        blockName = "while";  break;
1357
    case HL_DO_WHILE:
1358
        blockName = "do";  break;
1359
    case HL_SWITCH:
1360
        blockName = "switch";  break;
1361
    default: return 0;
1362
    }
1363
    char name[32];
1364
    sprintf(name, "@%s_%u_%c", blockName, hllBlocks[blocki].blockNumber, prefix);
1365
    symi = makeLabelSymbol(name);
1366
    symi = symbols[symi].st_name;
1367
    // save name in block, in case it is needed again
1368
    if (k == HLL_BREAK) {
1369
        hllBlocks[blocki].breakLabel = symi;
1370
    }
1371
    else {
1372
        hllBlocks[blocki].continueLabel = symi;
1373
    }
1374
    return symi;
1375
}
1376
 
1377
 
1378
// Make a symbol for branch label etc., address not known yet. Returns zero if already defined
1379
uint32_t CAssembler::makeLabelSymbol(const char * name) {
1380
    ElfFWC_Sym2 sym;
1381
    zeroAllMembers(sym);
1382
    sym.st_type = STT_FUNC;
1383
    sym.st_other = STV_HIDDEN | STV_IP;
1384
    sym.st_section = section;
1385
    sym.st_name = symbolNameBuffer.putStringN(name, (uint32_t)strlen(name));
1386
    uint32_t symi = addSymbol(sym);  // save symbol with name
1387
    if (symi == 0) {
1388
        errors.reportLine(ERR_SYMBOL_DEFINED);
1389
    }
1390
    return symi;
1391
}
1392
 
1393
// Merge jump instruction with preceding arithmetic instruction.
1394
// If successful, returns true and puts the result in code1
1395
bool CAssembler::mergeJump(SCode & code2) {
1396
    if (cmd.optiLevel == 0) return false;        // merge only if optimization is on
1397
    if (code2.label) return false;               // cannot merge if there is a label between the two instructions
1398
    if (codeBuffer.numEntries() == 0) return false; // no previous instruction to merge with
1399
    SCode code1 = codeBuffer[codeBuffer.numEntries()-1]; // previous code
1400
 
1401
    if (code1.section != code2.section) return false; // must be in same section
1402
    SCode code3 = code1 | code2;  // combined code
1403
    code3.reg1 = code1.reg1;
1404
    code3.dest = code1.dest;
1405
    uint32_t type = code1.dtype;
1406
    // first instruction cannot have memory operand or other special options
1407
    if (code1.etype & (XPR_MEM | XPR_SYM1 | XPR_MASK | XPR_OPTION | XPR_OPTIONS | XPR_JUMPOS | XPR_ERROR)) return false;
1408
    if (!(code2.etype & XPR_JUMPOS)) return false;
1409
 
1410
    /*if (code2.instruction == II_JUMP) {
1411
        // combine unconditional jump with add/sub
1412
        if (code2.etype & (XPR_MEM | XPR_OPTION | XPR_REG)) return false;
1413
        if ((code1.instruction & ~1) != II_ADD) return false;  // only add and sub
1414
        if (type & TYP_FLOAT) return false;
1415
        // successful combination of add/sub and jump
1416
        codeBuffer.pop();        // remove previous code from buffer
1417
        code2 = code3;
1418
        return true;
1419
    } */
1420
 
1421
    // second instruction must test the result of the first instruction
1422
    if (code1.dest != code2.reg1) return false;
1423
    // must have same operand type
1424
    if ((code1.dtype & 0xF) > (code2.dtype & 0xF)) {
1425
        if (!(code2.dtype & TYP_PLUS)) return false;
1426
    }
1427
    if ((code1.dtype & 0xF) < (code2.dtype & 0xF)) {
1428
        if (!(code1.dtype & TYP_PLUS)) return false;
1429
        type = code2.dtype;
1430
    }
1431
    type |= code2.dtype & TYP_UNS;  // signed/unsigned distinction only relevant for second instruction
1432
    code3.dtype = type;
1433
 
1434
    // check if constant bigger than 32 bits
1435
    if ((type & XPR_INT) && !(type & TYP_UNS) && (code1.value.i < (int32_t)0x80000000 || code1.value.i > (int32_t)0x7FFFFFFF)) return false;
1436
    if ((type & XPR_INT) && (type & TYP_UNS) && (code1.value.u > (uint64_t)0xFFFFFFFF)) return false;
1437
    if ((type & XPR_FLT) && (type & 0xFF) > TYP_FLOAT32) return false;
1438
 
1439
    switch (code1.instruction) {
1440
    case II_ADD: case II_SUB:
1441
        if (type & TYP_FLOAT) return false;
1442
        if (code1.instruction == II_ADD && code1.value.u == 1 && !(type & TYP_UNS)) {
1443
            // check if it fits increment_compare/jump below/above
1444
            code3.value.u = code2.value.u;
1445
            /*
1446
            uint32_t nbits = (1 << (type & 7)) * 8;  // number of bits in constant
1447
            if ((code2.instruction & 0xFFFE00) == II_JUMP_NEGATIVE && (code2.etype & XPR_INT)
1448
            && (code3.value.u & (((uint64_t)1 << nbits) - 1)) != (uint64_t)1 << (nbits - 1)) { // check for overflow
1449
                // convert jump_sbelow n to jump_sbeloweq n-1
1450
                // or jump_saboveeq n to jump sabove n-1
1451
                code3.value.u--;
1452
                code3.instruction ^= II_JUMP_NEGATIVE ^ II_JUMP_POSITIVE ^ II_JUMP_INVERT;
1453
            }*/
1454
            if ((code3.instruction & 0xFFFE00) == II_JUMP_POSITIVE || (code3.instruction & 0xFFFE00) == II_JUMP_NEGATIVE) {
1455
                // successful combination of add 1 and jump_sbelow/above
1456
                code3.instruction = (code3.instruction & 0xFFFF00) | II_INCREMENT;
1457
                code3.etype = (code1.etype & ~XPR_IMMEDIATE) | code2.etype;
1458
                codeBuffer.pop();        // remove previous code from buffer
1459
                code2 = code3;
1460
                return true;
1461
            }
1462
        }
1463
        // add/sub + compare
1464
        if (!(code2.etype & XPR_INT) || code2.value.i != 0 || (code2.instruction & 0xFF) != II_COMPARE) return false; // must compare against zero
1465
 
1466
        //??:
1467
        if ((type & TYP_UNS) && (code3.instruction & 0xFFFE00) != II_JUMP_ZERO) return false;  // unsigned works only for == and !=
1468
        // successful combination of add/sub and signed compare with zero
1469
        code3.instruction = code1.instruction | (code2.instruction & 0xFFFF00);
1470
        code3.etype = code1.etype | (code2.etype & ~(XPR_IMMEDIATE | XPR_OPTIONS));
1471
        codeBuffer.pop();        // remove previous code from buffer
1472
        code2 = code3;
1473
        return true;
1474
 
1475
    case II_AND: case II_OR: case II_XOR:
1476
    //case II_SHIFT_LEFT:  case II_SHIFT_RIGHT_U:
1477
        // must compare for equal to zero
1478
        if (!(code2.etype & XPR_INT) || code2.value.i != 0) return false;
1479
        //if ((code2.instruction & 0xFFFE00) != II_JUMP_ZERO) return false;
1480
        if ((code2.instruction & ~ II_JUMP_INVERT) != (II_JUMP_ZERO | II_COMPARE)) return false;
1481
        // combine instruction codes
1482
        code3.instruction = code1.instruction | (code2.instruction & 0xFFFF00);
1483
        code3.etype = code1.etype | (code2.etype & ~XPR_IMMEDIATE);
1484
        // successful combination of and/or/xor/shift and compare with zero
1485
        codeBuffer.pop();        // remove previous code from buffer
1486
        code2 = code3;
1487
        return true;
1488
    }
1489
    // everything else fails
1490
    return false;
1491
}
1492
 
1493
// check if line contains unconditional direct jump and nothing else
1494
uint32_t CAssembler::hasJump(uint32_t line) {
1495
    if (cmd.optiLevel == 0) return 0;             // don't optimize jump if optimization is off
1496
    if (line >= lines.numEntries()) return 0;     // there is no line here
1497
    uint32_t tokB = lines[line].firstToken;
1498
    uint32_t tokN = lines[line].numTokens;        // number of tokens in line
1499
    if (tokN > 0 && tokens[tokB+tokN-1].type == TOK_OPR && tokens[tokB+tokN-1].id == ';') tokN--;  // ignore ';'
1500
    lineError = false;
1501
    if (tokN == 1 && tokens[tokB].type == TOK_HLL) {  // high level keyword
1502
        if (tokens[tokB].id == HLL_BREAK || tokens[tokB].id == HLL_CONTINUE) {
1503
            return findBreakTarget(tokens[tokB].id);  // break or continue statement
1504
        }
1505
    }
1506
    if (tokN == 2 && tokens[tokB].type == TOK_INS && tokens[tokB].id == II_JUMP && tokens[tokB+1].type == TOK_SYM) {
1507
        // jump symbol
1508
       // return tokens[tokB+1].value.w;
1509
        return tokens[tokB+1].id;
1510
    }
1511
    return 0;  // anything else
1512
}
1513
 
1514
// interpret condition in if(), while(), and for(;;) statements
1515
void CAssembler::interpretCondition(SCode & code) {
1516
    if ((code.instruction & 0xFF) == II_COMPARE) {
1517
        // compare instruction. condition is in option bits
1518
        switch ((code.optionbits >> 1) & 3) {
1519
        case 0:
1520
            code.instruction |= II_JUMP_ZERO;  break;
1521
        case 1:
1522
            code.instruction |= (code.dtype & TYP_UNS) ? II_JUMP_CARRY : II_JUMP_NEGATIVE;  break;
1523
        case 2:
1524
            code.instruction |= (code.dtype & TYP_UNS) ? II_JUMP_UABOVE : II_JUMP_POSITIVE;  break;
1525
        case 3:
1526
            errors.reportLine(ERR_EXPECT_LOGICAL); // should not occur
1527
        }
1528
        if (code.optionbits & 1) code.instruction ^= II_JUMP_INVERT; // invert if bit 0    
1529
        if (code.dtype & TYP_FLOAT) { // floating point. resolve ordered/unordered
1530
            //if ((code.instruction & 0x7F00) == (II_JUMP_NOTZERO & 0x7F00)) code.optionbits |= 8;  // a != b is unordered. This has already been done in CAssembler::op2Registers
1531
            if ((code.optionbits & 8) && (code.instruction & 0x7F00) - 0x1000 < 0x2000) {
1532
                code.instruction ^= II_JUMP_UNORDERED; // unordered bit
1533
            }
1534
        }
1535
    }
1536
    else if ((code.instruction & 0xFF) == II_AND && (code.etype & XPR_INT)) {
1537
        // if (r1 & )
1538
        if (code.value.u != 0 && (code.value.u & (code.value.u-1)) == 0) {
1539
            // n is a power of 2. test_bit
1540
            code.instruction = II_TEST_BIT | II_JUMP_TRUE;
1541
            code.value.u = bitScanReverse(code.value.u);
1542
        }
1543
        else {
1544
            code.instruction = II_TEST_BITS_OR | II_JUMP_TRUE;
1545
        }
1546
        if (code.optionbits & 4) code.instruction ^= II_JUMP_INVERT;
1547
    }
1548
    else if ((code.instruction & 0xFF) == II_TEST_BITS_AND && (code.etype & XPR_INT)) {
1549
        code.instruction |= II_JUMP_TRUE;
1550
        if (code.optionbits & 1) code.instruction ^= II_JUMP_INVERT;
1551
    }
1552
    else if (code.instruction == 0 && code.etype == XPR_INT) {
1553
        // constant condition. always true or always false
1554
        code.instruction = II_JUMP;
1555
        if (code.value.i == 0) code.instruction |= II_JUMP_INVERT;
1556
 
1557
        //!!
1558
        code.etype = 0;
1559
    }
1560
    else {  // unrecognized expression
1561
        errors.reportLine(ERR_EXPECT_LOGICAL);
1562
        code.instruction = II_JUMP;
1563
    }
1564
    code.optionbits = 0;
1565
}
1566
 
1567
 
1568
// push registers on stack
1569
void CAssembler::codePush() {
1570
    uint32_t state = 0;                     // 0: begin, 1: after type, 2: after 'push', 3: after '(', 
1571
                                            // 4: after register 1, 5: after comma, 6: after register 2, 7: after comma,
1572
                                            // 8: after constant, 9: after ')'
1573
    int32_t reg1 = -1;                      // register  1, stack pointer if specified
1574
    int32_t reg2 = -1;                      // register  2
1575
    uint32_t imm = -1;                       // immediate operand
1576
    uint32_t ot  = 3;                       // operand type
1577
    uint32_t tok = 0;                       // token index
1578
    SToken token;                           // token
1579
    SCode code;                             // code structure
1580
    zeroAllMembers(code);
1581
    code.section = section;
1582
    // loop through tokens on line
1583
    for (tok = tokenB; tok < tokenB + tokenN; tok++) {
1584
        token = tokens[tok];
1585
        if (token.type == TOK_XPR && expressions[token.value.w].etype & XPR_REG) {
1586
            // this is an alias for a register. Translate to register
1587
            token.type = TOK_REG;
1588
            token.id = expressions[token.value.w].reg1;
1589
        }
1590
 
1591
        switch (state) {
1592
        case 0:               // begin. expect type or 'push'
1593
            if (token.id == HLL_PUSH) state = 2;
1594
            else if (token.type == TOK_TYP) {
1595
                ot = tokens[tok].id;
1596
                state = 1;
1597
            }
1598
            else errors.report(token);
1599
            break;
1600
 
1601
        case 1:               // after type. expect 'push'
1602
            if (token.id == HLL_PUSH) state = 2;
1603
            else errors.report(token);
1604
            break;
1605
 
1606
        case 2:  // after 'push'. expect '('
1607
            if (token.type == TOK_OPR && token.id == '(') state = 3;
1608
            else errors.report(token);
1609
            break;
1610
 
1611
        case 3:  // after '('. expect register
1612
            if (token.type != TOK_REG) {
1613
                errors.report(token); return;
1614
            }
1615
            state = 4;
1616
            reg1 = token.id;
1617
            break;
1618
 
1619
        case 4:  // after register. expect ',' or ')'
1620
            if (token.type == TOK_OPR && token.id == ',') state = 5;
1621
            else if (token.type == TOK_OPR && token.id == ')') state = 9;
1622
            else errors.report(token);
1623
            break;
1624
 
1625
        case 5:  // after comma. expect register or constant
1626
            if (token.type == TOK_REG) {
1627
                reg2 = token.id;  state = 6;
1628
            }
1629
            else if (token.type == TOK_NUM || token.type == TOK_SYM) {
1630
                imm = expression(tok, 1, 0).value.w;  state = 8;
1631
            }
1632
            else errors.report(token);
1633
            break;
1634
 
1635
        case 6:  // after second register. expect comma or ')'
1636
            if (token.type == TOK_OPR && token.id == ',') state = 7;
1637
            else if (token.type == TOK_OPR && token.id == ')') state = 9;
1638
            else errors.report(token);
1639
            break;
1640
 
1641
        case 7:  // after second comma. expect constant
1642
            if (token.type == TOK_NUM || token.type == TOK_SYM) {
1643
                imm = expression(tok, 1, 0).value.w;  state = 8;
1644
            }
1645
            else errors.report(token);
1646
            break;
1647
 
1648
        case 8:  // after constant. expect ')'
1649
            if (token.type == TOK_OPR && token.id == ')') state = 9;
1650
            else errors.report(token);
1651
            break;
1652
 
1653
        default:  // after ')'. expect nothing
1654
            errors.report(token);
1655
            break;
1656
        }
1657
    }
1658
    if (state != 9) {
1659
        errors.reportLine(ERR_UNFINISHED_INSTRUCTION);
1660
        return;
1661
    }
1662
    if (reg2 == -1) {  // stack pointer not specified. use default stack pointer
1663
        reg2 = reg1;  reg1 = 0x1F | REG_R;
1664
    }
1665
    if (int32_t(imm) == -1) {  // no immediate operand. push only one register
1666
        imm = reg2 & 0x1F;
1667
    }
1668
    if ((imm & 0x1F) < uint32_t(reg2 & 0x1F)) {
1669
        errors.reportLine(ERR_OPERANDS_WRONG_ORDER);
1670
        return;
1671
    }
1672
    if (!(reg1 & REG_R)) {
1673
        errors.reportLine(ERR_WRONG_OPERANDS);
1674
        return;
1675
    }
1676
    if ((reg2 & REG_V) && (imm & 0x80)) {
1677
        errors.reportLine(ERR_WRONG_OPERANDS);
1678
        return;
1679
    }
1680
    code.instruction = II_PUSH;
1681
    code.dest = reg1;
1682
    code.reg1 = reg2;
1683
    code.value.u = imm;
1684
    code.etype = XPR_INT | XPR_REG | XPR_REG1;
1685
    code.dtype = TYP_INT8 | (ot & 0xF);
1686
    checkCode1(code);
1687
    fitCode(code);
1688
    if (lineError) return;
1689
    codeBuffer.push(code);  // save code
1690
}
1691
 
1692
 
1693
// pop register from stack
1694
void CAssembler::codePop() {
1695
    uint32_t state = 0;                     // 0: begin, 1: after type, 2: after 'push', 3: after '(', 
1696
                                            // 4: after register 1, 5: after comma, 6: after register 2, 7: after comma,
1697
                                            // 8: after constant, 9: after ')'
1698
    int32_t reg1 = -1;                      // register  1, stack pointer if specified
1699
    int32_t reg2 = -1;                      // register  2
1700
    uint32_t imm = -1;                       // immediate operand
1701
    uint32_t ot = 3;                       // operand type
1702
    uint32_t tok = 0;                       // token index
1703
    SToken token;                           // token
1704
    SCode code;                             // code structure
1705
    zeroAllMembers(code);
1706
    code.section = section;
1707
    // loop through tokens on line
1708
    for (tok = tokenB; tok < tokenB + tokenN; tok++) {
1709
        token = tokens[tok];
1710
        if (token.type == TOK_XPR && expressions[token.value.w].etype & XPR_REG) {
1711
            // this is an alias for a register. Translate to register
1712
            token.type = TOK_REG;
1713
            token.id = expressions[token.value.w].reg1;
1714
        }
1715
        switch (state) {
1716
        case 0:               // begin. expect type or 'push'
1717
            if (token.id == HLL_POP) state = 2;
1718
            else if (token.type == TOK_TYP) {
1719
                ot = tokens[tok].id;
1720
                state = 1;
1721
            }
1722
            else errors.report(token);
1723
            break;
1724
 
1725
        case 1:               // after type. expect 'push'
1726
            if (token.id == HLL_POP) state = 2;
1727
            else errors.report(token);
1728
            break;
1729
 
1730
        case 2:  // after 'push'. expect '('
1731
            if (token.type == TOK_OPR && token.id == '(') state = 3;
1732
            else errors.report(token);
1733
            break;
1734
 
1735
        case 3:  // after '('. expect register
1736
            if (token.type != TOK_REG) {
1737
                errors.report(token); return;
1738
            }
1739
            state = 4;
1740
            reg1 = token.id;
1741
            break;
1742
 
1743
        case 4:  // after register. expect ',' or ')'
1744
            if (token.type == TOK_OPR && token.id == ',') state = 5;
1745
            else if (token.type == TOK_OPR && token.id == ')') state = 9;
1746
            else errors.report(token);
1747
            break;
1748
 
1749
        case 5:  // after comma. expect register or constant
1750
            if (token.type == TOK_REG) {
1751
                reg2 = token.id;  state = 6;
1752
            }
1753
            else if (token.type == TOK_NUM || token.type == TOK_SYM) {
1754
                imm = expression(tok, 1, 0).value.w;  state = 8;
1755
            }
1756
            else errors.report(token);
1757
            break;
1758
 
1759
        case 6:  // after second register. expect comma or ')'
1760
            if (token.type == TOK_OPR && token.id == ',') state = 7;
1761
            else if (token.type == TOK_OPR && token.id == ')') state = 9;
1762
            else errors.report(token);
1763
            break;
1764
 
1765
        case 7:  // after second comma. expect constant
1766
            if (token.type == TOK_NUM || token.type == TOK_SYM) {
1767
                imm = expression(tok, 1, 0).value.w;  state = 8;
1768
            }
1769
            else errors.report(token);
1770
            break;
1771
 
1772
        case 8:  // after constant. expect ')'
1773
            if (token.type == TOK_OPR && token.id == ')') state = 9;
1774
            else errors.report(token);
1775
            break;
1776
 
1777
        default:  // after ')'. expect nothing
1778
            errors.report(token);
1779
            break;
1780
        }
1781
    }
1782
    if (state != 9) {
1783
        errors.reportLine(ERR_UNFINISHED_INSTRUCTION);
1784
        return;
1785
    }
1786
    if (reg2 == -1) {  // stack pointer not specified. use default stack pointer
1787
        reg2 = reg1;  reg1 = 0x1F | REG_R;
1788
    }
1789
    if (int32_t(imm) == -1) {  // no immediate operand. push only one register
1790
        imm = reg2 & 0x1F;
1791
    }
1792
    if ((imm & 0x1F) < uint32_t(reg2 & 0x1F)) {
1793
        errors.reportLine(ERR_OPERANDS_WRONG_ORDER);
1794
        return;
1795
    }
1796
    if (!(reg1 & REG_R)) {
1797
        errors.reportLine(ERR_WRONG_OPERANDS);
1798
        return;
1799
    }
1800
    if ((reg2 & REG_V) && (imm & 0x80)) {
1801
        errors.reportLine(ERR_WRONG_OPERANDS);
1802
        return;
1803
    }
1804
    code.instruction = II_POP;
1805
    code.dest = reg1;
1806
    code.reg1 = reg2;
1807
    code.value.u = imm;
1808
    code.etype = XPR_INT | XPR_REG | XPR_REG1;
1809
    code.dtype = TYP_INT8 | (ot & 0xF);
1810
    checkCode1(code);
1811
    fitCode(code);
1812
    if (lineError) return;
1813
    codeBuffer.push(code);  // save code
1814
}

powered by: WebSVN 2.1.0

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