Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
7983 leency 1
(*
7597 akron1 2
    BSD 2-Clause License
3
 
7983 leency 4
    Copyright (c) 2018-2020, Anton Krotov
7597 akron1 5
    All rights reserved.
6
*)
7
 
8
MODULE PARS;
9
 
7983 leency 10
IMPORT PROG, SCAN, ARITH, STRINGS, ERRORS, LISTS, IL, CONSOLE, PATHS, UTILS,
11
       C := COLLECTIONS, TARGETS, THUMB;
7597 akron1 12
 
13
 
14
CONST
15
 
16
    eCONST*   =  1;  eTYPE*   =  2;  eVAR*     =  3;  eEXPR*    =  4;
17
    eVREC*    =  5;  ePROC*   =  6;  eVPAR*    =  7;  ePARAM*   =  8;
18
    eSTPROC*  =  9;  eSTFUNC* = 10;  eSYSFUNC* = 11;  eSYSPROC* = 12;
19
    eIMP*     = 13;
20
 
21
 
22
TYPE
23
 
24
    PATH* = PATHS.PATH;
25
 
26
    PARSER* = POINTER TO rPARSER;
27
 
7693 akron1 28
    POSITION* = RECORD (SCAN.POSITION)
29
 
30
        parser*: PARSER
31
 
32
    END;
33
 
7597 akron1 34
    EXPR* = RECORD
35
 
36
        obj*:         INTEGER;
8097 maxcodehac 37
        _type*:       PROG._TYPE;
7597 akron1 38
        value*:       ARITH.VALUE;
39
        stproc*:      INTEGER;
40
        readOnly*:    BOOLEAN;
41
        ident*:       PROG.IDENT
42
 
43
    END;
44
 
45
    STATPROC  = PROCEDURE (parser: PARSER);
46
    EXPRPROC  = PROCEDURE (parser: PARSER; VAR e: EXPR);
8097 maxcodehac 47
    RETPROC   = PROCEDURE (parser: PARSER; e: EXPR; t: PROG._TYPE; pos: POSITION): BOOLEAN;
7597 akron1 48
 
49
    rPARSER = RECORD (C.ITEM)
50
 
51
        fname*:      PATH;
52
        path:        PATH;
53
        lib_path:    PATH;
54
        ext:         PATH;
55
        modname:     PATH;
56
        scanner:     SCAN.SCANNER;
57
        lex*:        SCAN.LEX;
58
        sym*:        INTEGER;
59
        unit*:       PROG.UNIT;
60
        constexp*:   BOOLEAN;
61
        main*:       BOOLEAN;
62
 
63
        open*:       PROCEDURE (parser: PARSER; modname: ARRAY OF CHAR): BOOLEAN;
64
        parse*:      PROCEDURE (parser: PARSER);
65
        StatSeq*:    STATPROC;
66
        expression*: EXPRPROC;
67
        designator*: EXPRPROC;
68
        chkreturn:   RETPROC;
69
 
70
        create*:     PROCEDURE (path, lib_path: PATH; StatSeq: STATPROC; expression, designator: EXPRPROC; chkreturn: RETPROC): PARSER
71
 
72
    END;
73
 
74
 
75
VAR
76
 
77
    parsers: C.COLLECTION;
78
 
7983 leency 79
    lines*, modules: INTEGER;
7597 akron1 80
 
7696 akron1 81
 
7597 akron1 82
PROCEDURE destroy* (VAR parser: PARSER);
83
BEGIN
84
    IF parser.scanner # NIL THEN
85
        SCAN.close(parser.scanner)
86
    END;
87
 
88
    C.push(parsers, parser);
89
    parser := NIL
90
END destroy;
91
 
92
 
7693 akron1 93
PROCEDURE getpos (parser: PARSER; VAR pos: POSITION);
7597 akron1 94
BEGIN
7693 akron1 95
    pos.line   := parser.lex.pos.line;
96
    pos.col    := parser.lex.pos.col;
97
    pos.parser := parser
98
END getpos;
99
 
100
 
101
PROCEDURE error* (pos: POSITION; errno: INTEGER);
102
BEGIN
103
    ERRORS.ErrorMsg(pos.parser.fname, pos.line, pos.col, errno)
7597 akron1 104
END error;
105
 
106
 
7693 akron1 107
PROCEDURE check* (condition: BOOLEAN; pos: POSITION; errno: INTEGER);
7597 akron1 108
BEGIN
109
    IF ~condition THEN
7693 akron1 110
        error(pos, errno)
7597 akron1 111
    END
112
END check;
113
 
114
 
115
PROCEDURE check1* (condition: BOOLEAN; parser: PARSER; errno: INTEGER);
7693 akron1 116
VAR
117
    pos: POSITION;
118
 
7597 akron1 119
BEGIN
120
    IF ~condition THEN
7693 akron1 121
        getpos(parser, pos);
122
        error(pos, errno)
7597 akron1 123
    END
124
END check1;
125
 
126
 
127
PROCEDURE Next* (parser: PARSER);
128
VAR
129
    errno: INTEGER;
130
 
131
BEGIN
132
    SCAN.Next(parser.scanner, parser.lex);
133
    errno := parser.lex.error;
8097 maxcodehac 134
    IF errno = 0 THEN
135
        IF (TARGETS.RealSize = 0) & (parser.lex.sym = SCAN.lxFLOAT) THEN
7693 akron1 136
            errno := -SCAN.lxERROR13
8097 maxcodehac 137
        ELSIF (TARGETS.BitDepth = 16) & (parser.lex.sym = SCAN.lxCHAR) & (parser.lex.value.typ = ARITH.tWCHAR) THEN
7693 akron1 138
            errno := -SCAN.lxERROR10
139
        END
140
    END;
141
 
7597 akron1 142
    IF errno # 0 THEN
143
        check1(FALSE, parser, errno)
144
    END;
145
    parser.sym := parser.lex.sym
146
END Next;
147
 
148
 
7693 akron1 149
PROCEDURE NextPos (parser: PARSER; VAR pos: POSITION);
7597 akron1 150
BEGIN
151
    Next(parser);
7693 akron1 152
    getpos(parser, pos)
7597 akron1 153
END NextPos;
154
 
155
 
156
PROCEDURE checklex* (parser: PARSER; sym: INTEGER);
157
VAR
158
    err: INTEGER;
159
 
160
BEGIN
161
 
162
    IF parser.sym # sym THEN
163
 
164
        CASE sym OF
165
        |SCAN.lxCOMMA:   err := 65
166
        |SCAN.lxRROUND:  err := 33
167
        |SCAN.lxPOINT:   err := 26
168
        |SCAN.lxIDENT:   err := 22
169
        |SCAN.lxRSQUARE: err := 71
170
        |SCAN.lxRCURLY:  err := 35
171
        |SCAN.lxUNDEF:   err := 34
172
        |SCAN.lxTHEN:    err := 88
173
        |SCAN.lxEND:     err := 27
174
        |SCAN.lxDO:      err := 89
175
        |SCAN.lxUNTIL:   err := 90
