IMPLEMENTATION MODULE CGStatements;

FROM CGCode                IMPORT CGcContext;
FROM CGMethods             IMPORT CMethImplCodeGenerator;
FROM CGType                IMPORT CExpressionCodeGenerator;
FROM CGClass               IMPORT CClassDecl;
FROM CGDesig               IMPORT CDesigCodeGenerator;

FROM YaflDesignator	   IMPORT Desig;
FROM YaflExpressions 	   IMPORT ExpressionList;
FROM YaflLoops 		   IMPORT SpecialPattern, FillPattern;
FROM YaflType		   IMPORT Type, TypedNonTerminal;

FROM YaflGStatements        IMPORT  DummyStatCodeGenerator,
                                   NopStatementCodeGenerator,
                                   AssignmentCodeGenerator,
                                   MethInvStatCodeGenerator,
                                   DebugStatCodeGenerator,
                                   AssertStatCodeGenerator,
                                   InLineStatCodeGenerator,
                                   LoopStatCodeGenerator,
                                   IfStatCodeGenerator,
                                   ElsIfCodeGenerator,
                                   CaseStatCodeGenerator,
                                   CaseAltCodeGenerator,
                                   CaseTagCodeGenerator,
                                   WhatStatCodeGenerator,
                                   WhatAltCodeGenerator,
                                   WhatTagCodeGenerator,
                                   StatListCodeGenerator;
FROM YaflGMethods          IMPORT MethImplCodeGenerator;

FROM YaflStatements        IMPORT Statement;
FROM YaflGC                IMPORT YaflGC;
FROM YaflExpressions       IMPORT Expression;
FROM YaflCfg               IMPORT YaflCfg, CurrentSpot;
FROM YaflLex		   IMPORT LexicalAnalyzer;
FROM Linked                IMPORT LinkedList, StringLinkable;
FROM String                IMPORT String;
FROM YaflPredefined        IMPORT PredefItems, VoidType;
FROM YaflMetImplementation IMPORT MethodImplementation;
FROM YaflDeclarations      IMPORT SingleDataItem;
FROM YaflLiteral           IMPORT IntegerLiteral;
FROM Streams               IMPORT StdOut;
FROM YaflNTList            IMPORT NTList;
FROM YaflClasses           IMPORT ClassDeclaration;
FROM YaflParamClasses      IMPORT ClassActual, ClassFormal;
FROM List IMPORT List;
IMPORT SYSTEM;

   CLASS CDummyStatCodeGenerator;
     INHERITS DummyStatCodeGenerator(CGcContext);
     
   END CDummyStatCodeGenerator;

--------------------------------------------------------

   CLASS CNopStatementCodeGenerator;
     INHERITS NopStatementCodeGenerator(CGcContext);
     
    REDEFINE METHOD GenerateCode;
      BEGIN
      END GenerateCode;
      
   END CNopStatementCodeGenerator;
   
