/* %Z%%M% %I% %E% */ /* * Copyright (c) 1990, 1991, 1992, 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 routine contains code for converting routines from expression trees * to call trees: */ #ifndef CALL_DEFS_H #include "call_defs.h" #endif #ifndef FLAGS_DEFS_H #include "flags_defs.h" #endif #ifndef HEAP_EXPORTS_H #include "heap_exports.h" #endif #ifndef LINT_H #include "lint.h" #endif #ifndef MSG_EXPORTS_H #include "msg_exports.h" #endif #ifndef NEED_EXPORTS_H #include "need_exports.h" #endif #ifndef OBJECT_DEFS_H #include "object_defs.h" #endif #ifndef ROUTINE_DEFS_H #include "routine_defs.h" #endif #ifndef STATEMENT_EXPORTS_H #include "statement_exports.h" #endif #ifndef TABLE_EXPORTS_H #include "table_exports.h" #endif #ifndef TYPE_DEFS_H #include "type_defs.h" #endif #ifndef UNIX_ASSERT_H #include "unix_assert.h" #endif #ifndef VAR_DEFS_H #include "var_defs.h" #endif #ifndef VECTOR_DEFS_H #include "vector_defs.h" #endif LOCAL void routine_initial_access(Routine, Type_ref, Object_table, int); LOCAL void routine_print_access(Routine, Type_ref, Routine_table, int); LOCAL void vars_replace(Vars, Type_refs, Type_refs, Type_tables); /* * routine_convert(routine, convert) * This routine will generate the routine body for "routine" using * "gen" control the generation. */ void routine_convert( Routine routine, Convert convert) { Heap heap; Type_need need; Need_table need_table; Type_needs needs; Type_refs new_type_refs; Object_ref object_ref; Vec(Object_ref) object_refs; Object_table object_table; Type_refs old_type_refs; Type_ref parameter; Type_refs parameters; Type_refs returns; Routine_entry routine_entry; Vec(Routine_entry) routine_entrys; Routine_table routine_table; Routine_type routine_type; Vec(Routine_type) routine_types; Table(Str, Type_ref) synonyms; Vars takes; Type_ref type_ref; Type_tables type_tables; Type_proto type_proto; Var var; Vars vars; /* Temporarily insert all needs routines into the routine table: */ heap = convert->heap; need_table = routine->need_table; type_tables = convert->type_tables; routine->temp_first = vec_size(Type_ref, convert->temps); routine_entrys = vec_create(Routine_entry, heap); routine_table = convert->routine_table; needs = routine->needs; VEC_LOOP(Type_need, needs, need) { routine_entry = routine_entry_insert(routine_table, need->name, need->type_ref, need->proto, -1, 0); vec_append(Routine_entry, routine_entrys, routine_entry); need_table_routine_insert(need_table, need->name, need->type_ref, need->proto); } /*XXX: This should probably be eliminated: */ /* Temporarily insert initial objects into the constant table: */ object_table = convert->object_table; object_refs = vec_create(Object_ref, heap); parameters = routine->type_ref->parameters; TYPE_REFS_LOOP(parameters, parameter) { object_ref = object_ref_insert(object_table, "??", parameter, parameter, -1); vec_append(Object_ref, object_refs, object_ref); } /* Temporarily insert all routine types into the synonym table: */ synonyms = convert->synonyms; routine_types = routine->routine_types; old_type_refs = type_refs_empty_create(type_tables); new_type_refs = old_type_refs; type_proto = routine->type_proto; VEC_LOOP(Routine_type, routine_types, routine_type) { type_ref = routine_type->type_proto->type_ref; old_type_refs = type_refs_append(old_type_refs, type_ref_create(routine_type->name, type_tables), type_tables); new_type_refs = type_refs_append(new_type_refs, type_ref, type_tables); if (table_insert(Str, Type_ref, synonyms, routine_type->name, type_ref)) { msg_out(convert->msg, routine->position, "%s is already defined"); } } if (!type_refs_is_empty(new_type_refs)) { type_proto = type_proto_replace(routine->type_proto, old_type_refs, new_type_refs, type_tables); routine->needs = type_proto->needs; routine->returns = type_proto->returns; routine->signals = type_proto->signals; vars_replace(routine->takes, old_type_refs, new_type_refs, type_tables); routine->type_proto = type_proto; vars_replace(routine->vars, old_type_refs, new_type_refs, type_tables); routine->yields = type_proto->yields; (void)routine_entry_replace(convert->routine_table, routine->name, routine->type_ref, type_proto); } type_proto_needed(type_proto, type_tables); if (type_refs_size(routine->returns) > 1 ) { type_refs_multiple_needed(routine->returns, type_tables); } /* Now we can finally scan over all statements: */ statement_list_convert(routine->statements, convert); /* For debugging, force print routines for all variables: */ takes = routine->takes; vars = routine->vars; returns = routine->returns; if (convert->flags->debug && (routine->external == (Str)0)) { VEC_LOOP(Var, takes, var) { routine_print_access(routine, var->type_ref, routine_table, var->position); } VEC_LOOP(Var, vars, var) { routine_print_access(routine, var->type_ref, routine_table, var->position); } TYPE_REFS_LOOP(returns, type_ref) { routine_print_access(routine, type_ref, routine_table, routine->returns_position); } } /* Force the need entries for all variable initial objects: */ VEC_LOOP(Var, takes, var) { routine_initial_access(routine, var->type_ref, object_table, var->position); } VEC_LOOP(Var, vars, var) { routine_initial_access(routine, var->type_ref, object_table, var->position); } TYPE_REFS_LOOP(returns, type_ref) { routine_initial_access(routine, type_ref, object_table, routine->returns_position); } /* Now remove the temporarily inserted routines: */ VEC_LOOP(Routine_entry, routine_entrys, routine_entry) { routine_entry_delete(routine_entry); } routine->temp_last = vec_size(Type_ref, convert->temps); /* Remove temporarily inserted initial objects: */ VEC_LOOP(Object_ref, object_refs, object_ref) { object_ref_delete(object_ref); } /* Remove the synonyms: */ VEC_LOOP(Routine_type, routine_types, routine_type) { assert(table_delete(Str, Type_ref, synonyms, routine_type->name) == 0); } /* Mark the routine as used in the routine table: */ routine_entry = routine_entry_lookup(routine_table, routine->name, routine->type_ref->name, routine->position); assert(routine_entry != (Routine_entry)0); routine_entry_used(routine_entry, routine_table); } /* * routine_initial_access(routine, type_ref, object_table, position) */ /* ARGSUSED */ LOCAL void routine_initial_access( Routine routine, Type_ref type_ref, Object_table object_table, int position) { Object_ref object_ref; if (type_ref_is_routine(type_ref)) { return; } else if (type_ref_contains_parameter(type_ref) || type_ref_is_parameterized(type_ref)) { need_table_object_insert(routine->need_table, "??", type_ref, type_ref); } else { object_ref = object_ref_lookup(object_table, "??", type_ref); if (object_ref == (Object_ref)0) { object_ref = object_ref_insert(object_table, "??", type_ref, type_ref, position); } object_ref->used++; } } /* * routine_print_access(routine, type_ref, routine_table) */ /* ARGSUSED */ LOCAL void routine_print_access( Routine routine, Type_ref type_ref, Routine_table routine_table, int position) { Routine_ref routine_ref; if (type_ref_is_routine(type_ref)) { return; } else if (type_ref_contains_parameter(type_ref) || type_ref_is_parameterized(type_ref)) { Type_refs takes; Type_proto type_proto; Type_tables type_tables; Type_refs type_refs_empty; type_tables = routine_table->type_tables; type_refs_empty = type_refs_empty_create(type_tables); takes = type_ref->type_refs; takes = type_refs_append(takes, type_ref_create("out_stream", type_tables), type_tables); type_proto = type_proto_create(Type_proto_procedure, type_ref->parameters, takes, type_refs_empty, type_refs_empty, type_signals_empty_create(type_tables), type_needs_empty_create(type_tables), 0, type_tables); need_table_routine_insert(routine->need_table, "print", type_ref, type_proto); } else { routine_ref = routine_ref_lookup(routine_table, "print", type_ref, position); if (routine_ref == (Routine_ref)0) { routine_ref = routine_ref_insert(routine_table, "print", type_ref, position); } routine_entry_used(routine_ref->routine_entry, routine_table); } } /* * vars_replace(vars, old_type_refs, new_type_refs, type_tables) * This routine will update each variable "vars" so that each occurrance * of a type reference in "old_types_refs" is replaced by the * corresponding type reference in "new_type_refs". */ LOCAL void vars_replace( Vars vars, Type_refs old_type_refs, Type_refs new_type_refs, Type_tables type_tables) { Var var; VEC_LOOP(Var, vars, var) { var->type_ref = type_ref_replace(var->type_ref, old_type_refs, new_type_refs, type_tables); } }