Как макровключенный язык отслеживает исходный код для отладки?

Это - более теоретический вопрос о макросах (я думаю). Я знаю, что макросы берут исходный код и производят объектный код, не оценивая его, позволяя программистам создать больше универсальных синтаксических структур. Если бы я должен был классифицировать эти две макро-системы, то я сказал бы, что было "C стиль" макрос и "макрос" стиля Lisp.

Кажется, что отладка макросов может быть немного хитрой, потому что во времени выполнения, код, который на самом деле работает, отличается от источника.

Как отладчик отслеживает осуществление программы с точки зрения предварительно обработанного исходного кода? Существует ли специальный "режим отладки", который должен быть установлен собрать дополнительные данные о макросе?

В C я могу понять, что Вы установили переключатель времени компиляции для отладки, но как будет интерпретируемый язык, такой как некоторые формы Lisp, не так ли?

Принесите извинения за то, что не было испытано это, но набор инструментальных средств шепелявости требует большего количества времени, чем я должен потратить к фигуре.

9
задан Sean Woods 9 July 2010 в 16:25
поделиться

6 ответов

Я не думаю, что есть принципиальная разница между макросами "стиля C" и "стиля Lisp" в том, как они компилируются. Оба преобразуют исходный код до того, как его увидит компилятор. Большая разница в том, что макросы C используют препроцессор C (более слабый вторичный язык, который в основном предназначен для простой подстановки строк), в то время как макросы Lisp написаны на самом Lisp (и, следовательно, могут делать что угодно).

(Кстати: я давно не видел некомпилированного Лиспа ... определенно, с начала века. сложнее, так как у вас есть больше информации.)

Я согласен с Майклом: я вообще не видел отладчика для C, который бы обрабатывал макросы. Код, использующий макросы, трансформируется еще до того, как что-либо произойдет. Режим «отладки» для компиляции кода C обычно означает, что он хранит функций, типов, переменных, имен файлов и т. Д. - я не думаю, что какие-либо из них хранят информацию о макросах .

  • Для отладки программ, которые используют макросы , Lisp почти такой же как C здесь: ваш отладчик видит скомпилированный код, а не макрос заявление. Обычно макросы оставался простым и отлаженным самостоятельно перед применением, во избежание необходимость в этом, как и в C.

  • Для отладки макросов сами , прежде чем вы пойдете и используете его где-нибудь, у Lisp есть особенности которые делают это проще, чем в C, например, ответы и macroexpand-1 (хотя в C очевидно есть способ макрос развернуть весь файл полностью на однажды).Вы можете увидеть до и после макрорасширения, прямо в вашем редакторе, когда вы пишете Это.

Я не могу вспомнить ни одного случая, когда я сталкивался с ситуацией, когда отладка в самого определения макроса была бы полезной. Либо это ошибка в определении макроса, и в этом случае macroexpand-1 немедленно изолирует проблему, либо это ошибка ниже этого значения, и в этом случае обычные средства отладки работают нормально, и мне все равно, что Макрорасширение произошло между двумя кадрами моего стека вызовов.

3
ответ дан 4 December 2019 в 21:07
поделиться

В LispWorks разработчики могут использовать инструмент Stepper .

LispWorks предоставляет пошаговый режим, в котором можно пройти через полный процесс расширения макроса .

3
ответ дан 4 December 2019 в 21:07
поделиться

Я не знаю о макросах лиспа (которые, как я подозреваю, вероятно, сильно отличаются от макросов Си) или отладке, но многие - вероятно, большинство - отладчики Си/Си++ не особенно хорошо справляются с отладкой макросов препроцессора Си на уровне исходного текста.

Как правило, отладчики Си/Си++ не "заходят" в определение макроса. Если макрос разворачивается в несколько операторов, то отладчик обычно просто остается на одной и той же строке исходного текста (где вызывается макрос) для каждой операции "шага" отладчика.

