Subversion Repositories Kolibri OS

Rev

Rev 8097 | 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
6613 leency 3
 
8859 leency 4
    Copyright (c) 2018-2021, Anton Krotov
7597 akron1 5
    All rights reserved.
6613 leency 6
*)
7
 
8
MODULE SCAN;
9
 
8859 leency 10
IMPORT TXT := TEXTDRV, ARITH, S := STRINGS, ERRORS, LISTS;
6613 leency 11
 
7597 akron1 12
 
6613 leency 13
CONST
14
 
8859 leency 15
    NUMLEN  = 256;
16
    IDLEN   = 256;
17
    TEXTLEN = 512;
6613 leency 18
 
7693 akron1 19
    lxUNDEF*   =  0;  lxIDENT*   =  1;  lxINTEGER*   =  2;  lxHEX*     =  3;
20
    lxCHAR*    =  4;  lxFLOAT*   =  5;  lxSTRING*    =  6;  lxCOMMENT* =  7;
21
    lxEOF*     =  8;
6613 leency 22
 
7693 akron1 23
    lxPLUS*    = 21;  lxMINUS*   = 22;  lxMUL*       = 23;  lxSLASH*   = 24;
24
    lxNOT*     = 25;  lxAND*     = 26;  lxPOINT*     = 27;  lxCOMMA*   = 28;
25
    lxSEMI*    = 29;  lxBAR*     = 30;  lxLROUND*    = 31;  lxLSQUARE* = 32;
26
    lxLCURLY*  = 33;  lxCARET*   = 34;  lxEQ*        = 35;  lxNE*      = 36;
27
    lxLT*      = 37;  lxGT*      = 38;  lxCOLON*     = 39;  lxRROUND*  = 40;
28
    lxRSQUARE* = 41;  lxRCURLY*  = 42;  lxLE*        = 43;  lxGE*      = 44;
29
    lxASSIGN*  = 45;  lxRANGE*   = 46;
6613 leency 30
 
7693 akron1 31
    lxKW       = 51;
6613 leency 32
 
7693 akron1 33
    lxARRAY*   = 51;  lxBEGIN*   = 52;  lxBY*        = 53;  lxCASE*    = 54;
34
    lxCONST*   = 55;  lxDIV*     = 56;  lxDO*        = 57;  lxELSE*    = 58;
35
    lxELSIF*   = 59;  lxEND*     = 60;  lxFALSE*     = 61;  lxFOR*     = 62;
36
    lxIF*      = 63;  lxIMPORT*  = 64;  lxIN*        = 65;  lxIS*      = 66;
37
    lxMOD*     = 67;  lxMODULE*  = 68;  lxNIL*       = 69;  lxOF*      = 70;
38
    lxOR*      = 71;  lxPOINTER* = 72;  lxPROCEDURE* = 73;  lxRECORD*  = 74;
39
    lxREPEAT*  = 75;  lxRETURN*  = 76;  lxTHEN*      = 77;  lxTO*      = 78;
40
    lxTRUE*    = 79;  lxTYPE*    = 80;  lxUNTIL*     = 81;  lxVAR*     = 82;
41
    lxWHILE*   = 83;
7597 akron1 42
 
7693 akron1 43
    lxERROR01* =  -1;  lxERROR02* =  -2;  lxERROR03* =  -3;  lxERROR04* =  -4;
8859 leency 44
    lxERROR05* =  -5;  (*lxERROR06* =  -6;*)  lxERROR07* =  -7;  lxERROR08* =  -8;
7693 akron1 45
    lxERROR09* =  -9;  lxERROR10* = -10;  lxERROR11* = -11;  lxERROR12* = -12;
46
    lxERROR13* = -13;
7597 akron1 47
 
48
 
6613 leency 49
TYPE
50
 
8859 leency 51
    TEXTSTR* = ARRAY TEXTLEN OF CHAR;
52
    IDSTR* = ARRAY IDLEN OF CHAR;
