%{ CODE HEADER
/*
 * The Termprocessor Kimwitu
 *
 * Copyright (c) 1991 University of Twente, Dept TIOS.
 * All rights reserved.
 *
 */
%}
/*
 * gutil.k
 */
%{
#if ! (defined(lint) || defined(SABER) || defined(CODECENTER))
  static char gutil_kAccesSid[] = "@(#)$Id: gutil.k,v 1.29 1998/01/29 10:57:34 belinfan Rel $";
#endif
%}
/***************************************************************************/

%{ KC_UNPARSE
#include "gutil.h"
%}
%{ KC_UNPARSE
static int g_no_of_phyla;
static int g_no_of_operators;
static int gl_no_of_args;
#define PHYLUMNUMBEROFFSET 0 /* should be >= 0; == the index of the last dummy element */
#define OPERATORNUMBEROFFSET 0 /* should be >= 0; == the index of the last dummy element */
%}
%{ KC_UNPARSE
static selvarstack cl_selvarstack = 0; /* initialised by the view_init_stacks view in util.k */
#define cf_pushselvar(o) do { cl_selvarstack = Consselvarstack( o, cl_selvarstack ); \
			      g_ctext_level++; \
			    } while(kc_zero_constant)
#define cf_topselvar() (cl_selvarstack->u.Consselvarstack.ID_1)
#define cf_popselvar() do { selvarstack tmp_cl_selvarstack = cl_selvarstack; \
		            cl_selvarstack = cl_selvarstack->u.Consselvarstack.selvarstack_1; \
			    free_selvarstack( tmp_cl_selvarstack, False ); \
			    g_ctext_level--; \
			  } while(kc_zero_constant)

static selvarstack cl_dollarvarstack = 0; /* initialised by the view_init_stacks view in util.k */
#define cf_pushdollarvar(o) do { cl_dollarvarstack = Consselvarstack( o, cl_dollarvarstack ); \
			    } while(kc_zero_constant)
#define cf_topdollarvar() (cl_dollarvarstack->u.Consselvarstack.ID_1)
#define cf_popdollarvar() do { selvarstack tmp_cl_dollarvarstack = cl_dollarvarstack; \
		            cl_dollarvarstack = cl_dollarvarstack->u.Consselvarstack.selvarstack_1; \
			    free_selvarstack( tmp_cl_dollarvarstack, False ); \
			  } while(kc_zero_constant)

static selvarstack cl_dollarvarextstack = 0; /* initialised by the view_init_stacks view in util.k */
#define cf_pushdollarvarext(o) do { cl_dollarvarextstack = Consselvarstack( o, cl_dollarvarextstack ); \
			    } while(kc_zero_constant)
#define cf_topdollarvarext() (cl_dollarvarextstack->u.Consselvarstack.ID_1)
#define cf_popdollarvarext() do { selvarstack tmp_cl_dollarvarextstack = cl_dollarvarextstack; \
		            cl_dollarvarextstack = cl_dollarvarextstack->u.Consselvarstack.selvarstack_1; \
			    free_selvarstack( tmp_cl_dollarvarextstack, False ); \
			  } while(kc_zero_constant)

static ID gl_phylum = 0;
static phylumdeclaration gl_phydecl = 0;
static ID gl_view = 0;
static ID gl_operator = 0;
static Ccode_option gl_cco = 0;
static storageoption gl_storageoption = 0;
static int gl_atomicity; /*used as boolean*/
static boolean gl_no_attributes;
static arguments gl_args = 0;
static rewriterulesinfo gl_rewrite_rewriteinfo = 0;
static char *g_emptystring = "";
static int g_ctext_level = 0;
static int g_withexpr_nr = 0;
static int g_fe_selvar_nr = 0;
static char *gl_return_type = "";
static ID gl_return_ID = 0;
static char *gl_star_string = "";
static char *gl_function = "";
static ID gl_sto = 0;
static int gl_hashtablenr_next = 0;
static int gl_hashtablenr_prev = 0;
static int gl_nr_of_hashtables = 0;
static boolean gl_rewrite_goto_used = False;
static boolean gl_unparse_goto_used = False;
static boolean gl_outmost_nonleaf_predicates = False;
static ID gl_type = 0;
static int gl_j = 0;
static boolean gl_print_line_directive = False;
%}
%{
/* string(s) stuff */
#include <string.h>
#if (! defined(KC_STDC) ) && defined(sun)
   extern char *sprintf();
#endif
%}

/***************************************************************************/

boolean f_something_to_initialize( cco ) Ccode_option cco;
{
    with( cco ) {
	CcodeOption( attr, ct ): {
	    return (boolean)(f_attributes_to_initialize( attr ) || (! f_NilCtexts( ct )));
}   }   }

