IMPLEMENTATION MODULE CGModules;

IMPORT SYSTEM;
FROM Conversions           IMPORT IntConversions;
FROM String                IMPORT String;
FROM Streams               IMPORT Stream, StdOut;
FROM YaflCfg               IMPORT CurrentSpot, YaflCfg;
FROM YaflController        IMPORT Controller;
FROM YaflGC                IMPORT YaflGC;

------------------------------
-- C Code Generators
------------------------------
FROM CGCode    IMPORT CGcContext;
FROM CGClass   IMPORT CClassImplCodeGenerator;
FROM CGMethods IMPORT CPredefMethCodeGenerator,
                      CMethDefCodeGenerator,
                      CMethImplCodeGenerator;

------------------------------
-- Generic Code Generators
------------------------------
FROM YaflGClass   IMPORT ClassImplCodeGenerator;
FROM YaflGMethods IMPORT MethDeclCodeGenerator;

------------------------------
-- Non Terminals
------------------------------
FROM YaflModules           IMPORT CompilationUnit, 
                                  ImplementationModule,
                                  DefinitionModule,
                                  ModuleSet;
FROM YaflCreator           IMPORT Creators;
FROM YaflClImplementation  IMPORT ClassImplementation;
FROM YaflClDefinition      IMPORT ClassDefinition;
FROM YaflClasses           IMPORT ClassDeclaration;
FROM YaflNTList            IMPORT DeclList, 
                                  MultiDeclList,
                                  ClassList,
                                  NTSet;
