/*
 *
 *  (c) COPYRIGHT INRIA, 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.
 * 
 */

/*
 * Compiler of language A.
 *
 * Author: I. Vatton (INRIA)
 *
 */

#include "thot_sys.h"
#include "compilmsg.h"
#include "appmsg.h"
#include "message.h"
#include "appdef.h"
#include "constgrm.h"
#include "constmedia.h"
#include "typemedia.h"
#include "typegrm.h"
#include "fileaccess.h"
#include "app.h"
#include "modif.h"
#include "menuaction.h"
#include "registry.h"
#include "fileaccess.h"
#include "thotdir.h"

#include "parser_f.h"
#include "compilmsg_f.h"
#include "callbackinit_f.h"
#include "platform_f.h"
#include "memory_f.h"
#include "message_f.h"
#include "readstr_f.h"
#include "fileaccess_f.h"
#include "writeapp_f.h"

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

THOT_EXPORT int          LineNum;
THOT_EXPORT PtrEventsSet pAppli;
THOT_EXPORT PtrSSchema   pSSchema;
extern int          IncNbIdent;

int                 LineNum;	/* lines counter in source file */
static Name         fileName;
PtrSSchema          pSSchema;
PtrEventsSet        pAppli;
/* Pointer to the list of application schemas linked with EDITOR.A */
PtrAppName          SchemasUsed = NULL;
/* Pointer to the list of menu names effectively used */
PtrAppName          MenusUsed = NULL;
/* Pointer to the list of item names effectively used */
PtrAppName          ItemsUsed = NULL;
/* Pointer to the list of action names effectively used */
PtrAppName          ActionsUsed = NULL;
/* Pointer to the list of menus displayed in the main application frame */
PtrAppMenu          MainWindowMenus = NULL;
/* Pointer to the list of menus displayed in standard document frames */
PtrAppMenu          DocWindowMenus = NULL;
/* Pointer to the list of menus displayed in specific document frames */
PtrAppDocType       DocTypeMenus = NULL;

static boolean      FirstInPair = False;/* keyword "First" found             */
static boolean      SecondInPair = False;/* keyword "Second" found           */
static int          typeNum;
static int          attrNum;
static int          curEvent;		/* the current event                 */
static char        *eventAction;	/* the action linked with the event  */
static boolean      PreEvent;
static boolean      DefaultSection;	/* within the section DEFAULT        */
static boolean      ElementsSection;	/* within the section ELEMENTS       */
static boolean      AttributesSection;	/* within the section ATTRIBUTES     */
static boolean      MenusSection;	/* within the section MENUS          */
static PtrAppMenu  *MenuList;
static int          ViewNumber;
static char         MenuName[100];
static char         SubmenuName[100];
static char         ItemName[100];
static char         ItemType;		/* 'B' = Button,    'T' = Toggle,    */

				     	/* 'S' = Separator, 'D' = Dynamic.   */
static char         ActionName[100];

/* the list RegisteredAppEvents have to be conform to the type enum APPevent
   defined into appaction.h */
char               *RegisteredAppEvents[] =
{
   "AttrMenu",
   "AttrCreate",
   "AttrModify",
   "AttrRead",
   "AttrSave",
   "AttrExport",
   "AttrDelete",
   "ElemMenu",
   "ElemNew",
   "ElemRead",
   "ElemSave",
   "ElemExport",
   "ElemDelete",
   "ElemSelect",
   "ElemExtendSelect",
   "ElemActivate",
   "ElemSetReference",
   "ElemInclude",
   "ElemFetchInclude",
   "ElemCopy",
   "ElemPaste",
   "ElemChange",
   "ElemMove",
   "ElemTextModify",
   "ElemGraphModify",
   "ElemTransform",
   "ElemMouseOver",
   "ElemMouseOut",
   "PRuleCreate",
   "PRuleModify",
   "PRuleDelete",
   "DocOpen",
   "DocTmpOpen",
   "DocCreate",
   "DocClose",
   "DocSave",
   "DocExport",
   "DocNatPresent",
   "ViewOpen",
   "ViewClose",
   "ViewResize",
   "ViewScroll",
   "Init",
   "Exit"
};

/*----------------------------------------------------------------------
   MenuActionList adds into the list ActionsUsed actions        
   used by the new set of menus pointed by firstMenu.   
   If actions already exist in the list, they are not added.
   In the same way this function adds menu names used in the set into the
   list MenusUsed and item names into the list ItemsUsed.
  ----------------------------------------------------------------------*/
#ifdef __STDC__
static void         MenuActionList (PtrAppMenu firstMenu)

#else  /* __STDC__ */
static void         MenuActionList (firstMenu)
PtrAppMenu          firstMenu;

#endif /* __STDC__ */

