bmstu-iu9 / refal-5-lambda

Компилятор Рефала-5λ
https://bmstu-iu9.github.io/refal-5-lambda
Other
79 stars 35 forks source link

Расширение возможностей отладчика #85

Closed Mazdaywik closed 3 years ago

Mazdaywik commented 7 years ago

На данный момент отладчик поддерживает отображение текущего вызова (print call, print callee, print arg), переменных в текущем вызове (vars, print t.Var, t.Var), переходы на следующий шаг (step) и до полного завершения текущего вызова (next). Точки останова можно ставить на имя функции (при этом одноимённые локальные функции разных файлов не различаются) либо на номер шага. Есть и другие возможности, которые не имеют прямого отношения к текущей задаче.

Это неплохая функциональность, но её мало. Помимо отображения текущего вызова нужно ещё и понимание контекста этого вызова. Что влечёт как минимум печать всего поля зрения:

print viewfield
print view
print vf

Но поле зрения может быть громадным, да и не наглядным. Нужна более узкая выжимка данных. Что-то вроде стека вызовов.

Классического стека вызовов в Рефале нет, вместо него есть поле зрения, переписываемое на каждом шаге. И ближайшим аналогом может быть список функций, подлежащих вызову после завершения текущей. Но контекст вызова функции — это не только те функции, которые будут вычисляться после текущей, но и функция, которая потребит результат вычисления текущей. Например, для поля зрения

<F <G <H> <I>> <J>>

после выполнения функции H будет вызвана функция I, но контекст её вызова — функция G. Аналогично, после G будет вызвана J, но нам может быть интересен вызов G как аргумент функции F.

Следовательно, нужна команда трассировки стека (назовём её по аналогии с GDB, backtrace, bt), которая будет отображать стек вызовов как с функциями после текущей, так и с функциями вокруг текущей.

Введём обозначения. Будем обозначать следующую функцию, на которую будет передано управление как @N, где N — порядковый номер, объемлющую функцию как ^N. При этом текущий вызов будет обозначаться одновременно как @0 и ^0. В примере выше @1 будет ссылаться на вызов I, ^1 будет ссылаться на вызов G. Полная трассировка стека (примерный вывод для backtrace) будет выглядеть так:

@0  ^0   <H ...>
@1       <I ...>
@2  ^1   <G ...>
@3       <J ...>
@4  ^2   <F ...>

Ссылки на вызовы @N, ^N можно использовать в команде print (распечатывают соответствующий функциональный вызов), а также на них можно ставить точки останова. Точки останова можно отображать в трассировке стека:

@0  ^0   <H ...>
@1      *<I ...>
@2  ^1  *<G ...>
@3       <J ...>
@4  ^2   <F ...>

С точки зрения эффективности, поиск точек @N выполняется эффективно (просто идём по списку вызовов), но точки ^N придётся искать, перебирая поле зрения в обратном направлении. Если это окажется медленным, то придётся придумывать что-нибудь для оптимизации.

Можно заметить, что команда next в этом случае оказывается эквивалентной паре команд breakpoint @1, run. Идея благодатная, и она развивается в расширение синтаксиса команды next. А именно, команда next ??? в некотором смысле эквивалентна паре команд breakpoint ???, run. При этом если использовалась команда next FuncName, то воображаемая точка останова не добавляется в таблицу точек останова, как если бы использовалась явная команда breakpoint FuncName.

Если во время выполнения команды next или next ??? произойдёт останов по другой причине (превышение лимита памяти, точка останова), то продолжить движение к следующей точке можно командой next continue или next c (или n c, nc).

Отладчик должен давать пользователю информацию, полезную для отладки. А для этого нужно выводить читабельные сообщения. А читабельность понятие растяжимое. Распечатка выражения в несколько строк с отступами позволяет наглядно увидеть структуру. Однако, распечатка выражения в одну строку экономит вертикальное место на экране.

Полный дамп поля зрения позволяет узнать всё, но может выдать слишком много информации. Трассировка стека позволяет увидеть такую выжимку, как порядок вызова функций, но по ней невозможно всё узнать о соотношении между различными вызовами (видно, в какие функции вложен текущий, но не видны соотношения между другими вызовами). Компромиссом между ними было бы скелетное отображение — дамп поля зрения (или какого-нибудь вызова @N, ^N), в котором присутствуют только скобки вызова без обрабатываемых данных (в примере выше было скелетное отображение).