6613 leency 53
 
8097 maxcodehac 54
    DEF = POINTER TO RECORD (LISTS.ITEM)
55
 
8859 leency 56
        ident: IDSTR
8097 maxcodehac 57
 
58
    END;
59
 
8859 leency 60
    STRING* = POINTER TO RECORD (LISTS.ITEM)
6613 leency 61
 
8859 leency 62
        s*: TEXTSTR;
63
        offset*, offsetW*, hash: INTEGER
6613 leency 64
 
7597 akron1 65
    END;
66
 
8859 leency 67
    IDENT* = RECORD
68
 
69
        s*:    IDSTR;
70
        hash*: INTEGER
71
 
72
    END;
73
 
7597 akron1 74
    POSITION* = RECORD
75
 
76
        line*, col*: INTEGER
77
 
78
    END;
79
 
80
    LEX* = RECORD
81
 
7693 akron1 82
        sym*:       INTEGER;
83
        pos*:       POSITION;
84
        ident*:     IDENT;
8859 leency 85
        string*:    STRING;
7693 akron1 86
        value*:     ARITH.VALUE;
8859 leency 87
        error*:     INTEGER
7597 akron1 88
 
89
    END;
90
 
7693 akron1 91
    SCANNER* = TXT.TEXT;
7597 akron1 92
 
8859 leency 93
    KEYWORD = ARRAY 10 OF CHAR;
7597 akron1 94
 
8859 leency 95
 
6613 leency 96
VAR
97
 
7696 akron1 98
    delimiters: ARRAY 256 OF BOOLEAN;
6613 leency 99
 
8097 maxcodehac 100
    upto, LowerCase, _if: BOOLEAN;
6613 leency 101
 
8859 leency 102
    strings, def: LISTS.LIST;
7597 akron1 103
 
8859 leency 104
    KW: ARRAY 33 OF RECORD upper, lower: KEYWORD; uhash, lhash: INTEGER END;
8097 maxcodehac 105
 
7597 akron1 106
 
8859 leency 107
PROCEDURE enterKW (s: KEYWORD; idx: INTEGER);
108
BEGIN
109
    KW[idx].lower := s;
110
    KW[idx].upper := s;
111
    S.UpCase(KW[idx].upper);
112
    KW[idx].uhash := S.HashStr(KW[idx].upper);
113
    KW[idx].lhash := S.HashStr(KW[idx].lower);
114
END enterKW;
7597 akron1 115
 
8859 leency 116
 
117
PROCEDURE checkKW (ident: IDENT): INTEGER;
7597 akron1 118
VAR
8859 leency 119
    i, res: INTEGER;
6613 leency 120
 
121
BEGIN
8859 leency 122
    res := lxIDENT;
123
    i := 0;
124
    WHILE i < LEN(KW) DO
125
        IF (KW[i].uhash = ident.hash) & (KW[i].upper = ident.s)
126
        OR LowerCase & (KW[i].lhash = ident.hash) & (KW[i].lower = ident.s) THEN
127
            res := i + lxKW;
128
            i := LEN(KW)
129
        END;
130
        INC(i)
7597 akron1 131
    END
6613 leency 132
 
8859 leency 133
    RETURN res
134
END checkKW;
6613 leency 135
 
7597 akron1 136
 
8859 leency 137
PROCEDURE enterStr* (s: TEXTSTR): STRING;
138
VAR
139
    str, res: STRING;
140
    hash: INTEGER;
141
 
6613 leency 142
BEGIN
8859 leency 143
    hash := S.HashStr(s);
144
    str := strings.first(STRING);
145
    res := NIL;
146
    WHILE str # NIL DO
147
        IF (str.hash = hash) & (str.s = s) THEN
148
            res := str;
149
            str := NIL
150
        ELSE
151
            str := str.next(STRING)
152
        END
153
    END;
154
    IF res = NIL THEN
155
        NEW(res);
156
        res.s := s;
