Сообщения об ошибках транслятора С0



Министерство образования и науки Российской Федерации

 

Федеральное агенство по образованию

 

КАЗАНСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ

им. А.Н.ТУПОЛЕВА

-------------------------------------------------------------------------------------------

Д.Г. Хохлов

 

 

СИСТЕМНОЕ

ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ

 

Лабораторный практикум

 

 

КАЗАНЬ 2008

 

 


 

УДК 681.3.06               

 

Хохлов Д.Г. Системное программное обеспечение. Лабораторный практикум. - Казань: Изд-во Казанского техн. ун-та, 2008. - 71 с.

 

Описывается лабораторный практикум по методам реализации базовых структур данных и операторов языка высокого уровня на уровне машинного языка или языка ассемблера; этапы и методы трансляции типовых конструкций программы. Изложение построено на базе языков семейства С. Используется учебный транслятор С0 («Си-ноль») для подмножества языка С.

Основу практикума составляют переработанные материалы лекций и лабораторные практикумы курсов "Системное программное обеспечение" и "Системное программирование", много лет читаемых автором на кафедре автоматизированных систем обработки информации и управления Казанского государственного технического университета имени А.Н. Туполева (КГТУ-КАИ).

Для студентов направления 230100 – Информатика и вычислительная техника, а также смежных направлений и других лиц, изучающих программирование. Может использоваться для самоподготовки.

 

 

Табл. - 2, Ил. - 11, Библиогр. - 27 назв.

 

 

Ó Дмитрий Григорьевич Хохлов, 2008

.
ПРЕДИСЛОВИЕ

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

Реальные системные программы (трансляторы, операционные системы и др.) очень громоздки и сложны для детального изуче­ния. К тому же их исходные тексты малодоступны. Один из путей решения данной проблемы - создание программного обеспечения для учебных целей.

По этому принципу построен данный практикум. В приложении к практикуму приводится C-программа учебного компилятора C0 – «Си-ноль», переводящего программу с подмножества языка С на язык ассемблера .

Учебный компилятор С0 разработан на кафедре АСОИУ КАИ до­центом Хохловым Д.Г.  для обучения студентов эле­ментарным методам трансляции и описан в учебном пособии [1]. Целью изучения системы программирования С0 является также зак­репление знаний языка С и языка ассемблера или первоначальное знакомство с ними.

В лабораторном практикуме студенты составляют и отлажива­ют C0-программу, изучают ее объектный код на языке ассемблера и процесс его получения компилятором, реализуют простые расши­рения языка и компилятора C0.

Основу практикума составляют переработанные лабораторные практикумы и материалы лекций курсов "Системное программное обеспечение" и "Системное программирование", много лет читаемых автором на кафедре автоматизированных систем обработки информации и управления Казанского государственного технического университета имени А.Н. Туполева (КГТУ-КАИ).

Для студентов направления 230100 – Информатика и вычислительная техника, а также смежных направлений и других лиц, изучающих программирование. Может использоваться для самоподготовки.


Лабораторная работа № 1

Входной язык и объектный код транслятора C0

Учебный транслятор С0 разработан на кафедре АСОИУ КАИ доцентом Хохловым Д.Г. для обучения студентов элементарным методам трансляции.

Цель работы - изучение задачи, решаемой транслятором C0: структуры и формы его входных и выходных данных.

Входной язык С0

Язык С0 является очень упрощенным вариантом языка С. Знакомство с новым языком удобнее всего начинать с примера программы.

Пример 1. Программа "Коды символов". Задача: для каждого вводимого символа выводить на экран его десятичный и восьмеричный коды, перед которыми выводить знак равенства. Закончить работу при нажатии клавиши Esc или Ctrl-Break.

Если после запуска программы набирать, например, текст: " язык С0",

то на экране появится строка:

=32=4я=239=357з=167=247ы=235=353к=170=252 =32=40C=67=1030=48=60

При нажатии клавиши <Esc>, с кодом 27, программа прекращает работу.

Программа 1. С0-программа "Коды символов"

Можно написать и короче,

kod (x,baza)                 в стиле, характерном для С:

{ int y;

if ((y = x / baza) != 0)   kod (x,baza)

kod (y,baza);           { if (x >= baza)

putchar (x % baza + 48);       kod (x/baza, baza);

}                         putchar (x % baza + 48);

int c;                     }

