- •Лекция № 3 теория языков и формальных грамматик
- •3.1 Способы определения языков
- •3.2 Формальные грамматики
- •3.3 Грамматики с ограничениями на правила
- •Лекция № 4 способы записи синтаксиса языка. Распознаватели
- •4.1 Метаязык Хомского
- •4.2 Метаязык Хомского-Щутценберже
- •4.3 Бэкуса-Наура формы (бнф)
- •4.4 Расширенные Бэкуса-Наура формы (рбнф)
- •4.5 Диаграммы Вирта
- •Диаграмм Вирта
- •4.6 Распознаватели
- •Лекция № 5 демонстрационный язык программирования dpl
- •5.1 Синтаксис и семантика dpl
- •5.1.1 Элементарные конструкции
- •5.1.2 Составные конструкции. Организация программы
- •5.1.3 Краткое описание семантики языка
- •5.3 Описание пользовательского синтаксиса с использованием диаграмм Вирта
- •6.2 Транслитератор
- •6.3 Грамматики и распознаватели для лексического анализа
- •6.3.1 Связь между диаграммой Вирта и конечным автоматом
- •В эквивалентный конечный автомат
- •Задающая идентификатор
- •6.3.2 Связь между диаграммами Вирта и праволинейными грамматиками. Преобразование правой рекурсии в итерацию
- •Грамматик в диаграммы Вирта
- •В итеративную диаграмму Вирта
- •Идентификатора в итеративную диаграмму Вирта
- •Идентификатора в итеративную диаграмму Вирта (окончание)
- •6.3.3 Связь между диаграммами Вирта и грамматиками с левой рекурсией. Преобразование левой рекурсии в итерацию
- •В итеративную диаграмму Вирта
- •6.4 Методы лексического анализа
- •6.4.1 Организация непрямого лексического анализатора
- •Лексического анализатора
- •6.4.2 Организация прямого лексического анализатора
- •Прямого лексического анализатора
- •Лекция № 7 лексический анализатор демонстрационного языка программирования
- •7.1 Транслитератор dpl
- •7.1.1 Общая организация транслитератора
- •7.1.2 Программная реализация транслитератора
- •7.2 Непрямой лексический анализатор dpl
- •7.2.1 Диаграммы Вирта для отдельных автоматов непрямого лексического анализатора
- •7.2.1 Программная реализация отдельных автоматов
- •7.2.3 Общая структура непрямого лексического анализатора
- •7.3 Прямой лексический анализатор dpl
- •Прямого лексического анализатора
- •Прямого лексического анализатора (продолжение)
- •Прямого лексического анализатора (окончание)
- •Лекция № 8 общие принципы организации синтаксического разбора
- •8.1 Назначение синтаксического разбора
- •8.2 Классификация методов синтаксического разбора
- •Синтаксического разбора
- •8.3 Методы разбора
- •С операции умножения
- •Распознавателя самых нижних ветвей дерева выступает лексический анализатор
- •8.4 Последовательность разбора
- •8.5 Использование просмотра вперед
- •8.6 Использование возвратов
- •8.7 Выводы
- •Лекция № 9 использование автоматов с магазинной памятью для нисходящего разбора слева направо
- •9.1 Организация автомата с магазинной памятью
- •9.1.1 Операции автомата
- •9.1.2 Распознаватель скобочных выражений
- •9.2 Общая связь между грамматиками и автоматами с магазинной памятью
- •9.3 Связь между s-грамматикой и автоматом с магазинной памятью
- •9.3.1 Обобщенный алгоритм построения нисходящего амп
- •9.4 Построение автомата с магазинной памятью по q-грамматике
- •9.4.1 Построение нисходящего автомата
- •Заменить (αr), Сдвиг
- •Вытолкнуть, Сдвиг.
- •Вытолкнуть.
- •9.4.2 Примеры построения амп по q-грамматике
- •Список использованных источников
- •Содержание
7.1.2 Программная реализация транслитератора
Реализация транслитератора, как и любого другого программного модуля, во многом зависит от стиля программирования. Несмотря на простоту, эта задача может быть рассмотрена и в более широком контексте. Транслитератор можно использовать как совокупность нескольких функций, проверяющих принадлежность символа к одному из классов. Такая реализация выглядит вполне логичной при процедурном программировании. Вместе с тем следует отметить, что транслитератор не используется сам по себе. Он является промежуточным звеном между функциями, обеспечивающими чтение символов из входного потока и лексическим анализатором. Это промежуточное звено обычно скрывает от лексического анализатора механизм чтения и преобразования символов. Сканеру так же ничего не надо знать об открытии входного потока и манипуляции с ним. Поэтому, при объектно-ориентированном подходе, получение значение нового символа, его класса, а также манипуляция входным потоком реализуются как единый объект (на основе класса). Этот класс инкапсулирует внутренние операции, а также объединяет разбросанные по программе структуры данных, используемые для ввода символов и их преобразования.
В результате этого решения, транслитератор оказался представлен следующим кодом:
// Функции транслитератора,
// используемые для определения класса лексем
// Определяет принадлежность символа к классу букв
bool inline isLetter(int ch) {
if((ch>='A' && ch<='Z') || (ch>='a' && ch<='z'))
return true;
else
return false;
}
//
// Определяет принадлежность символа
// к классу двоичных цифр
bool inline isBin(int ch) {
if((ch=='0' || ch=='1'))
return true;
else
return false;
}
//
// Определяет принадлежность символа
// к классу восьмеричных цифр
bool inline isOctal(int ch) {
if((ch >= '0' && ch <= '7'))
return true;
else
return false;
}
//
// Определяет принадлежность символа
// к классу десятичных цифр
bool inline isDigit(int ch) {
if((ch >= '0' && ch <= '9'))
return true;
else
return false;
}
//
// Определяет принадлежность символа
// к классу шестнадцатеричных цифр
bool inline isHex(int ch) {
if((ch >= '0' && ch <= '9') ||
(ch >= 'A' && ch <= 'F') ||
(ch >= 'a' && ch <= 'f'))
return true;
else
return false;
}
//
// Определяет принадлежность символа
// к классу пропусков
bool inline isSkip(int ch) {
if(ch==' ' || ch=='\t' || ch=='\n' || ch=='\f')
return true;
else
return false;
}
//
// Определяет принадлежность
// к классу игнорируемых символов
bool inline isIgnore(int ch) {
if(ch>0 && ch<' ' && ch!='\t'
&& ch!='\n' && ch!='\f')
return true;
else
return false;
}
//
// Читает следующий символ из входного потока
static void nxsi(void) {
if((si = getc(infil)) == '\n') {
++line; column = 0;
}
else ++column;
++poz; // Переход к следующей позиции в файле
}
При использовании объектно-ориентированного подхода все эти данные можно инкапсулировать в один класс, обеспечив доступ к ним через соответствующий интерфейс. Следует также отдельно отметить последнюю строку функции nxsi():
++poz; // Переход к следующей позиции в файле
Она присутствует только в непрямом лексическом анализаторе и предназначена для фиксации позиции в файле, что позволяет осуществлять откаты назад в том случае, если проверяемая версия о значении лексемы не подтвердится. Взятие следующего символа в прямом сканере происходит без использования этого «довеска».
