GNU MIX Development Kit (mdk): Начало работы

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3. Начало работы

В этой главе вы найдёте примеры сеансов кодирования, компиляции, запуска и отладки с использованием утилит MDK. Предполагается знакомство с мифическим компьютером MIX и его языке ассемблера MIXAL (описанными в "Искусстве программирования" Кнута). Чтобы освежить их в памяти, см. 2. Учебник по MIX и MIXAL.

3.1 Написание исходного файла  Пример исходного файла на MIXAL.
3.2 Компиляция  Использование mixasm для компиляции
                                исходных файлов в двоичный формат.
3.3 Запуск программы  
3.4 Использование mixguile  Использование интерпретатора Scheme для
                                запуска и отладки программ.
3.5 Использование Scheme в mixvm и gmixvm  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.1 Написание исходного файла

Программы на MIXAL могут быть написаны в виде ASCII-файлов в любом текстовом редакторе. Приведём обязательную программу hello world, написанную на языке ассемблера MIXAL.

 
*                                                        (1)
* hello.mixal: сказать 'hello world' на MIXAL            (2)
*                                                        (3)
* label ins    operand     comment                       (4)
TERM    EQU    19          номер устройства консоли в MIX (5)
        ORIG   1000        начальный адрес               (6)
START   OUT    MSG(TERM)   вывести данные с адреса MSG   (7)
        HLT                прекратить работу             (8)
MSG     ALF    "MIXAL"                                   (9)
        ALF    " HELL"                                   (10)
        ALF    "O WOR"                                   (11)
        ALF    "LD   "                                   (12)
        END    START       конец программы               (13)
При использовании утилит MDK исходным файлам MIXAL следует давать расширение `.mixal'. Как вы можете видеть в этом примере, каждая строка в файле MIXAL может быть разделена на четыре поля, разделённые любым количеством пробельных символов (пробелы и знаки табуляции). В определении MIXAL Кнута каждое поле должно начинаться в фиксированной колонке, но ассемблер MDK ослабляет это требование и позволяет форматировать файл по вашему усмотрению. Ограничения связаны только со строками комментариев (такими, как 1-4), которые должны начинаться со звёздочки (*), помещённой в первой колонке, и с полями меток (см. ниже), которые, если они присутствуют, также должны начинаться в первой колонке. Четыре поля, присутствующие в каждой строке, не являющейся комментарием, это:

  • необязательная метка, которая либо ссылается на текущий адрес памяти (как START и MSG в строках 7 и 9), либо определяет символ (TERM) (если она присутствует, метка обязана начинаться в первой колонке строки, ибо первый пробельный символ в строке отмечает начало второго поля).
  • мнемоника операции, которая может представляет либо инструкцию MIX (OUT и HLT в строках 7 и 9), либо псевдоинструкцию ассемблера (например, псевдоинструкция ORIG в строке 6(10)).
  • необязательный операнд (псевдо)инструкции, и
  • необязательный комментарий -- произвольный текст.

Строки 9-12 в файле `hello.mixal' показываеют также второе (и последнее) различие между определениями MIXAL Кнута и нашими: операнд псевдоинструкции ALf (слово из пяти литер) должно быть заключено в двойные кавычки(11). Если вы знакомы с MIXAL, работа этого примера программы должна быть понятна. См. полное определение MIXAL в томе 1 "Искусства программирования", учебник -- 2. Учебник по MIX и MIXAL.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.2 Компиляция

В состав MDK входят три эмулятора компьютера MIX: mixvm, gmixvm и mixguile. Они могут выполнять двоичные файлы, содержащие инструкции MIX, записанные в двоичном представлении. Транслировать исходные файлы на MIXAL в такой двоичный вид можно ассемблером MIXAL mixasm. Так, для компиляции файла `hello.mixal' вы можете использовать в командной строке оболочки следующую команду:

 
mixasm -g hello RET

Если исходный файл не содержит ошибок, будет создан двоичный файл `hello.mix', который может быть загружен и запущен виртуальной машиной MIX. Флаг -g указывает ассемблеру включать в исполняемый файл отладочную информацию (полное описание всех параметров компиляции см. в 5. mixasm, ассемблер MIXAL). Теперь всё готово для запуска вашей первой программы MIX, что описано в следующем разделе.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.3 Запуск программы

