/*
 * parser.c,v 1.1 1994/01/28 17:21:39 franktor Exp
 *
 * parser.c 
 * 
 * Routines to parse SR RPN as well as description
 * of attribute sets and diagnostic sets
 *
 * Syntax parsed for RPN
 *   RPN 		::= operand | Operator RPN RPN 
 *   operand 		::= ResultSetID | AttributeList Term
 *   AttributeList	::= AttributeElement | AttributeList AttributeElement 
 *
 *   Operator		::= AND | OR | AND-NOT
 *   AttributeElement	::= ATTRIBUTE SET KEYWORD
 *   ResultSetId      	::= KEYWORD
 *   Term		::= VALUE
 *   
 * Syntax parsed for attributeset description
 *   AttrSet		::= ATTRTSET SetName SetOid BEGIN ASetDesc END
 *   ASetDesc		::= AttrDesc | ASetDesc AttrDesc
 *   AttrDesc		::= AttrName AttrType AttrVal
 * 
 *   SetName		::= VALUE
 *   SetOid		::= OID
 *   AttrName		::= VALUE
 *   AttrType		::= INTEGER
 *   AttrVal		::= INTEGER
 *
 * Syntax parsed for diagnostic sets
 *   DiagSet		::= DIAGSET SetName SetOid BEGIN DSetDesc END
 *   DSetDesc		::= DiagDesc | DSetDesc DiagDesc
 *   DiagDesc           ::= DiagVal DiagDesc
 *
 *   DiagVal		::= INTEGER
 *   DiagDesc		::= Text terminated with a newline character or a hash-sign
 *
*/

#include <sr-parser.h>
#include <malloc.h>
#include <string.h>

				/* Known attribute sets */
struct AttributeSet 	*attributeSets		= (struct AttributeSet *) NULL;
				/* Known diagnostic sets */
struct DiagSet		*diagnosticSets		= (struct DiagSet *) NULL;

FILE			*inpFile		= (FILE *) NULL;
char			*inpStr			= (char *) NULL;
char			*inpStrPtr;

int			lineNo			= 0;
int			charNo			= 0;

struct operatorElem *parseOperator ( char * ); 
struct operandElem *parseOperand ( char * ); 
struct attributeElem *parseAttributeElem ( char * ); 



/* utility routines for parsers */
      
void setInpFile ( FILE *f )      
{
   if ( !f )
   {
      LOG ( facUtil, llevExceptions, "parser, can't parse undefined file" );
      return;
   }
   
   inpFile = f;
   if ( inpStr )
   {
      free ( inpStr );
      inpStr = (char *) NULL;
      inpStrPtr = (char *) NULL;
   }
}

setInpStr ( char *s )
{
   inpFile = (FILE *) NULL;
   if ( inpStr )
      free ( inpStr );
   inpStrPtr = inpStr = strdup ( s );
}

int getChar ( )
{
   if ( inpFile )
      return getc(inpFile);
   else if ( *inpStrPtr )
      return *inpStrPtr++;
   else
      return EOF;
}

char *getToken ( )
{
   static char  c		= 0;
   static char	token[2048];
   char		*cp;
   int		skip		= 0;
   int		isquoted	= 0;

   if ( c == 0 )
      c = getChar();
   
   for ( ;(isspace ( c ) || skip == 1 || c == '#') && c != EOF; c = getChar () )
   {
      if ( c == '\n' )
      {
	 lineNo++;
	 charNo = 0;
	 skip = 0;
      }
      else
	 charNo++;
      if ( c == '#' )
	 skip = 1;
   }
   
   if ( c == EOF )
      return (char *) NULL;
   
   cp = token;
   if ( c == '"' )
   {
      c = getChar();
      isquoted = 1;
   }
   while ( c && ((!(isspace(c))) || (isquoted && (isspace(c) && c!='\n'))) )
   {
      *cp++ = c;
      c = getChar();
      if ( c == '"' )
      {
	 isquoted = 0;
	 c = getChar ();
	 break;			/* a quoted string must always begin and end with a quote */
      }
   }
   *cp = '\0';

   return token;
}