157
        res.offset  := -1;
158
        res.offsetW := -1;
159
        res.hash := hash;
160
        LISTS.push(strings, res)
6613 leency 161
    END
162
 
8859 leency 163
    RETURN res
164
END enterStr;
7597 akron1 165
 
8859 leency 166
 
7693 akron1 167
PROCEDURE nextc (text: TXT.TEXT): CHAR;
168
BEGIN
169
    TXT.next(text)
170
    RETURN text.peak
171
END nextc;
172
 
173
 
8859 leency 174
PROCEDURE setIdent* (VAR ident: IDENT; s: IDSTR);
175
BEGIN
176
    ident.s := s;
177
    ident.hash := S.HashStr(s)
178
END setIdent;
179
 
180
 
7693 akron1 181
PROCEDURE ident (text: TXT.TEXT; VAR lex: LEX);
7597 akron1 182
VAR
183
    c: CHAR;
8859 leency 184
    i: INTEGER;
7597 akron1 185
 
6613 leency 186
BEGIN
7693 akron1 187
    c := text.peak;
7597 akron1 188
    ASSERT(S.letter(c));
6613 leency 189
 
8859 leency 190
    i := 0;
191
    WHILE (i < IDLEN - 1) & (S.letter(c) OR S.digit(c)) DO
192
        lex.ident.s[i] := c;
193
        INC(i);
7693 akron1 194
        c := nextc(text)
7597 akron1 195
    END;
196
 
8859 leency 197
    lex.ident.s[i] := 0X;
198
    lex.ident.hash := S.HashStr(lex.ident.s);
199
    lex.sym := checkKW(lex.ident);
200
 
201
    IF S.letter(c) OR S.digit(c) THEN
202
        ERRORS.WarningMsg(lex.pos.line, lex.pos.col, 2);
203
        WHILE S.letter(c) OR S.digit(c) DO
204
            c := nextc(text)
7696 akron1 205
        END
6613 leency 206
    END
7597 akron1 207
END ident;
6613 leency 208
 
209
 
7693 akron1 210
PROCEDURE number (text: TXT.TEXT; VAR lex: LEX);
8859 leency 211
TYPE
212
    NUMSTR = ARRAY NUMLEN OF CHAR;
213
 
7597 akron1 214
VAR
215
    c: CHAR;
216
    hex: BOOLEAN;
8859 leency 217
    error, sym, i: INTEGER;
218
    num: NUMSTR;
6613 leency 219
 
8859 leency 220
 
221
    PROCEDURE push (VAR num: NUMSTR; VAR i: INTEGER; c: CHAR);
222
    BEGIN
223
        IF i < NUMLEN - 1 THEN
224
            num[i] := c;
225
            INC(i)
226
        END
227
    END push;
228
 
229
 
7597 akron1 230
BEGIN
7693 akron1 231
    c := text.peak;
7597 akron1 232
    ASSERT(S.digit(c));
6613 leency 233
 
8859 leency 234
    i := 0;
235
 
7597 akron1 236
    error := 0;
6613 leency 237
 
8097 maxcodehac 238
    sym := lxINTEGER;
7597 akron1 239
    hex := FALSE;
240
 
241
    WHILE S.digit(c) DO
8859 leency 242
        push(num, i, c);
7693 akron1 243
        c := nextc(text)
6613 leency 244
    END;
7597 akron1 245
 
8859 leency 246
    WHILE S.hexdigit(c) OR LowerCase & ("a" <= c) & (c <= "f") DO
247
        S.cap(c);
248
        push(num, i, c);
7693 akron1 249
        c := nextc(text);
7597 akron1 250
        hex := TRUE
6613 leency 251
    END;
7597 akron1 252
 
8859 leency 253
    IF (c = "H") OR LowerCase & (c = "h") THEN
254
        push(num, i, c);
7693 akron1 255
        TXT.next(text);
8097 maxcodehac 256
        sym := lxHEX
