IMPLEMENTATION MODULE YaflCfg;

FROM Conversions IMPORT IntConversions, RealConversions;
FROM Directories IMPORT Operations;
FROM Streams IMPORT StdOut, Stream;
IMPORT Stack;
IMPORT String;
IMPORT SYSTEM;
FROM YaflFName IMPORT UnixFileNameMapper, MvsFileNameMapper, DosFileNameMapper;
FROM YaflWorlds IMPORT WorldList, World;

  ONCE CLASS YaflCfg;

      VAR
        TheConfig: Configuration;
        Initialized: BOOLEAN;
        TheProjectFileExt,
        TheLinkerResponseFileExt,
        TheObjExt,
        TheDirPrefix, TheDirSep: ARRAY OF CHAR;
        TheCaseLiteralLimit,
        TheTraceModeLevel,
        TheMaxPreprocessorFormals,
        TheWarningLevel, 
        TheInternalMaxIdentLen,
        TheExternalMaxIdentLen,
        TheMaxStringLen,
        TheTargetPlatform: INTEGER;
        KeepFieldInfoFlag, 
        ForceKeepFieldInfoFlag, 
        DebugModeFlag,
        ProfileModeFlag,
        LiterateProgrammingFlag,
        ImmediateErrorFlag,
        SilentModeFlag,
        ForceStructFlag,
        StripMemModeFlag,
        FlushMemModeFlag,
        CheckArrayFlag,
        CheckVoidObjectFlag,
        CheckAssertFlag,
        CheckDebugFlag,
        CheckWhatFlag,
        CheckCaseFlag,
        CheckDualStackFlag,
        CheckVoidMethodFlag,
        AppendErrorFile,
        PleaseTagFlag,
        PleaseCheckTypeFlag,
        PleaseGenerateCodeFlag,
        PleaseGenerateMetricsFlag,
        PleaseLintFlag,
        PleaseGeneratePreConditionFlag,
        PleaseGeneratePostConditionFlag,
        PleaseGenerateClassInvariantFlag,
        PleaseGenerateLoopInvariantFlag,
        PleaseGenerateAbsolutePathNamesFlag : BOOLEAN;

        TheStatLevel,
        TheVerboseLevel: INTEGER;

        TheErrorFName: ARRAY OF CHAR;
        TheNameMapper: PatternFileNameMapper;

        PleaseOptimizeDirectLinkFlag,
        PleaseOptimizeInLineFlag,             
        PleaseOptimizeRemoveMethodsFlag,      
        PleaseOptimizeRemoveDebugFlag,
        PleaseOptimizeValueStackFlag: BOOLEAN; 
        
        TheStatStream : OutputStream; 
        TheCheckVersionLevel: INTEGER;
      
      METHOD ObjExt: ARRAY OF CHAR;
        BEGIN 
        RESULT := TheObjExt;
        IF RESULT = VOID THEN
          CASE SYSTEM.OperatingSystem OF
            SYSTEM.Unix, SYSTEM.Qnx, SYSTEM.Coherent:
              RESULT := 'o';
              END;
            SYSTEM.Dos, SYSTEM.OS2, SYSTEM.Windows:
              RESULT := 'obj';
              END;
            SYSTEM.Mvs:
              RESULT := 'OBJ';
              END;
            END;
          END;
        END ObjExt;

      METHOD ProjectFileExt: ARRAY OF CHAR;
        BEGIN
        RESULT := TheProjectFileExt;
        IF RESULT = VOID THEN
          RESULT := "prj";
          END;
        END ProjectFileExt;

      METHOD LinkerResponseFileExt: ARRAY OF CHAR;
        BEGIN
        RESULT := TheLinkerResponseFileExt;
        IF RESULT = VOID THEN
          RESULT := "arf";
          END;
        END LinkerResponseFileExt;

      METHOD DirSep: ARRAY OF CHAR;
        BEGIN
        RESULT := TheDirSep;
        IF RESULT = VOID THEN
          RESULT := SYSTEM.DirSeparator;
          END;
        END DirSep;

      METHOD CaseLiteralLimit: INTEGER;
        BEGIN
        RESULT := TheCaseLiteralLimit;
        END CaseLiteralLimit;

      METHOD InternalMaxIdentLen: INTEGER;
        BEGIN
        RESULT := TheInternalMaxIdentLen;
        END InternalMaxIdentLen;
        
      METHOD ExternalMaxIdentLen: INTEGER;
        BEGIN
        RESULT := TheExternalMaxIdentLen;
        END ExternalMaxIdentLen;
        
      METHOD MaxStringLen: INTEGER;
        BEGIN
        RESULT := TheMaxStringLen;
        END MaxStringLen;
        
      METHOD MaxPreprocessorFormals: INTEGER;                                       
        BEGIN
        RESULT := TheMaxPreprocessorFormals;
        END MaxPreprocessorFormals;
        
      METHOD FindValue (Label: ARRAY OF CHAR): ARRAY OF CHAR;
        BEGIN                  
        IF SYSTEM.OperatingSystem <> SYSTEM.Mvs THEN
          RESULT := SYSTEM.GetEnvironment (Label);
          END;
        IF RESULT = VOID THEN
          RESULT := GetConfig.SubstituteVariables(GetConfig.FindValue(Label));
          END;
        END FindValue; 
        
      METHOD StringToMemorySize (a: ARRAY OF CHAR): INTEGER;
        VAR
          i: INTEGER;
          b: ARRAY OF CHAR;
          Ch: CHAR;
        BEGIN
        b := String.UpperCase(String.Strip(a));
        i := 0;
        WHILE (i < b.SIZE) AND NOT SYSTEM.IsLetter(b[i]) DO
          i := i + 1;
          END;
        IF i >= b.SIZE THEN
          RESULT := IntConversions.StringToInt (b);
         ELSE
          Ch := b[i];
          b := b.SLICE (0, i-1);
          CASE Ch OF
            'K':
              RESULT := SYSTEM.TRUNC(1024.0 * RealConversions.StringToReal (b));
              END;
            'M':
              RESULT := SYSTEM.TRUNC(1024.0 * 1024.0 *
                                     RealConversions.StringToReal (b));
              END;
           ELSE
            RESULT := IntConversions.StringToInt (b);
            END;
          END;  
        END StringToMemorySize;
        
      METHOD FindMultiLineValue (Label: ARRAY OF CHAR): 
                                             ARRAY OF ARRAY OF CHAR;
        BEGIN
        RESULT := GetConfig.FindMultiLineValue(Label);
        END FindMultiLineValue; 
        
      METHOD ReadWorlds;
        VAR
          a: ARRAY OF CHAR;
          i: INTEGER;
          
          METHOD AddWorlds (a: ARRAY OF CHAR);
            VAR
              w: World;
              p: ARRAY OF ARRAY OF CHAR;
              BEGIN
            p := String.BreakInWords (Source := a,
                                      SkipSeparator := " ,;",
                                      KeepSeparator := VOID);
            IF p <> VOID THEN                          
              FOR i := 0 TO p.SIZE - 1 DO
                IF WorldList.Find (p[i]) = VOID THEN 
                  w.CREATE (Name := "", 
                            Prefix := p[i]);
                  WorldList.Append (w);
                  ASSERT p[i] <> VOID;
                  ----------------------------
                  -- If the verbose flag is set, display
                  -- some information about the worlds.
                  ----------------------------
                  IF YaflCfg.VerboseLevel > 0 THEN
                    StdOut.WriteString ("World [");
                    StdOut.WriteInt (WorldList.Size, 0);
                    StdOut.WriteLine ("] " + p[i]);
                    END;
                  END;
                END;
              END;                          
            END AddWorlds;        
      
          METHOD FindVal (Lab: ARRAY OF CHAR): ARRAY OF CHAR;
            BEGIN
            RESULT := YaflCfg.FindValue (Lab);
            IF RESULT = VOID THEN
              RESULT := YaflCfg.FindValue (String.UpperCase (Lab));
              END;
            END FindVal;  
     
        BEGIN
        a := FindVal ("yworlds");
        AddWorlds (a);
        i := 1;
        a := FindVal ("yworlds" + IntConversions.IntToString (i, 0));
        WHILE a <> VOID DO
          AddWorlds (a);
          i := i + 1;
          a := FindVal ("yworlds" + IntConversions.IntToString (i, 0));
          END;
        END ReadWorlds;
        
      METHOD RemoveEntry (EntryName: ARRAY OF CHAR): BOOLEAN;
        BEGIN           
        FOR i := GetConfig.ParamList.Size - 1 TO 0 BY -1 DO
          IF String.Equals (GetConfig.ParamList.Get(i).Variable, 
                            EntryName) THEN
            GetConfig.ParamList.Delete(i);
            RESULT := TRUE;
            END;
          END;
        END RemoveEntry;

      METHOD UseFile (FName: ARRAY OF CHAR);
        BEGIN       
        GetConfig.UseFile (FName);
        StdOut.WriteLine ("Using supplementary configuration file : " + FName);
        UseTheCurrentConfig;
        END UseFile;
        
      METHOD UseConfigFile (Radix, Extension: ARRAY OF CHAR);
        VAR 
          p: ARRAY OF InputStream;
          BEGIN                     
        p := OpenHomeStreams (Radix, Extension);
        IF p <> VOID THEN
          FOR i := 0 TO p.SIZE - 1 DO
            GetConfig.UseStream (p[i]);
            p[i].Close;
            p[i] := VOID;
            END;
          END;
        UseTheCurrentConfig;
        END UseConfigFile;

      METHOD UseTheCurrentConfig;
        VAR
          a: ARRAY OF CHAR;
          i: INTEGER;
          p: ARRAY OF ARRAY OF CHAR;
        
          METHOD FindInteger (Label: ARRAY OF CHAR): INTEGER;
            VAR
              a: ARRAY OF CHAR;
            BEGIN
            a := FindValue (Label);
            IF a <> VOID THEN
              RESULT := IntConversions.StringToInt (a);
              END;
            END FindInteger;
            
          METHOD FindMemorySize (Label: ARRAY OF CHAR): INTEGER;
            VAR
              a: ARRAY OF CHAR;
            BEGIN
            a := FindValue (Label);
            IF a <> VOID THEN
              RESULT := StringToMemorySize (a);
              END;
            END FindMemorySize;
            
        BEGIN
        IF TheDirPrefix = VOID THEN
          TheDirPrefix := "wrk";
          END;
        a := FindValue ("DIR_PREFIX");
        IF a <> VOID THEN
          TheDirPrefix := a;
          END;
        TheObjExt := FindValue ("OBJ_EXT"); -- If none is supplied,
                                            -- a default selection will be
                                            -- used
        TheProjectFileExt := FindValue("PROJECT_EXT");
        TheLinkerResponseFileExt := FindValue ("LINKER_RESPONSE_EXT"); 
        TheDirSep := FindValue ("DIR_SEP");
        IF TheDirSep = VOID THEN
          TheDirSep := SYSTEM.DirSeparator.CLONE;
          END;
        i := FindInteger ("CASE_LIMIT");
        IF i > 0 THEN
          TheCaseLiteralLimit := i;
         ELSIF TheTargetPlatform = SYSTEM.Mvs THEN
          TheCaseLiteralLimit := 256; 
         ELSE
          TheCaseLiteralLimit := 10; -- Arbitrary default value;
          END;
        i := FindInteger ("EXTERNAL_IDENT_LEN_LIMIT");
        IF i >= 8 THEN
          TheExternalMaxIdentLen := i;
         ELSIF TheTargetPlatform = SYSTEM.Mvs THEN
          TheExternalMaxIdentLen := 8;  -- Mvs system linker limitation
         ELSE
          TheExternalMaxIdentLen := 32; -- Ansi default value
          END;       
        i := FindInteger ("INTERNAL_IDENT_LEN_LIMIT");
        IF i >= 8 THEN
          TheInternalMaxIdentLen := i;
         ELSE
          TheInternalMaxIdentLen := 32; -- Ansi default value
          END;       
        i := FindInteger ("STRING_LEN_LIMIT");
        IF i >= 40 THEN
          TheMaxStringLen := i;
         ELSIF TheTargetPlatform = SYSTEM.Mvs THEN
          TheMaxStringLen := 70;  -- In order to accomodate the 80
                                  -- columns 
         ELSE
          TheMaxStringLen := 255;   -- Ansi default value
          END;
        i := FindInteger ("PREPROC_FORMALS");
        IF i > 0 THEN
          TheMaxPreprocessorFormals := i;
         ELSE
          TheMaxPreprocessorFormals := 12; -- Arbitrary default value;
          END;
        i := FindMemorySize("INITIAL_ALLOC");
        IF i > 0 THEN
          SYSTEM.InitialAlloc (i);
          END;
        i := FindMemorySize ("MAX_ALLOC");
        IF i > 0 THEN
          SYSTEM.SetMaxMem (i);
          END;
        a := FindValue ("YDEFAULT");
        IF a <> VOID THEN
          p := String.BreakInWords (Source := a, 
                                    SkipSeparator := " ", 
                                    KeepSeparator := VOID);
          IF p <> VOID THEN
            FOR j := 0 TO p.SIZE - 1 DO
              VOID := CommandLineOption (p[j]);
              END;
            END;                         
          END;
        ReadWorlds;
        a := FindValue ("INCLUDE");
        IF a <> VOID THEN
          IF RemoveEntry ("INCLUDE") THEN
            UseFile (a);
            END;
          END;
        NameMapper.SetSourcePattern (FindValue ("SOURCE_PATTERN"));
        NameMapper.SetTargetPattern (FindValue ("TARGET_PATTERN"));
        NameMapper.SetTempPattern (FindValue ("TEMP_PATTERN"));
        NameMapper.SetProjectPattern (FindValue ("PROJECT_PATTERN"));
        END UseTheCurrentConfig;
          
      METHOD Initialize;
        BEGIN
        IF NOT Initialized THEN
          TheTargetPlatform := SYSTEM.OperatingSystem;
          Initialized := TRUE;
          TheTraceModeLevel := 1;
          DebugModeFlag := TRUE;
          -----------------------------
          -- By default, the compilation process
          -- ought to be complete (syntax, semantics,
          -- code generation, metrics).
          -----------------------------
          SetPleaseTag (TRUE);
          SetPleaseCheckType (TRUE);
          PleaseGenerateCodeFlag := TRUE;
          PleaseGenerateAbsolutePathNamesFlag := SYSTEM.OperatingSystem =
                                                 SYSTEM.Mvs;
          PleaseGenerateMetricsFlag := TRUE;
          PleaseLintFlag := FALSE;
          TheWarningLevel := 1;
          TheCheckVersionLevel := 1;
          UseConfigFile ("yc","cfg");
          END;
        END Initialize;
          
      REDEFINE METHOD CREATE;
        BEGIN
        BASE;  -- ???
        Initialize;
        END CREATE;
        
      METHOD DirPrefix: ARRAY OF CHAR;
        BEGIN
        RESULT := TheDirPrefix;
        END DirPrefix;
        
      METHOD SetDirPrefix (Prefix: ARRAY OF CHAR);
        BEGIN
        TheDirPrefix := Prefix;
        END SetDirPrefix;
                                   
      METHOD TargetPlatform: INTEGER;
        BEGIN              
        RESULT := TheTargetPlatform;
        END TargetPlatform;
        
      METHOD SetTargetPlatform (Value : INTEGER);
        BEGIN             
        TheTargetPlatform := Value; 
        IF TheTargetPlatform = SYSTEM.Mvs THEN
          TheExternalMaxIdentLen := 8;    -- Mvs system linker limitation in
          TheCaseLiteralLimit    := 256;  -- order to avoid range problems
          END; -- IF
        END SetTargetPlatform;
        
      METHOD WarningLevel: INTEGER;
        BEGIN
        RESULT := TheWarningLevel;
        END WarningLevel;          
        
      METHOD SetWarningLevel (Value : INTEGER);
        BEGIN               
        TheWarningLevel := Value;
        END SetWarningLevel;    
        
      METHOD DebugMode : BOOLEAN;
        BEGIN
        RESULT := DebugModeFlag;
        END DebugMode;
        
      METHOD SetDebugMode (Value : BOOLEAN);
        BEGIN
        DebugModeFlag := Value;
        END SetDebugMode;                       
      
      METHOD ProfileMode : BOOLEAN;
        BEGIN
        RESULT := ProfileModeFlag;
        END ProfileMode;
        
      METHOD SetProfileMode (Value : BOOLEAN);
        BEGIN
        ProfileModeFlag := Value;
        END SetProfileMode;                       
      
      METHOD TraceModeLevel: INTEGER;
        BEGIN
        RESULT := TheTraceModeLevel;
        END TraceModeLevel;                   
        
      METHOD SetTraceModeLevel (Value : INTEGER);
        BEGIN                 
        TheTraceModeLevel := Value;
        END SetTraceModeLevel;  

      METHOD LiterateProgrammingErrorProcessing: BOOLEAN;
        BEGIN
        RESULT := LiterateProgrammingFlag;
        END LiterateProgrammingErrorProcessing;

      METHOD SetLiterateProgrammingErrorProcessing (Value: BOOLEAN);
        BEGIN
        LiterateProgrammingFlag := Value;
        END SetLiterateProgrammingErrorProcessing;

      METHOD CheckVersionLevel: INTEGER;
        BEGIN
        RESULT := TheCheckVersionLevel;
        END CheckVersionLevel;
        
      METHOD SetCheckVersionLevel(Value: INTEGER);
        BEGIN
        TheCheckVersionLevel := Value;
        END SetCheckVersionLevel;

      METHOD VerboseLevel: INTEGER;
        BEGIN
        RESULT := TheVerboseLevel;
        END VerboseLevel;           
        
      METHOD SetVerboseLevel (Value : INTEGER); 
        BEGIN
        TheVerboseLevel := Value;
        IF Value > 0 THEN
          SetImmediateErrors (FALSE);
          END; -- IF
        END SetVerboseLevel;
        
      METHOD ImmediateErrors: BOOLEAN;
        BEGIN
        RESULT := ImmediateErrorFlag;
        END ImmediateErrors;    
        
      METHOD SetImmediateErrors (Value : BOOLEAN);
        BEGIN                  
        ImmediateErrorFlag := Value;
        END SetImmediateErrors; 

      METHOD SilentMode: BOOLEAN;
        BEGIN
        RESULT := SilentModeFlag;
        END SilentMode;       
        
      METHOD SetSilentMode (Value : BOOLEAN);
        BEGIN             
        SilentModeFlag := Value;
        IF SilentModeFlag THEN
          SetVerboseLevel (0);
          END; -- IF
        END SetSilentMode;      

      METHOD StatLevel: INTEGER;
        BEGIN
        RESULT := TheStatLevel;
        END StatLevel;
      
      METHOD SetStatLevel (Value : INTEGER);
        BEGIN           
        TheStatLevel := Value;
        END SetStatLevel;
                
      METHOD StripMemMode: BOOLEAN;
        BEGIN
        RESULT := StripMemModeFlag;
        END StripMemMode;
        
      METHOD SetStripMemMode (Value : BOOLEAN);
        BEGIN
        StripMemModeFlag := Value;
        END SetStripMemMode;
        
      METHOD FlushMemMode: BOOLEAN;
        BEGIN
        RESULT := FlushMemModeFlag;
        END FlushMemMode;         
        
      METHOD SetFlushMemMode (Value : BOOLEAN);
        BEGIN           
        FlushMemModeFlag := Value;
        END SetFlushMemMode;    
        
      METHOD ForceStruct: BOOLEAN;
        BEGIN
        RESULT := ForceStructFlag;
        END ForceStruct;
        
      METHOD SetForceStruct (Value: BOOLEAN);
        BEGIN
        ForceStructFlag := Value;
        END SetForceStruct;
        
      METHOD KeepFieldInfo : BOOLEAN; 
        BEGIN
        IF TraceModeLevel < 2 THEN
          RESULT := KeepFieldInfoFlag OR ForceKeepFieldInfoFlag;
         ELSE
          RESULT := TRUE;        
          END;
        END KeepFieldInfo;

      METHOD SetKeepFieldInfo (Value: BOOLEAN);
        BEGIN
        KeepFieldInfoFlag := Value;
        END SetKeepFieldInfo;
                                        
      METHOD ForceKeepFieldInfo : BOOLEAN;
        BEGIN                  
        RESULT := ForceKeepFieldInfoFlag;
        END ForceKeepFieldInfo; 
        
      METHOD SetForceKeepFieldInfo (Value : BOOLEAN);
        BEGIN
        ForceKeepFieldInfoFlag := Value;
        END SetForceKeepFieldInfo;
        
      METHOD CheckWhat : BOOLEAN;
        BEGIN      
        RESULT := CheckWhatFlag;
        END CheckWhat;
        
      METHOD SetCheckWhat (Value : BOOLEAN);
        BEGIN
        CheckWhatFlag := Value;
        END SetCheckWhat;
        
      METHOD CheckCase : BOOLEAN;
        BEGIN      
        RESULT := CheckCaseFlag;
        END CheckCase;
      
      METHOD SetCheckCase (Value : BOOLEAN);
        BEGIN
        CheckCaseFlag := Value;
        END SetCheckCase;
                        
      METHOD CheckArray : BOOLEAN;
        BEGIN      
        RESULT := CheckArrayFlag;
        END CheckArray;
      
      METHOD SetCheckArray (Value : BOOLEAN);
        BEGIN
        CheckArrayFlag := Value;
        END SetCheckArray;
        
      METHOD CheckDebug : BOOLEAN;
        BEGIN      
        RESULT := CheckDebugFlag;
        END CheckDebug;
      
      METHOD SetCheckDebug (Value : BOOLEAN);
        BEGIN
        CheckDebugFlag := Value;
        END SetCheckDebug;

      METHOD CheckAssert : BOOLEAN;
        BEGIN      
        RESULT := CheckAssertFlag;
        END CheckAssert;
      
      METHOD SetCheckAssert (Value : BOOLEAN);
        BEGIN
        CheckAssertFlag := Value;
        END SetCheckAssert;

      METHOD CheckVoidObject : BOOLEAN;
        BEGIN      
        RESULT := CheckVoidObjectFlag;
        END CheckVoidObject;
      
      METHOD SetCheckVoidObject (Value : BOOLEAN);
        BEGIN
        CheckVoidObjectFlag := Value;
        END SetCheckVoidObject;

      METHOD CheckVoidMethod : BOOLEAN;
        BEGIN      
        RESULT := CheckVoidMethodFlag;
        END CheckVoidMethod;
      
      METHOD SetCheckVoidMethod (Value : BOOLEAN);
        BEGIN
        CheckVoidMethodFlag := Value;
        END SetCheckVoidMethod;

      METHOD CheckDualStack : BOOLEAN;
        BEGIN      
        RESULT := CheckDualStackFlag;
        END CheckDualStack;
      
      METHOD SetCheckDualStack (Value : BOOLEAN);
        BEGIN
        CheckDualStackFlag := Value;
        END SetCheckDualStack;

