Browse Source

fcl-passrc: refactor ParseStatement, split ParseElse

mattias 2 years ago
parent
commit
5b9d738da0
1 changed files with 265 additions and 215 deletions
  1. 265 215
      packages/fcl-passrc/src/pparser.pp

+ 265 - 215
packages/fcl-passrc/src/pparser.pp

@@ -284,6 +284,9 @@ type
   private
     const FTokenRingSize = 32;
     type
+
+      { TTokenRec }
+
       TTokenRec = record
         Token: TToken;
         AsString: String;
@@ -293,6 +296,25 @@ type
         IsEscaped : Boolean;
       end;
       PTokenRec = ^TTokenRec;
+
+      { TParseStatementParams }
+
+      TParseStatementParams = record
+        Parser: TPasParser;
+        Parent: TPasImplBlock;
+        NewImplElement: TPasImplElement;
+        CurBlock: TPasImplBlock;
+        { $IFDEF VerbosePasParserWriteln}
+        function GetPrefix: string;
+        { $ENDIF VerbosePasParserWriteln}
+        function CloseBlock: boolean; // true if parent reached
+        function CloseStatement(CloseIfs: boolean): boolean; // true if parent reached
+        procedure CreateBlock(NewBlock: TPasImplBlock);
+        function CreateElement(AClass: TPTreeElement): TPasElement; overload;
+        function CreateElement(AClass: TPTreeElement; const ASrcPos: TPasSourcePos): TPasElement; overload;
+        function ParseElse: boolean; // true if it was a case-else
+      end;
+      //PParseStatementParams = ^TParseStatementParams;
   private
     FCurModule: TPasModule;
     FCurTokenEscaped: Boolean;
@@ -6097,83 +6119,26 @@ end;
 procedure TPasParser.ParseStatement(Parent: TPasImplBlock;
   out NewImplElement: TPasImplElement);
 var
-  CurBlock: TPasImplBlock;
+  Params: TParseStatementParams;
   PrevToken: TToken;
-
-  {$IFDEF VerbosePasParserWriteln}
-  function i: string;
-  var
-    c: TPasElement;
-  begin
-    Result:='ParseStatement ';
-    c:=CurBlock;
-    while c<>nil do begin
-      Result:=Result+'  ';
-      c:=c.Parent;
-    end;
-  end;
-  {$ENDIF VerbosePasParserWriteln}
-
-  function CloseBlock: boolean; // true if parent reached
-  var C: TPasImplBlockClass;
-    NeedUnget: Boolean;
-  begin
-    C:=TPasImplBlockClass(CurBlock.ClassType);
-    if C=TPasImplExceptOn then
-      begin
-      Engine.FinishScope(stExceptOnStatement,CurBlock);
-      NeedUnget:=CurToken=tkSemicolon;
-      if NeedUnget then
-        NextToken;
-      if (CurToken in [tkend,tkelse])
-          or ((CurToken=tkIdentifier) and (lowercase(CurTokenString)='on')) then
-        // ok
-      else
-        ParseExcExpectedAorB('end','on');
-      if NeedUnget then
-        UngetToken;
-      end
-    else if C=TPasImplWithDo then
-      Engine.FinishScope(stWithExpr,CurBlock);
-    CurBlock:=CurBlock.Parent as TPasImplBlock;
-    Result:=CurBlock=Parent;
-  end;
-
-  function CloseStatement(CloseIfs: boolean): boolean; // true if parent reached
-  begin
-    if CurBlock=Parent then exit(true);
-    while CurBlock.CloseOnSemicolon
-        or (CloseIfs and (CurBlock is TPasImplIfElse)) do
-      if CloseBlock then exit(true);
-    Result:=false;
-  end;
-
-  procedure CreateBlock(NewBlock: TPasImplBlock);
-  begin
-    CurBlock.AddElement(NewBlock);
-    CurBlock:=NewBlock;
-    if NewImplElement=nil then NewImplElement:=CurBlock;
-  end;
+  CmdElem: TPasImplElement;
 
   procedure CheckStatementCanStart;
   begin
-    if (CurBlock.Elements.Count=0) then
+    if (Params.CurBlock.Elements.Count=0) then
       exit; // at start of block
     if PrevToken in [tkSemicolon,tkColon,tkElse,tkotherwise] then
       exit;
     {$IFDEF VerbosePasParserWriteln}
