/*
 *
 *  (c) COPYRIGHT INRIA, Grif, 1996.
 *  Please first read the full copyright statement in file COPYRIGHT.
 *
 */

/*
 * Warning:
 * This module is part of the Thot library, which was originally
 * developed in French. That's why some comments are still in
 * French, but their translation is in progress and the full module
 * will be available in English in the next release.
 * 
 */

/*
 * Le programme GRM cree un fichier contenant la representation
 * codee d'une grammaire, a` partir d'un fichier contenant la   
 * description de cette grammaire sous la forme BNF.
 * La grammaire codee est destinee aux programmes STR, PRS, TRA ou APP
 * qui compilent, selon cette grammaire, un schema de structure,
 * de presentation, de traduction ou d'application.
 *
 * Author: V. Quint (INRIA)
 *
 */

#include "thot_sys.h"
#include "grmmsg.h"
#include "compilmsg.h"
#include "constgrm.h"
#include "constint.h"
#include "conststr.h"
#include "constprs.h"
#include "message.h"
#include "fileaccess.h"
#include "typegrm.h"
#include "typeint.h"
#include "fileaccess.h"
#include "thotdir.h"

typedef char        fname[30];	/* nom de fichier */

#undef THOT_EXPORT
#define THOT_EXPORT
#include "compil_tv.h"
#undef THOT_EXPORT
#define THOT_EXPORT extern
#include "analsynt_tv.h"

#include "compilmsg_f.h"
#include "fileaccess_f.h"

#define NBSTRING 200		/* nombre max de chaines dans une grammaire */
#define MAXNRULE 160		/* nombre max de regles de la grammaire */
#define MAXREF   50		/* nombre max de references a une regle */

#define MAX_STRING_GRM	200	/* nombre max de chaines dans une grammaire */
#define MAX_RULE_GRM	160	/* nombre max de regles de la grammaire */
#define MAX_RULE_REF	50	/* nombre max de references a une regle */

typedef struct _RefList
  {
     int                 NRuleRefs;	/* number of references in the list */
     int                 RuleRef[MAX_RULE_REF];		/* number of a referred list */
  }
RefList;

int                  LineNum;	/* compteur de lignes */
static RefList       identRef[MAX_IDENTIFIERS];	/* table des references des identificateurs */
static RefList       kwRef[MAX_STRING_GRM];	/* table des references des mots-cles */
static int           Nstrings;	/* longueur effective de la table */
static SrcIdentDesc  strng[MAX_STRING_GRM];	/* table des chaines */
static RefList       nameRef;	/* liste des references a 'NAME' */
static RefList       numberRef;	/* liste des references a 'NUMBER' */
static RefList       stringRef;	/* liste des references a 'STRING' */
static Name          fileName;	/* nom du fichier a compiler */

static int           shortKeywordCode;	/* code du dernier mot-cle court cree */
static int           KeywordCode;	/* code du dernier mot-cle long cree */
static int           NSyntRules;	/* longueur effective de la table */
static SyntacticRule SyntRule[MAX_RULE_GRM];	/* table des regles codees */
static int           curRule;	/* regle en cours de generation */
static int           curIndx;	/* position courante dans la regle courante */
static FILE         *listFile;	/* fichier des listes */

#include "parser_f.h"
#include "platform_f.h"
#include "message_f.h"

#ifdef __STDC__
extern void         TtaInitializeAppRegistry (char *);
extern void         TtaSaveAppRegistry (void);

#else
extern void         TtaInitializeAppRegistry ();
extern void         TtaSaveAppRegistry ();

#endif /* __STDC__ */

/*----------------------------------------------------------------------
   InitRefTables initialise les tables des references.		
  ----------------------------------------------------------------------*/
#ifdef __STDC__
static void         InitRefTables ()

#else  /* __STDC__ */
static void         InitRefTables ()
#endif				/* __STDC__ */

{
   int                 j;

   for (j = 0; j < MAX_IDENTIFIERS; j++)
      identRef[j].NRuleRefs = 0;
   for (j = 0; j < MAX_STRING_GRM; j++)
      kwRef[j].NRuleRefs = 0;
   nameRef.NRuleRefs = 0;
   numberRef.NRuleRefs = 0;
   stringRef.NRuleRefs = 0;
}