FROM YaflPredefined        IMPORT PredefItems;
FROM YaflMethods           IMPORT MethodDeclaration;
FROM YaflParser            IMPORT NonTerminal, Walker;
FROM YaflStatements        IMPORT Statement;


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

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

    METHOD CClassImp(Gc: ClassImplCodeGenerator): CClassImplCodeGenerator;
      BEGIN
      WHAT Gc OF
        IN CClassImplCodeGenerator:
          RESULT := TAG;
          END;
        END;
      END CClassImp;

    METHOD CDefModule(Gc: DefModuleCodeGenerator): CDefModuleCodeGenerator;
      BEGIN
      WHAT Gc OF
        IN CDefModuleCodeGenerator:
          RESULT := TAG;
          END;
        END;
      END CDefModule;

    METHOD GenerateDataStructures (Pass: INTEGER;
                                   PublicOnly: BOOLEAN);
      VAR
        ClIm: ClassImplementation;
        ClList: DeclList (ClassImplementation);
      BEGIN
      ClList := Obj.Classes;
      FOR i := 0 TO ClList.Size - 1 DO
        ClIm := ClList.Get(i);
        IF (PublicOnly AND (ClIm.Definition <> VOID) ) 
           OR ( (NOT PublicOnly) AND (ClIm.Definition = VOID) ) THEN
          Output.Extern;
          Output.Char;
          Output.Star;
          Ctx.ClassDeclGenerateLiteral(ClIm.Gc);
          Output.SemiColon;
          Output.WriteLn;
          CClassImp(ClIm.Gc).GenerateDualStructure(Pass);
          CClassImp(ClIm.Gc).GenerateDataStructure(Pass);
          IF Pass = 2 THEN
            IF ClIm.NeedsConstructFunc THEN
              CClassImp(ClIm.Gc).GenerateConstructFuncHeader (WithBody := FALSE);
              Output.SemiColon;
              Output.WriteLn;
              END;
            CClassImp(ClIm.Gc).GenerateDualInitHeader (0, WithBody := FALSE);
            Output.SemiColon;
            Output.WriteLn;
            END;
          END;
        END;
      END GenerateDataStructures;

    METHOD GenerateAnchorDefinitions (PublicOnly: BOOLEAN);
      VAR
        ClList: DeclList (ClassImplementation);
        ClIm: ClassImplementation;
      BEGIN
      ClList := Obj.Classes;
      FOR i := 0 TO ClList.Size - 1 DO
        ClIm := ClList.Get(i);
        IF PublicOnly THEN
          CClassImp(ClIm.Gc).GeneratePublicAnchorDefinitions;
         ELSE
          CClassImp(ClIm.Gc).GeneratePrivateAnchorDefinitions;
          END;
        END;
      END GenerateAnchorDefinitions;

    METHOD GenerateDbxExtRefVariables;
      BEGIN
      Output.IfDefined(Output.FullTraceModeLabel);
      FOR Cl IN Obj.Classes DO
        CClassImp(Cl.Gc).GenerateDbxExtRefVariables;
        END;
      Output.EndIf;
      END GenerateDbxExtRefVariables;
      
    METHOD GenerateHeaderFile1;
      VAR
        Incs: ARRAY OF ARRAY OF CHAR;
        BEGIN
      Incs := Obj.IncludePragmas + Obj.DefModule.IncludePragmas;
      IF Incs <> VOID THEN
        FOR i := 0 TO Incs.SIZE - 1 DO
          Output.PragmaInclude (Incs[i]);
          END;
        END;
      ----------------------------------------
      -- Then, generate the additive data structure, as well as the
      -- corresponding macros to denote their size
      -- Public classes only
      ----------------------------------------
      GenerateDataStructures( Pass := 1,
                              PublicOnly := TRUE);
      ----------------------------------------
      -- Generate the external variable declaration for
      -- the module name.                              
      ----------------------------------------                              
      Output.Extern;
      Output.Char;
      Output.Star;
      Ctx.CompilationUnitGenerateLiteral(THIS);
      Output.SemiColon;
      Output.WriteLn;
      GenerateDbxExtRefVariables;
      END GenerateHeaderFile1;
      
    METHOD GenerateHeaderFile2;
      BEGIN                                   
      ----------------------------------------
      -- Now, generate the complete data structures, including the
      -- inheritance information.
      -- Public classes only
      ----------------------------------------
      GenerateDataStructures(Pass := 2, PublicOnly := TRUE);
      GenerateAnchorDefinitions(PublicOnly := TRUE);
      GenerateInitializationHeader(0, WithBody := FALSE);
      Output.SemiColon;
      Output.WriteLn;
      GenerateDbxExtRefVariables;
      END GenerateHeaderFile2;

    METHOD GenerateHeaderFiles: INTEGER;
      VAR
        TheOutput: YaflGC;
      BEGIN
      TheOutput := Creators.Stream.CreateGC;
      TheOutput.OpenHeaderFile(Obj, 1);
      IF TheOutput.ErrorCode = Stream.NoError THEN
        Ctx.SetOutput (TheOutput);
        GenerateHeaderFile1;
        RESULT := Output.GeneratedLines;                                
        TheOutput.Close;
        Ctx.SetOutput(VOID);
        END;

      TheOutput := Creators.Stream.CreateGC;
      ASSERT TheOutput <> VOID;
      TheOutput.OpenHeaderFile(Obj, 2);
      ASSERT TheOutput <> VOID;
      IF TheOutput.ErrorCode = Stream.NoError THEN
        ----------------------------------------
        -- Now, generate the complete data structures, including
        -- the inheritance information.
        -- Public classes only
        ----------------------------------------
        Ctx.SetOutput (TheOutput);
        GenerateHeaderFile2;
        RESULT := RESULT + Output.GeneratedLines;
        TheOutput.Close;
        Ctx.SetOutput(VOID);
        END;
      END GenerateHeaderFiles;

    METHOD GenerateInstances;
      VAR
        ClassName, ModName: ARRAY OF CHAR;
        ClList: DeclList (ClassImplementation);
        ClIm: ClassImplementation;
      BEGIN
      ClList := Obj.Classes;
      ModName := Obj.Id.Data;
      FOR i := 0 TO ClList.Size - 1 DO
        ClIm := ClList.Get(i);
        ClassName := ClIm.Id.Data;
        -------------------------------
        -- First, dual instances
        -------------------------------
        Output.DualType (ModName, ClassName);

        Output.DualInstance(ModName, ClassName);        
        Output.SemiColon;
        Output.WriteLn;

        -------------------------------
        -- Then, once class instances
        -- obj_ptr inst = (obj_ptr)0;
        -------------------------------
        IF ClIm.Once THEN
          Output.ObjPtr;
          Output.OnceClassInstance (ModName, ClassName);
          Output.Becomes;
          Output.LeftParent;
          Output.ObjPtr;
          Output.RightParent;
          Output.WriteChar ('0');
          Output.SemiColon;
          Output.WriteLn;
          END;
        CClassImp(ClIm.Gc).OutputOnceItems;
        END;
      END GenerateInstances;

    METHOD GenerateDualRef;
      BEGIN
      Output.ModuleDualRef(Obj.Id.Data);
      END GenerateDualRef;

    METHOD GenerateBodyFile: INTEGER;
      VAR
        TheOutput: YaflGC;
      BEGIN
      TheOutput := Creators.Stream.CreateGC;
      TheOutput.OpenBodyFile(Obj);
      IF TheOutput.ErrorCode = Stream.NoError THEN
        Ctx.SetOutput (TheOutput);
        GeneratePrefix;
        -------------------------------------------
        -- Include the right header files.
        -------------------------------------------
        GenerateIncludes;
        IF YaflCfg.PleaseGlobalOptimize THEN
          -- Undefine CHECK_VERSION
          Output.Undefine;
          Output.CheckVersion;
          Output.Define;
          Output.CheckVersion;
          Output.WriteLine("(importing,dual,elem_size,dual_size)");
          END;
        IF YaflCfg.CheckVersionLevel > 1 THEN
          GenerateVersionReferences;
          END;
        -------------------------------------------
        -- Generate the data structure as well as the
        -- duals for private classes.
        -------------------------------------------
        Output.Char;
        Output.Star;
        Ctx.CompilationUnitGenerateLiteral(THIS);
        Output.Becomes;      
        Output.QuotedString (Obj.Id.Data, 
                             UseEsc := FALSE);
        Output.SemiColon;
        Output.WriteLn;        
        -------------------------------------------
        -- #Define the current module name
        -------------------------------------------
        Output.Define;
        Output.CurrentModuleName;
        Output.WriteChar (' ');
        Ctx.CompilationUnitGenerateLiteral(THIS);
        Output.WriteLn;
        -------------------------------------------
        -- Create the module dual
        -------------------------------------------
        Output.ModuleDual;
        Output.WriteChar (' ');
        GenerateDualRef;
        Output.SemiColon;
        Output.WriteLn;
        -------------------------------------------
        -- Generate the inline parts
        -------------------------------------------
        IF Obj.InLine <> VOID THEN
          Obj.InLine.Gc.GenerateCode;
          END;
        GenerateDataStructures(Pass := 1, PublicOnly := FALSE);
        GenerateDataStructures(Pass := 2, PublicOnly := FALSE);
        GenerateInstances;
        GenerateAnchorDefinitions(PublicOnly := FALSE);
        ----------------------------------------------
        -- All the symbols have been made visible.
        -- There cannot be any kind of cyclic visibility
        -- problem anymore. From now on, class-related
        -- code will be groupe whenever possible.
        ----------------------------------------------
        Obj.Classes.GenerateCode;
        GenerateInitialization;
        Output.WriteLn;
        
        --------------------------------------
        -- Generate the version key information...
        --------------------------------------
        Output.Int;
        CDefModule(Obj.DefModule.Gc).GenerateVersionKey;
        Output.SemiColon;
        Output.WriteLn;
        
        RESULT := Output.GeneratedLines;
        Output.Close;
        Ctx.SetOutput (VOID);
        END;
      END GenerateBodyFile;
        
   VAR
      GenLines: INTEGER;
      
    REDEFINE METHOD GeneratedLines: INTEGER;
      BEGIN
      RESULT := GenLines;
      END GeneratedLines;  
      
   REDEFINE METHOD GenerateCode;
      BEGIN
      YaflCfg.GetController.Capture (Controller.GenerateC);
      CurrentSpot.PushCurrentModule (Obj);
      GenLines := GenerateHeaderFiles;
      Obj.DefModule.ResetVersionKey;
      GenLines := GenLines + GenerateBodyFile;
      CurrentSpot.PopCurrentModule;
      END GenerateCode;

    METHOD GenerateIncludes;
      VAR
        p: ARRAY OF DefinitionModule;
      BEGIN
      p := Obj.TransitiveClosure.Row;
      FOR Pass := 1 TO 2 DO
        FOR i := 0 TO p.SIZE - 1 DO
          CDefModule(p[i].Gc).GenerateInclude(MainModule := Obj, Pass);
          END;
        END;
      END GenerateIncludes;
      
    METHOD GenerateVersionReferences;
      VAR
        p: ARRAY OF DefinitionModule;
      BEGIN
      p := Obj.TransitiveClosure.Row;
      FOR Pass := 1 TO 2 DO
        FOR i := 0 TO p.SIZE - 1 DO 
          Output.Extern;
          Output.Int;
          CDefModule(p[i].Gc).GenerateVersionKey;
          Output.SemiColon;
          Output.WriteLn;
          END;
        END;
      END GenerateVersionReferences;

    METHOD GenerateVersionRefUsage;
      VAR
        p: ARRAY OF DefinitionModule;
      BEGIN
      p := Obj.TransitiveClosure.Row;
      FOR Pass := 1 TO 2 DO
        FOR i := 0 TO p.SIZE - 1 DO 
          CDefModule(p[i].Gc).GenerateVersionKey;
          Output.Becomes;
          Output.WriteChar ('0');
          Output.SemiColon;
          Output.WriteLn;
          END;
        END;
      END GenerateVersionRefUsage;

    METHOD GeneratePrefix;
      BEGIN
      YaflCfg.GenerateDefines(Output);
      GenerateDefines;
      Output.IncludeRuntime;
      IF YaflCfg.TraceModeLevel = 2 THEN
        GenerateDbxModulePrefix;
        END;
      END GeneratePrefix;

    METHOD GenerateDefines;
      BEGIN
      Output.Define;
      Output.SourceLines;
      Output.Space;
      Output.WriteInt(Obj.LineCount, 0);
      Output.WriteLn;
      END GenerateDefines;
      
    -----------------------------------------------
    -- this method generates the text of the C include
    -- of the runtime of the debugger that must be
    -- present in each debugged module;
    -- it comes after the C include of the runtime of
    -- the compiler;this is necessary as the former
    -- redefines some macro definitions of the latter;
    -------------------------------------------------
    METHOD GenerateDbxModulePrefix;
      BEGIN                      
      Output.WriteLn;
      Output.IncludeDbxRuntime;
      END GenerateDbxModulePrefix;


    METHOD GenerateInitializationHeader( PassVarNr: INTEGER;
                                         WithBody: BOOLEAN);
      BEGIN
      Output.Void;
      Output.ModuleInitialization (Obj.Id.Data);
      IF WithBody THEN
        Output.YFormals (Arity := 1);
       ELSE
        Output.YArgs;
        Output.LeftParent;      
        END;
      Output.LeftParent;
      Output.Int;
      IF WithBody THEN
        Output.Comma;
        END;
      Output.UniqueItem (PassVarNr);
      Output.RightParent;
      IF NOT WithBody THEN
        Output.RightParent;
        END;
      END GenerateInitializationHeader;

    METHOD GenerateDualInitialization;
      BEGIN
      -- Name
      GenerateDualRef;
      Output.Dot;
      Output.WriteString ('name');
      Output.Becomes;
      Ctx.CompilationUnitGenerateLiteral(THIS);
      Output.SemiColon;
      Output.WriteLn;

      -- Lines
      GenerateDualRef;
      Output.Dot;
      Output.LineCount;
      Output.Becomes;
      Output.WriteInt (Obj.LineCount,0);
      Output.SemiColon;
      Output.WriteLn;