--------------------------------------------------------

   CLASS CAssignmentCodeGenerator;
     INHERITS AssignmentCodeGenerator(CGcContext);

     VAR
       IsFunc, IsLeftFunc: BOOLEAN;
       LeftTargetNr, TargetNr: INTEGER;
     
     METHOD Output: YaflGC;
       BEGIN
       RESULT := Ctx.Output;
       END Output;

    METHOD GenerateSelfOperation(Left: Desig;
				 Op: INTEGER;
                                 Right: TypedNonTerminal);

        METHOD GenOp;
	  BEGIN
          CASE Op OF
            LexicalAnalyzer.Plus:
              Output.SelfPlus;
              END;
            LexicalAnalyzer.Minus:
              Output.SelfMinus;
              END;
            LexicalAnalyzer.Star:
              Output.SelfStar;
              END;
            LexicalAnalyzer.Mod:
              Output.SelfMod;
              END;
            LexicalAnalyzer.Slash:
              Output.SelfSlash;
              END;
            END;
	  END GenOp;

      BEGIN
      IF Left.Functional AND Right.Functional THEN
        Left.Gc.GenerateCode;
        GenOp;
        Right.Gc.GenerateCode;
        Output.SemiColon;
        Output.WriteLn;
       ELSE
	Output.WriteLn;
	Output.LeftBrace;
	Output.WriteLn;
	Output.ObjPtr;
	Output.UniqueItem (Left.Gc.Number);
	Output.SemiColon;
	Output.WriteLn;
        Ctx.TypedNTGenerateTempVariableDecl(Right.Gc);

	Ctx.TypedNTGenerateCodeWithTarget (Right.Gc, Right.Gc.Number);
        Ctx.DesigGenerateAddressWithTarget (Left.Gc, Left.Gc.Number);

	Output.SemiColon;
	Output.WriteLn;
	Output.LeftParent;
	Output.Star;
	Output.LeftParents(2);
        Ctx.TypeGenerateCode(Right.GetType.Gc);
	Output.Star;
	Output.RightParent;
	Output.UniqueItem (Left.Gc.Number);
	Output.RightParents(2);

	GenOp;
	Output.UniqueItem (Right.Gc.Number);
	Output.SemiColon;

	Output.WriteLn;
	Output.RightBrace;
	Output.WriteLn;
        END;
      END GenerateSelfOperation;


    REDEFINE METHOD GenerateCode;
                            
      ------------------------------------
      -- The TryOptimized method will check if
      -- the assignment can be generated by
      -- using one of C's self operators such
      -- as += or -=.
      ------------------------------------
      METHOD TryOptimized: BOOLEAN;
        BEGIN                    
        IF NOT Obj.ToVoid THEN
          -- First, make sure the right part is a complete expression
          WHAT Obj.RightExpr OF
            IN Expression:
              --------------------------
              -- The two subexpressions must be defined. Self operators
              -- do not work with unary operators.
              --------------------------
              IF (TAG.FirstExpr <> VOID) AND (TAG.SecondExpr <> VOID) THEN
                --------------------------------
                -- Don't even try to optimize array operations
                --------------------------------
                IF TAG.GetType.ArrayLevel = 0 THEN
                  ---------------------
                  -- Check if the designator matches the leftmost
                  -- sub-expression.
                  ---------------------
                  IF TAG.FirstExpr.Isomorph (Obj.LeftExpr) THEN
                    ------------------------
                    -- Make sure this operator can be 
                    -- simplified.
                    ------------------------
                    IF TAG.IsArithmeticOperator THEN
                      ---------------------------------------------
                      -- Make sure there are no side effects in the
                      -- sub-expression.
                      ---------------------------------------------
                      IF NOT Obj.LeftExpr.WithSideEffects THEN
                        -----------------------------
                        -- Well. We got that far. The optimization
                        -- is kosher.
                        -----------------------------
                        GenerateSelfOperation (Obj.LeftExpr,
                                               TAG.Relation,
                                               TAG.SecondExpr);
			RESULT := TRUE;
                        END;
                      END;
                    END;
                  END;
                END;
              END;
           ELSE 
            -- If it is no expression, don't abort, simply use the 
            -- default code generation scheme
            END;
          END;
        END TryOptimized;
        
	METHOD GenerateRightPart;
	  BEGIN
	  IF IsFunc THEN
            Obj.RightExpr.Gc.GenerateCode;
	   ELSE
	    ASSERT TargetNr <> 0;
	    Output.UniqueItem (TargetNr);
	    END;
	  END GenerateRightPart;

	METHOD GenLValue;
	  BEGIN
	  IF IsLeftFunc THEN
	    Obj.LeftExpr.Gc.GenerateCode;
	   ELSE
	    Output.LeftParent;
	    Output.Star;
	    Output.LeftParent;
	    Output.LeftParent;
            Ctx.TypeGenerateCode(Obj.LeftExpr.GetType.Gc);
	    Output.Star;
	    Output.RightParent;
	    Output.UniqueItem (LeftTargetNr);
	    Output.RightParent;
	    Output.RightParent;
	    END;
	  END GenLValue;

      BEGIN
      IsLeftFunc := Obj.LeftExpr.Functional;
      IsFunc := IsLeftFunc AND Obj.RightExpr.Functional;
      IF NOT TryOptimized THEN
	IF NOT IsLeftFunc THEN
  	  LeftTargetNr := YaflCfg.UniqueNumber;
	  END;
	IF NOT IsFunc THEN
	  Output.WriteLn;
	  Output.LeftBrace;
	  Output.WriteLn;
	  Ctx.TypeGenerateCode (Obj.RightExpr.GetType.Gc);
	  TargetNr := Obj.RightExpr.HashValue;
	  Output.UniqueItem (TargetNr);
	  Output.SemiColon;
	  Output.WriteLn;
	  IF NOT IsLeftFunc THEN
	    Output.ObjPtr;
	    Output.UniqueItem (LeftTargetNr);
	    Output.SemiColon;
	    Output.WriteLn;
	    END;
	  END;
        IF Obj.ToVoid AND IsFunc THEN
          Output.LeftParent;
          Output.Void;
          Output.RightParent;
          Obj.RightExpr.Gc.GenerateCode;
          Output.SemiColon;
          Output.WriteLn;
         ELSE
	  IF NOT IsFunc THEN
  	    Ctx.TypedNTGenerateCodeWithTarget (Obj.RightExpr.Gc, TargetNr);
	    END;
	  IF NOT IsLeftFunc THEN
	    Ctx.DesigGenerateAddressWithTarget (Obj.LeftExpr.Gc, 
                                                LeftTargetNr);
	    END;
          IF Obj.LeftExpr.GetType.UseObjPtr THEN
            Output.AssignObjPtr;
            Output.LeftParent;
	    GenLValue;
            Output.Comma;
	    GenerateRightPart;
            Output.RightParent;
           ELSE
	    GenLValue;
            Output.Becomes;
	    GenerateRightPart;
            END;
          Output.SemiColon;
          Output.WriteLn;
          END;
	IF NOT IsFunc THEN
	  Output.WriteLn;
	  Output.RightBrace;
	  Output.WriteLn;
	  END;
        END;
      END GenerateCode;
      
   END CAssignmentCodeGenerator;
   