Это может сделать отладку макросов немного более болезненной, чем они могли бы быть - еще одна причина избегать их в C/C++. Если макрос ведет себя действительно загадочным образом, я перехожу в режим ассемблера, чтобы отладить его или расширить макрос (вручную или с помощью переключателя компилятора). Довольно редко приходится идти на такую крайность; если вы пишете настолько сложные макросы, вы, вероятно, используете неправильный подход.

1
ответ дан 4 December 2019 в 21:07
поделиться

Простой ответ заключается в том, что это сложно ;-) Есть несколько различных вещей, которые способствуют возможности отладки программы, и еще больше для отслеживания макросов.

В C и C++ препроцессор используется для расширения макросов и include в реальный исходный код. Имена исходных файлов и номера строк отслеживаются в этом расширенном исходном файле с помощью директив #line.

http://msdn.microsoft.com/en-us/library/b5w2czay(VS.80).aspx

Когда программа на C или C++ компилируется с включенной отладкой, ассемблер генерирует дополнительную информацию в объектном файле, которая отслеживает исходные строки, имена символов, дескрипторы типов и т.д.

http://sources.redhat.com/gdb/onlinedocs/stabs.html

Операционная система имеет функции, позволяющие отладчику присоединяться к процессу и контролировать его выполнение; пауза, одиночный шаг и т.д.

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

Динамические языки обычно выполняются в виртуальной машине, будь то интерпретатор или виртуальная машина байткода. Именно виртуальная машина предоставляет крючки, позволяющие отладчику контролировать поток программы и проверять состояние программы.

0
ответ дан 4 December 2019 в 21:07
поделиться

Вам действительно следует изучить поддержку, которую имеет Racket для отладки кода с помощью макросов. Как упоминает Кен, эта поддержка имеет два аспекта. С одной стороны, существует проблема отладки макросов: в Common Lisp лучший способ сделать это - просто развернуть формы макросов вручную. С CPP ситуация аналогична, но более примитивна - вы должны пропустить код только через расширение CPP и проверить результат. Однако обоих из них недостаточно для более сложных макросов, и это было мотивацией для наличия отладчика макросов в Racket - он показывает вам шаги расширения синтаксиса один за другим с дополнительными указаниями на основе графического интерфейса для такие вещи, как связанные идентификаторы и т. д.

Что касается , использующего макросы , Racket всегда был более продвинутым, чем другие реализации Scheme и Lisp. Идея состоит в том, что каждое выражение (как синтаксический объект) представляет собой код плюс дополнительные данные, содержащие его исходное местоположение. Таким образом, когда форма является макросом, расширенный код, который имеет части, поступающие из макроса, будет иметь правильное исходное местоположение - из определения макроса, а не из его использования (где формы на самом деле отсутствуют). Некоторые реализации Scheme и Lisp будут реализовывать ограниченное для этого использование идентификатора подчиненных форм, как упоминалось dmitry-vk.

2
ответ дан 4 December 2019 в 21:07
поделиться

Обычно в C отладка на уровне исходного кода имеет гранулярность строки («следующая» команда) или гранулярность уровня инструкции. ("шаг в"). Макропроцессоры вставляют в обработанный исходный код специальные директивы, которые позволяют компилятору сопоставлять скомпилированные последовательности инструкций ЦП со строками исходного кода.

В Лиспе не существует соглашения между макросами и компилятором для отслеживания сопоставления исходного кода и компилируемого кода, поэтому не всегда возможно выполнить пошаговое выполнение исходного кода.

Очевидный вариант - выполнить пошаговое выполнение в макрорасширенном коде. Компилятор уже видит окончательную, расширенную версию кода и может отслеживать сопоставление исходного кода с машинным кодом.

Другой вариант - использовать тот факт, что выражения lisp во время манипуляции имеют идентичность. Если макрос прост и просто выполняет деструктуризацию и вставку кода в шаблон, тогда некоторые выражения расширенного кода будут идентичны (в отношении сравнения EQ) выражениям, которые были прочитаны из исходного кода. В этом случае компилятор может отображать некоторые выражения из расширенного кода в исходный код.

1
ответ дан 4 December 2019 в 21:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: