IMPLEMENTATION MODULE CGClass;

-- IMPORT SYSTEM;
FROM List                  IMPORT List;

------------------------------
-- C Code Generators.
------------------------------
FROM CGCode         IMPORT CGcContext;
FROM CGMethods      IMPORT CMethImplCodeGenerator;
FROM CGDeclarations IMPORT CSingleDataItemCodeGenerator;
FROM CGMethods      IMPORT CPredefMethCodeGenerator,
                           CMethDefCodeGenerator,
                           CMethImplCodeGenerator,
                           CMethDecl;
------------------------------
-- Generic Code Generators.
------------------------------
FROM YaflGClass   IMPORT DummyClDeclCodeGenerator,
                         PredefClassCodeGenerator,
                         ClassImplCodeGenerator;
FROM YaflGMethods IMPORT MethImplCodeGenerator,
                         MethDefCodeGenerator;

------------------------------
-- Non Terminals.
------------------------------
FROM YaflClImplementation  IMPORT ClassImplementation;
FROM YaflMethods           IMPORT MethodDeclaration;
FROM YaflType              IMPORT Type;
FROM YaflDeclarations      IMPORT SingleDataItem;
FROM YaflMetImplementation IMPORT MethodImplementation;
FROM YaflMetDefinition     IMPORT MethodDefinition;
FROM YaflParamClasses      IMPORT ClassFormal, 
                                  ClassActual;
FROM YaflPredefined        IMPORT ThisDataItem;
FROM YaflModules           IMPORT CompilationUnit;
FROM YaflIdentifiers       IMPORT Ident;
FROM YaflCfg               IMPORT CurrentSpot,
                                  YaflCfg;
FROM YaflNTList            IMPORT DeclList, 
                                  NTList, 
                                  MethodList;
FROM YaflPredefined        IMPORT PredefItems;
FROM YaflDictionary        IMPORT MethodReference;
FROM Streams               IMPORT StdOut;

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

  CLASS CDummyClDeclCodeGenerator;
    INHERITS DummyClDeclCodeGenerator(CGcContext);
    
    METHOD GenerateMinDualRef;
      BEGIN
      Ctx.ClassDeclGenerateMinDualRef(THIS);
      END GenerateMinDualRef;   

    METHOD GenerateConstructFuncId;
      BEGIN
      Ctx.ClassDeclGenerateConstructFuncId(THIS);
      END GenerateConstructFuncId;   

    METHOD GenerateCreateAnchorId;
      BEGIN
      Ctx.ClassDeclGenerateCreateAnchorId(THIS);
      END GenerateCreateAnchorId;   

    METHOD GenerateMinimalDualExtract;
      BEGIN
      Ctx.ClassDeclGenerateMinimalDualExtract(THIS);
      END GenerateMinimalDualExtract;   

    METHOD GenerateDualRef;
      BEGIN
      Ctx.ClassDeclGenerateDualRef(THIS);
      END GenerateDualRef;   

    METHOD GenerateCast;
      BEGIN
      Ctx.ClassDeclGenerateCast(THIS);
      END GenerateCast;   

  END CDummyClDeclCodeGenerator;
  
---------------------------------------------------   

  CLASS CVirtualClassDeclCodeGenerator;
    INHERITS VirtualClassDeclCodeGenerator(CGcContext);
     
    METHOD GenerateDualRef;
      VAR
        Ref: ClassDeclaration;
      BEGIN
      ASSERT Ctx.Output <> VOID;
      Ctx.Output.LeftParents(3);
      ASSERT Obj.FormalRef <> VOID;
      Ref := Obj.FormalRef.Set.Class;
      ASSERT Ref <> VOID;
      Ctx.Output.Class(Ref.Module.Id.Data, Ref.Id.Data);
      Ctx.Output.Star;
      Ctx.Output.RightParent;
      ASSERT Obj.GetDataItemRef <> VOID;
      WHAT Obj.GetDataItemRef OF
        IN ThisDataItem:
          Ctx.Output.This;
          END; -- IN
       ELSE
        WHAT Obj.GetDataItemRef.MethodContext.Gc OF
          IN CMethImplCodeGenerator:
            TAG.GenerateLocal(Obj.GetDataItemRef);
            END; -- IN
          END; -- WHAT
        END; -- WHAT
      Ctx.Output.RightParent;
      Ctx.Output.Arrow;
      ASSERT Obj.FormalRef <> VOID;
      Ctx.Output.Yu (Obj.FormalRef.Id.Data);
      Ctx.Output.RightParent;
      END GenerateDualRef;

    METHOD GenerateMinDualRef;
      BEGIN
      Ctx.ClassDeclGenerateMinDualRef(THIS);
      END GenerateMinDualRef;   

    METHOD GenerateConstructFuncId;
      BEGIN
      Ctx.ClassDeclGenerateConstructFuncId(THIS);
      END GenerateConstructFuncId;   

    METHOD GenerateCreateAnchorId;
      BEGIN
      Ctx.ClassDeclGenerateCreateAnchorId(THIS);
      END GenerateCreateAnchorId;   

    METHOD GenerateMinimalDualExtract;
      BEGIN
      Ctx.ClassDeclGenerateMinimalDualExtract(THIS);
      END GenerateMinimalDualExtract;   

    METHOD GenerateCast;
      BEGIN
      Ctx.ClassDeclGenerateCast(THIS);
      END GenerateCast;   

  END CVirtualClassDeclCodeGenerator;
   
---------------------------------------------------   
   
  CLASS CInstClassDefCodeGenerator;
    INHERITS InstClassDefCodeGenerator(CGcContext);
     
    METHOD GenerateMinDualRef;
      BEGIN
      Ctx.ClassDeclGenerateMinDualRef(THIS);
      END GenerateMinDualRef;   

    METHOD GenerateConstructFuncId;
      BEGIN
      Ctx.ClassDeclGenerateConstructFuncId(THIS);
      END GenerateConstructFuncId;   

    METHOD GenerateCreateAnchorId;
      BEGIN
      Ctx.ClassDeclGenerateCreateAnchorId(THIS);
      END GenerateCreateAnchorId;   

    METHOD GenerateMinimalDualExtract;
      BEGIN
      Ctx.ClassDeclGenerateMinimalDualExtract(THIS);
      END GenerateMinimalDualExtract;   

    METHOD GenerateDualRef;
      BEGIN
      Ctx.ClassDeclGenerateDualRef(THIS);
      END GenerateDualRef;   

    METHOD GenerateCast;
      BEGIN
      Ctx.ClassDeclGenerateCast(THIS);
      END GenerateCast;   

  END CInstClassDefCodeGenerator;
  
---------------------------------------------------   
   
  CLASS CPredefClassCodeGenerator;
    INHERITS PredefClassCodeGenerator(CGcContext);
     
    METHOD GenerateDualRef;
      BEGIN
      ASSERT Ctx.Output <> VOID;
      Ctx.Output.Ampersand;
      Ctx.Output.PredefinedDual (Obj.ShortCName);
      END GenerateDualRef;  

    METHOD GenerateMinDualRef;
      BEGIN
      Ctx.ClassDeclGenerateMinDualRef(THIS);
      END GenerateMinDualRef;   

    METHOD GenerateConstructFuncId;
      BEGIN
      Ctx.ClassDeclGenerateConstructFuncId(THIS);
      END GenerateConstructFuncId;   

    METHOD GenerateCreateAnchorId;
      BEGIN
      Ctx.ClassDeclGenerateCreateAnchorId(THIS);
      END GenerateCreateAnchorId;   

    METHOD GenerateMinimalDualExtract;
      BEGIN
      Ctx.ClassDeclGenerateMinimalDualExtract(THIS);
      END GenerateMinimalDualExtract;   

    METHOD GenerateCast;
      BEGIN
      Ctx.ClassDeclGenerateCast(THIS);
      END GenerateCast;   

  END CPredefClassCodeGenerator;
  
---------------------------------------------------   

  CLASS CClassImplCodeGenerator;
    INHERITS ClassImplCodeGenerator(CGcContext);


	METHOD CMethImp(GC: MethImplCodeGenerator): CMethImplCodeGenerator;
      BEGIN
	  WHAT GC OF
        IN CMethImplCodeGenerator:
          RESULT := TAG;
          END;
        END;
      END CMethImp;

	METHOD CMethDef(GC: MethDefCodeGenerator): CMethDefCodeGenerator;
      BEGIN
	  WHAT GC OF
        IN CMethDefCodeGenerator:
          RESULT := TAG;
          END;
        END;
      END CMethDef;