main ()                 int c;

{ c=0;                 main ()

while (c != 27)      { while ((c=getchar())!=27)

{ c = getchar ();       { putchar (61);

putchar (61);          kod (c,10);

kod (c,10);                putchar (61);

 putchar (61);           kod (c,8);

kod (c,8);            }

}                    }

}

Пояснения к программе "Коды символов" . Рекурсивная функция kod выводит на экран (точнее, в стандартный выходной файл) целочисленное значение х в системе счисления с заданным основанием baza (2 £ baza £ 10).

Оператор putchar (x % baza + 48); выводит на экран младшую цифру числа x, имеющую значение x%baza (% - остаток от деления). Если x содержит более одной цифры, то перед этим с помощью рекурсивного вызова kod(x/baza,baza); выводится значение старших разрядов числа x, равное x/baza.

Например, если x=932 и baza=10, то сначала рекурсивный вызов функции kod выводит старшие разряды числа x, равные x/10=93, затем выводится младшая цифра x, равная x%10=2.

Переменная y в функции kod используется для демонстрационных целей, без нее можно обойтись. В правом столбце и аналогичной С0-программе функции putn в библиотеке языка С0 (приложение1) показано более короткое решение.

Число 61 используется в этой программе как код символа '=', 48 - код цифры ноль '0'.

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

Параметры функций могут быть только входными (ввиду отсутствия операции получения адреса). Поэтому результат работы функции передается только в виде ее значения или присваивается глобальной переменной. В отличие от языка С, параметры не описываются (в языке С нет и стандартной функции putn).

Имеются следующие операторы: оператор-выражение, составной оператор, сокращенный условный оператор (if без else), цикл с предусловием, оператор возврата.

Оператор-выражение представляет собой выражение, заканчивающееся точкой с запятой:

выражение;

Условный оператор используется для организации ветвлений. В языке С0 разрешен только сокращенный условный оператор:

if (выражение) оператор

Для организации повторяющихся действий используется цикл с предусловием:

while (выражение) оператор

Выражение в операторах if и while считается истинным, если оно не равно нулю. Внутри операторов if и while разрешено использовать только один оператор. Если в этом месте требуется написать последовательность из нескольких операторов, используется составной оператор, т. е. последовательность операторов, заключенная в операторные скобки { и }:

{ оператор_1 ... оператор_n }

Эти скобки превращают последовательность операторов в один составной оператор. В некоторых языках для этой цели используются служебные слова begin и end.

Оператор возврата завершает выполнение подпрограммы (функции) и задает значение функции (если она обладает значением):

return [выражение];

В выражениях допускаются:

· арифметические операции: +, -, *, /, %,

· сравнения: ==, !=, <, >, <=, >=,

· присваивание =,

· скобки ().

Отсутствующие в языке C0 логические операции И и ИЛИ можно заменить арифметическим умножением и сложением, соответственно.

Примечания.

1. Cлужебные слова int, if, while, return пишутся строчными буквами.

2. Длина имени не ограничена, но учитываются не более 8 символов.

3. Отсутствующий оператор return в конце описания функции вставляется автоматически.

Грамматика языка С0.

программа                         ::= {oписание-переменных | описание-функции}...

описание-переменных ::= int имя [,имя]...;

описание-функции   ::= имя ( [имя[,имя]...] )

                                      { [описание-переменных]...[оператор]... }

оператор ::= [выражение]; | { [оператор]... } |

                    if (выражение) оператор | return [выражение];

                   while (выражение) оператор

выражение ::= терм [{ + | - | * | / | % | < | > | <= |>= | == | != | = } терм]...

терм               ::= число | имя | имя ([выражение[,выражение]...]) |

                   - терм | (выражение)

имя      ::= буква [буква|цифра]...

число     ::= цифра ...

буква     ::= A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|

                   a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z

цифра    ::= 0|1|2|3|4|5|6|7|8|9

Эта грамматика описывает не только синтаксис, но и лексику языка С0. К лексике относятся четыре последних правила.

Стандартные функции языка С0 . Библиотека std.asm (приложение 1) присоединяется к программе на этапе ее ассемблирования и содержит следующие стандартные функции (все они кроме putn имеются и в языке С).