176
        |SCAN.lxCOLON:   err := 53
177
        |SCAN.lxOF:      err := 67
178
        |SCAN.lxASSIGN:  err := 96
179
        |SCAN.lxTO:      err := 57
180
        |SCAN.lxLROUND:  err := 64
181
        |SCAN.lxEQ:      err := 32
182
        |SCAN.lxSEMI:    err := 24
183
        |SCAN.lxRETURN:  err := 38
184
        |SCAN.lxMODULE:  err := 21
185
        END;
186
 
187
        check1(FALSE, parser, err)
188
    END
189
END checklex;
190
 
191
 
192
PROCEDURE ExpectSym* (parser: PARSER; sym: INTEGER);
193
BEGIN
194
    Next(parser);
195
    checklex(parser, sym)
196
END ExpectSym;
197
 
198
 
199
PROCEDURE ImportList (parser: PARSER);
200
VAR
7693 akron1 201
    name:    SCAN.IDENT;
202
    parser2: PARSER;
203
    pos:     POSITION;
204
    alias:   BOOLEAN;
205
    unit:    PROG.UNIT;
206
    ident:   PROG.IDENT;
7597 akron1 207
 
208
BEGIN
209
    alias := FALSE;
210
 
211
    REPEAT
212
 
213
        ExpectSym(parser, SCAN.lxIDENT);
214
        name := parser.lex.ident;
215
 
216
        getpos(parser, pos);
217
 
218
        IF ~alias THEN
7693 akron1 219
            ident := PROG.addIdent(parser.unit, name, PROG.idMODULE);
