/* A grammar file for parsing of a DDL file; incomplete, designed simply
to extract cifnames and variables.  This file is a prototype for an
automatically created file */
%{
#define CIFVARDEC        /* define variables in this file */
#include <stdio.h>
#include <math.h>
#include "cifvars.h"
#define errornum cifcmnptr->errornum
#define errormes cifcmnptr->errormes
/* external function for printing errors */

extern int yylex(void);
int yyerror(char *errmes);

/* local variables */
struct {
void * location;
void * esdlocation; /* if there is any attached esd */
int size;
int maxentries;
int checktype;      /* for checking data type */
} attdata[100];     /* information on each loop item */

int noinloop = 0;
int looppos = 0;
double * doubleptr;
int packets = 0;        /* count the packets */
char junk[81];      /* for storing unknown datatypes */
char safestr[40];   /* for controlling size of error message */
char recentitem[40]; /* latest item, for error messages */
%}

/* Bison declarations */
%union{
int flag;         /* for flagging type of loop blocks */
char item[81];         /* for single items */
double number[2]; /* including esd */
}

%token <item> ITEMNAME     /* a cif item */
%token <item> LOOP         /* start looping */
%token <item> ITEMVALUE    /* the value for the item */
%token <item> ITEMDEF      /* data block name */
%token <item> VARNAME      /* variable name in final program */
%token <item> VARTYPE      /* type of variable */
%token <item> NAME         /* name of unknown cif item follows*/ 
%token <item> UNKATTR      /* an unknown attribute name */
%token <item> DATASTRING   /* a string of data */
%token <item> QUESTION     /* a question mark */
%token <number> DNUM       /* a number */
%token <item> C_ATOM_SITE_ANISO_LABEL /* Automatically created */
%token <item> C_ATOM_SITE_ANISO_RATIO /* Automatically created */
%token <item> C_ATOM_SITE_ANISO_U_11 /* Automatically created */
%token <item> C_ATOM_SITE_ANISO_U_12 /* Automatically created */
%token <item> C_ATOM_SITE_ANISO_U_13 /* Automatically created */
%token <item> C_ATOM_SITE_ANISO_U_22 /* Automatically created */
%token <item> C_ATOM_SITE_ANISO_U_23 /* Automatically created */
%token <item> C_ATOM_SITE_ANISO_U_33 /* Automatically created */
%token <item> C_REFINE_LS_EXTINCTION_METHOD /* Automatically created */
%token <item> C_REFLNS_NUMBER_TOTAL /* Automatically created */
%token <item> C_REFLNS_NUMBER_OBSERVED /* Automatically created */

%type <item> input attributeassoc loopblock keyvaluepair
%type <item> anattribute looptop loopbottom 
%type <number> anumber
%%

/* Grammar rules */
input:  attributeassoc      /* file is sequence of lists of associations */
        | input attributeassoc    
        ;    

attributeassoc: keyvaluepair
                {
                strncpy(recentitem,$1,40); recentitem[39]=0x00;
                }
	       | loopblock
                {
                strncpy(recentitem,$1,40); recentitem[39]=0x00;
                }
               | error
                {
                if(errornum == 0)    /* no other messages */
                  {
                   errornum = 5;
                   sprintf(errormes, "Parse error: latest item name %s\n",recentitem);
                   }
                }
             ;

loopblock: LOOP looptop loopbottom
         {
         if(looppos!=0 && errornum == 0) {   /* loop mismatch */
         strncpy(safestr, $2, 40);
         sprintf(errormes, "Looped item miscount: %s, packets %d\n",safestr,packets);
         errornum = 1;  /* continue on anyway */
         }       
	 /* set everything back to zero */
	 noinloop = 0; looppos = 0; packets = 0;
	 }
         | LOOP looptop error         /* no values */
         {
         if(errornum == 0)
              {
              strncpy(safestr, $2, 40);
              sprintf(errormes, "No loop values: %s\n",safestr);
              errornum = 1;
              }
         }
	 ;

looptop: anattribute
         {
	     strncpy($$,$1,80);  /* store for later */
             $$[80] = 0x00;  /* terminate correctly */
             /* first time through; initialise */
	     noinloop = 1;
	 }
         | looptop anattribute
	 {
	     noinloop++;
	 }
         ;

