Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | 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 PROG;
9
 
10
IMPORT SCAN, LISTS, ARITH, ERRORS, MACHINE, C := COLLECTIONS, mConst := CONSTANTS, CODE, UTILS;
11
 
12
 
13
CONST
14
 
15
    MAXARRDIM*    = 5;
16
    MAXSCOPE      = 16;
17
    MAXSYSVPARAM* = 26;
18
 
19
    idNONE*    =  0;  idGUARD   =  1;  idMODULE* =  2;  idCONST*   =  3;
20
    idTYPE*    =  4;  idSTFUNC* =  5;  idSTPROC* =  6;  idVAR*     =  7;
21
    idPROC*    =  8;  idVPAR*   =  9;  idPARAM*  = 10;  idSYSFUNC* = 11;
22
    idSYSPROC* = 12;  idIMP*    = 13;
23
 
24
    tINTEGER* =  1;  tBYTE*      =  2;  tCHAR*   =  3;  tSET*    =  4;
25
    tBOOLEAN* =  5;  tREAL*      =  6;  tARRAY*  =  7;  tRECORD* =  8;
26
    tPOINTER* =  9;  tPROCEDURE* = 10;  tSTRING* = 11;  tNIL*    = 12;
27
    tCARD16*  = 13;  tCARD32*    = 14;  tANYREC* = 15;  tWCHAR*  = 16;
28
 
29
    BASICTYPES* = {tINTEGER, tBYTE, tCHAR, tSET, tBOOLEAN, tREAL, tCARD16, tCARD32, tWCHAR};
30
 
31
    stABS*  =  1;  stASR*  =  2;  stCHR*    =  3;  stFLOOR* =  4;
32
    stFLT*  =  5;  stLEN*  =  6;  stLSL*    =  7;  stODD*   =  8;
33
    stORD*  =  9;  stROR*  = 10;  stASSERT* = 11;  stDEC*   = 12;
34
    stEXCL* = 13;  stINC*  = 14;  stINCL*   = 15;  stNEW*   = 16;
35
    stPACK* = 17;  stUNPK* = 18;  sysADR*   = 19;  sysSIZE* = 20;
36
    sysGET* = 21;  sysPUT* = 22;
37
 
38
    stDISPOSE* = 23;  stLSR*     = 24;  stBITS*  = 25;  sysCODE*  = 26;
39
    sysMOVE*   = 27;  stLENGTH*  = 28;  stMIN*   = 29;  stMAX*    = 30;
40
    sysSADR*   = 31;  sysTYPEID* = 32;  sysCOPY* = 33;  sysINF*   = 34;
41
    sysPUT8*   = 35;  sysPUT16*  = 36;  stCOPY*  = 37;  stWCHR*   = 38;
42
    sysWSADR*  = 39;  sysPUT32*  = 40;
43
 
44
    default*   =  2;
45
    stdcall*   =  4;  _stdcall*   = stdcall + 1;
46
    ccall*     =  6;  _ccall*     = ccall + 1;
47
    ccall16*   =  8;  _ccall16*   = ccall16 + 1;
48
    win64*     = 10;  _win64*     = win64 + 1;
49
    stdcall64* = 12;  _stdcall64* = stdcall64 + 1;
50
    default64* = 14;
51
    systemv*   = 16;  _systemv*   = systemv + 1;
52
 
53
    noalign* = 20;
54
 
55
    callee_clean_up* = {default, stdcall, _stdcall, default64, stdcall64, _stdcall64};
56
    caller_clean_up* = {ccall, ccall16, win64, systemv, _ccall, _ccall16, _win64, _systemv};
57
    callconv32* = {default, stdcall, ccall, ccall16, _stdcall, _ccall, _ccall16};
58
    callconv64* = {default64, win64, stdcall64, systemv, _win64, _stdcall64, _systemv};
59
 
60
    STACK_FRAME = 2;
61
 
62
 
63
TYPE
64
 
65
    IDENT* = POINTER TO rIDENT;
66
 
67
    UNIT* = POINTER TO rUNIT;
68
 
69
    PROGRAM* = POINTER TO rPROGRAM;
70
 
71
    TYPE_* = POINTER TO rTYPE_;
72
 
73
    FRWPTR* = POINTER TO RECORD (LISTS.ITEM)
74
 
75
        type:        TYPE_;
76
        baseIdent:   SCAN.IDENT;
77
        linked:      BOOLEAN;
78
 
79
        pos*:        SCAN.POSITION;
80
        notRecord*:  BOOLEAN
81
 
82
    END;
83
 
84
    IDENTS = POINTER TO RECORD (LISTS.LIST)
85
 
86
        add*:   PROCEDURE (unit: UNIT; ident: SCAN.IDENT; typ: INTEGER): IDENT;
87
        get*:   PROCEDURE (unit: UNIT; ident: SCAN.IDENT; currentScope: BOOLEAN): IDENT
88
 
89
    END;
90
 
91
    PROC* = POINTER TO RECORD (LISTS.ITEM)
92
 
93
        label*:      INTEGER;
94
        used*:       BOOLEAN;
95
        processed*:  BOOLEAN;
96
        import*:     LISTS.ITEM;
97
        using*:      LISTS.LIST;
98
        enter*,
99
        leave*:      LISTS.ITEM
100
 
101
    END;
102
 
103
    USED_PROC = POINTER TO RECORD (LISTS.ITEM)
104
 
105
        proc: PROC
106
 
107
    END;
108
 
109
    rUNIT = RECORD (LISTS.ITEM)
110
 
111
        program*:    PROGRAM;
112
        name*:       SCAN.IDENT;
113
        idents*:     IDENTS;
114
        frwPointers: LISTS.LIST;
115
        gscope:      IDENT;
116
        closed*:     BOOLEAN;
117
        scopeLvl*:   INTEGER;
118
        sysimport*:  BOOLEAN;
119
 
120
        scopes*:     ARRAY MAXSCOPE OF PROC;
121
 
122
        scope*:      RECORD
123
 
124
            open*:   PROCEDURE (unit: UNIT; proc: PROC): BOOLEAN;
