/***********************************************************************
 *
 * Projet   : DilibPro
 * Module   : SgmlPath
 * Fichier  : SgmlPath.c
 * Auteur   : Ducloy
 * Date     : 12/93
 * $Id: SgmlPath.c,v 1.3 2005/06/22 14:20:12 parmentf Exp $
 ***********************************************************************
 *
 * Copyright (c) 1994 CNRS/CRIN & INRIA Lorraine
 * 
 ***********************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#include "SgmlPath.h"
#include "RegExp.h"
#include "Except.h"

int atoi();

/******* Gestion des instructions *********************************/

SgmlPathProg *SgmlPathProgCreate(char* str)
{
     SgmlPathProg *prog;

     prog=(SgmlPathProg *)malloc(sizeof(SgmlPathProg));
     prog->firstStep=NULL;
     prog->lastStep=NULL;
     prog->source=str;

#ifdef DILIBDEBUG
     prog->SgmlPathProg_CurrentStep=0;
#endif

     return prog;
}

void SgmlPathProgFree(SgmlPathProg *prog)
{
 

      /*                             NE MARCHE PAS 
 
      */

}


SgmlPathStep *SgmlPathStepAdd(SgmlPathProg *prog,
			      enum SgmlPath_StepCode_Enum code)
{
  SgmlPathStep *step;

  step= (SgmlPathStep *)malloc(sizeof(SgmlPathStep));
  step->statCode=code;
  step->nextTrue=NULL;

  if(prog->firstStep)
   {
   }
  else
    {
    prog->firstStep=step;
  }

#ifdef DILIBDEBUG
  step->numStep =prog->SgmlPathProg_CurrentStep++;
  step->previous=prog->lastStep;
#endif

  prog->lastStep=step;

  return step;
}


#ifdef DILIBDEBUG
SgmlPathStepVisualOperator(SgmlPathStep *s)
{
  switch(SgmlPathStep_Operator(s))
    {
    case  SgmlPath_StepOperator_equal:
      printf("=");return;
    case  SgmlPath_StepOperator_GT:
      printf(">");return;
    case  SgmlPath_StepOperator_GE:
      printf(">=");return;
    case  SgmlPath_StepOperator_LT:
      printf("<");return;
    case  SgmlPath_StepOperator_LE:
      printf("<=");return;
    }
}

SgmlPathStepVisualMode(SgmlPathStep *s)
{
  enum SgmlPath_StepMode_Enum mode;
  mode = SgmlPathStep_Mode(s);

  switch(mode)
    {
    case SgmlPath_StepMode_String:
      printf("{string ");
      SgmlPathStepVisualOperator(s);
      printf("%s",SgmlPathStep_String(s));
      break;
    case SgmlPath_StepMode_RegExp:
      printf("{RegExp ");
      printf("%s",s->commentStr);
      break;
    case SgmlPath_StepMode_Num:
      printf("{Num ");
      break;
    }
  printf("}");
}

SgmlPathStepVisual(SgmlPathStep *s)
{
  printf ("%d :",s->numStep);
  printf ("[%d]",SgmlPathStep_CurrentContext(s));
  switch (s->statCode)
    {
    case SgmlPath_StepCode_First: 
      printf ("First ; "); 
      break;
    case SgmlPath_StepCode_Last: 
      printf ("Last ; "); 
      break;
    case SgmlPath_StepCode_IterSon: 
      printf ("IterSon ; "); 
      break;
    case SgmlPath_StepCode_IfData: 
      printf ("IfData ; "); 
      break;
    case SgmlPath_StepCode_Data_Test: 
      printf ("Data_Test ; "); 
      SgmlPathStepVisualMode(s);
      break;
    case SgmlPath_StepCode_IfTag: 
      printf ("IfTag"); 
      printf ("=%s ; ", SgmlPathStep_String(s));
      break;
    case SgmlPath_StepCode_IfAttId:
      printf ("IfAttId"); 
      printf ("=%s ; ", SgmlPathStep_String(s));
      break;
    case SgmlPath_StepCode_IfAttVal:
      printf ("IfAttVal"); 
      printf ("=%s ; ", SgmlPathStep_String(s));
      break;
    case SgmlPath_StepCode_Exec: 
      printf ("Exec ;"); 
      break;    
   case SgmlPath_StepCode_SonNumber: 
      printf ("SonNumber = %d ;",SgmlPathStep_Number(s) ); 
      printf ("[-> %d] ",SgmlPathStep_NewContext(s));
      break;
    };

  if (SgmlPathStep_NextTrue(s))
    { printf ("true=%d ; ",SgmlPathStep_NextTrue(s)->numStep);
    }

  if (SgmlPathStep_Return(s))
    { printf ("ret=%d ; ",SgmlPathStep_Return(s)->numStep);
    }
  printf ("\n");
  if (s->previous) SgmlPathStepVisual(s->previous);
};

SgmlPathProgVisual(SgmlPathProg *prog)
{
  SgmlPathStepVisual(prog->lastStep);
  printf ("\n");
}
#endif