------------------------------
    METHOD GenerateConstructFuncHeader(WithBody: BOOLEAN);
      VAR
        Arity: INTEGER;
        FormalList: NTList(ClassFormal);
        TheObj: ClassImplementation;
      BEGIN
      TheObj := Obj;
      Ctx.Output.ObjPtr;
      GenerateConstructFuncId;
      IF TheObj.ClassFormals <> VOID THEN
        FormalList := TheObj.ClassFormals.FormalList;
        Arity := FormalList.Size + 1;
       ELSE
        Arity := 1;     
        END;
      ------------------------------
      -- Depending on this being
      -- a function header or body,
      -- generate the proper code by using
      -- macros in such a way that this
      -- code can be compiled by both K&R and
      -- Ansi compilers.
      --
      -- While is is theoretically possible that one designs
      -- a parameterized class with more than 7 or 8 formal 
      -- classes, we do assume there will be no such extreme
      -- case, and use the macro-based scheme, instead of
      -- verbatim conditionnal compilation withOut further
      -- testing. Check the code generation attached to 
      -- methods more information regarding the two schemes
      -- for formal parameters,
      ------------------------------    
      IF WithBody THEN
        Ctx.Output.YFormals (Arity);
       ELSE
        Ctx.Output.YArgs;
        Ctx.Output.LeftParent;  -- Must be matched by a RightParent after the 
                            -- parameters.
        END;    
      Ctx.Output.LeftParent;
      Ctx.Output.ObjPtr;
      IF WithBody THEN
        Ctx.Output.Comma;
        END;
      Ctx.Output.This;   -- Now, Generate parameters.
      FOR f IN FormalList DO
        Ctx.Output.Comma;
        Ctx.Output.MinimalDual;
        Ctx.Output.Star;
        IF WithBody THEN
          Ctx.Output.Comma;
          END;
        Ctx.Output.Yu (f.Id.Data);
        END;
      IF NOT WithBody THEN 
        Ctx.Output.RightParent; -- Matches the LeftParent used with the YArg macro
        END;    
      Ctx.Output.RightParent;
      END GenerateConstructFuncHeader;
      
    METHOD GenerateConstructFunc;
      VAR
        Cl, InhCl: ClassDeclaration;
        InhParams: NTList(ClassActual);
        FormalList: NTList(ClassFormal);
      BEGIN
      GenerateConstructFuncHeader(WithBody := TRUE);
      Ctx.Output.LeftBrace;
      Ctx.Output.WriteLn;
      IF Obj.ClassFormals <> VOID THEN
        FormalList := Obj.ClassFormals.FormalList;
        FOR i := 0 TO FormalList.Size - 1 DO
          Ctx.Output.LeftParents(2);
          Ctx.Output.Class (Obj.ModuleName, Obj.Id.Data);
          Ctx.Output.Star;
          Ctx.Output.RightParent;
          Ctx.Output.This;
          Ctx.Output.RightParent;
          Ctx.Output.Arrow;
          Ctx.Output.Yu (FormalList.Get(i).Id.Data);
          Ctx.Output.Becomes;
          Ctx.Output.Yu (FormalList.Get(i).Id.Data);
          Ctx.Output.SemiColon;
          Ctx.Output.WriteLn;
          END;
        END;
      IF Obj.Inherits <> VOID THEN
        InhCl := Obj.Inherits.Class;
        IF Obj.Inherits.Actuals <> VOID THEN
          InhParams := Obj.Inherits.Actuals.ActualList;
          END;
        IF InhCl.NeedsConstructFunc THEN    
          CClassDecl.GenerateConstructFuncId(InhCl.Gc);
          Ctx.Output.LeftParent;
          Ctx.Output.This;
          IF InhParams <> VOID THEN
            FOR i := 0 TO InhParams.Size - 1 DO
              Ctx.Output.Comma;
              Cl := InhParams.Get(i).Class;
              WHAT Cl OF
                IN VirtualClassDecl:
                  -----------------------------
                  -- If a parameter provided in
                  -- the inheritance clause refers
                  -- to a VirtualClassDecl, it must
                  -- be one of the current's class
                  -- formal parameters.
                  -----------------------------
                  Ctx.Output.Yu (TAG.FormalRef.Id.Data);
                  END;
               ELSE
                -------------------------------
                -- Plain ClassDeclaration, general case
                -------------------------------
                CClassDecl.GenerateMinDualRef(Cl.Gc);
                END;
              END;
            END;
          Ctx.Output.RightParent;
          Ctx.Output.SemiColon;
          Ctx.Output.WriteLn;
          END;
        END;    
      Ctx.Output.Return;
      Ctx.Output.This;
      Ctx.Output.SemiColon;
      Ctx.Output.RightBrace;
      Ctx.Output.WriteLn;
      END GenerateConstructFunc;  
      
    METHOD GenerateAlignPrefix;
      BEGIN
      Ctx.Output.LeftParent;
      Ctx.Output.Align;
      Ctx.Output.Star;
      Ctx.Output.LeftParents(2);
      END GenerateAlignPrefix;
      
    METHOD GenerateAlignPostfix;
      BEGIN        
      Ctx.Output.BreakDefine;
      Ctx.Output.Plus;
      Ctx.Output.Align;
      Ctx.Output.Minus;
      Ctx.Output.WriteChar ('1');
      Ctx.Output.RightParent;
      Ctx.Output.Slash;
      Ctx.Output.Align;
      Ctx.Output.RightParents(2);
      END GenerateAlignPostfix;

    METHOD GenerateDataStructure(Pass: INTEGER);
      VAR
        Empty: BOOLEAN;
        ModName, ClassName: ARRAY OF CHAR;
      BEGIN
      ASSERT (Pass = 1) OR (Pass = 2);
      ModName := Obj.ModuleName;
      ClassName := Obj.Id.Data;
      Empty := TRUE;
      Ctx.Output.WriteLn;
      Ctx.Output.TypeDef;
      Ctx.Output.Struct;
      Ctx.Output.LeftBrace;
      Ctx.Output.WriteLn;
      ---------------------------------------
      -- Emit the fields
      ---------------------------------------
      IF Pass = 2 THEN
        IF Obj.Inherits <> VOID THEN
          ----------------------------------
          -- Reserve space for inherited
          -- data structure
          ----------------------------------
          Ctx.Output.Char;
          Ctx.Output.UniqueItem(YaflCfg.UniqueNumber);
          Ctx.Output.LeftBracket;
          Ctx.Output.AdditiveSize (Obj.Inherits.Class.Module.Id.Data,
                               Obj.Inherits.Class.Id.Data);
          Ctx.Output.RightBracket;
          Ctx.Output.SemiColon;
          Ctx.Output.WriteLn;
          Empty := FALSE;
          END;
        END;
      ---------------------------------------
      -- Generate the references to the duals
      -- for parameterized classes.
      ---------------------------------------   
      IF Obj.ClassFormals <> VOID THEN
        FOR f IN Obj.ClassFormals.FormalList DO
          Ctx.Output.MinimalDual;
          Ctx.Output.Star;
          Ctx.Output.Yu(f.Id.Data);
          Ctx.Output.SemiColon;
          Ctx.Output.WriteLn;
          END;
        END;
      ---------------------------------------
      -- Generate the fields data structure
      ---------------------------------------   
      FOR Attr IN Obj.Attributes | NOT Attr.Once DO
        WHAT Attr.Gc OF
          IN CSingleDataItemCodeGenerator:
            TAG.GenerateDeclaration (Zap := FALSE);
            END;
          END; -- what
        Empty := FALSE;
        END;
      IF Empty THEN
        Ctx.Output.Char;
        Ctx.Output.UniqueItem(YaflCfg.UniqueNumber);
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;
        END;
      Ctx.Output.RightBrace;
      IF Pass = 1 THEN
        Ctx.Output.Additive (ModName, ClassName);
       ELSE  -- Pass = 2
        Ctx.Output.Class (ModName, ClassName);
        END;
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
      IF Pass = 1 THEN -- Generate the AdditiveSize macro
        Ctx.Output.NoCut;
        Ctx.Output.Define;
        Ctx.Output.AdditiveSize (ModName, ClassName);
        Ctx.Output.LeftParent;
        GenerateAlignPrefix;
        Ctx.Output.SizeOf;
        Ctx.Output.LeftParent;
        Ctx.Output.Additive (ModName, ClassName);
        Ctx.Output.RightParent;
        GenerateAlignPostfix;
        IF Obj.Inherits <> VOID THEN
          Ctx.Output.Plus;
          Ctx.Output.AdditiveSize (Obj.Inherits.Class.Module.Id.Data,
                               Obj.Inherits.Class.Id.Data);
          END;
        Ctx.Output.RightParent;
        Ctx.Output.Cut;
        Ctx.Output.WriteLn;
       ELSE -- Pass = 2;
        IF Obj.Once THEN
          ----------------------------
          -- Declare unique instance of
          -- ONCE classes
          ----------------------------
          Ctx.Output.Extern;
          Ctx.Output.ObjPtr;
          Ctx.Output.OnceClassInstance (ModName, ClassName);
          Ctx.Output.SemiColon;
          Ctx.Output.WriteLn;
          END;
        END;
      END GenerateDataStructure;
      
    METHOD GenerateDualStructure(Pass: INTEGER);
      VAR
        ModName, ClassName: ARRAY OF CHAR;
        OriginalMethods: DeclList (MethodDeclaration);
        
        METHOD GenerateMethodRef(CurMethod: MethodDeclaration);
          BEGIN
          Ctx.Output.MethodRef;
          CMethDecl.GenerateMethodRef(CurMethod.Gc);
          Ctx.Output.SemiColon;           
          Ctx.Output.WriteLn;
          END GenerateMethodRef;
          
      BEGIN
      ASSERT (Pass = 1) OR (Pass = 2);
      ModName := Obj.ModuleName;
      ClassName := Obj.Id.Data;
      Ctx.Output.WriteLn;
      Ctx.Output.TypeDef;
      Ctx.Output.Struct;
      Ctx.Output.LeftBrace;
      Ctx.Output.WriteLn;
      ---------------------------------------
      -- Emit the pointer to the attached functions.
      ---------------------------------------
      IF Pass = 1 THEN
        IF Obj.Inherits = VOID THEN
          ---------------------------------
          -- Save space for a minimal dual;
          ---------------------------------
          Ctx.Output.MinimalDual;
          Ctx.Output.UniqueItem (YaflCfg.UniqueNumber);
          Ctx.Output.SemiColon;
          Ctx.Output.WriteLn;
          END;
       ELSE -- Pass = 2
        IF Obj.Inherits <> VOID THEN
          ----------------------------------
          -- Reserve space for inherited
          -- data structure
          ----------------------------------
          Ctx.Output.Char;
          Ctx.Output.UniqueItem (YaflCfg.UniqueNumber);
          Ctx.Output.LeftBracket;
          Ctx.Output.AdditiveDualSize (Obj.Inherits.Class.Module.Id.Data,
                                   Obj.Inherits.Class.Id.Data);
          Ctx.Output.RightBracket;
          Ctx.Output.SemiColon;
          Ctx.Output.WriteLn;
         ELSE
          Ctx.Output.MinimalDual;
          Ctx.Output.UniqueItem (YaflCfg.UniqueNumber);
          Ctx.Output.SemiColon;
          Ctx.Output.WriteLn;
          END;
        END;
      OriginalMethods := Obj.MethodsInDual;
      IF OriginalMethods.Size > 0 THEN
        FOR Meth IN OriginalMethods DO
          GenerateMethodRef(Meth);  
          END;                                    
       ELSE
        Ctx.Output.Char;
        Ctx.Output.UniqueItem (YaflCfg.UniqueNumber);
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;
        END;
      Ctx.Output.RightBrace;
      IF Pass = 1 THEN
        Ctx.Output.AdditiveDual (ModName, ClassName);
       ELSE  -- Pass = 2
        Ctx.Output.DualType (ModName, ClassName);
        END;
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
      IF Pass = 1 THEN -- Generate the AdditiveSize macro
        Ctx.Output.NoCut;
        Ctx.Output.Define;
        Ctx.Output.AdditiveDualSize (ModName, ClassName);
        Ctx.Output.LeftParent;
        GenerateAlignPrefix;
        Ctx.Output.SizeOf;
        Ctx.Output.LeftParent;
        Ctx.Output.AdditiveDual (ModName, ClassName);
        Ctx.Output.RightParent;
        GenerateAlignPostfix;
        IF Obj.Inherits <> VOID THEN
          Ctx.Output.BreakDefine;
          Ctx.Output.Plus;
          Ctx.Output.AdditiveDualSize (Obj.Inherits.Class.Module.Id.Data,
                                   Obj.Inherits.Class.Id.Data);
          END;
        Ctx.Output.RightParent;
        Ctx.Output.Cut;
        Ctx.Output.WriteLn;
       ELSE -- Pass = 2;
        --------------------------------
        -- External declaration for the dual
        -- data structure instance
        --------------------------------
        Ctx.Output.Extern;
        Ctx.Output.DualType (ModName, ClassName);
        Ctx.Output.DualInstance (ModName, ClassName);
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;
        END;
      END GenerateDualStructure;

    METHOD OutputOnceItems;
      BEGIN
      FOR Meth IN Obj.Methods DO
        CMethImp(Meth.Gc).OutputOnceItems;
        END;
      FOR Loc IN Obj.Attributes | Loc.Once DO
        WHAT Loc.Gc OF
          IN CSingleDataItemCodeGenerator:
            TAG.GenerateDeclaration (Zap := TRUE);
            END;
          END; -- what
        END;
      END OutputOnceItems;

    ---------------------------------------------------------
    -- This method only generates anchor definitions for private
    -- methods, as public ones should have been generated in
    -- the header files, based on the non-redefined methods
    -- listed in the corresponding definition module.
    ---------------------------------------------------------
    METHOD GeneratePrivateAnchorDefinitions;
      BEGIN
      FOR CurMeth IN Obj.Methods | CurMeth.Definition = VOID DO
        IF (CurMeth.IsCreate) OR NOT CurMeth.Redefine THEN
          CMethDecl.GenerateAnchorDefinition(CurMeth.Gc);
          END;
        END;
      END GeneratePrivateAnchorDefinitions;
          
    VAR
      OnceTabNr:      INTEGER;
      MarkingArrayNr: INTEGER;
      
    METHOD GenerateArrays;
      VAR
        i: INTEGER;
      BEGIN        
      i := Obj.MarkableObjectsInAttributes;
      IF i > 0 THEN
        --------------------------------------------------------------
        -- The marking array is an array containing the offsets 
        -- (in the data structure) of the objects
        -- who are reachable from THIS.
        -- The array is ended by a -1 value.
        --------------------------------------------------------------
        Ctx.Output.Static;
        Ctx.Output.Int;   
        MarkingArrayNr := YaflCfg.UniqueNumber;
        Ctx.Output.UniqueItem (MarkingArrayNr);
        Ctx.Output.LeftBracket;                     
        Ctx.Output.WriteInt(i + 1, 0);
        Ctx.Output.RightBracket;
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;
        END;            
      IF Obj.GetOnceList <> VOID THEN  
        ------------------------------
        -- Make sure the once variables are still accessible,
        -- since they might have been removed in the process
        -- (for instance, through the global optimization)
        ------------------------------
        FOR j IN  Obj.GetOnceList.Size - 1 TO 0 BY -1 | 
              Obj.GetOnceList.Get(j).Deleted DO
          Obj.GetOnceList.Delete (j);
          END;                                     
        IF Obj.GetOnceList.Size = 0 THEN
          Obj.ResetOnceList;
         ELSE
          Ctx.Output.Static;
          Ctx.Output.ObjPtr;
          Ctx.Output.Star;
          OnceTabNr := YaflCfg.UniqueNumber;
          Ctx.Output.UniqueItem (OnceTabNr);
          Ctx.Output.LeftBracket;
          Ctx.Output.WriteInt (Obj.GetOnceList.Size + 1 , 0);
          Ctx.Output.RightBracket;
          Ctx.Output.SemiColon;
          Ctx.Output.WriteLn;
          END;
        END;
      END GenerateArrays;
      

    REDEFINE METHOD GenerateCode;
      BEGIN
      Ctx.Output.Char;
      Ctx.Output.Star;
      Ctx.ClassDeclGenerateLiteral(THIS);
      Ctx.Output.Becomes;
      Ctx.Output.QuotedString (Obj.Id.Data, UseEsc := FALSE);
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
            
      IF Obj.NeedsConstructFunc THEN
        GenerateConstructFunc;
        END;
      GenerateArrays;
      CurrentSpot.PushCurrentClass (Obj);
      FOR Meth IN Obj.Methods DO
        CurrentSpot.PushCurrentMethod (Meth);
        IF Meth.NeedsSeparateAnchor THEN
          CMethDecl.GenerateAnchorBody(Meth.Gc);
          END;
        IF NOT Meth.Deferred THEN
          Meth.Gc.GenerateCode;
         ELSE 
          -- added by RJC for pre- and postconditions.
          IF NOT YaflCfg.PleaseGlobalOptimize THEN
            Meth.Gc.GenerateDbxMethodCode;
            END;
          END;
        CurrentSpot.PopCurrentMethod;
        END;
      IF (Obj.Definition <> VOID) THEN
        FOR MethDef IN Obj.Definition.Methods | MethDef.Deferred DO
          CMethDecl.GenerateAnchorBody(MethDef.Gc);
          -- added by RJC for pre- and postconditions.
          IF NOT YaflCfg.PleaseGlobalOptimize THEN
            MethDef.Gc.GenerateDbxMethodCode;
            END;
          END;
        END;
      GenerateFieldReferenceVariables;
      GenerateDualInit;
      GenerateClassInitialization;
      IF (YaflCfg.TraceModeLevel = 2) OR
         (Obj.Publish) THEN
        GenerateDbxClassCode;
        END;
      GenerateDataDictionaryInfo;
      -- XXJC
      GenerateMethodChainInit;
      -- XXJC
      CurrentSpot.PopCurrentClass;
      END GenerateCode;

    METHOD GenerateDualInitHeader (ParamNr: INTEGER;
                                   WithBody: BOOLEAN);
      VAR
        ModName, ClName: ARRAY OF CHAR;
      BEGIN
      Ctx.Output.Void;
      ModName := Obj.ModuleName;
      ClName := Obj.Id.Data;
      Ctx.Output.ClassDualInitialization (ModName, ClName);
      IF WithBody THEN
        Ctx.Output.YFormals (Arity := 1);
       ELSE
        Ctx.Output.YArgs;
        Ctx.Output.LeftParent;
        END;    
      Ctx.Output.LeftParent;
      Ctx.Output.DualType (ModName, ClName);
      Ctx.Output.Star;
      IF WithBody THEN
        Ctx.Output.Comma;
        END;
      Ctx.Output.UniqueItem (ParamNr);
      Ctx.Output.RightParent;
      IF NOT WithBody THEN
        Ctx.Output.RightParent;
        END;
      END GenerateDualInitHeader;

    METHOD GenerateDualInitDummy(MinNr: INTEGER);
      BEGIN
      END GenerateDualInitDummy;
      
    METHOD GenerateFillTables;
      VAR
        DumVarNr, j: INTEGER;
        Attribute: SingleDataItem;
      BEGIN
      IF Obj.GetOnceList <> VOID THEN
        FOR i := 0 TO Obj.GetOnceList.Size - 1 DO
          Ctx.Output.UniqueItem (OnceTabNr);
          Ctx.Output.LeftBracket;
          Ctx.Output.WriteInt (i, 0);
          Ctx.Output.RightBracket;
          Ctx.Output.Becomes;
          ASSERT Obj.GetOnceList.Get(i) <> VOID;
          ASSERT Obj.GetOnceList.Get(i).OnceNumber <> 0;
          Ctx.Output.Ampersand;
          Ctx.Output.UniqueItem (Obj.GetOnceList.Get(i).OnceNumber);
          Ctx.Output.SemiColon;
          Ctx.Output.WriteLn;
          END;
        Ctx.Output.UniqueItem (OnceTabNr);
        Ctx.Output.LeftBracket;
        Ctx.Output.WriteInt (Obj.GetOnceList.Size, 0);
        Ctx.Output.RightBracket;
        Ctx.Output.Becomes;
        Ctx.Output.Null;
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;
        END;       
      IF Obj.MarkableObjectsInAttributes > 0 THEN
        ASSERT MarkingArrayNr <> 0;
        Ctx.Output.LeftBrace;              
        DumVarNr := GenerateDummyObject;
      
        j := 0;
        FOR i := 0 TO Obj.Attributes.Size - 1 DO
          Attribute := Obj.Attributes.Get(i);
          IF Attribute.GetType.UseObjPtr AND NOT Attribute.Once THEN
            Ctx.Output.UniqueItem (MarkingArrayNr);
            Ctx.Output.LeftBracket;
            Ctx.Output.WriteInt(j,0);
            Ctx.Output.RightBracket;
            Ctx.Output.Becomes;
            Ctx.Output.Offset;
            Ctx.Output.LeftParent;
            Ctx.Output.UniqueItem(DumVarNr);
            Ctx.Output.Comma;
            Attribute.Gc.GenerateCode;
            Ctx.Output.RightParent;
            Ctx.Output.SemiColon;
            Ctx.Output.WriteLn;
            j := j + 1;
            END;
          END;
        Ctx.Output.UniqueItem (MarkingArrayNr);
        Ctx.Output.LeftBracket;
        Ctx.Output.WriteInt(j,0);
        Ctx.Output.RightBracket;
        Ctx.Output.Becomes;    
        Ctx.Output.WriteInt (-1,0);
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;      
        Ctx.Output.RightBrace;
        Ctx.Output.WriteLn;
        END;          
      END GenerateFillTables;
      
    ------------------------------------------
    -- Generate the function that initializes a 
    -- dual structure attached to THIS.
    ------------------------------------------
    METHOD GenerateDualInit;
