Задание: графически отобразить рекурсивный вызов функции.
Пример для решения: прохождение функции по многомерному массиву с целью сравнить его с другим массивом.
Использованные технологии: LISP, PHP, HTML, JS.
Описание: Скрипт получает трассировку вызова функции из программы LispWorks, парсит её и, используя библиотеку для отрисовки графов, пошагово выводит граф в виде отдельных картинок. В просмотрщике есть возможность переходить по картинкам вперёд-назад. Результатом работы является TGZ-архив, который содержит исходную трассировку, набор картинок и HTML-просмотрщик.
Интересные особенности: В связи с тем, что отрисовщик графов изначально работал только с массивами, после парсинга вся информация о текущем состоянии графа пакуется в массив.
Скрипт использует класс Diagram (© 2004 Diogo Resende, diogo@ect-ua.com, Portugal)
Показать/скрыть главный цикл
foreach($data as $currline => $v) {
$resolved = '';
$line = trim($v);
$call_id = substr($line, 0, 1);
if (contains($line, '> ...')) {
$fx_iteration++;
$i=0;
$args1='';
$args2='';
$k=$currline;
while(true) {
if (contains($data[++$k], '>> ')) {
$args1 .= gettxt($data[$k].'<', '>> ', '<').', ';
$z = ++$k;
if (contains($data[$z], '>> ')) {
$args2 .= gettxt($data[$z].'<', '>> ', '<').', ';
}
} else {
break;
}
}
$args1_nohtml = gettxt($args1, ': ', ',');
$args2_nohtml = gettxt($args2, ': ', ',');
$args1 = trim($args1, ', ');
$args2 = trim($args2, ', ');
$args = 'args: <span style="font-weight:normal;">'.$args1_nohtml.' <b>and</b> '.$args2_nohtml.'</span>'; // COMMENT THIS!
$resline = $currline + $arg_count+1;
if (contains($data[$resline], '< ...')) {
$answer = trim(gettxt($data[$resline+1].'<', '<< VALUE-0 : ', '<'));
$nodes[$fx_iteration]['parent'] = $solved[count($solved)-1];
$nodes[$fx_iteration]['level'] = $call_id;
$nodes[$fx_iteration]['has_split'] = false;
$nodes[$fx_iteration]['args'] = $args;
$nodes[$fx_iteration]['value'] = $answer;
$levels_fx[$call_id][] = $fx_iteration;
echo '#'.$fx_iteration.') Function ['.$call_id.'] call, parent: './*$curr_split_parent.'/'.*/$solved[count($solved)-1].', '.$args.', instant answer ('.$answer.')<br>';
$resolved = $fx_iteration;
$childs[$solved[count($solved)-1]][] = $fx_iteration;
$answer_array[$fx_iteration] = $answer;
$levels[$call_id]++;
$out_array .= '"|'.$fx_iteration.'|'.$args1_nohtml.', '.$args2_nohtml.'", ';
$draw = normalize($out_array, $opened_braces);
} else {
$for_solving[$call_id]['args'] = $args;
$nodes[$fx_iteration]['parent'] = $solved[count($solved)-1];
$nodes[$fx_iteration]['level'] = $call_id;
$nodes[$fx_iteration]['has_split'] = true;
$nodes[$fx_iteration]['args'] = $args;
$nodes[$fx_iteration]['value'] = 'n/a';
$levels_fx[$call_id][] = $fx_iteration;
echo '#'.$fx_iteration.') Function ['.$call_id.'] call, parent: './*$curr_split_parent.'/'.*/$solved[count($solved)-1].', '.$args.', split<br>';
$unsolved[$call_id] = 2;
$childs[$solved[count($solved)-1]][] = $fx_iteration;
$out_array .= '"|'.$fx_iteration.'|'.$args1_nohtml.', '.$args2_nohtml.'" => array(';
$opened_braces++;
$draw = normalize($out_array, $opened_braces);
$levels[$call_id]++;
$curr_split_parent = $call_id.'-'.$fx_iteration;
array_push($solved, $fx_iteration);
}
}
if (contains($line, '< ...')) {
if (isset($for_solving[$call_id])) {
$resline = $currline;
$answer = gettxt($data[$resline+1].'<', '<< VALUE-0 : ', '<');
$resolved = array_pop($solved);
echo '*** Function ['.$call_id.'] answer: '.$answer.', parent '.$resolved.' closed<br>';
$answer_array[$resolved] = $answer;
if (--$unsolved[$call_id] == 0) {
$out_array .= ')';
$opened_braces--;
} else {
$out_array .= '), ';
$opened_braces--;
}
$draw = normalize($out_array, $opened_braces);
unset($for_solving[$call_id]);
}
}
if (isset($draw)) {
$drawer++;
eval('$draw = '.$draw);
$g->SetData($draw);
$info['answers'] = $answer_array;
$info['current'] = $fx_iteration;
$allchildsneed = array_unique(array_merge($white, get_all_childs($resolved)));
$white = $info['childs'] = $allchildsneed;
@$g->Draw('./work/'.$filename.'/'.$drawer.'.png', $info);
unset($draw);
}
flush();
}
Права: Написан по заказу RTU в рамках европроекта по модернизации существующих программ обучения. Принадлежит RTU.
Ссылки:
LISP (wikipedia)
Класс Diagram
Курс “функциональное программирование LISP”