------------------------------------------------------------------------
-- add the data that was previously in the debugger structures
------------------------------------------------------------------------
      GenerateDbxDualInitialization;

      --------------------
      -- Profile Information
      --------------------
      Output.IfDefined(Output.ProfileModeLabel);
      GenerateDualRef;
      Output.Dot;
      Output.ProfileLines;
      Output.Becomes;
      Output.ProfileLines;
      Output.SemiColon;
      Output.WriteLn;
      Output.EndIf;

      END GenerateDualInitialization;

    METHOD GenerateDbxDualInitialization;
      BEGIN
      -- complete file name of the source file
      GenerateDualRef;
      Output.Dot;
      Output.SourceFileName;
      Output.Becomes;
      Output.QuotedString(YaflCfg.NameMapper.MakeAbsolute(
                              Obj.GetWorld.BuildSourceFName (Obj.Id.Data, 
                                                        YaflCfg.ImpExt)),
                          UseEsc := TRUE);
      Output.SemiColon;
      Output.WriteLn;
      -- array of statements line numbers
      Output.IfDefined(Output.FullTraceModeLabel);
      GenerateDualRef;
      Output.Dot;
      Output.LineNumbers;
      Output.Becomes;
      Output.ModuleLinesRef(Obj.Id.Data);
      Output.SemiColon;
      Output.WriteLn;
      Output.EndIf;
      -- Lines
      GenerateDualRef;
      Output.Dot;
      Output.FirstClass;
      Output.Becomes;
      IF (Obj.Classes <> VOID) AND (Obj.Classes.Size > 0) THEN
        Ctx.ClassDeclGenerateMinDualRef(Obj.Classes.Get(0).Gc);
       ELSE
        Output.Null;
        END; -- IF
      Output.SemiColon;
      Output.WriteLn;
      -- Lines
      GenerateDualRef;
      Output.Dot;
      Output.LastClass;
      Output.Becomes;
      IF (Obj.Classes <> VOID) AND (Obj.Classes.Size > 0) THEN
        Ctx.ClassDeclGenerateMinDualRef(Obj.Classes.Get(Obj.Classes.Size - 1).Gc);
       ELSE
        Output.Null;
        END; -- IF
      Output.SemiColon;
      Output.WriteLn;
      END GenerateDbxDualInitialization;

    METHOD GenerateRegisterModule;
      BEGIN
      Output.RegisterModule;
      Output.LeftParent;
      Output.Ampersand;
      GenerateDualRef;
      Output.RightParent;
      Output.SemiColon;
      Output.WriteLn;
      END GenerateRegisterModule;


    METHOD GeneratePassOneInit;
      VAR
        ClList: DeclList(ClassImplementation);
        ClIm: ClassImplementation;
      BEGIN
      GenerateDualInitialization;
      GenerateRegisterModule;
      ClList := Obj.Classes;
      FOR i := 0 TO ClList.Size - 1 DO
        ClIm := ClList.Get(i);
        CClassImp(ClIm.Gc).GenerateDualInitialization;
        CClassImp(ClIm.Gc).GenerateClassFieldsInsertion;
        CClassImp(ClIm.Gc).GenerateRegistration;
        END;
      END GeneratePassOneInit;
  
    METHOD GeneratePassTwelveInit;
      BEGIN
