Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. (*
  2.     Copyright 2016 Anton Krotov
  3.  
  4.     This file is part of Compiler.
  5.  
  6.     Compiler is free software: you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation, either version 3 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     Compiler is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with Compiler. If not, see <http://www.gnu.org/licenses/>.
  18. *)
  19.  
  20. MODULE SCAN;
  21.  
  22. IMPORT UTILS, sys := SYSTEM;
  23.  
  24. CONST
  25.  
  26.   Tab = 8;
  27.   maxINT* = 7FFFFFFFH;
  28.   minINT* = 80000000H;
  29.   maxREAL* = 3.39E38;
  30.   maxDBL* = 1.69D308;
  31.   minREAL* = 1.41E-45;
  32.   IDLENGTH = 255;
  33.   STRLENGTH* = 256;
  34.  
  35.   lxEOF = 0; lxINT = -1; lxREAL = -2; lxSTRING = -3; lxIDENT = -4; lxHEX = -5; lxCHX = -6; lxLONGREAL = -7;
  36.   lxARRAY = 1; lxBEGIN = 2; lxBY = 3; lxCASE = 4; lxCONST = 5; lxDIV = 6; lxDO = 7; lxELSE = 8;
  37.   lxELSIF = 9; lxEND = 10; lxFALSE = 11; lxFOR = 12; lxIF = 13; lxIMPORT = 14; lxIN = 15; lxIS = 16;
  38.   lxMOD = 17; lxMODULE = 18; lxNIL = 19; lxOF = 20; lxOR = 21; lxPOINTER = 22; lxPROCEDURE = 23;
  39.   lxRECORD = 24; lxREPEAT = 25; lxRETURN = 26; lxTHEN = 27; lxTO = 28; lxTRUE = 29; lxTYPE = 30;
  40.   lxUNTIL = 31; lxVAR = 32; lxWHILE = 33;
  41.  
  42.   lxPlus = 51; lxMinus = 52; lxMult = 53; lxSlash = 54; lxNot = 55; lxAnd = 56; lxComma = 57; lxSemi = 58;
  43.   lxStick = 59; lxLRound = 60; lxLSquare = 61; lxLCurly = 62; lxCaret = 63; lxRRound = 64; lxRSquare = 65;
  44.   lxRCurly = 66; lxDot = 67; lxDbl = 68; lxAssign = 69; lxColon = 70;
  45.   lxEQ = 71; lxNE = 72; lxLT = 73; lxGT = 74; lxLE = 75; lxGE = 76;
  46.  
  47.   lxERR0 = 100; lxERR1 = 101; lxERR2 = 102; lxERR3 = 103; lxERR4 = 104; lxERR5 = 105; lxERR6 = 106;
  48.   lxERR7 = 107; lxERR8 = 108; lxERR9 = 109; lxERR10 = 110; lxERR11 = 111; lxERR20 = 120;
  49.  
  50. TYPE
  51.  
  52.   TCoord* = RECORD line*, col*: INTEGER END;
  53.  
  54.   NODE* = POINTER TO RECORD
  55.     Left, Right: NODE;
  56.     tLex: INTEGER;
  57.     Name*: UTILS.STRING
  58.   END;
  59.  
  60.   SCANNER* = POINTER TO RECORD
  61.     File, ccol, cline, count, tLex, vINT: INTEGER;
  62.     coord: TCoord;
  63.     ch, vCHX: CHAR;
  64.     Lex: UTILS.STRING;
  65.     vFLT: LONGREAL;
  66.     id: NODE;
  67.     buf, bufpos: INTEGER;
  68.     CR, UTF8: BOOLEAN
  69.   END;
  70.  
  71. VAR
  72.  
  73.   Lex*: UTILS.STRING; File, ccol, cline, count*, tLex*, vINT*: INTEGER;
  74.   coord*: TCoord;
  75.   vFLT*: LONGREAL; id*: NODE; ch, vCHX*: CHAR;
  76.   buf, bufpos: INTEGER; CR, UTF8: BOOLEAN;
  77.   Nodes: ARRAY 256 OF NODE;
  78.   _START*, _version*: NODE;
  79.  
  80. PROCEDURE AddNode*(Name: UTILS.STRING): NODE;
  81. VAR cur, res: NODE;
  82.  
  83.   PROCEDURE NewNode(Right: BOOLEAN);
  84.   BEGIN
  85.     NEW(res);
  86.     UTILS.MemErr(res = NIL);
  87.     res.Name := Name;
  88.     res.tLex := lxIDENT;
  89.     res.Left := NIL;
  90.     res.Right := NIL;
  91.     IF Right THEN
  92.       cur.Right := res
  93.     ELSE
  94.       cur.Left := res
  95.     END
  96.   END NewNode;
  97.  
  98. BEGIN
  99.   res := NIL;
  100.   cur := Nodes[ORD(Name[0])];
  101.   REPEAT
  102.     IF Name > cur.Name THEN
  103.       IF cur.Right # NIL THEN
  104.         cur := cur.Right
  105.       ELSE
  106.         NewNode(TRUE)
  107.       END
  108.     ELSIF Name < cur.Name THEN
  109.       IF cur.Left # NIL THEN
  110.         cur := cur.Left
  111.       ELSE
  112.         NewNode(FALSE)
  113.       END
  114.     ELSE
  115.       res := cur
  116.     END
  117.   UNTIL res # NIL
  118.   RETURN res
  119. END AddNode;
  120.  
  121. PROCEDURE Backup*(scanner: SCANNER);
  122. BEGIN
  123.   scanner.File := File;
  124.   scanner.ccol := ccol;
  125.   scanner.cline := cline;
  126.   scanner.ch := ch;
  127.   scanner.Lex := Lex;
  128.   scanner.count := count;
  129.   scanner.coord := coord;
  130.   scanner.tLex := tLex;
  131.   scanner.vINT := vINT;
  132.   scanner.vFLT := vFLT;
  133.   scanner.vCHX := vCHX;
  134.   scanner.buf := buf;
  135.   scanner.bufpos := bufpos;
  136.   scanner.CR := CR;
  137.   scanner.UTF8 := UTF8
  138. END Backup;
  139.  
  140. PROCEDURE Recover*(scanner: SCANNER);
  141. BEGIN
  142.   File := scanner.File;
  143.   ccol := scanner.ccol;
  144.   cline := scanner.cline;
  145.   ch := scanner.ch;
  146.   Lex := scanner.Lex;
  147.   count := scanner.count;
  148.   coord := scanner.coord;
  149.   tLex := scanner.tLex;
  150.   vINT := scanner.vINT;
  151.   vFLT := scanner.vFLT;
  152.   vCHX := scanner.vCHX;
  153.   buf := scanner.buf;
  154.   bufpos := scanner.bufpos;
  155.   CR := scanner.CR;
  156.   UTF8 := scanner.UTF8
  157. END Recover;
  158.  
  159. PROCEDURE Next;
  160. VAR cr: BOOLEAN;
  161. BEGIN
  162.   cr := FALSE;
  163.   sys.GET(bufpos, ch);
  164.   INC(ccol);
  165.   CASE ch OF
  166.   |0AX: IF ~CR THEN INC(cline) END; ccol := 0
  167.   |0DX: INC(cline); ccol := 0; cr := TRUE
  168.   |09X: DEC(ccol); ccol := (ccol DIV Tab) * Tab + Tab
  169.   |80X..0BFX: IF UTF8 THEN DEC(ccol) END
  170.   ELSE
  171.   END;
  172.   CR := cr;
  173.   INC(bufpos)
  174. END Next;
  175.  
  176. PROCEDURE Open*(FName: ARRAY OF CHAR; VAR FHandle: INTEGER): BOOLEAN;
  177. VAR n, size: INTEGER; c: CHAR;
  178. BEGIN
  179.   File := UTILS.OpenF(FName);
  180.   FHandle := File;
  181.   IF File # 0 THEN
  182.     CR := FALSE;
  183.     UTF8 := FALSE;
  184.     ccol := 0;
  185.     cline := 1;
  186.     ch := 0X;
  187.     size := UTILS.FileSize(File);
  188.     buf := UTILS.GetMem(size + 1024);
  189.     UTILS.MemErr(buf = 0);
  190.     sys.PUT(buf + size, 0X);
  191.     n := UTILS.Read(File, buf, size);
  192.     UTILS.CloseF(File);
  193.     bufpos := buf;
  194.     sys.GET(buf, c);
  195.     IF c = 0EFX THEN
  196.       sys.GET(buf + 1, c);
  197.       IF c = 0BBX THEN
  198.         sys.GET(buf + 2, c);
  199.         IF c = 0BFX THEN
  200.           INC(bufpos, 3);
  201.           UTF8 := TRUE
  202.         END
  203.       END
  204.     END;
  205.     Next
  206.   END
  207.   RETURN (File # 0) & (n = size)
  208. END Open;
  209.  
  210. PROCEDURE Space(ch: CHAR): BOOLEAN;
  211.   RETURN (ch <= 20X) & (ch > 0X)
  212. END Space;
  213.  
  214. PROCEDURE Letter(ch: CHAR): BOOLEAN;
  215.   RETURN (ch >= "A") & (ch <= "Z") OR (ch >= "a") & (ch <= "z") OR (ch = "_")
  216. END Letter;
  217.  
  218. PROCEDURE Digit*(ch: CHAR): BOOLEAN;
  219.   RETURN (ch >= "0") & (ch <= "9")
  220. END Digit;
  221.  
  222. PROCEDURE HexDigit*(ch: CHAR): BOOLEAN;
  223.   RETURN (ch >= "A") & (ch <= "F") OR (ch >= "0") & (ch <= "9")
  224. END HexDigit;
  225.  
  226. PROCEDURE PutChar(ch: CHAR);
  227. BEGIN
  228.   Lex[count] := ch;
  229.   IF ch # 0X THEN
  230.     INC(count)
  231.   END
  232. END PutChar;
  233.  
  234. PROCEDURE PutNext(ch: CHAR);
  235. BEGIN
  236.   PutChar(ch);
  237.   Next
  238. END PutNext;
  239.  
  240. PROCEDURE Ident;
  241. BEGIN
  242.   tLex := lxIDENT;
  243.   WHILE Letter(ch) OR Digit(ch) DO
  244.     PutNext(ch)
  245.   END;
  246.   PutChar(0X);
  247.   IF count > IDLENGTH THEN
  248.     tLex := lxERR10
  249.   END
  250. END Ident;
  251.  
  252. PROCEDURE hex*(ch: CHAR): INTEGER;
  253. VAR Res: INTEGER;
  254. BEGIN
  255.   Res := ORD(ch);
  256.   CASE ch OF
  257.   |"0".."9": DEC(Res, ORD("0"))
  258.   |"A".."F": DEC(Res, ORD("A") - 10)
  259.   ELSE
  260.   END
  261.   RETURN Res
  262. END hex;
  263.  
  264. PROCEDURE StrToInt16(str: UTILS.STRING): INTEGER;
  265. VAR i, res, n: INTEGER; flag: BOOLEAN;
  266. BEGIN
  267.   res := 0;
  268.   i := 0;
  269.   n := 0;
  270.   WHILE str[i] = "0" DO
  271.     INC(i)
  272.   END;
  273.   flag := TRUE;
  274.   WHILE flag & (str[i] # "X") & (str[i] # "H") DO
  275.     INC(n);
  276.     IF n > 8 THEN
  277.       tLex := lxERR5;
  278.       flag := FALSE
  279.     ELSE
  280.       res := LSL(res, 4) + hex(str[i]);
  281.       INC(i)
  282.     END
  283.   END
  284.   RETURN res
  285. END StrToInt16;
  286.  
  287. PROCEDURE StrToChx(str: UTILS.STRING): CHAR;
  288. VAR res: INTEGER;
  289. BEGIN
  290.   res := StrToInt16(str);
  291.   IF (res < 0) OR (res > 0FFH) THEN
  292.     tLex := lxERR6;
  293.     res := 0
  294.   END
  295.   RETURN CHR(res)
  296. END StrToChx;
  297.  
  298. PROCEDURE StrToInt*(str: UTILS.STRING): INTEGER;
  299. VAR i, res: INTEGER; flag: BOOLEAN;
  300. BEGIN
  301.   res := 0;
  302.   i := 0;
  303.   flag := TRUE;
  304.   WHILE flag & (str[i] # 0X) DO
  305.     IF res > maxINT DIV 10 THEN
  306.       tLex := lxERR5;
  307.       flag := FALSE;
  308.       res := 0
  309.     ELSE
  310.       res := res * 10;
  311.       IF res > maxINT - (ORD(str[i]) - ORD("0")) THEN
  312.         tLex := lxERR5;
  313.         flag := FALSE;
  314.         res := 0
  315.       ELSE
  316.         res := res + (ORD(str[i]) - ORD("0"));
  317.         INC(i)
  318.       END
  319.     END
  320.   END
  321.   RETURN res
  322. END StrToInt;
  323.  
  324. PROCEDURE StrToFloat(str: UTILS.STRING): LONGREAL;
  325. VAR i, scale: INTEGER; res, m, d: LONGREAL; minus, nez: BOOLEAN;
  326.  
  327.   PROCEDURE Error(e: INTEGER; VAR cont: BOOLEAN);
  328.   BEGIN
  329.     tLex := e;
  330.     res := 0.0D0;
  331.     cont := FALSE
  332.   END Error;
  333.  
  334.   PROCEDURE Inf(VAR cont: BOOLEAN; VAR i: INTEGER);
  335.   BEGIN
  336.     IF UTILS.IsInf(res) THEN
  337.       Error(lxERR7, cont)
  338.     END;
  339.     INC(i)
  340.   END Inf;
  341.  
  342.   PROCEDURE part1(): BOOLEAN;
  343.   VAR cont: BOOLEAN;
  344.   BEGIN
  345.     res := 0.0D0;
  346.     i := 0;
  347.     d := 1.0D0;
  348.     nez := FALSE;
  349.     cont := TRUE;
  350.     WHILE cont & Digit(str[i]) DO
  351.       nez := nez OR (str[i] # "0");
  352.       res := res * 10.0D0 + LONG(FLT(ORD(str[i]) - ORD("0")));
  353.       Inf(cont, i)
  354.     END
  355.     RETURN cont
  356.   END part1;
  357.  
  358.   PROCEDURE part2(): BOOLEAN;
  359.   VAR cont: BOOLEAN;
  360.   BEGIN
  361.     INC(i);
  362.     cont := TRUE;
  363.     WHILE cont & Digit(str[i]) DO
  364.       nez := nez OR (str[i] # "0");
  365.       d := d / 10.0D0;
  366.       res := res + LONG(FLT(ORD(str[i]) - ORD("0"))) * d;
  367.       Inf(cont, i)
  368.     END
  369.     RETURN cont
  370.   END part2;
  371.  
  372.   PROCEDURE part3(): BOOLEAN;
  373.   VAR cont: BOOLEAN;
  374.   BEGIN
  375.     cont := TRUE;
  376.     IF str[i] = 0X THEN
  377.       IF res > LONG(maxREAL) THEN
  378.         Error(lxERR7, cont)
  379.       ELSIF nez & ((res = 0.0D0) OR (res < LONG(minREAL)) & (tLex = lxREAL)) THEN
  380.         Error(lxERR9, cont)
  381.       END
  382.     END
  383.     RETURN cont
  384.   END part3;
  385.  
  386.   PROCEDURE part4(): BOOLEAN;
  387.   VAR cont: BOOLEAN;
  388.   BEGIN
  389.     IF str[i] = "D" THEN
  390.       tLex := lxLONGREAL
  391.     END;
  392.     INC(i);
  393.     m := 10.0D0;
  394.     minus := FALSE;
  395.     IF str[i] = "+" THEN
  396.       INC(i)
  397.     ELSIF str[i] = "-" THEN
  398.       minus := TRUE;
  399.       INC(i);
  400.       m := 0.1D0
  401.     END;
  402.     scale := 0;
  403.     cont := TRUE;
  404.     WHILE cont & Digit(str[i]) DO
  405.       IF scale > maxINT DIV 10 THEN
  406.         Error(lxERR8, cont)
  407.       ELSE
  408.         scale := scale * 10;
  409.         IF scale > maxINT - (ORD(str[i]) - ORD("0")) THEN
  410.           Error(lxERR8, cont)
  411.         ELSE
  412.           scale := scale + (ORD(str[i]) - ORD("0"));
  413.           INC(i)
  414.         END
  415.       END
  416.     END
  417.     RETURN cont
  418.   END part4;
  419.  
  420.   PROCEDURE part5(): BOOLEAN;
  421.   VAR cont: BOOLEAN; i: INTEGER;
  422.   BEGIN
  423.     cont := TRUE;
  424.     IF scale = maxINT THEN
  425.       Error(lxERR8, cont)
  426.     END;
  427.     i := 1;
  428.     WHILE cont & (i <= scale) DO
  429.       res := res * m;
  430.       Inf(cont, i)
  431.     END;
  432.     IF cont & (nez & (res = 0.0D0) OR (res > 0.0D0) & (res < LONG(minREAL)) & (tLex = lxREAL)) THEN
  433.       Error(lxERR9, cont)
  434.     ELSIF cont & (tLex = lxREAL) & (res > LONG(maxREAL)) THEN
  435.       Error(lxERR7, cont)
  436.     END
  437.     RETURN cont
  438.   END part5;
  439.  
  440. BEGIN
  441.   IF part1() & part2() & part3() & part4() & part5() THEN END
  442.   RETURN res
  443. END StrToFloat;
  444.  
  445. PROCEDURE Number;
  446. VAR nextchr: CHAR;
  447. BEGIN
  448.   tLex := lxINT;
  449.   WHILE Digit(ch) DO
  450.     PutNext(ch)
  451.   END;
  452.   IF ch = "H" THEN
  453.     tLex := lxHEX
  454.   ELSIF ch = "X" THEN
  455.     tLex := lxCHX
  456.   END;
  457.   IF tLex # lxINT THEN
  458.     PutNext(ch)
  459.   ELSE
  460.     WHILE HexDigit(ch) DO
  461.       tLex := lxHEX;
  462.       PutNext(ch)
  463.     END;
  464.     IF tLex = lxHEX THEN
  465.       IF ch = "H" THEN
  466.         PutNext(ch)
  467.       ELSIF ch = "X" THEN
  468.         tLex := lxCHX;
  469.         PutNext(ch)
  470.       ELSE
  471.         tLex := lxERR1
  472.       END
  473.     ELSIF ch = "." THEN
  474.       sys.GET(bufpos, nextchr);
  475.       IF nextchr # "." THEN
  476.         tLex := lxREAL;
  477.         PutNext(ch);
  478.         WHILE Digit(ch) DO
  479.           PutNext(ch)
  480.         END;
  481.         IF (ch = "E") OR (ch = "D") THEN
  482.           PutNext(ch);
  483.           IF (ch = "+") OR (ch = "-") THEN
  484.             PutNext(ch)
  485.           END;
  486.           IF ~Digit(ch) THEN
  487.             tLex := lxERR2
  488.           ELSE
  489.             WHILE Digit(ch) DO
  490.               PutNext(ch)
  491.             END
  492.           END
  493.         END
  494.       END
  495.     END
  496.   END;
  497.   PutChar(0X)
  498. END Number;
  499.  
  500. PROCEDURE Delim(ch: CHAR): INTEGER;
  501. VAR Res: INTEGER;
  502. BEGIN
  503.   CASE ch OF
  504.   |"+": Res := lxPlus
  505.   |"-": Res := lxMinus
  506.   |"*": Res := lxMult
  507.   |"/": Res := lxSlash
  508.   |"~": Res := lxNot
  509.   |"&": Res := lxAnd
  510.   |",": Res := lxComma
  511.   |";": Res := lxSemi
  512.   |"|": Res := lxStick
  513.   |"[": Res := lxLSquare
  514.   |"{": Res := lxLCurly
  515.   |"^": Res := lxCaret
  516.   |"=": Res := lxEQ
  517.   |"#": Res := lxNE
  518.   |")": Res := lxRRound
  519.   |"]": Res := lxRSquare
  520.   |"}": Res := lxRCurly
  521.   |">": Res := lxGT
  522.   |"<": Res := lxLT
  523.   |":": Res := lxColon
  524.   ELSE
  525.   END
  526.   RETURN Res
  527. END Delim;
  528.  
  529. PROCEDURE Comment;
  530. VAR c, level: INTEGER; cont: BOOLEAN;
  531. BEGIN
  532.   c := 1;
  533.   level := 1;
  534.   cont := TRUE;
  535.   WHILE cont & (level > 0) DO
  536.     Next;
  537.     CASE ch OF
  538.     |"(": c := 2
  539.     |")": IF c = 3 THEN DEC(level) END; c := 1
  540.     |"*": IF c = 2 THEN INC(level); c := 1 ELSE c := 3 END
  541.     |0X : cont := FALSE
  542.     ELSE
  543.           c := 1
  544.     END;
  545.   END;
  546.   IF cont THEN
  547.     Next
  548.   END
  549. END Comment;
  550.  
  551. PROCEDURE GetLex*;
  552. BEGIN
  553.   WHILE Space(ch) DO
  554.     Next
  555.   END;
  556.   coord.col := ccol;
  557.   coord.line := cline;
  558.   count := 0;
  559.   CASE ch OF
  560.   |"A".."Z", "a".."z", "_":
  561.     Ident;
  562.     id := AddNode(Lex);
  563.     tLex := id.tLex;
  564.   |"0".."9":
  565.     Number;
  566.     CASE tLex OF
  567.     |lxINT:  vINT := StrToInt(Lex)
  568.     |lxHEX:  vINT := StrToInt16(Lex)
  569.     |lxCHX:  vCHX := StrToChx(Lex)
  570.     |lxREAL: vFLT := StrToFloat(Lex)
  571.     ELSE
  572.     END
  573.   |22X:
  574.     tLex := lxSTRING;
  575.     Next;
  576.     WHILE (ch # 22X) & (ch >= 20X) DO
  577.       PutNext(ch)
  578.     END;
  579.     IF ch = 22X THEN
  580.       Next
  581.     ELSE
  582.       tLex := lxERR3
  583.     END;
  584.     PutChar(0X);
  585.     INC(count);
  586.     IF count > STRLENGTH THEN
  587.       tLex := lxERR11
  588.     END
  589.   |"/":
  590.     tLex := Delim(ch);
  591.     PutNext(ch);
  592.     IF ch = "/" THEN
  593.       WHILE (ch >= 20X) OR (ch = 9X) DO
  594.         PutNext(ch)
  595.       END;
  596.       GetLex
  597.     END;
  598.     PutChar(0X)
  599.   |">", "<", ":":
  600.     tLex := Delim(ch);
  601.     PutNext(ch);
  602.     IF ch = "=" THEN
  603.       CASE tLex OF
  604.       |lxLT:    tLex := lxLE
  605.       |lxGT:    tLex := lxGE
  606.       |lxColon: tLex := lxAssign
  607.       ELSE
  608.       END;
  609.       PutNext(ch)
  610.     END;
  611.     PutChar(0X)
  612.   |".":
  613.     tLex := lxDot;
  614.     PutNext(ch);
  615.     IF ch = "." THEN
  616.       tLex := lxDbl;
  617.       PutNext(ch)
  618.     END;
  619.     PutChar(0X)
  620.   |"(":
  621.     tLex := lxLRound;
  622.     PutNext(ch);
  623.     IF ch = "*" THEN
  624.       Comment;
  625.       GetLex
  626.     END;
  627.     PutChar(0X)
  628.   |"+", "-", "*", "~", "&", ",", ";", "|",
  629.    "[", "{", "^", "=", "#", ")", "]", "}":
  630.     tLex := Delim(ch);
  631.     PutChar(ch);
  632.     PutNext(0X)
  633.   |0X:
  634.     tLex := lxEOF;
  635.     PutChar(0X)
  636.   ELSE
  637.     tLex := lxERR4
  638.   END
  639. END GetLex;
  640.  
  641. PROCEDURE AddNodeKey(Name: UTILS.STRING; key: INTEGER);
  642. VAR node: NODE;
  643. BEGIN
  644.   node := AddNode(Name);
  645.   node.tLex := key
  646. END AddNodeKey;
  647.  
  648. PROCEDURE Init;
  649. VAR i: INTEGER; node: NODE;
  650. BEGIN
  651.   FOR i := 0 TO LEN(Nodes) - 1 DO
  652.     NEW(node);
  653.     UTILS.MemErr(node = NIL);
  654.     sys.PUT(sys.ADR(node.Name), i);
  655.     node.Left := NIL;
  656.     node.Right := NIL;
  657.     node.tLex := lxIDENT;
  658.     Nodes[i] := node
  659.   END;
  660.   _START := AddNode("lib_init");
  661.   _version := AddNode("version");
  662.   AddNodeKey("MOD", lxMOD);
  663.   AddNodeKey("ELSE", lxELSE);
  664.   AddNodeKey("RETURN", lxRETURN);
  665.   AddNodeKey("CASE", lxCASE);
  666.   AddNodeKey("IF", lxIF);
  667.   AddNodeKey("POINTER", lxPOINTER);
  668.   AddNodeKey("TYPE", lxTYPE);
  669.   AddNodeKey("BEGIN", lxBEGIN);
  670.   AddNodeKey("DIV", lxDIV);
  671.   AddNodeKey("FALSE", lxFALSE);
  672.   AddNodeKey("IN", lxIN);
  673.   AddNodeKey("NIL", lxNIL);
  674.   AddNodeKey("RECORD", lxRECORD);
  675.   AddNodeKey("TO", lxTO);
  676.   AddNodeKey("VAR", lxVAR);
  677.   AddNodeKey("ARRAY", lxARRAY);
  678.   AddNodeKey("DO", lxDO);
  679.   AddNodeKey("END", lxEND);
  680.   AddNodeKey("IS", lxIS);
  681.   AddNodeKey("OF", lxOF);
  682.   AddNodeKey("PROCEDURE", lxPROCEDURE);
  683.   AddNodeKey("THEN", lxTHEN);
  684.   AddNodeKey("WHILE", lxWHILE);
  685.   AddNodeKey("BY", lxBY);
  686.   AddNodeKey("CONST", lxCONST);
  687.   AddNodeKey("ELSIF", lxELSIF);
  688.   AddNodeKey("IMPORT", lxIMPORT);
  689.   AddNodeKey("MODULE", lxMODULE);
  690.   AddNodeKey("OR", lxOR);
  691.   AddNodeKey("REPEAT", lxREPEAT);
  692.   AddNodeKey("TRUE", lxTRUE);
  693.   AddNodeKey("UNTIL", lxUNTIL);
  694.   AddNodeKey("FOR", lxFOR)
  695. END Init;
  696.  
  697. BEGIN
  698.   Init
  699. END SCAN.