Категории
Самые читаемые книги
ЧитаемОнлайн » Компьютеры и Интернет » Программирование » Давайте создадим компилятор! - Джек Креншоу

Давайте создадим компилятор! - Джек Креншоу

Читать онлайн Давайте создадим компилятор! - Джек Креншоу

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 36 37 38 39 40 41 42 43 44 ... 62
Перейти на страницу:

Но исправить это невероятно просто. Все, что нам нужно – сделать SkipComment рекурсивной:

{–}

{ Skip A Comment Field }

procedure SkipComment;

begin

while Look <> '}' do begin

GetChar;

if Look = '{' then SkipComment;

end;

GetChar;

end;

{–}

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

Многосимвольные разделители

Все это хорошо для случаев, когда комментарии ограничены одиночными символами, но как быть с такими случаями как C или стандартный Pascal, где требуются два символа? Хорошо, принцип все еще тот же самый, но мы должны совсем немного изменить наш подход. Я уверен, что вы не удивитесь узнав, что это более сложный случай.

Для многосимвольной ситуации проще всего перехватывать левый ограничитель в GetChar. Мы можем «токенизировать» его прямо здесь, заменяя его одиночным символом.

Давайте условимся, что мы используем ограничители C '/*' и '*/'. Сначала мы должны возвратиться к методу 'GetCharX'. В еще одной копии вашего компилятора переименуйте GetChar в GetCharX и затем введите следующую новую процедуру GetChar:

{–}

{ Read New Character. Intercept '/*' }

procedure GetChar;

begin

if TempChar <> ' ' then begin

Look := TempChar;

TempChar := ' ';

end

else begin

GetCharX;

if Look = '/' then begin

Read(TempChar);

if TempChar = '*' then begin

Look := '{';

TempChar := ' ';

end;

end;

end;

end;

{–}

Как вы можете видеть эта процедура перехватывает каждое появление '/'. Затем она исследует следующий символ в потоке. Если это символ '*', то мы нашли начало комментария и GetChar возвратит его односимвольный заменитель. (Для простоты я использую тот же самый символ '{' как я делал для Паскаля. Если бы вы писали компилятор C, вы без сомнения захотели бы использовать какой-то другой символ, не используемый где-то еще в C. Выберите что вам нравится... даже $FF, что-нибудь уникальное).

Если символ, следующий за '/' не '*', тогда GetChar прячет его в новой глобальной переменной TempChar и возвращает '/'.

Обратите внимание, что вы должны объявить эту новую переменную и присвоить ей значение ' '. Мне нравится делать подобные вещи с использование конструкции «типизированная константа» в Turbo Pascal:

const TempChar: char = ' ';

Теперь нам нужна новая версия SkipComment:

{–}

{ Skip A Comment Field }

procedure SkipComment;

begin

repeat

repeat

GetCharX;

until Look = '*';

GetCharX;

until Look = '/';

GetChar;

end;

{–}

Обратите внимание на несколько вещей: прежде всего нет необходимости изменять функцию IsWhite и процедуру SkipWhite так как GetChar возвращает токен '{'. Если вы измените этот символ токена, тогда конечно вы также должны будете изменить символ в этих двух подпрограммах.

Во-вторых, заметьте, что SkipComment вызывает в своем цикле не GetChar а GetCharX. Это означает, что завершающий '/' не перехватывается и обрабатывается SkipComment. В-третьих, хотя работу выполняет процедура GetChar, мы все же можем работать с символами комментариев вложенными в строки в кавычках, вызывая GetCharX вместо GetChar пока мы находимся внутри строки. Наконец, заметьте, что мы можем снова обеспечить вложенные комментарии добавив одиночное утверждение в SkipComment, точно также как мы делали прежде.

Односторонние комментарии

Пока что я показал вам как работать с любыми видами комментариев, ограниченных слева и справа. Остались только односторонние комментарии подобные используемым в ассемблере или Ada, которые завершаются концом строки. На практике этот способ проще. Единственная процедура, которая должна быть изменена – SkipComment, которая должна теперь завершаться на символе переноса строки:

{–}

{ Skip A Comment Field }

procedure SkipComment;

begin

repeat

GetCharX;

until Look = CR;

