
- •Учебное пособие
- •Учебное пособие
- •Оглавление
- •2. 2 Регулярные выражения
- •2. 3 Грамматика
- •2. 4 Способы получения одних цепочек символов из других
- •2. 5 Формальное определение языка
- •2. 6 Расширенные грамматики
- •2. 7 Задачи анализа
- •2. 8 Синтаксические диаграммы
- •2. 9 Введение в компиляцию
- •2. 30 Структура компилятора
- •2. 11 Проходы компилятора
- •3 Алгоритмический язык spl
- •3. 4 Символы
- •3. 4 Оператор цикла
- •4 Лексический анализ
- •4. 5 Блок-схема функции void main (int ac, char * av [ ])
- •4. 5 Блок-схема функции void number ()
- •4. 5 Блок-схема функции void word ()
- •4. 5 Блок-схема функции char*add(char*nm)
- •5 Полный синтаксис языка spl
- •5.6Алфавит нетерминальных символов
- •5. 6 Синтаксические диаграммы и функции распознавания цепочек для нетерминальных символов
- •6 Пояснения к выполнению курсовой работы
- •6. 7 Пример выполнения курсовой работы
- •6. 7 Варианты заданий для курсовой работы
- •6. 7 Требования к оформлению курсовой работы
- •7 Вопросы к экзамену
- •8 Список литературы
- •Учебное пособие
4. 5 Блок-схема функции void main (int ac, char * av [ ])
В функции get () блок №1 в интерпретаторе должен быть if(nch==EOF)
{ lex=EOF;
.-.-.-.-.-.-.-.-
return;
}
Однако программа part1.c предназначена только лишь для того, чтобы прочитать текст программы на SPL, распознать лексемы, а идентификаторы занести в специальную таблицу идентификаторов char TNM [400]. Поэтому в данной программе в функции get ( ) блок №1 являет собой цикл while (nch!=EOF). Он позволяет прочитать весь текст программы на SPL до конца файла. Далее идет цикл while (isspace(nch)), позволяющий пропускать символы пробела, табуляции, перехода на новую строку и на новую страницу.
Если символ nch, прочитанный из файла с помощью функции get (), не является одним из перечисленных выше, то происходит его распознавание с вызовом функции number( ) или word( ).
Если nch является одним из перечисленных специальных символов, например, ‘(’, ‘)’, ‘+’ и т.д., то лексема получает соответствующее значение, считывается новый символ и происходит возврат в цикл (блок №1). В противном случае выдается сообщение о недопустимом символе и происходит выход из программы.
4. 5 Блок-схема функции void number ()
Блок №1 представляет собой цикл for ( ). В нем значение лексемы lval вначале определяется. Затем проверяется, что nch – цифра. Если это так, то происходит вычисление нового значения lval в блоке №2. Старое значение lval умножается на 10. К нему прибавляется результат вычитания из кода прочитанной цифры (nch) кода нуля. В таблице кодов ASCII код нуля в “10” системе равен 48, код “1” – 49, код “2” – 50 и т.д. Соответственно в “16”-ричной системе – (30)16, (31)16, (32)16 и т.д.
Таким образом, разница кодов позволяет получить прочитанную цифру. Предположим, из программы на SPL считывается константа 541. По первой цифре “5” будет вызвана функция number (). lval=0. nch содержит код цифры “5”, т.е. (35)16. Итак, условие – является ли содержимое nch кодом цифры, дает положительный ответ. В результате происходит переход к блоку №2. В нем вычисляем lval=10*0+(35)16 – (30)16 =5. После этого происходит возврат в циклы, считывается из файла новое значение nch. Это код (34)16 цифры “4”.
Теперь в блоке №2 lval=10*5+(34)16 – (30)16 =54.
После считывания кода цифры “1” lval=10*54+(31)16 – (30)16=541.
После того как очередной прочитанный символ окажется не цифрой, происходит выход из цикла. Лексема получает значение NUMB, и происходит выход из функции.
4. 5 Блок-схема функции void word ()
П
Блок №2 реализуется в виде цикла for. В указатель p заносится адрес tx[0]. Затем проверяется условие, что nch – буква или цифра. Если это так, то реализуется блок №3. По адресу в указателе p, т.е. в tx[0], заносится символ nch. После этого значение p увеличивается на 1, то есть в р находится адрес tx [1]. Происходит возвращение в цикл. Считывается новое значение nch. Если он буква или цифра, вновь выполняется блок №2. теперь уже символ nch заносится в tx [1], после чего в р заносится адрес tx [2] и т.д. Если прочитанный символ nch – не буква и не цифра, происходит выход из цикла. В очередной элемент массива tx заносится ‘\0’ – признак конца строки символов. В tx сформирована некая последовательность букв или букв и цифр. Теперь предстоит проверить, что собой она представляет. Это может быть одно из служебных (зарезервированных) слов, перечисленных в массиве char*serv [] .
Проверка выполняется в цикле (блоки №5 и №6). В случае совпадения строки символов tx и одного из служебных слов lex получает значение соответствующего элемента из массива int cdl [ ].
Например, если в tx находится строка символов end, то она совпадает с элементом end из seev [1] и лексема lex=ENDL, т.е. lex=258 (см. enum={BEGINL=257, ENDL…};).
Если содержимое tx не совпало ни с одним служебным словом, значит, - это идентификатор переменной или функции. В этом случае lex=IDEN, т.е. 269, и его необходимо занести в таблицу идентификаторов char TNM [400]. Для этого вызывается функция add (tx). Она возвращает указатель char*. Поэтому, чтобы присвоить возвращаемый адрес переменной целого типа int lval, применяется явное преобразование типа
lval=(int) add (tx).