boolean f_NilCtexts( c ) Ctexts c;
{
    with( c ) {
	NilCtexts(): { return True; }
	ConsCtexts( *, * ): { return False; }
}   }



static boolean f_attributes_to_initialize( attr ) attributes attr;
{
    foreach( a; attributes attr ) {
	with( a ) {
	    Attribute( *, *, Noattribute_initialisation() ): {/*EMPTY*/}
	    Attribute( *, *, Yesattribute_initialisation( * )): {
		return True;
	    }
	}
    }
    return False;
}

boolean f_no_attrs_in_Ccode_option( cco ) Ccode_option cco;
{
    with( cco ) {
	CcodeOption( Nilattributes(), * ): { return True; }
	CcodeOption( Consattributes( *, *), *): { return False; }
}   }

/***************************************************************************/

/*
 * we use it in the unparse stuff
 */
%{ KC_UNPARSE_HEADER
#include "gen.h"
%}
boolean f_all_alternatives_nullary( a ) alternatives a;
{
    foreach( alt; alternatives a ) {
	with( alt ) {
	    Alternative( *, Consarguments( *, * )): { return False; }
	    Alternative( *, Nilarguments() ): {/*EMPTY*/}
	}
    }
    return True;
}

/***************************************************************************/

%{
#include "util.h"
%}

ID f_phylumofwithcasesinfo( wcso ) withcasesinfo wcso;
{
    ID id;
    with( wcso ) {
	Nilwithcasesinfo(): {
	    v_report(NonFatal( NoFileLine(), Problem1S( "Error: can not find type of with expression" )));
	    return Id( Str( mkcasestring( "KC_ERRORunknownTYPE" )));
 	}
	Conswithcasesinfo( wco, r_wcso ): {
	    with( wco ) {
	        Withcaseinfo( patrep, *, * ): {
		    if ( eq_ID(id = f_phylumofpatternrepresentation( patrep ), f_emptyId() )) {
			return f_phylumofwithcasesinfo( r_wcso );
		    } else {
			return id;
}   }   }   }   }   }

ID f_phylumofpatternrepresentation( a_patrep ) patternrepresentation a_patrep;
{
    with( a_patrep ) {
	Nilpatternrepresentation(): {
	    return f_emptyId();
	}
	Conspatternrepresentation( a_patrep_elem, r_patrep ): {
	    with( a_patrep_elem ) {
		PRBinding( *, * ): {
		    return f_phylumofpatternrepresentation( r_patrep );
		}
		PRNonLeafBinding( *, *, * ): {
		    return f_phylumofpatternrepresentation( r_patrep );
		}
		PRVarPredicate( *, *, * ): {
		    return f_phylumofpatternrepresentation( r_patrep );
		}
		PROperPredicate( *, id ): {
		    return f_phylumofoperator( id );
		}
		PRDefault(): {
		    return f_phylumofpatternrepresentation( r_patrep );
		}
		PRWildcard( * ): {
		    return f_phylumofpatternrepresentation( r_patrep );
		}
		PRStringLiteral( *, * ): {
		    return f_phylumofpatternrepresentation( r_patrep );
		}
		PRIntLiteral( *, * ): {
		    return f_phylumofpatternrepresentation( r_patrep );
}   }   }   }   }

/***************************************************************************/

Cvariabledeclarations sort_extend_Cvariabledeclarations( C_vardecls, fn_args ) Cvariabledeclarations C_vardecls; fnarguments fn_args;
{
    return t_sort_extend_Cvariabledeclarations( C_vardecls, fn_args, NilCvariabledeclarations() );
}
Cvariabledeclarations t_sort_extend_Cvariabledeclarations( C_vardecls, fn_args, temp ) Cvariabledeclarations C_vardecls; fnarguments fn_args; Cvariabledeclarations temp; 
{
    with( fn_args ){
	Nilfnarguments() : { return temp; }
	Consfnarguments( a_fnarg, r_fnargs ): {
	    temp =  t_sort_extend_Cvariabledeclarations( C_vardecls, r_fnargs, temp );
	    return ConsCvariabledeclarations( lookup_and_createCvariabledeclaration( a_fnarg, C_vardecls ), temp );
}   }   }

