Давайте создадим компилятор!
Добавить в закладки К обложке
- Введение - Страница 1
- Основа - Страница 3
- Синтаксический анализ выражений - Страница 4
- Одиночные цифры - Страница 5
- Выражения с двумя цифрами - Страница 6
- Общая форма выражения - Страница 8
- Использование стека - Страница 9
- Умножение и деление - Страница 10
- Круглые скобки - Страница 11
- Унарный минус - Страница 12
- Слово об оптимизации - Страница 13
- Снова выражения - Страница 15
- Переменные - Страница 16
- Функции - Страница 17
- Подробнее об обработке ошибок - Страница 18
- Присваивание - Страница 19
- Многосимвольные токены - Страница 20
- Пробелы - Страница 21
- Интерпретаторы - Страница 23
- Интерпретатор - Страница 25
- Немного философии - Страница 27
- Управляющие конструкции - Страница 30
- План - Страница 31
- Немного основ - Страница 32
- Оператор IF - Страница 34
- Оператор WHILE - Страница 35
- Оператор LOOP - Страница 36
- Цикл FOR - Страница 37
- Оператор DO - Страница 38
- Оператор BREAK - Страница 39
- Заключение - Страница 41
- Булевы выражения - Страница 43
- План - Страница 44
- Грамматика - Страница 45
- Операторы отношений - Страница 46
- Исправление грамматики - Страница 47
- Синтаксический анализатор - Страница 48
- Объединение с управляющими конструкциями - Страница 52
- Добавление присваиваний - Страница 53
- Лексический анализ - Страница 54
- Лексический анализ - Страница 55
- Конечные автоматы и альтернативы - Страница 56
- Эксперименты по сканированию - Страница 57
- Пробел - Страница 58
- Конечные автоматы - Страница 59
- Новые строки - Страница 60
- Операторы - Страница 61
- Списки, запятые и командные строки - Страница 62
- Становится интересней - Страница 63
- Возвращение символа - Страница 65
- Распределенные сканеры против централизованных - Страница 66
- Объединение сканера и парсера - Страница 67
- Заключение - Страница 72
- Немного философии - Страница 73
- Дорога домой - Страница 74
- Почему это так просто? - Страница 76
- Здесь нет ничего сложного! - Страница 77
- Заключение - Страница 80
- Вид сверху - Страница 81
- Верхний уровень - Страница 82
- Структура Паскаля - Страница 83
- Расширение - Страница 84
- Объявления - Страница 85
- Структура Си - Страница 87
- Представление «TINY» - Страница 90
- Подготовка - Страница 91
- Объявления - Страница 93
- Объявления и идентификаторы - Страница 94
- Инициализаторы - Страница 95
- Таблица идентификаторов - Страница 96
- Выполнимые утверждения - Страница 97
- Булева логика - Страница 99
- Управляющие структуры - Страница 101
- Лексический анализ - Страница 103
- Многосимвольные имена переменных - Страница 105
- Снова операторы отношений - Страница 106
- Ввод/Вывод - Страница 107
- Заключение - Страница 108
- Пересмотр лексического анализа - Страница 113
- Предпосылка - Страница 114
- Проблема - Страница 115
- Решение - Страница 116
- Исправление компилятора - Страница 118
- Заключение - Страница 119
- Разное - Страница 124
- Точки с запятой - Страница 125
- Синтаксический сахар - Страница 126
- Работа с точками с запятой - Страница 127
- Компромисс - Страница 128
- Комментарии - Страница 129
- Односимвольные разделители - Страница 130
- Многосимвольные разделители - Страница 132
- Односторонние комментарии - Страница 133
- Заключение - Страница 134
- Процедуры - Страница 135
- Последнее отклонение - Страница 136
- Основы - Страница 137
- Основа для экспериментов - Страница 138
- Объявление процедуры - Страница 140
- Вызов процедуры - Страница 142
- Передача параметров - Страница 143
- Семантика параметров - Страница 145
- Передача по значению - Страница 147
- Что неправильно? - Страница 149
- Передача по ссылке - Страница 151
- Локальные переменные - Страница 152
- Заключение - Страница 154
- Типы - Страница 155
- Что будет дальше? - Страница 156
- Таблица идентификаторов - Страница 157
- Добавление записей - Страница 159
- Распределение памяти - Страница 160
- Объявление типов - Страница 161
- Присваивания - Страница 162
- Трусливый выход - Страница 164
- Более приемлемое решение - Страница 165
- Литеральные аргументы - Страница 167
- Аддитивные выражения - Страница 168
- Почему так много процедур? - Страница 170
- Мультипликативные выражения - Страница 171
- Умножение - Страница 172
- Деление - Страница 173
- Завершение - Страница 174
- Приводить или не приводить - Страница 175
- Заключение - Страница 177
- Назад в будущее - Страница 178
- Новое начало, старое направление - Страница 179
- Начинаем заново? - Страница 181
- Модуль INPUT - Страница 182
- Модуль OUTPUT - Страница 184
- Модуль ERROR - Страница 185
- Лексический и синтаксический анализ - Страница 186
- Модуль SCANNER - Страница 188
- Решения, решения - Страница 189
- Синтаксический анализ - Страница 191
- Ссылки - Страница 193
- Конструирование модулей - Страница 194
- Совсем как классический? - Страница 196
- Расширение синтаксического анализатора - Страница 198
- Термы и выражения - Страница 200
- Присваивания - Страница 202
- Булева алгебра - Страница 203
- Булево «AND» - Страница 205
Новые строки
Продвигаясь прямо вперед, давайте модифицируем наш сканер для поддержки более чем одной строки. Как я упомянул последний раз, наиболее простой способ сделать это – просто обработать символы новой строки, возврат каретки и перевод строки, как незаполненное пространство. Фактически это способ, используемый подпрограммой iswhite из стандартной библиотеки C. Прежде мы не этого делали. Я хотел бы сделать это теперь, чтобы вы могли почувствовать результат.
Чтобы сделать это просто измените единственную выполнимую строку в IsWhite:
IsWhite := c in [' ', TAB, CR, LF];
Мы должны дать основной программы новое условие останова, так как она никогда не увидит CR. Давайте просто используем:
until Token = '.';
ОК, откомпилируйте эту программу и запустите ее. Попробуйте пару строк, завершаемых точкой. Я использовал:
now is the time
for all good men.
Эй, что случилось? Когда я набрал это, я не получил последний токен, точку. Программа не остановилась. Более того, когда я нажал клавишу 'enter' несколько раз, я все равно не получил точку.
Если вы все еще не можете выбраться из вашей программы, вы обнаружите, что набор точки в новой строке прервет ее.
Что здесь происходит? Ответ в том, что мы зависаем в SkipWhite. Короткий осмотр этой подпрограммы покажет, что пока мы печатаем пустые строки, мы просто продолжаем выполнение цикла. После того, как SkipWhite встречает LF, он пытается выполнить GetChar. Но так как входной буфер теперь пуст, оператор чтения в GetChar настаивает на наличии другой строки. Процедура Scan получает завершающую точку, все правильно, но она вызывает SkipWhite и SkipWhite не возвращается до тех пор, пока не получит непустую строку.
Такое поведение не настолько плохое, как кажется. В настоящем компиляторе мы читали бы символы из входного файла вместо консоли и пока мы имеем какую-то процедуру для работы с концом файла, все получится ОК. Но для чтения данных с консоли такое поведение слишком причудливое. Суть в том, что соглашение C/Unix просто не совместимо со структурой нашего анализатора, который запрашивает предсказывающий символ. Код, который мастера из Bell реализовали, не использует это соглашение, поэтому они нуждаются в 'ungetc'.
ОК, давайте исправим проблему. Чтобы сделать это, мы должны возвратиться к старому определению IsWhite (удалите символы CR и LF) и используйте процедуру Fin, которую я представил в последний раз. Если ее нет в вашей текущей версии Cradle, поместите ее там.
Также измените основную программу следующим обраазом:
{–}
{ Main Program }
begin
Init;
repeat
Token := Scan;
writeln(Token);
if Token = CR then Fin;
until Token = '.';
end.
{–}
Обратите внимание на «охраняющую» проверку, предшествующую вызову Fin. Это то, что заставляет все это работать, и проверяет, то мы не пытаемся прочитать строку дальше.
Сейчас испытайте этот код. Я думаю он понравится вам больше.
Если вы обратитесь к коду, который мы написали в последней главе, вы обнаружите, что я расставил вызовы Fin по всему коду, где прерывание строки было бы уместным. Это одна из тех областей, которые действительно влияют на восприятие, о котором я упомянул. В этой точке я должен убедить вас поэкспериментировать с различными способами организациями и посмотреть, как вам это понравится. Если вы хотите, чтобы ваш язык был по настоящему свободного стиля, тогда новые строки должны быть прозрачны. В этом случае наилучшим подходом было бы поместить следующие строки в начале Scan:
while Look = CR do
Fin;
Если, с другой стороны, вам нужен строчно-ориентированный язык подобный Ассемблеру, BASIC или FORTRAN (или даже Ada... заметьте, что он имеет комментарии, завершаемые новой строкой), тогда вам необходимо, чтобы Scan возвращал CR как токены. Он также должен съедать завершающие LF. Лучший способ сделать – использовать эту строку в самом начале Scan:
if Look = LF then Fin;
Для других соглашений вы будете должны использовать другие способы организации. В моем примере на последнем уроке я разрешил новые строки только в определенных местах, поэтому я занял какое-то промежуточное положение. В остальных частях этих занятий я буду выбирать такие способы обработки новых строк какие мне понравятся, но я хочу, чтобы вы знали, как выбрать для себя другой путь.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206