Subversion Repositories Kolibri OS

Rev

Rev 8097 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. (*
  2.     BSD 2-Clause License
  3.  
  4.     Copyright (c) 2018-2021, Anton Krotov
  5.     All rights reserved.
  6. *)
  7.  
  8. MODULE SCAN;
  9.  
  10. IMPORT TXT := TEXTDRV, ARITH, S := STRINGS, ERRORS, LISTS;
  11.  
  12.  
  13. CONST
  14.  
  15.     NUMLEN  = 256;
  16.     IDLEN   = 256;
  17.     TEXTLEN = 512;
  18.  
  19.     lxUNDEF*   =  0;  lxIDENT*   =  1;  lxINTEGER*   =  2;  lxHEX*     =  3;
  20.     lxCHAR*    =  4;  lxFLOAT*   =  5;  lxSTRING*    =  6;  lxCOMMENT* =  7;
  21.     lxEOF*     =  8;
  22.  
  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;
  30.  
  31.     lxKW       = 51;
  32.  
  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;
  42.  
  43.     lxERROR01* =  -1;  lxERROR02* =  -2;  lxERROR03* =  -3;  lxERROR04* =  -4;
  44.     lxERROR05* =  -5;  (*lxERROR06* =  -6;*)  lxERROR07* =  -7;  lxERROR08* =  -8;
  45.     lxERROR09* =  -9;  lxERROR10* = -10;  lxERROR11* = -11;  lxERROR12* = -12;
  46.     lxERROR13* = -13;
  47.  
  48.  
  49. TYPE
  50.  
  51.     TEXTSTR* = ARRAY TEXTLEN OF CHAR;
  52.     IDSTR* = ARRAY IDLEN OF CHAR;
  53.  
  54.     DEF = POINTER TO RECORD (LISTS.ITEM)
  55.  
  56.         ident: IDSTR
  57.  
  58.     END;
  59.  
  60.     STRING* = POINTER TO RECORD (LISTS.ITEM)
  61.  
  62.         s*: TEXTSTR;
  63.         offset*, offsetW*, hash: INTEGER
  64.  
  65.     END;
  66.  
  67.     IDENT* = RECORD
  68.  
  69.         s*:    IDSTR;
  70.         hash*: INTEGER
  71.  
  72.     END;
  73.  
  74.     POSITION* = RECORD
  75.  
  76.         line*, col*: INTEGER
  77.  
  78.     END;
  79.  
  80.     LEX* = RECORD
  81.  
  82.         sym*:       INTEGER;
  83.         pos*:       POSITION;
  84.         ident*:     IDENT;
  85.         string*:    STRING;
  86.         value*:     ARITH.VALUE;
  87.         error*:     INTEGER
  88.  
  89.     END;
  90.  
  91.     SCANNER* = TXT.TEXT;
  92.  
  93.     KEYWORD = ARRAY 10 OF CHAR;
  94.  
  95.  
  96. VAR
  97.  
  98.     delimiters: ARRAY 256 OF BOOLEAN;
  99.  
  100.     upto, LowerCase, _if: BOOLEAN;
  101.  
  102.     strings, def: LISTS.LIST;
  103.  
  104.     KW: ARRAY 33 OF RECORD upper, lower: KEYWORD; uhash, lhash: INTEGER END;
  105.  
  106.  
  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;
  115.  
  116.  
  117. PROCEDURE checkKW (ident: IDENT): INTEGER;
  118. VAR
  119.     i, res: INTEGER;
  120.  
  121. BEGIN
  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)
  131.     END
  132.  
  133.     RETURN res
  134. END checkKW;
  135.  
  136.  
  137. PROCEDURE enterStr* (s: TEXTSTR): STRING;
  138. VAR
  139.     str, res: STRING;
  140.     hash: INTEGER;
  141.  
  142. BEGIN
  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)
  161.     END
  162.  
  163.     RETURN res
  164. END enterStr;
  165.  
  166.  
  167. PROCEDURE nextc (text: TXT.TEXT): CHAR;
  168. BEGIN
  169.     TXT.next(text)
  170.     RETURN text.peak
  171. END nextc;
  172.  
  173.  
  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.  
  181. PROCEDURE ident (text: TXT.TEXT; VAR lex: LEX);
  182. VAR
  183.     c: CHAR;
  184.     i: INTEGER;
  185.  
  186. BEGIN
  187.     c := text.peak;
  188.     ASSERT(S.letter(c));
  189.  
  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);
  194.         c := nextc(text)
  195.     END;
  196.  
  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)
  205.         END
  206.     END
  207. END ident;
  208.  
  209.  
  210. PROCEDURE number (text: TXT.TEXT; VAR lex: LEX);
  211. TYPE
  212.     NUMSTR = ARRAY NUMLEN OF CHAR;
  213.  
  214. VAR
  215.     c: CHAR;
  216.     hex: BOOLEAN;
  217.     error, sym, i: INTEGER;
  218.     num: NUMSTR;
  219.  
  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.  
  230. BEGIN
  231.     c := text.peak;
  232.     ASSERT(S.digit(c));
  233.  
  234.     i := 0;
  235.  
  236.     error := 0;
  237.  
  238.     sym := lxINTEGER;
  239.     hex := FALSE;
  240.  
  241.     WHILE S.digit(c) DO
  242.         push(num, i, c);
  243.         c := nextc(text)
  244.     END;
  245.  
  246.     WHILE S.hexdigit(c) OR LowerCase & ("a" <= c) & (c <= "f") DO
  247.         S.cap(c);
  248.         push(num, i, c);
  249.         c := nextc(text);
  250.         hex := TRUE
  251.     END;
  252.  
  253.     IF (c = "H") OR LowerCase & (c = "h") THEN
  254.         push(num, i, c);
  255.         TXT.next(text);
  256.         sym := lxHEX
  257.  
  258.     ELSIF (c = "X") OR LowerCase & (c = "x") THEN
  259.         push(num, i, c);
  260.         TXT.next(text);
  261.         sym := lxCHAR
  262.  
  263.     ELSIF c = "." THEN
  264.  
  265.         IF hex THEN
  266.             sym := lxERROR01
  267.         ELSE
  268.  
  269.             c := nextc(text);
  270.  
  271.             IF c # "." THEN
  272.                 push(num, i, ".");
  273.                 sym := lxFLOAT
  274.             ELSE
  275.                 sym := lxINTEGER;
  276.                 text.peak := 7FX;
  277.                 upto := TRUE
  278.             END;
  279.  
  280.             WHILE S.digit(c) DO
  281.                 push(num, i, c);
  282.                 c := nextc(text)
  283.             END;
  284.  
  285.             IF (c = "E") OR LowerCase & (c = "e") THEN
  286.  
  287.                 push(num, i, c);
  288.                 c := nextc(text);
  289.                 IF (c = "+") OR (c = "-") THEN
  290.                     push(num, i, c);
  291.                     c := nextc(text)
  292.                 END;
  293.  
  294.                 IF S.digit(c) THEN
  295.                     WHILE S.digit(c) DO
  296.                         push(num, i, c);
  297.                         c := nextc(text)
  298.                     END
  299.                 ELSE
  300.                     sym := lxERROR02
  301.                 END
  302.  
  303.             END
  304.  
  305.         END
  306.  
  307.     ELSIF hex THEN
  308.         sym := lxERROR01
  309.  
  310.     END;
  311.  
  312.     IF (i = NUMLEN - 1) & (sym >= 0) THEN
  313.         sym := lxERROR07
  314.     END;
  315.  
  316.     num[i] := 0X;
  317.  
  318.     IF sym = lxINTEGER THEN
  319.         ARITH.iconv(num, lex.value, error)
  320.     ELSIF (sym = lxHEX) OR (sym = lxCHAR) THEN
  321.         ARITH.hconv(num, lex.value, error)
  322.     ELSIF sym = lxFLOAT THEN
  323.         ARITH.fconv(num, lex.value, error)
  324.     END;
  325.  
  326.     CASE error OF
  327.     |0:
  328.     |1: sym := lxERROR08
  329.     |2: sym := lxERROR09
  330.     |3: sym := lxERROR10
  331.     |4: sym := lxERROR11
  332.     |5: sym := lxERROR12
  333.     END;
  334.  
  335.     lex.sym := sym
  336. END number;
  337.  
  338.  
  339. PROCEDURE string (text: TXT.TEXT; VAR lex: LEX; quot: CHAR);
  340. VAR
  341.     c: CHAR;
  342.     i: INTEGER;
  343.     str: TEXTSTR;
  344.  
  345. BEGIN
  346.     c  := nextc(text);
  347.  
  348.     i := 0;
  349.     WHILE (i < LEN(str) - 1) & (c # quot) & (c # 0X) & ~text.eol & ~text.eof DO
  350.         str[i] := c;
  351.         c := nextc(text);
  352.         INC(i)
  353.     END;
  354.  
  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.  
  361.     IF c = quot THEN
  362.         TXT.next(text);
  363.         IF i # 1 THEN
  364.             lex.sym := lxSTRING
  365.         ELSE
  366.             lex.sym := lxCHAR;
  367.             ARITH.setChar(lex.value, ORD(str[0]))
  368.         END
  369.     ELSIF lex.sym # lxERROR05 THEN
  370.         lex.sym := lxERROR03
  371.     END;
  372.  
  373.     IF lex.sym = lxSTRING THEN
  374.         lex.string := enterStr(str);
  375.         lex.value.typ := ARITH.tSTRING;
  376.         lex.value.string := lex.string
  377.     END
  378.  
  379. END string;
  380.  
  381.  
  382. PROCEDURE comment (text: TXT.TEXT);
  383. VAR
  384.     c: CHAR;
  385.     cond, depth: INTEGER;
  386.  
  387. BEGIN
  388.     cond  := 0;
  389.     depth := 1;
  390.  
  391.     REPEAT
  392.  
  393.         c := text.peak;
  394.         TXT.next(text);
  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.  
  419. PROCEDURE delimiter (text: TXT.TEXT; c: CHAR): INTEGER;
  420. VAR
  421.     sym: INTEGER;
  422.     c0:  CHAR;
  423.  
  424. BEGIN
  425.     c0 := c;
  426.     c := nextc(text);
  427.  
  428.     CASE c0 OF
  429.     |"+":
  430.         sym := lxPLUS
  431.  
  432.     |"-":
  433.         sym := lxMINUS
  434.  
  435.     |"*":
  436.         sym := lxMUL
  437.  
  438.     |"/":
  439.         sym := lxSLASH;
  440.  
  441.         IF c = "/" THEN
  442.             sym := lxCOMMENT;
  443.             REPEAT
  444.                 TXT.next(text)
  445.             UNTIL text.eol OR text.eof
  446.         END
  447.  
  448.     |"~":
  449.         sym := lxNOT
  450.  
  451.     |"&":
  452.         sym := lxAND
  453.  
  454.     |".":
  455.         sym := lxPOINT;
  456.  
  457.         IF c = "." THEN
  458.             sym := lxRANGE;
  459.             TXT.next(text)
  460.         END
  461.  
  462.     |",":
  463.         sym := lxCOMMA
  464.  
  465.     |";":
  466.         sym := lxSEMI
  467.  
  468.     |"|":
  469.         sym := lxBAR
  470.  
  471.     |"(":
  472.         sym := lxLROUND;
  473.  
  474.         IF c = "*" THEN
  475.             sym := lxCOMMENT;
  476.             TXT.next(text);
  477.             comment(text)
  478.         END
  479.  
  480.     |"[":
  481.         sym := lxLSQUARE
  482.  
  483.     |"{":
  484.         sym := lxLCURLY
  485.  
  486.     |"^":
  487.         sym := lxCARET
  488.  
  489.     |"=":
  490.         sym := lxEQ
  491.  
  492.     |"#":
  493.         sym := lxNE
  494.  
  495.     |"<":
  496.         sym := lxLT;
  497.  
  498.         IF c = "=" THEN
  499.             sym := lxLE;
  500.             TXT.next(text)
  501.         END
  502.  
  503.     |">":
  504.         sym := lxGT;
  505.  
  506.         IF c = "=" THEN
  507.             sym := lxGE;
  508.             TXT.next(text)
  509.         END
  510.  
  511.     |":":
  512.         sym := lxCOLON;
  513.  
  514.         IF c = "=" THEN
  515.             sym := lxASSIGN;
  516.             TXT.next(text)
  517.         END
  518.  
  519.     |")":
  520.         sym := lxRROUND
  521.  
  522.     |"]":
  523.         sym := lxRSQUARE
  524.  
  525.     |"}":
  526.         sym := lxRCURLY
  527.  
  528.     END
  529.  
  530.     RETURN sym
  531. END delimiter;
  532.  
  533.  
  534. PROCEDURE Next* (text: SCANNER; VAR lex: LEX);
  535. VAR
  536.     c: CHAR;
  537.  
  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
  596.             IF IsDef(lex.ident.s) THEN
  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.  
  639. BEGIN
  640.  
  641.     REPEAT
  642.         c := text.peak;
  643.  
  644.         WHILE S.space(c) DO
  645.             c := nextc(text)
  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
  654.             number(text, lex)
  655.         ELSIF (c = '"') OR (c = "'") THEN
  656.             string(text, lex, c)
  657.         ELSIF delimiters[ORD(c)] THEN
  658.             lex.sym := delimiter(text, c)
  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
  676.         ELSIF c = 0X THEN
  677.             lex.sym := lxEOF;
  678.             text.skip := FALSE;
  679.             IF text.eof THEN
  680.                 INC(lex.pos.col)
  681.             END
  682.         ELSIF (c = 7FX) & upto THEN
  683.             upto := FALSE;
  684.             lex.sym := lxRANGE;
  685.             DEC(lex.pos.col);
  686.             TXT.next(text)
  687.         ELSE
  688.             TXT.next(text);
  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.  
  698.     UNTIL (lex.sym # lxCOMMENT) & ~text.skip
  699.  
  700. END Next;
  701.  
  702.  
  703. PROCEDURE open* (name: ARRAY OF CHAR): SCANNER;
  704.     RETURN TXT.open(name)
  705. END open;
  706.  
  707.  
  708. PROCEDURE close* (VAR scanner: SCANNER);
  709. BEGIN
  710.     TXT.close(scanner)
  711. END close;
  712.  
  713.  
  714. PROCEDURE init* (lower: BOOLEAN);
  715. VAR
  716.     i: INTEGER;
  717.     delim: ARRAY 23 OF CHAR;
  718.  
  719. BEGIN
  720.     upto := FALSE;
  721.     LowerCase := lower;
  722.  
  723.     FOR i := 0 TO 255 DO
  724.         delimiters[i] := FALSE
  725.     END;
  726.  
  727.     delim := "+-*/~&.,;|([{^=#<>:)]}";
  728.  
  729.     FOR i := 0 TO LEN(delim) - 2 DO
  730.         delimiters[ORD(delim[i])] := TRUE
  731.     END;
  732.  
  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)
  766. END init;
  767.  
  768.  
  769. PROCEDURE NewDef* (str: ARRAY OF CHAR);
  770. VAR
  771.     item: DEF;
  772.  
  773. BEGIN
  774.     NEW(item);
  775.     COPY(str, item.ident);
  776.     LISTS.push(def, item)
  777. END NewDef;
  778.  
  779.  
  780. BEGIN
  781.     def := LISTS.create(NIL);
  782.     strings := LISTS.create(NIL)
  783. END SCAN.