static Cvariabledeclaration lookup_and_createCvariabledeclaration( a_fnarg, C_vardecls )  ID a_fnarg; Cvariabledeclarations C_vardecls;
{
    Cvariabledeclaration result = 0;
    int number_of_results = 0;
    foreach( vard ; Cvariabledeclarations C_vardecls ) {
	with( vard ) {
	    CVariabledeclaration( type, cvars ): {
		foreach( cvar; Cvariables cvars ) {
		    with( cvar ) {
			CVPointer( *, name ): {
			    if (eq_ID( name, a_fnarg ) ) {
				result = CVariabledeclaration( type, ConsCvariables( cvar , NilCvariables() ));
				number_of_results++;
			}   }
			CVFunction( *, *, name ): {
			    if (eq_ID( name, a_fnarg ) ) {
				result = CVariabledeclaration( type, ConsCvariables( cvar , NilCvariables() ));
				number_of_results++;
			}   }
	    }   }   }
	    Fnargfpdecl( type, cvars ): {
		foreach( cvar; Cvariables cvars ) {
		    with( cvar ) {
			CVPointer( *, name ): {
			    if (eq_ID( name, a_fnarg ) ) {
				result = CVariabledeclaration( type, ConsCvariables( cvar , NilCvariables() ));
				number_of_results++;
			}   }
			CVFunction( *, *, name ): {
			    if (eq_ID( name, a_fnarg ) ) {
				result = CVariabledeclaration( type, ConsCvariables( cvar , NilCvariables() ));
				number_of_results++;
			}   }
	    }   }   }
    }   }
    if (number_of_results == 1) {
	return result;
    } else {
	/* error */
	if (number_of_results > 1) {
	    v_report(Warning( FileLine( a_fnarg->file, a_fnarg->line ), Problem1S1ID( "more than one type defined for function argument:", a_fnarg )));
    } else { /* (number_of_results < 1) */
	    v_report(Warning( FileLine( a_fnarg->file, a_fnarg->line ), Problem1S1ID( "can not find type of function argument:", a_fnarg )));
	}
    /* should be handled more gracefully */
	return CVariabledeclaration( Id( Str( mkcasestring( "KC_ERRORunknownTYPE" ))), ConsCvariables( CVPointer( 0, a_fnarg ), NilCvariables() ));
    }
}

/***************************************************************************/

%{
#include "parse.h"
%}
ac_parameter_type_list sort_extend_parameter_type_list( C_vardecls, $decl ) ac_declaration_list C_vardecls; ac_declarator decl;
{
	AcDeclarator( *, add ): {
		with( add ) {
			AcDirectDeclId( * ),
			AcDirectDeclPack( * ),
			AcDirectDeclArray( *, * ): { return AcParList( Nilac_parameter_list() ); }
			AcDirectDeclProto( *, fn_proto ): { return fn_proto; }
			AcDirectDeclKandR( *,  Consac_identifier_list( Id( Str( "void" )), Nilac_identifier_list() ) ): { /* trick to get an empty parameter list but check the decls */
				check_ac_parameter_declaration( C_vardecls, Nilac_identifier_list() );
				return AcParList( t_sort_extend_parameter_list( C_vardecls, Nilac_identifier_list(), Nilac_parameter_list() ) );
			}
			AcDirectDeclKandR( *,  fn_args ): {
				check_ac_parameter_declaration( C_vardecls, fn_args );
				return AcParList( t_sort_extend_parameter_list( C_vardecls, fn_args, Nilac_parameter_list() ) );
			}
		}
	}
}
ac_parameter_list t_sort_extend_parameter_list( C_vardecls, fn_args, temp ) ac_declaration_list C_vardecls; ac_identifier_list fn_args; ac_parameter_list temp; 
{
    with( fn_args ){
	Nilac_identifier_list() : { return temp; }
	Consac_identifier_list( a_fnarg, r_fnargs ): {
	    temp =  t_sort_extend_parameter_list( C_vardecls, r_fnargs, temp );
	    return Consac_parameter_list( lookup_and_create_ac_parameter_declaration( a_fnarg, C_vardecls ), temp );
}   }   }

static ac_parameter_declaration lookup_and_create_ac_parameter_declaration( a_fnarg, C_vardecls )  ID a_fnarg; ac_declaration_list C_vardecls;
{
    ac_parameter_declaration result = 0;
    int number_of_results = 0;
    foreach( $vard ; ac_declaration_list C_vardecls ) {
		AcDeclaration( type, cvars ): {
			foreach( $cvar; ac_init_declarator_list cvars ) {
				AcInitDecl( decl ): {
					ID name = f_ID_of_declarator( decl );
					if (eq_ID( name, a_fnarg ) ) {
						result = AcParDeclDecl( type, decl );
						number_of_results++;
	}	}	}	}	}
	if (number_of_results == 1) {
		return result;
	} else {
		/* error */
		if (number_of_results > 1) {
			v_report(Warning( FileLine( a_fnarg->file, a_fnarg->line ), Problem1S1ID( "more than one type defined for function argument:", a_fnarg )));
		} else { /* (number_of_results < 1) */
			v_report(Warning( FileLine( a_fnarg->file, a_fnarg->line ), Problem1S1ID( "can not find type of function argument:", a_fnarg )));
		}
		/* should be handled more gracefully */
		return AcParDeclDecl(
			 Consac_declaration_specifiers(
				AcDeclSpecTypeSpec(
					AcTypeSpec( Id( Str( mkcasestring( "KC_ERRORunknownTYPE" ))))),
				Nilac_declaration_specifiers()),
			 AcDeclarator(
				Nopointer(),
				AcDirectDeclId( a_fnarg )));
    }
}