-    writeln('TPasParser.ParseStatement.CheckSemicolon Prev=',PrevToken,' Cur=',CurToken,' ',CurBlock.ClassName,' ',CurBlock.Elements.Count,' ',TObject(CurBlock.Elements[0]).ClassName);
+    writeln('TPasParser.ParseStatement.CheckStatementCanStart Prev=',PrevToken,' Cur=',CurToken,' ',Params.CurBlock.ClassName,' ',Params.CurBlock.Elements.Count,' ',TObject(Params.CurBlock.Elements[0]).ClassName);
     {$ENDIF VerbosePasParserWriteln}
     // last statement not complete -> semicolon is missing
     ParseExcTokenError('Semicolon');
   end;
 
-var
-  CmdElem: TPasImplElement;
-
   procedure AddStatement(El: TPasImplElement);
   begin
-    CurBlock.AddElement(El);
+    Params.CurBlock.AddElement(El);
     CmdElem:=El;
     UngetToken;
   end;
@@ -6193,10 +6158,11 @@ var
 
 begin
   NewImplElement:=nil;
-  El:=nil;
-  Left:=nil;
+  Params.Parser:=Self;
+  Params.NewImplElement:=nil;
+  Params.CurBlock:=Parent;
+  Params.Parent:=Parent;
 
-  CurBlock := Parent;
   while True do
   begin
     PrevToken:=CurToken;
@@ -6208,110 +6174,56 @@ begin
     tkasm:
       begin
       CheckStatementCanStart;
-      El:=TPasImplElement(CreateElement(TPasImplAsmStatement,'',CurBlock,CurTokenPos));
+      El:=TPasImplElement(Params.CreateElement(TPasImplAsmStatement));
       ParseAsmBlock(TPasImplAsmStatement(El));
-      CurBlock.AddElement(El);
-      if NewImplElement=nil then NewImplElement:=CurBlock;
-      if CloseStatement(False) then
+      Params.CurBlock.AddElement(El);
+      if Params.NewImplElement=nil then Params.NewImplElement:=Params.CurBlock;
+      if Params.CloseStatement(False) then
         break;
       end;
     tkbegin:
       begin
       CheckStatementCanStart;
-      El:=TPasImplElement(CreateElement(TPasImplBeginBlock,'',CurBlock,CurTokenPos));
-      CreateBlock(TPasImplBeginBlock(El));
+      El:=TPasImplElement(Params.CreateElement(TPasImplBeginBlock));
+      Params.CreateBlock(TPasImplBeginBlock(El));
       end;
     tkrepeat:
       begin
       CheckStatementCanStart;
-      El:=TPasImplRepeatUntil(CreateElement(TPasImplRepeatUntil,'',CurBlock,CurTokenPos));
-      CreateBlock(TPasImplRepeatUntil(El));
+      El:=TPasImplRepeatUntil(Params.CreateElement(TPasImplRepeatUntil));
+      Params.CreateBlock(TPasImplRepeatUntil(El));
       end;
     tkIf:
       begin
       CheckStatementCanStart;
       SrcPos:=CurTokenPos;
       NextToken;
-      Left:=DoParseExpression(CurBlock);
+      Left:=DoParseExpression(Params.CurBlock);
       UngetToken;
-      El:=TPasImplIfElse(CreateElement(TPasImplIfElse,'',CurBlock,SrcPos));
+      El:=TPasImplIfElse(Params.CreateElement(TPasImplIfElse,SrcPos));
       TPasImplIfElse(El).ConditionExpr:=Left;
       Left.Parent:=El;
-      //WriteLn(i,'IF Condition="',Condition,'" Token=',CurTokenText);
-      CreateBlock(TPasImplIfElse(El));
+      //WriteLn(GetPrefix,'IF Condition="',Condition,'" Token=',CurTokenText);
+      Params.CreateBlock(TPasImplIfElse(El));
       ExpectToken(tkthen);
       end;
     tkelse,tkotherwise:
       // ELSE can close multiple blocks, similar to semicolon