------------------------------------------------------------

   CLASS CMethInvStatCodeGenerator;
     INHERITS MethInvStatCodeGenerator(CGcContext);
   
    METHOD Output: YaflGC;
      BEGIN
      RESULT := Ctx.Output;
      END Output;

    REDEFINE METHOD GenerateCode;
      BEGIN
      WHAT Obj.NTDesignator.Gc OF
        IN CDesigCodeGenerator:
  	  TAG.GenerateNoSideEffect;
	  END;
	END;
      END GenerateCode;
      
   END CMethInvStatCodeGenerator;
   
--------------------------------------------------------

   CLASS CDebugStatCodeGenerator;
     INHERITS DebugStatCodeGenerator(CGcContext);
     
     METHOD Output: YaflGC;
      BEGIN
      RESULT := Ctx.Output;
      END Output;

   REDEFINE METHOD GenerateCode;
      BEGIN
      IF Obj.Statements <> VOID THEN
        Output.IfDefined (YaflGC.CheckDebugLabel);
        Obj.Statements.Gc.GenerateCode;
        Output.EndIf;
        END;
      END GenerateCode;
      
   END CDebugStatCodeGenerator;

--------------------------------------------------------

   CLASS CAssertStatCodeGenerator;
     INHERITS AssertStatCodeGenerator(CGcContext);

    METHOD Output: YaflGC;
      BEGIN
      RESULT := Ctx.Output;
      END Output;
     
    REDEFINE METHOD GenerateCode;
      VAR
        Funct: BOOLEAN;
      BEGIN
      Output.IfDefined (YaflGC.CheckAssertLabel);
      Funct := Obj.Expr.Functional;
      IF NOT Funct THEN
	Output.WriteLn;
	Output.LeftBrace;
	Output.WriteLn;
        Ctx.TypedNTGenerateTempVariableDecl(Obj.Expr.Gc);
        Ctx.TypedNTGenerateCodeWithTarget (Obj.Expr.Gc,
					   Obj.Expr.Gc.Number);
        END;
      Output.If;
      Output.LeftParent;
      Output.Not;
      IF Funct THEN
        Obj.Expr.Gc.GenerateCode;
       ELSE 
	Output.UniqueItem(Obj.Expr.Gc.Number);
	END;
      Output.RightParent;
      Output.FailAssert (CurrentSpot.CurrentModule.Id.Data, Obj.LineNr);
      IF NOT Funct THEN
	Output.WriteLn;
	Output.RightBrace;
	Output.WriteLn;
        END;
      Output.EndIf;
      END GenerateCode;
      
   END CAssertStatCodeGenerator;