loopbottom: loopvalue
         {
	   attdata[looppos].location += attdata[looppos].size;/* for next time*/
	   attdata[looppos].esdlocation += attdata[looppos].size;
           if(noinloop>1) looppos = 1;
           else packets = 1;
	 }
         | loopbottom loopvalue
         {
             attdata[looppos].location += attdata[looppos].size; /* next time*/
	     attdata[looppos].esdlocation += attdata[looppos].size;
	     looppos++; 
	     if(looppos==noinloop)
	     { 
                 if(packets>=attdata[looppos-1].maxentries)
		 {
		     yyerror("Out of variable range in loop\n");
                     return(-1);
		 }
		 looppos -= noinloop;
                 packets++;
	     }
	 }

loopvalue: DATASTRING
           {
           if(attdata[looppos].checktype != 1 &&
           attdata[looppos].checktype != 0) {
             if(errornum == 0) {
               strncpy(safestr,$1,40);
               sprintf(errormes, "String %s in loop instead of number.\n",safestr);
               errornum = 2;
               }
             }
             else {
               strncpy(attdata[looppos].location,$1,80); /* store the string */
             }
           }
           | anumber
           {
               if(attdata[looppos].checktype != 2 &&
               attdata[looppos].checktype != 0) {
                 if(errornum == 0) {
                   sprintf(errormes, "Number %f instead of string in loop.\n",$1[0]);
                   errornum = 3;
                 }
               } else {
               doubleptr = (double*) attdata[looppos].location;
               *doubleptr = $1[0];
             doubleptr = (double*) attdata[looppos].esdlocation;
             *doubleptr = $1[1];
             }
           }
           | QUESTION
           {
           }
           ;

anumber: DNUM
         ;

/* the following lines are automatically generated based on a search
of the specified dictionary file */

