Subversion Repositories Kolibri OS

Rev

Rev 7597 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. (*
  2.     BSD 2-Clause License
  3.  
  4.     Copyright (c) 2018, 2019, Anton Krotov
  5.     All rights reserved.
  6. *)
  7.  
  8. MODULE PARS;
  9.  
  10. IMPORT PROG, SCAN, ARITH, STRINGS, ERRORS, LISTS, IL, CONSOLE, PATHS, UTILS, C := COLLECTIONS, mConst := CONSTANTS;
  11.  
  12.  
  13. CONST
  14.  
  15.     eCONST*   =  1;  eTYPE*   =  2;  eVAR*     =  3;  eEXPR*    =  4;
  16.     eVREC*    =  5;  ePROC*   =  6;  eVPAR*    =  7;  ePARAM*   =  8;
  17.     eSTPROC*  =  9;  eSTFUNC* = 10;  eSYSFUNC* = 11;  eSYSPROC* = 12;
  18.     eIMP*     = 13;
  19.  
  20.  
  21. TYPE
  22.  
  23.     PATH* = PATHS.PATH;
  24.  
  25.     PARSER* = POINTER TO rPARSER;
  26.  
  27.     POSITION* = RECORD (SCAN.POSITION)
  28.  
  29.         parser*: PARSER
  30.  
  31.     END;
  32.  
  33.     EXPR* = RECORD
  34.  
  35.         obj*:         INTEGER;
  36.         type*:        PROG.TYPE_;
  37.         value*:       ARITH.VALUE;
  38.         stproc*:      INTEGER;
  39.         readOnly*:    BOOLEAN;
  40.         ident*:       PROG.IDENT
  41.  
  42.     END;
  43.  
  44.     STATPROC  = PROCEDURE (parser: PARSER);
  45.     EXPRPROC  = PROCEDURE (parser: PARSER; VAR e: EXPR);
  46.     RETPROC   = PROCEDURE (parser: PARSER; e: EXPR; t: PROG.TYPE_; pos: POSITION): BOOLEAN;
  47.  
  48.     rPARSER = RECORD (C.ITEM)
  49.  
  50.         fname*:      PATH;
  51.         path:        PATH;
  52.         lib_path:    PATH;
  53.         ext:         PATH;
  54.         modname:     PATH;
  55.         scanner:     SCAN.SCANNER;
  56.         lex*:        SCAN.LEX;
  57.         sym*:        INTEGER;
  58.         unit*:       PROG.UNIT;
  59.         constexp*:   BOOLEAN;
  60.         main*:       BOOLEAN;
  61.  
  62.         open*:       PROCEDURE (parser: PARSER; modname: ARRAY OF CHAR): BOOLEAN;
  63.         parse*:      PROCEDURE (parser: PARSER);
  64.         StatSeq*:    STATPROC;
  65.         expression*: EXPRPROC;
  66.         designator*: EXPRPROC;
  67.         chkreturn:   RETPROC;
  68.  
  69.         create*:     PROCEDURE (path, lib_path: PATH; StatSeq: STATPROC; expression, designator: EXPRPROC; chkreturn: RETPROC): PARSER
  70.  
  71.     END;
  72.  
  73.  
  74. VAR
  75.  
  76.     program*: PROG.PROGRAM;
  77.  
  78.     parsers: C.COLLECTION;
  79.  
  80.  
  81. PROCEDURE destroy* (VAR parser: PARSER);
  82. BEGIN
  83.     IF parser.scanner # NIL THEN
  84.         SCAN.close(parser.scanner)
  85.     END;
  86.  
  87.     C.push(parsers, parser);
  88.     parser := NIL
  89. END destroy;
  90.  
  91.  
  92. PROCEDURE getpos (parser: PARSER; VAR pos: POSITION);
  93. BEGIN
  94.     pos.line   := parser.lex.pos.line;
  95.     pos.col    := parser.lex.pos.col;
  96.     pos.parser := parser
  97. END getpos;
  98.  
  99.  
  100. PROCEDURE error* (pos: POSITION; errno: INTEGER);
  101. BEGIN
  102.     ERRORS.ErrorMsg(pos.parser.fname, pos.line, pos.col, errno)
  103. END error;
  104.  
  105.  
  106. PROCEDURE check* (condition: BOOLEAN; pos: POSITION; errno: INTEGER);
  107. BEGIN
  108.     IF ~condition THEN
  109.         error(pos, errno)
  110.     END
  111. END check;
  112.  
  113.  
  114. PROCEDURE check1* (condition: BOOLEAN; parser: PARSER; errno: INTEGER);
  115. VAR
  116.     pos: POSITION;
  117.  
  118. BEGIN
  119.     IF ~condition THEN
  120.         getpos(parser, pos);
  121.         error(pos, errno)
  122.     END
  123. END check1;
  124.  
  125.  
  126. PROCEDURE Next* (parser: PARSER);
  127. VAR
  128.     errno: INTEGER;
  129.  
  130. BEGIN
  131.     SCAN.Next(parser.scanner, parser.lex);
  132.     errno := parser.lex.error;
  133.     IF (errno = 0) & (program.target.sys = mConst.Target_iMSP430) THEN
  134.         IF parser.lex.sym = SCAN.lxFLOAT THEN
  135.             errno := -SCAN.lxERROR13
  136.         ELSIF (parser.lex.sym = SCAN.lxCHAR) & (parser.lex.value.typ = ARITH.tWCHAR) THEN
  137.             errno := -SCAN.lxERROR10
  138.         END
  139.     END;
  140.  
  141.     IF errno # 0 THEN
  142.         check1(FALSE, parser, errno)
  143.     END;
  144.     parser.sym := parser.lex.sym
  145. END Next;
  146.  
  147.  
  148. PROCEDURE NextPos (parser: PARSER; VAR pos: POSITION);
  149. BEGIN
  150.     Next(parser);
  151.     getpos(parser, pos)
  152. END NextPos;
  153.  
  154.  
  155. PROCEDURE checklex* (parser: PARSER; sym: INTEGER);
  156. VAR
  157.     err: INTEGER;
  158.  
  159. BEGIN
  160.  
  161.     IF parser.sym # sym THEN
  162.  
  163.         CASE sym OF
  164.         |SCAN.lxCOMMA:   err := 65
  165.         |SCAN.lxRROUND:  err := 33
  166.         |SCAN.lxPOINT:   err := 26
  167.         |SCAN.lxIDENT:   err := 22
  168.         |SCAN.lxRSQUARE: err := 71
  169.         |SCAN.lxRCURLY:  err := 35
  170.         |SCAN.lxUNDEF:   err := 34
  171.         |SCAN.lxTHEN:    err := 88
  172.         |SCAN.lxEND:     err := 27
  173.         |SCAN.lxDO:      err := 89
  174.         |SCAN.lxUNTIL:   err := 90
  175.         |SCAN.lxCOLON:   err := 53
  176.         |SCAN.lxOF:      err := 67
  177.         |SCAN.lxASSIGN:  err := 96
  178.         |SCAN.lxTO:      err := 57
  179.         |SCAN.lxLROUND:  err := 64
  180.         |SCAN.lxEQ:      err := 32
  181.         |SCAN.lxSEMI:    err := 24
  182.         |SCAN.lxRETURN:  err := 38
  183.         |SCAN.lxMODULE:  err := 21
  184.         |SCAN.lxSTRING:  err := 66
  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(program, 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 = 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(program, 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 = "noalign" THEN
  504.         sf := PROG.sf_noalign
  505.     ELSE
  506.         check1(FALSE, parser, 124)
  507.     END;
  508.  
  509.     check1(sf IN program.target.sysflags, parser, 125);
  510.  
  511.     IF proc THEN
  512.         check1(sf IN PROG.proc_flags, parser, 123)
  513.     ELSE
  514.         check1(sf IN PROG.rec_flags, parser, 123)
  515.     END;
  516.  
  517.     CASE sf OF
  518.     |PROG.sf_stdcall:
  519.         res := PROG.stdcall
  520.     |PROG.sf_stdcall64:
  521.         res := PROG.stdcall64
  522.     |PROG.sf_ccall:
  523.         res := PROG.ccall
  524.     |PROG.sf_ccall16:
  525.         res := PROG.ccall16
  526.     |PROG.sf_win64:
  527.         res := PROG.win64
  528.     |PROG.sf_systemv:
  529.         res := PROG.systemv
  530.     |PROG.sf_code:
  531.         res := PROG.code
  532.     |PROG.sf_windows:
  533.         IF program.target.sys IN {mConst.Target_iConsole, mConst.Target_iGUI, mConst.Target_iDLL} THEN
  534.             res := PROG.stdcall
  535.         ELSIF program.target.sys IN {mConst.Target_iConsole64, mConst.Target_iGUI64, mConst.Target_iDLL64} THEN
  536.             res := PROG.win64
  537.         END
  538.     |PROG.sf_linux:
  539.         IF program.target.sys IN {mConst.Target_iELF32, mConst.Target_iELFSO32} THEN
  540.             res := PROG.ccall16
  541.         ELSIF program.target.sys IN {mConst.Target_iELF64, mConst.Target_iELFSO64} THEN
  542.             res := PROG.systemv
  543.         END
  544.     |PROG.sf_noalign:
  545.         res := PROG.noalign
  546.     END
  547.  
  548.     RETURN res
  549. END sysflag;
  550.  
  551.  
  552. PROCEDURE procflag (parser: PARSER; VAR import: IL.IMPORT_PROC; isProc: BOOLEAN): INTEGER;
  553. VAR
  554.     call: INTEGER;
  555.     dll, proc: SCAN.LEXSTR;
  556.     pos: POSITION;
  557.  
  558. BEGIN
  559.  
  560.     import := NIL;
  561.  
  562.     IF parser.sym = SCAN.lxLSQUARE THEN
  563.         getpos(parser, pos);
  564.         check1(parser.unit.sysimport, parser, 54);
  565.         Next(parser);
  566.         call := sysflag(parser, TRUE);
  567.         Next(parser);
  568.         IF parser.sym = SCAN.lxMINUS THEN
  569.             Next(parser);
  570.             INC(call)
  571.         END;
  572.         IF ~isProc THEN
  573.             checklex(parser, SCAN.lxRSQUARE)
  574.         END;
  575.         IF parser.sym = SCAN.lxCOMMA THEN
  576.             ExpectSym(parser, SCAN.lxSTRING);
  577.             dll := parser.lex.s;
  578.             ExpectSym(parser, SCAN.lxCOMMA);
  579.             ExpectSym(parser, SCAN.lxSTRING);
  580.             proc := parser.lex.s;
  581.             Next(parser);
  582.             import := IL.AddImp(dll, proc)
  583.         END;
  584.         checklex(parser, SCAN.lxRSQUARE);
  585.         Next(parser)
  586.     ELSE
  587.         CASE program.target.bit_depth OF
  588.         |16: call := PROG.default16
  589.         |32: call := PROG.default32
  590.         |64: call := PROG.default64
  591.         END
  592.     END;
  593.  
  594.     IF import # NIL THEN
  595.         check(~(program.target.sys IN {mConst.Target_iELF32, mConst.Target_iELF64, mConst.Target_iELFSO32,
  596.             mConst.Target_iELFSO64, mConst.Target_iMSP430}), pos, 70)
  597.     END
  598.  
  599.     RETURN call
  600. END procflag;
  601.  
  602.  
  603. PROCEDURE type (parser: PARSER; VAR t: PROG.TYPE_; flags: SET);
  604. CONST
  605.     comma   = 0;
  606.     closed  = 1;
  607.     forward = 2;
  608.  
  609. VAR
  610.     arrLen:     ARITH.VALUE;
  611.     typeSize:   ARITH.VALUE;
  612.     ident:      PROG.IDENT;
  613.     unit:       PROG.UNIT;
  614.     pos, pos2:  POSITION;
  615.     fieldType:  PROG.TYPE_;
  616.     baseIdent:  SCAN.IDENT;
  617.     a, b:       INTEGER;
  618.     RecFlag:    INTEGER;
  619.     import:     IL.IMPORT_PROC;
  620.  
  621. BEGIN
  622.     unit := parser.unit;
  623.     t := NIL;
  624.  
  625.     IF parser.sym = SCAN.lxIDENT THEN
  626.         ident := QIdent(parser, forward IN flags);
  627.  
  628.         IF ident # NIL THEN
  629.             check1(ident.typ = PROG.idTYPE, parser, 49);
  630.             t := ident.type;
  631.             check1(t # NIL, parser, 50);
  632.             IF closed IN flags THEN
  633.                 check1(t.closed, parser, 50)
  634.             END
  635.         END;
  636.  
  637.         Next(parser)
  638.  
  639.     ELSIF (parser.sym = SCAN.lxARRAY) OR ((parser.sym = SCAN.lxCOMMA) & (comma IN flags)) THEN
  640.  
  641.         IF parser.sym = SCAN.lxARRAY THEN
  642.             getpos(parser, pos2)
  643.         END;
  644.         NextPos(parser, pos);
  645.  
  646.         ConstExpression(parser, arrLen);
  647.  
  648.         check(arrLen.typ = ARITH.tINTEGER, pos, 43);
  649.         check(ARITH.check(arrLen),         pos, 39);
  650.         check(ARITH.getInt(arrLen) > 0,    pos, 51);
  651.  
  652.         t := PROG.enterType(program, PROG.tARRAY, -1, ARITH.getInt(arrLen), unit);
  653.  
  654.         IF parser.sym = SCAN.lxCOMMA THEN
  655.             type(parser, t.base, {comma, closed})
  656.         ELSIF parser.sym = SCAN.lxOF THEN
  657.             Next(parser);
  658.             type(parser, t.base, {closed})
  659.         ELSE
  660.             check1(FALSE, parser, 47)
  661.         END;
  662.  
  663.         t.align := t.base.align;
  664.  
  665.         a := t.length;
  666.         b := t.base.size;
  667.         check(ARITH.mulInt(a, b), pos2, 104);
  668.         check(ARITH.setInt(typeSize, a), pos2, 104);
  669.         t.size := a;
  670.  
  671.         t.closed := TRUE
  672.  
  673.     ELSIF parser.sym = SCAN.lxRECORD THEN
  674.         getpos(parser, pos2);
  675.         Next(parser);
  676.  
  677.         t := PROG.enterType(program, PROG.tRECORD, 0, 0, unit);
  678.         t.align := 1;
  679.  
  680.         IF parser.sym = SCAN.lxLSQUARE THEN
  681.             check1(parser.unit.sysimport, parser, 54);
  682.             Next(parser);
  683.             RecFlag := sysflag(parser, FALSE);
  684.             t.noalign := RecFlag = PROG.noalign;
  685.             ExpectSym(parser, SCAN.lxRSQUARE);
  686.             Next(parser)
  687.         END;
  688.  
  689.         IF parser.sym = SCAN.lxLROUND THEN
  690.             check1(~t.noalign, parser, 111);
  691.             ExpectSym(parser, SCAN.lxIDENT);
  692.             getpos(parser, pos);
  693.  
  694.             type(parser, t.base, {closed});
  695.  
  696.             check(t.base.typ IN {PROG.tRECORD, PROG.tPOINTER}, pos, 52);
  697.  
  698.             IF t.base.typ = PROG.tPOINTER THEN
  699.                 t.base := t.base.base;
  700.                 check(t.base # NIL, pos, 55)
  701.             END;
  702.  
  703.             check(~t.base.noalign, pos, 112);
  704.  
  705.             checklex(parser, SCAN.lxRROUND);
  706.             Next(parser);
  707.  
  708.             t.size := t.base.size;
  709.             IF t.base.align > t.align THEN
  710.                 t.align := t.base.align
  711.             END
  712.         ELSE
  713.             t.base := program.stTypes.tANYREC
  714.         END;
  715.  
  716.         WHILE parser.sym = SCAN.lxIDENT DO
  717.             FieldList(parser, t);
  718.  
  719.             ASSERT(parser.sym = SCAN.lxCOLON);
  720.             Next(parser);
  721.  
  722.             type(parser, fieldType, {closed});
  723.             check(PROG.setFields(t, fieldType), pos2, 104);
  724.  
  725.             IF (fieldType.align > t.align) & ~t.noalign THEN
  726.                 t.align := fieldType.align
  727.             END;
  728.  
  729.             IF parser.sym = SCAN.lxSEMI THEN
  730.                 ExpectSym(parser, SCAN.lxIDENT)
  731.             ELSE
  732.                 checklex(parser, SCAN.lxEND)
  733.             END
  734.         END;
  735.  
  736.         t.closed := TRUE;
  737.  
  738.         IL.AddRec(t.base.num);
  739.  
  740.         IF ~t.noalign THEN
  741.             check(UTILS.Align(t.size, t.align), pos2, 104);
  742.             check(ARITH.setInt(typeSize, t.size), pos2, 104)
  743.         END;
  744.  
  745.         checklex(parser, SCAN.lxEND);
  746.         Next(parser)
  747.  
  748.     ELSIF parser.sym = SCAN.lxPOINTER THEN
  749.         ExpectSym(parser, SCAN.lxTO);
  750.         Next(parser);
  751.  
  752.         t := PROG.enterType(program, PROG.tPOINTER, program.target.adr, 0, unit);
  753.         t.align := program.target.adr;
  754.  
  755.         getpos(parser, pos);
  756.  
  757.         IF parser.sym = SCAN.lxIDENT THEN
  758.             baseIdent := parser.lex.ident
  759.         END;
  760.  
  761.         type(parser, t.base, {forward});
  762.  
  763.         IF t.base # NIL THEN
  764.             check(t.base.typ = PROG.tRECORD, pos, 58)
  765.         ELSE
  766.             PROG.frwPtr(unit, t, baseIdent, pos)
  767.         END
  768.  
  769.     ELSIF parser.sym = SCAN.lxPROCEDURE THEN
  770.         NextPos(parser, pos);
  771.         t := PROG.enterType(program, PROG.tPROCEDURE, program.target.adr, 0, unit);
  772.         t.align := program.target.adr;
  773.         t.call := procflag(parser, import, FALSE);
  774.         FormalParameters(parser, t)
  775.     ELSE
  776.         check1(FALSE, parser, 49)
  777.     END
  778.  
  779. END type;
  780.  
  781.  
  782. PROCEDURE IdentDef (parser: PARSER; typ: INTEGER; VAR name: SCAN.IDENT): PROG.IDENT;
  783. VAR
  784.     ident:  PROG.IDENT;
  785.     pos:    POSITION;
  786.  
  787. BEGIN
  788.     ASSERT(parser.sym = SCAN.lxIDENT);
  789.  
  790.     name := parser.lex.ident;
  791.     getpos(parser, pos);
  792.     ident := PROG.addIdent(parser.unit, name, typ);
  793.     check(ident # NIL, pos, 30);
  794.     ident.pos := pos;
  795.     Next(parser);
  796.  
  797.     IF parser.sym = SCAN.lxMUL THEN
  798.         check1(ident.global, parser, 61);
  799.         ident.export := TRUE;
  800.         Next(parser)
  801.     END
  802.  
  803.     RETURN ident
  804. END IdentDef;
  805.  
  806.  
  807. PROCEDURE ConstTypeDeclaration (parser: PARSER; const: BOOLEAN);
  808. VAR
  809.     ident: PROG.IDENT;
  810.     name:  SCAN.IDENT;
  811.     pos:   POSITION;
  812.  
  813. BEGIN
  814.     IF const THEN
  815.         ident := IdentDef(parser, PROG.idNONE, name)
  816.     ELSE
  817.         ident := IdentDef(parser, PROG.idTYPE, name)
  818.     END;
  819.  
  820.     checklex(parser, SCAN.lxEQ);
  821.     NextPos(parser, pos);
  822.  
  823.     IF const THEN
  824.         ConstExpression(parser, ident.value);
  825.         IF ident.value.typ = ARITH.tINTEGER THEN
  826.             check(ARITH.check(ident.value), pos, 39)
  827.         ELSIF ident.value.typ = ARITH.tREAL THEN
  828.             check(ARITH.check(ident.value), pos, 40)
  829.         END;
  830.         ident.typ  := PROG.idCONST;
  831.         ident.type := PROG.getType(program, ident.value.typ)
  832.     ELSE
  833.         type(parser, ident.type, {})
  834.     END;
  835.  
  836.     checklex(parser, SCAN.lxSEMI);
  837.     Next(parser)
  838.  
  839. END ConstTypeDeclaration;
  840.  
  841.  
  842. PROCEDURE VarDeclaration (parser: PARSER);
  843. VAR
  844.     ident: PROG.IDENT;
  845.     name:  SCAN.IDENT;
  846.     t:     PROG.TYPE_;
  847.  
  848. BEGIN
  849.  
  850.     REPEAT
  851.         ident := IdentDef(parser, PROG.idVAR, name);
  852.  
  853.         IF parser.sym = SCAN.lxCOMMA THEN
  854.             ExpectSym(parser, SCAN.lxIDENT)
  855.         ELSIF parser.sym = SCAN.lxCOLON THEN
  856.             Next(parser);
  857.             type(parser, t, {});
  858.             PROG.setVarsType(parser.unit, t);
  859.             checklex(parser, SCAN.lxSEMI);
  860.             Next(parser)
  861.         ELSE
  862.             checklex(parser, SCAN.lxCOLON)
  863.         END
  864.  
  865.     UNTIL parser.sym # SCAN.lxIDENT
  866.  
  867. END VarDeclaration;
  868.  
  869.  
  870. PROCEDURE DeclarationSequence (parser: PARSER): BOOLEAN;
  871. VAR
  872.     ptr: PROG.FRWPTR;
  873.     endmod: BOOLEAN;
  874.     pos: POSITION;
  875.  
  876.  
  877.     PROCEDURE ProcDeclaration (parser: PARSER): BOOLEAN;
  878.     VAR
  879.         proc:       PROG.IDENT;
  880.         endname,
  881.         name:       SCAN.IDENT;
  882.         param:      PROG.PARAM;
  883.         unit:       PROG.UNIT;
  884.         ident:      PROG.IDENT;
  885.         e:          EXPR;
  886.         pos, pos1,
  887.         pos2:       POSITION;
  888.         label:      INTEGER;
  889.         enter:      IL.COMMAND;
  890.         call:       INTEGER;
  891.         t:          PROG.TYPE_;
  892.         import:     IL.IMPORT_PROC;
  893.         endmod, b:  BOOLEAN;
  894.         fparams:    SET;
  895.         variables:  LISTS.LIST;
  896.         int, flt:   INTEGER;
  897.         comma:      BOOLEAN;
  898.         code:       ARITH.VALUE;
  899.         codeProc:   BOOLEAN;
  900.  
  901.     BEGIN
  902.         endmod := FALSE;
  903.  
  904.         unit := parser.unit;
  905.  
  906.         call := procflag(parser, import, TRUE);
  907.  
  908.         getpos(parser, pos);
  909.         pos1 := pos;
  910.         checklex(parser, SCAN.lxIDENT);
  911.  
  912.         IF import # NIL THEN
  913.             proc := IdentDef(parser, PROG.idIMP, name);
  914.             proc.import := import;
  915.             program.procs.last(PROG.PROC).import := import
  916.         ELSE
  917.             proc := IdentDef(parser, PROG.idPROC, name)
  918.         END;
  919.  
  920.         check(PROG.openScope(unit, proc.proc), pos, 116);
  921.  
  922.         proc.type := PROG.enterType(program, PROG.tPROCEDURE, program.target.adr, 0, unit);
  923.         t := proc.type;
  924.         t.align := program.target.adr;
  925.         t.call  := call;
  926.  
  927.         FormalParameters(parser, t);
  928.  
  929.         codeProc := call IN {PROG.code, PROG._code};
  930.  
  931.         IF call IN {PROG.systemv, PROG._systemv} THEN
  932.             check(t.parSize <= PROG.MAXSYSVPARAM, pos, 120)
  933.         END;
  934.  
  935.         param := t.params.first(PROG.PARAM);
  936.         WHILE param # NIL DO
  937.             ident := PROG.addIdent(unit, param.name, PROG.idPARAM);
  938.             ASSERT(ident # NIL);
  939.             ident.type := param.type;
  940.             ident.offset := param.offset;
  941.             IF param.vPar THEN
  942.                 ident.typ := PROG.idVPAR
  943.             END;
  944.             param := param.next(PROG.PARAM)
  945.         END;
  946.  
  947.         IF import = NIL THEN
  948.             label := IL.NewLabel();
  949.             proc.proc.label := label
  950.         END;
  951.  
  952.         IF codeProc THEN
  953.             enter := IL.EnterC(label);
  954.             comma := FALSE;
  955.             WHILE (parser.sym # SCAN.lxSEMI) OR comma DO
  956.                 getpos(parser, pos2);
  957.                 ConstExpression(parser, code);
  958.                 check(code.typ = ARITH.tINTEGER, pos2, 43);
  959.                 IF program.target.sys # mConst.Target_iMSP430 THEN
  960.                     check(ARITH.range(code, 0, 255), pos2, 42)
  961.                 END;
  962.                 IL.AddCmd(IL.opCODE, ARITH.getInt(code));
  963.                 comma := parser.sym = SCAN.lxCOMMA;
  964.                 IF comma THEN
  965.                     Next(parser)
  966.                 ELSE
  967.                     checklex(parser, SCAN.lxSEMI)
  968.                 END
  969.             END
  970.         END;
  971.  
  972.         checklex(parser, SCAN.lxSEMI);
  973.         Next(parser);
  974.  
  975.         IF import = NIL THEN
  976.  
  977.             IF parser.main & proc.export & program.dll THEN
  978.                 IF program.obj THEN
  979.                     check((proc.name.s # "lib_init") & (proc.name.s # "version"), pos, 114)
  980.                 END;
  981.                 IL.AddExp(label, proc.name.s);
  982.                 proc.proc.used := TRUE
  983.             END;
  984.  
  985.             IF ~codeProc THEN
  986.                 b := DeclarationSequence(parser)
  987.             END;
  988.  
  989.             program.locsize := 0;
  990.             IF call IN {PROG._win64, PROG.win64} THEN
  991.                 fparams := PROG.getFloatParamsPos(proc.type, 3, int, flt);
  992.                 enter := IL.Enter(label, LSL(ORD(fparams), 5) + MIN(proc.type.parSize, 4))
  993.             ELSIF call IN {PROG._systemv, PROG.systemv} THEN
  994.                 fparams := PROG.getFloatParamsPos(proc.type, PROG.MAXSYSVPARAM - 1, int, flt);
  995.                 enter := IL.Enter(label, -(LSL(ORD(fparams), 5) + proc.type.parSize))
  996.             ELSIF codeProc THEN
  997.  
  998.             ELSE
  999.                 enter := IL.Enter(label, 0)
  1000.             END;
  1001.             proc.proc.enter := enter;
  1002.  
  1003.             IF ~codeProc & (parser.sym = SCAN.lxBEGIN) THEN
  1004.                 Next(parser);
  1005.                 parser.StatSeq(parser)
  1006.             END;
  1007.  
  1008.             IF ~codeProc & (t.base # NIL) THEN
  1009.                 checklex(parser, SCAN.lxRETURN);
  1010.                 NextPos(parser, pos);
  1011.                 parser.expression(parser, e);
  1012.                 check(parser.chkreturn(parser, e, t.base, pos), pos, 87)
  1013.             END;
  1014.  
  1015.             IF ~codeProc THEN
  1016.                 proc.proc.leave := IL.Leave(t.base # NIL, (t.base # NIL) & (t.base.typ = PROG.tREAL), program.locsize,
  1017.                     t.parSize * ORD((t.call IN PROG.callee_clean_up) OR (t.call IN {PROG.systemv, PROG._systemv})));
  1018.                 enter.param2 := program.locsize;
  1019.                 checklex(parser, SCAN.lxEND)
  1020.             ELSE
  1021.                 proc.proc.leave := IL.LeaveC()
  1022.             END;
  1023.  
  1024.             IF program.target.sys = mConst.Target_iMSP430 THEN
  1025.                 check((enter.param2 * ORD(~codeProc) + proc.type.parSize) * 2 + 16 < program.target.options.ram, pos1, 63)
  1026.             END
  1027.         END;
  1028.  
  1029.         IF parser.sym = SCAN.lxEND THEN
  1030.             ExpectSym(parser, SCAN.lxIDENT);
  1031.             getpos(parser, pos);
  1032.             endname := parser.lex.ident;
  1033.             IF ~codeProc & (import = NIL) THEN
  1034.                 check(endname = name, pos, 60);
  1035.                 ExpectSym(parser, SCAN.lxSEMI);
  1036.                 Next(parser)
  1037.             ELSE
  1038.                 IF endname = parser.unit.name THEN
  1039.                     ExpectSym(parser, SCAN.lxPOINT);
  1040.                     Next(parser);
  1041.                     endmod := TRUE
  1042.                 ELSIF endname = name THEN
  1043.                     ExpectSym(parser, SCAN.lxSEMI);
  1044.                     Next(parser)
  1045.                 ELSE
  1046.                     error(pos, 60)
  1047.                 END
  1048.             END
  1049.         END;
  1050.  
  1051.         IF ~codeProc & (import = NIL) THEN
  1052.             variables := LISTS.create(NIL);
  1053.         ELSE
  1054.             variables := NIL
  1055.         END;
  1056.  
  1057.         PROG.closeScope(unit, variables);
  1058.  
  1059.         IF ~codeProc & (import = NIL) THEN
  1060.             enter.variables := variables
  1061.         END
  1062.  
  1063.         RETURN endmod
  1064.     END ProcDeclaration;
  1065.  
  1066.  
  1067. BEGIN
  1068.     IF parser.sym = SCAN.lxCONST THEN
  1069.         Next(parser);
  1070.         WHILE parser.sym = SCAN.lxIDENT DO
  1071.             ConstTypeDeclaration(parser, TRUE)
  1072.         END
  1073.     END;
  1074.  
  1075.     IF parser.sym = SCAN.lxTYPE THEN
  1076.         Next(parser);
  1077.         WHILE parser.sym = SCAN.lxIDENT DO
  1078.             ConstTypeDeclaration(parser, FALSE)
  1079.         END
  1080.     END;
  1081.  
  1082.     ptr := PROG.linkPtr(parser.unit);
  1083.     IF ptr # NIL THEN
  1084.         pos.line := ptr.pos.line;
  1085.         pos.col  := ptr.pos.col;
  1086.         pos.parser := parser;
  1087.         IF ptr.notRecord THEN
  1088.             error(pos, 58)
  1089.         ELSE
  1090.             error(pos, 48)
  1091.         END
  1092.     END;
  1093.  
  1094.     IF parser.sym = SCAN.lxVAR THEN
  1095.         Next(parser);
  1096.         IF parser.sym = SCAN.lxIDENT THEN
  1097.             VarDeclaration(parser)
  1098.         END
  1099.     END;
  1100.  
  1101.     endmod := FALSE;
  1102.     WHILE ~endmod & (parser.sym = SCAN.lxPROCEDURE) DO
  1103.         Next(parser);
  1104.         endmod := ProcDeclaration(parser)
  1105.     END
  1106.  
  1107.     RETURN endmod
  1108. END DeclarationSequence;
  1109.  
  1110.  
  1111. PROCEDURE parse (parser: PARSER);
  1112. VAR
  1113.     unit:     PROG.UNIT;
  1114.     label:    INTEGER;
  1115.     name:     INTEGER;
  1116.     endmod:   BOOLEAN;
  1117.     errlabel: INTEGER;
  1118.     errno:    INTEGER;
  1119.  
  1120. BEGIN
  1121.     ASSERT(parser # NIL);
  1122.     ASSERT(parser.scanner # NIL);
  1123.  
  1124.     ExpectSym(parser, SCAN.lxMODULE);
  1125.     ExpectSym(parser, SCAN.lxIDENT);
  1126.  
  1127.     IF ~parser.main THEN
  1128.         check1(parser.lex.s = parser.modname, parser, 23)
  1129.     END;
  1130.  
  1131.     unit := PROG.newUnit(program, parser.lex.ident);
  1132.  
  1133.     parser.unit := unit;
  1134.  
  1135.     ExpectSym(parser, SCAN.lxSEMI);
  1136.  
  1137.     Next(parser);
  1138.     IF parser.sym = SCAN.lxIMPORT THEN
  1139.         ImportList(parser)
  1140.     END;
  1141.  
  1142.     CONSOLE.String("compiling "); CONSOLE.String(unit.name.s);
  1143.     IF parser.unit.sysimport THEN
  1144.         CONSOLE.String(" (SYSTEM)")
  1145.     END;
  1146.     CONSOLE.Ln;
  1147.  
  1148.     label := IL.NewLabel();
  1149.     IL.AddJmpCmd(IL.opJMP, label);
  1150.  
  1151.     name := IL.putstr(unit.name.s);
  1152.  
  1153.     errlabel := IL.NewLabel();
  1154.     IL.SetLabel(errlabel);
  1155.     IL.StrAdr(name);
  1156.     IL.Param1;
  1157.     IL.AddCmd0(IL.opERR);
  1158.  
  1159.     FOR errno := 1 TO LEN(IL.codes.errlabels) - 1 DO
  1160.         IL.SetErrLabel(errno);
  1161.         IL.AddCmd(IL.opPUSHC, errno);
  1162.         IL.AddJmpCmd(IL.opJMP, errlabel)
  1163.     END;
  1164.  
  1165.     endmod := DeclarationSequence(parser);
  1166.  
  1167.     IL.SetLabel(label);
  1168.  
  1169.     IF ~endmod THEN
  1170.  
  1171.         IF parser.sym = SCAN.lxBEGIN THEN
  1172.             Next(parser);
  1173.             parser.StatSeq(parser)
  1174.         END;
  1175.  
  1176.         checklex(parser, SCAN.lxEND);
  1177.  
  1178.         ExpectSym(parser, SCAN.lxIDENT);
  1179.         check1(parser.lex.s = unit.name.s, parser, 25);
  1180.         ExpectSym(parser, SCAN.lxPOINT)
  1181.  
  1182.     END;
  1183.  
  1184.     PROG.closeUnit(unit)
  1185. END parse;
  1186.  
  1187.  
  1188. PROCEDURE open (parser: PARSER; modname: ARRAY OF CHAR): BOOLEAN;
  1189. BEGIN
  1190.     ASSERT(parser # NIL);
  1191.  
  1192.     STRINGS.append(parser.fname, modname);
  1193.     STRINGS.append(parser.fname, parser.ext);
  1194.     STRINGS.append(parser.modname, modname);
  1195.  
  1196.     parser.scanner := SCAN.open(parser.fname)
  1197.  
  1198.     RETURN parser.scanner # NIL
  1199. END open;
  1200.  
  1201.  
  1202. PROCEDURE NewParser (): PARSER;
  1203. VAR
  1204.     pars:  PARSER;
  1205.     citem: C.ITEM;
  1206.  
  1207. BEGIN
  1208.     citem := C.pop(parsers);
  1209.     IF citem = NIL THEN
  1210.         NEW(pars)
  1211.     ELSE
  1212.         pars := citem(PARSER)
  1213.     END
  1214.  
  1215.     RETURN pars
  1216. END NewParser;
  1217.  
  1218.  
  1219. PROCEDURE create* (path, lib_path: PATH; StatSeq: STATPROC; expression, designator: EXPRPROC; chkreturn: RETPROC): PARSER;
  1220. VAR
  1221.     parser: PARSER;
  1222.  
  1223. BEGIN
  1224.     parser := NewParser();
  1225.  
  1226.     parser.path     := path;
  1227.     parser.lib_path := lib_path;
  1228.     parser.ext      := mConst.FILE_EXT;
  1229.     parser.fname    := path;
  1230.     parser.modname  := "";
  1231.     parser.scanner  := NIL;
  1232.     parser.unit     := NIL;
  1233.     parser.constexp := FALSE;
  1234.     parser.main     := FALSE;
  1235.  
  1236.     parser.open       := open;
  1237.     parser.parse      := parse;
  1238.     parser.StatSeq    := StatSeq;
  1239.     parser.expression := expression;
  1240.     parser.designator := designator;
  1241.     parser.chkreturn  := chkreturn;
  1242.     parser.create     := create
  1243.  
  1244.     RETURN parser
  1245. END create;
  1246.  
  1247.  
  1248. PROCEDURE init* (bit_depth, target: INTEGER; options: PROG.OPTIONS);
  1249. BEGIN
  1250.     program := PROG.create(bit_depth, target, options);
  1251.     parsers := C.create()
  1252. END init;
  1253.  
  1254.  
  1255. END PARS.