home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1985-1992 New York University
- *
- * This file is part of the Ada/Ed-C system. See the Ada/Ed README file for
- * warranty (none) and distribution info and also the GNU General Public
- * License for more details.
-
- */
- #include "4.h"
- #include "dbxprots.h"
- #include "setprots.h"
- #include "arithprots.h"
- #include "nodesprots.h"
- #include "errmsgprots.h"
- #include "evalprots.h"
- #include "miscprots.h"
- #include "smiscprots.h"
- #include "chapprots.h"
-
- static int exist_compatible_type(Set, Symbol);
- static int compatible_op(Symbol, Node, Symbol);
- static Tuple valid_op_types(Symbol, Node);
- static int in_unary_ops(Symbol);
- static int op_suffix(Symbol);
- static Symbol op_suffix_gen(Symbol, int);
- static int in_numeric_types(Symbol);
- static int eq_universal_types(Symbol, Symbol);
- static int in_mult_types(Symbol, Symbol);
- static int in_mixed_mult_types(Symbol, Symbol);
- static int in_mod_types(Symbol, Symbol);
- static int in_adding_types(Symbol, Symbol);
- static int in_expon_types(Symbol, Symbol);
- static Symbol valid_arg_list(Symbol, Node);
- static Const check_constant_overflow(Const);
- static void literal_expression(Node);
- static Tuple order_arg_list(Node, Tuple);
- static void bind_arg(Node, Symbol, int, int);
- static int in_comparison_ops(Symbol);
- static Set find_compatible_type(Set, Set);
- static Tuple valid_concatenation_type(Set, Set);
-
- /* we need the following constants in order to make some tests :
- * does a constant belong to its type interval ?
- */
-
- extern int ADA_MIN_INTEGER;
- extern int ADA_MAX_INTEGER;
- extern int *ADA_MAX_INTEGER_MP;
- extern int *ADA_MIN_INTEGER_MP;
- extern long ADA_MIN_FIXED, ADA_MAX_FIXED;
- extern int *ADA_MIN_FIXED_MP, *ADA_MAX_FIXED_MP;
-
- void result_types(Node expn) /*;result_types*/
- {
- /* This procedure performs the first pass of type resolution on over-
- * loadable constructs : operators, subprograms and literals.
- */
-
- Fortup ft1;
- Forset fs1, fs2;
- Node op_node;
- Node prefix_node;
- Node arg_list_node;
- Tuple tmp;
- Set types;
- Set ops;
- Symbol opn;
- Set opns;
- Set valid;
- Symbol sct;
- Symbol t;
- Set usable, set1;
- Symbol typ;
- int exists, nat;
- Symbol package;
- Node arg;
-
- if (cdebug2 > 3) TO_ERRFILE("AT PROC : result_types");
-
- /* Check for previous type error.*/
-
- if (noop_error ) {
- N_PTYPES(expn) = set_new(0);
- return;
- }
-
- op_node = N_AST1(expn);
- arg_list_node = N_AST2(expn);
- ops = set_new(0);
- types = set_new(0);
- /* The C code differs from SETL code in that set loop only needed for simple
- * names ds 8-jan-85
- * this is not longer the case!! gs apr 1 85
- */
- set1 = N_NAMES(op_node);
- FORSET(opn =(Symbol), set1, fs1);
- nat = NATURE(opn);
- if (nat == na_un_op || nat == na_op) {
- tmp = valid_op_types(opn, expn);
- opns = (Set) tmp[1];
- valid = (Set) tmp[2];
- if (set_size(valid) == 0)
- opns = set_new(0);
- /* A predefined operator is usable if its resulting types appears
- * in a lexically open scope, or a used package.
- */
- usable = set_new(0);
- if (N_KIND(op_node) == as_selector
- && SCOPE_OF(opn) == symbol_standard0) {
- /* use of P.'op' for a predefined operator. Name resolution
- * has already verified that the operator is defined in scope
- * P, or that the scope declares an implicit operator. (see
- * find_selected_comp and has_implicit_operator).
- */
- prefix_node = N_AST1(op_node);
- package = N_UNQ(prefix_node);
- /* after which it can be treated as a simple name.*/
- N_KIND(op_node) = as_simple_name;
- FORSET(t=(Symbol), valid, fs2);
- usable = set_with(usable, (char *) t);
- ENDFORSET(fs2);
- }
- else { /* normal infix usage of operator */
- FORSET(t=(Symbol), valid, fs2);
- sct = SCOPE_OF(t);
- if (tup_mem((char *)sct, open_scopes)
- || tup_mem((char *)sct, used_mods))
- usable = set_with(usable, (char *) t);
- ENDFORSET(fs2);
- }
- /* usable := {t in valid | (sct := SCOPE_OF(t)) in open_scopes
- * or sct in used_mods};
- */
- if (set_size(usable) == 0 && set_size(valid) == 1
- && set_size(N_NAMES(op_node)) == 1) {
- pass1_error("operator is not directly visible",
- "6.6, 8.3, 8.4", op_node);
- return;
- }
- else {
- ops = set_union(ops, opns );
- types = set_union(types, usable);
- }
- }
- else if (nat == na_procedure || nat == na_procedure_spec
- || nat == na_function || nat == na_function_spec
- || nat == na_entry || nat == na_entry_family ) {
- typ = valid_arg_list(opn, arg_list_node);
- if (typ != (Symbol)0 ) {
- types = set_with(types, (char *) typ);
- ops = set_with(ops, (char *) opn);
- }
- }
- else if (nat == na_literal) {
- /* A literal may overload a function. The literal is valid only
- * if the argument list is empty.
- */
- if (tup_size(N_LIST(arg_list_node)) == 0) {
- types = set_with(types, (char *) TYPE_OF(opn));
- ops = set_with(ops , (char *) opn);
- }
- }
- ENDFORSET(fs1);
-
- exists = FALSE;
- FORTUP(arg=(Node), N_LIST(arg_list_node), ft1);
- if (set_mem((char *)symbol_universal_fixed, N_PTYPES(arg))) {
- exists = TRUE;
- break;
- }
- ENDFORTUP(ft1);
- if (set_size(types) == 0 && exists ) {
- #ifdef ERRNUM
- errmsgn(267, 268, op_node);
- #else
- errmsg("Missing explicit conversion from universal fixed value",
- "3.5.9, 4.5.5", op_node);
- #endif
- noop_error = TRUE;
- }
- #ifdef DEBUG
- if (cdebug2 > 0) {
- TO_ERRFILE("resulting types ");
- /* use zpsymset from sdbx.c to list set for debugging
- * This is temporary measure until new errmsg package installed
- */
- zppsetsym(types);
- }
- #endif
- N_NAMES(op_node) = ops;
- N_OVERLOADED(op_node) = TRUE;
- N_PTYPES(expn) = types;
- }
-
- void disambiguate(Node expn, Symbol context_typ) /*;disambiguate*/
- {
- /* TBSL: check translation of this procedure CAREFULLY!! (ds 22 may)*/
-
- /* Called from resolve2, when more than one operator or function is
- * compatible with the context type. Apart from true ambiguity, this
- * can also happen if both a predefined and a user-defined operator are
- * visible. This is because all predefined operators in the language have
- * generic signatures (e.g. universal_integer rather than INTEGER) and as
- * result, a user-defined operator does not hide the corresponding
- * operator(they do not have the same signature). The solution is to
- * choose in favor of the user-defined op. if it is defined in the same
- * package as the type, or in an open scope, and in favor of the
- * defined one otherwise. For comparison operators which yields the pre-
- * defined type BOOLEAN, the above reasoning applies to the type of its
- * formals and not to the boolean context.
- *
- * On the other hand, a predefined operator of (generic) type o_t may be
- * compatible with arguments of type a_t and with the context c_t, while
- * a_t is in fact not compatible with c_t. To catch that case, we check
- * valid_op_types again to verify that the result is compatible with the
- * context.
- *
- * A final wrinkle : if the context is universal, as in a number declara-
- * tion, then the predefined operator is used even if a user-defined one
- * is in scope.
- */
-
- Node op_node;
- Node args_node;
- Set valid_ops, ovalid_ops;
- Symbol nam;
- Symbol opn;
- Forset fs1;
- int exists;
- Symbol sc, scc;
- Tuple tup;
- /*TBSL: there are a number of statements of the form
- * valid_ops = {x in valid_ops | c(x) }
- * In C we translate this as
- * ovalid_ops = valid_ops;
- * valid_ops = set_new(0);
- * FORSET(x=, ovalid_ops, fs1);
- * if(c(x)) set_with(valid_ops, x)
- * ENDFORSET
- * Perhaps later we can do this be removing elements from valid_ops.
- * Also we will eventually want to free dead sets.
- */
-
- op_node = N_AST1(expn);
- args_node = N_AST2(expn);
- valid_ops = N_NAMES(op_node);
- if (cdebug2 > 2) {
- TO_ERRFILE("AT PROC: disambiguate");
- FORSET(nam =(Symbol) , valid_ops, fs1);
- TO_ERRFILE("OVERLOADS ");
- ENDFORSET(fs1);
- }
- ovalid_ops = valid_ops;
- valid_ops = set_new(0);
- FORSET(opn=(Symbol), ovalid_ops, fs1);
- if ( (NATURE(opn) != na_op)
- || compatible_op(opn, args_node, context_typ))
- valid_ops = set_with(valid_ops, (char *) opn);
- ENDFORSET(fs1);
- /* return statements have been inserted earlier to simplify the logic
- * of the translation to c (ds 22 may 84)
- */
- if (in_univ_types(context_typ)) {
- ovalid_ops = valid_ops;
- valid_ops = set_new(0);
- FORSET(opn=(Symbol), ovalid_ops, fs1);
- if (TYPE_OF(opn) == context_typ)
- valid_ops = set_with(valid_ops, (char *) opn);
- ENDFORSET(fs1);
- N_NAMES(op_node) = valid_ops;
- return;
- }
-
- exists = FALSE;
- FORSET(nam=(Symbol), valid_ops, fs1);
- sc = SCOPE_OF(nam);
- tup = SIGNATURE(nam);
- if (tup!=(Tuple)0) /* avoid dereference of null pointer */
- scc = (Symbol) tup[1];
- else
- scc = (Symbol)0;
- if (NATURE(nam) != na_op && (sc == SCOPE_OF(context_typ)
- || in_open_scopes(sc)
- /* maybe a compar op. Check against scope of type of first formal.*/
- || (TYPE_OF(nam) == symbol_boolean
- && ( scc!=(Symbol)0 && sc == SCOPE_OF(TYPE_OF(scc)))) ) ) {
- exists = TRUE;
- break;
- }
- ENDFORSET(fs1);
- if (exists) {
- /* user-defined operator(s) hide derived operator.*/
- ovalid_ops = valid_ops;
- valid_ops = set_new(0);
- FORSET(nam=(Symbol), ovalid_ops, fs1);
- if (NATURE(nam) != na_op)
- valid_ops = set_with(valid_ops, (char *) nam);
- ENDFORSET(fs1);
- N_NAMES(op_node) = valid_ops;
- return;
- }
-
- exists = FALSE;
- FORSET(nam=(Symbol), valid_ops, fs1);
- if (NATURE(nam) == na_op) {
- exists = TRUE;
- break;
- }
- ENDFORSET(fs1);
- if (exists) {
- /* It will have precedence over imported user-defined functions.*/
- ovalid_ops = valid_ops;
- valid_ops = set_new(0);
- FORSET(nam=(Symbol), ovalid_ops, fs1);
- if (NATURE(nam) == na_op)
- valid_ops = set_with(valid_ops, (char *) nam);
- ENDFORSET(fs1);
-
- if (is_fixed_type(root_type(context_typ))) {
- /* remove mixed floating operators, that yield universal*/
- /* real, but are not compatible with a fixed type context*/
- ovalid_ops = valid_ops;
- valid_ops = set_new(0);
- FORSET(nam=(Symbol), ovalid_ops, fs1);
- if (TYPE_OF(nam) != symbol_universal_real)
- valid_ops = set_with(valid_ops, (char *) nam);
- ENDFORSET(fs1);
- }
- }
- N_NAMES(op_node) = valid_ops;
- }
-
- static int exist_compatible_type(Set set1, Symbol context_type)
- /*exist_compatible_type*/
- {
- /* retun true if it exists one type of set1 that id compatible
- * with context_type
- */
-
- Forset fs1;
- Symbol t;
-
- FORSET(t=(Symbol), set1, fs1);
- if (compatible_types(t, context_type))
- return TRUE;
- ENDFORSET(fs1);
- return FALSE;
- }
-
- static int compatible_op(Symbol opn, Node args_node, Symbol context_typ)
- /*;compatible_op*/
- {
- Tuple arg_list;
- Set types1, types2;
- Symbol t;
- Forset fs1;
-
- if (cdebug2 > 2) TO_ERRFILE("AT PROC compatible_op");
- /* In most cases, binary operators are homogenenous: the type of their
- * arguments is also the type of the result. We get the types of the
- * arguments to perform this test:
- */
- arg_list = N_LIST(args_node);
- if (tup_size(arg_list) == 0)
- types1 = set_new(0);
- else
- types1 = N_PTYPES(((Node)arg_list[1]));
-
- if (tup_size(arg_list) == 2 ) types2 = N_PTYPES(((Node) arg_list[2]));
-
- /* For comparison operators, the types of the operands are known to be
- * compatible and unrelated to the boolean result.
- */
-
- if (in_comparison_ops(opn)) return TRUE;
- if (opn == symbol_mulifl || opn == symbol_mulifx) {
- FORSET(t=(Symbol), types2, fs1);
- /* For these ops, the second argument yields the result type.*/
- if (compatible_types(t, context_typ))
- return TRUE;
- ENDFORSET(fs1);
- return FALSE;
- }
- if (opn == symbol_cat_ac )
- return ((exist_compatible_type (types1, context_typ)
- && exist_compatible_type (types2, component_type(context_typ))));
- if (opn == symbol_cat_ca)
- return ((exist_compatible_type (types2, context_typ)
- && exist_compatible_type (types1, component_type(context_typ))));
- if (opn == symbol_cat_cc)
- return ((exist_compatible_type (types2, component_type(context_typ))
- && exist_compatible_type (types1, component_type(context_typ))));
- return (exist_compatible_type (types1, context_typ));
- }
-
- void remove_conversions(Node expn) /*;remove_conversions*/
- {
- /* If after the previous procedure an expression is still ambiguous, this
- * may be due to an implicit conversion of a universal quantity. This can
- * only happen in the presence of user-defined operators. We therefore
- * attempt to resolve the expression again, after removing user-defined
- * operators from the tree, whose arguments are universal quantities.
- * A full disambiguation would require that we try to remove these selec-
- * tively. Here we simply remove all of them, and give up if the result
- * is still ambiguous.
- */
-
- Node args_node, arg, op_node, a_list_node, ts, a_expn;
- Set arg_types, arg_op, tset;
- Symbol n, t;
- int exists, nk;
- Fortup ft1;
- Forset fs1;
-
- if (cdebug2 > 2) TO_ERRFILE("AT PROC: remove_conversions");
-
- nk = N_KIND(expn);
- if (nk == as_call || nk == as_op || nk == as_un_op) {
- args_node = N_AST2(expn);
- FORTUP(arg =(Node), N_LIST(args_node), ft1);
- arg_types = N_PTYPES(arg);
- if (set_size( arg_types) < 2 ); /*$ unambiguous.*/
- else if (N_KIND(arg) != as_aggregate ) {
- op_node = N_AST1(arg);
- a_list_node = N_AST2(arg);
- arg_op = N_NAMES(op_node);
- if (!N_OVERLOADED(op_node) );
- /* Incomplete: could be an indexing on an overloaded call!*/
-
- else if (
- !in_op_designators(original_name((Symbol)set_arb(arg_op))))
- /* May be overloaded because some of its arguments are.*/
- remove_conversions(arg);
- else {
- exists = FALSE;
- FORTUP(ts=(Node), N_LIST(a_list_node), ft1);
- if (set_mem((char *) symbol_universal_integer,
- N_PTYPES(ts)) || set_mem(
- (char *)symbol_universal_real, N_PTYPES(ts))) {
- exists = TRUE;
- break;
- }
- ENDFORTUP(ft1);
- if (exists) {
- /* Some arg is universal. Resolve as predefined op */
- tset = set_new(0);
- FORSET(n=(Symbol), arg_op, fs1);
- if (NATURE(n) == na_op)
- tset = set_with(tset, (char *) n);
- ENDFORSET(fs1);
- N_NAMES(op_node) = tset;
- result_types(arg);
- }
- }
- }
- ENDFORTUP(ft1);
-
- /* Use the pruned argument list to resolve again the expression.*/
- result_types(expn);
- }
- else if (nk == as_all) {
- a_expn = N_AST1(expn);
- remove_conversions(a_expn);
- tset = set_new(0);
- FORSET(t=(Symbol), N_PTYPES(a_expn), fs1);
- if (is_access(t))
- tset = set_with(tset, (char *) designated_type(t));
- ENDFORSET(fs1);
- N_PTYPES(expn) = tset;
- }
- else { /* may be continued: indexing, selection. */
- ;
- }
- }
-
- static Tuple valid_op_types(Symbol opn, Node expn) /*;valid_op_types*/
- {
- /* This procedure is invoked during the bottom-up pass of type
- * resolution. It determines the possible result types of predefined
- * operators, using the possible types of their arguments.
- * All arithmetic operators have special rules that apply within literal
- * expressions. They are all treated in routine valid_arith_ops.
- * For other operators, the following rule applies:
- * Binary operators yield the intersection of the types of their two
- * arguments, provided that they are boolean (For boolean operators),
- * discrete (for ordering operators) , etc.
- * The concatenation operator provides an exception : it will
- * concatenate and array with an object of the component type, either
- * on the left or right.
- * The node can be a call ( "+"(a,b) for example) or a qualified name,
- * in which case the only way to distinguish between unary and binary
- * ops. is to look at the length of the argument list.
- */
-
- /* const unary_ops = ['+', '-', 'abs', 'not']; */
- Node op_node, arg_list_node, arg1, arg2;
- Set possible_types, opossible_types, typ1, typ2;
- Symbol t2, t, typ;
- Set types;
- Tuple arg_list, tup;
- Forset fs1, fs2;
- int exists;
-
- if (cdebug2 > 3) TO_ERRFILE("AT PROC : valid_op_types");
-
- op_node = N_AST1(expn);
- arg_list_node = N_AST2(expn);
-
- if (N_KIND(expn) == as_un_op
- || (tup_size(N_LIST(arg_list_node)) == 1 && in_unary_ops(opn ) ) )
- arg_list = order_arg_list(arg_list_node, unary_sig);
- else
- arg_list = order_arg_list(arg_list_node, binary_sig);
- if (arg_list == (Tuple)0) {
- tup = tup_new(2);
- tup[1] = (char *) set_new(0);
- tup[2] = (char *) set_new(0);
- return tup;
- }
-
- if (TYPE_OF(opn) == symbol_numeric)
- return valid_arith_types(opn, arg_list);
-
- if (tup_size(arg_list) == 1) {
- arg1 = (Node) arg_list[1];
- possible_types =set_new(0);
- FORSET(t=(Symbol), N_PTYPES(arg1), fs1);
- possible_types = set_with(possible_types, (char *) base_type(t));
- ENDFORSET(fs1);
- }
- else {
- /*Binary operator.*/
- arg1 = (Node) arg_list[1];
- arg2 = (Node) arg_list[2];
- typ1 = N_PTYPES(arg1);
- typ2 = N_PTYPES(arg2);
-
- if (opn == symbol_cat)
- /* Both arguments must have the same one-dimensional array type,
- * or one or both may have the component type of such an array type
- */
- return (valid_concatenation_type ( typ1, typ2));
-
- else{
- /* All other binary operators are homogeneous : the arguments
- * must have compatible types,
- */
- possible_types = set_new(0);
- FORSET(t=(Symbol), typ1, fs1);
- exists = FALSE;
- FORSET(t2=(Symbol), typ2, fs2);
- if (compatible_types(t, t2) && t != symbol_universal_fixed){
- exists = TRUE;
- break;
- }
- ENDFORSET(fs2);
- if (exists)
- possible_types = set_with(possible_types,
- (char *) base_type(t));
- ENDFORSET(fs1);
- }
- }
- /* Remove array types with incomplete private components.*/
- opossible_types = possible_types;
- possible_types = set_new(0);
- FORSET(t=(Symbol), opossible_types, fs1);
- /* the aim of this test is to remove array types with incomplete
- * private components. We think taht the use of the function
- * "is_fully_private" is indadequate in this case. The new test checks
- * id the array is incomplete and private
- */
- /* if(!is_array(t) || ! is_fully_private(t) ) {*/
- if (!is_array(t)
- || (! ((((int) misc_type_attributes (t)) & TA_INCOMPLETE)
- && (((int) misc_type_attributes (t))
- & (TA_PRIVATE | TA_LIMITED_PRIVATE)))))
- possible_types = set_with(possible_types, (char *) t);
- ENDFORSET(fs1);
-
- typ = TYPE_OF(opn);
- if (typ == symbol_boolean) {
- /* equality and membership operators.*/
-
- if (opn == symbol_eq || opn == symbol_ne) {
- exists = FALSE;
- FORSET(t=(Symbol), possible_types, fs1);
- if (! is_limited_type(t)) {
- types = set_new1((char *) symbol_boolean);
- exists = TRUE;
- break;
- }
- ENDFORSET(fs1);
- if (! exists) types = set_new(0);
- }
- else {
- if (set_size(possible_types) > 0)
- types = set_new1((char *) symbol_boolean);
- else
- types = set_new(0);
- }
- }
- else if(typ == symbol_boolean_type) {
- /* Boolean and short circuit operators.*/
-
- if (opn == symbol_andthen || opn == symbol_orelse) {
- types = set_new(0);
- FORSET(t=(Symbol), possible_types, fs1);
- if (root_type(t) == symbol_boolean)
- types = set_with(types, (char *) t);
- ENDFORSET(fs1);
- }
- else {
- types = set_new(0);
- FORSET(t=(Symbol), possible_types, fs1);
- if(root_type(t) == symbol_boolean || is_array(t)
- && no_dimensions(t) == 1
- && root_type((Symbol)(component_type(t))) == symbol_boolean)
- types = set_with(types, (char *) t);
- ENDFORSET(fs1);
- }
- }
- else if (typ == symbol_order_type) { /* Comparison operators.*/
- exists = FALSE;
- FORSET(t=(Symbol), possible_types, fs1);
- if (is_scalar_type(t) || is_array(t) && no_dimensions(t) == 1
- && is_discrete_type((Symbol)component_type(t))) {
- types = set_new1((char *) symbol_boolean);
- exists = TRUE;
- break;
- }
- ENDFORSET(fs1);
- if (!exists) types = set_new(0);
- }
- else if (typ == symbol_any) /* Syntax error*/
- types = set_new1((char *) symbol_any);
-
- else {
- /* The SETL simply prints the TYPE_OF field, i.e. the unique name
- * of some entry in the symbol table. In C, this is not enough!
- */
- char *msg = emalloct(100, "valid-op-types-msg");
-
- sprintf(msg, "at loc: %d, nature: %s, value: %s",
- typ, nature_str(NATURE(typ)), ORIG_NAME(typ) );
- #ifdef ERRNUM
- str_errmsgn(269, msg, 10, arg1);
- #else
- errmsg_str("system error: strange op type %", msg, "none", arg1);
- #endif
- efreet(msg, "valid-op-types-msg");
- }
- tup = tup_new(2);
- tup[1] = (char *) set_new1((char *) opn);
- tup[2] = (char *) types;
- return tup;
- }
-
- static int in_unary_ops(Symbol opn) /*;in_unary_ops*/
- {
- /* const unary_ops = ['+', '-', 'abs', 'not'];
- * corresponds to opn in unary_ops
- */
- return (opn == symbol_add || opn == symbol_sub || opn == symbol_abs
- || opn == symbol_not);
- }
- /* OP_SUFFIX codes used to represent SETL sfx character string values */
-
- #define OP_SUFFIX_NONE 0
- #define OP_SUFFIX_I 1
- #define OP_SUFFIX_FL 2
- #define OP_SUFFIX_FX 3
- #define OP_SUFFIX_FLI 4
- #define OP_SUFFIX_FXI 5
- #define OP_SUFFIX_IFL 6
- #define OP_SUFFIX_IFX 7
- #define OP_SUFFIX_U 8
- #define OP_SUFFIX_UI 9
- #define OP_SUFFIX_UFL 10
- #define OP_SUFFIX_UFX 11
-
- Tuple valid_arith_types(Symbol opn, Tuple arg_list) /*;valid_arith_types*/
- {
- /* Bottom-up pass over arithmetic expressions. return the pair:
- * [possible operators, possible result types] .
- */
- #ifdef TBSN
-
- macro i;
- "INTEGER" endm;
- macro fl;
- "FLOAT" endm;
- macro fx;
- "$FIXED" endm;
- macro ui;
- "universal_integer" endm;
- macro ur;
- "universal_real" endm;
- macro ufx;
- "universal_fixed" endm;
-
- const numeric_types = {
- i, fl, fx, ui, ur},
- universal_types = {
- ui, ur},
-
- adding_types = {
- [i , i ], [fl, fl], [fx, fx], [ui, i],
- [ui, ui], [ur, ur], [ur, fx], [ur, fl]},
-
- mult_types = {
- [i , i ], [fl, fl], [fx, fx], [ui, i ],
- [ui, ui], [ur, ur], [ur, fl]},
-
- mixed_mult_types = {
- [fx, i], [fx, ui], [ur, ui], [ur, i]},
-
- mod_types = {
- [i, i], [ui, i], [i, ui], [ui, ui]},
-
- expon_types = {
- [i , i ], [fl, i ], [ur, i ], [ui, i ],
- [i , ui], [fl, ui], [ur, ui], [ui, ui] },
-
-
- op_suffix = {
- [i, "i"], [ui, "i"], [fl, "fl"], [ur, "fl"],
- [fx, "fx"] , [ufx, "fx"]
- };
- #endif
-
- Set possible_types, types, ops, typ1, typ2;
- Symbol t;
- Symbol t1, t2, r_type, bt1, bt2;
- int sfx;
- Forset fs1, fs2;
- Tuple tup;
-
- if (cdebug2 > 3) TO_ERRFILE("AT PROC : valid_arith_types");
- if (tup_size(arg_list) == 1) { /* Unary ops return the type*/
- /* of their argument.*/
- possible_types = (Set) (N_PTYPES((Node)(arg_list[1])) );
-
- types = set_new(0);
- FORSET(t=(Symbol), possible_types, fs1);
- if (in_numeric_types(root_type(t)))
- types = set_with(types, (char *) base_type(t));
- ENDFORSET(fs1);
-
- /*Construct the unary version of the operator name.*/
- if (opn == symbol_add) opn = symbol_addu;
- else if (opn == symbol_sub) opn = symbol_subu;
- /*ops = ??{ opn + op_suffix(root_type(t)): t in types};*/
- ops = set_new(0);
- FORSET(t=(Symbol), types, fs1);
- ops = set_with(ops,
- (char *)op_suffix_gen(opn, op_suffix(root_type(t))));
- ENDFORSET(fs1);
- tup = tup_new(2);
- tup[1] = (char *) ops;
- tup[2] = (char *) types;
- return tup;
- }
- else {
- typ1 = N_PTYPES((Node)(arg_list[1]));
- typ2 = N_PTYPES((Node)(arg_list[2]));
-
- ops = set_new(0);
- types =set_new(0);
-
- FORSET(t1=(Symbol), typ1, fs1);
- FORSET(t2=(Symbol), typ2, fs2);
- sfx =OP_SUFFIX_NONE;/* Suffix to designate type of op.*/
- r_type = (Symbol)0; /*will indicate type found.*/
- bt1 = root_type(t1);
- bt2 = root_type(t2);
-
- if (opn == symbol_add || opn == symbol_sub) {
- if (in_adding_types(bt1, bt2)
- || in_adding_types(bt2, bt1) )
- r_type = intersect_types(t1, t2);
- }
- else if (opn == symbol_mul || opn == symbol_div) {
- if (in_mult_types(bt1, bt2) || in_mult_types(bt2, bt1) ) {
- if (is_fixed_type(bt1)||is_fixed_type(bt2))
- r_type = symbol_universal_fixed;
- else
- r_type = intersect_types(t1, t2);
- }
- else {
- /* Mixed mode operation on fixed types, or
- * literal expression.
- */
- if (in_mixed_mult_types(bt1, bt2) ) {
- if (eq_universal_types(bt1, bt2 )) {
- /* Literal expr.*/
- r_type = symbol_universal_real;
- sfx = OP_SUFFIX_FLI; /* Compile-time op.*/
- }
- else if (base_type(t2) == symbol_integer) {
- /* Mixed mode operation with a fixed type.
- * If the first argument is universal, the
- * result is $FIXED, i.e any fixed type.
- */
- if (t1 == symbol_universal_real )
- r_type = symbol_dfixed;
- else r_type = t1;
- sfx = OP_SUFFIX_FXI; /* Run-time operation.*/
- }
- else if (bt2 == symbol_universal_integer) {
- /* specific type on left*/
- r_type = t1;
- sfx = OP_SUFFIX_FXI;
- }
- }
- else if (in_mixed_mult_types(bt2, bt1)
- && opn == symbol_mul/* '*'*/) {
- /* Mixed modes are not commutative for division.*/
- if (eq_universal_types(bt1, bt2) ) {
- r_type = symbol_universal_real;
- sfx = OP_SUFFIX_IFL;
- }
- else if (base_type(t1) == symbol_integer) {
- /* $FIXED, or the specific fixed type t2.*/
- if (t2 == symbol_universal_real)
- r_type = symbol_dfixed;
- else r_type = t2;
- sfx = OP_SUFFIX_IFX;
- }
- else if (bt1 == symbol_universal_integer) {
- /* specific type on right*/
- r_type = t2;
- sfx = OP_SUFFIX_IFX;
- }
- }
- }
- }
- else if (opn == symbol_mod || opn == symbol_rem) {
- if (in_mod_types(bt1, bt2) )
- r_type = intersect_types(t1, t2);
- }
- else if(opn == symbol_exp) {
- /* The result of an exponentiation has the type of the
- * first argument.
- */
- if (in_expon_types(bt1, bt2)) r_type = t1;
- }
-
- if (r_type != (Symbol)0) { /* Pair of matching types found.*/
- /* The result type of an arithmetic operation does not carry
- * the constraint (if any) of the arguments. Therefore, drop
- * the constraint on the result if it appears as a subtype.
- */
- types = set_with(types, (char *) base_type(r_type));
-
- /* Append to the operator name a suffix that specifies the
- * type of its arguments and the type returned.
- */
- if (sfx == OP_SUFFIX_NONE)
- sfx = op_suffix(root_type(r_type));
- ops = set_with(ops, (char *) op_suffix_gen(opn , sfx) );
- }
- ENDFORSET(fs2);
- ENDFORSET(fs1);
- }
- tup = tup_new(2);
- tup[1] = (char *)ops;
- tup[2] = (char *)types;
- return tup;
- }
-
- static int op_suffix(Symbol ocode) /*;op_suffix*/
- {
- /* Return C analog of op_suffix in SETL version.
- * op_suffix = { [i, 'i'], [ui, 'i'], [fl, 'fl'], [ur, 'fl'],
- * [fx, 'fx'] , [ufx, 'fx']};
- */
- if (ocode == symbol_integer) return OP_SUFFIX_I;
- if (ocode == symbol_universal_integer) return OP_SUFFIX_I;
- if (ocode == symbol_float) return OP_SUFFIX_FL;
- if (ocode == symbol_universal_real) return OP_SUFFIX_FL;
- if (is_fixed_type(ocode)) return OP_SUFFIX_FX;
- if (ocode == symbol_universal_fixed) return OP_SUFFIX_FX;
- return OP_SUFFIX_NONE;
- }
-
- static Symbol op_suffix_gen(Symbol op, int sfx) /*;op_suffix_gen*/
- {
- /* Generate symbol correspond to op with suffix code sfx */
- if (sfx == OP_SUFFIX_NONE) return op;
- if (op == symbol_abs) {
- if (sfx == OP_SUFFIX_FL) return symbol_absfl;
- if (sfx == OP_SUFFIX_FX) return symbol_absfx;
- if (sfx == OP_SUFFIX_I) return symbol_absi;
- }
- else if (op == symbol_add) { /* + */
- if (sfx == OP_SUFFIX_FL) return symbol_addfl; /* +fl */
- if (sfx == OP_SUFFIX_FX) return symbol_addfx; /* +fx */
- if (sfx == OP_SUFFIX_I) return symbol_addi; /* +i */
- if (sfx == OP_SUFFIX_U) return symbol_addu; /* +u */
- if (sfx == OP_SUFFIX_UFL) return symbol_addufl; /* +ufl */
- if (sfx == OP_SUFFIX_UFX) return symbol_addufx; /* +ufx */
- if (sfx == OP_SUFFIX_UI) return symbol_addui; /* +ui */
- }
- else if (op == symbol_addu) { /* +u */
- if (sfx == OP_SUFFIX_FL) return symbol_addufl; /* +ufl */
- if (sfx == OP_SUFFIX_FX) return symbol_addufx; /* +ufx */
- if (sfx == OP_SUFFIX_I) return symbol_addui; /* +ui */
- }
- else if (op == symbol_div) { /* / */
- if (sfx == OP_SUFFIX_FL) return symbol_divfl; /* /fl */
- if (sfx == OP_SUFFIX_FLI) return symbol_divfli; /* /fli */
- if (sfx == OP_SUFFIX_FX) return symbol_divfx; /* /fx */
- if (sfx == OP_SUFFIX_FXI) return symbol_divfxi; /* /fxi */
- if (sfx == OP_SUFFIX_I) return symbol_divi; /* /i */
- }
- else if (op == symbol_exp) {
- if (sfx == OP_SUFFIX_I) return symbol_expi; /* **i */
- if (sfx == OP_SUFFIX_FL) return symbol_expfl; /* **fl */
- }
- else if (op == symbol_mod) { /* mod */
- if (sfx == OP_SUFFIX_I) return symbol_modi; /* modi */
- }
- else if (op == symbol_mul) { /* * */
- if (sfx == OP_SUFFIX_I) return symbol_muli; /* *i */
- if (sfx == OP_SUFFIX_FL) return symbol_mulfl; /* *fl */
- if (sfx == OP_SUFFIX_FLI) return symbol_mulfli; /* *fli */
- if (sfx == OP_SUFFIX_FX) return symbol_mulfx; /* *fx */
- if (sfx == OP_SUFFIX_FXI) return symbol_mulfxi; /* *fxi */
- if (sfx == OP_SUFFIX_IFL) return symbol_mulifl; /* *ifl */
- if (sfx == OP_SUFFIX_IFX) return symbol_mulifx; /* *ifx */
- }
- else if (op == symbol_rem) {
- if (sfx == OP_SUFFIX_I) return symbol_remi; /* remi */
- }
- else if (op == symbol_sub) { /* - */
- if (sfx == OP_SUFFIX_FL) return symbol_subfl; /* -fl */
- if (sfx == OP_SUFFIX_FX) return symbol_subfx; /* -fx */
- if (sfx == OP_SUFFIX_I) return symbol_subi; /* -i */
- if (sfx == OP_SUFFIX_U) return symbol_subu; /* -u */
- if (sfx == OP_SUFFIX_UFL) return symbol_subufl; /* -ufl */
- if (sfx == OP_SUFFIX_UFX) return symbol_subufx; /* -ufx */
- if (sfx == OP_SUFFIX_UI) return symbol_subui; /* -ui */
- }
- else if (op == symbol_subu) { /* -u */
- if (sfx == OP_SUFFIX_I) return symbol_subui; /* -ui */
- if (sfx == OP_SUFFIX_FL) return symbol_subufl; /* -ufl */
- if (sfx == OP_SUFFIX_FX) return symbol_subufx; /* -ufx */
- }
- #ifdef TBSL
- -- need to handle subui and addui more completely, check
- -- other unary operators
- #endif
- #ifdef DEBUG
- printf("unable to match operator\n");
- zpsym(op);
- #endif
- chaos("op_suffix_gen(4)");
- return (Symbol)0;
- }
-
- #undef OP_SUFFIX_NONE
- #undef OP_SUFFIX_I
- #undef OP_SUFFIX_FL
- #undef OP_SUFFIX_FX
- #undef OP_SUFFIX_FLI
- #undef OP_SUFFIX_FXI
- #undef OP_SUFFIX_IFL
- #undef OP_SUFFIX_IFX
- #undef OP_SUFFIX_U
- #undef OP_SUFFIX_UI
- #undef OP_SUFFIX_UFL
- #undef OP_SUFFIX_UFX
-
- Symbol intersect_types(Symbol t1, Symbol t2) /*;intersect_types*/
- {
- /* Find the more specific of two numeric types, if they are compatible.
- * In particular, if only one of them is universal, return the other.
- * Called to validate arithmetic arguments and bounds of subtypes.
- */
-
- if (cdebug2 > 3) TO_ERRFILE("AT PROC : intersect_types");
-
- #ifdef TBSN
- Const universal_types =
- { 'universal_integer', 'universal_real', '$FIXED' };
- #endif
- if (compatible_types(t1, t2)) {
- if (t1 == symbol_universal_integer || t1 == symbol_universal_real
- || t1 == symbol_dfixed)
- return (t2);
- else if (t2 == symbol_universal_integer || t2 == symbol_universal_real
- || t2 == symbol_dfixed)
- return (t1);
- else return(t1);
- }
- else return (Symbol)0;
- }
-
- static int in_numeric_types(Symbol t) /*;in_numeric_types*/
- {
- return t == symbol_integer
- || t == symbol_float
- || is_fixed_type(t)
- || t == symbol_universal_integer
- || t == symbol_universal_real;
- }
-
- static int eq_universal_types(Symbol t1, Symbol t2) /*;eq_universal_types*/
- {
- return (t1 == symbol_universal_integer && t2 == symbol_universal_real)
- || (t2 == symbol_universal_integer && t1 == symbol_universal_real);
- }
-
- static int in_adding_types(Symbol t1, Symbol t2) /*;in_adding_types*/
- {
- /* [symbol_integer , symbol_integer ],
- * [symbol_float, symbol_float],
- * [symbol_dfixed, symbol_dfixed],
- * [symbol_universal_real, symbol_universal_real],
- * [symbol_universal_integer, symbol_integer],
- * [symbol_universal_integer, symbol_universal_integer],
- * [symbol_universal_real, symbol_dfixed],
- * [symbol_universal_real, symbol_float] ,
- */
- if (t1 == t2) {
- if (t1 == symbol_integer || t1 == symbol_float || is_fixed_type(t1)
- || t1 == symbol_universal_real) return TRUE;
- }
- if (t1 == symbol_universal_integer)
- return (t2 == symbol_integer|| t2 == symbol_universal_integer);
- if (t1 == symbol_universal_real)
- return (is_fixed_type(t2) || t2 == symbol_float);
- return FALSE;
- }
-
- static int in_mult_types(Symbol t1, Symbol t2) /*;in_mult_types*/
- {
- /* { [symbol_integer , symbol_integer ],
- * [symbol_float, symbol_float],
- * [symbol_dfixed, symbol_dfixed],
- * [symbol_universal_integer, symbol_universal_integer],
-
- * [symbol_universal_integer, symbol_integer ],
- * [symbol_universal_real, symbol_universal_real],
- * [symbol_universal_real, symbol_float],
- * }
- */
- if (t1 == t2)
- return (t1 == symbol_integer || t1 == symbol_float || is_fixed_type(t1)
- || t1 == symbol_universal_integer || t1 == symbol_universal_real);
- if (t1 == symbol_universal_integer && t2 == symbol_integer)
- return TRUE;
- if (t1 == symbol_universal_real)
- return (t2 == symbol_float);
- return FALSE;
- }
-
- static int in_mixed_mult_types(Symbol t1, Symbol t2) /*;in_mixed_mult_types*/
- {
- /* [symbol_dfixed, symbol_integer],
- * [symbol_dfixed, symbol_universal_integer],
- * [symbol_universal_real, symbol_universal_integer],
- * [symbol_universal_real, symbol_integer]
- */
- if (is_fixed_type(t1))
- return (t2 == symbol_integer || t2 == symbol_universal_integer);
- if (t1 == symbol_universal_real)
- return (t2 == symbol_universal_integer || t2 == symbol_integer);
- return FALSE;
- }
-
- static int in_mod_types(Symbol t1, Symbol t2) /*;in_mod_types*/
- {
- /* [symbol_integer, symbol_integer],
- * [symbol_integer, symbol_universal_integer],
- * [symbol_universal_integer, symbol_integer],
- * [symbol_universal_integer, symbol_universal_integer]
- */
-
- if (t1 == symbol_integer)
- return (t2 == symbol_integer || t2 == symbol_universal_integer);
- if (t1 == symbol_universal_integer)
- return (t2 == symbol_integer || t2 == symbol_universal_integer);
- return FALSE;
- }
-
- static int in_expon_types(Symbol t1, Symbol t2) /*;in_expon_types*/
- {
- /* [symbol_integer , symbol_universal_integer],
- * [symbol_integer , symbol_integer ],
- * [symbol_float, symbol_integer ],
- * [symbol_float, symbol_universal_integer],
- * [symbol_universal_integer, symbol_universal_integer]
- * [symbol_universal_integer, symbol_integer ],
- * [symbol_universal_real, symbol_integer ],
- * [symbol_universal_real, symbol_universal_integer],
- */
- if (t1 == symbol_integer)
- return (t2 == symbol_integer || t2 == symbol_universal_integer);
- if (t1 == symbol_float)
- return (t2 == symbol_integer || t2 == symbol_universal_integer);
- if (t1 == symbol_universal_integer)
- return (t2 == symbol_integer || t2 == symbol_universal_integer);
- if (t1 == symbol_universal_real)
- return (t2 == symbol_integer || t2 == symbol_universal_integer);
- return FALSE;
- }
-
- static Symbol valid_arg_list(Symbol proc_name, Node arg_list_node)
- /*;valid_arg_list*/
- {
- Tuple formals, arg_list;
- Node actual;
- Set a_types;
- Symbol t;
- Forset fs1;
- Fortup ft1;
- int exists, i;
- Symbol f;
-
- if (cdebug2 > 3) TO_ERRFILE("AT PROC : valid_arg_list");
- /* This procedure is called during the bottom-up phase of overloading
- * resolution. It checks whether an argument list is compatible with
- * the formals of a subprogram, and yields the return type of the
- * subprogram if the answer is affirmative.
- * The arguments have already been processed by the first pass.
- */
-
- formals = SIGNATURE(proc_name);
- arg_list = order_arg_list(arg_list_node, formals); /*Normalize arguments*/
-
- if (cdebug2 > 0) TO_ERRFILE("valid arg list : formals ");
-
- if (arg_list == (Tuple)0) return (Symbol)0; /* no match, or error*/
-
- /* Traverse signature and actuals, and verify that types match.*/
-
- FORTUPI(f=(Symbol), formals, i, ft1);
- actual = (Node) arg_list[i];
- if (actual == OPT_NODE) continue; /* Default value exists.*/
- else a_types = N_PTYPES(actual);
-
- exists = FALSE;
- FORSET(t=(Symbol), a_types, fs1);
- if (compatible_types(TYPE_OF(f), t)) {
- exists = TRUE;
- break;
- }
- ENDFORSET(fs1);
- if (exists)
- continue;
- else
- return (Symbol)0;
- ENDFORTUP(ft1);
-
- /* All arguments have a match.*/
- return (TYPE_OF(proc_name));
- }
-
- void complete_op_expr(Node expn, Symbol ctx_type) /*;complete_op_expr*/
- {
- /* Complete the top-down pass of an expression with a predefined
- * operator.
- * For predefined operators, the signature of the operator does not
- * fix the type of the arguments, because it only specifies a class
- * of types. The precise type to be used is either imposed by context
- * (this is the argument ctx_type) or is found by requiring consistency
- * between the possible types of the arguments themselves.
- */
- #ifdef TBSN
- const comparison_ops = {
- '<', '<=', '>', '>=', '=', '/='
- };
- #endif
-
- Node o, args;
- Symbol op_name;
- Tuple arg_list;
- Node arg1, arg2;
- Set t_left, t_right, ok_types, univ;
- Symbol ctx_root, t2, t1, isym, typ;
- Forset fs1, fs2;
-
-
- o = N_AST1(expn);
- args = N_AST2(expn);
- op_name = N_UNQ(o);
- arg_list = N_LIST(args);
-
- if (cdebug2 > 0) TO_ERRFILE("complete_op_expr:");
-
- if (tup_size(arg_list) == 1)
- arg_list = order_arg_list(args, unary_sig);
- else
- arg_list = order_arg_list(args, binary_sig);
-
- if (arg_list == (Tuple)0) return;
- N_LIST(args) = arg_list; /* Normalize if named parameters. */
-
- if (tup_size( arg_list) == 2) { /*Binary operators.*/
- arg1 = (Node) arg_list[1];
- arg2 = (Node) arg_list[2];
- t_left = N_PTYPES(arg1);
- t_right = N_PTYPES(arg2);
-
- typ = TYPE_OF(op_name);
- if (typ == symbol_universal_integer || typ == symbol_universal_real
- || typ == symbol_universal_fixed
- || (typ!=(Symbol)0 && is_fixed_type(typ))) {
- ctx_root = root_type(ctx_type);
-
- if (ctx_type == symbol_universal_fixed) {
- /* Must have appeared in a conversion. Each argument must be of
- * some fixed type.
- */
- t1 = ctx_type; /* by default */
- FORSET(t1=(Symbol), t_left, fs1);
- if (compatible_types(t1, symbol_dfixed)) break;
- ENDFORSET(fs1);
-
- t2 = ctx_type;
- FORSET(t2=(Symbol), t_right, fs2);
- if (compatible_types(t2, symbol_dfixed)) break;
- ENDFORSET(fs1);
- /* TBSL: not catching ambiguity in these loops.*/
- resolve2(arg1, t1);
- resolve2(arg2, t2);
- }
- else if (op_name == symbol_mulfxi || op_name == symbol_mulifx
- || op_name == symbol_divfxi || op_name == symbol_expi
- || op_name == symbol_expfl) {
- /* For mixed mode fixed operations and exponentiation,
- * the type from context is imposed on the first
- * argument. The second one must be INTEGER.
- */
- if (op_name == symbol_mulifx) { /*permute arguments.*/
- Tuple tup= tup_new(2);
- tup[1] = (char *) arg2;
- tup[2] = (char *) arg1;
- N_LIST(args) = tup;
- arg1 = (Node) tup[1];
- arg2 = (Node) tup[2];
- op_name = symbol_mulfxi;
- N_UNQ(o) = symbol_mulfxi;
- }
-
- if (ctx_type == symbol_dfixed) {
- /* mixed mode expression in a context that does not
- * have an explicit fixed type: comparison or conversion.
- */
- errmsg("invalid context for mixed-mode operation",
- "4.5.5, 4.10", expn);
- }
- if (op_name == symbol_expfl && is_fixed_type(ctx_root)) {
- /* universal expression in fixed context: no ** .*/
- #ifdef ERRNUM
- errmsgn(270, 271, expn);
- #else
- errmsg(
- "Missing explicit conversion from universal_real value ",
- "4.5.6", expn);
- #endif
- }
- resolve2(arg1, ctx_type);
- resolve2(arg2, symbol_integer);
- /*
- * The second argument is not universal, yet the whole
- * may be constant-foldable. Fold arg2, and if static
- * make universal again.
- */
- eval_static(arg2);
- if (N_KIND(arg2) == as_ivalue )
- N_TYPE(arg2) = symbol_universal_integer;
- #ifdef TBSL
- /* TBSL (In C, will need explicit conversion)*/
- #endif
- }
- else if (op_name == symbol_mulfli
- || op_name == symbol_mulifl
- || op_name == symbol_divfli) {
- /* These mixed mode operations appear in number declara-
- * tions, in which case they are universal, or in a fixed
- * type context.
- */
- if (op_name == symbol_mulifl) { /* permute arguments.*/
- Tuple tup = tup_new(2);
- tup[1] = (char *) arg2;
- tup[2] = (char *) arg1;
- N_LIST(args) = tup;
- arg1 = (Node) tup[1];
- arg2 = (Node) tup[2];
- op_name = symbol_mulfli;
- N_UNQ(o) = symbol_mulfli;
- }
- if (ctx_root == symbol_universal_real)
- t2 = symbol_universal_integer;
- else if (is_fixed_type(ctx_root))
- /* universal expression in fixed context.*/
- t2 = symbol_integer;
- else {
- #ifdef ERRNUM
- errmsgn(272, 273, expn);
- #else
- errmsg("Invalid context for mixed mode operation",
- "4.5.5, 4.10", expn);
- #endif
- N_KIND(expn) = as_opt;
- return;
- }
- resolve2(arg1, ctx_type);
- resolve2(arg2, t2);
- }
- else {
- /* For other arithmetic operators, propagate context
- * type to arguments.
- */
- resolve2(arg1, ctx_type);
- resolve2(arg2, ctx_type);
- }
- /* If the context is universal, evaluate the corresponding
- * literal expression.
- */
- if (in_univ_types(ctx_type ) || (is_fixed_type(ctx_root)
- && N_KIND(arg1) == as_ivalue && N_KIND(arg2) == as_ivalue))
- literal_expression(expn);
- if ((op_name == symbol_mulfl || op_name == symbol_divfl)
- && (is_fixed_type(ctx_root)) && (!is_fixed_type(ctx_type))) {
- /* These floating point operation may appear in some fixed
- * type context if their constituents are literals. this is
- * an error because the operation yields a universal_fixed
- * quantity that must be explicitly converted If a conversion
- * is present, the context type itself is symbol_dfixed.
- */
- #ifdef ERRNUM
- l_errmsgn(274, 275, 276, expn);
- #else
- errmsg_l("Missing explicit conversion from ",
- "universal_fixed value ", "4.5.5", expn);
- #endif
- }
- }
- else if (typ == symbol_order_type || typ == symbol_discrete_type
- || typ == symbol_boolean) {
- /* Equality, set or comparison operators. Verify that there is
- * only one possible type choice for both arguments. If both arg.
- * are universal, we must choose a universal interpretation for
- * each. Otherwise, the non-universal type is applied to both.
- */
- #ifdef TBSN
- /* it happens to be wrong.*/
- /* In the case of an array compared to an aggregate, the array is
- * already constrained as it is an object.
- */
- need_constr_type = FALSE;
- exists = FALSE;
- if (N_KIND(arg1) == as_simple_name ) {
- arg1_name = N_UNQ(arg1);
- exists = TRUE;
- }
- #endif
- ok_types = set_new(0);
- FORSET(t1=(Symbol), t_left, fs1);
- FORSET(t2=(Symbol), t_right, fs2);
- isym = intersect_types(t1, t2);
- if (isym!=(Symbol)0) {
- #ifdef TBSN
- if (N_KIND(arg1) == as_selector) {
- obj = N_AST1(arg1);
- s_node = N_AST2(arg1);
- selector = N_VAL(s_node);
- types1 = N_PTYPES(obj);
- FORSET( o_t =(Symbol), types1, fs1);
- if (is_access(o_t) )
- t = (Symbol) designated_type(o_t);
- else
- t = o_t;
- if (is_record(t))
- decls = (Declaredmap)
- declared_components(base_type(t));
- else if (is_task_type(t))
- decls = DECLARED(t);
- arg1_name = dcl_get(decls, selector);
- if(arg1_name != (Symbol)0
- && compatible_types(TYPE_OF(arg1_name),isym)){
- exists = TRUE;
- break;
- }
- ENDFORSET(fs1);
- }
- if (exists && NATURE(arg1_name) == na_obj
- && NATURE(base_type(TYPE_OF(arg1_name))) == na_array)
- need_constr_type = TRUE;
- if (need_constr_type)
- ok_types = set_with(ok_types, (char *) isym);
- else
- ok_types =
- set_with(ok_types, (char *) base_type(isym));
- #endif
- ok_types = set_with(ok_types, (char *) base_type(isym));
- }
- ENDFORSET(fs2);
- ENDFORSET(fs1);
-
- if (set_size( ok_types) == 1)
- t1 = t2 = (Symbol) set_arb(ok_types);
- else {
- univ = set_new(0);
- FORSET(t1=(Symbol), ok_types, fs1);
- if (in_univ_types(t1))
- univ = set_with(univ, (char *) t1);
- ENDFORSET(fs1);
- if (set_size(univ) == 1)
- t1 = t2 = (Symbol) set_arb(univ);
- else {
- type_error(set_new1((char *)op_name),
- (Symbol)0, set_size(ok_types), expn);
- return;
- }
- }
- if (is_limited_type(t1)
- && (op_name !=symbol_in && op_name!=symbol_notin)) {
- #ifdef ERRNUM
- id_errmsgn(277, op_name, 278, o);
- #else
- errmsg_id("% not available on a limited type", op_name,
- "7.4.2", o);
- #endif
- return;
- }
- /* Now resolve each operand independently.*/
-
- resolve2(arg1, t1);
- /* The membership tests are not static but their arguments
- * may be universal. Convert them to non-universal form for
- * run-time evaluation. Also special case type mark as second arg.
- */
- if (op_name == symbol_in || op_name == symbol_notin) {
- if (t2 == symbol_universal_integer)
- specialize(arg1, symbol_integer);
- else if (t2 == symbol_universal_real)
- specialize(arg1, symbol_float);
- if (N_KIND(arg2) != as_simple_name)
- resolve2(arg2, t2);
- else
- /* type mark. Its type is of course its own name. */
- N_TYPE(arg2) = N_UNQ(arg2);
- }
- else /* resolve second argument */
- resolve2(arg2, t2);
- /* Comparison operators on literal expressions are evaluated
- * separately, because their arguments are in universal form.
- */
- if (in_comparison_ops(op_name ) && t1 == t2
- && in_univ_types(t1))
- literal_expression(expn);
- }
- else if (typ == symbol_array_type) { /* Concatenation operator.*/
- if (op_name == symbol_cat) {
- resolve2 (arg1, ctx_type);
- resolve2 (arg2, ctx_type);
- }
- else {
- if (op_name == symbol_cat_ac) {
- resolve2 (arg1, ctx_type);
- resolve2 (arg2, component_type (ctx_type));
- eval_static(arg2);
- }
- else {
- if (op_name == symbol_cat_ca) {
- resolve2 (arg1, component_type (ctx_type));
- resolve2 (arg2, ctx_type);
- eval_static(arg1);
- }
- else {
- if (op_name == symbol_cat_cc) {
- resolve2 (arg1, component_type (ctx_type));
- eval_static(arg1);
- resolve2 (arg2, component_type (ctx_type));
- eval_static(arg2);
- }
- }
- }
- }
- }
- else {
- /* Other binary operators.*/
- resolve2(arg1, ctx_type);
- resolve2(arg2, ctx_type);
- }
- }
- else {
- /*Unary operator. Type of argument is that imposed by context.*/
- arg1 = (Node)arg_list[1];
- resolve2(arg1, ctx_type);
- /* if the argument to unary minus is universal real, the default
- * operator is floating negation. If the context is fixed, adjust
- * accordingly.
- */
- if (op_name == symbol_subufl && is_fixed_type(ctx_type))
- N_UNQ(N_AST1(expn)) = symbol_subufx;
- if (in_univ_types(ctx_type))
- literal_expression(expn);
- }
- }
-
- void specialize(Node u_expr, Symbol ctx_type) /*;specialize*/
- {
- /* Convert a universal numeric into a specific one, if the context impo-
- * ses a non-universal numeric type.
- */
-
- int k;
- Const v;
- Rational ra;
-
- if (cdebug2 > 3) TO_ERRFILE("AT PROC : specialize");
-
- /*$$$$ Test should be more general.*/
- k = N_KIND(u_expr);
- if (k!=as_ivalue && k!=as_int_literal && k!=as_real_literal) return;
-
- if (!in_univ_types(ctx_type )) {
- v = (Const) N_VAL(u_expr);
-
- if (is_universal_integer(v)) {
- N_VAL(u_expr) =
- (char *) int_const(int_toi(v->const_value.const_uint));
- if (arith_overflow)
- /* overflow has occurs during conversion to integer */
- create_raise(u_expr, symbol_constraint_error);
- else /* From universal to SETL integer*/
- N_TYPE(u_expr) = symbol_integer;
- }
- else if (is_universal_real(v)) {
- if ( !is_fixed_type(root_type(ctx_type))) {
- /* N_VAL(u_expr) =
- * (char *) real_const(rat_tor(v->const_value.const_rat,
- * ADA_REAL_DIGITS));
- */
- ra = RATV (v);
-
- /* the conversion from a rational to a real value will be
- * correct is the rational value belongs to the real interval
- */
-
- if (rat_lss (ra, rat_frr (ADA_MIN_REAL)) ||
- rat_gtr (ra, rat_frr (ADA_MAX_REAL))) {
- /* overflow occurs during conversion */
- /*N_VAL (u_expr) = const_new (CONST_OM); */
- create_raise(u_expr, symbol_constraint_error);
- }
- else {
- N_VAL(u_expr) =
- (char *) real_const(rat_tor(v->const_value.const_rat,
- ADA_REAL_DIGITS));
- N_TYPE(u_expr) = symbol_float;
- }
- }
- else
- /* label universal constant with the specific fixed type */
- N_TYPE(u_expr) = ctx_type;
- }
- /*$$$ Do something about overflow in conversion.*/
- }
- }
-
- static Const check_constant_overflow(Const x) /*;check_constant_overflow*/
- {
- if is_const_om (x)
- return x;
- else if (is_const_int (x)) {
- if ((INTV (x) < ADA_MIN_INTEGER) || (INTV(x) > ADA_MAX_INTEGER))
- return const_new (CONST_OM);
- else
- return x;
- }
- /* else if (is_const_uint (x)) {
- * if (int_lss(UINTV (x), ADA_MIN_INTEGER_MP) || int_gtr(UINTV(x),
- * ADA_MAX_INTEGER_MP))
- * return const_new (CONST_OM);
- * else return x;
- * }
- * else if (is_const_rat (x)) {
- * if (rat_gtr (RATV (x), ADA_MAX_FLOAT) )
- * return const_new (CONST_OM);
- * else return x;
- */
- else if (is_const_fixed (x)) {
- if ((FIXEDV (x) < ADA_MIN_FIXED) || (FIXEDV(x) > ADA_MAX_FIXED))
- return const_new (CONST_OM);
- else
- return x;
- }
- else if (is_const_real (x)) {
- if ((REALV (x) < ADA_MIN_REAL) || (REALV(x) > ADA_MAX_REAL))
- return const_new (CONST_OM);
- else
- return x;
- }
- else
- return x;
- }
-
- /*TBSL: check argument types, esp. in calls, for type_error */
- static void literal_expression(Node expn) /*;literal_expression*/
- {
- /* TBSL: need to always return uint case converting input
- * cases of CONST_INT to long form - review this ds 11 sep 84
- */
- /* Use the arbitrary precision arithmetic package to evaluate an arith-
- * metic expression whose arguments are literal. This routine is called
- * in contexts that require a universal value, i.e. constant definitions.
- * If the constituents are not universal, the expression is returned as
- * is.
- * Several attributes deliver a universal value, but are nevertheless
- * evaluated at run-time. If these attributes are companion operands of
- * literals, then these literals must be converted to non-universal form,
- * real or integer depending on the attribute. Note that this conversion is
- * never to a fixed point type, even for attributes of fixed points.
- */
-
- Node op_node, args_node, e1, e2;
- Tuple arg_list;
- Const op1, op2;
- int is_int;
- Symbol sym;
- Const ivalue;
-
- if (cdebug2 > 3) TO_ERRFILE("AT PROC : literal_expression");
-
- op_node = N_AST1(expn);
- args_node = N_AST2(expn);
- arg_list = N_LIST(args_node);
-
- if (tup_size( arg_list) == 2 ) { /* binary operation.*/
- e1 = (Node) arg_list[1];
- e2 = (Node) arg_list[2];
-
- if (N_KIND(e1) == as_ivalue) {
- op1 = (Const) N_VAL(e1);
- /* extract possible values */
- if (N_KIND(e2) == as_ivalue) {
- op2 = (Const) N_VAL(e2);
- /* In the case of mixed mode operations on fixed types, the
- * second argument is already folded to INTEGER. If a static
- * evaluation is possible, make it into a universal object again
- */
- if (is_const_int(op2)
- && (is_const_rat(op1) || N_UNQ(op_node) == symbol_expi))
- op2 = uint_const(int_fri(INTV(op2)));
- }
- else {
- /* op2 is attribute expr. If first operand is integer, check
- * its bounds . If it is a mixed operation, convert the first
- * operand to the most precise floating type available.
- */
- if(is_const_int(op1) || is_const_uint(op1))
- specialize(e1, symbol_integer);
- else
- specialize(e1, symbol_float);
- return;
- }
- }
- else { /* op1 is attribute expr.*/
- if (N_KIND(e2) == as_ivalue) {
- op2 = (Const) N_VAL(e2);
- if(is_const_int(op2) || is_const_uint(op2))
- specialize(e2, symbol_integer);
- else
- specialize(e2, symbol_float);
- return;
- }
- else { /* They both are.*/
- return;
- }
- }
- }
- else {
- e1 = (Node) arg_list[1];
- if (N_KIND(e1) != as_ivalue) {
- return;
- }
- else {
- op1 = (Const) N_VAL(e1);
- }
- }
-
- is_int = is_universal_integer(op1);
- if ((! is_int && !(is_const_rat(op1)))
- || (tup_size(arg_list) == 2 && !(is_const_uint(op2))
- && !(is_const_rat(op2)))) {
- return;
- }
-
- sym =N_UNQ(op_node);
-
- if (sym == symbol_addi) {
- const_check(op1, CONST_UINT);
- const_check(op2, CONST_UINT);
- ivalue = uint_const(int_add(UINTV(op1), UINTV(op2)));
- }
- else if (sym == symbol_addfl || sym == symbol_addfx) {
- const_check(op1, CONST_RAT);
- const_check(op2, CONST_RAT);
- ivalue = rat_const(rat_add(RATV(op1), RATV(op2)));
- }
- else if (sym == symbol_subi) {
- const_check(op1, CONST_UINT);
- const_check(op2, CONST_UINT);
- ivalue = uint_const(int_sub(UINTV(op1), UINTV(op2)));
- }
- else if (sym == symbol_subfl|| sym == symbol_subfx) {
- const_check(op1, CONST_RAT);
- const_check(op2, CONST_RAT);
- ivalue = rat_const(rat_sub(RATV(op1), RATV(op2)));
- }
- else if (sym == symbol_muli) {
- const_check(op1, CONST_UINT);
- const_check(op2, CONST_UINT);
- ivalue = uint_const(int_mul(UINTV(op1), UINTV(op2)));
- }
- else if (sym == symbol_mulfl || sym == symbol_mulfx) {
- const_check(op1, CONST_RAT);
- const_check(op2, CONST_RAT);
- ivalue = rat_const(rat_mul(RATV(op1), RATV(op2)));
- }
- else if (sym == symbol_mulfxi || sym == symbol_mulfli) {
- const_check(op1, CONST_RAT);
- const_check(op2, CONST_UINT);
- RATV(op1) = RATV(op1);
- ivalue = rat_const(rat_red(int_mul(num(RATV(op1)), UINTV(op2)),
- den(RATV(op1))));
- }
- else if (sym == symbol_divfxi || sym == symbol_divfli) {
- const_check(op1, CONST_RAT);
- const_check(op2, CONST_UINT);
- if (int_eql(UINTV(op2),int_fri(0)))
- ivalue = const_new(CONST_OM);
- else
- ivalue = rat_const(rat_red(num(RATV(op1)), int_mul(den(RATV(op1)),
- UINTV(op2))));
- }
- else if (sym == symbol_divi) {
- const_check(op1, CONST_UINT);
- const_check(op2, CONST_UINT);
- ivalue = uint_const(int_quo(UINTV(op1), UINTV(op2)));
- }
- else if (sym == symbol_divfl || sym == symbol_divfx) {
- const_check(op1, CONST_RAT);
- const_check(op2, CONST_RAT);
- ivalue = rat_const(rat_div(RATV(op1), RATV(op2)));
- }
- else if (sym == symbol_remi) {
- const_check(op2, CONST_UINT);
- if (int_eql(UINTV(op2),int_fri(0)))
- ivalue = const_new(CONST_OM);
- else
- ivalue = uint_const(int_rem(UINTV(op1), UINTV(op2)));
- }
- else if (sym == symbol_modi) {
- const_check(op2, CONST_UINT);
- if (int_eql(UINTV(op2),int_fri(0)))
- ivalue = const_new(CONST_OM);
- else {
- const_check(op1, CONST_UINT);
- const_check(op2, CONST_UINT);
- ivalue = uint_const(int_mod(UINTV(op1), UINTV(op2)));
- }
- }
- else if (sym == symbol_expi) {
- const_check(op2, CONST_UINT);
- if (int_lss(UINTV(op2),int_fri(0)))
- ivalue = const_new(CONST_OM);
- else {
- const_check(op1, CONST_UINT);
- const_check(op2, CONST_UINT);
- ivalue = uint_const(int_exp(UINTV(op1), UINTV(op2)));
- }
- }
- else if (sym == symbol_expfl) {
- const_check(op1, CONST_RAT);
- const_check(op2, CONST_UINT);
- ivalue = rat_const(rat_exp(RATV(op1), UINTV(op2)));
- }
- else if (sym == symbol_eq) {
- ivalue = int_const(const_eq(op1, op2));
- }
- else if (sym == symbol_ne) {
- ivalue = int_const(!const_eq(op1, op2));
- }
- else if(sym == symbol_gt) {
- ivalue = int_const(const_gt(op1, op2));
- }
- else if (sym == symbol_lt) {
- ivalue = int_const(const_lt(op1, op2));
- }
- else if (sym == symbol_ge) {
- ivalue= int_const(const_ge(op1, op2));
- }
- else if (sym == symbol_le) {
- ivalue = int_const(const_le(op1, op2));
- }
- else if (sym == symbol_addui || sym == symbol_addufl || sym==symbol_addufx){
- ivalue = op1;
- }
- else if(sym == symbol_subui) {
- const_check(op1, CONST_UINT);
- ivalue = uint_const(int_umin(UINTV(op1)));
- }
- else if (sym == symbol_subufl || sym == symbol_subufx) {
- const_check(op1, CONST_RAT);
- ivalue = rat_const(rat_umin(RATV(op1)));
- }
- else if (sym == symbol_absi) {
- const_check(op1, CONST_UINT);
- ivalue = uint_const(int_abs(UINTV(op1)));
- }
- else if (sym == symbol_absfl || sym == symbol_absfx) {
- const_check(op1, CONST_RAT);
- ivalue = rat_const(rat_abs(RATV(op1)));
- }
- else { /* Error: not a universal operator. */
- ivalue = const_new(CONST_OM);
- }
-
- /* the previous calculus may have raised the overflow flag
- * if (arith_overflow) {
- * arith_overflow = FALSE;
- * ivalue = const_new (CONST_OM);}
- */
-
- ivalue = check_constant_overflow (ivalue);
-
- if (ivalue->const_kind == CONST_OM)
- create_raise(expn, symbol_constraint_error);
- else {
- N_KIND(expn) = as_ivalue;
- N_AST1(expn) = N_AST2(expn) = N_AST3(expn) = N_AST4(expn) = (Node)0;
- copy_span(e1, expn);
- N_VAL(expn) = (char *)ivalue;
- }
- }
-
- static Tuple order_arg_list(Node arg_list_node, Tuple sig) /*;order_arg_list*/
- {
- /* Normalize an argument list (possibly containing named associations)
- * according to the signature -sig-. Called for subprogram and operators.
- */
-
- Tuple arg_list;
- Node actual, arg, choice_list, a_expr, choice_node, id_node;
- int p, actuals_seen, i, first_named;
- Tuple new_list;
- Tuple named_args;
- Symbol f_name;
- int found_name;
- int exists;
- Fortup ft1, ft2;
-
- if (cdebug2 > 3) TO_ERRFILE("AT PROC : order_arg_list");
-
- arg_list = N_LIST(arg_list_node);
- exists = FALSE;
- FORTUPI(actual=(Node), arg_list, p, ft1);
- if (N_KIND(actual) == as_choice_list) {
- exists = TRUE;
- break;
- }
- ENDFORTUP(ft1);
- if (exists) {
- first_named = p;
- exists = FALSE;
- for (i = p+1;i <= tup_size(arg_list); i++) {
- actual = (Node) arg_list[i];
- if (N_KIND(actual) != as_choice_list) {
- exists= TRUE;
- break;
- }
- }
- if (exists) {
- #ifdef ERRNUM
- errmsgn(279, 280, actual);
- #else
- errmsg("No positional arguments can appear after named ones",
- "6.4", actual);
- #endif
- return (Tuple)0;
- }
- }
- else
- first_named = tup_size(arg_list) + 1;
- new_list = tup_new(first_named - 1);
- for (i = 1; i < first_named; i++)
- new_list[i] = arg_list[i];
- named_args = tup_new(tup_size(arg_list) - first_named + 1);
- for (i = first_named; i <= tup_size(arg_list); i++)
- named_args[i - first_named + 1] = arg_list[i];
- actuals_seen = first_named - 1;
-
- FORTUP(arg=(Node), named_args, ft1);
- choice_list = N_AST1(arg);
- a_expr = N_AST2(arg);
- exists = FALSE;
- if (tup_size(N_LIST(choice_list)) != 1) exists = TRUE;
- if (exists == FALSE) {
- FORTUP(choice_node = (Node), N_LIST(choice_list), ft2);
- if (N_KIND(choice_node) != as_choice_unresolved) {
- exists = TRUE;
- break;
- }
- ENDFORTUP(ft2);
- }
- if ( exists ) {
- #ifdef ERRNUM
- errmsgn(281, 280, choice_list);
- #else
- errmsg("Invalid format for argument association", "6.4",
- choice_list);
- #endif
- return (Tuple)0;
- }
- ENDFORTUP(ft1);
-
- if (cdebug2 > 2) {
- }
-
- for (i = first_named; i <= tup_size(sig); i++) {
- f_name = (Symbol) sig[i];
- found_name = FALSE;
-
- FORTUP(arg=(Node), named_args, ft1);
- choice_list = N_AST1(arg);
- a_expr = N_AST2(arg);
- id_node = N_AST1((Node) (N_LIST(choice_list)[1]));
- if (streq(N_VAL(id_node), original_name(f_name))) {
- found_name = TRUE;
- break;
- }
- ENDFORTUP(ft1);
-
- if (found_name) {
- new_list = tup_with(new_list, (char *) a_expr);
- actuals_seen += 1;
- current_node = id_node;
- check_void(N_VAL(id_node));
- }
- else if ((Node) default_expr(f_name) != OPT_NODE)
- new_list = tup_with(new_list , (char *) OPT_NODE);
- /* Just a marker. Type is correct*/
- else /* Name not present*/
- return (Tuple)0;
- }
-
- if (cdebug2 > 2) {
- }
-
- if (actuals_seen == tup_size(arg_list) /* all actuals seen.*/
- && tup_size(new_list) == tup_size(sig)) /* all formals matched */
- return(new_list);
- else return (Tuple)0;
- }
-
- void complete_arg_list(Tuple formals, Node arg_list_node) /*;complete_arg_list*/
- {
- /* This procedure completes the formatting of the argument list of
- * a subprogram or entry call. This is done in the second,
- * top-down pass of overloading resolution. The argument list is
- * reordered, the names of the formals are removed from the actuals,
- * and default values are inserted in the place of missing parameters.
- * Types have already been validated during pass one, and default para-
- * meters are known to exist where needed.
- */
-
- Tuple arg_list, complete_args;
- int i;
- Node actual, default_node, default_copy;
- Fortup ft1;
- Symbol f;
-
- if (cdebug2 > 3) TO_ERRFILE("AT PROC : complete_arg_list");
-
- arg_list = order_arg_list(arg_list_node, formals); /* Normalize arguments*/
- /* if arg_list = om then ?*/
-
- complete_args = tup_new(0);
- /* Complete type resolution of each actual, and insert default expression
- * for those that are missing; default expressions are known to exist.
- */
- FORTUPI(f=(Symbol), formals, i, ft1);
- actual = (Node) arg_list[i];
- /* If no named association, a default value must be present,
- * unless, there was a previous error.
- */
-
- if (actual == OPT_NODE) {
- if (f != symbol_any_id) {
- default_node = (Node) default_expr(f);
- /* we assume all trees read in before use so node should be
- * available.
- */
- default_copy = copy_tree(default_node);
- if (fold_context) eval_static(default_copy);
- /* No constant folding in the middle of a conformance check */
- complete_args = tup_with(complete_args, (char *) default_copy);
- }
- else /* previous error. */
- complete_args = tup_with(complete_args, (char *) OPT_NODE);
- }
- else {
- bind_arg(actual, TYPE_OF(f), NATURE(f), i);
- if (fold_context) eval_static(actual);
- complete_args = tup_with(complete_args, (char *) actual);
- }
- ENDFORTUP(ft1);
- N_LIST(arg_list_node) = complete_args;
- }
-
- static void bind_arg(Node actual, Symbol f_type, int f_mode, int i)/*;bind_arg*/
- {
- /* Unlike the high-level version of Ada/Ed, the C front-end does not
- * indicate what constraints, if any, must be applied to actual parameters.
- * The job is done completely by the code generator, and sequences of
- * constraint checks on entry and exit are emitted in gen_prelude and
- * gen_postlude.
- */
-
- Set a_types;
- Symbol a_type;
- int out_c;
- Node a;
- int exists, may_others;
- Forset fs1;
-
- if (cdebug2 > 3) TO_ERRFILE("AT PROC : bind_arg");
-
- a_types = N_PTYPES(actual);
-
- /* One of its possible types must be compatible with the formal.*/
- exists = FALSE;
- FORSET(a_type=(Symbol), a_types, fs1);
- if(compatible_types(f_type, a_type)) {
- exists = TRUE;
- break;
- }
- ENDFORSET(fs1);
- if (!exists) /* assertion failure */
- chaos("assertion failure bind_arg");
- /* An out parameter may appear as the actual for another out parameter.*/
- out_c = out_context;
- out_context = (f_mode == na_out);
- /* If the actual is an aggregate, there is no sliding for it, and named
- * associations can appear with "others" (cf. 4.3.2(6)).
- */
- may_others = full_others;
- full_others = TRUE;
-
- resolve2(actual, f_type);
- apply_constraint (actual, f_type);
-
- /* verify that inout and out parameters are valid targets
- * of assignments.
- */
- if (N_KIND(actual) == as_qual_range || N_KIND(actual) == as_qual_index
- || N_KIND(actual) == as_qual_discr || N_KIND(actual) == as_qual_aindex
- || N_KIND(actual) == as_qual_adiscr)
- a = N_AST1(actual);
- else
- a = actual;
-
- if (N_KIND(a) == as_insert) /* case of an array conversion */
- a = N_AST1(a);
- if (f_mode != na_in && !is_variable(a)) {
- #ifdef ERRNUM
- str_num_errmsgn(282, nature_str(f_mode), i, 283, actual);
- #else
- errmsg_str_num("% actual parameter no. % in call is not a variable",
- nature_str(f_mode), i, "6.4.1", actual);
- #endif
- }
-
- if (is_scalar_type(f_type)) /* Convert from universal value if need be.*/
- specialize(actual, f_type);
- out_context = out_c;
- full_others = may_others;
- }
-
- static int in_comparison_ops(Symbol op) /*;in_comparison_ops*/
- {
- /* test for comparison operator */
- return (
- op == symbol_eq || op == symbol_ne
- || op == symbol_lt || op == symbol_gt
- || op == symbol_le || op == symbol_ge );
- }
-
- static Set find_compatible_type(Set typ1, Set typ2) /*; find_compatible_type */
- {
- /* return the types of typ1 (t1) such as the component type of t1 is
- * compatible with at least one type of typ2
- */
-
- Set result;
- Symbol t1, t2;
- Forset fs1, fs2;
-
- result = set_new (0);
-
- FORSET (t1 = (Symbol), typ1, fs1);
- FORSET (t2 = (Symbol), typ2, fs2);
- if (compatible_types ((Symbol) component_type (t1), t2))
- result = set_with (result, (char *) base_type (t1));
- ENDFORSET (fs2);
- ENDFORSET (fs1);
- return result;
- }
-
- static Tuple valid_concatenation_type(Set typ1, Set typ2)
- /*;valid_concatenation_type*/
- {
- /* Concatenation is performed by 4 distinct operators, corresponding to
- * array-array, array-component, component-array, and component-component
- * cases. If either operand is an aggregate, or if both operands are
- * components, then the candidate resulting types are a subset of the
- * one-dimensional array types that are in scope.
- */
-
- Set arrays1, arrays2, arrays3, types, new_types;
- Set opns, types1, types2, types3;
- Symbol t1, t2, t3;
- Forset fs1, fs2, fs3;
- Tuple tup;
- int exist_composite_in_typ1, exist_composite_in_typ2;
-
- arrays1 = set_new (0);
- arrays2 = set_new (0);
- arrays3 = set_new (0);
- types = set_new (0);
- opns = set_new (0);
-
- FORSET (t1=(Symbol), typ1, fs1);
- if (is_array (t1) && no_dimensions (t1) == 1)
- arrays1 = set_with (arrays1, (char *) base_type (t1));
- ENDFORSET (fs1);
-
- FORSET (t1=(Symbol), typ2, fs1);
- if (is_array (t1) && no_dimensions (t1) == 1)
- arrays2 = set_with (arrays2, (char *) base_type (t1));
- ENDFORSET (fs1);
-
- FORSET (t1=(Symbol), find_agg_types (), fs1);
- if (is_array (t1) && no_dimensions (t1) == 1)
- arrays3 = set_with (arrays3, (char *) base_type (t1));
- ENDFORSET (fs1);
-
- exist_composite_in_typ1 = FALSE;
- FORSET (t1 = (Symbol), typ1, fs1);
- if (NATURE (base_type (t1)) == na_aggregate)
- {
- exist_composite_in_typ1 = TRUE;
- break;
- }
- ENDFORSET (fs1);
-
- exist_composite_in_typ2 = FALSE;
- FORSET (t1 = (Symbol), typ2, fs1);
- if (NATURE (base_type (t1)) == na_aggregate)
- {
- exist_composite_in_typ2 = TRUE;
- break;
- }
- ENDFORSET (fs1);
-
- /* First we look for compatible arrays to concatenate. */
- if (exist_composite_in_typ1)
- types = arrays2;
- else
- {
- FORSET (t1 = (Symbol), arrays1, fs1);
- FORSET (t2 = (Symbol), typ2, fs2);
- if (compatible_types (t1, t2))
- types = set_with (types, (char *) base_type (t1));
- ENDFORSET (fs2);
- ENDFORSET (fs1);
- }
- if (set_size (types) != 0)
- opns = set_with (opns, (char *)symbol_cat);
-
- /* Next, look for aggregate or array type concatenated with compatible
- * component.
- */
- if (exist_composite_in_typ1)
- types1 = find_compatible_type (arrays3, typ2);
- else
- types1 = find_compatible_type (arrays1, typ2);
-
- if (set_size (types1) != 0)
- {
- types = set_union (types, types1);
- opns = set_with (opns, (char *)symbol_cat_ac);
- }
-
- /* The component-array case is similar. */
- if (exist_composite_in_typ2)
- types2 = find_compatible_type (arrays3, typ1);
- else
- types2 = find_compatible_type (arrays2, typ1);
- if (set_size (types2) != 0)
- {
- types = set_union (types, types2);
- opns = set_with (opns, (char *)symbol_cat_ca);
- }
-
- /* Next, both arguments may be the component type of some one-dimensional
- * array type, as in `A` & 'B'. Note that the arguments may still be
- * arrays, and the result type be a one-dimensional array of arrays.
- * The candidate resulting types are all array types in scope whose
- * component types are compatible with both operands.
- */
-
- types3 = set_new (0);
- FORSET (t1 = (Symbol), arrays3, fs1);
- FORSET (t2 = (Symbol), typ1, fs2);
- FORSET (t3 = (Symbol), typ2, fs3);
- if (compatible_types ((Symbol) component_type (t1), t2)
- && compatible_types ((Symbol) component_type (t1), t3))
- types3 = set_with (types3, (char *)base_type (t1));
- ENDFORSET (fs3);
- ENDFORSET (fs2);
- ENDFORSET (fs1);
-
- if (set_size (types3) != 0) {
- types = set_union (types, types3);
- opns = set_with (opns, (char *)symbol_cat_cc);
- }
-
- /* Finally, if both arguments are aggregates, the result can be an array
- * type.
- */
- if ((exist_composite_in_typ1) && (exist_composite_in_typ2)) {
- types = set_with (types, (char *)symbol_array_type);
- opns = set_with (opns, (char *)symbol_cat);
- }
-
- new_types = set_new (0);
- FORSET (t1 = (Symbol), types, fs1);
- if (! is_limited_type (t1))
- new_types = set_with (new_types , (char *) t1);
- ENDFORSET (fs1);
-
- tup = tup_new (2);
- tup [1] = (char *) opns;
- tup [2] = (char *) new_types;
-
- return tup;
- }
-