-      repeat
-        {$IFDEF VerbosePasParserWriteln}
-        writeln('TPasParser.ParseStatement ELSE CurBlock=',CurBlock.ClassName);
-        {$ENDIF}
-        if CurBlock is TPasImplIfElse then
-          begin
-          if TPasImplIfElse(CurBlock).IfBranch=nil then
-          begin
-            // empty THEN statement  e.g. if condition then else
-            El:=TPasImplCommand(CreateElement(TPasImplCommand,'', CurBlock,CurTokenPos));
-            CurBlock.AddElement(El); // this sets TPasImplIfElse(CurBlock).IfBranch:=El
-          end;
-          if (CurToken=tkelse) and (TPasImplIfElse(CurBlock).ElseBranch=nil) then
-            begin
-              // Check if next token is an else too
-              NextToken;
-              if CurToken = tkElse then
-                begin
-                  // empty ELSE statement without semicolon e.g. if condition then [...] else else
-                  El:=TPasImplCommand(CreateElement(TPasImplCommand,'', CurBlock,CurTokenPos));
-                  CurBlock.AddElement(El); // this sets TPasImplIfElse(CurBlock).IfBranch:=El
-                  CloseBlock;
-                end;
-              UngetToken;
-              break; // add next statement as ElseBranch
-            end;
-          end
-        else if (CurBlock is TPasImplTryExcept) and (CurToken=tkelse) then
-          begin
-          // close TryExcept handler and open an TryExceptElse handler
-          CloseBlock;
-          El:=TPasImplTryExceptElse(CreateElement(TPasImplTryExceptElse,'',CurBlock,CurTokenPos));
-          TPasImplTry(CurBlock).ElseBranch:=TPasImplTryExceptElse(El);
-          CurBlock:=TPasImplTryExceptElse(El);
-          break;
-          end
-        else if (CurBlock is TPasImplCaseStatement) then
-          begin
-          UngetToken;
-          // Note: a TPasImplCaseStatement is parsed by a call of ParseStatement,
-          //       so it must be the top level block
-          if CurBlock<>Parent then
-            CheckToken(tkSemicolon);
-          exit;
-          end
-        else if (CurBlock is TPasImplWhileDo)
-            or (CurBlock is TPasImplForLoop)
-            or (CurBlock is TPasImplWithDo)
-            or (CurBlock is TPasImplRaise)
-            or (CurBlock is TPasImplGoto)
-            or (CurBlock is TPasImplExceptOn) then
-          // simply close block
-        else
-          ParseExcSyntaxError;
-        CloseBlock;
-      until false;
+      if Params.ParseElse then
+        exit;
     tkwhile:
       begin
         // while Condition do
         CheckStatementCanStart;
         SrcPos:=CurTokenPos;
         NextToken;
-        Left:=DoParseExpression(CurBlock);
+        Left:=DoParseExpression(Params.CurBlock);
         UngetToken;
-        //WriteLn(i,'WHILE Condition="',Condition,'" Token=',CurTokenText);
-        El:=TPasImplWhileDo(CreateElement(TPasImplWhileDo,'',CurBlock,SrcPos));
+        //WriteLn(GetPrefix,'WHILE Condition="',Condition,'" Token=',CurTokenText);
+        El:=TPasImplWhileDo(Params.CreateElement(TPasImplWhileDo,SrcPos));
         TPasImplWhileDo(El).ConditionExpr:=Left;
         Left.Parent:=El;
-        CreateBlock(TPasImplWhileDo(El));
+        Params.CreateBlock(TPasImplWhileDo(El));
         ExpectToken(tkdo);
       end;
     tkgoto:
@@ -6319,8 +6231,8 @@ begin
       CheckStatementCanStart;
       SrcPos:=CurTokenPos;
       ExpectTokens([tkIdentifier,tkNumber]);
-      ImplGoto:=TPasImplGoto(CreateElement(TPasImplGoto,'',CurBlock,SrcPos));
-      CreateBlock(ImplGoto);
+      ImplGoto:=TPasImplGoto(Params.CreateElement(TPasImplGoto,SrcPos));
+      Params.CreateBlock(ImplGoto);
       ImplGoto.LabelName:=CurTokenString;
       end;
     tkfor:
@@ -6328,7 +6240,7 @@ begin
         // for VarName := StartValue to EndValue do
         // for VarName in Expression do
         CheckStatementCanStart;
-        El:=TPasImplForLoop(CreateElement(TPasImplForLoop,'',CurBlock,CurTokenPos));
+        El:=TPasImplForLoop(Params.CreateElement(TPasImplForLoop));
         ExpectIdentifier;
         Expr:=CreatePrimitiveExpr(El,pekIdent,CurTokenString);
         TPasImplForLoop(El).VariableName:=Expr;
