/* %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 set of routines converts an expression tree into a sequence of * calls and assignments. */ #ifndef CALL_DEFS_H #include "call_defs.h" #endif #ifndef ERROR_EXPORTS_H #include "error_exports.h" #endif #ifndef EXP_DEFS_H #include "exp_defs.h" #endif #ifndef HEAP_EXPORTS_H #include "heap_exports.h" #endif #ifndef LIBC_EXPORTS_H #include "libc_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 STR_EXPORTS_H #include "str_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 UNIX_CTYPE_H #include "unix_ctype.h" #endif #ifndef UNIX_UNISTD_H #include "unix_unistd.h" #endif #ifndef VAR_DEFS_H #include "var_defs.h" #endif #ifndef VECTOR_DEFS_H #include "vector_defs.h" #endif LOCAL Call call_assign_exp_convert(Convert, Exp, Exp, Str, int, int, Vec(Call)); LOCAL Vec(Call) call_assign_op_convert(Convert, Exp, Str); LOCAL Call call_binary_convert(Convert, Exp, Type_refs, Str, Vec(Call)); LOCAL Call call_exp_convert_dot(Convert, Exp, Vec(Call)); LOCAL Vec(Call) call_list_cast(Vec(Call), Type_refs, Convert); LOCAL Call call_not_relation_convert(Convert, Exp, Type_refs, Str, Str, Vec(Call)); LOCAL Call call_static_invoke(Routine_ref, Vec(Call), int, Convert); LOCAL Call call_static_lookup(Str, Type_ref, int, int, int, int, Convert); LOCAL Call call_relation_convert(Convert, Exp, Type_refs, Str, Vec(Call)); LOCAL Call call_result_convert(Convert, Exp, Type_refs, Str, Vec(Call)); LOCAL Type_ref call_type_ref_get(Call, int, Convert); LOCAL Call call_unary_convert(Convert, Exp, Type_refs, Str, Vec(Call)); LOCAL Vec(Call) exps_to_calls(Vec(Exp), Type_refs, int, Vec(Call), Convert); LOCAL Routine_ref routine_ref_static_lookup(Str, Type_ref, int, int, int, int, Convert); /* * call_assign_convert(convert, exp) * This routine will return the sequence of calls associated with * "exp", where "exp" is an assignment or routine invocation. */ Vec(Call) call_assign_convert( Convert convert, Exp exp) { switch (exp->op) { case Exp_op_add: goto error; case Exp_op_add_assign: return call_assign_op_convert(convert, exp, "add"); case Exp_op_add_result: goto error; case Exp_op_and: goto error; case Exp_op_and_assign: return call_assign_op_convert(convert, exp, "and"); case Exp_op_and_if: goto error; case Exp_op_and_result: goto error; case Exp_op_arithmetic_if: goto error; case Exp_op_at: goto error; case Exp_op_array: goto error; case Exp_op_assign: return call_assign_op_convert(convert, exp, (Str)0); case Exp_op_call: { Call call; Vec(Call) sequence; sequence = vec_create(Call, convert->heap); call = call_exp_convert(convert, exp, convert->type_refs_empty, sequence); vec_append(Call, sequence, call); return sequence; } case Exp_op_define: goto error; case Exp_op_define_assign: return call_assign_op_convert(convert, exp, "define"); case Exp_op_define_result: goto error; case Exp_op_divide: goto error; case Exp_op_divide_assign: return call_assign_op_convert(convert, exp, "divide"); case Exp_op_divide_result: goto error; case Exp_op_dot: goto error; case Exp_op_equal: goto error; case Exp_op_error: goto error; case Exp_op_greater_than: goto error; case Exp_op_greater_than_or_equal: goto error; case Exp_op_identical: goto error; case Exp_op_integer: goto error; case Exp_op_left_shift: goto error; case Exp_op_left_shift_assign: return call_assign_op_convert(convert, exp, "left_shift"); case Exp_op_left_shift_result: goto error; case Exp_op_less_than: goto error; case Exp_op_less_than_or_equal: goto error; case Exp_op_list: goto error; case Exp_op_minus: goto error; case Exp_op_multiply: goto error; case Exp_op_multiply_assign: return call_assign_op_convert(convert, exp, "multiply"); case Exp_op_multiply_result: goto error; case Exp_op_not: goto error; case Exp_op_not_equal: goto error; case Exp_op_not_identical: goto error; case Exp_op_or: goto error; case Exp_op_or_assign: return call_assign_op_convert(convert, exp, "or"); case Exp_op_or_if: goto error; case Exp_op_or_result: goto error; case Exp_op_post_decrement: goto error; case Exp_op_post_increment: goto error; case Exp_op_power: goto error; case Exp_op_power_assign: return call_assign_op_convert(convert, exp, "power"); case Exp_op_power_result: goto error; case Exp_op_pre_decrement: goto error; case Exp_op_pre_increment: goto error; case Exp_op_remainder: goto error; case Exp_op_remainder_assign: return call_assign_op_convert(convert, exp, "remainder"); case Exp_op_remainder_result: goto error; case Exp_op_result: goto error; case Exp_op_right_shift: goto error; case Exp_op_right_shift_assign: return call_assign_op_convert(convert, exp, "right_shift"); case Exp_op_right_shift_result: goto error; case Exp_op_string: goto error; case Exp_op_subtract: goto error; case Exp_op_subtract_assign: return call_assign_op_convert(convert, exp, "subtract"); case Exp_op_subtract_result: goto error; case Exp_op_symbol: goto error; case Exp_op_text: goto error; case Exp_op_twiddle: { Call call; Vec(Call) sequence; sequence = vec_create(Call, convert->heap); call = call_exp_convert(convert, exp, convert->type_refs_empty, sequence); vec_append(Call, sequence, call); return sequence; } case Exp_op_xor: goto error; case Exp_op_xor_assign: return call_assign_op_convert(convert, exp, "xor"); case Exp_op_xor_result: goto error; default: assert_fail(); } error: msg_out(convert->msg, exp->position, "Missing assignment or call statement"); return vec_create(Call, convert->heap); } /* * call_assign_op_convert(convert, exp, op_name) * This routine will convert "exp" into a sequence of assignments and * routine invocations and store the result in "convert"->sequence. */ Vec(Call) call_assign_op_convert( Convert convert, Exp exp, Str op_name) { Heap heap; Exp_binary binary; Call call; int is_define; Exp left_exp; Vec(Exp) left_exps; int left_exps_size; Exp right_exp; Vec(Exp) right_exps; int right_exps_size; Vec(Call) sequence; heap = convert->heap; binary = exp->operands.binary; left_exp = binary->left; assert(left_exp->op == Exp_op_list); left_exps = left_exp->operands.list; left_exps_size = vec_size(Exp, left_exps); right_exp = binary->right; assert(right_exp->op == Exp_op_list); right_exps = right_exp->operands.list; right_exps_size = vec_size(Exp, right_exps); sequence = vec_create(Call, heap); is_define = 0; if (exp->op == Exp_op_define_assign) { is_define = 1; op_name = (Str)0; } /* Deal with simple assignment first: */ if ((left_exps_size == 1) && (right_exps_size == 1)) { left_exp = vec_fetch(Exp, left_exps, 0); right_exp = vec_fetch(Exp, right_exps, 0); call = call_assign_exp_convert(convert, left_exp, right_exp, op_name, 1, is_define, sequence); vec_append(Call, sequence, call); return sequence; } /* Check for empty lists: */ if (left_exps_size == 0) { msg_out(convert->msg, exp->position, "Empty left side of assignment"); return sequence; } if (right_exps_size == 0) { msg_out(convert->msg, exp->position, "Empty right side of assignment"); return sequence; } /* Try multiple assignement next: */ if (left_exps_size == right_exps_size) { Vec(Call) calls; int index; calls = vec_create(Exp, heap); for (index = 0; index < left_exps_size; index++) { left_exp = vec_fetch(Exp, left_exps, index); right_exp = vec_fetch(Exp, right_exps, index); (void)call_assign_exp_convert(convert, left_exp, right_exp, op_name, 0, is_define, sequence); call = vec_pop(Call, sequence); vec_append(Call, calls, call); } vec_vec_append(Call, sequence, calls); return sequence; } /* Try multiple assignment next: */ if ((left_exps_size > 1) && (right_exps_size == 1)) { Call var; Vec(Call) vars; Call call; Vec(Call) calls; Vec(Call) finals; int index; calls = vec_create(Call, heap); finals = vec_create(Call, heap); vars = vec_create(Call, heap); for (index = 0; index < left_exps_size; index++) { left_exp = vec_fetch(Exp, left_exps, index); var = call_assign_exp_convert(convert, left_exp, (Exp)0, op_name, 0, is_define,calls); vec_append(Call, vars, var); call = vec_pop(Call, calls); vec_append(Call, finals, call); } /* Get the right expression: */ right_exp = vec_fetch(Exp, right_exps, 0); call = call_exp_convert(convert, right_exp, convert->type_refs_empty, sequence); if (call->type != Call_type_multi) { /*XXX: Serious kludge here! */ call = call_multi_create(convert, call, call->type_refs); } call->value.multi->vars = vars; /* Construct the final sequence: */ vec_append(Call, sequence, call); vec_vec_append(Call, sequence, calls); vec_vec_append(Call, sequence, finals); return sequence; } assert_fail(); return sequence; } /* * call_binary_convert(convert, exp, type_refs, op_name, sequence) * This will return a call expression converted from "exp" and "op_name". */ Call call_binary_convert( Convert convert, Exp exp, Type_refs type_refs, Str op_name, Vec(Call) sequence) { Vec(Call) actuals; Exp_binary binary; Call call; Call left_call; Type_ref left_type_ref; int position; Call right_call; Type_ref right_type_ref; position = exp->position; binary = exp->operands.binary; left_call = call_exp_convert(convert, binary->left, type_refs, sequence); left_type_ref = call_type_ref_get(left_call, position, convert); right_call = call_exp_convert(convert, binary->right, left_call->type_refs, sequence); right_type_ref = call_type_ref_get(right_call, position, convert); if ((left_type_ref == (Type_ref)0) || (right_type_ref == (Type_ref)0)) { return left_call; } if (!type_ref_equal(left_type_ref, right_type_ref)) { msg_out(convert->msg, exp->position, "Left type for '%s' operator is %r and right type is %r", op_name, left_type_ref, right_type_ref); return left_call; } call = call_static_lookup(op_name, left_type_ref, 2, 1, 0, exp->position, convert); if (call == (Call)0) { msg_out(convert->msg, exp->position, "No %s operation", op_name); return left_call; } actuals = vec_create(Call, convert->heap); vec_append(Call, actuals, left_call); vec_append(Call, actuals, right_call); call = call_invoke_create(convert, call, actuals); return call; } /* * call_exp_constant(convert, exp, type_refs, sequence) * This routine will treat "exp" as a constant and return the * appropriate call node associated with it. */ Call call_exp_constant( Convert convert, Exp exp, Type_refs type_refs, Vec(Call) sequence) { Call call; Str name; Need_table need_table; Object_ref object_ref; Routine_ref routine_ref; Type_ref type_ref; Var var; call = (Call)0; if ((exp->op == Exp_op_symbol) && (type_refs_size(type_refs) == 1)) { name = exp->operands.symbol; type_ref = type_refs_fetch(type_refs, 0); /* This code was snarched from call_exp_convert() in symbol: */ object_ref = object_ref_lookup(convert->object_table, name, type_ref); if (object_ref != (Object_ref)0) { object_ref->used = 1; need_table = convert->routine->need_table; if (type_ref_contains_parameter(type_ref) || type_ref_is_parameterized(type_ref)) { need_table_object_insert(need_table, name, type_ref, type_ref); } exp->type_refs = type_ref->type_refs; call = call_object_create(convert, object_ref, exp->position); } } if (call == (Call)0) { msg_out(convert->msg, exp->position, "Constant not found"); call = call_error_create(convert, exp->position, "Undefined symbol"); } exp->type_refs = call->type_refs; return call; } /* * call_exp_convert(convert, exp, type_refs, sequence) * This routine will convert "exp" into associated Call object. * "type_refs" are the types to assign to "exp" if exp is a constant. * "type_refs" will be empty (size 0) if there is no appropriate guess. * "convert" contains needed conversion tables. */ Call call_exp_convert( Convert convert, Exp exp, Type_refs type_refs, Vec(Call) sequence) { Call call; switch (exp->op) { case Exp_op_add: call = call_binary_convert(convert, exp, type_refs, "add", sequence); break; case Exp_op_add_assign: goto error; case Exp_op_add_result: call = call_result_convert(convert, exp, type_refs, "add", sequence); break; case Exp_op_and: call = call_binary_convert(convert, exp, type_refs, "and", sequence); break; case Exp_op_and_assign: goto error; case Exp_op_and_if: { Call left_call; Call right_call; Exp_binary binary; binary = exp->operands.binary; left_call = call_exp_convert(convert, binary->left, convert->type_ref_logical->type_refs, sequence); right_call = call_exp_convert(convert, binary->right, convert->type_ref_logical->type_refs, sequence); call = call_binary_create(convert, Call_type_and_if, left_call, right_call); break; } case Exp_op_and_result: call = call_result_convert(convert, exp, type_refs, "and", sequence); break; case Exp_op_arithmetic_if: { Call cond_call; Call false_call; Type_ref false_type_ref; int position; Call true_call; Type_ref true_type_ref; Exp_trinary trinary; position = exp->position; trinary = exp->operands.trinary; cond_call = call_exp_convert(convert, trinary->first, convert->type_ref_logical->type_refs, sequence); true_call = call_exp_convert(convert, trinary->second, type_refs, sequence); false_call = call_exp_convert(convert, trinary->third, true_call->type_refs, sequence); true_type_ref = call_type_ref_get(true_call, position, convert); false_type_ref = call_type_ref_get(false_call, position, convert); if ((true_type_ref == (Type_ref)0) || (false_type_ref == (Type_ref)0)) { call = true_call; break; } if (!type_ref_equal(true_type_ref, false_type_ref)) { call = call_error_create(convert, position, "In ? : , " "types of and " "do not match!"); break; } call = call_if_create(convert, cond_call, true_call, false_call); break; } case Exp_op_at: { Exp_type exp_type; Routine_ref routine_ref; exp_type = exp->operands.type; routine_ref = routine_ref_static_lookup(exp_type->name, exp_type->type_ref, -1, -1, -1, exp->position, convert); if (routine_ref == (Routine_ref)0) { msg_out(convert->msg, exp->position, "%s@%r does not exist", exp_type->name, exp_type->type_ref); call = call_error_create(convert, exp->position, "Undefined routine"); break; } type_proto_needed(routine_ref->type_proto, convert->type_tables); call = call_routine_create(convert, routine_ref, exp->position); break; } case Exp_op_array: { Vec(Call) actuals; Exp_access access; Vec(Exp) exps; Str fetch_name; Routine_ref fetch_ref; Heap heap; Call left_call; Type_ref left_type_ref; int position; int size; heap = convert->heap; position = exp->position; /* Compute the call to the left of the '[': */ access = exp->operands.access; left_call = call_exp_convert(convert, access->exp, convert->type_refs_empty, sequence); left_type_ref = call_type_ref_get(left_call, position, convert); if (left_type_ref == (Type_ref)0) { call = left_call; break; } /* Compute the fetch# routine name: */ exps = access->list; size = vec_size(Exp, exps); fetch_name = strprintf(heap, "fetch%d", size); /* Lookup fetch#@left_type_ref(): */ fetch_ref = routine_ref_static_lookup(fetch_name, left_type_ref, size + 1, 1, 0, position, convert); if (fetch_ref == (Routine_ref)0) { call = left_call; break; } /* Compute expressions in [...]: */ actuals = exps_to_calls(exps, fetch_ref->type_proto->takes, 1, sequence, convert); vec_prepend(Call, actuals, left_call); call = call_static_invoke(fetch_ref, actuals, position, convert); break; } case Exp_op_assign: goto error; case Exp_op_define_result: goto error; case Exp_op_call: { Exp_access access; Vec(Call) actuals; Call left_call; Type_proto left_type_proto; Type_ref left_type_ref; int position; Call temp_call; Type_tables type_tables; type_tables = convert->type_tables; position = exp->position; /* Compute the call to the left of the '(': */ access = exp->operands.access; left_call = call_exp_convert(convert, access->exp, convert->type_refs_empty, sequence); left_type_ref = call_type_ref_get(left_call, position, convert); if (left_type_ref == (Type_ref)0) { call = left_call; break; } left_type_proto = type_proto_from_type_ref(left_type_ref, type_tables); exp->type_refs = left_type_proto->returns; /* Compute the calls to the right of the '(': */ actuals = exps_to_calls(access->list, left_type_proto->takes, 0, sequence, convert); /* This is a total kludge! */ if (left_call->type == Call_type_routine) { Routine_ref routine_ref; /* Get the parameterized version: */ routine_ref = left_call->value.routine->routine_ref; left_type_proto = routine_ref->routine_entry->type_proto; } if (type_proto_is_parameterized(left_type_proto)) { actuals = call_list_cast(actuals, left_type_proto->takes, convert); } /* * Complex expressions to the left of the '(' must be * stored in a temporary variable. (I think.) */ switch (left_call->type) { case Call_type_var: case Call_type_routine: call = call_invoke_create(convert, left_call, actuals); break; default: /* Create a temporary: */ temp_call = call_temp_create(convert, exp->position, left_type_ref); call = call_assign_create(convert, temp_call, left_call); vec_append(Call, sequence, call); call = call_invoke_create(convert, temp_call, actuals); } break; } case Exp_op_convert: { #ifdef INCOMPLETE Heap heap; heap = convert->heap; sub_call = call_exp_convert(convert, exp->operands.unary, convert->type_refs_empty, sequence); sub_call_type_refs = call->type_refs; if (type_refs_size(sub_call_type_refs != 1) { msg_out(convert->msg, exp->position, "No return value for unary `+'"); call = sub_call; break; } sub_call_type_ref = type_refs_fetch(sub_type_refs, 0); takes = vec_create(Call, heap); vec_append(Call, takes, sub_call); returns = ?->type_refs; call = call_invoke_create(convert, call, takes, returns); #endif /* INCOMPLETE */ assert_fail(); break; } case Exp_op_divide: call = call_binary_convert(convert, exp, type_refs, "divide", sequence); break; case Exp_op_divide_assign: goto error; case Exp_op_divide_result: call = call_result_convert(convert, exp, type_refs, "divide", sequence); break; case Exp_op_dot: call = call_exp_convert_dot(convert, exp, sequence); break; case Exp_op_equal: call = call_relation_convert(convert, exp, type_refs, "equal", sequence); break; case Exp_op_error: call = call_error_create(convert, exp->position, "Error"); break; case Exp_op_greater_than: call = call_relation_convert(convert, exp, type_refs, "greater_than", sequence); break; case Exp_op_greater_than_or_equal: call = call_not_relation_convert(convert, exp, type_refs, "greater_equal", "less_than", sequence); break; case Exp_op_identical: call = call_relation_convert(convert, exp, type_refs, "identical", sequence); break; case Exp_op_integer: call = call_integer_create(convert, exp->operands.integer, exp->position); break; case Exp_op_left_shift: call = call_binary_convert(convert, exp, type_refs, "left_shift", sequence); break; case Exp_op_left_shift_assign: goto error; case Exp_op_left_shift_result: call = call_result_convert(convert, exp, type_refs, "left_shift", sequence); break; case Exp_op_less_than: call = call_relation_convert(convert, exp, type_refs, "less_than", sequence); break; case Exp_op_less_than_or_equal: call = call_not_relation_convert(convert, exp, type_refs, "lesser_equal", "greater_than", sequence); break; case Exp_op_list: assert_fail(); break; case Exp_op_minus: call = call_unary_convert(convert, exp, type_refs, "minus", sequence); break; case Exp_op_multiply: call = call_binary_convert(convert, exp, type_refs, "multiply", sequence); break; case Exp_op_multiply_assign: goto error; case Exp_op_multiply_result: call = call_result_convert(convert, exp, type_refs, "multiply", sequence); break; case Exp_op_not: call = call_unary_convert(convert, exp, type_refs, "not", sequence); break; case Exp_op_not_equal: call = call_not_relation_convert(convert, exp, type_refs, "not_equal", "equal", sequence); break; case Exp_op_not_identical: call = call_not_relation_convert(convert, exp, type_refs, "not_identical", "identical", sequence); break; case Exp_op_or: call = call_binary_convert(convert, exp, type_refs, "or", sequence); break; case Exp_op_or_assign: goto error; case Exp_op_or_if: { Call left_call; Call right_call; Exp_binary binary; binary = exp->operands.binary; left_call = call_exp_convert(convert, binary->left, convert->type_ref_logical->type_refs, sequence); right_call = call_exp_convert(convert, binary->right, convert->type_ref_logical->type_refs, sequence); call = call_binary_create(convert, Call_type_or_if, left_call, right_call); break; } case Exp_op_or_result: call = call_result_convert(convert, exp, type_refs, "or", sequence); break; case Exp_op_post_decrement: assert_fail(); break; case Exp_op_post_increment: assert_fail(); break; case Exp_op_power: call = call_binary_convert(convert, exp, type_refs, "power", sequence); break; case Exp_op_power_assign: goto error; case Exp_op_power_result: call = call_result_convert(convert, exp, type_refs, "power", sequence); break; case Exp_op_pre_decrement: assert_fail(); break; case Exp_op_pre_increment: assert_fail(); break; case Exp_op_remainder: call = call_binary_convert(convert, exp, type_refs, "remainder", sequence); break; case Exp_op_remainder_assign: goto error; case Exp_op_remainder_result: call = call_result_convert(convert, exp, type_refs, "remainder", sequence); break; case Exp_op_result: call = call_result_convert(convert, exp, type_refs, (Str)0, sequence); break; case Exp_op_right_shift: call = call_binary_convert(convert, exp, type_refs, "right_shift", sequence); break; case Exp_op_right_shift_assign: goto error; case Exp_op_right_shift_result: call = call_result_convert(convert, exp, type_refs, "right_shift", sequence); break; case Exp_op_string: call = call_string_create(convert, exp->operands.string, exp->position); break; case Exp_op_subtract: call = call_binary_convert(convert, exp, type_refs, "subtract", sequence); break; case Exp_op_subtract_assign: goto error; case Exp_op_subtract_result: call = call_result_convert(convert, exp, type_refs, "subtract", sequence); break; case Exp_op_symbol: { Str name; int position; Routine_ref routine_ref; Type_ref type_ref; Var var; position = exp->position; /* Look for a variable first: */ name = exp->operands.symbol; var = table_lookup(Str, Var, convert->var_table, name); if (var != (Var)0) { exp->type_refs = var->type_ref->type_refs; call = call_var_create(convert, name, position, var->type_ref->type_refs); break; } /* Now try a constant: */ if (type_refs_size(type_refs) == 1) { Object_ref object_ref; Need_table need_table; /* This code is copied in call_exp_constant():*/ type_ref = type_refs_fetch(type_refs, 0); object_ref = object_ref_lookup(convert->object_table, name, type_ref); if (object_ref != (Object_ref)0) { object_ref->used = 1; need_table = convert->routine->need_table; if (type_ref_contains_parameter(type_ref) || type_ref_is_parameterized(type_ref)) { need_table_object_insert(need_table, name, type_ref, type_ref); } exp->type_refs = type_ref->type_refs; call = call_object_create(convert, object_ref, position); break; } } /* Now try a routine: */ routine_ref = routine_ref_lookup(convert->routine_table, name, convert->type_ref_global, position); if (routine_ref != (Routine_ref)0) { routine_ref = routine_ref_static_lookup(name, convert->type_ref_global, -1, -1, -1, position, convert); type_proto_needed(routine_ref->type_proto, convert->type_tables); routine_entry_used(routine_ref->routine_entry, convert->routine_table); call = call_routine_create(convert, routine_ref, position); break; } /* No dice: */ msg_out(convert->msg, position, "Symbol %s is not defined", name); call = call_error_create(convert, position, "Undefined routine"); break; } case Exp_op_text: call = call_string_create(convert, exp->operands.string, exp->position); break; case Exp_op_twiddle: { Vec(Call) actuals; Vec(Exp) exps; int exps_size; Call obj_call; Type_ref obj_type_ref; Exp_object object; int position; Routine_ref routine_ref; Type_proto type_proto; Type_tables type_tables; position = exp->position; object = exp->operands.object; /* Get the object call expression: */ obj_call = call_exp_convert(convert, object->object, convert->type_refs_empty, sequence); obj_type_ref = call_type_ref_get(obj_call, position, convert); if (obj_type_ref == (Type_ref)0) { call = obj_call; break; } /* Find the routine being called: */ exps = object->list; exps_size = vec_size(Exp, exps); routine_ref = routine_ref_static_lookup(object->name, obj_type_ref, exps_size + 1, -1, 0, position, convert); if (routine_ref == (Routine_ref)0) { call = obj_call; break; } type_proto = routine_ref->type_proto; exp->type_refs = type_proto->returns; /* Convert the expresions to the right of the '(': */ type_tables = convert->type_tables; actuals = exps_to_calls(exps, type_refs_lop(type_proto->takes, type_tables), 0, sequence, convert); vec_prepend(Call, actuals, obj_call); if (type_proto_is_parameterized(type_proto)) { actuals = call_list_cast(actuals, routine_ref->routine_entry->type_proto->takes, convert); } call = call_static_invoke(routine_ref, actuals, position, convert); break; } case Exp_op_xor: call = call_binary_convert(convert, exp, type_refs, "xor", sequence); break; case Exp_op_xor_assign: goto error; case Exp_op_xor_result: call = call_result_convert(convert, exp, type_refs, "xor", sequence); break; default: assert_fail(); } if (exp->type_refs == (Type_refs)0) { exp->type_refs = call->type_refs; } return call; error: assert_fail(); /* NOTREACHED */ } /* * call_exp_convert_dot(convert, exp, sequence) * This routine will do all of the work necessary to convert the * dot expression "exp" into a call and return it. */ LOCAL Call call_exp_convert_dot( Convert convert, Exp exp, Vec(Call) sequence) { Vec(Call) actuals; Call call; Exp_field field; Str get_name; Call left_call; Type_ref left_type_ref; int position; Routine_ref routine_ref; Type_proto type_proto; position = exp->position; field = exp->operands.field; /* Compute the expression to the left of the '.': */ left_call = call_exp_convert(convert, field->exp, convert->type_refs_empty, sequence); left_type_ref = call_type_ref_get(left_call, position, convert); if (left_type_ref == (Type_ref)0) { return left_call; } /* Get the prototype: */ get_name = strprintf(convert->heap, "%s_get", field->name); routine_ref = routine_ref_static_lookup(get_name, left_type_ref, 1, 1, 0, position, convert); if (routine_ref == (Routine_ref)0) { return left_call; } type_proto = routine_ref->type_proto; actuals = vec_create(Call, convert->heap); vec_append(Call, actuals, left_call); if (type_proto_is_parameterized(type_proto)) { actuals = call_list_cast(actuals, routine_ref->routine_entry->type_proto->takes, convert); } call = call_static_invoke(routine_ref, actuals, position, convert); exp->type_refs = type_proto->returns; return call; } /* * call_static_lookup(name, type_ref, * takes, returns, yields, position, convert) * This routine will return a call routine object corresponding to * "type_ref"@"name" using "convert"->routine_table. This routine * will verify that the number of actuals and returns match. */ Call call_static_lookup( Str name, Type_ref type_ref, int takes, int returns, int yields, int position, Convert convert) { Routine_ref routine_ref; /* Look up the typedef for the routine/iterator */ routine_ref = routine_ref_static_lookup(name, type_ref, takes, returns, yields, position, convert); if (routine_ref == (Routine_ref)0) { msg_out(convert->msg, position, "The %s%@ routine does not exist", name, type_ref); return (Call)0; } return call_routine_create(convert, routine_ref, position); } /* * routine_ref_static_lookup(name, type_ref, * takes, returns, yields, position, convert) * This routine will return the routine ref associated with * "name"@"type_ref". */ LOCAL Routine_ref routine_ref_static_lookup( Str name, Type_ref type_ref, int takes, int returns, int yields, int position, Convert convert) { int returns_size; Routine_entry routine_entry; Routine_ref routine_ref; int takes_size; int yields_size; Type_proto type_proto; Routine_table routine_table; routine_table = convert->routine_table; routine_ref = routine_ref_lookup(routine_table, name, type_ref, position); if (routine_ref == (Routine_ref)0) { routine_entry = routine_entry_lookup(routine_table, name, type_ref->name, position); if (routine_entry == (Routine_entry)0) { return routine_ref; } routine_ref = routine_ref_insert(routine_table, name, type_ref, position); } routine_entry_used(routine_ref->routine_entry, routine_table); type_proto = routine_ref->type_proto; assert(type_proto->kind == Type_proto_procedure); takes_size = type_refs_size(type_proto->takes); if ((takes >= 0) && (takes_size != takes)) { msg_out(convert->msg, position, "%s%@ has %d actuals instead of %d actuals", name, type_ref, takes_size, takes); } returns_size = type_refs_size(type_proto->returns); if ((returns >= 0) && (returns_size != returns)) { msg_out(convert->msg, position, "%s%@ has %d returns instead of %d returns", name, type_ref, returns_size, returns); } yields_size = type_refs_size(type_proto->yields); if ((yields > 0) && (yields_size != yields)) { assert_fail(); } return routine_ref; } /* * call_not_relation_convert(convert, exp, type_refs, * message, op_name, sequence) * This will return a call expression converted from "exp" and "op_name". */ /* ARGSUSED */ Call call_not_relation_convert( Convert convert, Exp exp, Type_refs type_refs, Str message, Str op_name, Vec(Call) sequence) { return call_not_create(convert, call_relation_convert(convert, exp, type_refs, op_name, sequence)); } /* * call_relation_convert(convert, exp, type_refs, op_name, sequence) * This will return a call expression converted from "exp" and "op_name". */ Call call_relation_convert( Convert convert, Exp exp, Type_refs type_refs, Str op_name, Vec(Call) sequence) { return call_binary_convert(convert, exp, type_refs, op_name, sequence); } /* * call_result_convert(convert, exp, op_name, type_refs, sequence) * This will return the call expression resulting from "::=". */ /* ARGSUSED */ Call call_result_convert( Convert convert, Exp exp, Type_refs type_refs, Str op_name, Vec(Call) sequence) { Exp_binary binary; binary = exp->operands.binary; return call_assign_exp_convert(convert, binary->left, binary->right, op_name, 0, (op_name != (Str)0) && strequal(op_name, "define"), sequence); } /* * call_assign_exp_convert(convert, left_exp, right_exp, op_name, * is_simple, is_define, sequence) * This routine will return the call expression resulting from * ::= . If "is_simple" is 1, the * resulting intermediate result is not stored in a temporary. * If "is_define" is 1, is meant to be defined as * a variable. */ LOCAL Call call_assign_exp_convert( Convert convert, Exp left_exp, Exp right_exp, Str op_name, int is_simple, int is_define, Vec(Call) sequence) { Call call; Call left_call; Str name; Call right_call; switch (left_exp->op) { case Exp_op_define: { Exp_define define; Type_ref synonym_type_ref; Type_ref type_ref; Var var; if (is_define) { msg_out(convert->msg, left_exp->position, "Definition assigment to already defined variable"); } define = left_exp->operands.define; name = define->name; type_ref = define->type_ref; synonym_type_ref = table_lookup(Str, Type_ref, convert->synonyms, type_ref->name); if (synonym_type_ref != (Type_ref)0) { type_ref = synonym_type_ref; } var = heap_allocate(convert->heap, Var); var->comment = ""; var->name = name; var->position = left_exp->position; var->type_ref = type_ref; if (table_insert(Str, Var, convert->routine->var_table, name, var)) { var = table_lookup(Str, Var, convert->routine->var_table, name); assert(var != (Var)0); if (!type_ref_equal(var->type_ref, type_ref)) { msg_out(convert->msg, left_exp->position, "%s is defined more than once", name); } } else { vec_append(Var, convert->routine->vars, var); } goto symbol_cont; } case Exp_op_symbol: { Call exp_call; Call temp_call; Var var; /* Lookup variable: */ name = left_exp->operands.symbol; symbol_cont: var = table_lookup(Str, Var, convert->var_table, name); if (is_define) { Type_ref type_ref; assert(right_exp != (Exp)0); right_call = call_exp_convert(convert, right_exp, convert->type_refs_empty, sequence); if (type_refs_size(right_call->type_refs) != 1) { msg_out(convert->msg, right_exp->position, "Expression should return one value"); return right_call; } type_ref = type_refs_fetch(right_call->type_refs, 0); if (left_exp->op != Exp_op_symbol) { msg_out(convert->msg, left_exp->position, "Definition assigment must be to a variable"); return right_call; } name = left_exp->operands.symbol; var = table_lookup(Str, Var, convert->var_table, name); if (var != (Var)0) { if (!type_ref_equal(var->type_ref, type_ref)) { msg_out(convert->msg, left_exp->position, "Variable %s already exists!", name); return right_call; } } var = heap_allocate(convert->heap, Var); var->comment = (Str)0; var->name = name; var->position = left_exp->position; var->type_ref = type_ref; if (table_insert(Str, Var, convert->var_table, name, var) == 0) { vec_append(Var, convert->routine->vars, var); } left_call = call_var_create(convert, name, left_exp->position, type_ref->type_refs); } else { if (var == (Var)0) { if (!strequal(name, "??")) { msg_out(convert->msg, left_exp->position, "Undefined variable %s", name); call = call_var_create(convert, name, left_exp->position, convert->type_refs_empty); if (!is_simple) { vec_append(Call, sequence, call); } return call; } /* * It sure would be nice to know * the real type here. */ var = heap_allocate(convert->heap, Var); var->name = "??"; var->type_ref = convert->type_ref_global; } left_call = call_var_create(convert, name, left_exp->position, var->type_ref->type_refs); if (right_exp == (Exp)0) { right_call = call_temp_create(convert, left_exp->position, var->type_ref); exp_call = right_call; } else { right_call = call_exp_convert(convert, right_exp, var->type_ref->type_refs, sequence); } } if (op_name != (Str)0) { Vec(Call) actuals; Routine_ref op_routine_ref; op_routine_ref = routine_ref_static_lookup(op_name, var->type_ref, 2, 1, 0, left_exp->position, convert); if (op_routine_ref == (Routine_ref)0) { return left_call; } actuals = vec_create(Call, convert->heap); vec_append(Call, actuals, left_call); vec_append(Call, actuals, right_call); right_call = call_static_invoke(op_routine_ref, actuals, left_exp->position, convert); } if (is_simple) { return call_assign_create(convert, left_call, right_call); } else { if (right_call->type == Call_type_temp) { temp_call = right_call; } else { temp_call = call_temp_create(convert, left_exp->position, var->type_ref); call = call_assign_create(convert, temp_call, right_call); vec_append(Call, sequence, call); } call = call_assign_create(convert, left_call, temp_call); vec_append(Call, sequence, call); return (right_exp == (Exp)0) ? exp_call : temp_call; } } case Exp_op_dot: { Vec(Call) actuals; Call assign_call; Call base_call; Type_ref base_type_ref; Call exp_call; Exp_field field; Heap heap; int position; Type_ref right_type_ref; Call set_call; Str set_name; Routine_ref set_routine_ref; Type_proto set_type_proto; Call temp_call; heap = convert->heap; position = left_exp->position; /* * Compute the expression to the left of the '.' * (i.e. the base expression): * base := */ field = left_exp->operands.field; base_call = call_exp_convert(convert, field->exp, convert->type_refs_empty, sequence); base_type_ref = call_type_ref_get(base_call, position, convert); if (base_type_ref == (Type_ref)0) { return base_call; } /* * For complex assignments (i.e, '::='), * assign the base expression to a temporary variable, * provided that it isn't already a variable. */ if ((op_name != (Str)0) && (field->exp->op != Exp_op_symbol)) { Call assign_call; Call temp_call; temp_call = call_temp_create(convert, left_exp->position, base_type_ref); assign_call = call_assign_create(convert, temp_call, base_call); vec_append(Call, sequence, assign_call); base_call = temp_call; } /* Find the _set routine: */ set_name = strprintf(heap, "%s_set", field->name); set_routine_ref = routine_ref_static_lookup(set_name, base_type_ref, 2, 0, 0, position, convert); if (set_routine_ref == (Routine_ref)0) { return base_call; } set_type_proto = set_routine_ref->type_proto; /* Evaluate the right expression: */ right_type_ref = type_refs_fetch(set_type_proto->takes, 1); if (right_exp == (Exp)0) { right_call = call_temp_create(convert, left_exp->position, right_type_ref); exp_call = right_call; } else { right_call = call_exp_convert(convert, right_exp, right_type_ref->type_refs, sequence); } /* * For complex result assignments '::=', perform the * operation using the _get routine. */ if (op_name != (Str)0) { Call get_call; Routine_ref get_routine_ref; Str get_name; Routine_ref op_routine_ref; /* Find the _get routine: */ get_name = strprintf(heap, "%s_get", field->name); get_routine_ref = routine_ref_static_lookup(get_name, base_type_ref, 1, 1, 0, position, convert); op_routine_ref = routine_ref_static_lookup(op_name, right_type_ref, 2, 1, 0, position, convert); if ((get_routine_ref == (Routine_ref)0) || (op_routine_ref == (Routine_ref)0)) { return base_call; } actuals = vec_create(Call, convert->heap); vec_append(Call, actuals, base_call); get_call = call_static_invoke(get_routine_ref, actuals, position, convert); actuals = vec_create(Call, convert->heap); vec_append(Call, actuals, get_call); vec_append(Call, actuals, right_call); right_call = call_static_invoke(op_routine_ref, actuals, position, convert); /* (_get(), */ } /* := */ if (is_simple || (right_call->type == Call_type_temp)) { temp_call = right_call; } else { temp_call = call_temp_create(convert, left_exp->position, right_type_ref); assign_call = call_assign_create(convert, temp_call, right_call); vec_append(Call, sequence, assign_call); } /* _set(, */ actuals = vec_create(Call, heap); vec_append(Call, actuals, base_call); vec_append(Call, actuals, temp_call); set_call = call_static_invoke(set_routine_ref, actuals, position, convert); if (is_simple) { return set_call; } else { vec_append(Call, sequence, set_call); return (right_exp == (Exp)0) ? exp_call : temp_call; } } case Exp_op_array: { Exp_access access; Call assign_call; Call base_call; Type_ref base_type_ref; Heap heap; int index; int position; Type_ref right_type_ref; int size; Call store_call; Str store_name; Routine_ref store_routine_ref; Type_proto store_type_proto; Vec(Call) sub_calls; Vec(Exp) sub_exps; Vec(Call) takes; Call temp_call; heap = convert->heap; position = left_exp->position; /* * Compute the base expression to the left of the '[' * base := */ access = left_exp->operands.access; base_call = call_exp_convert(convert, access->exp, convert->type_refs_empty, sequence); base_type_ref = call_type_ref_get(base_call, position, convert); if (base_type_ref == (Type_ref)0) { return base_call; } /* * For complex assignments (i.e, '::='), * assign the base expression to a temporary variable, * provided that it isn't already a variable. */ if ((op_name != (Str)0) && (access->exp->op != Exp_op_symbol)) { Call assign_call; Call temp_call; temp_call = call_temp_create(convert, left_exp->position, base_type_ref); assign_call = call_assign_create(convert, temp_call, base_call); vec_append(Call, sequence, assign_call); base_call = temp_call; } /* Find the store# routine: */ size = vec_size(Exp, access->list); store_name = strprintf(heap, "store%d", size); store_routine_ref = routine_ref_static_lookup(store_name, base_type_ref, size + 2, 0, 0, position, convert); if (store_routine_ref == (Routine_ref)0) { return base_call; } store_type_proto = store_routine_ref->type_proto; /* Evaluate the right expression: */ right_type_ref = type_refs_fetch(store_type_proto->takes, size + 1); right_call = call_exp_convert(convert, right_exp, right_type_ref->type_refs, sequence); /* Evaluate all of the expressions between the brackets: */ sub_exps = access->list; sub_calls = vec_create(Call, heap); for (index = 0; index < size; index++) { Call sub_call; Exp sub_exp; Type_ref sub_type_ref; sub_exp = vec_fetch(Exp, sub_exps, index); sub_type_ref = type_refs_fetch(store_type_proto->takes, index + 1); sub_call = call_exp_convert(convert, sub_exp, sub_type_ref->type_refs, sequence); /* * For complex assignments ('::=') store complex * sub-script expressions into temporaries: */ if (op_name != (Str)0) { Call temp_call; switch (sub_call->type) { case Call_type_integer: case Call_type_var: case Call_type_temp: case Call_type_text: break; default: temp_call = call_temp_create(convert, left_exp->position, sub_type_ref); sub_call = call_assign_create(convert, temp_call, sub_call); vec_append(Call, sequence, sub_call); sub_call = temp_call; } } vec_append(Call, sub_calls, sub_call); } /* * For complex result assignments '::=', perform the * operation using the store# routine. */ if (op_name != (Str)0) { Vec(Call) actuals; Call fetch_call; Str fetch_name; Routine_ref fetch_routine_ref; Routine_ref op_routine_ref; /* Find the _fetch routine: */ fetch_name = strprintf(heap, "fetch%d", size); fetch_routine_ref = routine_ref_static_lookup(fetch_name, base_type_ref, size + 1, 1, 0, position, convert); if (fetch_routine_ref == (Routine_ref)0) { return base_call; } actuals = vec_create(Call, heap); vec_append(Call, actuals, base_call); vec_vec_append(Call, actuals, sub_calls); fetch_call = call_static_invoke(fetch_routine_ref, actuals, position, convert); op_routine_ref = routine_ref_static_lookup(op_name, right_type_ref, 2, 1, 0, position, convert); if (op_routine_ref == (Routine_ref)0) { return base_call; } actuals = vec_create(Call, convert->heap); vec_append(Call, actuals, fetch_call); vec_append(Call, actuals, right_call); right_call = call_static_invoke(op_routine_ref, actuals, position, convert); /* (fetch#(, ), */ } /* := */ if (is_simple || (right_call->type == Call_type_temp)) { temp_call = right_call; } else { temp_call = call_temp_create(convert, left_exp->position, right_type_ref); assign_call = call_assign_create(convert, temp_call, right_call); vec_append(Call, sequence, assign_call); } /* store#(, , */ takes = vec_create(Call, heap); vec_append(Call, takes, base_call); vec_vec_append(Call, takes, sub_calls); vec_append(Call, takes, temp_call); if (type_proto_is_parameterized(store_type_proto)) { takes = call_list_cast(takes, store_routine_ref->routine_entry->type_proto->takes, convert); } store_call = call_static_invoke(store_routine_ref, takes, position, convert); if (is_simple) { return store_call; } else { vec_append(Call, sequence, store_call); return store_call; /* This may be wrong! */ } } } error: assert(call != call); /* NOTREACHED */ } /* * call_unary_convert(convert, exp, type_refs, op_name, sequence) * This will return a call expression converted from "exp" and "op_name". */ Call call_unary_convert( Convert convert, Exp exp, Type_refs type_refs, Str op_name, Vec(Call) sequence) { Vec(Call) actuals; Call call; int position; Routine_ref routine_ref; Call unary_call; Exp unary_exp; Type_ref unary_type_ref; position = exp->position; unary_exp = exp->operands.unary; unary_call = call_exp_convert(convert, unary_exp, type_refs, sequence); unary_type_ref = call_type_ref_get(unary_call, position, convert); if (unary_type_ref == (Type_ref)0) { return unary_call; } routine_ref = routine_ref_static_lookup(op_name, unary_type_ref, 1, 1, 0, position, convert); if (routine_ref == (Routine_ref)0) { return unary_call; } actuals = vec_create(Call, convert->heap); vec_append(Call, actuals, unary_call); call = call_static_invoke(routine_ref, actuals, position, convert); return call; } /* * call_list_cast(calls, types, convert) * This routine will insert a cast for each parmaterized type in "types" * and return the the result. */ Vec(Call) call_list_cast( Vec(Call) calls, Type_refs types, Convert convert) { Call call; int index; Vec(Call) new_calls; int size; Type_ref type_ref; new_calls = (Vec(Call))0; size = vec_size(Call, calls); if (size != type_refs_size(types)) { /* There is some sort of problem that will be caught later. */ return calls; } for (index = 0; index < size; index++) { call = vec_fetch(Call, calls, index); type_ref = type_refs_fetch(types, index); if (type_ref_is_parameter(type_ref)) { if (new_calls == (Vec(Call))0) { new_calls = vec_copy(Call, calls); } call = call_cast_create(convert, call, type_ref); vec_store(Call, new_calls, index, call); } } return (new_calls == (Vec(Call))0) ? calls : new_calls; } /* * call_type_ref_get(call, position, convert) * This routine will return the type reference associated with "call". * If the number of type references in "call" is not one, an error * message is generated using "position" and "convert" and (Type_ref)0 * is returned. */ LOCAL Type_ref call_type_ref_get( Call call, int position, Convert convert) { int size; Type_ref type_ref; Type_refs type_refs; type_refs = call->type_refs; size = type_refs_size(type_refs); if (size == 1) { type_ref = type_refs_fetch(type_refs, 0); } else { msg_out(convert->msg, position, "Expression returns %d types instead of 1 type!", size); type_ref = (Type_ref)0; } return type_ref; } /* * exps_to_calls(exps, type_refs, offset, sequence, convert) * This routine will return a call list corresponding to "exps". * The default type for each expression can be found in "type_refs" * offset by "offset". "sequence" and "convert" are needed to * pull off the conversion. */ LOCAL Vec(Call) exps_to_calls( Vec(Exp) exps, Type_refs type_refs, int offset, Vec(Call) sequence, Convert convert) { Call call; Vec(Call) calls; Exp exp; int exps_size; Heap heap; int index; Type_ref temp_type_ref; Type_refs temp_type_refs; int size; heap = convert->heap; exps_size = vec_size(Exp, exps); size = type_refs_size(type_refs); calls = vec_create(Call, heap); for (index = 0; index < exps_size; index++) { exp = vec_fetch(Exp, exps, index); if (index + offset < size) { temp_type_ref = type_refs_fetch(type_refs, index + offset); temp_type_refs = temp_type_ref->type_refs; } else { temp_type_refs = convert->type_refs_empty; } call = call_exp_convert(convert, exp, temp_type_refs, sequence); vec_append(Call, calls, call); } return calls; } /* * call_static_invoke(routine_ref, actuals, position, convert) * This routine will return the call that results from invoking * the routine specified by "routine_ref" with parameters of "actuals". */ LOCAL Call call_static_invoke( Routine_ref routine_ref, Vec(Call) actuals, int position, Convert convert) { Call call; Type_ref return_type_ref; Type_refs return_type_refs; Routine_entry routine_entry; int size; call = call_routine_create(convert, routine_ref, position); call = call_invoke_create(convert, call, actuals); /* Figure out whether or not to cast the return value: */ routine_entry = routine_ref->routine_entry; return_type_refs = routine_entry->type_proto->returns; size = type_refs_size(return_type_refs); switch (size) { case 0: break; case 1: return_type_ref = type_refs_fetch(return_type_refs, 0); if (type_ref_is_parameter(return_type_ref)) { return_type_ref = type_refs_fetch(routine_ref->type_proto->returns, 0); call = call_cast_create(convert, call, return_type_ref); } break; default: call = call_multi_create(convert, call, return_type_refs); break; } return call; }