/******************** le controleur d'iteration **********************/

SgmlPathIterator *SgmlPathIteratorCreate(SgmlPathProg *prog)
{
SgmlPathIterator *iterator;

iterator= (SgmlPathIterator *)malloc(sizeof(SgmlPathIterator));
     iterator->prog=prog;
     iterator->context
         =(SgmlPath_StepContext *)malloc
	 (prog->numberOfContext*sizeof(SgmlPath_StepContext));
     return(iterator);
}

void SgmlPathIteratorFree(SgmlPathIterator *iterator)
{
  /* NE MARCHE PAS */
}

SgmlPathIterator *SgmlPathIteratorInit(SgmlPathIterator *iterator,
				       SgmlNode         *node)
{
 iterator->tree=node;
 iterator->currentStep=iterator->prog->firstStep;
 iterator->context[0].currentNode=node;
 return iterator;
}

/********************** l'interprete des commandes *******************/

#define IteratorCurrentNode(s)    \
         iterator->context[SgmlPathStep_CurrentContext(step)].currentNode

#define IteratorCurrentString(s)    \
         iterator->context[SgmlPathStep_CurrentContext(step)].currentString

#define IteratorCurrentAtt(s)    \
         iterator->context[SgmlPathStep_CurrentContext(step)].currentAtt

SgmlNode *SgmlPath_Inter_Exec(SgmlPathIterator *iterator,
			      SgmlPathStep     *step)
{
  SgmlNode *retNode;

  iterator->currentStep=SgmlPathStep_Return(step);
  retNode=IteratorCurrentNode(step);
  return retNode;
}

SgmlNode *SgmlPath_Inter_SonNumber(SgmlPathIterator *iterator,
				   SgmlPathStep     *step)
{
  SgmlNode *n1;
  SgmlNode *son;
  if((n1=IteratorCurrentNode(step))
     &&(son=SgmlGetSonNumber(n1,SgmlPathStep_Number(step))))
    {
      iterator->context[SgmlPathStep_NewContext(step)].currentNode=son;
      iterator->currentStep= SgmlPathStep_NextTrue(step);
    }
  else
    {
      iterator->currentStep= SgmlPathStep_Return(step);
    }
  return son;
}

SgmlNode *SgmlPath_Inter_First(SgmlPathIterator *iterator,
			       SgmlPathStep     *step)
{
  SgmlNode *n1;
  SgmlNode *son;
  if((n1=IteratorCurrentNode(step))
     &&(son=SgmlFirst(n1)))
    {
      iterator->context[SgmlPathStep_NewContext(step)].currentNode=son;
      iterator->currentStep= SgmlPathStep_NextTrue(step);
    }
  else
    {
      iterator->currentStep= SgmlPathStep_Return(step);
    }
  return son;
}

SgmlNode *SgmlPath_Inter_Last(SgmlPathIterator *iterator,
			      SgmlPathStep     *step)
{
  SgmlNode *n1;
  SgmlNode *son;
  if((n1=IteratorCurrentNode(step))
     &&(son=SgmlLast(n1)))
    {
      iterator->context[SgmlPathStep_NewContext(step)].currentNode=son;
      iterator->currentStep= SgmlPathStep_NextTrue(step);
    }
  else
    {
      iterator->currentStep= SgmlPathStep_Return(step);
    }
  return son;
}

SgmlNode *SgmlPath_Inter_Parent(SgmlPathIterator *iterator,
				SgmlPathStep     *step)
{
  SgmlNode *n1;
  SgmlNode *parent;
  if((n1=IteratorCurrentNode(step))
     &&(parent=SgmlFather(n1)))
    {
      iterator->context[SgmlPathStep_NewContext(step)].currentNode=parent;
      iterator->currentStep= SgmlPathStep_NextTrue(step);
    }
  else
    {
      iterator->currentStep= SgmlPathStep_Return(step);
    }
  return parent;
}


void SgmlPath_Inter_IterSon(SgmlPathIterator *iterator,
			    SgmlPathStep     *step)
{
  SgmlNode *n1;

  if((n1=IteratorCurrentNode(step)->next))
     {
      IteratorCurrentNode(step)=n1;
      iterator->currentStep= SgmlPathStep_NextTrue(step);
     }
     else
    {
      iterator->currentStep= SgmlPathStep_Return(step);
    }
}

SgmlNode *SgmlPath_Inter_IfTag(SgmlPathIterator *iterator,
			       SgmlPathStep     *step)
{
  SgmlNode *n1;

  if ((n1=IteratorCurrentNode(step))
      &&(strcmp(SgmlTag(n1), SgmlPathStep_String(step))==0))
    iterator->currentStep= SgmlPathStep_NextTrue(step);
  else
    {
      iterator->currentStep= SgmlPathStep_Return(step);
    }
  return n1;
}