static void check_ac_parameter_declaration( C_vardecls, fn_args ) ac_declaration_list C_vardecls; ac_identifier_list fn_args;
{
    foreach( $vard ; ac_declaration_list C_vardecls ) {
		AcDeclaration( *, cvars ): {
			foreach( $cvar; ac_init_declarator_list cvars ) {
				AcInitDecl( decl ): {
					ID name = f_ID_of_declarator( decl );
					int number_of_results = 0;
					foreach( a_fnarg; ac_identifier_list fn_args) {
						if (eq_ID( name, a_fnarg ) ) {
							number_of_results++;
						}
					}
					if (number_of_results > 1) {
						v_report(Warning( FileLine( name->file, name->line ), Problem1S1ID( "more than one function argument for type definition:", name )));
					} else if (number_of_results < 1) {
						v_report(Warning( FileLine( name->file, name->line ), Problem1S1ID( "can not find declared function argument:", name )));
					}
	}	}	}	}
}

/***************************************************************************/

%{
#include "unpk.h"
#ifndef MALLOC
#  define MALLOC emalloc
#endif
#ifndef REALLOC
/*
 * # ifdef lint
 * #  define REALLOC(kc_p,kc_s) (kc_p,kc_s,0)
 * # else
 */
#  define REALLOC erealloc
/*
 * # endif
 */
#endif
#ifndef FREE
#  define FREE efree
#endif
#ifndef efree
/*
 * # ifdef lint
 * #  define efree(kc_p) 
 * # else
 */
#  define efree(kc_p) free((kc_malloc_t)(kc_p))
/*
 * # endif
 */
#endif
%}
void unparse_charptr( s, printer_fn, v ) char *s; void (*printer_fn)(char *dummy1, uview dummy2); view v;
{
    printer_fn( s, v );
}

char *f_mkstars( i ) int i;
{
    static char star_string[] = "**************";
    static char *malloced_star_string = 0;
    static char empty_string[] = "";

    if (i <= 0 ) {
	return empty_string;
    } else if (i <= (int)strlen(star_string)) {
	return &(star_string[strlen(star_string)-i]);
    } else {
	char *ptr = 0;
	int j;
	if (malloced_star_string == 0) {
	    malloced_star_string = (char *)MALLOC((kc_size_t) i+1 );
	    ptr = malloced_star_string;
	} else if ( i > (int)strlen(malloced_star_string) ) {
	    malloced_star_string = (char *)REALLOC((kc_voidptr_t)malloced_star_string, (kc_size_t)i+1 );
	    ptr = malloced_star_string;
	}
	if (ptr != 0) {
            for (j = 0; j< i; j++) {
		*ptr++ = '*';
	    }
	    *ptr = '\0';
	}
	return &(malloced_star_string[strlen(malloced_star_string)-i]);
    }	
}

char *f_mknls( i ) int i;
{
    static char empty_string[] = "";
    static char nl_string[] = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
    static char *malloced_nl_string = 0;

    if (i <= 0 ) {
	return empty_string;
    } else if (i <= (int)strlen(nl_string)) {
	return &(nl_string[strlen(nl_string)-i]);
    } else {
	char *ptr = 0;
	int j;
	if (malloced_nl_string == 0) {
	    malloced_nl_string = (char *)MALLOC( (kc_size_t)i+1 );
	    ptr = malloced_nl_string;
	} else if ( i > (int)strlen(malloced_nl_string) ) {
	    malloced_nl_string = (char *)REALLOC( (kc_voidptr_t)malloced_nl_string, (kc_size_t)i+1 );
	    ptr = malloced_nl_string;
	}
	if (ptr != 0) {
            for (j = 0; j< i; j++) {
		*ptr++ = '\n';
	    }
	    *ptr = '\0';
	}
	return &(malloced_nl_string[strlen(malloced_nl_string)-i]);
    }	
}

/*
 * HACK to get rid of backslash problems
 */
%{
#define QUOTEDBACKSLASH '\\'
%}

char *f_mkquotednls( ii ) int ii;
{
    static char empty_string[] = "";
    static char nl_string[] = "\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n\\\n\\n";
    static char *malloced_nl_string = 0;
    int i = 4*ii;

    if (i <= 0 ) {
	return empty_string;
    } else if (i <= (int)strlen(nl_string)) {
	return &(nl_string[strlen(nl_string)-i]);
    } else {
	char *ptr = 0;
	int j;
	if (malloced_nl_string == 0) {
	    malloced_nl_string = (char *)MALLOC( (kc_size_t)i+1 );
	    ptr = malloced_nl_string;
	} else if ( i > (int)strlen(malloced_nl_string) ) {
	    malloced_nl_string = (char *)REALLOC( (kc_voidptr_t)malloced_nl_string, (kc_size_t)i+1 );
	    ptr = malloced_nl_string;
	}
	if (ptr != 0) {
            for (j = 0; j< i; j+=4) {
		*ptr++ = QUOTEDBACKSLASH;
		*ptr++ = '\n';
		*ptr++ = QUOTEDBACKSLASH;
		*ptr++ = 'n';
	    }
	    *ptr = '\0';
	}
	return &(malloced_nl_string[strlen(malloced_nl_string)-i]);
    }	
}

