
LABEL ([ \t]*\/\/[ \t]*[+]{3,}[[:print:]]*)
IDENTIFIER ("(GENERATED CODE HERE)")

%{
  #include<stdio.h>
  #include<stdarg.h>
  #include"pns.h"
  #include"codegen.h"

  static const char lntxt[] = LINEDIR;
  static int flag, skip, i, j, k, line, lntxtlen;
  static va_list param;
  static FILE *out;
  static char *stmp, cc, *fileName;
  static cblock bl;
  static char *inclname;

  void mfprint(char *str, ...) { // updates line based on the format string
    int ii;
    va_list par;

    for(ii = 0; str[ii]; ii++)
      line += (str[ii] == '\n');

    va_start(par, str);
    vfprintf(out, str, par);
    va_end(par);
  }

%}


%%

\#include\"spcommon\.h\"\/\/\-\-\-[^\n]* {
                                   if(inclname) 
				     fprintf(out, "#include\"%s\"", inclname);
				   else
				     fputs("#include\"spcommon.h\"", out);
                                   }


{LABEL}/{IDENTIFIER} {
                       flag = 0; skip = 1;
		       // mfprint used in order to update 'line' automatically
                       mfprint("%s (BEGINNING OF CODE)\n", yytext);
		       for(i = 0; yytext[i] == ' ' || yytext[i] == '\t'; i++);
		       cc = yytext[i];
		       yytext[i] = 0; // get indentation string in yytext
		       bl = va_arg(param, cblock); // get string to insert
		       stmp = bl.text;
		       if(stmp) {
			 if(bl.file) {
			   mfprint("#line %d \"%s\"\n", bl.line, bl.file);
			   for(j = 0; stmp[j]; j++) {
			     fwrite(stmp+j, sizeof(stmp[j]), 1, out);
			     if(stmp[j] == '\r' || stmp[j] == '\n') {
			       fprintf(out, "%s", yytext); // print indentation
			       line += (stmp[j] == '\n');
			     }
			   }
			   mfprint("\n#line %d \"%s\"\n", line+2, fileName);
			 }
			 else { // look for LINEDIR requests
			   for(j = 0, k = 0; stmp[j]; j++, k++) {
			     if(stmp[j] == lntxt[k])
			       continue;
			     if(!lntxt[k]) { // a LINEDIR request was found
			       mfprint("\n#line %d \"%s\"\n",line+2, fileName);
			       k = -1;
			       continue;
			     }
			     for(j = j - k; k >= 0; k--, j++)
			       fwrite(stmp+j, sizeof(*stmp), 1, out);
			     j--;
			     if(stmp[j] == '\r' || stmp[j] == '\n') {
			       fprintf(out, "%s", yytext); // print indentation
			       line += (stmp[j] == '\n');
			     }
			   }
			 }
		       }
                       yytext[i] = cc; // restore yytext
		       // mfprint used in order to update 'line' automatically
                       mfprint("\n%s (END OF CODE)\n", yytext);
                     }

{IDENTIFIER}  {
                if(flag)
                  fprintf(out, "%s", yytext);
                flag = 1;
              }

.   {
      if(!skip)
        fprintf(out, "%s", yytext);
    }

\n|\r  { 
         skip = 0;
         fprintf(out, "%s", yytext);
	 line += (yytext[0] == '\n');
       }

%%


int yywrap(void) {
  return 1;
}

int FillTemplate(struct input template, FILE* outp, char* outpname, \
		 char* incname, char* preamble, ...) {

  static int fl = 0;

  if(!template.file && !template.buf)
    merror(0, "CODE GENERATION: Invalid template input");

  line = 1;
  inclname = incname;

  va_start(param, preamble);

  flag = 0; skip = 0;
  fileName = outpname;

  lntxtlen = strlen(LINEDIR);

  out = outp;

  if(template.file) {
    yyin = template.file;

    if(fl)
      yyrestart(template.file);
  }
  else
    yy_scan_string(template.buf);

  if(preamble)
    mfprint(preamble); // this will also update 'line'

  yylex();

  va_end(param);

  fl = 1;

  return 1;
}


/* int main() { // test example

  FILE *f, *g;
  f = fopen("ProcessTemplate.c","r");
  g = fopen("Output.c", "w");

  FillTemplate(f,g, "\nSegment 1\n", "\nSegment 2\n");

  fclose(f);
  fclose(g);

  } */
