$include "defs.icn"
$include "global_vars.icn"
#
# outermost_op(h,t)
#
# input: A denotation in the form of an array of pointers to primaries.
#        h points to the start of the array, t to the end. The array
#        should not be empty.
#
# output: A pointer to the outermost operator in the array, as determined
#         by the heuristic.
#
# heuristic: 1) If the denotation contains primaries of less than
#               "infinite" precedence, then the outermost operator
#               is the leftmost primary in the rightmost sequence of
    #               of primaries of lowest precedence.
#               In the case where the lowest precedence is that of the
#               exponentiation operator, the outermost operator is just
#               the leftmost operator of lowest precedence.
#            2) If the denotation does not contain any primaries of less
#               than infinite precedence, then the outermost operator
#               is the only primary which is not bracketed (i.e. is not
#               a list of primaries), and it may have no more than one
#               right arg and one left arg.
#            3) If there is no such primary, then this routine fails.
#               Mkappl2 will usually use the first primary in this case.
#
# 	WARNING: This is a HORRIBLE algorithm.  But we don't have the
#		time to fix it.
#

procedure outermost_op(array, head, tail)
    local    op, lowest_prec, i, p ,has_left_arg, has_right_arg, len,in_seq
    # # of primaries in array
    # Determine the lowest precedence in the denotation
    lowest_prec := INFINITE
    p := head
    yyinfo("outermost_op p = "|| p || " head = " || head || " tail = " || tail)
    yyinfo("array = " || type(array))
    while (p ~= tail + 1 ) do { # was +1 DJD
#            for (p = h; p != t+1; p++)
	yyinfo("type(array(p) = " || type(array[p]))
	i := precedence(array[p])
	yyinfo("i = " || i)
	if ( i < lowest_prec ) then
	    lowest_prec := i
	p +:= 1
    }
    yyinfo("lower_prec = " || lowest_prec)
    case ( lowest_prec ) of {
	INFINITE:
	    # Find unbracketed primary and check if ok
	{
	    yyinfo("INFINITE")
	    op := nil
	    p := head
	    while p ~= tail + 1 do {
#                    for (p = h; p != t+1; p++)
		if ( not (is_list(array[p])) ) then
		    op := p
		p +:= 1
	    }
	    if ( /op ) then {
		# there's no reasonable operator, return the NIL
		return nil
	    }

	    len := tail - head + 1
	    if op = head then has_left_arg := FALSE
	    else if is_list(array[head]) then has_left_arg := TRUE
	    else has_left_arg := FALSE

	    if op = tail then has_right_arg := FALSE
	    else if is_list(array[tail]) then has_right_arg := TRUE
	    else has_right_arg := FALSE

	    if ( not(    has_left_arg &  has_right_arg & len == 3) |
		not(has_left_arg &  has_right_arg & len == 2) |
		(has_left_arg & !has_right_arg & len == 2)
		)  then {
		    # Cant uniquely determine operator
		    op := nil
		    return nil
		}
	}
	EXPLEVEL:
	    {
		yyinfo("EXPLEVEL")
		p := head
		repeat {
		    if (precedence(array[p] = lowest_prec)) then {
			op := p
			break
		    }
		    p +:= 1
		}
	    }
	ASGNLEVEL:
	    {
		yyinfo("ASSGNLEVEL")
		p := head
		repeat {
		    if (precedence(array[p]) = lowest_prec) then {
			op := p
			break
		    }
		    p +:= 1

		}
	    }
	DEREFLEVEL:
	    {
		yyinfo("DEREFLEVEL")
		p := head
		repeat {
		    if (precedence(array[p] = lowest_prec)) then {
			op := p
			break
		    }
		    p +:= 1

		}
	    }
	default: {
	    yyinfo("default")
            # Find leftmost primary in rightmost sequence
	    in_seq := FALSE
	    p := head
	    while (p ~= tail + 1 ) do {
#	    for (p = h; p != t+1; p++) {
		if ( precedence(array[p]) = lowest_prec ) then {
		    if ( in_seq ~= TRUE ) then
			op := p
		} else
		    in_seq := FALSE
		p +:= 1
	    }
	}
    }

    return ( op )

end