--------------------------------------------------------

   CLASS CInLineStatCodeGenerator;
     INHERITS InLineStatCodeGenerator(CGcContext);
     
    METHOD Output: YaflGC;
      BEGIN
      RESULT := Ctx.Output;
      END Output;

    REDEFINE METHOD GenerateCode;
      BEGIN
      Output.WriteLn;
      FOR i := 0 TO Obj.GetLineList.Size - 1 DO
        WHAT Obj.GetLineList.Get(i) OF
          IN StringLinkable:
            Output.WriteString (String.Strip(TAG.GetString));
            Output.WriteLn;
            END;
          END;
        END;
      END GenerateCode;
      
   END CInLineStatCodeGenerator;

--------------------------------------------------------

  CLASS CIfStatCodeGenerator;
    INHERITS IfStatCodeGenerator(CGcContext);

    METHOD Output: YaflGC;
      BEGIN
      RESULT := Ctx.Output;
      END Output;
     
     REDEFINE METHOD GenerateCode;
       VAR
         IfAltList: NTList(IfAlt);
         BraceCount: INTEGER;
         Continue, First: BOOLEAN;
         TheIfAlt: IfAlt;
       BEGIN
       IfAltList := Obj.IfAlts;
       Continue := TRUE;
       First := TRUE;
       FOR i := 0 TO IfAltList.Size - 1 WHILE Continue DO
         TheIfAlt := IfAltList.Get(i);
         IF TheIfAlt.Never THEN
           IF YaflCfg.VerboseLevel > 0 THEN
             TheIfAlt.Warning ("Dead code eliminated [1]");
  	     END;
          ELSE
           IF NOT First THEN
             Output.Else;
             END;
           First := FALSE;
           IF TheIfAlt.Always THEN
             Continue := FALSE;
             IF YaflCfg.VerboseLevel > 0 THEN
               TheIfAlt.Warning ("Dead code eliminated [2]");
      	       END;
            ELSE
	     IF TheIfAlt.Cond.Functional THEN
               Output.If;
               Output.LeftParent;
               TheIfAlt.Cond.Gc.GenerateCode;
               Output.RightParent;
	      ELSE
	       Output.WriteLn;
	       Output.LeftBrace;
	       BraceCount := BraceCount + 1;
	       Output.Int;
	       Output.UniqueItem (TheIfAlt.Cond.Gc.Number);
	       Output.SemiColon;
	       Output.WriteLn;

	       Ctx.TypedNTGenerateCodeWithTarget (TheIfAlt.Cond.Gc,
						  TheIfAlt.Cond.Gc.Number);
	       Output.If;
	       Output.LeftParent;
	       Output.UniqueItem (TheIfAlt.Cond.Gc.Number);
	       Output.RightParent;
	       END;
             END;
           Output.LeftBrace;
           TheIfAlt.Statements.Gc.GenerateCode;
           Output.RightBrace;
           END;
         END;
       IF Continue AND (Obj.ElseStatements <> VOID) THEN
         IF NOT First THEN
           Output.Else;
           END;
         Output.LeftBrace;
         Obj.ElseStatements.Gc.GenerateCode;
         Output.RightBrace;
         END;
       FOR i := 1 TO BraceCount DO
	 Output.RightBrace;
         END;
       END GenerateCode;
       
   END CIfStatCodeGenerator;

--------------------------------------------------------

   CLASS CElsIfCodeGenerator;
     INHERITS ElsIfCodeGenerator(CGcContext);
     
    METHOD Output: YaflGC;
      BEGIN
      RESULT := Ctx.Output;
      END Output;

    REDEFINE METHOD GenerateCode;
      BEGIN
      Output.WriteLn;
      Output.Else;
      Output.If;
      Output.LeftParent;
      Obj.Cond.Gc.GenerateCode;
      Output.RightParent;
      Obj.Statements.Gc.GenerateCode;
      END GenerateCode;
      
   END CElsIfCodeGenerator;