125
            close*:  PROCEDURE (unit: UNIT; variables: LISTS.LIST)
126
 
127
        END;
128
 
129
        close*:      PROCEDURE (unit: UNIT);
130
        setvars*:    PROCEDURE (unit: UNIT; type: TYPE_);
131
 
132
        pointers*:   RECORD
133
 
134
            add*:    PROCEDURE (unit: UNIT; type: TYPE_; baseIdent: SCAN.IDENT; pos: SCAN.POSITION);
135
            link*:   PROCEDURE (unit: UNIT): FRWPTR
136
 
137
        END
138
 
139
    END;
140
 
141
    FIELD* = POINTER TO rFIELD;
142
 
143
    PARAM* = POINTER TO rPARAM;
144
 
145
    FIELDS = POINTER TO RECORD (LISTS.LIST)
146
 
147
        add*:        PROCEDURE (rec: TYPE_; name: SCAN.IDENT; export: BOOLEAN): BOOLEAN;
148
        get*:        PROCEDURE (rec: TYPE_; name: SCAN.IDENT; unit: UNIT): FIELD;
149
        set*:        PROCEDURE (rec: TYPE_; type: TYPE_): BOOLEAN
150
 
151
    END;
152
 
153
    PARAMS = POINTER TO RECORD (LISTS.LIST)
154
 
155
        size*:       INTEGER;
156
 
157
        add*:        PROCEDURE (proc: TYPE_; name: SCAN.IDENT; vPar: BOOLEAN): BOOLEAN;
158
        get*:        PROCEDURE (proc: TYPE_; name: SCAN.IDENT): PARAM;
159
        set*:        PROCEDURE (proc: TYPE_; type: TYPE_);
160
        getfparams*: PROCEDURE (proc: TYPE_; maxparam: INTEGER; VAR int, flt: INTEGER): SET
161
 
162
    END;
163
 
164
    rTYPE_ = RECORD (LISTS.ITEM)
165
 
166
        typ*:        INTEGER;
167
        size*:       INTEGER;
168
        length*:     INTEGER;
169
        align*:      INTEGER;
170
        base*:       TYPE_;
171
        fields*:     FIELDS;
172
        params*:     PARAMS;
173
        unit*:       UNIT;
174
        closed*:     BOOLEAN;
175
        num*:        INTEGER;
176
        call*:       INTEGER;
177
        import*:     BOOLEAN;
178
        noalign*:    BOOLEAN
179
 
180
    END;
181
 
182
    rFIELD = RECORD (LISTS.ITEM)
183
 
184
        type*:       TYPE_;
185
        name*:       SCAN.IDENT;
186
        export*:     BOOLEAN;
187
        offset*:     INTEGER
188
 
189
    END;
190
 
191
    rPARAM = RECORD (LISTS.ITEM)
192
 
193
        name*:       SCAN.IDENT;
194
        type*:       TYPE_;
195
        vPar*:       BOOLEAN;
196
        offset*:     INTEGER
197
 
198
    END;
199
 
200
    rIDENT = RECORD (LISTS.ITEM)
201
 
202
        name*:       SCAN.IDENT;
203
        typ*:        INTEGER;
204
        export*:     BOOLEAN;
205
        import*:     LISTS.ITEM;
206
        unit*:       UNIT;
207
        value*:      ARITH.VALUE;
208
        type*:       TYPE_;
209
        stproc*:     INTEGER;
210
        global*:     BOOLEAN;
211
        scopeLvl*:   INTEGER;
212
        offset*:     INTEGER;
213
        proc*:       PROC;
214
        pos*:        SCAN.POSITION
215
 
216
    END;
217
 
218
    UNITS* = POINTER TO RECORD (LISTS.LIST)
219
 
220
        program:     PROGRAM;
221
 
222
        create*:     PROCEDURE (units: UNITS; name: SCAN.IDENT): UNIT;
223
        get*:        PROCEDURE (units: UNITS; name: SCAN.IDENT): UNIT
224
 
225
    END;
226
 
227
    rPROGRAM = RECORD
228
 
229
        recCount:    INTEGER;
230
        units*:      UNITS;
231
        types*:      LISTS.LIST;
232
        sysunit*:    UNIT;
233
        rtl*:        UNIT;
234
        bss*:        INTEGER;
235
        locsize*:    INTEGER;
236
 
237
        procs*:      LISTS.LIST;
238
        dll*:        BOOLEAN;
239
        obj*:        BOOLEAN;
240
 
241
        stTypes*:     RECORD
242
 
243
            tINTEGER*, tBYTE*, tCHAR*, tWCHAR*, tSET*, tBOOLEAN*, tREAL*, tSTRING*, tNIL*,
244
            tCARD16*, tCARD32*, tANYREC*: TYPE_
245
 
246
        END;
247
 
248
        target*:     RECORD
249
 
250
            bit_depth*:  INTEGER;
251
            word*:       INTEGER;
252
            adr*:        INTEGER;
253
            sys*:        INTEGER
254
 
255
        END;
256
 
257
        enterType*:  PROCEDURE (program: PROGRAM; typ, size, length: INTEGER; unit: UNIT): TYPE_;
258
        getType*:    PROCEDURE (program: PROGRAM; typ: INTEGER): TYPE_
259
 
260
    END;
261
 
262
    DELIMPORT = PROCEDURE (import: LISTS.ITEM);
263
 
264
 
265
VAR
266
 
267
    idents: C.COLLECTION;
268
 
269
 
270
PROCEDURE NewIdent (): IDENT;
271
VAR
272
    ident: IDENT;
273
    citem: C.ITEM;
274
 
275
BEGIN
276
    citem := C.pop(idents);
277
    IF citem = NIL THEN
278
        NEW(ident)
279
    ELSE
280
        ident := citem(IDENT)
281
    END
282
 
283
    RETURN ident
284
END NewIdent;
285
 
286
 
287
PROCEDURE getOffset* (program: PROGRAM; varIdent: IDENT): INTEGER;
288
VAR
289
    word: INTEGER;
290
    size: INTEGER;
291
 
292
BEGIN
293
    IF varIdent.offset = -1 THEN