@@ -6372,8 +6284,8 @@ begin
         if (CurToken<>tkDo) then
           ParseExcTokenError(TokenInfos[tkDo]);
         Engine.FinishScope(stForLoopHeader,El);
-        CreateBlock(TPasImplForLoop(El));
-        //WriteLn(i,'FOR "',VarName,'" := ',StartValue,' to ',EndValue,' Token=',CurTokenText);
+        Params.CreateBlock(TPasImplForLoop(El));
+        //WriteLn(GetPrefix,'FOR "',VarName,'" := ',StartValue,' to ',EndValue,' Token=',CurTokenText);
       end;
     tkwith:
       begin
@@ -6382,21 +6294,21 @@ begin
         CheckStatementCanStart;
         SrcPos:=CurTokenPos;
         NextToken;
-        El:=TPasImplWithDo(CreateElement(TPasImplWithDo,'',CurBlock,SrcPos));
-        Expr:=DoParseExpression(CurBlock);
-        //writeln(i,'WITH Expr="',Expr,'" Token=',CurTokenText);
+        El:=TPasImplWithDo(Params.CreateElement(TPasImplWithDo,SrcPos));
+        Expr:=DoParseExpression(Params.CurBlock);
+        //writeln(GetPrefix,'WITH Expr="',Expr,'" Token=',CurTokenText);
         TPasImplWithDo(El).AddExpression(Expr);
         Expr.Parent:=El;
         Engine.BeginScope(stWithExpr,Expr);
-        CreateBlock(TPasImplWithDo(El));
+        Params.CreateBlock(TPasImplWithDo(El));
         repeat
           if CurToken=tkdo then break;
           if CurToken<>tkComma then
             ParseExcTokenError(TokenInfos[tkdo]);
           NextToken;
-          Expr:=DoParseExpression(CurBlock);
-          //writeln(i,'WITH ...,Expr="',Expr,'" Token=',CurTokenText);
-          TPasImplWithDo(CurBlock).AddExpression(Expr);
+          Expr:=DoParseExpression(Params.CurBlock);
+          //writeln(GetPrefix,'WITH ...,Expr="',Expr,'" Token=',CurTokenText);
+          TPasImplWithDo(Params.CurBlock).AddExpression(Expr);
           Engine.BeginScope(stWithExpr,Expr);
         until false;
       end;
@@ -6405,30 +6317,30 @@ begin
         CheckStatementCanStart;
         SrcPos:=CurTokenPos;
         NextToken;
-        Left:=DoParseExpression(CurBlock);
+        Left:=DoParseExpression(Params.CurBlock);
         UngetToken;
-        //writeln(i,'CASE OF Expr="',Expr,'" Token=',CurTokenText);
+        //writeln(GetPrefix,'CASE OF Expr="',Expr,'" Token=',CurTokenText);
         ExpectToken(tkof);
-        El:=TPasImplCaseOf(CreateElement(TPasImplCaseOf,'',CurBlock,SrcPos));
+        El:=TPasImplCaseOf(Params.CreateElement(TPasImplCaseOf,SrcPos));
         TPasImplCaseOf(El).CaseExpr:=Left;
         Left.Parent:=El;
-        CreateBlock(TPasImplCaseOf(El));
+        Params.CreateBlock(TPasImplCaseOf(El));
         repeat
           NextToken;
-          //writeln(i,'CASE OF Token=',CurTokenText);
+          //writeln(GetPrefix,'CASE OF Token=',CurTokenText);
           case CurToken of
           tkend:
             begin
-            if CurBlock.Elements.Count=0 then
+            if Params.CurBlock.Elements.Count=0 then
               ParseExc(nParserExpectCase,SParserExpectCase);
             break; // end without else
             end;
           tkelse,tkotherwise:
             begin
               // create case-else block
-              El:=TPasImplCaseElse(CreateElement(TPasImplCaseElse,'',CurBlock,CurTokenPos));
-              TPasImplCaseOf(CurBlock).ElseBranch:=TPasImplCaseElse(El);
-              CreateBlock(TPasImplCaseElse(El));
+              El:=TPasImplCaseElse(Params.CreateElement(TPasImplCaseElse));
+              TPasImplCaseOf(Params.CurBlock).ElseBranch:=TPasImplCaseElse(El);
+              Params.CreateBlock(TPasImplCaseElse(El));
               El:=nil;
               break;
             end