--------------------------------------------------------

   CLASS CCaseStatCodeGenerator;
     INHERITS CaseStatCodeGenerator(CGcContext);
     
    METHOD CCaseAlt(Gc: CaseAltCodeGenerator): CCaseAltCodeGenerator;
      BEGIN
      WHAT Gc OF
        IN CCaseAltCodeGenerator:
          RESULT := TAG;
          END;
        END;
      END CCaseAlt;

    METHOD Output: YaflGC;
      BEGIN
      RESULT := Ctx.Output;
      END Output;

    REDEFINE METHOD GenerateCode;
      VAR
        DiscVar: INTEGER;
        Funct, First: BOOLEAN;
        TheCaseAlt: CaseAlt;
        TheObj: CaseStatement;

        METHOD SimpleCase (TheObj: CaseStatement): BOOLEAN;
          VAR
            TheCaseAlt: CaseAlt;
            TheCaseTag: CaseTag;
          BEGIN
          IF TheObj.CaseAlts.Size = 1 THEN
            TheCaseAlt := TheObj.CaseAlts.Get(0);
            IF TheCaseAlt.Tags.Size = 1 THEN
              TheCaseTag := TheCaseAlt.Tags.Get(0);
              RESULT := TheCaseTag.FirstValue = TheCaseTag.SecondValue;
              END;
            END;
          END SimpleCase;

      BEGIN
      TheObj := Obj;
      IF TheObj.CaseAlts = VOID THEN
        IF TheObj.ElseAlt <> VOID THEN
          TheObj.ElseAlt.Gc.GenerateCode;
          END;
       ELSIF SimpleCase (TheObj) THEN
        Output.LeftBrace;
	Funct  := TheObj.Expr.Functional;
	IF NOT Funct THEN
          Ctx.TypedNTGenerateTempVariableDecl(TheObj.Expr.Gc);
	  END;
        Output.WriteLn;
        Output.If;
        Output.LeftParent;
	IF Funct THEN
          TheObj.Expr.Gc.GenerateCode;
	 ELSE
	  Output.UniqueItem (TheObj.Expr.Gc.Number);
	  END;
        Output.Equal;
        Output.WriteInt(TheObj.CaseAlts.Get(0).Tags.Get(0).FirstValue, 0);
        Output.RightParent;
        Output.WriteLn;
        TheObj.CaseAlts.Get(0).Statements.Gc.GenerateCode;
        Output.WriteLn;
        IF TheObj.ElseAlt <> VOID THEN
          Output.Else;
          Output.WriteLn;
          TheObj.ElseAlt.Gc.GenerateCode;
          END;
        Output.RightBrace;
        Output.WriteLn;
       ELSE 
        Output.LeftBrace;
        Output.WriteString (PredefItems.Integer.CName);
        DiscVar := YaflCfg.UniqueNumber;
        Output.UniqueItem (DiscVar);
        Output.Becomes;
        TheObj.Expr.Gc.GenerateCode;
        Output.SemiColon;
        Output.Switch;
        Output.LeftParent;
        Output.UniqueItem(DiscVar);
        Output.RightParent;
        Output.LeftBrace;
        Output.WriteLn;
        FOR i := 0 TO TheObj.CaseAlts.Size - 1 DO
          TheCaseAlt := TheObj.CaseAlts.Get(i);
          IF NOT TheCaseAlt.NoLiteral THEN
            CCaseAlt(TheCaseAlt.Gc).GenerateLiteralLabels;
            IF NOT TheCaseAlt.LiteralOnly THEN
              Output.Jump(TheCaseAlt.Gc.Number);
             ELSE
              Output.LeftBrace;
              TheCaseAlt.Gc.GenerateCode;
              Output.Break;
              Output.SemiColon;
              Output.RightBrace;
              END;
            END;
          END;
        Output.Default;
        Output.Colon;
        Output.SemiColon;
        Output.WriteLn;
        First := TRUE;
        FOR i := 0 TO TheObj.CaseAlts.Size - 1 DO
          TheCaseAlt := Obj.CaseAlts.Get(i);
          IF NOT TheCaseAlt.LiteralOnly THEN
            IF NOT First THEN
              Output.Else;
              END;
            First := FALSE;
            Output.If;
            Output.LeftParent;
            CCaseAlt(TheCaseAlt.Gc).GenerateComparaisons(DiscVar);
            Output.RightParent;
            Output.LeftBrace;
            Output.WriteLn;
	    Output.DefineJumpTarget (TheCaseAlt.Gc.Number);
            TheCaseAlt.Gc.GenerateCode;
            Output.RightBrace;
            Output.WriteLn;
            END;
          END;
        IF Obj.ElseAlt <> VOID THEN
          IF NOT First THEN
            Output.Else;
            END;
          Obj.ElseAlt.Gc.GenerateCode;
         ELSE
          Output.IfDefined (YaflGC.CheckCaseLabel);
          IF NOT First THEN
            Output.Else;
            END;
          Output.FailCase (CurrentSpot.CurrentModule.Id.Data,
                           Obj.LineNr, DiscVar);
          Output.EndIf;
          END;
        Output.WriteLn;
        Output.RightBrace;
        Output.RightBrace;
        Output.WriteLn;
        END;
      END GenerateCode;
      
   END CCaseStatCodeGenerator;

