#define _P_DOWN "!"
#define _P_OK (c && c!=')')

char *_P_ERR[2];
WFF *_P_stak, *_P_dummy = 0;

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

WFF *parse( fla, Pstak, cn)  
char fla[];                   /**  Text of formula to be parsed  **/
WFF Pstak[];                  /**  Target array of subformulas   **/
char *cn[];                   /**  Available connectives         **/
{
   int i=0,j=0;
   
   _P_stak = Pstak;
   while ( fla[i] && fla[i] != '\n' ) if ( fla[i++] != ' ' ) 
   fla[j++] = fla[i-1];  fla[j] = '\0';
   
   i = s_parse( fla, cn );  if (i) return(Pstak+i);
   
   
   printf("\n ERROR: "); puts(*_P_ERR);
   for ( i = 0; i < _P_ERR[1]-fla; i++ ) printf(" ");
   puts(_P_DOWN);  puts(fla); return(0);
}

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

#define ERROR(s,ws) { *_P_ERR=s; _P_ERR[1]=ws; return(0); }

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

int s_parse( fla, cn )  char fla[], *cn[];
{
   int sbf[20], pptr=0, oldptr, ns=0, i,j;
   char dcn[19], c;
   
   c = *fla;
   while (_P_OK)
   {
      oldptr = pptr;
      while (strchr(cn[1],(c=fla[pptr++]))) ; i = pptr-1;
      if (islower(c) || strchr(*cn,c)) 
      sbf[ns] = Loc(c, _P_dummy, _P_dummy);
      else if (c == '(' || c == '.')
      {
         if (!(sbf[ns] = s_parse( fla+pptr, cn,_P_stak))) return(0);
         j = Match(fla+pptr-1);  if (!j) return(0);
         pptr += j-1;
      }
      else ERROR("This can't begin a subformula", fla+pptr-1)
      if (strchr(cn[1], fla[oldptr]))
      while (i > oldptr) 
      sbf[ns] = Loc(fla[--i], _P_dummy, _P_stak+sbf[ns]);
      c = fla[pptr];
      if (_P_OK)
      {
         if (c == '-' && fla[pptr+1] == '>') c = fla[++pptr];
         if (strchr(cn[2],c)) dcn[ns++] = c; else
         {  printf("Bad character %c\n", c);
         ERROR("Dyadic connective expected here", fla+pptr) }
         c = fla[++pptr];
         if (!_P_OK) ERROR("Subformula expected", fla+pptr)
      }
   }
   return(Finish(sbf, dcn, ns, cn[2]));
}

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

int Match( start ) char *start;
{
   int i;
   
   for (i = 1; start[i] && start[i] != ')'; i++)
   if (start[i] == '(') i += Match(start+i)-1;
   if (*start == '.') return(i);
   if (!start[i]) ERROR("Unmatched left parenthesis", start)
   return(i+1);
}

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

int Finish( subf, conn, tot, dyads )
            int subf[];        /**  Offsets of main subformulas  **/
            char conn[];       /**  Corresponding connectives    **/
            int tot;           /**  Number of subformulas        **/
            char dyads[];      /**  Available dyadic connectives **/
{
   int i, m=0;
   char *sk;
   
   if (!tot) return(*subf);
   sk = dyads;
   for (i = 0; i < tot; i++)
   if (strchr(dyads,conn[i]) >= sk)
   {
      m = i;  sk = strchr(dyads,conn[i]);
   }
   i = m+1;
   return(Loc(conn[m], _P_stak+Finish(subf, conn, m, dyads),
              _P_stak+Finish(subf+i, conn+i, tot-i, dyads)));
}

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

int Loc( mn, lft, rgt )  
         char mn;                  /**  Main connective of sbfml  **/
         WFF *lft, *rgt;           /**  Pointers left and right   **/
{
   int i;
   
   for (i = 0; (_P_stak+i)->sym; i++)
   if ( (_P_stak+i)->sym == mn && (_P_stak+i)->lsub == lft
                            && (_P_stak+i)->rsub == rgt )
   return(i);
   (_P_stak+i)->sym = mn; 
   (_P_stak+i)->lsub = lft;
   (_P_stak+i)->rsub = rgt;  
   return(i);
}
