IMPLEMENTATION MODULE CGType; 

FROM YaflGC IMPORT YaflGC;

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

------------------------------
-- Generic Code Generators
------------------------------
FROM YaflGCode       IMPORT GC;
FROM YaflGType       IMPORT TypedNTCodeGenerator;
FROM YaflGClass      IMPORT ClassDeclCodeGenerator;
FROM YaflGMethods    IMPORT MethDeclCodeGenerator;

------------------------------
-- Non Terminals
------------------------------
FROM YaflType         IMPORT TypedNonTerminal,
                             Type;

FROM YaflPredefined   IMPORT PredefMethod,
                             PredefItems, 
                             PredefClass,
                             ThisDataItem;
FROM YaflClasses      IMPORT ClassDeclaration;
FROM YaflDeclarations IMPORT SingleDataItem, ConstDeclaration;
FROM YaflDictionary   IMPORT MethodReference, EntryReference,
                             CallReference, AttributeReference,
                             CallDictionary;
FROM YaflDesignator IMPORT DesigElement, Desig;
FROM YaflParser       IMPORT NonTerminal, Walker, LimitedWalker;
FROM Streams          IMPORT StdOut;
FROM YaflLex          IMPORT LexicalAnalyzer;
FROM YaflParamClasses IMPORT ClassActual;
FROM YaflCfg          IMPORT CurrentSpot, YaflCfg;
FROM YaflError        IMPORT WarningHandler;
FROM YaflMetImplementation IMPORT MethodImplementation;
FROM YaflMethods IMPORT MethodDeclaration;
FROM YaflSystem IMPORT SystemMethod;
FROM YaflClImplementation IMPORT ClassImplementation;
FROM YaflLiteral     IMPORT Literal;

  CLASS CIntLiteralCodeGenerator;
    INHERITS IntLiteralCodeGenerator(CGcContext);
    
    METHOD Output: YaflGC;
      BEGIN
      ASSERT Ctx.Output <> VOID;
      RESULT := Ctx.Output;
      END Output;

    REDEFINE METHOD GenerateCode;
      BEGIN
      Ctx.TypedNTGenerateCode(THIS); 
      END GenerateCode;

    REDEFINE METHOD GenerateEvaluationCode;
      BEGIN
      Output.LeftParent;
      Output.WriteString (PredefItems.Integer.CName);
      Output.RightParent;
      Output.WriteInt (Obj.Value, 0);
      END GenerateEvaluationCode;

  END CIntLiteralCodeGenerator;
  
----------------------------------------------------

  CLASS CRealLiteralCodeGenerator;
    INHERITS RealLiteralCodeGenerator(CGcContext);
  
    METHOD Output: YaflGC;
      BEGIN
      ASSERT Ctx.Output <> VOID;
      RESULT := Ctx.Output;
      END Output;

    REDEFINE METHOD GenerateCode;
      BEGIN
      Ctx.TypedNTGenerateCode(THIS); 
      END GenerateCode;

    REDEFINE METHOD GenerateEvaluationCode;
      BEGIN
      Output.WriteReal (Obj.Value, 0, 0);
      END GenerateEvaluationCode;
      
  END CRealLiteralCodeGenerator;
  
----------------------------------------------------

  CLASS CStringLiteralCodeGenerator;
    INHERITS StringLiteralCodeGenerator(CGcContext);
    
    METHOD Output: YaflGC;
      BEGIN
      ASSERT Ctx.Output <> VOID;
      RESULT := Ctx.Output;
      END Output;

    REDEFINE METHOD GenerateCode;
      BEGIN
      Ctx.TypedNTGenerateCode(THIS); 
      END GenerateCode;

    REDEFINE METHOD GenerateEvaluationCode;
      BEGIN
      IF Obj.IsSingleChar THEN
        Output.LiteralChar (Obj.Value[0]);
       ELSE
        Output.NewString (Obj.Value);
        END;
      END GenerateEvaluationCode;

  END CStringLiteralCodeGenerator;
  
----------------------------------------------------

  CLASS CBooleanLiteralCodeGenerator;
    INHERITS BooleanLiteralCodeGenerator(CGcContext);
    
    METHOD Output: YaflGC;
      BEGIN
      ASSERT Ctx.Output <> VOID;
      RESULT := Ctx.Output;
      END Output;

    REDEFINE METHOD GenerateCode;
      BEGIN
      Ctx.TypedNTGenerateCode(THIS); 
      END GenerateCode;

    REDEFINE METHOD GenerateEvaluationCode;
      BEGIN
      IF Obj.Value THEN
        Output.WriteChar ('1');
       ELSE
        Output.WriteChar ('0');
        END;
      END GenerateEvaluationCode;

  END CBooleanLiteralCodeGenerator;       
  
