| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
Данный текст - часть разработок группы SpellMasters.Мы надеемся,что кажущаяся
абстрактность этой статьи не отпугнет читателя, и полученные результаты
помогут кому-нибудь в его экспериментах с написанием компилятора
(интерпретатора, транслятора), разработке и создании виртуальных машин. Мы НЕ
БУДЕМ рассказывать о том, КАК написать все это, но мы покажем возможные
подводные камни и варианты решений возникающих проблем. Нами планируется
написать несколько подобных статей, все отклики мы ждем как на ящик журнала
([email protected]), так и на наши адреса (указаны в конце статьи).
SpellMasters.
Представим что у нас есть следующий код:
var a,b:integer; //integer- 4 байта
c,d:double; //double - 8 байт
begin
a=1;
b=3;
c=a-b;
d=b-d;
end.
Рассмотрим процесс компиляции этого кода:
I) Встречаем объявление переменной (ключевое слово var)
Создаем таблицу переменных по алгоритму:
а. Устанавливаем текущей переменной первую.
б. Берется имя текущей переменной.
в. Ищем это имя в таблице переменных.
г. Если имя найдено то выдаем сообщение об ошибке "Multiple Declaration for
<имя переменной>" и останавливаемся.
д. Если имя не найдено то заносим его в первую чистую строку таблицы.
(Здесь же определяется ее размер и адрес в статической памяти)
е. Берем в качестве текущей переменной следующую переменную (если таковой нет
то алгоритм завершает работу)и переходим к шагу б.
Таким образом получаем следующую таблицу переменных:
--------------------------------------------------
| имя | размер | адрес в статической памяти |
|--------------------------------------------------|
|a | 4 | 0 |
|b | 4 | 4 |
|c | 8 | 8 |
|d | 8 | 16 |
--------------------------------------------------
II) Разбор основного кода:
/*
Обозначим операции след образом:
(периведение типов не учитывается)
subra код регистра, адрес вычитаемого - операция вычитания с указанием кода регистра и адреса вычитаемого
(SUB from <R>egister <A>ddres)
movra код регистра,адрес источника - перемещение числа из источника в региcтр с указанием адреса
источника (MOV to <R>egister from <A>ddres)
movar адрес приемника, код регистра - перемещение числа из регитра в приемник
(MOV to <A>ddres from <R>egister)
movac адрес приемника, константа - перемещение константы в приемник
(MOV to <A>ddres <C>onst)
*/
Сначала надо все перевести в префиксную форму
получаем код:
=(a,1)
=(b,3)
=(c,-(a,b))
=(d,-(b,d))
Далее начинаем разбор.
Когда встречаем операцию то пишем в выходной файл ее код.
Когда встречаем имя переменной то ищем есть ли она в таблице. Если нет, то
выдаем сообщение об ошибке "Undefined symbol <имя переменной>", если есть, то
пишем в выходной файл ее адрес (здесь же проверяем сколько операндов у текущей
операции)
таким образом получаем код:
movac 0,1 // a=1
movac 4,3 // b=3
movra AX,0 // в AX помещаем a
subra AX,4 // a-b в Ax
movar 8,AX // c=AX (c=a-b)
movra AX,4 // в AX помещаем b
subra AX,16 // b-d в AX
movar 16,AX // d=AX (d=b-d)
А вот как распределена статическая память
байты\биты 01234567
--------
0 | |
1 | |- переменная a - 4 байта
2 | |
3 |________|
4 | |
5 | |- переменная b - 4 байта
6 | |
7 |________|
8 | |
9 | |
10 | |
11 | |- переменная с - 8 байт
12 | |
13 | |
14 | |
15 |________|
16 | |
17 | |
18 | |
19 | |- переменная d - 8 баит
20 | |
21 | |
22 | |
23 |________|
24 | |
25 | |- свободная память (динамическая память, она же куча)
.
.
.
На этом пока все.
Eternal Shield ([email protected])
Gamma ([email protected])
G3nius ([email protected])
|
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |