Subversion Repositories Kolibri OS

Rev

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