--      METHOD AOption (Code: CHAR;
--                      Positive: BOOLEAN;
--                      CompleteOption: ARRAY OF CHAR): BOOLEAN;
--        BEGIN
--        RESULT := TRUE;
--        ASSERT Code = SYSTEM.UCASE(Code);
--        CASE Code OF
--           'A': -- check all extended assertions
--              PleaseGenerateClassInvariantFlag := TRUE;
--              PleaseGenerateLoopInvariantFlag := TRUE;
--              PleaseGeneratePostConditionFlag := TRUE;
--              PleaseGeneratePreConditionFlag := TRUE;
--              END;
--           'C': -- check class invariant
--              PleaseGenerateClassInvariantFlag := TRUE;
--              END;
--           'L': -- check loop invariant
--              PleaseGenerateLoopInvariantFlag := TRUE;
--              END;   
--           'O': -- check postcondition
--              PleaseGeneratePostConditionFlag := TRUE;
--              END;   
--           'R': -- check precondition
--              PleaseGeneratePreConditionFlag := TRUE;
--              END;
--         ELSE
--          RESULT := FALSE;
--          END;
--        END AOption;
        
      METHOD BOption (Code: CHAR;
                      Positive: BOOLEAN;
                      CompleteOption: ARRAY OF CHAR): BOOLEAN;
        BEGIN
        RESULT := TRUE;
        ASSERT Code = SYSTEM.UCASE(Code);
        CASE Code OF
          'S':   
            IF CompleteOption.SIZE > 3 THEN

              SetPleaseTag (FALSE);   
              SetGenerateCode (FALSE);   
              SetPleaseCheckType (FALSE);
              SetGenerateMetrics (FALSE);

              CASE CompleteOption[3] OF
                 '0':
                   -- Nothing to do
                   END;
                 '1':           
                   SetPleaseTag (TRUE);
                   END;
                 '2': 
                   SetPleaseCheckType (TRUE);
                   END;
                 '3':                        
                   SetGenerateCode (TRUE);
                   END;
                 '4':                     
                   SetGenerateMetrics (TRUE);
                   END;        
                ELSE
                 RESULT := FALSE;
                 END; -- CASE
             ELSE
              RESULT := FALSE;
              END; -- IF         
            END;
         ELSE
          RESULT := FALSE;
          END;
        END BOption;
        
      METHOD COption (Code: CHAR;
                      Positive: BOOLEAN;
                      CompleteOption: ARRAY OF CHAR): BOOLEAN;
        BEGIN
        RESULT := TRUE;
        ASSERT Code = SYSTEM.UCASE(Code);
        CASE Code OF
          'R':
            SetCheckArray (Positive);
            END;
          'O':
            SetCheckVoidObject (Positive);
            END;
          'A':
            SetCheckAssert (Positive);
            END;
          'D':
            SetCheckDebug (Positive);
            END;
          'W':
            SetCheckWhat (Positive);
            END;
          'C':
            SetCheckCase (Positive);
            END;
          'M':
            SetCheckVoidMethod (Positive);
            END;
          'S':
            SetCheckDualStack (Positive);
            END;
          'F':
            SetForceKeepFieldInfo (Positive);
            END;
          'E':
            SetGenerateMetrics (Positive);
            END;
          'V': 
            IF CompleteOption.SIZE > 3 THEN
              CASE CompleteOption[3] OF
                '0':
                  SetCheckVersionLevel (0);
                  END;
                '1':
                  SetCheckVersionLevel (1);
                  END;
                '2':
                  SetCheckVersionLevel (2);
                  END;
               ELSE
                RESULT := FALSE;
                END;
              END;
            END;
          'X':
            SetGenerateAbsolutePathNames (Positive);
            END;
          'P':
            SetProfileMode (Positive);
            END;
         ELSE
          RESULT := FALSE;
          END;
        END COption;
        
      METHOD EOption (Code: CHAR;
                      Positive: BOOLEAN;
                      CompleteOption: ARRAY OF CHAR): BOOLEAN;
        BEGIN                      
        RESULT := TRUE;
        ASSERT Code = SYSTEM.UCASE(Code);
        CASE Code OF
          'Z':
            SetImmediateErrors (Positive);
            END;
          'X':
            SetPleaseLint (Positive);
            END;
          'S':
            SetSilentMode (Positive);
            END;
          'L':
            SetLiterateProgrammingErrorProcessing (Positive);
            END;
          'O', 'A':
            IF CompleteOption.SIZE > 3 THEN
              TheErrorFName := CompleteOption.SLICE (3, 
                                                     CompleteOption.SIZE - 3);
              IF Code = 'A' THEN
                AppendErrorFile := TRUE;
               ELSE 
                Operations.Delete (TheErrorFName);                                                     
                END;
              END;
            END;
         ELSE
          RESULT := FALSE;
          END;
        END EOption;
        
      METHOD MOption (Code: CHAR;
                      Positive: BOOLEAN;
                      CompleteOption: ARRAY OF CHAR): BOOLEAN;
        VAR
          NumBytes: INTEGER;                      
        BEGIN                      
        RESULT := TRUE;
        ASSERT Code = SYSTEM.UCASE(Code);
        CASE Code OF
          'B': 
            IF Positive THEN
              SYSTEM.TraceMode;
              END;
            END;                      
          'S':
            SetStripMemMode (Positive);
            END;
          'F':
            SetFlushMemMode (Positive);
            END;
          'D':  
            GetConfig.SaveStream (StdOut);
            END;
          'A':
            IF CompleteOption.SIZE > 3 THEN
              NumBytes := StringToMemorySize (CompleteOption.SLICE(3, 
                                              CompleteOption.SIZE-3));
              IF NumBytes > 100 THEN
                SYSTEM.SetMaxMem (NumBytes);
                END;                                                     
              END;
            END;
          'C':
            IF CompleteOption.SIZE > 3 THEN
              UseFile(CompleteOption.SLICE(3, CompleteOption.SIZE-3));
              END;
            END;
         ELSE
          RESULT := FALSE;
          END;
        END MOption;
        
      METHOD OOption (Code: CHAR;
                      Positive: BOOLEAN;
                      CompleteOption: ARRAY OF CHAR): BOOLEAN;
        VAR
          IdLen, StrLen: INTEGER;                         
          Ch: CHAR;
        BEGIN                      
        RESULT := TRUE;
        ASSERT Code = SYSTEM.UCASE(Code);
        CASE Code OF
          'I':
            IF CompleteOption.SIZE > 3 THEN
              IdLen := IntConversions.StringToInt (CompleteOption.SLICE(3, 
                                                     CompleteOption.SIZE-3));
              IF IdLen > 6 THEN
                TheInternalMaxIdentLen := IdLen;
                END;                                                     
              END;
            END;
          'X':
            IF CompleteOption.SIZE > 3 THEN
              IdLen := IntConversions.StringToInt (CompleteOption.SLICE(3, 
                                                     CompleteOption.SIZE-3));
              IF IdLen > 6 THEN
                TheExternalMaxIdentLen := IdLen;
                END;                                                     
              END;
            END;
          'S':
            IF CompleteOption.SIZE > 3 THEN
              StrLen := IntConversions.StringToInt (CompleteOption.SLICE(3, 
                                                     CompleteOption.SIZE-3));
              IF StrLen > 40 THEN
                TheMaxStringLen := StrLen;
                END;                                                     
              END;
            END;
          'T':
            IF CompleteOption.SIZE > 3 THEN
              Ch := SYSTEM.UCASE(CompleteOption[3]);
              CASE Ch OF
                'U':
                  SetTargetPlatform (SYSTEM.Unix);
                  END;
                'D', 'W':
                  SetTargetPlatform (SYSTEM.Dos);
                  END;
                'O':
                  SetTargetPlatform (SYSTEM.OS2);
                  END;
                'M':
                  SetTargetPlatform (SYSTEM.Mvs);
                  END;
                'Q':
                  SetTargetPlatform (SYSTEM.Qnx);
                  END;
               ELSE
                RESULT := FALSE;
                END;
              END;
            END;
         ELSE
          RESULT := FALSE;
          END;
        END OOption;
        
      METHOD QOption (Code: CHAR;
                      Positive: BOOLEAN;
                      CompleteOption: ARRAY OF CHAR): BOOLEAN;
        BEGIN                      
        RESULT := TRUE;
        ASSERT Code = SYSTEM.UCASE(Code);
        CASE Code OF
          'L' :                                   
            SetPleaseOptimizeDirectLink (Positive);
            END;
          'I' : 
            SetPleaseOptimizeInLine (Positive);
            END;
          'R' :
            SetPleaseOptimizeRemoveMethods (Positive);
            END;
          'D' : 
            SetPleaseOptimizeRemoveDebug (Positive);
            END;
          'S' : 
            SetPleaseOptimizeValueStack (Positive);
            END;
          'A' :
            SetPleaseGlobalOptimize (TRUE);
            END;
          'O' :
            SetStatsStream (CompleteOption.SLICE (3, CompleteOption.SIZE-3));
            END;
         ELSE
          RESULT := FALSE;
          END;
        END QOption;
        
      METHOD CommandLineOption (Opt: ARRAY OF CHAR): BOOLEAN;
        VAR
          Positive: BOOLEAN;
        BEGIN
        Initialize;
        IF (Opt[0] = '-') THEN
          RESULT := TRUE;
          Positive := Opt[Opt.SIZE - 1] <> '0';
          --------------------------------------
          -- For the time being, we'll consider options
          -- as case independant. This might change in
          -- the future, of course.
          --------------------------------------
          CASE SYSTEM.UCASE(Opt[1]) OF
            'D':
              SetDebugMode (Positive);
              END;
            'S':
              IF Opt.SIZE <= 2 THEN
                SetStatLevel (0);
               ELSE
                CASE Opt[2] OF
                  '0':
                    SetStatLevel (0);
                    END;
                  '1':
                    SetStatLevel (1);
                    END;
                  '2':
                    SetStatLevel (2);
                    END;
                 ELSE
                  RESULT := FALSE;
                  END; -- CASE   
                END; -- IF
              END;
            'V':
              IF Opt.SIZE <= 2 THEN
                SetVerboseLevel (1);
               ELSE
                CASE Opt[2] OF
                  '0':
                    SetVerboseLevel (0);
                    END;
                  '1':
                    SetVerboseLevel (1);
                    END;
                  '2':
                    SetVerboseLevel (2);
                    END;
                  '3':
                    SetVerboseLevel (3);
                    END;
                 ELSE
                  RESULT := FALSE;
                  END;   
                END;
              END;
            'W':
              IF Opt.SIZE <= 2 THEN
                SetWarningLevel (1);
               ELSE
                CASE Opt[2] OF
                  '0':
                    SetWarningLevel (0);
                    END;
                  '1':
                    SetWarningLevel (1);
                    END;
                  '2':
                    SetWarningLevel (2);
                    END;
                 ELSE
                  RESULT := FALSE;
                  END;   
                END;
              END;
            'K':
              IF Opt.SIZE <= 2 THEN
                SetTraceModeLevel (1);
               ELSE
                CASE Opt[2] OF
                  '0':
                    SetTraceModeLevel (0);
                    END;
                  '1':
                    SetTraceModeLevel (1);
                    END;
                  '2':
                    SetTraceModeLevel (2);
                    END;
                 ELSE
                  RESULT := FALSE;
                  END;   
                END;
              END;
            --------------------------------------
            -- Now, test multi-character command-line options
            --------------------------------------            