-----------------------------------------------------------------------
-- generate the additional informations needed by the debugger
-----------------------------------------------------------------------
    METHOD GenerateDbxDualInit;
      BEGIN
      --------------------------------------
      -- The beginline field
      --------------------------------------
      Ctx.Output.UniqueItem (MinNr);
      Ctx.Output.Arrow;
      Ctx.Output.BeginLine;
      Ctx.Output.Becomes;           
      Ctx.Output.WriteInt (Obj.LineNr, 0);
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
      --------------------------------------
      -- The endline field
      --------------------------------------
      Ctx.Output.UniqueItem (MinNr);
      Ctx.Output.Arrow;
      Ctx.Output.EndLine;
      Ctx.Output.Becomes;           
      Ctx.Output.WriteInt (Obj.EndIdent.LineNr, 0);
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
      --------------------------------------
      -- The once_ptr field
      --------------------------------------
      Ctx.Output.UniqueItem (MinNr);
      Ctx.Output.Arrow;
      Ctx.Output.OncePtr;
      Ctx.Output.Becomes;           
      IF Obj.Once THEN
        Ctx.Output.Ampersand;
        Ctx.Output.OnceClassInstance(ModName, ClName);
       ELSE
        Ctx.Output.Null;
        END; -- IF
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
      END GenerateDbxDualInit;
                 
      VAR
        VarNr, MinNr: INTEGER;
        OrgCl, InhCl: ClassDeclaration;
        ModName, ClName: ARRAY OF CHAR;
        KillDefined, CloneDefined: BOOLEAN;
        OrgMeth: MethodDeclaration;
        DefMeths: DeclList(MethodDefinition);
      BEGIN
      VarNr := YaflCfg.UniqueNumber;
      MinNr := YaflCfg.UniqueNumber;
      GenerateDualInitHeader (VarNr,
                              WithBody := TRUE);
      Ctx.Output.WriteLn;
      Ctx.Output.LeftBrace;
      Ctx.Output.WriteLn;
      Ctx.Output.MinimalDual;
      Ctx.Output.Star;
      Ctx.Output.UniqueItem (MinNr);
      Ctx.Output.Becomes;
      Ctx.Output.LeftParent;
      Ctx.Output.MinimalDual;
      Ctx.Output.Star;
      Ctx.Output.RightParent;
      Ctx.Output.UniqueItem (VarNr);
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;

      ---------------------------------------------
      -- First, call base class dual initialization
      ---------------------------------------------
      IF Obj.Inherits <> VOID THEN
        InhCl := Obj.Inherits.Class;
        Ctx.Output.ClassDualInitialization (InhCl.Module.Id.Data, InhCl.Id.Data);
        Ctx.Output.LeftParents(2);
        Ctx.Output.DualType (InhCl.Module.Id.Data, InhCl.Id.Data);
        Ctx.Output.Star;
        Ctx.Output.RightParent;
        Ctx.Output.UniqueItem (VarNr);
        Ctx.Output.RightParent;
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;
        END;
      ModName := Obj.ModuleName;
      ClName := Obj.Id.Data;

      --------------------------------------
      -- First, fill the minimal_dual prefix
      --------------------------------------

      --------------------------------------
      -- The element_size field:
      --------------------------------------
      Ctx.Output.UniqueItem (MinNr);
      Ctx.Output.Arrow;
      Ctx.Output.ElementSize;
      Ctx.Output.Becomes;
      Ctx.Output.SizeOf;
      Ctx.Output.LeftParent;
      Ctx.Output.Class (ModName, ClName);
      Ctx.Output.RightParent;
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;

      --------------------------------------
      -- The dual_size field:
      --------------------------------------
      Ctx.Output.UniqueItem (MinNr);
      Ctx.Output.Arrow;
      Ctx.Output.DualSize;
      Ctx.Output.Becomes;
      Ctx.Output.SizeOf;
      Ctx.Output.LeftParent;
      Ctx.Output.DualType (ModName, ClName);
      Ctx.Output.RightParent;
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
      -------------------------------------
      -- The class_name field:
      -------------------------------------
      Ctx.Output.UniqueItem (MinNr);
      Ctx.Output.Arrow;
      Ctx.Output.ClassName;
      Ctx.Output.Becomes;
      Ctx.Output.QuotedString (ClName, FALSE);
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
 
      -------------------------------------
      -- The module_name field:
      -------------------------------------
      Ctx.Output.UniqueItem (MinNr);
      Ctx.Output.Arrow;
      Ctx.Output.ModuleName;
      Ctx.Output.Becomes;
      Ctx.Output.QuotedString (ModName, FALSE);
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;    
      
      --------------------------------------
      -- The once_inst field
      --------------------------------------
      Ctx.Output.UniqueItem (MinNr);
      Ctx.Output.Arrow;
      Ctx.Output.OnceInstance;
      Ctx.Output.Becomes;
      IF Obj.Once THEN   
        Ctx.Output.Ampersand;
        Ctx.Output.OnceClassInstance (Obj.ModuleName, Obj.Id.Data);
       ELSE
        Ctx.Output.Null;
        END;
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
 
      --------------------------------------
      -- The inherited field
      --------------------------------------
      Ctx.Output.UniqueItem (MinNr);
      Ctx.Output.Arrow;
      Ctx.Output.Inherited;
      Ctx.Output.Becomes;
      Ctx.Output.LeftParent;
      Ctx.Output.ObjPtr;
      Ctx.Output.RightParent;
      IF InhCl = VOID THEN
        Ctx.Output.Zero;
       ELSE
        CClassDecl.GenerateDualRef(InhCl.Gc);
        END;
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
                 
      --------------------------------------
      -- The original_method_count field
      --------------------------------------
      Ctx.Output.UniqueItem (MinNr);
      Ctx.Output.Arrow;
      Ctx.Output.OrigMethCount;
      Ctx.Output.Becomes;           
      Ctx.Output.WriteInt (Obj.MethodsInDual.Size, 0);
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
                 
      Ctx.Output.UniqueItem (MinNr);
      Ctx.Output.Arrow;
      Ctx.Output.OnceTab;
      Ctx.Output.Becomes;
      IF Obj.GetOnceList = VOID THEN
        Ctx.Output.Null;
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;
       ELSE 
        ASSERT OnceTabNr <> 0;
        Ctx.Output.UniqueItem (OnceTabNr);
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;
        END;
      GenerateDbxDualInit;
      ----------------------
      -- The offsets array  
      -- first we set the the array
      ----------------------
      Ctx.Output.UniqueItem (MinNr);
      Ctx.Output.Arrow;
      Ctx.Output.MarkArray;
      Ctx.Output.Becomes;
      IF Obj.MarkableObjectsInAttributes = 0 THEN
        Ctx.Output.Null;
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;
       ELSE    
        Ctx.Output.UniqueItem (MarkingArrayNr);
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;

        Ctx.Output.UniqueItem (MinNr);
        Ctx.Output.Arrow;
        Ctx.Output.ReqMark;
        Ctx.Output.Becomes;
        Ctx.Output.One;
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;
        END;
        
      FOR CurMeth IN Obj.Methods DO
        IF CurMeth.Redefine THEN
          IF NOT CurMeth.IsCreate THEN
            IF CurMeth.Id.Data = PredefItems.Clone.Id.Data THEN
              ASSERT NOT CloneDefined;
              CloneDefined := TRUE;
              Ctx.Output.UniqueItem (MinNr);
              Ctx.Output.Arrow;
              Ctx.Output.CloneFunc;
              Ctx.Output.Becomes;
              CMethDecl.GenerateMethodRef(CurMeth.Gc);
              Ctx.Output.SemiColon;
             ELSIF CurMeth.Id.Data = PredefItems.Kill.Id.Data THEN
              ASSERT NOT KillDefined;
              KillDefined := TRUE;                    
              Ctx.Output.UniqueItem (MinNr);
              Ctx.Output.Arrow;
              Ctx.Output.KillFunc;
              Ctx.Output.Becomes;
              CMethDecl.GenerateMethodRef(CurMeth.Gc);
              Ctx.Output.SemiColon;
             ELSE
              -----------------------------------------
              -- Not a predefined method, use the method's
              -- original class
              -----------------------------------------
              OrgMeth := CurMeth.Redefined (TRUE);
              IF OrgMeth.AppearsInDual THEN
                OrgCl := OrgMeth.Class;
                Ctx.Output.LeftParents(2);
                Ctx.Output.DualType (OrgCl.Module.Id.Data, OrgCl.Id.Data);
                Ctx.Output.Star;
                Ctx.Output.RightParent;
                Ctx.Output.UniqueItem (VarNr);
                Ctx.Output.RightParent;
                Ctx.Output.Arrow;
                CMethDecl.GenerateMethodPointer(OrgMeth.Gc);
                Ctx.Output.Becomes;
                CMethDecl.GenerateMethodRef(CurMeth.Gc);
                Ctx.Output.SemiColon;
                Ctx.Output.WriteLn;
                END;
              END;
            END;
         ------------------------------
         -- NeedsSeparateAnchor will return FALSE if
         -- CurMeth is strapped withOut anchor
         -- in which case it does not even have to
         -- be present in the dual structure.
         ------------------------------
         ELSIF CurMeth.NeedsSeparateAnchor THEN
          IF NOT CurMeth.Deferred THEN
            Ctx.Output.UniqueItem (VarNr);
            Ctx.Output.Arrow;
            CMethDecl.GenerateMethodPointer(CurMeth.Gc);
            Ctx.Output.Becomes;
            CMethDecl.GenerateMethodRef(CurMeth.Gc);
            Ctx.Output.SemiColon;
            END;
          END;
        Ctx.Output.WriteLn;
        END;
        
      ---------------------------------------------
      -- Assign the default clone_func for cloning,
      -- or 0 for the kill method if required
      ---------------------------------------------
      IF (InhCl = VOID) THEN
        IF NOT CloneDefined THEN
          Ctx.Output.UniqueItem(MinNr);
          Ctx.Output.Arrow;
          Ctx.Output.CloneFunc;
          Ctx.Output.Becomes;
          Ctx.Output.DefaultClone;
          Ctx.Output.SemiColon;
          Ctx.Output.WriteLn;
          END;
        IF NOT KillDefined THEN
          Ctx.Output.UniqueItem(MinNr);
          Ctx.Output.Arrow;
          Ctx.Output.KillFunc;
          Ctx.Output.Becomes;
          Ctx.Output.WriteChar ('0');
          Ctx.Output.SemiColon;
          Ctx.Output.WriteLn;
          END;
        END;
      IF (Obj.Definition <> VOID) THEN
        ---------------------------------------------
        -- Now, go through the definition module,
        -- and initialize references to the functions
        -- attached to deferred method to 0.
        ---------------------------------------------
        DefMeths := Obj.Definition.Methods;
        FOR m IN DefMeths | m.Deferred DO
          Ctx.Output.UniqueItem (VarNr);
          Ctx.Output.Arrow;
          CMethDecl.GenerateMethodPointer(m.Gc);
          Ctx.Output.Becomes;
          Ctx.Output.Zero;
          Ctx.Output.SemiColon;
          END;
        END;
      GenerateDualInitDummy(MinNr);      
      Ctx.Output.RightBrace;
      Ctx.Output.WriteLn;
      END GenerateDualInit;

    METHOD GenerateFieldsInitDummy;
      BEGIN
      FOR Loc IN Obj.Attributes | NOT Loc.Removed DO
        WHAT Loc.Gc OF 
          IN CSingleDataItemCodeGenerator:
            TAG.GenerateFieldInitDummy(Obj.Module,Obj);
            END;
          END;                                                        
        END; -- FOR
      END GenerateFieldsInitDummy;

    METHOD GenerateClassInitialization;
      BEGIN
      Ctx.Output.Static;
      Ctx.Output.Void;
      Ctx.Output.ClassInitialization (Obj.ModuleName, Obj.Id.Data);
      Ctx.Output.YFormals (Arity := 0);
      Ctx.Output.LeftBrace;
      Ctx.Output.WriteLn;
      GenerateFillTables;
      ---------------------------------------
      -- If an initialization code has been defined,
      -- generate it.
      ---------------------------------------
      IF Obj.ClassBody <> VOID THEN
        Obj.ClassBody.Gc.GenerateCode;
        END;
      Ctx.Output.RightBrace;
      Ctx.Output.WriteLn;
      END GenerateClassInitialization;
      
    METHOD GenerateFieldReferenceVariables;
      VAR
        ModName, ClaName: ARRAY OF CHAR;

      METHOD GenerateFieldReferenceVariable(AttrName: ARRAY OF CHAR);
        BEGIN
        Ctx.Output.Static;
        Ctx.Output.FieldInfo;
        Ctx.Output.Star;
        Ctx.Output.DbxFieldReference(ModName, ClaName, AttrName);
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;
        END GenerateFieldReferenceVariable;

      BEGIN
      ModName := Obj.ModuleName;
      ClaName := Obj.Id.Data;
      FOR Attr IN Obj.Attributes | NOT Attr.Removed DO
        IF Attr.KeepInfo THEN
          GenerateFieldReferenceVariable(Attr.Id.Data);
          END; -- IF
        END;
      END GenerateFieldReferenceVariables;
  
    METHOD GenerateDummyObject: INTEGER;
      BEGIN
      Ctx.Output.Class(Obj.ModuleName, Obj.Id.Data);
      Ctx.Output.Space;
      RESULT := YaflCfg.UniqueNumber;
      Ctx.Output.UniqueItem(RESULT);
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
      END GenerateDummyObject;
        

    METHOD GenerateDataDictionaryInfo;
      VAR
        ModName,ClaName : ARRAY OF CHAR;
        DumVarNr: INTEGER;

        METHOD GenerateFieldAdd(AttrName : ARRAY OF CHAR;
                                TheType : Type;
                                OnceInst : SingleDataItem;
                                Hide: BOOLEAN);
          VAR
            Cl  : ClassDeclaration;
          BEGIN
          Ctx.Output.DbxFieldReference(ModName, ClaName, AttrName);
          Ctx.Output.Becomes;
          Ctx.Output.AddField;
          Ctx.Output.LeftParent;
          Ctx.Output.QuotedString(AttrName, UseEsc := FALSE);
          Ctx.Output.Comma;
          Cl := TheType.SimpleType;
          Ctx.Output.LeftParent;
          Ctx.Output.MinimalDual;
          Ctx.Output.Star;
          Ctx.Output.RightParent;
          WHAT Cl OF
            IN VirtualClassDecl:
              Ctx.Output.Ampersand;
              Ctx.Output.VirtualDual;
              END;
           ELSE
              CClassDecl.GenerateDualRef(Cl.Gc);
            END;
          Ctx.Output.Comma;
          Ctx.Output.WriteInt(TheType.ArrayLevel,0);
          Ctx.Output.Comma;
          IF OnceInst <> VOID THEN
            Ctx.Output.Ampersand;
            OnceInst.Gc.GenerateCode;
            Ctx.Output.Comma;
            Ctx.Output.Zero;
           ELSE
            Ctx.Output.Null;
            Ctx.Output.Comma;
            Ctx.Output.Offset;
            Ctx.Output.LeftParent;
            Ctx.Output.UniqueItem(DumVarNr);
            Ctx.Output.Comma;
            Ctx.Output.Yu(AttrName);
            Ctx.Output.RightParent;
            END;         
          Ctx.Output.Comma;
          GenerateMinDualRef;
