%{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define YYDEBUG 1
#define YYERROR_VERBOSE

/*GLOBALS section */
char struct_name[255];
char * string_val;
FILE * fp,*hfp,*cfp; /* fp: the c program; hfp: the header file; cfp: the control file example */
char * line;
char  outstring[1000];
int cmtflag = 0;
int newflag = 0;
int nflag = 0;
int endflag = 0;

void yyerror(char *s){
   printf("ERROR: yyerror: %s\n",s);
}

void header(FILE *fp){
      fprintf(fp,"/* AUTOGENERATED structure input routine */\n");
      fprintf(fp,"#include <stdio.h>\n");
      fprintf(fp,"#include <stdlib.h>\n");
      fprintf(fp,"#include <time.h>\n");
      fprintf(fp,"#include <string.h>\n");
      fprintf(fp,"#include \"machine.h\"\n");
      fprintf(fp,"/*TO DO: MANUALLY ADD the header for the structure */\n");
      fprintf(fp,"/*TO DO: MANUALLY ADD strings or other structures not implemented */\n");
      fprintf(fp,"/*TO DO: MANUALLY REMOVE purely internal variables and flags (not to be read in) */\n");
}
void h_header(FILE *fp){
      fprintf(fp,"/* AUTOGENERATED header file for structure input routines */\n");
}

void prog(char * s,const char * strname){
      sprintf(s,"void input_%s_values(char * filename,struct %s *Struct_Ptr){\n",strname,strname);
}
void inp_intro(FILE *fp){
   fprintf(fp,"   char *line;\n");
   fprintf(fp,"   char *token;\n");
   fprintf(fp,"   FILE *fp;\n");
   fprintf(fp,"   char *sep;\n");
   fprintf(fp,"   int error;\n");
   fprintf(fp,"   int rflag = 0;\n");
   fprintf(fp,"   line = (char *)calloc(MAX_STRING_LEN,sizeof(char));\n");
   fprintf(fp,"   sep = strdup(\" ,;\\t\\n\\r\") ;\n");
   fprintf(fp,"   \n");
   fprintf(fp,"   /*********************************************************/\n");
   fprintf(fp,"   /* Open the control file                                 */\n");
   fprintf(fp,"   /*********************************************************/\n");
   fprintf(fp,"   if((fp = fopen(filename,\"r\")) == NULL) {\n");
   fprintf(fp,"      fprintf(stderr,\"ERROR: %s reader: can't open input file [%%s]\\n\",filename);\n",struct_name);
   fprintf(fp,"      return;\n");
   fprintf(fp,"    }\n");
   fprintf(fp,"\n");
   fprintf(fp,"   while (fgets(line, MAX_STRING_LEN, fp) != NULL) {\n");
   fprintf(fp,"      /* ignore comment and blank lines */\n");
   fprintf(fp,"      if(line[0]=='%%' || line[0]=='#'||(token = strtok(line,sep))==NULL) {\n");
   fprintf(fp,"	      continue;\n");
}

%}
%union{
int index;
double val;
char * name;
}
%token <val> NUMBER
%token <name> NAME POINTER KEY STRNAME OTHER STRSTART
%token <index> INDEX
%type <name> Name Key Pointer
%type <index> index Index
%%
input:  | input line ;

/* parse an ordinary structure member (int float or ca_float) */
member: Key Name Other {fprintf(stderr,"/* %s Member name: %s */\n",$1,$2);
                  fprintf(fp,"/*Input section for member:\n%s %s\n*/",$1, $2);
                  if (strcasecmp ($1,"int") == 0){
                     fprintf(cfp,"%-20s 1  /* %s %s */\n",$2,$1,$2);
                     fprintf(fp,"      }else if (strcasecmp(token,\"%s\")==0){\n",$2);
                     fprintf(fp,"         if ((token = strtok(NULL, sep)) != NULL){\n");
                     fprintf(fp,"            Struct_Ptr->%s = atoi(token);\n",$2);
                     fprintf(fp,"         }\n");
                  }else if (strcasecmp ($1,"float") == 0 || strcasecmp($1,"ca_float") ==0){
                     fprintf(cfp,"%-20s 1.0e-01  /* %s %s */\n",$2,$1,$2);
                     fprintf(fp,"      }else if (strcasecmp(token,\"%s\")==0){\n",$2);
                     fprintf(fp,"         if ((token = strtok(NULL, sep)) != NULL){\n");
                     fprintf(fp,"            Struct_Ptr->%s = (%s)atof(token);\n",$2,$1);
                     fprintf(fp,"         }\n");
                  } else if (strcasecmp ($1,"tomo_t") == 0){
                     fprintf(cfp,"%-20s 10000  /* %s %s */\n",$2,$1,$2);
                     fprintf(fp,"      }else if (strcasecmp(token,\"%s\")==0){\n",$2);
                     fprintf(fp,"         if ((token = strtok(NULL, sep)) != NULL){\n");
                     fprintf(fp,"            Struct_Ptr->%s = (%s)atoi(token);\n",$2,$1);
                     fprintf(fp,"         }\n");
                  } else if (strcasecmp ($1,"uchar") == 0){
                     fprintf(cfp,"%-20s 1  /* %s %s */\n",$2,$1,$2);
                     fprintf(fp,"      }else if (strcasecmp(token,\"%s\")==0){\n",$2);
                     fprintf(fp,"         if ((token = strtok(NULL, sep)) != NULL){\n");
                     fprintf(fp,"            Struct_Ptr->%s = (%s)atoi(token);\n",$2,$1);
                     fprintf(fp,"         }\n");
                  }else{
                     fprintf(fp,"/* not understood\n%s %s\n*/",$1, $2);
		  }

                 }