----------------------------------------------------

  CLASS CVoidLitCodeGenerator;
    INHERITS VoidLitCodeGenerator(CGcContext);
    
    METHOD Output: YaflGC;
      BEGIN
      ASSERT Ctx.Output <> VOID;
      RESULT := Ctx.Output;
      END Output;

    REDEFINE METHOD GenerateCode;
      BEGIN
      Ctx.TypedNTGenerateCode(THIS); 
      END GenerateCode;

   REDEFINE METHOD GenerateEvaluationCode;
     BEGIN
     Output.LeftParent;
     Output.ObjPtr;
     Output.RightParent;
     Output.Zero;
     END GenerateEvaluationCode;

  END CVoidLitCodeGenerator;

----------------------------------------------------
  
  CLASS CExpressionCodeGenerator;
    INHERITS ExpressionCodeGenerator(CGcContext);
    
    METHOD Output: YaflGC;
      BEGIN
      ASSERT Ctx.Output <> VOID;
      RESULT := Ctx.Output;
      END Output;

    REDEFINE METHOD GenerateCodeWithTarget (TargetNr: INTEGER);
      VAR
	    IsFunc: BOOLEAN;

      METHOD DoConcat (FirstExpr, SecondExpr: TypedNonTerminal;
                       Functional: BOOLEAN);
        VAR
          CatArr: ARRAY OF TypedNonTerminal;
        CONST
          MaxArity = 5;
          
        METHOD GenerateSlice (From, Len: INTEGER);

  	      METHOD GenerateArg (i: INTEGER);
  	        BEGIN
  	        IF Functional THEN
  	          CatArr[i].Gc.GenerateCode;
  	         ELSE
  	          Output.UniqueItem (CatArr[i].Gc.Number);
  	          END;
  	        END GenerateArg;

	      METHOD GenerateNonRecursive;
	        BEGIN
            Output.UnivConcat(Arity := Len);
            Output.LeftParent;
            FOR i := From TO From + Len - 1 DO
              IF i <> From THEN
                Output.Comma;
                END;
              GenerateArg (i);
              END;
            Output.RightParent;
	        END GenerateNonRecursive;

	      METHOD GenerateRecursive;
	        BEGIN
            Output.UnivConcat (Arity := MaxArity);
            Output.LeftParent;
            FOR i := From TO From + MaxArity - 2 DO
              GenerateArg (i);
              Output.Comma;
              END;
            GenerateSlice (From + MaxArity - 1, Len - MaxArity + 1);
            Output.RightParent;
	        END GenerateRecursive;

          BEGIN
	      Output.Flush;
          ASSERT Len > 1;
          IF Len <= MaxArity THEN
	        GenerateNonRecursive;
	      ELSE
	        GenerateRecursive;
	        END;
          END GenerateSlice;

	    VAR
	      TheExpr: TypedNonTerminal;
          
        BEGIN
        CatArr := Obj.GrabConcat;
     	IF Functional THEN
	      IF TargetNr > 0 THEN
	        Output.UniqueItem (TargetNr);
	        Output.Becomes;
	        END;
          GenerateSlice (0, CatArr.SIZE);
	    ELSE
	      Output.WriteLn;
	      Output.LeftBrace;
	      Output.WriteLn;
	      FOR i := 0 TO CatArr.SIZE - 1 DO
            Ctx.TypedNTGenerateTempVariableDecl(CatArr[i].Gc);
	        END;
	      FOR i := 0 TO CatArr.SIZE - 1 DO
	        TheExpr := CatArr[i];
            Ctx.TypedNTGenerateCodeWithTarget(TheExpr.Gc,
                                              TheExpr.Gc.Number);
	        IF TheExpr.RequiresTempSaving THEN
	          Output.FlyVReg;
	          Output.LeftParent;
	          Output.UniqueItem (TheExpr.Gc.Number);
	          Output.RightParent;
	          Output.SemiColon;
	          Output.WriteLn;
	          END;
	        END;
	      IF TargetNr > 0 THEN
	        Output.UniqueItem (TargetNr);
	        Output.Becomes;
	        END;
          GenerateSlice (0, CatArr.SIZE);
	      Output.SemiColon;
	      Output.WriteLn;
	      Output.RightBrace;
	      Output.WriteLn;
	      END;
        END DoConcat;
         
      METHOD GenLeftEval;
	    BEGIN
	    IF NOT IsFunc THEN
          Ctx.TypedNTGenerateCodeWithTarget (Obj.FirstExpr.Gc,
					       Obj.FirstExpr.Gc.Number);
	      END;
	    END GenLeftEval;

      METHOD GenRightEval;
	    BEGIN
	    IF NOT IsFunc THEN
          Ctx.TypedNTGenerateCodeWithTarget (Obj.SecondExpr.Gc,
					       Obj.SecondExpr.Gc.Number);
	      END;
	    END GenRightEval;

      METHOD GenLeftRef;
	    BEGIN
	    IF IsFunc THEN
	      Ctx.TypedNTGenerateCode(Obj.FirstExpr.Gc);
	    ELSE
          Output.UniqueItem (Obj.FirstExpr.Gc.Number);
	      END;
	    END GenLeftRef;

      METHOD GenRightRef;
	    BEGIN
	    IF IsFunc THEN
	      Ctx.TypedNTGenerateCode(Obj.SecondExpr.Gc);
	    ELSE
          Output.UniqueItem (Obj.SecondExpr.Gc.Number);
	      END;
	    END GenRightRef;

	  METHOD GenLValue;
	    BEGIN
	    IF TargetNr > 0 THEN
  	      Output.UniqueItem (TargetNr);
          Output.Becomes;
	      END;
	    END GenLValue;

      METHOD GenOp (Code: INTEGER);
         BEGIN
	     CASE Code OF
           LexicalAnalyzer.Star:
             Output.Star;
             END;
           LexicalAnalyzer.Minus:
             Output.Minus;
             END;
           LexicalAnalyzer.Plus:
             Output.Plus;
             END;
           LexicalAnalyzer.Slash:
             Output.Slash;
             END;
           LexicalAnalyzer.Mod:
             Output.Mod;
             END;
           LexicalAnalyzer.Equal:
             Output.Equal;
             END;
           LexicalAnalyzer.NonEqual:
             Output.NonEqual;
             END;
           LexicalAnalyzer.Greater:
             Output.Greater;
             END;
           LexicalAnalyzer.SmallerEqual:
             Output.SmallerEqual;
             END;
           LexicalAnalyzer.Smaller:
             Output.Smaller;
             END;
           LexicalAnalyzer.GreaterEqual:
             Output.GreaterEqual;
	         END;
	       END;
	     END GenOp;

      METHOD GenNormal;
        BEGIN
        GenRightEval;
	    GenLValue;
	    Output.LeftParent;
        IF Obj.Relation = LexicalAnalyzer.Iff THEN
          Output.LeftParent;
          
          Output.LeftParent;
            
          Output.LeftParent;
          GenLeftRef;
          Output.RightParent;
          
          Output.QuestionMark;
          Output.WriteChar ('1');
          Output.Colon;
          Output.WriteChar ('0');
              
          Output.RightParent;
          
          Output.Equal;
          
          Output.LeftParent;
          
          Output.LeftParent;
          GenRightRef;
          Output.RightParent;
          
          Output.QuestionMark;
          Output.WriteChar ('1');
          Output.Colon;
          Output.WriteChar ('0');
          
          Output.RightParent;
          
          Output.RightParent;
        ELSE
  	      GenLeftRef;
	      GenOp (Obj.Relation);
	      GenRightRef;
          END;
	    Output.RightParent;
	    END GenNormal;

      BEGIN
      IsFunc := Obj.Functional;
      IF Obj.GetFolded <> VOID THEN
	    GenLValue;
	    Output.LeftParent;
        Obj.GetFolded.Gc.GenerateCode;
	    Output.RightParent;
	    IF NOT IsFunc THEN
	      Output.SemiColon;
	      Output.WriteLn;
	      END;
      ELSIF (Obj.Relation = LexicalAnalyzer.Plus) AND
	    (Obj.FirstExpr.GetType.ArrayLevel > 0) THEN
	    IF IsFunc THEN
  	      GenLValue;
	      END;
	    DoConcat (Obj.FirstExpr, Obj.SecondExpr, IsFunc);
      ELSE
	    IF IsFunc THEN
	      GenLValue;
	      Output.LeftParent;
	    ELSE
	      ASSERT TargetNr <> 0;
  	      Output.WriteLn;
	      Output.LeftBrace;
	      Output.WriteLn;
	      Ctx.TypedNTGenerateTempVariableDecl (Obj.FirstExpr.Gc);
  	      IF Obj.SecondExpr <> VOID THEN
	        Ctx.TypedNTGenerateTempVariableDecl (Obj.SecondExpr.Gc);
	        END;
	      GenLeftEval;
	      END;
        CASE Obj.Relation OF
          LexicalAnalyzer.Plus:
            ASSERT Obj.FirstExpr.GetType.ArrayLevel = 0;
            GenNormal;
            END;
          LexicalAnalyzer.Minus:
            IF Obj.SecondExpr = VOID THEN
	      GenLValue;
              Output.Minus;
	      GenLeftRef;
             ELSE
  	      GenNormal;
              END;
            END;
          LexicalAnalyzer.And:
	    IF IsFunc THEN
  	      GenLeftRef;
              Output.QuestionMark;
	      GenRightRef;
              Output.Colon;
              Output.Zero;
	     ELSE
	      Output.If;
	      Output.LeftParent;
	      GenLeftRef;
	      Output.RightParent;
	      Output.WriteLn;
	      Output.LeftBrace;
	      Output.WriteLn;
	      GenRightEval;
	      GenLValue;
	      GenRightRef;
	      Output.SemiColon;
	      Output.WriteLn;
	      Output.RightBrace;
	      Output.WriteLn;
	      Output.Else;
	      Output.WriteLn;
	      GenLValue;
	      Output.WriteChar ('0');
	      END;
            END;
          LexicalAnalyzer.Or:
	        IF IsFunc THEN
	          GenLeftRef;
              Output.QuestionMark;
              Output.WriteChar ('1');
              Output.Colon;
	          GenRightRef;
	        ELSE
              Output.If;
	          Output.LeftParent;
	          GenLeftRef;
	          Output.RightParent;
	          GenLValue;
	          Output.WriteChar ('1');
	          Output.SemiColon;
	          Output.WriteLn;
	          Output.Else;
	          Output.WriteLn;
	          Output.LeftBrace;
	          GenRightEval;
	          GenLValue;
	          GenRightRef;
	          Output.SemiColon;
	          Output.RightBrace;
	          END;
            END;
          LexicalAnalyzer.Implies:
	        IF IsFunc THEN
	          GenLeftRef;
              Output.QuestionMark;
	          GenRightRef;
              Output.Colon;
              Output.WriteChar ('1');
	        ELSE
              Output.If;
	          Output.LeftParent;
	          Output.Not;
	          GenLeftRef;
	          Output.RightParent;
	          GenLValue;
	          Output.WriteChar ('1');
	          Output.SemiColon;
	          Output.WriteLn;
	          Output.Else;
	          Output.WriteLn;
	          Output.LeftBrace;
	          GenRightEval;
	          GenLValue;
	          GenRightRef;
	          Output.SemiColon;
	          Output.RightBrace;
	          END;
            END;
          LexicalAnalyzer.Not:
	      GenLValue;
          Output.Not;
	      GenLeftRef;
          END;
	  ELSE
	   GenNormal;
          END;
        IF IsFunc THEN
          Output.RightParent;
         ELSE
          Output.SemiColon;
          Output.WriteLn;
          Output.RightBrace;
          Output.WriteLn;
          END;
        END;
      END GenerateCodeWithTarget;

    REDEFINE METHOD GenerateEvaluationCode;
      BEGIN
      ASSERT Obj.Functional;
      GenerateCodeWithTarget (0);
      END GenerateEvaluationCode;
      
    REDEFINE METHOD GenerateCode;
      BEGIN
      GenerateCodeWithTarget (0);
      END GenerateCode;

    METHOD GenerateSelfOperation;
      BEGIN
      ASSERT Obj.FirstExpr <> VOID;
      ASSERT Obj.SecondExpr <> VOID;
      Obj.FirstExpr.Gc.GenerateCode;
      CASE Obj.Relation OF
        LexicalAnalyzer.Plus:
          Output.SelfPlus;
          END;
        LexicalAnalyzer.Minus:
          Output.SelfMinus;
          END;
        LexicalAnalyzer.Star:
          Output.SelfStar;
          END;
        LexicalAnalyzer.Mod:
          Output.SelfMod;
          END;
        LexicalAnalyzer.Slash:
          Output.SelfSlash;
          END;
        END;
      Obj.SecondExpr.Gc.GenerateCode;
      Output.SemiColon;
      Output.WriteLn;
      END GenerateSelfOperation;
      
  END CExpressionCodeGenerator;
  