-- patched by bernard
-- useful not only for debugger now
      Output.Comment("BERNARD10");
      IF (YaflCfg.TraceModeLevel = 2) OR Obj.Publish THEN
        GenerateDbxModulePassTwoInit;
        END;
      END GeneratePassTwelveInit;
      
    ------------------------------------------------------
    -- this method generates the text of the C function call
    -- to the module initialization function of the debugger;
    -- it must be made in pass two because ???
    ------------------------------------------------------
    METHOD GenerateDbxModulePassTwoInit;
      BEGIN
--      Output.Comment("DbxImplementationModule GeneratePassTwoInit");
-- patched by bernard
-- useful not only for debugger now
      Output.Comment("BERNARD4");
      IF NOT Obj.Publish THEN
        Output.IfDefined(Output.FullTraceModeLabel);
        END; -- IF
      Output.DbxModuleInitialization(Obj.Id.Data);
      Output.LeftParent;
      Output.RightParent;
      Output.SemiColon;
      Output.WriteLn;
-- patched by bernard
-- useful not only for debugger now
      IF NOT Obj.Publish THEN
        Output.EndIf;
        END;
      END GenerateDbxModulePassTwoInit;

    METHOD GenerateDbxModulePassThreeInit;
      BEGIN
--      Output.Comment("DbxImplementationModule GeneratePassThreeInit");
-- patched by bernard
-- useful not only for debugger now
      Output.Comment("BERNARD5");
      IF NOT Obj.Publish THEN
        Output.IfDefined(Output.FullTraceModeLabel);
        END; -- IF
      Output.DbxYaflInit;
      Output.LeftParent;
      Output.RightParent;
      Output.SemiColon;                  
      Output.WriteLn;