/*----------------------------------------------------------------------
   AddRefToTable ajoute le numero de la regle courante dans la     
   liste des references passee en parametre.               
  ----------------------------------------------------------------------*/

#ifdef __STDC__
static void         AddRefToTable (RefList * ref, indLine wi)

#else  /* __STDC__ */
static void         AddRefToTable (ref, wi)
RefList            *ref;
indLine             wi;

#endif /* __STDC__ */

{
   if (ref->NRuleRefs >= MAX_RULE_REF)
      CompilerMessage (wi, GRM, FATAL, NO_SPACE_LEFT_IN_REF_TABLL, inputLine, LineNum);
   else
      ref->RuleRef[ref->NRuleRefs++] = curRule;
}


/*----------------------------------------------------------------------
   PutToken	Put a token in the current rule.                
  ----------------------------------------------------------------------*/

#ifdef __STDC__
static void         PutToken (SyntacticCode code, indLine wi)

#else  /* __STDC__ */
static void         PutToken (code, wi)
SyntacticCode       code;
indLine             wi;

#endif /* __STDC__ */

{
   if (curIndx >= RULE_LENGTH)
      CompilerMessage (wi, GRM, FATAL, INVALID_RULE_SIZE, inputLine, LineNum);
   else
      SyntRule[curRule - 1][curIndx++] = code;
}


/*----------------------------------------------------------------------
   ProcessToken traite le mot commencant a` la position wi dans la 
   ligne courante, de longueur wl et code grammatical code,   
   apparaissant dans la regl r. Si c'est un identif, rank    
   contient son rang dans la table des identificateurs.    
  ----------------------------------------------------------------------*/

#ifdef __STDC__
static void         ProcessToken (indLine wi, indLine wl, SyntacticCode code, int r, int rank)

#else  /* __STDC__ */
static void         ProcessToken (wi, wl, code, r, rank)
indLine             wi;
indLine             wl;
SyntacticCode       code;
int                 r;
int                 rank;

#endif /* __STDC__ */

