/* National Institute of Standards and Technology (NIST)
/* National Computer System Laboratory (NCSL)
/* Office Systems Engineering (OSE) Group
/* ********************************************************************
/*                            D I S C L A I M E R
/*                              (March 8, 1989)
/*  
/* There is no warranty for the NIST NCSL OSE SGML parser and/or the NIST
/* NCSL OSE SGML parser validation suite.  If the SGML parser and/or
/* validation suite is modified by someone else and passed on, NIST wants
/* the parser's recipients to know that what they have is not what NIST
/* distributed, so that any problems introduced by others will not
/* reflect on our reputation.
/* 
/* Policies
/* 
/* 1. Anyone may copy and distribute verbatim copies of the SGML source
/* code as received in any medium.
/* 
/* 2. Anyone may modify your copy or copies of SGML parser source code or
/* any portion of it, and copy and distribute such modifications provided
/* that all modifications are clearly associated with the entity that
/* performs the modifications.
/* 
/* NO WARRANTY
/* ===========
/* 
/* NIST PROVIDES ABSOLUTELY NO WARRANTY.  THE SGML PARSER AND VALIDATION
/* SUITE ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
/* EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
/* THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS
/* WITH YOU.  SHOULD THE SGML PARSER OR VALIDATION SUITE PROVE DEFECTIVE,
/* YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
/* 
/* IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL NIST BE LIABLE FOR
/* DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL,
/* INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
/* INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
/* BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A
/* FAILURE OF THE PROGRAM TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY
/* NIST) THE PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF
/* SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
*/

/************************************************************************/
/*   TITLE:          SGML PARSER                                        */
/*   SYSTEM:         DTD PROCESSOR                                      */
/*   SUBSYSTEM:                                                         */
/*   SOURCE FILE:    DETERMIN.C                                        */
/*   AUTHOR:         Michael Garris                                     */
/*                                                                      */
/*   DATE CREATED:                                                      */
/************************************************************************/
#include <stdio.h>
#include "detdefs.h"
#include "detglbl.h"
/**************************/
/* MAIN (to be removed) ***/
/**************************/
main(argc, argv)
int argc;
char *argv[];
{
	char eltname[128];
   FILE *infile;
   char inrec[2048];
   int j, c, error = 0;

   if ((infile = fopen("cmfile.sgm", "r")) == NULL){
     printf("unable to open cmfile.sgm \n");
     exit(1);
   }
   while(fgets(eltname, sizeof(eltname), infile) != NULL){
   	fgets(inrec, sizeof(inrec), infile);
      for(j = 0; j < sizeof(inrec); j++){
         if (inrec[j] < ' ') {
            inrec[j] = '\0';
            break;
         }
      }
      if (determin(inrec) == TRUE) {
        error = 1;
		  printf("For element %s:", eltname);
        printf("the content model:\n%s\n", inrec);
		printf("is SUSPICIOUS and/or AMBIGUOUS\n");
      }
   }
   fclose(infile);
   /*(void) unlink(fname);*/
   if (error != 0) {
      printf("\n\nSuspicious and/or ambiguous content models were found\n");
      printf("in this document - do you want to continue (Y/N)?  ");
      fflush(stdout);
      c = getchar();
      printf("\n");
      if ((c == 'y') || (c == 'Y'))
         exit(0);
      exit(1);
   }
   exit(0);
}