{
   PtrAppName          curAction, prevAction;
   PtrAppName          curMenu, prevMenu;
   PtrAppName          curItem, prevItem;
   PtrAppMenu          menu;
   PtrAppMenuItem      item, menuitem;
   boolean             found;

   menu = firstMenu;
   /* check the new set of menus */
   while (menu != NULL)
     {
	/* look at if the menu name is already in the list MenusUsed */
	curMenu = MenusUsed;
	found = False;
	prevMenu = NULL;
	while (!found && curMenu != NULL)
	  {
	     if (curMenu->AppNameValue != NULL &&
		 strcmp (curMenu->AppNameValue, menu->AppMenuName) == 0)
		/* the menu name is already in the list */
		found = True;
	     else
	       {
		  prevMenu = curMenu;
		  /* next menu name in the list MenusUsed */
		  curMenu = curMenu->AppNextName;
	       }
	  }
	if (!found)
	   /* the menu name is a new name, add it into the list */
	  {
	     curMenu = (PtrAppName) TtaGetMemory (sizeof (AppName));
	     if (menu->AppMenuName == NULL)
		curMenu->AppNameValue = NULL;
	     else
		curMenu->AppNameValue = TtaStrdup (menu->AppMenuName);
	     curMenu->AppNextName = NULL;
	     if (prevMenu == NULL)
		MenusUsed = curMenu;
	     else
		prevMenu->AppNextName = curMenu;
	  }

	/* check the list of item names of the new menu and its submenus */
	item = menu->AppMenuItems;
	menuitem = NULL;
	while (item != NULL)
	  {
	     /* skip menu separators */
	     if (item->AppItemType != 'S')
	       {
		  /* look at if the item name is already in the list ItemsUsed */
		  curItem = ItemsUsed;
		  found = False;
		  prevItem = NULL;
		  while (!found && curItem != NULL)
		    {
		       if (curItem->AppNameValue != NULL && item->AppItemName != NULL &&
			   strcmp (curItem->AppNameValue, item->AppItemName) == 0)
			  /* the item name is already in the list */
			  found = True;
		       else
			 {
			    prevItem = curItem;
			    /* passe au nom suivant de la liste */
			    curItem = curItem->AppNextName;
			 }
		    }
		  if (!found)
		     /* le nom de l'item n'est pas in the list, on l'y met */
		    {
		       curItem = (PtrAppName) TtaGetMemory (sizeof (AppName));
		       curItem->AppNameValue = TtaStrdup (item->AppItemName);
		       curItem->AppNextName = NULL;
		       if (prevItem == NULL)
			  ItemsUsed = curItem;
		       else
			  prevItem->AppNextName = curItem;
		    }
	       }
	     if (item->AppItemActionName != NULL)
		/* cet item a une action definie */
	       {
		  /* cherche si l'action de l'item est in the list des actions */
		  curAction = ActionsUsed;
		  found = False;
		  prevAction = NULL;
		  while (!found && curAction != NULL)
		    {
		       if (curAction->AppNameValue != NULL &&
			   strcmp (curAction->AppNameValue, item->AppItemActionName) == 0)
			  /* l'action de l'item est in the list */
			  found = True;
		       else
			 {
			    prevAction = curAction;
			    /* passe a l'action suivante de la liste */
			    curAction = curAction->AppNextName;
			 }
		    }
		  if (!found)
		     /* l'action de l'item n'est pas in the list, on l'y met */
		    {
		       curAction = (PtrAppName) TtaGetMemory (sizeof (AppName));
		       curAction->AppNameValue = TtaStrdup (item->AppItemActionName);
		       curAction->AppStandardName = item->AppStandardAction;
		       curAction->AppNextName = NULL;
		       if (prevAction == NULL)
			  ActionsUsed = curAction;
		       else
			  prevAction->AppNextName = curAction;
		    }
	       }

	     if (item->AppSubMenu != NULL)
	       {
		  /* initialise le traitement les items du sous-menu */
		  menuitem = item;
		  item = item->AppSubMenu;
	       }
	     else
	       {
		  /* passe a l'item suivant */
		  item = item->AppNextItem;
		  if (menuitem != NULL && item == NULL)
		    {
		       /* reprend le traitement les items du menu */
		       item = menuitem->AppNextItem;
		       menuitem = NULL;
		    }
	       }
	  }
	/* passe au menu suivant */
	menu = menu->AppNextMenu;
     }
}

/*----------------------------------------------------------------------
   MakeMenusAndActionList construit la liste des noms de toutes    
   les actions effectivement utiles, la liste de tous les noms de  
   menus effectivement utiles et de tous les noms d'item utiles.   
  ----------------------------------------------------------------------*/
static void         MakeMenusAndActionList ()
{
   PtrAppDocType       menusDoc;

   /* cherche les actions, les menus et les items de la fenetre principale */
   MenuActionList (MainWindowMenus);
   /* cherche les actions, les menus et les items des frames document
      normales */
   MenuActionList (DocWindowMenus);
   /* cherche les actions les menus et les items des frames document de type
      particulier */
   menusDoc = DocTypeMenus;
   while (menusDoc != NULL)
     {
	MenuActionList (menusDoc->AppDocTypeMenus);
	menusDoc = menusDoc->AppNextDocType;
     }
}

/*----------------------------------------------------------------------
   RegisteredEvent checks whether eventName is in the list of      
   registered events and returns True if yes, and the rank of the  
   event in the list (rank).                                       
  ----------------------------------------------------------------------*/
#ifdef __STDC__
static boolean      RegisteredEvent (char *eventName, int *rank)
#else  /* __STDC__ */
static boolean      RegisteredEvent (eventName, rank)
char               *eventName;
int                *rank;

#endif /* __STDC__ */
{
   int                 evtNum, evt;
   boolean             found;

   /* cherche le nom de l'evenement dans la table */
   evtNum = sizeof (RegisteredAppEvents) / sizeof (char *);

   found = False;
   for (evt = 0; evt < evtNum && !found; (evt)++)
      if (strcmp (eventName, RegisteredAppEvents[evt]) == 0)
	{
	   found = True;
	   *rank = evt;
	}
   return found;
}

/*----------------------------------------------------------------------
   ConstructAbstractSchStruct                                      
  ----------------------------------------------------------------------*/
static PtrSSchema   ConstructAbstractSchStruct ()
{
   PtrSSchema          pSS;

   pSS = (PtrSSchema) TtaGetMemory (sizeof (StructSchema));
   memset (pSS, 0, sizeof (StructSchema));
   pSS->SsCode = 0;

   /* initialise les types de base */
   strcpy (pSS->SsRule[CharString].SrName, "TEXT_UNIT");
   strcpy (pSS->SsRule[GraphicElem].SrName, "GRAPHICS_UNIT");
   strcpy (pSS->SsRule[Symbol].SrName, "SYMBOL_UNIT");
   strcpy (pSS->SsRule[Picture].SrName, "PICTURE_UNIT");
   strcpy (pSS->SsRule[Refer].SrName, "REFERENCE_UNIT");
   strcpy (pSS->SsRule[PageBreak].SrName, "PAGE_BREAK");
   pSS->SsNRules = MAX_BASIC_TYPE - 1;
   pSS->SsNAttributes = 0;
   return pSS;
}

/*----------------------------------------------------------------------
   NewMenuComplete                                                 
  ----------------------------------------------------------------------*/