SgmlNode *SgmlPath_Inter_IfAttId(SgmlPathIterator *iterator,
				 SgmlPathStep     *step)
{
  SgmlNode *n1;
  SgmlNode *a1;

  if ((n1=IteratorCurrentNode(step))
      &&(a1=SgmlGetAttById(n1,SgmlPathStep_String(step))))
    {
      IteratorCurrentAtt(step)=a1;
      iterator->currentStep= SgmlPathStep_NextTrue(step);
    }
  else
    {
      iterator->currentStep= SgmlPathStep_Return(step);
    }
  return n1;
}

SgmlNode *SgmlPath_Inter_IfAttVal(SgmlPathIterator *iterator,
				  SgmlPathStep     *step)
{
  SgmlNode *a1;

  if ((a1=IteratorCurrentAtt(step))
      &&(strcmp(SgmlAttVal(a1),SgmlPathStep_String(step))==0))
    {
      iterator->currentStep= SgmlPathStep_NextTrue(step);
    }
  else
    {
      iterator->currentStep= SgmlPathStep_Return(step);
    }
  return a1;
}

SgmlNode *SgmlPath_Inter_IfData(SgmlPathIterator *iterator,
				SgmlPathStep     *step)
{
  SgmlNode *n1;

  if ((n1=IteratorCurrentNode(step))
      &&SgmlIsData(n1))
    {
      iterator->currentStep= SgmlPathStep_NextTrue(step);
      IteratorCurrentString(step)=SgmlDataString(n1);
    }
  else
    {
      iterator->currentStep= SgmlPathStep_Return(step);
    }
  return n1;
}

SgmlNode *SgmlPath_Inter_GetAttVal(SgmlPathIterator *iterator,
				   SgmlPathStep     *step)
{
  SgmlNode *n1;
  static SgmlNode *lastAtt=NULL;
  if(lastAtt){SgmlFree(lastAtt); lastAtt=NULL;}
  if ((n1=IteratorCurrentAtt(step)))
    {
      iterator->currentStep= SgmlPathStep_NextTrue(step);
      IteratorCurrentString(step)=SgmlAttVal(n1);
      IteratorCurrentNode(step)=(lastAtt=SgmlDataCreate(SgmlAttVal(n1)));
    }
  else
    {
      iterator->currentStep= SgmlPathStep_Return(step);
    }
  return n1;
}

char *SgmlPath_Inter_TestEval(SgmlPathStep *step,
			      char         *str)
{
  int resComp;
  int workInt;
  switch(SgmlPathStep_Mode(step))
    {
    case SgmlPath_StepMode_RegExp:
      return RegExpFind(SgmlPathStep_RegExp(step),str);
    case SgmlPath_StepMode_String:
      resComp=strcmp(str,SgmlPathStep_String(step));
      switch(SgmlPathStep_Operator(step))
	{
	case SgmlPath_StepOperator_equal:
	  if(resComp==0)return str;
	  else return NULL;
	case SgmlPath_StepOperator_GT:
	  if(resComp>0)return str;
	  else return NULL;
	case SgmlPath_StepOperator_GE:
	  if(resComp>=0)return str;
	  else return NULL;
	case SgmlPath_StepOperator_LT:
	  if(resComp<0)return str;
	  else return NULL;
	case SgmlPath_StepOperator_LE:
	  if(resComp<=0)return str;
	  else return NULL;
	}
    case SgmlPath_StepMode_Num:
      workInt=atoi(str);
      switch(SgmlPathStep_Operator(step))
	{
	case SgmlPath_StepOperator_equal:
	  if(workInt==SgmlPathStep_Number(step))return str;
	  else return NULL;
	case SgmlPath_StepOperator_GT:
	  if(workInt>SgmlPathStep_Number(step))return str;
	  else return NULL;
	case SgmlPath_StepOperator_GE:
	  if(workInt>=SgmlPathStep_Number(step))return str;
	  else return NULL;
	case SgmlPath_StepOperator_LT:
	  if(workInt<SgmlPathStep_Number(step))return str;
	  else return NULL;
	case SgmlPath_StepOperator_LE:
	  if(workInt<=SgmlPathStep_Number(step))return str;
	  else return NULL;
	}
    }
  return NULL;
}

void SgmlPath_Inter_Data_Test(SgmlPathIterator *iterator,
			      SgmlPathStep     *step)
{
  if (SgmlPath_Inter_TestEval(step,IteratorCurrentString(step)))
    {
      iterator->currentStep= SgmlPathStep_NextTrue(step);
    }
  else
    {
      iterator->currentStep= SgmlPathStep_Return(step);
    }
}

