/*------------------------------------------------------------\
|                                                             |
| Tool    :                     DRUC                          |
|                                                             |
| File    :                  VMCASMLD.C                       |
|                                                             |
| Authors :                Patrick Renaud                     |
|                                                             |
| Date    :                   11/01/94                        |
|                                                             |
\------------------------------------------------------------*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <malloc.h>
#include MPH_H
#include MUT_H
#include RDS_H
#include RUT_H
#include RTL_H
#include RWI_H
#include RFM_H
#include RPR_H

#include "drucutil.h"
#include "druchier.h"
#include "vmcasmld.h"

/*------------------------------------------------------------\
|                                                             |
|                  DRUCVMC   variables                        |
|                                                             |
\------------------------------------------------------------*/

extern long                       DrucCtmMax;
extern DrucTypeStructRuleComment *DrucRuleCommentList;


static char DrucFileBuffer [ DRUC_MAX_FILE_BUFFER + 1 ];

/*------------------------------------------------------------\
|                                                             |
|                  DRUVMC    Fonctions                        |
|                                                             |
\------------------------------------------------------------*/

/*------------------------------------------------------------\
|                                                             |
|                  DrucComputeCtm                             |
|                                                             |
\------------------------------------------------------------*/

void DrucComputeCtm ( DrucInstructionCourante
                    )

DrucTypeStructInstruction *DrucInstructionCourante;

{

int                       IndexInstruction;
long                      Value;
int                       IndexMesure = 0;

  while (  DrucInstructionCourante->RELATION  [ IndexMesure ] 
          != DRUC_UNDEFINED_RELATION 
        )
  {
    if (   ( DrucInstructionCourante->MESURE  [ IndexMesure ]
            == DRUC_MESURE_AXIALE )                  
        ||
           (  DrucInstructionCourante->MESURE  [ IndexMesure ]
            == DRUC_MESURE_GEODESIQUE )
       )
    {
      Value      = DrucInstructionCourante->VALEUR [ IndexMesure ];

      DrucCtmMax = ( DrucCtmMax > Value ?
                     DrucCtmMax :
                     Value
                   );

      DrucStructRdsLayer [ DrucInstructionCourante->LAYER_1 ].CTM  = 
      ( Value > DrucStructRdsLayer [ DrucInstructionCourante->LAYER_1 ].CTM ?
        Value : 
        DrucStructRdsLayer [ DrucInstructionCourante->LAYER_1 ].CTM 
      );

      DrucStructRdsLayer [ DrucInstructionCourante->LAYER_2 ].CTM  = 
      ( Value > DrucStructRdsLayer [ DrucInstructionCourante->LAYER_2 ].CTM ?
        Value : 
        DrucStructRdsLayer [ DrucInstructionCourante->LAYER_2 ].CTM 
      );
    }

    IndexMesure ++;
  }
}

/*------------------------------------------------------------\
|                                                             |
|                  DrucReadNextCodeAsm                        |
|                                                             |
| Lit le code assembleur suivant ou sort                      |
| Retourne le code lu                                         |
\------------------------------------------------------------*/

int DrucReadNextCodeAsm (
                        )

{

/*\
 * on peut passer unparametre pour verifier la classe d'appartenance de la lecture
\*/
int TmpLecture;

  if ( fscanf( DrucFileAssembler, "%d", &TmpLecture ) == EOF 
     )
  {
    DRUC_EXIT ( DRUC_ERROR_READ_PARAM );
  }

  DrucComputeCheckSumm ( TmpLecture
                       );
  return ( TmpLecture
         );
}

/*------------------------------------------------------------\
|                                                             |
|                  DrucReadAsm                                |
|                                                             |
| Lit le code assembleur de druc et charge la pile d'execution|
| Le fichier pointe sur le debut du code                      |
\------------------------------------------------------------*/