-- patched by bernard
-- useful not only for debugger now
      IF NOT Obj.Publish THEN
        Output.EndIf;
        END;
      END GenerateDbxModulePassThreeInit;
      
    METHOD GeneratePassThirteenInit;
      VAR
        ClList: DeclList (ClassImplementation);
        ClIm: ClassImplementation;
        BEGIN
      -----------------------------------------------------
      -- If the module is molten, the YAM code interpretor
      -- must be called to handle the pass initializations
      -----------------------------------------------------
-----------------------------------------
-- after the second pass has been fully completed, all the debug
-- info must be in the debugger data structures
-- we can now proceed to the global initialization of the debugger
-- this initialization must be done only once but this is checked
-- in the initialization code itself
-----------------------------------------
-- patched by bernard
-- useful not only for debugger now
      Output.Comment("BERNARD11");
      IF (YaflCfg.TraceModeLevel = 2) OR Obj.Publish THEN
        GenerateDbxModulePassThreeInit;
        END;
      ClList := Obj.Classes;
      FOR i := 0 TO ClList.Size - 1 DO
        ClIm := ClList.Get(i);
        IF ClIm.Once THEN           
          -------------------------------
          -- Allocate the instance
          -------------------------------
          Output.OnceClassInstance(Obj.Id.Data, ClIm.Id.Data);
          Output.Becomes;
          IF ClIm.NeedsConstructFunc THEN
            CClassImp(ClIm.Gc).GenerateConstructFuncId;
            END;
          Output.LeftParent;
          Output.Alloc;
          Output.LeftParents(2);
          Output.WriteString (PredefItems.Integer.CName);
          Output.RightParent;
          Output.Zero;
          Output.Comma;
          Output.Zero;
          Output.Comma;
          Output.Ampersand;
          Output.DualInstance (Obj.Id.Data, ClIm.Id.Data);
          Output.RightParents(2);
          Output.SemiColon;
          Output.WriteLn;
          END;
        END;

      END GeneratePassThirteenInit;

    METHOD CallGenerateAnchorId(Gc: MethDeclCodeGenerator);
      BEGIN
      WHAT Gc OF
        IN CPredefMethCodeGenerator:
          TAG.GenerateAnchorId;
          END;
        IN CMethDefCodeGenerator:
          TAG.GenerateAnchorId;
          END;
        IN CMethImplCodeGenerator:
          TAG.GenerateAnchorId;
          END;
        END;
      END CallGenerateAnchorId;

    METHOD GeneratePassFourteenInit;
      VAR
        CreateMeth: MethodDeclaration;
        ClList: DeclList (ClassImplementation);
        ClIm: ClassImplementation;
      BEGIN

      ----------------------------------------- 
      -- Taking pass 14 initialization actions
      -----------------------------------------
      ClList := Obj.Classes;
      FOR i := 0 TO ClList.Size - 1 DO
        ClIm := ClList.Get(i);
        IF ClIm.Once THEN           
          -----------------------------
          -- Create it if necessary
          -----------------------------
          CreateMeth := ClIm.Create;
          IF CreateMeth <> PredefItems.Create THEN
            CallGenerateAnchorId(CreateMeth.Gc);
            Output.LeftParent;
            Output.OnceClassInstance(Obj.Id.Data, ClIm.Id.Data);
            Output.RightParent;
            Output.SemiColon;
            Output.WriteLn;
            END;
          END;
        Output.ClassInitialization (Obj.Id.Data, ClIm.Id.Data);
        Output.LeftParent;
        Output.RightParent;
        Output.SemiColon;
        Output.WriteLn;
        END;
      END GeneratePassFourteenInit;
      
    METHOD GeneratePassFifteenInit;
      BEGIN