220
            check(ident # NIL, pos, 30)
7597 akron1 221
        END;
222
 
223
        Next(parser);
224
 
225
        IF (parser.sym = SCAN.lxCOMMA) OR (parser.sym = SCAN.lxSEMI) THEN
226
            alias := FALSE;
8097 maxcodehac 227
            unit := PROG.getUnit(name);
7597 akron1 228
 
229
            IF unit # NIL THEN
7693 akron1 230
                check(unit.closed, pos, 31)
7597 akron1 231
            ELSE
232
                parser2 := parser.create(parser.path, parser.lib_path,
233
                    parser.StatSeq, parser.expression, parser.designator, parser.chkreturn);
234
 
235
                IF ~parser2.open(parser2, name.s) THEN
236
                    IF parser.path # parser.lib_path THEN
237
                        destroy(parser2);
238
                        parser2 := parser.create(parser.lib_path, parser.lib_path,
239
                            parser.StatSeq, parser.expression, parser.designator, parser.chkreturn);
7693 akron1 240
                        check(parser2.open(parser2, name.s), pos, 29)
7597 akron1 241
                    ELSE
7693 akron1 242
                        error(pos, 29)
7597 akron1 243
                    END
244
                END;
245
 
246
                parser2.parse(parser2);
247
                unit := parser2.unit;
248
                destroy(parser2)
249
            END;
8097 maxcodehac 250
            IF unit = PROG.program.sysunit THEN
7597 akron1 251
                parser.unit.sysimport := TRUE
252
            END;
253
            ident.unit := unit
254
 
255
        ELSIF parser.sym = SCAN.lxASSIGN THEN
256
            alias := TRUE
257
 
258
        ELSE
259
            check1(FALSE, parser, 28)
260
        END
261
 
262
    UNTIL parser.sym = SCAN.lxSEMI;
263
 
264
    Next(parser)
265
 
266
END ImportList;
267
 
268
 
269
PROCEDURE QIdent (parser: PARSER; forward: BOOLEAN): PROG.IDENT;
270
VAR
271
    ident: PROG.IDENT;
272
    unit:  PROG.UNIT;
273
 
274
BEGIN
275
    ASSERT(parser.sym = SCAN.lxIDENT);
276
 
7693 akron1 277
    ident := PROG.getIdent(parser.unit, parser.lex.ident, FALSE);
7597 akron1 278
 
279
    IF ~forward THEN
280
        check1(ident # NIL, parser, 48)
281
    END;
282
 
283
    IF (ident # NIL) & (ident.typ = PROG.idMODULE) THEN
284
        unit := ident.unit;
285
        ExpectSym(parser, SCAN.lxPOINT);
286
        ExpectSym(parser, SCAN.lxIDENT);
7693 akron1 287
        ident := PROG.getIdent(unit, parser.lex.ident, FALSE);
7597 akron1 288
        check1((ident # NIL) & ident.export, parser, 48)
289
    END
290
 
291
    RETURN ident
292
END QIdent;
293
 
294
 
295
PROCEDURE strcmp* (VAR v: ARITH.VALUE; v2: ARITH.VALUE; operator: INTEGER);
296
VAR
297
    str: SCAN.LEXSTR;
298
    string1, string2: SCAN.IDENT;
299
    bool: BOOLEAN;
300
 
301
BEGIN
302
 
303
    IF v.typ = ARITH.tCHAR THEN
304
        ASSERT(v2.typ = ARITH.tSTRING);
305
        ARITH.charToStr(v, str);
306
        string1 := SCAN.enterid(str);
307
        string2 := v2.string(SCAN.IDENT)
308
    END;
309
 
310
    IF v2.typ = ARITH.tCHAR THEN
311
        ASSERT(v.typ = ARITH.tSTRING);
312
        ARITH.charToStr(v2, str);
313
        string2 := SCAN.enterid(str);
314
        string1 := v.string(SCAN.IDENT)
315
    END;
316
 
317
    IF v.typ = v2.typ THEN
318
        string1 := v.string(SCAN.IDENT);
319
        string2 := v2.string(SCAN.IDENT)
320
    END;
321
 
322
    CASE operator OF
323
    |SCAN.lxEQ: bool := string1.s =  string2.s
324
    |SCAN.lxNE: bool := string1.s #  string2.s
325
    |SCAN.lxLT: bool := string1.s <  string2.s
326
    |SCAN.lxGT: bool := string1.s >  string2.s
327
    |SCAN.lxLE: bool := string1.s <= string2.s
328
    |SCAN.lxGE: bool := string1.s >= string2.s
329
    END;
330
 
331
    ARITH.setbool(v, bool)
332
END strcmp;
333
 
334
 
335
PROCEDURE ConstExpression* (parser: PARSER; VAR v: ARITH.VALUE);
336
VAR
337
    e: EXPR;
7693 akron1 338
    pos: POSITION;
7597 akron1 339
 
340
BEGIN
341
    getpos(parser, pos);
342
    parser.constexp := TRUE;
343
    parser.expression(parser, e);
344
    parser.constexp := FALSE;
7693 akron1 345
    check(e.obj = eCONST, pos, 62);
7597 akron1 346
    v := e.value
347
END ConstExpression;
348
 
349
 
8097 maxcodehac 350
PROCEDURE FieldList (parser: PARSER; rec: PROG._TYPE);
7597 akron1 351
VAR
7693 akron1 352
    name:   SCAN.IDENT;
353
    export: BOOLEAN;
354
    pos:    POSITION;
7597 akron1 355
 
356
BEGIN
357
    ASSERT(parser.sym = SCAN.lxIDENT);
358
 
359
    WHILE parser.sym = SCAN.lxIDENT DO
360
 
361
        getpos(parser, pos);
362
 
363
        name := parser.lex.ident;
364
 
365
        Next(parser);
366
 
367
        export := parser.sym = SCAN.lxMUL;
368
 
369
        IF export THEN
370
            check1(parser.unit.scopeLvl = 0, parser, 61);
371
            Next(parser)
372
        END;
373
 
7693 akron1 374
        check(PROG.addField(rec, name, export), pos, 30);
7597 akron1 375
 
376
        IF parser.sym = SCAN.lxCOMMA THEN
377
            ExpectSym(parser, SCAN.lxIDENT)
378
        ELSE
379
            checklex(parser, SCAN.lxCOLON)
380
        END
381
 
382
    END
383
 
384
END FieldList;
385
 
386
 
8097 maxcodehac 387
PROCEDURE FormalParameters (parser: PARSER; _type: PROG._TYPE);
7597 akron1 388
VAR
389
    ident: PROG.IDENT;
390
 
391
 
8097 maxcodehac 392
    PROCEDURE FPSection (parser: PARSER; _type: PROG._TYPE);
7597 akron1 393
    VAR
394
        ident:   PROG.IDENT;
395
        exit:    BOOLEAN;
396
        vPar:    BOOLEAN;
397
        dim:     INTEGER;
8097 maxcodehac 398
        t0, t1:  PROG._TYPE;
7597 akron1 399
 
400
    BEGIN
401
        vPar := parser.sym = SCAN.lxVAR;
402
        IF vPar THEN
403
            Next(parser)
404
        END;
405
 
406
        checklex(parser, SCAN.lxIDENT);
407
        exit := FALSE;
408
 
409
        WHILE (parser.sym = SCAN.lxIDENT) & ~exit DO
8097 maxcodehac 410
            check1(PROG.addParam(_type, parser.lex.ident, vPar), parser, 30);
7597 akron1 411
            Next(parser);
412
            IF parser.sym = SCAN.lxCOMMA THEN
413
                ExpectSym(parser, SCAN.lxIDENT)
414
            ELSIF parser.sym = SCAN.lxCOLON THEN
415
                Next(parser);
416
                dim := 0;
417
                WHILE parser.sym = SCAN.lxARRAY DO
418
                    INC(dim);
419
                    check1(dim <= PROG.MAXARRDIM, parser, 84);
420
                    ExpectSym(parser, SCAN.lxOF);
421
                    Next(parser)
422
                END;
423
                checklex(parser, SCAN.lxIDENT);
424
                ident := QIdent(parser, FALSE);
425
                check1(ident.typ = PROG.idTYPE, parser, 68);
426
 
8097 maxcodehac 427
                t0 := ident._type;
7597 akron1 428
                t1 := t0;
429
 
430
                WHILE dim > 0 DO
8097 maxcodehac 431
                    t1 := PROG.enterType(PROG.tARRAY, -1, 0, parser.unit);
7597 akron1 432
                    t1.base := t0;
433
                    t0 := t1;
434
                    DEC(dim)
435
                END;
436
 
8097 maxcodehac 437
                PROG.setParams(_type, t1);
7597 akron1 438
                Next(parser);
439
                exit := TRUE
440
            ELSE
441
                checklex(parser, SCAN.lxCOLON)
442
            END
443
        END
444
 
445
    END FPSection;
446
 
447
 
448
BEGIN
449
    IF parser.sym = SCAN.lxLROUND THEN
450
 
451
        Next(parser);
452
 
453
        IF (parser.sym = SCAN.lxVAR) OR (parser.sym = SCAN.lxIDENT) THEN
8097 maxcodehac 454
            FPSection(parser, _type);
7597 akron1 455
            WHILE parser.sym = SCAN.lxSEMI DO
456
                Next(parser);
8097 maxcodehac 457
                FPSection(parser, _type)
7597 akron1 458
            END
459
        END;
460
 
461
        checklex(parser, SCAN.lxRROUND);
462
        Next(parser);
463
 
464
        IF parser.sym = SCAN.lxCOLON THEN
465
            ExpectSym(parser, SCAN.lxIDENT);
466
            ident := QIdent(parser, FALSE);
467
            check1(ident.typ = PROG.idTYPE, parser, 68);
8097 maxcodehac 468
            check1(~(ident._type.typ IN {PROG.tRECORD, PROG.tARRAY}), parser, 69);
469
            check1( ~(ODD(_type.call) & (ident._type.typ = PROG.tREAL)), parser, 113);
470
            _type.base := ident._type;
7597 akron1 471
            Next(parser)
472
        ELSE
8097 maxcodehac 473
            _type.base := NIL
7597 akron1 474
        END
475
 
476
    END
477
END FormalParameters;
478
 
479
 
7693 akron1 480
PROCEDURE sysflag (parser: PARSER; proc: BOOLEAN): INTEGER;
7597 akron1 481
VAR
7693 akron1 482
    res, sf: INTEGER;
7597 akron1 483
 
484
BEGIN
485
    IF parser.lex.s = "stdcall" THEN
7693 akron1 486
        sf := PROG.sf_stdcall
487
    ELSIF parser.lex.s = "stdcall64" THEN
488
        sf := PROG.sf_stdcall64
489
    ELSIF parser.lex.s = "ccall" THEN
490
        sf := PROG.sf_ccall
491
    ELSIF parser.lex.s = "ccall16" THEN
492
        sf := PROG.sf_ccall16
493
    ELSIF parser.lex.s = "win64" THEN
494
        sf := PROG.sf_win64
495
    ELSIF parser.lex.s = "systemv" THEN
496
        sf := PROG.sf_systemv
497
    ELSIF parser.lex.s = "windows" THEN
498
        sf := PROG.sf_windows
499
    ELSIF parser.lex.s = "linux" THEN
500
        sf := PROG.sf_linux
501
    ELSIF parser.lex.s = "code" THEN
502
        sf := PROG.sf_code
8097 maxcodehac 503
    ELSIF parser.lex.s = "oberon" THEN
504
        sf := PROG.sf_oberon
7693 akron1 505
    ELSIF parser.lex.s = "noalign" THEN
506
        sf := PROG.sf_noalign
507
    ELSE
508
        check1(FALSE, parser, 124)
509
    END;
510
 
8097 maxcodehac 511
    check1(sf IN PROG.program.sysflags, parser, 125);
7693 akron1 512
 
513
    IF proc THEN
514
        check1(sf IN PROG.proc_flags, parser, 123)
515
    ELSE
516
        check1(sf IN PROG.rec_flags, parser, 123)
517
    END;
518
 
519
    CASE sf OF
520
    |PROG.sf_stdcall:
7597 akron1 521
        res := PROG.stdcall
7693 akron1 522
    |PROG.sf_stdcall64:
7597 akron1 523
        res := PROG.stdcall64
7693 akron1 524
    |PROG.sf_ccall:
7597 akron1 525
        res := PROG.ccall
7693 akron1 526
    |PROG.sf_ccall16:
7597 akron1 527
        res := PROG.ccall16
7693 akron1 528
    |PROG.sf_win64:
7597 akron1 529
        res := PROG.win64
7693 akron1 530
    |PROG.sf_systemv:
7597 akron1 531
        res := PROG.systemv
7693 akron1 532
    |PROG.sf_code:
533
        res := PROG.code
8097 maxcodehac 534
    |PROG.sf_oberon:
535
        IF TARGETS.OS IN {TARGETS.osWIN32, TARGETS.osLINUX32, TARGETS.osKOS} THEN
536
            res := PROG.default32
537
        ELSIF TARGETS.OS IN {TARGETS.osWIN64, TARGETS.osLINUX64} THEN
538
            res := PROG.default64
539
        END
7693 akron1 540
    |PROG.sf_windows:
7983 leency 541
        IF TARGETS.OS = TARGETS.osWIN32 THEN
7597 akron1 542
            res := PROG.stdcall
7983 leency 543
        ELSIF TARGETS.OS = TARGETS.osWIN64 THEN
7597 akron1 544
            res := PROG.win64
545
        END
7693 akron1 546
    |PROG.sf_linux:
7983 leency 547
        IF TARGETS.OS = TARGETS.osLINUX32 THEN
7597 akron1 548
            res := PROG.ccall16
7983 leency 549
        ELSIF TARGETS.OS = TARGETS.osLINUX64 THEN
7597 akron1 550
            res := PROG.systemv
551
        END
7693 akron1 552
    |PROG.sf_noalign:
7597 akron1 553
        res := PROG.noalign
554
    END
555
 
556
    RETURN res
557
END sysflag;
558
 
559
 
8097 maxcodehac 560
PROCEDURE procflag (parser: PARSER; VAR _import: IL.IMPORT_PROC; isProc: BOOLEAN): INTEGER;
7597 akron1 561
VAR
562
    call: INTEGER;
563
    dll, proc: SCAN.LEXSTR;
7693 akron1 564
    pos: POSITION;
7597 akron1 565
 
8097 maxcodehac 566
 
567
    PROCEDURE getStr (parser: PARSER; VAR name: SCAN.LEXSTR);
568
    VAR
569
        pos: POSITION;
570
        str: ARITH.VALUE;
571
 
572
    BEGIN
573
        getpos(parser, pos);
574
        ConstExpression(parser, str);
575
        IF str.typ = ARITH.tSTRING THEN
576
            name := str.string(SCAN.IDENT).s
577
        ELSIF str.typ = ARITH.tCHAR THEN
578
            ARITH.charToStr(str, name)
579
        ELSE
580
            check(FALSE, pos, 117)
581
        END
582
    END getStr;
583
 
584
 
7597 akron1 585
BEGIN
8097 maxcodehac 586
    _import := NIL;
7597 akron1 587
 
588
    IF parser.sym = SCAN.lxLSQUARE THEN
589
        getpos(parser, pos);
590
        check1(parser.unit.sysimport, parser, 54);
591
        Next(parser);
7693 akron1 592
        call := sysflag(parser, TRUE);
7597 akron1 593
        Next(parser);
594
        IF parser.sym = SCAN.lxMINUS THEN
595
            Next(parser);
596
            INC(call)
597
        END;
8097 maxcodehac 598
 
599
        IF isProc & (parser.sym = SCAN.lxCOMMA) THEN
600
            Next(parser);
601
            getStr(parser, dll);
7983 leency 602
            STRINGS.UpCase(dll);
8097 maxcodehac 603
            checklex(parser, SCAN.lxCOMMA);
7597 akron1 604
            Next(parser);
8097 maxcodehac 605
            getStr(parser, proc);
606
            _import := IL.AddImp(dll, proc)
7597 akron1 607
        END;
8097 maxcodehac 608
 
7597 akron1 609
        checklex(parser, SCAN.lxRSQUARE);
610
        Next(parser)
611
    ELSE
7983 leency 612
        CASE TARGETS.BitDepth OF
7693 akron1 613
        |16: call := PROG.default16
8097 maxcodehac 614
        |32: IF TARGETS.CPU = TARGETS.cpuX86 THEN
615
                 call := PROG.default32
616
             ELSE
7983 leency 617
                 call := PROG.ccall
618
             END
7693 akron1 619
        |64: call := PROG.default64
7597 akron1 620
        END
621
    END;
622
 
8097 maxcodehac 623
    IF _import # NIL THEN
7983 leency 624
        check(TARGETS.Import, pos, 70)
7597 akron1 625
    END
626
 
627
    RETURN call
628
END procflag;
629
 
630
 
8097 maxcodehac 631
PROCEDURE _type (parser: PARSER; VAR t: PROG._TYPE; flags: SET);
7597 akron1 632
CONST
633
    comma   = 0;
634
    closed  = 1;
635
    forward = 2;
636
 
637
VAR
638
    arrLen:     ARITH.VALUE;
639
    typeSize:   ARITH.VALUE;
640
    ident:      PROG.IDENT;
641
    unit:       PROG.UNIT;
7693 akron1 642
    pos, pos2:  POSITION;
8097 maxcodehac 643
    fieldType:  PROG._TYPE;
7597 akron1 644
    baseIdent:  SCAN.IDENT;
645
    a, b:       INTEGER;
646
    RecFlag:    INTEGER;
8097 maxcodehac 647
    _import:     IL.IMPORT_PROC;
7597 akron1 648
 
649
BEGIN
650
    unit := parser.unit;
651
    t := NIL;
652
 
653
    IF parser.sym = SCAN.lxIDENT THEN
654
        ident := QIdent(parser, forward IN flags);
655
 
656
        IF ident # NIL THEN
657
            check1(ident.typ = PROG.idTYPE, parser, 49);
8097 maxcodehac 658
            t := ident._type;
7597 akron1 659
            check1(t # NIL, parser, 50);
660
            IF closed IN flags THEN
661
                check1(t.closed, parser, 50)
662
            END
663
        END;
664
 
665
        Next(parser)
666
 
667
    ELSIF (parser.sym = SCAN.lxARRAY) OR ((parser.sym = SCAN.lxCOMMA) & (comma IN flags)) THEN
668
 
669
        IF parser.sym = SCAN.lxARRAY THEN
670
            getpos(parser, pos2)
671
        END;
672
        NextPos(parser, pos);
673
 
674
        ConstExpression(parser, arrLen);
675
 
7693 akron1 676
        check(arrLen.typ = ARITH.tINTEGER, pos, 43);
677
        check(ARITH.check(arrLen),         pos, 39);
678
        check(ARITH.getInt(arrLen) > 0,    pos, 51);
7597 akron1 679
 
8097 maxcodehac 680
        t := PROG.enterType(PROG.tARRAY, -1, ARITH.getInt(arrLen), unit);
7597 akron1 681
 
682
        IF parser.sym = SCAN.lxCOMMA THEN
8097 maxcodehac 683
            _type(parser, t.base, {comma, closed})
7597 akron1 684
        ELSIF parser.sym = SCAN.lxOF THEN
685
            Next(parser);
8097 maxcodehac 686
            _type(parser, t.base, {closed})
7597 akron1 687
        ELSE
688
            check1(FALSE, parser, 47)
689
        END;
690
 
691
        t.align := t.base.align;
692
 
693
        a := t.length;
694
        b := t.base.size;
7693 akron1 695
        check(ARITH.mulInt(a, b), pos2, 104);
696
        check(ARITH.setInt(typeSize, a), pos2, 104);
7597 akron1 697
        t.size := a;
698
 
699
        t.closed := TRUE
700
 
701
    ELSIF parser.sym = SCAN.lxRECORD THEN
702
        getpos(parser, pos2);
703
        Next(parser);
704
 
8097 maxcodehac 705
        t := PROG.enterType(PROG.tRECORD, 0, 0, unit);
7597 akron1 706
        t.align := 1;
707
 
708
        IF parser.sym = SCAN.lxLSQUARE THEN
709
            check1(parser.unit.sysimport, parser, 54);
710
            Next(parser);
7693 akron1 711
            RecFlag := sysflag(parser, FALSE);
712
            t.noalign := RecFlag = PROG.noalign;
7597 akron1 713
            ExpectSym(parser, SCAN.lxRSQUARE);
714
            Next(parser)
715
        END;
716
 
717
        IF parser.sym = SCAN.lxLROUND THEN
718
            check1(~t.noalign, parser, 111);
719
            ExpectSym(parser, SCAN.lxIDENT);
720
            getpos(parser, pos);
721
 
8097 maxcodehac 722
            _type(parser, t.base, {closed});
7597 akron1 723
 
7693 akron1 724
            check(t.base.typ IN {PROG.tRECORD, PROG.tPOINTER}, pos, 52);
7597 akron1 725
 
726
            IF t.base.typ = PROG.tPOINTER THEN
727
                t.base := t.base.base;
7693 akron1 728
                check(t.base # NIL, pos, 55)
7597 akron1 729
            END;
730
 
7693 akron1 731
            check(~t.base.noalign, pos, 112);
7597 akron1 732
 
733
            checklex(parser, SCAN.lxRROUND);
734
            Next(parser);
735
 
736
            t.size := t.base.size;
737
            IF t.base.align > t.align THEN
738
                t.align := t.base.align
739
            END
740
        ELSE
8097 maxcodehac 741
            t.base := PROG.program.stTypes.tANYREC
7597 akron1 742
        END;
743
 
744
        WHILE parser.sym = SCAN.lxIDENT DO
745
            FieldList(parser, t);
746
 
747
            ASSERT(parser.sym = SCAN.lxCOLON);
748
            Next(parser);
749
 
8097 maxcodehac 750
            _type(parser, fieldType, {closed});
7693 akron1 751
            check(PROG.setFields(t, fieldType), pos2, 104);
7597 akron1 752
 
753
            IF (fieldType.align > t.align) & ~t.noalign THEN
754
                t.align := fieldType.align
755
            END;
756
 
757
            IF parser.sym = SCAN.lxSEMI THEN
758
                ExpectSym(parser, SCAN.lxIDENT)
759
            ELSE
760
                checklex(parser, SCAN.lxEND)
761
            END
762
        END;
763
 
764
        t.closed := TRUE;
765
 
7693 akron1 766
        IL.AddRec(t.base.num);
7597 akron1 767
 
768
        IF ~t.noalign THEN
7693 akron1 769
            check(UTILS.Align(t.size, t.align), pos2, 104);
770
            check(ARITH.setInt(typeSize, t.size), pos2, 104)
7597 akron1 771
        END;
772
 
773
        checklex(parser, SCAN.lxEND);
774
        Next(parser)
775
 
7693 akron1 776
    ELSIF parser.sym = SCAN.lxPOINTER THEN
7597 akron1 777
        ExpectSym(parser, SCAN.lxTO);
778
        Next(parser);
779
 
8097 maxcodehac 780
        t := PROG.enterType(PROG.tPOINTER, TARGETS.AdrSize, 0, unit);
7983 leency 781
        t.align := TARGETS.AdrSize;
7597 akron1 782
 
783
        getpos(parser, pos);
784
 
785
        IF parser.sym = SCAN.lxIDENT THEN
786
            baseIdent := parser.lex.ident
787
        END;
788
 
8097 maxcodehac 789
        _type(parser, t.base, {forward});
7597 akron1 790
 
791
        IF t.base # NIL THEN
7693 akron1 792
            check(t.base.typ = PROG.tRECORD, pos, 58)
7597 akron1 793
        ELSE
7693 akron1 794
            PROG.frwPtr(unit, t, baseIdent, pos)
7597 akron1 795
        END
796
 
797
    ELSIF parser.sym = SCAN.lxPROCEDURE THEN
798
        NextPos(parser, pos);
8097 maxcodehac 799
        t := PROG.enterType(PROG.tPROCEDURE, TARGETS.AdrSize, 0, unit);
7983 leency 800
        t.align := TARGETS.AdrSize;
8097 maxcodehac 801
        t.call := procflag(parser, _import, FALSE);
7597 akron1 802
        FormalParameters(parser, t)
803
    ELSE
804
        check1(FALSE, parser, 49)
805
    END
806
 
8097 maxcodehac 807
END _type;
7597 akron1 808
 
809
 
810
PROCEDURE IdentDef (parser: PARSER; typ: INTEGER; VAR name: SCAN.IDENT): PROG.IDENT;
811
VAR
812
    ident:  PROG.IDENT;
7693 akron1 813
    pos:    POSITION;
7597 akron1 814
 
815
BEGIN
816
    ASSERT(parser.sym = SCAN.lxIDENT);
817
 
818
    name := parser.lex.ident;
819
    getpos(parser, pos);
7693 akron1 820
    ident := PROG.addIdent(parser.unit, name, typ);
821
    check(ident # NIL, pos, 30);
7597 akron1 822
    ident.pos := pos;
823
    Next(parser);
824
 
825
    IF parser.sym = SCAN.lxMUL THEN
826
        check1(ident.global, parser, 61);
827
        ident.export := TRUE;
828
        Next(parser)
829
    END
830
 
831
    RETURN ident
832
END IdentDef;
833
 
834
 
8097 maxcodehac 835
PROCEDURE ConstTypeDeclaration (parser: PARSER; _const: BOOLEAN);
7597 akron1 836
VAR
7693 akron1 837
    ident: PROG.IDENT;
838
    name:  SCAN.IDENT;
839
    pos:   POSITION;
7597 akron1 840
 
841
BEGIN
8097 maxcodehac 842
    IF _const THEN
7597 akron1 843
        ident := IdentDef(parser, PROG.idNONE, name)
844
    ELSE
845
        ident := IdentDef(parser, PROG.idTYPE, name)
846
    END;
847
 
848
    checklex(parser, SCAN.lxEQ);
849
    NextPos(parser, pos);
850
 
8097 maxcodehac 851
    IF _const THEN
7597 akron1 852
        ConstExpression(parser, ident.value);
853
        IF ident.value.typ = ARITH.tINTEGER THEN
7693 akron1 854
            check(ARITH.check(ident.value), pos, 39)
7597 akron1 855
        ELSIF ident.value.typ = ARITH.tREAL THEN
7693 akron1 856
            check(ARITH.check(ident.value), pos, 40)
7597 akron1 857
        END;
858
        ident.typ  := PROG.idCONST;
8097 maxcodehac 859
        ident._type := PROG.getType(ident.value.typ)
7597 akron1 860
    ELSE
8097 maxcodehac 861
        _type(parser, ident._type, {})
7597 akron1 862
    END;
863
 
864
    checklex(parser, SCAN.lxSEMI);
865
    Next(parser)
866
 
867
END ConstTypeDeclaration;
868
 
869
 
870
PROCEDURE VarDeclaration (parser: PARSER);
871
VAR
7693 akron1 872
    ident: PROG.IDENT;
873
    name:  SCAN.IDENT;
8097 maxcodehac 874
    t:     PROG._TYPE;
7597 akron1 875
 
876
BEGIN
877
 
878
    REPEAT
879
        ident := IdentDef(parser, PROG.idVAR, name);
880
 
881
        IF parser.sym = SCAN.lxCOMMA THEN
882
            ExpectSym(parser, SCAN.lxIDENT)
883
        ELSIF parser.sym = SCAN.lxCOLON THEN
884
            Next(parser);
8097 maxcodehac 885
            _type(parser, t, {});
7693 akron1 886
            PROG.setVarsType(parser.unit, t);
7597 akron1 887
            checklex(parser, SCAN.lxSEMI);
888
            Next(parser)
889
        ELSE
890
            checklex(parser, SCAN.lxCOLON)
891
        END
892
 
893
    UNTIL parser.sym # SCAN.lxIDENT
894
 
895
END VarDeclaration;
896
 
897
 
898
PROCEDURE DeclarationSequence (parser: PARSER): BOOLEAN;
899
VAR
900
    ptr: PROG.FRWPTR;
901
    endmod: BOOLEAN;
7693 akron1 902
    pos: POSITION;
7597 akron1 903
 
904
 
905
    PROCEDURE ProcDeclaration (parser: PARSER): BOOLEAN;
906
    VAR
907
        proc:       PROG.IDENT;
908
        endname,
909
        name:       SCAN.IDENT;
7693 akron1 910
        param:      PROG.PARAM;
7597 akron1 911
        unit:       PROG.UNIT;
912
        ident:      PROG.IDENT;
913
        e:          EXPR;
7693 akron1 914
        pos, pos1,
915
        pos2:       POSITION;
7597 akron1 916
        label:      INTEGER;
7693 akron1 917
        enter:      IL.COMMAND;
7597 akron1 918
        call:       INTEGER;
8097 maxcodehac 919
        t:          PROG._TYPE;
920
        _import:    IL.IMPORT_PROC;
7597 akron1 921
        endmod, b:  BOOLEAN;
922
        fparams:    SET;
923
        variables:  LISTS.LIST;
924
        int, flt:   INTEGER;
7693 akron1 925
        comma:      BOOLEAN;
7983 leency 926
        code, iv:   ARITH.VALUE;
927
        codeProc,
928
        handler:    BOOLEAN;
7597 akron1 929
 
930
    BEGIN
931
        endmod := FALSE;
7983 leency 932
        handler := FALSE;
7597 akron1 933
 
934
        unit := parser.unit;
935
 
8097 maxcodehac 936
        call := procflag(parser, _import, TRUE);
7597 akron1 937
 
938
        getpos(parser, pos);
7693 akron1 939
        pos1 := pos;
7597 akron1 940
        checklex(parser, SCAN.lxIDENT);
941
 
8097 maxcodehac 942
        IF _import # NIL THEN
7597 akron1 943
            proc := IdentDef(parser, PROG.idIMP, name);
8097 maxcodehac 944
            proc._import := _import;
945
            IF _import.name = "" THEN
946
                _import.name := name.s
947
            END;
948
            PROG.program.procs.last(PROG.PROC)._import := _import
7597 akron1 949
        ELSE
950
            proc := IdentDef(parser, PROG.idPROC, name)
951
        END;
952
 
7693 akron1 953
        check(PROG.openScope(unit, proc.proc), pos, 116);
7597 akron1 954
 
8097 maxcodehac 955
        proc._type := PROG.enterType(PROG.tPROCEDURE, TARGETS.AdrSize, 0, unit);
956
        t := proc._type;
7983 leency 957
        t.align := TARGETS.AdrSize;
7693 akron1 958
        t.call  := call;
7597 akron1 959
 
960
        FormalParameters(parser, t);
7693 akron1 961
 
7983 leency 962
        IF parser.sym = SCAN.lxLSQUARE THEN
963
            getpos(parser, pos2);
964
            check(TARGETS.target = TARGETS.STM32CM3, pos2, 24);
965
            Next(parser);
966
            getpos(parser, pos2);
967
            ConstExpression(parser, iv);
968
            check(iv.typ = ARITH.tINTEGER, pos2, 43);
969
            check((0 <= ARITH.Int(iv)) & (ARITH.Int(iv) <= THUMB.maxIVT), pos2, 46);
970
            check(THUMB.SetIV(ARITH.Int(iv)), pos2, 121);
971
            checklex(parser, SCAN.lxRSQUARE);
972
            Next(parser);
973
            handler := TRUE
974
        END;
975
 
7693 akron1 976
        codeProc := call IN {PROG.code, PROG._code};
977
 
7597 akron1 978
        IF call IN {PROG.systemv, PROG._systemv} THEN
7693 akron1 979
            check(t.parSize <= PROG.MAXSYSVPARAM, pos, 120)
7597 akron1 980
        END;
981
 
7693 akron1 982
        param := t.params.first(PROG.PARAM);
7597 akron1 983
        WHILE param # NIL DO
7693 akron1 984
            ident := PROG.addIdent(unit, param.name, PROG.idPARAM);
7597 akron1 985
            ASSERT(ident # NIL);
8097 maxcodehac 986
            ident._type := param._type;
7693 akron1 987
            ident.offset := param.offset;
988
            IF param.vPar THEN
7597 akron1 989
                ident.typ := PROG.idVPAR
990
            END;
7693 akron1 991
            param := param.next(PROG.PARAM)
7597 akron1 992
        END;
993
 
8097 maxcodehac 994
        IF _import = NIL THEN
7693 akron1 995
            label := IL.NewLabel();
7983 leency 996
            proc.proc.label := label;
997
            proc.proc.used  := handler;
998
            IF handler THEN
999
                IL.AddCmd2(IL.opHANDLER, label, ARITH.Int(iv))
1000
            END
7693 akron1 1001
        END;
1002
 
1003
        IF codeProc THEN
1004
            enter := IL.EnterC(label);
1005
            comma := FALSE;
1006
            WHILE (parser.sym # SCAN.lxSEMI) OR comma DO
1007
                getpos(parser, pos2);
1008
                ConstExpression(parser, code);
1009
                check(code.typ = ARITH.tINTEGER, pos2, 43);
8097 maxcodehac 1010
                IF TARGETS.WordSize > TARGETS.InstrSize THEN
1011
                    CASE TARGETS.InstrSize OF
1012
                    |1: check(ARITH.range(code, 0, 255), pos, 42)
1013
                    |2: check(ARITH.range(code, 0, 65535), pos, 110)
1014
                    END
7693 akron1 1015
                END;
1016
                IL.AddCmd(IL.opCODE, ARITH.getInt(code));
1017
                comma := parser.sym = SCAN.lxCOMMA;
1018
                IF comma THEN
1019
                    Next(parser)
1020
                ELSE
1021
                    checklex(parser, SCAN.lxSEMI)
1022
                END
1023
            END
1024
        END;
1025
 
7597 akron1 1026
        checklex(parser, SCAN.lxSEMI);
1027
        Next(parser);
1028
 
8097 maxcodehac 1029
        IF _import = NIL THEN
7597 akron1 1030
 
7983 leency 1031
            IF parser.main & proc.export & TARGETS.Dll THEN
1032
                IF TARGETS.target = TARGETS.KolibriOSDLL THEN
7693 akron1 1033
                    check((proc.name.s # "lib_init") & (proc.name.s # "version"), pos, 114)
7597 akron1 1034
                END;
7693 akron1 1035
                IL.AddExp(label, proc.name.s);
7597 akron1 1036
                proc.proc.used := TRUE
1037
            END;
1038
 
7693 akron1 1039
            IF ~codeProc THEN
1040
                b := DeclarationSequence(parser)
1041
            END;
7597 akron1 1042
 
8097 maxcodehac 1043
            PROG.ResetLocSize;
7597 akron1 1044
            IF call IN {PROG._win64, PROG.win64} THEN
8097 maxcodehac 1045
                fparams := PROG.getFloatParamsPos(proc._type, 3, int, flt);
1046
                enter := IL.Enter(label, LSL(ORD(fparams), 5) + MIN(proc._type.parSize, 4))
7597 akron1 1047
            ELSIF call IN {PROG._systemv, PROG.systemv} THEN
8097 maxcodehac 1048
                fparams := PROG.getFloatParamsPos(proc._type, PROG.MAXSYSVPARAM - 1, int, flt);
1049
                enter := IL.Enter(label, -(LSL(ORD(fparams), 5) + proc._type.parSize))
7693 akron1 1050
            ELSIF codeProc THEN
1051
 
7597 akron1 1052
            ELSE
7693 akron1 1053
                enter := IL.Enter(label, 0)
7597 akron1 1054
            END;
1055
            proc.proc.enter := enter;
1056
 
7693 akron1 1057
            IF ~codeProc & (parser.sym = SCAN.lxBEGIN) THEN
7597 akron1 1058
                Next(parser);
1059
                parser.StatSeq(parser)
1060
            END;
1061
 
7693 akron1 1062
            IF ~codeProc & (t.base # NIL) THEN
7597 akron1 1063
                checklex(parser, SCAN.lxRETURN);
1064
                NextPos(parser, pos);
1065
                parser.expression(parser, e);
7693 akron1 1066
                check(parser.chkreturn(parser, e, t.base, pos), pos, 87)
7597 akron1 1067
            END;
1068
 
7693 akron1 1069
            IF ~codeProc THEN
8097 maxcodehac 1070
                proc.proc.leave := IL.Leave(t.base # NIL, (t.base # NIL) & (t.base.typ = PROG.tREAL), PROG.program.locsize,
7693 akron1 1071
                    t.parSize * ORD((t.call IN PROG.callee_clean_up) OR (t.call IN {PROG.systemv, PROG._systemv})));
8097 maxcodehac 1072
                enter.param2 := PROG.program.locsize;
7693 akron1 1073
                checklex(parser, SCAN.lxEND)
1074
            ELSE
1075
                proc.proc.leave := IL.LeaveC()
1076
            END;
1077
 
7983 leency 1078
            IF TARGETS.CPU = TARGETS.cpuMSP430 THEN
8097 maxcodehac 1079
                check((enter.param2 * ORD(~codeProc) + proc._type.parSize) * 2 + 16 < PROG.program.options.ram, pos1, 63)
7693 akron1 1080
            END
7597 akron1 1081
        END;
1082
 
1083
        IF parser.sym = SCAN.lxEND THEN
8097 maxcodehac 1084
            Next(parser);
1085
            IF parser.sym = SCAN.lxIDENT THEN
1086
                getpos(parser, pos);
1087
                endname := parser.lex.ident;
1088
                IF ~codeProc & (_import = NIL) THEN
1089
                    check(endname = name, pos, 60);
7597 akron1 1090
                    ExpectSym(parser, SCAN.lxSEMI);
1091
                    Next(parser)
1092
                ELSE
8097 maxcodehac 1093
                    IF endname = parser.unit.name THEN
1094
                        ExpectSym(parser, SCAN.lxPOINT);
1095
                        Next(parser);
1096
                        endmod := TRUE
1097
                    ELSIF endname = name THEN
1098
                        ExpectSym(parser, SCAN.lxSEMI);
1099
                        Next(parser)
1100
                    ELSE
1101
                        error(pos, 60)
1102
                    END
7597 akron1 1103
                END
8097 maxcodehac 1104
            ELSIF parser.sym = SCAN.lxSEMI THEN
1105
                Next(parser)
1106
            ELSE
1107
                checklex(parser, SCAN.lxIDENT)
7597 akron1 1108
            END
1109
        END;
1110
 
8097 maxcodehac 1111
        IF ~codeProc & (_import = NIL) THEN
7597 akron1 1112
            variables := LISTS.create(NIL);
1113
        ELSE
1114
            variables := NIL
1115
        END;
1116
 
7693 akron1 1117
        PROG.closeScope(unit, variables);
7597 akron1 1118
 
8097 maxcodehac 1119
        IF ~codeProc & (_import = NIL) THEN
7597 akron1 1120
            enter.variables := variables
1121
        END
1122
 
1123
        RETURN endmod
1124
    END ProcDeclaration;
1125
 
1126
 
1127
BEGIN
1128
    IF parser.sym = SCAN.lxCONST THEN
1129
        Next(parser);
1130
        WHILE parser.sym = SCAN.lxIDENT DO
1131
            ConstTypeDeclaration(parser, TRUE)
1132
        END
1133
    END;
1134
 
1135
    IF parser.sym = SCAN.lxTYPE THEN
1136
        Next(parser);
1137
        WHILE parser.sym = SCAN.lxIDENT DO
1138
            ConstTypeDeclaration(parser, FALSE)
1139
        END
1140
    END;
1141
 
7693 akron1 1142
    ptr := PROG.linkPtr(parser.unit);
7597 akron1 1143
    IF ptr # NIL THEN
7693 akron1 1144
        pos.line := ptr.pos.line;
1145
        pos.col  := ptr.pos.col;
1146
        pos.parser := parser;
7597 akron1 1147
        IF ptr.notRecord THEN
7693 akron1 1148
            error(pos, 58)
7597 akron1 1149
        ELSE
7693 akron1 1150
            error(pos, 48)
7597 akron1 1151
        END
1152
    END;
1153
 
1154
    IF parser.sym = SCAN.lxVAR THEN
1155
        Next(parser);
1156
        IF parser.sym = SCAN.lxIDENT THEN
1157
            VarDeclaration(parser)
1158
        END
1159
    END;
1160
 
1161
    endmod := FALSE;
1162
    WHILE ~endmod & (parser.sym = SCAN.lxPROCEDURE) DO
1163
        Next(parser);
1164
        endmod := ProcDeclaration(parser)
1165
    END
1166
 
1167
    RETURN endmod
1168
END DeclarationSequence;
1169
 
1170
 
1171
PROCEDURE parse (parser: PARSER);
1172
VAR
7693 akron1 1173
    unit:     PROG.UNIT;
1174
    label:    INTEGER;
1175
    name:     INTEGER;
1176
    endmod:   BOOLEAN;
1177
    errlabel: INTEGER;
1178
    errno:    INTEGER;
7597 akron1 1179
 
1180
BEGIN
1181
    ASSERT(parser # NIL);
1182
    ASSERT(parser.scanner # NIL);
1183
 
1184
    ExpectSym(parser, SCAN.lxMODULE);
1185
    ExpectSym(parser, SCAN.lxIDENT);
1186
 
1187
    IF ~parser.main THEN
1188
        check1(parser.lex.s = parser.modname, parser, 23)
1189
    END;
1190
 
8097 maxcodehac 1191
    unit := PROG.newUnit(parser.lex.ident);
7597 akron1 1192
 
1193
    parser.unit := unit;
1194
 
1195
    ExpectSym(parser, SCAN.lxSEMI);
1196
 
1197
    Next(parser);
1198
    IF parser.sym = SCAN.lxIMPORT THEN
1199
        ImportList(parser)
1200
    END;
1201
 
7983 leency 1202
    INC(modules);
1203
 
1204
    CONSOLE.String("compiling ");
8097 maxcodehac 1205
    CONSOLE.String("("); CONSOLE.Int(modules); CONSOLE.String(") ");
7983 leency 1206
    CONSOLE.String(unit.name.s);
7597 akron1 1207
    IF parser.unit.sysimport THEN
1208
        CONSOLE.String(" (SYSTEM)")
1209
    END;
1210
    CONSOLE.Ln;
1211
 
8097 maxcodehac 1212
    IF TARGETS.CPU IN {TARGETS.cpuX86, TARGETS.cpuAMD64} THEN
1213
        IL.fname(parser.fname)
1214
    END;
1215
 
7693 akron1 1216
    label := IL.NewLabel();
1217
    IL.AddJmpCmd(IL.opJMP, label);
7597 akron1 1218
 
7693 akron1 1219
    name := IL.putstr(unit.name.s);
7597 akron1 1220
 
7693 akron1 1221
    errlabel := IL.NewLabel();
1222
    IL.SetLabel(errlabel);
1223
    IL.StrAdr(name);
1224
    IL.Param1;
8097 maxcodehac 1225
    IL.AddCmd(IL.opPUSHC, modules);
7693 akron1 1226
    IL.AddCmd0(IL.opERR);
7597 akron1 1227
 
7693 akron1 1228
    FOR errno := 1 TO LEN(IL.codes.errlabels) - 1 DO
1229
        IL.SetErrLabel(errno);
1230
        IL.AddCmd(IL.opPUSHC, errno);
1231
        IL.AddJmpCmd(IL.opJMP, errlabel)
1232
    END;
1233
 
7597 akron1 1234
    endmod := DeclarationSequence(parser);
1235
 
7693 akron1 1236
    IL.SetLabel(label);
7597 akron1 1237
 
1238
    IF ~endmod THEN
1239
 
1240
        IF parser.sym = SCAN.lxBEGIN THEN
1241
            Next(parser);
1242
            parser.StatSeq(parser)
1243
        END;
1244
 
1245
        checklex(parser, SCAN.lxEND);
1246
 
1247
        ExpectSym(parser, SCAN.lxIDENT);
1248
        check1(parser.lex.s = unit.name.s, parser, 25);
1249
        ExpectSym(parser, SCAN.lxPOINT)
1250
    END;
1251
 
7696 akron1 1252
    INC(lines, parser.lex.pos.line);
7693 akron1 1253
    PROG.closeUnit(unit)
7597 akron1 1254
END parse;
1255
 
1256
 
1257
PROCEDURE open (parser: PARSER; modname: ARRAY OF CHAR): BOOLEAN;
1258
BEGIN
1259
    ASSERT(parser # NIL);
1260
 
1261
    STRINGS.append(parser.fname, modname);
1262
    STRINGS.append(parser.fname, parser.ext);
1263
    STRINGS.append(parser.modname, modname);
1264
 
1265
    parser.scanner := SCAN.open(parser.fname)
1266
 
1267
    RETURN parser.scanner # NIL
1268
END open;
1269
 
1270
 
1271
PROCEDURE NewParser (): PARSER;
1272
VAR
1273
    pars:  PARSER;
1274
    citem: C.ITEM;
1275
 
1276
BEGIN
1277
    citem := C.pop(parsers);
1278
    IF citem = NIL THEN
1279
        NEW(pars)
1280
    ELSE
1281
        pars := citem(PARSER)
1282
    END
1283
 
1284
    RETURN pars
1285
END NewParser;
1286
 
1287
 
1288
PROCEDURE create* (path, lib_path: PATH; StatSeq: STATPROC; expression, designator: EXPRPROC; chkreturn: RETPROC): PARSER;
1289
VAR
1290
    parser: PARSER;
1291
 
1292
BEGIN
1293
    parser := NewParser();
1294
 
1295
    parser.path     := path;
1296
    parser.lib_path := lib_path;
7983 leency 1297
    parser.ext      := UTILS.FILE_EXT;
7597 akron1 1298
    parser.fname    := path;
1299
    parser.modname  := "";
1300
    parser.scanner  := NIL;
1301
    parser.unit     := NIL;
1302
    parser.constexp := FALSE;
1303
    parser.main     := FALSE;
1304
 
1305
    parser.open       := open;
1306
    parser.parse      := parse;
1307
    parser.StatSeq    := StatSeq;
1308
    parser.expression := expression;
1309
    parser.designator := designator;
1310
    parser.chkreturn  := chkreturn;
1311
    parser.create     := create
1312
 
1313
    RETURN parser
1314
END create;
1315
 
1316
 
7983 leency 1317
PROCEDURE init* (options: PROG.OPTIONS);
7597 akron1 1318
BEGIN
8097 maxcodehac 1319
    PROG.create(options);
7696 akron1 1320
    parsers := C.create();
7983 leency 1321
    lines   := 0;
1322
    modules := 0
7597 akron1 1323
END init;
1324
 
1325
 
7983 leency 1326
END PARS.