getchar () Вводит с клавиатуры символ с отображением на экране и выдает в качестве значения его код. Реагирует на Ctrl-Break.

getch()   Вводит с клавиатуры символ без отображения на экране и выдает в качестве значения его код. Реагирует на Ctrl-Break.

putchar (x) Выводит на экран символ с кодом х. Не имеет значения.

putn (x) Выводит на экран целoе значение х. Не имеет значения.

 

Использование компилятора С0

 Для трансляции и выполнения С0-программы используется следующая последовательность команд операционной системы:

c0.exe                                                         трансляция

masm p.exe     (или  tasm p.exe)           ассемблирование

tlink p.obj                                                  компоновка

p.exe [<входной_файл] [>выходной_файл] выполнение

Компилятор С0 вводит исходную программу из файла p.с0, помещая результат трансляции на языке ассемблера в файл p.asm. Затем производятся ассемблирование, компоновка (редактирование связей) и выполнение программы. Объектный и исполняемый модули транслируемой программы обычно получаются в файлах p.obj и p.exe.

    Для ассемблирования необходима библиотека стандартных функций - файл std.asm - который присоединяется псевдокомандой INCLUDE к транслируемой программе на этапе ее ассемблирования. Эта команда вставляется транслятором С0. Используется ассемблер masm.exe или tasm.exe.

Транслятор C0 переносит строки исходной программы в получаемую из нее ассемблерную программу в виде строк комментария, начинающихся символом ";". За каждой такой строкой размещается объектный код, т.е. команды, полученные в результате ее трансляции.

Сообщения об ошибках в исходной программе также вставляются транслятором С0 в объектный код в виде строк комментария, содержащего номер (тип) ошибки и символ "^", указывающий на текущую позицию предшествующей исходной строки в момент обнаружения ошибки. В конце объектной программы вставляется итоговое сообщение о количестве обнаруженных ошибок, дублируемое на экране.

Ассемблер при запуске запрашивает имена выходных файлов для объектной программы, листинга (протокола) трансляции и таблицы перекрестных ссылок. На эти запросы можно отвечать клавишей <Enter>. 

Если же ассемблер выдаст предупреждения (Warning) или сообщения об ошибках (Error), необходимо повторить ассемблирование, указав какое-либо имя файла для листинга трансляции, например, p.lst. По содержимому этого файла можно определить, в каких строках ассемблерной программы и соответствующих им строках С0-программы обнаружены ошибки.

Обычно эти ошибки вызваны использованием имен несуществующих функций и переменных.

Сообщения об ошибках транслятора С0

1. Число больше 32767

2. Слишком много имен

3. Тpебуется int или имя функции

4. Многокpатно описанное имя

5. Тpебуется '('

6. Тpебуется имя

7. Тpебуется ')'

8. Не удалось откpыть входной или выходной файл

9. Недопустимый символ

 10. Тpебуется ','

 11. Тpебуется '{'

 12. Тpебуется ';'

 13. Тpебуется '}'

 14. Имя не описано

 15. Невеpный огpаничитель в выpажении

 16. Невеpный тип опеpанда выpажения

 17. Несоответствующие типы опеpандов

 18. Невеpный тип левого опеpанда пpисваивания

 19. Нет имени функции

 20. Невеpный вызов функции

 21. Деление на ноль

 

Язык ассемблера IBM PC

Рассмотрим минимальный набор средств языка ассемблера IBM PC, достаточный для понимания работы транслятора С0 (подробнее см. [1]).

В языке ассемблера строчные и заглавные буквы считаются одинаковыми (в данной книге команды для наглядности обычно выделяются заглавными буквами). Символ подчеркивания "_" рассматривается как буква. Используется строчный формат команд: каждая команда пишется с начала новой строки. Команда в общем случае состоит из четырех частей (полей): метки, названия, операндов и комментария, и имеет вид:

метка     название операнд,...,операнд ; комментарий

Поля обычно не содержат пробелов и разделяются пробелами. Любое поле может отсутствовать. Название команды состоит из одной или нескольких букв и определяет ее смысл. Операнды уточняют смысл команды и присутствуют только тогда, когда есть название. Они разделяются запятыми. Метка - это имя, смысл которого зависит от вида команды.