294
        IF varIdent.global THEN
295
            IF MACHINE.Align(program.bss, varIdent.type.align) THEN
296
                IF UTILS.maxint - program.bss >= varIdent.type.size THEN
297
                    varIdent.offset := program.bss;
298
                    INC(program.bss, varIdent.type.size)
299
                END
300
            END
301
        ELSE
302
            word := program.target.word;
303
            size := varIdent.type.size;
304
            IF MACHINE.Align(size, word) THEN
305
                size := size DIV word;
306
                IF UTILS.maxint - program.locsize >= size THEN
307
                    INC(program.locsize, size);
308
                    varIdent.offset := program.locsize;
309
                END
310
            END
311
        END
312
    END
313
 
314
    RETURN varIdent.offset
315
END getOffset;
316
 
317
 
318
PROCEDURE close (unit: UNIT);
319
VAR
320
    ident, prev: IDENT;
321
    offset: INTEGER;
322
 
323
BEGIN
324
    ident := unit.idents.last(IDENT);
325
    WHILE (ident # NIL) & (ident.typ # idGUARD) DO
326
        IF (ident.typ = idVAR) & (ident.offset = -1) THEN
327
            ERRORS.hintmsg(ident.name.s, ident.pos.line, ident.pos.col, 0);
328
            IF ident.export THEN
329
                offset := getOffset(unit.program, ident)
330
            END
331
        END;
332
        ident := ident.prev(IDENT)
333
    END;
334
 
335
    ident := unit.idents.last(IDENT);
336
    WHILE ident # NIL DO
337
        prev := ident.prev(IDENT);
338
        IF ~ident.export THEN
339
            LISTS.delete(unit.idents, ident);
340
            C.push(idents, ident)
341
        END;
342
        ident := prev
343
    END;
344
 
345
    unit.closed := TRUE
346
END close;
347
 
348
 
349
PROCEDURE unique (unit: UNIT; ident: SCAN.IDENT): BOOLEAN;
350
VAR
351
    item: IDENT;
352
 
353
BEGIN
354
    ASSERT(ident # NIL);
355
 
356
    item := unit.idents.last(IDENT);
357
    WHILE (item.typ # idGUARD) & (item.name # ident) DO
358
        item := item.prev(IDENT)
359
    END
360
 
361
    RETURN item.typ = idGUARD
362
END unique;
363
 
364
 
365
PROCEDURE addIdent (unit: UNIT; ident: SCAN.IDENT; typ: INTEGER): IDENT;
366
VAR
367
    item:   IDENT;
368
    res:    BOOLEAN;
369
    proc:   PROC;
370
    procs:  LISTS.LIST;
371
 
372
BEGIN
373
    ASSERT(unit # NIL);
374
    ASSERT(ident # NIL);
375
 
376
    res := unique(unit, ident);
377
 
378
    IF res THEN
379
        item := NewIdent();
380
 
381
        item.name   := ident;
382
        item.typ    := typ;
383
        item.unit   := NIL;
384
        item.export := FALSE;
385
        item.import := NIL;
386
        item.type   := NIL;
387
        item.value.typ := 0;
388
        item.stproc := 0;
389
 
390
        item.global := unit.scopeLvl = 0;
391
        item.scopeLvl := unit.scopeLvl;
392
        item.offset := -1;
393
 
394
        IF item.typ IN {idPROC, idIMP} THEN
395
            NEW(proc);
396
            proc.import := NIL;
397
            proc.label := 0;
398
            proc.used := FALSE;
399
            proc.processed := FALSE;
400
            proc.using := LISTS.create(NIL);
401
            procs := unit.program.procs;
402
            LISTS.push(procs, proc);
403
            item.proc := proc
404
        END;
405
 
406
        LISTS.push(unit.idents, item)
407
    ELSE
408
        item := NIL
409
    END
410
 
411
    RETURN item
412
END addIdent;
413
 
414
 
415
PROCEDURE UseProc* (unit: UNIT; call_proc: PROC);
416
VAR
417
    procs:    LISTS.LIST;
418
    cur:      LISTS.ITEM;
419
    proc:     USED_PROC;
420
 
421
BEGIN
422
    IF unit.scopeLvl = 0 THEN
423
        call_proc.used := TRUE
424
    ELSE
425
        procs := unit.scopes[unit.scopeLvl].using;
426
 
427
        cur := procs.first;
428
        WHILE (cur # NIL) & (cur(USED_PROC).proc # call_proc) DO
429
            cur := cur.next
430
        END;
431
 
432
        IF cur = NIL THEN
433
            NEW(proc);
434
            proc.proc := call_proc;
435
            LISTS.push(procs, proc)
436
        END
437
    END
438
END UseProc;
439
 
440
 
441
PROCEDURE setvars (unit: UNIT; type: TYPE_);
442
VAR
443
    item: IDENT;
444
 
445
BEGIN
446
    ASSERT(type # NIL);
447
 
448
    item := unit.idents.last(IDENT);
449
    WHILE (item # NIL) & (item.typ = idVAR) & (item.type = NIL) DO
450
        item.type := type;
451
        item := item.prev(IDENT)
452
    END
453
END setvars;
454
 
455
 
456
PROCEDURE getIdent (unit: UNIT; ident: SCAN.IDENT; currentScope: BOOLEAN): IDENT;
457
VAR
458
    item: IDENT;
459
 
460
BEGIN
461
    ASSERT(ident # NIL);
462
 
463
    item := unit.idents.last(IDENT);
464
 
465
    ASSERT(item # NIL);
466
 
467
    IF currentScope THEN
468
        WHILE (item.name # ident) & (item.typ # idGUARD) DO
469
            item := item.prev(IDENT)
470
        END;
471
        IF item.name # ident THEN
472
            item := NIL
473
        END
474
    ELSE
475
        WHILE (item # NIL) & (item.name # ident) DO
476
            item := item.prev(IDENT)
477
        END
478
    END
479
 
480
    RETURN item
481
END getIdent;
482
 
483
 
484
PROCEDURE openScope (unit: UNIT; proc: PROC): BOOLEAN;
485
VAR
486
    item: IDENT;
487
    res:  BOOLEAN;
488
 
489
BEGIN
490
    INC(unit.scopeLvl);
491
 
492
    res := unit.scopeLvl < MAXSCOPE;
493
 
494
    IF res THEN
495
 
496
        unit.scopes[unit.scopeLvl] := proc;
497
 
498
        NEW(item);
499
        item := NewIdent();
500
 
501
        item.name := NIL;
502
        item.typ  := idGUARD;
503
 
504
        LISTS.push(unit.idents, item)
505
    END
506
 
507
    RETURN res
508
END openScope;
509
 
510
 
511
PROCEDURE closeScope (unit: UNIT; variables: LISTS.LIST);
512
VAR
513
    item: IDENT;
514
    del:  IDENT;
515
    lvar: CODE.LOCALVAR;
516
 
517
BEGIN
518
    item := unit.idents.last(IDENT);
519
 
520
    WHILE (item # NIL) & (item.typ # idGUARD) DO
521
        del  := item;
522
        item := item.prev(IDENT);
523
        IF (del.typ = idVAR) & (del.offset = -1) THEN
524
            ERRORS.hintmsg(del.name.s, del.pos.line, del.pos.col, 0)
525
        END;
526
        IF (variables # NIL) & (del.typ IN {idVAR, idPARAM}) & (del.offset # -1) THEN
527
            IF del.type.typ IN BASICTYPES - {tREAL} + {tPOINTER, tPROCEDURE} THEN
528
                lvar := CODE.NewVar();
529
                lvar.offset := del.offset;
530
                lvar.size   := del.type.size;
531
                IF del.typ = idVAR THEN
532
                    lvar.offset := -lvar.offset
533
                END;
534
                LISTS.push(variables, lvar)
535
            END
536
        END;
537
        LISTS.delete(unit.idents, del);
538
        C.push(idents, del)
539
    END;
540
 
541
    IF (item # NIL) & (item.typ = idGUARD) THEN
542
        LISTS.delete(unit.idents, item);
543
        C.push(idents, item)
544
    END;
545
 
546
    DEC(unit.scopeLvl)
547
 
548
END closeScope;
549
 
550
 
551
PROCEDURE frwptr (unit: UNIT; type: TYPE_; baseIdent: SCAN.IDENT; pos: SCAN.POSITION);
552
VAR
553
    newptr: FRWPTR;
554
 
555
BEGIN
556
    ASSERT(unit # NIL);
557
    ASSERT(type # NIL);
558
    ASSERT(baseIdent # NIL);
559
 
560
    NEW(newptr);
561
 
562
    newptr.type       := type;
563
    newptr.baseIdent  := baseIdent;
564
    newptr.pos        := pos;
565
    newptr.linked     := FALSE;
566
    newptr.notRecord  := FALSE;
567
 
568
    LISTS.push(unit.frwPointers, newptr)
569
END frwptr;
570
 
571
 
572
PROCEDURE linkptr (unit: UNIT): FRWPTR;
573
VAR
574
    item:  FRWPTR;
575
    ident: IDENT;
576
    res:   FRWPTR;
577
 
578
BEGIN
579
    res  := NIL;
580
    item := unit.frwPointers.last(FRWPTR);
581
 
582
    WHILE (item # NIL) & ~item.linked & (res = NIL) DO
583
        ident := unit.idents.get(unit, item.baseIdent, TRUE);
584
 
585
        IF (ident # NIL) THEN
586
            IF (ident.typ = idTYPE) & (ident.type.typ = tRECORD) THEN
587
                item.type.base := ident.type;
588
                item.linked := TRUE
589
            ELSE
590
                item.notRecord := TRUE;
591
                res := item
592
            END
593
        ELSE
594
            item.notRecord := FALSE;
595
            res := item
596
        END;
597
 
598
        item := item.prev(FRWPTR)
599
    END
600
 
601
    RETURN res
602
END linkptr;
603
 
604
 
605
PROCEDURE isTypeEq* (t1, t2: TYPE_): BOOLEAN;
606
VAR
607
    res: BOOLEAN;
608
    param1, param2: LISTS.ITEM;
609
 
610
BEGIN
611
    IF t1 = t2 THEN
612
        res := TRUE
613
    ELSIF (t1 = NIL) OR (t2 = NIL) THEN
614
        res := FALSE
615
    ELSIF (t1.typ = tPROCEDURE) & (t2.typ = tPROCEDURE) THEN
616
 
617
        param1 := t1.params.first;
618
        param2 := t2.params.first;
619
 
620
        res := (t1.call = t2.call) & ((param1 # NIL) = (param2 # NIL));
621
 
622
        WHILE res & (param1 # NIL) & (param2 # NIL) DO
623
            res := (param1(PARAM).vPar = param2(PARAM).vPar) & isTypeEq(param1(PARAM).type, param2(PARAM).type);
624
            param1 := param1.next;
625
            param2 := param2.next;
626
            res := res & ((param1 # NIL) = (param2 # NIL))
627
        END;
628
 
629
        res := res & isTypeEq(t1.base, t2.base)
630
 
631
    ELSIF (t1.typ = tARRAY) & (t2.typ = tARRAY) THEN
632
        res := (t1.length = 0) & (t2.length = 0) & isTypeEq(t1.base, t2.base)
633
    ELSE
634
        res := FALSE
635
    END
636
 
637
    RETURN res
638
END isTypeEq;
639
 
640
 
641
PROCEDURE isBaseOf* (t0, t1: TYPE_): BOOLEAN;
642
VAR
643
    res: BOOLEAN;
644
 
645
BEGIN
646
    res := ((t0.typ = tPOINTER) & (t1.typ = tPOINTER)) OR ((t0.typ = tRECORD) & (t1.typ = tRECORD));
647
 
648
    IF (t0.typ = tPOINTER) & (t1.typ = tPOINTER) THEN
649
        t0 := t0.base;
650
        t1 := t1.base
651
    END;
652
 
653
    WHILE res & (t1 # NIL) & (t1 # t0) DO
654
        t1 := t1.base
655
    END
656
 
657
    RETURN res & (t1 = t0)
658
END isBaseOf;
659
 
660
 
661
PROCEDURE isOpenArray* (t: TYPE_): BOOLEAN;
662
    RETURN (t.typ = tARRAY) & (t.length = 0)
663
END isOpenArray;
664
 
665
 
666
PROCEDURE getunit (units: UNITS; name: SCAN.IDENT): UNIT;
667
VAR
668
    item: UNIT;
669
 
670
BEGIN
671
    ASSERT(name # NIL);
672
 
673
    item := units.first(UNIT);
674
 
675
    WHILE (item # NIL) & (item.name # name) DO
676
        item := item.next(UNIT)
677
    END;
678
 
679
    IF (item = NIL) & (name.s = "SYSTEM") THEN
680
        item := units.program.sysunit
681
    END
682
 
683
    RETURN item
684
END getunit;
685
 
686
 
687
PROCEDURE enterStTypes (unit: UNIT; program: PROGRAM);
688
VAR
689
    ident:   IDENT;
690
    stName:  SCAN.IDENT;
691
 
692
BEGIN
693
 
694
    stName     := SCAN.enterid("INTEGER");
695
    ident      := addIdent(unit, stName, idTYPE);
696
    ident.type := program.stTypes.tINTEGER;
697
 
698
    stName     := SCAN.enterid("BYTE");
699
    ident      := addIdent(unit, stName, idTYPE);
700
    ident.type := program.stTypes.tBYTE;
701
 
702
    stName     := SCAN.enterid("CHAR");
703
    ident      := addIdent(unit, stName, idTYPE);
704
    ident.type := program.stTypes.tCHAR;
705
 
706
    stName     := SCAN.enterid("WCHAR");
707
    ident      := addIdent(unit, stName, idTYPE);
708
    ident.type := program.stTypes.tWCHAR;
709
 
710
    stName     := SCAN.enterid("SET");
711
    ident      := addIdent(unit, stName, idTYPE);
712
    ident.type := program.stTypes.tSET;
713
 
714
    stName     := SCAN.enterid("BOOLEAN");
715
    ident      := addIdent(unit, stName, idTYPE);
716
    ident.type := program.stTypes.tBOOLEAN;
717
 
718
    stName     := SCAN.enterid("REAL");
719
    ident      := addIdent(unit, stName, idTYPE);
720
    ident.type := program.stTypes.tREAL;
721
 
722
END enterStTypes;
723
 
724
 
725
PROCEDURE enterStProcs (unit: UNIT);
726
 
727
 
728
    PROCEDURE EnterProc (unit: UNIT; name: SCAN.LEXSTR; idtyp, proc: INTEGER);
729
    VAR
730
        ident: IDENT;
731
    BEGIN
732
        ident := addIdent(unit, SCAN.enterid(name), idtyp);
733
        ident.stproc := proc
734
    END EnterProc;
735
 
736
 
737
BEGIN
738
    EnterProc(unit, "ASSERT",   idSTPROC,  stASSERT);
739
    EnterProc(unit, "DEC",      idSTPROC,  stDEC);
740
    EnterProc(unit, "EXCL",     idSTPROC,  stEXCL);
741
    EnterProc(unit, "INC",      idSTPROC,  stINC);
742
    EnterProc(unit, "INCL",     idSTPROC,  stINCL);
743
    EnterProc(unit, "NEW",      idSTPROC,  stNEW);
744
    EnterProc(unit, "PACK",     idSTPROC,  stPACK);
745
    EnterProc(unit, "UNPK",     idSTPROC,  stUNPK);
746
    EnterProc(unit, "DISPOSE",  idSTPROC,  stDISPOSE);
747
    EnterProc(unit, "COPY",     idSTPROC,  stCOPY);
748
 
749
    EnterProc(unit, "ABS",      idSTFUNC,  stABS);
750
    EnterProc(unit, "ASR",      idSTFUNC,  stASR);
751
    EnterProc(unit, "CHR",      idSTFUNC,  stCHR);
752
    EnterProc(unit, "WCHR",     idSTFUNC,  stWCHR);
753
    EnterProc(unit, "FLOOR",    idSTFUNC,  stFLOOR);
754
    EnterProc(unit, "FLT",      idSTFUNC,  stFLT);
755
    EnterProc(unit, "LEN",      idSTFUNC,  stLEN);
756
    EnterProc(unit, "LSL",      idSTFUNC,  stLSL);
757
    EnterProc(unit, "ODD",      idSTFUNC,  stODD);
758
    EnterProc(unit, "ORD",      idSTFUNC,  stORD);
759
    EnterProc(unit, "ROR",      idSTFUNC,  stROR);
760
    EnterProc(unit, "BITS",     idSTFUNC,  stBITS);
761
    EnterProc(unit, "LSR",      idSTFUNC,  stLSR);
762
    EnterProc(unit, "LENGTH",   idSTFUNC,  stLENGTH);
763
    EnterProc(unit, "MIN",      idSTFUNC,  stMIN);
764
    EnterProc(unit, "MAX",      idSTFUNC,  stMAX);
765
END enterStProcs;
766
 
767
 
768
PROCEDURE newunit (units: UNITS; name: SCAN.IDENT): UNIT;
769
VAR
770
    unit:    UNIT;
771
    idents:  IDENTS;
772
 
773
BEGIN
774
    ASSERT(units # NIL);
775
    ASSERT(name # NIL);
776
 
777
    NEW(unit);
778
 
779
    NEW(idents);
780
    ASSERT(LISTS.create(idents) = idents);
781
 
782
    idents.add       := addIdent;
783
    idents.get       := getIdent;
784
 
785
    unit.program     := units.program;
786
    unit.name        := name;
787
    unit.closed      := FALSE;
788
    unit.idents      := idents;
789
    unit.frwPointers := LISTS.create(NIL);
790
 
791
    unit.scope.open    := openScope;
792
    unit.scope.close   := closeScope;
793
    unit.close         := close;
794
    unit.setvars       := setvars;
795
    unit.pointers.add  := frwptr;
796
    unit.pointers.link := linkptr;
797
 
798
    ASSERT(unit.scope.open(unit, NIL));
799
 
800
    enterStTypes(unit, units.program);
801
    enterStProcs(unit);
802
 
803
    ASSERT(unit.scope.open(unit, NIL));
804
 
805
    unit.gscope := unit.idents.last(IDENT);
806
 
807
    LISTS.push(units, unit);
808
 
809
    unit.scopeLvl := 0;
810
    unit.scopes[0] := NIL;
811
 
812
    unit.sysimport := FALSE;
813
 
814
    IF unit.name.s = mConst.RTL_NAME THEN
815
        unit.program.rtl := unit
816
    END
817
 
818
    RETURN unit
819
END newunit;
820
 
821
 
822
PROCEDURE getField (self: TYPE_; name: SCAN.IDENT; unit: UNIT): FIELD;
823
VAR
824
    field:  FIELD;
825
 
826
BEGIN
827
    ASSERT(self # NIL);
828
    ASSERT(name # NIL);
829
    ASSERT(unit # NIL);
830
 
831
    field := NIL;
832
    WHILE (self # NIL) & (field = NIL) DO
833
 
834
        field := self.fields.first(FIELD);
835
 
836
        WHILE (field # NIL) & (field.name # name) DO
837
            field := field.next(FIELD)
838
        END;
839
 
840
        IF field = NIL THEN
841
            self := self.base
842
        END
843
 
844
    END;
845
 
846
    IF (field # NIL) & (self.unit # unit) & ~field.export THEN
847
        field := NIL
848
    END
849
 
850
    RETURN field
851
END getField;
852
 
853
 
854
PROCEDURE addField (self: TYPE_; name: SCAN.IDENT; export: BOOLEAN): BOOLEAN;
855
VAR
856
    field:  FIELD;
857
    res:    BOOLEAN;
858
 
859
BEGIN
860
    ASSERT(name # NIL);
861
 
862
    res := getField(self, name, self.unit) = NIL;
863
 
864
    IF res THEN
865
        NEW(field);
866
 
867
        field.name   := name;
868
        field.export := export;
869
        field.type   := NIL;
870
        field.offset := self.size;
871
 
872
        LISTS.push(self.fields, field)
873
    END
874
 
875
    RETURN res
876
END addField;
877
 
878
 
879
PROCEDURE setFields (self: TYPE_; type: TYPE_): BOOLEAN;
880
VAR
881
    item: FIELD;
882
    res:  BOOLEAN;
883
 
884
BEGIN
885
    ASSERT(type # NIL);
886
 
887
    item := self.fields.first(FIELD);
888
 
889
    WHILE (item # NIL) & (item.type # NIL) DO
890
        item := item.next(FIELD)
891
    END;
892
 
893
    res := TRUE;
894
 
895
    WHILE res & (item # NIL) & (item.type = NIL) DO
896
        item.type := type;
897
        IF ~self.noalign THEN
898
            res := MACHINE.Align(self.size, type.align)
899
        ELSE
900
            res := TRUE
901
        END;
902
        item.offset := self.size;
903
        res := res & (UTILS.maxint - self.size >= type.size);
904
        IF res THEN
905
            INC(self.size, type.size)
906
        END;
907
        item := item.next(FIELD)
908
    END
909
 
910
    RETURN res
911
END setFields;
912
 
913
 
914
PROCEDURE getParam (self: TYPE_; name: SCAN.IDENT): PARAM;
915
VAR
916
    item:   PARAM;
917
 
918
BEGIN
919
    ASSERT(name # NIL);
920
 
921
    item := self.params.first(PARAM);
922
 
923
    WHILE (item # NIL) & (item.name # name) DO
924
        item := item.next(PARAM)
925
    END
926
 
927
    RETURN item
928
END getParam;
929
 
930
 
931
PROCEDURE addParam (self: TYPE_; name: SCAN.IDENT; vPar: BOOLEAN): BOOLEAN;
932
VAR
933
    param:  PARAM;
934
    res:    BOOLEAN;
935
 
936
BEGIN
937
    ASSERT(name # NIL);
938
 
939
    res := self.params.get(self, name) = NIL;
940
 
941
    IF res THEN
942
        NEW(param);
943
 
944
        param.name := name;
945
        param.type := NIL;
946
        param.vPar := vPar;
947
 
948
        LISTS.push(self.params, param)
949
    END
950
 
951
    RETURN res
952
END addParam;
953
 
954
 
955
PROCEDURE Dim* (t: TYPE_): INTEGER;
956
VAR
957
    res: INTEGER;
958
 
959
BEGIN
960
    res := 0;
961
    WHILE isOpenArray(t) DO
962
        t := t.base;
963
        INC(res)
964
    END
965
    RETURN res
966
END Dim;
967
 
968
 
969
PROCEDURE OpenBase* (t: TYPE_): TYPE_;
970
BEGIN
971
    WHILE isOpenArray(t) DO t := t.base END
972
    RETURN t
973
END OpenBase;
974
 
975
 
976
PROCEDURE getFloatParamsPos (self: TYPE_; maxoffs: INTEGER; VAR int, flt: INTEGER): SET;
977
VAR
978
    res: SET;
979
    param: PARAM;
980
 
981
BEGIN
982
    res := {};
983
    int := 0;
984
    flt := 0;
985
    param := self.params.first(PARAM);
986
    WHILE (param # NIL) & (param.offset <= maxoffs + STACK_FRAME) DO
987
        IF ~param.vPar & (param.type.typ = tREAL) THEN
988
            INCL(res, param.offset - STACK_FRAME);
989
            INC(flt)
990
        END;
991
        param := param.next(PARAM)
992
    END;
993
 
994
    int := self.params.size - flt
995
 
996
    RETURN res
997
END getFloatParamsPos;
998
 
999
 
1000
PROCEDURE setParams (self: TYPE_; type: TYPE_);
1001
VAR
1002
    item: LISTS.ITEM;
1003
    param: PARAM;
1004
    word, size: INTEGER;
1005
 
1006
BEGIN
1007
    ASSERT(type # NIL);
1008
 
1009
    word := MACHINE.target.bit_depth DIV 8;
1010
 
1011
    item := self.params.first;
1012
 
1013
    WHILE (item # NIL) & (item(PARAM).type # NIL) DO
1014
        item := item.next
1015
    END;
1016
 
1017
    WHILE (item # NIL) & (item(PARAM).type = NIL) DO
1018
        param := item(PARAM);
1019
        param.type := type;
1020
        IF param.vPar THEN
1021
            IF type.typ = tRECORD THEN
1022
                size := 2
1023
            ELSIF isOpenArray(type) THEN
1024
                size := Dim(type) + 1
1025
            ELSE
1026
                size := 1
1027
            END;
1028
            param.offset := self.params.size + ORD(type.typ = tRECORD) + Dim(type) + STACK_FRAME;
1029
            INC(self.params.size, size)
1030
        ELSE
1031
            IF type.typ IN {tRECORD, tARRAY} THEN
1032
                IF isOpenArray(type) THEN
1033
                    size := Dim(type) + 1
1034
                ELSE
1035
                    size := 1
1036
                END
1037
            ELSE
1038
                size := type.size;
1039
                ASSERT(MACHINE.Align(size, word));
1040
                size := size DIV word
1041
            END;
1042
            param.offset := self.params.size + Dim(type) + STACK_FRAME;
1043
            INC(self.params.size, size)
1044
        END;
1045
 
1046
        item := item.next
1047
    END
1048
 
1049
END setParams;
1050
 
1051
 
1052
PROCEDURE enterType (program: PROGRAM; typ, size, length: INTEGER; unit: UNIT): TYPE_;
1053
VAR
1054
    t:        TYPE_;
1055
    fields:   FIELDS;
1056
    params:   PARAMS;
1057
 
1058
BEGIN
1059
    NEW(t);
1060
 
1061
    NEW(fields);
1062
    ASSERT(LISTS.create(fields) = fields);
1063
 
1064
    NEW(params);
1065
    ASSERT(LISTS.create(params) = params);
1066
 
1067
    t.typ     := typ;
1068
    t.size    := size;
1069
    t.length  := length;
1070
    t.align   := 0;
1071
    t.base    := NIL;
1072
    t.fields  := fields;
1073
    t.params  := params;
1074
    t.unit    := unit;
1075
    t.num     := 0;
1076
    IF program.target.bit_depth = 32 THEN
1077
        t.call := default
1078
    ELSIF program.target.bit_depth = 64 THEN
1079
        t.call := default64
1080
    END;
1081
    t.import  := FALSE;
1082
    t.noalign := FALSE;
1083
 
1084
    t.fields.add := addField;
1085
    t.fields.get := getField;
1086
    t.fields.set := setFields;
1087
 
1088
    t.params.add := addParam;
1089
    t.params.get := getParam;
1090
    t.params.getfparams := getFloatParamsPos;
1091
    t.params.set := setParams;
1092
    t.params.size := 0;
1093
 
1094
    IF typ IN {tARRAY, tRECORD} THEN
1095
        t.closed := FALSE;
1096
        IF typ = tRECORD THEN
1097
            INC(program.recCount);
1098
            t.num := program.recCount
1099
        END
1100
    ELSE
1101
        t.closed := TRUE
1102
    END;
1103
 
1104
    LISTS.push(program.types, t)
1105
 
1106
    RETURN t
1107
END enterType;
1108
 
1109
 
1110
PROCEDURE getType (program: PROGRAM; typ: INTEGER): TYPE_;
1111
VAR
1112
    res: TYPE_;
1113
 
1114
BEGIN
1115
 
1116
    IF typ = ARITH.tINTEGER THEN
1117
        res := program.stTypes.tINTEGER
1118
    ELSIF typ = ARITH.tREAL THEN
1119
        res := program.stTypes.tREAL
1120
    ELSIF typ = ARITH.tSET THEN
1121
        res := program.stTypes.tSET
1122
    ELSIF typ = ARITH.tBOOLEAN THEN
1123
        res := program.stTypes.tBOOLEAN
1124
    ELSIF typ = ARITH.tCHAR THEN
1125
        res := program.stTypes.tCHAR
1126
    ELSIF typ = ARITH.tWCHAR THEN
1127
        res := program.stTypes.tWCHAR
1128
    ELSIF typ = ARITH.tSTRING THEN
1129
        res := program.stTypes.tSTRING
1130
    ELSE
1131
        res := NIL
1132
    END;
1133
 
1134
    ASSERT(res # NIL)
1135
 
1136
    RETURN res
1137
END getType;
1138
 
1139
 
1140
PROCEDURE createSysUnit (program: PROGRAM);
1141
VAR
1142
    ident: IDENT;
1143
    unit:  UNIT;
1144
 
1145
 
1146
    PROCEDURE EnterProc (sys: UNIT; name: SCAN.LEXSTR; idtyp, proc: INTEGER);
1147
    VAR
1148
        ident: IDENT;
1149
    BEGIN
1150
        ident := addIdent(sys, SCAN.enterid(name), idtyp);
1151
        ident.stproc := proc;
1152
        ident.export := TRUE
1153
    END EnterProc;
1154
 
1155
 
1156
BEGIN
1157
    unit := program.units.create(program.units, SCAN.enterid("$SYSTEM"));
1158
 
1159
    EnterProc(unit, "ADR",    idSYSFUNC, sysADR);
1160
    EnterProc(unit, "SIZE",   idSYSFUNC, sysSIZE);
1161
    EnterProc(unit, "SADR",   idSYSFUNC, sysSADR);
1162
    EnterProc(unit, "WSADR",  idSYSFUNC, sysWSADR);
1163
    EnterProc(unit, "TYPEID", idSYSFUNC, sysTYPEID);
1164
    EnterProc(unit, "INF",    idSYSFUNC, sysINF);
1165
 
1166
    EnterProc(unit, "GET",    idSYSPROC, sysGET);
1167
    EnterProc(unit, "PUT",    idSYSPROC, sysPUT);
1168
    EnterProc(unit, "PUT8",   idSYSPROC, sysPUT8);
1169
    EnterProc(unit, "PUT16",  idSYSPROC, sysPUT16);
1170
    EnterProc(unit, "PUT32",  idSYSPROC, sysPUT32);
1171
    EnterProc(unit, "CODE",   idSYSPROC, sysCODE);
1172
    EnterProc(unit, "MOVE",   idSYSPROC, sysMOVE);
1173
    EnterProc(unit, "COPY",   idSYSPROC, sysCOPY);
1174
 
1175
    ident := addIdent(unit, SCAN.enterid("CARD16"), idTYPE);
1176
    ident.type := program.stTypes.tCARD16;
1177
    ident.export := TRUE;
1178
 
1179
    ident := addIdent(unit, SCAN.enterid("CARD32"), idTYPE);
1180
    ident.type := program.stTypes.tCARD32;
1181
    ident.export := TRUE;
1182
 
1183
    unit.close(unit);
1184
 
1185
    program.sysunit := unit
1186
END createSysUnit;
1187
 
1188
 
1189
PROCEDURE DelUnused* (program: PROGRAM; DelImport: DELIMPORT);
1190
VAR
1191
    proc:   PROC;
1192
    flag:   BOOLEAN;
1193
 
1194
 
1195
    PROCEDURE process (proc: PROC);
1196
    VAR
1197
        used_proc: LISTS.ITEM;
1198
 
1199
    BEGIN
1200
        proc.processed := TRUE;
1201
 
1202
        used_proc := proc.using.first;
1203
        WHILE used_proc # NIL DO
1204
            used_proc(USED_PROC).proc.used := TRUE;
1205
            used_proc := used_proc.next
1206
        END
1207
 
1208
    END process;
1209
 
1210
 
1211
BEGIN
1212
 
1213
    REPEAT
1214
 
1215
        flag := FALSE;
1216
        proc := program.procs.first(PROC);
1217
 
1218
        WHILE proc # NIL DO
1219
            IF proc.used & ~proc.processed THEN
1220
                process(proc);
1221
                flag := TRUE
1222
            END;
1223
            proc := proc.next(PROC)
1224
        END
1225
 
1226
    UNTIL ~flag;
1227
 
1228
    proc := program.procs.first(PROC);
1229
 
1230
    WHILE proc # NIL DO
1231
        IF ~proc.used THEN
1232
            IF proc.import = NIL THEN
1233
                CODE.delete2(proc.enter, proc.leave)
1234
            ELSE
1235
                DelImport(proc.import)
1236
            END
1237
        END;
1238
        proc := proc.next(PROC)
1239
    END
1240
 
1241
END DelUnused;
1242
 
1243
 
1244
PROCEDURE create* (bit_depth, sys: INTEGER): PROGRAM;
1245
VAR
1246
    program: PROGRAM;
1247
    units:   UNITS;
1248
 
1249
BEGIN
1250
    idents := C.create();
1251
 
1252
    MACHINE.SetBitDepth(bit_depth);
1253
    NEW(program);
1254
    NEW(units);
1255
    ASSERT(LISTS.create(units) = units);
1256
 
1257
    program.target.bit_depth := bit_depth;
1258
    program.target.word      := bit_depth DIV 8;
1259
    program.target.adr       := bit_depth DIV 8;
1260
    program.target.sys       := sys;
1261
 
1262
    program.recCount := -1;
1263
    program.bss := 0;
1264
 
1265
    program.units := units;
1266
    program.types := LISTS.create(NIL);
1267
 
1268
    program.procs := LISTS.create(NIL);
1269
 
1270
    program.enterType := enterType;
1271
    program.getType   := getType;
1272
 
1273
    program.stTypes.tINTEGER := enterType(program, tINTEGER,  program.target.word, 0, NIL);
1274
    program.stTypes.tBYTE    := enterType(program, tBYTE,                       1, 0, NIL);
1275
    program.stTypes.tCHAR    := enterType(program, tCHAR,                       1, 0, NIL);
1276
    program.stTypes.tWCHAR   := enterType(program, tWCHAR,                      2, 0, NIL);
1277
    program.stTypes.tSET     := enterType(program, tSET,      program.target.word, 0, NIL);
1278
    program.stTypes.tBOOLEAN := enterType(program, tBOOLEAN,                    1, 0, NIL);
1279
    program.stTypes.tREAL    := enterType(program, tREAL,                       8, 0, NIL);
1280
    program.stTypes.tSTRING  := enterType(program, tSTRING,   program.target.word, 0, NIL);
1281
    program.stTypes.tNIL     := enterType(program, tNIL,      program.target.word, 0, NIL);
1282
    program.stTypes.tCARD16  := enterType(program, tCARD16,                     2, 0, NIL);
1283
    program.stTypes.tCARD32  := enterType(program, tCARD32,                     4, 0, NIL);
1284
    program.stTypes.tANYREC  := enterType(program, tRECORD,                     0, 0, NIL);
1285
    program.stTypes.tANYREC.closed := TRUE;
1286
 
1287
    program.stTypes.tINTEGER.align := program.stTypes.tINTEGER.size;
1288
    program.stTypes.tBYTE.align    := 1;
1289
    program.stTypes.tCHAR.align    := program.stTypes.tCHAR.size;
1290
    program.stTypes.tWCHAR.align   := program.stTypes.tWCHAR.size;
1291
    program.stTypes.tSET.align     := program.stTypes.tSET.size;
1292
    program.stTypes.tBOOLEAN.align := program.stTypes.tBOOLEAN.size;
1293
    program.stTypes.tREAL.align    := program.stTypes.tREAL.size;
1294
    program.stTypes.tCARD16.align   := program.stTypes.tCARD16.size;
1295
    program.stTypes.tCARD32.align   := program.stTypes.tCARD32.size;
1296
 
1297
    units.program := program;
1298
 
1299
    units.create := newunit;
1300
    units.get    := getunit;
1301
 
1302
    program.dll := FALSE;
1303
    program.obj := FALSE;
1304
 
1305
    createSysUnit(program)
1306
 
1307
    RETURN program
1308
END create;
1309
 
1310
 
1311
END PROG.