{
   int                 i;
   int                 j;
   boolean             known;

   if (code < 1099 && code > 1000)
      /* un caractere separateur */
      switch (code - 1000)
	    {
	       case 1:
		  curIndx = 1;	/* =  */
		  break;
	       case 2:
		  PutToken (2000, wi);	/* .  */
		  curIndx = 0;
		  break;
	       case 3:
		  PutToken (2003, wi);	/* /  */
		  break;
	       case 4:
		  PutToken (2001, wi);	/* [  */
		  break;
	       case 5:
		  PutToken (2002, wi);	/* ]  */
		  break;
	       case 6:
		  PutToken (2004, wi);	/* <  */
		  break;
	       case 7:
		  PutToken (2005, wi);	/* >  */
		  break;
	    }
   else if (code >= 1102 && code <= 1104)
      /* un type de base */
      switch (code)
	    {
	       case 1102:
		  /* NOM */
		  PutToken (3001, wi);
		  AddRefToTable (&nameRef, wi);
		  break;
	       case 1103:
		  /* STRING */
		  PutToken (3003, wi);
		  AddRefToTable (&stringRef, wi);
		  break;
	       case 1104:
		  /* NOMBRE */
		  PutToken (3002, wi);
		  AddRefToTable (&numberRef, wi);
		  break;
	    }
   else if (code == 3001)
      /* un symbole de la grammaire */
      if (curIndx == 0)
	 /* nouvelle regle */
	{
	   curRule = rank;
	   fprintf (listFile, "%5d", rank);
	   if (curRule > NSyntRules)
	      if (curRule <= MAX_RULE_GRM)
		 NSyntRules = curRule;
	      else
		 CompilerMessage (wi, GRM, FATAL, NO_SPACE_LEFT_IN_RULES_TABLE, inputLine, LineNum);
	   Identifier[rank - 1].SrcIdentDefRule = rank;
	}
      else
	{
	   /* la regle est en cours */
	   if (rank == curRule)
	      CompilerMessage (wi, GRM, FATAL, NO_SPACE_LEFT_IN_RULES_TABLE, inputLine, LineNum);
	   else
	      PutToken (rank, wi);
	   Identifier[rank - 1].SrcIdentRefRule = rank;
	   AddRefToTable (&identRef[rank - 1], wi);
	}
   else if (code == 3003)
      /* une chaine entre quotes */
     {
	i = 0;
	known = False;
	if (wl - 1 > IDENTIFIER_LENGTH)
	   CompilerMessage (wi, GRM, FATAL, INVALID_STRING_SIZE, inputLine, LineNum);
	/* est-elle deja dans la table ? */
	else
	  {
	     do
	       {
		  if (strng[i].SrcIdentLen == wl - 1)
		    {
		       j = 0;
		       do
			  j++;
		       while (inputLine[wi + j - 2] == strng[i].SrcIdentifier[j - 1] &&
			      j < wl - 1);
		       if (j == wl - 1)
			  if (inputLine[wi + j - 2] == strng[i].SrcIdentifier[j - 1])
			     known = True;
		    }
		  i++;
	       }
	     while (!known && i < Nstrings);
	     if (known)
		/* deja dans la table */
		AddRefToTable (&kwRef[i - 1], wi);
	     /* elle n'est pas dans la table, on la met */
	     else if (Nstrings >= MAX_STRING_GRM)
		CompilerMessage (wi, GRM, FATAL, NO_SPACE_LEFT_IN_STRING_TABLE, inputLine, LineNum);
	     else
	       {
		  strng[Nstrings].SrcIdentLen = wl - 1;
		  for (j = 0; j < wl - 1; j++)
		     strng[Nstrings].SrcIdentifier[j] = inputLine[wi + j - 1];
		  if (strng[Nstrings].SrcIdentLen == 1)
		     /* mot-cle court */
		    {
		       shortKeywordCode++;
		       strng[Nstrings].SrcIdentCode = shortKeywordCode;
		    }
		  else
		     /* mot-cle long */
		    {
		       KeywordCode++;
		       strng[Nstrings].SrcIdentCode = KeywordCode;
		    }
		  AddRefToTable (&kwRef[Nstrings], wi);
		  Nstrings++;
		  i = Nstrings;
	       }
	     if (!error)
		PutToken (strng[i - 1].SrcIdentCode, wi);
	  }
     }
}


/*----------------------------------------------------------------------
   InitGrammar initialise la table des mots-cles et la table des   
   regles.                                                 
  ----------------------------------------------------------------------*/

#ifdef __STDC__
static void         InitGrammar ()

#else  /* __STDC__ */
static void         InitGrammar ()
#endif				/* __STDC__ */