int DrucReadAsm ( DrucTabInstruction
                )

    DrucTypeStructInstruction ***DrucTabInstruction;
{
int                        TmpIndexMesure;
int                        IndexLayer;
int                        DrucNombreInstructions;
boolean                    FlagBegin;
int                        TmpCheckSumm;
int                        TmpLecture;
DrucTypeStructInstruction *DrucStructInstruction = ( DrucTypeStructInstruction *)NULL;
DrucTypeStructInstruction *TmpStructInstruction;

  DrucNombreInstructions = 0;
  DrucCtmMax             = DRUC_UNDEFINED_CTM;
  FlagBegin              = DRUC_FALSE;

  while ( FlagBegin != DRUC_TRUE )
  {
    TmpLecture = DrucReadNextCodeAsm (
                                     );
    switch ( TmpLecture 
           )
    {
      case DRUC_ASM_BEGIN_LAYER :
      {
        for ( IndexLayer  = 0;
              IndexLayer != RDS_MAX_LAYER;
              IndexLayer ++
            )
        {
          DrucStructRdsLayer [ IndexLayer ].RDS_INDEX = DrucReadNextCodeAsm ();
          DrucStructRdsLayer [ IndexLayer ].WIDTH     = DrucReadNextCodeAsm ();
          DrucStructRdsLayer [ IndexLayer ].CTM       = DrucReadNextCodeAsm ();

          DrucCtmMax = ( DrucCtmMax > DrucStructRdsLayer [ IndexLayer ].CTM ?
                         DrucCtmMax :
                         DrucStructRdsLayer [ IndexLayer ].CTM 
                       );
        }
        break;
      }
      case DRUC_ASM_END_LAYER :
      {
        break;
      }
      case DRUC_ASM_BEGIN_DEFINE :
      {
        TmpStructInstruction =
           ( DrucTypeStructInstruction *)malloc (sizeof ( DrucTypeStructInstruction ));

        if ( TmpStructInstruction == (DrucTypeStructInstruction *)NULL 
           )
        {
          DRUC_EXIT ( DRUC_ERROR_MEMOIRE );
        }

        TmpStructInstruction->NEXT        = DrucStructInstruction;
        TmpStructInstruction->INSTRUCTION = TmpLecture;
        TmpStructInstruction->LAYER_DEST  = DrucReadNextCodeAsm ();
        TmpStructInstruction->OP_COMPOSE  = DrucReadNextCodeAsm ();
        TmpStructInstruction->LAYER_1     = DrucReadNextCodeAsm ();
        TmpStructInstruction->LAYER_2     = DrucReadNextCodeAsm ();

        for ( TmpIndexMesure = 0;
              TmpIndexMesure < DRUC_MAX_MESURES;
              TmpIndexMesure ++
            )
        {
          ( TmpStructInstruction->REGLE_NUM ) [ TmpIndexMesure ] = DRUC_UNDEFINED_REGLE;
          ( TmpStructInstruction->RELATION  ) [ TmpIndexMesure ] = DRUC_UNDEFINED_RELATION;
          ( TmpStructInstruction->MESURE    ) [ TmpIndexMesure ] = DRUC_UNDEFINED_MESURE;
          ( TmpStructInstruction->OP_COMPARE) [ TmpIndexMesure ] = DRUC_UNDEFINED_OPERATEUR;
          ( TmpStructInstruction->VALEUR    ) [ TmpIndexMesure ] = DRUC_UNDEFINED_VALEUR;
        }

        DrucStructInstruction             = TmpStructInstruction;
        DrucNombreInstructions ++;
        break;
      }
      case DRUC_ASM_END_DEFINE :
      {
        break;
      }
      case DRUC_ASM_BEGIN_UNDEFINE :
      {
        TmpStructInstruction =
           ( DrucTypeStructInstruction *)malloc (sizeof ( DrucTypeStructInstruction ));

        if ( TmpStructInstruction == (DrucTypeStructInstruction *)NULL 
           )
        {
          DRUC_EXIT ( DRUC_ERROR_MEMOIRE );
        }

        TmpStructInstruction->NEXT        = DrucStructInstruction;
        DrucStructInstruction             = TmpStructInstruction;
        TmpStructInstruction->INSTRUCTION = TmpLecture;
        TmpStructInstruction->LAYER_DEST  = DRUC_UNDEFINED_LAYER;
        TmpStructInstruction->OP_COMPOSE  = DRUC_UNDEFINED_OP_COMPOSE;
        TmpStructInstruction->LAYER_1     = DrucReadNextCodeAsm ();
        TmpStructInstruction->LAYER_2     = DRUC_UNDEFINED_LAYER;

        for ( TmpIndexMesure = 0;
              TmpIndexMesure < DRUC_MAX_MESURES;
              TmpIndexMesure ++
            )
        {
          ( TmpStructInstruction->REGLE_NUM ) [ TmpIndexMesure ] = DRUC_UNDEFINED_REGLE;
          ( TmpStructInstruction->RELATION  ) [ TmpIndexMesure ] = DRUC_UNDEFINED_RELATION;
          ( TmpStructInstruction->MESURE    ) [ TmpIndexMesure ] = DRUC_UNDEFINED_MESURE;
          ( TmpStructInstruction->OP_COMPARE) [ TmpIndexMesure ] = DRUC_UNDEFINED_OPERATEUR;
          ( TmpStructInstruction->VALEUR    ) [ TmpIndexMesure ] = DRUC_UNDEFINED_VALEUR;
        }
        DrucNombreInstructions ++;
        break;
      }
      case DRUC_ASM_END_UNDEFINE :
      {
        break;
      }
      case DRUC_ASM_BEGIN_REGLE :
      {
        TmpStructInstruction =
           ( DrucTypeStructInstruction *)malloc (sizeof ( DrucTypeStructInstruction ));

        if ( TmpStructInstruction == (DrucTypeStructInstruction *)NULL 
           )
        {
          DRUC_EXIT ( DRUC_ERROR_MEMOIRE );
        }

        TmpStructInstruction->NEXT        = DrucStructInstruction;
        TmpStructInstruction->INSTRUCTION = TmpLecture;
        TmpStructInstruction->OP_COMPOSE  = DrucReadNextCodeAsm ();
        TmpStructInstruction->LAYER_1     = DrucReadNextCodeAsm ();
        TmpStructInstruction->LAYER_2     = DrucReadNextCodeAsm ();
        TmpStructInstruction->LAYER_DEST  = DRUC_UNDEFINED_LAYER;

        for ( TmpIndexMesure = 0;
              TmpIndexMesure < DRUC_MAX_MESURES;
              TmpIndexMesure ++
            )
        {
          TmpStructInstruction->REGLE_NUM  [ TmpIndexMesure ] = DrucReadNextCodeAsm ();
          TmpStructInstruction->RELATION   [ TmpIndexMesure ] = DrucReadNextCodeAsm ();
          TmpStructInstruction->MESURE     [ TmpIndexMesure ] = DrucReadNextCodeAsm ();
          TmpStructInstruction->OP_COMPARE [ TmpIndexMesure ] = DrucReadNextCodeAsm ();
          TmpStructInstruction->VALEUR     [ TmpIndexMesure ] = DrucReadNextCodeAsm ();
        }

        DrucComputeCtm ( TmpStructInstruction
                       );

        DrucStructInstruction             = TmpStructInstruction;
        DrucNombreInstructions ++;

        if ( DrucStructStat.FLAG_FLATTEN_MODE  == DRUC_HIERARCHIE 
           )
        {
          DrucDuplicateHierarchicalRule ( & DrucStructInstruction,
                                          & DrucNombreInstructions
                                        );
        }
        break;
      }
      case DRUC_ASM_END_REGLE :
      {
        break;
      }
      case DRUC_ASM_BEGIN_CHECKSUMM :
      {
        if ( fscanf( DrucFileAssembler, "%d", &TmpCheckSumm ) == EOF 
           )
        {
          DRUC_EXIT ( DRUC_ERROR_NO_CHECKSUM 
                    );
        }
        if (( TmpCheckSumm - DrucCheckSumm ) != 0 
           )
        {
          DRUC_EXIT ( DRUC_ERROR_CHECKSUMM 
                    );
        }
        FlagBegin = DRUC_TRUE;
        break;
      }
      default :
      {
        DRUC_EXIT ( DRUC_ERROR_FILE_PARAM );
      }
    } /* switch */
  }

  if ( DrucStructStat.FLAG_FLATTEN_MODE  == DRUC_HIERARCHIE 
     )
  {
    DrucAddHierarchicalRules ( & DrucStructInstruction,
                               & DrucNombreInstructions
                             );
  }

  **DrucTabInstruction =
      ( DrucTypeStructInstruction *)malloc
             (sizeof (  DrucTypeStructInstruction ) * DrucNombreInstructions );

  for ( IndexLayer  = DrucNombreInstructions - 1;
        IndexLayer >= 0;
        IndexLayer --
      )
  {
    (**DrucTabInstruction) [ IndexLayer ].NEXT        = (DrucTypeStructInstruction *)NULL;
    (**DrucTabInstruction) [ IndexLayer ].INSTRUCTION = DrucStructInstruction->INSTRUCTION;
    (**DrucTabInstruction) [ IndexLayer ].LAYER_DEST  = DrucStructInstruction->LAYER_DEST;
    (**DrucTabInstruction) [ IndexLayer ].OP_COMPOSE  = DrucStructInstruction->OP_COMPOSE;
    (**DrucTabInstruction) [ IndexLayer ].LAYER_1     = DrucStructInstruction->LAYER_1;
    (**DrucTabInstruction) [ IndexLayer ].LAYER_2     = DrucStructInstruction->LAYER_2;

    for ( TmpIndexMesure = 0;
          TmpIndexMesure < DRUC_MAX_MESURES;
          TmpIndexMesure ++
        )
    {
      (**DrucTabInstruction) [ IndexLayer ].REGLE_NUM  [ TmpIndexMesure ] =
                               DrucStructInstruction->REGLE_NUM [ TmpIndexMesure ] ;

      (**DrucTabInstruction) [ IndexLayer ].RELATION   [ TmpIndexMesure ] =
                               DrucStructInstruction->RELATION [ TmpIndexMesure ] ;

      (**DrucTabInstruction) [ IndexLayer ].MESURE     [ TmpIndexMesure ] =
                               DrucStructInstruction->MESURE [ TmpIndexMesure ] ;

      (**DrucTabInstruction) [ IndexLayer ].OP_COMPARE [ TmpIndexMesure ] =
                               DrucStructInstruction->OP_COMPARE [ TmpIndexMesure ] ;

      (**DrucTabInstruction) [ IndexLayer ].VALEUR     [ TmpIndexMesure ] =
                               DrucStructInstruction->VALEUR [ TmpIndexMesure ] ;
    }
    TmpStructInstruction  = DrucStructInstruction;
    DrucStructInstruction = DrucStructInstruction->NEXT;

    free ( TmpStructInstruction 
         );
  }

  for ( IndexLayer  = 0;
        IndexLayer  < DrucNombreInstructions -1;
        IndexLayer ++
      )
  {
    (**DrucTabInstruction)[ IndexLayer ].NEXT = (**DrucTabInstruction) +1;
  }
  return ( DrucNombreInstructions 
         );
}

