Auto-Determination of Precedence and Associativity

assoc.sci, prec.sci, and parser.sci are the scripts that determine the precedence and the associativity of the arithmetic Scilab operators. The results are used in the section called Operator Precedence And Associativity in Chapter 4.

assoc.sci

function a = assoc(oper, typ)
// Return the associativity a of 
// operator oper which accepts type typ.
// oper can be a matrix of operators.
//
// typ can be 'n' for numeric, or 'b' for boolean.
// If typ is omitted, numeric is assumed.

[nl, nr] = argn()
if nr == 1 then
    typ = 'n'
end

select typ
case 'n' then
    args = string([1.1 1.2 1.5])
    deff('b = equal(x, y)', 'b = abs(x - y) < 1.2*%eps')
case 'b' then
    args = string(['%f' '%t' '%f'])
    deff('b = equal(x, y)', 'b = x == y')
else
    error('unknown type ' + typ)
end

a = []
for op = oper
    expr = '[' + args(1) + op 
               + args(2) + op + args(3) + ',' ..
               + '(' + args(1) + op + args(2) + ')' 
               + op + args(3) + ',' ..
               + args(1) + op + '(' + args(2) 
               + op + args(3) + ')]'
    //disp(expr)
    r = evstr(expr)
    //disp(r)

    if equal(r(2), r(3)) then
        a = [a 'non']
    elseif equal(r(1), r(2)) then
        a = [a 'left']
    elseif equal(r(1), r(3)) then
        a = [a 'right']
    else
        error('could not determine associativity')
    end
end

prec.sci

function p = prec(op1, op2)
// determine the relative precedence of operator op1 vs op2
// If operator op1 has a higher precedence than op2 then p = -1.
// In the opposite case p = 1.  If both have the same precedence
// level p = 0

args = string([1.1 1.2 1.5])
deff('b = equal(x, y)', 'b = abs(x - y) < 1.2*%eps')

expr = '[' + args(1) + op1 + args(2) + op2 + args(3) + ',' ..
           + '(' + args(1) + op1 + args(2) + ')' + op2 + args(3) + ',' ..
           + args(1) + op1 + '(' + args(2) + op2 + args(3) + ')]'

//disp(expr)
r = evstr(expr)
//disp(r)

if equal(r(2), r(3)) then
    p = 0
elseif equal(r(1), r(2)) then
    p = -1
elseif equal(r(1), r(3)) then
    p = 1
else
    error('could not determine precedence level')
end
function p = prec1(uop, op)
// determine what relative precedence the unary operator uop has
// with respect to operator op.  The return values are like those
// of prec()

args = string([1.1 1.2])
//args = string([(1.1+0.9*%i) (1.2-0.8*%i)])
deff('b = equal(x, y)', 'b = abs(x - y) < 1.2*%eps')

expr = '[' + uop + args(1) + op + args(2) + ',' ..
           + '(' + uop + args(1) + ')' + op + args(2) + ']'

//disp(expr)
r = evstr(expr)
//disp(r)

if equal(r(1), r(2)) then
    p = -1
else
    p = 1
end
function p = lprec(op1, op2)
// determine relative precedence of the
// logical operators op1 and op2

v = ['%f' '%t']
for i = 1:2
    for j = 1:2
        for k = 1:2
            args = string([v(i) v(j) v(k)])
            expr = '[' + args(1) + op1 + args(2) + op2 + args(3) + ',' ..
                       + '(' + args(1) + op1 + args(2) + ')' + op2 + args(3) + ',' ..
                        + args(1) + op1 + '(' + args(2) + op2 + args(3) + ')]'

            //disp(expr)
            r = evstr(expr)
            //disp(r)

            if r(2) == r(3) then
                p = 0
            elseif r(1) == r(2) then
                p = -1
                return
            elseif r(1) == r(3) then
                p = 1
                return
            else
                error('could not determine precedence level')
            end
        end
    end
end

parser.sci

// determine properties of Scilab's parser:
// associativity and precedence level of operators

getf('assoc.sci');
getf('prec.sci');

numop1 = ['+' '-'];
numop2 = ['+' '-' '*' '/' '\' '^' '.*' './' '.\' '.^'];
logop1 = ['~'];
logop2 = ['&' '|'];

// inquire associativity
an = assoc(numop2, 'n');
ab = assoc(logop2, 'b');

// figure out the relative precedence of binary numeric operators
pm2 = [];
for i = numop2
    row = [];
    for j = numop2
        row = [row prec(i, j)];
    end
    pm2 = [pm2; row];
end
[lev, idx] = sort( sum(pm2, 'r') );
lev = lev - min(lev) + 1;               // minimum := 1

nop2 = numop2;
for op = numop1  // mark binary oparators that have a unary twin
    patch = find(op == nop2);
    nop2(patch) = op + '/2';
end

relp2 = [string(lev); nop2(idx); an(idx)]';


relp1 = [];
for i = numop1
    row = [];
    for j = numop2
        row = [row, prec1(i, j)];
    end
    hop = numop2(find(row > 0.5)); // operators with higher precedence
    minhop = 0;
    for op = hop
        minhop = max( minhop, find(relp2(:, 2) == op) );
    end
    // now minhop is the index of the lowest precedence binary operator
    // that has a higher precedence than the unary operator i, or 0 if
    // there is none
    if minhop == 0
        uop = evstr(relp2(1, 1)) + 1;
    else
        uop = evstr(relp2(minhop, 1)) - 1;
    end
    relp1 = [relp1; [string(uop), i+'/1', 'right']];
end
//relp1

// Merge unary operators into matrix of binary operators
relp = [relp1; relp2];
[dummy, idx] = sort(evstr(relp(:, 1)));
relp(idx, :)