%{
#define MKSELVARMAXINTREPR 30
%}

ID f_mkselvar( prefix, level) char *prefix; int level;
{
    /* HACK we suppose that MKSELVARMAXINTREPR charcters for the integer will be sufficient
     * we test for MKSELVARMAXINTREPR+1 for the \0
     */
    char fixbuf[BUFSIZ];
    char *dynbuf = 0;
    char *buf = 0;
    ID id;
    if (strlen(prefix) + MKSELVARMAXINTREPR + 1 > BUFSIZ) {
	dynbuf = (char*)MALLOC((kc_size_t) strlen(prefix) + MKSELVARMAXINTREPR + 1);
        buf = dynbuf;
    } else {
	buf = fixbuf;
    }
    (void)strcpy( buf, prefix );
    (void)sprintf( &buf[strlen(prefix)], "%d", level );
    id = Id( Str( mkcasestring( buf )));
    if (dynbuf != 0) {
	FREE((kc_voidptr_t) dynbuf );
    }
    return id;
}

ID f_mkselvar2( prefix, level, branch) char *prefix; int level; int branch;
{
    /* HACK we suppose that 2*MKSELVARMAXINTREPR charcters for the integers will be sufficient
     * (2 integers, 1 underscore, 1 \0)
     * we test for 2*MKSELVARMAXINTREPR+2 for the \0
     */
    char fixbuf[BUFSIZ];
    char *dynbuf = 0;
    char *buf = 0;
    ID id;
    int constant_factor = MKSELVARMAXINTREPR + 1 + MKSELVARMAXINTREPR + 1;
    if (strlen(prefix) + constant_factor > BUFSIZ) {
	dynbuf = (char*)MALLOC((kc_size_t) strlen(prefix) + constant_factor);
        buf = dynbuf;
    } else {
	buf = fixbuf;
    }
    (void)strcpy( buf, prefix );
    (void)sprintf( &buf[strlen(prefix)], "%d_%d", level, branch );
    id = Id( Str( mkcasestring( buf )));
    if (dynbuf != 0) {
	FREE((kc_voidptr_t) dynbuf );
    }
    return id;
}


/*
 * make a file name from a (likely quoted) string, that may contain
 * a complete (absolute or relative path), and may, or may not end in
 * `.k'. if the ending is .k, then replace it by the (one letter) suffix;
 * if we don't have a .k ending, it will probably be stdin, so we
 * extend the name.
 * We keep in mind that we may have to remove quotes (")
 * The _caller_ will have to FREE filename.
 */
char *f_mk_filename( a_casestring, suffix ) casestring a_casestring; char suffix;
{
    char *filename, *basename;
    int baselen;

    if ((basename = strrchr( a_casestring->name, '/' )) == 0) {
	basename = a_casestring->name;
    }
    if (*basename == '/') {
	basename++;
    } else if (*basename == '"') {
	basename++;
    }
    baselen = strlen(basename);
    filename = (char*)MALLOC((kc_size_t)baselen+3); /* for .c\0 */
    (void)strcpy( filename, basename );
    if (baselen > 0 && filename[baselen-1] == '"' ) {
	filename[baselen-1] = '\0';
	baselen--;
    }
    if ( baselen > 1 && (filename[baselen-1] == 'k' && filename[baselen-2] == '.' )) {
	filename[baselen-1] = suffix;
    } else {
	filename[baselen] = '.';
	filename[baselen+1] = suffix;
	filename[baselen+2] = '\0';
    }
    return filename;
}

/***************************************************************************/
/*
 * make a name that can be used in the #define file/guard name
 * derive it from the .c or .h file
 * (we expect a basename with suffix)
 */
%{
#include <ctype.h>
%}
char *f_make_identifier_basename( fn ) char *fn;
{
    int len, i;
    char *nn;

    len = strlen(fn);
    /*SUPPRESS 622*/
    assert(len >2);
    nn = (char*)MALLOC((kc_size_t)(len-2+1)); /* -2: drop .c; +1: add '\0' */
    (void)strncpy(nn, fn, len-2);
    nn[len-2] = '\0';
    for (i=0; i< len-2; i++) {
	if (! isalnum(nn[i])) {
	    nn[i] = '_';
    }   }
    return nn;
}

