STRING	\"[^"]*
CHARC	\'[^']*
AB	"//"
CB	"/*"
CE	"*/"
ESC	"\\"
BB	"{"
BE	"}"
SP	[ \n\t]
STMNT	.*";"
TRY	"try"{SP}*{BB}
CATCH	"catch"{SP}*"("{SP}*/.*")"{SP}*"{"
ELIPS	"..."{SP}*")"{SP}*"{"
ARGU	.*{SP}*")"{SP}*"{"
CEMPTY	{SP}*")"{SP}*"{"
THROW	"throw".*";"
THROWD	")"{SP}*"throw"{SP}*"(".*")"/{SP}*"{"
%START Try Catch CatchArg ThrowD End
%{
#include <string.h>
int scope;
char *throwArgs[YYLMAX];
%}
%%
{STRING}|{CHARC}	{	/* Skip character or string constants */
				if(yytext[yyleng-1] == '\\')
					yymore();
				else
					printf("%s%c", yytext, input());
			}
{AB}.*$	{ /* C++ comment handling */ ECHO; }
{CB}	{ /* C comment handling */
			int c;
			ECHO;
			while(1) {
				output(c=input());
				/* Check for end of comment */
				if( c == '*' ) {
					if((c=input()) == '/') {
						output(c);
						break;
					}
					unput(c);
				}
			}
		}
{TRY}	{
			printf("if(setjmp(*ExH::stk++)==0) {");
			scope=0;
			BEGIN Try;
		}
<Try>{BE}		{ 
			ECHO; 
			if(--scope < 0) {
			     printf("ExH::stk--; }"); /* Pop */
			     BEGIN Catch;
			}
<Catch,End>{CATCH}	{ scope = 0; BEGIN CatchArg; }
<CatchArg>{ELIPS}	{
			printf("else {");
			BEGIN 0;
		}
<CatchArg>{CEMPTY}	{
			fprintf(stderr, "ERROR: Catch must have an argument\n");
			exit(1);
		}
<CatchArg>{ARGU}	{
			char *type, *ref, *var=0;

			/* Looks for reference */
			type = strtok(yytext, ")");
			ref = strchr(type, '&');

			/* Identifies the type */
			type = strtok(yytext, " \t\n&");
			printf("else if( ExH::ex()->type() == %s::stype()) {", type);

			/* Looks for a variable declaration */
			if(var = strtok(NULL, " \t\n)")) {
				if(ref) ref = "&";
				else ref = "";
				printf(" %s%s %s = *((%s*)ExH::ex());", type, ref, var, type);
			}
			BEGIN Catch;
		}
<Catch,Try,ThrowD>{BB}	{ECHO; ++scope;}
<Catch>{BE}	{ 
			ECHO; 
			if(--scope < 0) BEGIN End;
		}
<End>{STMNT}	|
<End>{BE}	{
			printf("else unexpected();");
			ECHO;
			BEGIN 0;
		}
{THROW}	{	/* Normal throw */
			char *p;

			/* skip 'throw' and pass the rest of the sentence as argument */
			p = strtok(yytext+5, ";");
			if(!p) p = "";
			printf("ExH::throw(%s);", p);
		}
{THROWD}	{	/* Throw Declaration ( type f() throw (x1, x2, etc) ) */
			char *p;
			p = strstr(yytext, "throw");
			*p = 0;

			/* Save throw args for future catchs */
			strcpy(throwArgs, p+5);

			/* Prints function name and start with try */
			printf("%s{ if(setjmp(*ExH::try_())==0)", yytext);

			/* Prints the function body */
			scope = 0;
			BEGIN ThrowD;
		}
<ThrowD>{BE}	{
			ECHO;
			if(--scope <= 0) {
				char *p;

				p = strchr(throwArgs, '(') + 1;
				while(p=strtok(p, " ,)")) {
					printf("else if( ExH::ex()->type() == %s::stype()) ", p);
					printf("ExH::throw(*ExH::ex());");
					p = 0;
				}
				printf("else unexpected(); }");
				BEGIN 0;
			}
		}