-- patched by bernard
-- useful not only for debugger now
      Output.Comment("BERNARD12");
      IF (YaflCfg.TraceModeLevel = 2) OR Obj.Publish THEN
        GenerateDbxModulePassFiveInit;
        END;
      END GeneratePassFifteenInit;
      
    METHOD GeneratePassSixteenInit;
      BEGIN
      Ctx.Output.IfDefined(Ctx.Output.FullTraceModeLabel);
      Ctx.Output.IfDefined(Output.CheckPreCondLabel);
      FOR Cl IN Obj.Classes DO
        CClassImp(Cl.Gc).GenerateMethodChainInitCall;
        END;
      Ctx.Output.EndIf;
      Ctx.Output.EndIf;
      END GeneratePassSixteenInit;

    METHOD GeneratePassElevenInit;
      VAR
        p: ARRAY OF DefinitionModule;
      BEGIN
      ----------------------------------------- 
      -- Taking pass 1& initialization actions
      -----------------------------------------
      p := Obj.DefModule.CombinedImported.Row;
      IF p <> VOID THEN
        FOR i := 0 TO p.SIZE - 1 DO
          Ctx.CompilationUnitGenerateVersionChecking(p[i].Gc, Obj);
          END;
        END;
      END GeneratePassElevenInit;
      
    METHOD GenerateDbxModulePassFiveInit;
      BEGIN
      Output.IfDefined(Output.FullTraceModeLabel);
      Output.DbxYaflBegin;
      Output.LeftParent;
      Output.RightParent;
      Output.SemiColon;                  
      Output.WriteLn;
      Output.EndIf;
      END GenerateDbxModulePassFiveInit;
      
    METHOD GenerateInitialization;
      VAR
        PassVarNr, GuardVarNr: INTEGER;
        ImportSet: ModuleSet;
        ImportArray: ARRAY OF DefinitionModule;
      
      METHOD GenerateGuard (Pass: INTEGER);
        BEGIN
        Output.WriteLn;
        Output.If;
        Output.LeftParent;
        Output.UniqueItem (PassVarNr);
        Output.Equal;
        Output.WriteInt (Pass, 0);
        Output.RightParent;
        END GenerateGuard;  
      
      METHOD GenerateProfileArray;
        BEGIN
        Output.IfDefined(Output.ProfileModeLabel);
        -- Output.
        Output.Static;
        Output.UnsignedInt;
        Output.LeftBracket;
        Output.RightBracket;
        Output.ModuleProfileRef(Obj.Id.Data);
        Output.Becomes;
        Output.LeftBrace;
        FOR i := 1 TO Obj.LineCount - 1 DO
          Output.WriteInt(0, 0);
          Output.Comma;
          END; -- FOR
        Output.WriteInt(0, 0);
        Output.RightBrace;
        Output.SemiColon;
        Output.WriteLn;
        END GenerateProfileArray;

      BEGIN