void reportError ( char *msg, char *tok )
{
   printf ( "Parser found syntax error at position %d on line %d: %s - last token read \"%s\"\n",
	    charNo, lineNo, msg, tok );
   LOG ( facUtil, llevExceptions,
	 "Parser found syntax error at position %d on line %d: %s - last token read \"%s\"",
	 charNo, lineNo, msg, tok );
}


/* attribute set parser */

Boolean parseAttrSet ( FILE *input )
{
   char			*tok;
   struct AttributeSet	*set;
   struct Attribute	*attr;

   setInpFile ( input );
   
   for ( tok = getToken(); tok && strcasecmp ( tok, "ATTRSET" ); tok = getToken() );
   if ( tok )
   {
      set = (struct AttributeSet *) smalloc ( sizeof (struct AttributeSet) );
      
      /* get name and OID of attribute set */
      tok = getToken();
      set->name = strdup ( tok );
      tok = getToken();
      set->oid = OID_dup ( OID_str2Oid ( tok ) );

      tok = getToken ();
      if ( strcasecmp ( tok, "BEGIN" ) )
      {
	 reportError ( "Expected to find BEGIN", tok );
	 return False;
      }

      for ( tok = getToken(); tok && strcasecmp ( tok, "END" ); tok = getToken() )
      {
	 attr = (struct Attribute *) malloc ( sizeof (struct Attribute) );
	 attr->name = strdup ( tok );
	 tok = getToken();
	 attr->type = atoi ( tok );
	 tok = getToken();
	 attr->value = atoi ( tok );
	 attr->set = set;

	 attr->next = set->attributes;
	 set->attributes = attr;
      }

      set->next = attributeSets;
      attributeSets = set;
   }

   return True;
}



/* RPN parser */

Boolean isAttributeElement ( char *tok )
{
   struct AttributeSet		*set;
   struct Attribute		*attr;

   for ( set = attributeSets; set; set = set->next )
      for ( attr = set->attributes; attr; attr = attr->next )
	 if ( !strcasecmp ( tok, attr->name ) )
	    return True;

   return False;
}


Boolean isResultSetId ( char *tok )
{
   return False;
}


termKind classifyToken ( char *tok )
{
   if ( (!tok) || (!*tok) )
      return _none;
   
   if ( !strcasecmp ( tok, "AND" ) )
      return _oprAND;
   else if ( !strcasecmp ( tok, "OR" ) )
      return _oprOR;
   else if ( !strcasecmp ( tok, "AND-NOT" ) )
      return _oprANDNOT;
   else if ( isAttributeElement ( tok ) )
      return _attributeElement;
   else if ( isResultSetId ( tok ) )
      return _resultSetId;
   else
      return _term;
}

struct rpnElem *parseRPN ( char *tok )
{
   struct rpnElem	*rpn	= (struct rpnElem *) malloc ( sizeof(struct rpnElem) );
   
   switch ( classifyToken ( tok ) )
   {
    /* Operand */
    case _resultSetId:
    case _attributeElement:
      rpn->isOperand = True;
      rpn->un.operand = parseOperand ( tok );
      break;

    /* Operator RPN RPN */
    case _oprAND:
    case _oprOR:
    case _oprANDNOT:
      rpn->isOperand = False;
      rpn->un.rpn.operator = parseOperator ( tok );
      rpn->un.rpn.rpn1 = parseRPN ( tok = getToken () );
      rpn->un.rpn.rpn2 = parseRPN ( tok = getToken () );
      break;

    default:
      reportError ( "Expected to find Operand or Operator", tok );
      exit ( 0 );
   }

   return rpn;
}

struct Attribute *parseAttribute ( char *tok )
{
   struct AttributeSet		*set;
   struct Attribute		*attr;

