IMPLEMENTATION MODULE CGQuantifier;

FROM YaflCfg IMPORT YaflCfg;
FROM YaflDeclarations IMPORT Declaration;
FROM YaflDesignator IMPORT Desig;
FROM YaflExpressions IMPORT ExpressionList;
FROM YaflGC IMPORT YaflGC;
FROM YaflLex IMPORT LexicalAnalyzer;
FROM YaflLiteral IMPORT Literal, IntegerLiteral;
FROM YaflLoops IMPORT SpecialPattern, FillPattern, LoopStatement;
FROM YaflNTList IMPORT NTList;
FROM YaflMetDefinition IMPORT MethodDefinition;
FROM YaflPredefined IMPORT PredefItems, VoidType;
FROM YaflType IMPORT TypedNonTerminal, Type;
IMPORT SYSTEM;
IMPORT ModuleTable;
IMPORT Space;

  CLASS CQuantifierCodeGenerator;
    INHERITS QuantifierCodeGenerator (CGcContext);
    
    VAR
      SpecCG: CSetSpecCodeGenerator;
      Output: YaflGC;
      MyAllCounterVar,
      MyTempVarNr,
      TargetNr: INTEGER;
      
    METHOD VarName (Nr: INTEGER);
      BEGIN
      SpecCG.VarName (Nr);
      END VarName;
      
    METHOD MyInitializations;
      BEGIN
      IF NOT Obj.Argument.Functional THEN
        MyTempVarNr := YaflCfg.UniqueNumber;
        SpecCG.DeclareInt (MyTempVarNr);
        END;
      CASE Obj.Code OF
        LexicalAnalyzer.All:
          MyAllCounterVar := YaflCfg.UniqueNumber;
          SpecCG.DeclareInt (MyAllCounterVar);
          VarName (MyAllCounterVar);
          Output.Becomes;
          Output.Zero;
          Output.SemiColon;
          Output.WriteLn;
          ReturnFalse;
          END;
        LexicalAnalyzer.ForAll:
          ReturnTrue;
          END;
        LexicalAnalyzer.First,
        LexicalAnalyzer.Last:
          IF SpecCG.Obj.Status <> SpecCG.Obj.IntervalSetS THEN
            ReturnFalse;
            END;
          END;
        LexicalAnalyzer.ThereIs:
          ReturnFalse;
          END;
       ELSE
        END;  
      END MyInitializations;
      
    METHOD Step: INTEGER;
      BEGIN
      RESULT := SpecCG.Step;
      END Step;

    METHOD MyPostInitializations;
      BEGIN
      IF (Obj.Code = LexicalAnalyzer.First) OR 
         (Obj.Code = LexicalAnalyzer.Last) THEN
        IF SpecCG.Obj.Status = SpecCG.Obj.IntervalSetS THEN
          VarName (TargetNr);
          Output.Becomes;
          VarName (SpecCG.IndexVarNr);
          IF Step > 0 THEN
            Output.Minus;
           ELSE
            Output.Plus;
            END;
          Output.One;
          Output.SemiColon;
          Output.WriteLn;
          END;
        END;
      END MyPostInitializations;

    METHOD ReturnTrue;
      BEGIN
      Output.WriteLn;
      VarName(TargetNr);
      Output.Becomes;
      Output.True;
      Output.SemiColon;
      Output.WriteLn;
      END ReturnTrue;
      
    METHOD ReturnMinusOne;
      BEGIN
      Output.WriteLn;
      VarName(TargetNr);
      Output.Becomes;
      Output.Minus;
      Output.One;
      Output.SemiColon;
      Output.WriteLn;
      END ReturnMinusOne;

    METHOD AccumulateAll;
      CONST
        InitialSize = 7;
      BEGIN
      Output.WriteLn;
      Output.LeftBrace;
      Output.WriteLn;
      
      Output.If;
      Output.LeftParent;
      Output.Not;
      VarName (TargetNr);
      Output.RightParent;
      Output.WriteLn;
      
      VarName(TargetNr);
      Output.Becomes;
      Output.FlyVReg;
      Output.LeftParent;
      Output.Alloc;
      Output.LeftParent;
      Output.WriteInt (InitialSize, 0);
      Output.Comma;
      Output.WriteInt (Obj.SetSpec.FreeVariableType.ArrayLevel + 1, 0);
      Output.Comma;
      Ctx.ClassDeclGenerateMinDualRef (Obj.SetSpec.
                     FreeVariableType.SimpleType.Gc);
      Output.RightParent;
      Output.RightParent;
      Output.SemiColon;
      Output.WriteLn;
      Output.Else;
      Output.If;
      Output.LeftParent;
      VarName (MyAllCounterVar);
      Output.GreaterEqual;
      Output.High;
      Output.LeftParent;
      VarName (TargetNr);
      Output.RightParent;
      Output.RightParent;
      Output.WriteLn;
      VarName (TargetNr);
      Output.Becomes;
      Output.FlyVReg;
      Output.LeftParent;
      Output.ReAlloc;
      Output.LeftParent;
      VarName (TargetNr);
      Output.RightParent;
      Output.RightParent;
      Output.SemiColon;
      Output.WriteLn;
      
      Output.ArrayElement;
      Output.LeftParent;
      VarName (TargetNr);
      Output.Comma;
      IF Obj.SetSpec.FreeVariableType.UseObjPtr THEN
        Output.ObjPtr;
       ELSE
        Ctx.ClassDeclGenerateCast (Obj.SetSpec.
                     FreeVariableType.SimpleType.Gc);
        END;             
      Output.Comma;
      VarName (MyAllCounterVar);
      Output.RightParent;
      Output.Becomes;
      
      VarName (SpecCG.FreeVarNr);
      Output.SemiColon;
      
      Output.WriteLn;
      VarName (MyAllCounterVar);
      Output.Increment;
      Output.SemiColon;
      
      Output.WriteLn;
      Output.RightBrace;
      Output.WriteLn;
      END AccumulateAll;
      
      
    METHOD MyBody;
      VAR
        Negate: BOOLEAN;
      BEGIN
      Negate := Obj.Code = LexicalAnalyzer.ForAll;
      IF NOT Obj.Argument.Functional THEN
        SpecCG.GenCode (Obj.Argument, MyTempVarNr);
        END;
      Output.If;
      Output.LeftParent;
      IF Negate THEN
        Output.Not;
        END;
      Output.LeftParent;
      IF Obj.Argument.Functional THEN
        Obj.Argument.Gc.GenerateCode;
       ELSE 
        VarName(MyTempVarNr);
        END;
      Output.RightParent;
      Output.RightParent;
      CASE Obj.Code OF
        LexicalAnalyzer.All:
          AccumulateAll;
          END;
        LexicalAnalyzer.ThereIs:
          Output.WriteLn;
          Output.LeftBrace;
          Output.WriteLn;
          ReturnTrue;
          SpecCG.JumpToExit;
          Output.WriteLn;
          Output.RightBrace;
          Output.WriteLn;
          END;
        LexicalAnalyzer.ForAll:
          Output.WriteLn;
          Output.LeftBrace;
          Output.WriteLn;
          ReturnFalse;
          SpecCG.JumpToExit;
          Output.WriteLn;
          Output.RightBrace;
          Output.WriteLn;
          END;
        LexicalAnalyzer.Last,
        LexicalAnalyzer.First:
          Output.WriteLn;
          Output.LeftBrace;
          Output.WriteLn;
          VarName(TargetNr);
          Output.Becomes;
          VarName (SpecCG.FreeVarNr);
          Output.SemiColon;
          SpecCG.JumpToExit;
          Output.RightBrace;
          Output.WriteLn;
          END;
        END;
      END MyBody;
      
    METHOD MyPostlogue;
      BEGIN
      IF Obj.Code = LexicalAnalyzer.All THEN
        Output.If;
        Output.LeftParent;
        VarName (TargetNr);
        Output.RightParent;
        Output.WriteLn;
        
        Output.If;
        Output.LeftParent;
        VarName (MyAllCounterVar);
        Output.Smaller;
        Output.High;
        Output.LeftParent;
        VarName (TargetNr);
        Output.RightParent;
        Output.RightParent;
        Output.WriteLn;
        
        VarName (TargetNr);
        Output.Becomes;
        Output.FlyVReg;
        Output.LeftParent;
        Output.UnivSlice;
        Output.LeftParent;
        VarName (TargetNr);
        Output.Comma;
        Output.Zero;
        Output.Comma;
        VarName (MyAllCounterVar);
        Output.RightParent;
        Output.RightParent;
        Output.SemiColon;
        Output.WriteLn;
        END;
      END MyPostlogue;
 
    METHOD ReturnFalse;
      BEGIN
      Output.UniqueItem (TargetNr);
      Output.Becomes;
      Output.LeftParent;
      Ctx.TypeGenerateCode (Obj.GetType.Gc);
      Output.RightParent;
      Output.Zero;
      Output.SemiColon;
      Output.WriteLn;
      END ReturnFalse;
      
    REDEFINE METHOD GenerateCodeWithTarget(TargetNr: INTEGER);
      VAR
        FailLabel: INTEGER;
      BEGIN
      WHAT Obj.SetSpec.Gc OF
        IN CSetSpecCodeGenerator:
          SpecCG := TAG;
          END;
        END;
      Output := Ctx.Output;
      THIS.TargetNr := TargetNr;
      IF Obj.Code = LexicalAnalyzer.Last THEN
        SpecCG.SetReversed;
        END;
      
      SpecCG.PrologueSection;
      IF Obj.Code = LexicalAnalyzer.ForAll THEN
        FailLabel := SpecCG.ExitLabel;
       ELSE
        FailLabel := SpecCG.FailureLabel;
        END;
      
      MyInitializations;
      
      
      SpecCG.InitializationSection(FailLabel);
      
      MyPostInitializations;
      
      SpecCG.CheckFiltersSection;
      
      MyBody;
      
      SpecCG.FetchNextSection(FailLabel);
      
      SpecCG.FailureSection;
      SpecCG.ExitLabelSection;
      MyPostlogue;
      SpecCG.PostlogueSection;
      END GenerateCodeWithTarget;
      
  END CQuantifierCodeGenerator;
  --------------------------------------

  CLASS CLoopStatCodeGenerator;
    INHERITS LoopStatCodeGenerator(CGcContext);
    
    VAR
      Output: YaflGC;
      VBpVar: INTEGER;
      SetSpecCG: CSetSpecCodeGenerator;

    METHOD GenerateStatements;
      BEGIN
      Output.WriteLn;
      Output.LeftBrace;
      Output.WriteLn;
      IF Obj.Statements <> VOID THEN
        Obj.Statements.Gc.GenerateCode;
        END;
      IF VBpVar <> 0 THEN
        -------------------------
        -- Restore the value stack pointer
        -- on every iteration
        -------------------------
        Output.RestoreVStack (VBpVar);  
        END;
      Output.RightBrace;
      Output.WriteLn;
      END GenerateStatements;
     
    METHOD GenerateSimpleWhileLoop;
      VAR
        TopLabel, BottomLabel,
        TempVarNr: INTEGER;                              
      BEGIN
      IF Obj.Cond.Functional THEN
        Output.While;
        Output.LeftParent;
        Obj.Cond.Gc.GenerateCode;
        Output.RightParent;
        GenerateStatements;
       ELSE
        Output.LeftBrace;
        TopLabel := YaflCfg.UniqueNumber;
        BottomLabel := YaflCfg.UniqueNumber;
        TempVarNr := YaflCfg.UniqueNumber;
        Output.Int;
        Output.UniqueItem(TempVarNr);
        Output.SemiColon;
        Output.WriteLn;
        
        Output.DefineJumpTarget (TopLabel);
        
        Ctx.TypedNTGenerateCodeWithTarget (Obj.Cond.Gc, TempVarNr);
        Output.If;
        Output.LeftParent;
        Output.UniqueItem (TempVarNr);
        Output.RightParent;
        Output.Jump (BottomLabel);
        
        GenerateStatements;
        
        Output.Jump (TopLabel);
        
        Output.DefineJumpTarget (BottomLabel);
        Output.RightBrace;
        END; 
      END GenerateSimpleWhileLoop;

      
    METHOD GenerateForLoop;
      VAR
        LowerBoundVarNr, UpperBoundVarNr, Step, IndexVarNr: INTEGER;
      BEGIN
      IndexVarNr := Obj.SetSpec.FreeVariable.HashValue;
      LowerBoundVarNr := YaflCfg.UniqueNumber;
      UpperBoundVarNr := YaflCfg.UniqueNumber;
      Output.LeftBrace;
      SetSpecCG.DeclareInt (LowerBoundVarNr);
      SetSpecCG.DeclareInt (UpperBoundVarNr);
      SetSpecCG.DeclareInt (IndexVarNr);
      Ctx.TypedNTGenerateCodeWithTarget 
          (Obj.SetSpec.FirstRefExpression.Gc,
           LowerBoundVarNr);
      Ctx.TypedNTGenerateCodeWithTarget 
          (Obj.SetSpec.SecondRefExpression.Gc,
           UpperBoundVarNr);
           
      Output.For;
      Output.LeftParent;
      Output.UniqueItem (IndexVarNr);
      Output.Becomes;
      Output.UniqueItem (LowerBoundVarNr);
      Output.SemiColon;
      
      Step := SetSpecCG.Step;
      
      Output.LeftParent;
      Output.UniqueItem (IndexVarNr);
      IF Step > 0 THEN
        Output.SmallerEqual;
       ELSE
        Output.GreaterEqual;
        END;
      Output.UniqueItem (UpperBoundVarNr);
      Output.RightParent;
      IF Obj.Cond <> VOID THEN
        ASSERT Obj.Cond.Functional;
        Output.And;
        Output.LeftParent;
        Obj.Cond.Gc.GenerateCode;
        Output.RightParent;
        END;
      Output.SemiColon;
      
      Output.UniqueItem (IndexVarNr);
      IF Step = 1 THEN
        Output.Increment;
       ELSIF Step = -1 THEN
        Output.Decrement;
       ELSIF Step < 0 THEN
        Output.SelfPlus;
        Output.WriteInt (Step, 0);
        END;
      Output.RightParent;
      GenerateStatements;  
      Output.RightBrace;
      Output.WriteLn;
  	  END GenerateForLoop;
      
    METHOD GenericScheme;
      VAR
        TempVarNr: INTEGER;
      BEGIN
      IF Obj.ShouldRestoreValueStack THEN
        Obj.SetSpec.ForceShouldRestoreStack;
        END;
      SetSpecCG.PrologueSection;
      
      IF (Obj.Cond <> VOID) AND NOT Obj.Cond.Functional THEN
        TempVarNr := YaflCfg.UniqueNumber;
        SetSpecCG.DeclareInt (TempVarNr);
        END;
      SetSpecCG.InitializationSection(SetSpecCG.ExitLabel);
      
      SetSpecCG.CheckFiltersSection;
      
      IF Obj.Cond <> VOID THEN
        IF TempVarNr = 0 THEN
          Output.If;
          Output.LeftParent;
          Output.Not;
          Output.LeftParent;
          Obj.Cond.Gc.GenerateCode;
          Output.RightParent;
          Output.RightParent;
          SetSpecCG.JumpToExit;
         ELSE 
          Ctx.TypedNTGenerateCodeWithTarget (Obj.Cond.Gc, TempVarNr);
          Output.If;
          Output.LeftParent;
          Output.Not;
          SetSpecCG.VarName (TempVarNr);
          Output.RightParent;
          SetSpecCG.JumpToExit;
          END;
        END;
      GenerateStatements;
      
      SetSpecCG.FetchNextSection(SetSpecCG.ExitLabel);
      
      SetSpecCG.ExitLabelSection;
      SetSpecCG.PostlogueSection;
      
      END GenericScheme;

    METHOD GenerateFillPattern (Output: YaflGC;
                                Patt: FillPattern): BOOLEAN;
      VAR
        TheType: Type;
        TheValue: TypedNonTerminal;
        FillWithZero,
        IsChars,
        StartZero: BOOLEAN;
        FromVar, ToVar: INTEGER;

      METHOD GenerateLValue (LValue: Desig);
        VAR
          ExprList: ExpressionList;
	   Buff: TypedNonTerminal;
        BEGIN
        ExprList := LValue.Last.BrExpr;
        Buff := ExprList.Get(ExprList.Size - 1);
        ExprList.Delete(ExprList.Size - 1);
        LValue.Gc.GenerateCode;
        ExprList.Append (Buff);
        END GenerateLValue;

      BEGIN
      TheValue := Patt.Value;
      TheType := Patt.LValue.GetType;
      IsChars := TheType.Match(PredefItems.Char.MakeType(0));
      IF (TheType = VoidType) THEN
        FillWithZero := TRUE;
        RESULT := TRUE;
       ELSIF (TheValue.GetFolded <> VOID) AND
  	              TheValue.GetFolded.IsDefaultValue THEN
        FillWithZero := TRUE;
        RESULT := TRUE;
       ELSE
        RESULT := IsChars;
        END;
      IF RESULT THEN
        Output.WriteLn;
        Output.LeftBrace;
        Output.WriteLn;
        Output.WriteLine ("/* Optimized pattern */");
        StartZero := (Patt.FromIndex.GetFolded <> VOID) AND 
                             Patt.FromIndex.GetFolded.IsDefaultValue;
        IF NOT StartZero THEN
 	   FromVar := YaflCfg.UniqueNumber;
          END;
        ToVar := YaflCfg.UniqueNumber;
        SetSpecCG.DeclareInt (ToVar);
        IF NOT StartZero THEN
 	   SetSpecCG.DeclareInt (FromVar);
 	   Ctx.TypedNTGenerateCodeWithTarget (Patt.FromIndex.Gc,
                                          FromVar);
          END;                                   
        Ctx.TypedNTGenerateCodeWithTarget (Patt.ToIndex.Gc,
					 ToVar);
        Output.If;
        Output.LeftParent;
        SetSpecCG.VarName(ToVar);
        Output.GreaterEqual;
        IF StartZero THEN
          Output.Zero;
         ELSE
 	   SetSpecCG.VarName(FromVar);
	   END;
        Output.RightParent;
        Output.Memset;
        Output.LeftParent;

        Output.LeftParent;
        Output.LeftParent;
        TheType.Gc.GenerateCode;
        Output.Star;
        Output.RightParent;

        GenerateLValue (Patt.LValue);
        Output.RightParent;

        IF NOT StartZero THEN
          Output.Plus;
	   SetSpecCG.VarName(FromVar);
	   END;

        Output.Comma;
        IF FillWithZero THEN
          Output.Zero;
         ELSE
 	   TheValue.Gc.GenerateCode;
	   END;
        Output.Comma;
        Output.LeftParent;
        SetSpecCG.VarName(ToVar);
        IF NOT StartZero THEN
          Output.Minus;
          SetSpecCG.VarName(FromVar);
	   END;
        Output.Plus;
        Output.WriteChar ('1');
        Output.RightParent;
        IF NOT IsChars THEN
          Output.Star;
	   Output.SizeOf;
	   Output.LeftParent;
	   TheType.Gc.GenerateCode;
	   Output.RightParent;
          END;
        Output.RightParent;
        Output.SemiColon;
        Output.WriteLn;
        Output.RightBrace;
        Output.WriteLn;
        END;
      END GenerateFillPattern;

    METHOD GenerateOptimizedPattern (Patt: SpecialPattern): BOOLEAN;
      BEGIN
      IF (Patt <> VOID) AND NOT YaflCfg.CheckArray AND NOT
        YaflCfg.CheckVoidObject THEN
        WHAT Patt OF
          IN FillPattern:
            RESULT := GenerateFillPattern (Output, TAG);
            END;
          END;
        END;
      END GenerateOptimizedPattern;
      
    METHOD GeneratePrologue;
      BEGIN
      IF Obj.ShouldRestoreValueStack THEN
        VBpVar := YaflCfg.UniqueNumber;
        END;
      -----------------------
      -- Keep track of the value 
      -- stack pointer on loop entry.
      -----------------------
      Output.LeftBrace;
      IF VBpVar <> 0 THEN
        VBpVar := YaflCfg.UniqueNumber;
        Output.ObjPtr;
        Output.Star;
        Output.UniqueItem (VBpVar);
        Output.SemiColon;
        Output.WriteLn;
        Output.SaveVStack (VBpVar);
        END;
      END GeneratePrologue;  

      
    METHOD GeneratePostlogue;
      BEGIN  
      Output.WriteLn;  
      Output.RightBrace;
      Output.WriteLn;  
      END GeneratePostlogue;
    
    REDEFINE METHOD GenerateCode;
      BEGIN  
      IF Obj.SetSpec <> VOID THEN
        WHAT Obj.SetSpec.Gc OF
          IN CSetSpecCodeGenerator:
            SetSpecCG := TAG;
            END;
          END;
        END;
      Output := Ctx.Output;
      ASSERT Output <> VOID;
      IF NOT GenerateOptimizedPattern (Obj.Pattern) THEN
        ASSERT Obj <> VOID;  
        IF Obj.SetSpec = VOID THEN
          GeneratePrologue;
          GenerateSimpleWhileLoop;
          GeneratePostlogue;
         ELSIF (Obj.SetSpec.Status = Obj.SetSpec.IntervalSetS) AND
            ((Obj.Cond = VOID) OR Obj.Cond.Functional) AND
            (Obj.SetSpec.Filters = VOID) THEN
          GeneratePrologue;
          GenerateForLoop;
          GeneratePostlogue;
         ELSE
          GenericScheme;
          END; 
        END;
      END GenerateCode; 
     
  END CLoopStatCodeGenerator;