--            'A':
--              RESULT := AOption (SYSTEM.UCASE(Opt[2]), Positive, Opt);
--              END;
            'B':
              RESULT := BOption (SYSTEM.UCASE(Opt[2]), Positive, Opt);
              END;
            'C':
              RESULT := COption (SYSTEM.UCASE(Opt[2]), Positive, Opt);
              END;
            'E':
              RESULT := EOption (SYSTEM.UCASE(Opt[2]), Positive, Opt);
              END;
            'M':
              RESULT := MOption (SYSTEM.UCASE(Opt[2]), Positive, Opt);
              END;
            'O':
              RESULT := OOption (SYSTEM.UCASE(Opt[2]), Positive, Opt);
              END;
            'Q':
              RESULT := QOption (SYSTEM.UCASE(Opt[2]), Positive, Opt);
              END;
           ELSE
            RESULT := FALSE;
            END;
          END;
        END CommandLineOption;
        
      VAR
        Static: ONCE INTEGER;

      METHOD UniqueNumber: INTEGER;
        BEGIN
        Static := Static + 1;
        RESULT := Static;
        END UniqueNumber;
        
      METHOD ResetUniqueNumber;
        BEGIN
        Static := 0;
        END ResetUniqueNumber;

      METHOD GenerateDefines (Output: YaflGC);
        BEGIN
        ---------------------------
        -- If the trace level is 0, the tracing information
        -- is cancelled alltogether; while it is handled separately
        -- if the full debugging options are enabled, and the Trace
        -- level is 2.
        ---------------------------
        IF ProfileModeFlag THEN
          Output.DefineLabel(YaflGC.ProfileModeLabel);
          END;
        IF TheTraceModeLevel = 2 THEN
          Output.DefineLabel(YaflGC.FullTraceModeLabel);
          END;
        IF TheTraceModeLevel = 1 THEN
          Output.DefineLabel (YaflGC.TraceModeLabel);
          END;
        IF ForceStructFlag THEN
          Output.DefineLabel (YaflGC.ForceStructLabel);
          END;
        IF DebugModeFlag THEN
          Output.DefineLabel (YaflGC.DebugModeLabel);
         ELSE
          IF CheckArrayFlag THEN
            Output.DefineLabel (YaflGC.CheckArrayLabel);
            END;
          IF CheckDualStackFlag THEN
            Output.DefineLabel (YaflGC.CheckDualLabel);
            END;
          IF CheckWhatFlag THEN
            Output.DefineLabel (YaflGC.CheckWhatLabel);
            END;
          IF CheckCaseFlag THEN
            Output.DefineLabel (YaflGC.CheckCaseLabel);
            END;
          IF CheckDebugFlag THEN
            Output.DefineLabel (YaflGC.CheckDebugLabel);
            END;
          IF CheckAssertFlag THEN
            Output.DefineLabel (YaflGC.CheckAssertLabel);
            END;
          IF CheckVoidMethodFlag THEN
            Output.DefineLabel (YaflGC.CheckVoidMethodLabel);
            END;
          IF CheckVoidObjectFlag THEN
            Output.DefineLabel (YaflGC.CheckVoidObjectLabel);
            END;
          END;
        IF PleaseGeneratePreConditionFlag THEN
          Output.DefineLabel (YaflGC.CheckPreCondLabel);
          END;
        IF PleaseGeneratePostConditionFlag THEN
          Output.DefineLabel (YaflGC.CheckPostCondLabel);
          END;
        IF PleaseGenerateClassInvariantFlag THEN
          Output.DefineLabel (YaflGC.CheckClassInvariantLabel);
          END;
        IF PleaseGenerateLoopInvariantFlag THEN
          Output.DefineLabel (YaflGC.CheckLoopInvariantLabel);
          END;
        IF PleaseGeneratePostConditionFlag OR 
           PleaseGeneratePreConditionFlag THEN
          Output.DefineLabel (YaflGC.NeedAddMethRefLabel);
          END;
        IF TheCheckVersionLevel > 0 THEN
          Output.DefineLabel (YaflGC.CheckVersionLabel);
          END;
        END GenerateDefines;
        
      VAR
        TheOutputFile: OutputStream;
        
      METHOD ErrorOutputFile: OutputStream;
        BEGIN
        IF TheOutputFile = VOID THEN
          IF TheErrorFName <> VOID THEN
            TheOutputFile.CREATE;
            IF AppendErrorFile THEN
              TheOutputFile.Open (TheErrorFName, Stream.AppendAccess);
             ELSE
              TheOutputFile.Create (TheErrorFName, Stream.WriteAccess);
              END;          
            ASSERT TheOutputFile.ErrorCode = Stream.NoError;
            END;
          END;
        RESULT := TheOutputFile;
        END ErrorOutputFile;
        
      METHOD PleaseTag: BOOLEAN;
        BEGIN
        RESULT := PleaseTagFlag;
        END PleaseTag;
          
      METHOD PleaseCheckType : BOOLEAN; 
        BEGIN
        RESULT := PleaseCheckTypeFlag;
        END PleaseCheckType;
                
      METHOD PleaseGenerateCode: BOOLEAN;
        BEGIN
        RESULT := PleaseGenerateCodeFlag;
        END PleaseGenerateCode;
        
      METHOD PleaseGenerateMetrics: BOOLEAN;
        BEGIN
        RESULT := PleaseGenerateMetricsFlag;
        END PleaseGenerateMetrics;
        
      METHOD PleaseLint: BOOLEAN;
        BEGIN
        RESULT := PleaseLintFlag;
        END PleaseLint;
 
      METHOD PleaseGeneratePreCondition: BOOLEAN;
        BEGIN
        RESULT := PleaseGeneratePreConditionFlag;
        END PleaseGeneratePreCondition;
        
      METHOD PleaseGeneratePostCondition: BOOLEAN;
        BEGIN
        RESULT := PleaseGeneratePostConditionFlag;
        END PleaseGeneratePostCondition;
        
      METHOD PleaseGenerateClassInvariant: BOOLEAN;
        BEGIN
        RESULT := PleaseGenerateClassInvariantFlag;
        END PleaseGenerateClassInvariant;
        
      METHOD PleaseGenerateLoopInvariant: BOOLEAN;
        BEGIN
        RESULT := PleaseGenerateLoopInvariantFlag;
        END PleaseGenerateLoopInvariant;
        
      METHOD PleaseGenerateAbsolutePathNames: BOOLEAN;
        BEGIN
        RESULT := PleaseGenerateAbsolutePathNamesFlag;
        END PleaseGenerateAbsolutePathNames;

      METHOD PleaseOptimizeDirectLink : BOOLEAN;
        BEGIN
        RESULT := PleaseOptimizeDirectLinkFlag;
        END PleaseOptimizeDirectLink;
        
      METHOD PleaseOptimizeInLine : BOOLEAN;
        BEGIN
        RESULT := PleaseOptimizeInLineFlag;
        END PleaseOptimizeInLine;
                 
      METHOD PleaseOptimizeRemoveMethods : BOOLEAN;
        BEGIN
        RESULT := PleaseOptimizeRemoveMethodsFlag;
        END PleaseOptimizeRemoveMethods;
        
      METHOD PleaseOptimizeRemoveDebug : BOOLEAN;
        BEGIN
        RESULT := PleaseOptimizeRemoveDebugFlag;
        END PleaseOptimizeRemoveDebug;
        
      METHOD PleaseOptimizeValueStack: BOOLEAN; 
        BEGIN                        
        RESULT := PleaseOptimizeValueStackFlag;
        END PleaseOptimizeValueStack;
                                          
      METHOD PleaseGlobalOptimize : BOOLEAN;
        BEGIN
        RESULT := PleaseOptimizeDirectLinkFlag OR
                  PleaseOptimizeInLineFlag OR
                  PleaseOptimizeRemoveMethodsFlag OR
                  PleaseOptimizeRemoveDebugFlag OR
                  PleaseOptimizeValueStackFlag;
        END PleaseGlobalOptimize;
        
      METHOD SetPleaseTag (Val : BOOLEAN);
        BEGIN      
        PleaseTagFlag := Val;
        END SetPleaseTag;    
          
      METHOD SetPleaseCheckType (Val : BOOLEAN);
        BEGIN                  
        PleaseCheckTypeFlag := Val;
        END SetPleaseCheckType; 
        
      METHOD SetGenerateCode (Val : BOOLEAN);       
        BEGIN
        PleaseGenerateCodeFlag := Val;
        END SetGenerateCode;
        
      METHOD SetGenerateMetrics (Val : BOOLEAN);
        BEGIN
        PleaseGenerateMetricsFlag := Val;
        END SetGenerateMetrics;
        
      METHOD SetPleaseLint (Val : BOOLEAN);
        BEGIN
        PleaseLintFlag := Val;
        END SetPleaseLint;
        
      METHOD SetGeneratePreCondition (Val : BOOLEAN);
        BEGIN
        PleaseGeneratePreConditionFlag := Val;
        END SetGeneratePreCondition;
        
      METHOD SetGenerateAbsolutePathNames (Val : BOOLEAN);
        BEGIN
        PleaseGenerateAbsolutePathNamesFlag := Val;
        END SetGenerateAbsolutePathNames;
        
      METHOD SetPleaseOptimizeDirectLink (Val : BOOLEAN);
        BEGIN
        PleaseOptimizeDirectLinkFlag := Val;
        END SetPleaseOptimizeDirectLink;
        
      METHOD SetPleaseOptimizeInLine (Val : BOOLEAN);
        BEGIN
        PleaseOptimizeInLineFlag := Val;
        END SetPleaseOptimizeInLine;
                 
      METHOD SetPleaseOptimizeRemoveMethods (Val : BOOLEAN);
        BEGIN
        PleaseOptimizeRemoveMethodsFlag := Val;
        END SetPleaseOptimizeRemoveMethods;
        
      METHOD SetPleaseOptimizeRemoveDebug (Val : BOOLEAN);
        BEGIN
        PleaseOptimizeRemoveDebugFlag := Val;
        END SetPleaseOptimizeRemoveDebug;
        
      METHOD SetPleaseOptimizeValueStack (Val : BOOLEAN); 
        BEGIN                        
        PleaseOptimizeValueStackFlag := Val;
        END SetPleaseOptimizeValueStack;
                                       
      METHOD SetPleaseGlobalOptimize (Val : BOOLEAN);
        BEGIN
        SetPleaseOptimizeDirectLink (Val);
        SetPleaseOptimizeInLine (Val);
        SetPleaseOptimizeRemoveMethods (Val);
        SetPleaseOptimizeRemoveDebug (Val);
        SetPleaseOptimizeValueStack (Val);
        END SetPleaseGlobalOptimize;
                
      METHOD GarbageCollector;
        BEGIN
        IF VerboseLevel > 1 THEN
          StdOut.WriteString ("Garbage collection: ");
          StdOut.WriteInt (SYSTEM.Allocated,0);
          StdOut.WriteChar ("[");
          StdOut.WriteInt (SYSTEM.Allocations, 0);
          StdOut.WriteChar ("]");
          END;
        SYSTEM.GarbageCollector;
        IF VerboseLevel > 1 THEN
          StdOut.WriteString ("->");
          StdOut.WriteInt (SYSTEM.Allocated,0);
          StdOut.WriteChar ("[");
          StdOut.WriteInt (SYSTEM.Allocations, 0);
          StdOut.WriteLine ("]");
          END;
        END GarbageCollector;
        
      METHOD NameMapper: PatternFileNameMapper;
        BEGIN
        IF TheNameMapper = VOID THEN
          CASE SYSTEM.OperatingSystem OF
            SYSTEM.Dos, SYSTEM.OS2, SYSTEM.Windows:
              TheNameMapper := DosFileNameMapper;
              END;
            SYSTEM.Unix, SYSTEM.Coherent, SYSTEM.Qnx:
              TheNameMapper := UnixFileNameMapper;
              END;
            SYSTEM.Mvs:
              TheNameMapper := MvsFileNameMapper;
              END;
            END;
          END;
        RESULT := TheNameMapper;
        END NameMapper;  

      METHOD DoOpenHomeStreams (Radix, Extension: ARRAY OF CHAR;
                                Buff: ARRAY OF InputStream): INTEGER;
        VAR       
          Var: ARRAY OF CHAR;
          Pathes: ARRAY OF ARRAY OF CHAR;                              
          GoOn: BOOLEAN;
          Index: INTEGER;
          Input: InputStream;
          Res: INTEGER;
          
          METHOD CheckName (FName: ARRAY OF CHAR);
            BEGIN      
            IF Input = VOID THEN
              Input.CREATE;
              END;
            Input.Open (FName, Input.ReadAccess);
            IF Input.ErrorCode = Input.NoError THEN
              Buff[Res] := Input;
              Input.CREATE;
              Res := Res + 1;
              END;
            END CheckName;
          
        BEGIN             
        GoOn := TRUE;
        WHILE GoOn DO           
          IF Pathes = VOID THEN      
            Var := FindValue ("YAFL_HOME");
            IF Var = VOID THEN
              GoOn := FALSE;
             ELSE
              Pathes := String.BreakInWords (Var, SkipSeparator := ";, ",
                                                  KeepSeparator := VOID);
              END;
            END;              
          IF (Pathes <> VOID) AND (Index < Pathes.SIZE) THEN
            CheckName (NameMapper.BuildProjectFileName (Pathes[Index],
                                                        Radix,
                                                        Extension));
            Index := Index + 1;
           ELSE 
            GoOn := FALSE;
            END;
          GoOn := GoOn AND (Res < Buff.SIZE) AND (Input <> VOID);  
          END;          

        -- Patched by Louis
        IF Res < Buff.SIZE THEN
          CheckName(NameMapper.BuildProjectFileName(VOID, 
                                                    Radix, 
                                                    Extension));
          END; -- IF

        RESULT := Res;
        END DoOpenHomeStreams;                         
        
      METHOD OpenHomeStream (Radix, Extension: ARRAY OF CHAR): InputStream;
        VAR
          Buff: ONCE ARRAY OF InputStream;
        BEGIN                             
        IF Buff = VOID THEN
          Buff.CREATE (1);
          END;          
        VOID := DoOpenHomeStreams (Radix, Extension, Buff);
        RESULT := Buff[0];
        Buff[0] := VOID;
        END OpenHomeStream;
        
      METHOD OpenHomeStreams (Radix, Extension: ARRAY OF CHAR): 
                     ARRAY OF InputStream;
        VAR
          i: INTEGER;
          Buff: ONCE ARRAY OF InputStream;         
        CONST
          MaxStreams = 16;
        BEGIN                             
        IF Buff = VOID THEN
          Buff.CREATE (MaxStreams);
          END;
        i := DoOpenHomeStreams (Radix, Extension, Buff);
        IF i > 0 THEN
          RESULT := Buff.SLICE (0, i);
          END;
        FOR j := 0 TO Buff.SIZE - 1 DO
          Buff[j] := VOID;
          END;
        END OpenHomeStreams;

      METHOD SetStatsStream (FName : ARRAY OF CHAR);
        BEGIN
        StdOut.WriteLine ("Using stats stream : " + FName);                                     
        TheStatStream.CREATE;
        TheStatStream.Create(FName, Stream.ReadWriteAccess);
        IF (TheStatStream.ErrorCode <> Stream.NoError) THEN
          StdOut.WriteLine ("Oups... error while opening the stream");
          END;        
        END SetStatsStream;

      METHOD StatsStream : OutputStream;
        BEGIN         
        RESULT := TheStatStream;
        END StatsStream;
      
    -------------------------------------------------       
      VAR       
        TheController : Controller;
                      
      METHOD SetController (Control : Controller);
        BEGIN              
        TheController := Control;
        END SetController;      
      
      METHOD GetController : Controller;
        BEGIN                
        IF TheController = VOID THEN
          TheController.CREATE;
          END; -- IF
        RESULT := TheController;
        END GetController;  

      VAR
        IsInterrupted : BOOLEAN;
      
      METHOD Interrupted : BOOLEAN;
        BEGIN      
        RESULT := IsInterrupted;
        END Interrupted;
      
      METHOD SetInterrupted (Val : BOOLEAN);
        BEGIN            
        IsInterrupted := Val;
        IF (IsInterrupted) AND
           (VerboseLevel > 0) THEN
          StdOut.WriteLine ("Compilation interrupted");
          END; -- IF
        END SetInterrupted;    
        
      METHOD GetConfig: Configuration;
        BEGIN         
        IF TheConfig = VOID THEN
          TheConfig.CREATE;
          END;
        RESULT := TheConfig;
        END GetConfig;

      METHOD UseConfig (Config : Configuration);
        BEGIN
        TheConfig := Config;
        UseTheCurrentConfig;
        END UseConfig;
        
    END YaflCfg;

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

  ONCE CLASS CurrentSpot;

      VAR
        CurrentCompilationRunValue: CompilationRun;
        ModuleStack: Stack(CompilationUnit);
        ClassStack: Stack(ClassDeclaration);
        MethodStack: Stack(MethodDeclaration);

      REDEFINE METHOD CREATE;
        BEGIN
        BASE;
        ModuleStack.CREATE;
        ClassStack.CREATE;
        MethodStack.CREATE; 
        END CREATE;

      METHOD CurrentCompilationRun: CompilationRun;
        BEGIN
        RESULT := CurrentCompilationRunValue;
        END CurrentCompilationRun;
        
      METHOD CurrentModule: CompilationUnit;
        BEGIN
        RESULT := ModuleStack.Top;
        END CurrentModule;

      METHOD CurrentClass: ClassDeclaration;
        BEGIN
        RESULT := ClassStack.Top;
        END CurrentClass;

      METHOD CurrentMethod: MethodDeclaration;
        BEGIN
        RESULT := MethodStack.Top;
        END CurrentMethod;

      METHOD SetCurrentCompilationRun (Value: CompilationRun);
        BEGIN
        CurrentCompilationRunValue := Value;
        ModuleStack.Purge;
        ClassStack.Purge;
        MethodStack.Purge;
        END SetCurrentCompilationRun;
        
      METHOD PushCurrentModule (Value: CompilationUnit);
        BEGIN                                 
        ModuleStack.Push (Value);
        ClassStack.Purge;
        MethodStack.Purge;
        END PushCurrentModule;

      METHOD PushCurrentClass (Value: ClassDeclaration);
        BEGIN
        ASSERT CurrentModule <> VOID;
        ClassStack.Push(Value);
        MethodStack.Purge;
        END PushCurrentClass;

      METHOD PushCurrentMethod (Value: MethodDeclaration);
        BEGIN
        ASSERT CurrentModule <> VOID;
        ASSERT CurrentClass <> VOID;
        MethodStack.Push(Value);
        END PushCurrentMethod;

      METHOD PopCurrentModule;
        BEGIN
        ModuleStack.Drop;
        END PopCurrentModule;

      METHOD PopCurrentClass;
        BEGIN
        ClassStack.Drop;
        END PopCurrentClass;

      METHOD PopCurrentMethod;
        BEGIN
        MethodStack.Drop;
        END PopCurrentMethod;
        
    END CurrentSpot;

END YaflCfg;