-- patched by bernard
-- useful not only for debugger now
      Output.Comment("BERNARD6");
      IF (YaflCfg.TraceModeLevel = 2) OR Obj.Publish THEN
        GenerateDbxModuleInitialization;
        END;
      PassVarNr := YaflCfg.UniqueNumber;
      GuardVarNr := YaflCfg.UniqueNumber;
      GenerateInitializationHeader(PassVarNr, WithBody := TRUE);
      Output.WriteLn;
      Output.LeftBrace;
      Output.WriteLn;
      Output.Static;
      Output.Int;
      Output.UniqueItem (GuardVarNr);
      Output.Becomes;
      Output.Zero;
      Output.SemiColon;
      Output.WriteLn;
      ---------------------------
      -- Make sure that pass >= Guard
      ---------------------------
      Output.If;
      Output.LeftParent;
      Output.UniqueItem (PassVarNr);
      Output.Smaller;
      Output.UniqueItem (GuardVarNr);
      Output.RightParent;
      Output.Return;
      Output.SemiColon;
      Output.WriteLn;

      -------------------------------
      -- Set guard as pass + 1
      -------------------------------
      Output.UniqueItem (GuardVarNr);
      Output.Becomes;
      Output.UniqueItem (PassVarNr);
      Output.Plus;
      Output.WriteChar ('1');
      Output.SemiColon;
      Output.WriteLn;

      --------------------------------
      -- Call the imported modules initializations
      ---------------------------------
      ImportSet := Obj.GetImportList.BuildSet;
      ASSERT ImportSet <> VOID;
      IF Obj.DefModule.GetImportList <> VOID THEN
        ImportSet.DoUnion (Obj.DefModule.GetImportList.BuildSet);
        END;
      ImportArray := ImportSet.Row;        
      FOR i := 0 TO ImportArray.SIZE - 1 DO
        Output.ModuleInitialization (ImportArray[i].Id.Data);
        Output.LeftParent;
        Output.UniqueItem (PassVarNr);
        Output.RightParent;
        Output.SemiColon;
        Output.WriteLn;
        END;
      IF Obj.Classes.Size > 0 THEN
        GenerateGuard (Pass := 1);
        Output.LeftBrace;
        IF YaflCfg.CheckVersionLevel > 1 THEN
          GenerateVersionRefUsage;
          END;
        GeneratePassOneInit;
        Output.RightBrace;
        Output.WriteLn;
        
        Output.Else;
        
        GenerateGuard (Pass := 11);
        Output.LeftBrace;
        GeneratePassElevenInit;
        Output.RightBrace;
        Output.WriteLn;
        
        Output.Else;
        
        GenerateGuard (Pass := 12);
        Output.LeftBrace;
        GeneratePassTwelveInit;
        Output.RightBrace;
        Output.WriteLn;
        
        Output.Else;
        
        GenerateGuard (Pass := 13);
        Output.LeftBrace;
        GeneratePassThirteenInit;
        Output.RightBrace;
        Output.WriteLn;
        
        Output.Else;
        
        GenerateGuard (Pass := 14);
        Output.LeftBrace;
        GeneratePassFourteenInit;
        Output.RightBrace;
        Output.WriteLn;
        
        Output.Else;
        
        GenerateGuard (Pass := 15);
        Output.LeftBrace;
        GeneratePassFifteenInit;
        Output.RightBrace;
        Output.WriteLn;

        Output.Else;
        
        GenerateGuard (Pass := 16);
        Output.LeftBrace;
        GeneratePassSixteenInit;
        Output.RightBrace;
        Output.WriteLn;
        
        
        END;
      Output.RightBrace;
      Output.WriteLn;        
      END GenerateInitialization;
      
    METHOD GenerateDbxModuleInitialization;
      VAR
        ModName : ARRAY OF CHAR;

      ----------------------------------------------------
      -- this method generates the text of a C declaration for a static
      -- (external) pointer to a dbx-module;this variable is used to hold the
      -- result of the add_module so that the structure can be referred to
      -- in other places,in the same way that for the methods;
      -- however,it is not used yet;
      ----------------------------------------------------------
      METHOD GenerateReferenceVariable;
        BEGIN
        Output.Static;
        Output.DbxModule;
        Output.Star;
        Output.DbxModuleReference(ModName);
        Output.SemiColon;
        Output.WriteLn;
        END GenerateReferenceVariable;

      --------------------------------------------------------------
      -- this method generates the text of a C declaration for a static
      -- initialized array of unsigneds containing all the line numbers
      -- of instructions in the module;these lines are the ones where
      -- breakpoints can be set in the debugger;
      -- this array will be attached to the dbx-module structure;
      -----------------------------------------------------------------
      METHOD GenerateLineNumbersArray;
        VAR
          Walk : Walker;
          p : NonTerminal;
        BEGIN
        Output.Static;
        Output.UnsignedInt;
        Output.ModuleLinesRef(Obj.Id.Data);
        Output.LeftBracket;
        Output.RightBracket;
        Output.Becomes;
        Output.LeftBrace;
        Walk.CREATE(Obj);
        p := Walk.Next;
        WHILE p <> VOID DO
          WHAT p OF
            IN Statement:
              ASSERT TAG.LineNr > 0; -- check that the numbers are ok
              Output.WriteInt(TAG.LineNr,0);
              Output.Comma;
              END;
           ELSE  -- don't abort;it could be anything else
            END;
          p := Walk.Next;
          END;
        Output.WriteChar('0'); -- 0 can't be a line number;this signal the end of
                               -- the array;
        Output.RightBrace;
        Output.SemiColon;
        Output.WriteLn;
        END GenerateLineNumbersArray;

      -----------------------------------------------------
      -- generates the text of the C function call that adds a new
      -- module in the debugger data structures,with the appropriate
      -- parameters;
      -- the result of the function is a pointer to a dbx-module
      -- that is assigned to a static external variable so the
      -- structure can be referred to elsewhere;this is not used yet;
      ----------------------------------------------------------
