Subversion Repositories Kolibri OS

Rev

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

  1. (*
  2.     BSD 2-Clause License
  3.  
  4.     Copyright (c) 2018-2023, Anton Krotov
  5.     All rights reserved.
  6. *)
  7.  
  8. MODULE PROG;
  9.  
  10. IMPORT SCAN, LISTS, ARITH, ERRORS, C := COLLECTIONS, IL, UTILS, TARGETS, STRINGS, PATHS;
  11.  
  12.  
  13. CONST
  14.  
  15.     MAXARRDIM*    = 5;
  16.     MAXSCOPE      = 16;
  17.     MAXSYSVPARAM* = 26;
  18.  
  19.     idNONE*    =  0;  idGUARD   =  1;  idMODULE* =  2;  idCONST*   =  3;
  20.     idTYPE*    =  4;  idSTFUNC* =  5;  idSTPROC* =  6;  idVAR*     =  7;
  21.     idPROC*    =  8;  idVPAR*   =  9;  idPARAM*  = 10;  idSYSFUNC* = 11;
  22.     idSYSPROC* = 12;  idIMP*    = 13;
  23.  
  24.     tINTEGER* =  1;  tBYTE*      =  2;  tCHAR*   =  3;  tSET*    =  4;
  25.     tBOOLEAN* =  5;  tREAL*      =  6;  tARRAY*  =  7;  tRECORD* =  8;
  26.     tPOINTER* =  9;  tPROCEDURE* = 10;  tSTRING* = 11;  tNIL*    = 12;
  27.     tCARD32*  = 13;  tANYREC*    = 14;  tWCHAR*  = 15;  tNONE*   = 16;
  28.  
  29.     BASICTYPES* = {tINTEGER, tBYTE, tCHAR, tSET, tBOOLEAN, tREAL, tCARD32, tWCHAR};
  30.  
  31.     stABS*  =  1;  stASR*  =  2;  stCHR*    =  3;  stFLOOR* =  4;
  32.     stFLT*  =  5;  stLEN*  =  6;  stLSL*    =  7;  stODD*   =  8;
  33.     stORD*  =  9;  stROR*  = 10;  stASSERT* = 11;  stDEC*   = 12;
  34.     stEXCL* = 13;  stINC*  = 14;  stINCL*   = 15;  stNEW*   = 16;
  35.     stPACK* = 17;  stUNPK* = 18;  sysADR*   = 19;  sysSIZE* = 20;
  36.     sysGET* = 21;  sysPUT* = 22;
  37.  
  38.     stDISPOSE* = 23;  stLSR*     = 24;  stBITS*   = 25;  sysCODE*  = 26;
  39.     sysMOVE*   = 27;  stLENGTH*  = 28;  stMIN*    = 29;  stMAX*    = 30;
  40.     sysSADR*   = 31;  sysTYPEID* = 32;  sysCOPY*  = 33;  sysINF*   = 34;
  41.     sysPUT8*   = 35;  sysPUT16*  = 36;  stCOPY*   = 37;  stWCHR*   = 38;
  42.     sysWSADR*  = 39;  sysPUT32*  = 40;  (*sysNOP*   = 41;  sysEINT*  = 42;
  43.     sysDINT*   = 43;*)sysGET8*   = 44;  sysGET16* = 45;  sysGET32* = 46;
  44.     sysVAL* = 47;
  45.  
  46.     default32* =  2;  _default32* = default32 + 1;
  47.     stdcall*   =  4;  _stdcall*   = stdcall + 1;
  48.     cdecl*     =  6;  _cdecl*     = cdecl + 1;
  49.     ccall*     =  8;  _ccall*     = ccall + 1;
  50.     win64*     = 10;  _win64*     = win64 + 1;
  51.     default64* = 12;  _default64* = default64 + 1;
  52.     systemv*   = 14;  _systemv*   = systemv + 1;
  53.     default16* = 16;  _default16* = default16 + 1;
  54.     code*      = 18;  _code*      = code + 1;
  55.     fastcall*  = 20;  _fastcall*  = fastcall + 1;
  56.  
  57.     noalign* = 22;
  58.  
  59.     callee_clean_up* = {default32, _default32, stdcall, _stdcall, default64, _default64, fastcall, _fastcall};
  60.  
  61.     sf_stdcall* =  0; sf_oberon*    = 1; sf_cdecl*   = 2; sf_ccall*  = 3;
  62.     sf_win64*   =  4; sf_systemv*   = 5; sf_windows* = 6; sf_linux*  = 7;
  63.     sf_code*    =  8; sf_fastcall*  = 9;
  64.     sf_noalign* = 10;
  65.  
  66.     proc_flags* = {sf_stdcall, sf_cdecl, sf_ccall, sf_win64, sf_systemv, sf_windows, sf_linux, sf_code, sf_oberon, sf_fastcall};
  67.     rec_flags*  = {sf_noalign};
  68.  
  69.     STACK_FRAME = 2;
  70.  
  71.  
  72. TYPE
  73.  
  74.     OPTIONS* = RECORD
  75.  
  76.         version*, stack*, ram*, rom*, tab*: INTEGER;
  77.         pic*, lower*, uses*: BOOLEAN;
  78.         checking*: SET
  79.  
  80.     END;
  81.  
  82.     IDENT* = POINTER TO rIDENT;
  83.  
  84.     UNIT* = POINTER TO rUNIT;
  85.  
  86.     _TYPE* = POINTER TO rTYPE;
  87.  
  88.     FRWPTR* = POINTER TO RECORD (LISTS.ITEM)
  89.  
  90.         _type:       _TYPE;
  91.         baseIdent:   SCAN.IDENT;
  92.         linked:      BOOLEAN;
  93.  
  94.         pos*:        SCAN.POSITION;
  95.         notRecord*:  BOOLEAN
  96.  
  97.     END;
  98.  
  99.     PROC* = POINTER TO RECORD (LISTS.ITEM)
  100.  
  101.         label*:      INTEGER;
  102.         used*:       BOOLEAN;
  103.         processed*:  BOOLEAN;
  104.         _import*:    LISTS.ITEM;
  105.         using*:      LISTS.LIST;
  106.         enter*,
  107.         leave*:      LISTS.ITEM
  108.  
  109.     END;
  110.  
  111.     USED_PROC = POINTER TO RECORD (LISTS.ITEM)
  112.  
  113.         proc: PROC
  114.  
  115.     END;
  116.  
  117.     rUNIT = RECORD (LISTS.ITEM)
  118.  
  119.         fname*:      PATHS.PATH;
  120.         name*:       SCAN.IDENT;
  121.         idents*:     LISTS.LIST;
  122.         frwPointers: LISTS.LIST;
  123.         gscope:      IDENT;
  124.         closed*:     BOOLEAN;
  125.         scopeLvl*:   INTEGER;
  126.         sysimport*:  BOOLEAN;
  127.         scopes*:     ARRAY MAXSCOPE OF PROC
  128.  
  129.     END;
  130.  
  131.     FIELD* = POINTER TO rFIELD;
  132.  
  133.     PARAM* = POINTER TO rPARAM;
  134.  
  135.     rTYPE = RECORD (LISTS.ITEM)
  136.  
  137.         typ*:        INTEGER;
  138.         size*:       INTEGER;
  139.         parSize*:    INTEGER;
  140.         length*:     INTEGER;
  141.         align*:      INTEGER;
  142.         base*:       _TYPE;
  143.         fields*:     LISTS.LIST;
  144.         params*:     LISTS.LIST;
  145.         unit*:       UNIT;
  146.         closed*:     BOOLEAN;
  147.         num*:        INTEGER;
  148.         call*:       INTEGER;
  149.         _import*:    BOOLEAN;
  150.         noalign*:    BOOLEAN
  151.  
  152.     END;
  153.  
  154.     rFIELD = RECORD (LISTS.ITEM)
  155.  
  156.         _type*:      _TYPE;
  157.         name*:       SCAN.IDENT;
  158.         export*:     BOOLEAN;
  159.         offset*:     INTEGER
  160.  
  161.     END;
  162.  
  163.     rPARAM = RECORD (LISTS.ITEM)
  164.  
  165.         name*:       SCAN.IDENT;
  166.         _type*:      _TYPE;
  167.         vPar*:       BOOLEAN;
  168.         offset*:     INTEGER
  169.  
  170.     END;
  171.  
  172.     rIDENT = RECORD (LISTS.ITEM)
  173.  
  174.         name*:       SCAN.IDENT;
  175.         typ*:        INTEGER;
  176.         export*:     BOOLEAN;
  177.         _import*:    LISTS.ITEM;
  178.         unit*:       UNIT;
  179.         value*:      ARITH.VALUE;
  180.         _type*:      _TYPE;
  181.         stproc*:     INTEGER;
  182.         global*:     BOOLEAN;
  183.         scopeLvl*:   INTEGER;
  184.         offset*:     INTEGER;
  185.         proc*:       PROC;
  186.         pos*:        SCAN.POSITION
  187.  
  188.     END;
  189.  
  190.     PROGRAM = RECORD
  191.  
  192.         recCount:    INTEGER;
  193.         units*:      LISTS.LIST;
  194.         types*:      LISTS.LIST;
  195.         sysunit*:    UNIT;
  196.         rtl*:        UNIT;
  197.         bss*:        INTEGER;
  198.         locsize*:    INTEGER;
  199.  
  200.         procs*:      LISTS.LIST;
  201.  
  202.         sysflags*:   SET;
  203.         options*:    OPTIONS;
  204.  
  205.         stTypes*:    RECORD
  206.  
  207.             tINTEGER*, tBYTE*, tCHAR*, tWCHAR*, tSET*, tBOOLEAN*, tREAL*,
  208.             tSTRING*, tNIL*, tCARD32*, tANYREC*, tNONE*: _TYPE
  209.  
  210.         END
  211.  
  212.     END;
  213.  
  214.     DELIMPORT = PROCEDURE (_import: LISTS.ITEM);
  215.  
  216.  
  217. VAR
  218.  
  219.     LowerCase*: BOOLEAN;
  220.     idents: C.COLLECTION;
  221.     program*: PROGRAM;
  222.  
  223.  
  224. PROCEDURE NewIdent (): IDENT;
  225. VAR
  226.     ident: IDENT;
  227.     citem: C.ITEM;
  228.  
  229. BEGIN
  230.     citem := C.pop(idents);
  231.     IF citem = NIL THEN
  232.         NEW(ident)
  233.     ELSE
  234.         ident := citem(IDENT)
  235.     END
  236.  
  237.     RETURN ident
  238. END NewIdent;
  239.  
  240.  
  241. PROCEDURE getOffset* (varIdent: IDENT): INTEGER;
  242. VAR
  243.     size, glob_align: INTEGER;
  244.  
  245. BEGIN
  246.     IF varIdent.offset = -1 THEN
  247.         size := varIdent._type.size;
  248.         IF varIdent.global THEN
  249.             IF TARGETS.WinLin THEN
  250.                 glob_align := 16
  251.             ELSE
  252.                 glob_align := varIdent._type.align
  253.             END;
  254.             IF UTILS.Align(program.bss, glob_align) THEN
  255.                 IF UTILS.maxint - program.bss >= size THEN
  256.                     varIdent.offset := program.bss;
  257.                     INC(program.bss, size)
  258.                 END
  259.             END
  260.         ELSE
  261.             IF UTILS.Align(size, TARGETS.WordSize) THEN
  262.                 size := size DIV TARGETS.WordSize;
  263.                 IF UTILS.maxint - program.locsize >= size THEN
  264.                     INC(program.locsize, size);
  265.                     varIdent.offset := program.locsize
  266.                 END
  267.             END
  268.         END;
  269.  
  270.         IF varIdent.offset = -1 THEN
  271.             ERRORS.Error(204)
  272.         END
  273.     END
  274.  
  275.     RETURN varIdent.offset
  276. END getOffset;
  277.  
  278.  
  279. PROCEDURE closeUnit* (unit: UNIT);
  280. VAR
  281.     ident, prev: IDENT;
  282.     offset: INTEGER;
  283.  
  284. BEGIN
  285.     ident := unit.idents.last(IDENT);
  286.     WHILE (ident # NIL) & (ident.typ # idGUARD) DO
  287.         IF (ident.typ = idVAR) & (ident.offset = -1) THEN
  288.             ERRORS.HintMsg(ident.name.s, ident.pos.line, ident.pos.col, 0);
  289.             IF ident.export THEN
  290.                 offset := getOffset(ident)
  291.             END
  292.         END;
  293.         ident := ident.prev(IDENT)
  294.     END;
  295.  
  296.     ident := unit.idents.last(IDENT);
  297.     WHILE ident # NIL DO
  298.         prev := ident.prev(IDENT);
  299.         IF ~ident.export THEN
  300.             LISTS.delete(unit.idents, ident);
  301.             C.push(idents, ident)
  302.         END;
  303.         ident := prev
  304.     END;
  305.  
  306.     unit.closed := TRUE
  307. END closeUnit;
  308.  
  309.  
  310. PROCEDURE IdEq* (a, b: SCAN.IDENT): BOOLEAN;
  311.     RETURN (a.hash = b.hash) & (a.s = b.s)
  312. END IdEq;
  313.  
  314.  
  315. PROCEDURE unique (unit: UNIT; ident: SCAN.IDENT): BOOLEAN;
  316. VAR
  317.     item: IDENT;
  318.  
  319. BEGIN
  320.     item := unit.idents.last(IDENT);
  321.     WHILE (item.typ # idGUARD) & ~IdEq(item.name, ident) DO
  322.         item := item.prev(IDENT)
  323.     END
  324.  
  325.     RETURN item.typ = idGUARD
  326. END unique;
  327.  
  328.  
  329. PROCEDURE addIdent* (unit: UNIT; ident: SCAN.IDENT; typ: INTEGER): IDENT;
  330. VAR
  331.     item:  IDENT;
  332.     res:   BOOLEAN;
  333.     proc:  PROC;
  334.  
  335. BEGIN
  336.     ASSERT(unit # NIL);
  337.  
  338.     res := unique(unit, ident);
  339.  
  340.     IF res THEN
  341.         item := NewIdent();
  342.  
  343.         item.name    := ident;
  344.         item.typ     := typ;
  345.         item.unit    := NIL;
  346.         item.export  := FALSE;
  347.         item._import := NIL;
  348.         item._type   := NIL;
  349.         item.value.typ := 0;
  350.         item.stproc := 0;
  351.  
  352.         item.global := unit.scopeLvl = 0;
  353.         item.scopeLvl := unit.scopeLvl;
  354.         item.offset := -1;
  355.  
  356.         IF item.typ IN {idPROC, idIMP} THEN
  357.             NEW(proc);
  358.             proc._import := NIL;
  359.             proc.label := 0;
  360.             proc.used := FALSE;
  361.             proc.processed := FALSE;
  362.             proc.using := LISTS.create(NIL);
  363.             LISTS.push(program.procs, proc);
  364.             item.proc := proc
  365.         END;
  366.  
  367.         LISTS.push(unit.idents, item)
  368.     ELSE
  369.         item := NIL
  370.     END
  371.  
  372.     RETURN item
  373. END addIdent;
  374.  
  375.  
  376. PROCEDURE UseProc* (unit: UNIT; call_proc: PROC);
  377. VAR
  378.     procs: LISTS.LIST;
  379.     cur:   LISTS.ITEM;
  380.     proc:  USED_PROC;
  381.  
  382. BEGIN
  383.     IF unit.scopeLvl = 0 THEN
  384.         call_proc.used := TRUE
  385.     ELSE
  386.         procs := unit.scopes[unit.scopeLvl].using;
  387.  
  388.         cur := procs.first;
  389.         WHILE (cur # NIL) & (cur(USED_PROC).proc # call_proc) DO
  390.             cur := cur.next
  391.         END;
  392.  
  393.         IF cur = NIL THEN
  394.             NEW(proc);
  395.             proc.proc := call_proc;
  396.             LISTS.push(procs, proc)
  397.         END
  398.     END
  399. END UseProc;
  400.  
  401.  
  402. PROCEDURE setVarsType* (unit: UNIT; _type: _TYPE);
  403. VAR
  404.     item: IDENT;
  405.  
  406. BEGIN
  407.     ASSERT(_type # NIL);
  408.  
  409.     item := unit.idents.last(IDENT);
  410.     WHILE (item # NIL) & (item.typ = idVAR) & (item._type = NIL) DO
  411.         item._type := _type;
  412.         item := item.prev(IDENT)
  413.     END
  414. END setVarsType;
  415.  
  416.  
  417. PROCEDURE getIdent* (unit: UNIT; ident: SCAN.IDENT; currentScope: BOOLEAN): IDENT;
  418. VAR
  419.     item: IDENT;
  420.  
  421. BEGIN
  422.     item := unit.idents.last(IDENT);
  423.  
  424.     IF item # NIL THEN
  425.  
  426.         IF currentScope THEN
  427.             WHILE (item.typ # idGUARD) & ~IdEq(item.name, ident) DO
  428.                 item := item.prev(IDENT)
  429.             END;
  430.             IF item.typ = idGUARD THEN
  431.                 item := NIL
  432.             END
  433.         ELSE
  434.             WHILE (item # NIL) & ~IdEq(item.name, ident) DO
  435.                 item := item.prev(IDENT)
  436.             END
  437.         END
  438.  
  439.     END
  440.  
  441.     RETURN item
  442. END getIdent;
  443.  
  444.  
  445. PROCEDURE openScope* (unit: UNIT; proc: PROC): BOOLEAN;
  446. VAR
  447.     item: IDENT;
  448.     res:  BOOLEAN;
  449.  
  450. BEGIN
  451.     INC(unit.scopeLvl);
  452.  
  453.     res := unit.scopeLvl < MAXSCOPE;
  454.  
  455.     IF res THEN
  456.  
  457.         unit.scopes[unit.scopeLvl] := proc;
  458.  
  459.         NEW(item);
  460.         item := NewIdent();
  461.  
  462.         item.name.s := "";
  463.         item.name.hash := 0;
  464.         item.typ  := idGUARD;
  465.  
  466.         LISTS.push(unit.idents, item)
  467.     END
  468.  
  469.     RETURN res
  470. END openScope;
  471.  
  472.  
  473. PROCEDURE closeScope* (unit: UNIT);
  474. VAR
  475.     item: IDENT;
  476.     del:  IDENT;
  477.  
  478. BEGIN
  479.     item := unit.idents.last(IDENT);
  480.  
  481.     WHILE (item # NIL) & (item.typ # idGUARD) DO
  482.         del  := item;
  483.         item := item.prev(IDENT);
  484.         IF (del.typ = idVAR) & (del.offset = -1) THEN
  485.             ERRORS.HintMsg(del.name.s, del.pos.line, del.pos.col, 0)
  486.         END;
  487.         LISTS.delete(unit.idents, del);
  488.         C.push(idents, del)
  489.     END;
  490.  
  491.     IF (item # NIL) & (item.typ = idGUARD) THEN
  492.         LISTS.delete(unit.idents, item);
  493.         C.push(idents, item)
  494.     END;
  495.  
  496.     DEC(unit.scopeLvl)
  497. END closeScope;
  498.  
  499.  
  500. PROCEDURE frwPtr* (unit: UNIT; _type: _TYPE; baseIdent: SCAN.IDENT; pos: SCAN.POSITION);
  501. VAR
  502.     newptr: FRWPTR;
  503.  
  504. BEGIN
  505.     ASSERT(unit # NIL);
  506.     ASSERT(_type # NIL);
  507.  
  508.     NEW(newptr);
  509.  
  510.     newptr._type      := _type;
  511.     newptr.baseIdent := baseIdent;
  512.     newptr.pos       := pos;
  513.     newptr.linked    := FALSE;
  514.     newptr.notRecord := FALSE;
  515.  
  516.     LISTS.push(unit.frwPointers, newptr)
  517. END frwPtr;
  518.  
  519.  
  520. PROCEDURE linkPtr* (unit: UNIT): FRWPTR;
  521. VAR
  522.     item:  FRWPTR;
  523.     ident: IDENT;
  524.     res:   FRWPTR;
  525.  
  526. BEGIN
  527.     res  := NIL;
  528.     item := unit.frwPointers.last(FRWPTR);
  529.  
  530.     WHILE (item # NIL) & ~item.linked & (res = NIL) DO
  531.         ident := getIdent(unit, item.baseIdent, TRUE);
  532.  
  533.         IF (ident # NIL) THEN
  534.             IF (ident.typ = idTYPE) & (ident._type.typ = tRECORD) THEN
  535.                 item._type.base := ident._type;
  536.                 item.linked := TRUE
  537.             ELSE
  538.                 item.notRecord := TRUE;
  539.                 res := item
  540.             END
  541.         ELSE
  542.             item.notRecord := FALSE;
  543.             res := item
  544.         END;
  545.  
  546.         item := item.prev(FRWPTR)
  547.     END
  548.  
  549.     RETURN res
  550. END linkPtr;
  551.  
  552.  
  553. PROCEDURE isTypeEq* (t1, t2: _TYPE): BOOLEAN;
  554. VAR
  555.     res: BOOLEAN;
  556.     param1, param2: LISTS.ITEM;
  557.  
  558. BEGIN
  559.     IF t1 = t2 THEN
  560.         res := TRUE
  561.     ELSIF (t1 = NIL) OR (t2 = NIL) THEN
  562.         res := FALSE
  563.     ELSIF (t1.typ = tPROCEDURE) & (t2.typ = tPROCEDURE) THEN
  564.  
  565.         param1 := t1.params.first;
  566.         param2 := t2.params.first;
  567.  
  568.         res := ((t1.call = t2.call) OR (t1.call IN {code, _code}) OR (t2.call IN {code, _code})) & ((param1 # NIL) = (param2 # NIL));
  569.  
  570.         WHILE res & (param1 # NIL) & (param2 # NIL) DO
  571.             res := (param1(PARAM).vPar = param2(PARAM).vPar) & isTypeEq(param1(PARAM)._type, param2(PARAM)._type);
  572.             param1 := param1.next;
  573.             param2 := param2.next;
  574.             res := res & ((param1 # NIL) = (param2 # NIL))
  575.         END;
  576.  
  577.         res := res & isTypeEq(t1.base, t2.base)
  578.  
  579.     ELSIF (t1.typ = tARRAY) & (t2.typ = tARRAY) THEN
  580.         res := (t1.length = 0) & (t2.length = 0) & isTypeEq(t1.base, t2.base)
  581.     ELSE
  582.         res := FALSE
  583.     END
  584.  
  585.     RETURN res
  586. END isTypeEq;
  587.  
  588.  
  589. PROCEDURE isBaseOf* (t0, t1: _TYPE): BOOLEAN;
  590. VAR
  591.     res: BOOLEAN;
  592.  
  593. BEGIN
  594.     res := (t0.typ = t1.typ) & (t0.typ IN {tPOINTER, tRECORD});
  595.  
  596.     IF res & (t0.typ = tPOINTER) THEN
  597.         t0 := t0.base;
  598.         t1 := t1.base
  599.     END;
  600.  
  601.     IF res THEN
  602.         WHILE (t1 # NIL) & (t1 # t0) DO
  603.             t1 := t1.base
  604.         END;
  605.         res := t1 # NIL
  606.     END
  607.  
  608.     RETURN res
  609. END isBaseOf;
  610.  
  611.  
  612. PROCEDURE isOpenArray* (t: _TYPE): BOOLEAN;
  613.     RETURN (t.typ = tARRAY) & (t.length = 0)
  614. END isOpenArray;
  615.  
  616.  
  617. PROCEDURE arrcomp* (src, dst: _TYPE): BOOLEAN;
  618.     RETURN (dst.typ = tARRAY) & isOpenArray(src) &
  619.             ~isOpenArray(src.base) & ~isOpenArray(dst.base) &
  620.             isTypeEq(src.base, dst.base)
  621. END arrcomp;
  622.  
  623.  
  624. PROCEDURE getUnit* (name: PATHS.PATH): UNIT;
  625. VAR
  626.     item: UNIT;
  627.  
  628. BEGIN
  629.     item := program.units.first(UNIT);
  630.  
  631.     WHILE (item # NIL) & (item.fname # name) DO
  632.         item := item.next(UNIT)
  633.     END;
  634.  
  635.     IF (item = NIL) & ((name = "SYSTEM") OR LowerCase & (name = "system")) THEN
  636.         item := program.sysunit
  637.     END
  638.  
  639.     RETURN item
  640. END getUnit;
  641.  
  642.  
  643. PROCEDURE enterStTypes (unit: UNIT);
  644.  
  645.  
  646.     PROCEDURE enter (unit: UNIT; nameStr: SCAN.IDSTR; _type: _TYPE);
  647.     VAR
  648.         ident: IDENT;
  649.         upper: SCAN.IDSTR;
  650.         name:  SCAN.IDENT;
  651.  
  652.     BEGIN
  653.         IF LowerCase THEN
  654.             SCAN.setIdent(name, nameStr);
  655.             ident := addIdent(unit, name, idTYPE);
  656.             ident._type := _type
  657.         END;
  658.         upper := nameStr;
  659.         STRINGS.UpCase(upper);
  660.         SCAN.setIdent(name, upper);
  661.         ident := addIdent(unit, name, idTYPE);
  662.         ident._type := _type
  663.     END enter;
  664.  
  665.  
  666. BEGIN
  667.     enter(unit, "integer", program.stTypes.tINTEGER);
  668.     enter(unit, "byte",    program.stTypes.tBYTE);
  669.     enter(unit, "char",    program.stTypes.tCHAR);
  670.     enter(unit, "set",     program.stTypes.tSET);
  671.     enter(unit, "boolean", program.stTypes.tBOOLEAN);
  672.  
  673.     IF TARGETS.RealSize # 0 THEN
  674.         enter(unit, "real", program.stTypes.tREAL)
  675.     END;
  676.  
  677.     IF TARGETS.BitDepth >= 32 THEN
  678.         enter(unit, "wchar", program.stTypes.tWCHAR)
  679.     END
  680. END enterStTypes;
  681.  
  682.  
  683. PROCEDURE enterStProcs (unit: UNIT);
  684.  
  685.  
  686.     PROCEDURE Enter (unit: UNIT; nameStr: SCAN.IDSTR; nfunc, tfunc: INTEGER);
  687.     VAR
  688.         ident: IDENT;
  689.         upper: SCAN.IDSTR;
  690.         name:  SCAN.IDENT;
  691.  
  692.     BEGIN
  693.         IF LowerCase THEN
  694.             SCAN.setIdent(name, nameStr);
  695.             ident := addIdent(unit, name, tfunc);
  696.             ident.stproc := nfunc;
  697.             ident._type := program.stTypes.tNONE
  698.         END;
  699.         upper := nameStr;
  700.         STRINGS.UpCase(upper);
  701.         SCAN.setIdent(name, upper);
  702.         ident := addIdent(unit, name, tfunc);
  703.         ident.stproc := nfunc;
  704.         ident._type := program.stTypes.tNONE
  705.     END Enter;
  706.  
  707.  
  708. BEGIN
  709.     Enter(unit, "assert", stASSERT, idSTPROC);
  710.     Enter(unit, "dec",    stDEC,    idSTPROC);
  711.     Enter(unit, "excl",   stEXCL,   idSTPROC);
  712.     Enter(unit, "inc",    stINC,    idSTPROC);
  713.     Enter(unit, "incl",   stINCL,   idSTPROC);
  714.     Enter(unit, "new",    stNEW,    idSTPROC);
  715.     Enter(unit, "copy",   stCOPY,   idSTPROC);
  716.  
  717.     Enter(unit, "abs",    stABS,    idSTFUNC);
  718.     Enter(unit, "asr",    stASR,    idSTFUNC);
  719.     Enter(unit, "chr",    stCHR,    idSTFUNC);
  720.     Enter(unit, "len",    stLEN,    idSTFUNC);
  721.     Enter(unit, "lsl",    stLSL,    idSTFUNC);
  722.     Enter(unit, "odd",    stODD,    idSTFUNC);
  723.     Enter(unit, "ord",    stORD,    idSTFUNC);
  724.     Enter(unit, "ror",    stROR,    idSTFUNC);
  725.     Enter(unit, "bits",   stBITS,   idSTFUNC);
  726.     Enter(unit, "lsr",    stLSR,    idSTFUNC);
  727.     Enter(unit, "length", stLENGTH, idSTFUNC);
  728.     Enter(unit, "min",    stMIN,    idSTFUNC);
  729.     Enter(unit, "max",    stMAX,    idSTFUNC);
  730.  
  731.     IF TARGETS.RealSize # 0 THEN
  732.         Enter(unit, "pack",  stPACK,  idSTPROC);
  733.         Enter(unit, "unpk",  stUNPK,  idSTPROC);
  734.         Enter(unit, "floor", stFLOOR, idSTFUNC);
  735.         Enter(unit, "flt",   stFLT,   idSTFUNC)
  736.     END;
  737.  
  738.     IF TARGETS.BitDepth >= 32 THEN
  739.         Enter(unit, "wchr", stWCHR, idSTFUNC)
  740.     END;
  741.  
  742.     IF TARGETS.Dispose THEN
  743.         Enter(unit, "dispose", stDISPOSE, idSTPROC)
  744.     END
  745.  
  746. END enterStProcs;
  747.  
  748.  
  749. PROCEDURE newUnit* (name: SCAN.IDENT): UNIT;
  750. VAR
  751.     unit: UNIT;
  752.  
  753. BEGIN
  754.     NEW(unit);
  755.  
  756.     unit.name        := name;
  757.     unit.closed      := FALSE;
  758.     unit.idents      := LISTS.create(NIL);
  759.     unit.frwPointers := LISTS.create(NIL);
  760.  
  761.     ASSERT(openScope(unit, NIL));
  762.  
  763.     enterStTypes(unit);
  764.     enterStProcs(unit);
  765.  
  766.     ASSERT(openScope(unit, NIL));
  767.  
  768.     unit.gscope := unit.idents.last(IDENT);
  769.  
  770.     LISTS.push(program.units, unit);
  771.  
  772.     unit.scopeLvl := 0;
  773.     unit.scopes[0] := NIL;
  774.  
  775.     unit.sysimport := FALSE;
  776.  
  777.     IF unit.name.s = UTILS.RTL_NAME THEN
  778.         program.rtl := unit
  779.     END
  780.  
  781.     RETURN unit
  782. END newUnit;
  783.  
  784.  
  785. PROCEDURE getField* (self: _TYPE; name: SCAN.IDENT; unit: UNIT): FIELD;
  786. VAR
  787.     field: FIELD;
  788.  
  789. BEGIN
  790.     ASSERT(self # NIL);
  791.     ASSERT(unit # NIL);
  792.  
  793.     field := NIL;
  794.     WHILE (self # NIL) & (field = NIL) DO
  795.  
  796.         field := self.fields.first(FIELD);
  797.  
  798.         WHILE (field # NIL) & ~IdEq(field.name, name) DO
  799.             field := field.next(FIELD)
  800.         END;
  801.  
  802.         IF field = NIL THEN
  803.             self := self.base
  804.         END
  805.  
  806.     END;
  807.  
  808.     IF (field # NIL) & (self.unit # unit) & ~field.export THEN
  809.         field := NIL
  810.     END
  811.  
  812.     RETURN field
  813. END getField;
  814.  
  815.  
  816. PROCEDURE addField* (self: _TYPE; name: SCAN.IDENT; export: BOOLEAN): BOOLEAN;
  817. VAR
  818.     field: FIELD;
  819.     res:   BOOLEAN;
  820.  
  821. BEGIN
  822.     res := getField(self, name, self.unit) = NIL;
  823.  
  824.     IF res THEN
  825.         NEW(field);
  826.  
  827.         field.name   := name;
  828.         field.export := export;
  829.         field._type  := NIL;
  830.         field.offset := self.size;
  831.  
  832.         LISTS.push(self.fields, field)
  833.     END
  834.  
  835.     RETURN res
  836. END addField;
  837.  
  838.  
  839. PROCEDURE setFields* (self: _TYPE; _type: _TYPE): BOOLEAN;
  840. VAR
  841.     item: FIELD;
  842.     res:  BOOLEAN;
  843.  
  844. BEGIN
  845.     ASSERT(_type # NIL);
  846.  
  847.     item := self.fields.first(FIELD);
  848.  
  849.     WHILE (item # NIL) & (item._type # NIL) DO
  850.         item := item.next(FIELD)
  851.     END;
  852.  
  853.     res := TRUE;
  854.  
  855.     WHILE res & (item # NIL) & (item._type = NIL) DO
  856.         item._type := _type;
  857.         IF ~self.noalign THEN
  858.             res := UTILS.Align(self.size, _type.align)
  859.         ELSE
  860.             res := TRUE
  861.         END;
  862.         item.offset := self.size;
  863.         res := res & (UTILS.maxint - self.size >= _type.size);
  864.         IF res THEN
  865.             INC(self.size, _type.size)
  866.         END;
  867.         item := item.next(FIELD)
  868.     END
  869.  
  870.     RETURN res
  871. END setFields;
  872.  
  873.  
  874. PROCEDURE getParam* (self: _TYPE; name: SCAN.IDENT): PARAM;
  875. VAR
  876.     item: PARAM;
  877.  
  878. BEGIN
  879.     item := self.params.first(PARAM);
  880.  
  881.     WHILE (item # NIL) & ~IdEq(item.name, name) DO
  882.         item := item.next(PARAM)
  883.     END
  884.  
  885.     RETURN item
  886. END getParam;
  887.  
  888.  
  889. PROCEDURE addParam* (self: _TYPE; name: SCAN.IDENT; vPar: BOOLEAN): BOOLEAN;
  890. VAR
  891.     param: PARAM;
  892.     res:   BOOLEAN;
  893.  
  894. BEGIN
  895.     res := getParam(self, name) = NIL;
  896.  
  897.     IF res THEN
  898.         NEW(param);
  899.  
  900.         param.name  := name;
  901.         param._type := NIL;
  902.         param.vPar  := vPar;
  903.  
  904.         LISTS.push(self.params, param)
  905.     END
  906.  
  907.     RETURN res
  908. END addParam;
  909.  
  910.  
  911. PROCEDURE Dim* (t: _TYPE): INTEGER;
  912. VAR
  913.     res: INTEGER;
  914.  
  915. BEGIN
  916.     res := 0;
  917.     WHILE isOpenArray(t) DO
  918.         t := t.base;
  919.         INC(res)
  920.     END
  921.     RETURN res
  922. END Dim;
  923.  
  924.  
  925. PROCEDURE OpenBase* (t: _TYPE): _TYPE;
  926. BEGIN
  927.     WHILE isOpenArray(t) DO t := t.base END
  928.     RETURN t
  929. END OpenBase;
  930.  
  931.  
  932. PROCEDURE getFloatParamsPos* (self: _TYPE; maxoffs: INTEGER; VAR int, flt: INTEGER): SET;
  933. VAR
  934.     res: SET;
  935.     param: PARAM;
  936.  
  937. BEGIN
  938.     res := {};
  939.     int := 0;
  940.     flt := 0;
  941.     param := self.params.first(PARAM);
  942.     WHILE (param # NIL) & (param.offset <= maxoffs + STACK_FRAME) DO
  943.         IF ~param.vPar & (param._type.typ = tREAL) THEN
  944.             INCL(res, param.offset - STACK_FRAME);
  945.             INC(flt)
  946.         END;
  947.         param := param.next(PARAM)
  948.     END;
  949.  
  950.     int := self.parSize - flt
  951.  
  952.     RETURN res
  953. END getFloatParamsPos;
  954.  
  955.  
  956. PROCEDURE setParams* (self: _TYPE; _type: _TYPE);
  957. VAR
  958.     item: LISTS.ITEM;
  959.     param: PARAM;
  960.     word, size: INTEGER;
  961.  
  962. BEGIN
  963.     ASSERT(_type # NIL);
  964.  
  965.     word := UTILS.target.bit_depth DIV 8;
  966.  
  967.     item := self.params.first;
  968.  
  969.     WHILE (item # NIL) & (item(PARAM)._type # NIL) DO
  970.         item := item.next
  971.     END;
  972.  
  973.     WHILE (item # NIL) & (item(PARAM)._type = NIL) DO
  974.         param := item(PARAM);
  975.         param._type := _type;
  976.         IF param.vPar THEN
  977.             IF _type.typ = tRECORD THEN
  978.                 size := 2
  979.             ELSIF isOpenArray(_type) THEN
  980.                 size := Dim(_type) + 1
  981.             ELSE
  982.                 size := 1
  983.             END;
  984.             param.offset := self.parSize + ORD(_type.typ = tRECORD) + Dim(_type) + STACK_FRAME;
  985.             INC(self.parSize, size)
  986.         ELSE
  987.             IF _type.typ IN {tRECORD, tARRAY} THEN
  988.                 IF isOpenArray(_type) THEN
  989.                     size := Dim(_type) + 1
  990.                 ELSE
  991.                     size := 1
  992.                 END
  993.             ELSE
  994.                 size := _type.size;
  995.                 ASSERT(UTILS.Align(size, word));
  996.                 size := size DIV word
  997.             END;
  998.             param.offset := self.parSize + Dim(_type) + STACK_FRAME;
  999.             INC(self.parSize, size)
  1000.         END;
  1001.  
  1002.         item := item.next
  1003.     END
  1004.  
  1005. END setParams;
  1006.  
  1007.  
  1008. PROCEDURE enterType* (typ, size, length: INTEGER; unit: UNIT): _TYPE;
  1009. VAR
  1010.     t: _TYPE;
  1011.  
  1012. BEGIN
  1013.     NEW(t);
  1014.  
  1015.     t.typ     := typ;
  1016.     t.size    := size;
  1017.     t.length  := length;
  1018.     t.align   := 0;
  1019.     t.base    := NIL;
  1020.     t.fields  := LISTS.create(NIL);
  1021.     t.params  := LISTS.create(NIL);
  1022.     t.unit    := unit;
  1023.     t.num     := 0;
  1024.  
  1025.     CASE TARGETS.BitDepth OF
  1026.     |16: t.call := default16
  1027.     |32: t.call := default32
  1028.     |64: t.call := default64
  1029.     END;
  1030.  
  1031.     t._import := FALSE;
  1032.     t.noalign := FALSE;
  1033.     t.parSize := 0;
  1034.  
  1035.     IF typ IN {tARRAY, tRECORD} THEN
  1036.         t.closed := FALSE;
  1037.         IF typ = tRECORD THEN
  1038.             INC(program.recCount);
  1039.             t.num := program.recCount
  1040.         END
  1041.     ELSE
  1042.         t.closed := TRUE
  1043.     END;
  1044.  
  1045.     LISTS.push(program.types, t)
  1046.  
  1047.     RETURN t
  1048. END enterType;
  1049.  
  1050.  
  1051. PROCEDURE getType* (typ: INTEGER): _TYPE;
  1052. VAR
  1053.     res: _TYPE;
  1054.  
  1055. BEGIN
  1056.  
  1057.     CASE typ OF
  1058.     |ARITH.tINTEGER: res := program.stTypes.tINTEGER
  1059.     |ARITH.tREAL:    res := program.stTypes.tREAL
  1060.     |ARITH.tSET:     res := program.stTypes.tSET
  1061.     |ARITH.tBOOLEAN: res := program.stTypes.tBOOLEAN
  1062.     |ARITH.tCHAR:    res := program.stTypes.tCHAR
  1063.     |ARITH.tWCHAR:   res := program.stTypes.tWCHAR
  1064.     |ARITH.tSTRING:  res := program.stTypes.tSTRING
  1065.     END
  1066.  
  1067.     RETURN res
  1068. END getType;
  1069.  
  1070.  
  1071. PROCEDURE createSysUnit;
  1072. VAR
  1073.     ident: IDENT;
  1074.     unit:  UNIT;
  1075.     name:  SCAN.IDENT;
  1076.  
  1077.  
  1078.     PROCEDURE EnterProc (sys: UNIT; nameStr: SCAN.IDSTR; idtyp, proc: INTEGER);
  1079.     VAR
  1080.         ident: IDENT;
  1081.         upper: SCAN.IDSTR;
  1082.         name:  SCAN.IDENT;
  1083.  
  1084.     BEGIN
  1085.         IF LowerCase THEN
  1086.             SCAN.setIdent(name, nameStr);
  1087.             ident := addIdent(sys, name, idtyp);
  1088.             ident.stproc := proc;
  1089.             ident._type := program.stTypes.tNONE;
  1090.             ident.export := TRUE
  1091.         END;
  1092.         upper := nameStr;
  1093.         STRINGS.UpCase(upper);
  1094.         SCAN.setIdent(name, upper);
  1095.         ident := addIdent(sys, name, idtyp);
  1096.         ident.stproc := proc;
  1097.         ident._type := program.stTypes.tNONE;
  1098.         ident.export := TRUE
  1099.     END EnterProc;
  1100.  
  1101.  
  1102. BEGIN
  1103.     SCAN.setIdent(name, "$SYSTEM");
  1104.     unit := newUnit(name);
  1105.     unit.fname := "SYSTEM";
  1106.  
  1107.     EnterProc(unit, "adr",    idSYSFUNC, sysADR);
  1108.     EnterProc(unit, "size",   idSYSFUNC, sysSIZE);
  1109.     EnterProc(unit, "sadr",   idSYSFUNC, sysSADR);
  1110.     EnterProc(unit, "typeid", idSYSFUNC, sysTYPEID);
  1111.  
  1112.     EnterProc(unit, "get",    idSYSPROC, sysGET);
  1113.     EnterProc(unit, "get8",   idSYSPROC, sysGET8);
  1114.     EnterProc(unit, "put",    idSYSPROC, sysPUT);
  1115.     EnterProc(unit, "put8",   idSYSPROC, sysPUT8);
  1116.     EnterProc(unit, "code",   idSYSPROC, sysCODE);
  1117.     EnterProc(unit, "move",   idSYSPROC, sysMOVE);
  1118.     EnterProc(unit, "val",    idSYSPROC, sysVAL);
  1119.            (*
  1120.     IF program.target.sys = mConst.Target_iMSP430 THEN
  1121.         EnterProc(unit, "nop",  idSYSPROC, sysNOP);
  1122.         EnterProc(unit, "eint", idSYSPROC, sysEINT);
  1123.         EnterProc(unit, "dint", idSYSPROC, sysDINT)
  1124.     END;
  1125.          *)
  1126.     IF TARGETS.RealSize # 0 THEN
  1127.         EnterProc(unit, "inf",    idSYSFUNC, sysINF);
  1128.     END;
  1129.  
  1130.     IF TARGETS.CPU IN {TARGETS.cpuX86, TARGETS.cpuAMD64} THEN
  1131.         EnterProc(unit, "copy",   idSYSPROC, sysCOPY)
  1132.     END;
  1133.  
  1134.     IF TARGETS.BitDepth >= 32 THEN
  1135.         EnterProc(unit, "wsadr",  idSYSFUNC, sysWSADR);
  1136.         EnterProc(unit, "put16",  idSYSPROC, sysPUT16);
  1137.         EnterProc(unit, "put32",  idSYSPROC, sysPUT32);
  1138.         EnterProc(unit, "get16",  idSYSPROC, sysGET16);
  1139.         EnterProc(unit, "get32",  idSYSPROC, sysGET32);
  1140.  
  1141.         IF LowerCase THEN
  1142.             SCAN.setIdent(name, "card32");
  1143.             ident := addIdent(unit, name, idTYPE);
  1144.             ident._type := program.stTypes.tCARD32;
  1145.             ident.export := TRUE
  1146.         END;
  1147.         SCAN.setIdent(name, "CARD32");
  1148.         ident := addIdent(unit, name, idTYPE);
  1149.         ident._type := program.stTypes.tCARD32;
  1150.         ident.export := TRUE;
  1151.     END;
  1152.  
  1153.     closeUnit(unit);
  1154.  
  1155.     program.sysunit := unit
  1156. END createSysUnit;
  1157.  
  1158.  
  1159. PROCEDURE DelUnused* (DelImport: DELIMPORT);
  1160. VAR
  1161.     proc: PROC;
  1162.     flag: BOOLEAN;
  1163.  
  1164.  
  1165.     PROCEDURE process (proc: PROC);
  1166.     VAR
  1167.         used_proc: LISTS.ITEM;
  1168.  
  1169.     BEGIN
  1170.         proc.processed := TRUE;
  1171.  
  1172.         used_proc := proc.using.first;
  1173.         WHILE used_proc # NIL DO
  1174.             used_proc(USED_PROC).proc.used := TRUE;
  1175.             used_proc := used_proc.next
  1176.         END
  1177.  
  1178.     END process;
  1179.  
  1180.  
  1181. BEGIN
  1182.  
  1183.     REPEAT
  1184.         flag := FALSE;
  1185.         proc := program.procs.first(PROC);
  1186.  
  1187.         WHILE proc # NIL DO
  1188.             IF proc.used & ~proc.processed THEN
  1189.                 process(proc);
  1190.                 flag := TRUE
  1191.             END;
  1192.             proc := proc.next(PROC)
  1193.         END
  1194.  
  1195.     UNTIL ~flag;
  1196.  
  1197.     proc := program.procs.first(PROC);
  1198.  
  1199.     WHILE proc # NIL DO
  1200.         IF ~proc.used THEN
  1201.             IF proc._import = NIL THEN
  1202.                 IL.delete2(proc.enter, proc.leave)
  1203.             ELSE
  1204.                 DelImport(proc._import)
  1205.             END
  1206.         END;
  1207.         proc := proc.next(PROC)
  1208.     END
  1209.  
  1210. END DelUnused;
  1211.  
  1212.  
  1213. PROCEDURE ResetLocSize*;
  1214. BEGIN
  1215.     program.locsize := 0
  1216. END ResetLocSize;
  1217.  
  1218.  
  1219. PROCEDURE create* (options: OPTIONS);
  1220. BEGIN
  1221.     LowerCase := options.lower;
  1222.     SCAN.init(options.lower);
  1223.     idents := C.create();
  1224.  
  1225.     UTILS.SetBitDepth(TARGETS.BitDepth, TARGETS.RealSize = 8);
  1226.  
  1227.     program.options := options;
  1228.  
  1229.     CASE TARGETS.OS OF
  1230.     |TARGETS.osWIN32:    program.sysflags := {sf_oberon, sf_windows, sf_stdcall, sf_cdecl, sf_ccall, sf_fastcall, sf_noalign}
  1231.     |TARGETS.osLINUX32:  program.sysflags := {sf_oberon, sf_linux, sf_stdcall, sf_cdecl, sf_ccall, sf_fastcall, sf_noalign}
  1232.     |TARGETS.osKOS:      program.sysflags := {sf_oberon, sf_stdcall, sf_cdecl, sf_ccall, sf_fastcall, sf_noalign}
  1233.     |TARGETS.osWIN64:    program.sysflags := {sf_oberon, sf_windows, sf_win64, sf_systemv, sf_ccall, sf_noalign}
  1234.     |TARGETS.osLINUX64:  program.sysflags := {sf_oberon, sf_linux, sf_win64, sf_systemv, sf_ccall, sf_noalign}
  1235.     |TARGETS.osNONE:     program.sysflags := {sf_code}
  1236.     END;
  1237.  
  1238.     program.recCount := -1;
  1239.     program.bss := 0;
  1240.  
  1241.     program.units := LISTS.create(NIL);
  1242.     program.types := LISTS.create(NIL);
  1243.     program.procs := LISTS.create(NIL);
  1244.  
  1245.     program.stTypes.tINTEGER := enterType(tINTEGER, TARGETS.WordSize, 0, NIL);
  1246.     program.stTypes.tBYTE    := enterType(tBYTE,                   1, 0, NIL);
  1247.     program.stTypes.tCHAR    := enterType(tCHAR,                   1, 0, NIL);
  1248.     program.stTypes.tSET     := enterType(tSET,     TARGETS.WordSize, 0, NIL);
  1249.     program.stTypes.tBOOLEAN := enterType(tBOOLEAN,                1, 0, NIL);
  1250.  
  1251.     program.stTypes.tINTEGER.align := TARGETS.WordSize;
  1252.     program.stTypes.tBYTE.align    := 1;
  1253.     program.stTypes.tCHAR.align    := 1;
  1254.     program.stTypes.tSET.align     := TARGETS.WordSize;
  1255.     program.stTypes.tBOOLEAN.align := 1;
  1256.  
  1257.     IF TARGETS.BitDepth >= 32 THEN
  1258.         program.stTypes.tWCHAR  := enterType(tWCHAR,  2, 0, NIL);
  1259.         program.stTypes.tCARD32 := enterType(tCARD32, 4, 0, NIL);
  1260.         program.stTypes.tWCHAR.align  := 2;
  1261.         program.stTypes.tCARD32.align := 4
  1262.     END;
  1263.  
  1264.     IF TARGETS.RealSize # 0 THEN
  1265.         program.stTypes.tREAL := enterType(tREAL, TARGETS.RealSize, 0, NIL);
  1266.         IF TARGETS.OS = TARGETS.osLINUX32 THEN
  1267.             program.stTypes.tREAL.align := 4
  1268.         ELSE
  1269.             program.stTypes.tREAL.align := TARGETS.RealSize
  1270.         END
  1271.     END;
  1272.  
  1273.     program.stTypes.tSTRING := enterType(tSTRING, TARGETS.WordSize, 0, NIL);
  1274.     program.stTypes.tNIL    := enterType(tNIL,    TARGETS.WordSize, 0, NIL);
  1275.     program.stTypes.tNONE   := enterType(tNONE,   0, 0, NIL);
  1276.     program.stTypes.tANYREC := enterType(tRECORD, 0, 0, NIL);
  1277.     program.stTypes.tANYREC.closed := TRUE;
  1278.  
  1279.     createSysUnit
  1280. END create;
  1281.  
  1282.  
  1283. END PROG.