static void         NewMenuComplete ()
{
   PtrAppMenu          Menu, NewMenu, CurMenu;
   PtrAppMenuItem      Item, NewItem, SubMenu;
   boolean             found;

   /* les variables MenuList, MenuName, SubmenuName, ItemName, ItemType */
   /* et ActionName sont a jour. */

   /* On cherche d'abord le menu */
   if (MenuList != NULL)
      CurMenu = *MenuList;
   else
      CurMenu = NULL;
   Menu = NULL;
   while (Menu == NULL && CurMenu != NULL)
      if (CurMenu->AppMenuName != NULL &&
	  strcmp (MenuName, CurMenu->AppMenuName) == 0)
	 Menu = CurMenu;
      else
	 CurMenu = CurMenu->AppNextMenu;

   if (Menu == NULL)
      /* creation d'un nouveau menu */
     {
	NewMenu = (PtrAppMenu) TtaGetMemory (sizeof (AppMenu));
	NewMenu->AppMenuName = TtaStrdup (MenuName);
	NewMenu->AppMenuView = ViewNumber;	/* la vue concenee */
	NewMenu->AppMenuItems = NULL;
	NewMenu->AppNextMenu = NULL;
	if (*MenuList == NULL)
	   /* il n'y a pas encore de menus in the list */
	   *MenuList = NewMenu;
	else
	  {
	     /* ajoute le nouveau menu en fin de la liste des menus */
	     Menu = *MenuList;
	     while (Menu->AppNextMenu != NULL)
		Menu = Menu->AppNextMenu;
	     Menu->AppNextMenu = NewMenu;
	  }
	Menu = NewMenu;
     }

   SubMenu = NULL;
   Item = NULL;
   if (SubmenuName[0] != '\0')
      /* il y a un sous-menu. On cherche son entree dans le menu */
     {
	found = False;
	Item = Menu->AppMenuItems;
	while (Item != NULL && !found)
	   if (Item->AppItemName != NULL &&
	       strcmp (Item->AppItemName, SubmenuName) == 0)
	      found = True;
	   else
	      Item = Item->AppNextItem;
	if (!found)
	   /* cet item n'existe pas, on le met */
	  {
	     /* cree un nouvel item  */
	     NewItem = (PtrAppMenuItem) TtaGetMemory (sizeof (AppMenuItem));
	     NewItem->AppItemName = TtaStrdup (SubmenuName);
	     NewItem->AppItemActionName = NULL;
	     NewItem->AppSubMenu = NULL;
	     NewItem->AppItemType = ' ';
	     NewItem->AppStandardAction = False;
	     NewItem->AppNextItem = NULL;
	     /* chaine le nouvel item en fin de liste d'items du menu */
	     if (Menu->AppMenuItems == NULL)
		Menu->AppMenuItems = NewItem;
	     else
	       {
		  /* cherche le dernier item du menu */
		  Item = Menu->AppMenuItems;
		  while (Item->AppNextItem != NULL)
		     Item = Item->AppNextItem;
		  Item->AppNextItem = NewItem;
	       }
	     Item = NewItem;
	  }
	SubMenu = Item;
     }

   if (ItemName[0] != '\0' || ItemType == 'S')
     {
	if (SubMenu != NULL)
	   Item = SubMenu->AppSubMenu;
	else
	   Item = Menu->AppMenuItems;
	/* Cherche si cet item est deja dans le menu, sauf si c'est un */
	/* separateur: on peut avoir plusieurs separateurs dans le meme menu */
	found = False;
	if (ItemType != 'S')
	   while (Item != NULL && !found)
	      if (Item->AppItemName != NULL &&
		  strcmp (Item->AppItemName, ItemName) == 0)
		 found = True;
	      else
		 Item = Item->AppNextItem;
	if (found)
	   CompilerMessage (1, APP, FATAL, APP_ITEM_ALREADY_EXISTS, inputLine,
			  LineNum);
	else
	   /* cet item n'existe pas, on le met */
	  {
	     /* cree un nouvel item  */
	     NewItem = (PtrAppMenuItem) TtaGetMemory (sizeof (AppMenuItem));
	     if (ItemName[0] == '\0')
		NewItem->AppItemName = NULL;
	     else
		NewItem->AppItemName = TtaStrdup (ItemName);
	     NewItem->AppItemActionName = NULL;
	     NewItem->AppSubMenu = NULL;
	     NewItem->AppItemType = ItemType;
	     NewItem->AppStandardAction = False;
	     NewItem->AppNextItem = NULL;
	     if (SubMenu == NULL)
		/* chaine le nouvel item en fin de liste d'items du menu */
		if (Menu->AppMenuItems == NULL)
		   Menu->AppMenuItems = NewItem;
		else
		  {
		     /* cherche le dernier item du menu */
		     Item = Menu->AppMenuItems;
		     while (Item->AppNextItem != NULL)
			Item = Item->AppNextItem;
		     Item->AppNextItem = NewItem;
		  }
	     else
		/* chaine le nouvel item en fin de liste */
	     if (SubMenu->AppSubMenu == NULL)
		SubMenu->AppSubMenu = NewItem;
	     else
	       {
		  Item = SubMenu->AppSubMenu;
		  while (Item->AppNextItem != NULL)
		     Item = Item->AppNextItem;
		  Item->AppNextItem = NewItem;
	       }
	     /* on met l'action, sauf si c'est un separateur ou un */
	     /* sous-menu dynamique */
	     if (ActionName[0] != '\0')
	       {
		  NewItem->AppItemActionName = TtaStrdup (ActionName);
		  /* Il faut tester s'il s'agit d'une action standard */
		  NewItem->AppStandardAction = (strncmp (ActionName, "Ttc", 3) == 0);
	       }
	  }
     }
}


/*----------------------------------------------------------------------
   InitMenu                                                        
  ----------------------------------------------------------------------*/
static void         InitMenu ()
{
   ViewNumber = 0;
   MenuName[0] = '\0';
   SubmenuName[0] = '\0';
   ItemName[0] = '\0';
   ItemType = ' ';
   ActionName[0] = '\0';
}


/*----------------------------------------------------------------------
   ProcessShortKeyWord traite un mot-cle court.                    
  ----------------------------------------------------------------------*/
#ifdef __STDC__
static void         ProcessShortKeyWord (int x, SyntacticCode r, SyntacticCode pr)

#else  /* __STDC__ */
static void         ProcessShortKeyWord (x, r, pr)
int                 x;
SyntacticCode       r;
SyntacticCode       pr;

#endif /* __STDC__ */
{
   int                 typeId;

   switch (x)
	 {
	       /* traitement selon le code du mot-cle court */
	    case CHR_59:
	       /*  ;  */
	       switch (r)
		     {
			case RULE_EvtAction:
			   if (DefaultSection)
			      typeId = 0;
			   else if (ElementsSection)
			      typeId = typeNum;
			   else if (AttributesSection)
			      typeId = attrNum;
			   else
			      typeId = 0;
			   TteAddActionEvent (pAppli, typeId, curEvent, PreEvent, eventAction);
			   curEvent = 0;
			   PreEvent = True;
			   eventAction = NULL;
			   break;
			case RULE_NewMenu:
			   NewMenuComplete ();
			   InitMenu ();
			   break;
			default:
			   break;
		     }
	       break;
	    case CHR_44:
	       /*  ,  */
	       break;

	    case CHR_46:
	       /* .  */
	       break;

	    case CHR_58:
	       /* :  */
	       if (r == RULE_Menus)
		  InitMenu ();
	       break;

	    default:
	       break;
	 }
}


/*----------------------------------------------------------------------
   ProcessLongKeyWord traite un mot-cle long.                      
  ----------------------------------------------------------------------*/
#ifdef __STDC__
static void         ProcessLongKeyWord (int x, SyntacticCode r, indLine wi)

#else  /* __STDC__ */
static void         ProcessLongKeyWord (x, r, wi)
int                 x;
SyntacticCode       r;
indLine             wi;

#endif /* __STDC__ */