Любой текст от точки с запятой до конца строки рассматривается как комментарий, в частности, вся строка может состоять только из комментария.

Имеются три типа команд: машинная команда, псевдокоманда и макрокоманда (здесь не рассматривается).

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

Машинная команда имеет не более двух операндов. Обычно первый из них служит приемником информации (сокращенно - прм), а второй - ее источником (ист).

Например, команда вида MOV прм,ист обозначает пересылку (move - переслать) из источника в приемник: ист --> прм.

Команда ADD прм,ист обозначает сложение (add - прибавить) приемника с источником и запись суммы в приемник:

прм + ист --> прм

Присваивание A = B + 9 выполняется следующими командами с использованием двухбайтового регистра AX:

M1: MOV AX,B           ; B      -->     AX

ADD AX,9           ; AX+9 -->    AX

MOV A,AX          ; AX -->     A

Операнды приемник и источник могут быть адресом переменной (области памяти), например A, B, или названием регистра, например, AX; источник может быть также непосредственным операндом - числом, участвующим в операции, как например, в команде ADD AX,9.

Адрес переменной (области памяти) может также задаваться в виде смещение[BP], где смещение обозначает целое число, например 4[BP] обозначает адрес, равный содержимому регистра BP, сложенному с заданным смещением 4: BP+4.

Перед машинной командой можно поставить (в том числе в отдельной строке) метку с двоеточием, как M1 в команде MOV приведенного примера. Эта метка обозначает адрес данной команды и используется для переходов к ней из других мест программы командами перехода, например: JMP M1.

Псевдокоманда (директива) не обозначает какую-либо операцию при выполнении программы. Это - указание ассемблеру, влияющее на трансляцию программы.  Метки перед псевдокомандами не содержат двоеточия.

Псевдокоманда DW (define word - определить слово) вида

метка DW ?

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

Например, переменные A и B в приведенном выше примере можно было разместить в памяти псевдокомандами

A DW ?

B DW ?

Следующая псевдокоманда создает область из 100 слов:

метка DW 100 DUP (?)

Запись 100 DUP (?) обозначает 100-кратное повторение операнда (?).

Псевдокоманда ASSUME (предполагать) указывает ассемблеру имена сегментов команд, стека и данных программы (программе необходимо поместить их адреса в регистры сегментов CS, SS, DS):

 

ASSUME CS:сегмент-команд, SS:сегмент-стека, DS:сегмент-данных

 

Используются также следующие псевдокоманды.

INCLUDE имя-файла      ; вставить заданный файл

имя-сегмента  SEGMENT                         ; начало сегмента

имя-сегмента  ENDS                                 ; конец сегмента

имя-процедуры PROC    FAR                ; начало процедуры (дальней)

имя-процедуры ENDP                                 ; конец процедуры

END      точка-входа             ; конец программы

 

В архитектуре процессора IBM PC предусмотрены двухбайтовые регистры: AX, BX, DX - для выполнения операций; BP – база для вычисления адреса; SP - указатель стека (адрес последнего записанного байта); CS, SS, DS - для адресов сегментов. AH - старший байт регистра AX; DL - младший байт регистра DX. Регистры флагов – однобитовые регистры, содержащие характеристики результата команды: знак, равенство/неравенство нулю, наличие переполнения и т.п.

Машинные команды

Пересылки:

MOV     прм, ист          ; ист    --> прм

LEA       регистр, адрес ; адрес --> регистр

РОР       регистр           ; стек ==>  регистр (вытолкнуть)

РUSH              регистр           ; регистр ==> стек (втолкнуть)

 

Операции:

ADD      прм, ист ; сложение                прм + ист --> прм

SUB       прм, ист ; вычитание              прм - ист --> прм

NEG      прм    ; изменение знака              -прм       --> прм

IMUL     ист         ; умножение     AX * ист --> (DX,AX)

CWD                        ; слово - в двойное слово AX --> (DX,AX)

IDIV      ист     ; деление (DX,AX) / ист --> AX частное

(DX,AX) % ист --> DX остаток

TEST     AX,AX  ; проверка значения AX и получение флагов

CMP      AX,BX  ; сравнение AX с BX и получение флагов