/**************************************************************************/

/*
 * this function reorders the rewrite/unparsedeclsinfo in a phylum as follows:
 * the rewrite/unparsedeclsinfos per phylum are collected
 * (concatenated one after the other)
 * and then, for each view an rewrite/unparseviewsinfo is created, containing
 * the 'projection' of the collected rewrite/unparsedeclsinfo on this
 * particular view.
 */

%{
static ID global_filterview; /* to be used by filteronview */
%}

rewriterulesinfo f_rewriterulesinfoofalternativeinview( a_alternative, a_view ) alternative a_alternative; ID a_view;
{
	global_filterview = a_view;
    return filter_rewriterulesinfo( a_alternative->rewriteinfo, filterrewriteruleinfoonview );
}

rewriteviewsinfo f_rewriteviewsinfoofalternatives( a_alternatives, a_views ) alternatives a_alternatives; viewnames a_views;
{
    rewriterulesinfo tmp_rewriterulesinfo = f_rewriterulesinfoofalternatives( a_alternatives );
    rewriteviewsinfo tmp_rewriteviewsinfo = Nilrewriteviewsinfo();
    foreach (a_view; viewnames a_views ) {
	global_filterview = a_view;
	tmp_rewriteviewsinfo = Consrewriteviewsinfo( Rewriteviewinfo( a_view, filter_rewriterulesinfo( tmp_rewriterulesinfo, filterrewriteruleinfoonview )), tmp_rewriteviewsinfo );
    }
    return tmp_rewriteviewsinfo;
}

unparseviewsinfo f_unparseviewsinfoofalternatives( a_alternatives, a_views ) alternatives a_alternatives; viewnames a_views;
{
    unparsedeclsinfo tmp_unparsedeclsinfo = f_unparsedeclsinfoofalternatives( a_alternatives );
    unparseviewsinfo tmp_unparseviewsinfo = Nilunparseviewsinfo();
    foreach (a_view; viewnames a_views ) {
	global_filterview = a_view;
	tmp_unparseviewsinfo = Consunparseviewsinfo( Unparseviewinfo( a_view, filter_unparsedeclsinfo( tmp_unparsedeclsinfo, filterunparsedeclinfoonview )), tmp_unparseviewsinfo );
    }
    return tmp_unparseviewsinfo;
}

static boolean filterrewriteruleinfoonview( a_rewriteruleinfo ) rewriteruleinfo a_rewriteruleinfo;
{
    return is_viewname_in_rewriteruleinfo( global_filterview, a_rewriteruleinfo );
}

static boolean filterunparsedeclinfoonview( a_unparsedeclinfo ) unparsedeclinfo a_unparsedeclinfo;
{
    return is_viewname_in_unparsedeclinfo( global_filterview, a_unparsedeclinfo );
}

static boolean is_viewname_in_rewriteruleinfo( a_view, a_rewriteruleinfo ) ID a_view; rewriteruleinfo a_rewriteruleinfo;
{
    with( a_rewriteruleinfo ) {
	Rewriteruleinfo( *, *, RewriteClause( a_viewnames, * )): {
	    return is_viewname_in_viewnames( a_view, a_viewnames );
}   }   }

static boolean is_viewname_in_unparsedeclinfo( a_view, a_unparsedeclinfo ) ID a_view; unparsedeclinfo a_unparsedeclinfo;
{
    with( a_unparsedeclinfo ) {
	Unparsedeclinfo( *, *, UnparseClause( a_viewnames, * )): {
	    return is_viewname_in_viewnames( a_view, a_viewnames );
}   }   }

static boolean is_viewname_in_viewnames( a_view, a_viewnames ) ID a_view; viewnames a_viewnames;
{
    foreach( a_viewname; viewnames a_viewnames ) {
	if ( eq_ID( a_view, a_viewname ) ) {
	    return True;
    }   }
    return False;
}

/*
 * collect the rewrite/unparsedeclsinfo of the alternatives.
 * NOTE: it is of vital importance that the rewrite/unparsedeclsinfo is _not_
 * reordered, because the current order corresponds to the tree/pattern
 * matching strategy.
 */
static rewriterulesinfo f_rewriterulesinfoofalternatives( a_alternatives ) alternatives a_alternatives;
{
    rewriterulesinfo tmp = Nilrewriterulesinfo();
    foreach( a_alternative; alternatives a_alternatives ) {
	tmp = concat_rewriterulesinfo( a_alternative->rewriteinfo, tmp );
    }
    return tmp;
}
static unparsedeclsinfo f_unparsedeclsinfoofalternatives( a_alternatives ) alternatives a_alternatives;
{
    unparsedeclsinfo tmp = Nilunparsedeclsinfo();
    foreach( a_alternative; alternatives a_alternatives ) {
	tmp = concat_unparsedeclsinfo( a_alternative->unparseinfo, tmp );
    }
    return tmp;
}