{
   switch (x)
	 {
	       /* traitement selon le code du mot-cle */
	    case KWD_APPLICATION:
	       /* initialisation */
	       DefaultSection = False;
	       ElementsSection = False;
	       AttributesSection = False;
	       MenusSection = False;
	       break;

	    case KWD_USES:
	       /* le mot-cle' USES */
	       if (strcmp (fileName, "EDITOR") != 0)
		  /* ce n'est pas EDITOR.A qu'on compile, refus */
		  CompilerMessage (wi, APP, FATAL, FORBIDDEN_OUTSIDE_EDITOR_I,
				 inputLine, LineNum);
	       else
		  SchemasUsed = NULL;
	       break;

	    case KWD_DEFAULT:
	       DefaultSection = True;
	       break;

	    case KWD_ELEMENTS:
	       ElementsSection = True;
	       DefaultSection = False;
	       break;

	    case KWD_ATTRIBUTES:
	       AttributesSection = True;
	       DefaultSection = False;
	       ElementsSection = False;
	       break;

	    case KWD_MENUS:
	       /* debut de la section MENUS */
	       DefaultSection = False;	/* la section DEFAULT est donc finie */
	       ElementsSection = False;
	       AttributesSection = False;
	       MenusSection = True;
	       if (strcmp (fileName, "EDITOR") != 0)
		  /* ce n'est pas EDITOR.A qu'on compile, refus */
		  CompilerMessage (wi, APP, FATAL, FORBIDDEN_OUTSIDE_EDITOR_I,
				 inputLine, LineNum);
	       break;

	    case KWD_BEGIN:
	       if (r == RULE_MenuList)
		  InitMenu ();
	       break;

	    case KWD_END:
	       break;

	    case KWD_Post:
	       if (curEvent == TteAttrMenu)
		  CompilerMessage (wi, APP, FATAL, ONLY_IF_PRE_ALLOWED, inputLine,
				 LineNum);
	       PreEvent = False;
	       break;

	    case KWD_Pre:
	       PreEvent = True;
	       break;

	    case KWD_First:
	       FirstInPair = True;
	       break;

	    case KWD_Second:
	       SecondInPair = True;
	       break;

	    case KWD_Main:
	       MenuList = &MainWindowMenus;
	       break;

	    case KWD_Window:
	       break;

	    case KWD_Document:
	       MenuList = &DocWindowMenus;
	       break;

	    case KWD_Windows:
	       break;

	    case KWD_Separator:
	       ItemType = 'S';
	       ItemName[0] = '\0';
	       ActionName[0] = '\0';
	       break;

	    case KWD_Button:
	       ItemType = 'B';
	       break;

	    case KWD_Toggle:
	       ItemType = 'T';
	       break;

	    case KWD_Dynamic:
	       ItemType = 'D';
	       ActionName[0] = '\0';
	       break;

	    default:
	       break;
	 }
}

/*----------------------------------------------------------------------
   ProcessName processes a name.                                      
  ----------------------------------------------------------------------*/
#ifdef __STDC__
static void         ProcessName (SyntacticCode r, SyntacticCode pr, indLine wl, indLine wi)
#else  /* __STDC__ */
static void         ProcessName (r, pr, wl, wi)
SyntacticCode       r;
SyntacticCode       pr;
indLine             wl;
indLine             wi;