keyvaluepair: NAME DATASTRING      /* something we don't know about */
              {
/*              printf("%s + string %s\n",$1,$2); */
               strncpy($$,$1,40);  /* store for errors */
              }
              | NAME anumber
              {
/*              printf("%s + number %f\n",$1,$2[0]); */
               strncpy($$,$1,40);  /* store for errors */
              }
              | NAME QUESTION
              {
               strncpy($$,$1,40);  /* store for errors */
              }
             | C_ATOM_SITE_ANISO_LABEL QUESTION
               {
         strncpy($$,$1,40);
     }         | C_ATOM_SITE_ANISO_LABEL error
    {
               if(errornum == 0) {     /* no previous error */
               strncpy(safestr,$1,40);
               sprintf(errormes,"Type mismatch: %s\n",safestr);
               errornum = 4;
               }
             }
      | C_ATOM_SITE_ANISO_LABEL DATASTRING
     {
             strncpy(cifcmnptr->mylabel[0],$2,80);
             }
             | C_ATOM_SITE_ANISO_RATIO QUESTION
               {
         strncpy($$,$1,40);
     }         | C_ATOM_SITE_ANISO_RATIO error
    {
               if(errornum == 0) {     /* no previous error */
               strncpy(safestr,$1,40);
               sprintf(errormes,"Type mismatch: %s\n",safestr);
               errornum = 4;
               }
             }
      | C_ATOM_SITE_ANISO_RATIO anumber
     {
             cifcmnptr->atrat[0] = $2[0];             cifcmnptr->atratesd[0] = $2[1];
             }
             | C_ATOM_SITE_ANISO_U_11 QUESTION
               {
         strncpy($$,$1,40);
     }         | C_ATOM_SITE_ANISO_U_11 error
    {
               if(errornum == 0) {     /* no previous error */
               strncpy(safestr,$1,40);
               sprintf(errormes,"Type mismatch: %s\n",safestr);
               errornum = 4;
               }
             }
      | C_ATOM_SITE_ANISO_U_11 anumber
     {
             cifcmnptr->atsiteu[0][0] = $2[0];             cifcmnptr->atsiteuesd[0][0] = $2[1];
             }
             | C_ATOM_SITE_ANISO_U_12 QUESTION
               {
         strncpy($$,$1,40);
     }         | C_ATOM_SITE_ANISO_U_12 error
    {
               if(errornum == 0) {     /* no previous error */
               strncpy(safestr,$1,40);
               sprintf(errormes,"Type mismatch: %s\n",safestr);
               errornum = 4;
               }
             }
      | C_ATOM_SITE_ANISO_U_12 anumber
     {
             cifcmnptr->atsiteu[0][1] = $2[0];             cifcmnptr->atsiteuesd[0][1] = $2[1];
             }
             | C_ATOM_SITE_ANISO_U_13 QUESTION
               {
         strncpy($$,$1,40);
     }         | C_ATOM_SITE_ANISO_U_13 error
    {
               if(errornum == 0) {     /* no previous error */
               strncpy(safestr,$1,40);
               sprintf(errormes,"Type mismatch: %s\n",safestr);
               errornum = 4;
               }
             }
      | C_ATOM_SITE_ANISO_U_13 anumber
     {
             cifcmnptr->atsiteu[0][2] = $2[0];             cifcmnptr->atsiteuesd[0][2] = $2[1];
             }
             | C_ATOM_SITE_ANISO_U_22 QUESTION
               {
         strncpy($$,$1,40);
     }         | C_ATOM_SITE_ANISO_U_22 error
    {
               if(errornum == 0) {     /* no previous error */
               strncpy(safestr,$1,40);
               sprintf(errormes,"Type mismatch: %s\n",safestr);
               errornum = 4;
               }
             }
      | C_ATOM_SITE_ANISO_U_22 anumber
     {
             cifcmnptr->atsiteu[0][3] = $2[0];             cifcmnptr->atsiteuesd[0][3] = $2[1];
             }
             | C_ATOM_SITE_ANISO_U_23 QUESTION
               {
         strncpy($$,$1,40);
     }         | C_ATOM_SITE_ANISO_U_23 error
    {
               if(errornum == 0) {     /* no previous error */
               strncpy(safestr,$1,40);
               sprintf(errormes,"Type mismatch: %s\n",safestr);
               errornum = 4;
               }
             }
      | C_ATOM_SITE_ANISO_U_23 anumber
     {
             cifcmnptr->atsiteu[0][4] = $2[0];             cifcmnptr->atsiteuesd[0][4] = $2[1];
             }
             | C_ATOM_SITE_ANISO_U_33 QUESTION
               {
         strncpy($$,$1,40);
     }         | C_ATOM_SITE_ANISO_U_33 error
    {
               if(errornum == 0) {     /* no previous error */
               strncpy(safestr,$1,40);
               sprintf(errormes,"Type mismatch: %s\n",safestr);
               errornum = 4;
               }
             }
      | C_ATOM_SITE_ANISO_U_33 anumber
     {
             cifcmnptr->atsiteu[0][5] = $2[0];             cifcmnptr->atsiteuesd[0][5] = $2[1];
             }
             | C_REFINE_LS_EXTINCTION_METHOD QUESTION
               {
         strncpy($$,$1,40);
     }         | C_REFINE_LS_EXTINCTION_METHOD error
    {
               if(errornum == 0) {     /* no previous error */
               strncpy(safestr,$1,40);
               sprintf(errormes,"Type mismatch: %s\n",safestr);
               errornum = 4;
               }
             }
      | C_REFINE_LS_EXTINCTION_METHOD DATASTRING
     {
             strncpy(cifcmnptr->extmet,$2,80);
             }
             | C_REFLNS_NUMBER_TOTAL QUESTION
               {
         strncpy($$,$1,40);
     }         | C_REFLNS_NUMBER_TOTAL error
    {
               if(errornum == 0) {     /* no previous error */
               strncpy(safestr,$1,40);
               sprintf(errormes,"Type mismatch: %s\n",safestr);
               errornum = 4;
               }
             }
      | C_REFLNS_NUMBER_TOTAL anumber
     {
             cifcmnptr->reftot[0] = $2[0];             cifcmnptr->reftotesd[0] = $2[1];
             }
             | C_REFLNS_NUMBER_OBSERVED QUESTION
               {
         strncpy($$,$1,40);
     }         | C_REFLNS_NUMBER_OBSERVED error
    {
               if(errornum == 0) {     /* no previous error */
               strncpy(safestr,$1,40);
               sprintf(errormes,"Type mismatch: %s\n",safestr);
               errornum = 4;
               }
             }
      | C_REFLNS_NUMBER_OBSERVED anumber
     {
             cifcmnptr->reftot[1] = $2[0];             cifcmnptr->reftotesd[1] = $2[1];
             }
          ;     /* end of simple processes */

/* When an item name is detected inside a loop, a pointer to the beginning
of the array corresponding to that item is created.  If that item has not
been declared as an array variable, an error should be registered. */