{
   Keywords[0].SrcKeywordLen = 1;
   Keywords[0].SrcKeyword[0] = '=';
   Keywords[0].SrcKeywordCode = 1001;
   Keywords[1].SrcKeywordLen = 1;
   Keywords[1].SrcKeyword[0] = '.';
   Keywords[1].SrcKeywordCode = 1002;
   Keywords[2].SrcKeywordLen = 1;
   Keywords[2].SrcKeyword[0] = '/';
   Keywords[2].SrcKeywordCode = 1003;
   Keywords[3].SrcKeywordLen = 1;
   Keywords[3].SrcKeyword[0] = '[';
   Keywords[3].SrcKeywordCode = 1004;
   Keywords[4].SrcKeywordLen = 1;
   Keywords[4].SrcKeyword[0] = ']';
   Keywords[4].SrcKeywordCode = 1005;
   Keywords[5].SrcKeywordLen = 1;
   Keywords[5].SrcKeyword[0] = '<';
   Keywords[5].SrcKeywordCode = 1006;
   Keywords[6].SrcKeywordLen = 1;
   Keywords[6].SrcKeyword[0] = '>';
   Keywords[6].SrcKeywordCode = 1007;
   LastShortKeyword = 7;
   strncpy (Keywords[7].SrcKeyword, "END", KEWWORD_LENGTH);
   Keywords[7].SrcKeywordLen = strlen (Keywords[7].SrcKeyword);
   Keywords[7].SrcKeywordCode = 1101;
   strncpy (Keywords[8].SrcKeyword, "NAME", KEWWORD_LENGTH);
   Keywords[8].SrcKeywordLen = strlen (Keywords[8].SrcKeyword);
   Keywords[8].SrcKeywordCode = 1102;
   strncpy (Keywords[9].SrcKeyword, "STRING", KEWWORD_LENGTH);
   Keywords[9].SrcKeywordLen = strlen (Keywords[9].SrcKeyword);
   Keywords[9].SrcKeywordCode = 1103;
   strncpy (Keywords[10].SrcKeyword, "NUMBER", KEWWORD_LENGTH);
   Keywords[10].SrcKeywordLen = strlen (Keywords[10].SrcKeyword);
   Keywords[10].SrcKeywordCode = 1104;
   NKeywords = 11;
   GramRule[0][1] = 2;
   GramRule[0][2] = 2004;
   GramRule[0][3] = 2;
   GramRule[0][4] = 2005;
   GramRule[0][5] = 1101;
   GramRule[0][6] = 2000;
   GramRule[1][1] = 3;
   GramRule[1][2] = 1001;
   GramRule[1][3] = 4;
   GramRule[1][4] = 1002;
   GramRule[1][5] = 2000;
   GramRule[2][1] = 3001;
   GramRule[2][2] = 2000;
   GramRule[3][1] = 5;
   GramRule[3][2] = 2003;
   GramRule[3][3] = 6;
   GramRule[3][4] = 2000;
   GramRule[4][1] = 1102;
   GramRule[4][2] = 2003;
   GramRule[4][3] = 1103;
   GramRule[4][4] = 2003;
   GramRule[4][5] = 1104;
   GramRule[4][6] = 2000;
   GramRule[5][1] = 7;
   GramRule[5][2] = 2004;
   GramRule[5][3] = 1003;
   GramRule[5][4] = 7;
   GramRule[5][5] = 2005;
   GramRule[5][6] = 2000;
   GramRule[6][1] = 8;
   GramRule[6][2] = 2004;
   GramRule[6][3] = 8;
   GramRule[6][4] = 2005;
   GramRule[6][5] = 2000;
   GramRule[7][1] = 9;
   GramRule[7][2] = 2003;
   GramRule[7][3] = 1004;
   GramRule[7][4] = 9;
   GramRule[7][5] = 2004;
   GramRule[7][6] = 9;
   GramRule[7][7] = 2005;
   GramRule[7][8] = 1005;
   GramRule[7][9] = 2003;
   GramRule[7][10] = 1006;
   GramRule[7][11] = 9;
   GramRule[7][12] = 2004;
   GramRule[7][13] = 9;
   GramRule[7][14] = 2005;
   GramRule[7][15] = 1007;
   GramRule[7][16] = 2000;
   GramRule[8][1] = 3;
   GramRule[8][2] = 2003;
   GramRule[8][3] = 10;
   GramRule[8][4] = 2000;
   GramRule[9][1] = 3003;
   GramRule[9][2] = 2000;
   NGramRules = 10;
}


/*----------------------------------------------------------------------
   WriteFiles ecrit les mots-cles et regles dans le fichier de     
   sortie de type .GRM, produit le fichier .LST et le      
   fichier .h                                              
  ----------------------------------------------------------------------*/

#ifdef __STDC__
static void         WriteFiles ()

#else  /* __STDC__ */
static void         WriteFiles ()
#endif				/* __STDC__ */