Интеллектуальное отображение, когда сама среда выбирает оптимальный режим, во-первых, сложно в реализации, во-вторых, всё равно не даст 100%-ного предсказания того, что нужно пользователю. Поэтому предлагается более простой вариант: пользователь выбирает режимы отображения. Режимы доступны следующие:

Ну и раз есть режимы, потребуется команда mode, отображающая текущие установки.

Другие мелкие улучшения:

Итого:

Mazdaywik commented 7 years ago

С недавних пор (#96) в языке стали поддерживаться имена на маленькую букву. А значит, команды print arg, print vf и другие уже становятся неоднозначными. Есть предложение служебные понятия начинать со знака $:

print $arg
print $callee
print $viewfield
Mazdaywik commented 6 years ago

Задача вполне подходит на курсовой проект.

Mazdaywik commented 6 years ago

Предыдущая задача про отладчик — #49.

Mazdaywik commented 6 years ago

Также не хватает неинтерактивного режима, когда отладчик читает команды из заданного пользователем файла. Например, можно создать такой файл:

trace Func1 > log.txt
trace Func2 > log.txt

, указать его в опции командной строки ++enable+debugger=debug.txt и программа отработает самостоятельно, при её завершении будет создан файл log.txt с трассировками двух функций.

Mazdaywik commented 5 years ago

Никто не взял как тему курсового.

Mazdaywik commented 5 years ago

Эта задача опять выносится на курсовую работу по компиляторам.

К слову, в отладчике что-то сломалось, он останавливается не по breakpoint’у, а в какие-то рандомные моменты через десяток шагов. Это тоже надо починить.

Mazdaywik commented 5 years ago

Задача не была выбрана в качестве курсовой.

Mazdaywik commented 4 years ago

Не, не надо её на ВКР. Она больше подходит для курсовой.

Mazdaywik commented 4 years ago

На летнюю практику этот отладчик достаточно заставить работать (на тройку). Расширение его новыми командами желательно (оценка выше тройки), но не обязательно.

Mazdaywik commented 4 years ago

Студент делал другое задание на практику, вне Рефала-5λ.

Mazdaywik commented 3 years ago

@Santalov, поставьте, пожалуйста галочки против тех пунктов, которые Вы сделали.

Mazdaywik commented 3 years ago

@Santalov, а комментарии Вы не прочитали: https://github.com/bmstu-iu9/refal-5-lambda/issues/85#issuecomment-324217770, https://github.com/bmstu-iu9/refal-5-lambda/issues/85#issuecomment-410936966. 🙂

Santalov commented 3 years ago

Извините, не заметил. Доработаю. Насчет #85(comment), не очень понял, зачем это нужно, если имена переменных начинаются с типа и всегда содержат точку, а команды отладчика не содержат точек.

Mazdaywik commented 3 years ago

Насчёт #85(comment), не очень понял, зачем это нужно, если имена переменных начинаются с типа и всегда содержат точку, а команды отладчика не содержат точек.

Я уже сам забыл, что имел ввиду в этом комментарии. Наверное, чтобы можно было писать $vf без print, как и в случае переменных.

Когда будет время, создайте, пожалуйста, багу про ошибку с условиями.

Mazdaywik commented 3 years ago

По поводу комментария https://github.com/bmstu-iu9/refal-5-lambda/issues/85#issuecomment-410936966 и коммита bca16da26c4da1eb996df69427b639a1768907b7.

Дурная голова ногам покоя не даёт, в смысле дурной руководитель — исполнителям. 🤦‍♂️ Опция командной строки ++enable-debugger= не поддерживается уже давно (вызов find_debugger_flag() удалён в 50ec68f627c88cb3c3c4b5fc077c651f3a162194). Вместо неё используются параметры из @refal-5-lambda-diagnostics.ini. А сама функция find_debugger_flag() осталась в исходниках по ошибке.

Если посмотреть на коммит, где был удалён вызов этой функции:

https://github.com/bmstu-iu9/refal-5-lambda/blob/b39319f6a1b6de9b3ca1a469ced36b3810e87e55/src/srlib/refalrts-diagnostic-initializer.cpp#L217-L224

видно, что после получения позиции флага этот флаг из массива аргументов удалялся. Иначе приложение, читающее аргументы командной строки, об эту опцию бы «спотыкалось».

Я в прошлую субботу указал на комментарий, но не догадался уточнить, что эту функцию следовало реализовать иначе. 🤦‍♂️ Следовало добавить параметр debugger_script в @refal-5-lambda-diagnostics.ini. Для этого нужно поправить refalrts-diagnostics-defs.h и refalrts-diagnostics-initializer.cpp. Лучше всего добавить параметр в refalrts::debugger::create_debugger(VM *vm, const char *script); и поле debugger_script в DiagnosticConfig.

Mazdaywik commented 3 years ago

Ай-нанэ-нанэ:

D:\Mazdaywik\Documents\Refal-5-lambda\autotests>run 1-dry-run.sref
Prepare common prefix...
+Linking (+ natives) ../src/lib\refalrts.rasl
+Linking (+ natives) ../src/lib/debug\refalrts-debugger.rasl
+Linking (+ natives) ../src/lib/debug\refalrts-diagnostic-initializer.rasl
+Linking (+ natives) ../src/lib\refalrts-dynamic.rasl
+Linking (+ natives) ../src/lib\refalrts-functions.rasl
+Linking (+ natives) ../src/lib\exe\refalrts-main.rasl
+Linking (+ natives) ../src/lib/debug\refalrts-profiler.rasl
+Linking (+ natives) ../src/lib\refalrts-vm.rasl
+Linking (+ natives) ../src/lib\refalrts-vm-api.rasl
+Linking (+ natives) ../src/lib/platform-Windows\refalrts-platform-specific.rasl
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
../src/lib\refalrts.cpp:
../src/lib/debug\refalrts-debugger.cpp:
Warning W8057 ../src/lib/debug\refalrts-debugger.cpp 716: Parameter 'callee' is never used in function RefalDebugger::is_debug_stop(Node *,RefalFunction *)
Error E2291 ../src/lib/debug\refalrts-debugger.cpp 919: } expected in function RefalDebugger::trace_option(Cmd &,FILE *)
Error E2034 ../src/lib/debug\refalrts-debugger.cpp 921: Cannot convert 'FILE *' to 'FileAndName' in function RefalDebugger::trace_option(Cmd &,FILE *)
Error E2141 ../src/lib/debug\refalrts-debugger.cpp 921: Declaration syntax error in function RefalDebugger::trace_option(Cmd &,FILE *)
Error E2139 ../src/lib/debug\refalrts-debugger.cpp 921: Declaration missing ; in function RefalDebugger::trace_option(Cmd &,FILE *)
Warning W8004 ../src/lib/debug\refalrts-debugger.cpp 921: 'file' is assigned a value that is never used in function RefalDebugger::trace_option(Cmd &,FILE *)
Warning W8057 ../src/lib/debug\refalrts-debugger.cpp 921: Parameter 'out' is never used in function RefalDebugger::trace_option(Cmd &,FILE *)
Error E2190 ../src/lib/debug\refalrts-debugger.cpp 921: Unexpected }
Error E2141 ../src/lib/debug\refalrts-debugger.cpp 922: Declaration syntax error
Error E2190 ../src/lib/debug\refalrts-debugger.cpp 923: Unexpected }
Warning W8057 ../src/lib/debug\refalrts-debugger.cpp 997: Parameter 'skeleton' is never used in function RefalDebugger::print_view_field_option(FILE *,bool,bool)
*** 7 errors in Compile ***
../src/lib/debug\refalrts-diagnostic-initializer.cpp:
../src/lib\refalrts-dynamic.cpp:
../src/lib\refalrts-functions.cpp:
../src/lib\exe\refalrts-main.cpp:
../src/lib/debug\refalrts-profiler.cpp:
../src/lib\refalrts-vm.cpp:
../src/lib\refalrts-vm-api.cpp:
../src/lib/platform-windows\refalrts-platform-specific.cpp:
Mazdaywik commented 3 years ago

Исправил проблемы с Borland C++ Compiler 5.5.1.