> G:=proc() S(args) end proc: S:=proc() V(args,95) end proc: V:= proc() Kr(args,99) end proc: Kr:= proc() local k; where(5): [nargs, sum(args[k], k=1..nargs)] end proc: G(64,59,39,10,17,44); TopLevel: G(64,59,39,10,17,44) [64, 59, 39, 10, 17, 44] G: S(args) [64, 59, 39, 10, 17, 44] S: V(args,95) [64, 59, 39, 10, 17, 44, 95] V: Kr(args,99) [64, 59, 39, 10, 17, 44, 95, 99] Currently in Kr. [8, 427] > Kr(Kr(64, 59, 39, 10, 17, 44)); ⇒ [1, [6, 233]] |
TopLevel: Kr(Kr(64,59,39,10,17,44)) [64, 59, 39, 10, 17, 44] Currently in Kr. TopLevel: Kr(Kr(64,59,39,10,17,44)) [[6, 233]] Currently in Kr. |
Следует отметить, что пакетный отладчик (Debugger) располагает where-командой, аналогичной where-процедуре, за исключением того, что первую можно выполнять интерактивно в отладочном режиме, инициируемом отладчиком. При этом, наибольший эффект от использования where-процедуры можно получить при трассировке рекурсивных вызовов процедур и/или функций. Наряду с процедурами, механизм трассировки на основе where-процедуры можно использовать и для пользовательских функций, как это иллюстрирует пример определения Fnс-функции посредством функционального (->)оператора:
> Fnc:= () -> [where(5), evalf(sqrt(sum(args['k']^2, 'k' = 1..nargs)), 3)]; Fnc := ( ) → where 5( ), evalf ' 'nargsk∑ = 1 args' 'k 2 , 3 > V(Kr(Fnc((42, 47, 67, 89, 96, 62)))); ⇒ [2, 99 + [1, [171.]]] TopLevel: V(Kr(Fnc(42,47,67,89,96,62))) [42, 47, 67, 89, 96, 62] Currently in Fnc. TopLevel: V(Kr(Fnc(42,47,67,89,96,62))) [[171.]] Currently in Kr. TopLevel: V(Kr(Fnc(42,47,67,89,96,62))) [[1, [171.]]] V: Kr(args,99) [[1, [171.]], 99] Currently in Kr. |
Данный фрагмент использует две процедуры V и Kr, определенные в предыдущем фрагменте, и определяет Fnc-функцию, содержащую вызов where-процедуры, что позволяет использовать для нее описанный механизм тестирования вызовов через стэк.
Встроенный DEBUG-отладчик ориентирован на отладку достаточно сложных процедур в интерактивном режиме и базируется на механизме контрольных точек (check points), допуская два варианта исполнения. По первому варианту режим отладки активируется по функции DEBUG({<Комментарий>}), идентификация Input-параграфа которого производится “DBG>”-метками. Тогда как отмена режима отладки производится по команде {quit|stop|done}, при этом следует иметь в виду, что при вводе команд режима отладки кодирование после них разделителя не допускается. В DEBUG-режиме отладки допускается использование более 16 команд: cont, next, step, into, stopwhen, return, stop, list, where, showstat, showstop, stopat, stoperror и др., обеспечивающих целый ряд важных отладочных функций, с которыми детально можно ознакомиться в книгах [8,9] либо в определенной степени по справке пакета, а также по поставляемой с пакетом документации [78-85]. Там же достаточно детально можно ознакомиться и с ограничениями по применению DEBUG-отладчика. Здесь мы вкратце остановимся лишь на некоторых из наиболее используемых командах режима отладки. Прежде всего, отметим, что кодирование команд DEBUG-режима отладки завершается { |;|:}-разделителем, что отличает их синтаксис от синтаксиса предложений Maple-языка, а также то, что вид разделителя не влияет на возврат результата выполнения команд, как это имеет место в случае традиционных предложений Maple-языка. Новые релизы пакета часто расширяют функции отладчика.
Прежде всего, в целях удобства установки в процедурах контрольных точек рекомендуется пронумеровать составляющие их предложения, что обеспечивает команда отладчика showstat(Proc {, <Диапазон>}), возвращающая определение Proc-процедуры с приписанными ее предложениям номерами, позволяя использовать их при установке контрольных точек. По команде отладчика stopat(Proc {, <{номер|диапазон}> {, <ЛУ>}}) производится установка контрольных точек в предложения Proc-процедуры с номерами, определяемыми ее вторым параметром. При этом, третий необязательный ЛУ-параметр определяет логическое условие, true-значение которого разрешает производить останов в данной контрольной точке. Данное условие может связывать как глобальные, так и локальные переменные, а также и формальные аргументы процедуры. Если предложения процедуры не нумеровались, то производится установка контрольной точки в начало процедуры. По stopat-команде возвращается список всех установленных контрольных точек, а отмена конкретной контрольной точки производится по команде unstopat(Proc, <номер>), тогда как команда unstopat() отменяет все контрольные точки. Расстановка контрольных точек производится в соответствии с логикой отлаживаемой процедуры. В отличие от метода трассировки, метод контрольных точек позволяет исключать из анализа прозрачные участки программ, существенно уменьшая вывод избыточной отладочной информации. В процессе выполнения процедуры производится останов перед предложением, в котором была установлена контрольная точка, позволяя провести отладочные операции. По cont-команде можно продолжить выполнение процедуры до следующей установленной контрольной точки.
По команде stopwhen(<Id>) определяется режим мониторинга значений для указанной ее аргументом локальной или глобальной переменной. В случае глобальной переменной указывается только ее имя, тогда как локальная требует указания в качестве фактического параметра команды списка, первый элемент которого определяет имя процедуры, а второй – имя собственно ее локальной переменной. Отмена мониторинга производится по unstopwhen-команде, относительно которой остается в силе сказанное в адрес команды unstopat. Наконец, по команде stoperror(<Сообщение>) определяется мониторинг появления заданного ее фактическим аргументом диагностического сообщения об ошибках. При возникновении в процессе выполнения процедуры ошибочной ситуации с указанным сообщением (если она не обрабатывается traperror-функцией) активируется режим отладки, выводятся сообщение об ошибке и вызвавшее ее предложение процедуры. По команде showstop() можно получать информацию о всех функциях и процедурах, содержащих предложения stopat, stoperror и stopwhen. Тогда как по функции debugopts предоставляется возможность как проверять, так и модифицировать параметры, управляющие режимом DEBUG-отладки процедур.
При этом, следует иметь в виду, что в случае использования в процедуре нескольких одноименных переменных контрольная точка для их мониторинга по stopwhen-команде устанавливается только для первого их вхождения в тело процедуры, как это хорошо иллюстрирует следующий достаточно простой фрагмент:
> F:= proc(x) local a,b; a:= 64: b:= sqrt(x + a): a:= `if`(x >= 0, a, `End`) end proc: > stopwhen([F, a]); ⇒ [[F, a]] > F(39); a := 64 |
F: 2 b := sqrt(x+a); [DBG> cont ⇒ 64 > F(-12); a := 64 F: 2 b := sqrt(x+a); [DBG> cont ⇒ End > V:= proc(x) local a,b; a:= 64: b:= sqrt(x + a): a:= `if`(x >= 0, evalf(b, 4),`K`) end proc: V(2006); stopwhen([V, a]): ⇒ 45.51 > V(2006); a := 64 V: 2 b := sqrt(x+a); [DBG> a:= 1942 V: 2 b := sqrt(x+a); [DBG> cont ⇒ 62.84 |
Не имеет особого смысла установка в процедуре контрольной точки после последнего предложения ее тела: если предложение было отлично от return-предложения, то процедура возвращает NULL-значение, в противном случае – результат выполнения returnпредложения. По stopat-процедуре вообще невозможна установка контрольной точки после последнего предложения процедуры, ибо end-предложение не нумеруется.
При этом, следует иметь в виду, что в DEBUG-отладочном режиме допускается производить вычисления с участием переменных процедуры, выводить промежуточные результаты и присваивать значения переменным процедуры, производя мониторинг вариантов вычислений. Перед выходом из отладочного DEBUG-режима следует отменить установки точек всех типов, т.е. действие stop{at|when|error}-команд, и только после этого выполнить {stop|done|quit}-команду, отменяющую режим отладки с выводом соответствующего сообщения и возвратом в вычислительную среду пакета. В противном же случае производится выход из отладочного режима, но ядро пакета остается в так называемом оперативном DEBUG-режиме, активируемом только в момент вызова соответствующих процедур и функций, определенных указанными командами, которые в этом случае выступают уже на уровне функций языка и требуют соответствующего синтаксиса (должны завершаться {;|:}-разделителем). В оперативном режиме DEBUG допускается использование всех вышерассмотренных команд/функций, тогда как внутри режима отладки определенных ими процедур/функций допускается использование всех команд отладочного режима. Установка контрольных точек любого из рассмотренных трех типов может производиться и внутри самих процедур, инициируя режим отладки в моменты их вызовов, однако, на наш взгляд, это не самая лучшая технология отладки. В [12] и [91] можно найти ряд весьма поучительных примеров применения вышерассмотренных DEBUG-средств языка пакета для отладки достаточно простых процедур.
Из данных примеров не только четко прослеживаются основные принципы тестирования процедур на основе контрольных точек, но из них также следует, что средство функции DEBUG уже для относительно несложных процедур является малообозримым и может быть рекомендовано только в достаточно сложных для отладки обычными средствами случаях.