-------------------------------   
-- patched by bernard
-- we add a boolean attribute to each field info to tell
-- if this field should be visible          
-------------------------------   
          Ctx.Output.Comma;
          Ctx.Output.BoolValue(NOT Hide);
          Ctx.Output.RightParent;
          Ctx.Output.SemiColon;
          Ctx.Output.WriteLn;
          END GenerateFieldAdd;

      METHOD GenerateClassDecls1;
        BEGIN
        FOR Loc IN Obj.Attributes | Loc.KeepInfo AND NOT Loc.Removed DO
          IF Loc.Once THEN
            GenerateFieldAdd(AttrName := Loc.Id.Data,
                               TheType := Loc.GetType,
                               OnceInst := Loc,
                               Hide := Loc.HideInfo);
           ELSE
            GenerateFieldAdd(AttrName := Loc.Id.Data,
                             TheType := Loc.GetType,
                             OnceInst := VOID,
                             Hide := Loc.HideInfo);
            END;
          END;
        END GenerateClassDecls1;

      METHOD GenerateMethodDictionary;
        VAR
          MethList              : DeclList(MethodDeclaration);
          CurMethod             : MethodDeclaration;
          ReturnType            : Type;
          ReturnArrayLevel      : INTEGER;
          MethodArity           : INTEGER;
          MethReturnType        : ClassDeclaration;
        BEGIN
        IF (YaflCfg.TraceModeLevel > 0) OR Obj.Publish THEN
        
          ASSERT Obj <> VOID;
          MethList:=Obj.MethodsInDual;
    
          FOR i:= 0 TO MethList.Size - 1 DO
            CurMethod := MethList.Get(i);
            ReturnType := CurMethod.Return;

            IF ReturnType = VOID THEN
              ReturnArrayLevel := 0;
             ELSE
              ReturnArrayLevel := ReturnType.ArrayLevel;
              MethReturnType := ReturnType.ConstrainedClass.SimpleType;
              END; -- IF ReturnType = VOID
               
            MethodArity := CurMethod.Arity;
         