MIX -- мифический компьютер, и бесполезно пытаться заказать его у вашего поставщика аппаратного обеспечения. Тем не менее, MDK предоставляет три программных эмулятора этого компьютера. Это

  • mixvm, эмулятор, ориентированный на использование командной строки,
  • gmixvm, основанный на GTK графический интерфейс mixvm, и
  • mixguile, оболочка Guile со встроенным эмулятором MIX.

Все три эмулятора используют один и тот же набор команд пользователя, но, как отмечено выше, предлагают различные пользовательские интерфейсы. В этом разделе мы опишем некоторые из этих команд и покажем вам, как пользоваться ими в командной строке mixvm. Вы можете также использовать их в командной строке gmixvm (see section 7. gmixvm, виртуальная машина на основе GTK) или работать со встроенными примитивами Scheme mixguile (see section 3.4 Использование mixguile).

Используя эмуляторы MIX вы можете запускать ваши программы на MIXAL, предварительно скомпилированные mixasm в двоичные файлы `.mix'. mixvm может использоваться в интерактивном или в неинтерактивном режиме. В втором случае mixvm загружает вашу программу в память, выполняет её (создавая выходные файлы, обусловленые наличием в программе инструкций MIXAL OUT) и завершает работу при обнаружении инструкции HLT. В интерактивном режиме вы попадёте в приглашение оболочки, позволяющее вам давать команды работающей виртуальной машине. Эти команды позволят вам загружать, запускать и отлаживать программы, а также проверять состояние компьютера MIX (содержимое регистров, ячеек памяти и т.д.).

3.3.1 Неинтерактивный режим  
3.3.2 Интерактивный режим  
3.3.3 Команды отладки  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.3.1 Неинтерактивный режим

Для запуска mixvm в неинтерактивном режиме используйте флаг -r. Так, для запуска программы `hello.mix' введите:

 
mixvm -r hello RET

в приглашении командной строки. Вы получите такой вывод:

 
MIXAL HELLO WORLD

