Subversion Repositories Kolibri OS

Rev

Rev 7983 | Rev 8859 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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