   for ( set = attributeSets; set; set = set->next )
      for ( attr = set->attributes; attr; attr = attr->next )
	 if ( !strcasecmp ( tok, attr->name ) )
	    return attr;

   reportError ( "Unknown attribute name", tok );

   return (struct Attribute *) NULL;
}

struct operandElem *parseOperand ( char *tok )
{
   struct operandElem	*opr	= (struct operandElem *) malloc ( sizeof ( struct operandElem ) );
   struct attributeElem *attr, *next;
   
   switch ( classifyToken ( tok ) )
   {
    /* ResultSetId */
    case _resultSetId:
      opr->isResultSet = True;
      opr->un.resultSetId = tok;
      break;

    case _attributeElement:
      opr->isResultSet = False;
      opr->un.attributesPlusTerm.attrList = next = (struct attributeElem *) NULL;
      while ( classifyToken ( tok ) == _attributeElement )
      {
	 attr = (struct attributeElem *) malloc ( sizeof ( struct attributeElem ) );
	 attr->attr = parseAttribute ( tok );
	 attr->next = (struct attributeElem *) NULL;
	 if ( !opr->un.attributesPlusTerm.attrList )
	    opr->un.attributesPlusTerm.attrList = attr;
	 else
	    next->next = attr;
	 next = attr;

	 tok = getToken();
      }
      opr->un.attributesPlusTerm.term = strdup ( tok );
      break;

    default:
      reportError ( "Expected to find resultSetId or attributeElement", tok );
      exit ( 0 );
   }

   return opr;
}

struct operatorElem *parseOperator ( char *tok )   
{
   struct operatorElem	*opr	= (struct operatorElem *) malloc ( sizeof ( struct operatorElem ) );
   
   switch ( classifyToken ( tok ) )
   {
    case _oprAND:
      opr->operator = AND;
      break;

    case _oprOR:
      opr->operator = OR;
      break;

    case _oprANDNOT:
      opr->operator = ANDNOT;
      break;

    default: break;
   }

   return opr;
}

struct attributeElem *parseAttributeElem ( char *tok )
{
   struct attributeElem		*a	= (struct attributeElem *) malloc (sizeof ( struct attributeElem ) );
   struct AttributeSet		*set;
   struct Attribute		*attr;

   for ( set = attributeSets; set; set = set->next )
      for ( attr = set->attributes; attr; attr = attr->next )
	 if ( !strcasecmp ( tok, attr->name ) )
	 {
	    a->attr = attr;
	    return a;
	 }

   return (struct attributeElem *) NULL;
}


/* diagnostic sets */
Boolean parseDiagSet ( FILE *input )
{
   char			*tok;
   struct DiagSet	*set;
   struct DiagMsg	*msg;
   
   setInpFile ( input );

   for ( tok = getToken(); tok && strcasecmp ( tok, "DIAGSET" ); tok = getToken() );

   if ( tok )
   {
      set = (struct DiagSet *) smalloc ( sizeof ( struct DiagSet ) );

      /* get name and OID of diagnostic set */
      tok = getToken ();
      set->name = strdup ( tok );
      tok = getToken ();
      set->oid = OID_dup ( OID_str2Oid ( tok ) );

      tok = getToken();
      if ( strcasecmp ( tok, "BEGIN" ) )
      {
	 reportError ( "Expected to find BEGIN", tok );
	 return False;
      }

      for ( tok = getToken (); tok && strcasecmp ( tok, "END" ); tok = getToken() )
      {
	 msg = (struct DiagMsg *) smalloc ( sizeof ( struct DiagMsg ) );
	 msg->condition = atoi ( tok );
	 tok = getToken ();
	 msg->msg = strdup ( tok );

	 msg->next = set->messages;
	 set->messages = msg;
      }

      set->next = diagnosticSets;
      diagnosticSets = set;
   }

   return True;
}


      
   
   

