Subversion Repositories Kolibri OS

Rev

Rev 7597 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
7597 akron1 1
(*
2
    BSD 2-Clause License
3
 
4
    Copyright (c) 2018, 2019, Anton Krotov
5
    All rights reserved.
6
*)
7
 
8
MODULE STATEMENTS;
9
 
10
IMPORT
11
 
12
    PARS, PROG, SCAN, ARITH, STRINGS, LISTS, CODE, X86, AMD64,
13
    ERRORS, MACHINE, AVL := AVLTREES, CONSOLE, C := COLLECTIONS, mConst := CONSTANTS;
14
 
15
 
16
CONST
17
 
18
    eCONST   =  PARS.eCONST;   eTYPE     =  PARS.eTYPE;     eVAR      =  PARS.eVAR;
19
    eEXPR    =  PARS.eEXPR;    eVREC     =  PARS.eVREC;     ePROC     =  PARS.ePROC;
20
    eVPAR    =  PARS.eVPAR;    ePARAM    =  PARS.ePARAM;    eSTPROC   =  PARS.eSTPROC;
21
    eSTFUNC  =  PARS.eSTFUNC;  eSYSFUNC  =  PARS.eSYSFUNC;  eSYSPROC  =  PARS.eSYSPROC;
22
    eIMP     =  PARS.eIMP;
23
 
24
    errASSERT = 1;  errPTR  =  2;  errDIV  =  3;  errPROC = 4;
25
    errGUARD  = 5;  errIDX  =  6;  errCASE =  7;  errCOPY = 8;
26
    errCHR    = 9;  errWCHR = 10;  errBYTE = 11;
27
 
28
    chkIDX* = 0; chkGUARD* = 1; chkPTR* = 2; chkCHR* = 3; chkWCHR* = 4; chkBYTE* = 5;
29
 
30
    chkALL* = {chkIDX, chkGUARD, chkPTR, chkCHR, chkWCHR, chkBYTE};
31
 
32
 
33
TYPE
34
 
35
    isXXX = PROCEDURE (e: PARS.EXPR): BOOLEAN;
36
 
37
    RANGE = RECORD
38
 
39
        a, b: INTEGER
40
 
41
    END;
42
 
43
    CASE_LABEL = POINTER TO rCASE_LABEL;
44
 
45
    rCASE_LABEL = RECORD (AVL.DATA)
46
 
47
        range: RANGE;
48
 
49
        variant, self: INTEGER;
50
 
51
        type: PROG.TYPE_;
52
 
53
        prev: CASE_LABEL
54
 
55
    END;
56
 
57
    CASE_VARIANT = POINTER TO RECORD (LISTS.ITEM)
58
 
59
        label:      INTEGER;
60
        cmd:        CODE.COMMAND;
61
        processed:  BOOLEAN
62
 
63
    END;
64
 
65
 
66
VAR
67
 
68
    begcall, endcall: CODE.COMMAND;
69
 
70
    checking: SET;
71
 
72
    CaseLabels, CaseVar: C.COLLECTION;
73
 
74
    CaseVariants: LISTS.LIST;
75
 
76
 
77
PROCEDURE isExpr (e: PARS.EXPR): BOOLEAN;
78
    RETURN e.obj IN {eCONST, eVAR, eEXPR, eVPAR, ePARAM, eVREC}
79
END isExpr;
80
 
81
 
82
PROCEDURE isVar (e: PARS.EXPR): BOOLEAN;
83
    RETURN e.obj IN {eVAR, eVPAR, ePARAM, eVREC}
84
END isVar;
85
 
86
 
87
PROCEDURE isBoolean (e: PARS.EXPR): BOOLEAN;
88
    RETURN isExpr(e) & (e.type.typ = PROG.tBOOLEAN)
89
END isBoolean;
90
 
91
 
92
PROCEDURE isInteger (e: PARS.EXPR): BOOLEAN;
93
    RETURN isExpr(e) & (e.type.typ = PROG.tINTEGER)
94
END isInteger;
95
 
96
 
97
PROCEDURE isByte (e: PARS.EXPR): BOOLEAN;
98
    RETURN isExpr(e) & (e.type.typ = PROG.tBYTE)
99
END isByte;
100
 
101
 
102
PROCEDURE isInt (e: PARS.EXPR): BOOLEAN;
103
    RETURN isByte(e) OR isInteger(e)
104
END isInt;
105
 
106
 
107
PROCEDURE isReal (e: PARS.EXPR): BOOLEAN;
108
    RETURN isExpr(e) & (e.type.typ = PROG.tREAL)
109
END isReal;
110
 
111
 
112
PROCEDURE isSet (e: PARS.EXPR): BOOLEAN;
113
    RETURN isExpr(e) & (e.type.typ = PROG.tSET)
114
END isSet;
115
 
116
 
117
PROCEDURE isString (e: PARS.EXPR): BOOLEAN;
118
    RETURN (e.obj = eCONST) & (e.type.typ IN {PROG.tSTRING, PROG.tCHAR})
119
END isString;
120
 
121
 
122
PROCEDURE isStringW (e: PARS.EXPR): BOOLEAN;
123
    RETURN (e.obj = eCONST) & (e.type.typ IN {PROG.tSTRING, PROG.tCHAR, PROG.tWCHAR})
124
END isStringW;
125
 
126
 
127
PROCEDURE isChar (e: PARS.EXPR): BOOLEAN;
128
    RETURN isExpr(e) & (e.type.typ = PROG.tCHAR)
129
END isChar;
130
 
131
 
132
PROCEDURE isCharArray (e: PARS.EXPR): BOOLEAN;
133
    RETURN isExpr(e) & (e.type.typ = PROG.tARRAY) & (e.type.base.typ = PROG.tCHAR)
134
END isCharArray;
135
 
136
 
137
PROCEDURE isCharW (e: PARS.EXPR): BOOLEAN;
138
    RETURN isExpr(e) & (e.type.typ = PROG.tWCHAR)
139
END isCharW;
140
 
141
 
142
PROCEDURE isCharArrayW (e: PARS.EXPR): BOOLEAN;
143
    RETURN isExpr(e) & (e.type.typ = PROG.tARRAY) & (e.type.base.typ = PROG.tWCHAR)
144
END isCharArrayW;
145
 
146
 
147
PROCEDURE isCharArrayX (e: PARS.EXPR): BOOLEAN;
148
    RETURN isExpr(e) & (e.type.typ = PROG.tARRAY) & (e.type.base.typ IN {PROG.tCHAR, PROG.tWCHAR})
149
END isCharArrayX;
150
 
151
 
152
PROCEDURE isPtr (e: PARS.EXPR): BOOLEAN;
153
    RETURN isExpr(e) & (e.type.typ = PROG.tPOINTER)
154
END isPtr;
155
 
156
 
157
PROCEDURE isRec (e: PARS.EXPR): BOOLEAN;
158
    RETURN isExpr(e) & (e.type.typ = PROG.tRECORD)
159
END isRec;
160
 
161
 
162
PROCEDURE isArr (e: PARS.EXPR): BOOLEAN;
163
    RETURN isExpr(e) & (e.type.typ = PROG.tARRAY)
164
END isArr;
165
 
166
 
167
PROCEDURE isProc (e: PARS.EXPR): BOOLEAN;
168
    RETURN isExpr(e) & (e.type.typ = PROG.tPROCEDURE) OR (e.obj IN {ePROC, eIMP})
169
END isProc;
170
 
171
 
172
PROCEDURE isNil (e: PARS.EXPR): BOOLEAN;
173
    RETURN e.type.typ = PROG.tNIL
174
END isNil;
175
 
176
 
177
PROCEDURE getpos (parser: PARS.PARSER; VAR pos: SCAN.POSITION);
178
BEGIN
179
    pos := parser.lex.pos
180
END getpos;
181
 
182
 
183
PROCEDURE NextPos (parser: PARS.PARSER; VAR pos: SCAN.POSITION);
184
BEGIN
185
    PARS.NextPos(parser, pos)
186
END NextPos;
187
 
188
 
189
PROCEDURE strlen (e: PARS.EXPR): INTEGER;
190
VAR
191
    res: INTEGER;
192
 
193
BEGIN
194
    ASSERT(isString(e));
195
    IF e.type.typ = PROG.tCHAR THEN
196
        res := 1
197
    ELSE
198
        res := LENGTH(e.value.string(SCAN.IDENT).s)
199
    END
200
    RETURN res
201
END strlen;
202
 
203
 
204
PROCEDURE _length (s: ARRAY OF CHAR): INTEGER;
205
VAR
206
    i, res: INTEGER;
207
 
208
BEGIN
209
    i := 0;
210
    res := 0;
