Subversion Repositories Kolibri OS

Rev

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