- •Теория языков программирования и методы трансляции
- •1. Языки и кризис программирования.
- •2. Математические методы описания языков программирования.
- •3. Основные понятия и определения.
- •1. S→ab→aAb→aaAb→aaaB→aaabB→aaabbB→aaabbbB→aaabbbb.
- •2. S→ab→AbB→AbbB→AbbbB→Abbbb→aAbbbb→aaAbbbb→aaabbbb
- •Load a mult b
- •4. Этапы построения транслятора.
- •5. Основные методы поиска ошибок в исходных текстах программ.
- •Устройство управления
- •6. Современное состояние и перспективы развития программирования трансляторов.
- •7. Лексический анализ. Интуитивный подход.
- •8. Классы лексем и их особенности.
- •9. Формирование таблиц лексем и построение дескрипторного текста исходной программы.
- •На основании составленных таблиц можно записать входной текст через введённые дескрипторы (дескрипторный текст):
- •10. Синтаксический анализ. Метод рекурсивного спуска.
- •11. Пример грамматики упрощенного языка Паскаль.
- •12. Пример программы на упрощенном Паскале.
- •Var sum, sumsq, I, value, mean, variance : integer;
- •13. Алгоритм синтаксического анализа по методу рекурсивного спуска.
- •Void read()
- •Void idlist()
- •Void assign()
- •15. Лексический анализ, регулярные грамматики и конечные автоматы.
- •17. Грамматики типа ll(k). Алгоритмы построения магазинных анализаторов.
- •18. Детерминированный синтаксический анализ сверху вниз.
- •19. Правила определения детерминированного мп-разпознавателя по ll(1) грамматике.
- •20. Заключение.
- •Литература
13. Алгоритм синтаксического анализа по методу рекурсивного спуска.
Данный метод относится к разделу синтаксического анализа текста программы. Данный метод является интуитивным. Он не гарантирует обнаружение всех 100% синтаксических ошибок, но он очень прост в реализации и может применяться для несложных языков программирования, например, для языков, описывающих исходные данные в сложных программных системах.
Рассмотрим на примере грамматики упрощенного Паскаля. Грамматика упрощенного Паскаля имеет вид (продукции пронумерованы для справки):
1. <PROG>→program<PROGRAM-NAME>var<DEC-LIST>begin<STMT-
LIST>END.
2. <PROG-NAME> →id
3. <DEC-LIST>→ <DEC>|<DEC-LIST>;<DEC>
4. <DEC> →<ID-LIST>:<TYPE>
5. <TYPE> → integer
6. <ID-LIST> →id|<ID-LIST>, id
7. <STMT-LIST>→<STMT>|<STMT-LIST>;<STMT>
8. <STMT>→<ASSIGN>|<READ>|<WRITE>|<FOR>
9. <ASSIGN> →id:=<EXP>
10. <EXP> →<TERM>|<EXP>+<TERM>|<EXP> - <TERM>
11. <TERM>→ <FACTOR>|<TERM>*<FACTOR>|<TERM> div <FACTOR>
12. <FACTOR> →id|int|(EXP)
13. <READ> →read(<ID-LIST>)
14. <WRITE> →write(<ID-LIST>)
15. <FOR>→ for<INDEX-EXP> do <BODY>
16. INDEX-EXP>→ id:=<EXP> to <EXP>
17. <BODY>→ <STMT>|begin<STMT-LIST> end
Продукции, выделенные красным цветом, содержат левые рекурсии, поэтому нисходящий метод синтаксического анализа будет зацикливаться на них. Преобразуем выделенные продукции, так чтобы левые рекурсии устранились.
1. <PROG>→program<PROGRAM-NAME>var<DEC-LIST>begin<STMT-
LIST>END.
2. <PROG-NAME> →id
3. <DEC-LIST>→ <DEC>|{;<DEC>}
4. <DEC> →<ID-LIST>:<TYPE>
5. <TYPE> → integer
6. <ID-LIST> →id|{, id}
7. <STMT-LIST>→<STMT>|{;<STMT>}
8. <STMT>→<ASSIGN>|<READ>|<WRITE>|<FOR>
9. <ASSIGN> →id:=<EXP>
10. <EXP> →<TERM>|{+<TERM>| - <TERM>}
11. <TERM>→ <FACTOR>|{*<FACTOR>| div <FACTOR>}
12. <FACTOR> →id|int|(EXP)
13. <READ> →read(<ID-LIST>)
14. <WRITE> →write(<ID-LIST>)
15. <FOR>→ for<INDEX-EXP> do <BODY>
16. INDEX-EXP>→ id:=<EXP> to <EXP>
17. <BODY>→ <STMT>|begin<STMT-LIST> end
Нотация в фигурных скобках означает, что конструкция в фигурных скобках может или быть пропущена или повторяться несколько раз.
Синтаксический разбор. Синтаксический разбор в этом случае состоит из отдельных процедур, которые должны быть заранее запрограммированы для каждого нетерминального символа определённого в грамматике. В данном случае их будет 17. Каждая процедура ищет в входном потоке лексем подстроку, которая начинается с текущей лексемы интерпретируемой данной процедурой. В процессе своей работы процедура может вызывать другие подобные процедуры или рекурсивно обращаться сама к себе для поиска других нетерминальных символов.
Если процедура находит соответствующий нетерминальный символ, то она заканчивает свою работу, передаёт в вызвавшую её программу признак успешного завершения и устанавливает указатель на первую лексему следующей строки.
Если процедура не может найти нужную строку, которая могла бы быть интерпретирована как требуемый нетерминальный символ, она заканчивает работу с признаком неудачи или вызывает процедуру диагностики и процедуру восстановления.
Пример рекурсивного спуска. Рассмотрим строку, начинающуюся с ключевого слова read, использую метод рекурсивного спуска. Обратимся к примеру программы, составленной на упрощенном Паскале. Строка номер 8:
read(value);
В этой строке 5 лексем : read, ( , value, ), ;
Первая лексема read. Поэтому должна быть процедура или функция с именем read. В качестве языка программирования программы синтаксического анализатора выберем С++.