211
    WHILE (i < LEN(s)) & (s[i] # 0X) DO
212
        IF (s[i] <= CHR(127)) OR (s[i] >= CHR(192)) THEN
213
            INC(res)
214
        END;
215
        INC(i)
216
    END
217
 
218
    RETURN res
219
END _length;
220
 
221
 
222
PROCEDURE utf8strlen (e: PARS.EXPR): INTEGER;
223
VAR
224
    res: INTEGER;
225
 
226
BEGIN
227
    ASSERT(isStringW(e));
228
    IF e.type.typ IN {PROG.tCHAR, PROG.tWCHAR} THEN
229
        res := 1
230
    ELSE
231
        res := _length(e.value.string(SCAN.IDENT).s)
232
    END
233
    RETURN res
234
END utf8strlen;
235
 
236
 
237
PROCEDURE StrToWChar (s: ARRAY OF CHAR): INTEGER;
238
VAR
239
    res: ARRAY 2 OF WCHAR;
240
 
241
BEGIN
242
    ASSERT(STRINGS.Utf8To16(s, res) = 1)
243
    RETURN ORD(res[0])
244
END StrToWChar;
245
 
246
 
247
PROCEDURE isStringW1 (e: PARS.EXPR): BOOLEAN;
248
    RETURN (e.obj = eCONST) & isString(e) & (utf8strlen(e) = 1) & (strlen(e) > 1)
249
END isStringW1;
250
 
251
 
252
PROCEDURE assigncomp (e: PARS.EXPR; t: PROG.TYPE_): BOOLEAN;
253
VAR
254
    res: BOOLEAN;
255
 
256
 
257
    PROCEDURE arrcomp (src, dst: PROG.TYPE_): BOOLEAN;
258
        RETURN (dst.typ = PROG.tARRAY) & PROG.isOpenArray(src) &
259
                ~PROG.isOpenArray(src.base) & ~PROG.isOpenArray(dst.base) &
260
                PROG.isTypeEq(src.base, dst.base)
261
    END arrcomp;
262
 
263
 
264
BEGIN
265
    IF isExpr(e) OR (e.obj IN {ePROC, eIMP}) THEN
266
        IF arrcomp(e.type, t) THEN
267
            res := TRUE
268
        ELSIF isInt(e) & (t.typ IN {PROG.tBYTE, PROG.tINTEGER}) THEN
269
            IF (e.obj = eCONST) & (t.typ = PROG.tBYTE) THEN
270
                res := ARITH.range(e.value, 0, 255)
271
            ELSE
272
                res := TRUE
273
            END
274
        ELSIF isSet(e) & (t.typ = PROG.tSET) THEN
275
            res := TRUE
276
        ELSIF isBoolean(e) & (t.typ = PROG.tBOOLEAN) THEN
277
            res := TRUE
278
        ELSIF isReal(e) & (t.typ = PROG.tREAL) THEN
279
            res := TRUE
280
        ELSIF isChar(e) & (t.typ = PROG.tCHAR) THEN
281
            res := TRUE
282
        ELSIF (e.obj = eCONST) & isChar(e) & (t.typ = PROG.tWCHAR) THEN
283
            res := TRUE
284
        ELSIF isStringW1(e) & (t.typ = PROG.tWCHAR) THEN
285
            res := TRUE
286
        ELSIF isCharW(e) & (t.typ = PROG.tWCHAR) THEN
287
            res := TRUE
288
        ELSIF PROG.isBaseOf(t, e.type) THEN
289
            res := TRUE
290
        ELSIF ~PROG.isOpenArray(t) & ~PROG.isOpenArray(e.type) & PROG.isTypeEq(t, e.type) THEN
291
            res := TRUE
292
        ELSIF isNil(e) & (t.typ IN {PROG.tPOINTER, PROG.tPROCEDURE}) THEN
293
            res := TRUE
294
        ELSIF isString(e) & ((t.typ = PROG.tARRAY) & (t.base.typ = PROG.tCHAR) & (t.length > strlen(e))) THEN
295
            res := TRUE
296
        ELSIF isStringW(e) & ((t.typ = PROG.tARRAY) & (t.base.typ = PROG.tWCHAR) & (t.length > utf8strlen(e))) THEN
297
            res := TRUE
298
        ELSE
299
            res := FALSE
300
        END
301
    ELSE
302
        res := FALSE
303
    END
304
    RETURN res
305
END assigncomp;
306
 
307
 
308
PROCEDURE String (e: PARS.EXPR): INTEGER;
309
VAR
310
    offset: INTEGER;
311
    string: SCAN.IDENT;
312
 
313
BEGIN
314
    IF strlen(e) # 1 THEN
315
        string := e.value.string(SCAN.IDENT);
316
        IF string.offset = -1 THEN
317
            string.offset := CODE.putstr(string.s);
318
        END;
319
        offset := string.offset
320
    ELSE
321
        offset := CODE.putstr1(ARITH.Int(e.value))
322
    END
323
 
324
    RETURN offset
325
END String;
326
 
327
 
328
PROCEDURE StringW (e: PARS.EXPR): INTEGER;
329
VAR
330
    offset: INTEGER;
331
    string: SCAN.IDENT;
332
 
333
BEGIN
334
    IF utf8strlen(e) # 1 THEN
335
        string := e.value.string(SCAN.IDENT);
336
        IF string.offsetW = -1 THEN
337
            string.offsetW := CODE.putstrW(string.s);
338
        END;
339
        offset := string.offsetW
340
    ELSE
341
        IF e.type.typ IN {PROG.tWCHAR, PROG.tCHAR} THEN
342
            offset := CODE.putstrW1(ARITH.Int(e.value))
343
        ELSE (* e.type.typ = PROG.tSTRING *)
344
            string := e.value.string(SCAN.IDENT);
345
            IF string.offsetW = -1 THEN
346
                string.offsetW := CODE.putstrW(string.s);
347
            END;
348
            offset := string.offsetW
349
        END
350
    END
351
 
352
    RETURN offset
353
END StringW;
354
 
355
 
356
PROCEDURE CheckRange (range, line, errno: INTEGER);
357
VAR
358
    label: INTEGER;
359
 
360
BEGIN
361
    label := CODE.NewLabel();
362
    CODE.AddCmd2(CODE.opCHKIDX, label, range);
363
    CODE.OnError(line, errno);
364
    CODE.SetLabel(label)
365
END CheckRange;
366
 
367
 
368
PROCEDURE assign (e: PARS.EXPR; VarType: PROG.TYPE_; line: INTEGER): BOOLEAN;
369
VAR
370
    res:    BOOLEAN;
371
    label:  INTEGER;
372
 
373
 
374
    PROCEDURE arrcomp (src, dst: PROG.TYPE_): BOOLEAN;
375
        RETURN (dst.typ = PROG.tARRAY) & PROG.isOpenArray(src) &
376
                ~PROG.isOpenArray(src.base) & ~PROG.isOpenArray(dst.base) &
377
                PROG.isTypeEq(src.base, dst.base)
378
    END arrcomp;
379
 
380
 
381
BEGIN
382
    IF isExpr(e) OR (e.obj IN {ePROC, eIMP}) THEN
383
        res := TRUE;
384
        IF arrcomp(e.type, VarType) THEN
385
 
386
            IF ~PROG.isOpenArray(VarType) THEN
387
                CODE.AddCmd(CODE.opCONST, VarType.length)
388
            END;
389
            CODE.AddCmd(CODE.opCOPYA, VarType.base.size);
390
            label := CODE.NewLabel();
391
            CODE.AddJmpCmd(CODE.opJE, label);
392
            CODE.OnError(line, errCOPY);
393
            CODE.SetLabel(label)
394
 
395
        ELSIF isInt(e) & (VarType.typ IN {PROG.tBYTE, PROG.tINTEGER}) THEN
396
            IF VarType.typ = PROG.tINTEGER THEN
397
                IF e.obj = eCONST THEN
398
                    CODE.AddCmd(CODE.opSAVEC, ARITH.Int(e.value))
399
                ELSE
400
                    CODE.AddCmd0(CODE.opSAVE)
401
                END
402
            ELSE
403
                IF e.obj = eCONST THEN
404
                    res := ARITH.range(e.value, 0, 255);
405
                    IF res THEN
406
                        CODE.AddCmd(CODE.opSAVE8C, ARITH.Int(e.value))
407
                    END
408
                ELSE
409
                    IF chkBYTE IN checking THEN
410
                        label := CODE.NewLabel();
411
                        CODE.AddCmd2(CODE.opCHKBYTE, label, 0);
412
                        CODE.OnError(line, errBYTE);
413
                        CODE.SetLabel(label)
414
                    END;
415
                    CODE.AddCmd0(CODE.opSAVE8)
416
                END
417
            END
418
        ELSIF isSet(e) & (VarType.typ = PROG.tSET) THEN
419
            IF e.obj = eCONST THEN
420
                CODE.AddCmd(CODE.opSAVEC, ARITH.Int(e.value))
421
            ELSE
422
                CODE.AddCmd0(CODE.opSAVE)
423
            END
424
        ELSIF isBoolean(e) & (VarType.typ = PROG.tBOOLEAN) THEN
425
            IF e.obj = eCONST THEN
426
                CODE.AddCmd(CODE.opSBOOLC, ARITH.Int(e.value))
427
            ELSE
428
                CODE.AddCmd0(CODE.opSBOOL)
429
            END
430
        ELSIF isReal(e) & (VarType.typ = PROG.tREAL) THEN
431
            IF e.obj = eCONST THEN
432
                CODE.Float(ARITH.Float(e.value))
433
            END;
434
            CODE.savef
435
        ELSIF isChar(e) & (VarType.typ = PROG.tCHAR) THEN
436
            IF e.obj = eCONST THEN
437
                CODE.AddCmd(CODE.opSAVE8C, ARITH.Int(e.value))
438
            ELSE
439
                CODE.AddCmd0(CODE.opSAVE8)
440
            END
441
        ELSIF (e.obj = eCONST) & isChar(e) & (VarType.typ = PROG.tWCHAR) THEN
442
            CODE.AddCmd(CODE.opSAVE16C, ARITH.Int(e.value))
443
        ELSIF isStringW1(e) & (VarType.typ = PROG.tWCHAR) THEN
444
            CODE.AddCmd(CODE.opSAVE16C, StrToWChar(e.value.string(SCAN.IDENT).s))
445
        ELSIF isCharW(e) & (VarType.typ = PROG.tWCHAR) THEN
446
            IF e.obj = eCONST THEN
447
                CODE.AddCmd(CODE.opSAVE16C, ARITH.Int(e.value))
448
            ELSE
449
                CODE.AddCmd0(CODE.opSAVE16)
450
            END
451
        ELSIF PROG.isBaseOf(VarType, e.type) THEN
452
            IF VarType.typ = PROG.tPOINTER THEN
453
                CODE.AddCmd0(CODE.opSAVE)
454
            ELSE
455
                CODE.AddCmd(CODE.opCOPY, VarType.size)
456
            END
457
        ELSIF (e.type.typ = PROG.tCARD32) & (VarType.typ = PROG.tCARD32) THEN
458
            CODE.AddCmd0(CODE.opSAVE32)
459
        ELSIF (e.type.typ = PROG.tCARD16) & (VarType.typ = PROG.tCARD16) THEN
460
            CODE.AddCmd0(CODE.opSAVE16)
461
        ELSIF ~PROG.isOpenArray(VarType) & ~PROG.isOpenArray(e.type) & PROG.isTypeEq(VarType, e.type) THEN
462
            IF e.obj = ePROC THEN
463
                CODE.AssignProc(e.ident.proc.label)
464
            ELSIF e.obj = eIMP THEN
465
                CODE.AssignImpProc(e.ident.import)
466
            ELSE
467
                IF VarType.typ = PROG.tPROCEDURE THEN
468
                    CODE.AddCmd0(CODE.opSAVE)
469
                ELSE
470
                    CODE.AddCmd(CODE.opCOPY, VarType.size)
471
                END
472
            END
473
        ELSIF isNil(e) & (VarType.typ IN {PROG.tPOINTER, PROG.tPROCEDURE}) THEN
474
            CODE.AddCmd(CODE.opSAVEC, 0)
475
        ELSIF isString(e) & ((VarType.typ = PROG.tARRAY) & (VarType.base.typ = PROG.tCHAR) & (VarType.length > strlen(e))) THEN
476
            CODE.saves(String(e), strlen(e) + 1)
477
        ELSIF isStringW(e) & ((VarType.typ = PROG.tARRAY) & (VarType.base.typ = PROG.tWCHAR) & (VarType.length > utf8strlen(e))) THEN
478
            CODE.saves(StringW(e), (utf8strlen(e) + 1) * 2)
479
        ELSE
480
            res := FALSE
481
        END
482
    ELSE
483
        res := FALSE
484
    END
485
    RETURN res
486
END assign;
487
 
488
 
489
PROCEDURE LoadConst (e: PARS.EXPR);
490
BEGIN
491
    CODE.AddCmd(CODE.opCONST, ARITH.Int(e.value))
492
END LoadConst;
493
 
494
 
495
PROCEDURE paramcomp (parser: PARS.PARSER; pos: SCAN.POSITION; e: PARS.EXPR; p: PROG.PARAM);
496
 
497
    PROCEDURE arrcomp (e: PARS.EXPR; p: PROG.PARAM): BOOLEAN;
498
    VAR
499
        t1, t2: PROG.TYPE_;
500
 
501
    BEGIN
502
        t1 := p.type;
503
        t2 := e.type;
504
        WHILE (t2.typ = PROG.tARRAY) & PROG.isOpenArray(t1) DO
505
            t1 := t1.base;
506
            t2 := t2.base
507
        END
508
 
509
        RETURN PROG.isTypeEq(t1, t2)
510
    END arrcomp;
511
 
512
 
513
    PROCEDURE ArrLen (t: PROG.TYPE_; n: INTEGER): INTEGER;
514
    VAR
515
        res: INTEGER;
516
    BEGIN
517
        REPEAT
518
            res := t.length;
519
            t := t.base;
520
            DEC(n)
521
        UNTIL (n < 0) OR (t.typ # PROG.tARRAY);
522
        ASSERT(n < 0)
523
        RETURN res
524
    END ArrLen;
525
 
526
 
527
    PROCEDURE OpenArray (t, t2: PROG.TYPE_);
528
    VAR
529
        n: INTEGER;
530
        d1, d2: INTEGER;
531
    BEGIN
532
        IF t.length # 0 THEN
533
            CODE.AddCmd(CODE.opPARAM, 1);
534
            n := PROG.Dim(t2) - 1;
535
            WHILE n >= 0 DO
536
                CODE.AddCmd(CODE.opCONST, ArrLen(t, n));
537
                CODE.AddCmd(CODE.opPARAM, 1);
538
                DEC(n)
539
            END
540
        ELSE
541
            d1 := PROG.Dim(t);
542
            d2 := PROG.Dim(t2);
543
            IF d1 # d2 THEN
544
                n := d2 - d1;
545
                WHILE d2 > d1 DO
546
                    CODE.AddCmd(CODE.opCONST, ArrLen(t, d2 - 1));
547
                    DEC(d2)
548
                END;
549
                d2 := PROG.Dim(t2);
550
                WHILE n > 0 DO
551
                    CODE.AddCmd(CODE.opROT, d2);
552
                    DEC(n)
553
                END
554
            END;
555
            CODE.AddCmd(CODE.opPARAM, PROG.Dim(t2) + 1)
556
        END
557
    END OpenArray;
558
 
559
 
560
BEGIN
561
    IF p.vPar THEN
562
 
563
        PARS.check(isVar(e), parser, pos, 93);
564
        IF p.type.typ = PROG.tRECORD THEN
565
            PARS.check(PROG.isBaseOf(p.type, e.type), parser, pos, 66);
566
            IF e.obj = eVREC THEN
567
                IF e.ident # NIL THEN
568
                    CODE.AddCmd(CODE.opVADR, e.ident.offset - 1)
569
                ELSE
570
                    CODE.AddCmd0(CODE.opPUSHT)
571
                END
572
            ELSE
573
                CODE.AddCmd(CODE.opCONST, e.type.num)
574
            END;
575
            CODE.AddCmd(CODE.opPARAM, 2)
576
        ELSIF PROG.isOpenArray(p.type) THEN
577
            PARS.check(arrcomp(e, p), parser, pos, 66);
578
            OpenArray(e.type, p.type)
579
        ELSE
580
            PARS.check(PROG.isTypeEq(e.type, p.type), parser, pos, 66);
581
            CODE.AddCmd(CODE.opPARAM, 1)
582
        END;
583
        PARS.check(~e.readOnly, parser, pos, 94)
584
 
585
    ELSE
586
        PARS.check(isExpr(e) OR isProc(e), parser, pos, 66);
587
        IF PROG.isOpenArray(p.type) THEN
588
            IF e.type.typ = PROG.tARRAY THEN
589
                PARS.check(arrcomp(e, p), parser, pos, 66);
590
                OpenArray(e.type, p.type)
591
            ELSIF isString(e) & (p.type.typ = PROG.tARRAY) & (p.type.base.typ = PROG.tCHAR) THEN
592
                CODE.AddCmd(CODE.opSADR, String(e));
593
                CODE.AddCmd(CODE.opPARAM, 1);
594
                CODE.AddCmd(CODE.opCONST, strlen(e) + 1);
595
                CODE.AddCmd(CODE.opPARAM, 1)
596
            ELSIF isStringW(e) & (p.type.typ = PROG.tARRAY) & (p.type.base.typ = PROG.tWCHAR) THEN
597
                CODE.AddCmd(CODE.opSADR, StringW(e));
598
                CODE.AddCmd(CODE.opPARAM, 1);
599
                CODE.AddCmd(CODE.opCONST, utf8strlen(e) + 1);
600
                CODE.AddCmd(CODE.opPARAM, 1)
601
            ELSE
602
                PARS.error(parser, pos, 66)
603
            END
604
        ELSE
605
            PARS.check(~PROG.isOpenArray(e.type), parser, pos, 66);
606
            PARS.check(assigncomp(e, p.type), parser, pos, 66);
607
            IF e.obj = eCONST THEN
608
                IF e.type.typ = PROG.tREAL THEN
609
                    CODE.Float(ARITH.Float(e.value));
610
                    CODE.pushf
611
                ELSIF e.type.typ = PROG.tNIL THEN
612
                    CODE.AddCmd(CODE.opCONST, 0);
613
                    CODE.AddCmd(CODE.opPARAM, 1)
614
                ELSIF isStringW1(e) & (p.type.typ = PROG.tWCHAR) THEN
615
                    CODE.AddCmd(CODE.opCONST, StrToWChar(e.value.string(SCAN.IDENT).s));
616
                    CODE.AddCmd(CODE.opPARAM, 1)
617
                ELSIF (e.type.typ = PROG.tSTRING) OR
618
                      (e.type.typ IN {PROG.tCHAR, PROG.tWCHAR}) & (p.type.typ = PROG.tARRAY) & (p.type.base.typ IN {PROG.tCHAR, PROG.tWCHAR}) THEN
619
                    CODE.SetMinDataSize(p.type.size);
620
                    IF p.type.base.typ = PROG.tCHAR THEN
621
                        CODE.AddCmd(CODE.opSADR, String(e))
622
                    ELSE (* WCHAR *)
623
                        CODE.AddCmd(CODE.opSADR, StringW(e))
624
                    END;
625
                    CODE.AddCmd(CODE.opPARAM, 1)
626
                ELSE
627
                    LoadConst(e);
628
                    CODE.AddCmd(CODE.opPARAM, 1)
629
                END
630
            ELSIF e.obj = ePROC THEN
631
                PARS.check(e.ident.global, parser, pos, 85);
632
                CODE.PushProc(e.ident.proc.label);
633
                CODE.AddCmd(CODE.opPARAM, 1)
634
            ELSIF e.obj = eIMP THEN
635
                CODE.PushImpProc(e.ident.import);
636
                CODE.AddCmd(CODE.opPARAM, 1)
637
            ELSIF isExpr(e) & (e.type.typ = PROG.tREAL) THEN
638
                CODE.pushf
639
            ELSE
640
                IF (p.type.typ = PROG.tBYTE) & (e.type.typ = PROG.tINTEGER) & (chkBYTE IN checking) THEN
641
                    CheckRange(256, pos.line, errBYTE)
642
                END;
643
                CODE.AddCmd(CODE.opPARAM, 1)
644
            END
645
        END
646
 
647
    END
648
END paramcomp;
649
 
650
 
651
PROCEDURE stProc (parser: PARS.PARSER; VAR e: PARS.EXPR);
652
VAR
653
    e2:    PARS.EXPR;
654
    pos:   SCAN.POSITION;
655
    proc:  INTEGER;
656
    label: INTEGER;
657
    n, i:  INTEGER;
658
    code:  ARITH.VALUE;
659
    e1:    PARS.EXPR;
660
    wchar: BOOLEAN;
661
    cmd1,
662
    cmd2:  CODE.COMMAND;
663
 
664
 
665
    PROCEDURE varparam (parser: PARS.PARSER; pos: SCAN.POSITION; isfunc: isXXX; readOnly: BOOLEAN; VAR e: PARS.EXPR);
666
    BEGIN
667
        parser.designator(parser, e);
668
        PARS.check(isVar(e), parser, pos, 93);
669
        PARS.check(isfunc(e), parser, pos, 66);
670
        IF readOnly THEN
671
            PARS.check(~e.readOnly, parser, pos, 94)
672
        END
673
    END varparam;
674
 
675
 
676
    PROCEDURE shift_minmax (proc: INTEGER): CHAR;
677
    VAR
678
        res: CHAR;
679
    BEGIN
680
        CASE proc OF
681
        |PROG.stASR: res := "A"
682
        |PROG.stLSL: res := "L"
683
        |PROG.stROR: res := "O"
684
        |PROG.stLSR: res := "R"
685
        |PROG.stMIN: res := "m"
686
        |PROG.stMAX: res := "x"
687
        END
688
        RETURN res
689
    END shift_minmax;
690
 
691
 
692
BEGIN
693
    ASSERT(e.obj IN {eSTPROC, eSTFUNC, eSYSPROC, eSYSFUNC});
694
 
695
    getpos(parser, pos);
696
    proc := e.stproc;
697
 
698
    IF e.obj IN {eSYSPROC, eSYSFUNC} THEN
699
        IF parser.unit.scopeLvl > 0 THEN
700
            parser.unit.scopes[parser.unit.scopeLvl].enter(CODE.COMMAND).allocReg := FALSE
701
        END
702
    END;
703
 
704
    IF e.obj IN {eSTPROC, eSYSPROC} THEN
705
 
706
        CASE proc OF
707
        |PROG.stASSERT:
708
            parser.expression(parser, e);
709
            PARS.check(isBoolean(e), parser, pos, 66);
710
            IF e.obj = eCONST THEN
711
                IF ~ARITH.getBool(e.value) THEN
712
                    CODE.OnError(pos.line, errASSERT)
713
                END
714
            ELSE
715
                label := CODE.NewLabel();
716
                CODE.AddJmpCmd(CODE.opJE, label);
717
                CODE.OnError(pos.line, errASSERT);
718
                CODE.SetLabel(label)
719
            END
720
 
721
        |PROG.stINC, PROG.stDEC:
722
            CODE.pushBegEnd(begcall, endcall);
723
            varparam(parser, pos, isInt, TRUE, e);
724
            IF e.type.typ = PROG.tINTEGER THEN
725
                IF parser.sym = SCAN.lxCOMMA THEN
726
                    NextPos(parser, pos);
727
                    CODE.setlast(begcall);
728
                    parser.expression(parser, e2);
729
                    CODE.setlast(endcall.prev(CODE.COMMAND));
730
                    PARS.check(isInt(e2), parser, pos, 66);
731
                    IF e2.obj = eCONST THEN
732
                        CODE.AddCmd(CODE.opINCC + ORD(proc = PROG.stDEC), ARITH.Int(e2.value))
733
                    ELSE
734
                        CODE.AddCmd0(CODE.opINC + ORD(proc = PROG.stDEC))
735
                    END
736
                ELSE
737
                    CODE.AddCmd0(CODE.opINC1 + ORD(proc = PROG.stDEC))
738
                END
739
            ELSE  (* e.type.typ = PROG.tBYTE *)
740
                IF parser.sym = SCAN.lxCOMMA THEN
741
                    NextPos(parser, pos);
742
                    CODE.setlast(begcall);
743
                    parser.expression(parser, e2);
744
                    CODE.setlast(endcall.prev(CODE.COMMAND));
745
                    PARS.check(isInt(e2), parser, pos, 66);
746
                    IF e2.obj = eCONST THEN
747
                        CODE.AddCmd(CODE.opINCCB + ORD(proc = PROG.stDEC), ARITH.Int(e2.value))
748
                    ELSE
749
                        CODE.AddCmd0(CODE.opINCB + ORD(proc = PROG.stDEC))
750
                    END
751
                ELSE
752
                    CODE.AddCmd0(CODE.opINC1B + ORD(proc = PROG.stDEC))
753
                END
754
            END;
755
            CODE.popBegEnd(begcall, endcall)
756
 
757
        |PROG.stINCL, PROG.stEXCL:
758
            CODE.pushBegEnd(begcall, endcall);
759
            varparam(parser, pos, isSet, TRUE, e);
760
            PARS.checklex(parser, SCAN.lxCOMMA);
761
            NextPos(parser, pos);
762
            CODE.setlast(begcall);
763
            parser.expression(parser, e2);
764
            CODE.setlast(endcall.prev(CODE.COMMAND));
765
            PARS.check(isInt(e2), parser, pos, 66);
766
            IF e2.obj = eCONST THEN
767
                PARS.check(ARITH.range(e2.value, 0, MACHINE.target.maxSet), parser, pos, 56);
768
                CODE.AddCmd(CODE.opINCLC + ORD(proc = PROG.stEXCL), ARITH.Int(e2.value))
769
            ELSE
770
                CODE.AddCmd0(CODE.opINCL + ORD(proc = PROG.stEXCL))
771
            END;
772
            CODE.popBegEnd(begcall, endcall)
773
 
774
        |PROG.stNEW:
775
            varparam(parser, pos, isPtr, TRUE, e);
776
            CODE.New(e.type.base.size, e.type.base.num)
777
 
778
        |PROG.stDISPOSE:
779
            varparam(parser, pos, isPtr, TRUE, e);
780
            CODE.AddCmd0(CODE.opDISP)
781
 
782
        |PROG.stPACK:
783
            varparam(parser, pos, isReal, TRUE, e);
784
            PARS.checklex(parser, SCAN.lxCOMMA);
785
            NextPos(parser, pos);
786
            parser.expression(parser, e2);
787
            PARS.check(isInt(e2), parser, pos, 66);
788
            IF e2.obj = eCONST THEN
789
                CODE.AddCmd(CODE.opPACKC, ARITH.Int(e2.value))
790
            ELSE
791
                CODE.AddCmd0(CODE.opPACK)
792
            END
793
 
794
        |PROG.stUNPK:
795
            varparam(parser, pos, isReal, TRUE, e);
796
            PARS.checklex(parser, SCAN.lxCOMMA);
797
            NextPos(parser, pos);
798
            varparam(parser, pos, isInteger, TRUE, e2);
799
            CODE.AddCmd0(CODE.opUNPK)
800
 
801
        |PROG.stCOPY:
802
            parser.expression(parser, e);
803
            IF isString(e) OR isCharArray(e) THEN
804
                wchar := FALSE
805
            ELSIF isStringW(e) OR isCharArrayW(e) THEN
806
                wchar := TRUE
807
            ELSE
808
                PARS.check(FALSE, parser, pos, 66)
809
            END;
810
 
811
            IF isCharArrayX(e) & ~PROG.isOpenArray(e.type) THEN
812
                CODE.AddCmd(CODE.opCONST, e.type.length)
813
            END;
814
 
815
            PARS.checklex(parser, SCAN.lxCOMMA);
816
            NextPos(parser, pos);
817
 
818
            IF wchar THEN
819
                varparam(parser, pos, isCharArrayW, TRUE, e1)
820
            ELSE
821
                IF e.obj = eCONST THEN
822
                    varparam(parser, pos, isCharArrayX, TRUE, e1)
823
                ELSE
824
                    varparam(parser, pos, isCharArray, TRUE, e1)
825
                END;
826
 
827
                wchar := e1.type.base.typ = PROG.tWCHAR
828
            END;
829
 
830
            IF ~PROG.isOpenArray(e1.type) THEN
831
                CODE.AddCmd(CODE.opCONST, e1.type.length)
832
            END;
833
 
834
            IF e.obj = eCONST THEN
835
                IF wchar THEN
836
                    CODE.AddCmd(CODE.opSADR, StringW(e));
837
                    CODE.AddCmd(CODE.opCONST, utf8strlen(e) + 1)
838
                ELSE
839
                    CODE.AddCmd(CODE.opSADR, String(e));
840
                    CODE.AddCmd(CODE.opCONST, strlen(e) + 1)
841
                END;
842
                CODE.AddCmd(CODE.opCOPYS2, e1.type.base.size)
843
            ELSE
844
                CODE.AddCmd(CODE.opCOPYS, e1.type.base.size)
845
            END
846
 
847
        |PROG.sysGET:
848
            parser.expression(parser, e);
849
            PARS.check(isInt(e), parser, pos, 66);
850
            IF e.obj = eCONST THEN
851
                LoadConst(e)
852
            END;
853
            PARS.checklex(parser, SCAN.lxCOMMA);
854
            NextPos(parser, pos);
855
            parser.designator(parser, e2);
856
            PARS.check(isVar(e2), parser, pos, 93);
857
            PARS.check((e2.type.typ IN PROG.BASICTYPES) OR (e2.type.typ = PROG.tPOINTER) OR (e2.type.typ = PROG.tPROCEDURE), parser, pos, 66);
858
            CODE.SysGet(e2.type.size)
859
 
860
        |PROG.sysPUT, PROG.sysPUT8, PROG.sysPUT16, PROG.sysPUT32:
861
            CODE.pushBegEnd(begcall, endcall);
862
            parser.expression(parser, e);
863
            PARS.check(isInt(e), parser, pos, 66);
864
            IF e.obj = eCONST THEN
865
                LoadConst(e)
866
            END;
867
            PARS.checklex(parser, SCAN.lxCOMMA);
868
            NextPos(parser, pos);
869
            CODE.setlast(begcall);
870
            parser.expression(parser, e2);
871
            PARS.check(isExpr(e2), parser, pos, 66);
872
 
873
            IF proc = PROG.sysPUT THEN
874
                PARS.check((e2.type.typ IN PROG.BASICTYPES) OR (e2.type.typ = PROG.tPOINTER) OR (e2.type.typ = PROG.tPROCEDURE), parser, pos, 66);
875
                IF e2.obj = eCONST THEN
876
                    IF e2.type.typ = PROG.tREAL THEN
877
                        CODE.setlast(endcall.prev(CODE.COMMAND));
878
                        CODE.Float(ARITH.Float(e2.value));
879
                        CODE.savef
880
                    ELSE
881
                        LoadConst(e2);
882
                        CODE.setlast(endcall.prev(CODE.COMMAND));
883
                        CODE.SysPut(e2.type.size)
884
                    END
885
                ELSE
886
                    CODE.setlast(endcall.prev(CODE.COMMAND));
887
                    IF e2.type.typ = PROG.tREAL THEN
888
                        CODE.savef
889
                    ELSIF e2.type.typ = PROG.tBYTE THEN
890
                        CODE.SysPut(PARS.program.stTypes.tINTEGER.size)
891
                    ELSE
892
                        CODE.SysPut(e2.type.size)
893
                    END
894
                END
895
 
896
            ELSIF (proc = PROG.sysPUT8) OR (proc = PROG.sysPUT16) OR (proc = PROG.sysPUT32) THEN
897
                PARS.check(e2.type.typ IN {PROG.tINTEGER, PROG.tBYTE, PROG.tCHAR, PROG.tWCHAR, PROG.tCARD16, PROG.tCARD32}, parser, pos, 66);
898
                IF e2.obj = eCONST THEN
899
                    LoadConst(e2)
900
                END;
901
                CODE.setlast(endcall.prev(CODE.COMMAND));
902
                IF proc = PROG.sysPUT8 THEN
903
                    CODE.SysPut(1)
904
                ELSIF proc = PROG.sysPUT16 THEN
905
                    CODE.SysPut(2)
906
                ELSIF proc = PROG.sysPUT32 THEN
907
                    CODE.SysPut(4)
908
                END
909
 
910
            END;
911
            CODE.popBegEnd(begcall, endcall)
912
 
913
        |PROG.sysMOVE:
914
            FOR i := 1 TO 2 DO
915
                parser.expression(parser, e);
916
                PARS.check(isInt(e), parser, pos, 66);
917
                IF e.obj = eCONST THEN
918
                    LoadConst(e)
919
                END;
920
                PARS.checklex(parser, SCAN.lxCOMMA);
921
                NextPos(parser, pos)
922
            END;
923
 
924
            parser.expression(parser, e);
925
            PARS.check(isInt(e), parser, pos, 66);
926
            IF e.obj = eCONST THEN
927
                LoadConst(e)
928
            END;
929
            CODE.AddCmd0(CODE.opMOVE)
930
 
931
        |PROG.sysCOPY:
932
            FOR i := 1 TO 2 DO
933
                parser.designator(parser, e);
934
                PARS.check(isVar(e), parser, pos, 93);
935
                n := PROG.Dim(e.type);
936
                WHILE n > 0 DO
937
                    CODE.drop;
938
                    DEC(n)
939
                END;
940
                PARS.checklex(parser, SCAN.lxCOMMA);
941
                NextPos(parser, pos)
942
            END;
943
 
944
            parser.expression(parser, e);
945
            PARS.check(isInt(e), parser, pos, 66);
946
            IF e.obj = eCONST THEN
947
                LoadConst(e)
948
            END;
949
            CODE.AddCmd0(CODE.opMOVE)
950
 
951
        |PROG.sysCODE:
952
            REPEAT
953
                getpos(parser, pos);
954
                PARS.ConstExpression(parser, code);
955
                PARS.check(code.typ = ARITH.tINTEGER, parser, pos, 43);
956
                PARS.check(ARITH.range(code, 0, 255), parser, pos, 42);
957
                IF parser.sym = SCAN.lxCOMMA THEN
958
                    PARS.Next(parser)
959
                ELSE
960
                    PARS.checklex(parser, SCAN.lxRROUND)
961
                END;
962
                CODE.AddCmd(CODE.opCODE, ARITH.getInt(code))
963
            UNTIL parser.sym = SCAN.lxRROUND
964
 
965
        END;
966
 
967
        e.obj := eEXPR;
968
        e.type := NIL
969
 
970
    ELSIF e.obj IN {eSTFUNC, eSYSFUNC} THEN
971
 
972
        CASE e.stproc OF
973
        |PROG.stABS:
974
            parser.expression(parser, e);
975
            PARS.check(isInt(e) OR isReal(e), parser, pos, 66);
976
            IF e.obj = eCONST THEN
977
                PARS.check(ARITH.abs(e.value), parser, pos, 39)
978
            ELSE
979
                CODE.abs(isReal(e))
980
            END
981
 
982
        |PROG.stASR, PROG.stLSL, PROG.stROR, PROG.stLSR, PROG.stMIN, PROG.stMAX:
983
            parser.expression(parser, e);
984
            PARS.check(isInt(e), parser, pos, 66);
985
            PARS.checklex(parser, SCAN.lxCOMMA);
986
            NextPos(parser, pos);
987
            parser.expression(parser, e2);
988
            PARS.check(isInt(e2), parser, pos, 66);
989
            e.type := PARS.program.stTypes.tINTEGER;
990
            IF (e.obj = eCONST) & (e2.obj = eCONST) THEN
991
                ASSERT(ARITH.opInt(e.value, e2.value, shift_minmax(proc)))
992
            ELSE
993
                IF e.obj = eCONST THEN
994
                    CODE.shift_minmax1(shift_minmax(proc), ARITH.Int(e.value))
995
                ELSIF e2.obj = eCONST THEN
996
                    CODE.shift_minmax2(shift_minmax(proc), ARITH.Int(e2.value))
997
                ELSE
998
                    CODE.shift_minmax(shift_minmax(proc))
999
                END;
1000
                e.obj := eEXPR
1001
            END
1002
 
1003
        |PROG.stCHR:
1004
            parser.expression(parser, e);
1005
            PARS.check(isInt(e), parser, pos, 66);
1006
            e.type := PARS.program.stTypes.tCHAR;
1007
            IF e.obj = eCONST THEN
1008
                ARITH.setChar(e.value, ARITH.getInt(e.value));
1009
                PARS.check(ARITH.check(e.value), parser, pos, 107)
1010
            ELSE
1011
                IF chkCHR IN checking THEN
1012
                    CheckRange(256, pos.line, errCHR)
1013
                ELSE
1014
                    CODE.AddCmd0(CODE.opCHR)
1015
                END
1016
            END
1017
 
1018
        |PROG.stWCHR:
1019
            parser.expression(parser, e);
1020
            PARS.check(isInt(e), parser, pos, 66);
1021
            e.type := PARS.program.stTypes.tWCHAR;
1022
            IF e.obj = eCONST THEN
1023
                ARITH.setWChar(e.value, ARITH.getInt(e.value));
1024
                PARS.check(ARITH.check(e.value), parser, pos, 101)
1025
            ELSE
1026
                IF chkWCHR IN checking THEN
1027
                    CheckRange(65536, pos.line, errWCHR)
1028
                ELSE
1029
                    CODE.AddCmd0(CODE.opWCHR)
1030
                END
1031
            END
1032
 
1033
        |PROG.stFLOOR:
1034
            parser.expression(parser, e);
1035
            PARS.check(isReal(e), parser, pos, 66);
1036
            e.type := PARS.program.stTypes.tINTEGER;
1037
            IF e.obj = eCONST THEN
1038
                PARS.check(ARITH.floor(e.value), parser, pos, 39)
1039
            ELSE
1040
                CODE.floor
1041
            END
1042
 
1043
        |PROG.stFLT:
1044
            parser.expression(parser, e);
1045
            PARS.check(isInt(e), parser, pos, 66);
1046
            e.type := PARS.program.stTypes.tREAL;
1047
            IF e.obj = eCONST THEN
1048
                ARITH.flt(e.value)
1049
            ELSE
1050
                PARS.check(CODE.flt(), parser, pos, 41)
1051
            END
1052
 
1053
        |PROG.stLEN:
1054
            cmd1 := CODE.getlast();
1055
            varparam(parser, pos, isArr, FALSE, e);
1056
            IF e.type.length > 0 THEN
1057
                cmd2 := CODE.getlast();
1058
                CODE.delete2(cmd1.next, cmd2);
1059
                CODE.setlast(cmd1);
1060
                ASSERT(ARITH.setInt(e.value, e.type.length));
1061
                e.obj := eCONST
1062
            ELSE
1063
                CODE.len(PROG.Dim(e.type))
1064
            END;
1065
            e.type := PARS.program.stTypes.tINTEGER
1066
 
1067
        |PROG.stLENGTH:
1068
            parser.expression(parser, e);
1069
            IF isCharArray(e) THEN
1070
                IF e.type.length > 0 THEN
1071
                    CODE.AddCmd(CODE.opCONST, e.type.length)
1072
                END;
1073
                CODE.AddCmd0(CODE.opLENGTH)
1074
            ELSIF isCharArrayW(e) THEN
1075
                IF e.type.length > 0 THEN
1076
                    CODE.AddCmd(CODE.opCONST, e.type.length)
1077
                END;
1078
                CODE.AddCmd0(CODE.opLENGTHW)
1079
            ELSE
1080
                PARS.check(FALSE, parser, pos, 66);
1081
            END;
1082
            e.type := PARS.program.stTypes.tINTEGER
1083
 
1084
        |PROG.stODD:
1085
            parser.expression(parser, e);
1086
            PARS.check(isInt(e), parser, pos, 66);
1087
            e.type := PARS.program.stTypes.tBOOLEAN;
1088
            IF e.obj = eCONST THEN
1089
                ARITH.odd(e.value)
1090
            ELSE
1091
                CODE.odd
1092
            END
1093
 
1094
        |PROG.stORD:
1095
            parser.expression(parser, e);
1096
            PARS.check(isChar(e) OR isBoolean(e) OR isSet(e) OR isCharW(e) OR isStringW1(e), parser, pos, 66);
1097
            IF e.obj = eCONST THEN
1098
                IF isStringW1(e) THEN
1099
                    ASSERT(ARITH.setInt(e.value, StrToWChar(e.value.string(SCAN.IDENT).s)))
1100
                ELSE
1101
                    ARITH.ord(e.value)
1102
                END
1103
            ELSE
1104
                IF isBoolean(e) THEN
1105
                    CODE.ord
1106
                END
1107
            END;
1108
            e.type := PARS.program.stTypes.tINTEGER
1109
 
1110
        |PROG.stBITS:
1111
            parser.expression(parser, e);
1112
            PARS.check(isInt(e), parser, pos, 66);
1113
            IF e.obj = eCONST THEN
1114
                ARITH.bits(e.value)
1115
            END;
1116
            e.type := PARS.program.stTypes.tSET
1117
 
1118
        |PROG.sysADR:
1119
            parser.designator(parser, e);
1120
            IF isVar(e) THEN
1121
               n := PROG.Dim(e.type);
1122
               WHILE n > 0 DO
1123
                    CODE.drop;
1124
                    DEC(n)
1125
               END
1126
            ELSIF e.obj = ePROC THEN
1127
                CODE.PushProc(e.ident.proc.label)
1128
            ELSIF e.obj = eIMP THEN
1129
                CODE.PushImpProc(e.ident.import)
1130
            ELSE
1131
                PARS.check(FALSE, parser, pos, 108)
1132
            END;
1133
            e.type := PARS.program.stTypes.tINTEGER
1134
 
1135
        |PROG.sysSADR:
1136
            parser.expression(parser, e);
1137
            PARS.check(isString(e), parser, pos, 66);
1138
            CODE.AddCmd(CODE.opSADR, String(e));
1139
            e.type := PARS.program.stTypes.tINTEGER;
1140
            e.obj := eEXPR
1141
 
1142
        |PROG.sysWSADR:
1143
            parser.expression(parser, e);
1144
            PARS.check(isStringW(e), parser, pos, 66);
1145
            CODE.AddCmd(CODE.opSADR, StringW(e));
1146
            e.type := PARS.program.stTypes.tINTEGER;
1147
            e.obj := eEXPR
1148
 
1149
        |PROG.sysTYPEID:
1150
            parser.expression(parser, e);
1151
            PARS.check(e.obj = eTYPE, parser, pos, 68);
1152
            IF e.type.typ = PROG.tRECORD THEN
1153
                ASSERT(ARITH.setInt(e.value, e.type.num))
1154
            ELSIF e.type.typ = PROG.tPOINTER THEN
1155
                ASSERT(ARITH.setInt(e.value, e.type.base.num))
1156
            ELSE
1157
                PARS.check(FALSE, parser, pos, 52)
1158
            END;
1159
            e.obj := eCONST;
1160
            e.type := PARS.program.stTypes.tINTEGER
1161
 
1162
        |PROG.sysINF:
1163
            PARS.check(CODE.inf(), parser, pos, 41);
1164
            e.obj := eEXPR;
1165
            e.type := PARS.program.stTypes.tREAL
1166
 
1167
        |PROG.sysSIZE:
1168
            parser.expression(parser, e);
1169
            PARS.check(e.obj = eTYPE, parser, pos, 68);
1170
            ASSERT(ARITH.setInt(e.value, e.type.size));
1171
            e.obj := eCONST;
1172
            e.type := PARS.program.stTypes.tINTEGER
1173
 
1174
        END
1175
 
1176
    END;
1177
 
1178
    PARS.checklex(parser, SCAN.lxRROUND);
1179
    PARS.Next(parser);
1180
 
1181
    IF e.obj # eCONST THEN
1182
        e.obj := eEXPR
1183
    END
1184
 
1185
END stProc;
1186
 
1187
 
1188
PROCEDURE ActualParameters (parser: PARS.PARSER; VAR e: PARS.EXPR);
1189
VAR
1190
    proc:  PROG.TYPE_;
1191
    param: LISTS.ITEM;
1192
    e1:    PARS.EXPR;
1193
    pos:   SCAN.POSITION;
1194
 
1195
BEGIN
1196
    ASSERT(parser.sym = SCAN.lxLROUND);
1197
 
1198
    IF (e.obj IN {ePROC, eIMP}) OR isExpr(e) THEN
1199
        proc := e.type;
1200
        PARS.check1(proc.typ = PROG.tPROCEDURE, parser, 86);
1201
        PARS.Next(parser);
1202
 
1203
        param := proc.params.first;
1204
        WHILE param # NIL DO
1205
            getpos(parser, pos);
1206
 
1207
            CODE.setlast(begcall);
1208
 
1209
            IF param(PROG.PARAM).vPar THEN
1210
                parser.designator(parser, e1)
1211
            ELSE
1212
                parser.expression(parser, e1)
1213
            END;
1214
            paramcomp(parser, pos, e1, param(PROG.PARAM));
1215
            param := param.next;
1216
            IF param # NIL THEN
1217
                PARS.checklex(parser, SCAN.lxCOMMA);
1218
                PARS.Next(parser)
1219
            END
1220
        END;
1221
 
1222
        PARS.checklex(parser, SCAN.lxRROUND);
1223
        PARS.Next(parser);
1224
 
1225
        e.obj := eEXPR;
1226
        e.type := proc.base
1227
 
1228
    ELSIF e.obj IN {eSTPROC, eSTFUNC, eSYSPROC, eSYSFUNC} THEN
1229
        PARS.Next(parser);
1230
        stProc(parser, e)
1231
    ELSE
1232
        PARS.check1(FALSE, parser, 86)
1233
    END
1234
 
1235
END ActualParameters;
1236
 
1237
 
1238
PROCEDURE qualident (parser: PARS.PARSER; VAR e: PARS.EXPR);
1239
VAR
1240
    ident:  PROG.IDENT;
1241
    import: BOOLEAN;
1242
    pos:    SCAN.POSITION;
1243
 
1244
BEGIN
1245
    PARS.checklex(parser, SCAN.lxIDENT);
1246
    getpos(parser, pos);
1247
    import := FALSE;
1248
    ident := parser.unit.idents.get(parser.unit, parser.lex.ident, FALSE);
1249
    PARS.check1(ident # NIL, parser, 48);
1250
    IF ident.typ = PROG.idMODULE THEN
1251
        PARS.ExpectSym(parser, SCAN.lxPOINT);
1252
        PARS.ExpectSym(parser, SCAN.lxIDENT);
1253
        ident := ident.unit.idents.get(ident.unit, parser.lex.ident, FALSE);
1254
        PARS.check1((ident # NIL) & ident.export, parser, 48);
1255
        import := TRUE
1256
    END;
1257
    PARS.Next(parser);
1258
 
1259
    e.readOnly := FALSE;
1260
    e.ident := ident;
1261
 
1262
    CASE ident.typ OF
1263
    |PROG.idCONST:
1264
        e.obj   := eCONST;
1265
        e.type  := ident.type;
1266
        e.value := ident.value
1267
    |PROG.idTYPE:
1268
        e.obj  := eTYPE;
1269
        e.type := ident.type
1270
    |PROG.idVAR:
1271
        e.obj  := eVAR;
1272
        e.type := ident.type;
1273
        e.readOnly := import
1274
    |PROG.idPROC:
1275
        e.obj   := ePROC;
1276
        e.type  := ident.type
1277
    |PROG.idIMP:
1278
        e.obj   := eIMP;
1279
        e.type  := ident.type
1280
    |PROG.idVPAR:
1281
        e.type := ident.type;
1282
        IF e.type.typ = PROG.tRECORD THEN
1283
            e.obj := eVREC
1284
        ELSE
1285
            e.obj := eVPAR
1286
        END
1287
    |PROG.idPARAM:
1288
        e.obj  := ePARAM;
1289
        e.type := ident.type;
1290
        e.readOnly := (e.type.typ IN {PROG.tRECORD, PROG.tARRAY})
1291
    |PROG.idSTPROC:
1292
        e.obj    := eSTPROC;
1293
        e.stproc := ident.stproc
1294
    |PROG.idSTFUNC:
1295
        e.obj    := eSTFUNC;
1296
        e.stproc := ident.stproc
1297
    |PROG.idSYSPROC:
1298
        e.obj    := eSYSPROC;
1299
        e.stproc := ident.stproc
1300
    |PROG.idSYSFUNC:
1301
        PARS.check(~parser.constexp, parser, pos, 109);
1302
        e.obj    := eSYSFUNC;
1303
        e.stproc := ident.stproc
1304
    |PROG.idNONE:
1305
        PARS.check(FALSE, parser, pos, 115)
1306
    END;
1307
 
1308
    IF isVar(e) THEN
1309
        PARS.check(e.ident.global OR (e.ident.scopeLvl = parser.unit.scopeLvl), parser, pos, 105)
1310
    END
1311
 
1312
END qualident;
1313
 
1314
 
1315
PROCEDURE deref (pos: SCAN.POSITION; e: PARS.EXPR; load: BOOLEAN; error: INTEGER);
1316
VAR
1317
    label:  INTEGER;
1318
 
1319
BEGIN
1320
    IF load THEN
1321
        CODE.load(e.type.size)
1322
    END;
1323
 
1324
    IF chkPTR IN checking THEN
1325
        label := CODE.NewLabel();
1326
        CODE.AddJmpCmd(CODE.opJNZ, label);
1327
        CODE.OnError(pos.line, error);
1328
        CODE.SetLabel(label)
1329
    END
1330
END deref;
1331
 
1332
 
1333
PROCEDURE designator (parser: PARS.PARSER; VAR e: PARS.EXPR);
1334
VAR
1335
    field:  PROG.FIELD;
1336
    pos:    SCAN.POSITION;
1337
    t, idx: PARS.EXPR;
1338
 
1339
 
1340
    PROCEDURE LoadAdr (e: PARS.EXPR);
1341
    VAR
1342
        offset: INTEGER;
1343
 
1344
        PROCEDURE OpenArray (e: PARS.EXPR);
1345
        VAR
1346
            offset, n: INTEGER;
1347
        BEGIN
1348
            offset := e.ident.offset;
1349
            n := PROG.Dim(e.type);
1350
            WHILE n >= 0 DO
1351
                CODE.AddCmd(CODE.opVADR, offset);
1352
                DEC(offset);
1353
                DEC(n)
1354
            END
1355
        END OpenArray;
1356
 
1357
 
1358
    BEGIN
1359
        IF e.obj = eVAR THEN
1360
            offset := PROG.getOffset(PARS.program, e.ident);
1361
            IF e.ident.global THEN
1362
                CODE.AddCmd(CODE.opGADR, offset)
1363
            ELSE
1364
                CODE.AddCmd(CODE.opLADR, -offset)
1365
            END
1366
        ELSIF e.obj = ePARAM THEN
1367
            IF (e.type.typ = PROG.tRECORD) OR ((e.type.typ = PROG.tARRAY) & (e.type.length > 0)) THEN
1368
                CODE.AddCmd(CODE.opVADR, e.ident.offset)
1369
            ELSIF PROG.isOpenArray(e.type) THEN
1370
                OpenArray(e)
1371
            ELSE
1372
                CODE.AddCmd(CODE.opLADR, e.ident.offset)
1373
            END
1374
        ELSIF e.obj IN {eVPAR, eVREC} THEN
1375
            IF PROG.isOpenArray(e.type) THEN
1376
                OpenArray(e)
1377
            ELSE
1378
                CODE.AddCmd(CODE.opVADR, e.ident.offset)
1379
            END
1380
        END
1381
    END LoadAdr;
1382
 
1383
 
1384
    PROCEDURE OpenIdx (parser: PARS.PARSER; pos: SCAN.POSITION; e: PARS.EXPR);
1385
    VAR
1386
        label:  INTEGER;
1387
        type:   PROG.TYPE_;
1388
        n, offset, k: INTEGER;
1389
 
1390
    BEGIN
1391
 
1392
        IF chkIDX IN checking THEN
1393
            label := CODE.NewLabel();
1394
            CODE.AddCmd2(CODE.opCHKIDX2, label, 0);
1395
            CODE.OnError(pos.line, errIDX);
1396
            CODE.SetLabel(label)
1397
        ELSE
1398
            CODE.AddCmd(CODE.opCHKIDX2, -1)
1399
        END;
1400
 
1401
        type := PROG.OpenBase(e.type);
1402
        IF type.size # 1 THEN
1403
            CODE.AddCmd(CODE.opMULC, type.size)
1404
        END;
1405
        n := PROG.Dim(e.type) - 1;
1406
        k := n;
1407
        WHILE n > 0 DO
1408
            CODE.AddCmd0(CODE.opMUL);
1409
            DEC(n)
1410
        END;
1411
        CODE.AddCmd0(CODE.opADD);
1412
        offset := e.ident.offset - 1;
1413
        n := k;
1414
        WHILE n > 0 DO
1415
            CODE.AddCmd(CODE.opVADR, offset);
1416
            DEC(offset);
1417
            DEC(n)
1418
        END
1419
    END OpenIdx;
1420
 
1421
 
1422
BEGIN
1423
    qualident(parser, e);
1424
 
1425
    IF e.obj IN {ePROC, eIMP} THEN
1426
        PROG.UseProc(parser.unit, e.ident.proc)
1427
    END;
1428
 
1429
    IF isVar(e) THEN
1430
        LoadAdr(e)
1431
    END;
1432
 
1433
    WHILE parser.sym = SCAN.lxPOINT DO
1434
        getpos(parser, pos);
1435
        PARS.check1(isExpr(e) & (e.type.typ IN {PROG.tRECORD, PROG.tPOINTER}), parser, 73);
1436
        IF e.type.typ = PROG.tPOINTER THEN
1437
            deref(pos, e, TRUE, errPTR)
1438
        END;
1439
        PARS.ExpectSym(parser, SCAN.lxIDENT);
1440
        IF e.type.typ = PROG.tPOINTER THEN
1441
            e.type := e.type.base;
1442
            e.readOnly := FALSE
1443
        END;
1444
        field := e.type.fields.get(e.type, parser.lex.ident, parser.unit);
1445
        PARS.check1(field # NIL, parser, 74);
1446
        e.type := field.type;
1447
        IF e.obj = eVREC THEN
1448
            e.obj := eVPAR
1449
        END;
1450
        IF field.offset # 0 THEN
1451
            CODE.AddCmd(CODE.opADDR, field.offset)
1452
        END;
1453
        PARS.Next(parser);
1454
        e.ident := NIL
1455
 
1456
    ELSIF parser.sym = SCAN.lxLSQUARE DO
1457
 
1458
        REPEAT
1459
 
1460
            PARS.check1(isArr(e), parser, 75);
1461
            NextPos(parser, pos);
1462
            parser.expression(parser, idx);
1463
            PARS.check(isInt(idx), parser, pos, 76);
1464
 
1465
            IF idx.obj = eCONST THEN
1466
                IF e.type.length > 0 THEN
1467
                    PARS.check(ARITH.range(idx.value, 0, e.type.length - 1), parser, pos, 83);
1468
                    IF ARITH.Int(idx.value) > 0 THEN
1469
                        CODE.AddCmd(CODE.opADDR, ARITH.Int(idx.value) * e.type.base.size)
1470
                    END
1471
                ELSE
1472
                    PARS.check(ARITH.range(idx.value, 0, MACHINE.target.maxInt), parser, pos, 83);
1473
                    LoadConst(idx);
1474
                    OpenIdx(parser, pos, e)
1475
                END
1476
            ELSE
1477
                IF e.type.length > 0 THEN
1478
                    IF chkIDX IN checking THEN
1479
                        CheckRange(e.type.length, pos.line, errIDX)
1480
                    END;
1481
                    IF e.type.base.size # 1 THEN
1482
                        CODE.AddCmd(CODE.opMULC, e.type.base.size)
1483
                    END;
1484
                    CODE.AddCmd0(CODE.opADD)
1485
                ELSE
1486
                    OpenIdx(parser, pos, e)
1487
                END
1488
            END;
1489
 
1490
            e.type := e.type.base
1491
 
1492
        UNTIL parser.sym # SCAN.lxCOMMA;
1493
 
1494
        PARS.checklex(parser, SCAN.lxRSQUARE);
1495
        PARS.Next(parser);
1496
        e.ident := NIL
1497
 
1498
    ELSIF parser.sym = SCAN.lxCARET DO
1499
        getpos(parser, pos);
1500
        PARS.check1(isPtr(e), parser, 77);
1501
        deref(pos, e, TRUE, errPTR);
1502
        e.type := e.type.base;
1503
        e.readOnly := FALSE;
1504
        PARS.Next(parser);
1505
        e.ident := NIL;
1506
        e.obj := eVREC
1507
 
1508
    ELSIF (parser.sym = SCAN.lxLROUND) & isExpr(e) & (e.type.typ IN {PROG.tRECORD, PROG.tPOINTER}) DO
1509
 
1510
        IF e.type.typ = PROG.tRECORD THEN
1511
            PARS.check1(e.obj = eVREC, parser, 78)
1512
        END;
1513
        NextPos(parser, pos);
1514
        qualident(parser, t);
1515
        PARS.check(t.obj = eTYPE, parser, pos, 79);
1516
 
1517
        IF e.type.typ = PROG.tRECORD THEN
1518
            PARS.check(t.type.typ = PROG.tRECORD, parser, pos, 80);
1519
            IF chkGUARD IN checking THEN
1520
                IF e.ident = NIL THEN
1521
                    CODE.TypeGuard(CODE.opTYPEGD, t.type.num, pos.line, errGUARD)
1522
                ELSE
1523
                    CODE.AddCmd(CODE.opVADR, e.ident.offset - 1);
1524
                    CODE.TypeGuard(CODE.opTYPEGR, t.type.num, pos.line, errGUARD)
1525
                END
1526
            END;
1527
        ELSE
1528
            PARS.check(t.type.typ = PROG.tPOINTER, parser, pos, 81);
1529
            IF chkGUARD IN checking THEN
1530
                CODE.TypeGuard(CODE.opTYPEGP, t.type.base.num, pos.line, errGUARD)
1531
            END
1532
        END;
1533
 
1534
        PARS.check(PROG.isBaseOf(e.type, t.type), parser, pos, 82);
1535
 
1536
        e.type := t.type;
1537
 
1538
        PARS.checklex(parser, SCAN.lxRROUND);
1539
        PARS.Next(parser)
1540
 
1541
    END
1542
 
1543
END designator;
1544
 
1545
 
1546
PROCEDURE ProcCall (e: PARS.EXPR; procType: PROG.TYPE_; isfloat: BOOLEAN; VAR fregs: INTEGER; parser: PARS.PARSER; pos: SCAN.POSITION; CallStat: BOOLEAN);
1547
VAR
1548
    cconv:    INTEGER;
1549
    params:   INTEGER;
1550
    callconv: INTEGER;
1551
    fparams:  INTEGER;
1552
    int, flt: INTEGER;
1553
    stk_par:  INTEGER;
1554
 
1555
BEGIN
1556
    cconv := procType.call;
1557
    params := procType.params.size;
1558
 
1559
    IF cconv IN {PROG._win64, PROG.win64} THEN
1560
        callconv := CODE.call_win64;
1561
        fparams := LSL(ORD(procType.params.getfparams(procType, 3, int, flt)), 5) + MIN(params, 4)
1562
    ELSIF cconv IN {PROG._systemv, PROG.systemv} THEN
1563
        callconv := CODE.call_sysv;
1564
        fparams := LSL(ORD(procType.params.getfparams(procType, PROG.MAXSYSVPARAM - 1, int, flt)), 5) + params;
1565
        stk_par := MAX(0, int - 6) + MAX(0, flt - 8)
1566
    ELSE
1567
        callconv := CODE.call_stack;
1568
        fparams := 0
1569
    END;
1570
    CODE.setlast(begcall);
1571
    fregs := CODE.precall(isfloat);
1572
 
1573
    IF cconv IN {PROG._ccall16, PROG.ccall16} THEN
1574
        CODE.AddCmd(CODE.opALIGN16, params)
1575
    ELSIF cconv IN {PROG._win64, PROG.win64} THEN
1576
        CODE.AddCmd(CODE.opWIN64ALIGN16, params)
1577
    ELSIF cconv IN {PROG._systemv, PROG.systemv} THEN
1578
        CODE.AddCmd(CODE.opSYSVALIGN16, params + stk_par)
1579
    END;
1580
    CODE.setlast(endcall.prev(CODE.COMMAND));
1581
 
1582
    IF e.obj = eIMP THEN
1583
        CODE.CallImp(e.ident.import, callconv, fparams)
1584
    ELSIF e.obj = ePROC THEN
1585
        CODE.Call(e.ident.proc.label, callconv, fparams)
1586
    ELSIF isExpr(e) THEN
1587
        deref(pos, e, CallStat, errPROC);
1588
        CODE.CallP(callconv, fparams)
1589
    END;
1590
 
1591
    IF cconv IN {PROG._ccall16, PROG.ccall16} THEN
1592
        CODE.AddCmd(CODE.opCLEANUP, params);
1593
        CODE.AddCmd0(CODE.opPOPSP)
1594
    ELSIF cconv IN {PROG._win64, PROG.win64} THEN
1595
        CODE.AddCmd(CODE.opCLEANUP, MAX(params + params MOD 2, 4) + 1);
1596
        CODE.AddCmd0(CODE.opPOPSP)
1597
    ELSIF cconv IN {PROG._systemv, PROG.systemv} THEN
1598
        CODE.AddCmd(CODE.opCLEANUP, params + stk_par);
1599
        CODE.AddCmd0(CODE.opPOPSP)
1600
    ELSIF cconv IN {PROG._ccall, PROG.ccall} THEN
1601
        CODE.AddCmd(CODE.opCLEANUP, params)
1602
    END;
1603
 
1604
    IF ~CallStat THEN
1605
        IF isfloat THEN
1606
            PARS.check(CODE.resf(fregs), parser, pos, 41)
1607
        ELSE
1608
            CODE.res(fregs)
1609
        END
1610
    END
1611
END ProcCall;
1612
 
1613
 
1614
PROCEDURE expression (parser: PARS.PARSER; VAR e: PARS.EXPR);
1615
VAR
1616
    pos, pos0, pos1: SCAN.POSITION;
1617
 
1618
    op:        INTEGER;
1619
    e1:        PARS.EXPR;
1620
    constant:  BOOLEAN;
1621
    operator:  ARITH.RELATION;
1622
    error:     INTEGER;
1623
 
1624
 
1625
    PROCEDURE relation (sym: INTEGER): BOOLEAN;
1626
        RETURN (sym = SCAN.lxEQ) OR (sym = SCAN.lxNE) OR
1627
               (sym = SCAN.lxLT) OR (sym = SCAN.lxLE) OR
1628
               (sym = SCAN.lxGT) OR (sym = SCAN.lxGE) OR
1629
               (sym = SCAN.lxIN) OR (sym = SCAN.lxIS)
1630
    END relation;
1631
 
1632
 
1633
    PROCEDURE AddOperator (sym: INTEGER): BOOLEAN;
1634
        RETURN (sym = SCAN.lxPLUS) OR (sym = SCAN.lxMINUS) OR
1635
               (sym = SCAN.lxOR)
1636
    END AddOperator;
1637
 
1638
 
1639
    PROCEDURE MulOperator (sym: INTEGER): BOOLEAN;
1640
        RETURN (sym = SCAN.lxMUL) OR (sym = SCAN.lxSLASH) OR
1641
               (sym = SCAN.lxDIV) OR (sym = SCAN.lxMOD) OR
1642
               (sym = SCAN.lxAND)
1643
    END MulOperator;
1644
 
1645
 
1646
    PROCEDURE element (parser: PARS.PARSER; VAR e: PARS.EXPR);
1647
    VAR
1648
        e1, e2: PARS.EXPR;
1649
        pos:    SCAN.POSITION;
1650
        range:  BOOLEAN;
1651
 
1652
    BEGIN
1653
        range := FALSE;
1654
        getpos(parser, pos);
1655
        expression(parser, e1);
1656
        PARS.check(isInt(e1), parser, pos, 76);
1657
 
1658
        IF e1.obj = eCONST THEN
1659
            PARS.check(ARITH.range(e1.value, 0, MACHINE.target.maxSet), parser, pos, 44)
1660
        END;
1661
 
1662
        range := parser.sym = SCAN.lxRANGE;
1663
 
1664
        IF range THEN
1665
            NextPos(parser, pos);
1666
            expression(parser, e2);
1667
            PARS.check(isInt(e2), parser, pos, 76);
1668
 
1669
            IF e2.obj = eCONST THEN
1670
                PARS.check(ARITH.range(e2.value, 0, MACHINE.target.maxSet), parser, pos, 44)
1671
            END
1672
        ELSE
1673
            IF e1.obj = eCONST THEN
1674
                e2 := e1
1675
            END
1676
        END;
1677
 
1678
        e.type := PARS.program.stTypes.tSET;
1679
 
1680
        IF (e1.obj = eCONST) & (e2.obj = eCONST) THEN
1681
            ARITH.constrSet(e.value, e1.value, e2.value);
1682
            e.obj := eCONST
1683
        ELSE
1684
            IF range THEN
1685
                IF e1.obj = eCONST THEN
1686
                    CODE.AddCmd(CODE.opRSETL, ARITH.Int(e1.value))
1687
                ELSIF e2.obj = eCONST THEN
1688
                    CODE.AddCmd(CODE.opRSETR, ARITH.Int(e2.value))
1689
                ELSE
1690
                    CODE.AddCmd0(CODE.opRSET)
1691
                END
1692
            ELSE
1693
                CODE.AddCmd0(CODE.opRSET1)
1694
            END;
1695
            e.obj := eEXPR
1696
        END
1697
 
1698
    END element;
1699
 
1700
 
1701
    PROCEDURE set (parser: PARS.PARSER; VAR e: PARS.EXPR);
1702
    VAR
1703
        e1: PARS.EXPR;
1704
 
1705
    BEGIN
1706
        ASSERT(parser.sym = SCAN.lxLCURLY);
1707
 
1708
        e.obj := eCONST;
1709
        e.type := PARS.program.stTypes.tSET;
1710
        ARITH.emptySet(e.value);
1711
 
1712
        PARS.Next(parser);
1713
        IF parser.sym # SCAN.lxRCURLY THEN
1714
            element(parser, e1);
1715
 
1716
            IF e1.obj = eCONST THEN
1717
                ARITH.opSet(e.value, e1.value, "+")
1718
            ELSE
1719
                e.obj := eEXPR
1720
            END;
1721
 
1722
            WHILE parser.sym = SCAN.lxCOMMA DO
1723
                PARS.Next(parser);
1724
                element(parser, e1);
1725
                IF (e.obj = eCONST) & (e1.obj = eCONST) THEN
1726
                    ARITH.opSet(e.value, e1.value, "+")
1727
                ELSE
1728
                    IF e.obj = eCONST THEN
1729
                        CODE.AddCmd(CODE.opADDSL, ARITH.Int(e.value))
1730
                    ELSIF e1.obj = eCONST THEN
1731
                        CODE.AddCmd(CODE.opADDSR, ARITH.Int(e1.value))
1732
                    ELSE
1733
                        CODE.AddCmd0(CODE.opADDS)
1734
                    END;
1735
                    e.obj := eEXPR
1736
                END
1737
            END;
1738
            PARS.checklex(parser, SCAN.lxRCURLY)
1739
        END;
1740
        PARS.Next(parser);
1741
    END set;
1742
 
1743
 
1744
    PROCEDURE factor (parser: PARS.PARSER; VAR e: PARS.EXPR);
1745
    VAR
1746
        sym:      INTEGER;
1747
        pos:      SCAN.POSITION;
1748
        e1:       PARS.EXPR;
1749
        isfloat:  BOOLEAN;
1750
        fregs:    INTEGER;
1751
 
1752
 
1753
        PROCEDURE LoadVar (e: PARS.EXPR; parser: PARS.PARSER; pos: SCAN.POSITION);
1754
        BEGIN
1755
            IF ~(e.type.typ IN {PROG.tRECORD, PROG.tARRAY}) THEN
1756
                IF e.type.typ = PROG.tREAL THEN
1757
                    PARS.check(CODE.loadf(), parser, pos, 41)
1758
                ELSE
1759
                    CODE.load(e.type.size)
1760
                END
1761
            END
1762
        END LoadVar;
1763
 
1764
 
1765
    BEGIN
1766
        sym := parser.sym;
1767
 
1768
        IF (sym = SCAN.lxINTEGER) OR (sym = SCAN.lxHEX) OR (sym = SCAN.lxFLOAT) OR (sym = SCAN.lxCHAR) OR (sym = SCAN.lxSTRING) THEN
1769
            e.obj := eCONST;
1770
            e.value := parser.lex.value;
1771
            e.type := PARS.program.getType(PARS.program, e.value.typ);
1772
            PARS.Next(parser)
1773
 
1774
        ELSIF sym = SCAN.lxNIL THEN
1775
            e.obj   := eCONST;
1776
            e.type  := PARS.program.stTypes.tNIL;
1777
            PARS.Next(parser)
1778
 
1779
        ELSIF (sym = SCAN.lxTRUE) OR (sym = SCAN.lxFALSE) THEN
1780
            e.obj   := eCONST;
1781
            ARITH.setbool(e.value, sym = SCAN.lxTRUE);
1782
            e.type  := PARS.program.stTypes.tBOOLEAN;
1783
            PARS.Next(parser)
1784
 
1785
        ELSIF sym = SCAN.lxLCURLY THEN
1786
            set(parser, e)
1787
 
1788
        ELSIF sym = SCAN.lxIDENT THEN
1789
            getpos(parser, pos);
1790
 
1791
            CODE.pushBegEnd(begcall, endcall);
1792
 
1793
            designator(parser, e);
1794
            IF isVar(e) THEN
1795
                LoadVar(e, parser, pos)
1796
            END;
1797
            IF parser.sym = SCAN.lxLROUND THEN
1798
                e1 := e;
1799
                ActualParameters(parser, e);
1800
                PARS.check(e.type # NIL, parser, pos, 59);
1801
                isfloat := e.type.typ = PROG.tREAL;
1802
                IF e1.obj IN {ePROC, eIMP} THEN
1803
                    ProcCall(e1, e1.ident.type, isfloat, fregs, parser, pos, FALSE)
1804
                ELSIF isExpr(e1) THEN
1805
                    ProcCall(e1, e1.type, isfloat, fregs, parser, pos, FALSE)
1806
                END
1807
            END;
1808
            CODE.popBegEnd(begcall, endcall)
1809
 
1810
        ELSIF sym = SCAN.lxLROUND THEN
1811
            PARS.Next(parser);
1812
            expression(parser, e);
1813
            PARS.checklex(parser, SCAN.lxRROUND);
1814
            PARS.Next(parser);
1815
            IF isExpr(e) & (e.obj # eCONST) THEN
1816
                e.obj := eEXPR
1817
            END
1818
 
1819
        ELSIF sym = SCAN.lxNOT THEN
1820
            NextPos(parser, pos);
1821
            factor(parser, e);
1822
            PARS.check(isBoolean(e), parser, pos, 72);
1823
            IF e.obj # eCONST THEN
1824
                CODE.not;
1825
                e.obj := eEXPR
1826
            ELSE
1827
                ASSERT(ARITH.neg(e.value))
1828
            END
1829
 
1830
        ELSE
1831
            PARS.check1(FALSE, parser, 34)
1832
        END
1833
    END factor;
1834
 
1835
 
1836
    PROCEDURE term (parser: PARS.PARSER; VAR e: PARS.EXPR);
1837
    VAR
1838
        pos: SCAN.POSITION;
1839
        op:  INTEGER;
1840
        e1:  PARS.EXPR;
1841
 
1842
        label:  INTEGER;
1843
        label1: INTEGER;
1844
 
1845
    BEGIN
1846
        factor(parser, e);
1847
        label := -1;
1848
 
1849
        WHILE MulOperator(parser.sym) DO
1850
            op  := parser.sym;
1851
            getpos(parser, pos);
1852
            PARS.Next(parser);
1853
 
1854
            IF op = SCAN.lxAND THEN
1855
                IF ~parser.constexp THEN
1856
 
1857
                    IF label = -1 THEN
1858
                        label := CODE.NewLabel()
1859
                    END;
1860
 
1861
                    IF e.obj = eCONST THEN
1862
                        CODE.AddCmd(CODE.opCONST, ORD(ARITH.getBool(e.value)))
7667 akron1 1863
                    END;
1864
                    CODE.AddCmd0(CODE.opACC);
7597 akron1 1865
                    CODE.AddJmpCmd(CODE.opJZ, label);
1866
                    CODE.drop
1867
                END
1868
            END;
1869
 
1870
            factor(parser, e1);
1871
 
1872
            CASE op OF
1873
            |SCAN.lxMUL:
1874
                PARS.check(isInt(e) & isInt(e1) OR isReal(e) & isReal(e1) OR isSet(e) & isSet(e1), parser, pos, 37);
1875
                IF (e.obj = eCONST) & (e1.obj = eCONST) THEN
1876
 
1877
                   CASE e.value.typ OF
1878
                   |ARITH.tINTEGER: PARS.check(ARITH.opInt(e.value, e1.value, "*"),   parser, pos, 39)
1879
                   |ARITH.tREAL:    PARS.check(ARITH.opFloat(e.value, e1.value, "*"), parser, pos, 40)
1880
                   |ARITH.tSET:     ARITH.opSet(e.value, e1.value, "*")
1881
                   END
1882
 
1883
                ELSE
1884
                    IF isInt(e) THEN
1885
                        IF e.obj = eCONST THEN
1886
                            CODE.AddCmd(CODE.opMULC, ARITH.Int(e.value))
1887
                        ELSIF e1.obj = eCONST THEN
1888
                            CODE.AddCmd(CODE.opMULC, ARITH.Int(e1.value))
1889
                        ELSE
1890
                            CODE.AddCmd0(CODE.opMUL)
1891
                        END
1892
                    ELSIF isReal(e) THEN
1893
                        IF e.obj = eCONST THEN
1894
                            CODE.Float(ARITH.Float(e.value))
1895
                        ELSIF e1.obj = eCONST THEN
1896
                            CODE.Float(ARITH.Float(e1.value))
1897
                        END;
1898
                        CODE.fbinop(CODE.opMULF)
1899
                    ELSIF isSet(e) THEN
1900
                        IF e.obj = eCONST THEN
1901
                            CODE.AddCmd(CODE.opMULSC, ARITH.Int(e.value))
1902
                        ELSIF e1.obj = eCONST THEN
1903
                            CODE.AddCmd(CODE.opMULSC, ARITH.Int(e1.value))
1904
                        ELSE
1905
                            CODE.AddCmd0(CODE.opMULS)
1906
                        END
1907
                    END;
1908
                    e.obj := eEXPR
1909
                END
1910
 
1911
            |SCAN.lxSLASH:
1912
                PARS.check(isReal(e) & isReal(e1) OR isSet(e) & isSet(e1), parser, pos, 37);
1913
                IF (e1.obj = eCONST) & isReal(e1) THEN
1914
                    PARS.check(~ARITH.isZero(e1.value), parser, pos, 45)
1915
                END;
1916
                IF (e.obj = eCONST) & (e1.obj = eCONST) THEN
1917
 
1918
                    CASE e.value.typ OF
1919
                    |ARITH.tREAL: PARS.check(ARITH.opFloat(e.value, e1.value, "/"), parser, pos, 40)
1920
                    |ARITH.tSET:  ARITH.opSet(e.value, e1.value, "/")
1921
                    END
1922
 
1923
                ELSE
1924
                    IF isReal(e) THEN
1925
                        IF e.obj = eCONST THEN
1926
                            CODE.Float(ARITH.Float(e.value));
1927
                            CODE.fbinop(CODE.opDIVFI)
1928
                        ELSIF e1.obj = eCONST THEN
1929
                            CODE.Float(ARITH.Float(e1.value));
1930
                            CODE.fbinop(CODE.opDIVF)
1931
                        ELSE
1932
                            CODE.fbinop(CODE.opDIVF)
1933
                        END
1934
                    ELSIF isSet(e) THEN
1935
                        IF e.obj = eCONST THEN
1936
                            CODE.AddCmd(CODE.opDIVSC, ARITH.Int(e.value))
1937
                        ELSIF e1.obj = eCONST THEN
1938
                            CODE.AddCmd(CODE.opDIVSC, ARITH.Int(e1.value))
1939
                        ELSE
1940
                            CODE.AddCmd0(CODE.opDIVS)
1941
                        END
1942
                    END;
1943
                    e.obj := eEXPR
1944
                END
1945
 
1946
            |SCAN.lxDIV, SCAN.lxMOD:
1947
                PARS.check(isInt(e) & isInt(e1), parser, pos, 37);
1948
                IF e1.obj = eCONST THEN
1949
                    PARS.check(~ARITH.isZero(e1.value), parser, pos, 46)
1950
                END;
1951
                IF (e.obj = eCONST) & (e1.obj = eCONST) THEN
1952
 
1953
                    IF op = SCAN.lxDIV THEN
1954
                        PARS.check(ARITH.opInt(e.value, e1.value, "D"), parser, pos, 39)
1955
                    ELSE
1956
                        ASSERT(ARITH.opInt(e.value, e1.value, "M"))
1957
                    END
1958
 
1959
                ELSE
1960
                    IF e1.obj # eCONST THEN
1961
                        label1 := CODE.NewLabel();
1962
                        CODE.AddJmpCmd(CODE.opJNZ, label1)
1963
                    END;
1964
                    IF e.obj = eCONST THEN
1965
                        CODE.OnError(pos.line, errDIV);
1966
                        CODE.SetLabel(label1);
1967
                        CODE.AddCmd(CODE.opDIVL + ORD(op = SCAN.lxMOD), ARITH.Int(e.value))
1968
                    ELSIF e1.obj = eCONST THEN
1969
                        CODE.AddCmd(CODE.opDIVR + ORD(op = SCAN.lxMOD), ARITH.Int(e1.value))
1970
                    ELSE
1971
                        CODE.OnError(pos.line, errDIV);
1972
                        CODE.SetLabel(label1);
1973
                        CODE.AddCmd0(CODE.opDIV  + ORD(op = SCAN.lxMOD))
1974
                    END;
1975
                    e.obj := eEXPR
1976
                END
1977
 
1978
            |SCAN.lxAND:
1979
                PARS.check(isBoolean(e) & isBoolean(e1), parser, pos, 37);
1980
 
1981
                IF (e.obj = eCONST) & (e1.obj = eCONST) THEN
1982
                    ARITH.opBoolean(e.value, e1.value, "&")
1983
                ELSE
1984
                    e.obj := eEXPR;
1985
                    IF e1.obj = eCONST THEN
1986
                        CODE.AddCmd(CODE.opCONST, ORD(ARITH.getBool(e1.value)))
7667 akron1 1987
                    END;
1988
                    CODE.AddCmd0(CODE.opACC)
7597 akron1 1989
                END
1990
 
1991
            END
1992
        END;
1993
 
1994
        IF label # -1 THEN
1995
            CODE.SetLabel(label)
1996
        END
1997
    END term;
1998
 
1999
 
2000
    PROCEDURE SimpleExpression (parser: PARS.PARSER; VAR e: PARS.EXPR);
2001
    VAR
2002
        pos: SCAN.POSITION;
2003
        op:  INTEGER;
2004
        e1:  PARS.EXPR;
2005
 
2006
        plus, minus: BOOLEAN;
2007
 
2008
        label: INTEGER;
2009
 
2010
    BEGIN
2011
        plus  := parser.sym = SCAN.lxPLUS;
2012
        minus := parser.sym = SCAN.lxMINUS;
2013
 
2014
        IF plus OR minus THEN
2015
            getpos(parser, pos);
2016
            PARS.Next(parser)
2017
        END;
2018
 
2019
        term(parser, e);
2020
 
2021
        IF plus OR minus THEN
2022
            PARS.check(isInt(e) OR isReal(e) OR isSet(e), parser, pos, 36);
2023
 
2024
            IF minus & (e.obj = eCONST) THEN
2025
                PARS.check(ARITH.neg(e.value), parser, pos, 39)
2026
            END;
2027
 
2028
            IF e.obj # eCONST THEN
2029
                IF minus THEN
2030
                    IF isInt(e) THEN
2031
                        CODE.AddCmd0(CODE.opUMINUS)
2032
                    ELSIF isReal(e) THEN
2033
                        CODE.AddCmd0(CODE.opUMINF)
2034
                    ELSIF isSet(e) THEN
2035
                        CODE.AddCmd0(CODE.opUMINS)
2036
                    END
2037
                END;
2038
                e.obj := eEXPR
2039
            END
2040
        END;
2041
 
2042
        label := -1;
2043
 
2044
        WHILE AddOperator(parser.sym) DO
2045
 
2046
            op  := parser.sym;
2047
            getpos(parser, pos);
2048
            PARS.Next(parser);
2049
 
2050
            IF op = SCAN.lxOR THEN
2051
 
2052
                IF ~parser.constexp THEN
2053
 
2054
                    IF label = -1 THEN
2055
                        label := CODE.NewLabel()
2056
                    END;
2057
 
2058
                    IF e.obj = eCONST THEN
2059
                        CODE.AddCmd(CODE.opCONST, ORD(ARITH.getBool(e.value)))
7667 akron1 2060
                    END;
2061
                    CODE.AddCmd0(CODE.opACC);
7597 akron1 2062
                    CODE.AddJmpCmd(CODE.opJNZ, label);
2063
                    CODE.drop
2064
                END
2065
 
2066
            END;
2067
 
2068
            term(parser, e1);
2069
 
2070
            CASE op OF
2071
            |SCAN.lxPLUS, SCAN.lxMINUS:
2072
 
2073
                IF op = SCAN.lxPLUS THEN
2074
                    op := ORD("+")
2075
                ELSE
2076
                    op := ORD("-")
2077
                END;
2078
 
2079
                PARS.check(isInt(e) & isInt(e1) OR isReal(e) & isReal(e1) OR isSet(e) & isSet(e1), parser, pos, 37);
2080
                IF (e.obj = eCONST) & (e1.obj = eCONST) THEN
2081
 
2082
                   CASE e.value.typ OF
2083
                   |ARITH.tINTEGER: PARS.check(ARITH.opInt(e.value, e1.value, CHR(op)),   parser, pos, 39)
2084
                   |ARITH.tREAL:    PARS.check(ARITH.opFloat(e.value, e1.value, CHR(op)), parser, pos, 40)
2085
                   |ARITH.tSET:     ARITH.opSet(e.value, e1.value, CHR(op))
2086
                   END
2087
 
2088
                ELSE
2089
                    IF isInt(e) THEN
2090
                        IF e.obj = eCONST THEN
2091
                            CODE.AddCmd(CODE.opADDL + ORD(op = ORD("-")), ARITH.Int(e.value))
2092
                        ELSIF e1.obj = eCONST THEN
2093
                            CODE.AddCmd(CODE.opADDR + ORD(op = ORD("-")), ARITH.Int(e1.value))
2094
                        ELSE
2095
                            CODE.AddCmd0(CODE.opADD  + ORD(op = ORD("-")))
2096
                        END
2097
                    ELSIF isReal(e) THEN
2098
                        IF e.obj = eCONST THEN
2099
                            CODE.Float(ARITH.Float(e.value));
2100
                            CODE.fbinop(CODE.opADDFI + ORD(op = ORD("-")))
2101
                        ELSIF e1.obj = eCONST THEN
2102
                            CODE.Float(ARITH.Float(e1.value));
2103
                            CODE.fbinop(CODE.opADDF  + ORD(op = ORD("-")))
2104
                        ELSE
2105
                            CODE.fbinop(CODE.opADDF  + ORD(op = ORD("-")))
2106
                        END
2107
                    ELSIF isSet(e) THEN
2108
                        IF e.obj = eCONST THEN
2109
                            CODE.AddCmd(CODE.opADDSL + ORD(op = ORD("-")), ARITH.Int(e.value))
2110
                        ELSIF e1.obj = eCONST THEN
2111
                            CODE.AddCmd(CODE.opADDSR + ORD(op = ORD("-")), ARITH.Int(e1.value))
2112
                        ELSE
2113
                            CODE.AddCmd0(CODE.opADDS  + ORD(op = ORD("-")))
2114
                        END
2115
                    END;
2116
                    e.obj := eEXPR
2117
                END
2118
 
2119
            |SCAN.lxOR:
2120
                PARS.check(isBoolean(e) & isBoolean(e1), parser, pos, 37);
2121
 
2122
                IF (e.obj = eCONST) & (e1.obj = eCONST) THEN
2123
                    ARITH.opBoolean(e.value, e1.value, "|")
2124
                ELSE
2125
                    e.obj := eEXPR;
2126
                    IF e1.obj = eCONST THEN
2127
                        CODE.AddCmd(CODE.opCONST, ORD(ARITH.getBool(e1.value)))
7667 akron1 2128
                    END;
2129
                    CODE.AddCmd0(CODE.opACC)
7597 akron1 2130
                END
2131
 
2132
            END
2133
        END;
2134
 
2135
        IF label # -1 THEN
2136
            CODE.SetLabel(label)
2137
        END
2138
 
2139
    END SimpleExpression;
2140
 
2141
 
2142
    PROCEDURE cmpcode (op: INTEGER): INTEGER;
2143
    VAR
2144
        res: INTEGER;
2145
    BEGIN
2146
        CASE op OF
2147
        |SCAN.lxEQ: res := 0
2148
        |SCAN.lxNE: res := 1
2149
        |SCAN.lxLT: res := 2
2150
        |SCAN.lxLE: res := 3
2151
        |SCAN.lxGT: res := 4
2152
        |SCAN.lxGE: res := 5
2153
        END
2154
 
2155
        RETURN res
2156
    END cmpcode;
2157
 
2158
 
2159
    PROCEDURE BoolCmp (eq, val: BOOLEAN);
2160
    BEGIN
2161
       IF eq = val THEN
2162
           CODE.AddCmd0(CODE.opNER)
2163
       ELSE
2164
           CODE.AddCmd0(CODE.opEQR)
2165
       END
2166
    END BoolCmp;
2167
 
2168
 
2169
    PROCEDURE strcmp (VAR e, e1: PARS.EXPR; op: INTEGER): BOOLEAN;
2170
    VAR
2171
        res: BOOLEAN;
2172
 
2173
    BEGIN
2174
 
2175
        res := TRUE;
2176
 
2177
        IF isString(e) & isCharArray(e1) THEN
2178
            CODE.AddCmd(CODE.opSADR, String(e));
2179
            CODE.AddCmd(CODE.opCONST, strlen(e) + 1);
2180
            CODE.AddCmd0(CODE.opEQS2 + cmpcode(op))
2181
 
2182
        ELSIF isString(e) & isCharArrayW(e1) THEN
2183
            CODE.AddCmd(CODE.opSADR, StringW(e));
2184
            CODE.AddCmd(CODE.opCONST, utf8strlen(e) + 1);
2185
            CODE.AddCmd0(CODE.opEQSW2 + cmpcode(op))
2186
 
2187
        ELSIF isStringW(e) & isCharArrayW(e1) THEN
2188
            CODE.AddCmd(CODE.opSADR, StringW(e));
2189
            CODE.AddCmd(CODE.opCONST, utf8strlen(e) + 1);
2190
            CODE.AddCmd0(CODE.opEQSW2 + cmpcode(op))
2191
 
2192
        ELSIF isCharArray(e) & isString(e1) THEN
2193
            CODE.AddCmd(CODE.opSADR, String(e1));
2194
            CODE.AddCmd(CODE.opCONST, strlen(e1) + 1);
2195
            CODE.AddCmd0(CODE.opEQS + cmpcode(op))
2196
 
2197
        ELSIF isCharArrayW(e) & isString(e1) THEN
2198
            CODE.AddCmd(CODE.opSADR, StringW(e1));
2199
            CODE.AddCmd(CODE.opCONST, utf8strlen(e1) + 1);
2200
            CODE.AddCmd0(CODE.opEQSW + cmpcode(op))
2201
 
2202
        ELSIF isCharArrayW(e) & isStringW(e1) THEN
2203
            CODE.AddCmd(CODE.opSADR, StringW(e1));
2204
            CODE.AddCmd(CODE.opCONST, utf8strlen(e1) + 1);
2205
            CODE.AddCmd0(CODE.opEQSW + cmpcode(op))
2206
 
2207
        ELSIF isCharArrayW(e) & isCharArrayW(e1) THEN
2208
            CODE.AddCmd0(CODE.opEQSW + cmpcode(op))
2209
 
2210
        ELSIF isCharArray(e) & isCharArray(e1) THEN
2211
            CODE.AddCmd0(CODE.opEQS + cmpcode(op))
2212
 
2213
        ELSIF isString(e) & isString(e1) THEN
2214
            PARS.strcmp(e.value, e1.value, op)
2215
 
2216
        ELSE
2217
            res := FALSE
2218
 
2219
        END
2220
 
2221
        RETURN res
2222
    END strcmp;
2223
 
2224
 
2225
BEGIN
2226
    getpos(parser, pos0);
2227
    SimpleExpression(parser, e);
2228
    IF relation(parser.sym) THEN
2229
        IF (isCharArray(e) OR isCharArrayW(e)) & (e.type.length # 0) THEN
2230
            CODE.AddCmd(CODE.opCONST, e.type.length)
2231
        END;
2232
        op  := parser.sym;
2233
        getpos(parser, pos);
2234
        PARS.Next(parser);
2235
 
2236
        pos1 := parser.lex.pos;
2237
        SimpleExpression(parser, e1);
2238
 
2239
        IF (isCharArray(e1) OR isCharArrayW(e1)) & (e1.type.length # 0) THEN
2240
            CODE.AddCmd(CODE.opCONST, e1.type.length)
2241
        END;
2242
 
2243
        constant := (e.obj = eCONST) & (e1.obj = eCONST);
2244
 
2245
        CASE op OF
2246
        |SCAN.lxEQ: operator := "="
2247
        |SCAN.lxNE: operator := "#"
2248
        |SCAN.lxLT: operator := "<"
2249
        |SCAN.lxLE: operator := "<="
2250
        |SCAN.lxGT: operator := ">"
2251
        |SCAN.lxGE: operator := ">="
2252
        |SCAN.lxIN: operator := "IN"
2253
        |SCAN.lxIS: operator := ""
2254
        END;
2255
 
2256
        error := 0;
2257
 
2258
        CASE op OF
2259
        |SCAN.lxEQ, SCAN.lxNE:
2260
 
2261
            IF isInt(e) & isInt(e1) OR isSet(e) & isSet(e1) OR isChar(e) & isChar(e1) OR isCharW(e) & isCharW(e1) OR
2262
            isCharW(e) & isChar(e1) & (e1.obj = eCONST) OR isCharW(e1) & isChar(e) & (e.obj = eCONST) OR
2263
            isCharW(e1) & (e1.obj = eCONST) & isChar(e) & (e.obj = eCONST) OR
2264
            isCharW(e) & (e.obj = eCONST) & isChar(e1) & (e1.obj = eCONST) OR
2265
            isPtr(e) & isPtr(e1) & (PROG.isBaseOf(e.type, e1.type) OR PROG.isBaseOf(e1.type, e.type)) THEN
2266
                IF constant THEN
2267
                    ARITH.relation(e.value, e1.value, operator, error)
2268
                ELSE
2269
                    IF e.obj = eCONST THEN
2270
                        CODE.AddCmd(CODE.opEQ + cmpcode(op) + 6,  ARITH.Int(e.value))
2271
                    ELSIF e1.obj = eCONST THEN
2272
                        CODE.AddCmd(CODE.opEQ + cmpcode(op) + 12, ARITH.Int(e1.value))
2273
                    ELSE
2274
                        CODE.AddCmd0(CODE.opEQ + cmpcode(op))
2275
                    END
2276
                END
2277
 
2278
            ELSIF isStringW1(e) & isCharW(e1) THEN
2279
                CODE.AddCmd(CODE.opEQ + cmpcode(op) + 6, StrToWChar(e.value.string(SCAN.IDENT).s))
2280
 
2281
            ELSIF isStringW1(e1) & isCharW(e) THEN
2282
                CODE.AddCmd(CODE.opEQ + cmpcode(op) + 12, StrToWChar(e1.value.string(SCAN.IDENT).s))
2283
 
2284
            ELSIF isBoolean(e) & isBoolean(e1) THEN
2285
                IF constant THEN
2286
                    ARITH.relation(e.value, e1.value, operator, error)
2287
                ELSE
2288
                    IF e.obj = eCONST THEN
2289
                        BoolCmp(op = SCAN.lxEQ, ARITH.Int(e.value) # 0)
2290
                    ELSIF e1.obj = eCONST THEN
2291
                        BoolCmp(op = SCAN.lxEQ, ARITH.Int(e1.value) # 0)
2292
                    ELSE
2293
                        IF op = SCAN.lxEQ THEN
2294
                            CODE.AddCmd0(CODE.opEQB)
2295
                        ELSE
2296
                            CODE.AddCmd0(CODE.opNEB)
2297
                        END
2298
                    END
2299
                END
2300
 
2301
            ELSIF isReal(e) & isReal(e1) THEN
2302
                IF constant THEN
2303
                    ARITH.relation(e.value, e1.value, operator, error)
2304
                ELSE
2305
                    IF e.obj = eCONST THEN
2306
                        CODE.Float(ARITH.Float(e.value));
2307
                        CODE.fcmp(CODE.opEQF + cmpcode(op) + 6)
2308
                    ELSIF e1.obj = eCONST THEN
2309
                        CODE.Float(ARITH.Float(e1.value));
2310
                        CODE.fcmp(CODE.opEQF + cmpcode(op))
2311
                    ELSE
2312
                        CODE.fcmp(CODE.opEQF + cmpcode(op))
2313
                    END
2314
                END
2315
 
2316
            ELSIF (isStringW(e) OR isCharArrayX(e)) & (isStringW(e1) OR isCharArrayX(e1)) THEN
2317
                IF ~strcmp(e, e1, op) THEN
2318
                    PARS.error(parser, pos, 37)
2319
                END
2320
 
2321
            ELSIF isPtr(e) & isNil(e1) OR isNil(e) & isPtr(e1) THEN
2322
                CODE.AddCmd0(CODE.opEQ + cmpcode(op) + 6)
2323
 
2324
            ELSIF isProc(e) & isNil(e1) THEN
2325
                IF e.obj IN {ePROC, eIMP} THEN
2326
                    PARS.check(e.ident.global, parser, pos0, 85);
2327
                    constant := TRUE;
2328
                    e.obj := eCONST;
2329
                    ARITH.setbool(e.value, op = SCAN.lxNE)
2330
                ELSE
2331
                    CODE.AddCmd0(CODE.opEQ + cmpcode(op) + 6)
2332
                END
2333
 
2334
            ELSIF isNil(e) & isProc(e1) THEN
2335
                IF e1.obj IN {ePROC, eIMP} THEN
2336
                    PARS.check(e1.ident.global, parser, pos1, 85);
2337
                    constant := TRUE;
2338
                    e.obj := eCONST;
2339
                    ARITH.setbool(e.value, op = SCAN.lxNE)
2340
                ELSE
2341
                    CODE.AddCmd0(CODE.opEQ + cmpcode(op) + 6)
2342
                END
2343
 
2344
            ELSIF isProc(e) & isProc(e1) & PROG.isTypeEq(e.type, e1.type) THEN
2345
                IF e.obj = ePROC THEN
2346
                    PARS.check(e.ident.global, parser, pos0, 85)
2347
                END;
2348
                IF e1.obj = ePROC THEN
2349
                    PARS.check(e1.ident.global, parser, pos1, 85)
2350
                END;
2351
                IF (e.obj IN {ePROC, eIMP}) & (e1.obj IN {ePROC, eIMP}) THEN
2352
                    constant := TRUE;
2353
                    e.obj := eCONST;
2354
                    IF op = SCAN.lxEQ THEN
2355
                        ARITH.setbool(e.value, e.ident = e1.ident)
2356
                    ELSE
2357
                        ARITH.setbool(e.value, e.ident # e1.ident)
2358
                    END
2359
                ELSIF e.obj = ePROC THEN
2360
                    CODE.ProcCmp(e.ident.proc.label, cmpcode(op) = 0)
2361
                ELSIF e1.obj = ePROC THEN
2362
                    CODE.ProcCmp(e1.ident.proc.label, cmpcode(op) = 0)
2363
                ELSIF e.obj = eIMP THEN
2364
                    CODE.ProcImpCmp(e.ident.import, cmpcode(op) = 0)
2365
                ELSIF e1.obj = eIMP THEN
2366
                    CODE.ProcImpCmp(e1.ident.import, cmpcode(op) = 0)
2367
                ELSE
2368
                    CODE.AddCmd0(CODE.opEQ + cmpcode(op))
2369
                END
2370
 
2371
            ELSIF isNil(e) & isNil(e1) THEN
2372
                constant := TRUE;
2373
                e.obj := eCONST;
2374
                ARITH.setbool(e.value, op = SCAN.lxEQ)
2375
 
2376
            ELSE
2377
                PARS.error(parser, pos, 37)
2378
            END
2379
 
2380
        |SCAN.lxLT, SCAN.lxLE, SCAN.lxGT, SCAN.lxGE:
2381
            IF isInt(e) & isInt(e1) OR isChar(e) & isChar(e1) OR isCharW(e) & isCharW(e1) OR
2382
                isCharW(e) & isChar(e1) & (e1.obj = eCONST) OR isCharW(e1) & isChar(e) & (e.obj = eCONST) OR
2383
                isCharW(e1) & (e1.obj = eCONST) & isChar(e) & (e.obj = eCONST) OR
2384
                isCharW(e) & (e.obj = eCONST) & isChar(e1) & (e1.obj = eCONST) THEN
2385
 
2386
                IF constant THEN
2387
                    ARITH.relation(e.value, e1.value, operator, error)
2388
                ELSE
2389
                    IF e.obj = eCONST THEN
2390
                        CODE.AddCmd(CODE.opEQ + cmpcode(op) + 6, ARITH.Int(e.value))
2391
                    ELSIF e1.obj = eCONST THEN
2392
                        CODE.AddCmd(CODE.opEQ + cmpcode(op) + 12, ARITH.Int(e1.value))
2393
                    ELSE
2394
                        CODE.AddCmd0(CODE.opEQ + cmpcode(op))
2395
                    END
2396
                END
2397
 
2398
            ELSIF isStringW1(e) & isCharW(e1) THEN
2399
                CODE.AddCmd(CODE.opEQ + cmpcode(op) + 6, StrToWChar(e.value.string(SCAN.IDENT).s))
2400
 
2401
            ELSIF isStringW1(e1) & isCharW(e) THEN
2402
                CODE.AddCmd(CODE.opEQ + cmpcode(op) + 12, StrToWChar(e1.value.string(SCAN.IDENT).s))
2403
 
2404
            ELSIF isReal(e) & isReal(e1) THEN
2405
                IF constant THEN
2406
                    ARITH.relation(e.value, e1.value, operator, error)
2407
                ELSE
2408
                    IF e.obj = eCONST THEN
2409
                        CODE.Float(ARITH.Float(e.value));
2410
                        CODE.fcmp(CODE.opEQF + cmpcode(op) + 6)
2411
                    ELSIF e1.obj = eCONST THEN
2412
                        CODE.Float(ARITH.Float(e1.value));
2413
                        CODE.fcmp(CODE.opEQF + cmpcode(op))
2414
                    ELSE
2415
                        CODE.fcmp(CODE.opEQF + cmpcode(op))
2416
                    END
2417
                END
2418
 
2419
            ELSIF (isStringW(e) OR isCharArrayX(e)) & (isStringW(e1) OR isCharArrayX(e1)) THEN
2420
                IF ~strcmp(e, e1, op) THEN
2421
                    PARS.error(parser, pos, 37)
2422
                END
2423
 
2424
            ELSE
2425
                PARS.error(parser, pos, 37)
2426
            END
2427
 
2428
        |SCAN.lxIN:
2429
            PARS.check(isInt(e) & isSet(e1), parser, pos, 37);
2430
            IF e.obj = eCONST THEN
2431
                PARS.check(ARITH.range(e.value, 0, MACHINE.target.maxSet), parser, pos0, 56)
2432
            END;
2433
            IF constant THEN
2434
                ARITH.relation(e.value, e1.value, operator, error)
2435
            ELSE
2436
                IF e.obj = eCONST THEN
2437
                    CODE.AddCmd(CODE.opINL, ARITH.Int(e.value))
2438
                ELSIF e1.obj = eCONST THEN
2439
                    CODE.AddCmd(CODE.opINR, ARITH.Int(e1.value))
2440
                ELSE
2441
                    CODE.AddCmd0(CODE.opIN)
2442
                END
2443
            END
2444
 
2445
        |SCAN.lxIS:
2446
            PARS.check(isExpr(e) & (e.type.typ IN {PROG.tRECORD, PROG.tPOINTER}), parser, pos, 73);
2447
            IF e.type.typ = PROG.tRECORD THEN
2448
                PARS.check(e.obj = eVREC, parser, pos0, 78)
2449
            END;
2450
            PARS.check(e1.obj = eTYPE, parser, pos1, 79);
2451
 
2452
            IF e.type.typ = PROG.tRECORD THEN
2453
                PARS.check(e1.type.typ = PROG.tRECORD,  parser, pos1, 80);
2454
                IF e.ident = NIL THEN
2455
                    CODE.TypeCheck(e1.type.num)
2456
                ELSE
2457
                    CODE.AddCmd(CODE.opVADR, e.ident.offset - 1);
2458
                    CODE.TypeCheckRec(e1.type.num)
2459
                END
2460
            ELSE
2461
                PARS.check(e1.type.typ = PROG.tPOINTER, parser, pos1, 81);
2462
                CODE.TypeCheck(e1.type.base.num)
2463
            END;
2464
 
2465
            PARS.check(PROG.isBaseOf(e.type, e1.type), parser, pos1, 82)
2466
 
2467
        END;
2468
 
2469
        ASSERT(error = 0);
2470
 
2471
        e.type := PARS.program.stTypes.tBOOLEAN;
2472
 
2473
        IF ~constant THEN
2474
            e.obj := eEXPR
2475
        END
2476
 
2477
    END
2478
END expression;
2479
 
2480
 
2481
PROCEDURE ElementaryStatement (parser: PARS.PARSER);
2482
VAR
2483
    e, e1:    PARS.EXPR;
2484
    pos:      SCAN.POSITION;
2485
    line:     INTEGER;
2486
    call:     BOOLEAN;
2487
    fregs:    INTEGER;
2488
 
2489
BEGIN
2490
    getpos(parser, pos);
2491
 
2492
    CODE.pushBegEnd(begcall, endcall);
2493
 
2494
    designator(parser, e);
2495
 
2496
    IF parser.sym = SCAN.lxASSIGN THEN
2497
        line := parser.lex.pos.line;
2498
        PARS.check(isVar(e), parser, pos, 93);
2499
        PARS.check(~e.readOnly, parser, pos, 94);
2500
 
2501
        CODE.setlast(begcall);
2502
 
2503
        NextPos(parser, pos);
2504
        expression(parser, e1);
2505
 
2506
        CODE.setlast(endcall.prev(CODE.COMMAND));
2507
 
2508
        PARS.check(assign(e1, e.type, line), parser, pos, 91);
2509
        IF e1.obj = ePROC THEN
2510
            PARS.check(e1.ident.global, parser, pos, 85)
2511
        END;
2512
        call := FALSE
2513
    ELSIF parser.sym = SCAN.lxEQ THEN
2514
        PARS.check1(FALSE, parser, 96)
2515
    ELSIF parser.sym = SCAN.lxLROUND THEN
2516
        e1 := e;
2517
        ActualParameters(parser, e1);
2518
        PARS.check((e1.type = NIL) OR ODD(e.type.call), parser, pos, 92);
2519
        call := TRUE
2520
    ELSE
2521
        PARS.check(isProc(e), parser, pos, 86);
2522
        PARS.check((e.type.base = NIL) OR ODD(e.type.call), parser, pos, 92);
2523
        PARS.check1(e.type.params.first = NIL, parser, 64);
2524
        call := TRUE
2525
    END;
2526
 
2527
    IF call THEN
2528
        IF e.obj IN {ePROC, eIMP} THEN
2529
            ProcCall(e, e.ident.type, FALSE, fregs, parser, pos, TRUE)
2530
        ELSIF isExpr(e) THEN
2531
            ProcCall(e, e.type, FALSE, fregs, parser, pos, TRUE)
2532
        END
2533
    END;
2534
 
2535
    CODE.popBegEnd(begcall, endcall)
2536
END ElementaryStatement;
2537
 
2538
 
2539
PROCEDURE IfStatement (parser: PARS.PARSER; if: BOOLEAN);
2540
VAR
2541
    e:     PARS.EXPR;
2542
    pos:   SCAN.POSITION;
2543
 
2544
    label, L: INTEGER;
2545
 
2546
BEGIN
2547
    L := CODE.NewLabel();
2548
 
2549
    IF ~if THEN
2550
        CODE.AddCmd0(CODE.opLOOP);
2551
        CODE.SetLabel(L)
2552
    END;
2553
 
2554
    REPEAT
2555
        NextPos(parser, pos);
2556
 
2557
        label := CODE.NewLabel();
2558
 
2559
        expression(parser, e);
2560
        PARS.check(isBoolean(e), parser, pos, 72);
2561
 
2562
        IF e.obj = eCONST THEN
2563
            IF ~ARITH.getBool(e.value) THEN
2564
                CODE.AddJmpCmd(CODE.opJMP, label)
2565
            END
2566
        ELSE
2567
            CODE.AddJmpCmd(CODE.opJNE, label)
2568
        END;
2569
 
2570
        IF if THEN
2571
            PARS.checklex(parser, SCAN.lxTHEN)
2572
        ELSE
2573
            PARS.checklex(parser, SCAN.lxDO)
2574
        END;
2575
 
2576
        PARS.Next(parser);
2577
        parser.StatSeq(parser);
2578
 
2579
        CODE.AddJmpCmd(CODE.opJMP, L);
2580
        CODE.SetLabel(label)
2581
 
2582
    UNTIL parser.sym # SCAN.lxELSIF;
2583
 
2584
    IF if THEN
2585
        IF parser.sym = SCAN.lxELSE THEN
2586
            PARS.Next(parser);
2587
            parser.StatSeq(parser)
2588
        END;
2589
        CODE.SetLabel(L)
2590
    END;
2591
 
2592
    PARS.checklex(parser, SCAN.lxEND);
2593
 
2594
    IF ~if THEN
2595
        CODE.AddCmd0(CODE.opENDLOOP)
2596
    END;
2597
 
2598
    PARS.Next(parser)
2599
END IfStatement;
2600
 
2601
 
2602
PROCEDURE RepeatStatement (parser: PARS.PARSER);
2603
VAR
2604
    e:     PARS.EXPR;
2605
    pos:   SCAN.POSITION;
2606
    label: INTEGER;
2607
 
2608
BEGIN
2609
    CODE.AddCmd0(CODE.opLOOP);
2610
 
2611
    label := CODE.NewLabel();
2612
    CODE.SetLabel(label);
2613
 
2614
    PARS.Next(parser);
2615
    parser.StatSeq(parser);
2616
    PARS.checklex(parser, SCAN.lxUNTIL);
2617
    NextPos(parser, pos);
2618
    expression(parser, e);
2619
    PARS.check(isBoolean(e), parser, pos, 72);
2620
 
2621
    IF e.obj = eCONST THEN
2622
        IF ~ARITH.getBool(e.value) THEN
2623
            CODE.AddJmpCmd(CODE.opJMP, label)
2624
        END
2625
    ELSE
2626
        CODE.AddJmpCmd(CODE.opJNE, label)
2627
    END;
2628
 
2629
    CODE.AddCmd0(CODE.opENDLOOP)
2630
END RepeatStatement;
2631
 
2632
 
2633
PROCEDURE LabelCmp (a, b: AVL.DATA): INTEGER;
2634
VAR
2635
   La, Ra, Lb, Rb, res: INTEGER;
2636
 
2637
BEGIN
2638
    La := a(CASE_LABEL).range.a;
2639
    Ra := a(CASE_LABEL).range.b;
2640
    Lb := b(CASE_LABEL).range.a;
2641
    Rb := b(CASE_LABEL).range.b;
2642
    IF (Ra < Lb) OR (La > Rb) THEN
2643
        res := ORD(La > Lb) - ORD(La < Lb)
2644
    ELSE
2645
        res := 0
2646
    END
2647
 
2648
    RETURN res
2649
END LabelCmp;
2650
 
2651
 
2652
PROCEDURE DestroyLabel (VAR label: AVL.DATA);
2653
BEGIN
2654
    C.push(CaseLabels, label);
2655
    label := NIL
2656
END DestroyLabel;
2657
 
2658
 
2659
PROCEDURE NewVariant (label: INTEGER; cmd: CODE.COMMAND): CASE_VARIANT;
2660
VAR
2661
    res:   CASE_VARIANT;
2662
    citem: C.ITEM;
2663
 
2664
BEGIN
2665
    citem := C.pop(CaseVar);
2666
    IF citem = NIL THEN
2667
        NEW(res)
2668
    ELSE
2669
        res := citem(CASE_VARIANT)
2670
    END;
2671
 
2672
    res.label := label;
2673
    res.cmd := cmd;
2674
    res.processed := FALSE
2675
 
2676
    RETURN res
2677
END NewVariant;
2678
 
2679
 
2680
PROCEDURE CaseStatement (parser: PARS.PARSER);
2681
VAR
2682
    e:      PARS.EXPR;
2683
    pos:    SCAN.POSITION;
2684
 
2685
 
2686
    PROCEDURE isRecPtr (caseExpr: PARS.EXPR): BOOLEAN;
2687
        RETURN isRec(caseExpr) OR isPtr(caseExpr)
2688
    END isRecPtr;
2689
 
2690
 
2691
    PROCEDURE Label (parser: PARS.PARSER; caseExpr: PARS.EXPR; VAR type: PROG.TYPE_): INTEGER;
2692
    VAR
2693
        a:      INTEGER;
2694
        label:  PARS.EXPR;
2695
        pos:    SCAN.POSITION;
2696
        value:  ARITH.VALUE;
2697
 
2698
    BEGIN
2699
        getpos(parser, pos);
2700
        type := NIL;
2701
 
2702
        IF isChar(caseExpr) THEN
2703
            PARS.ConstExpression(parser, value);
2704
            PARS.check(value.typ = ARITH.tCHAR, parser, pos, 99);
2705
            a := ARITH.getInt(value)
2706
        ELSIF isCharW(caseExpr) THEN
2707
            PARS.ConstExpression(parser, value);
2708
            IF (value.typ = ARITH.tSTRING) & (_length(value.string(SCAN.IDENT).s) = 1) & (LENGTH(value.string(SCAN.IDENT).s) > 1) THEN
2709
                ASSERT(ARITH.setInt(value, StrToWChar(value.string(SCAN.IDENT).s)))
2710
            ELSE
2711
                PARS.check(value.typ IN {ARITH.tWCHAR, ARITH.tCHAR}, parser, pos, 99)
2712
            END;
2713
            a := ARITH.getInt(value)
2714
        ELSIF isInt(caseExpr) THEN
2715
            PARS.ConstExpression(parser, value);
2716
            PARS.check(value.typ = ARITH.tINTEGER, parser, pos, 99);
2717
            a := ARITH.getInt(value)
2718
        ELSIF isRecPtr(caseExpr) THEN
2719
            qualident(parser, label);
2720
            PARS.check(label.obj = eTYPE, parser, pos, 79);
2721
            PARS.check(PROG.isBaseOf(caseExpr.type, label.type), parser, pos, 99);
2722
            IF isRec(caseExpr) THEN
2723
                a := label.type.num
2724
            ELSE
2725
                a := label.type.base.num
2726
            END;
2727
            type := label.type
2728
        END
2729
 
2730
        RETURN a
2731
    END Label;
2732
 
2733
 
2734
    PROCEDURE CheckType (node: AVL.NODE; type: PROG.TYPE_; parser: PARS.PARSER; pos: SCAN.POSITION);
2735
    BEGIN
2736
        IF node # NIL THEN
2737
            PARS.check(~(PROG.isBaseOf(node.data(CASE_LABEL).type, type) OR PROG.isBaseOf(type, node.data(CASE_LABEL).type)), parser, pos, 100);
2738
            CheckType(node.left, type, parser, pos);
2739
            CheckType(node.right, type, parser, pos)
2740
        END
2741
    END CheckType;
2742
 
2743
 
2744
    PROCEDURE LabelRange (parser: PARS.PARSER; caseExpr: PARS.EXPR; VAR tree: AVL.NODE; variant: INTEGER): AVL.NODE;
2745
    VAR
2746
        label:     CASE_LABEL;
2747
        citem:     C.ITEM;
2748
        pos, pos1: SCAN.POSITION;
2749
        node:      AVL.NODE;
2750
        newnode:   BOOLEAN;
2751
        range:     RANGE;
2752
 
2753
    BEGIN
2754
        citem := C.pop(CaseLabels);
2755
        IF citem = NIL THEN
2756
            NEW(label)
2757
        ELSE
2758
            label := citem(CASE_LABEL)
2759
        END;
2760
 
2761
        label.variant := variant;
2762
        label.self := CODE.NewLabel();
2763
 
2764
        getpos(parser, pos1);
2765
        range.a := Label(parser, caseExpr, label.type);
2766
 
2767
        IF parser.sym = SCAN.lxRANGE THEN
2768
            PARS.check1(~isRecPtr(caseExpr), parser, 53);
2769
            NextPos(parser, pos);
2770
            range.b := Label(parser, caseExpr, label.type);
2771
            PARS.check(range.a <= range.b, parser, pos, 103)
2772
        ELSE
2773
            range.b := range.a
2774
        END;
2775
 
2776
        label.range := range;
2777
 
2778
        IF isRecPtr(caseExpr) THEN
2779
            CheckType(tree, label.type, parser, pos1)
2780
        END;
2781
        tree := AVL.insert(tree, label, LabelCmp, newnode, node);
2782
        PARS.check(newnode, parser, pos1, 100)
2783
 
2784
        RETURN node
2785
 
2786
    END LabelRange;
2787
 
2788
 
2789
    PROCEDURE CaseLabelList (parser: PARS.PARSER; caseExpr: PARS.EXPR; VAR tree: AVL.NODE; variant: INTEGER): AVL.NODE;
2790
    VAR
2791
        exit: BOOLEAN;
2792
        res:  AVL.NODE;
2793
 
2794
    BEGIN
2795
        exit := FALSE;
2796
        REPEAT
2797
            res := LabelRange(parser, caseExpr, tree, variant);
2798
            IF parser.sym = SCAN.lxCOMMA THEN
2799
                PARS.check1(~isRecPtr(caseExpr), parser, 53);
2800
                PARS.Next(parser)
2801
            ELSE
2802
                exit := TRUE
2803
            END
2804
        UNTIL exit
2805
 
2806
        RETURN res
2807
    END CaseLabelList;
2808
 
2809
 
2810
    PROCEDURE case (parser: PARS.PARSER; caseExpr: PARS.EXPR; VAR tree: AVL.NODE; end: INTEGER);
2811
    VAR
2812
        sym:      INTEGER;
2813
        t:        PROG.TYPE_;
2814
        variant:  INTEGER;
2815
        node:     AVL.NODE;
2816
        last:     CODE.COMMAND;
2817
 
2818
    BEGIN
2819
        sym := parser.sym;
2820
        IF sym # SCAN.lxBAR THEN
2821
            variant := CODE.NewLabel();
2822
            node := CaseLabelList(parser, caseExpr, tree, variant);
2823
            PARS.checklex(parser, SCAN.lxCOLON);
2824
            PARS.Next(parser);
2825
            IF isRecPtr(caseExpr) THEN
2826
                t := caseExpr.type;
2827
                caseExpr.ident.type := node.data(CASE_LABEL).type
2828
            END;
2829
 
2830
            last := CODE.getlast();
2831
            CODE.SetLabel(variant);
2832
 
2833
            IF ~isRecPtr(caseExpr) THEN
2834
                LISTS.push(CaseVariants, NewVariant(variant, last))
2835
            END;
2836
 
2837
            parser.StatSeq(parser);
2838
            CODE.AddJmpCmd(CODE.opJMP, end);
2839
 
2840
            IF isRecPtr(caseExpr) THEN
2841
                caseExpr.ident.type := t
2842
            END
2843
        END
2844
    END case;
2845
 
2846
 
2847
    PROCEDURE Table (node: AVL.NODE; else: INTEGER);
2848
    VAR
2849
        L, R: INTEGER;
2850
        range: RANGE;
2851
        left, right: AVL.NODE;
2852
        last: CODE.COMMAND;
2853
        v: CASE_VARIANT;
2854
 
2855
    BEGIN
2856
        IF node # NIL THEN
2857
 
2858
            range := node.data(CASE_LABEL).range;
2859
 
2860
            left := node.left;
2861
            IF left # NIL THEN
2862
                L := left.data(CASE_LABEL).self
2863
            ELSE
2864
                L := else
2865
            END;
2866
 
2867
            right := node.right;
2868
            IF right # NIL THEN
2869
                R := right.data(CASE_LABEL).self
2870
            ELSE
2871
                R := else
2872
            END;
2873
 
2874
            last := CODE.getlast();
2875
 
2876
            v := CaseVariants.last(CASE_VARIANT);
2877
            WHILE (v # NIL) & (v.label # 0) & (v.label # node.data(CASE_LABEL).variant) DO
2878
                v := v.prev(CASE_VARIANT)
2879
            END;
2880
 
2881
            ASSERT((v # NIL) & (v.label # 0));
2882
            CODE.setlast(v.cmd);
2883
 
2884
            CODE.SetLabel(node.data(CASE_LABEL).self);
2885
            CODE.case(range.a, range.b, L, R);
2886
            IF v.processed THEN
2887
                CODE.AddJmpCmd(CODE.opJMP, node.data(CASE_LABEL).variant)
2888
            END;
2889
            v.processed := TRUE;
2890
 
2891
            CODE.setlast(last);
2892
 
2893
            Table(left, else);
2894
            Table(right, else)
2895
        END
2896
    END Table;
2897
 
2898
 
2899
    PROCEDURE TableT (node: AVL.NODE);
2900
    BEGIN
2901
        IF node # NIL THEN
2902
            CODE.caset(node.data(CASE_LABEL).range.a, node.data(CASE_LABEL).variant);
2903
 
2904
            TableT(node.left);
2905
            TableT(node.right)
2906
        END
2907
    END TableT;
2908
 
2909
 
2910
    PROCEDURE ParseCase (parser: PARS.PARSER; e: PARS.EXPR; pos: SCAN.POSITION);
2911
    VAR
2912
        table, end, else: INTEGER;
2913
        tree: AVL.NODE;
2914
        item:  LISTS.ITEM;
2915
 
2916
    BEGIN
2917
        LISTS.push(CaseVariants, NewVariant(0, NIL));
2918
        end   := CODE.NewLabel();
2919
        else  := CODE.NewLabel();
2920
        table := CODE.NewLabel();
2921
        CODE.AddCmd(CODE.opSWITCH, ORD(isRecPtr(e)));
2922
        CODE.AddJmpCmd(CODE.opJMP, table);
2923
 
2924
        tree := NIL;
2925
 
2926
        case(parser, e, tree, end);
2927
        WHILE parser.sym = SCAN.lxBAR DO
2928
            PARS.Next(parser);
2929
            case(parser, e, tree, end)
2930
        END;
2931
 
2932
        CODE.SetLabel(else);
2933
        IF parser.sym = SCAN.lxELSE THEN
2934
            PARS.Next(parser);
2935
            parser.StatSeq(parser);
2936
            CODE.AddJmpCmd(CODE.opJMP, end)
2937
        ELSE
2938
            CODE.OnError(pos.line, errCASE)
2939
        END;
2940
 
2941
        PARS.checklex(parser, SCAN.lxEND);
2942
        PARS.Next(parser);
2943
 
2944
        IF isRecPtr(e) THEN
2945
            CODE.SetLabel(table);
2946
            TableT(tree);
2947
            CODE.AddJmpCmd(CODE.opJMP, else)
2948
        ELSE
2949
            tree.data(CASE_LABEL).self := table;
2950
            Table(tree, else)
2951
        END;
2952
 
2953
        AVL.destroy(tree, DestroyLabel);
2954
        CODE.SetLabel(end);
2955
        CODE.AddCmd0(CODE.opENDSW);
2956
 
2957
        REPEAT
2958
            item := LISTS.pop(CaseVariants);
2959
            C.push(CaseVar, item)
2960
        UNTIL item(CASE_VARIANT).cmd = NIL
2961
 
2962
    END ParseCase;
2963
 
2964
 
2965
BEGIN
2966
    NextPos(parser, pos);
2967
    expression(parser, e);
2968
    PARS.check(isInt(e) OR isChar(e) OR isCharW(e) OR isPtr(e) OR isRec(e), parser, pos, 95);
2969
    IF isRecPtr(e) THEN
2970
        PARS.check(isVar(e), parser, pos, 93);
2971
        PARS.check(e.ident # NIL, parser, pos, 106)
2972
    END;
2973
    IF isRec(e) THEN
2974
        PARS.check(e.obj = eVREC, parser, pos, 78)
2975
    END;
2976
 
2977
    IF e.obj = eCONST THEN
2978
        LoadConst(e)
2979
    ELSIF isRec(e) THEN
2980
        CODE.drop;
2981
        CODE.AddCmd(CODE.opLADR, e.ident.offset - 1);
2982
        CODE.load(PARS.program.target.word)
2983
    ELSIF isPtr(e) THEN
2984
        deref(pos, e, FALSE, errPTR);
2985
        CODE.AddCmd(CODE.opSUBR, PARS.program.target.word);
2986
        CODE.load(PARS.program.target.word)
2987
    END;
2988
 
2989
    PARS.checklex(parser, SCAN.lxOF);
2990
    PARS.Next(parser);
2991
    ParseCase(parser, e, pos)
2992
END CaseStatement;
2993
 
2994
 
2995
PROCEDURE ForStatement (parser: PARS.PARSER);
2996
VAR
2997
    e:       PARS.EXPR;
2998
    pos:     SCAN.POSITION;
2999
    step:    ARITH.VALUE;
3000
    st:      INTEGER;
3001
    ident:   PROG.IDENT;
3002
    offset:  INTEGER;
3003
    L1, L2:  INTEGER;
3004
 
3005
BEGIN
3006
    CODE.AddCmd0(CODE.opLOOP);
3007
 
3008
    L1 := CODE.NewLabel();
3009
    L2 := CODE.NewLabel();
3010
 
3011
    PARS.ExpectSym(parser, SCAN.lxIDENT);
3012
    ident := parser.unit.idents.get(parser.unit, parser.lex.ident, TRUE);
3013
    PARS.check1(ident # NIL, parser, 48);
3014
    PARS.check1(ident.typ = PROG.idVAR, parser, 93);
3015
    PARS.check1(ident.type.typ = PROG.tINTEGER, parser, 97);
3016
    PARS.ExpectSym(parser, SCAN.lxASSIGN);
3017
    NextPos(parser, pos);
3018
    expression(parser, e);
3019
    PARS.check(isInt(e), parser, pos, 76);
3020
 
3021
    offset := PROG.getOffset(PARS.program, ident);
3022
 
3023
    IF ident.global THEN
3024
        CODE.AddCmd(CODE.opGADR, offset)
3025
    ELSE
3026
        CODE.AddCmd(CODE.opLADR, -offset)
3027
    END;
3028
 
3029
    IF e.obj = eCONST THEN
3030
        CODE.AddCmd(CODE.opSAVEC, ARITH.Int(e.value))
3031
    ELSE
3032
        CODE.AddCmd0(CODE.opSAVE)
3033
    END;
3034
 
3035
    CODE.SetLabel(L1);
3036
 
3037
    IF ident.global THEN
3038
        CODE.AddCmd(CODE.opGADR, offset)
3039
    ELSE
3040
        CODE.AddCmd(CODE.opLADR, -offset)
3041
    END;
3042
    CODE.load(ident.type.size);
3043
 
3044
    PARS.checklex(parser, SCAN.lxTO);
3045
    NextPos(parser, pos);
3046
    expression(parser, e);
3047
    PARS.check(isInt(e), parser, pos, 76);
3048
 
3049
    IF parser.sym = SCAN.lxBY THEN
3050
        NextPos(parser, pos);
3051
        PARS.ConstExpression(parser, step);
3052
        PARS.check(step.typ = ARITH.tINTEGER, parser, pos, 76);
3053
        st := ARITH.getInt(step);
3054
        PARS.check(st # 0, parser, pos, 98)
3055
    ELSE
3056
        st := 1
3057
    END;
3058
 
3059
    IF e.obj = eCONST THEN
3060
        IF st > 0 THEN
3061
            CODE.AddCmd(CODE.opLER, ARITH.Int(e.value))
3062
        ELSE
3063
            CODE.AddCmd(CODE.opGER, ARITH.Int(e.value))
3064
        END
3065
    ELSE
3066
        IF st > 0 THEN
3067
            CODE.AddCmd0(CODE.opLE)
3068
        ELSE
3069
            CODE.AddCmd0(CODE.opGE)
3070
        END
3071
    END;
3072
 
3073
    CODE.AddJmpCmd(CODE.opJNE, L2);
3074
 
3075
    PARS.checklex(parser, SCAN.lxDO);
3076
    PARS.Next(parser);
3077
    parser.StatSeq(parser);
3078
 
3079
    IF ident.global THEN
3080
        CODE.AddCmd(CODE.opGADR, offset)
3081
    ELSE
3082
        CODE.AddCmd(CODE.opLADR, -offset)
3083
    END;
3084
 
3085
    IF st = 1 THEN
3086
        CODE.AddCmd0(CODE.opINC1)
3087
    ELSIF st = -1 THEN
3088
        CODE.AddCmd0(CODE.opDEC1)
3089
    ELSE
3090
        IF st > 0 THEN
3091
            CODE.AddCmd(CODE.opINCC, st)
3092
        ELSE
3093
            CODE.AddCmd(CODE.opDECC, -st)
3094
        END
3095
    END;
3096
 
3097
    CODE.AddJmpCmd(CODE.opJMP, L1);
3098
 
3099
    PARS.checklex(parser, SCAN.lxEND);
3100
    PARS.Next(parser);
3101
 
3102
    CODE.SetLabel(L2);
3103
 
3104
    CODE.AddCmd0(CODE.opENDLOOP)
3105
 
3106
END ForStatement;
3107
 
3108
 
3109
PROCEDURE statement (parser: PARS.PARSER);
3110
VAR
3111
    sym: INTEGER;
3112
 
3113
BEGIN
3114
    sym := parser.sym;
3115
 
3116
    IF sym = SCAN.lxIDENT THEN
3117
        ElementaryStatement(parser)
3118
    ELSIF sym = SCAN.lxIF THEN
3119
        IfStatement(parser, TRUE)
3120
    ELSIF sym = SCAN.lxWHILE THEN
3121
        IfStatement(parser, FALSE)
3122
    ELSIF sym = SCAN.lxREPEAT THEN
3123
        RepeatStatement(parser)
3124
    ELSIF sym = SCAN.lxCASE THEN
3125
        CaseStatement(parser)
3126
    ELSIF sym = SCAN.lxFOR THEN
3127
        ForStatement(parser)
3128
    END
3129
END statement;
3130
 
3131
 
3132
PROCEDURE StatSeq (parser: PARS.PARSER);
3133
BEGIN
3134
    statement(parser);
3135
    WHILE parser.sym = SCAN.lxSEMI DO
3136
        PARS.Next(parser);
3137
        statement(parser)
3138
    END
3139
END StatSeq;
3140
 
3141
 
3142
PROCEDURE chkreturn (parser: PARS.PARSER; e: PARS.EXPR; t: PROG.TYPE_; pos: SCAN.POSITION): BOOLEAN;
3143
VAR
3144
    res: BOOLEAN;
3145
 
3146
BEGIN
3147
    res := assigncomp(e, t);
3148
    IF res THEN
3149
        IF e.obj = eCONST THEN
3150
            IF e.type.typ = PROG.tREAL THEN
3151
                CODE.Float(ARITH.Float(e.value))
3152
            ELSIF e.type.typ = PROG.tNIL THEN
3153
                CODE.AddCmd(CODE.opCONST, 0)
3154
            ELSE
3155
                LoadConst(e)
3156
            END
3157
        ELSIF (e.type.typ = PROG.tINTEGER) & (t.typ = PROG.tBYTE) & (chkBYTE IN checking) THEN
3158
            CheckRange(256, pos.line, errBYTE)
3159
        ELSIF e.obj = ePROC THEN
3160
            PARS.check(e.ident.global, parser, pos, 85);
3161
            CODE.PushProc(e.ident.proc.label)
3162
        ELSIF e.obj = eIMP THEN
3163
            CODE.PushImpProc(e.ident.import)
3164
        END;
3165
 
3166
        IF e.type.typ = PROG.tREAL THEN
3167
            CODE.retf
3168
        END
3169
    END
3170
 
3171
    RETURN res
3172
END chkreturn;
3173
 
3174
 
3175
PROCEDURE setrtl;
3176
VAR
3177
    rtl: PROG.UNIT;
3178
 
3179
 
3180
    PROCEDURE getproc (rtl: PROG.UNIT; name: SCAN.LEXSTR; idx: INTEGER);
3181
    VAR
3182
        id:    PROG.IDENT;
3183
 
3184
    BEGIN
3185
        id := rtl.idents.get(rtl, SCAN.enterid(name), FALSE);
3186
 
3187
        IF (id # NIL) & (id.import # NIL) THEN
3188
            CODE.codes.rtl[idx] := -id.import(CODE.IMPORT_PROC).label;
3189
            id.proc.used := TRUE
3190
        ELSIF (id # NIL) & (id.proc # NIL) THEN
3191
            CODE.codes.rtl[idx] := id.proc.label;
3192
            id.proc.used := TRUE
3193
        ELSE
3194
            ERRORS.error5("procedure ", mConst.RTL_NAME, ".", name, " not found")
3195
        END
3196
    END getproc;
3197
 
3198
 
3199
BEGIN
3200
    rtl := PARS.program.rtl;
3201
    ASSERT(rtl # NIL);
3202
 
3203
    getproc(rtl,  "_move",      CODE._move);
3204
    getproc(rtl,  "_move2",     CODE._move2);
3205
    getproc(rtl,  "_set",       CODE._set);
3206
    getproc(rtl,  "_set2",      CODE._set2);
3207
    getproc(rtl,  "_div",       CODE._div);
3208
    getproc(rtl,  "_mod",       CODE._mod);
3209
    getproc(rtl,  "_div2",      CODE._div2);
3210
    getproc(rtl,  "_mod2",      CODE._mod2);
3211
    getproc(rtl,  "_arrcpy",    CODE._arrcpy);
3212
    getproc(rtl,  "_rot",       CODE._rot);
3213
    getproc(rtl,  "_new",       CODE._new);
3214
    getproc(rtl,  "_dispose",   CODE._dispose);
3215
    getproc(rtl,  "_strcmp",    CODE._strcmp);
3216
    getproc(rtl,  "_error",     CODE._error);
3217
    getproc(rtl,  "_is",        CODE._is);
3218
    getproc(rtl,  "_isrec",     CODE._isrec);
3219
    getproc(rtl,  "_guard",     CODE._guard);
3220
    getproc(rtl,  "_guardrec",  CODE._guardrec);
3221
    getproc(rtl,  "_length",    CODE._length);
3222
    getproc(rtl,  "_init",      CODE._init);
3223
    getproc(rtl,  "_dllentry",  CODE._dllentry);
3224
    getproc(rtl,  "_strcpy",    CODE._strcpy);
3225
    getproc(rtl,  "_exit",      CODE._exit);
3226
    getproc(rtl,  "_strcpy2",   CODE._strcpy2);
3227
    getproc(rtl,  "_lengthw",   CODE._lengthw);
3228
    getproc(rtl,  "_strcmp2",   CODE._strcmp2);
3229
    getproc(rtl,  "_strcmpw",   CODE._strcmpw);
3230
    getproc(rtl,  "_strcmpw2",  CODE._strcmpw2);
3231
 
3232
END setrtl;
3233
 
3234
 
3235
PROCEDURE compile* (path, lib_path, modname, outname: PARS.PATH; target, version, stack, base: INTEGER; pic: BOOLEAN; chk: SET);
3236
VAR
3237
    parser:  PARS.PARSER;
3238
    ext: PARS.PATH;
3239
    amd64: BOOLEAN;
3240
 
3241
BEGIN
3242
    amd64 := target IN {mConst.Target_iConsole64, mConst.Target_iGUI64, mConst.Target_iDLL64, mConst.Target_iELF64};
3243
    ext := mConst.FILE_EXT;
3244
    CaseLabels := C.create();
3245
    CaseVar := C.create();
3246
 
3247
    CaseVariants := LISTS.create(NIL);
3248
    LISTS.push(CaseVariants, NewVariant(0, NIL));
3249
 
3250
    checking := chk;
3251
 
3252
    IF amd64 THEN
3253
        CODE.init(6, CODE.little_endian)
3254
    ELSE
3255
        CODE.init(8, CODE.little_endian)
3256
    END;
3257
 
3258
    parser := PARS.create(path, lib_path, StatSeq, expression, designator, chkreturn);
3259
    IF parser.open(parser, mConst.RTL_NAME) THEN
3260
        parser.parse(parser);
3261
        PARS.destroy(parser)
3262
    ELSE
3263
        PARS.destroy(parser);
3264
        parser := PARS.create(lib_path, lib_path, StatSeq, expression, designator, chkreturn);
3265
        IF parser.open(parser, mConst.RTL_NAME) THEN
3266
            parser.parse(parser);
3267
            PARS.destroy(parser)
3268
        ELSE
3269
            ERRORS.error5("file ", lib_path, mConst.RTL_NAME, mConst.FILE_EXT, " not found")
3270
        END
3271
    END;
3272
 
3273
    parser := PARS.create(path, lib_path, StatSeq, expression, designator, chkreturn);
3274
    parser.main := TRUE;
3275
 
3276
    IF parser.open(parser, modname) THEN
3277
        parser.parse(parser)
3278
    ELSE
3279
        ERRORS.error5("file ", path, modname, mConst.FILE_EXT, " not found")
3280
    END;
3281
 
3282
    PARS.destroy(parser);
3283
 
3284
    IF PARS.program.bss > mConst.MAX_GLOBAL_SIZE THEN
3285
        ERRORS.error1("size of global variables is too large")
3286
    END;
3287
 
3288
    setrtl;
3289
 
3290
    PROG.DelUnused(PARS.program, CODE.DelImport);
3291
 
3292
    CODE.codes.bss := PARS.program.bss;
3293
    IF amd64 THEN
3294
        AMD64.CodeGen(CODE.codes, outname, target, stack, base)
3295
    ELSE
3296
        X86.CodeGen(CODE.codes, outname, target, stack, base, version, pic)
3297
    END
3298
END compile;
3299
 
3300
 
3301
END STATEMENTS.