<?php

// $Date: 2004/01/20 09:51:14 $
// $Revision: 1.11 $
// $Author: jcrocholl $

// $head is supposed to be an array consisting of
// - the following properties:
//   - with: '' or 'with' for generic methods
//   - type: 'function' or 'procedure' or 
//           '' for just a block of variables
//   - name: name of the function or procedure
//   - return: return type of the function
// - and the following arrays:
//   - names, modes, types, bounds, initials, comments
//   - one entry for each parameter
//   - and possibly a function return value
//   - if comments has one extra, that's for above the head

// add another row of parameters to the head
function add_variable(&$head$name$mode$type$bound$initial$comment) {
    
$head['names'][] = $name;
    
$head['modes'][] = $mode;
    
$head['types'][] = $type;
    
$head['bounds'][] = $bound;
    
$head['initials'][] = $initial;
    
$head['comments'][] = $comment;
}

// signature of a function or procedure
function signature($head) {
    
$count count($head['names']);
    for (
$i 0$i $count$i++) {
        if (
$result$result .= '; ';
        
$result .= $head['names'][$i] . ' : ';
        if (
$head['modes'][$i]) $result .= $head['modes'][$i] . ' ';
        
$result .= $head['types'][$i];
        
$result .= $head['bounds'][$i] . ' ';
        if (
defined($head['initials'][$i]))
            
$result .= ':= ' $head['initials'][$i];
    }
    if (
$head['type'] == 'procedure') {
        return 
"procedure $head[name]($result)";
    } elseif (
$head['type'] == 'function') {
        return 
"function $head[name]($result) return $head[return]";
    } else {
        print 
"error: signature($head[type])\n";
        if (
$result$result .= ';';
        return 
$result;
    }
}

function 
format_name($name) {
    
$parts explode(','$name);
    
$result trim(array_shift($parts));
    while (
$parts$result .= ', ' trim(array_shift($parts));
    return 
$result;
}

function 
format_type($type) {
    return 
type($type);
}

function 
format_mode($mode$type '') {
    if (
$mode == 'in') return keyword('in ');
    if (
$mode == 'out') return keyword('out ');
    if (
$mode == 'inout') return keyword('in ') . keyword('out ');
    if (
$mode == 'return') return keyword('return ');
    if (
$mode == 'constant') return keyword('constant ');
    if (
$mode == 'access') return keyword('access ');
    if (
$mode == '') {
        if (
$type == 'function' or $type == 'procedure'
            return 
keyword('in ');
        else return 
'';
    }
    exit(
"unknown mode: '$mode'\n");
}

function 
format_bound($bound) {
    if (
$bound == '') return '';
    return 
'(' bounds($bound) . ')';
}

function 
format_initial($initial) {
    if (
$initial == '') return '';
    return 
' := ' term($initial);
}

function 
format_comment($comment) {
    if (!
$comment) return '';
    return 
comment("-- $comment");
}

// Pretty print a head. Second parameter tail can be 
// '' or ';' or 'is' if we have a function or procedure.
function format_head(&$head_by_ref$tail '') {
    
$head $head_by_ref;
    
$type $head['type'];
    
$count count($head['names']);
    
$result ''// 'start' . newline();

    // extra comment is for above the head
    
if (count($head['comments']) > $count
        
$result .= $head['comments'][$count];

    
// format all parameter entries
    
if ($tail == 'is'$tail keyword(' is');
    for (
$i 0$i $count$i++) {
        
$head['names'][$i] = format_name($head['names'][$i]);
        
$head['modes'][$i] = format_mode($head['modes'][$i], $type);
        
$head['types'][$i] = format_type($head['types'][$i]);
        
$head['bounds'][$i] = format_bound($head['bounds'][$i]);
        
$head['initials'][$i] = format_initial($head['initials'][$i]);
        
$head['comments'][$i] = format_comment($head['comments'][$i]);
        
// print "'" . $head['names'][$i] . 
        //     "', '" . $head['modes'][$i] . 
        //     "', '" . $head['types'][$i] . "'\n";
    
}
    
    if (
$type) {
        global 
$indent_level;
        
$indent_level--; 
        
$result .= indent(); 
        
$indent_level++;
    }

    if (
$type == 'procedure') {
        if (
$head['with']) $result .= keyword('with ');
        
$result .= keyword('procedure ') . name($head['name']);
        if (
$type == 'procedure' and $tail and !$count$result .= $tail;
        
$result .= newline();
    } elseif (
$type == 'function') {
        if (
$head['with']) $result .= keyword('with ');
        
$result .= keyword('function ') . name($head['name']) . newline();
        
// tail comes after the function return value
        
$return_tail $tail$tail '';
        
// don't use function return value as parameter
        
$count--;
    } elseif (
$head['with']) {
        exit(
"error: 'with' can only appear with a function or procedure\n");
    }

    
// calculate maximum width of parameter names and specs
    
for ($i 0$i $count$i++) {
        
$l  length($head['names'][$i]);
        
$max_names max($max_names$l);
        
$l  length($head['modes'][$i]); // ' : in '
        
$l += length($head['types'][$i]);     // 'Integer_Array'
        
$l += length($head['bounds'][$i]);    // '(1 .. Size)'
        
$l += length($head['initials'][$i]);  // ' := Integers(3)'
        
$l += 1// semicolon or final closing bracket
        
if ($i == $count 1$l += length($tail);
        if (
$head['comments'][$i]) $max_specs max($max_specs$l);
    }

    
// calculate maximum width of function return value
    
if ($type == 'function') {
        
$l  6;                                  // 'return'
        
$l += length($head['types'][$count]); // ' Integer_Array'
        
$l += length($head['bounds'][$count]);    // '(1 .. Size)'
        
$l += length($return_tail);               // ' is'
        
$l -= $max_names// overlaps
        
$l -= 1// return is shifted left by one 
        
if ($head['comments'][$count])
            
$max_specs max($max_specs$l);
    }

    
// collect the parameters
    
for ($i 0$i $count$i++) {
        if (
$i == and ($type == 'function' or $type == 'procedure'))
            
$result .= indent(-1) . '(';
        else 
$result .= indent();
        
$result .= fill($head['names'][$i], $max_names);

        
$spec  ' : ';
        
$spec .= $head['modes'][$i];
        
$spec .= $head['types'][$i];
        
$spec .= $head['bounds'][$i];
        
$spec .= $head['initials'][$i];
        if (
$i == $count 1) {
            if (
$type == 'function' or
                
$type == 'procedure'$spec .= ')' $tail;
            else 
$spec .= ';';
        } else 
$spec .= ';';

        if (
$head['comments'][$i]) {
            
$result .= fill($spec$max_specs 1);
            
$result .= $head['comments'][$i];
        } else 
$result .= $spec;
        
$result .= newline();
    }

    
// collect the function return value
    
if ($type == 'function') {
        
$spec  keyword('return ');
        
$spec .= $head['types'][$count];
        
$spec .= $head['bounds'][$count];
        
$spec .= $return_tail;
        
        
$result .= indent(-1);
        if (
$head['comments'][$count]) {
            
$result .= fill($spec$max_names $max_specs 2);
            
$result .= $head['comments'][$count];
        } else 
$result .= $spec;
        
$result .= newline();
    }

    global 
$dont_clear_head;
    if (!
$dont_clear_head$head_by_ref = array();
    
// And that's all folks!
    
return $result// . 'end' . newline();
}

?>