@@ -6436,31 +6348,31 @@ begin
             // read case values
             repeat
               SrcPos:=CurTokenPos;
-              Left:=DoParseExpression(CurBlock);
-              //writeln(i,'CASE value="',Expr,'" Token=',CurTokenText);
-              if CurBlock is TPasImplCaseStatement then
+              Left:=DoParseExpression(Params.CurBlock);
+              //writeln(GetPrefix,'CASE value="',Expr,'" Token=',CurTokenText);
+              if Params.CurBlock is TPasImplCaseStatement then
                 begin
-                TPasImplCaseStatement(CurBlock).AddExpression(Left);
+                TPasImplCaseStatement(Params.CurBlock).AddExpression(Left);
                 Left:=nil;
                 end
               else
                 begin
-                El:=TPasImplCaseStatement(CreateElement(TPasImplCaseStatement,'',CurBlock,SrcPos));
+                El:=TPasImplCaseStatement(Params.CreateElement(TPasImplCaseStatement,SrcPos));
                 TPasImplCaseStatement(El).AddExpression(Left);
                 Left:=nil;
-                CreateBlock(TPasImplCaseStatement(El));
+                Params.CreateBlock(TPasImplCaseStatement(El));
                 El:=nil;
                 end;
-              //writeln(i,'CASE after value Token=',CurTokenText);
+              //writeln(GetPrefix,'CASE after value Token=',CurTokenText);
               if (CurToken=tkComma) then
                 NextToken
               else if (CurToken<>tkColon) then
                 ParseExcTokenError(TokenInfos[tkComma]);
             until Curtoken=tkColon;
             // read statement
-            ParseStatement(CurBlock,SubBlock);
+            ParseStatement(Params.CurBlock,SubBlock);
             // CurToken is now at last token of case-statement
-            CloseBlock;
+            Params.CloseBlock;
             if CurToken<>tkSemicolon then
               NextToken;
             if (CurToken in [tkSemicolon,tkelse,tkend,tkotherwise]) then
@@ -6473,53 +6385,53 @@ begin
         until false;
         if CurToken=tkend then
         begin
-          if CloseBlock then break;
-          if CloseStatement(false) then break;
+          if Params.CloseBlock then break;
+          if Params.CloseStatement(false) then break;
         end;
       end;
     tktry:
       begin
       CheckStatementCanStart;
-      El:=TPasImplTry(CreateElement(TPasImplTry,'',CurBlock,CurTokenPos));
-      CreateBlock(TPasImplTry(El));
+      El:=TPasImplTry(Params.CreateElement(TPasImplTry));
+      Params.CreateBlock(TPasImplTry(El));
       end;
     tkfinally:
       begin
-        if CloseStatement(true) then
+        if Params.CloseStatement(true) then
         begin
           UngetToken;
           break;
         end;
-        if CurBlock is TPasImplTry then
+        if Params.CurBlock is TPasImplTry then
         begin
-          El:=TPasImplTryFinally(CreateElement(TPasImplTryFinally,'',CurBlock,CurTokenPos));
-          TPasImplTry(CurBlock).FinallyExcept:=TPasImplTryFinally(El);
-          CurBlock:=TPasImplTryFinally(El);
+          El:=TPasImplTryFinally(Params.CreateElement(TPasImplTryFinally));
+          TPasImplTry(Params.CurBlock).FinallyExcept:=TPasImplTryFinally(El);
+          Params.CurBlock:=TPasImplTryFinally(El);
           El:=nil;
         end else
           ParseExcSyntaxError;
       end;
     tkexcept:
       begin
-        if CloseStatement(true) then
+        if Params.CloseStatement(true) then
         begin
           UngetToken;
           break;
         end;
-        if CurBlock is TPasImplTry then
+        if Params.CurBlock is TPasImplTry then
         begin
-          //writeln(i,'EXCEPT');
-          El:=TPasImplTryExcept(CreateElement(TPasImplTryExcept,'',CurBlock,CurTokenPos));
-          TPasImplTry(CurBlock).FinallyExcept:=TPasImplTryExcept(El);
-          CurBlock:=TPasImplTryExcept(El);
+          //writeln(GetPrefix,'EXCEPT');
+          El:=TPasImplTryExcept(Params.CreateElement(TPasImplTryExcept));
+          TPasImplTry(Params.CurBlock).FinallyExcept:=TPasImplTryExcept(El);
+          Params.CurBlock:=TPasImplTryExcept(El);
         end else
           ParseExcSyntaxError;
       end;
     tkraise:
       begin
       CheckStatementCanStart;