SgmlNode *SgmlPathNext(SgmlPathIterator *iterator)
{
  SgmlPathStep     *pathStep;
  if ((pathStep=iterator->currentStep))
    {
      switch(SgmlPathStep_Code(pathStep))
	{
	case SgmlPath_StepCode_Exec:
	  return SgmlPath_Inter_Exec(iterator,pathStep);

	case SgmlPath_StepCode_SonNumber:
	  SgmlPath_Inter_SonNumber(iterator,pathStep);
	  return (SgmlPathNext(iterator));
	case SgmlPath_StepCode_First:
	  SgmlPath_Inter_First(iterator,pathStep);
	  return (SgmlPathNext(iterator));
	case SgmlPath_StepCode_Last:
	  SgmlPath_Inter_Last(iterator,pathStep);
	  return (SgmlPathNext(iterator));
	case SgmlPath_StepCode_Parent:
	  SgmlPath_Inter_Parent(iterator,pathStep);
	  return (SgmlPathNext(iterator));

	case SgmlPath_StepCode_IterSon:
	  SgmlPath_Inter_IterSon(iterator,pathStep);
	  return (SgmlPathNext(iterator));

	case SgmlPath_StepCode_IfTag:
	  SgmlPath_Inter_IfTag(iterator,pathStep);
	  return (SgmlPathNext(iterator));

	case SgmlPath_StepCode_IfAttId:
	  SgmlPath_Inter_IfAttId(iterator,pathStep);
	  return (SgmlPathNext(iterator));

	case SgmlPath_StepCode_IfAttVal:
	  SgmlPath_Inter_IfAttVal(iterator,pathStep);
	  return (SgmlPathNext(iterator));

	case SgmlPath_StepCode_GetAttVal:
	  SgmlPath_Inter_GetAttVal(iterator,pathStep);
	  return (SgmlPathNext(iterator));

	case SgmlPath_StepCode_IfData:
	  SgmlPath_Inter_IfData(iterator,pathStep);
	  return (SgmlPathNext(iterator));

	case SgmlPath_StepCode_Data_Test:
	  SgmlPath_Inter_Data_Test(iterator,pathStep);
	  return (SgmlPathNext(iterator));

	default:
	  break;

        }
    }
  return NULL;
}

/************ Le Compilateur des paths ********************************/

/* declarations */

enum compilerModeEnum
{
  ModeSgmlNode,
  ModeData
};

struct SgmlPathCompilerContextStruct
{
  SgmlPathProg *prog;
  enum compilerModeEnum mode;
  char         *str;
  int           currentStepContext;
  SgmlPathStep *lastStep;
  SgmlPathStep *retIter;
  SgmlPathStep *firstStep;
};

typedef struct SgmlPathCompilerContextStruct SgmlPathCompilerContext;

SgmlPathStep *SgmlPathStepCompile();
SgmlPathStep *SgmlPathStepCompileData();
SgmlPathStep *SgmlPathStepCompile_AfterAttId();

static enum SgmlPath_StepMode_Enum     SgmlPath_NextMode ;
static enum SgmlPath_StepOperator_Enum SgmlPath_NextOperator;

/********************************/

SgmlPathCompilerContext *SgmlPathCompilerContextCreate(SgmlPathProg *prog,
						       char         *str1)
{
SgmlPathCompilerContext *compilerContext;

compilerContext = 
   (SgmlPathCompilerContext *)malloc(sizeof(SgmlPathCompilerContext));

     compilerContext->str=str1;
     compilerContext->prog=prog;
     compilerContext->mode=ModeSgmlNode;
     compilerContext->prog->numberOfContext=1;
     compilerContext->currentStepContext=0;
     compilerContext->retIter           =NULL;
     compilerContext->firstStep         =NULL;
     compilerContext->lastStep          =NULL;

return compilerContext;
}

/*********************** fonctions lexicales *********************/

/*
  gestion memoire des fonctions lexicales du compilateur :
  on alloue une zone de manoeuvre egale a la taille du path.
 */

static char *SgmlPathCompiler_WorkSpace;
static int   SgmlPathCompiler_SizeWorkSpace=0;

void SgmlPathCompilerSkipSpaces(SgmlPathCompilerContext *context)
{
  if(context->str[0]==' ')
    {
      context->str++;
      SgmlPathCompilerSkipSpaces(context);
    }
}

char *SgmlPathCompilerGetIdent(SgmlPathCompilerContext *context)
{
  char *id;
  static RegExp *REident;
  static int firstCall=0;
  if (firstCall==0)
    {
      firstCall=1;
      REident=RegExpCreate("[A-Za-z][A-Za-z0-9_.:\-]*");
    }
  RegExpIf_Ta
    (REident, context->str, ident, sstr,
     {
       id=malloc(strlen(ident)+1);
       strcpy(id, ident);
       context->str=sstr;
     },
     {
       ExceptSetError("SgmlPath", "SYNT", "uncorrect symbol at: ", 
                          context->str,"",1);
       id=NULL;
     });
  return(id);
}

char *SgmlPathCompilerGetUntil(SgmlPathCompilerContext *context,
			       char                     carac)
{
  char *p1;
  char *p2;
  char c1;
  char c2;
  char *str1;

  p1=context->str;
  p2=SgmlPathCompiler_WorkSpace;
  
  while((c1=*p1++))
    {
      if(c1==carac)
	{
	  *p2='\0';
	  str1=malloc(p2-SgmlPathCompiler_WorkSpace+1);
	  strcpy(str1,SgmlPathCompiler_WorkSpace);
	  context->str=p1;
	  return str1;
	}
      if (c1=='\\') 
	{
	  c2=*p1++;
	  if (!c2) return NULL;
	  *p2++=c2;
	}
      else *p2++=c1;
    }
  return NULL;
}