7597 akron1 257
 
8859 leency 258
    ELSIF (c = "X") OR LowerCase & (c = "x") THEN
259
        push(num, i, c);
7693 akron1 260
        TXT.next(text);
8097 maxcodehac 261
        sym := lxCHAR
7597 akron1 262
 
263
    ELSIF c = "." THEN
264
 
265
        IF hex THEN
8097 maxcodehac 266
            sym := lxERROR01
6613 leency 267
        ELSE
7597 akron1 268
 
7693 akron1 269
            c := nextc(text);
7597 akron1 270
 
271
            IF c # "." THEN
8859 leency 272
                push(num, i, ".");
8097 maxcodehac 273
                sym := lxFLOAT
7597 akron1 274
            ELSE
8097 maxcodehac 275
                sym := lxINTEGER;
7693 akron1 276
                text.peak := 7FX;
277
                upto := TRUE
7597 akron1 278
            END;
279
 
280
            WHILE S.digit(c) DO
8859 leency 281
                push(num, i, c);
7693 akron1 282
                c := nextc(text)
7597 akron1 283
            END;
284
 
8859 leency 285
            IF (c = "E") OR LowerCase & (c = "e") THEN
7597 akron1 286
 
8859 leency 287
                push(num, i, c);
7693 akron1 288
                c := nextc(text);
7597 akron1 289
                IF (c = "+") OR (c = "-") THEN
8859 leency 290
                    push(num, i, c);
7693 akron1 291
                    c := nextc(text)
7597 akron1 292
                END;
293
 
294
                IF S.digit(c) THEN
295
                    WHILE S.digit(c) DO
8859 leency 296
                        push(num, i, c);
7693 akron1 297
                        c := nextc(text)
7597 akron1 298
                    END
299
                ELSE
8097 maxcodehac 300
                    sym := lxERROR02
7597 akron1 301
                END
302
 
303
            END
304
 
6613 leency 305
        END
7597 akron1 306
 
7693 akron1 307
    ELSIF hex THEN
8097 maxcodehac 308
        sym := lxERROR01
7597 akron1 309
 
310
    END;
311
 
8859 leency 312
    IF (i = NUMLEN - 1) & (sym >= 0) THEN
8097 maxcodehac 313
        sym := lxERROR07
7597 akron1 314
    END;
315
 
8859 leency 316
    num[i] := 0X;
317
 
8097 maxcodehac 318
    IF sym = lxINTEGER THEN
8859 leency 319
        ARITH.iconv(num, lex.value, error)
8097 maxcodehac 320
    ELSIF (sym = lxHEX) OR (sym = lxCHAR) THEN
8859 leency 321
        ARITH.hconv(num, lex.value, error)
8097 maxcodehac 322
    ELSIF sym = lxFLOAT THEN
8859 leency 323
        ARITH.fconv(num, lex.value, error)
7597 akron1 324
    END;
325
 
326
    CASE error OF
327
    |0:
8097 maxcodehac 328
    |1: sym := lxERROR08
329
    |2: sym := lxERROR09
330
    |3: sym := lxERROR10
331
    |4: sym := lxERROR11
332
    |5: sym := lxERROR12
333
    END;
6613 leency 334
 
8097 maxcodehac 335
    lex.sym := sym
7597 akron1 336
END number;
337
 
338
 
7693 akron1 339
PROCEDURE string (text: TXT.TEXT; VAR lex: LEX; quot: CHAR);
7597 akron1 340
VAR
7693 akron1 341
    c: CHAR;
8859 leency 342
    i: INTEGER;
343
    str: TEXTSTR;
7597 akron1 344
 
345
BEGIN
7693 akron1 346
    c  := nextc(text);
7597 akron1 347
 
8859 leency 348
    i := 0;