/******************************/
/* DETERMIN *******************/
/*  takes pointer to a string */
/******************************/
int determin(expr)
char expr[];
{
   STATEID *stateid;   /* structure of start state pointer and */
                       /*   final state pointer */
   /* Preprocess the string.  First by reducing the content model
        to its simplest form.  Second by tokenizing the content model
        for use in determining validity of it. */
   preproc(expr,buffer);  /* buffsize is the length of buffer */
   ambmodel = FALSE;  /* assume valid */
 
   /* "endbuf" will point to the end of the expression in the buffer */
   /* must send "buffer + 1" to avoid looking at the opening GRPO */

   endbuf = findendofgrp(buffer+1,1);

   /* invokes function to build FSA from expression in buffer */
   /* on return, stateid will point to the FSA's start state  */
   /* final state */

   stateid = proclowgrp(buffer,tokseen);

   /* invokes procedure to traverse entire FSA listing states visited */
    procinordr(stateid->startptr,stateid->finalptr);  

   /* invokes procedure which traverses FSA checking for non-determinism */

   procdet(stateid->startptr ,stateid->finalptr);
   free((char *)stateid);  /* will free last stateid */
   freeFSA();   /* will free linked list of dynamically allocated memory */
   head = NULL;

   return(ambmodel);
   if (ambmodel == FALSE)
       printf("Content Model is not ambiguous\n");
   else 
      printf("AMBIGUOUS Content Model\n");
}
/************************************************************************/
/************************************************************************/
/* PROCLOWGRP takes an expression in "buffer" and produces an equivalent*/
/* FSA using a constructive algorithm.                                  */
/************************************************************************/
STATEID *proclowgrp(buffer,tokseen)
ITEM *buffer;/* contains expression */
ITEM *tokseen;/*contains tokens already FSAtokened */
{
   int nest;/* current level of nested parens */
   ITEM *iptr = buffer;/* pointer to expression in buffer */
   STATEID *stateid;/* points to start and final state of */
                    /* 'intermediate' FSA */
   ITEM *tokptr = tokseen;/*pointer to end of token seen list */

   /* while 'subgroups' remain in expression... */
   while((nest = nestlevel(iptr)) != 0){
      /* invokes procedure to point to lowest-level, leftmost, subgroup */
      getlowgrp(&iptr,nest);
      /* invokes procedure to process each (token,occurance indicator)   */ 
      /* pair in the current subgroup, replacing them by a pointer to an */
      /* equivalent 'intermediate' FSAid */
      tokensingrp(iptr,tokseen,&tokptr);
      /* invokes procedure to process all FSA pointers and connectors in */
      /* the current subgroup, replacing the entire subgroup by a pointer*/
      /* to a more complex intermediate FSAid */
      lowgrp(iptr, nest);
      /* reset pointer to beginning of expression in buffer and repeat the */
      /* above process */
      iptr = buffer;
   }
   /* if, once above loop is exited, the expression pointer does not point */
   /* to a FSAid, then an error in the constructive algorithm has occurred */
   if(iptr++->itoken != POINTER)
      myexit(1,"FSA pointer id not found");
   /* if constructive algorithm has completed normally, then only one FSAid*/
   /* pointer remains in the expression.                                   */
   stateid = iptr->ptoken;
   /* return the pointer to the 'ultimate' FSAid for the*/
   /* inputted expression*/
   return(stateid);
}
/************************************************************************/
/************************************************************************/
/* TOKENSINGRP takes all (token,occurace indicator) pairs in a subgroup */
/* and builds an equivalent FSA representing each, replacing each pair  */
/* with a FSAid pointer which points to the corresponding FSA.          */
/************************************************************************/
void tokensingrp(iptr,tokseen,ptrin)
ITEM *iptr;/* points to a token within subgroup in expression */
ITEM *tokseen;/* points to head of token seen list */
ITEM **ptrin;/* points to next location available in token seen list */
{
   int token, occind;
	register int connector;
   STATEID *FSAtokid;/* FSAid pointing to the start and final */
                     /* state of the FSA equivalent to a */
                     /* (token,occurance indicator) pair */
   register ITEM *tokptr = *ptrin;
   int inst;/* instance of token in token seen list */

   /* while not end of current subgroup... */
   while((connector = iptr++->itoken) != GRPC){
      /* skip connector, in first pass connector = GRPO */
      /* if pointing to a FSAid pointer within subgroup, skip it */
      /* because it has already been "FSAtokened"             */
      if(iptr->itoken == POINTER){
/*       commented out by Michael D. Garris on 11/23/87  */
/*       due to the introduction of ITEM type            */
         /* invoke procedure to skip the pointer */
/*         skippointer(&iptr);       */
         iptr += 2;
         /* now continue and skip next connector */
         continue;
      }
      /* invoke function to get current token from subgroup           */
      /* and strip the location where the token was from the subgroup */
      token = gettoken(iptr);
      /* add new token to token seen list */
      if (tokptr >= (tokseen + BUFFSIZE)) {
        printf("overflow (tokptr) in proclowgrp()\n");
        exit(0);
      }
      tokptr++->itoken = token;
      /* search list to determine instances of token in token seen list */
      inst = searchtoken(token,tokseen,tokptr);
      /* invoke function to get current occurance indicator from subgoup */
      /* and strip the location where the indicator was from the subgroup*/ 
      occind = getoccind(iptr);
      /* invoke function which takes a (token,occurance indicator) pair */
      /* and build an equivalent FSA, returning the FSAid pointer */
      /* pointing to the start and final state of the newly built FSA  */
      FSAtokid = FSAtoken(token,inst,occind);
      /* invoke procedure which inserts the FSAid pointer into the */
      /* subgoup at the location where the most recently stripped */
      /* token and occurance indicator had been */
      insertpointer(&iptr,FSAtokid);
   }
   /* return from procedure after all (token,occurance indicator) pairs */
   /* have been "FSAtokened"                                            */
   *ptrin = tokptr;
}  
/************************************************************************/
/************************************************************************/
/* FSATOKEN inputs a (token,occurance indicator) pair and builds an     */
/* builds an equivalent FSA, returning a FSAid pointer which points     */
/* to the start and final state of the newly built FSA                  */
/************************************************************************/
STATEID *FSAtoken(token,inst,occind)
int token,inst,occind;
{
   STATE *start,*final;/* pointers to the start state */
                       /* and final state of the FSA to be built */
   STATEID *startid;/* FSAid of FSA to be built */

   /* invokes function which allocates memory for a start state */
   start = buildstate();
   /* invokes function which allocates memory for a final state */
   final = buildstate();
   /* execute code according to the current occurance indicator */
   switch(occind){
      /* if occurance indicator is required ...*/
      case REQ:
         /* set start state to point to final state */
         start -> lptr = final;
         /* and label the edge with the token */
         start -> llabel = token;
         start -> linst = inst;
            /****************************/
            /* A1 ==>       A           */
            /*         [S]----->[F]     */
            /****************************/
         break;
      /* if occurance indicator is optional ... */
      case REP:
      case OPT:
         /* set start state to point to final state with one edge */
         start -> lptr = final;
         /* and label the edge with the token */
         start -> llabel = token;
         start -> linst = inst;
         /* also set start state to point to final state with */
         /* another edge */
         start -> rptr = final;
         /* and label the edge with EMPTY */
         start -> rlabel = EMPTY;
            /****************************/
            /* A? ==>       A           */
            /*         [S]=====>[F]     */     
            /*              e           */
            /****************************/
         if(occind == OPT)
            break;
         /* Otherwise set final state back to start state */
         final->lptr = start;
         final->llabel = BACK;
            /****************************/
            /* A? ==>       A           */
            /*         [S]=====>[F]     */     
            /*          ^   e    |      */
            /*          |        |      */
            /*          +--------+      */
            /*               b          */
            /****************************/
      break;
      /* if occurance indicator is required-repeatable... */
      case PLUS:
         /* set start state to point to final state */
         start -> lptr = final;
         /* and label the edge with the token */
         start -> llabel = token;
         start -> linst = inst;
         /* set the final state to point to itself */
         final -> lptr = final;
         /* and label the edge with the token */
         final -> llabel = token;
         final -> linst = inst;
            /****************************/
            /* A+ ==>       A           */
            /*         [S]----->[F]-+   */     
            /*                  ^   |A  */ 
            /*                  |___|   */
            /****************************/
         break;
   }
   /* invoke function which allocates memory for a FSAid */
   startid = buildid();
   /* set "startid" to point to the start state of the FSA just built */
   startid -> startptr = start;
   /* set "startid" to point to the final state of the FSA just built */
   startid -> finalptr = final;
         /****************************/
         /*  [ID]--->[S]- ... ->[F]  */     
         /*    |                 ^   */
         /*    |_________________|   */ 
         /****************************/
   /* return the pointer to the FSAid of the FSA just built */
   return(startid);
}
/************************************************************************/
/************************************************************************/
/* LOWGRP inputs a subgroup of an expression whose tokens have pre-     */
/* viously been "FSAtokened" and processes these FSAtokens with their   */
/* connectors, building an FSA equivalent to the "content" of the       */
/* current subgroup.  This procedure then passes this "subgroup"FSA     */
/* along with the occurance indicator on the subgroup to another process*/
/* which builds an FSA equivalent to the "entire" subgroup, repalcing   */
/* the subgroup with an FSAid pointer pointing to the newly built ,more */
/* complex, FSA.                                                        */
/************************************************************************/
void lowgrp(iptr, nest)
ITEM *iptr;
int nest;
{
   int connector,occindongrp;
   STATEID *FSAid;/* the "ultimate" FSAid for the subgroup */
   STATEID *FSAtokid;/* the FSAtokens from the subgroup being */
                     /* added to the "ultimate" FSAid for the subgroup */

   /* invokes procedure which will strip the GRPO from the subgroup */
   stripunit(INT,iptr);
   /* invokes function which allocates memory for a FSAid */
   FSAid = buildid();
   /* invokes a function to get and strip current /*
   /* FSAtoken from the subgroup */
   FSAtokid = getFSAtoken(iptr);
   /* for the first FSAtoken stripped from the subgroup, */
   /* simply set the "ultimate" FSAid to point to it.    */
   /* set FSAid to point to the first FSAtoken's start state */
   FSAid -> startptr = FSAtokid -> startptr;
   /* and set FSAid to plint to the first FSAtoken's final state */
   FSAid -> finalptr = FSAtokid -> finalptr;
   free((char *)FSAtokid);   
   /* while not end of subgroup... */
   while((connector = getconnector(iptr)) != GRPC){
      /* invokes a function to get and strip current connector from subgroup */
      /* invokes a function to get and strip next FSAtoken from subgroup */
      FSAtokid = getFSAtoken(iptr);
      /* invokes a function to build a new "ultimate" FSAid, returning */
      /* a FSAid pointer pointing to the newly built "unltimate" FSA. */
      FSAid = FSAgrp(FSAid,connector,FSAtokid);
   }
   /* if level of nesting > 1, then the occurance indicator along with */
   /* the "ultimate" FSA just built for the current subgroup must be   */
   /* processed                                                        */
/* INTERESTING */
   if(nest >= 1){
      /* invokes a function to get and strip the occurance indicator off */
      /* of the current subgroup                                         */
      occindongrp = getoccind(iptr);
      /* invokes a function taking the "ultimate" FSA and the occurance */
      /* indicator from the current subgroup and building an equivalent */
      /* new ultimate FSA for the "entire" subgroup, returning the FSAid*/
      /* pointer pointing to the new, more complex, FSA                 */
      FSAid = FSAgrpocid(FSAid,occindongrp);
   }
   /* invoke a procedure to insert the newly built "ultimate" FSAid */
   /* pointer into the expression where the current subgroup was located*/
   insertpointer(&iptr,FSAid);
   /* exit this procedure after entire subgroup has been processed and */
   /* replaced by an equivalent FSAid pointer                          */
}  
/************************************************************************/
/************************************************************************/
/* GETFSATOKEN gets the FSAtoken pointed to by "iptr", strips the space */
/* taken by the FSAtoken from the expression, and returns the FSAtoken  */ 
/************************************************************************/
STATEID *getFSAtoken(iptr)
ITEM *iptr;
{
   STATEID *stateid;/* will contain the FSAtoken */

   /* if "iptr" does not point to a FSAid, then execution error */
   /* in constructive algorithm                                 */
   if(iptr->itoken != POINTER)
      myexit(1,"FSA token id ponter not found");
   /* invoke procedure to strip the, -1, signalling a pointer */
   /* from the expression at "iptr"                           */
   stripunit(INT,iptr);
   /* set "stateid" to the current FSAtoken pointed to */
   stateid = iptr->ptoken;
   /* invoke procedure to strip the current FSAtoken from the expression */
   stripunit(PTR,iptr);
   /* return "stateid" which was assigned FSAtoken */
   return(stateid);
}
/************************************************************************/
/************************************************************************/
/* FSAGRP inputs the most recent "ultimate" FSAid and (connector,FSAid) */
/* pair, building a new, more complex, "ultimate" FSA, returning the    */
/* FSAid pointing to the "new" ultimate FSA.                            */
/************************************************************************/
STATEID *FSAgrp(FSAid,connector,FSAtokid)
STATEID *FSAid,*FSAtokid;
int connector;
{
   STATE *newstart, *newfinal;/* new start and final states */
                              /* of new "ultimate" FSA being built */
   STATEID *newstartid;/* new FSAid to point to FSA being built */

   switch(connector){
      /* if connector is the sequence operator ... */
      case SEQ:
         /* if the "ultimate" FSA's final state's left pointer is NULL ...*/
         if((FSAid->finalptr->lptr) == NULL){
            /* then the left pointer is set to point to the start */
            /* state of the FSAtokid */
            FSAid->finalptr->lptr = FSAtokid -> startptr;
            /* and the edge is marked EMPTY */
            FSAid->finalptr->llabel = EMPTY;
         }
         /* otherwise the left pointer of the "ultimate" FSA's final state */
         /* is assigned to something valid */
         else{
            /* so check the right pointer of the "ultimate FSA's final */
            /* and if not NULL ... */
            if((FSAid->finalptr->rptr) == NULL){
               /* then the right pointer is set to point to the start */
               /* state of the FSAtokid */
               FSAid->finalptr->rptr = FSAtokid -> startptr;
               /* and the edge is marked EMPTY */
               FSAid->finalptr->rlabel = EMPTY;
            }
            /* otherwise the final state of the "utimate" FSA is full */
            /* which means an error occurred in the constructive algorithm */
            else
               myexit(1,"no null ptr found in state");
         }
            /*********************************/
            /* [FSAid]---->[S]- ... ->[F]--+ */
            /*    |                    ^   | */
            /*    |____________________|  e| */
            /*                 +-----------+ */
            /*                 |             */
            /*                 V             */
            /* [FSAtokid]---->[S]- ... ->[F] */
            /*    |                       ^  */
            /*    |_______________________|  */
            /*********************************/

         /* set the "ultimate" FSAid to point to the finalstate of */
         /* the FSAtokid */
         FSAid->finalptr = FSAtokid->finalptr;
         /* release the memory of the FSAtokid */
         free((char *)FSAtokid);
            /***********************************/
            /* [FSAid]---->[S]- ... ->[F]--+   */
            /*    |                        |   */
            /*    |                   e    |   */
            /* +--+              +---------+   */
            /* |                 |             */
            /* |                 V             */
            /* | [FSAtokid]-||  [S]- ... ->[F] */
            /* |    |                       ^  */
            /* |    =                       |  */
            /* +----------------------------+  */
            /***********************************/
         /* return the "new" ultimate FSAid */
         return(FSAid);
      /* if connector is the OR operator ...*/
      case OR:
         /* allocate memory for a new start state */
         newstart = buildstate();
         /* allocate memory for a new final state */
         newfinal = buildstate();
         /* allocate memory for a new FSAid */
         newstartid = buildid();
         /* set new FSAid to point to new start state */
         newstartid->startptr = newstart;
         /* set new FSAid to point to new final state */
         newstartid->finalptr = newfinal;
         /* set new start state to point to start state of "ultimate" FSA */
         newstart->lptr = FSAid->startptr;
         /* mark the edge EMPTY */
         newstart->llabel = EMPTY;
         /* set new start state to point to start state of FSAtokid */
         newstart->rptr = FSAtokid->startptr;
         /* mark the edge EMPTY */
         newstart->rlabel = EMPTY;
      /*************************************************************/
      /*                            +---------------+              */
      /*                            |               |              */
      /*                            |               V              */
      /*                           e|  [FSAid]---->[S]- ... ->[F]  */
      /*                            |     |                    ^   */
      /*                            |     |____________________|   */
      /* [newstartid]--->[newstart]=+----------------+             */
      /*           |                      e          |             */
      /*           |                                 V             */
      /*           V                 [FSAtokid]---->[S]- ... ->[F] */
      /*         [newfinal]             |                       ^  */
      /*                                |_______________________|  */
      /*************************************************************/
         /* if left pointer of "ultimate" FSA's final state is NULL ..*/
         if((FSAid->finalptr->lptr) == NULL){
            /* set FSAid to point to the new final state */
            FSAid->finalptr->lptr = newfinal;
            /* and mark the edge as EMPTY */
            FSAid->finalptr->llabel = EMPTY;
         }
         /* otherwise the left pointer of the "ultimate" FSA's final state */
         /* is assigned valid data */
         else{
            /* if right pointer of "ultimate" FSA's final state is NULL ..*/
            if((FSAid->finalptr->rptr) == NULL){
               /* set FSAid to point to the new final state */
               FSAid->finalptr->rptr = newfinal;
               /* and mark the edge as EMPTY */
               FSAid->finalptr->rlabel = EMPTY;
            }
            else
               /* otherwise the final state of "ultimate" FSA is full */
               /* implying that an error has occurred in the constructive */
               /* algotithm */
               myexit(1,"no null ptr found in state");
         }
        /* if left pointer of FSAtokid's final state pointer is NULL ...*/ 
        if((FSAtokid->finalptr->lptr) == NULL){
            /* set FSAtoken's final state to the new final state */
            FSAtokid->finalptr->lptr = newfinal;
            /* and mark the edge as EMPTY */
            FSAtokid->finalptr->llabel = EMPTY;
         }
         /* otherwise the left pointer is already assigned */
         else{
            /* if right pointer of FSAtokid's final state pointer is NULL ...*/
            if((FSAtokid->finalptr->rptr) == NULL){
               /* set FSAtoken's final state to the new final state */
               FSAtokid->finalptr->rptr = newfinal;
               /* and mark the edge as EMPTY */
               FSAtokid->finalptr->rlabel = EMPTY;
            }
            else
               /* otherwise FSAtokid's final state is full implying an */
               /* error has occurred in the constructive algorithm */
               myexit(1,"no null ptr found in state");
         }
         /* release the memory of the  "old" ultimate FSAid */
         free((char *)FSAid);  /* we took cast out */
         /* release the memory of the FSAtoken's id */
         free((char *)FSAtokid); /* we took cast out */
   /*********************************************************************/
   /*                     +-----------------+                           */
   /* [newstartid]        |                 |                           */
   /*     |   |           |                 V                           */
   /*     |   |          e|    [FSAid]-||  [S]- ... ->[F]---+           */
   /*     |   |           |       |                         |e          */
   /*     |   |           |       =                         V           */
   /*     |   +->[newstart]                                 [newfinal]  */
   /*     |               |     =                           ^   ^       */
   /*     |              e|     |                           |e  |       */
   /*     |               |   [FSAtokid]-||  [S]- ... ->[F]-+   |       */
   /*     |               |                   ^                 |       */
   /*     |               |___________________|                 |       */
   /*     |_____________________________________________________|       */
   /*********************************************************************/
         /* return newstartid to become the new "ultimate" FSAid */
         return(newstartid);
   }
   return(0);
}        
/************************************************************************/
/************************************************************************/
/* FSAGRPOCID inputs an equivalent FSA of a subgroup and the occurance  */
/* indicator on that group and forms a new FSA for that "entire" sub-   */
/* group, returning a FSAid for the new, more complex, FSA.             */
/************************************************************************/
STATEID *FSAgrpocid(FSAid,occindongrp)
STATEID *FSAid;
int occindongrp;
{
   STATEID *newstartid;/* new FSAid, to be used if, optional, */
                       /* occurance indicator */
   STATE *newstart;/* new start state for FSA being built */
                   /* if occurance indicator is ,optional */

   STATE *newfinal;/* new final state for FSA being built */
                   /* if occurance indicator is required/repeatable */

   switch(occindongrp){
      /* if occurance indicator on the group is required ...*/
      case(REQ):
         /* simply return, no changes to current FSA is needed */
         return(FSAid);
      /* if occurance indicator on the group is required-repeatable ...*/
      case(PLUS):
         /* allocate new final state if plus */
         newfinal = buildstate();
         /* set newfinal to point to FSA's start state */
         newfinal->lptr = FSAid->startptr;
         /* and mark the edge as BACK */
         newfinal->llabel = BACK;
         /* if the FSA's final state's left pointer is NULL ...*/
         if((FSAid->finalptr->lptr) == NULL){
            /* set FSA's final state to point to new final state */
            FSAid->finalptr->lptr = newfinal;
            /* and mark the edge as EMPTY */
            FSAid->finalptr->llabel = EMPTY;
            /* update FSAid's finalptr to point to new final state */
            FSAid->finalptr = newfinal;
         }
         /* otherwise the left pointer of the final state has already */
         /* been assigned */
         else{
            /* if the FSA's final state's right pointer is NULL ...*/
            if((FSAid->finalptr->rptr) == NULL){
               /* set FSA's final state to point to new final state */
               FSAid->finalptr->rptr = newfinal;
               /* and mark the edge as EMPTY */
               FSAid->finalptr->rlabel = EMPTY;
               /* update FSAid's finalptr to point to new final state */
               FSAid->finalptr = newfinal;
            }
            else
               /* otherwise an error has occurred in the constructive */
               /* algorithm because the final state is full */
               myexit(1,"no null ptr found in state");
         }
            /*******************************/
            /*               __________    */
            /*              |    b     |   */
            /*              V          |   */
            /*  [FSAid]--->[S]- ... ->[F]  */     
            /*      |                  ^   */
            /*      |__________________|   */ 
            /*******************************/
         /* return the FSAid of the old FSA as the new FSAid */
         return(FSAid);
      /* if occurance indicator on the group is optional .. */
      case(REP):
      case(OPT):
         /* allocate memory for a new FSAid */
         newstartid = buildid();
         /* allocate memory for a new start state */
         newstart = buildstate();
         /* allocate memory for a new final state */
         newfinal = buildstate();
         /* set the new FSAid to point to the new start state */
         newstartid->startptr = newstart;

         /* set the new FSAid to point to the new final state */
         newstartid->finalptr = newfinal;

         /* set the new start state to point to the start state of the */
         /* current FSA */
         newstart->lptr = FSAid->startptr;
         /* and mark the edge as EMPTY */
         newstart->llabel = EMPTY;

         /* set the new start state to point to the new final state */
         newstart->rptr = newfinal;
         newstart->rlabel = EMPTY;

         /* set old final state to point to the new final state */
         if(FSAid->finalptr->lptr == NULL){
            FSAid->finalptr->lptr = newfinal;
            /* set old final state's left pointer to EMPTY */
            FSAid->finalptr->llabel = EMPTY;
         }
         else{
            if(FSAid->finalptr->rptr == NULL){
               FSAid->finalptr->rptr = newfinal;
               FSAid->finalptr->rlabel = EMPTY;
            }
            else{
               fprintf(stderr,"State pointer overflow occurred\n");
               exit(1);
            }
         }         
         /* release the memory of the old FSAid */
         free((char *)FSAid); /* we took cast out */

            /*******************************************************/
            /*                      +---------------+              */
            /* [newstartid]        e|               |              */
            /*     |  |             |               V              */
            /*     |  +--->[newstart]  [FSAid]-||  [S]- ... ->[F]  */     
            /*     |                |         |               ^ ^  */
            /*     |               e|         =               | |  */ 
            /*     |                +-------------------------+ |  */
            /*     |____________________________________________|  */
            /*******************************************************/
         /* return the new FSAid to replace the old FSAid */
         if(occindongrp == OPT)
            return(newstartid);
         /* Otherwise set newfinal state to point to new start state */
         newfinal->lptr = newstart;
         newfinal->llabel = BACK;
         return(newstartid);
   }
   /* code should never be reached, but if so, then an error in */
   /* the constructive algorithm */
   return(0);
}
