Построение срезов для программ на динамических языках
3
В качестве примера представлен граф программных зависимо-
стей для следующей программы (см. рис. 1). Зависимости по данным
изображены на рисунке сплошными стрелками, по управлению —
прерывистыми.
var i, sum, product: integer;
begin
read(n);
i := 1;
sum := 0;
product := 1;
while i <= n do
sum := sum + i;
product := product * i;
i := i + 1;
end;
write(sum);
write(product);
end.
Когда ГПЗ построен, вычисление среза по заданному оператору в
программе, которому соответствует одна из вершин ГПЗ, сводится к
определению множества вершин графа, достижимых по дугам зави-
симостей из вершины-критерия, которое и будет являться срезом.
При определении достижимости дуги зависимостей по данным и
управлению равнозначны. Задачу построения среза, таким образом,
можно считать решенной при наличии ГПЗ для анализируемой про-
граммы.
При построении срезов для программы и конкретного набора ее
исходных данных построенный ГПЗ модифицируется некоторым об-
разом с учетом траектории выполнения, собранной при фактическом
запуске программы. Простейший вариант, описанный в [7], предпо-
лагает ограничение ГПЗ по множеству вершин, входящих в траекто-
рию (т. е. операторов, которые были реально выполнены). После по-
лучения ограниченного графа построение среза идет как обычно.
Особенности динамических языков.
В качестве определяющих
особенностей динамических языков, влияющих на создание срезов,
можно выделить динамическую типизацию, возможность модифика-
ции типов данных и кодогенерации «на лету», а также интерпрета-
цию как основной способ исполнения программ. Наиболее распро-
страненные на данный момент динамические языки программирова-
ния, такие как Python, Ruby, Lua, Perl, PHP и многие диалекты Lisp,
обладают всеми перечисленными особенностями в совокупности.
Динамическая типизация
означает, что понятие типа данных в
языке связывается только с конкретным значением во время выпол-
нения программы, а не с переменной или именем на стадии компиля-