EXPORT {
@@
extern void free_expr( expr );
extern guardlist reverse_guardlist( guardlist gl );
extern void customprint_guardlist( FILE *f, guardlist gl );
}
GLOBAL {
  /* put this new definition ABOVE the autogenerated one.. */
  /* in order to call customprint_guard() */
  void print_fdefn( FILE *f, fdefn p )
  {
	switch( p->tag )
	{
	case fdefn_is_onerule:
		fputs( "function method ", f );
		fputs( p->u.onerule.fname, f );
		fputs( "( ", f );
		fputs( p->u.onerule.param, f );
		fputs( " : int ) : int\n{\n\t ", f );
		print_expr( f, p->u.onerule.e );
		fputs( "\n}\n", f );
		break;
	case fdefn_is_manyrules:
		fputs( "function method ", f );
		fputs( p->u.manyrules.fname, f );
		fputs( "( ", f );
		fputs( p->u.manyrules.param, f );
		fputs( " : int ) : int\n{\n", f );
		customprint_guardlist( f, p->u.manyrules.l );
		fputs( "\n}\n", f );
		break;
	default:
		fprintf( stderr,
		 "print_fdefn: impossible tag %d\n", p->tag );
		exit(1);
	}
  }
  /* move the auto-generated one (below) to one side! */
  #define print_fdefn(a,b)   SIDELINED_print_fdefn(a,b)
@@
  void free_expr( expr e )
  {
	switch( e->tag )
	{
	case expr_is_num:
		break;
	case expr_is_id:
		free( (void *)e->u.id_s );
		break;
	case expr_is_call:
		free( (void *)e->u.call.s );
		free_expr( e->u.call.e );
		break;
	case expr_is_binop:
		free_expr( e->u.binop.l );
		free_expr( e->u.binop.r );
		break;
	default:
		fprintf( stderr,
		 "free_expr: impossible tag %d\n", e->tag );
		exit(1);
	}
	free( (void *) e );
  }
  guardlist reverse_guardlist( guardlist gl )
  {
  	guardlist result = guardlist_nil();
	while( guardlist_kind(gl) != guardlist_is_nil )
	{
		guard     hd;
		guardlist tl;
		get_guardlist_cons( gl, &hd, &tl );
		result = guardlist_cons( hd, result );
		gl = tl;
	}
	return result;
  }

  /* custom guard list printer, special case '| true'.. */
  void customprint_guardlist( FILE *f, guardlist gl )
  {
	while( guardlist_kind(gl) != guardlist_is_nil )
	{
		guard     hd;
		guardlist tl;
		bexpr     cond;
		expr      e;
		get_guardlist_cons( gl, &hd, &tl );
		get_guard_pair( hd, &cond, &e );

		// if the last guard is true..
		if( guardlist_kind(tl) == guardlist_is_nil
		&&  bexpr_kind(cond)   == bexpr_is_truev )
		{
			fprintf( f, "\n\t\t " );
			print_expr( f, e );
			return;
		} else
		{
			print_guard( f, gl->hd );
		}

		gl    = tl;
	}
	fprintf( f, "\n\t\t -1000000" );
  }
}

TYPE {
	arithop   =  plus				"+"
		  or minus				"-"
		  or times				"*"
		  or divide				"/"
		  or mod				"%"
		  ;
	expr      =  num( int n )			1
	          or id( string s )			1
	          or call( string s, expr e )		1 "(" 2 ")"
	          or binop( expr l, arithop op, expr r ) "(" 1 2 3 ")"
	          ;
	boolop    =  eq					"=="
		  or ne					"!="
		  or gt					">"
		  or ge					">="
		  or lt					"<"
		  or le					"<="
		  ;
	bexpr     =  truev				"True"
	          or falsev				"False"
		  or binop( expr l, boolop op, expr r )  1 2 3
		  ;
	guard     =  pair( bexpr cond, expr e )		"\tif " 1 " then\n\t\t " 2 "\n\telse "
		  ;
	guardlist =  nil				"\n\t\t -1000000"
		  or cons( guard hd, guardlist tl )     1 2
		  ;
	fdefn     =  onerule( string fname, string param, expr e )
		     "function method " 1 "( " 2 " : int ) : int\n{\n\t " 3 "\n}\n"
	          |  manyrules( string fname, string param, guardlist l )
		     "function method " 1 "( " 2 " : int ) : int\n{\n" 3
		     "\n}\n"
		  ;
}