ID f_typeof( a_path ) path a_path;
{
	if (eq_ID(a_path->id, f_emptyId())) {
    	with( a_path ) {
			Nilpath(): {
	    		return f_phylumofoperator( a_path->op );
			}
			Conspath( i, r_path ): {
			    return f_subphylumofoperator( r_path->op, Int( i ) );
		   }   }
	} else {
		return a_path->id;
	}
}

ID f_operatorofpatternrepresentation( a_patternrepresentation ) patternrepresentation a_patternrepresentation;
{
    with( a_patternrepresentation ) {
	Nilpatternrepresentation(): {
	    return f_emptyId();
	}
	Conspatternrepresentation( e, * ): {
	    return f_operatorofelem_patternrepresentation( e );
}   }   }

static ID f_operatorofelem_patternrepresentation(a_elem_patternrepresentation ) elem_patternrepresentation a_elem_patternrepresentation;
{
    with( a_elem_patternrepresentation ) {
	PRBinding( p, * ): { return f_operatorofpath( p ); }
	PRVarPredicate( ps, *, * ): { return f_operatorofpaths( ps ); }
	PROperPredicate( p, * ): { return f_operatorofpath( p ); }
	PRNonLeafBinding( p, *, * ): { return f_operatorofpath( p ); }
	PRDefault(): { return f_emptyId(); }
	PRWildcard( p ): { return f_operatorofpath( p ); }
	PRStringLiteral( p, * ): { return f_operatorofpath( p ); }
	PRIntLiteral( p, * ): { return f_operatorofpath( p ); }
}   }

static ID f_operatorofpaths( a_paths ) paths a_paths;
{
    with( a_paths ) {
	Nilpaths(): {
	    return f_emptyId();
	}
	Conspaths( p, * ): {
	    return f_operatorofpath( p );
}   }   }

static ID f_operatorofpath( a_path ) path a_path;
{
    with( a_path ) {
	Nilpath(): {
	    return a_path->op;
	}
	Conspath( *, r_path ): {
	    return r_path->op;
}   }   }

ID f_typeofunpsubterm( a_unpsubterm, a_operator ) unpsubterm a_unpsubterm; ID a_operator;
{
    with( a_unpsubterm ) {
	UnpSubTerm( a_id ): { return f_phylumofpatternID( a_id ); }
	UnpDollarvarTerm( i ): { return f_subphylumofoperator( a_operator, i ); }
	UnpSubAttr( an_id, an_unpattributes ): { return f_check_unpattributes_in_phylum( an_unpattributes, f_phylumofpatternID( an_id ) ); }
	UnpDollarvarAttr( i, a_unpattributes ): { return f_check_unpattributes_in_phylum( a_unpattributes, f_subphylumofoperator( a_operator, i ) ); }
	UnpCastedVariable( a_cast, * ): { return a_cast; }
}   }


/**************************************************************************/

boolean f_outmost_nl_preds_in_rewriterulesinfo( ri ) rewriterulesinfo ri;
{
    with( ri ) {
	Nilrewriterulesinfo(): { return False; }
	Consrewriterulesinfo( Rewriteruleinfo( preds, *, * ), r_ri ): {
	    return (boolean) (f_outmost_nl_preds_in_patternrepresentation( preds )
		    	     || f_outmost_nl_preds_in_rewriterulesinfo( r_ri ));
}   }   }

static boolean f_outmost_nl_preds_in_patternrepresentation( p ) patternrepresentation p;
{
    with( p ) {
	Nilpatternrepresentation(): { return False; }
	Conspatternrepresentation( a_p, r_p ): {
	    return (boolean) (f_outmost_nl_preds_in_elem_patternrepresentation( a_p )
		    	    || f_outmost_nl_preds_in_patternrepresentation( r_p ));
}   }   }

static boolean f_outmost_nl_preds_in_elem_patternrepresentation( e_p ) elem_patternrepresentation e_p;
{
    with( e_p ) {
	PRBinding( *, * ): { return False; }
	PRVarPredicate( a_p, *, * ): {
	    return f_outmost_nl_preds_in_paths( a_p );
	}
	PROperPredicate( *, * ): { return False; }
	PRNonLeafBinding( *, *, * ): { return False; }
	PRDefault(): { return False; }
	PRWildcard( * ): { return False; }
	PRStringLiteral( *, * ): { return False; }
	PRIntLiteral( *, * ): { return False; }
}   }

static boolean f_outmost_nl_preds_in_paths( p ) paths p;
{
    with( p ) {
	Nilpaths(): { return False; }
	Conspaths( Nilpath(), * ): { return True; }
	Conspaths( Conspath( *, * ), r_p ): {
	    return f_outmost_nl_preds_in_paths( r_p );
}   }   }