char *SgmlPathCompilerGetString(SgmlPathCompilerContext *compilerContext)
{
  char *p1;
  char *p2;
  char c1;
  char c2;
  char *str1;

  p1=compilerContext->str;
  p2=SgmlPathCompiler_WorkSpace;

  while((c1=*p1++))
    {
      switch(c1)
	{
	case '/':
	  /* case '&': */
	case '#':
	case '@':

	  *p2='\0';
	  str1=malloc(p2-SgmlPathCompiler_WorkSpace+1);
	  strcpy(str1,SgmlPathCompiler_WorkSpace);
	  compilerContext->str=p1-1;     
                   /* le separateur est traite par l'appelant */
	  return str1;

	case '\\':

	  c2=*p1++;
	  if (!c2) return NULL;
	  *p2++=c2;
	  break;

	default:

	  *p2++=c1;
	  break;
	}
    }

  if (p2==SgmlPathCompiler_WorkSpace) return NULL;
  *p2='\0';
  str1=malloc(p2-SgmlPathCompiler_WorkSpace+1);
  strcpy(str1,SgmlPathCompiler_WorkSpace);
  compilerContext->str=p1-1;
  return str1;

}

int SgmlPathCompilerGetNumber(SgmlPathCompilerContext *context)
{
    static int firstCall=0;
    static RegExp *REnumber;
    int number;
  if (firstCall==0)
    {
      firstCall=1;
      REnumber=RegExpCreate("[0-9][0-9]*");
    }
  RegExpIf_Ta
    (REnumber, context->str, ident, sstr,
     {
       number =atoi(ident);
       context->str=sstr;
     },
     {
       number=0;
     });
  return(number);
}

void SgmlPathCompiler_GetOperator(SgmlPathCompilerContext *compilerContext)
{
  switch(compilerContext->str[0])
    {
    case '=':

      compilerContext->str++;
      SgmlPath_NextOperator= SgmlPath_StepOperator_equal;
      return;

    case '>':

      compilerContext->str++;
      if(compilerContext->str[0]=='=')
	{
	  compilerContext->str++;
	  SgmlPath_NextOperator= SgmlPath_StepOperator_GE;
	}
      else SgmlPath_NextOperator= SgmlPath_StepOperator_GT;
      return;

    case '<':

      compilerContext->str++;
      if(compilerContext->str[0]=='=')
	{
	  compilerContext->str++;
	  SgmlPath_NextOperator= SgmlPath_StepOperator_LE;
	}
      else SgmlPath_NextOperator= SgmlPath_StepOperator_LT;
      return;

    }
}


int SgmlPathCompiler_GetMode(SgmlPathCompilerContext *compilerContext)
{
  compilerContext->str++;
  switch(compilerContext->str[0])
    {
    case 'n':
      compilerContext->str++;
      SgmlPath_NextMode=SgmlPath_StepMode_Num;
      return 1;
    default:
      return 0; /* return NULL; */
    }
}
/************************traitement des instructions elementaires ********/
/*   les fonctions generales */


void SgmlPath_InitImplicit_NextStep()
{
  SgmlPath_NextMode     =SgmlPath_StepMode_String;
  SgmlPath_NextOperator =SgmlPath_StepOperator_equal;
}

SgmlPathStep *SgmlPathCompilerNewStat(SgmlPathCompilerContext *compilerContext,
				      enum SgmlPath_StepCode_Enum code)
{
     SgmlPathStep *step;
     SgmlPathStep *previousStep;

     previousStep=compilerContext->lastStep;

     step=SgmlPathStepAdd(compilerContext->prog,code);

     SgmlPathStep_Mode(step)    =SgmlPath_NextMode;
     SgmlPathStep_Operator(step)=SgmlPath_NextOperator;

     compilerContext->lastStep=step;

     if(previousStep)SgmlPathStep_NextTrue(previousStep)=step;
     else compilerContext->firstStep=step;
     SgmlPathStep_Return(step)=compilerContext->retIter;

     SgmlPathStep_CurrentContext(step)=compilerContext->currentStepContext;
     return step;
}

void SgmlPathCompiler_NewStepContext(SgmlPathCompilerContext *compilerContext,
				     SgmlPathStep *step)
{
  compilerContext->prog->numberOfContext++;
  compilerContext->currentStepContext++;
  SgmlPathStep_NewContext(step)=compilerContext->currentStepContext;
  return;
}

/* les fonctions specialisees */

SgmlPathStep *SgmlPathCompiler_Gen_First(
                       SgmlPathCompilerContext *compilerContext)
{
  SgmlPathStep *step;
  step=SgmlPathCompilerNewStat(compilerContext,SgmlPath_StepCode_First);
  SgmlPathCompiler_NewStepContext(compilerContext,step);
  SgmlPathStepCompile(compilerContext);
  return step;
}