;

/* parse a pointer member - and create input for a character string */
pmember: Key Pointer Other {
                             fprintf(stderr,"/* %s Pointer member name: %s */\n",$1,$2);
                             fprintf(fp,"/* Input section for %s pointer: %s */ \n",$1,$2);
                             if(strcasecmp($1,"char") ==0 ){
                                fprintf(stderr,"/* Read in a string to the pointer */");

                                /* get the part of the name after the * and all spaces */
                                string_val=(strdup($2+1+strspn(($2+1)," ")));
                                fprintf(cfp,"%-20s this-is-a-string /* %s %s */\n",(string_val),$1,(string_val));
                                fprintf(fp,"      }else if (strcasecmp(token,\"%s\")==0){\n",(string_val));
                                fprintf(fp,"         if ((token = strtok(NULL, sep)) != NULL){\n");
                                fprintf(fp,"            sprintf(Struct_Ptr->%s,token);\n",(string_val));
                                fprintf(fp,"         }\n");
                                free(string_val);
                             }else{
                                fprintf(fp,"/* cannot input %s pointer %s */\n",$1,$2);
                             }
                           }

/* parse a (single index) array of int, float, ca_float or char */
array: Key Name Index Other { if ($3 == 0){
                              fprintf(stderr,"/* %s -- Can't do multi arrays yet */\n",$1);
                           }else if (strcasecmp($1,"char")==0){
                              fprintf(stderr,"/* Member %s string array %s index %i*/\n",$1,$2,$3);
                              fprintf(cfp,"%-20s this-is-a-string  /* %s %s */\n",$2,$1,$2);
                              fprintf(fp,"      }else if (strcasecmp(token,\"%s\")==0){\n",$2);
                              fprintf(fp,"         if ((token = strtok(NULL, sep)) != NULL){\n");
                              fprintf(fp,"            sprintf(Struct_Ptr->%s,token);\n",$2);
                              fprintf(fp,"         }\n");

                           }else if (strcasecmp($1,"int")==0 || (strcasecmp($1,"float")==0) || (strcasecmp($1,"ca_float")==0)){
                              fprintf(stderr,"/* Member %s array %s index %i*/\n",$1,$2,$3);
                              fprintf(fp,"/* Input loop for array: %s*/\n",$2);


                              fprintf(fp,"      }else if (strcasecmp(token,\"%s\")==0){\n",$2);
                              fprintf(fp,"         for(i=0;i<%i;i++){\n",$3);

                              if (strcasecmp ($1,"int") == 0){
                                 /* make an example entry for an array */
                                 fprintf(cfp,"%-20s ",$2);
                                 { int i; for(i=0;i<$3;i++) fprintf(cfp,"1 ");}
                                 fprintf(cfp," /* %s %s[%i] */\n",$1,$2,$3);
                                 fprintf(fp,"            if ((token = strtok(NULL, sep)) != NULL){\n");
                                 fprintf(fp,"               Struct_Ptr->%s[i] = atoi(token);\n",$2);
                                 fprintf(fp,"            }\n");

                              }else if (strcasecmp ($1,"float") == 0 || strcasecmp($1,"ca_float") == 0){
                                 /* make an example entry for an array */
                                 fprintf(cfp,"%-20s ",$2);
                                 { int i; for(i=0;i<$3;i++) fprintf(cfp,"1.0e-1 ");}
                                 fprintf(cfp," /* %s %s[%i] */\n",$1,$2,$3);
                                 fprintf(fp,"            if ((token = strtok(NULL, sep)) != NULL){\n");
                                 fprintf(fp,"               Struct_Ptr->%s[i] = (%s)atof(token);\n",$2,$1);
                                 fprintf(fp,"            }\n");
                              }


                              fprintf(fp,"         }/* end of array input loop */\n");
                              }
                           }