#endif /* __STDC__ */
{
   int                 i;
   Name                name;
   PtrAppDocType       docType, newDocType;
   PtrAppName          schUsed, newSchUsed;

   if (wl > MAX_NAME_LENGTH - 1)
      CompilerMessage (wi, COMPIL, FATAL, INVALID_WORD_SIZE, inputLine, LineNum);
   else
     {
	strncpy (name, &inputLine[wi - 1], wl);
	name[wl] = '\0';
     }
   switch (r)
	 {
	       /* r = numero de la regle ou apparait le nom */

	    case RULE_ElemIdent:
	       typeNum = 0;
	       if (pr == RULE_AppliModel)
		 {
		    if (strcmp (fileName, "EDITOR") == 0)
		      {
			 /* construct an abstract schemas structure */
			 pSSchema = ConstructAbstractSchStruct ();
			 /* acquiert un schema */
			 pAppli = TteNewEventsSet (pSSchema->SsCode, fileName);
			 /* Pointer to the list of schemas menus descriptors */
			 DocTypeMenus = NULL;
		      }
		    else
		      {
			 /* TypeName est ici le nom de la structure generique */
			 /* => on lit le schema de structure compile' */
			 pSSchema = (PtrSSchema) TtaGetMemory (sizeof (StructSchema));
			 if (!ReadStructureSchema (name, pSSchema))
			    CompilerMessage (wi, APP, FATAL, APP_STRUCT_SCHEM_NOT_FOUND,
					   inputLine, LineNum);
			 else if (strcmp (name, pSSchema->SsName) != 0)
			    CompilerMessage (wi, APP, FATAL,
					   UNMATCHING_STRUCT_SCHEME,
					   inputLine, LineNum);
			 else
			    /* acquiert un schema */
			    pAppli = TteNewEventsSet (pSSchema->SsCode, fileName);
		      }
		 }
	       else
		 {
		    /* is it an Element? */
		    if (pr == RULE_ElemActions)
		      {
			 i = 0;
			 while (strcmp (name, pSSchema->SsRule[i].SrName) != 0
				&& i < pSSchema->SsNRules)
			    i++;
			 if (i < pSSchema->SsNRules)
			   {
			      if (pSSchema->SsRule[i].SrConstruct == CsPairedElement)
				 /* c'est un element CsPairedElement */
				 if (!SecondInPair && !FirstInPair)
				    /* le nom du type n'etait pas precede' de First ou Second */
				    CompilerMessage (wi, APP, FATAL, MISSING_FIRST_SECOND,
						   inputLine, LineNum);
				 else
				   {
				      if (SecondInPair)
					 /* il s'agit du type suivant */
					 i++;
				   }
			      else
				 /* ce n'est pas un element CsPairedElement */
			      if (SecondInPair || FirstInPair)
				 /* le nom du type etait precede' de First ou Second */
				 CompilerMessage (wi, APP, FATAL, NOT_A_PAIR, inputLine,
						LineNum);
			      typeNum = i + 1;
			   }
			 else
			   {
			      if (strcmp (fileName, "EDITOR") == 0)
				{
				   strcpy (pSSchema->SsRule[i].SrName, name);
				   pSSchema->SsNRules++;
				   typeNum = i + 1;
				}
			      else
				 CompilerMessage (wi, APP, FATAL, UNKNOWN_TYPE_APP,
						inputLine, LineNum);
			   }
			 FirstInPair = False;
			 SecondInPair = False;
		      }
		 }
	       break;

	    case RULE_DocumentType:
	       if (pr == RULE_SchemaList)
		  /* un nom de type de document dans l'instruction USES */
		 {
		    /* acquiert un descripteur de schema A utilise' */
		    newSchUsed = (PtrAppName) TtaGetMemory (sizeof (AppName));
		    /* met le nom du schema A utilise' dans le descripteur */
		    newSchUsed->AppNameValue = TtaStrdup (name);
		    newSchUsed->AppStandardName = False;
		    /* chaine ce nouveau descripteur en fin de liste */
		    newSchUsed->AppNextName = NULL;
		    if (SchemasUsed == NULL)
		       /* la chaine etait vide */
		       SchemasUsed = newSchUsed;
		    else
		      {
			 schUsed = SchemasUsed;
			 while (schUsed->AppNextName != NULL)
			    schUsed = schUsed->AppNextName;
			 schUsed->AppNextName = newSchUsed;
		      }
		 }
	       else if (pr == RULE_Menus)
		  /* un type de document pour lequel on veut definir les boutons */
		  /* et menus des frames */
		 {
		    /* ajoute un type de document */
		    /* alloue un descripteur de type de document */
		    newDocType = (PtrAppDocType) TtaGetMemory (sizeof (AppDocType));
		    /* initialise ce descripteur */
		    newDocType->AppDocTypeName = TtaStrdup (name);
		    newDocType->AppDocTypeMenus = NULL;
		    newDocType->AppNextDocType = NULL;
		    if (DocTypeMenus == NULL)
		       DocTypeMenus = newDocType;
		    else
		      {
			 docType = DocTypeMenus;
			 while (docType->AppNextDocType != NULL)
			    docType = docType->AppNextDocType;
			 docType->AppNextDocType = newDocType;
		      }
		    newDocType->AppDocTypeMenus = NULL;
		    MenuList = &(newDocType->AppDocTypeMenus);
		 }
	       break;

	    case RULE_EvtIdent:
	       /* Le nom de l'evenement */
	       PreEvent = True;
	       /* cherche si l'evenement est dans la table des evenements definis */
	       if (!RegisteredEvent (name, &curEvent))
		  /* il n'y est pas, erreur */
		  CompilerMessage (wi, APP, FATAL, UNKNOWN_MESSAGE, inputLine, LineNum);
	       else if (!DefaultSection)
		 {
		    /* on n'est pas dans la section DEFAULT du schema A */
		    /* on n'accepte pas les evenements pour les documents, pour les */
		    /* vues, ni pour l'application */
		    if (curEvent >= TteDocOpen)
		       CompilerMessage (wi, APP, FATAL, NOT_IN_DEFAULT, inputLine,
				      LineNum);
		 }
	       else
		 {
		    if (curEvent >= TteInit)
		       /* c'est un evenement pour l'application */
		      {
			 if (strcmp (fileName, "EDITOR") != 0)
			    /* ce n'est pas EDITOR.A qu'on compile, refus */
			    CompilerMessage (wi, APP, FATAL, FORBIDDEN_OUTSIDE_EDITOR_I, inputLine,
					   LineNum);
		      }
		    else if (AttributesSection)
		      {
			 if (curEvent > TteAttrDelete)
			    CompilerMessage (wi, APP, FATAL, FORBIDDEN_FOR_AN_ATTR,
					   inputLine, LineNum);
		      }
		    else if (ElementsSection)
		      {
			 if (curEvent <= TteAttrDelete)
			    CompilerMessage (wi, APP, FATAL, FORBIDDEN_FOR_AN_ELEM,
					   inputLine, LineNum);
		      }
		 }
	       break;

	    case RULE_ActionIdent:
	       if (pr == RULE_ItemAction)
		  /* action associee a un item de menu */
		  strcpy (ActionName, name);
	       else if (pr == RULE_EvtAction)
		 {
		    /* action associee a un evenement */
		    eventAction = TtaStrdup (name);
		    TteAddAction (eventAction, 0);
		 }
	       break;

	    case RULE_AttrIdent:
	       attrNum = 0;
	       if (strcmp (fileName, "EDITOR") == 0 && pSSchema == NULL)
		 {
		    pSSchema = ConstructAbstractSchStruct ();
		    pAppli = TteNewEventsSet (pSSchema->SsCode, fileName);
		 }
	       if (pr == RULE_AttrActions)
		 {
		    i = 1;
		    while (strcmp (name, pSSchema->SsAttribute[i - 1].AttrOrigName) != 0
			   && i <= pSSchema->SsNAttributes)
		       i++;
		    if (i <= pSSchema->SsNAttributes)
		       attrNum = i;
		    else
		      {
			 if (strcmp (fileName, "EDITOR") == 0)
			   {
			      /* the file .A is a EDITOR.A */
			      strcpy (pSSchema->SsAttribute[i - 1].AttrOrigName, name);
			      pSSchema->SsNAttributes = pSSchema->SsNAttributes + 1;
			      attrNum = i;
			   }
			 else
			    CompilerMessage (wi, APP, FATAL, UNKNOWN_ATTR_APP, inputLine, LineNum);
		      }
		 }
	       break;

	    case RULE_MenuIdent:
	       /* un nom de menu */
	       strcpy (MenuName, name);
	       SubmenuName[0] = '\0';
	       ItemName[0] = '\0';
	       ItemType = ' ';
	       ActionName[0] = '\0';
	       break;

	    case RULE_SubmenuIdent:
	       /* un nom de sous-menu dans une definition de menu */
	       strcpy (SubmenuName, name);
	       break;

	    case RULE_ItemIdent:
	       /* un nom d'item de menu dans une definition de menu */
	       strcpy (ItemName, name);
	       break;

	    default:
	       break;
	 }
}

/*----------------------------------------------------------------------
   ProcessInteger genere un nombre.                                    
  ----------------------------------------------------------------------*/
#ifdef __STDC__
static void         ProcessInteger (SyntacticCode r, indLine wl, indLine wi)
#else  /* __STDC__ */
static void         ProcessInteger (r, wl, wi)
SyntacticCode       r;
indLine             wl;
indLine             wi;

#endif /* __STDC__ */
{
   int                 n;

   n = AsciiToInt (wi, wl);
   switch (r)
	 {
	       /* r = numero de la regle ou apparait le nombre */
	    case RULE_ViewNum:
	       ViewNumber = n;
	       break;
	    default:
	       break;
	 }
}


/*----------------------------------------------------------------------
   ProcessToken traite le mot commencant a` la position wi dans la 
   ligne courante, de longueur wl et de code grammatical c.
   Si c'est un identif. r est le numero de la regle dans   
   laquelle apparait ce mot, pr est le numero de la regle  
   precedente, celle qui a appele la regle r.              
  ----------------------------------------------------------------------*/
#ifdef __STDC__
static void         ProcessToken (indLine wi, indLine wl, SyntacticCode c, SyntacticCode r, SyntacticCode pr)
#else  /* __STDC__ */
static void         ProcessToken (wi, wl, c, r, pr)
indLine             wi;
indLine             wl;
SyntacticCode       c;
SyntacticCode       r;
SyntacticCode       pr;