--------------------------------------------------------

   CLASS CCaseAltCodeGenerator;
     INHERITS CaseAltCodeGenerator(CGcContext);
     
    METHOD Output: YaflGC; 
      BEGIN
      RESULT := Ctx.Output;
      END Output;

    METHOD CCaseTag(Gc: CaseTagCodeGenerator): CCaseTagCodeGenerator;
      BEGIN
      WHAT Gc OF
        IN CCaseTagCodeGenerator:
          RESULT := TAG;
          END;
        END;
      END CCaseTag;

    METHOD GenerateLiteralLabels;
      BEGIN
      IF Obj.Tags <> VOID THEN
        FOR i := 0 TO Obj.Tags.Size - 1 DO
          IF Obj.Tags.Get(i).UseLiteral THEN
            CCaseTag(Obj.Tags.Get(i).Gc).GenerateCases;
            END;
          END;
        END;
      END GenerateLiteralLabels;

    METHOD GenerateComparaisons(DiscNr: INTEGER);
      VAR
        First: BOOLEAN;
      BEGIN
      First := TRUE;
      IF Obj.Tags <> VOID THEN
        FOR i := 0 TO Obj.Tags.Size - 1 DO
          IF NOT Obj.Tags.Get(i).UseLiteral THEN
            IF NOT First THEN
              Output.Or;
              END;
            CCaseTag(Obj.Tags.Get(i).Gc).GenerateComparaisons(DiscNr);
            First := FALSE;
            END;
          END;
        END;
      END GenerateComparaisons;

    REDEFINE METHOD GenerateCode;
      BEGIN
      IF Obj.Statements <> VOID THEN
        Obj.Statements.Gc.GenerateCode;
        END;
      END GenerateCode;
      
   END CCaseAltCodeGenerator;

--------------------------------------------------------

   CLASS CCaseTagCodeGenerator;
     INHERITS CaseTagCodeGenerator(CGcContext);
     
    METHOD Output: YaflGC;
      BEGIN
      RESULT := Ctx.Output;
      END Output;

    METHOD GenerateValue(i: INTEGER);
      BEGIN
      IF Obj.UseChars THEN
        Output.LiteralChar (SYSTEM.CHR(i));
       ELSE
        Output.WriteInt (i, 0);
        END;
      END GenerateValue;

    METHOD GenerateCases;
      BEGIN
      ASSERT Obj.UseLiteral;
      FOR i := Obj.FirstValue TO Obj.SecondValue DO
        Output.Case;
        GenerateValue(i);
        Output.Colon;
        Output.WriteLn;
        END;
      END GenerateCases;

    METHOD GenerateComparaisons(DiscNr: INTEGER);
      BEGIN
      ASSERT NOT Obj.UseLiteral;
      Output.LeftParent;
      IF Obj.SecondExpr = VOID THEN
        Output.UniqueItem (DiscNr);
        Output.Equal;
        GenerateValue(Obj.FirstValue);
       ELSE
        Output.LeftParent;
        Output.UniqueItem (DiscNr);
        Output.GreaterEqual;
        GenerateValue(Obj.FirstValue);
        Output.RightParent;
        Output.And;
        Output.LeftParent;
        Output.UniqueItem (DiscNr);
        Output.SmallerEqual;
        GenerateValue(Obj.SecondValue);
        Output.RightParent;
        END;
      Output.RightParent;
      END GenerateComparaisons;

   END CCaseTagCodeGenerator;