SgmlPathStep *SgmlPathCompiler_Gen_FirstIfData(
		       SgmlPathCompilerContext *compilerContext)
{
  SgmlPathStep *step1;
  SgmlPathStep *step2;
  step1=SgmlPathCompilerNewStat(compilerContext,SgmlPath_StepCode_First);
  SgmlPathCompiler_NewStepContext(compilerContext,step1);
  step2=SgmlPathCompilerNewStat(compilerContext,SgmlPath_StepCode_IfData);
  compilerContext->mode=ModeData;
  SgmlPathStepCompileData(compilerContext);
  return step1;
}

SgmlPathStep *SgmlPathCompiler_Gen_Last(
		       SgmlPathCompilerContext *compilerContext)
{
  SgmlPathStep *step;

  step=SgmlPathCompilerNewStat(compilerContext,SgmlPath_StepCode_Last);
  SgmlPathCompiler_NewStepContext(compilerContext,step);
  SgmlPathStepCompile(compilerContext);

  return step;
}

SgmlPathStep *SgmlPathCompiler_Gen_Parent(
		       SgmlPathCompilerContext *compilerContext)
{
  SgmlPathStep *step;

  step=SgmlPathCompilerNewStat(compilerContext,SgmlPath_StepCode_Parent);
  SgmlPathCompiler_NewStepContext(compilerContext,step);
  SgmlPathStepCompile(compilerContext);

  return step;
}

SgmlPathStep *SgmlPathCompiler_Gen_SonNumber(
		       SgmlPathCompilerContext *compilerContext)
{
  int number;
  SgmlPathStep *step;

  number=SgmlPathCompilerGetNumber(compilerContext);

  if (number==0)
      return SgmlPathCompiler_Gen_Last(compilerContext);
  if (number==1)
      return SgmlPathCompiler_Gen_First(compilerContext);

  step=SgmlPathCompilerNewStat
    (compilerContext,SgmlPath_StepCode_SonNumber);
  SgmlPathStep_Number(step)=number;
  SgmlPathCompiler_NewStepContext(compilerContext,step);
  SgmlPathStepCompile(compilerContext);
  return step;

}

SgmlPathStep *SgmlPathCompiler_Gen_IterSon(
		       SgmlPathCompilerContext *compilerContext)
{
  SgmlPathStep *step;
  SgmlPathStep *step1;
  SgmlPathStep *returnStep;

  step=SgmlPathCompilerNewStat(compilerContext,SgmlPath_StepCode_First);
  SgmlPathCompiler_NewStepContext(compilerContext,step);
  step1=SgmlPathCompilerNewStat(compilerContext,SgmlPath_StepCode_IterSon);
  returnStep=compilerContext->retIter;
  compilerContext->retIter=step1;
  SgmlPathStep_NextTrue(step)=SgmlPathStepCompile(compilerContext);
  compilerContext->retIter=returnStep;

  return step;
}

SgmlPathStep *SgmlPathCompiler_Gen_IfTag(
		       SgmlPathCompilerContext *compilerContext)
{
  SgmlPathStep *step;

  step=SgmlPathCompilerNewStat(compilerContext,SgmlPath_StepCode_IfTag);
  SgmlPathStep_String(step)=SgmlPathCompilerGetIdent(compilerContext);
  SgmlPathStepCompile(compilerContext);

  return step;
}

SgmlPathStep *SgmlPathCompiler_Gen_IfAttId(
                       SgmlPathCompilerContext *compilerContext)
{
  SgmlPathStep *step;

  step=SgmlPathCompilerNewStat(compilerContext,SgmlPath_StepCode_IfAttId);
  SgmlPathStep_String(step)=SgmlPathCompilerGetIdent(compilerContext);
  SgmlPathStepCompile_AfterAttId(compilerContext);

  return step;
}

SgmlPathStep *SgmlPathCompiler_Gen_IfAttVal(
                       SgmlPathCompilerContext *compilerContext)
{
  SgmlPathStep *step;

  step=SgmlPathCompilerNewStat(compilerContext,SgmlPath_StepCode_IfAttVal);
  SgmlPathStep_String(step)=SgmlPathCompilerGetString(compilerContext);
  SgmlPathStepCompile(compilerContext);

  return step;
}

SgmlPathStep *SgmlPathCompiler_Gen_IterSonTag(
                       SgmlPathCompilerContext *compilerContext)
{
  SgmlPathStep *step;
  SgmlPathStep *step1;
  SgmlPathStep *step2;
  SgmlPathStep *returnStep;

  step=SgmlPathCompilerNewStat(compilerContext,SgmlPath_StepCode_First);
  SgmlPathCompiler_NewStepContext(compilerContext,step);
  step1=SgmlPathCompilerNewStat(compilerContext,SgmlPath_StepCode_IterSon);
  returnStep=compilerContext->retIter;
  compilerContext->retIter=step1;
  step2=SgmlPathCompiler_Gen_IfTag(compilerContext);
  SgmlPathStep_NextTrue(step)=step2;
  compilerContext->retIter=returnStep;
  return step;
}