/*------------------------------------------------------------\
|                                                             |
|                   DrucReadRulesComment                      |
|                                                             |
\------------------------------------------------------------*/

void DrucReadRulesComment (
                          )

{

long                       Rule;
DrucTypeStructRuleComment *Comment;
char                      *Flag;
char                      *TmpBuffer;

  while ( 1 
        )
  {
    Flag = fgets( DrucFileBuffer, DRUC_MAX_FILE_BUFFER, DrucFileAssembler );

    if ( Flag != (char *)NULL 
       )
    {
      if ( strstr( DrucFileBuffer, DRUC_DRC_END_COMMENT ) != (char *)NULL 
         )
      {
        return;
      }

      if (  sscanf ( DrucFileBuffer, "%d\n", &Rule ) == EOF
         )
      {
        DRUC_EXIT( DRUC_ERROR_BAD_COMMENT );
      }
      TmpBuffer = strchr ( DrucFileBuffer, ' '
                         );
      TmpBuffer ++;
      Comment = (DrucTypeStructRuleComment *)
                      rdsalloc( sizeof( DrucTypeStructRuleComment ), 
                      1
                );

      Comment->NEXT       = DrucRuleCommentList;
      DrucRuleCommentList = Comment;
      Comment->RULE       = Rule;
      Comment->COMMENT    = (char *)rdsalloc( strlen( DrucFileBuffer ) + 1, 0 );

      strcpy ( Comment->COMMENT, TmpBuffer
             );
    }
  }
}