/***************************************************************************/

/*
 * this function is called when deciding to print (dummy) `return (cast)0;'
 * code in a default with case of a non-void function, to suppress lint
 * messages about `has both return(e); and return;'
 *
 * the idea is that when this function is called we know that the return-type
 * is not a ptr type, nor is it a phylum.
 * This routine should check if it is something else that we now (ie. that we
 * generate in kc (eg. a view, a hashtable, a boolean, etc.)
 *
 * right now we use a terrible search strategy (linear!),
 * we should use the the uniq strategy, and have a new IDtype
 * for types.
 */
boolean f_is_known_ptr_type( id ) ID id;
{
	static phylumnames known = 0;

	if (! known ) {		/* to be extended with new types */
		known = Nilphylumnames();
		known = Consphylumnames( Id( Str( mkcasestring( "kc_voidptr_t" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_malloc_t" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_voidfnptr_t" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_realloc_arg_t" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_size_t" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "size_t" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "unsigned" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_memset_size_t" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_memory_blocksinfo_t" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_enum_phyla" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_enum_operators" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_enum_phyla_list" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_size_t_list" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "KC_UNIQ_INFO" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_hashnode_t" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_tp_boolean" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "boolean" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_hastable_storage_mode_t" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_hashtable_t" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_private_malloc_t" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_Align" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "kc_qsort_firstarg_t" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "KC_IO_STATUS" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "view" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "uview" ))), known );
		known = Consphylumnames( Id( Str( mkcasestring( "rview" ))), known );
	}
	foreach( pn; phylumnames known ) {
		if ( eq_ID( pn, id )) {
			return True;
	}	}
	return False;
}

/***************************************************************************/

/*
 * rewrite rules to simplify the pattern representations,
 * by eliminating the PRWildcard(*) and PRDefault()
 * This rules will be used just before code is generared
 */

Conspatternrepresentation( PRWildcard( * ), r )	->	r;
Conspatternrepresentation( PRDefault(), r )		->	r;

/*
 * we need the routine below to make sure that we only rewrite the
 * predicates in the withcaseinfo.
 * If we would also rewrite the bindings, we would loose the 'type'
 * attribute that contains important type information.
 */
%{
#include "rk.h"		/* for the rewrite_withcasesinfo call below */
%}

withcasesinfo my_rewrite_withcasesinfo(withcasesinfo $a_withcasesinfo)
{
	Nilwithcasesinfo(): { return $0; }
	Conswithcasesinfo( Withcaseinfo( p, b, ct ), r ): {
		return Conswithcasesinfo(
				Withcaseinfo(
				  rewrite_patternrepresentation(p, base_rview), b, ct ),
				my_rewrite_withcasesinfo( r ) );
	}
}

/***************************************************************************/

/*
 * Compute the position of the sole (single) dollar variable or
 * pattern in a patternchain. This is to be used to set the right $0
 * for a foreach statement.
 * NOTE: if there is more than a single pattern or dollar variable,
 * then we don't set $0. We call this failure.
 * We indicate failure by returning -1.
 * We start with inital return value of -2, meaning: mothing found, but
 * no failure yet.
 * A zero or positive return value indicates the index of the pattern
 * or dollar variable.
 */

int pos_of_sole_dollar_or_pattern_in_patternchain(patternchain a_patternchain)
{
	return t_pos_of_sole_dollar_or_pattern_in_patternchain(a_patternchain, -2, 1);

}

int t_pos_of_sole_dollar_or_pattern_in_patternchain(patternchain a_patternchain, int tmp_result, int pos)
{
	if (tmp_result == -1) { /*failure*/
		return tmp_result;
	}
	with( a_patternchain ) {
		Conspatternchain( h, t ): {
			tmp_result = t_pos_of_sole_dollar_or_pattern_in_patternchain( t, tmp_result, pos+1 );
			if (tmp_result == -1) { /*failure*/
				return tmp_result;
			}
			with( h ) {
				PatternchainitemOutmost( p ): {
					with( p ) {
						OPOperatorWildcard( id ): {
							with( id ) {
								Id( uid ): {
								    with( uid->type ) {
										ITPatternVariable( *, * ),
										ITUnknown(): { /* only variable */
											return tmp_result;
										}
										default: {
											if (tmp_result >= 0) {
												return -1; /*failure*/
											} else {
												return pos;
						}	}	}	}	}	}
						default: {
							if (tmp_result >= 0) {
								return -1; /*failure*/
							} else {
								return pos;
				}	}	}	}
				PatternchainitemGroup( * ): {
					return -1; /* ERROR found */
				}
				PatternchainitemDollarid( * ): {
					if (tmp_result >= 0) {
						return -1; /*failure*/
					} else {
						return pos;
		}	}	}	}
		Nilpatternchain(): {
			return tmp_result;
		}
	}
}