{
   int                 mc, l, r, i, j, ic;
   int                 lineLength;
   int                 maxIdent;
   FILE               *GRMfile;
   FILE               *Hfile;

   /* met le suffixe GRM a la fin du nom de fichier */
   lineLength = 0;
   while (fileName[lineLength] != '.')
      lineLength++;
   strcpy (&fileName[lineLength + 1], "GRM");
   /* cree le fichier .GRM */
   GRMfile = fopen (fileName, "w");

   /* cree le fichier .h */
   strcpy (&fileName[lineLength + 1], "h");
   Hfile = fopen (fileName, "w");
   if (Hfile == NULL)
     {
	TtaDisplayMessage (FATAL, TtaGetMessage (GRM, CANT_CREATE_HEADER_FILE), fileName);
	exit (1);
     }
   else
     {
	fileName[lineLength] = '\0';
	putc ('\f', listFile);
	fprintf (listFile, "\n\n*** SHORT KEY-WORDS ***\n\n");
	fprintf (listFile, "code  character  numbers of rules using the key-word\n\n");
	fprintf (Hfile, "/* Definitions for compiler of language %s */\n\n", fileName);
	fprintf (Hfile, "/*  SHORT KEY-WORDS  */\n\n");

	for (mc = 0; mc < Nstrings; mc++)
	  {
	     if (strng[mc].SrcIdentLen == 1)
	       {
		  fprintf (Hfile, "#define CHR_%d \t%4d\n",
		  (int) strng[mc].SrcIdentifier[0], strng[mc].SrcIdentCode);
		  fprintf (GRMfile, "%c %4d\n", strng[mc].SrcIdentifier[0], strng[mc].SrcIdentCode);
		  fprintf (listFile, "%4d      ", strng[mc].SrcIdentCode);
		  if (strng[mc].SrcIdentifier[0] < ' ')
		     fprintf (listFile, "\\%3d ", (int) strng[mc].SrcIdentifier[0]);
		  else
		     fprintf (listFile, "%c    ", strng[mc].SrcIdentifier[0]);
		  lineLength = 15;
		  for (j = 0; j < kwRef[mc].NRuleRefs; j++)
		    {
		       if (lineLength > 76)
			 {
			    fprintf (listFile, "\n");
			    fprintf (listFile, "               ");
			    lineLength = 15;
			 }
		       fprintf (listFile, " %3d", kwRef[mc].RuleRef[j]);
		       lineLength += 4;
		    }
		  fprintf (listFile, "\n");
	       }
	  }
	fprintf (GRMfile, "\n");
	fprintf (listFile, "\n\n\n*** LONG KEY-WORDS ***\n\n");
	fprintf (listFile, "code  key-word      numbers of rules using the key-word\n\n");
	fprintf (Hfile, "\n/*  LONG KEY-WORDS  */\n\n");

	/* cherche la longueur du plus long des mots-cles */
	maxIdent = 0;
	for (mc = 0; mc < Nstrings; mc++)
	   if (strng[mc].SrcIdentLen > maxIdent)
	      maxIdent = strng[mc].SrcIdentLen;
	/* ecrit les mots-cles et les regles qui les utilisent */
	for (mc = 0; mc < Nstrings; mc++)
	  {
	     if (strng[mc].SrcIdentLen > 1)
	       {
		  fprintf (Hfile, "#define KWD_%s \t%4d\n",
			   strng[mc].SrcIdentifier, strng[mc].SrcIdentCode);
		  fprintf (listFile, "%4d  ", strng[mc].SrcIdentCode);
		  for (l = 0; l < strng[mc].SrcIdentLen; l++)
		    {
		       putc (strng[mc].SrcIdentifier[l], GRMfile);
		       if (strng[mc].SrcIdentifier[l] < ' ')
			  fprintf (listFile, "*");
		       else
			  putc (strng[mc].SrcIdentifier[l], listFile);
		    }
		  for (j = strng[mc].SrcIdentLen + 1; j <= maxIdent; j++)
		     fprintf (listFile, " ");
		  lineLength = maxIdent + 6;
		  fprintf (GRMfile, " %4d\n", strng[mc].SrcIdentCode);
		  for (j = 0; j < kwRef[mc].NRuleRefs; j++)
		    {
		       if (lineLength > 76)
			 {
			    fprintf (listFile, "\n");
			    lineLength = maxIdent + 8;
			    for (l = 1; l <= lineLength; l++)
			       fprintf (listFile, " ");
			 }
		       fprintf (listFile, " %3d", kwRef[mc].RuleRef[j]);
		       lineLength += 4;
		    }
		  fprintf (listFile, "\n");
	       }
	  }
	fprintf (listFile, "\n\n\n*** TABLE OF RULES AND REFERENCES ***\n\n");

	fprintf (listFile, "The code is the code of the symbol and the code of the rule\n");
	fprintf (listFile, "where that symbol appears in the left part. For each symbole,\n");
	fprintf (listFile, "the rule numbers indicate the rules that use that symbol in\n");
	fprintf (listFile, "right part.\n\n");
	fprintf (listFile, " code  symbol        rule numbers\n\n");
	fprintf (Hfile, "\n/*  RULES  */\n\n");

	/* cherche la longueur du plus long des symboles */
	maxIdent = 0;
	for (ic = 0; ic < NIdentifiers; ic++)
	   if (Identifier[ic].SrcIdentLen > maxIdent)
	      maxIdent = Identifier[ic].SrcIdentLen;
	/* ecrit les symboles et leurs references */
	for (ic = 0; ic < NIdentifiers; ic++)
	  {
	     fprintf (Hfile, "#define RULE_%s \t%4d\n", Identifier[ic].SrcIdentifier, ic + 1);
	     fprintf (listFile, " %4d  ", ic + 1);
	     for (l = 0; l < Identifier[ic].SrcIdentLen; l++)
		if (Identifier[ic].SrcIdentifier[l] < ' ')
		   fprintf (listFile, "*");
		else
		   putc (Identifier[ic].SrcIdentifier[l], listFile);
	     for (j = Identifier[ic].SrcIdentLen; j < maxIdent; j++)
		fprintf (listFile, " ");
	     lineLength = maxIdent + 7;
	     for (j = 0; j < identRef[ic].NRuleRefs; j++)
	       {
		  if (lineLength > 76)
		    {
		       fprintf (listFile, "\n");
		       lineLength = maxIdent + 9;
		       for (l = 1; l <= lineLength; l++)
			  fprintf (listFile, " ");
		    }
		  fprintf (listFile, " %3d", identRef[ic].RuleRef[j]);
		  lineLength += 4;
	       }
	     fprintf (listFile, "\n");
	  }
	fflush (Hfile);
	fclose (Hfile);

	fprintf (listFile, "\n\n\n*** REFERENCES TO BASIC TYPES ***\n\n");
	fprintf (listFile, "Numbers of the rules using NAME\n");

	lineLength = 0;
	for (j = 0; j < nameRef.NRuleRefs; j++)
	  {
	     if (lineLength > 76)
	       {
		  fprintf (listFile, "\n");
		  lineLength = 0;
	       }
	     fprintf (listFile, " %3d", nameRef.RuleRef[j]);
	     lineLength += 4;
	  }
	fprintf (listFile, "\n\n");

	fprintf (listFile, "Numbers of the rules using NUMBER\n");

	lineLength = 0;
	for (j = 0; j < numberRef.NRuleRefs; j++)
	  {
	     if (lineLength > 76)
	       {
		  fprintf (listFile, "\n");
		  lineLength = 0;
	       }
	     fprintf (listFile, " %3d", numberRef.RuleRef[j]);
	     lineLength += 4;
	  }
	fprintf (listFile, "\n\n");

	fprintf (listFile, "Numbers of the rules using STRING\n");

	lineLength = 0;
	for (j = 0; j < stringRef.NRuleRefs; j++)
	  {
	     if (lineLength > 76)
	       {
		  fprintf (listFile, "\n");
		  lineLength = 0;
	       }
	     fprintf (listFile, " %3d", stringRef.RuleRef[j]);
	     lineLength += 4;
	  }
	fprintf (listFile, "\n");
	fprintf (GRMfile, "\n");
	lineLength = 0;		/* ligne courante vide */
	for (r = 0; r < NSyntRules; r++)
	   /* ecrit la table des regles */
	  {
	     fprintf (GRMfile, "%4d ", r + 1);
	     /* numero du symbole defini par la regle */
	     lineLength += 5;
	     /* ecrit le contenu de la regle */
	     i = 0;
	     do
	       {
		  i++;
		  fprintf (GRMfile, "%4d ", SyntRule[r][i]);
		  lineLength += 5;
		  if (lineLength > 79)
		    {
		       fprintf (GRMfile, "\n");
		       lineLength = 0;
		    }
	       }
	     while (SyntRule[r][i] != 2000);
	     /* 2000 = Fin de la regle */
	     if (lineLength > 0)
	       {
		  fprintf (GRMfile, "\n");
		  lineLength = 0;
	       }
	  }
     }
   fclose (GRMfile);
}