GetChar;

end;

{–}

Если ведущий символ – одиночный, как ";" в ассемблере, тогда мы по существу все сделали. Если это двухсимвольный токен, как "–" из Ada, нам необходимо только изменить проверки в GetChar. В любом случае это более легкая проблема чем двухсторонние комментарии.

Заключение

К этому моменту у нас есть возможность работать и с комментариями и точками с запятой, так же как и с другими видами синтаксического сахара. Я показал вам несколько способов работы с каждым из них, в зависимости от желаемых соглашений. Остался единственный вопрос – какие из этих соглашений мы должны использовать в KISS/TINY?

По причинам, которые я высказал по ходу дела, я выбираю следующее:

• Точки с запятой – терминаторы а не разделители.

• Точки с запятой необязательны.

• Комментарии ограничены фигурными скобками.

• Комментарии могут быть вложенными.

Поместите код, соответствующий этим случаям в вашу копию TINY. Теперь у вас есть TINY Version 1.2.

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

Увидимся.

Процедуры

Введение

Наконец-то мы принимаемся за хорошую главу!

К этому моменту мы изучили почти все основные особенности компиляторов и синтаксического анализа. Мы узнали как транслировать арифметические выражения, булевы выражения, управляющие конструкции, объявления данных и операторы ввода/вывода. Мы определили язык TINY 1.3, который воплощает все эти возможности, и написали элементарный компилятор, который может их транслировать. Добавив файловый ввод/вывод мы могли бы действительно иметь работающий компилятор, способный производить выполнимые объектные файлы из программ, написанных на TINY. С таким компилятором мы могли бы писать простые программы, способные считывать целочисленные данные, выполнять над ними вычисления и выводить результаты.

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

Эти возможности, которые будут обсуждены в следующих двух главах, так сказать отделят мужчин от игрушек. «Настоящие» языки имеют более одного типа данных и они поддерживают вызовы процедур. Более чем любые другие, именно эти две возможности дают языку большую часть его характера и индивидуальности. Как только мы предоставим их, наши языки, TINY и его преемники, перестанут быть игрушками и получат характер настоящих языков, пригодных для серъезного программирования.

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

Последнее отклонение

Эта глава была необычайно трудной для меня. Причина не имеет никакого отношения непосредственно к теме... я знал, о чем хотел рассказать уже какое-то время, и фактически я представил большинство из этого на Software Development '89, в феврале. Больше это имело отношение к подходу. Позвольте мне объяснить.

Когда я впервые начал эту серию, я сказал вам, что мы будем использовать некоторые «приемы» чтобы упростить себе жизнь и позволить нам получить общее представление не вдаваясь слишком подробно в детали. Среди этих приемов была идея рассмотрения отдельных частей компилятора в отдельные моменты времени, т.е. выполнения экспериментов, использующих Cradle как основу. Когда, например, мы исследовали выражения мы работали только с этой частью теории компиляции. Когда мы исследовали управляющие структуры, мы писали различные программы, все еще основанные на Cradle, для выполнения этой части. Мы включили эти понятия в полный язык довольно недавно. Эти методы служили нам действительно очень хорошо и привели нас к разработке компилятора для TINY версии 1.3.

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

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

Вы долны понять, что то, чем мы здесь занимаемся немного уникально. Существует ряд статей таких как статьи по Small C от Кейна и Хендрикса, которые представляли законченный компилятор для одного языка или другого. Это другое. В этой обучающей серии вы наблюдаете за моей разработкой и реализацией и языка и компилятора в реальном режиме времени.

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

1 ... 36 37 38 39 40 41 42 43 44 ... 62
Перейти на страницу:
На этой странице вы можете бесплатно скачать Давайте создадим компилятор! - Джек Креншоу торрент бесплатно.
Комментарии
КОММЕНТАРИИ 👉
Комментарии
Татьяна
Татьяна 21.11.2024 - 19:18
Одним словом, Марк Твен!
Без носенко Сергей Михайлович
Без носенко Сергей Михайлович 25.10.2024 - 16:41
Я помню брата моего деда- Без носенко Григория Корнеевича, дядьку Фёдора т тётю Фаню. И много слышал от деда про Загранное, Танцы, Савгу...