SgmlPathStep *SgmlPathCompiler_Gen_Data_IfRegExp(
                       SgmlPathCompilerContext *compilerContext)
{
  SgmlPathStep *step1;
  char *re1;

  compilerContext->str++;   /* saut du premier ? */
  step1=SgmlPathCompilerNewStat
    (compilerContext,SgmlPath_StepCode_Data_Test);
  SgmlPathStep_Mode(step1)=SgmlPath_StepMode_RegExp;
  if((re1=SgmlPathCompilerGetUntil(compilerContext,'?')))
    {
      SgmlPathStep_RegExp(step1)=RegExpCreate(re1);
      SgmlPathStepCompileData(compilerContext);
#ifdef DILIBDEBUG
      step1->commentStr=re1;
#endif
      return step1;
    }
  return NULL;
}

SgmlPathStep *SgmlPathCompiler_Gen_Data_Test(
                       SgmlPathCompilerContext *compilerContext)
{
  SgmlPathStep *step1;

  step1=SgmlPathCompilerNewStat
    (compilerContext,SgmlPath_StepCode_Data_Test);

  SgmlPathStep_Mode(step1)    =SgmlPath_NextMode;
  SgmlPathStep_Operator(step1)=SgmlPath_NextOperator;
  switch (SgmlPath_NextMode)
    {
    case SgmlPath_StepMode_String:
      SgmlPathStep_String(step1)  =SgmlPathCompilerGetString(compilerContext);
      break;
    case SgmlPath_StepMode_Num:
      SgmlPathStep_Number(step1)  =SgmlPathCompilerGetNumber(compilerContext);
      break;
    default:
      ExceptSetError("SgmlPath", "DEV", "error or not yet implemented","","",1);
      break;
    }

  SgmlPathStepCompileData(compilerContext);

#ifdef DILIBDEBUG
  step1->commentStr=str1;
#endif

  return step1;
}

SgmlPathStep *SgmlPathCompiler_Gen_Exec(SgmlPathCompilerContext *s)
{
  return(SgmlPathCompilerNewStat(s,SgmlPath_StepCode_Exec));
}

SgmlPathStep *SgmlPathStepCompileAttVal();

SgmlPathStep *SgmlPathCompiler_Gen_GetAttVal(
                       SgmlPathCompilerContext *compilerContext)
{
  SgmlPathStep *step1;
  step1=SgmlPathCompilerNewStat(compilerContext,SgmlPath_StepCode_GetAttVal);
  SgmlPathStepCompileAttVal(compilerContext);
  return step1;
}


/****************************************************************/

SgmlPathStep *SgmlPathCompile_AfterSlash(
                       SgmlPathCompilerContext *compilerContext)
{
  char c0;

  if ((c0=compilerContext->str[0]))
    {
      if(isdigit((int)c0))
	{
	  return SgmlPathCompiler_Gen_SonNumber(compilerContext);
	}
      else
	{
	  if(isalpha((int)c0))
	    {
	      return SgmlPathCompiler_Gen_IterSonTag(compilerContext);
	    }
	  else
	    {
	      compilerContext->str++;
	      switch(c0)
		{
		case '/':
		  return SgmlPathCompiler_Gen_First(compilerContext);
		case '*':
		  return SgmlPathCompiler_Gen_IterSon(compilerContext);
		case '.':
		  if (compilerContext->str[0]=='.')
		    {
		      compilerContext->str++;
		      return SgmlPathCompiler_Gen_Parent(compilerContext);
		    }
		  else 
		    {
		      ExceptSetError("SgmlPath", "SYNT", "wrong operator at: ",
				     compilerContext->str,"",1);
		    }
		  break;

		default:
		  ExceptSetError("SgmlPath", "SYNT", "wrong operator at: ", 
                          compilerContext->str,"",1);
		  break;
		}
	    }
	}
    }
  /*  else    fin de path, on genere exec */

    return SgmlPathCompiler_Gen_Exec(compilerContext);
}

SgmlPathStep *SgmlPathCompile_AfterTagZone(
                       SgmlPathCompilerContext *compilerContext)
{
  char c0;

  SgmlPathCompilerSkipSpaces(compilerContext);

  if ((c0=compilerContext->str[0]))
    {      

      switch(c0)
	{
        case '/':
	case '#':
	  return SgmlPathStepCompile(compilerContext);
	default:
	  return SgmlPathCompiler_Gen_IfAttId(compilerContext);
	}
    }
  else
    {
      return SgmlPathCompiler_Gen_Exec(compilerContext);
    }
}

SgmlPathStep *SgmlPathStepCompile_AfterAttId(
                       SgmlPathCompilerContext *compilerContext)
{

  char c0;

  if ((c0=compilerContext->str[0]))
    {
      switch(c0)
	{
	case '/':
	case '#':
	  return SgmlPathStepCompile(compilerContext);

	case '@':
	  if (compilerContext->str[1]=='#')
	    {
	      compilerContext->str+=2;
	      return SgmlPathCompiler_Gen_GetAttVal(compilerContext);
	    }
	  else
	    ExceptSetError("SgmlPath", "SYNT", "Syntax Error at: ", 
			   compilerContext->str-1,"",1);	    

	case ' ':
	  compilerContext->str++;
	  return SgmlPathCompile_AfterTagZone(compilerContext);

	case '=':
	  compilerContext->str++;
	  return SgmlPathCompiler_Gen_IfAttVal(compilerContext);

	default:
	  ExceptSetError("SgmlPath", "SYNT", "Syntax Error at: ", 
                          compilerContext->str-1,"",1);
	  return NULL;
	}
    }
  else     /*fin de path, on genere exec */
    {
      return SgmlPathCompiler_Gen_Exec(compilerContext);
    }
}