/*------------------------------------------------------------\
|                                                             |
|                  DrucInitInstruction                        |
|                                                             |
| Ouvre le fichier contenant le code assembleur de DRUC       |
| Lit et charge le code dans la pile d'execution              |
| Initialise la structure DrucStructRdsLayer                  |
| Initialise la structure DrucStructDefine                    |
| Initialise la structure DrucStructRegle                     |
\------------------------------------------------------------*/

int DrucInitInstruction ( TmpFileName , 
                          DrucTabInstruction
                        )

DrucTypeStructInstruction **DrucTabInstruction;
char                       *TmpFileName;

{

int      IndexLayer;
int      DrucNombreInstructions;
boolean  FlagBegin;
char    *FlagBuffer;

  DrucCheckSumm         = DRUC_UNDEFINED_CHECKSUMM;

  DrucInitStructLayers (
                       );

  DrucFileAssembler = fopen ( TmpFileName ,
                              "r"
                            );

  if ( DrucFileAssembler == (FILE *)NULL 
     )
  {
    DRUC_EXIT ( DRUC_ERROR_NO_RULE_FILE 
              );
  }
  FlagBegin  = DRUC_FALSE;
  FlagBuffer = (char *)NULL;

  while ( FlagBegin != DRUC_TRUE 
        )
  {
    FlagBuffer = fgets ( DrucFileBuffer, 
                         DRUC_MAX_FILE_BUFFER, 
                         DrucFileAssembler 
                       );

    if ( FlagBuffer != (char *)NULL 
       )
    {
      if ( strstr ( DrucFileBuffer, DRUC_DRC_RULES ) != (char *)NULL 
         )
      {
        FlagBegin = DRUC_TRUE;
      }
    }
    else
    {
    DRUC_EXIT ( DRUC_ERROR_NO_RULE_IN_FILE 
              );
    }
  }
  
  DrucNombreInstructions = DrucReadAsm ( & DrucTabInstruction
                                       );
  FlagBegin  = DRUC_FALSE;
  FlagBuffer = (char *)NULL;

  while ( FlagBegin != DRUC_TRUE 
        )
  {
    FlagBuffer = fgets ( DrucFileBuffer, 
                         DRUC_MAX_FILE_BUFFER, 
                         DrucFileAssembler 
                       );

    if ( FlagBuffer != (char *)NULL 
       )
    {
      if ( strstr ( DrucFileBuffer, DRUC_DRC_COMMENT ) != (char *)NULL 
         )
      {
        FlagBegin = DRUC_TRUE;
      }
    }
    else
    {
      DRUC_EXIT ( DRUC_ERROR_COMMENT_FILE 
                );
    }
  }

  DrucReadRulesComment (
                       );
  fclose               ( DrucFileAssembler 
                       );
  return               ( DrucNombreInstructions 
                       );
}