--            Ctx.Output.AppendMethod;
            Ctx.Output.LeftParent;
        
            -- Pointer to the minimal dual 
            GenerateMinDualRef;
            Ctx.Output.Comma;
    
            -- Name of the method generation 
            Ctx.Output.NoCut;
            Ctx.Output.Quote;
            Ctx.Output.WriteString(CurMethod.Id.Data);
            Ctx.Output.Quote;
            Ctx.Output.Cut;
            Ctx.Output.Comma;
     
            -- Arity of the method generation
            Ctx.Output.WriteInt(MethodArity,0);
            Ctx.Output.Comma;
     
            -- Pointer to the return's minimal dual 
            IF MethReturnType = VOID THEN
              Ctx.Output.WriteInt(0,0);
             ELSE
              WHAT MethReturnType OF
                IN VirtualClassDecl:
                  Ctx.Output.WriteInt(0,0);
                  END;
               ELSE
                 CClassDecl.GenerateMinDualRef(MethReturnType.Gc);
                END;
              END;
            Ctx.Output.Comma;
     
            -- Return's array level generation
            Ctx.Output.WriteInt(ReturnArrayLevel,0);
            Ctx.Output.Comma;
       
            -- Original number in the dual
            ASSERT i >= 0;

            Ctx.Output.WriteInt(i,0);
            Ctx.Output.RightParent;
            Ctx.Output.SemiColon;
            Ctx.Output.WriteLn;

            END; -- FOR i:=0 TO MethList.Size-1 DO
          END; -- IF YaflCfg.TraceModeLevel > 0 THEN