#endif /* __STDC__ */
{
   if (c < 1000)
     {
	/* symbole intermediaire de la grammaire, erreur */
	CompilerMessage (wi, APP, FATAL, INTERMEDIATE_SYMBOL, inputLine,
		       LineNum);
     }
   else if (c < 1100)
      /* mot-cle court */
      ProcessShortKeyWord (c, r, pr);
   else if (c < 2000)
      /* mot-cle long */
      ProcessLongKeyWord (c, r, wi);
   else
      /* type de base */
      switch (c)
	    {
	       case 3001:
		  /* un nom */
		  ProcessName (r, pr, wl, wi);
		  break;
	       case 3002:
		  /* un nombre */
		  ProcessInteger (r, wl, wi);
		  break;
	    }
}


/*----------------------------------------------------------------------
   WriteChar write a single character.                            
  ----------------------------------------------------------------------*/

#ifdef __STDC__
static void         WriteChar (FILE * Hfile, unsigned char ch)

#else  /* __STDC__ */
static void         WriteChar (Hfile, ch)
FILE               *Hfile;
unsigned char       ch;

#endif /* __STDC__ */

{
   int                 code;

   if (ch < ' ' || ch > '~')
      /* non ASCII character. Replace it by an ASCII character or its octal code */
     {
	code = (int) ch;
	switch (code)
	      {
		 case 224:
		 case 225:
		 case 226:
		 case 227:
		 case 228:
		 case 229:
		    fprintf (Hfile, "a");
		    break;
		 case 230:
		    fprintf (Hfile, "ae");
		    break;
		 case 231:
		    fprintf (Hfile, "c");
		    break;
		 case 232:
		 case 233:
		 case 234:
		 case 235:
		    fprintf (Hfile, "e");
		    break;
		 case 236:
		 case 237:
		 case 238:
		 case 239:
		    fprintf (Hfile, "i");
		    break;
		 case 160:
		    fprintf (Hfile, "_");
		    break;
		 case 241:
		    fprintf (Hfile, "n");
		    break;
		 case 242:
		 case 243:
		 case 244:
		 case 245:
		 case 246:
		 case 248:
		    fprintf (Hfile, "o");
		    break;
		 case 247:
		    fprintf (Hfile, "oe");
		    break;
		 case 249:
		 case 250:
		 case 251:
		 case 252:
		    fprintf (Hfile, "u");
		    break;
		 case 253:
		    fprintf (Hfile, "y");
		    break;
		 default:
		    fprintf (Hfile, "_%o", code);
		    break;
	      }
     }
   else
      /* printable character. Write it as is */
      fprintf (Hfile, "%c", ch);
}

/*----------------------------------------------------------------------
   WriteName                                                       
  ----------------------------------------------------------------------*/

#ifdef __STDC__
static void         WriteName (FILE * Hfile, Name n)

#else  /* __STDC__ */
static void         WriteName (Hfile, n)
FILE               *Hfile;
Name                n;

#endif /* __STDC__ */

{
   int                 i;

   i = 0;
   while (n[i] != '\0')
     {
	WriteChar (Hfile, n[i]);
	i++;
     }
}

/*----------------------------------------------------------------------
   WriteRuleName                                                   
  ----------------------------------------------------------------------*/

#ifdef __STDC__
static void         WriteRuleName (FILE * Hfile, int r)

#else  /* __STDC__ */
static void         WriteRuleName (Hfile, r)
FILE               *Hfile;
int                 r;

#endif /* __STDC__ */

{
   if (pSSchema->SsRule[r].SrName[0] == '\0')
      fprintf (Hfile, "ID%d", r+1);
   else
      WriteName (Hfile, pSSchema->SsRule[r].SrName);
}

/*----------------------------------------------------------------------
   WriteAttribute                                                  
  ----------------------------------------------------------------------*/

#ifdef __STDC__
static void         WriteAttribute (FILE * Hfile, int a)

#else  /* __STDC__ */
static void         WriteAttribute (Hfile, a)
FILE               *Hfile;
int                 a;

#endif /* __STDC__ */

{
   int                 j;
   TtAttribute        *pAttr;

   pAttr = &pSSchema->SsAttribute[a];
   if (pAttr->AttrGlobal)
      return;			/* AttrGlobal means "attribute written" */
   fprintf (Hfile, "#define ");
   WriteName (Hfile, pSSchema->SsName);
   fprintf (Hfile, "_ATTR_");
   WriteName (Hfile, pAttr->AttrName);
   fprintf (Hfile, " %d\n", a + 1);
   if (pAttr->AttrType == AtEnumAttr)
      for (j = 0; j < pAttr->AttrNEnumValues; j++)
	{
	   fprintf (Hfile, "#define ");
	   WriteName (Hfile, pSSchema->SsName);
	   fprintf (Hfile, "_ATTR_");
	   WriteName (Hfile, pAttr->AttrName);
	   fprintf (Hfile, "_VAL_");
	   WriteName (Hfile, pAttr->AttrEnumValue[j]);
	   fprintf (Hfile, " %d\n", j + 1);
	}
   pAttr->AttrGlobal = True;
}

/*----------------------------------------------------------------------
   WriteBasicElements                                              
  ----------------------------------------------------------------------*/

#ifdef __STDC__
static void         WriteBasicElements (FILE * Hfile)

#else  /* __STDC__ */
static void         WriteBasicElements (Hfile)
FILE               *Hfile;

#endif /* __STDC__ */

{
   int                 r;

   fprintf (Hfile, "#define ");
   WriteName (Hfile, pSSchema->SsName);
   r = CharString;
   fprintf (Hfile, "_EL_");
   WriteRuleName (Hfile, r);
   fprintf (Hfile, " %d\n", r+1);

   fprintf (Hfile, "#define ");
   WriteName (Hfile, pSSchema->SsName);
   r = GraphicElem;
   fprintf (Hfile, "_EL_");
   WriteRuleName (Hfile, r);
   fprintf (Hfile, " %d\n", r+1);

   fprintf (Hfile, "#define ");
   WriteName (Hfile, pSSchema->SsName);
   r = Symbol;
   fprintf (Hfile, "_EL_");
   WriteRuleName (Hfile, r);
   fprintf (Hfile, " %d\n", r+1);

   fprintf (Hfile, "#define ");
   WriteName (Hfile, pSSchema->SsName);
   r = Picture;
   fprintf (Hfile, "_EL_");
   WriteRuleName (Hfile, r);
   fprintf (Hfile, " %d\n", r+1);

   fprintf (Hfile, "#define ");
   WriteName (Hfile, pSSchema->SsName);
   r = PageBreak;
   fprintf (Hfile, "_EL_");
   WriteRuleName (Hfile, r);
   fprintf (Hfile, " %d\n", r+1);
}

/*----------------------------------------------------------------------
   WriteRule                                                       
   si pExtensRule est non nul, il s'agit d'une regle d'extension  
  ----------------------------------------------------------------------*/

#ifdef __STDC__
static void         WriteRule (FILE * Hfile, int r, SRule * pExtensRule)