Переходы (выполняются по значению флагов):

 

JNZ        метка   ; если не равно 0 (после команды TEST)

JE          метка   ; если =            (после команды CMP)

JNE       метка   ; если не =       (после команды CMP)

JL       метка   ; если <            (после команды CMP)

JG         метка   ; если >            (после команды CMP)

JLE      метка   ; если <=          (после команды CMP)

JGE               метка   ; если >=          (после команды CMP)

JMP     метка   ; безусловный переход

CALL   имя-проц ; с возвратом; адрес-возврата ==> стек

RET       n   ; убрать из стека адреса возврата и n байт; возврат

Объектный код компилятора C0

 

Объектный код, т. е. результат трансляции С0-программы, представляет собой программу на языке ассемблера IBM PC, состоящую из сегмента кода (команд), сегмента данных и сегмента стека. Сегмент данных содержит области для хранения значений глобальных переменных С0-программы, создаваемые псевдокомандами вида:

_имя DW ?

Локальные переменные и параметры каждой функции С0-программы хранятся в сегменте стека в виде кадра, структура которого показана на рис. 1. Адрес кадра находится в регистре ВР. На рис. 2 показан кадр стека функции kod.

В отличие от глобальных переменных, адреса которых в ассемблерной программе задаются их именами, адреса локальных переменных задаются с помощью смещений относительно регистра ВР в виде:

смещeние [BP].

В этом случае в объектной программе "Коды символов" адресом переменной с является ее имя, а адрес переменной (параметра) x запишется как 6[ВР].

Сегмент команд состоит из процедур на языке ассемблера. Каждая процедура соответствует одной функции С0-программы и имеет такое же имя (перед ним вставляется подчеркивание). Процедуры размещены в таком же порядке, как функции С0-программы.

 

 


     Локальная переменная k

 


-4                   . . .

 


-2   Локальная переменная 1

 


BP    Адрес предыдущего кадра                   -2   Значение y

 


2    Адрес возврата                      BP 0   Адрес предыд. кадра

 


4       Параметр n                               2   Адрес возврата

 


. . .                                       4   Значение baza

                            

  Параметр 1                                           6   Значение x

 

     
 


      Рис. 1. Кадр стека                               Рис. 2. Кадр стека

функции kod

Пример 2. Структура объектной программы для примера 1:

ASSUME CS:KOM_,SS:STEK_,DS:DAN_

;        Сегмент стека

STEK_ SEGMENT STACK

DW   10000 DUP (?) ; Область памяти для стека

DNOST_ DW   ?

STEK_ ENDS

;        Сегмент команд

KOM_ SEGMENT

_kod PROC     ;

. . .          ; Объектный код функции kod

_kod ENDP          ;

_main PROC          ;

. . .          ; Объектный код функции main

_main ENDP        ;

INCLUDE std.asm ; Процедуры библиотечных функций

KOM_ ENDS

;        Сегмент данных

DAN_ SEGMENT

_c   DW ? ;Область для значения глобальной переменной c

DAN_ ENDS

END _main    ; Адрес точки входа в программу

;Компилятоp С0 от 10/04/08;

;колич. ошибок 0

Структура обычной процедуры (не main):

_имя PROC

; Пролог процедуры (создание кадра стека)

 PUSH BP                  ; Сохранение регистра BP

 MOV BP,SP               ; Адрес кадра стека

[ SUB SP,2*кол.лок.переменных ;Создание лок-х пер-х]

; Объектный код операторов функции

. . .

; Объектный код оператора return ; обычной функции (не main)

[ ADD SP,2*кол.лок.перем-х ;Удаление локальных пер-х ]

 POP BP          ; Восстановление регистра BP

 RET 2*кол.параметров ;Удаление параметров и возврат

_имя ENDP

Команда PUSH сохраняет значение регистра BP в стеке, MOV пересылает адрес кадра стека в регистр BP, SUB выделяет в кадре стека место для локальных переменных.

Команда ADD удаляет из стека локальные переменные, РОР восстанавливает в регистре BP адрес кадра вызывающей функции, RET удаляет из стека параметры функции и выполняет возврат.

Для функции main вместо команды RET используются команды:

 

MOV AH,4CH

INT 21H

 