--        CurClass:=CurClass.BaseClass;
--        END; -- WHILE CurClass <> VOID

--        Ctx.Output.WriteString("*/");
--        Ctx.Output.WriteLn;
        END GenerateMethodDictionary;

      BEGIN
      ModName := Obj.ModuleName;
      ClaName := Obj.Id.Data;
      Ctx.Output.Static;     
      Ctx.Output.Void;       
      Ctx.Output.ClassFieldsInsertion(ModName,ClaName);
      Ctx.Output.YFormals (Arity := 0);
      Ctx.Output.WriteLn;         
      Ctx.Output.LeftBrace; 
      Ctx.Output.WriteLn;        
      DumVarNr := GenerateDummyObject;
      GenerateClassDecls1;
      GenerateFieldsInitDummy;
      GenerateMethodDictionary;
      Ctx.Output.RightBrace;
      Ctx.Output.WriteLn;
      END GenerateDataDictionaryInfo;

    METHOD GenerateDbxClassCode;
      VAR
        ModName,ClaName : ARRAY OF CHAR;

      METHOD GenerateReferenceVariable;
        BEGIN
        Ctx.Output.Static;
        Ctx.Output.DbxClass;
        Ctx.Output.Star;
        Ctx.Output.DbxClassReference(ModName,ClaName);
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;
        END GenerateReferenceVariable;

