| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397 |
- (*
- BSD 2-Clause License
- Copyright (c) 2018-2022, Anton Krotov
- All rights reserved.
- *)
- MODULE PARS;
- IMPORT PROG, SCAN, ARITH, STRINGS, ERRORS, LISTS, IL, CONSOLE, PATHS, UTILS,
- C := COLLECTIONS, TARGETS, THUMB, MSP430;
- CONST
- eCONST* = 1; eTYPE* = 2; eVAR* = 3; eEXPR* = 4;
- eVREC* = 5; ePROC* = 6; eVPAR* = 7; ePARAM* = 8;
- eSTPROC* = 9; eSTFUNC* = 10; eSYSFUNC* = 11; eSYSPROC* = 12;
- eIMP* = 13;
- TYPE
- PATH* = PATHS.PATH;
- PARSER* = POINTER TO rPARSER;
- POSITION* = RECORD (SCAN.POSITION)
- parser*: PARSER
- END;
- EXPR* = RECORD
- obj*: INTEGER;
- _type*: PROG._TYPE;
- value*: ARITH.VALUE;
- stproc*: INTEGER;
- readOnly*: BOOLEAN;
- ident*: PROG.IDENT
- END;
- STATPROC = PROCEDURE (parser: PARSER);
- EXPRPROC = PROCEDURE (parser: PARSER; VAR e: EXPR);
- RETPROC = PROCEDURE (parser: PARSER; e: EXPR; t: PROG._TYPE; pos: POSITION): BOOLEAN;
- rPARSER = RECORD (C.ITEM)
- fname*: PATH;
- path: PATH;
- lib_path: PATH;
- ext: PATH;
- modname: PATH;
- scanner: SCAN.SCANNER;
- lex*: SCAN.LEX;
- sym*: INTEGER;
- unit*: PROG.UNIT;
- constexp*: BOOLEAN;
- main*: BOOLEAN;
- open*: PROCEDURE (parser: PARSER; modname, FileExt: ARRAY OF CHAR): BOOLEAN;
- parse*: PROCEDURE (parser: PARSER);
- StatSeq*: STATPROC;
- expression*: EXPRPROC;
- designator*: EXPRPROC;
- chkreturn: RETPROC;
- create*: PROCEDURE (path, lib_path: PATH; StatSeq: STATPROC; expression, designator: EXPRPROC; chkreturn: RETPROC): PARSER
- END;
- VAR
- parsers: C.COLLECTION;
- lines*, modules: INTEGER;
- PROCEDURE destroy* (VAR parser: PARSER);
- BEGIN
- IF parser.scanner # NIL THEN
- SCAN.close(parser.scanner)
- END;
- C.push(parsers, parser);
- parser := NIL
- END destroy;
- PROCEDURE getpos (parser: PARSER; VAR pos: POSITION);
- BEGIN
- pos.line := parser.lex.pos.line;
- pos.col := parser.lex.pos.col;
- pos.parser := parser
- END getpos;
- PROCEDURE error* (pos: POSITION; errno: INTEGER);
- BEGIN
- ERRORS.ErrorMsg(pos.parser.fname, pos.line, pos.col, errno)
- END error;
- PROCEDURE check* (condition: BOOLEAN; pos: POSITION; errno: INTEGER);
- BEGIN
- IF ~condition THEN
- error(pos, errno)
- END
- END check;
- PROCEDURE check1* (condition: BOOLEAN; parser: PARSER; errno: INTEGER);
- VAR
- pos: POSITION;
- BEGIN
- IF ~condition THEN
- getpos(parser, pos);
- error(pos, errno)
- END
- END check1;
- PROCEDURE Next* (parser: PARSER);
- VAR
- errno: INTEGER;
- BEGIN
- SCAN.Next(parser.scanner, parser.lex);
- errno := parser.lex.error;
- IF errno = 0 THEN
- IF (TARGETS.RealSize = 0) & (parser.lex.sym = SCAN.lxFLOAT) THEN
- errno := -SCAN.lxERROR13
- ELSIF (TARGETS.BitDepth = 16) & (parser.lex.sym = SCAN.lxCHAR) & (parser.lex.value.typ = ARITH.tWCHAR) THEN
- errno := -SCAN.lxERROR10
- END
- END;
- IF errno # 0 THEN
- check1(FALSE, parser, errno)
- END;
- parser.sym := parser.lex.sym
- END Next;
- PROCEDURE NextPos (parser: PARSER; VAR pos: POSITION);
- BEGIN
- Next(parser);
- getpos(parser, pos)
- END NextPos;
- PROCEDURE checklex* (parser: PARSER; sym: INTEGER);
- VAR
- err: INTEGER;
- BEGIN
- IF parser.sym # sym THEN
- CASE sym OF
- |SCAN.lxCOMMA: err := 65
- |SCAN.lxRROUND: err := 33
- |SCAN.lxPOINT: err := 26
- |SCAN.lxIDENT: err := 22
- |SCAN.lxRSQUARE: err := 71
- |SCAN.lxRCURLY: err := 35
- |SCAN.lxUNDEF: err := 34
- |SCAN.lxTHEN: err := 88
- |SCAN.lxEND: err := 27
- |SCAN.lxDO: err := 89
- |SCAN.lxUNTIL: err := 90
- |SCAN.lxCOLON: err := 53
- |SCAN.lxOF: err := 67
- |SCAN.lxASSIGN: err := 96
- |SCAN.lxTO: err := 57
- |SCAN.lxLROUND: err := 64
- |SCAN.lxEQ: err := 32
- |SCAN.lxSEMI: err := 24
- |SCAN.lxRETURN: err := 38
- |SCAN.lxMODULE: err := 21
- END;
- check1(FALSE, parser, err)
- END
- END checklex;
- PROCEDURE ExpectSym* (parser: PARSER; sym: INTEGER);
- BEGIN
- Next(parser);
- checklex(parser, sym)
- END ExpectSym;
- PROCEDURE ImportList (parser: PARSER);
- VAR
- fname, path, ext, _name: PATH;
- name: SCAN.IDENT;
- parser2: PARSER;
- pos: POSITION;
- alias, _in: BOOLEAN;
- unit: PROG.UNIT;
- ident: PROG.IDENT;
- BEGIN
- alias := FALSE;
- REPEAT
- ExpectSym(parser, SCAN.lxIDENT);
- name := parser.lex.ident;
- getpos(parser, pos);
- IF ~alias THEN
- ident := PROG.addIdent(parser.unit, name, PROG.idMODULE);
- check(ident # NIL, pos, 30)
- END;
- Next(parser);
- path := parser.path;
- fname := "";
- ext := UTILS.FILE_EXT;
- COPY(name.s, _name);
- _in := FALSE;
- IF parser.sym = SCAN.lxIN THEN
- _in := TRUE;
- Next(parser);
- IF parser.sym = SCAN.lxSTRING THEN
- STRINGS.trim(parser.lex.string.s, fname)
- ELSIF parser.sym = SCAN.lxCHAR THEN
- fname[0] := CHR(ARITH.Int(parser.lex.value));
- fname[1] := 0X
- ELSE
- check1(FALSE, parser, 117)
- END;
- STRINGS.replace(fname, "/", UTILS.slash);
- STRINGS.replace(fname, "\", UTILS.slash);
- PATHS.DelSlashes(fname);
- PATHS.split(fname, path, _name, ext);
- IF PATHS.isRelative(path) THEN
- PATHS.RelPath(parser.path, path, fname);
- STRINGS.append(fname, _name);
- STRINGS.append(fname, ext);
- PATHS.split(fname, path, _name, ext)
- END;
- Next(parser)
- END;
- IF (parser.sym = SCAN.lxCOMMA) OR (parser.sym = SCAN.lxSEMI) THEN
- alias := FALSE;
- IF (fname = "") & ((_name = "SYSTEM") OR PROG.LowerCase & (_name = "system")) THEN
- unit := PROG.program.sysunit
- ELSE
- IF fname # "" THEN
- unit := PROG.getUnit(fname)
- ELSE
- fname := path;
- STRINGS.append(fname, _name);
- STRINGS.append(fname, UTILS.FILE_EXT);
- unit := PROG.getUnit(fname);
- IF unit = NIL THEN
- fname := parser.lib_path;
- STRINGS.append(fname, _name);
- STRINGS.append(fname, UTILS.FILE_EXT);
- unit := PROG.getUnit(fname)
- END
- END
- END;
- IF unit # NIL THEN
- check(unit.closed, pos, 31)
- ELSE
- parser2 := parser.create(path, parser.lib_path,
- parser.StatSeq, parser.expression, parser.designator, parser.chkreturn);
- IF ~parser2.open(parser2, _name, ext) THEN
- IF (path # parser.lib_path) & ~_in THEN
- destroy(parser2);
- parser2 := parser.create(parser.lib_path, parser.lib_path,
- parser.StatSeq, parser.expression, parser.designator, parser.chkreturn);
- check(parser2.open(parser2, _name, ext), pos, 29)
- ELSE
- error(pos, 29)
- END
- END;
- parser2.parse(parser2);
- unit := parser2.unit;
- unit.fname := parser2.fname;
- destroy(parser2)
- END;
- IF unit = PROG.program.sysunit THEN
- parser.unit.sysimport := TRUE
- END;
- ident.unit := unit
- ELSIF parser.sym = SCAN.lxASSIGN THEN
- alias := TRUE
- ELSE
- check1(FALSE, parser, 28)
- END
- UNTIL parser.sym = SCAN.lxSEMI;
- Next(parser)
- END ImportList;
- PROCEDURE QIdent (parser: PARSER; forward: BOOLEAN): PROG.IDENT;
- VAR
- ident: PROG.IDENT;
- unit: PROG.UNIT;
- BEGIN
- ASSERT(parser.sym = SCAN.lxIDENT);
- ident := PROG.getIdent(parser.unit, parser.lex.ident, FALSE);
- IF ~forward THEN
- check1(ident # NIL, parser, 48)
- END;
- IF (ident # NIL) & (ident.typ = PROG.idMODULE) THEN
- unit := ident.unit;
- ExpectSym(parser, SCAN.lxPOINT);
- ExpectSym(parser, SCAN.lxIDENT);
- ident := PROG.getIdent(unit, parser.lex.ident, FALSE);
- check1((ident # NIL) & ident.export, parser, 48)
- END
- RETURN ident
- END QIdent;
- PROCEDURE strcmp* (VAR v: ARITH.VALUE; v2: ARITH.VALUE; operator: INTEGER);
- VAR
- str: SCAN.TEXTSTR;
- string1, string2: SCAN.STRING;
- bool: BOOLEAN;
- BEGIN
- IF v.typ = ARITH.tCHAR THEN
- ASSERT(v2.typ = ARITH.tSTRING);
- ARITH.charToStr(v, str);
- string1 := SCAN.enterStr(str);
- string2 := v2.string(SCAN.STRING)
- END;
- IF v2.typ = ARITH.tCHAR THEN
- ASSERT(v.typ = ARITH.tSTRING);
- ARITH.charToStr(v2, str);
- string2 := SCAN.enterStr(str);
- string1 := v.string(SCAN.STRING)
- END;
- IF v.typ = v2.typ THEN
- string1 := v.string(SCAN.STRING);
- string2 := v2.string(SCAN.STRING)
- END;
- CASE operator OF
- |SCAN.lxEQ: bool := string1.s = string2.s
- |SCAN.lxNE: bool := string1.s # string2.s
- |SCAN.lxLT: bool := string1.s < string2.s
- |SCAN.lxGT: bool := string1.s > string2.s
- |SCAN.lxLE: bool := string1.s <= string2.s
- |SCAN.lxGE: bool := string1.s >= string2.s
- END;
- ARITH.setbool(v, bool)
- END strcmp;
- PROCEDURE ConstExpression* (parser: PARSER; VAR v: ARITH.VALUE);
- VAR
- e: EXPR;
- pos: POSITION;
- BEGIN
- getpos(parser, pos);
- parser.constexp := TRUE;
- parser.expression(parser, e);
- parser.constexp := FALSE;
- check(e.obj = eCONST, pos, 62);
- v := e.value
- END ConstExpression;
- PROCEDURE FieldList (parser: PARSER; rec: PROG._TYPE);
- VAR
- name: SCAN.IDENT;
- export: BOOLEAN;
- pos: POSITION;
- BEGIN
- ASSERT(parser.sym = SCAN.lxIDENT);
- WHILE parser.sym = SCAN.lxIDENT DO
- getpos(parser, pos);
- name := parser.lex.ident;
- Next(parser);
- export := parser.sym = SCAN.lxMUL;
- IF export THEN
- check1(parser.unit.scopeLvl = 0, parser, 61);
- Next(parser)
- END;
- check(PROG.addField(rec, name, export), pos, 30);
- IF parser.sym = SCAN.lxCOMMA THEN
- ExpectSym(parser, SCAN.lxIDENT)
- ELSE
- checklex(parser, SCAN.lxCOLON)
- END
- END
- END FieldList;
- PROCEDURE FormalParameters (parser: PARSER; _type: PROG._TYPE);
- VAR
- ident: PROG.IDENT;
- PROCEDURE FPSection (parser: PARSER; _type: PROG._TYPE);
- VAR
- ident: PROG.IDENT;
- exit: BOOLEAN;
- vPar: BOOLEAN;
- dim: INTEGER;
- t0, t1: PROG._TYPE;
- pos: POSITION;
- BEGIN
- vPar := parser.sym = SCAN.lxVAR;
- IF vPar THEN
- Next(parser)
- END;
- checklex(parser, SCAN.lxIDENT);
- exit := FALSE;
- WHILE (parser.sym = SCAN.lxIDENT) & ~exit DO
- check1(PROG.addParam(_type, parser.lex.ident, vPar), parser, 30);
- Next(parser);
- IF parser.sym = SCAN.lxCOMMA THEN
- ExpectSym(parser, SCAN.lxIDENT)
- ELSIF parser.sym = SCAN.lxCOLON THEN
- Next(parser);
- getpos(parser, pos);
- dim := 0;
- WHILE parser.sym = SCAN.lxARRAY DO
- INC(dim);
- check1(dim <= PROG.MAXARRDIM, parser, 84);
- ExpectSym(parser, SCAN.lxOF);
- Next(parser)
- END;
- checklex(parser, SCAN.lxIDENT);
- ident := QIdent(parser, FALSE);
- check1(ident.typ = PROG.idTYPE, parser, 68);
- t0 := ident._type;
- t1 := t0;
- WHILE dim > 0 DO
- t1 := PROG.enterType(PROG.tARRAY, -1, 0, parser.unit);
- t1.base := t0;
- t0 := t1;
- DEC(dim)
- END;
- IF _type.call IN {PROG.fastcall, PROG._fastcall} THEN
- check(t1.typ # PROG.tREAL, pos, 126)
- END;
- PROG.setParams(_type, t1);
- Next(parser);
- exit := TRUE
- ELSE
- checklex(parser, SCAN.lxCOLON)
- END
- END
- END FPSection;
- BEGIN
- IF parser.sym = SCAN.lxLROUND THEN
- Next(parser);
- IF (parser.sym = SCAN.lxVAR) OR (parser.sym = SCAN.lxIDENT) THEN
- FPSection(parser, _type);
- WHILE parser.sym = SCAN.lxSEMI DO
- Next(parser);
- FPSection(parser, _type)
- END
- END;
- checklex(parser, SCAN.lxRROUND);
- Next(parser);
- IF parser.sym = SCAN.lxCOLON THEN
- ExpectSym(parser, SCAN.lxIDENT);
- ident := QIdent(parser, FALSE);
- check1(ident.typ = PROG.idTYPE, parser, 68);
- check1(~(ident._type.typ IN {PROG.tRECORD, PROG.tARRAY}), parser, 69);
- check1( ~(ODD(_type.call) & (ident._type.typ = PROG.tREAL)), parser, 113);
- _type.base := ident._type;
- Next(parser)
- ELSE
- _type.base := NIL
- END
- END
- END FormalParameters;
- PROCEDURE sysflag (parser: PARSER; proc: BOOLEAN): INTEGER;
- VAR
- res, sf: INTEGER;
- BEGIN
- checklex(parser, SCAN.lxIDENT);
- IF parser.lex.ident.s = "stdcall" THEN
- sf := PROG.sf_stdcall
- ELSIF parser.lex.ident.s = "cdecl" THEN
- sf := PROG.sf_cdecl
- ELSIF parser.lex.ident.s = "ccall" THEN
- sf := PROG.sf_ccall
- ELSIF parser.lex.ident.s = "win64" THEN
- sf := PROG.sf_win64
- ELSIF parser.lex.ident.s = "systemv" THEN
- sf := PROG.sf_systemv
- ELSIF parser.lex.ident.s = "windows" THEN
- sf := PROG.sf_windows
- ELSIF parser.lex.ident.s = "linux" THEN
- sf := PROG.sf_linux
- ELSIF parser.lex.ident.s = "code" THEN
- sf := PROG.sf_code
- ELSIF parser.lex.ident.s = "oberon" THEN
- sf := PROG.sf_oberon
- ELSIF parser.lex.ident.s = "fastcall" THEN
- sf := PROG.sf_fastcall
- ELSIF parser.lex.ident.s = "noalign" THEN
- sf := PROG.sf_noalign
- ELSE
- check1(FALSE, parser, 124)
- END;
- check1(sf IN PROG.program.sysflags, parser, 125);
- IF proc THEN
- check1(sf IN PROG.proc_flags, parser, 123)
- ELSE
- check1(sf IN PROG.rec_flags, parser, 123)
- END;
- CASE sf OF
- |PROG.sf_stdcall:
- res := PROG.stdcall
- |PROG.sf_cdecl:
- res := PROG.cdecl
- |PROG.sf_ccall:
- IF TARGETS.OS IN {TARGETS.osWIN32, TARGETS.osLINUX32, TARGETS.osKOS} THEN
- res := PROG.ccall
- ELSIF TARGETS.OS = TARGETS.osWIN64 THEN
- res := PROG.win64
- ELSIF TARGETS.OS = TARGETS.osLINUX64 THEN
- res := PROG.systemv
- END
- |PROG.sf_win64:
- res := PROG.win64
- |PROG.sf_systemv:
- res := PROG.systemv
- |PROG.sf_code:
- res := PROG.code
- |PROG.sf_fastcall:
- res := PROG.fastcall
- |PROG.sf_oberon:
- IF TARGETS.OS IN {TARGETS.osWIN32, TARGETS.osLINUX32, TARGETS.osKOS} THEN
- res := PROG.default32
- ELSIF TARGETS.OS IN {TARGETS.osWIN64, TARGETS.osLINUX64} THEN
- res := PROG.default64
- END
- |PROG.sf_windows:
- IF TARGETS.OS = TARGETS.osWIN32 THEN
- res := PROG.stdcall
- ELSIF TARGETS.OS = TARGETS.osWIN64 THEN
- res := PROG.win64
- END
- |PROG.sf_linux:
- IF TARGETS.OS = TARGETS.osLINUX32 THEN
- res := PROG.ccall
- ELSIF TARGETS.OS = TARGETS.osLINUX64 THEN
- res := PROG.systemv
- END
- |PROG.sf_noalign:
- res := PROG.noalign
- END
- RETURN res
- END sysflag;
- PROCEDURE procflag (parser: PARSER; VAR _import: IL.IMPORT_PROC; isProc: BOOLEAN): INTEGER;
- VAR
- call: INTEGER;
- dll, proc: SCAN.TEXTSTR;
- pos: POSITION;
- PROCEDURE getStr (parser: PARSER; VAR name: SCAN.TEXTSTR);
- VAR
- pos: POSITION;
- str: ARITH.VALUE;
- BEGIN
- getpos(parser, pos);
- ConstExpression(parser, str);
- IF str.typ = ARITH.tSTRING THEN
- name := str.string(SCAN.STRING).s
- ELSIF str.typ = ARITH.tCHAR THEN
- ARITH.charToStr(str, name)
- ELSE
- check(FALSE, pos, 117)
- END
- END getStr;
- BEGIN
- _import := NIL;
- IF parser.sym = SCAN.lxLSQUARE THEN
- getpos(parser, pos);
- check1(parser.unit.sysimport, parser, 54);
- Next(parser);
- call := sysflag(parser, TRUE);
- Next(parser);
- IF parser.sym = SCAN.lxMINUS THEN
- Next(parser);
- INC(call)
- END;
- IF isProc & (parser.sym = SCAN.lxCOMMA) THEN
- Next(parser);
- getStr(parser, dll);
- STRINGS.UpCase(dll);
- checklex(parser, SCAN.lxCOMMA);
- Next(parser);
- getStr(parser, proc);
- _import := IL.AddImp(dll, proc)
- END;
- checklex(parser, SCAN.lxRSQUARE);
- Next(parser)
- ELSE
- CASE TARGETS.BitDepth OF
- |16: call := PROG.default16
- |32: IF TARGETS.CPU = TARGETS.cpuX86 THEN
- call := PROG.default32
- ELSE
- call := PROG.cdecl
- END
- |64: IF TARGETS.CPU = TARGETS.cpuAMD64 THEN
- call := PROG.default64
- ELSE
- call := PROG.cdecl
- END
- END
- END;
- IF _import # NIL THEN
- check(TARGETS.Import, pos, 70)
- END
- RETURN call
- END procflag;
- PROCEDURE _type (parser: PARSER; VAR t: PROG._TYPE; flags: SET);
- CONST
- comma = 0;
- closed = 1;
- forward = 2;
- VAR
- arrLen: ARITH.VALUE;
- typeSize: ARITH.VALUE;
- ident: PROG.IDENT;
- unit: PROG.UNIT;
- pos, pos2: POSITION;
- fieldType: PROG._TYPE;
- baseIdent: SCAN.IDENT;
- a, b: INTEGER;
- RecFlag: INTEGER;
- _import: IL.IMPORT_PROC;
- BEGIN
- unit := parser.unit;
- t := NIL;
- IF parser.sym = SCAN.lxIDENT THEN
- ident := QIdent(parser, forward IN flags);
- IF ident # NIL THEN
- check1(ident.typ = PROG.idTYPE, parser, 49);
- t := ident._type;
- check1(t # NIL, parser, 50);
- IF closed IN flags THEN
- check1(t.closed, parser, 50)
- END
- END;
- Next(parser)
- ELSIF (parser.sym = SCAN.lxARRAY) OR ((parser.sym = SCAN.lxCOMMA) & (comma IN flags)) THEN
- IF parser.sym = SCAN.lxARRAY THEN
- getpos(parser, pos2)
- END;
- NextPos(parser, pos);
- ConstExpression(parser, arrLen);
- check(arrLen.typ = ARITH.tINTEGER, pos, 43);
- check(ARITH.check(arrLen), pos, 39);
- check(ARITH.getInt(arrLen) > 0, pos, 51);
- t := PROG.enterType(PROG.tARRAY, -1, ARITH.getInt(arrLen), unit);
- IF parser.sym = SCAN.lxCOMMA THEN
- _type(parser, t.base, {comma, closed})
- ELSIF parser.sym = SCAN.lxOF THEN
- Next(parser);
- _type(parser, t.base, {closed})
- ELSE
- check1(FALSE, parser, 47)
- END;
- t.align := t.base.align;
- a := t.length;
- b := t.base.size;
- check(ARITH.mulInt(a, b), pos2, 104);
- check(ARITH.setInt(typeSize, a), pos2, 104);
- t.size := a;
- t.closed := TRUE
- ELSIF parser.sym = SCAN.lxRECORD THEN
- getpos(parser, pos2);
- Next(parser);
- t := PROG.enterType(PROG.tRECORD, 0, 0, unit);
- t.align := 1;
- IF parser.sym = SCAN.lxLSQUARE THEN
- check1(parser.unit.sysimport, parser, 54);
- Next(parser);
- RecFlag := sysflag(parser, FALSE);
- t.noalign := RecFlag = PROG.noalign;
- ExpectSym(parser, SCAN.lxRSQUARE);
- Next(parser)
- END;
- IF parser.sym = SCAN.lxLROUND THEN
- check1(~t.noalign, parser, 111);
- ExpectSym(parser, SCAN.lxIDENT);
- getpos(parser, pos);
- _type(parser, t.base, {closed});
- check(t.base.typ IN {PROG.tRECORD, PROG.tPOINTER}, pos, 52);
- IF t.base.typ = PROG.tPOINTER THEN
- t.base := t.base.base;
- check(t.base # NIL, pos, 55)
- END;
- check(~t.base.noalign, pos, 112);
- checklex(parser, SCAN.lxRROUND);
- Next(parser);
- t.size := t.base.size;
- IF t.base.align > t.align THEN
- t.align := t.base.align
- END
- ELSE
- t.base := PROG.program.stTypes.tANYREC
- END;
- WHILE parser.sym = SCAN.lxIDENT DO
- FieldList(parser, t);
- ASSERT(parser.sym = SCAN.lxCOLON);
- Next(parser);
- _type(parser, fieldType, {closed});
- check(PROG.setFields(t, fieldType), pos2, 104);
- IF (fieldType.align > t.align) & ~t.noalign THEN
- t.align := fieldType.align
- END;
- IF parser.sym = SCAN.lxSEMI THEN
- ExpectSym(parser, SCAN.lxIDENT)
- ELSE
- checklex(parser, SCAN.lxEND)
- END
- END;
- t.closed := TRUE;
- IL.AddRec(t.base.num);
- IF ~t.noalign THEN
- check(UTILS.Align(t.size, t.align), pos2, 104);
- check(ARITH.setInt(typeSize, t.size), pos2, 104)
- END;
- checklex(parser, SCAN.lxEND);
- Next(parser)
- ELSIF parser.sym = SCAN.lxPOINTER THEN
- ExpectSym(parser, SCAN.lxTO);
- Next(parser);
- t := PROG.enterType(PROG.tPOINTER, TARGETS.AdrSize, 0, unit);
- t.align := TARGETS.AdrSize;
- getpos(parser, pos);
- IF parser.sym = SCAN.lxIDENT THEN
- baseIdent := parser.lex.ident
- END;
- _type(parser, t.base, {forward});
- IF t.base # NIL THEN
- check(t.base.typ = PROG.tRECORD, pos, 58)
- ELSE
- PROG.frwPtr(unit, t, baseIdent, pos)
- END
- ELSIF parser.sym = SCAN.lxPROCEDURE THEN
- NextPos(parser, pos);
- t := PROG.enterType(PROG.tPROCEDURE, TARGETS.AdrSize, 0, unit);
- t.align := TARGETS.AdrSize;
- t.call := procflag(parser, _import, FALSE);
- FormalParameters(parser, t)
- ELSE
- check1(FALSE, parser, 49)
- END
- END _type;
- PROCEDURE IdentDef (parser: PARSER; typ: INTEGER; VAR name: SCAN.IDENT): PROG.IDENT;
- VAR
- ident: PROG.IDENT;
- pos: POSITION;
- BEGIN
- ASSERT(parser.sym = SCAN.lxIDENT);
- name := parser.lex.ident;
- getpos(parser, pos);
- ident := PROG.addIdent(parser.unit, name, typ);
- check(ident # NIL, pos, 30);
- ident.pos := pos;
- Next(parser);
- IF parser.sym = SCAN.lxMUL THEN
- check1(ident.global, parser, 61);
- ident.export := TRUE;
- Next(parser)
- END
- RETURN ident
- END IdentDef;
- PROCEDURE ConstTypeDeclaration (parser: PARSER; _const: BOOLEAN);
- VAR
- ident: PROG.IDENT;
- name: SCAN.IDENT;
- pos: POSITION;
- BEGIN
- IF _const THEN
- ident := IdentDef(parser, PROG.idNONE, name)
- ELSE
- ident := IdentDef(parser, PROG.idTYPE, name)
- END;
- checklex(parser, SCAN.lxEQ);
- NextPos(parser, pos);
- IF _const THEN
- ConstExpression(parser, ident.value);
- IF ident.value.typ = ARITH.tINTEGER THEN
- check(ARITH.check(ident.value), pos, 39)
- ELSIF ident.value.typ = ARITH.tREAL THEN
- check(ARITH.check(ident.value), pos, 40)
- END;
- ident.typ := PROG.idCONST;
- ident._type := PROG.getType(ident.value.typ)
- ELSE
- _type(parser, ident._type, {})
- END;
- checklex(parser, SCAN.lxSEMI);
- Next(parser)
- END ConstTypeDeclaration;
- PROCEDURE VarDeclaration (parser: PARSER);
- VAR
- ident: PROG.IDENT;
- name: SCAN.IDENT;
- t: PROG._TYPE;
- BEGIN
- REPEAT
- ident := IdentDef(parser, PROG.idVAR, name);
- IF parser.sym = SCAN.lxCOMMA THEN
- ExpectSym(parser, SCAN.lxIDENT)
- ELSIF parser.sym = SCAN.lxCOLON THEN
- Next(parser);
- _type(parser, t, {});
- PROG.setVarsType(parser.unit, t);
- checklex(parser, SCAN.lxSEMI);
- Next(parser)
- ELSE
- checklex(parser, SCAN.lxCOLON)
- END
- UNTIL parser.sym # SCAN.lxIDENT
- END VarDeclaration;
- PROCEDURE DeclarationSequence (parser: PARSER): BOOLEAN;
- VAR
- ptr: PROG.FRWPTR;
- endmod: BOOLEAN;
- pos: POSITION;
- PROCEDURE ProcDeclaration (parser: PARSER): BOOLEAN;
- VAR
- proc: PROG.IDENT;
- endname,
- name: SCAN.IDENT;
- param: PROG.PARAM;
- unit: PROG.UNIT;
- ident: PROG.IDENT;
- e: EXPR;
- pos, pos1,
- pos2: POSITION;
- label: INTEGER;
- enter: IL.COMMAND;
- call: INTEGER;
- t: PROG._TYPE;
- _import: IL.IMPORT_PROC;
- endmod, b: BOOLEAN;
- fparams: SET;
- int, flt: INTEGER;
- comma: BOOLEAN;
- code, iv: ARITH.VALUE;
- codeProc,
- handler: BOOLEAN;
- line: INTEGER;
- BEGIN
- endmod := FALSE;
- handler := FALSE;
- unit := parser.unit;
- call := procflag(parser, _import, TRUE);
- getpos(parser, pos);
- pos1 := pos;
- checklex(parser, SCAN.lxIDENT);
- line := pos.line;
- IF _import # NIL THEN
- proc := IdentDef(parser, PROG.idIMP, name);
- proc._import := _import;
- IF _import.name = "" THEN
- COPY(name.s, _import.name)
- END;
- PROG.program.procs.last(PROG.PROC)._import := _import
- ELSE
- proc := IdentDef(parser, PROG.idPROC, name)
- END;
- check(PROG.openScope(unit, proc.proc), pos, 116);
- proc._type := PROG.enterType(PROG.tPROCEDURE, TARGETS.AdrSize, 0, unit);
- t := proc._type;
- t.align := TARGETS.AdrSize;
- t.call := call;
- FormalParameters(parser, t);
- IF parser.sym = SCAN.lxLSQUARE THEN
- getpos(parser, pos2);
- check((TARGETS.CPU = TARGETS.cpuTHUMB) & (TARGETS.OS = TARGETS.osNONE), pos2, 24);
- Next(parser);
- getpos(parser, pos2);
- ConstExpression(parser, iv);
- check(iv.typ = ARITH.tINTEGER, pos2, 43);
- check((0 <= ARITH.Int(iv)) & (ARITH.Int(iv) <= THUMB.maxIVT), pos2, 46);
- check(THUMB.SetIV(ARITH.Int(iv)), pos2, 121);
- checklex(parser, SCAN.lxRSQUARE);
- Next(parser);
- handler := TRUE
- END;
- codeProc := call IN {PROG.code, PROG._code};
- IF call IN {PROG.systemv, PROG._systemv} THEN
- check(t.parSize <= PROG.MAXSYSVPARAM, pos, 120)
- END;
- param := t.params.first(PROG.PARAM);
- WHILE param # NIL DO
- ident := PROG.addIdent(unit, param.name, PROG.idPARAM);
- ASSERT(ident # NIL);
- ident._type := param._type;
- ident.offset := param.offset;
- IF param.vPar THEN
- ident.typ := PROG.idVPAR
- END;
- param := param.next(PROG.PARAM)
- END;
- IF _import = NIL THEN
- label := IL.NewLabel();
- proc.proc.label := label;
- proc.proc.used := handler;
- IF handler THEN
- IL.AddCmd2(IL.opHANDLER, label, ARITH.Int(iv))
- END
- END;
- IF codeProc THEN
- enter := IL.EnterC(label);
- comma := FALSE;
- WHILE (parser.sym # SCAN.lxSEMI) OR comma DO
- getpos(parser, pos2);
- ConstExpression(parser, code);
- check(code.typ = ARITH.tINTEGER, pos2, 43);
- IF TARGETS.WordSize > TARGETS.InstrSize THEN
- CASE TARGETS.InstrSize OF
- |1: check(ARITH.range(code, 0, 255), pos, 42)
- |2: check(ARITH.range(code, 0, 65535), pos, 110)
- END
- END;
- IL.AddCmd(IL.opCODE, ARITH.getInt(code));
- comma := parser.sym = SCAN.lxCOMMA;
- IF comma THEN
- Next(parser)
- ELSE
- checklex(parser, SCAN.lxSEMI)
- END
- END
- END;
- checklex(parser, SCAN.lxSEMI);
- Next(parser);
- IF _import = NIL THEN
- IF parser.main & proc.export & TARGETS.Dll THEN
- IF TARGETS.target = TARGETS.KolibriOSDLL THEN
- check((proc.name.s # "lib_init") & (proc.name.s # "version"), pos, 114)
- END;
- IL.AddExp(label, proc.name.s);
- proc.proc.used := TRUE
- END;
- IF ~codeProc THEN
- b := DeclarationSequence(parser)
- END;
- PROG.ResetLocSize;
- IF call IN {PROG._win64, PROG.win64} THEN
- fparams := PROG.getFloatParamsPos(proc._type, 3, int, flt);
- enter := IL.Enter(label, LSL(ORD(fparams), 5) + MIN(proc._type.parSize, 4))
- ELSIF call IN {PROG._systemv, PROG.systemv} THEN
- fparams := PROG.getFloatParamsPos(proc._type, PROG.MAXSYSVPARAM - 1, int, flt);
- enter := IL.Enter(label, -(LSL(ORD(fparams), 5) + proc._type.parSize))
- ELSIF codeProc THEN
- ELSIF call IN {PROG.fastcall, PROG._fastcall} THEN
- enter := IL.Enter(label, proc._type.parSize)
- ELSE
- enter := IL.Enter(label, 0)
- END;
- proc.proc.enter := enter;
- IF ~codeProc & (parser.sym = SCAN.lxBEGIN) THEN
- Next(parser);
- parser.StatSeq(parser)
- END;
- IF ~codeProc & (t.base # NIL) THEN
- checklex(parser, SCAN.lxRETURN);
- NextPos(parser, pos);
- parser.expression(parser, e);
- check(parser.chkreturn(parser, e, t.base, pos), pos, 87)
- END;
- IF ~codeProc THEN
- proc.proc.leave := IL.Leave(t.base # NIL, (t.base # NIL) & (t.base.typ = PROG.tREAL), PROG.program.locsize,
- t.parSize * ORD((t.call IN PROG.callee_clean_up) OR (t.call IN {PROG.systemv, PROG._systemv})));
- enter.param2 := PROG.program.locsize;
- checklex(parser, SCAN.lxEND)
- ELSE
- proc.proc.leave := IL.LeaveC()
- END;
- IF (TARGETS.CPU = TARGETS.cpuMSP430) & ~codeProc THEN
- check(MSP430.CheckProcDataSize(enter.param2 + proc._type.parSize, PROG.program.options.ram), pos1, 63);
- enter.param2 := enter.param2 * 65536 + line;
- enter.param3 := IL.codes.errlabels[10]
- END
- END;
- IF parser.sym = SCAN.lxEND THEN
- Next(parser);
- IF parser.sym = SCAN.lxIDENT THEN
- getpos(parser, pos);
- endname := parser.lex.ident;
- IF ~codeProc & (_import = NIL) THEN
- check(PROG.IdEq(endname, name), pos, 60);
- ExpectSym(parser, SCAN.lxSEMI);
- Next(parser)
- ELSE
- IF PROG.IdEq(endname, parser.unit.name) THEN
- ExpectSym(parser, SCAN.lxPOINT);
- Next(parser);
- endmod := TRUE
- ELSIF PROG.IdEq(endname, name) THEN
- ExpectSym(parser, SCAN.lxSEMI);
- Next(parser)
- ELSE
- error(pos, 60)
- END
- END
- ELSIF parser.sym = SCAN.lxSEMI THEN
- Next(parser)
- ELSE
- checklex(parser, SCAN.lxIDENT)
- END
- END;
- PROG.closeScope(unit);
- RETURN endmod
- END ProcDeclaration;
- BEGIN
- IF parser.sym = SCAN.lxCONST THEN
- Next(parser);
- WHILE parser.sym = SCAN.lxIDENT DO
- ConstTypeDeclaration(parser, TRUE)
- END
- END;
- IF parser.sym = SCAN.lxTYPE THEN
- Next(parser);
- WHILE parser.sym = SCAN.lxIDENT DO
- ConstTypeDeclaration(parser, FALSE)
- END
- END;
- ptr := PROG.linkPtr(parser.unit);
- IF ptr # NIL THEN
- pos.line := ptr.pos.line;
- pos.col := ptr.pos.col;
- pos.parser := parser;
- IF ptr.notRecord THEN
- error(pos, 58)
- ELSE
- error(pos, 48)
- END
- END;
- IF parser.sym = SCAN.lxVAR THEN
- Next(parser);
- IF parser.sym = SCAN.lxIDENT THEN
- VarDeclaration(parser)
- END
- END;
- endmod := FALSE;
- WHILE ~endmod & (parser.sym = SCAN.lxPROCEDURE) DO
- Next(parser);
- endmod := ProcDeclaration(parser)
- END
- RETURN endmod
- END DeclarationSequence;
- PROCEDURE parse (parser: PARSER);
- VAR
- unit: PROG.UNIT;
- label: INTEGER;
- name: INTEGER;
- endmod: BOOLEAN;
- errlabel: INTEGER;
- errno: INTEGER;
- ident: PROG.IDENT;
- BEGIN
- ASSERT(parser # NIL);
- ASSERT(parser.scanner # NIL);
- ExpectSym(parser, SCAN.lxMODULE);
- ExpectSym(parser, SCAN.lxIDENT);
- IF ~parser.main THEN
- check1(parser.lex.ident.s = parser.modname, parser, 23)
- END;
- unit := PROG.newUnit(parser.lex.ident);
- unit.fname := parser.fname;
- parser.unit := unit;
- ExpectSym(parser, SCAN.lxSEMI);
- Next(parser);
- IF parser.sym = SCAN.lxIMPORT THEN
- ImportList(parser)
- END;
- INC(modules);
- CONSOLE.String("compiling ");
- CONSOLE.String("("); CONSOLE.Int(modules); CONSOLE.String(") ");
- CONSOLE.String(unit.name.s);
- IF unit.sysimport THEN
- CONSOLE.String(" (SYSTEM)")
- END;
- CONSOLE.Ln;
- IF PROG.program.options.uses THEN
- ident := unit.idents.first(PROG.IDENT);
- WHILE ident # NIL DO
- IF (ident.typ = PROG.idMODULE) & (ident.unit # PROG.program.sysunit) THEN
- CONSOLE.String(" "); CONSOLE.String(ident.unit.fname); CONSOLE.Ln
- END;
- ident := ident.next(PROG.IDENT)
- END;
- CONSOLE.Ln
- END;
- IF TARGETS.CPU IN {TARGETS.cpuX86, TARGETS.cpuAMD64} THEN
- IL.fname(parser.fname)
- END;
- label := IL.NewLabel();
- IL.Jmp(IL.opJMP, label);
- name := IL.putstr(unit.name.s);
- errlabel := IL.NewLabel();
- IL.SetLabel(errlabel);
- IL.StrAdr(name);
- IL.Param1;
- IL.AddCmd(IL.opPUSHC, modules);
- IL.AddCmd0(IL.opERR);
- FOR errno := 1 TO LEN(IL.codes.errlabels) - 1 DO
- IL.SetErrLabel(errno);
- IL.AddCmd(IL.opPUSHC, errno);
- IL.Jmp(IL.opJMP, errlabel)
- END;
- endmod := DeclarationSequence(parser);
- IL.SetLabel(label);
- IF ~endmod THEN
- IF parser.sym = SCAN.lxBEGIN THEN
- Next(parser);
- parser.StatSeq(parser)
- END;
- checklex(parser, SCAN.lxEND);
- ExpectSym(parser, SCAN.lxIDENT);
- check1(parser.lex.ident.s = unit.name.s, parser, 25);
- ExpectSym(parser, SCAN.lxPOINT)
- END;
- INC(lines, parser.lex.pos.line);
- PROG.closeUnit(unit)
- END parse;
- PROCEDURE open (parser: PARSER; modname, FileExt: ARRAY OF CHAR): BOOLEAN;
- BEGIN
- ASSERT(parser # NIL);
- STRINGS.append(parser.fname, modname);
- STRINGS.append(parser.fname, FileExt);
- STRINGS.append(parser.modname, modname);
- parser.scanner := SCAN.open(parser.fname)
- RETURN parser.scanner # NIL
- END open;
- PROCEDURE NewParser (): PARSER;
- VAR
- pars: PARSER;
- citem: C.ITEM;
- BEGIN
- citem := C.pop(parsers);
- IF citem = NIL THEN
- NEW(pars)
- ELSE
- pars := citem(PARSER)
- END
- RETURN pars
- END NewParser;
- PROCEDURE create* (path, lib_path: PATH; StatSeq: STATPROC; expression, designator: EXPRPROC; chkreturn: RETPROC): PARSER;
- VAR
- parser: PARSER;
- BEGIN
- parser := NewParser();
- parser.path := path;
- parser.lib_path := lib_path;
- parser.ext := UTILS.FILE_EXT;
- parser.fname := path;
- parser.modname := "";
- parser.scanner := NIL;
- parser.unit := NIL;
- parser.constexp := FALSE;
- parser.main := FALSE;
- parser.open := open;
- parser.parse := parse;
- parser.StatSeq := StatSeq;
- parser.expression := expression;
- parser.designator := designator;
- parser.chkreturn := chkreturn;
- parser.create := create
- RETURN parser
- END create;
- PROCEDURE init* (options: PROG.OPTIONS);
- BEGIN
- PROG.create(options);
- parsers := C.create();
- lines := 0;
- modules := 0
- END init;
- END PARS.
|