ws   ([' '\t])
comment_start ("/*")
comment_end   ("*/")
%Start  incomment_block
%Start  tcl_commands
%{
#undef input
#undef unput
#include "y.tab.h"
#include <stdio.h>
#include <assert.h>
#include <tcl.h>
/*************************************************************************/
/* Scanner for the task-graph language.					 */
/*************************************************************************/
int incomment = 0;
int in_tclcmd = 0;
int Linenum   = 0;
char * Input;
extern Tcl_Interp * pTcl_Interp;
int  ptr = 0;
yywrap() {
	if (incomment || in_tclcmd) {
	   printf("Scanner error - unexpected end of file \n");
	}
	ptr = 0;
	Input = 0;
	return 1;
}
printtok(int t) {
    printf ("%d",Linenum);
    switch (t) {
       case CONCURRENT: printf("CONCURRENT\n"); break;
       case SEQUENTIAL: printf("SEQUENTIAL\n"); break;
       case BEGN: printf("BEGIN\n"); break;
       case END:  printf("END\n");break;
       case STRING: printf("STRING \"%s\"\n",yylval.string); break;
       case ICONST: printf("ICONST %d\n",yylval.val); break;
       case AT: printf("AT\n"); break;
       case ID: printf("ID %s\n",yylval.string); break;
       case TCL_CMD_BEGIN: printf("TCL_CMD_BEGIN\n"); break;
       case TCL_CMD_END: printf("TCL_CMD_END\n"); break;
       default: assert(0);
    }
}

#define YY_INPUT(buf,result,max_size) 		\
	{ 					\
	  if (Input == 0) result =  YY_NULL;    \
	  else { 				\
	    buf[0] = Input[ptr ++] ; 		\
	    result =1; 				\
          } 					\
	}

#ifdef LINUX
char yyinput() {
	char res[32];
	int result;
	YY_INPUT(res, result, 1024);
	return (result? res[0] : 0);
}
	
#else

char input() {
	if (Input == 0) return 0;
	return Input[ptr++];
}
#endif

void unput(char c) {
	if (ptr == 0) return;
	ptr--;
	Input[ptr] = c;
}

%}
%%

[\n] {
	Linenum++;
}

"#"[^\n]*[\n] {
	Linenum++;
}

"concurrent" {
	return CONCURRENT;
}

"sequential" {
	return SEQUENTIAL;
}

"at"  { return AT;   }

"begin"  { return BEGN; }

"end" { return END; }

"inputs" { return INPUT_VARS; }

"synchronizer" { return MAILBOX; }

":" { return ':' ; }

"%{" { 
       BEGIN tcl_commands;
       in_tclcmd = 1;
       return TCL_CMD_BEGIN;
}

"%}"   {
        BEGIN 0; 
        in_tclcmd = 0;
	return TCL_CMD_END;
}

[0-9]+ {
	yylval.val = atoi(yytext);
	return ICONST;
}

<tcl_commands>[^\n^%]*(\n|%)  {
	char next;
        if (yytext[yyleng-1] == '\n') {
            Linenum ++;
	    yymore(); 
	} else {
	    unput(next = yyinput()); /* {  - paren balancing */
	    if (next == '}' ) { 
	     	yyless(yyleng -1);
	    	yylval.string = yytext;
                Linenum ++;
	    	return STRING;
	     } else {
	     	yymore();
	     }
	}
}

\$[a-zA-Z0-9_]* {
       yylval.string = yytext;
       return ID;
}

[a-zA-Z_][a-zA-Z0-9_]* {
       yylval.string = yytext;
       return SIMPLE_ID;
}

{ws}* {}

. {
	char error_buffer[256];
	sprintf(error_buffer,"Invalid token in task-graph spec on line %d\n",
	            Linenum);
	Tcl_SetResult(pTcl_Interp,error_buffer,TCL_VOLATILE);
	return -1;
}

%%
#ifdef SCANNER
YYSTYPE yylval;
main (int argc, char * argv[]) {
	int t;
	printf ("scanner test\n");
	++argv, -argc;
	if (argc>0) yyin = fopen(argv[0],"r");
	Input = (char *)malloc(4096);
	fread(Input,1,4096,yyin);
	while (t = yylex()) {
	    printf("main: token returned %d\n",t);
	    printtok(t);
	}

}
#endif