-      ImplRaise:=TPasImplRaise(CreateElement(TPasImplRaise,'',CurBlock,CurTokenPos));
-      CreateBlock(ImplRaise);
+      ImplRaise:=TPasImplRaise(Params.CreateElement(TPasImplRaise));
+      Params.CreateBlock(ImplRaise);
       NextToken;
       If Curtoken in [tkElse,tkEnd,tkSemicolon,tkotherwise] then
         // raise without object
@@ -6541,54 +6453,54 @@ begin
     tkend:
       begin
         // Note: ParseStatement should return with CurToken at last token of the statement
-        if CloseStatement(true) then
+        if Params.CloseStatement(true) then
         begin
           // there was none requiring an END
           UngetToken;
           break;
         end;
         // still a block left
-        if CurBlock is TPasImplBeginBlock then
+        if Params.CurBlock is TPasImplBeginBlock then
         begin
           // close at END
-          if CloseBlock then break; // close end
-          if CloseStatement(false) then break;
-        end else if CurBlock is TPasImplCaseElse then
+          if Params.CloseBlock then break; // close end
+          if Params.CloseStatement(false) then break;
+        end else if Params.CurBlock is TPasImplCaseElse then
         begin
-          if CloseBlock then break; // close else
-          if CloseBlock then break; // close caseof
-          if CloseStatement(false) then break;
-        end else if CurBlock is TPasImplTryHandler then
+          if Params.CloseBlock then break; // close else
+          if Params.CloseBlock then break; // close caseof
+          if Params.CloseStatement(false) then break;
+        end else if Params.CurBlock is TPasImplTryHandler then
         begin
-          if CloseBlock then break; // close finally/except
-          if CloseBlock then break; // close try
-          if CloseStatement(false) then break;
+          if Params.CloseBlock then break; // close finally/except
+          if Params.CloseBlock then break; // close try
+          if Params.CloseStatement(false) then break;
         end else
           ParseExcSyntaxError;
       end;
     tkSemiColon:
-      if CloseStatement(true) then break;
+      if Params.CloseStatement(true) then break;
     tkFinalization:
-      if CloseStatement(true) then
+      if Params.CloseStatement(true) then
         begin
         UngetToken;
         break;
         end;
     tkuntil:
       begin
-        if CloseStatement(true) then
+        if Params.CloseStatement(true) then
         begin
           UngetToken;
           break;
         end;
-        if CurBlock is TPasImplRepeatUntil then
+        if Params.CurBlock is TPasImplRepeatUntil then
         begin
           NextToken;
-          Left:=DoParseExpression(CurBlock);
+          Left:=DoParseExpression(Params.CurBlock);
           UngetToken;
-          TPasImplRepeatUntil(CurBlock).ConditionExpr:=Left;
-          //WriteLn(i,'UNTIL Condition="',Condition,'" Token=',CurTokenString);
-          if CloseBlock then break;
+          TPasImplRepeatUntil(Params.CurBlock).ConditionExpr:=Left;
+          //WriteLn(GetPrefix,'UNTIL Condition="',Condition,'" Token=',CurTokenString);
+          if Params.CloseBlock then break;
         end else
           ParseExcSyntaxError;
       end;
@@ -6613,11 +6525,11 @@ begin
           // in try except:
           // on E: Exception do
           // on Exception do
-          if CurBlock is TPasImplTryExcept then
+          if Params.CurBlock is TPasImplTryExcept then
           begin
             SrcPos:=CurTokenPos;
             ExpectIdentifier;
-            ImplExceptOn:=TPasImplExceptOn(CreateElement(TPasImplExceptOn,'',CurBlock,SrcPos));
+            ImplExceptOn:=TPasImplExceptOn(Params.CreateElement(TPasImplExceptOn,SrcPos));
             El:=ImplExceptOn;
             SrcPos:=CurSourcePos;
             Name:=CurTokenString;