anattribute: NAME    /* an unknown name */
             {
                attdata[noinloop].location = junk;
                attdata[noinloop].size = 0;
                attdata[noinloop].maxentries = 100000; /* not used */
                attdata[noinloop].esdlocation = junk;
                attdata[noinloop].checktype = 0;
             }
             | C_ATOM_SITE_ANISO_LABEL
             {
             /* store name for possible use in error messages */
                strncpy($$,$1,40);
                $$[40] = 0x00;
             /* set data pointer to here */
    attdata[noinloop].location = (char*) &cifcmnptr->mylabel[0];
    attdata[noinloop].size = sizeof(cifstring);
    attdata[noinloop].maxentries = MYLABELMAX  ;    attdata[noinloop].checktype = 1;
             }
             | C_ATOM_SITE_ANISO_RATIO
             {
             /* store name for possible use in error messages */
                strncpy($$,$1,40);
                $$[40] = 0x00;
             /* set data pointer to here */
    attdata[noinloop].location = (char*) &cifcmnptr->atrat[0];
    attdata[noinloop].size = sizeof(double);
    attdata[noinloop].maxentries = ATRATMAX  ;    attdata[noinloop].checktype = 2;
    attdata[noinloop].esdlocation = (char*) &cifcmnptr->atratesd[0];
             }
             | C_ATOM_SITE_ANISO_U_11
             {
             /* store name for possible use in error messages */
                strncpy($$,$1,40);
                $$[40] = 0x00;
             /* set data pointer to here */
    attdata[noinloop].location = (char*) &cifcmnptr->atsiteu[0][0];
    attdata[noinloop].size = sizeof(atsiteutype);
    attdata[noinloop].maxentries = ATSITEUMAX  ;    attdata[noinloop].checktype = 2;
    attdata[noinloop].esdlocation = (char*) &cifcmnptr->atsiteuesd[0][0];
             }
             | C_ATOM_SITE_ANISO_U_12
             {
             /* store name for possible use in error messages */
                strncpy($$,$1,40);
                $$[40] = 0x00;
             /* set data pointer to here */
    attdata[noinloop].location = (char*) &cifcmnptr->atsiteu[0][1];
    attdata[noinloop].size = sizeof(atsiteutype);
    attdata[noinloop].maxentries = ATSITEUMAX  ;    attdata[noinloop].checktype = 2;
    attdata[noinloop].esdlocation = (char*) &cifcmnptr->atsiteuesd[0][1];
             }
             | C_ATOM_SITE_ANISO_U_13
             {
             /* store name for possible use in error messages */
                strncpy($$,$1,40);
                $$[40] = 0x00;
             /* set data pointer to here */
    attdata[noinloop].location = (char*) &cifcmnptr->atsiteu[0][2];
    attdata[noinloop].size = sizeof(atsiteutype);
    attdata[noinloop].maxentries = ATSITEUMAX  ;    attdata[noinloop].checktype = 2;
    attdata[noinloop].esdlocation = (char*) &cifcmnptr->atsiteuesd[0][2];
             }
             | C_ATOM_SITE_ANISO_U_22
             {
             /* store name for possible use in error messages */
                strncpy($$,$1,40);
                $$[40] = 0x00;
             /* set data pointer to here */
    attdata[noinloop].location = (char*) &cifcmnptr->atsiteu[0][3];
    attdata[noinloop].size = sizeof(atsiteutype);
    attdata[noinloop].maxentries = ATSITEUMAX  ;    attdata[noinloop].checktype = 2;
    attdata[noinloop].esdlocation = (char*) &cifcmnptr->atsiteuesd[0][3];
             }
             | C_ATOM_SITE_ANISO_U_23
             {
             /* store name for possible use in error messages */
                strncpy($$,$1,40);
                $$[40] = 0x00;
             /* set data pointer to here */
    attdata[noinloop].location = (char*) &cifcmnptr->atsiteu[0][4];
    attdata[noinloop].size = sizeof(atsiteutype);
    attdata[noinloop].maxentries = ATSITEUMAX  ;    attdata[noinloop].checktype = 2;
    attdata[noinloop].esdlocation = (char*) &cifcmnptr->atsiteuesd[0][4];
             }
             | C_ATOM_SITE_ANISO_U_33
             {
             /* store name for possible use in error messages */
                strncpy($$,$1,40);
                $$[40] = 0x00;
             /* set data pointer to here */
    attdata[noinloop].location = (char*) &cifcmnptr->atsiteu[0][5];
    attdata[noinloop].size = sizeof(atsiteutype);
    attdata[noinloop].maxentries = ATSITEUMAX  ;    attdata[noinloop].checktype = 2;
    attdata[noinloop].esdlocation = (char*) &cifcmnptr->atsiteuesd[0][5];
             }
          ;

%%

/* Extra C code */
int yyerror(char *arg)
{
/* don't print anything as we have a better method */
if(errornum == 0) {   /* no previous error */
strncpy(errormes, arg, 20);
strncat(errormes, " Last item: ",12);
strncat(errormes, recentitem, 40);
strncat(errormes, "\n",2);
errornum = 5;  /* parse error */
}
return(0);
}