/*----------------------------------------------------------------------
   CheckKeyword teste si la chaine de longueur wl commencant a` la 
   position wi de la ligne courante est un mot-cle bien    
   forme'.                                                 
  ----------------------------------------------------------------------*/

#ifdef __STDC__
static void         CheckKeyword (indLine wi, indLine wl)

#else  /* __STDC__ */
static void         CheckKeyword (wi, wl)
indLine             wi;
indLine             wl;

#endif /* __STDC__ */

{
   indLine             j;

   if (wl == 2)
     {
	/* mot-cle court */
	if ((inputLine[wi - 1] >= '!'
	     && inputLine[wi - 1] <= '/') || (inputLine[wi - 1] >= ':'
		   && inputLine[wi - 1] <= '@') || (inputLine[wi - 1] >= '['
						    && inputLine[wi - 1] <= '`') || inputLine[wi - 1] == '|' || inputLine[wi - 1] == '~')
	  {
	     if (inputLine[wi - 1] == '\'')
		CompilerMessage (wi, GRM, FATAL, BAD_KEYWORD, inputLine, LineNum);
	  }
	else
	   CompilerMessage (wi, GRM, FATAL, BAD_KEYWORD, inputLine, LineNum);
     }
   else
     {
	/* mot-cle long */
	if ((inputLine[wi - 1] >= 'A'
	     && inputLine[wi - 1] <= 'Z') || (inputLine[wi - 1] >= 'a'
	     && inputLine[wi - 1] <= 'z') || (((int) inputLine[wi - 1]) >= 1
					      && inputLine[wi - 1] < ' '))
	   /* le premier caractere est une lettre */
	  {
	     j = wi;
	     do
	       {
		  if (!((inputLine[j] >= 'A'
			 && inputLine[j] <= 'Z') || (inputLine[j] >= 'a'
			     && inputLine[j] <= 'z') || (inputLine[j] >= '0'
		  && inputLine[j] <= '9') || (((int) inputLine[wi - 1]) >= 1
					      && inputLine[wi - 1] < ' ')))
		     CompilerMessage (wi, GRM, FATAL, BAD_KEYWORD, inputLine, LineNum);
		  j++;
	       }
	     while (!error && j < wi + wl - 2);
	  }
	else
	   CompilerMessage (wi, GRM, FATAL, BAD_KEYWORD, inputLine, LineNum);
     }
}