Они обеспечивает выход в операционную систему с помощью функции 4СН прерывания номер 21H (типа 21Н).

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

Структура процедуры main:

_main PROC FAR

 MOV AX,DAN_ ;Адрес сегмента данных--> регистр DS

 MOV DS,AX ;

 MOV AX,STEK_ ;Адрес сегмента стека --> регистр SS

 MOV SS,AX ;

 LEA SP,DNOST_ ;Адрес дна стека

; Пролог процедуры (создание кадра стека)

   . . .

; Объектный код операторов функции main

   . . .

; Объектный код оператора return; функции main

[ ADD SP,2*кол.лок.перем-х ;Удаление локальных пер-х ]

 POP BP        ; Восстановление регистра BP

 MOV AH,4CH          ; Выход в MS DOS

 INT 21H             ;

_main ENDP

 

Обозначим объектный код некоторой конструкции С0-программы как

объект_код (конструкция).

Ниже в обобщенном виде приведена форма объектного кода разных видов операторов языка С0, которые записаны перед своим объектным кодом в виде комментария языка ассемблера (как в выходном файле компилятора С0).

; выражение;

объект_код (выражение)

; { оператор_1; оператор_2; ... оператор_n; }

объект_код (оператор_1)

объект_код (оператор_2)

. . .

объект_код (оператор_n)

; return выражение;

объект_код (выражение)

ADD    SP,2*кол.лок.переменных

POP    BP

RET    2*кол.параметров

; if (выражение) оператор

объект_код (выражение)

РОР AX          ; значение выражения

TEST AX,AX          ; проверка значения

JNZ CC_i             ; истина (не нуль)

JMP CC_i+1        ; обход оператора

СС_i:

объект_код (оператор)

СС_i+1:

; while (выражение) оператор

СС_i:

объект_код (выражение)

РОР AX         ;значение выражения

TEST AX,AX         ;проверка значения

JNZ CC_i+1        ;истина

JMP CC_i+2        ;выход из цикла

CC_i+1:

объект_код (оператор)   ;тело цикла

JMP CС_i             ;переход на начало цикла

CC_i+2:

Для организации ветвлений и циклов компилятор вставляет в объектную программу метки вида СС_1, СС_2и т. д., которые здесь обозначены как СС_i. Чтобы вставляемые транслятором метки не могли совпасть с именами функций или глобальных переменных С0-программы, транслятор добавляет к меткам символ подчеркивания “_”, который в языке ассемблера используется наравне с буквами. Этот прием называется декорированием имен. Имена функций и глобальных переменных, в свою очередь, приходится декорировать, чтобы они не совпали с именами сегментов, регистров или команд языка ассемблера.

В объектном коде операторов if и while пару соседних команд перехода нельзя заменить одной командой с противоположным условием, так как в IBM PC условный переход возможен лишь на расстояние не более 128 байтов. Если объект_код (оператор) занимает более 128 байт, возникнет ошибка. В отличие от условного перехода, безусловный переход возможен на любое расстояние.

Объектный код выражения состоит из групп команд, реализующих операции выражения в порядке их выполнения. Результат каждой операции (в том числе значение функции) и значение выражения помещаются в регистр AX.

Если выражение заключено в скобки, например, условие в операторах if и while или выражение-параметр в вызове функции, его значение затем помещается в стек.

Выражение из одного операнда (без операций) – переменная или константа, переводится в команду вида:

MOV  AX,константа  

илиMOV  AX,адрес-переменной

 

Если операндами являются константы (числа), то операция выполняется транслятором, заменяется результатом и не появляется в объектном коде, например, объектный код выражения 8 / 2 + X совпадает с объектным кодом выражения 4 + X.

Объектный код операции состоит из следующих шагов.

1. Загрузка 2-го операнда в регистр BX (для присваивания и изменения знака вместо BX используется AX).

2. Загрузка 1-го операнда в регистр AX. (кроме присваивания и изменения знака).

3. Выполнение операции над AX и BX с записью результата в AX (остаток от деления получается в DX). Функции возвращают значение в регистре AX.

4. Если операция не является последней в выражении, то ее результат помещается в стек.

Указанный порядок загрузки операндов важен, если оба операнда являются результатами других операций и поэтому выбираются из стека (2-й операнд попадает туда позже, чем 1-й операнд, и поэтому должен выбираться в первую очередь).