SgmlPathStep *SgmlPathStepCompile(
                       SgmlPathCompilerContext *compilerContext)
{

  char c0;

  if ((c0=compilerContext->str[0]))
    {
      compilerContext->str++;
      switch(c0)
	{
	case '/':
	  return SgmlPathCompile_AfterSlash(compilerContext);

	case '#':
	  return SgmlPathCompiler_Gen_FirstIfData(compilerContext);

	case ' ':
	case '@':
	  return SgmlPathCompile_AfterTagZone(compilerContext);

	default:
	  ExceptSetError("SgmlPath", "SYNT", "Syntax Error at: ", 
                          compilerContext->str-1,"",1);
	  return NULL;
	}
    }
  else     /*fin de path, on genere exec */
    {
      return SgmlPathCompiler_Gen_Exec(compilerContext);
    }
}

SgmlPathStep *SgmlPathStepCompileData_InstEnCours(
                       SgmlPathCompilerContext *compilerContext)
{
  char c0;

  if ((c0=compilerContext->str[0]))
    {
      switch(c0)
	{
	case '?':
	  return SgmlPathCompiler_Gen_Data_IfRegExp(compilerContext);
	case '=':
	case '>':
	case '<':
	  SgmlPathCompiler_GetOperator(compilerContext);
	  return SgmlPathCompiler_Gen_Data_Test(compilerContext);
	  break;
	case ':':
	  SgmlPathCompiler_GetMode(compilerContext);
	  return SgmlPathStepCompileData_InstEnCours(compilerContext);
	case '/':
	  if ((compilerContext->str[1]=='.')&&(compilerContext->str[2]=='.'))
	    {
	      compilerContext->str+=3;
	      return SgmlPathCompiler_Gen_Parent(compilerContext);
	    }
	  else 
	    {
	      ExceptSetError("SgmlPath", "SYNTAX(data) ", "wrong operator at: ",
			     compilerContext->str,"",1);
	      return NULL;
	    }
	  break;
	default:
	  return SgmlPathCompiler_Gen_Data_Test(compilerContext);
	}
    }
  else     /*instruction non terminee */
    {
      return NULL;
    }

}

SgmlPathStep *SgmlPathStepCompileData(
     SgmlPathCompilerContext *compilerContext)
{

  SgmlPath_InitImplicit_NextStep();

  if (compilerContext->str[0])
    return SgmlPathStepCompileData_InstEnCours(compilerContext);
  else     /*fin de path, on genere exec */
    {
      return SgmlPathCompiler_Gen_Exec(compilerContext);
    }

}

SgmlPathStep *SgmlPathStepCompileAttVal(
     SgmlPathCompilerContext *compilerContext)
{

  SgmlPath_InitImplicit_NextStep();

  if (compilerContext->str[0])
    {
      ExceptSetError("SgmlPath", "SYNT", "Not Yet Implemented: ", 
		     compilerContext->str-1,"",1);
      return SgmlPathStepCompileData_InstEnCours(compilerContext);
    }
  else     /*fin de path, on genere exec */
    {
 
      return SgmlPathCompiler_Gen_Exec(compilerContext);
    }

}

SgmlPathProg *SgmlPathCompile(char *str)
{
     SgmlPathCompilerContext *compilerContext;
     SgmlPathProg *prog;
     char c0;
     int lenStr;

     lenStr=strlen(str);
     if (lenStr>=SgmlPathCompiler_SizeWorkSpace)
       {
	 if(SgmlPathCompiler_SizeWorkSpace>0)free(SgmlPathCompiler_WorkSpace);
	 SgmlPathCompiler_SizeWorkSpace=lenStr+1;
	 SgmlPathCompiler_WorkSpace=malloc(SgmlPathCompiler_SizeWorkSpace);
       }

     prog=SgmlPathProgCreate(str);
     compilerContext=SgmlPathCompilerContextCreate(prog,str);
     if ((c0=compilerContext->str[0]))
       {
	 if (c0=='/') 
	   {
	     compilerContext->str++;
	     if ((c0=compilerContext->str[0]))
	       {
		 switch(c0)
		   {
		   case '0':
		   case '1':
		     compilerContext->str++;
		     SgmlPathStepCompile(compilerContext);
		     break;
		   case '/':
		     SgmlPathStepCompile(compilerContext);
		     break;
		   default:
		     SgmlPathCompiler_Gen_IfTag(compilerContext);
		     break;
		   }
	       }
	   }
	 else SgmlPathCompile_AfterSlash(compilerContext);
       }
     else return NULL;
     return prog;
}

