
%{

struct op {
	void (*eval) (char*, struct op*);
	char *bytec;
	int wa;
	union { int n; struct op *o; char *a; } arg[0];
};

#define INIT_BYTEC_SIZE 32; 
#define FNTAB_SIZE 57;

struct bytec {
	char *c;
	int index;
	int size;
	int hashval;
};

struct bytec *fnstack[256];
int fnsptr;
struct bytec *curfn;

struct bytec **fntab;
int fntabsz;

void add_function( struct bytec *fn )
{
	int i, index = fn->hashval % fntabsz;
	struct bytec **tmp;
	for ( i = 0; i < 10; i++, index++, index %= fntabsz )
		if ( !fntab[index] ) {
			fntab[index] = fn;
			return;
		}
	tmp = fntab; i = fntabsz;
	fntabsz *= 3;
	fntab = calloc( fntabsz, sizeof(struct bytec *) );
	add_function( fn );
	for ( ; i >= 0; i-- ) if ( tmp[i] ) add_function( tmp[i] );
}

void init_globals( void )
{
	fnsptr = 0;
	curfn = new_fn();
	fntabsz = FNTAB_SIZE;
	fntab = calloc( fntabsz, sizeof(struct bytec *) );
}

struct bytec *new_fn( void )
{
	struct bytec *res = malloc( sizeof(struct bytec) );
	res->c = malloc( INIT_BYTEC_SIZE );
	res->index = 0;
	res->size = INIT_BYTEC_SIZE;
	return res;
}

void push_fn( struct bytec *fn ) {
	fnstack[fptr++] = curfn;
	curfn = fn;
}
void pop_fn( int hashval ) {
	char *code;
	emit_char( 0 );
	code = curfn->c = realloc( curfn->c, curfn->index );
	if ( hashval ) {
		curfn -> hashval = hashval;
		add_function( curfn );
	} else free( curfn );
	curfn = fnstack[--fptr];
	emit_char( 'f' );
	emit_int( (int)code );
}

void checkbd( int sz ) {
	curfn->index += sz;
	if ( curfn->index >= curfn->size + sizeof(int) ) {
		curfn->size *= 2;
		curfn->c = realloc( curfn->c, curfn->size );
	}
}
void emit_char( char c ) { 
	curfn->c[curfn->index] = c; 
	checkbd( 1 ); 
}
void emit_int( int n ) { 
	((int*)curfn->c)[curfn->index] = n; 
	checkbd( sizeof(int) ); 
}

int string_hash( char *key )
{
	int hval = 1;
	while ( *key )
		hval += *++key + (hval << 4);
	return hval;
}

%}

%option noyywrap

%%

#.*$		/* comments */
[ \t\n\r]	/* whitespace */
[0-9]+		{ emit_char( 'n' ); emit_int( atoi(yytext) ); }
"$"[0-9]+	{ emit_char( 'v' ); emit_int( atoi(yytext+1) ); }
[A-Za-z_]+	{ emit_char( 'c' ); emit_int( string_hash(yytext) ); }
[.:\\]		{ emit_char( yytext[0] ); }
"("[0-9]+	{ 
	struct bytec *fn = new_fn();
	push_fn( fn );
	emit_int( atoi(yytext+1) );
}
")"		{ pop_fn( 0 ); }
"):"[A-Za-z_]+	{ pop_fn( string_hash(yytext+2) ); }
.		{ 
	fprintf( stderr, "Unknown character: %s\n", yytext ); 
	exit( 1 );
}

%%

int main( int ac, char *av[] )
{
	if ( ac > 1 ) yyin = fopen( av[1], "r" );
	else yyin = stdin;
	yylex();
}