----      METHOD GenerateModuleAdd;
----        BEGIN
----        Output.DbxModuleReference(ModName);
----        Output.Becomes;
----        Output.DbxAddModule;
----        Output.LeftParent;
----        Output.QuotedString(ModName,UseEsc := FALSE);
----        Output.Comma;
----        Output.QuotedString(YaflCfg.NameMapper.MakeAbsolute(
----                                Obj.GetWorld.BuildSourceFName (ModName, 
----                                                          YaflCfg.ImpExt)),
----                            UseEsc := TRUE);
----        Output.Comma;
----        Output.WriteInt(Obj.LineNr,0);
----        Output.Comma;
----        Output.WriteInt(Obj.EndIdent.LineNr,0);
----        Output.Comma;
----        Output.ModuleLinesRef(Obj.Id.Data);
----        Output.RightParent;
----        Output.SemiColon;
----        Output.WriteLn;
----        END GenerateModuleAdd;

      METHOD GenerateModuleAdd;
        BEGIN
        Output.DbxAddModule;
        Output.LeftParent;
        Output.Ampersand; -- ???
        Output.ModuleDualRef(Obj.Id.Data);
        Output.RightParent;
        Output.SemiColon;
        Output.WriteLn;
        END GenerateModuleAdd;

      -------------------------------------------------------
      -- this method generates the text of the sequence of calls
      -- to the debugger initializations functions for the classes
      -- declared in the module;they come just after the initialization
      -- of the module so they will be attached to it (see the code
      -- of the runtime)
      -------------------------------------------------------
      METHOD GenerateModuleDecls;
        VAR
          ClList: DeclList (ClassImplementation);

        METHOD GenerateClassInit(ClaName : ARRAY OF CHAR);
          BEGIN
          Output.DbxClassInitialization(ModName, ClaName);
          Output.LeftParent;
          Output.RightParent;
          Output.SemiColon;
          Output.WriteLn;
          END GenerateClassInit;

        BEGIN
        ClList := Obj.Classes;
        FOR i := 0 TO ClList.Size - 1 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
          IF (YaflCfg.TraceModeLevel = 2) OR (ClList.Get(i).Publish) THEN
            GenerateClassInit(ClaName := ClList.Get(i).Id.Data);
            END; -- IF
          END;
        END GenerateModuleDecls;

      BEGIN
-- patched by bernard
-- useful not only for debugger now
      Output.Comment("BERNARD7");
      IF NOT Obj.Publish THEN
        Output.IfDefined(Output.FullTraceModeLabel);
        END;
      ModName := Obj.Id.Data;
      GenerateReferenceVariable;
      GenerateLineNumbersArray;
      Output.Static;
      Output.Void;
      Output.DbxModuleInitialization(ModName);
      Output.IfDef;
      Output.Ansi;
      Output.LeftParent;
      Output.Void;
      Output.RightParent;
      Output.ElseDef;
      Output.LeftParent;
      Output.RightParent;
      Output.EndIf;
      Output.WriteLn;
      Output.LeftBrace;
      Output.WriteLn;
-- patched by bernard
-- old version of the module dictionary
      GenerateModuleAdd;
      GenerateModuleDecls;
      Output.RightBrace;
      Output.WriteLn;
-- patched by bernard
-- useful not only for debugger now
      IF NOT Obj.Publish THEN
        Output.EndIf;
        END;
      END GenerateDbxModuleInitialization;
      
    REDEFINE METHOD CreateContext: CGcContext;
      BEGIN
      RESULT.CREATE;
      END CreateContext;

  END CImplModuleCodeGenerator;
   
-----------------------------------------------------------

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

    METHOD GenerateInclude( MainModule: ImplementationModule;
                            Pass: INTEGER);
      BEGIN
      IF NOT YaflCfg.PleaseGlobalOptimize THEN
        Output.UserInclude (Obj.HeaderFName (MainModule, Pass));
       ELSE
        Output.UserInclude (String.LowerCase (YaflCfg.NameMapper.
            BuildTargetFileName("",Obj.Id.Data,
                YaflCfg.HeaderExt+IntConversions.IntToString (Pass, 0),"")));
        END;
      END GenerateInclude;

    METHOD GenerateVersionKey;
      BEGIN
      Output.VersionKey (Obj.Id.Data, Obj.VersionKey);
      END GenerateVersionKey;
           
  END CDefModuleCodeGenerator;
    
END CGModules;