/*----------------------------------------------------------------------
   CheckDefAndRef verifie que tous les symboles intermediaires     
   sont bien definis et reference's.                       
  ----------------------------------------------------------------------*/

#ifdef __STDC__
static boolean      CheckDefAndRef ()

#else  /* __STDC__ */
static boolean      CheckDefAndRef ()
#endif				/* __STDC__ */

{
   int                 ic;
   boolean             ok;

   ok = True;
   for (ic = 0; ic < NIdentifiers; ic++)
     {
	if (Identifier[ic].SrcIdentDefRule == 0)
	  {
	     TtaDisplayMessage (FATAL, TtaGetMessage (GRM, UNDEFINED_SYMBOL), Identifier[ic].SrcIdentifier);
	     ok = False;
	  }
	if (Identifier[ic].SrcIdentRefRule == 0)
	   if (ic > 0)
	     {
		TtaDisplayMessage (FATAL, TtaGetMessage (GRM, UNREFERENCED_SYMBOL), Identifier[ic].SrcIdentifier);
		ok = False;
	     }
     }
   return ok;
}


/*----------------------------------------------------------------------
   main program                                                    
  ----------------------------------------------------------------------*/

#ifdef __STDC__
int                 main (int argc, char **argv)

#else  /* __STDC__ */
int                 main (argc, argv)
int                 argc;
char              **argv;

#endif /* __STDC__ */