@@ -6642,7 +6554,7 @@ begin
               ImplExceptOn.TypeEl:=ParseSimpleType(ImplExceptOn,SrcPos,'');
               end;
             Engine.FinishScope(stExceptOnExpr,ImplExceptOn);
-            CreateBlock(ImplExceptOn);
+            Params.CreateBlock(ImplExceptOn);
             ExpectToken(tkDo);
           end else
             ParseExcSyntaxError;
@@ -6650,7 +6562,7 @@ begin
       else
         begin
         SrcPos:=CurTokenPos;
-        Left:=DoParseExpression(CurBlock);
+        Left:=DoParseExpression(Params.CurBlock);
         case CurToken of
           tkAssign,
           tkAssignPlus,
@@ -6659,12 +6571,12 @@ begin
           tkAssignDivision:
             begin
             // assign statement
-            El:=TPasImplAssign(CreateElement(TPasImplAssign,'',CurBlock,SrcPos));
+            El:=TPasImplAssign(Params.CreateElement(TPasImplAssign,SrcPos));
             TPasImplAssign(El).Left:=Left;
             Left.Parent:=El;
             TPasImplAssign(El).Kind:=TokenToAssignKind(CurToken);
             NextToken;
-            Right:=DoParseExpression(CurBlock);
+            Right:=DoParseExpression(Params.CurBlock);
             TPasImplAssign(El).Right:=Right;
             Right.Parent:=El;
             Right:=nil;
@@ -6677,27 +6589,29 @@ begin
             else if not (Left is TPrimitiveExpr) then
               ParseExcTokenError(TokenInfos[tkSemicolon]);
             // label mark. todo: check mark identifier in the list of labels
-            El:=TPasImplLabelMark(CreateElement(TPasImplLabelMark,'', CurBlock,SrcPos));
+            El:=TPasImplLabelMark(Params.CreateElement(TPasImplLabelMark,SrcPos));
             TPasImplLabelMark(El).LabelId:=TPrimitiveExpr(Left).Value;
-            CurBlock.AddElement(El);
+            Params.CurBlock.AddElement(El);
             CmdElem:=TPasImplLabelMark(El);
             end;
         else
           // simple statement (function call)
-          El:=TPasImplSimple(CreateElement(TPasImplSimple,'',CurBlock,SrcPos));
+          El:=TPasImplSimple(Params.CreateElement(TPasImplSimple,SrcPos));
           TPasImplSimple(El).Expr:=Left;
           Left.Parent:=El;
           AddStatement(El);
         end;
 
-        if (NewImplElement=nil) and not (CmdElem is TPasImplLabelMark) then
-          NewImplElement:=CmdElem;
+        if (Params.NewImplElement=nil) and not (CmdElem is TPasImplLabelMark) then
+          Params.NewImplElement:=CmdElem;
         end;
       end;
     else
       ParseExcSyntaxError;
     end;
   end;
+
+  NewImplElement:=Params.NewImplElement;
 end;
 
 procedure TPasParser.ParseLabels(AParent: TPasElement);
@@ -8164,6 +8078,142 @@ begin
   NewExprElement := DoParseExpression(nil);
 end;
 