Поскольку наша программа использует для вывода устройство MIX номер 19 (see section 3.1 Написание исходного файла), вывод направляется на стандартный вывод оболочки. При использовании любого другого устройства MIX (диски, барабаны, строчный принтер и т.д.) mixvm создаст файл, имя которого соответствует устройству (например, `disk4.dev') и запишет вывод туда(12).

Виртуальная машина может также сообщить время выполнения программы, в соответствии со временем (виртуальным), требуемым каждой инструкцией (see section 2.1.2.12 Временные характеристики). Вывод статистики времени выполнения включается флагом -t. Запуск

 
mixvm -t -r hello RET

даст следующий вывод:

 
MIXAL HELLO WORLD
** Execution time: 11

Иногда вы предпочтёте сохранять результаты работы вашей программы в регистрах MIX, а не записывать их на устройствах. В таких случаях будет полезен флаг mixvm -d, заставляющий mixvm после выполнения загруженной программы выводить содержимое регистров и флагов. Например, введя в приглашении оболочки следующую команду:

 
mixvm -d -r hello

вы получите такой вывод:

 
MIXAL HELLO WORLD
rA: + 00 00 00 00 00 (0000000000)
rX: + 00 00 00 00 00 (0000000000)
rJ: + 00 00 (0000)
rI1: + 00 00 (0000)     rI2: + 00 00 (0000)     
rI3: + 00 00 (0000)     rI4: + 00 00 (0000)     
rI5: + 00 00 (0000)     rI6: + 00 00 (0000)     
Overflow: F
Cmp: E

включающий, помимо вывода программы и времени выполнения, содержимое регистров MIX и значения триггера переполнения и флага сравнения (признаться, не слишком интересные в нашем примере).

Как можно видеть, неинтерактивный запуск программ накладывает много ограничений. Вы не можете ни заглянуть в память машины, ни выполнять инструкции программы по шагам или устанавливать точки останова(13). Перейдём к интерактивному режиму.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.3.2 Интерактивный режим

Чтобы войти в интерактивный режим виртуальной машины MIX, введите:

 
mixvm RET

в приглашении командной строки. Вы попадёте в командную оболочку mixvm и увидите следующее приглашение:

 
MIX >

Виртуальная машина инициализирована и готова к вашим командам. Командная оболочка mixvm использует GNU readline, и поэтому в вашем распоряжении находятся дополнение команд (TAB) и возиожности истории команд, равно как и другие способы редактирования командных строк, общие для всех использующих эту библиотеку утилит (полное описание средств редактирования строк readline см. в @xref{Command Line Editing,,,Readline}.)

Обычно, первое, что вы захотите сделать, это загрузка в память скомпилированной программы MIX. Это осуществляется командой load, принимающей в качестве аргумента название загружаемого файла `.mix'. Так, ввод

 
MIX > load hello RET
Program loaded. Start address: 3000
MIX >

загрузит `hello.mix' в память виртуальной машины и установит счётчик программы на адрес первой инструкции. Вы можете посмотреть содержимое счётчика программы командой pc:

 
MIX > pc
Current address: 3000
MIX >

После загрузки всё готово к запуску программы. Для этого, как вы, конечно, догадались, служит команда run:

 
MIX > run
Running ...
MIXAL HELLO WORLD                                                     
... done
Elapsed time: 11 /Total program time: 11 (Total uptime: 11)
MIX > 

Обратите внимание, что статистика времена более полна. Вы видите прошедшее время выполнения (т.е. время выполнения инструкций после последней точки останова), общее время выполнения программы до данного момента (которое в нашем случае совпадает с прошедшим временем, поскольку нет точек останова), и общее время работы виртуальной машины (вы можете загружать и запускать несколько программ в одном сеансе)(14). После выполнения программы счётчик программы будет указывать на адрес слова, следующего за инструкцией HLT. В нашем случае запрос значения счётчика программы после завершения работы программы даст:

 
MIX > pc
Current address: 3002
MIX >

Вы можете просмотреть содержимое ячейки памяти, передавая её адрес в качестве аргумента команды pmem:

 
MIX > pmem 3001
3001: + 00 00 00 02 05 (0000000133)
MIX >

и убедиться в том, что ячейка 3001 содержит двоичное представление инструкции HLT. Также аргументом pmem может быть диапазон адресов в виде ОТ-ДО:

 
MIX > pmem 3000-3006
3000: + 46 58 00 19 37 (0786957541)
3001: + 00 00 00 02 05 (0000000133)
3002: + 14 09 27 01 13 (0237350989)
3003: + 00 08 05 13 13 (0002118477)
3004: + 16 00 26 16 19 (0268542995)
3005: + 13 04 00 00 00 (0219152384)
3006: + 00 00 00 00 00 (0000000000)
MIX >

Аналогичным образом вы можете просматривать содержимое регистров и флагов MIX. Например, чтобы запросить содержимое регистра A вы можете ввести:

 
MIX > preg A
rA: + 00 00 00 00 00 (0000000000)
MIX >

Используйте команду help, чтобы получить список всех доступных команд и help КОМАНДА чтобы получить справку по конкретной команде, например:

 
MIX > help run
run             Run loaded or given MIX code file. Usage: run [FILENAME]
MIX > 

Полный список доступных в приглашении MIX команд см. в 6. mixvm, эмулятор компьютера MIX. В следующем подразделе вы найдёте краткое описание команд, полезных для отладки программ.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.3.3 Команды отладки

Интерактивный режим mixvm даёт возможности пошагового выполнения программ и установки точек останова. Для пошагового выполнения используйте next. Чтобы выполнить наш пример из двух инструкций `hello.mix', вы можете сделать следующее:

 
MIX > load hello
Program loaded. Start address: 3000
MIX > pc
Current address: 3000
MIX > next
MIXAL HELLO WORLD
Elapsed time: 1 /Total program time: 1 (Total uptime: 1)
MIX > pc
Current address: 3001
MIX > next
End of program reached at address 3002
Elapsed time: 10 /Total program time: 11 (Total uptime: 11)
MIX > pc
Current address: 3002
MIX > next
MIXAL HELLO WORLD
Elapsed time: 1 /Total program time: 1 (Total uptime: 12)
MIX > 
MIX > run
Running ...
... done
Elapsed time: 10 /Total program time: 11 (Total uptime: 22)
MIX >
(заметим, что этот пример также показывает, как виртуальная машина обрабатывает накопительную статистику времени и автоматический перезапуск программы).

Установить по заданному адресу точку останова можно командой sbpa (set breakpoint at address, установить точку останова по адресу). Если установлена точка останова, run остановится перед выполнением инструкции по заданному адресу. Новое выполнение run завершит выполнение программы. Вернёмся к нашему примеру hello world:

 
MIX > sbpa 3001
Breakpoint set at address 3001
MIX > run
Running ...
MIXAL HELLO WORLD                                                     
... stopped: breakpoint at line 8 (address 3001)
Elapsed time: 1 /Total program time: 1 (Total uptime: 23)
MIX > run
Running ...
... done
Elapsed time: 10 /Total program time: 11 (Total uptime: 33)
MIX >

Заметьте, что поскольку мы компилировали `hello.mixal' с отладочной информацией (флаг -g mixasm), виртуальноая машина может указать нам строку исходного файла, соответствующую точке останова. Собственно говоря, можно непосредственно устанавливать точки останова на строках исходного кода командой sbp НОМЕР_СТРОКИ:

 
MIX > sbp 4
Breakpoint set at line 7
MIX > 

sbp устанавливает точку останова на первой осмысленной строке исходного кода. Так, в вышеприведённом примере мы потребовали установить точку останова на строке, не соответствующей инструкции MIX, и она была установлена на первой строке, содержащей реальную инструкции после заданной. Чтобы снять точку останова, используйте cbpa АДРЕС и cbp НОМЕР_СТРОКИ, или cabp чтобы удалить все установленные точки останова. Вы можете также установить условную точку останова, т.е. указать mixvm прерывать выполнение программы только когда меняется значение регистра, ячейки памяти, флага сравнения или триггера переполнения командами sbp[rmco] (see section 6.2.2 Команды отладки).

MIXAL позволяет определять символические константы, либо используя псевдоинструкцию EQU, либо начиная строку инструкции с метки (что присваивает метке значение текущего адреса памяти). Поэтому с каждой программой на MIXAL связана таблица символов, которую вы можете просматривать командой psym. В нашем примере hello world вы можете получить следующий вывод:

 
MIX > psym
START:  3000
TERM:  19
MSG:  3002
MIX > 

Также при отладке полезны команды strace (включающая отслеживание выполненных инструкций), pbt (выводящая след выполненных инструкций) и weval (вычисляющая на лету значение w-выражения). Полное описание всех доступных команд MIX см. в 6. mixvm, эмулятор компьютера MIX.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.4 Использование mixguile

Используя mixguile вы можете запускать эмулятор MIX, встроенный в оболочку Guile, т.е. использовать функции и программы Scheme. Как и mixvm, mixguile может работать как в интерактивном, так и в неинтерактивном режиме. Следующие подразделы содержат краткое описание использование этого эмулятора MIX.

3.4.1 Оболочка mixguile  Использование виртуальной машины MIX Scheme.
3.4.2 Дополнительные функции MIX Scheme  Функции Scheme, доступные виртуальной машине.
3.4.3 Определение новых функций  Определение собственных функции Scheme.
3.4.4 Функции-ловушки  
3.4.5 Скрипты Scheme  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.4.1 Оболочка mixguile

Если вы введёте

 
mixguile RET
в приглашении командной строки, то попадёте в приглашение оболочки Guile:

 
guile>
Вы вошли в цикл ввода, обработки и вывода Scheme (read-eval-print loop, REPL), предлагающий вам все возможности Guile и новый набор встроенных процедур для выполнения и отладки программ MIX. Каждая команда mixvm, описанная в предыдущих разделах (и в see section 6. mixvm, эмулятор компьютера MIX) имеет соответствующую функцию Scheme, название которой образовано добавлением к названию команды префикса mix-. Так, чтобы загрузить программу hello world, можно ввести:

 
guile> (mix-load "hello")
Program loaded. Start address: 3000
guile> 
а запустить её можно командой mix-run:

 
guile> (mix-run)
Running ...
MIXAL HELLO WORLD                                                     
... done
Elapsed time: 11 /Total program time: 11 (Total uptime: 11)
guile> 
Таким же образом вы можете выполнять команду по шагам, используя функцию Scheme mix-next, или установить точку останова:

 
guile> (mix-sbp 4)
Breakpoint set at line 5
guile> 
или, если вам интересно содержимое регистра:

 
guile> (mix-preg 'A)
rA: + 00 00 00 00 00 (0000000000)
guile> 

Основная идея: в вашем распоряжении находятся все команды mixvm и gmixvm в виде функций mix-. Но, если вас это удивляет, заметим, что это только начало. В вашем распоряжении также полный интерпретатор Scheme, и вы можете, например, определять новые функции, комбинируя функции mix- и остальные примитивы Scheme. В следующих разделах вы обнаружите примеры использование интерпретатора Guile.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.4.2 Дополнительные функции MIX Scheme

Функции mix-, соответствующие командам mixvm, не возвращают никакого значения и работают только засчёт побочных эффектов (возможно, включающих информационные сообщения на стандартный вывод и/или поток ошибок). При написании собственных функций Scheme для управления виртуальной машиной MIX из mixguile (see section 3.4.3 Определение новых функций), вам, вероятно, понадобятся функции Scheme, возвращающие значение регистров, ячеек памяти и т.д. Не волнуйтесь, mixguile предлагает вам и такие функции. Например, чтобы получить значение (числовое) регистра, можно использовать mix-reg:

 
guile> (mix-reg 'I2)
0
guile> 
Заметьте, что в отличие от (mix-preg 'I2), выражение (mix-reg 'I2) в этом примере вычисляет номер Scheme и не создаёт никакого побочного эффекта:

 
guile> (number? (mix-reg 'I2))
#t
guile> (number? (mix-preg 'I2))
rI2: + 00 00 (0000)     
#f
guile> 

Аналогичным образом можно обращаться к содержимому памяти командой (mix-cell), или к счётчику программы командой (mix-loc):

 
guile> (mix-cell 3000)
786957541
guile> (mix-loc)
3002
guile> 

Значение флага сравнения и триггера переполнения возвращают функции mix-cmp и mix-over соответственно. Полный список дополнительных функций см. в 8. mixguile, виртуальная машина на основе Scheme.

В следующем разделе мы увидим пример использования этих функций для расширения функциональности mixguile.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.4.3 Определение новых функций

Scheme -- мощный язык, и вы можете использовать его внутри mixguile, чтобы легко расширять возможности интерпретатора MIX. Например, вы легко можете определить функцию, загружающую файл, выводяющую его имя, выполняющую его и, наконец, показывающую содержимое регистров, всё в один приём:

 
guile> (define my-load-and-run  RET
         (lambda (file)   RET
           (mix-load file)   RET
           (display "File loaded: ")   RET
           (mix-pprog)   RET
           (mix-run)   RET
           (mix-preg)))   RET
guile> 
и использовать её для запуска ваших программ:

 
guile> (my-load-and-run "hello")
Program loaded. Start address: 3000
File loaded: hello.mix
Running ...
MIXAL HELLO WORLD                                                     
... done
Elapsed time: 11 /Total program time: 11 (Total uptime: 33)
rA: + 00 00 00 00 00 (0000000000)
rX: + 00 00 00 00 00 (0000000000)
rJ: + 00 00 (0000)
rI1: + 00 00 (0000)     rI2: + 00 00 (0000)     
rI3: + 00 00 (0000)     rI4: + 00 00 (0000)     
rI5: + 00 00 (0000)     rI6: + 00 00 (0000)     
guile> 

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

 
guile> (define my-load-and-run-with-bp
         (lambda (file line)
           (mix-load file)
           (mix-sbp line)
           (mix-run)))
guile> (my-load-and-run-with-bp "samples/primes" 10)
Program loaded. Start address: 3000
Breakpoint set at line 10
Running ...
... stopped: breakpoint at line 10 (address 3001)
Elapsed time: 1 /Total program time: 1 (Total uptime: 45)
guile>

Третьим примером рассмотрим функцию, загружающую программу, выполняющую её и выводящую содержимое памяти между начальным и конечным адресами программы:

 
guile> (define my-run
         (lambda (file)
           (mix-load file)
           (let ((start (mix-loc)))
             (mix-run)
             (mix-pmem start (mix-loc)))))
guile> (my-run "hello")
Program loaded. Start address: 3000
Running ...
MIXAL HELLO WORLD                                                     
... done
Elapsed time: 11 /Total program time: 11 (Total uptime: 11)
3000: + 46 58 00 19 37 (0786957541)
3001: + 00 00 00 02 05 (0000000133)
3002: + 14 09 27 01 13 (0237350989)
guile> 

Как вы видите, возможности практически не ограничены. Конечно, вводить определение функций при каждом запуске mixguile не нужно. Вы можете записать их в файл и загрузить функцией Scheme load. Например, вы можете создать файл, скажем, `functions.scm' с вашими определениями (или любыми выражениями Scheme) и загрузить его в приглашении mixguile:

 
guile> (load "functions.scm")

Кроме того, вы можете указать mixguile загружать его каждый раз. При запуске mixguile, она проверяет файл `mixguile.scm' в каталоге конфигурации MDK (`~/.mdk') и, если он существует, загружает его перед тем, как войти в REPL. Поэтому вы можете скопировать ваши определения в этот файла или загрузить `functions.scm' из `mixguile.scm'.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.4.4 Функции-ловушки

Ловушки -- это функции, вызываемые до или после некоторого события. В mixguile вы можете определять ловушки команд и остановов, связанные, соответственно, с выполнением команды и с прерыванием программы. Следующие разделы содержат учебник по использованию функций-ловушек в mixguile.

3.4.4.1 Ловушки команд  
3.4.4.2 Ловушки остановов  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.4.4.1 Ловушки команд

В предыдущем разделе мы видели как с помощью определённых пользователем функций расширяется функциональномть mixguile. Часто вы будете писать новые функции, некоторым образом усовершенствующие работу встроенных команд mixvm, по следующему образцу:

  1. Подготовиться к выполнению команды
  2. Выполнить желаемую команду
  3. Осуществить операции после выполнения команды

Мы называем функции, выполняемые на шаге (a) ловушками до команды, а на шаге (c) -- ловушками после команды. mixguile позволяет задать ловушки до и после любой команды mixvm, используя функции mix-add-pre-hook и mix-add-post-hook, принимающие в качестве аргументов символ, называющий команду, и выполняемую перед командой (после команды) функцию. Другими словами, mixguile будет выполнять шаги (a) и (c) при каждом выполнении (b). Функции-ловушки должны принимать единственный аргумент, являющийся списком строк аргументов команды. Например, определим следующие ловушки для команды next:

 
(define next-pre-hook
  (lambda (arglist)
    (mix-slog #f)))

(define next-post-hook
  (lambda (arglist)
    (display "Stopped at line ")
    (display (mix-src-line-no))
    (display ": ")
    (display (mix-src-line))
    (newline)
    (mix-slog #t)))
В этих функциях мы используем функции mix-slog для отключения информационных сообщений, создаваемых виртуальной машиной, поскольку генерируем свои сообщения в ловушке после команды. Для установки этих ловушек нам следует написать:

 
(mix-add-pre-hook 'next next-pre-hook)
(mix-add-post-hook 'next next-post-hook)
Допустим, мы поместили эти выражения в файл инициализации mixguile. При выполнении mix-next мы получим следующий результат:

 
guile> (mix-next)
MIXAL HELLO WORLD                                                     
Stopped at line 6:             HLT   
guile> 

Во втором, более сложном, примере, определим ловушки, выводящие адрес и содержимое ячейки памяти, модифицированной smem. Функции-ловушки должны быть примерно такими:

 
(define smem-pre-hook
  (lambda (arglist)
    (if (eq? (length arglist) 2)
        (begin
          (display "Changing address ")
          (display (car arglist))
          (newline)
          (display "Old contents: ")
          (display (mix-cell (string->number (car arglist))))
          (newline))
        (error "Wrong arguments" arglist))))

(define smem-post-hook
  (lambda (arglist)
    (if (eq? (length arglist) 2)
        (begin
          (display "New contents: ")
          (display (mix-cell (string->number (car arglist))))
          (newline)))))
и установить их можно так:

 
(mix-add-pre-hook 'smem smem-pre-hook)
(mix-add-post-hook 'smem smem-post-hook)
После этого выполнение mix-smem даст:

 
guile> (mix-smem 2000 100)
Changing address 2000
Old contents: 0
New contents: 100
guile>

Вы можете добавить заданной команде любое количество ловушек. Они будут выполняться в том порядке, в котором они зарегистрированы. Вы можете также определить глобальные ловушки до (после) команды, которые будут выполняться перед (после) любой выполняемой команды mixvm. Глобальные функции-ловушки должны принимать два аргумента, а именно строку, называющую вызываемую команду, и список строк её аргументов. Устанавливаются они функциями Scheme mix-add-global-pre-hook и mix-add-global-post-hook. Простой пример глобальной ловушки:

 
guile> (define pre-hook
         (lambda (cmd args)
           (display cmd)
           (display " invoked with arguments ")
           (display args)
           (newline)))
guile> (mix-add-global-pre-hook pre-hook)
ok
guile> (mix-pmem 120 125)
pmem invoked with arguments (120-125)
0120: + 00 00 00 00 00 (0000000000)
0121: + 00 00 00 00 00 (0000000000)
0122: + 00 00 00 00 00 (0000000000)
0123: + 00 00 00 00 00 (0000000000)
0124: + 00 00 00 00 00 (0000000000)
0125: + 00 00 00 00 00 (0000000000)
guile>

Заметьте, что если внутри глобальной ловушки вы вызываете команды mixvm, будут выполняться и их ловушки команд. Так, если вы установили описанные выше ловушки next и глобальные ловушки, выполнение mix-next приведёт к следующему результату:

 
guile> (mix-next 5)
next invoked with arguments (5)
slog invoked with arguments (off)
MIXAL HELLO WORLD                                                     
Stopped at line 7: MSG         ALF   "MIXAL"
slog invoked with arguments (on)
guile> 

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


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.4.4.2 Ловушки остановов

В предыдущем разделе мы рассмотрели, как связывать ловушки с выполнением команд, но это ещё не всё. Вы можете также связывать функции-ловушки с прерыванием выполнения программы, т.е. задавать функции, вызываемые при каждой остановке выполнения программы MIX из-за точки останова, обязательной или условной. Ловушки останова принимают в качестве аргументов номер строки и адреса памяти, где произошёл останов. Простая ловушка, ведущая лог строк и адресов остановов, может быть определена:

 
(define break-hook
  (lambda (line address)
    (display "Breakpoint encountered at line ")
    (display line)
    (display " and address ")
    (display address)
    (newline)))
и установлена для обязательных и условных точек останова:

 
(mix-add-break-hook break-hook)
(mix-add-cond-break-hook break-hook)
После этого при каждом обнаружении виртуальной машиной точки останова будет вычисляться break-code(15).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.4.5 Скрипты Scheme

Другой полезный способ использования mixguile -- написание исполняемых скриптов, предоставляющих набор команд. Это делается флагом -s mixguile (будучи оболочкой Scheme, mixguile принимает все параметры команды guile, для получения списка всех доступных параметров команды введите mixguile -h). Например, если у вас есть очень полезная программа MIX `foo.mix', которую вы собираетесь использовать достаточно часто, вам не нужно каждый раз запускать виртуальную машину MIX, загружать и выполнять программу, можно просто написать скрипт Scheme:

 
#! /usr/bin/mixguile -s
!#
;;; runprimes: выполняет программу primes.mix

;; загрузить файл, который вы хотите запустить
(mix-load "../samples/primes")
;; выполнить его
(mix-run)
;; вывести содержимое регистров
(mix-pall)
;; ...

Просто сохраните это скрипт в файле, скажем, `runtest', сделайте его исполняемым (chmod +x runtest) и запустите его из оболочки Unix:

 
$ ./runtest
Program loaded. Start address: 3000
Running ...
... done
Elapsed time: 190908 /Total program time: 190908 (Total uptime: 190908)
rA: + 30 30 30 30 30 (0511305630)
rX: + 30 30 32 32 39 (0511313959)
rJ: + 47 18 (3026)
rI1: + 00 00 (0000)     rI2: + 55 51 (3571)     
rI3: + 00 19 (0019)     rI4: + 31 51 (2035)     
rI5: + 00 00 (0000)     rI6: + 00 00 (0000)     
Overflow: F
Cmp: L
$

Заметьте, что это гораздо более гибкий способ, чем неинтерактивный запуск программ с помощью mixvm (see section 3.3.1 Неинтерактивный режим), поскольку в скрипте Scheme вы можете использовать любое сочетание команд (а не только выполнение программы и просмотр регистров). Дополнительные параметры командной строки mixguile см. в 8.1 Вызов mixguile.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.5 Использование Scheme в mixvm и gmixvm

В предыдущем разделе (see section 3.4 Использование mixguile) мы рассмотрели возможности использования Scheme для управления виртуальной машиной MIX и расширения набора команд mixvm и gmixvm, предлагаемые оболочкой Guile mixguile. Эти возможности не ограничены оболочкой mixguile. На самом деле, и mixvm, и gmixvm включают встроенный интерпретатор Guile и могут вычислять выражения Scheme. Чтобы вычислить выражение из одной строки в приглашении mixvm или gmixvm, просто введите его и нажмите клавишу ввода (анализатор команд распознает, что это выражение Scheme, поскольку оно заключено в скобки, и передаст его интерпретатору Guile). Пример сеанса работы с использованием выражений Scheme:

 
MIX > load hello
Program loaded. Start address: 3000
MIX > (define a (mix-loc))
MIX > run
Running ...
MIXAL HELLO WORLD                                                     
... done
Elapsed time: 11 /Total program time: 11 (Total uptime: 11)
MIX > (mix-pmem a)
3000: + 46 58 00 19 37 (0786957541)
MIX > (mix-pmem (mix-loc))
3002: + 14 09 27 01 13 (0237350989)
MIX >

Вы можете также загрузить и выполнить файл командой scmf:

 
MIX> scmf /path/to/file/file.scm

Поэтому при работе в mixvm и gmixvm в вашем распоряжении находятся все описанные выше возможности mixguile (новые функции, определения новых команд, ловушки...). Другими словами, эти программы можно расширять с помощью Scheme. Примеры этого см. в 3.4 Использование mixguile.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated on June, 9 2003 using texi2html