----      METHOD GenerateClassAdd;
----        BEGIN
----        Ctx.Output.DbxClassReference(ModName,ClaName);
----        Ctx.Output.Becomes;
----        Ctx.Output.DbxAddClass;
----        Ctx.Output.LeftParent;
----        Ctx.Output.QuotedString(ClaName,UseEsc := FALSE);
----        Ctx.Output.Comma;
----        IF Obj.Once THEN
----          Ctx.Output.Ampersand;
----          Ctx.Output.OnceClassInstance(ModName,ClaName);
----         ELSE
----          Ctx.Output.Null;
----          END;
----        Ctx.Output.Comma;
----    GenerateMinDualRef;
----        Ctx.Output.Comma;
----        Ctx.Output.WriteInt(Obj.LineNr,0);
----        Ctx.Output.Comma;
----        Ctx.Output.WriteInt(Obj.EndIdent.LineNr,0);
----        Ctx.Output.RightParent;
----        Ctx.Output.SemiColon;
----        Ctx.Output.WriteLn;
----        END GenerateClassAdd;

      METHOD GenerateClassAdd;
        BEGIN
        Ctx.Output.DbxAddClass;
        Ctx.Output.LeftParent;
        GenerateMinDualRef;
        Ctx.Output.RightParent;
        Ctx.Output.SemiColon;
        Ctx.Output.WriteLn;
        END GenerateClassAdd;

      METHOD GenerateClassDecls2;
        
        METHOD GenerateMethodInit(Meth: MethodImplementation);
          BEGIN
--          IF NOT Meth.Deferred THEN
            Ctx.Output.Comment("BERNARD2");
            CMethImp(Meth.Gc).GenerateDbxMethodInitialization;
            Ctx.Output.LeftParent;
            Ctx.Output.RightParent;
            Ctx.Output.SemiColon;
            Ctx.Output.WriteLn;
--            END;
          END GenerateMethodInit;
          
        METHOD GenerateDeferredMethodInit(Meth: MethodDefinition);
          BEGIN
          -- XXJC
--          IF NOT Meth.Deferred THEN
            Ctx.Output.Comment("BERNARD3");
        Ctx.Output.IfDefined(Ctx.Output.FullTraceModeLabel);
            CMethDef(Meth.Gc).GenerateDbxMethodInitialization;
            Ctx.Output.LeftParent;
            Ctx.Output.RightParent;
            Ctx.Output.SemiColon;
            Ctx.Output.WriteLn;
        Ctx.Output.EndIf;     
--            END;
          -- END XXJC
          END GenerateDeferredMethodInit;

        BEGIN    
        FOR m IN Obj.Methods | (YaflCfg.TraceModeLevel = 2) OR m.Publish DO
-- patched by bernard
-- useful not only for debugger now
-- CAUTION: there is one subtle difference when the mechanism
-- is used for the debugger, or for the data dictionary
-- in the first case the initialization must be done globally
-- for the whole module, but in the second case it must be done
-- selectively only for PUBLISHed classes
          GenerateMethodInit(m);
          END;
        IF Obj.Definition <> VOID THEN  
          FOR Meth IN Obj.Definition.Methods | Meth.Deferred DO
            GenerateDeferredMethodInit(Meth);
            END;
          END;  
        END GenerateClassDecls2;

      BEGIN
      ModName := Obj.ModuleName;
      ClaName := Obj.Id.Data;
--      Ctx.Output.Comment("DbxClassImplementation GenerateCode");
      -----------------------------------------------------
      -- generates class initialization function
      -----------------------------------------------------
-- patched by bernard
-- useful not only for debugger now
      IF NOT Obj.Publish THEN
        Ctx.Output.IfDefined(Ctx.Output.FullTraceModeLabel);
        END;
      GenerateReferenceVariable;
      Ctx.Output.Static;
      Ctx.Output.Void;
      Ctx.Output.DbxClassInitialization(ModName,ClaName);
      Ctx.Output.IfDef;
      Ctx.Output.Ansi;
      Ctx.Output.LeftParent;
      Ctx.Output.Void;
      Ctx.Output.RightParent;
      Ctx.Output.ElseDef;
      Ctx.Output.LeftParent;
      Ctx.Output.RightParent;
      Ctx.Output.EndIf;
      Ctx.Output.WriteLn;
      Ctx.Output.LeftBrace;
      Ctx.Output.WriteLn;
      GenerateClassAdd;
      GenerateClassDecls2;
      Ctx.Output.RightBrace;
      Ctx.Output.WriteLn;
-- patched by bernard
-- useful not only for debugger now
      IF NOT Obj.Publish THEN
        Ctx.Output.EndIf;
        END;
      END GenerateDbxClassCode;

    METHOD GenerateRegistration;
      BEGIN
      Ctx.Output.RegisterClass;
      Ctx.Output.LeftParent;
      GenerateMinDualRef;
      Ctx.Output.RightParent;
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
      END GenerateRegistration;
      
    METHOD GenerateDualInitialization;
      BEGIN
      Ctx.Output.ClassDualInitialization (Obj.ModuleName, Obj.Id.Data);
      Ctx.Output.LeftParent;
      GenerateDualRef;
      Ctx.Output.RightParent;
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;  
      END GenerateDualInitialization;

    METHOD GenerateClassFieldsInsertion;
      BEGIN
      ASSERT Ctx.Output <> VOID;
      Ctx.Output.ClassFieldsInsertion (Obj.ModuleName, Obj.Id.Data);
      Ctx.Output.LeftParent;
      Ctx.Output.RightParent;
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
      END GenerateClassFieldsInsertion;

    METHOD GeneratePublicAnchorDefinitions;
      BEGIN
      IF Obj.Definition <> VOID THEN
        FOR m IN Obj.Definition.Methods | m.Deferred DO
          CMethDecl.GenerateAnchorDefinition(m.Gc);
          END;
        END;
      FOR m IN Obj.Methods | m.Public DO
        CMethDecl.GenerateAnchorDefinition(m.Gc);
        END;            
      IF YaflCfg.PleaseGlobalOptimize THEN
        GenerateEntryPoints;
        END;
      END GeneratePublicAnchorDefinitions;
      