#else  /* __STDC__ */
static void         WriteRule (Hfile, r, pExtensRule)
FILE               *Hfile;
int                 r;
SRule              *pExtensRule;

#endif /* __STDC__ */

{
   int                 i;
   SRule              *pRule;

   if (pExtensRule != NULL)
      pRule = pExtensRule;
   else
      pRule = &pSSchema->SsRule[r];
   if (pRule->SrConstruct != CsNatureSchema &&
       !(pRule->SrConstruct == CsPairedElement && !pRule->SrFirstOfPair))
     {
	fprintf (Hfile, "#define ");
	WriteName (Hfile, pSSchema->SsName);
	if (pExtensRule == NULL)
	  {
	     fprintf (Hfile, "_EL_");
	     WriteRuleName (Hfile, r);
	  }
	else
	  {
	     fprintf (Hfile, "_EXT_");
	     if (pRule->SrName[0] == '\0')
		fprintf (Hfile, "Root");
	     else
		WriteName (Hfile, pRule->SrName);
	  }
	fprintf (Hfile, " %d\n", r+1);

	if (pRule->SrNLocalAttrs > 0)
	   for (i = 0; i < pRule->SrNLocalAttrs; i++)
	      WriteAttribute (Hfile, pRule->SrLocalAttr[i] - 1);
     }
}

/*----------------------------------------------------------------------
   WriteDefineFile                                                 
  ----------------------------------------------------------------------*/
#ifdef __STDC__
static void         WriteDefineFile (char *fname)

#else  /* __STDC__ */
static void         WriteDefineFile (fname)
char               *fname;

#endif /* __STDC__ */

{
   boolean             firstLocalAttribute;
   boolean             first;
   int                 firstRule;
   int                 i;
   int                 rule;
   SRule              *pRule;
   Name                HFileName;
   FILE               *Hfile;

   sprintf (HFileName, "%s.h", fname);
   Hfile = fopen (HFileName, "w");
   if (Hfile != NULL)
     {
        fprintf (Hfile, "/* File generated by app - do not edit! */\n");
        fprintf (Hfile, "/* #################################### */\n");
	fprintf (Hfile, "/* Types and attributes for the document type %s */\n", pSSchema->SsName);
	/* write global attributes */
	if (pSSchema->SsNAttributes > 0 && pSSchema->SsAttribute[0].AttrGlobal)
	   fprintf (Hfile, "\n/* Global attributes */\n");

	for (i = 0; i < pSSchema->SsNAttributes; i++)
	   if (pSSchema->SsAttribute[i].AttrGlobal)
	     {
		pSSchema->SsAttribute[i].AttrGlobal = False;
		/* tell WriteAttribute that it should write attribute values */
		WriteAttribute (Hfile, i);
		pSSchema->SsAttribute[i].AttrGlobal = True;
	     }
	/* write local attributes */
	firstLocalAttribute = True;
	for (i = 0; i < pSSchema->SsNAttributes; i++)
	   if (!pSSchema->SsAttribute[i].AttrGlobal)
	     {
		if (firstLocalAttribute)
		  {
		     fprintf (Hfile, "\n/* Local attributes */\n");
		     firstLocalAttribute = False;
		  }
		WriteAttribute (Hfile, i);
	     }
	/* write Thot basic types */
	fprintf (Hfile, "\n/* Basic elements */\n");
	WriteBasicElements (Hfile);

	/* write constants */
	rule = MAX_BASIC_TYPE;
	if (pSSchema->SsRule[rule].SrConstruct == CsConstant)
	  {
	     fprintf (Hfile, "\n/* Constants */\n");
	     while (pSSchema->SsRule[rule].SrConstruct == CsConstant)
		WriteRule (Hfile, rule++, NULL);
	  }
	firstRule = rule;
	/* write parameters */
	first = True;
	for (rule = firstRule; rule < pSSchema->SsNRules; rule++)
	   if (pSSchema->SsRule[rule].SrParamElem)
	     {
		if (first)
		  {
		     fprintf (Hfile, "\n/* Parameters */\n");
		     first = False;
		  }
		WriteRule (Hfile, rule, NULL);
	     }
	/* write rules */
	if (pSSchema->SsNRules >= firstRule)
	   fprintf (Hfile, "\n/* Elements */\n");
	for (rule = firstRule; rule < pSSchema->SsNRules; rule++)
	  {
	     pRule = &pSSchema->SsRule[rule];
	     /* skip parameters, associated elements, */
	     /* Extern and Included elements and units */
	     if (!pRule->SrParamElem &&
		 !pRule->SrAssocElem &&
		 !pRule->SrRefImportedDoc &&
		 !pRule->SrUnitElem)
		/* ignore lists added for associated elements */
		if (pRule->SrConstruct != CsList)
		   WriteRule (Hfile, rule, NULL);
		else if (!pSSchema->SsRule[pRule->SrListItem - 1].SrAssocElem)
		   WriteRule (Hfile, rule, NULL);
	  }
	/* write extension rules */
	if (pSSchema->SsExtension && pSSchema->SsNExtensRules > 0)
	  {
	     fprintf (Hfile, "\n/* Extension rules */\n");
	     for (rule = 0; rule < pSSchema->SsNExtensRules; rule++)
	       {
		  pRule = &pSSchema->SsExtensBlock->EbExtensRule[rule];
		  WriteRule (Hfile, rule, pRule);
	       }
	  }
	/* write associated elements */
	first = True;
	for (rule = firstRule; rule < pSSchema->SsNRules; rule++)
	   if (pSSchema->SsRule[rule].SrAssocElem)
	     {
		if (first)
		  {
		     fprintf (Hfile, "\n/* Associated elements */\n");
		     first = False;
		  }
		WriteRule (Hfile, rule, NULL);
	     }
	if (!first)
	   /* there is at least one associated element. Write LIST rules added */
	   /* for associated elements */
	  {
	     for (rule = firstRule; rule < pSSchema->SsNRules; rule++)
	       {
		  pRule = &pSSchema->SsRule[rule];
		  if (pRule->SrConstruct == CsList)
		     if (pSSchema->SsRule[pRule->SrListItem - 1].SrAssocElem)
			WriteRule (Hfile, rule, NULL);
	       }
	  }
	/* write exported elements */
	first = True;
	for (rule = firstRule; rule < pSSchema->SsNRules; rule++)
	   if (pSSchema->SsRule[rule].SrUnitElem)
	     {
		if (first)
		  {
		     fprintf (Hfile, "\n/* Units */\n");
		     first = False;
		  }
		WriteRule (Hfile, rule, NULL);
	     }

	first = True;
	for (rule = firstRule; rule < pSSchema->SsNRules; rule++)
	   if (pSSchema->SsRule[rule].SrConstruct == CsNatureSchema)
	     {
		if (first)
		  {
		     fprintf (Hfile, "\n/* Imported natures */\n");
		     first = False;
		  }
		fprintf (Hfile, "#define ");
		WriteName (Hfile, pSSchema->SsName);
		fprintf (Hfile, "_EL_");
		WriteRuleName (Hfile, rule);
		fprintf (Hfile, " %d\n", rule+1);
	     }
     }
}

