123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493 |
- MODULE FoxParser; (** AUTHOR "fof & fn"; PURPOSE "Oberon Compiler: Parser"; **)
- (* (c) fof ETH Zurich, 2009 *)
- IMPORT Basic := FoxBasic, Scanner := FoxScanner, D := Debugging, SyntaxTree := FoxSyntaxTree, Global := FoxGlobal, Diagnostics, Streams, Strings, StringPool;
- CONST
- Trace = FALSE;
- CascadedWithSupport = TRUE;
- (** the parser reflects the following EBNF:
- Module = ('module' | 'cellnet' [Flags]) Identifier ['in' Identifier]';'
- {ImportList} DeclarationSequence [Body]
- 'end' Identifier '.'.
- ImportList = 'import' Import { ',' Import } ';'.
- Import = Identifier [':=' Identifier] ['in' Identifier].
- DeclarationSequence = {
- 'const' [ConstDeclaration] {';' [ConstDeclaration]}
- |'type' [TypeDeclaration] {';' [TypeDeclaration]}
- |'var' [VariableDeclaration] {';' [VariableDeclaration]}
- | ProcedureDeclaration
- | OperatorDeclaration
- | ';'
- }
- Declaration = IdentifierDefinition '=' Expression.
- TypeDeclaration = IdentifierDefinition '=' Type.
- VariableDeclaration = VariableNameList ':' Type.
- VariableNameList = IdentifierDefinition [Flags] [':=' Expression | 'extern' String] {',' IdentifierDefinition [Flags] [':=' Expression | 'extern' String] }.
- OperatorDeclaration = 'operator' [Flags] ['-'] String ['*'|'-'] FormalParameters ';'
- DeclarationSequence [Body] 'end' String.
- ProcedureDeclaration = 'procedure' ['^'|'&'|'~'|'-'|Flags ['-']] IdentifierDefinition [FormalParameters]';'
- DeclarationSequence [Body] 'end' Identifier.
- Flags = '{' [Identifier ['(' Expression ')'|'=' Expression] {',' Identifier ['(' Expression ')' | '=' Expression ] } ] '}'.
- FormalParameters = '(' [ParameterDeclaration {';' ParameterDeclaration}] ')' [':' [Flags] Type].
- ParameterDeclaration = ['var'|'const'] Identifier [Flags] ['= Expression] {',' Identifier [Flags] ['= Expression]}':' Type.
- PortList = '(' [PortDeclaration {';' PortDeclaration}] ')'.
- PortDeclaration = Identifier [Flags] {',' Identifier [Flags]}':' Type.
- Type = ArrayType | RecordType | PointerType | ObjectType | CellType | CellnetType | PortType
- | ProcedureType | EnumerationType | QualifiedIdentifier.
- PortType = 'port' ('in'|'out') ['(' Expression ')']
- EnumerationType = 'enum' ['('QualifiedIdentifier')'] IdentifierDefinition ['=' Expression]
- {',' IdentifierDefinition ['=' Expression]} 'end'.
- ArrayType = 'array' 'of' Type | 'array' Expression {',' Expression} 'of' Type
- | 'array' '[' MathArraySize {',' MathArraySize} ']' ['of' Type].
- MathArraySize = Expression | '*' | '?'.
- RecordType = 'record' [Flags] ['(' QualifiedIdentifier ')'] [VariableDeclaration {';' VariableDeclaration}] 'end'.
- PointerType = 'pointer' [Flags] 'to' Type.
- CellType = 'cell' [Flags] [PortList] [';'] DeclarationSequence [Body] 'end' [Identifier].
- ObjectType = 'object' | 'object' [Flags] ['(' (QualifiedIdentifier | ArrayType) ')'] DeclarationSequence [Body] 'end' [Identifier] .
- ProcedureType = 'procedure' [Flags] [FormalParameters].
- Body = 'begin' [Flags] StatementSequence ['finally' StatementSequence]
- | 'code' Code.
- Code = { any \ 'end' \ 'with' } ['with' {('in'|'out') StatementSequence}] .
- StatementBlock = [Flags] StatementSequence.
- StatementSequence = Statement {';' Statement}.
- Statement =
- [
- Designator [':=' Expression |'!' Expression | '?' Expression | '<<' Expresssion | '>>' Expression]
- | 'if' Expression 'then' StatementSequence
- {'elsif' Expression 'then' StatementSequence}
- ['else' StatementSequence]
- 'end'
- | 'with' Identifier ':' QualifiedIdentifier 'do' StatementSequence
- {['|' Identifier ':'] QualifiedIdentifier 'do' StatementSequence}
- [else StatementSequence]
- 'end'
- | 'case' Expression 'of' ['|'] Case {'|' Case} ['else' StatementSequence] 'end'
- | 'while' Expression 'do' StatementSequence 'end'
- | 'repeat' StatementSequence 'until' Expression
- | 'for' Identifier ':=' Expression 'to' Expression ['by' Expression] 'do'
- StatementSequence 'end'
- | 'loop' StatementSequence 'end'
- | 'exit'
- | 'return' [Expression]
- | 'await' Expression
- | 'begin' StatementBlock 'end'
- | 'code' {any} 'end'
- ].
- Case = RangeExpression {',' RangeExpression} ':' StatementSequence.
- Expression = RangeExpression [RelationOp RangeExpression].
- RelationOp = '=' | '.=' | '#' | '.#'
- | '<' | '.<' | '<=' | '.<=' | '>' | '.>' | '>=' | '.>='
- | '??' | '!!' | '<<?' | '>>?'
- | 'in' | 'is'
- SimpleExpression = ['+'|'-'] Term {AddOp Term}.
- AddOp = '+' | '-' | 'or'.
- Term = Factor {MulOp Factor}.
- MulOp = '*' | '**' | '.*' | '+*' | '/' | '\' | './' | 'div' | 'mod' | '&'.
- Factor = Number | Character | String | 'nil' | 'imag' | 'true' | 'false' | Set
- | '(' Expression ')' | '~' Factor | Factor '`' | Designator | MathArray.
- | 'SIZE' 'OF' Designator | 'ADDRESS' 'OF' Designator
- MathArray = '[' Expression {',' Expression} ']'.
- Set = '{' [ RangeExpression {',' RangeExpression} ] '}'.
- Designator = ('self' | 'result' | Identifier)
- {'.' Identifier | '[' IndexList ']' | '(' [ExpressionList] ')' | '^'} [Flags].
- RangeExpression = SimpleExpression | [SimpleExpression] '..' [SimpleExpression] ['by' SimpleExpression] | '*'.
- IndexList = '?' [',' ExpressionList ] | ExpressionList [',' '?'].
- ExpressionList = Expression { ',' Expression }.
- IdentifierDefinition = Identifier [ '*' | '-' ].
- QualifiedIdentifier = Identifier ['.' Identifier].
- Identifier = Letter {Letter | Digit | '_'}.
- Letter = 'A' | 'B' | .. | 'Z' | 'a' | 'b' | .. | 'z'.
- String = '"' {Character} '"' | "'" {Character} "'".
- Number = Integer | Real.
- Integer = Digit {Digit} | '0' 'x' {HexDigit} | Digit {HexDigit} 'H' .
- Real = Digit {Digit} '.' {Digit} [ScaleFactor].
- ScaleFactor = ('E' | 'D') ['+' | '-'] digit {digit}.
- HexDigit = Digit | 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
- Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' .
- **)
- TYPE
- Position*=Scanner.Position;
- Parser* = OBJECT
- VAR scanner-: Scanner.Scanner;
- token-: Scanner.Token;
- diagnostics: Diagnostics.Diagnostics;
- currentScope: SyntaxTree.Scope;
- recentCommentItem: ANY; recentLine: LONGINT;
- recentComment: SyntaxTree.Comment;
- moduleScope: SyntaxTree.ModuleScope;
- error-: BOOLEAN;
- Lax-: BOOLEAN;
- indent: LONGINT; (* for debugging purposes only *)
- hasToken: BOOLEAN;
- prevPosition-: Position;
- (* conditional compilation *)
- CONST Processing = 0; ProcessingElse = 1; Skipping = 2; Ignoring = 3; IgnoringElse = 4;
- VAR conditional: WORD;
- VAR conditionals: ARRAY 10 OF WORD;
- VAR definitions: ARRAY 10 OF Scanner.IdentifierType;
- VAR conditionalCount, definitionCount: SIZE;
- PROCEDURE S( CONST s: ARRAY OF CHAR ); (* for debugging purposes only *)
- VAR i: LONGINT;
- BEGIN
- D.Ln; INC( indent ); D.Int( indent,1 );
- FOR i := 1 TO indent DO D.Str( " " ); END;
- D.Str( "start: " ); D.Str( s ); D.Str( " at pos " ); D.Int( token.position.start,1 );
- END S;
- PROCEDURE E( CONST s: ARRAY OF CHAR ); (* for debugging purposes only *)
- VAR i: LONGINT;
- BEGIN
- D.Ln; D.Int( indent,1 );
- FOR i := 1 TO indent DO D.Str( " " ); END;
- D.Str( "end : " ); D.Str( s ); D.Str( " at pos " ); D.Int( token.position.start,1 );
- DEC(indent);
- END E;
- PROCEDURE EE( CONST s, t: ARRAY OF CHAR ); (* for debugging purposes only *)
- VAR i: LONGINT;
- BEGIN
- D.Ln; D.Int( indent,1 );
- FOR i := 1 TO indent DO D.Str( " " ); END;
- D.Str( "end : " ); D.Str( s ); D.Str( " (" ); D.Str( t ); D.Str( ") at pos " );
- DEC(indent);
- END EE;
- (** constructor, init parser with scanner providing input and with diagnostics for error output *)
- PROCEDURE & Init*( scanner: Scanner.Scanner; diagnostics: Diagnostics.Diagnostics; CONST definitions: ARRAY OF CHAR );
- VAR begin, end: LONGINT (* SIZE! *); definition: ARRAY 32 OF CHAR;
- BEGIN
- conditional := Processing;
- conditionalCount := 0;
- definitionCount := 0;
- begin := 0;
- REPEAT
- end := Strings.Find (definitions, begin, ',');
- IF end # -1 THEN
- Strings.Copy (definitions, begin, end - begin, definition);
- begin := end + 1;
- ELSE
- Strings.Copy (definitions, begin, Strings.Length (definitions) - begin, definition);
- END;
- IF definition # "" THEN
- StringPool.GetIndex (definition, SELF.definitions[definitionCount]);
- INC (definitionCount);
- END;
- UNTIL end = -1;
- SELF.scanner := scanner;
- SELF.diagnostics := diagnostics;
- error := ~GetNextToken(token);
- hasToken := TRUE;
- IF error THEN Basic.Error(diagnostics, scanner.source^, Basic.invalidPosition, "no input stream") END;
- recentCommentItem := NIL; recentComment := NIL;
- (* debugging *)
- indent := 0;
- Lax := FALSE;
- END Init;
- PROCEDURE Reset*;
- BEGIN
- error := FALSE;
- END Reset;
- PROCEDURE SetLax*;
- BEGIN
- Lax := TRUE;
- END SetLax;
- (** output error message and / or given code *)
- PROCEDURE Error(position: Position; code: LONGINT; CONST message: ARRAY OF CHAR);
- BEGIN
- Basic.ErrorC(diagnostics, scanner.source^, position, code, message);
- error := TRUE
- END Error;
- (* conditional compilation according to the following syntax *)
- (* Block = '#' 'if' Condition 'then' Block { '#' 'elsif' Condition 'then' Block } ['#' 'else' Block] '#' 'end' | any symbol until next new line. *)
- PROCEDURE GetNextToken(VAR token: Scanner.Token): BOOLEAN;
- VAR line: Streams.Position; end: Scanner.Symbol; startPos, endPos: LONGINT;
- BEGIN
- LOOP
- line := token.position.line;
- IF ~scanner.GetNextToken (token) THEN RETURN FALSE END;
- IF (token.symbol = Scanner.Unequal) & (token.position.line # line) THEN
- IF ~ConditionalStatement (token) THEN RETURN FALSE END;
- ELSIF (conditional = Processing) OR (conditional = ProcessingElse) THEN
- RETURN TRUE;
- ELSIF token.symbol = Scanner.Code THEN
- end := scanner.SkipToEndOfCode(startPos, endPos, token);
- WHILE end = Scanner.Unequal DO
- REPEAT scanner.GetNextCharacter() UNTIL (scanner.ch # Scanner.LF) & (scanner.ch # 0X);
- end := scanner.SkipToEndOfCode(startPos, endPos, token);
- END;
- END;
- END;
- END GetNextToken;
- PROCEDURE ConditionalStatement(VAR token: Scanner.Token): BOOLEAN;
- VAR value: BOOLEAN;
- (* Factor = Identifier | '~' Factor | '(' Condition ')'. *)
- PROCEDURE Factor (VAR value: BOOLEAN): BOOLEAN;
- VAR i: SIZE;
- BEGIN
- IF token.symbol = Scanner.Identifier THEN
- value := FALSE; i := 0;
- WHILE (i # definitionCount) & ~value DO value := token.identifier = definitions[i]; INC (i) END;
- IF ~scanner.GetNextToken (token) THEN RETURN FALSE END;
- ELSIF token.symbol = Scanner.Not THEN
- IF ~scanner.GetNextToken (token) THEN RETURN FALSE END;
- IF ~Factor (value) THEN RETURN FALSE END;
- value := ~value;
- ELSIF token.symbol = Scanner.LeftParenthesis THEN
- IF ~scanner.GetNextToken (token) THEN RETURN FALSE END;
- IF ~Condition (value) THEN RETURN FALSE END;
- IF token.symbol # Scanner.RightParenthesis THEN Error (token.position, Scanner.RightParenthesis, ""); RETURN FALSE END;
- IF ~scanner.GetNextToken (token) THEN RETURN FALSE END;
- ELSE
- Error (token.position, Scanner.Identifier, ""); RETURN FALSE;
- END;
- RETURN TRUE;
- END Factor;
- (* Term = Factor {'&' Factor}. *)
- PROCEDURE Term (VAR value: BOOLEAN): BOOLEAN;
- VAR next: BOOLEAN;
- BEGIN
- IF ~Factor (value) THEN RETURN FALSE END;
- WHILE token.symbol = Scanner.And DO
- IF ~scanner.GetNextToken (token) THEN RETURN FALSE END;
- IF ~Factor (next) THEN RETURN FALSE END;
- IF ~next THEN value := FALSE END;
- END;
- RETURN TRUE;
- END Term;
- (* Condition = Term {'or' Term}. *)
- PROCEDURE Condition (VAR value: BOOLEAN): BOOLEAN;
- VAR next: BOOLEAN;
- BEGIN
- IF ~Term (value) THEN RETURN FALSE END;
- WHILE token.symbol = Scanner.Or DO
- IF ~scanner.GetNextToken (token) THEN RETURN FALSE END;
- IF ~Term (next) THEN RETURN FALSE END;
- IF next THEN value := TRUE END;
- END;
- RETURN TRUE;
- END Condition;
- BEGIN
- IF ~scanner.GetNextToken (token) THEN RETURN FALSE END;
- IF token.symbol = Scanner.If THEN
- IF ~scanner.GetNextToken (token) THEN RETURN FALSE END;
- IF ~Condition (value) THEN RETURN FALSE END;
- IF token.symbol # Scanner.Then THEN Error (token.position, Scanner.Then, ""); RETURN FALSE END;
- conditionals[conditionalCount] := conditional; INC (conditionalCount);
- IF (conditional # Processing) & (conditional # ProcessingElse) THEN conditional := Ignoring;
- ELSIF value THEN conditional := Processing ELSE conditional := Skipping;
- END;
- ELSIF token.symbol = Scanner.Elsif THEN
- IF ~scanner.GetNextToken (token) THEN RETURN FALSE END;
- IF ~Condition (value) THEN RETURN FALSE END;
- IF token.symbol # Scanner.Then THEN Error (token.position, Scanner.Then, ""); RETURN FALSE END;
- IF (conditional = Processing) & (conditionalCount # 0) OR (conditional = Ignoring) THEN conditional := Ignoring;
- ELSIF conditional = Skipping THEN IF value THEN conditional := Processing ELSE conditional := Skipping END;
- ELSE Error(token.position,Basic.InvalidCode,"invalid conditional elsif"); RETURN FALSE END;
- ELSIF token.symbol = Scanner.Else THEN
- IF (conditional = Processing) & (conditionalCount # 0) OR (conditional = Ignoring) THEN conditional := IgnoringElse;
- ELSIF conditional = Skipping THEN conditional := ProcessingElse;
- ELSE Error(token.position,Basic.InvalidCode,"invalid conditional else"); RETURN FALSE END;
- ELSIF token.symbol = Scanner.End THEN
- IF conditionalCount # 0 THEN DEC (conditionalCount); conditional := conditionals[conditionalCount];
- ELSE Error(token.position,Basic.InvalidCode,"invalid conditional end"); RETURN FALSE END;
- ELSE
- Error(token.position,Basic.InvalidCode,"invalid conditional statement"); RETURN FALSE;
- END;
- RETURN TRUE;
- END ConditionalStatement;
- (** helper procedures interfacing to the scanner **)
- PROCEDURE SkipComments(b: BOOLEAN);
- VAR comment: SyntaxTree.Comment;
- BEGIN
- WHILE ~error & (b & (TokenB()= Scanner.Comment) OR ~b & (Symbol() = Scanner.Comment)) DO
- comment := SyntaxTree.NewComment(token.position, currentScope, token.string^,token.stringLength);
- IF moduleScope # NIL THEN
- moduleScope.AddComment(comment);
- END;
- IF recentComment = NIL THEN
- recentComment := comment;
- IF token.position.line = recentLine THEN
- IF recentCommentItem # NIL THEN
- IF (recentCommentItem IS SyntaxTree.Symbol) THEN
- IF recentCommentItem(SyntaxTree.Symbol).comment = NIL THEN
- recentCommentItem(SyntaxTree.Symbol).SetComment(comment)
- END;
- ELSIF (recentCommentItem IS SyntaxTree.Statement) THEN
- IF recentCommentItem(SyntaxTree.Statement).comment = NIL THEN
- recentCommentItem(SyntaxTree.Statement).SetComment(comment)
- END;
- ELSIF (recentCommentItem IS SyntaxTree.IfPart) THEN
- IF recentCommentItem(SyntaxTree.IfPart).comment = NIL THEN
- recentCommentItem(SyntaxTree.IfPart).SetComment(comment)
- END;
- ELSIF (recentCommentItem IS SyntaxTree.CasePart) THEN
- IF recentCommentItem(SyntaxTree.CasePart).comment = NIL THEN
- recentCommentItem(SyntaxTree.CasePart).SetComment(comment)
- END;
- ELSIF (recentCommentItem IS SyntaxTree.WithPart) THEN
- IF recentCommentItem(SyntaxTree.WithPart).comment = NIL THEN
- recentCommentItem(SyntaxTree.WithPart).SetComment(comment)
- END;
- END;
- comment.SetItem(recentCommentItem,TRUE);
- recentComment := NIL;
- recentCommentItem := NIL
- END;
- END;
- END;
- NextToken;
- (*error := ~GetNextToken(token);*)
- END;
- END SkipComments;
- (** Get next token from scanner and store it in object-local variable 'token' *)
- PROCEDURE NextToken*;
- BEGIN
- (*
- error := ~GetNextToken(token) OR error;
- hasToken := TRUE;
- SkipComments();
- *)
- hasToken := FALSE;
- END NextToken;
- PROCEDURE Symbol*(): LONGINT;
- BEGIN
- IF ~hasToken OR (token.symbol = Scanner.Escape) THEN
- prevPosition := token.position;
- error := ~GetNextToken(token) OR error;
- IF token.symbol = Scanner.Escape THEN
- error := ~GetNextToken(token) OR error;
- END;
- hasToken := TRUE;
- SkipComments(FALSE);
- END;
- RETURN token.symbol;
- END Symbol;
- (* stop on escape symbol *)
- PROCEDURE TokenB*(): LONGINT;
- BEGIN
- IF ~hasToken THEN
- prevPosition := token.position;
- error := ~GetNextToken(token) OR error;
- hasToken := TRUE;
- SkipComments(TRUE);
- END;
- RETURN token.symbol;
- END TokenB;
- (** Check if current token equals sym. If yes then return true, return false otherwise *)
- PROCEDURE PeekB*(symbol: Scanner.Symbol): BOOLEAN;
- BEGIN
- RETURN TokenB() = symbol
- END PeekB;
- (** Check if current token equals sym. If yes then return true, return false otherwise *)
- PROCEDURE Peek*(symbol: Scanner.Symbol): BOOLEAN;
- BEGIN
- SkipComments(FALSE);
- RETURN Symbol() = symbol
- END Peek;
- (** Check if the current token equals sym.If yes then read next token, report error otherwise. returns success value *)
- PROCEDURE Mandatory*( symbol: Scanner.Symbol): BOOLEAN;
- BEGIN
- ASSERT( symbol # Scanner.Identifier ); ASSERT( symbol # Scanner.String ); ASSERT( symbol # Scanner.Number ); (* because of NextToken ! *)
- IF ~Peek(symbol) THEN
- Error( token.position, symbol, "" );
- RETURN FALSE
- ELSE
- NextToken;
- RETURN TRUE
- END
- END Mandatory;
- (** Check if the current token equals sym. If yes then read next token, report error otherwise *)
- PROCEDURE Check( symbol: Scanner.Symbol );
- VAR b: BOOLEAN;
- BEGIN
- b := Mandatory( symbol );
- END Check;
- (** Check if current token is an identifier. If yes then copy identifier to name and get next token,
- report error otherwise and set name to empty name. returns success value *)
- PROCEDURE MandatoryIdentifier( VAR name: SyntaxTree.Identifier): BOOLEAN;
- BEGIN
- IF Peek(Scanner.Identifier) THEN
- name := token.identifier;
- NextToken;
- RETURN TRUE
- ELSE
- Error( token.position, Scanner.Identifier, "" );
- name := SyntaxTree.invalidIdentifier;
- RETURN FALSE
- END
- END MandatoryIdentifier;
- (** Expect an identifier (using MandatoryIdentifier) and return identifier object **)
- PROCEDURE Identifier(VAR position: Position): SyntaxTree.Identifier;
- VAR name: SyntaxTree.Identifier; identifier: SyntaxTree.Identifier;
- BEGIN
- position := token.position;
- IF MandatoryIdentifier(name) THEN
- position := token.position;
- identifier := name;
- ELSE
- identifier := SyntaxTree.invalidIdentifier;
- END;
- RETURN identifier
- END Identifier;
- (** Check if current token is a string (or string-like character). If yes then copy identifier to name and get next token,
- report error otherwise and set name to empty name. returns success value*)
- PROCEDURE MandatoryString*( VAR name: Scanner.StringType ): BOOLEAN;
- BEGIN
- IF Peek( Scanner.String) THEN
- name := token.string;
- NextToken;
- RETURN TRUE
- ELSIF Peek( Scanner.Character) THEN (* for compatibility with release: characters treated as strings *)
- name := token.string;
- NextToken;
- RETURN TRUE
- ELSE
- Error( token.position, Scanner.String, "" );
- NEW(name,1); name^ := "";
- RETURN FALSE
- END
- END MandatoryString;
- (** Check if current token is an identifier and if the name matches. If yes then get next token, report error otherwise. returns success value*)
- PROCEDURE ExpectThisIdentifier( name: SyntaxTree.Identifier ): BOOLEAN;
- VAR string: ARRAY 64 OF CHAR;
- BEGIN
- IF name = SyntaxTree.invalidIdentifier THEN (* nothing to be expected *)
- RETURN TRUE
- ELSIF (Symbol() # Scanner.Identifier) OR (token.identifier # name) THEN
- Basic.GetString(name,string);
- Error( token.position, Scanner.Identifier, string );
- RETURN FALSE
- ELSE
- NextToken;
- RETURN TRUE
- END
- END ExpectThisIdentifier;
- (** Check if current token is an identifier and if the name matches. If yes then get next token, report error otherwise. returns success value*)
- PROCEDURE ExpectThisString( CONST name: ARRAY OF CHAR ): BOOLEAN;
- BEGIN
- IF Peek(Scanner.String) & (token.string^ = name) THEN
- NextToken;
- RETURN TRUE
- ELSE
- Error( token.position, Scanner.String, name );
- RETURN FALSE
- END
- END ExpectThisString;
- (** Check if current token equals sym. If yes then get next token, return false otherwise *)
- PROCEDURE Optional*( symbol: Scanner.Symbol ): BOOLEAN;
- BEGIN
- (* do not use for Identifier, String or Number, if the result is needed ! *)
- IF Peek(symbol) THEN
- NextToken;
- RETURN TRUE
- ELSE
- RETURN FALSE
- END
- END Optional;
- PROCEDURE OptionalB*( symbol: Scanner.Symbol ): BOOLEAN;
- BEGIN
- (* do not use for Identifier, String or Number, if the result is needed ! *)
- IF PeekB(symbol) THEN
- NextToken;
- RETURN TRUE
- ELSE
- RETURN FALSE
- END
- END OptionalB;
- (* ignore one ore more tokens of type symbol *)
- PROCEDURE Ignore(symbol: Scanner.Symbol);
- BEGIN WHILE Optional(symbol) DO END;
- END Ignore;
- (** Parsing according to the EBNF **)
- (** QualifiedIdentifier = Identifier ['.' Identifier]. **)
- PROCEDURE QualifiedIdentifier*( ): SyntaxTree.QualifiedIdentifier;
- VAR prefix,suffix: SyntaxTree.Identifier; qualifiedIdentifier: SyntaxTree.QualifiedIdentifier; position0,position1: Position;
- BEGIN
- IF Trace THEN S( "QualifiedIdentifier" ) END;
- prefix := Identifier(position0);
- IF prefix # SyntaxTree.invalidIdentifier THEN
- IF ~Optional( Scanner.Period )THEN
- suffix := prefix; prefix := SyntaxTree.invalidIdentifier; (* empty *)
- ELSE
- suffix := Identifier(position1);
- END;
- qualifiedIdentifier := SyntaxTree.NewQualifiedIdentifier( position0, prefix,suffix);
- ELSE
- qualifiedIdentifier := SyntaxTree.invalidQualifiedIdentifier;
- END;
- IF Trace THEN E( "QualifiedIdentifier" ) END;
- RETURN qualifiedIdentifier
- END QualifiedIdentifier;
- (** IdentifierDefinition = Identifier [ '*' | '-' ]. **)
- PROCEDURE IdentifierDefinition( VAR name: SyntaxTree.Identifier; VAR access: SET; allowedReadOnly: BOOLEAN);
- VAR position: Position;
- BEGIN
- IF Trace THEN S( "IdentifierDefinition" ) END;
- name := Identifier(position);
- IF Optional( Scanner.Times ) THEN
- access := SyntaxTree.Public + SyntaxTree.Protected + SyntaxTree.Internal;
- ELSIF Optional( Scanner.Minus ) THEN
- IF ~allowedReadOnly THEN
- Error( token.position, Basic.InvalidCode, "may not be defined read-only" )
- ELSE
- access := SyntaxTree.ReadOnly + {SyntaxTree.InternalWrite};
- END;
- ELSE
- access := SyntaxTree.Internal;
- END;
- IF Trace THEN E( "IdentifierDefinition") END;
- END IdentifierDefinition;
- (** ExpressionList = Expression { ',' Expression }. **)
- PROCEDURE ExpressionList( expressionList: SyntaxTree.ExpressionList );
- VAR expression: SyntaxTree.Expression;
- BEGIN
- IF Trace THEN S( "ExpressionList" ) END;
- REPEAT
- expression := Expression();
- expressionList.AddExpression( expression )
- UNTIL ~Optional( Scanner.Comma );
- IF Trace THEN E( "ExpressionList" ) END;
- END ExpressionList;
- (** IndexList = '?' [',' ExpressionList] | Expression { ',' Expression } [',' '?' [',' ExpressionList] ] **)
- PROCEDURE IndexList(expressionList: SyntaxTree.ExpressionList);
- VAR
- position: Position;
- done: BOOLEAN;
- BEGIN
- IF Trace THEN S( "IndexList" ) END;
- position := token.position;
- IF Optional(Scanner.Questionmark) THEN
- expressionList.AddExpression(SyntaxTree.NewTensorRangeExpression(position));
- IF Optional(Scanner.Comma) THEN
- ExpressionList(expressionList);
- END
- ELSE
- expressionList.AddExpression(Expression());
- done := FALSE;
- WHILE ~done DO
- IF Optional(Scanner.Comma) THEN
- IF Optional(Scanner.Questionmark) THEN
- expressionList.AddExpression(SyntaxTree.NewTensorRangeExpression(position));
- IF Optional(Scanner.Comma) THEN
- ExpressionList(expressionList);
- END;
- done := TRUE;
- ELSE
- expressionList.AddExpression(Expression())
- END
- ELSE
- done := TRUE
- END
- END
- END;
- IF Trace THEN E( "IndexList" ) END;
- END IndexList;
- (** RangeExpression = SimpleExpression | [SimpleExpression] '..' [SimpleExpression] ['by' SimpleExpression] | '*'.
- i.e., a RangeExpression can have one of the following forms:
- '*'
- '..' [delimiter]
- '..' 'by' SimpleExpression
- '..' SimpleExpression
- '..' SimpleExpression 'by' SimpleExpression
- SimpleExpression
- SimpleExpression '..' [delimiter]
- SimpleExpression '..' 'by' SimpleExpression
- SimpleExpression '..' SimpleExpression
- SimpleExpression '..' SimpleExpression 'by' SimpleExpression
- a RangeExpression is always delimited by any of the following symbols: ",", ";", ":", "]", ")", "}", "=", "#", "END".
- **)
- PROCEDURE RangeExpression(): SyntaxTree.Expression;
- VAR
- expression, first, last, step: SyntaxTree.Expression;
- position: Position;
- PROCEDURE HasDelimiter(): BOOLEAN;
- BEGIN RETURN
- Peek(Scanner.Comma) OR Peek(Scanner.Semicolon) OR Peek(Scanner.Colon) OR
- Peek(Scanner.RightBracket) OR Peek(Scanner.RightParenthesis) OR Peek(Scanner.RightBrace) OR
- Peek(Scanner.Equal) OR Peek(Scanner.Unequal) OR Peek(Scanner.End)
- END HasDelimiter;
- BEGIN
- IF Trace THEN S( "RangeExpression" ) END;
- position := token.position;
- IF Optional(Scanner.Times) THEN
- expression := SyntaxTree.NewRangeExpression(position, NIL, NIL, NIL)
- ELSIF Optional(Scanner.Upto) THEN
- (* is range expression *)
- first := NIL;
- IF HasDelimiter() THEN
- last := NIL;
- step := NIL
- ELSIF Optional(Scanner.By) THEN
- last := NIL;
- step := SimpleExpression()
- ELSE
- last := SimpleExpression();
- IF Optional(Scanner.By) THEN
- step := SimpleExpression()
- ELSE
- step := NIL
- END
- END;
- expression := SyntaxTree.NewRangeExpression(position, first, last, step)
- ELSE
- expression := SimpleExpression();
- IF OptionalB(Scanner.Upto) THEN
- (* is range expression *)
- first := expression;
- IF HasDelimiter() THEN
- last := NIL;
- step := NIL
- ELSIF Optional(Scanner.By) THEN
- last := NIL;
- step := SimpleExpression()
- ELSE
- last := SimpleExpression();
- IF Optional(Scanner.By) THEN
- step := SimpleExpression()
- ELSE
- step := NIL
- END
- END;
- expression := SyntaxTree.NewRangeExpression(position, first, last, step)
- END;
- END;
- IF Trace THEN E( "RangeExpression" ) END;
- RETURN expression
- END RangeExpression;
- (** Designator = ('self' | 'result' | Identifier)
- {'.' Identifier | '[' IndexList ']' | '(' [ExpressionList] ')' | '^'} [Flags].
- **)
- PROCEDURE Designator( ): SyntaxTree.Designator;
- VAR
- designator: SyntaxTree.Designator; expressionList: SyntaxTree.ExpressionList;
- identifier: SyntaxTree.Identifier; position: Position;
- qualifiedIdentifier: SyntaxTree.QualifiedIdentifier;
- qualifiedType : SyntaxTree.QualifiedType;
- BEGIN
- IF Trace THEN S( "Designator" ) END;
- position := token.position;
- IF Optional(Scanner.Self) THEN
- designator := SyntaxTree.NewSelfDesignator(position);
- ELSIF Optional(Scanner.Result) THEN
- designator := SyntaxTree.NewResultDesignator(position);
- (* ADDRESS AND SIZE can be type identifiers used for type conversion *)
- ELSIF (Symbol() = Scanner.Address) OR (Symbol()=Scanner.Size) THEN
- identifier := token.identifier;
- designator := SyntaxTree.NewIdentifierDesignator(position,identifier);
- NextToken;
- ELSIF (Symbol() = Scanner.New) THEN
- identifier := token.identifier;
- designator := SyntaxTree.NewIdentifierDesignator(position,identifier);
- NextToken;
- IF Symbol() # Scanner.LeftParenthesis THEN (* NEW Type () *)
- qualifiedIdentifier := QualifiedIdentifier();
- qualifiedType := SyntaxTree.NewQualifiedType(qualifiedIdentifier.position, currentScope, qualifiedIdentifier);
- IF Mandatory( Scanner.LeftParenthesis ) THEN
- expressionList := SyntaxTree.NewExpressionList();
- IF ~Optional(Scanner.RightParenthesis) THEN
- ExpressionList( expressionList );
- Check( Scanner.RightParenthesis )
- END;
- END;
- designator := SyntaxTree.NewBuiltinCallDesignator(position,Global.New, NIL, expressionList);
- designator(SyntaxTree.BuiltinCallDesignator).SetReturnType(qualifiedType);
- (* special case: NEW Type() *)
- END;
- ELSE
- identifier := Identifier(position);
- designator := SyntaxTree.NewIdentifierDesignator(position,identifier);
- END;
- designator.End(token.position);
- LOOP
- position := token.position;
- IF OptionalB( Scanner.LeftParenthesis ) THEN
- expressionList := SyntaxTree.NewExpressionList();
- IF ~Optional( Scanner.RightParenthesis ) THEN
- ExpressionList( expressionList );
- Check( Scanner.RightParenthesis )
- END;
- designator := SyntaxTree.NewParameterDesignator( position,designator,expressionList);
- ELSIF OptionalB( Scanner.Period ) THEN
- IF ~Optional(Scanner.Identifier) THEN (* make sure token is read *) END;
- position := token.position;
- CASE token.identifierString[0] OF
- "a".."z", "A" .. "Z":
- (*IF Peek(Scanner.Size) (* special rule: support for SYSTEM.SIZE *) THEN*)
- identifier := token.identifier;
- NextToken;
- ELSE
- identifier := Identifier(position);
- END;
- designator := SyntaxTree.NewSelectorDesignator(position,designator,identifier);
- ELSIF OptionalB( Scanner.LeftBracket ) THEN
- expressionList := SyntaxTree.NewExpressionList();
- IndexList( expressionList );
- Check( Scanner.RightBracket );
- designator:= SyntaxTree.NewBracketDesignator( position,designator,expressionList );
- ELSIF OptionalB( Scanner.Arrow ) THEN
- designator:= SyntaxTree.NewArrowDesignator( position,designator );
- ELSE EXIT
- END;
- designator.End(token.position);
- END;
- IF OptionalB(Scanner.LeftBrace) THEN
- designator.SetModifiers(Flags());
- END;
- designator.End(token.position);
- (*IF OptionalB(Scanner.Escape) THEN END; (* skip breaking signal *)*)
- IF Trace THEN E( "Designator" ) END;
- RETURN designator
- END Designator;
- (** Set = '{' [ RangeExpression {',' RangeExpression} ] '}'. **)
- PROCEDURE Set( ): SyntaxTree.Expression;
- VAR
- set: SyntaxTree.Set;
- BEGIN
- IF Trace THEN S( "Set" ) END;
- set := SyntaxTree.NewSet(token.position);
- Check(Scanner.LeftBrace);
- IF ~Optional(Scanner.RightBrace) THEN
- REPEAT
- set.elements.AddExpression(RangeExpression())
- UNTIL ~Optional(Scanner.Comma);
- Check(Scanner.RightBrace);
- END;
- set.End(token.position);
- IF Trace THEN E( "Set" ) END;
- RETURN set
- END Set;
- (* MathArray = '[' Expression {',' Expression} ']'. *)
- PROCEDURE MathArray(): SyntaxTree.Expression;
- VAR array: SyntaxTree.MathArrayExpression; element: SyntaxTree.Expression;
- BEGIN
- array := SyntaxTree.NewMathArrayExpression(token.position);
- IF ~Optional(Scanner.RightBracket) THEN
- REPEAT
- element := Expression();
- array.elements.AddExpression(element);
- UNTIL ~Optional(Scanner.Comma);
- Check(Scanner.RightBracket);
- END;
- array.End(token.position);
- RETURN array
- END MathArray;
- (** Factor = Number | Character | String | 'nil' | 'imag' | 'true' | 'false' | Set
- | '(' Expression ')' | '~' Factor | Factor '`' | Designator | MathArray.
- | 'SIZE' 'OF' Designator | 'ADDRESS' 'OF' Designator | 'ALIAS' OF Expression
- **)
- PROCEDURE Factor( ): SyntaxTree.Expression;
- VAR factor: SyntaxTree.Expression; position: Position; operator: LONGINT;
- BEGIN
- IF Trace THEN S( "Factor" ) END;
- position := token.position;
- CASE Symbol() OF
- | Scanner.Number:
- IF (token.numberType = Scanner.Integer) THEN
- factor := SyntaxTree.NewIntegerValue( position, token.integer);
- ELSIF (token.numberType = Scanner.Hugeint) THEN
- factor := SyntaxTree.NewIntegerValue(position, token.hugeint);
- ELSIF (token.numberType = Scanner.Real) OR (token.numberType = Scanner.Longreal) THEN
- factor := SyntaxTree.NewRealValue( position, token.real);
- factor(SyntaxTree.RealValue).SetSubtype(token.numberType);
- ELSE HALT( 100 )
- END;
- NextToken;
- | Scanner.Character:
- factor := SyntaxTree.NewCharacterValue(position,token.character);
- NextToken;
- | Scanner.String:
- factor := SyntaxTree.NewStringValue( position, token.string );
- NextToken;
- WHILE (Symbol() = Scanner.String) OR (Symbol() = Scanner.Character) DO
- IF Symbol() = Scanner.Character THEN
- factor(SyntaxTree.StringValue).AppendChar(token.character);
- ELSE
- factor(SyntaxTree.StringValue).Append(token.string);
- END;
- factor.End(token.position);
- NextToken;
- END;
- | Scanner.Nil:
- factor := SyntaxTree.NewNilValue( position );
- NextToken;
- | Scanner.Imag:
- factor := SyntaxTree.NewComplexValue(position, 0, 1);
- factor(SyntaxTree.ComplexValue).SetSubtype(Scanner.Real);
- NextToken;
- | Scanner.True:
- factor := SyntaxTree.NewBooleanValue( position, TRUE );
- NextToken;
- | Scanner.False:
- factor := SyntaxTree.NewBooleanValue( position, FALSE );
- NextToken;
- | Scanner.LeftBrace:
- factor := Set();
- | Scanner.LeftParenthesis:
- NextToken;
- factor := Expression();
- Check( Scanner.RightParenthesis );
- factor.End( token.position);
- | Scanner.Not:
- NextToken;
- factor := Factor();
- factor := SyntaxTree.NewUnaryExpression( position, factor, Scanner.Not );
- factor.End( token.position);
- | Scanner.Address, Scanner.Size:
- operator := Symbol();
- factor := Designator(); (* ADDRESS AND SIZE can be type identifiers used for type conversion *)
- IF Optional(Scanner.Of) THEN
- factor := Designator();
- factor := SyntaxTree.NewUnaryExpression( position, factor, operator );
- END;
- factor.End (token.position)
- | Scanner.Alias:
- operator := Symbol();
- NextToken();
- IF Mandatory(Scanner.Of) THEN
- factor := Factor();
- factor := SyntaxTree.NewUnaryExpression( position, factor, operator );
- END;
- factor.End (token.position)
- | Scanner.Self, Scanner.Result, Scanner.Identifier, Scanner.New:
- factor := Designator();
- factor.End( token.position);
- | Scanner.LeftBracket:
- NextToken;
- factor := MathArray();
- factor.End(token.position);
- ELSE
- Error( position, Basic.ValueStartIncorrectSymbol, "" );
- NextToken; factor := SyntaxTree.invalidExpression;
- END;
- (* suffix *)
- IF OptionalB(Scanner.Transpose) THEN
- IF (factor IS SyntaxTree.UnaryExpression) & (factor(SyntaxTree.UnaryExpression).operator = Scanner.Transpose) THEN
- (* transpose operator has higher precedence than not, reevaluate expression: *)
- factor := factor(SyntaxTree.UnaryExpression).left;
- factor := SyntaxTree.NewUnaryExpression(position,factor,Scanner.Transpose);
- factor := SyntaxTree.NewUnaryExpression(position,factor,Scanner.Not);
- ELSE
- factor := SyntaxTree.NewUnaryExpression(position,factor,Scanner.Transpose);
- END;
- END;
- IF Trace THEN E( "Factor" ) END;
- RETURN factor
- END Factor;
- (** Term = Factor {MulOp Factor}.
- MulOp = '*' | '**' | '.*' | '+*' | '/' | '\' | './' | 'div' | 'mod' | '&'.
- **)
- PROCEDURE Term( ): SyntaxTree.Expression;
- VAR term, factor: SyntaxTree.Expression; operator: LONGINT; position: Position;
- BEGIN
- IF Trace THEN S( "Term" ) END;
- position := token.position;
- term := Factor();
- WHILE (TokenB() >= Scanner.Times) & (TokenB() <= Scanner.And) DO
- operator := Symbol();
- NextToken;
- factor := Factor();
- term := SyntaxTree.NewBinaryExpression( position, term, factor, operator );
- END;
- term.End( token.position);
- IF Trace THEN E( "Term" ) END;
- RETURN term
- END Term;
- (** SimpleExpression = ['+'|'-'] Term {AddOp Term}.
- AddOp = '+' | '-' | 'or'.
- **)
- PROCEDURE SimpleExpression( ): SyntaxTree.Expression;
- VAR operator: LONGINT; term, expression: SyntaxTree.Expression; position: Position;
- BEGIN
- IF Trace THEN S( "SimpleExpression" ) END;
- position := token.position;
- IF Peek(Scanner.Plus) OR Peek(Scanner.Minus) THEN (* sign should be part of the factor *)
- operator := Symbol();
- NextToken;
- term := Term();
- expression := SyntaxTree.NewUnaryExpression( position, term, operator );
- ELSE expression := Term();
- END;
- WHILE (TokenB() >= Scanner.Or) & (TokenB() <= Scanner.Minus) DO
- operator := Symbol();
- NextToken;
- term := Term();
- expression := SyntaxTree.NewBinaryExpression( position, expression, term, operator );
- END;
- IF Trace THEN E( "SimpleExpression" ) END;
- RETURN expression
- END SimpleExpression;
- (**
- Expression = RangeExpression [RelationOp RangeExpression].
- RelationOp = '=' | '.=' | '#' | '.#'
- | '<' | '.<' | '<=' | '.<=' | '>' | '.>' | '>=' | '.>='
- | '??' | '!!' | '<<?' | '>>?'
- | 'in' | 'is'
- **)
- PROCEDURE Expression*( ): SyntaxTree.Expression;
- VAR expression, rightExpression: SyntaxTree.Expression; operator: LONGINT; position: Position;
- BEGIN
- IF Trace THEN S( "Expression" ) END;
- expression := RangeExpression();
- position := expression.position;
- IF (TokenB() >= Scanner.Equal) & (TokenB() <= Scanner.Is) THEN
- operator := Symbol();
- NextToken;
- rightExpression := RangeExpression();
- expression := SyntaxTree.NewBinaryExpression(position, expression, rightExpression, operator );
- expression.End(token.position);
- END;
- (*IF OptionalB(Scanner.Escape) THEN END; (* skip breaking escape *)*)
- IF Trace THEN E( "Expression" ) END;
- RETURN expression
- END Expression;
- (** Case = RangeExpression {',' RangeExpression} ':' StatementSequence. **)
- PROCEDURE Case( caseStatement: SyntaxTree.CaseStatement );
- VAR
- casePart: SyntaxTree.CasePart;
- statements: SyntaxTree.StatementSequence;
- element: SyntaxTree.Expression;
- BEGIN
- IF Trace THEN S( "Case" ) END;
- casePart := SyntaxTree.NewCasePart();
- casePart.SetPosition(token.position);
- CommentCasePart(casePart);
- REPEAT
- element := RangeExpression();
- casePart.elements.AddExpression( element );
- UNTIL ~Optional( Scanner.Comma );
- Check( Scanner.Colon );
- statements := StatementSequence(caseStatement);
- casePart.SetStatements( statements );
- caseStatement.AddCasePart( casePart );
- casePart.SetEnd(token.position);
- IF Trace THEN E( "Case" ) END;
- END Case;
- (** Statement =
- [
- Designator [':=' Expression |'!' Expression | '?' Expression | '<<' Expresssion | '>>' Expression]
- | 'if' Expression 'then' StatementSequence
- {'elsif' Expression 'then' StatementSequence}
- ['else' StatementSequence]
- 'end'
- | 'with' Identifier ':' QualifiedIdentifier 'do' StatementSequence
- {'|' [Identifier ':'] QualifiedIdentifier 'do' StatementSequence}
- [else StatementSequence]
- 'end'
- | 'case' Expression 'of' ['|'] Case {'|' Case} ['else' StatementSequence] 'end'
- | 'while' Expression 'do' StatementSequence 'end'
- | 'repeat' StatementSequence 'until' Expression
- | 'for' Identifier ':=' Expression 'to' Expression ['by' Expression] 'do'
- StatementSequence 'end'
- | 'loop' StatementSequence 'end'
- | 'exit'
- | 'return' [Expression]
- | 'await' Expression
- | 'begin' StatementBlock 'end'
- | 'code' {any} 'end'
- ].
- **)
- PROCEDURE Statement*( statements: SyntaxTree.StatementSequence; outer: SyntaxTree.Statement): BOOLEAN;
- VAR qualifiedIdentifier: SyntaxTree.QualifiedIdentifier; expression: SyntaxTree.Expression; designator: SyntaxTree.Designator; statement: SyntaxTree.Statement;
- ifStatement: SyntaxTree.IfStatement; elsifPart: SyntaxTree.IfPart; statementSequence: SyntaxTree.StatementSequence; withStatement: SyntaxTree.WithStatement;
- withPart: SyntaxTree.WithPart; caller: SyntaxTree.ProcedureCallStatement;
- caseStatement: SyntaxTree.CaseStatement; whileStatement: SyntaxTree.WhileStatement; repeatStatement: SyntaxTree.RepeatStatement; forStatement: SyntaxTree.ForStatement;
- identifier: SyntaxTree.Identifier; loopStatement: SyntaxTree.LoopStatement; returnStatement: SyntaxTree.ReturnStatement; awaitStatement: SyntaxTree.AwaitStatement;
- qualifiedType: SyntaxTree.QualifiedType; code : SyntaxTree.Code; position: Position; result: BOOLEAN;
- commToken: Scanner.Symbol;
- BEGIN
- IF Trace THEN S( "Statement" ) END;
- CASE Symbol() OF
- | Scanner.Identifier, Scanner.Self, Scanner.Result, Scanner.New:
- designator := Designator();
- position := token.position;
- IF OptionalB( Scanner.Becomes ) THEN
- expression := Expression();
- statement := SyntaxTree.NewAssignment( position, designator, expression,outer );
- CommentStatement(statement);
- ELSIF PeekB(Scanner.ExclamationMark) OR PeekB(Scanner.Questionmark) OR PeekB(Scanner.LessLess) OR PeekB(Scanner.GreaterGreater) THEN
- commToken := Symbol();
- NextToken;
- expression := Expression();
- statement := SyntaxTree.NewCommunicationStatement(position, commToken, designator, expression, outer);
- CommentStatement(statement);
- ELSE
- caller := SyntaxTree.NewProcedureCallStatement(designator.position, FALSE, designator,outer);
- statement := caller;
- CommentStatement(statement);
- END;
- statement.End(prevPosition);
- statements.AddStatement( statement );
- (*IF OptionalB(Scanner.Escape) THEN END;*)
- result := TRUE
- | Scanner.If:
- NextToken;
- ifStatement := SyntaxTree.NewIfStatement( token.position ,outer);
- CommentStatement(ifStatement);
- expression := Expression();
- ifStatement.ifPart.SetCondition( expression );
- Check( Scanner.Then );
- statementSequence := StatementSequence(ifStatement);
- ifStatement.ifPart.SetStatements( statementSequence );
- ifStatement.ifPart.SetEnd(token.position);
- WHILE Optional( Scanner.Elsif ) DO
- elsifPart := SyntaxTree.NewIfPart();
- elsifPart.SetPosition(token.position);
- CommentIfPart(elsifPart);
- ifStatement.AddElsifPart( elsifPart);
- expression := Expression();
- elsifPart.SetCondition( expression );
- Check( Scanner.Then );
- statementSequence := StatementSequence(ifStatement);
- elsifPart.SetStatements( statementSequence );
- elsifPart.SetEnd(token.position);
- END;
- IF Optional( Scanner.Else ) THEN
- statementSequence := StatementSequence(ifStatement);
- ifStatement.SetElsePart( statementSequence );
- END;
- ifStatement.End(token.position);
- Check( Scanner.End ); statements.AddStatement( ifStatement );
- result := TRUE
- | Scanner.With:
- withStatement := SyntaxTree.NewWithStatement( token.position ,outer);
- CommentStatement(withStatement);
- NextToken;
- identifier := Identifier(position);
- IF Optional(Scanner.Period) & Optional(Scanner.Identifier) THEN
- Error(position,Basic.InvalidCode,"forbidden qualified identifier in with statement");
- END;
- designator := SyntaxTree.NewIdentifierDesignator(position,identifier);
- withStatement.SetVariable(designator);
- Check( Scanner.Colon );
- IF Optional(Scanner.Bar) THEN (* ignore *) END;
- REPEAT
- withPart := SyntaxTree.NewWithPart();
- withPart.SetPosition(token.position);
- CommentWithPart(withPart);
- withStatement.AddWithPart(withPart);
- qualifiedIdentifier := QualifiedIdentifier();
- IF Optional(Scanner.Colon) THEN (* compatibility with old format *)
- Basic.Warning(diagnostics, scanner.source^, qualifiedIdentifier.position, "deprecated form of with statement, remove the repeated variable");
- qualifiedIdentifier := QualifiedIdentifier();
- END;
- qualifiedType := SyntaxTree.NewQualifiedType(qualifiedIdentifier.position, currentScope, qualifiedIdentifier);
- withPart.SetType(qualifiedType);
- Check( Scanner.Do );
- statementSequence := StatementSequence(withStatement);
- withPart.SetStatements( statementSequence );
- withPart.SetEnd(token.position);
- UNTIL ~Optional(Scanner.Bar) OR ~CascadedWithSupport;
- IF CascadedWithSupport & Optional(Scanner.Else) THEN
- statementSequence := StatementSequence(withStatement);
- withStatement.SetElsePart(statementSequence);
- END;
- Check( Scanner.End );
- withStatement.End(token.position);
- statements.AddStatement( withStatement );
- result := TRUE
- | Scanner.Case:
- caseStatement := SyntaxTree.NewCaseStatement( token.position,outer );
- CommentStatement(caseStatement);
- NextToken;
- expression := Expression();
- Check( Scanner.Of );
- caseStatement.SetVariable( expression );
- IF Optional(Scanner.Bar) THEN END;
- REPEAT
- Case(caseStatement)
- UNTIL ~Optional(Scanner.Bar);
- IF Optional( Scanner.Else ) THEN
- statementSequence := StatementSequence(caseStatement);
- caseStatement.SetElsePart( statementSequence );
- END;
- Check( Scanner.End );
- caseStatement.End(token.position);
- statements.AddStatement( caseStatement );
- result := TRUE
- | Scanner.While:
- NextToken;
- whileStatement := SyntaxTree.NewWhileStatement( token.position, outer );
- CommentStatement(whileStatement);
- expression := Expression();
- Check( Scanner.Do );
- whileStatement.SetCondition( expression );
- statementSequence := StatementSequence(whileStatement);
- whileStatement.SetStatements( statementSequence );
- Check( Scanner.End );
- whileStatement.End(token.position);
- statements.AddStatement( whileStatement );
- result := TRUE
- | Scanner.Repeat:
- NextToken;
- repeatStatement := SyntaxTree.NewRepeatStatement( token.position, outer );
- CommentStatement(repeatStatement);
- statementSequence := StatementSequence(repeatStatement);
- repeatStatement.SetStatements( statementSequence );
- Check( Scanner.Until );
- expression := Expression();
- repeatStatement.End(prevPosition);
- repeatStatement.SetCondition( expression );
- statements.AddStatement( repeatStatement );
- result := TRUE
- | Scanner.For:
- NextToken;
- forStatement := SyntaxTree.NewForStatement( token.position, outer);
- CommentStatement(forStatement);
- identifier := Identifier(position);
- IF Optional(Scanner.Period) & Optional(Scanner.Identifier) THEN
- Error(position,Basic.InvalidCode,"forbidden non-local counter variable");
- END;
- designator := SyntaxTree.NewIdentifierDesignator(position,identifier);
- forStatement.SetVariable( designator );
- Check( Scanner.Becomes );
- expression := Expression();
- forStatement.SetFrom( expression );
- Check( Scanner.To );
- expression := Expression();
- forStatement.SetTo( expression );
- IF Optional( Scanner.By ) THEN
- expression := Expression();
- forStatement.SetBy( expression );
- END;
- Check( Scanner.Do );
- statementSequence := StatementSequence(forStatement);
- forStatement.SetStatements( statementSequence );
- Check( Scanner.End );
- forStatement.End(token.position);
- statements.AddStatement( forStatement );
- result := TRUE
- | Scanner.Loop:
- NextToken;
- loopStatement := SyntaxTree.NewLoopStatement( token.position ,outer);
- CommentStatement(loopStatement);
- statementSequence := StatementSequence(loopStatement);
- loopStatement.SetStatements( statementSequence );
- Check( Scanner.End );
- loopStatement.End(token.position);
- statements.AddStatement( loopStatement );
- result := TRUE;
- | Scanner.Exit:
- NextToken;
- statement := SyntaxTree.NewExitStatement( token.position, outer);
- CommentStatement(statement);
- statements.AddStatement( statement );
- result := TRUE;
- | Scanner.Return:
- NextToken;
- returnStatement := SyntaxTree.NewReturnStatement( token.position, outer);
- CommentStatement(returnStatement);
- IF (Symbol() >= Scanner.Plus) & (Symbol() <= Scanner.Identifier) THEN
- expression := Expression();
- returnStatement.SetReturnValue( expression );
- END;
- returnStatement.End(token.position);
- statements.AddStatement( returnStatement );
- result := TRUE;
- | Scanner.Ignore:
- position := token.position;
- CommentStatement(statement);
- NextToken;
- designator := Designator();
- caller := SyntaxTree.NewProcedureCallStatement(designator.position, TRUE, designator,outer);
- statements.AddStatement( caller );
- result := TRUE;
- | Scanner.Begin:
- NextToken; statement := StatementBlock(outer); statements.AddStatement( statement ); Check( Scanner.End );
- statement.End(token.position);
- result := TRUE;
- | Scanner.Await:
- awaitStatement := SyntaxTree.NewAwaitStatement( token.position, outer );
- CommentStatement(awaitStatement);
- NextToken;
- expression := Expression();
- awaitStatement.SetCondition( expression );
- statements.AddStatement( awaitStatement );
- awaitStatement.End(token.position);
- result := TRUE
- | Scanner.Code:
- (* assemble *)
- code := Code(outer);
- Check(Scanner.End);
- code.End(token.position);
- statements.AddStatement( code );
- result := TRUE
- | Scanner.End: result := FALSE (* end of if, with, case, while, for, loop, or statement sequence *)
- | Scanner.Until: result := FALSE (* end of repeat *)
- | Scanner.Else: result := FALSE (* else of if or case *)
- | Scanner.Elsif: result := FALSE (* elsif of if *)
- | Scanner.Bar: result := FALSE (* next case *)
- | Scanner.Finally: result := FALSE (* end block by finally statement *)
- | Scanner.Semicolon: result := FALSE (* allow the empty statement *)
- (* builtin pseudo procedures are resolved by checker *)
- ELSE
- result := FALSE;
- (*
- IF Lax THEN
- expression := Expression();
- statement := SyntaxTree.NewAssignment( position, NIL, expression,outer );
- statements.AddStatement(statement);
- result := ~error;
- ELSE
- result := FALSE;
- END;
- *)
- END;
- IF Trace THEN E( "Statement" ) END;
- RETURN result
- END Statement;
- (** StatementSequence = Statement {';' Statement}. **)
- PROCEDURE StatementSequence*(outer: SyntaxTree.Statement ): SyntaxTree.StatementSequence;
- VAR statements: SyntaxTree.StatementSequence; b: BOOLEAN;
- BEGIN
- IF Trace THEN S( "StatementSequence" ) END;
- statements := SyntaxTree.NewStatementSequence();
- IF Lax THEN
- WHILE ~Peek(Scanner.Return) & Statement(statements,outer) DO Ignore(Scanner.Semicolon) END;
- IF Peek(Scanner.Return) & Statement(statements,outer) THEN Ignore(Scanner.Semicolon) END; (* return bound to end of statement sequence *)
- ELSE
- REPEAT
- b := Statement( statements,outer )
- UNTIL ~Optional( Scanner.Semicolon );
- END;
- IF Trace THEN E( "StatementSequence" ) END;
- RETURN statements
- END StatementSequence;
- (** StatementBlock = [Flags] StatementSequence. **)
- PROCEDURE StatementBlock(outer: SyntaxTree.Statement): SyntaxTree.StatementBlock;
- VAR block: SyntaxTree.StatementBlock; position: Position;
- BEGIN
- IF Trace THEN S( "StatementBlock" ) END;
- position := token.position;
- position.start := position.end;
- block := SyntaxTree.NewStatementBlock( position, outer, NIL );
- CommentStatement(block);
- IF Optional( Scanner.LeftBrace ) THEN
- block.SetModifier(Flags());
- END;
- block.SetStatementSequence( StatementSequence(block) );
- IF Trace THEN E( "StatementBlock" ) END;
- RETURN block
- END StatementBlock;
- (** Code = { any \ 'end' \ 'with' } ['with' {('in'|'out') StatementSequence}] . **)
- PROCEDURE Code(outer: SyntaxTree.Statement): SyntaxTree.Code;
- VAR startPos: Position; endPos, i ,len: LONGINT; codeString: Scanner.StringType; code: SyntaxTree.Code;
- end: Scanner.Symbol; in, out: BOOLEAN; statements, rules: SyntaxTree.StatementSequence;
- BEGIN
- startPos := token.position;
- end := scanner.SkipToEndOfCode(startPos.start, endPos, token);
- codeString := token.string;
- WHILE (end = Scanner.Unequal) & ConditionalStatement (token) DO
- end := scanner.SkipToEndOfCode(startPos.start, endPos, token);
- IF (conditional = Processing) OR (conditional = ProcessingElse) THEN
- codeString := Strings.ConcatToNew (codeString^, token.string^);
- END;
- END;
- IF (end = Scanner.End) OR (end = Scanner.With) THEN
- code := SyntaxTree.NewCode(startPos,outer);
- i := 0; len := LEN(codeString^);
- code.SetSourceCode(codeString,len);
- IF (end = Scanner.With) & Mandatory(Scanner.With) THEN
- in := Optional(Scanner.In);
- out := Optional(Scanner.Out);
- WHILE in OR out DO
- statements := StatementSequence(code);
- IF in THEN rules := code.inRules ELSE rules := code.outRules END;
- FOR i := 0 TO statements.Length()-1 DO
- rules.AddStatement(statements.GetStatement(i));
- END;
- in := Optional(Scanner.In);
- out := Optional(Scanner.Out);
- END;
- END;
- END;
- RETURN code;
- END Code;
- (** Body = 'begin' [Flags] StatementSequence ['finally' StatementSequence]
- | 'code' Code. **)
- PROCEDURE Body( scope: SyntaxTree.ProcedureScope ): SyntaxTree.Body;
- VAR body: SyntaxTree.Body; code: SyntaxTree.Code; position: Position; previousScope: SyntaxTree.Scope;
- BEGIN
- previousScope := currentScope;
- currentScope := scope;
- IF Trace THEN S( "Body" ) END;
- IF Peek( Scanner.Code ) THEN
- body := SyntaxTree.NewBody(token.position,scope); (* empty body for the time being *)
- (* assemble *)
- code := Code(body);
- body.SetCode(code);
- ELSIF Mandatory( Scanner.Begin ) THEN
- body := SyntaxTree.NewBody(token.position,scope);
- IF Optional( Scanner.LeftBrace ) THEN
- body.SetModifier(Flags());
- END;
- position := token.position;
- body.SetStatementSequence(StatementSequence(body));
- IF Optional( Scanner.Finally ) THEN
- body.SetFinally(StatementSequence(body));
- END;
- END;
- body.End(token.position); (* beginning of "end" is end of body *)
- IF Trace THEN E( "Body" ) END;
- currentScope := previousScope;
- RETURN body
- END Body;
- (** wrapper for a body in records and modules *)
- PROCEDURE BodyProcedure(parentScope: SyntaxTree.Scope): SyntaxTree.Procedure;
- VAR procedureScope: SyntaxTree.ProcedureScope; procedure: SyntaxTree.Procedure;
- BEGIN
- procedureScope := SyntaxTree.NewProcedureScope(parentScope);
- IF parentScope IS SyntaxTree.ModuleScope THEN
- procedure := SyntaxTree.NewProcedure( token.position, Global.ModuleBodyName,procedureScope);
- procedure.SetAccess(SyntaxTree.Hidden);
- ELSE
- procedure := SyntaxTree.NewProcedure( token.position, Global.RecordBodyName,procedureScope);
- (*! todo: make this a hidden token. Problematic when used with paco. *)
- procedure.SetAccess(SyntaxTree.Public + SyntaxTree.Protected + SyntaxTree.Internal);
- END;
- parentScope.AddProcedureDeclaration(procedure);
- procedure.SetType(SyntaxTree.NewProcedureType(SyntaxTree.invalidPosition,parentScope));
- procedure.SetBodyProcedure(TRUE);
- procedureScope.SetBody(Body(procedureScope));
- RETURN procedure
- END BodyProcedure;
- (* ProcedureType = 'procedure' [Flags] [FormalParameters]. *)
- PROCEDURE ProcedureType(position: Position; parentScope: SyntaxTree.Scope): SyntaxTree.ProcedureType;
- VAR procedureType: SyntaxTree.ProcedureType;
- BEGIN
- IF Trace THEN S( "ProcedureType" ) END;
- (* procedure token already consumed *)
- procedureType := SyntaxTree.NewProcedureType( position, parentScope);
- IF Optional(Scanner.LeftBrace) THEN
- procedureType.SetModifiers(Flags());
- END;
- IF Optional(Scanner.LeftParenthesis) THEN FormalParameters( procedureType, parentScope) END;
- IF Trace THEN E( "ProcedureType" )
- END;
- RETURN procedureType;
- END ProcedureType;
- (** ObjectType = 'object' | 'object' [Flags] ['(' QualifiedIdentifier ')'] DeclarationSequence [Body] 'end' [Identifier] . **)
- PROCEDURE ObjectType(position: Position; name: SyntaxTree.Identifier; parentScope: SyntaxTree.Scope ): SyntaxTree.Type;
- VAR
- objectType: SyntaxTree.RecordType;
- pointerType: SyntaxTree.PointerType;
- recordScope: SyntaxTree.RecordScope;
- qualifiedIdentifier: SyntaxTree.QualifiedIdentifier;
- baseType: SyntaxTree.Type;
- identifier: SyntaxTree.Identifier;
- type: SyntaxTree.Type;
- modifiers: SyntaxTree.Modifier;
- BEGIN
- IF Trace THEN S( "ObjectType" ) END;
- (* token object already consumed *)
- (* generic empty OBJECT type *)
- IF Peek(Scanner.Semicolon) OR Peek(Scanner.RightParenthesis) THEN
- Scanner.GetKeyword(scanner.case,Scanner.Object,identifier);
- qualifiedIdentifier := SyntaxTree.NewQualifiedIdentifier(position,SyntaxTree.invalidIdentifier,identifier);
- type := SyntaxTree.NewQualifiedType( position, parentScope, qualifiedIdentifier );
- RETURN type
- END;
- recordScope := SyntaxTree.NewRecordScope(parentScope);
- pointerType := SyntaxTree.NewPointerType(position,parentScope);
- objectType := SyntaxTree.NewRecordType( position,parentScope,recordScope);
- objectType.IsObject(TRUE);
- objectType.SetPointerType(pointerType);
- pointerType.SetPointerBase(objectType);
- IF Optional(Scanner.LeftBrace) THEN
- modifiers := Flags();
- pointerType.SetModifiers(modifiers);
- END;
- IF Optional( Scanner.LeftParenthesis ) THEN
- qualifiedIdentifier := QualifiedIdentifier();
- baseType := SyntaxTree.NewQualifiedType(qualifiedIdentifier.position, parentScope, qualifiedIdentifier);
- objectType.SetBaseType(baseType);
- Check( Scanner.RightParenthesis )
- END;
- (*
- IF Optional( Scanner.Implements ) THEN
- REPEAT
- qualifiedIdentifier := QualifiedIdentifier()
- UNTIL ~Optional( Scanner.Comma );
- END;
- *)
- IF Optional( Scanner.Semicolon ) THEN
- (*Warning(token.position,Basic.InvalidCode,"no semicolon allowed here");*)
- END;
- DeclarationSequence( recordScope);
- IF Peek(Scanner.Begin) OR Peek(Scanner.Code) THEN
- recordScope.SetBodyProcedure(BodyProcedure(recordScope));
- END;
- Check(Scanner.End);
- IF ExpectThisIdentifier( name ) THEN
- (* check name not always, reflect in EBNF? *)
- END;
- IF Trace THEN E( "ObjectType" ) END;
- RETURN pointerType
- END ObjectType;
- (** CellType = 'cell' [Flags] [PortList] [';'] {ImportList} DeclarationSequence [Body] 'end' [Identifier]
- | 'object'. **)
- PROCEDURE CellType(position: Position; name: SyntaxTree.Identifier; parentScope: SyntaxTree.Scope; isCellNet: BOOLEAN): SyntaxTree.Type;
- VAR
- cellType: SyntaxTree.CellType;
- cellScope: SyntaxTree.CellScope;
- modifiers: SyntaxTree.Modifier;
- qualifiedIdentifier: SyntaxTree.QualifiedIdentifier;
- qualifiedType: SyntaxTree.Type;
- BEGIN
- IF Trace THEN S( "CellType" ) END;
- (* token cell already consumed *)
- cellScope := SyntaxTree.NewCellScope(parentScope);
- cellType := SyntaxTree.NewCellType( position, parentScope,cellScope);
- cellType.IsCellNet(isCellNet);
- cellScope.SetOwnerCell(cellType);
- IF Optional(Scanner.Colon) THEN
- qualifiedIdentifier := QualifiedIdentifier();
- qualifiedType := SyntaxTree.NewQualifiedType(qualifiedIdentifier.position, parentScope, qualifiedIdentifier );
- cellType.SetBaseType( qualifiedType );
- END;
- IF Optional(Scanner.LeftBrace) THEN
- modifiers := Flags();
- cellType.SetModifiers(modifiers);
- END;
- IF Optional( Scanner.LeftParenthesis ) THEN
- PortList(cellType,cellScope);
- END;
- IF Optional( Scanner.Semicolon ) THEN END;
- WHILE Optional(Scanner.Import) DO ImportList(cellScope) END;
- DeclarationSequence( cellScope);
- IF Peek(Scanner.Begin) OR Peek(Scanner.Code) THEN
- cellScope.SetBodyProcedure(BodyProcedure(cellScope));
- END;
- Check(Scanner.End);
- IF ExpectThisIdentifier( name ) THEN
- (* check name not always, reflect in EBNF? *)
- END;
- IF Trace THEN E( "CellType" ) END;
- RETURN cellType
- END CellType;
- (** PointerType = 'pointer' [Flags] 'to' Type. **)
- PROCEDURE PointerType( position: Position; parentScope: SyntaxTree.Scope ): SyntaxTree.PointerType;
- VAR pointerType: SyntaxTree.PointerType; base: SyntaxTree.Type; modifiers: SyntaxTree.Modifier;
- BEGIN
- IF Trace THEN S( "PointerType" ) END;
- (* pointer token already consumed *)
- pointerType := SyntaxTree.NewPointerType( position ,parentScope);
- IF Optional(Scanner.LeftBrace) THEN
- modifiers := Flags();
- pointerType.SetModifiers(modifiers)
- END;
- Check( Scanner.To );
- base := Type(SyntaxTree.invalidIdentifier, parentScope);
- pointerType.SetPointerBase( base );
- IF base IS SyntaxTree.RecordType THEN
- base(SyntaxTree.RecordType).SetPointerType(pointerType);
- END;
- IF Trace THEN E( "PointerType" ) END;
- RETURN pointerType
- END PointerType;
- (**
- RecordType = 'record' [Flags] ['(' QualifiedIdentifier ')'] [VariableDeclaration {';' VariableDeclaration}] 'end'.
- **)
- PROCEDURE RecordType(position: Position; parentScope:SyntaxTree.Scope ): SyntaxTree.RecordType;
- VAR
- recordType: SyntaxTree.RecordType;
- recordScope: SyntaxTree.RecordScope;
- qualifiedIdentifier: SyntaxTree.QualifiedIdentifier; flags: SET; qualifiedType: SyntaxTree.QualifiedType;
- modifier: SyntaxTree.Modifier;
- BEGIN
- IF Trace THEN S( "RecordType" ) END;
- (* record token already consumed *)
- flags := {};
- recordScope := SyntaxTree.NewRecordScope(parentScope);
- recordType := SyntaxTree.NewRecordType( position, parentScope, recordScope);
- IF Optional( Scanner.LeftBrace ) THEN
- modifier := Flags();
- recordType.SetModifiers(modifier);
- END;
- IF Optional( Scanner.LeftParenthesis ) THEN
- qualifiedIdentifier := QualifiedIdentifier();
- qualifiedType := SyntaxTree.NewQualifiedType(qualifiedIdentifier.position, parentScope, qualifiedIdentifier );
- recordType.SetBaseType( qualifiedType );
- Check( Scanner.RightParenthesis )
- END;
- IF Lax THEN
- WHILE Peek(Scanner.Identifier) DO VariableDeclaration(recordScope); Ignore(Scanner.Semicolon) END;
- ELSE
- REPEAT
- IF Peek(Scanner.Identifier) THEN VariableDeclaration( recordScope ) END;
- UNTIL ~Optional( Scanner.Semicolon );
- END;
- LOOP
- IF Optional(Scanner.Procedure) THEN ProcedureDeclaration(recordScope); Ignore(Scanner.Semicolon);
- ELSIF Optional(Scanner.Operator) THEN OperatorDeclaration(recordScope); Ignore(Scanner.Semicolon);
- ELSE EXIT
- END;
- END;
- (*WHILE Optional(Scanner.Procedure) DO ProcedureDeclaration(recordScope); Ignore(Scanner.Semicolon) END; *)
- Check( Scanner.End );
- IF Trace THEN E( "RecordType" ) END;
- RETURN recordType
- END RecordType;
- (** ArrayType = 'array' 'of' Type | 'array' Expression {',' Expression} 'of' Type
- | 'array' '[' MathArraySize {',' MathArraySize} ']' ['of' Type].
- MathArraySize = Expression | '*' | '?'.
- **)
- PROCEDURE ArrayType(position: Position; parentScope: SyntaxTree.Scope ): SyntaxTree.Type;
- VAR
- arrayType: SyntaxTree.ArrayType;
- type: SyntaxTree.Type;
- base: SyntaxTree.Type;
- expression: SyntaxTree.Expression;
- modifiers: SyntaxTree.Modifier;
- PROCEDURE MathArray(): SyntaxTree.Type;
- VAR mathType: SyntaxTree.MathArrayType; base: SyntaxTree.Type;
- BEGIN
- IF Optional(Scanner.Questionmark) THEN
- mathType := SyntaxTree.NewMathArrayType(position,parentScope, SyntaxTree.Tensor);
- ELSIF Optional(Scanner.Times) THEN (* open array *)
- mathType := SyntaxTree.NewMathArrayType(position,parentScope, SyntaxTree.Open);
- ELSE (* size given *)
- mathType := SyntaxTree.NewMathArrayType(position,parentScope, SyntaxTree.Static);
- expression := Expression();
- mathType.SetLength(expression);
- END;
- IF Optional(Scanner.Comma) THEN
- base := MathArray()
- ELSIF Mandatory(Scanner.RightBracket) THEN
- IF Optional( Scanner.Of ) THEN
- base := Type(SyntaxTree.invalidIdentifier , parentScope ); (* base type *)
- END;
- END;
- mathType.SetModifiers(modifiers);
- modifiers := NIL;
- mathType.SetArrayBase(base);
- RETURN mathType;
- END MathArray;
- BEGIN
- IF Trace THEN S( "ArrayType" ) END;
- (* array token already consumed *)
- IF Optional(Scanner.LeftBrace) THEN
- modifiers := Flags();
- END;
- IF Optional(Scanner.LeftBracket) THEN (* math array *)
- type := MathArray();
- ELSIF Optional( Scanner.Of ) THEN (* open array *)
- arrayType := SyntaxTree.NewArrayType(position,parentScope, SyntaxTree.Open);
- type := arrayType;
- base := Type( SyntaxTree.invalidIdentifier ,parentScope);
- arrayType.SetArrayBase( base )
- ELSE (* static array *)
- arrayType := SyntaxTree.NewArrayType(position,parentScope, SyntaxTree.Static);
- type := arrayType;
- expression := SimpleExpression();
- arrayType.SetLength( expression );
- position := token.position;
- IF Optional( Scanner.Comma ) THEN
- base := ArrayType( position,parentScope);
- arrayType.SetArrayBase( base )
- ELSIF Mandatory( Scanner.Of ) THEN
- base := Type(SyntaxTree.invalidIdentifier , parentScope ); (* base type *)
- arrayType.SetArrayBase( base );
- END;
- END;
- IF modifiers # NIL THEN
- Error(modifiers.position, Basic.InvalidCode, "forbidden modifiers");
- END;
- IF Trace THEN E( "ArrayType" ) END;
- RETURN type
- END ArrayType;
- (** EnumerationType = 'enum' ['('QualifiedIdentifier')'] IdentifierDefinition ['=' Expression]
- {',' IdentifierDefinition ['=' Expression]} 'end'. *)
- PROCEDURE EnumerationType(position: Position; parentScope: SyntaxTree.Scope): SyntaxTree.Type;
- VAR type: SyntaxTree.EnumerationType; scope: SyntaxTree.EnumerationScope; identifier: SyntaxTree.Identifier;
- qualifiedIdentifier: SyntaxTree.QualifiedIdentifier; qualifiedType: SyntaxTree.QualifiedType; access: SET;
- constant: SyntaxTree.Constant; expression: SyntaxTree.Expression;
- BEGIN
- (* enum token already consumed *)
- scope := SyntaxTree.NewEnumerationScope(parentScope);
- type := SyntaxTree.NewEnumerationType(position,parentScope, scope);
- IF Optional( Scanner.LeftParenthesis ) THEN
- qualifiedIdentifier := QualifiedIdentifier();
- qualifiedType := SyntaxTree.NewQualifiedType(qualifiedIdentifier.position, parentScope, qualifiedIdentifier );
- type.SetEnumerationBase( qualifiedType );
- Check( Scanner.RightParenthesis )
- END;
- REPEAT
- IdentifierDefinition(identifier,access,FALSE);
- position := token.position;
- constant := SyntaxTree.NewConstant( position, identifier );
- CommentSymbol(constant);
- constant.SetAccess(access);
- IF Optional(Scanner.Equal) THEN
- expression := Expression();
- constant.SetValue( expression );
- END;
- scope.AddConstant( constant );
- UNTIL ~Optional(Scanner.Comma);
- IF Mandatory(Scanner.End) THEN END;
- RETURN type
- END EnumerationType;
- (** PortType = 'port' ('in'|'out') ['(' Expression ')'] *)
- PROCEDURE PortType(position: Position; parentScope: SyntaxTree.Scope): SyntaxTree.Type;
- VAR type: SyntaxTree.Type; direction: LONGINT; sizeExpression: SyntaxTree.Expression;
- BEGIN
- (* port token already consumed *)
- IF Optional(Scanner.In) THEN
- direction := SyntaxTree.InPort
- ELSIF Optional(Scanner.Out) THEN
- direction := SyntaxTree.OutPort
- ELSE
- Error(position,Basic.InvalidCode,"invalid direction, expected IN or OUT");
- END;
- IF Optional(Scanner.LeftParenthesis) THEN
- sizeExpression := Expression();
- IF Mandatory(Scanner.RightParenthesis )THEN END;
- END;
- type := SyntaxTree.NewPortType(position, direction, sizeExpression, parentScope);
- RETURN type
- END PortType;
- (** Type = ArrayType | RecordType | PointerType | ObjectType | CellType | CellnetType | PortType
- | ProcedureType | EnumerationType | QualifiedIdentifier. *)
- PROCEDURE Type( name: SyntaxTree.Identifier; parentScope: SyntaxTree.Scope ): SyntaxTree.Type;
- VAR type: SyntaxTree.Type; qualifiedIdentifier: SyntaxTree.QualifiedIdentifier; position: Position;
- BEGIN
- IF Trace THEN S( "Type" ) END;
- position := token.position;
- IF Optional( Scanner.Array ) THEN type := ArrayType( position,parentScope );
- ELSIF Optional( Scanner.Record ) THEN type := RecordType( position,parentScope );
- ELSIF Optional( Scanner.Pointer ) THEN type := PointerType( position,parentScope );
- ELSIF Optional( Scanner.Object ) THEN type := ObjectType( position,name,parentScope );
- ELSIF Optional( Scanner.Cell) THEN type := CellType( position, name, parentScope,FALSE);
- ELSIF Optional( Scanner.CellNet) THEN type := CellType( position, name, parentScope, TRUE);
- ELSIF Optional( Scanner.Port) THEN type := PortType( position, parentScope)
- ELSIF Optional( Scanner.Procedure ) THEN type := ProcedureType( position,parentScope);
- ELSIF Optional( Scanner.Enum ) THEN type := EnumerationType( position,parentScope);
- ELSIF (Symbol() = Scanner.Address) OR (Symbol() = Scanner.Size) THEN
- qualifiedIdentifier := SyntaxTree.NewQualifiedIdentifier(position,SyntaxTree.invalidIdentifier, token.identifier);
- type := SyntaxTree.NewQualifiedType( qualifiedIdentifier.position, parentScope, qualifiedIdentifier );
- NextToken;
- ELSE qualifiedIdentifier := QualifiedIdentifier();
- type := SyntaxTree.NewQualifiedType( qualifiedIdentifier.position, parentScope, qualifiedIdentifier );
- END;
- IF Trace THEN E( "Type" ) END;
- RETURN type
- END Type;
- (** PortDeclaration = Identifier [Flags] {',' Identifier [Flags]}':' Type. **)
- PROCEDURE PortDeclaration(cell: SyntaxTree.CellType; parentScope: SyntaxTree.Scope);
- VAR
- type: SyntaxTree.Type; name: SyntaxTree.Identifier;
- firstParameter, parameter: SyntaxTree.Parameter;
- position: Position; modifiers: SyntaxTree.Modifier;
- BEGIN
- IF Trace THEN S( "PortDeclaration" ) END;
- firstParameter := cell.lastParameter;
- REPEAT
- name := Identifier(position);
- parameter := SyntaxTree.NewParameter(position,cell,name,SyntaxTree.ValueParameter);
- cell.AddParameter(parameter);
- IF Optional(Scanner.LeftBrace) THEN
- modifiers := Flags();
- parameter.SetModifiers(modifiers);
- END;
- UNTIL ~Optional( Scanner.Comma );
- Check( Scanner.Colon );
- type := Type( SyntaxTree.invalidIdentifier, parentScope);
- ASSERT(type # NIL);
- IF firstParameter # NIL THEN parameter := firstParameter.nextParameter ELSE parameter := cell.firstParameter END;
- WHILE parameter # NIL DO
- parameter.SetType( type );
- parameter := parameter.nextParameter;
- END;
- IF Trace THEN E( "PortDeclaration" )
- END;
- END PortDeclaration;
- (** PortList = '(' [PortDeclaration {';' PortDeclaration}] ')'. **)
- PROCEDURE PortList( cell: SyntaxTree.CellType ; parentScope: SyntaxTree.Scope);
- BEGIN
- IF Trace THEN S( "PortList" ) END;
- (* left parenthesis already consumed *)
- IF ~Optional( Scanner.RightParenthesis ) THEN
- IF Lax THEN
- WHILE Peek(Scanner.Identifier) OR Peek(Scanner.Var) OR Peek(Scanner.Const) DO PortDeclaration( cell, parentScope ); Ignore(Scanner.Semicolon) END;
- ELSE
- REPEAT PortDeclaration( cell, parentScope ); UNTIL ~Optional( Scanner.Semicolon );
- END;
- Check( Scanner.RightParenthesis );
- END;
- IF Trace THEN E( "PortList" ) END;
- END PortList;
- (** ParameterDeclaration = ['var'|'const'] Identifier [Flags] ['= Expression] {',' Identifier [Flags] ['= Expression]}':' Type.**)
- PROCEDURE ParameterDeclaration( procedureType: SyntaxTree.ProcedureType ; parentScope: SyntaxTree.Scope);
- VAR
- type: SyntaxTree.Type; name: SyntaxTree.Identifier;
- firstParameter, parameter: SyntaxTree.Parameter; kind: LONGINT; position: Position;
- BEGIN
- IF Trace THEN S( "ParameterDeclaration" ) END;
- IF Optional( Scanner.Var ) THEN (* var parameter *)
- kind := SyntaxTree.VarParameter
- ELSIF Optional( Scanner.Const ) THEN (* const parameter *)
- kind := SyntaxTree.ConstParameter
- ELSIF Symbol() # Scanner.Identifier THEN
- Error(token.position,Scanner.Identifier,"");
- RETURN
- ELSE kind := SyntaxTree.ValueParameter
- END;
- firstParameter := procedureType.lastParameter;
- REPEAT
- name := Identifier(position);
- parameter := SyntaxTree.NewParameter(position,procedureType,name,kind);
- IF Optional(Scanner.LeftBrace) THEN parameter.SetModifiers(Flags()) END;
- procedureType.AddParameter(parameter);
- IF Optional(Scanner.Equal) THEN
- parameter.SetDefaultValue(Expression());
- END
- UNTIL ~Optional( Scanner.Comma );
- Check( Scanner.Colon );
- type := Type( SyntaxTree.invalidIdentifier, parentScope);
- CommentSymbol(parameter);
- ASSERT(type # NIL);
- IF firstParameter # NIL THEN parameter := firstParameter.nextParameter ELSE parameter := procedureType.firstParameter END;
- WHILE parameter # NIL DO
- parameter.SetType( type );
- parameter := parameter.nextParameter;
- END;
- IF Trace THEN E( "ParameterDeclaration" )
- END;
- END ParameterDeclaration;
- (** FormalParameters = '(' [ParameterDeclaration {';' ParameterDeclaration}] ')' [':' [Flags] Type]. **)
- PROCEDURE FormalParameters( procedureType: SyntaxTree.ProcedureType ; parentScope: SyntaxTree.Scope);
- VAR type: SyntaxTree.Type; position: Position;
- BEGIN
- IF Trace THEN S( "FormalParameters" ) END;
- (* left parenthesis already consumed *)
- IF ~Optional( Scanner.RightParenthesis ) THEN
- IF Lax THEN
- WHILE Peek(Scanner.Identifier) OR Peek(Scanner.Const) OR Peek(Scanner.Var) DO
- ParameterDeclaration(procedureType, parentScope); Ignore(Scanner.Semicolon)
- END;
- ELSE
- REPEAT ParameterDeclaration( procedureType, parentScope ); UNTIL ~Optional( Scanner.Semicolon );
- END;
- Check( Scanner.RightParenthesis );
- END;
- IF Optional( Scanner.Colon ) THEN
- position:= token.position;
- IF Optional( Scanner.LeftBrace) THEN
- procedureType.SetReturnTypeModifiers(Flags());
- END;
- type := Type(SyntaxTree.invalidIdentifier,parentScope);
- (* formally, any type is permitted as return type. Actually some of them might simply not be usable *)
- procedureType.SetReturnType(type);
- END;
- IF Trace THEN E( "FormalParameters" ) END;
- END FormalParameters;
- (** Flags = '{' [Identifier ['(' Expression ')'|'=' Expression] {',' Identifier ['(' Expression ')' | '=' Expression ] } ] '}'. **)
- PROCEDURE Flags(): SyntaxTree.Modifier;
- VAR identifier: SyntaxTree.Identifier; modifier,list: SyntaxTree.Modifier; position: Position; expression: SyntaxTree.Expression;
- BEGIN
- IF Trace THEN S( "Flags" ) END;
- (* left brace already consumed *)
- list := NIL;
- IF Peek(Scanner.RightBrace) THEN (* empty flags *)
- ELSE
- REPEAT
- position := token.position;
- identifier := Identifier(position);
- IF Optional(Scanner.LeftParenthesis) THEN
- expression := Expression();
- Check(Scanner.RightParenthesis)
- ELSIF Optional(Scanner.Equal) THEN
- expression := Expression();
- ELSE
- expression := NIL
- END;
- modifier := SyntaxTree.NewModifier(position,identifier,expression);
- AppendModifier(list,modifier);
- UNTIL ~Optional( Scanner.Comma ) & ~Optional(Scanner.Semicolon);
- END;
- Check(Scanner.RightBrace);
- IF Trace THEN E( "Flags" ) END;
- RETURN list;
- END Flags;
- PROCEDURE SetNextInComment(c: SyntaxTree.Comment; this: ANY);
- BEGIN
- WHILE c # NIL DO
- c.SetItem(this,FALSE);
- c := c.nextComment
- END;
- END SetNextInComment;
- PROCEDURE CommentSymbol(symbol: SyntaxTree.Symbol);
- BEGIN
- IF (recentComment # NIL) (* & (recentComment.nextSymbol = NIL) *) THEN
- symbol.SetComment(recentComment);
- SetNextInComment(recentComment, symbol);
- recentComment := NIL
- END;
- recentLine := scanner.position.line;
- recentCommentItem := symbol;
- END CommentSymbol;
- PROCEDURE CommentStatement(symbol: SyntaxTree.Statement);
- BEGIN
- IF (recentComment # NIL) (* & (recentComment.nextSymbol = NIL) *) THEN
- symbol.SetComment(recentComment);
- SetNextInComment(recentComment, symbol);
- recentComment := NIL
- END;
- recentLine := scanner.position.line;
- recentCommentItem := symbol
- END CommentStatement;
- PROCEDURE CommentCasePart(symbol: SyntaxTree.CasePart);
- BEGIN
- IF (recentComment # NIL) (* & (recentComment.nextSymbol = NIL) *) THEN
- symbol.SetComment(recentComment);
- SetNextInComment(recentComment, symbol);
- recentComment := NIL
- END;
- recentLine := scanner.position.line;
- recentCommentItem := symbol
- END CommentCasePart;
- PROCEDURE CommentIfPart(symbol: SyntaxTree.IfPart);
- BEGIN
- IF (recentComment # NIL) (* & (recentComment.nextSymbol = NIL) *) THEN
- symbol.SetComment(recentComment);
- SetNextInComment(recentComment, symbol);
- recentComment := NIL
- END;
- recentLine := scanner.position.line;
- recentCommentItem := symbol
- END CommentIfPart;
- PROCEDURE CommentWithPart(symbol: SyntaxTree.WithPart);
- BEGIN
- IF (recentComment # NIL) (* & (recentComment.nextSymbol = NIL) *) THEN
- symbol.SetComment(recentComment);
- SetNextInComment(recentComment, symbol);
- recentComment := NIL
- END;
- recentLine := scanner.position.line;
- recentCommentItem := symbol
- END CommentWithPart;
- (** ProcedureDeclaration = 'procedure' ['^'|'&'|'~'|'-'|Flags ['-']] IdentifierDefinition [FormalParameters]';'
- DeclarationSequence [Body] 'end' Identifier.
- Forward declarations ignored.
- **)
- PROCEDURE ProcedureDeclaration( parentScope: SyntaxTree.Scope);
- VAR name: SyntaxTree.Identifier;
- procedure: SyntaxTree.Procedure;
- procedureType: SyntaxTree.ProcedureType;
- procedureScope : SyntaxTree.ProcedureScope;
- access: SET;
- position: Position;
- isConstructor: BOOLEAN;
- isFinalizer: BOOLEAN;
- isInline: BOOLEAN;
- modifiers: SyntaxTree.Modifier;
- forwardDeclaration: BOOLEAN;
- string: Scanner.StringType;
- parameter: SyntaxTree.Parameter;
- qualifiedIdentifier : SyntaxTree.QualifiedIdentifier;
- identifier: SyntaxTree.Identifier;
- kind: LONGINT;
- BEGIN
- IF Trace THEN S( "Procedure" ) END;
- (* procedure symbol has already been consumed *)
- modifiers := NIL;
- isConstructor := FALSE; isFinalizer := FALSE; isInline := FALSE;
- procedureType := SyntaxTree.NewProcedureType(token.position, parentScope);
- position := token.position;
- IF Optional( Scanner.Arrow) THEN (* ignore forward declarations *)
- forwardDeclaration := TRUE;
- ELSE forwardDeclaration := FALSE;
- END;
- IF Optional( Scanner.And ) THEN (* constructor *)
- isConstructor := TRUE
- ELSIF Optional( Scanner.Not ) THEN (* finalizer *)
- isFinalizer := TRUE
- ELSIF Optional( Scanner.Minus ) THEN (* inline *)
- isInline := TRUE;
- ELSIF Optional( Scanner.LeftBrace) THEN
- modifiers := Flags();
- IF Optional( Scanner.Minus ) THEN (* inline *)
- isInline := TRUE
- END;
- END;
- IF Peek(Scanner.String) OR Peek(Scanner.Character) THEN (* for compatibility with release *)
- Error (position, Basic.InvalidCode, "Invalid operator declaration: replace 'procedure' by 'operator' keyword!");
- OperatorDeclaration( parentScope );
- RETURN
- END;
- procedureScope := SyntaxTree.NewProcedureScope(parentScope);
- IF Optional(Scanner.LeftParenthesis) THEN (* type bound *)
- IF Optional(Scanner.Var) THEN
- kind := SyntaxTree.VarParameter
- ELSIF Optional(Scanner.Const) THEN
- kind := SyntaxTree.ConstParameter;
- ELSE
- kind := SyntaxTree.ConstParameter;
- END;
- identifier := Identifier(position);
- parameter := SyntaxTree.NewParameter(position, procedureType, identifier, kind);
- Check(Scanner.Colon);
- qualifiedIdentifier := SyntaxTree.NewQualifiedIdentifier(position, SyntaxTree.invalidIdentifier, Identifier(position));
- parameter.SetType(SyntaxTree.NewQualifiedType(position, procedureScope, qualifiedIdentifier));
- Check(Scanner.RightParenthesis);
- procedureType.SetSelfParameter(parameter);
- parameter.SetSelfParameter(TRUE);
- END;
- position:= token.position;
- IdentifierDefinition( name, access,TRUE);
- procedure := SyntaxTree.NewProcedure( position, name, procedureScope);
- procedure.SetConstructor(isConstructor);
- procedure.SetFinalizer(isFinalizer);
- procedure.SetInline(isInline);
- CommentSymbol(procedure);
- procedure.SetAccess(access);
- procedureType.SetModifiers(modifiers);
- procedure.SetType(procedureType);
- IF Optional(Scanner.Extern) & MandatoryString(string) THEN procedure.SetExternalName(string); END;
- IF Optional(Scanner.LeftParenthesis) THEN FormalParameters( procedureType, procedureScope) END;
- IF (procedure.externalName = NIL) & ~forwardDeclaration THEN
- IF Lax THEN Ignore(Scanner.Semicolon) ELSE Check( Scanner.Semicolon ) END;
- DeclarationSequence( procedureScope);
- IF Peek(Scanner.Begin) OR Peek(Scanner.Code) THEN
- procedureScope.SetBody(Body(procedureScope));
- END;
- Check(Scanner.End);
- IF ExpectThisIdentifier( name ) THEN END;
- END;
- parentScope.AddProcedureDeclaration( procedure );
- IF Trace THEN E( "Procedure") END;
- END ProcedureDeclaration;
- (** OperatorDeclaration = 'operator' [Flags] ['-'] String ['*'|'-'] FormalParameters ';'
- DeclarationSequence [Body] 'end' String.
- **)
- PROCEDURE OperatorDeclaration(parentScope: SyntaxTree.Scope );
- VAR
- string: Scanner.StringType;
- procedureScope: SyntaxTree.ProcedureScope;
- procedureType: SyntaxTree.ProcedureType;
- operator: SyntaxTree.Operator;
- access: SET;
- i: LONGINT; position: Position;
- modifiers: SyntaxTree.Modifier; (* nopov *)
- isInline, forward: BOOLEAN;
- BEGIN
- IF Trace THEN S( "Operator" ) END;
- (* token operator already consumed *)
- position := token.position;
- forward := Optional(Scanner.Arrow);
- isInline := FALSE;
- IF Optional( Scanner.LeftBrace) THEN
- modifiers := Flags();
- END;
- IF Optional( Scanner.Minus ) THEN (* inline *)
- isInline := TRUE;
- END;
- IF MandatoryString( string ) THEN
- (* copy string to name and check for length. LEN(name)>0, LEN(string)>0 can be presumed *)
- i := 0; WHILE (string^[i] # 0X) DO INC(i) END;
- IF i >= Scanner.MaxIdentifierLength THEN (* string too long to act as operator identifier *)
- Error(token.position,Basic.StringTooLong,"");
- END
- END;
- IF Optional( Scanner.Times ) THEN access := SyntaxTree.ReadOnly;
- ELSIF Optional( Scanner.Minus ) THEN access := SyntaxTree.ReadOnly;
- ELSE access := SyntaxTree.Internal;
- END;
- procedureScope := SyntaxTree.NewProcedureScope(parentScope);
- operator := SyntaxTree.NewOperator( token.position, SyntaxTree.NewIdentifier(string^), procedureScope);
- CommentSymbol(operator);
- operator.SetAccess(access);
- procedureType := SyntaxTree.NewProcedureType(token.position,parentScope);
- IF Mandatory(Scanner.LeftParenthesis) THEN FormalParameters( procedureType, procedureScope ) END;
- procedureType.SetModifiers(modifiers); (* nopov *)
- operator.SetType( procedureType );
- operator.SetInline(isInline);
- IF Lax THEN Ignore(Scanner.Semicolon) ELSE Check( Scanner.Semicolon ) END;
- IF ~forward THEN
- DeclarationSequence( procedureScope );
- IF Peek(Scanner.Begin) OR Peek(Scanner.Code) THEN
- procedureScope.SetBody(Body(procedureScope));
- END;
- IF Mandatory(Scanner.End) & ExpectThisString(string^) THEN END;
- END;
- parentScope.AddProcedureDeclaration(operator);
- IF parentScope IS SyntaxTree.ModuleScope THEN
- parentScope(SyntaxTree.ModuleScope).AddOperator(operator);
- ELSIF parentScope IS SyntaxTree.RecordScope THEN
- parentScope(SyntaxTree.RecordScope).AddOperator(operator);
- ELSE
- Error(position,Basic.InvalidCode,"Operators only allowed in module or record scope"); (* nopov *)
- END;
- IF Trace THEN EE( "Operator", string^ ) END;
- END OperatorDeclaration;
- (** VariableNameList = IdentifierDefinition [Flags] [':=' Expression | 'extern' String] {',' IdentifierDefinition [Flags] [':=' Expression | 'extern' String] }.**)
- PROCEDURE VariableNameList( scope: SyntaxTree.Scope );
- VAR varname: SyntaxTree.Identifier; position: Position; variable: SyntaxTree.Variable; flags,access: SET; string: Scanner.StringType;
- BEGIN
- IF Trace THEN S( "VariableNameList" ) END;
- REPEAT
- flags := {};
- position := token.position;
- IdentifierDefinition( varname, access,TRUE);
- variable := SyntaxTree.NewVariable( position, varname );
- CommentSymbol(variable);
- IF Optional(Scanner.LeftBrace) THEN variable.SetModifiers(Flags()) END;
- IF Optional(Scanner.Becomes) THEN variable.SetInitializer (Expression());
- ELSIF Optional(Scanner.Extern) & MandatoryString(string) THEN variable.SetExternalName(string); END;
- variable.SetAccess(access);
- scope.AddVariable(variable);
- UNTIL ~Optional( Scanner.Comma );
- IF Trace THEN E( "VariableNameList" ) END;
- END VariableNameList;
- (** VariableDeclaration = VariableNameList ':' Type. **)
- PROCEDURE VariableDeclaration(parentScope: SyntaxTree.Scope );
- VAR
- variable, firstVariable: SyntaxTree.Variable; type: SyntaxTree.Type;
- BEGIN
- IF Trace THEN S( "VariableDeclaration" ) END;
- firstVariable := parentScope.lastVariable;
- VariableNameList( parentScope );
- Check( Scanner.Colon );
- type := Type( SyntaxTree.invalidIdentifier, parentScope );
- variable := firstVariable;
- IF firstVariable # NIL THEN variable := firstVariable.nextVariable ELSE variable := parentScope.firstVariable END;
- WHILE variable # NIL DO
- variable.SetType( type );
- variable := variable.nextVariable;
- END;
- IF Trace THEN E( "VariableDeclaration" ) END;
- END VariableDeclaration;
- (** TypeDeclaration = IdentifierDefinition '=' Type.**)
- PROCEDURE TypeDeclaration(parentScope: SyntaxTree.Scope);
- VAR name: SyntaxTree.Identifier; position: Position; type: SyntaxTree.Type; typeDeclaration: SyntaxTree.TypeDeclaration; access: SET;
- BEGIN
- IF Trace THEN S( "TypeDeclaration" ) END;
- position := token.position;
- IdentifierDefinition( name, access,FALSE);
- typeDeclaration := SyntaxTree.NewTypeDeclaration( position,name);
- CommentSymbol(typeDeclaration);
- Check( Scanner.Equal );
- type := Type( name , parentScope);
- type.SetTypeDeclaration(typeDeclaration);
- typeDeclaration.SetDeclaredType(type);
- (*
- type.SetName(typeDeclaration.name); (* don't do that: overwrites global names ! *)
- *)
- typeDeclaration.SetAccess(access);
- parentScope.AddTypeDeclaration( typeDeclaration );
- IF Trace THEN E( "TypeDeclaration" ) END;
- END TypeDeclaration;
- (** ConstDeclaration = IdentifierDefinition '=' Expression. **)
- PROCEDURE ConstDeclaration(parentScope: SyntaxTree.Scope );
- VAR name: SyntaxTree.Identifier; position: Position; constant: SyntaxTree.Constant; expression: SyntaxTree.Expression; access: SET;
- BEGIN
- IF Trace THEN S( "ConstDeclaration" ) END;
- IdentifierDefinition( name, access, FALSE);
- position := token.position;
- constant := SyntaxTree.NewConstant( position, name );
- CommentSymbol(constant);
- constant.SetAccess(access);
- Check( Scanner.Equal );
- expression := Expression();
- constant.SetValue( expression );
- parentScope.AddConstant( constant );
- IF Trace THEN E( "ConstDeclaration" ) END;
- END ConstDeclaration;
- (** DeclarationSequence = { 'const' [ConstDeclaration] {';' [ConstDeclaration]}
- |'type' [TypeDeclaration] {';' [TypeDeclaration]}
- |'var' [VariableDeclaration] {';' [VariableDeclaration]}
- | ProcedureDeclaration
- | OperatorDeclaration
- | ';'
- }
- **)
- PROCEDURE DeclarationSequence( parentScope: SyntaxTree.Scope);
- VAR previousScope: SyntaxTree.Scope;
- BEGIN
- previousScope := currentScope;
- currentScope := parentScope;
- IF Trace THEN S( "DeclarationSequence" ) END;
- IF Lax THEN
- LOOP
- Ignore(Scanner.Semicolon);
- IF Optional(Scanner.Const) THEN
- WHILE Peek(Scanner.Identifier) DO ConstDeclaration(parentScope); Ignore(Scanner.Semicolon) END;
- ELSIF Optional(Scanner.Type) THEN
- WHILE Peek(Scanner.Identifier) DO TypeDeclaration(parentScope); Ignore(Scanner.Semicolon) END;
- ELSIF Optional(Scanner.Var) THEN
- WHILE Peek(Scanner.Identifier) DO VariableDeclaration(parentScope); Ignore(Scanner.Semicolon); END;
- ELSIF Optional(Scanner.Procedure) THEN
- ProcedureDeclaration(parentScope); Ignore(Scanner.Semicolon)
- ELSIF Optional(Scanner.Operator) THEN
- OperatorDeclaration(parentScope); Ignore(Scanner.Semicolon);
- ELSE
- EXIT
- END;
- END;
- ELSE
- LOOP
- IF Optional( Scanner.Const ) THEN
- REPEAT
- IF Peek(Scanner.Identifier) THEN ConstDeclaration( parentScope ) END
- UNTIL ~Optional( Scanner.Semicolon )
- ELSIF Optional( Scanner.Type ) THEN
- REPEAT
- IF Peek(Scanner.Identifier) THEN TypeDeclaration( parentScope) END
- UNTIL ~Optional( Scanner.Semicolon )
- ELSIF Optional( Scanner.Var ) THEN
- REPEAT
- IF Peek(Scanner.Identifier) THEN VariableDeclaration( parentScope ) END
- UNTIL ~Optional( Scanner.Semicolon )
- ELSIF Optional(Scanner.Operator) THEN
- OperatorDeclaration( parentScope);
- ELSIF Optional( Scanner.Procedure ) THEN
- ProcedureDeclaration( parentScope );
- ELSE EXIT
- END;
- Ignore(Scanner.Semicolon)
- END;
- END;
- currentScope := previousScope;
- IF Trace THEN E( "DeclarationSequence" ) END;
- END DeclarationSequence;
- (**
- ImportList = 'import' Import { ',' Import } ';'.
- Import = Identifier [':=' Identifier] ['in' Identifier].
- **)
- PROCEDURE ImportList( scope: SyntaxTree.Scope );
- VAR alias, name, context: SyntaxTree.Identifier; import: SyntaxTree.Import; position, idPosition: Position; aliased: BOOLEAN;
- BEGIN
- IF Trace THEN S( "ImportList" ) END;
- (* import token already consumed *)
- REPEAT
- alias := Identifier(idPosition);
- position := token.position;
- IF alias # SyntaxTree.invalidIdentifier THEN
- aliased := Optional( Scanner.Becomes );
- IF aliased THEN name := Identifier(idPosition) ELSE name := alias END;
- import := SyntaxTree.NewImport( position, alias, name, TRUE );
- CommentSymbol(import);
- IF Optional(Scanner.In) THEN
- position := token.position;
- context := Identifier(idPosition);
- IF context # SyntaxTree.invalidIdentifier THEN import.SetContext(context) END;
- ELSIF aliased & (name = alias) THEN
- Basic.Warning(diagnostics, scanner.source^, position, "duplicated import alias");
- END;
- WITH scope:
- SyntaxTree.ModuleScope DO
- scope.AddImport( import );
- | SyntaxTree.CellScope DO
- scope.AddImport( import );
- END;
- END;
- UNTIL ~Optional( Scanner.Comma );
- IF Lax THEN Ignore(Scanner.Semicolon) ELSE Check( Scanner.Semicolon ) END;
- IF Trace THEN E( "ImportList" ); END;
- END ImportList;
- (** Module = ('module' | 'cellnet' [Flags]) Identifier ['in' Identifier]';'
- {ImportList} DeclarationSequence [Body]
- 'end' Identifier '.'.
- **)
- PROCEDURE Module*(): SyntaxTree.Module;
- VAR moduleName, context: SyntaxTree.Identifier; module: SyntaxTree.Module; position: Position; isCellNet: BOOLEAN;
- scannerDiagnostics: Diagnostics.Diagnostics; modifiers: SyntaxTree.Modifier; (* c: SyntaxTree.Comment; *)
- BEGIN
- IF Trace THEN S( "Module" ) END;
- position := token.position;
- moduleScope := SyntaxTree.NewModuleScope(); (* needed to feed in comment already before module starts *)
- currentScope := moduleScope;
- isCellNet := Optional(Scanner.CellNet);
- IF isCellNet OR Mandatory( Scanner.Module ) THEN
- (*c := recentComment; recentComment := NIL;*)
- IF isCellNet & Optional(Scanner.LeftBrace) THEN modifiers := Flags() ELSE modifiers := NIL END;
- moduleName := Identifier(position);
- module := SyntaxTree.NewModule( scanner.source^, position, moduleName, moduleScope, scanner.case );
- CommentSymbol(module);
- (*
- module.SetComment(c);
- SetNextInComment(c, module);
- *)
- IF isCellNet THEN module.SetCellNet(TRUE); module.SetModifiers(modifiers); END;
- module.SetType(SyntaxTree.moduleType);
- IF Optional(Scanner.In) THEN
- position := token.position;
- context := Identifier(position);
- module.SetContext(context);
- END;
- IF Lax THEN Ignore(Scanner.Semicolon) ELSE Check(Scanner.Semicolon) END;
- IF ~Peek(Scanner.EndOfText) THEN
- module.SetClosingComment(recentComment);
- SetNextInComment(recentComment, module);
- recentComment := NIL;
- END;
- WHILE Optional(Scanner.Import) DO ImportList(moduleScope) END;
- DeclarationSequence( moduleScope);
- IF Peek(Scanner.Begin) OR Peek(Scanner.Code) THEN
- moduleScope.SetBodyProcedure(BodyProcedure(moduleScope)); (* insert empty body procedure if necessary *)
- END;
- Check(Scanner.End);
- IF ExpectThisIdentifier( moduleName ) THEN
- IF Symbol() # Scanner.Period THEN
- Error( token.position, Scanner.Period, "" )
- ELSIF ~error & ~scanner.error THEN (* read ahead to read comments and to check for next module *)
- scanner.ResetCase;
- scannerDiagnostics := NIL;
- scanner.ResetErrorDiagnostics(scannerDiagnostics);
- NextToken;
- scanner.ResetErrorDiagnostics(scannerDiagnostics);
- END;
- (*
- (* do not use Check for not reading after end of module *)
- IF ~Peek(Scanner.Module) & ~Peek(Scanner.CellNet) THEN
- SetNextInComment(recentComment,module);
- module.SetClosingComment(recentComment);
- recentComment := NIL;
- END;
- *)
- END;
- END;
- IF conditionalCount # 0 THEN Error (token.position, Basic.InvalidCode, "missing conditional end") END;
- IF Trace THEN E( "Module" ) END;
- RETURN module
- END Module;
- (** check if another module declaration is available after recent module parsing -> for parsing and compiling multiple modules within a single file **)
- PROCEDURE NextModule*(): BOOLEAN;
- BEGIN
- RETURN Peek(Scanner.Module) OR Peek(Scanner.CellNet);
- END NextModule;
- END Parser;
- (* utilities *)
- PROCEDURE AppendModifier(VAR list: SyntaxTree.Modifier; modifier: SyntaxTree.Modifier);
- VAR this, next: SyntaxTree.Modifier;
- BEGIN
- IF list = NIL THEN list := modifier
- ELSE
- this := list;
- next := list.nextModifier;
- WHILE next # NIL DO
- this := next;
- next := this.nextModifier;
- END;
- this.SetNext(modifier);
- END;
- END AppendModifier;
- (** parser retrieval **)
- PROCEDURE NewParser*( scanner: Scanner.Scanner; diagnostics: Diagnostics.Diagnostics; CONST definitions: ARRAY OF CHAR): Parser;
- VAR parser: Parser;
- BEGIN
- NEW( parser, scanner, diagnostics, definitions ); RETURN parser;
- END NewParser;
- END FoxParser.
- System.FreeDownTo FoxParser ~
|