Операция, операнды которой являются константами, не компилируется, а интерпретируется, т. е. выполняется транслятором, например, операторы

X=Y+2*5; и X=Y+10;    имеют одинаковый объектный код.

Объектный код 3-го шага в зависимости от операции имеет следующий вид.

Присваивание = :

 

MOV  адрес-переменной,AX

Операции сравнения ( == != < > <= >= ):

 

CMP  AX,BX

MOV  AX,1

усл-переход CC_i

SUB  AX,AX

CC_i:                       

 

Команда условного перехода вставляется в зависимости от использованной операции сравнения.

Операция:       == != <  >  <= >=

     усл-переход:   JE JNE JL JG JLE JGE

Арифметические операции:

 

+ : ADD  AX,BX    ; сложение

- : SUB  AX,BX    ; вычитание

- : NEG  AX       ; изменение знака

* : IMUL BX       ; умножение

/ или % :

CWD      ; преобразование делимого в 4 байта

IDIV BX       ; деление

Для операции %, если она последняя в выражении, добавляется команда:

MOV  AX,DX

Вызов функции        имя-функции (выражение_1, ... , выражение_n) :

 

объект_код (выражение_1) ; параметр_1 --> стек

. . .

объект_код (выражение_n) ; параметр_n --> стек

CALL имя-функции

 

Для ассемблирования необходимо наличие библиотеки стандартных функций - файла std.asm, который присоединяется командой INCLUDE к транслируемой программе на этапе ее ассемблирования (приложение 1). Эта команда вставляется компилятором С0 в конце сегмента кода.

Для наглядности результата трансляции компилятор C0 переносит строки исходной программы в получаемую из нее ассемблерную программу в виде строк комментария, начинающихся символом ";". За каждой такой строкой размещается объектный код, т.е. команды, полученные в результате ее трансляции (точнее - после ее ввода).

Сообщения об ошибках в исходной программе также вставляются компилятором С0 в объектный код в виде строк комментария, содержащего номер (тип) ошибки и символ "^", указывающий на текущую позицию предшествующей исходной строки в момент обнаружения ошибки. В конце объектной программы вставляется итоговое сообщение о количестве обнаруженных ошибок, дублируемое на экране.

Программа 2. Ниже приведена объектная программа для С0-программы  "Коды символов" (выведена в две колонки). Два последних оператора этой программы не приведены, т. к. практически совпадают с предыдущими двумя операторами и имеют аналогичный объектный код.

 

ASSUME CS:KOM_,SS:STEK_,DS:DAN_ STEK_ SEGMENT STACK      DW 100 DUP (?) DNOST_ DW ? STEK_ ENDS  ;kod (x,baza) KOM_ SEGMENT    ;{ int y; ; if ((y = x/baza)!= 0) _kod PROC PUSH BP MOV BP,SP SUB SP,2 MOV BX,4[BP] MOV AX,6[BP] CWD  IDIV BX MOV -2[BP],AX PUSH AX MOV BX,0 POP AX CMP AX,BX MOV AX,1 JNE CC_1 SUB AX,AX CC_1:      ; kod (y, baza); TEST AX,AX JNZ CC_3 JMP CC_2 CC_3:      MOV AX,-2[BP] PUSH AX MOV AX,4[BP] PUSH AX CALL _kod ; putchar (x%baza + 48); CC_2:      MOV BX,4[BP] MOV AX,6[BP] CWD  IDIV BX PUSH DX MOV BX,48 POP AX ADD AX,BX PUSH AX ;} CALL _putchar ADD SP,2 POP BP RET 4 ;int c; ;main () _kod ENDP _main PROC FAR MOV AX,DAN_ MOV DS,AX MOV AX,STEK_ MOV SS,AX ;{ c=0; LEA SP,DNOST_ PUSH BP MOV BP,SP MOV AX,0 ; while (c != 13) MOV _c,AX CC_4:      MOV BX,13 MOV AX,_c CMP AX,BX MOV AX,1 JNE CC_6 SUB AX,AX CC_6:      ; { c = getchar (); TEST AX,AX JNZ CC_7 JMP CC_5 CC_7:      CALL _getchar ; putchar (61); MOV _c,AX MOV AX,61 PUSH AX ; kod (c, 10); CALL _putchar MOV AX,_c PUSH AX MOV AX,10 PUSH AX ; } CALL _kod JMP CC_4 ;} CC_5:      POP BP MOV AH,4CH INT 21H ; _main ENDP INCLUDE std.asm KOM_ ENDS DAN_ SEGMENT    _c DW ? DAN_ ENDS  END _main ; Компилятоp С0 от 10/04/08: ; колич. ошибок 0