349
    WHILE (i < LEN(str) - 1) & (c # quot) & (c # 0X) & ~text.eol & ~text.eof DO
350
        str[i] := c;
7693 akron1 351
        c := nextc(text);
8859 leency 352
        INC(i)
6613 leency 353
    END;
7597 akron1 354
 
8859 leency 355
    str[i] := 0X;
356
 
357
    IF (i = LEN(str) - 1) & (c # quot) & (c # 0X) & ~text.eol & ~text.eof THEN
358
        lex.sym := lxERROR05
359
    END;
360
 
7597 akron1 361
    IF c = quot THEN
7693 akron1 362
        TXT.next(text);
8859 leency 363
        IF i # 1 THEN
364
            lex.sym := lxSTRING
7597 akron1 365
        ELSE
8859 leency 366
            lex.sym := lxCHAR;
367
            ARITH.setChar(lex.value, ORD(str[0]))
7597 akron1 368
        END
8859 leency 369
    ELSIF lex.sym # lxERROR05 THEN
7597 akron1 370
        lex.sym := lxERROR03
6613 leency 371
    END;
7597 akron1 372
 
373
    IF lex.sym = lxSTRING THEN
8859 leency 374
        lex.string := enterStr(str);
7597 akron1 375
        lex.value.typ := ARITH.tSTRING;
376
        lex.value.string := lex.string
6613 leency 377
    END
378
 
7597 akron1 379
END string;
380
 
381
 
7693 akron1 382
PROCEDURE comment (text: TXT.TEXT);
7597 akron1 383
VAR
384
    c: CHAR;
385
    cond, depth: INTEGER;
386
 
6613 leency 387
BEGIN
7693 akron1 388
    cond  := 0;
7597 akron1 389
    depth := 1;
6613 leency 390
 
7597 akron1 391
    REPEAT
392
 
7693 akron1 393
        c := text.peak;
394
        TXT.next(text);
7597 akron1 395
 
396
        IF c = "*" THEN
397
            IF cond = 1 THEN
398
                cond := 0;
399
                INC(depth)
400
            ELSE
401
               cond := 2
402
            END
403
        ELSIF c = ")" THEN
404
            IF cond = 2 THEN
405
                DEC(depth)
406
            END;
407
            cond := 0
408
        ELSIF c = "(" THEN
409
            cond := 1
410
        ELSE
411
            cond := 0
412
        END
413
 
414
    UNTIL (depth = 0) OR text.eof
415
 
416
END comment;
417
 
418
 
8859 leency 419
PROCEDURE delimiter (text: TXT.TEXT; c: CHAR): INTEGER;
8097 maxcodehac 420
VAR
421
    sym: INTEGER;
8859 leency 422
    c0:  CHAR;
8097 maxcodehac 423
 
6613 leency 424
BEGIN
8859 leency 425
    c0 := c;
7693 akron1 426
    c := nextc(text);
7597 akron1 427
 
8859 leency 428
    CASE c0 OF
7597 akron1 429
    |"+":
8097 maxcodehac 430
        sym := lxPLUS
7597 akron1 431
 
432
    |"-":
8097 maxcodehac 433
        sym := lxMINUS
7597 akron1 434
 
435
    |"*":
8097 maxcodehac 436
        sym := lxMUL
7597 akron1 437
 
438
    |"/":
8097 maxcodehac 439
        sym := lxSLASH;
7597 akron1 440
 
7693 akron1 441
        IF c = "/" THEN
8097 maxcodehac 442
            sym := lxCOMMENT;
7597 akron1 443
            REPEAT
7693 akron1 444
                TXT.next(text)
7597 akron1 445
            UNTIL text.eol OR text.eof
446
        END
447
 
448
    |"~":
8097 maxcodehac 449
        sym := lxNOT
7597 akron1 450
 
451
    |"&":
8097 maxcodehac 452
        sym := lxAND
7597 akron1 453
 
454
    |".":
8097 maxcodehac 455
        sym := lxPOINT;
7597 akron1 456
 
7693 akron1 457
        IF c = "." THEN
8097 maxcodehac 458
            sym := lxRANGE;
7693 akron1 459
            TXT.next(text)
6613 leency 460
        END
7597 akron1 461
 
462
    |",":
8097 maxcodehac 463
        sym := lxCOMMA
7597 akron1 464
 
465
    |";":
8097 maxcodehac 466
        sym := lxSEMI
7597 akron1 467
 
468
    |"|":
8097 maxcodehac 469
        sym := lxBAR
7597 akron1 470
 
471
    |"(":
8097 maxcodehac 472
        sym := lxLROUND;
7597 akron1 473
 
474
        IF c = "*" THEN
8097 maxcodehac 475
            sym := lxCOMMENT;
7693 akron1 476
            TXT.next(text);
7597 akron1 477
            comment(text)
478
        END
479
 
480
    |"[":
8097 maxcodehac 481
        sym := lxLSQUARE
7597 akron1 482
 
483
    |"{":
8097 maxcodehac 484
        sym := lxLCURLY
7597 akron1 485
 
486
    |"^":
8097 maxcodehac 487
        sym := lxCARET
7597 akron1 488
 
489
    |"=":
8097 maxcodehac 490
        sym := lxEQ
7597 akron1 491
 
492
    |"#":
8097 maxcodehac 493
        sym := lxNE
7597 akron1 494
 
495
    |"<":
8097 maxcodehac 496
        sym := lxLT;
7597 akron1 497
 
498
        IF c = "=" THEN
8097 maxcodehac 499
            sym := lxLE;
7693 akron1 500
            TXT.next(text)
7597 akron1 501
        END
502
 
503
    |">":
8097 maxcodehac 504
        sym := lxGT;
7597 akron1 505
 
506
        IF c = "=" THEN
8097 maxcodehac 507
            sym := lxGE;
7693 akron1 508
            TXT.next(text)
7597 akron1 509
        END
510
 
511
    |":":
8097 maxcodehac 512
        sym := lxCOLON;
7597 akron1 513
 
514
        IF c = "=" THEN
8097 maxcodehac 515
            sym := lxASSIGN;
7693 akron1 516
            TXT.next(text)
7597 akron1 517
        END
518
 
519
    |")":
8097 maxcodehac 520
        sym := lxRROUND
7597 akron1 521
 
522
    |"]":
8097 maxcodehac 523
        sym := lxRSQUARE
7597 akron1 524
 
525
    |"}":
8097 maxcodehac 526
        sym := lxRCURLY
7597 akron1 527
 
8859 leency 528
    END
6613 leency 529
 
8859 leency 530
    RETURN sym
7597 akron1 531
END delimiter;
532
 
533
 
7693 akron1 534
PROCEDURE Next* (text: SCANNER; VAR lex: LEX);
7597 akron1 535
VAR
536
    c: CHAR;
537
 
8097 maxcodehac 538
 
539
    PROCEDURE check (cond: BOOLEAN; text: SCANNER; lex: LEX; errno: INTEGER);
540
    BEGIN
541
        IF ~cond THEN
542
            ERRORS.ErrorMsg(text.fname, lex.pos.line, lex.pos.col, errno)
543
        END
544
    END check;
545
 
546
 
547
    PROCEDURE IsDef (str: ARRAY OF CHAR): BOOLEAN;
548
    VAR
549
        cur: DEF;
550
 
551
    BEGIN
552
        cur := def.first(DEF);
553
        WHILE (cur # NIL) & (cur.ident # str) DO
554
            cur := cur.next(DEF)
555
        END
556
 
557
        RETURN cur # NIL
558
    END IsDef;
559
 
560
 
561
    PROCEDURE Skip (text: SCANNER);
562
    VAR
563
        i: INTEGER;
564
 
565
    BEGIN
566
        i := 0;
567
        WHILE (i <= text.ifc) & ~text._skip[i] DO
568
            INC(i)
569
        END;
570
        text.skip := i <= text.ifc
571
    END Skip;
572
 
573
 
574
    PROCEDURE prep_if (text: SCANNER; VAR lex: LEX);
575
    VAR
576
        skip: BOOLEAN;
577
 
578
    BEGIN
579
        INC(text.ifc);
580
        text._elsif[text.ifc] := lex.sym = lxELSIF;
581
        IF lex.sym = lxIF THEN
582
            INC(text.elsec);
583
            text._else[text.elsec] := FALSE
584
        END;
585
        _if := TRUE;
586
        skip := TRUE;
587
        text.skip := FALSE;
588
 
589
        Next(text, lex);
590
        check(lex.sym = lxLROUND, text, lex, 64);
591
 
592
        Next(text, lex);
593
        check(lex.sym = lxIDENT, text, lex, 22);
594
 
595
        REPEAT
8859 leency 596
            IF IsDef(lex.ident.s) THEN
8097 maxcodehac 597
                skip := FALSE
598
            END;
599
 
600
            Next(text, lex);
601
            IF lex.sym = lxBAR THEN
602
                Next(text, lex);
603
                check(lex.sym = lxIDENT, text, lex, 22)
604
            ELSE
605
                check(lex.sym = lxRROUND, text, lex, 33)
606
            END
607
        UNTIL lex.sym = lxRROUND;
608
 
609
        _if := FALSE;
610
        text._skip[text.ifc] := skip;
611
        Skip(text);
612
        Next(text, lex)
613
    END prep_if;
614
 
615
 
616
    PROCEDURE prep_end (text: SCANNER; VAR lex: LEX);
617
    BEGIN
618
        check(text.ifc > 0, text, lex, 118);
619
        IF lex.sym = lxEND THEN
620
            WHILE text._elsif[text.ifc] DO
621
                DEC(text.ifc)
622
            END;
623
            DEC(text.ifc);
624
            DEC(text.elsec)
625
        ELSIF (lex.sym = lxELSE) OR (lex.sym = lxELSIF) THEN
626
            check(~text._else[text.elsec], text, lex, 118);
627
            text._skip[text.ifc] := ~text._skip[text.ifc];
628
            text._else[text.elsec] := lex.sym = lxELSE
629
        END;
630
        Skip(text);
631
        IF lex.sym = lxELSIF THEN
632
            prep_if(text, lex)
633
        ELSE
634
            Next(text, lex)
635
        END
636
    END prep_end;
637
 
638
 
6613 leency 639
BEGIN
640
 
7597 akron1 641
    REPEAT
7693 akron1 642
        c := text.peak;
7597 akron1 643
 
644
        WHILE S.space(c) DO
7693 akron1 645
            c := nextc(text)
7597 akron1 646
        END;
647
 
648
        lex.pos.line := text.line;
649
        lex.pos.col  := text.col;
650
 
651
        IF S.letter(c) THEN
652
            ident(text, lex)
653
        ELSIF S.digit(c) THEN
7693 akron1 654
            number(text, lex)
7597 akron1 655
        ELSIF (c = '"') OR (c = "'") THEN
7693 akron1 656
            string(text, lex, c)
7696 akron1 657
        ELSIF delimiters[ORD(c)] THEN
8859 leency 658
            lex.sym := delimiter(text, c)
8097 maxcodehac 659
        ELSIF c = "$" THEN
660
            IF S.letter(nextc(text)) THEN
661
                ident(text, lex);
662
                IF lex.sym = lxIF THEN
663
                    IF ~_if THEN
664
                        prep_if(text, lex)
665
                    END
666
                ELSIF (lex.sym = lxEND) OR (lex.sym = lxELSE) OR (lex.sym = lxELSIF) THEN
667
                    IF ~_if THEN
668
                        prep_end(text, lex)
669
                    END
670
                ELSE
671
                    check(FALSE, text, lex, 119)
672
                END
673
            ELSE
674
                check(FALSE, text, lex, 119)
675
            END
7597 akron1 676
        ELSIF c = 0X THEN
677
            lex.sym := lxEOF;
8097 maxcodehac 678
            text.skip := FALSE;
7597 akron1 679
            IF text.eof THEN
680
                INC(lex.pos.col)
681
            END
7693 akron1 682
        ELSIF (c = 7FX) & upto THEN
683
            upto := FALSE;
684
            lex.sym := lxRANGE;
685
            DEC(lex.pos.col);
686
            TXT.next(text)
7597 akron1 687
        ELSE
7693 akron1 688
            TXT.next(text);
7597 akron1 689
            lex.sym := lxERROR04
690
        END;
691
 
692
        IF lex.sym < 0 THEN
693
            lex.error := -lex.sym
694
        ELSE
695
            lex.error := 0
696
        END
697
 
8097 maxcodehac 698
    UNTIL (lex.sym # lxCOMMENT) & ~text.skip
7597 akron1 699
 
700
END Next;
701
 
702
 
703
PROCEDURE open* (name: ARRAY OF CHAR): SCANNER;
7693 akron1 704
    RETURN TXT.open(name)
7597 akron1 705
END open;
706
 
707
 
708
PROCEDURE close* (VAR scanner: SCANNER);
709
BEGIN
7693 akron1 710
    TXT.close(scanner)
7597 akron1 711
END close;
712
 
713
 
8097 maxcodehac 714
PROCEDURE init* (lower: BOOLEAN);
7597 akron1 715
VAR
716
    i: INTEGER;
717
    delim: ARRAY 23 OF CHAR;
718
 
719
BEGIN
7693 akron1 720
    upto := FALSE;
8097 maxcodehac 721
    LowerCase := lower;
7597 akron1 722
 
723
    FOR i := 0 TO 255 DO
7696 akron1 724
        delimiters[i] := FALSE
6613 leency 725
    END;
7597 akron1 726
 
727
    delim := "+-*/~&.,;|([{^=#<>:)]}";
728
 
729
    FOR i := 0 TO LEN(delim) - 2 DO
7696 akron1 730
        delimiters[ORD(delim[i])] := TRUE
6613 leency 731
    END;
732
 
8859 leency 733
    enterKW("array",      0);
734
    enterKW("begin",      1);
735
    enterKW("by",         2);
736
    enterKW("case",       3);
737
    enterKW("const",      4);
738
    enterKW("div",        5);
739
    enterKW("do",         6);
740
    enterKW("else",       7);
741
    enterKW("elsif",      8);
742
    enterKW("end",        9);
743
    enterKW("false",     10);
744
    enterKW("for",       11);
745
    enterKW("if",        12);
746
    enterKW("import",    13);
747
    enterKW("in",        14);
748
    enterKW("is",        15);
749
    enterKW("mod",       16);
750
    enterKW("module",    17);
751
    enterKW("nil",       18);
752
    enterKW("of",        19);
753
    enterKW("or",        20);
754
    enterKW("pointer",   21);
755
    enterKW("procedure", 22);
756
    enterKW("record",    23);
757
    enterKW("repeat",    24);
758
    enterKW("return",    25);
759
    enterKW("then",      26);
760
    enterKW("to",        27);
761
    enterKW("true",      28);
762
    enterKW("type",      29);
763
    enterKW("until",     30);
764
    enterKW("var",       31);
765
    enterKW("while",     32)
7597 akron1 766
END init;
6613 leency 767
 
7597 akron1 768
 
8097 maxcodehac 769
PROCEDURE NewDef* (str: ARRAY OF CHAR);
770
VAR
771
    item: DEF;
772
 
6613 leency 773
BEGIN
8097 maxcodehac 774
    NEW(item);
775
    COPY(str, item.ident);
776
    LISTS.push(def, item)
777
END NewDef;
778
 
779
 
780
BEGIN
8859 leency 781
    def := LISTS.create(NIL);
782
    strings := LISTS.create(NIL)
7983 leency 783
END SCAN.