;
Index: index {$$ = $1;}
       | Index index {$$=0;}
;

index: INDEX {printf("Parser: index %i\n",$1);}
;

endstr: STRNAME {fprintf(fp,"\n      }\n   }\nfree(line);\nfclose(fp);\n}\n/* End of structure %s */\n",$1);}
;
strstart: STRSTART STRNAME {printf("Parser: strname %s\n",$2);
                            if(strlen($2) > 253){
                               sprintf(struct_name,"very_long_name_struct\0");
                            }else{
                               sprintf(struct_name,"%s\0",$2);
                            }
                            printf("Starting input routine for structure %s\n");
                            fprintf(fp,"/* start of structure %s */\n",$2);
                            fprintf(hfp,"#ifndef %s_reader_h\n",$2);
                            fprintf(hfp,"#define %s_reader_h\n",$2);
                            prog(outstring,$2);
                            fprintf(fp,"%s",outstring);
                            fprintf(fp,"   int i;\n\n");
                            inp_intro(fp);
                            outstring[strlen(outstring)-2] = ';';
                            fprintf(hfp,"extern %s",outstring);
                           }
;
info:  Name {;} | Pointer {;} | Key {;} | Other {;} | Number {;} ;
line: array | strstart | endstr | member | pmember | info | info line;

Name: NAME {printf("parser: Name: %s\n",$1)}
;

Pointer: POINTER {printf("parser: Pointer: %s\n",$1)}
;

Number: NUMBER {printf("parser: Number %f\n",$1)}
;

Key: KEY {printf("parser: Key: %s\n",$1)}
;

Other: OTHER {printf("parser: Other: %s\n",$1)}
;

%%


/*
int yylex(void){
   char * token;
   int return_val;

   if (newflag == 0){
      newflag = 1;
      token = strtok(line," ,\t");
   }else{
      token = strtok(NULL," ,\t");
   }

   if (token == NULL){
      return 0;
   }


   if ( token[0] == '/' || token[0] == '#' || token[0] == '%'){
       return_val = CMT;
       yylval.name = strdup(token);
   }else if(isalpha(token[0])){
      yylval.name = strdup(token);
      return_val = NAME;
   }else{
      yylval.val = atof(token);
      return_val= NUMBER;
   }
   return (return_val);
}
*/

int main(int argc, char * argv[]){
    char command[1000];
    fp = fopen("P_out.c","w");
    hfp = fopen("P_out.h","w");
    cfp = fopen("Struct.in","w");
    fprintf(fp,"/*$Id: make_structure_reader.y 1030 2007-07-11 16:13:02Z  $*/\n");
    fprintf(hfp,"/*$Id: make_structure_reader.y 1030 2007-07-11 16:13:02Z  $*/\n");
    header (fp);
    h_header(hfp);
    /*print a usage message */
    printf("%s: Input a c structure definition from standard input, and\n",argv[0]);
    printf("    output a c program to read the structure from a control file\n");
    printf("    and an example control file. Some manual fine tuning of the results\n");
    printf("    will be necessary.\n\n");
    printf("    Files: P_out.c -- structure reading routine\n");
    printf("           P_out.h -- Prototype header for the routine\n");
    printf("           Struct.in -- example control file (blank)\n");
    printf("    Example usage: %s < control.h > messages.txt\n\n",argv[0]);
    /*                    */
    while (endflag == 0){
       printf("\n\n***\nParsing a line (control-d to finish) ...  \n");
       yyparse();
       printf("End flag %i\n",endflag);
    }
    fprintf(hfp,"#endif /* %s_reader_h */\n",struct_name);
    fclose (fp);
    fclose (hfp);
    fclose (cfp);
    sprintf(command,"cp P_out.c %s_reader.c \n",struct_name);
    system(command);
    sprintf(command,"cp P_out.h %s_reader.h \n",struct_name);
    system(command);
    sprintf(command,"cp Struct.in %s_input.in \n",struct_name);
    system(command);
    printf("Finished making %s_reader files (.c and .h)\nNow edit the files before using them.\n",struct_name);
    printf("%s_reader.c\n",struct_name);
    return(0);
}