/*----------------------------------------------------------------------
   Main pour le compilateur A.                                     
  ----------------------------------------------------------------------*/
#ifdef __STDC__
void                main (int argc, char **argv)
#else  /* __STDC__ */
void                main (argc, argv)
int                 argc;
char              **argv;

#endif /* __STDC__ */
{
   FILE               *filedesc;
   boolean             fileOK;
   char                buffer[200], cmd[800];
   char               *pwd, *ptr;
   Name                srceFileName;
   int                 i;
   int                 wi;	/* position du debut du mot courant dans la ligne */
   int                 wl;	/* longueur du mot courant */
   SyntacticType       wn;	/* SyntacticType du mot courant */
   SyntRuleNum         r;	/* numero de regle */
   SyntRuleNum         pr;	/* numero de la regle precedente */
   SyntacticCode       c;	/* code grammatical du mot trouve */
   int                 idNum;	/* indice dans Identifier du mot trouve, si */
   int                 nb;
   int                 param;

   TtaInitializeAppRegistry (argv[0]);
   /* no external action declared at that time */
   ActionList = NULL;
   APP = TtaGetMessageTable ("appdialogue", MSG_MAX_APP);
   COMPIL = TtaGetMessageTable ("compildialogue", COMP_MSG_MAX);
   error = False;
   /* initialize the parser */
   InitParser ();
   InitSyntax ("APP.GRM");
   if (!error)
     {
        /* prepare the cpp command */
	strcpy (cmd, "cpp ");
        param = 1;
	while (param < argc && argv[param][0] == '-')
	  {
	    /* keep cpp params */
	    strcat (cmd, argv[param]);
	    strcat (cmd, " ");
	    param++;
	  }
	/* keep the name of the schema to be compile */
	if (param >= argc)
	  {
	     TtaDisplaySimpleMessage (FATAL, APP, FILE_NOT_FOUND);
	     exit (1);
	  }
	else
	  {
	     /* get the name of the file to be compiled */
	     strncpy (srceFileName, argv[param], MAX_NAME_LENGTH - 1);
	     srceFileName[MAX_NAME_LENGTH - 1] = '\0';
	     param++;
	     strcpy (fileName, srceFileName);
	     /* check if the name contains a suffix */
	     ptr = strrchr(fileName, '.');
	     nb = strlen (srceFileName);
	     if (!ptr)
	       /* there is no suffix */
	       strcat (srceFileName, ".A");
	     else if (strcmp(ptr, ".A"))
	       {
		 /* it's not the valid suffix */
		 TtaDisplayMessage (FATAL, TtaGetMessage(APP, INVALID_FILE), srceFileName);
		 exit (1);
	       }
	     else
	       {
		 /* it's the valid suffix, cut the srcFileName here */
		 ptr[0] = '\0';
		 nb -= 2; /* length without the suffix */
	       }

	     /* add the suffix .SCH in srceFileName */
	     strcat (fileName, ".SCH");
	     
	     /* does the file to compile exist */
	     if (TtaFileExist (srceFileName) == 0)
	       TtaDisplaySimpleMessage (FATAL, APP, FILE_NOT_FOUND);
	     else
	       {
		 /* provide the real source file */
		 TtaFileUnlink (fileName);
		 pwd = TtaGetEnvString ("PWD");
		 i = strlen (cmd);
		 if (pwd != NULL)
		   sprintf (&cmd[i], "-I%s -C %s > %s", pwd, srceFileName, fileName);
		 else
		   sprintf (&cmd[i], "-C %s > %s", srceFileName, fileName);
		 i = system (cmd);
		 if (i == -1)
		   {
		     /* cpp is not available, copy directely the file */
		     TtaDisplaySimpleMessage (INFO, APP, APP_CPP_NOT_FOUND);
		     TtaFileCopy (srceFileName, fileName);
		   }

		 /* open the resulting file */
		 filedesc = TtaReadOpen (fileName);
		 /* ouvre le fichier a compiler */
		 if (filedesc == 0)
		   TtaDisplaySimpleMessage (FATAL, APP, FILE_NOT_FOUND);
		 else
		   {
		     /* suppress the suffix ".SCH" */
		     srceFileName[nb] = '\0';
		     fileName[nb] = '\0';
		     /* le fichier a compiler est ouvert */
		     NIdentifiers = 0;
		     /* table des identificateurs vide */
		     LineNum = 0;
		     /* encore aucune ligne lue */
		     pSSchema = NULL;
		     /* pas (encore) de schema de structure */
		     fileOK = True;
		     /* lit tout le fichier et fait l'analyse */
		     while (fileOK && !error)
		       /* lit une ligne */
		       {
			 i = 0;
			 do
			   fileOK = TtaReadByte (filedesc, &inputLine[i++]);
			 while (i < LINE_LENGTH && inputLine[i - 1] != '\n' && fileOK);
			 /* marque la fin reelle de la ligne */
			 inputLine[i - 1] = '\0';
			 /* incremente le compteur de lignes lues */
			 LineNum++;
			 if (i >= LINE_LENGTH)
			   /* ligne trop longue */
			   CompilerMessage (1, APP, FATAL, MAX_LINE_SIZE_EXCEEDED, inputLine, LineNum);
			 else if (inputLine[0] == '#')
			   /* cette ligne contient une directive du preprocesseur cpp */
			   {
			     sscanf (inputLine, "# %d %s", &LineNum, buffer);
			     LineNum--;
			   }
			 else
			   /* traduit tous 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 */
				   {
				     AnalyzeToken (wi, wl, wn, &c, &r, &idNum, &pr);
				     /* on analyse le mot */
				     if (!error)
				       /* on le traite */
				       ProcessToken (wi, wl, c, r, pr);
				   }
			       }
			     while (wi != 0 && !error);
			     /* il n'y a plus de mots a analyser dans la ligne */
			   }
		       }
		     /* fin du fichier */
		     if (!error)
		       ParserEnd ();
		     /* fin d'analyse */
		     if (!error)
		       {
			 MakeMenusAndActionList ();
			 /* ecrit le schema compile' dans le fichier de sortie     */
			 /* le directory des schemas est le directory courant      */
			 SchemaPath[0] = '\0';
			 strcpy (srceFileName, fileName);
			 GenerateApplication (srceFileName, pAppli);
			 strcpy (srceFileName, fileName);
			 if (strcmp (srceFileName, "EDITOR") != 0)
			   WriteDefineFile (srceFileName);
		       }
		   }
	       }
	  }
     }
   TtaSaveAppRegistry ();
   exit (0);
}
