/* %Z%%M% %I% %E% */ /* * Copyright (c) 1990, 1991, 1992, 1993, 1995 by Wayne C. Gramlich. * All rights reserved. * * Permission to use, copy, modify, distribute, and sell this software * for any purpose is hereby granted without fee provided that the above * copyright notice and this permission are retained. The author makes * no representations about the suitability of this software for any purpose. * It is provided "as is" without express or implied warranty. */ /* This file contains code for generating routines: */ #ifndef CALL_EXPORTS_H #include "call_exports.h" #endif #ifndef EXP_EXPORTS_H #include "exp_exports.h" #endif #ifndef FLAGS_DEFS_H #include "flags_defs.h" #endif #ifndef GEN_DEFS_H #include "gen_defs.h" #endif #ifndef LINT_H #include "lint.h" #endif #ifndef NEED_EXPORTS_H #include "need_defs.h" #endif #ifndef MODULE_DEFS_H #include "module_defs.h" #endif #ifndef ROUTINE_DEFS_H #include "routine_defs.h" #endif #ifndef STATEMENT_DEFS_H #include "statement_defs.h" #endif #ifndef STR_EXPORTS_H #include "str_exports.h" #endif #ifndef TYPE_DEFS_H #include "type_defs.h" #endif #ifndef UNIX_ASSERT_H #include "unix_assert.h" #endif #ifndef UNIX_CTYPE_H #include "unix_ctype.h" #endif #ifndef VAR_DEFS_H #include "var_defs.h" #endif #ifndef VECTOR_DEFS_H #include "vector_defs.h" #endif LOCAL void routine_gen(Routine, Gen); LOCAL void routine_linkage_gen(Routine, Gen); LOCAL void variable_gen(Gen, Str, Type_ref, Str, Routine); /* * routine_gen(routine, gen) * This routine will generate the routine body for "routine" using * "gen" control the generation. */ LOCAL void routine_gen( Routine routine, Gen gen) { int debug; int index; int is_parameterized; Type_refs returns; int returns_size; Str routine_name; Str routine_type; int size; Vars takes; int takes_size; int total; Str type; Type_ref type_ref; Type_proto type_proto; Var var; Vars vars; int vars_size; int variables_size; if (gen->linkage) { routine_linkage_gen(routine, gen); } if (routine->external != (Str)0) { return; } debug = gen->debug; routine_name = routine->name; routine_type = routine->type_ref->name; is_parameterized = type_ref_is_parameterized(routine->type_ref); gen->routine = routine; takes = routine->takes; takes_size = vec_size(Var, takes); type_proto = routine->type_proto; vars = routine->vars; vars_size = vec_size(Var, vars); /* Determine the routine type: */ gen_comments(gen, routine->comments, 0); returns = routine->returns; returns_size = type_refs_size(returns); switch (returns_size) { case 0: type = "void"; break; case 1: type_ref = type_refs_fetch(returns, 0); if (type_ref_is_parameter(type_ref)) { type = "void *"; } else { type = type_ref_string(type_ref, gen->heap); } break; default: type = type_refs_multiple_string(returns, gen->heap); } /* Emit the routine name with formals: */ gen_out(gen, "%s %\n", type, routine->returns_comment); gen_out(gen, "%s__%s(", routine->type_ref->name, routine_name); total = takes_size + (is_parameterized ? 1 : 0); if (total == 0) { gen_out(gen, "void)\n", 1); } else { extern Type_refs vars_to_type_refs(Vars, Type_tables); gen_out(gen, "\n"); assert(type_refs_equal(type_proto->takes, vars_to_type_refs(routine->takes, gen->type_tables))); for (index = 0; index < takes_size; index++) { var = vec_fetch(Var, takes, index); type_ref = var->type_ref; if (type_ref_is_parameter(type_ref)) { gen_out(gen, "%\tvoid *%S", 1, var->name); } else { gen_out(gen, "%\t%s %S", 1, type_ref_string(type_ref, gen->heap), var->name); } if (index + 1 == total) { gen_out(gen, ")"); } else { gen_out(gen, ","); } gen_out(gen, "%\n", var->comment); } } if (is_parameterized) { gen_out(gen, "%\tvoid *_block_)\n", 1); } /* Start the routine body: */ gen_out(gen, "{\n"); /* Emit the temporary variables: */ for (index = routine->temp_first; index < routine->temp_last; index++) { type_ref = vec_fetch(Type_ref, gen->temps, index); gen_out(gen, "%\t%s t__%d;\n", 1, type_ref_string(type_ref, gen->heap), index); } /* For debugging, emit the debugging variable declarations: */ variables_size = total + returns_size + vars_size; if (debug) { gen_out(gen, "%\tactivation___object activation__object;\n", 1); if (variables_size > 0) { gen_out(gen, "%\t%s__%s__frame__type f;\n", 1, routine_type, routine_name); } gen_out(gen, "\n"); } else { /* Emit the normal variable declarations: */ VEC_LOOP(Var, vars, var) { gen_out(gen, "%\t%s %S;%\n", 1, type_ref_string(var->type_ref, gen->heap), var->name, var->comment); } if ((vars_size != 0) || debug) { gen_out(gen, "\n"); } } /* Do debugger initialization: */ if (debug) { /* Load the variables into the stack frame: */ if (variables_size != 0) { gen_out(gen, "%\tactivation__object.frame = &f;\n", 1); } gen_out(gen, "%\tactivation__object.routine = " "&%s__%s__routine__object;\n", 1, routine_type, routine_name); if (is_parameterized) { gen_out(gen, "%\tf._block_ = _block_;\n", 1); } VEC_LOOP(Var, takes, var) { gen_out(gen, "%\tf.%S = %S;\n", 1, var->name, var->name); } } /* Initialize the variables: */ VEC_LOOP(Var, routine->vars, var) { gen_out(gen, "%\t%s%S = ", 1, gen->frame, var->name); type_init_gen(var->type_ref, gen); gen_out(gen, ";\n"); } if (debug) { gen_out(gen, "%\trun__time__push(&activation__object);\n", 1); assert(routine->breakpoint_enter != (Breakpoint)0); statement_breakpoint(routine->breakpoint_enter, gen, 1); } /* Generate the routine body: */ statement_list_gen(routine->statements, gen, 1); /* Generate the routine epilog: */ if (debug) { gen_out(gen, "epilog:\n"); assert(routine->breakpoint_return != (Breakpoint)0); statement_breakpoint(routine->breakpoint_return, gen, 1); gen_out(gen, "%\trun__time__pop();\n", 1); size = type_refs_size(returns); switch (size) { case 0: break; case 1: gen_out(gen, "%\treturn %sreturn__value__0;\n", 1, gen->frame); break; default: gen_out(gen, "%\t{\n", 1); gen_out(gen, "%\t%s return__struct;\n", 2, type_refs_multiple_string(returns, gen->heap)); for (index = 0; index < size; index++) { gen_out(gen, "%\treturn__struct.x%d = " "%sreturn__value__%d;\n", 2, index, gen->frame, index); } gen_out(gen, "%\treturn return__struct;\n", 2); gen_out(gen, "%\t}\n", 1); } } gen_out(gen, "}\n\n"); } /* * routine_linkage_gen(routine, gen) * This routine will output the linkage information needed for "routine" * to "gen". */ void routine_linkage_gen( Routine routine, Gen gen) { Breakpoint breakpoint; Vec(Breakpoint) breakpoints; int debug; int external; Heap heap; int index; int need_params; Type_ref return_type_ref; Type_refs returns; Str routine_name; Str routine_type; int size; Str type; Type_ref type_ref; Vars vars; Var var; int variables_size; Type_refs yields; heap = gen->heap; debug = gen->debug; if (!gen->linkage && !debug) { return; } external = (routine->external != (Str)0); if (external) { debug = 0; } routine_name = routine->name; type_ref = routine->type_ref; routine_type = type_ref->name; returns = routine->returns; /*XXX: Replace this with "type = type_refs_multiple_string(...)" */ switch (type_refs_size(returns)) { case 0: type = "void"; break; case 1: return_type_ref = type_refs_fetch(returns, 0); if (type_ref_is_parameter(return_type_ref)) { type = "void *"; } else { type = type_ref_string(return_type_ref, heap); } break; default: type = type_refs_multiple_string(returns, heap); } need_table_typedef_gen(routine->need_table, gen); if (debug && !external) { /* Emit the stack frame data structure: */ variables_size = (type_ref_is_parameterized(type_ref) ? 1 : 0) + vec_size(Var, routine->takes) + vec_size(Var, routine->vars) + type_refs_size(routine->returns); if (variables_size > 0) { gen_out(gen, "typedef struct {\n"); if (type_ref_is_parameterized(type_ref)) { gen_out(gen, "%\tvoid *_block_;\n", 1); } VEC_LOOP(Var, routine->takes, var) { type_ref = var->type_ref; if (type_ref_is_parameter(type_ref)) { gen_out(gen, "%\tvoid *%S;\n", 1, var->name); } else { type = type_ref_string(type_ref, heap); gen_out(gen, "%\t%s %S;\n", 1, type, var->name); } } VEC_LOOP(Var, routine->vars, var) { type_ref = var->type_ref; if (type_ref_is_parameter(type_ref)) { gen_out(gen, "%\tvoid *%S;\n", 1, var->name); } else { type = type_ref_string(type_ref, heap); gen_out(gen, "%\t%s %S;\n", 1, type, var->name); } } returns = routine->returns; size = type_refs_size(returns); for (index = 0; index < size; index++) { type_ref = type_refs_fetch(returns, index); if (type_ref_is_parameter(type_ref)) { gen_out(gen, "%\tvoid *return__value__%d;\n", 1, index); } else { type = type_ref_string(type_ref, heap); gen_out(gen, "%\t%s return__value__%d;\n", 1, type, index); } } gen_out(gen, "} %s__%s__frame__type;\n", routine_type, routine_name); } /* Emit the variables: */ size = vec_size(Var, routine->takes) + vec_size(Var, routine->vars) + type_refs_size(routine->returns); if (size > 0) { gen_out(gen, "static variable___object " "%s__%s__variables[%d] = {\n", routine_type, routine_name, size); VEC_LOOP(Var, routine->takes, var) { variable_gen(gen, var->name, var->type_ref, "argument", routine); } VEC_LOOP(Var, routine->vars, var) { variable_gen(gen, var->name, var->type_ref, "variable", routine); } returns = routine->returns; size = type_refs_size(returns); for (index = 0; index < size; index++) { Str variable_name; type_ref = type_refs_fetch(returns, index); variable_name = strprintf(heap, "return__value__%d", index); variable_gen(gen, variable_name, type_ref, "return", routine); } gen_out(gen, "};\n"); } } need_params = need_table_data_gen(routine->need_table, gen); gen_out(gen, "static routine___object %s%s__%s__routine__object = {\n", gen->flags->package_name, routine_type, routine_name); /* Output the information string: */ gen_out(gen, "%\t\"", 1); /* Output the routine name: */ gen_out(gen, "%s", routine->name); if (!strequal(routine->type_ref->name, "global__")) { gen_out(gen, "@%s", routine->type_ref->name); } /* Output the arguments: */ gen_out(gen, "("); vars = routine->takes; size = vec_size(Var, vars); for (index = 0; index < size; index++) { var = vec_fetch(Var, vars, index); gen_out(gen, "%s %r", var->name, var->type_ref); if (index + 1 < size) { gen_out(gen, ","); } } gen_out(gen, ")"); /* Output the returns: */ returns = routine->returns; size = type_refs_size(returns); if (size != 0) { gen_out(gen, "=>("); for (index = 0; index < size; index++) { type_ref = type_refs_fetch(returns, index); gen_out(gen, "%r", type_ref); if (index + 1 < size) { gen_out(gen, ","); } } gen_out(gen, ")"); } /* Output the yields: */ yields = routine->yields; size = type_refs_size(yields); if (size != 0) { gen_out(gen, "->"); for (index = 0; index < size; index++) { type_ref = type_refs_fetch(yields, index); gen_out(gen, "%r", type_ref); if (index + 1 < size) { gen_out(gen, ","); } } } gen_out(gen, "\""); /* Output the variable names: */ vars = routine->vars; size = vec_size(Var, vars); if (size != 0) { gen_out(gen, "\n%\t\"{", 2); for (index = 0; index < size; index++) { var = vec_fetch(Var, vars, index); gen_out(gen, "%s %r", var->name, var->type_ref); if (index + 1 < size) { gen_out(gen, ","); } } gen_out(gen, "}\""); } /* Output the line numbers: */ breakpoints = routine->breakpoints; size = vec_size(Breakpoint, breakpoints); if (size != 0) { gen_out(gen, "\n%\t\"[", 2); for (index = 0; index < size; index++) { breakpoint = vec_fetch(Breakpoint, breakpoints, index); gen_out(gen, "%d", breakpoint->line_number); if (index + 1 < size) { gen_out(gen, ","); } } gen_out(gen, "]\""); } gen_out(gen, ",\n"); gen_out(gen, "%\t(int *)0,\n", 1); /* Test coverage counts: */ gen_out(gen, "%\t(routine__info__type)0,\n", 1); /* Output the other stuff: */ gen_out(gen, "%\t&%s%s__module__object,\n", 1, gen->flags->package_name, routine->module->name); if (debug) { size = vec_size(Var, routine->takes) + vec_size(Var, routine->vars) + type_refs_size(routine->returns); gen_out(gen, "%\t%d,\n", 1, size); if (variables_size == 0) { gen_out(gen, "%\t(variable___object *)0,\n", 1); } else { gen_out(gen, "%\t%s__%s__variables,\n", 1, routine_type, routine_name); } } else { gen_out(gen, "%\t0,\n", 1); gen_out(gen, "%\t(variable___object *)0,\n", 1); } gen_out(gen, "%\t(void *)%s__%s,\n", 1, routine_type, routine_name); if (need_params) { gen_out(gen, "%\t&%s__%s__routine__params,\n", 1, routine_type, routine_name); } else { gen_out(gen, "%\t(routine___params *)0,\n", 1); } gen_out(gen, "};\n"); gen_out(gen, "\n"); } /* * routines_gen(types, gen) * This routine will generate the type routine declarations for * each routine in "routines" using "gen" control the generation. */ void routines_gen( Vec(Routine) routines, Gen gen) { Routine routine; /* Emit each routine body: */ VEC_LOOP(Routine, routines, routine) { routine_gen(routine, gen); } } #ifdef OLD /* * routine_signature_gen(routine, gen) * This routine will output the signature for "routine" to "gen". */ void routine_signature_gen( Routine routine, Gen gen) { int index; int is_parameterized; Str separator; int size; Vars takes; Type_ref type_ref; Var var; is_parameterized = type_ref_is_parameterized(routine->type_ref); takes = routine->takes; size = vec_size(Var, takes); if ((size == 0) && !is_parameterized) { gen_out(gen, "(void)"); } else { separator = "("; for (index = 0; index < size; index++) { var = vec_fetch(Var, takes, index); type_ref = var->type_ref; if (type_ref_is_parameter(type_ref)) { gen_out(gen, "%svoid *%s", separator, var->name); } else { gen_out(gen, "%s%s %s", separator, type_ref_string(var->type_ref, gen->heap), var->name); } separator = ", "; } if (is_parameterized) { gen_out(gen, "%svoid *_block_", separator); } gen_out(gen, ")"); } } #endif /* OLD */ /* * variable_gen(gen, variable_name, type_ref, variable_kind, routine) * This routine will emit a variable for "variable_name" to "gen". */ LOCAL void variable_gen( Gen gen, Str variable_name, Type_ref type_ref, Str variable_kind, Routine routine) { gen_out(gen, "%\tvariable__kind__%s, ", 1, variable_kind); gen_out(gen, "%\",\n", variable_name); gen_out(gen, "%\t(int)(&((%s__%s__frame__type *)0)->%S),\n", 2, routine->type_ref->name, routine->name, variable_name); if (type_ref_is_routine(type_ref)) { gen_out(gen, "%\tvariable__flavor__unparam,\n", 2); gen_out(gen, "%\t(void *)run__time__routine_print,\n", 2); } else if (type_ref_contains_parameter(type_ref)) { gen_out(gen, "%\tvariable__flavor__block,\n", 2); gen_out(gen, "%\t(void *)(&((%s__%s__block__type *)0)->%m__print),\n", 2, routine->type_ref->name, routine->name, type_ref); } else if (type_ref_is_parameterized(type_ref)) { gen_out(gen, "%\tvariable__flavor__static,\n", 2); gen_out(gen, "%\t(void *)&%s__%s__static.%m__print,\n", 2, routine->type_ref->name, routine->name, type_ref); } else { gen_out(gen, "%\tvariable__flavor__unparam,\n", 2); gen_out(gen, "%\t(void *)%s__print,\n", 2, type_ref->name); } }