--------------------------------------------------------

   CLASS CWhatStatCodeGenerator;
     INHERITS WhatStatCodeGenerator(CGcContext);
    
    METHOD Output: YaflGC;
      BEGIN
      RESULT := Ctx.Output;
      END Output; 

    REDEFINE METHOD GenerateCode;
      VAR
        SigVar: INTEGER;
        TempVar, ElseLabel, OutLabel: INTEGER;
      BEGIN
      IF Obj.WhatAlts = VOID THEN
        IF Obj.ElseAlt <> VOID THEN
          Obj.ElseAlt.Gc.GenerateCode;
          END;
       ELSE
        ElseLabel := YaflCfg.UniqueNumber;
        OutLabel := YaflCfg.UniqueNumber;
        TempVar := YaflCfg.UniqueNumber;
        Output.LeftBrace;
        Output.ObjPtr;
        Output.UniqueItem (TempVar);
        Output.SemiColon;
        Ctx.TypedNTGenerateCodeWithTarget (Obj.Expr.Gc, TempVar);
        -------------------------
        -- Store this temporary variable
        -- on the value registration stack
        -------------------------
        Output.WriteLn;
        Output.VReg;
        Output.LeftParent;
        Output.UniqueItem (TempVar);
        Output.RightParent;
        Output.SemiColon;

        Output.LeftBrace;
        Output.WriteLn;
        Output.ObjPtr;
        Output.Tag;
        Output.SemiColon;
        Output.WriteLn;

        Output.Int;
        SigVar := YaflCfg.UniqueNumber;
        Output.UniqueItem (SigVar);
        Output.SemiColon;
        Output.WriteLn;

        Output.Tag;
        Output.Becomes;
        Output.UniqueItem (TempVar);
        Output.SemiColon;
        Output.WriteLn;
                                 
        ---------------------
        -- Generate code to test whether TAG is
        -- VOID or not. This code is to be discarded
        -- altogether depending on compilation options.
        ---------------------
        Output.IfDefined (YaflGC.CheckWhatLabel);
        Output.If;
        Output.LeftParent;
        Output.Not;
        Output.Tag;
        Output.RightParent;
        Output.FailWhat (CurrentSpot.CurrentModule.Id.Data, Obj.LineNr,
                         VarNr := 0);
        Output.EndIf;
        Output.UniqueItem (SigVar);
        Output.Becomes;
        Output.FirstSignature(TRUE);
        Output.LeftParent;
        Output.Tag;
        Output.RightParent;
        Output.SemiColon;
        Output.WriteLn;

        FOR i := 0 TO Obj.WhatAlts.Size - 1 DO
          IF i <> 0 THEN
            Output.Else;
            END;
          WHAT Obj.WhatAlts.Get(i).Gc OF
            IN CWhatAltCodeGenerator: 
              TAG.GenerateWhatAlt(SigVar);
              END;
            END;
          END;
        Output.Else;
        Output.Jump(ElseLabel);
        Output.Jump(OutLabel);
        Output.RightBrace;
        Output.DefineJumpTarget (ElseLabel);
        IF Obj.ElseAlt <> VOID THEN
          Obj.ElseAlt.Gc.GenerateCode;
         ELSE
          Output.IfDefined (YaflGC.CheckWhatLabel);
          Output.FailWhat (CurrentSpot.CurrentModule.Id.Data, Obj.LineNr,
                           TempVar);
          Output.EndIf;
          END;
        Output.DefineJumpTarget (OutLabel);
        Output.RightBrace;
        END;
      END GenerateCode;
      
   END CWhatStatCodeGenerator;

--------------------------------------------------------

   CLASS CWhatAltCodeGenerator;
     INHERITS WhatAltCodeGenerator(CGcContext);
     
    METHOD Output: YaflGC;
      BEGIN
      RESULT := Ctx.Output;
      END Output;

    METHOD GenerateWhatAlt(SigVar: INTEGER);
      BEGIN
      Obj.PushTagType;
      Output.If;
      Output.LeftParent;
      WHAT Obj.WhatTagName.Gc OF
        IN CWhatTagCodeGenerator:
          TAG.GenerateWhatTag(SigVar);
          END;
        END;
      Output.RightParent;
      Output.LeftBrace;
      IF Obj.Statements <> VOID THEN
        Obj.Statements.Gc.GenerateCode;
        END;
      Output.RightBrace;
      Obj.PopTagType;
      END GenerateWhatAlt;
      
   END CWhatAltCodeGenerator;