-- Global Optimization


    ------------------------------
    -- Generates the names of methods callable straight
    ------------------------------
    METHOD GenerateEntryPoints;
      VAR 
        MethRef : MethodReference;
      BEGIN        
      FOR i := 0 TO Obj.Methods.Size-1 DO
        MethRef := Obj.Methods.Get(i).Reference;
        IF (MethRef <> VOID) AND MethRef.Monomorphable THEN
		  CMethImp(Obj.Methods.Get(i).Gc).GenerateMethodDefinition;
          END;
        END;
      END GenerateEntryPoints;

    METHOD GenerateMinDualRef;
      BEGIN
      Ctx.ClassDeclGenerateMinDualRef(THIS);
      END GenerateMinDualRef;   

    METHOD GenerateConstructFuncId;
      BEGIN
      Ctx.ClassDeclGenerateConstructFuncId(THIS);
      END GenerateConstructFuncId;   

    METHOD GenerateCreateAnchorId;
      BEGIN
      Ctx.ClassDeclGenerateCreateAnchorId(THIS);
      END GenerateCreateAnchorId;   

    METHOD GenerateMinimalDualExtract;
      BEGIN
      Ctx.ClassDeclGenerateMinimalDualExtract(THIS);
      END GenerateMinimalDualExtract;   

    METHOD GenerateDualRef;
      BEGIN
      Ctx.ClassDeclGenerateDualRef(THIS);
      END GenerateDualRef;   

    METHOD GenerateCast;
      BEGIN
      Ctx.ClassDeclGenerateCast(THIS);
      END GenerateCast;   

    METHOD GenerateVersionChecking(ImportingModule: ImplementationModule);
      BEGIN
      Ctx.ClassDeclGenerateVersionChecking(THIS, ImportingModule);
      END GenerateVersionChecking;

    METHOD GenerateDbxExtRefVariables;
      BEGIN
      FOR Meth IN Obj.Methods DO
        CMethImp(Meth.Gc).GenerateDbxExtRefVariable;
        END;
      IF Obj.Definition <> VOID THEN
        ASSERT Obj.Definition.Methods <> VOID;
        FOR Meth IN Obj.Definition.Methods | Meth.Deferred DO
          CMethDef(Meth.Gc).GenerateDbxExtRefVariable;
          END;
        END;
      END GenerateDbxExtRefVariables;

    METHOD GenerateMethodChainInitRef;
      BEGIN
      Ctx.Output.MethodChainInitialisation(Obj.Module.Id.Data, Obj.Id.Data);
      END GenerateMethodChainInitRef; 

    METHOD GenerateMethodChainInitCall;
      BEGIN
      --Ctx.Output.IfDefined(Ctx.Output.FullTraceModeLabel);
      --GenerateMethodChainInitRef;
	  --Ctx.Output.LeftParent;
	  --Ctx.Output.RightParent;
      --Ctx.Output.SemiColon;
      --Ctx.Output.WriteLn;
	  --Ctx.Output.EndIf;
      GenerateMethodChainInitRef;
	  Ctx.Output.LeftParent;
	  Ctx.Output.RightParent;
      Ctx.Output.SemiColon;
      Ctx.Output.WriteLn;
      END GenerateMethodChainInitCall; 

    METHOD GenerateMethodChainInit;
      BEGIN
      Ctx.Output.IfDefined(Ctx.Output.FullTraceModeLabel);
      Ctx.Output.Static;
      Ctx.Output.Void;
      GenerateMethodChainInitRef;
      Ctx.Output.IfDef;
      Ctx.Output.Ansi;                        
      Ctx.Output.LeftParent;
      Ctx.Output.Void;
      Ctx.Output.RightParent;
      Ctx.Output.ElseDef;
      Ctx.Output.LeftParent;
      Ctx.Output.RightParent;
      Ctx.Output.EndIf;
      Ctx.Output.WriteLn;
      Ctx.Output.LeftBrace;
	  FOR Meth IN Obj.Methods DO
        CMethImp(Meth.Gc).GenerateDbxMethodChainInsert;
        Ctx.Output.LeftParent;
        Ctx.Output.RightParent;
        Ctx.Output.SemiColon; 
  	    Ctx.Output.WriteLn;
        END;
      IF Obj.Definition <> VOID THEN
	    FOR Meth IN Obj.Definition.Methods | Meth.Deferred DO
          CMethDef(Meth.Gc).GenerateDbxMethodChainInsert;
          Ctx.Output.LeftParent;
          Ctx.Output.RightParent;
          Ctx.Output.SemiColon; 
  	      Ctx.Output.WriteLn;
          END;
        END;
      Ctx.Output.RightBrace;
	  Ctx.Output.WriteLn;
	  Ctx.Output.EndIf;
      END GenerateMethodChainInit; 

  END CClassImplCodeGenerator; 
           
   
  ONCE CLASS CClassDecl; -- METHOD
    
    METHOD GenerateConstructFuncId(Gc: ClassDeclCodeGenerator);
      BEGIN
      WHAT Gc OF
        IN CDummyClDeclCodeGenerator:
           TAG.GenerateConstructFuncId;
           END;
        IN CVirtualClassDeclCodeGenerator:
           TAG.GenerateConstructFuncId;
           END;
        IN CInstClassDefCodeGenerator:
           TAG.GenerateConstructFuncId;
           END;
        IN CPredefClassCodeGenerator:
           TAG.GenerateConstructFuncId;
           END;
        IN CClassImplCodeGenerator:
           TAG.GenerateConstructFuncId;
           END;
        END; -- what
      END GenerateConstructFuncId;
    
    METHOD GenerateMinDualRef(Gc: ClassDeclCodeGenerator);
      BEGIN
      WHAT Gc OF
        IN CDummyClDeclCodeGenerator:
           TAG.GenerateMinDualRef;
           END;
        IN CVirtualClassDeclCodeGenerator:
           TAG.GenerateMinDualRef;
           END;
        IN CInstClassDefCodeGenerator:
           TAG.GenerateMinDualRef;
           END;
        IN CPredefClassCodeGenerator:
           TAG.GenerateMinDualRef;
           END;
        IN CClassImplCodeGenerator:
           TAG.GenerateMinDualRef;
           END;
        END; -- what
      END GenerateMinDualRef;

    METHOD GenerateDualRef(Gc: ClassDeclCodeGenerator);
      BEGIN
      WHAT Gc OF
        IN CDummyClDeclCodeGenerator:
           TAG.GenerateDualRef;
           END;
        IN CVirtualClassDeclCodeGenerator:
           TAG.GenerateDualRef;
           END;
        IN CInstClassDefCodeGenerator:
           TAG.GenerateDualRef;
           END;
        IN CPredefClassCodeGenerator:
           TAG.GenerateDualRef;
           END;
        IN CClassImplCodeGenerator:
           TAG.GenerateDualRef;
           END;
        END; -- what
      END GenerateDualRef;

    METHOD GenerateLiteral(Gc: ClassDeclCodeGenerator);
      BEGIN
      WHAT Gc.Ctx OF
        IN CGcContext:
          TAG.ClassDeclGenerateLiteral(Gc);
          END;
        END;
      END GenerateLiteral;

    METHOD GenerateCreateAnchorId(Gc: ClassDeclCodeGenerator);
      BEGIN
      WHAT Gc OF
        IN CDummyClDeclCodeGenerator:
           TAG.GenerateCreateAnchorId;
           END;
        IN CVirtualClassDeclCodeGenerator:
           TAG.GenerateCreateAnchorId;
           END;
        IN CInstClassDefCodeGenerator:
           TAG.GenerateCreateAnchorId;
           END;
        IN CPredefClassCodeGenerator:
           TAG.GenerateCreateAnchorId;
           END;
        IN CClassImplCodeGenerator:
           TAG.GenerateCreateAnchorId;
           END;
        END; -- what
      END GenerateCreateAnchorId;

    METHOD GenerateCast(Gc: ClassDeclCodeGenerator);
      BEGIN
      WHAT Gc OF
        IN CDummyClDeclCodeGenerator:
           TAG.GenerateCast;
           END;
        IN CVirtualClassDeclCodeGenerator:
           TAG.GenerateCast;
           END;
        IN CInstClassDefCodeGenerator:
           TAG.GenerateCast;
           END;
        IN CPredefClassCodeGenerator:
           TAG.GenerateCast;
           END;
        IN CClassImplCodeGenerator:
           TAG.GenerateCast;
           END;
        END; -- what
      END GenerateCast;

    METHOD GenerateMinimalDualExtract(Gc: ClassDeclCodeGenerator);
      BEGIN
      WHAT Gc OF
        IN CDummyClDeclCodeGenerator:
           TAG.GenerateMinimalDualExtract;
           END;
        IN CVirtualClassDeclCodeGenerator:
           TAG.GenerateMinimalDualExtract;
           END;
        IN CInstClassDefCodeGenerator:
           TAG.GenerateMinimalDualExtract;
           END;
        IN CPredefClassCodeGenerator:
           TAG.GenerateMinimalDualExtract;
           END;
        IN CClassImplCodeGenerator:
           TAG.GenerateMinimalDualExtract;
           END;
        END; -- what
      END GenerateMinimalDualExtract;

    END CClassDecl;

END CGClass;