Порядок выполнения работы

1. Ознакомиться с теоретическим материалом.

2. Составить и отладить С0-программу для заданной препо­давателем задачи.

3. Составить отчет, включающий: условие задачи, тексты исходной и объектной программы, примеры входных данных и ре­зультатов работы программы.

4. Определить и изобразить в отчете структуру кадров сте­ка для функций объектной программы, найти в ней объектные коды отдельных операторов, разобраться в назначении каждой команды.

5. Сдать работу, ответив на вопросы преподавателя по язы­ку и использованию транслятора С0, исходной и объектной прог­раммам.

Необходимые для составления программы коды символов можно узнать с помощью приведенной в описании работы  С0-программы "Коды символов" (см. файлы kod_simv.c0,  od_simv.exe).

Задания

Составить С0-программы для решения следующих задач.

1) Подсчитать количества повторений во входном тексте сочетаний "РФ" и "РТ".

Указание: использовать переменную "символ, предшествующий текущему".

2) Вывести входной текст на экран с нумерацией строк.

3) Вывести входной текст на экран, заменяя строчные латинские буквы заглавными.

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

4) Входной текст состоит из слов, разделенных пробелами. Подсчитать количество слов и их среднюю длину.

Указание: использовать переменную "символ, предшествующий текущему".

5) Входной текст состоит из слов, разделенных пробелами. Найти максимальную длину слова.

6) Входной текст состоит из слов, разделенных пробелами. Подсчитать количество слов, начинающихся с буквы 'а'.

Указание: использовать переменную "символ, предшествующий текущему".

7) Входной текст состоит из слов, разделенных пробелами. Подсчитать количество слов, кончающихся буквой 'а'.

Указание: использовать переменную "символ, предшествующий текущему".

8) Вывести таблицу кодов символов, лежащих в диапазоне, задаваемом двумя вводимыми символами.

9) Подсчитать во входном тексте количество слов, у которых первый символ с совпадает с последним.

Указание: использовать переменную "символ, предшествующий текущему".

10) Составить функцию ввода целого числа со знаком getn(), которая пропускает пробелы и символы новой строки перед числом, читает число и выдает его значение в качестве значения функции. Пример использования этой функции: x=getn(); Поместить эту функцию в библиотеку std.asm.

Указание: использовать в качестве аналога функцию chislo() из программы вычисления выражения методом рекурсивного спуска (программа 4.1 из раздела 4.3.4 пособия [1]  или программа 7.3 из раздела 7.1 пособия [4] ).

11) Дано натуральное число N и N целых чисел. Найти сумму заданных целых чисел. Для ввода чисел использовать функцию getn() из задания 10.

12) Переписать на язык С0 программу 4.1 вычисления выражения методом рекурсивного спуска из раздела 4.3.4 учебного пособия [1].

Контрольные вопросы и упражнения

1. Как записать на языке С0 условие if (Z > 2 &&  Z < 8) ?

2. Как записать на языке С0 условие if (A==1 ||  B==6) ?

3. Что произойдет при выполнении оператора языка С0 putchar (49); ?

4. Что произойдет при выполнении оператора языка С0 putn(49);  ?

5. Написать на языке ассемблера объектный код оператора языка С0

     while (100 > a) a = 6 + a;       где a - параметр.

6. Написать на языке ассемблера объектный код оператора языка С0

     if (f(c) < 3) d = 20;            где f - функция; c, d – параметры.

7. Написать на языке ассемблера объектный код оператора языка С0

     return a * (b > 4);             где a, b - локальные переменные.

8. Написать на языке ассемблера объектный код оператора языка С0

     p(a, 2 + b % 8); где p - функция; a, b - глобальные переменные.


Дата добавления: 2019-02-12; просмотров: 378; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!