{
   FILE               *infile;
   boolean             fileOK;
   lineBuffer          sourceLine;	/* ligne source non traduite */
   indLine             i;	/* position courante dans la ligne en cours */
   indLine             wi;	/* position du debut du mot courant dans la ligne */
   indLine             wl;	/* longueur du mot courant */
   SyntacticType       wn;	/* SyntacticType du mot courant */
   SyntRuleNum         r;	/* numero de regle */
   SyntRuleNum         pr;	/* numero de la regle precedente */
   SyntacticCode       code;	/* code grammatical du mot trouve */
   int                 rank;	/* indice dans Identifier du mot trouve, si

				   identificateur */

   TtaInitializeAppRegistry (argv[0]);
   GRM = TtaGetMessageTable ("grmdialogue", GRM_MSG_MAX);
   COMPIL = TtaGetMessageTable ("compildialogue", COMP_MSG_MAX);

   if (argc != 2)
      TtaDisplaySimpleMessage (FATAL, GRM, UNKNOWN_FILE);
   else
     {
	strncpy (fileName, argv[1], MAX_NAME_LENGTH - 1);
	i = strlen (fileName);
	/* ajoute le suffixe .LAN */
	strcat (fileName, ".LAN");

	if (TtaFileExist (fileName) == 0)
	   TtaDisplaySimpleMessage (FATAL, GRM, UNKNOWN_FILE);
	else
	   /* le fichier d'entree existe, on l'ouvre */
	  {
	     infile = fopen (fileName, "r");
	     error = False;
	     InitGrammar ();
	     NIdentifiers = 0;	/* table des identificateurs vide */
	     Nstrings = 0;	/* table des chaines vide */
	     NSyntRules = 0;	/* table des  regles vide */
	     curIndx = 0;
	     LineNum = 0;
	     shortKeywordCode = 1000;
	     KeywordCode = 1100;
	     InitRefTables ();	/* initialise la table des references */
	     InitParser ();	/* initialise l'analyseur syntaxique */
	     /* met le suffixe LST a la fin du nom de fichier */
	     strcpy (&fileName[i + 1], "LST");
	     /* cree le fichier .LST */
	     listFile = fopen (fileName, "w");
	     fprintf (listFile, "GRAMMAR OF FILE ");
	     i = 0;
	     while (fileName[i] != '.')
		putc (fileName[i++], listFile);
	     fprintf (listFile, ".LAN\n\n\n");
	     fprintf (listFile, " rule\n");
	     fprintf (listFile, "number\n");

	     fprintf (listFile, "\n");
	     /* lit tout le fichier et fait l'analyse */
	     fileOK = True;
	     while (fileOK && !error)
		/* lit une ligne */
	       {
		  i = 0;
		  do
		     fileOK = TtaReadByte (infile, &inputLine[i++]);
		  while (i < LINE_LENGTH && inputLine[i - 1] != '\n' && fileOK);
		  /* marque la fin reelle de la ligne */
		  inputLine[i - 1] = '\0';
		  /* garde une copie de la ligne avant traduction */
		  strncpy ((char *) sourceLine, (char *) inputLine, LINE_LENGTH);
		  LineNum++;
		  /* traduit les caracteres de la ligne */
		  OctalToChar ();
		  /* analyse la ligne */
		  wi = 1;
		  wl = 0;
		  /* analyse tous les mots de la ligne courante */
		  do
		    {
		       i = wi + wl;
		       GetNextToken (i, &wi, &wl, &wn);		/* mot suivant */
		       if (wi > 0)
			 {
			    /* on a trouve un mot */
			    if (wn == SynString)
			       CheckKeyword (wi, wl);	/* mot-cle valide ? */
			    if (!error)
			       AnalyzeToken (wi, wl, wn, &code, &r, &rank, &pr);	/* on analyse le mot */
			    if (!error)
			       ProcessToken (wi, wl, code, r, rank);	/* on le traite */
			 }
		    }
		  while (wi != 0 && !error);
		  /* il n'y a plus de mots dans la ligne */
		  /* ecrit la ligne source dans le fichier .LST */
		  putc ('\t', listFile);
		  wi = 0;
		  while (sourceLine[wi] != '\0')
		     putc (sourceLine[wi++], listFile);
		  fprintf (listFile, "\n");
	       }
	     if (!error)
		ParserEnd ();	/* fin d'analyse */
	     if (!error)
		if (CheckDefAndRef ())
		  {
		     TtaDisplaySimpleMessage (INFO, GRM, NEW_GRAMMAR_FILE);
		     WriteFiles ();	/* ecrit les tables dans le fichier */
		  }
	     fclose (infile);
	     fclose (listFile);
	     TtaSaveAppRegistry ();
	  }
     }
   exit (0);
}