----------------------------------------------------

  CLASS CActualCodeGenerator;
    INHERITS ActualCodeGenerator(CGcContext);
    
    METHOD Output: YaflGC;
      BEGIN
      ASSERT Ctx.Output <> VOID;
      RESULT := Ctx.Output;
      END Output;

    REDEFINE METHOD GenerateCode;
      BEGIN
      ASSERT Obj.Expr.Functional;
      WHAT Obj.Expr.Gc OF 
        IN TypedNTCodeGenerator:
          WHAT TAG.Ctx OF
            IN CGcContext:
              TAG.TypedNTGenerateWithTempSaving(Obj.Expr.Gc);
              END;
            END;--  what 
          END; 
        END; -- what
      END GenerateCode;
      
  END CActualCodeGenerator;

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

  CLASS CInstTypeCodeGenerator;
    INHERITS InstTypeCodeGenerator(CGcContext);
    
    METHOD Output: YaflGC;
      BEGIN
      ASSERT Ctx.Output <> VOID;
      RESULT := Ctx.Output;
      END Output;

    REDEFINE METHOD GenerateCode;
      BEGIN
      Ctx.TypeGenerateCode(THIS);
      END GenerateCode; 

  END CInstTypeCodeGenerator;
  
----------------------------------------------------

  
END CGType;