--------------------------------------------------------

   CLASS CWhatTagCodeGenerator;
     INHERITS WhatTagCodeGenerator(CGcContext);
     
    METHOD Output: YaflGC;
      BEGIN
      RESULT := Ctx.Output;
      END Output;

    METHOD GenerateDualSig(First: BOOLEAN);
     VAR
       Temp : ClassDeclaration;
      BEGIN
      Temp := Obj.Class;
      CClassDecl.GenerateMinDualRef(Temp.Gc);
      Output.Arrow;
      IF First THEN
        Output.FirstSignature (FALSE);
       ELSE
        Output.LastSignature (FALSE);
        END;
      END GenerateDualSig;

    METHOD GenerateWhatTag(SigVar: INTEGER);
      VAR
        Cl: ClassDeclaration;
        ActualsArr: ARRAY OF ClassActual;
        FormalList: NTList(ClassFormal);
      BEGIN
      Cl := Obj.Class;
      IF Obj.Is THEN
        Output.LeftParent;
        Output.UniqueItem (SigVar);
        Output.Equal;
        GenerateDualSig(TRUE);
        Output.RightParent;
       ELSE
        Output.LeftParent;
        Output.UniqueItem (SigVar);
        Output.GreaterEqual;
        GenerateDualSig(TRUE);
        Output.RightParent;

        Output.And;

        Output.LeftParent;
        Output.UniqueItem (SigVar);
        Output.SmallerEqual;
        GenerateDualSig(FALSE);
        Output.RightParent;
        END;
      IF Obj.GetType.Actuals <> VOID THEN
        IF Obj.GetType.IsConstrained THEN
          ActualsArr := Obj.GetType.Actuals.ActualList.Row;
          ASSERT Cl.ClassFormals <> VOID;
          FormalList := Cl.ClassFormals.FormalList;
          Output.QuestionMark;
          FOR i := 0 TO ActualsArr.SIZE - 1 DO
            IF i > 0 THEN
              Output.And;
              END;
            Output.LeftParent;  
            Output.LeftParent;
            CClassDecl.GenerateCast(Obj.Class.Gc);
            Output.Tag;
            Output.RightParent;
            Output.Arrow;
            Output.Yu(FormalList.Get(i).Id.Data);
            Output.Equal;
            CClassDecl.GenerateMinDualRef(ActualsArr[i].Class.Gc);
            Output.RightParent;  
            END;
          Output.Colon;
          Output.WriteChar('0');
          END;    
        END;
      END GenerateWhatTag;
      
   END CWhatTagCodeGenerator;

--------------------------------------------------------

   CLASS CStatListCodeGenerator;
     INHERITS StatListCodeGenerator(CGcContext);
     
    METHOD Output: YaflGC;
      BEGIN
      RESULT := Ctx.Output;
      END Output;

    REDEFINE METHOD GenerateCode;
      CONST
        Threshold = 50;
        Step = 20;
      VAR
        VStackPtr: INTEGER;
        l: NTList(Statement);
      BEGIN
      Output.LeftBrace;
      l := Obj.GetList;
      IF l.Size > Threshold THEN
        VStackPtr := YaflCfg.UniqueNumber;
        Output.ObjPtr;
        Output.UniqueItem (VStackPtr);
        Output.SemiColon;
        Output.WriteLn;
        Output.SaveVStack (VStackPtr);
        END;
      FOR i := 0 TO l.Size - 1 DO
        Output.WriteLn;
        Output.TraceStep(l.Get(i).LineNr);
        l.Get(i).Gc.GenerateCode;
        IF VStackPtr <> 0 THEN
          IF i MOD Step = Step - 1 THEN
            IF l.Size - i > Step THEN
              Output.RestoreVStack (VStackPtr);
              END;
            END; 
          END;
        END;
      Output.RightBrace;
      END GenerateCode;

   END CStatListCodeGenerator;
      
END CGStatements;