------------------------------------
  CLASS CSetSpecCodeGenerator;
    INHERITS SetSpecCodeGenerator (CGcContext);
      
    VAR
      Output: YaflGC;
      TheReversed: BOOLEAN;
      TheCollVarNr,
      TheUpperBoundVarNr, 
      TheIndexVarNr,
      TheArrayVarNr,
      TheFreeVarNr, 
      TheTempVarNr,
      TheSaveVStackVarNr,
      
      TheFailureLabel,
      TheExitLabel,
      TheLoopTopLabel,
      TheFetchNextLabel: INTEGER;
      
    METHOD VarName (Nr: INTEGER);
      BEGIN
      IF Output = VOID THEN
        Output := Ctx.Output;
        END;
      ASSERT Nr <> 0;
      Output.UniqueItem (Nr);
      END VarName;
      
    METHOD DeclareInt (VarNr: INTEGER);
      BEGIN
      IF Output = VOID THEN
        Output := Ctx.Output;
        END;
      Output.Int;
      VarName(VarNr);
      Output.SemiColon;
      Output.WriteLn;
      END DeclareInt;   
      
    METHOD DeclareFreeVar;
      BEGIN
      ASSERT Obj.FreeVariable <> VOID;
      ASSERT Obj.FreeVariableType <> VOID;
      Ctx.TypeGenerateCode (Obj.FreeVariableType.Gc);
      VarName (TheFreeVarNr);
      Output.SemiColon;
      END DeclareFreeVar;
      
    METHOD SetReversed;
      BEGIN
      TheReversed := TRUE;
      END SetReversed;
        
    METHOD ExitLabel: INTEGER;
      BEGIN
      RESULT := TheExitLabel;
      END ExitLabel;
      
    METHOD FailureLabel: INTEGER;
      BEGIN
      RESULT := TheFailureLabel;
      END FailureLabel;      
      
    METHOD IndexVarNr: INTEGER;
      BEGIN
      RESULT := TheIndexVarNr;
      END IndexVarNr;
        
    METHOD FreeVarNr: INTEGER;
      BEGIN
      RESULT := TheFreeVarNr;
      END FreeVarNr;
      
    METHOD PrologueSection;
      BEGIN
      Output := Ctx.Output;
      TheFreeVarNr := Obj.FreeVariable.HashValue;
      
      TheExitLabel := YaflCfg.UniqueNumber;
      TheLoopTopLabel := YaflCfg.UniqueNumber;
      TheFetchNextLabel := YaflCfg.UniqueNumber;
      TheFailureLabel := YaflCfg.UniqueNumber;
      
      TheTempVarNr := YaflCfg.UniqueNumber;
      Output.WriteLn;
      Output.LeftBrace;
      DeclareInt (TheTempVarNr);
      IF Obj.ShouldRestoreStack THEN
        TheSaveVStackVarNr := YaflCfg.UniqueNumber;
        Output.ObjPtr;
        VarName (TheSaveVStackVarNr);
        Output.SemiColon;
        Output.WriteLn;
        END;
      CASE Obj.Status OF
        Obj.IntervalSetS:
          TheUpperBoundVarNr := YaflCfg.UniqueNumber;
          DeclareInt (TheUpperBoundVarNr);
          TheIndexVarNr := TheFreeVarNr;
          END;
        Obj.ArraySetS:
          TheArrayVarNr := YaflCfg.UniqueNumber;
          Output.ObjPtr;
          VarName (TheArrayVarNr);
          Output.SemiColon;
          Output.WriteLn;
        
          TheIndexVarNr := YaflCfg.UniqueNumber;
          DeclareInt (TheIndexVarNr);
          TheUpperBoundVarNr := YaflCfg.UniqueNumber;
          DeclareInt (TheUpperBoundVarNr);
          END;
        Obj.RandomCollSetS:
          TheCollVarNr := YaflCfg.UniqueNumber;
          Output.ObjPtr;
          VarName (TheCollVarNr);
          Output.SemiColon;
          Output.WriteLn;
        
          TheIndexVarNr := YaflCfg.UniqueNumber;
          DeclareInt (TheIndexVarNr);
          TheUpperBoundVarNr := YaflCfg.UniqueNumber;
          DeclareInt (TheUpperBoundVarNr);
          END;
        END;
      DeclareFreeVar;
      END PrologueSection;      
      
    METHOD GenCode (Expr: TypedNonTerminal;
                    TargetNr: INTEGER);
      BEGIN
      Ctx.TypedNTGenerateCodeWithTarget (Expr.Gc, TargetNr);
      END GenCode;     
      
    METHOD SetZero (VarNr: INTEGER);
      BEGIN
      Output.WriteLn;
      VarName (VarNr);
      Output.Becomes;
      Output.Zero;
      Output.SemiColon;
      Output.WriteLn;
      END SetZero;
      
    METHOD SetHighMinusOne (TheArrayVarNr, TargetVarNr: INTEGER);
      BEGIN
      Output.WriteLn;
      VarName (TargetVarNr);
      Output.Becomes;
      Output.High;
      Output.LeftParent;
      VarName (TheArrayVarNr);
      Output.RightParent;
      Output.Minus;
      Output.WriteChar ('1');
      Output.SemiColon;
      Output.WriteLn;
      END SetHighMinusOne;
      
    METHOD SetCollSizeMinusOne (TheCollVarNr, TargetVarNr: INTEGER);
      VAR
        SizeMeth: MethodDefinition;
        Decl: Declaration;
      BEGIN
      Output.WriteLn;
      VarName (TargetVarNr);
      Output.Becomes;
      Decl := ModuleTable.RandomCollectionClass.GetDecl(Space.StoreString("Size"));
      ASSERT Decl <> VOID;
      WHAT Decl OF
        IN MethodDefinition:
          SizeMeth := TAG;
          END;
        END; 
      ASSERT SizeMeth <> VOID;                             
      Output.Anchor (SizeMeth.Class.Module.Id.Data,
                     SizeMeth.Class.Id.Data,
                     SizeMeth.Id.Data);
      Output.LeftParent;
      VarName (TheCollVarNr);
      Output.RightParent;
      Output.Minus;
      Output.WriteChar ('1');
      Output.SemiColon;
      Output.WriteLn;
      END SetCollSizeMinusOne;
      
    METHOD ExtractCollElement (TheCollVarNr,
                               TheIndexVarNr,
                               TheTargetVarNr: INTEGER);
      VAR
        GetMeth: MethodDefinition;
      BEGIN
      Output.WriteLn;
      VarName (TheTargetVarNr);
      Output.Becomes;
      
      GetMeth := ModuleTable.RandomCollectionClass.Methods.
                              Find (Space.StoreString ("Get"));
      ASSERT GetMeth <> VOID;
      Output.Anchor (GetMeth.Class.Module.Id.Data,
                     GetMeth.Class.Id.Data,
                     GetMeth.Id.Data);
      Output.LeftParent;
      VarName (TheCollVarNr);
      Output.Comma;
      VarName (TheIndexVarNr);
      Output.RightParent;
      Output.SemiColon;
      Output.WriteLn;
      END ExtractCollElement;
      
    METHOD GenVReg (VarNr: INTEGER);
      BEGIN
      Output.WriteLn;
      Output.VReg;
      Output.LeftParent;
      VarName (VarNr);
      Output.RightParent;
      Output.SemiColon;
      Output.WriteLn;
      END GenVReg;
    
    METHOD GenerateBoundsTest(TargetIfFail: INTEGER);
      BEGIN
      Output.WriteLn;
      Output.WriteString ("/* Step is ");
      Output.WriteInt (Step, 0);
      IF TheReversed THEN
        Output.WriteString (" Reversed");
       ELSE 
        Output.WriteString (" Not reversed");
        END;
      Output.WriteLine (" */");
      
      Output.If;
      Output.LeftParent;
      VarName (TheIndexVarNr);
      IF Step < 0 THEN
        Output.Smaller;
       ELSE 
        Output.Greater;
        END;
      VarName (TheUpperBoundVarNr);  
      Output.RightParent;
      Output.Jump(TargetIfFail);
      END GenerateBoundsTest;
    
      
    METHOD InitializationSection(TargetIfFail: INTEGER);
    
    
      METHOD GenerateCheckNotNull(VarNr: INTEGER);
        BEGIN
        Output.If;
        Output.LeftParent;
        Output.Not;
        VarName (VarNr);
        Output.RightParent;
        Output.Jump(TargetIfFail);
        END GenerateCheckNotNull;
    
      BEGIN
      IF TheUpperBoundVarNr > 0 THEN
        CASE Obj.Status OF
          Obj.ArraySetS:
            ASSERT TheArrayVarNr <> 0;
            GenCode (Obj.FirstRefExpression, TheArrayVarNr);
            GenerateCheckNotNull (TheArrayVarNr);
            GenVReg (TheArrayVarNr);
            IF TheReversed THEN
              SetZero (TheUpperBoundVarNr);
              SetHighMinusOne (TheArrayVarNr, TheIndexVarNr);
             ELSE
              SetZero (TheIndexVarNr);
              SetHighMinusOne (TheArrayVarNr, TheUpperBoundVarNr);
              END;
            GenerateBoundsTest(TargetIfFail);
            END;
          Obj.RandomCollSetS:
            ASSERT TheCollVarNr <> 0;
            GenCode (Obj.FirstRefExpression, TheCollVarNr);
            GenerateCheckNotNull (TheCollVarNr);
            GenVReg (TheCollVarNr);
            IF TheReversed THEN
              SetZero (TheUpperBoundVarNr);
              SetCollSizeMinusOne (TheCollVarNr, TheIndexVarNr);
             ELSE
              SetZero (TheIndexVarNr);
              SetCollSizeMinusOne (TheCollVarNr, TheUpperBoundVarNr);
              END;
            GenerateBoundsTest(TargetIfFail);
            END;
          Obj.IntervalSetS:
            IF TheReversed THEN
              GenCode (Obj.FirstRefExpression, TheUpperBoundVarNr);
              GenCode (Obj.SecondRefExpression, TheIndexVarNr);
             ELSE
              GenCode (Obj.FirstRefExpression, TheIndexVarNr);
              GenCode (Obj.SecondRefExpression, TheUpperBoundVarNr);
              END;
            GenerateBoundsTest(TargetIfFail);
            END;
          END;
        END;
      IF TheSaveVStackVarNr <> 0 THEN
        Output.SaveVStack (TheSaveVStackVarNr);
        END;
      END InitializationSection;

    METHOD JumpToExit;
      BEGIN
      Output.WriteLn;
      Output.Jump (TheExitLabel);
      END JumpToExit;  
      
    METHOD JumpToFail;
      BEGIN
      Output.WriteLn;
      Output.Jump (TheFailureLabel);
      END JumpToFail;  
      
    METHOD CheckFiltersSection;
      VAR
        TheExpr: TypedNonTerminal;
      BEGIN
      Output.DefineJumpTarget (TheLoopTopLabel);
      IF TheSaveVStackVarNr <> 0 THEN
        Output.RestoreVStack (TheSaveVStackVarNr);
        END;
      CASE Obj.Status OF
        Obj.IntervalSetS:
          END;
        Obj.ArraySetS:
          ASSERT TheIndexVarNr <> TheFreeVarNr;
          VarName (TheFreeVarNr);
          Output.Becomes;
          Output.ArrayElement;
          Output.LeftParent;
          VarName (TheArrayVarNr);
          Output.Comma;
          Ctx.TypeGenerateCode (Obj.FreeVariableType.Gc);
          Output.Comma;
          VarName (TheIndexVarNr);
          Output.RightParent;
          Output.SemiColon;
          Output.WriteLn;
          END;
        Obj.RandomCollSetS:
          ASSERT TheIndexVarNr <> TheFreeVarNr;
          ExtractCollElement (TheCollVarNr, TheIndexVarNr, TheFreeVarNr);
          END;
        END;
      FOR Expr IN Obj.Filters DO
        IF Expr.Functional THEN
          Output.If;
          Output.LeftParent;
          Output.Not;
          Output.LeftParent;
          TheExpr := Expr;
          TheExpr.Gc.GenerateCode;
          Output.RightParent;
          Output.RightParent;
         ELSE
          GenCode (Expr, TheTempVarNr);
          Output.If;
          Output.LeftParent;
          Output.Not;
          Output.LeftParent;
          Output.UniqueItem (TheTempVarNr);
          Output.RightParent;
          Output.RightParent;
          END;
        Output.Jump(TheFetchNextLabel);
        END;  
      END CheckFiltersSection;
      
    METHOD Step: INTEGER;
      VAR
        Lit: Literal;
      BEGIN
      IF Obj.ByExpression <> VOID THEN
        Lit := Obj.ByExpression.GetFolded;
        ASSERT Lit <> VOID;
        WHAT Lit OF  
          IN IntegerLiteral:
            RESULT := TAG.Value;
            END;
          END;
       ELSE
        RESULT := 1;
        END;
      IF TheReversed THEN
        RESULT := -RESULT;
        END;
      END Step;
      
    METHOD FetchNextSection (TargetIfFail: INTEGER);
      VAR
        TheStep: INTEGER;
      BEGIN
      Output.DefineJumpTarget (TheFetchNextLabel);
      IF TheUpperBoundVarNr > 0 THEN
        VarName (TheIndexVarNr);
        TheStep := Step;
        ASSERT TheStep <> 0;
        IF TheStep = 1 THEN
          Output.Increment;
         ELSIF TheStep = -1 THEN
          Output.Decrement;
         ELSE
          IF TheStep > 0 THEN
            Output.SelfPlus;
           ELSE 
            Output.SelfMinus;
            END;
          Output.WriteInt (SYSTEM.ABS(TheStep), 0);
          END;
        Output.SemiColon;
        Output.WriteLn;
        GenerateBoundsTest (TargetIfFail);
        END;
      Output.Jump (TheLoopTopLabel);
      END FetchNextSection;  
      
    METHOD FailureSection;
      BEGIN
      Output.DefineJumpTarget (TheFailureLabel);
      END FailureSection;  

    
    METHOD ExitLabelSection;
      BEGIN
      Output.DefineJumpTarget (TheExitLabel);
      END ExitLabelSection;  
    
    METHOD PostlogueSection;
      BEGIN
      Output.RightBrace;
      Output.WriteLn;
      END PostlogueSection;
    
  END CSetSpecCodeGenerator;

END CGQuantifier;  
