/*
 * greval - Evaluate boolian combinations of select patterns for grep
 *
 * Edits:
 *    02-Feb-85   lmf   Initial creation
 *    10-Oct-85   lmf   Merge with SOUNDEX modules
 *    20-Oct-85   lmf   Fixup Soundex for non-exact match
 *    25-Jan-86   lmf   Modify XOR symbol for BOL soundex match
 */
#include <stdio.h>
#include "grep.h"
/*
 * This code was originally written by Mike Lutz, modified by
 * Bob Harper and stripped down by Mike Fraser for inclusion in grep.
 */

extern char lbuf[LMAX] ;               /* line to match */
extern char pbuf[NPATS][PMAX] ;        /* patterns to match */
extern match() ;                       /* match line to pattern */

extern smatch() ;                      /* soundex match routine */
extern sflag ;                         /* soundex match flag */

static char *nxtch = EOS ;             /* Parser scan pointer */
static char *errmsg ;                  /* Gets error message */

/*++
 * Evaluate driver
 */
greval(string)                         /* <peval> ::= <query> <EOS> */
char  *string ;
{
   register int val ;

   nxtch = string ;
      val = query() ;
      if (skipws() != EOS)
         error("Ill-formed expression") ;
      return(val) ;
}

static
query()                                /* <or> ::= <and> { '||' <and> } */
{
   register int   c ;
   int  vl, vr ;

   vl = patand() ;
   while ((c = skipws()) == '|' ) {
      vr = patand() ;
#ifdef   decus                                       /* why this ? */
      vl = (vl != 0 || vr != 0) ? 1 : 0 ;
#else
      vl = vl || vr ;
#endif
   }
   ungetch() ;
   return(vl) ;
}

static
patand()                               /* <and> ::= <xor> { '&&' <xor> } */
{
   register int   c ;
   int     vl, vr ;

   vl = patxor() ;
   while ((c = skipws()) == '&' || c == '+') {
      vr = patxor() ;
#ifdef   decus
      vl = (vl != 0 && vr != 0) ? 1 : 0 ;
#else
      vl = vl && vr ;
#endif
   }
   ungetch() ;
   return(vl) ;
}

static
patxor()                               /* <xor> ::= <not> { '^' <not> } */
{
   int     vl, vr ;

   vl = patnot() ;
   while (skipws() == '~') {
      vr = patnot() ;
      vl = (vl == vr) ? 0 : 1 ;
   }
   ungetch() ;
   return(vl) ;
}

static
patnot()                               /* <not> ::= <factor> | <unop> <not> */
{
   register int   c ;

   if ((c = skipws()) == '!') {
      return(!patnot()) ;
   }
   ungetch() ;
   return(factor()) ;
}

static
factor()                            /* <factor> ::= <value> | '(' <query> ')' */
{
   int     val ;

   if (skipws() == '(') {
      val = query() ;
      if (skipws() != ')')
         error("Missing right parenthesis") ;
      return(val) ;
   }
   ungetch() ;
   return(patval()) ;
}

static
patval()                               /* <value> ::= <match> */
{
   register int   c, m ;

   c = skipws() ;
   if(sflag)
      m = smatch(c - 'A') ;
   else
      m = match(lbuf, &pbuf[c - 'A'][0]) ;
   return(m) ;
}

/*
 * support routines
 */
static
getch()                   /* return next character from the expression string */
{
   return(*nxtch++) ;
}

static
ungetch()                             /* Put back the last character examined */
{
   return(*--nxtch) ;
}

static
skipws()             /* Skip over any white space and return terminating char */
{
   register char c ;

   while ((c = getch()) <= ' ' && c != EOS)
       ;
   return(c) ;
}