+{ TPasParser.TParseStatementParams }
+
+{ $IFDEF VerbosePasParserWriteln}
+function TPasParser.TParseStatementParams.GetPrefix: string;
+var
+  c: TPasElement;
+begin
+  Result:='ParseStatement ';
+  c:=CurBlock;
+  while c<>nil do begin
+    Result:=Result+'  ';
+    c:=c.Parent;
+  end;
+end;
+{ $ENDIF VerbosePasParserWriteln}
+
+function TPasParser.TParseStatementParams.CloseBlock: boolean;
+var C: TPasImplBlockClass;
+  NeedUnget: Boolean;
+  tk: TToken;
+begin
+  C:=TPasImplBlockClass(CurBlock.ClassType);
+  if C=TPasImplExceptOn then
+    begin
+    Parser.Engine.FinishScope(stExceptOnStatement,CurBlock);
+    NeedUnget:=Parser.CurToken=tkSemicolon;
+    if NeedUnget then
+      Parser.NextToken;
+    tk:=Parser.CurToken;
+    if (tk in [tkend,tkelse])
+        or ((tk=tkIdentifier) and (lowercase(Parser.CurTokenString)='on')) then
+      // ok
+    else
+      Parser.ParseExcExpectedAorB('end','on');
+    if NeedUnget then
+      Parser.UngetToken;
+    end
+  else if C=TPasImplWithDo then
+    Parser.Engine.FinishScope(stWithExpr,CurBlock);
+  CurBlock:=CurBlock.Parent as TPasImplBlock;
+  Result:=CurBlock=Parent;
+end;
+
+function TPasParser.TParseStatementParams.CloseStatement(CloseIfs: boolean
+  ): boolean;
+begin
+  if CurBlock=Parent then exit(true);
+  while CurBlock.CloseOnSemicolon
+      or (CloseIfs and (CurBlock is TPasImplIfElse)) do
+    if CloseBlock then exit(true);
+  Result:=false;
+end;
+
+procedure TPasParser.TParseStatementParams.CreateBlock(NewBlock: TPasImplBlock);
+begin
+  CurBlock.AddElement(NewBlock);
+  CurBlock:=NewBlock;
+  if NewImplElement=nil then NewImplElement:=CurBlock;
+end;
+
+function TPasParser.TParseStatementParams.CreateElement(AClass: TPTreeElement
+  ): TPasElement;
+begin
+  Result:=Parser.CreateElement(AClass,'',CurBlock,Parser.CurTokenPos);
+end;
+
+function TPasParser.TParseStatementParams.CreateElement(AClass: TPTreeElement;
+  const ASrcPos: TPasSourcePos): TPasElement;
+begin
+  Result:=Parser.CreateElement(AClass,'',CurBlock,ASrcPos);
+end;
+
+function TPasParser.TParseStatementParams.ParseElse: boolean;
+var
+  ImplCmd: TPasImplCommand;
+  TryElse: TPasImplTryExceptElse;
+begin
+  Result:=false;
+  repeat
+    {$IFDEF VerbosePasParserWriteln}
+    writeln('TPasParser.TParseStatementParams.ParseElse CurBlock=',CurBlock.ClassName);
+    {$ENDIF}
+    if CurBlock is TPasImplIfElse then
+      begin
+      if TPasImplIfElse(CurBlock).IfBranch=nil then
+      begin
+        // empty THEN statement  e.g. if condition then else
+        ImplCmd:=TPasImplCommand(CreateElement(TPasImplCommand));
+        CurBlock.AddElement(ImplCmd); // this sets TPasImplIfElse(CurBlock).IfBranch:=El
+      end;
+      if (Parser.CurToken=tkelse) and (TPasImplIfElse(CurBlock).ElseBranch=nil) then
+        begin
+          // Check if next token is an else too
+          Parser.NextToken;
+          if Parser.CurToken = tkElse then
+            begin
+              // empty ELSE statement without semicolon e.g. if condition then [...] else else
+              ImplCmd:=TPasImplCommand(CreateElement(TPasImplCommand));
+              CurBlock.AddElement(ImplCmd); // this sets TPasImplIfElse(CurBlock).IfBranch:=El
+              CloseBlock;
+            end;
+          Parser.UngetToken;
+          break; // add next statement as ElseBranch
+        end;
+      end
+    else if (CurBlock is TPasImplTryExcept) and (Parser.CurToken=tkelse) then
+      begin
+      // close TryExcept handler and open an TryExceptElse handler
+      CloseBlock;
+      TryElse:=TPasImplTryExceptElse(CreateElement(TPasImplTryExceptElse));
+      TPasImplTry(CurBlock).ElseBranch:=TryElse;
+      CurBlock:=TryElse;
+      break;
+      end
+    else if (CurBlock is TPasImplCaseStatement) then
+      begin
+      Parser.UngetToken;
+      // Note: a TPasImplCaseStatement is parsed by a call of ParseStatement,
+      //       so it must be the top level block
+      if CurBlock<>Parent then
+        Parser.CheckToken(tkSemicolon);
+      exit(true);
+      end
+    else if (CurBlock is TPasImplWhileDo)
+        or (CurBlock is TPasImplForLoop)
+        or (CurBlock is TPasImplWithDo)
+        or (CurBlock is TPasImplRaise)
+        or (CurBlock is TPasImplGoto)
+        or (CurBlock is TPasImplExceptOn) then
+      // simply close block
+    else
+      Parser.ParseExcSyntaxError;
+    CloseBlock;
+  until false;
+end;
+
 initialization
 {$IFDEF HASFS}
   DefaultFileResolverClass:=TFileResolver;