Опубликован: 23.07.2006 | Доступ: свободный | Студентов: 2215 / 889 | Оценка: 4.28 / 4.17 | Длительность: 21:37:00
Специальности: Системный архитектор
Лекция 4:

Теория языков

Аннотация: Различные способы задания языков в компиляции: грамматики; конечные и магазинные автоматы. Соотношения между различными способами задания языков. Приложения в компиляции.
Ключевые слова: определение, множества, входной, целый, ПО, алгоритм, класс, нетерминальный символ, грамматика, алфавит, терминальный символ, транзитивное замыкание, эквивалентность, нетерминал, запись, контекстно-свободная грамматика, регулярный язык, управляющее устройство, память, распознаватель, список, стек, конечные, конечный автомат, отображение множества, множество заключительных состояний, конфигурация автомата, автомат, слово, место, моделирование, разбиение, эквивалентные автоматы, подмножество, множество состояний, константы, формализм, вывод, операции, выражение, приоритет операций, равенство, входной алфавит, LR, Формальной грамматикой, программа, грамматики в форме Бэкуса-Наура, форма Бэкуса-Наура, Pascal, EBNF, BSI, ALGOL, синтаксис, присваивание, метасимволы, метасимвол, destination, контекст, представление, syntax, flow, diagram

В этой лекции рассматриваются следующие темы:

  • Различные способы задания языков в компиляции:
    • Грамматики
    • Конечные и магазинные автоматы
  • Соотношения между различными способами задания языков
  • Приложения этой теории в компиляции

Задача определения языка

Одна из первых задач, возникающих в процессе компиляции - это определение рассматриваемого языка программирования. При рассмотрении языков, состоящих из конечного множества цепочек, проще всего явным образом перечислить все допустимые входные цепочки. Но что делать с языками, не вводящими никаких ограничений на длину входной цепочки? Для потенциально бесконечных языков нам потребуется ввести какой-то конструктивный способ описания, который позволит нам задать правила, описывающие порождаемый ими язык. Такое описание должно удовлетворять некоторым свойствам:

  • Само описание должно иметь конечную длину
  • Для данного описания языка должен существовать алгоритм, который мог бы проверить принадлежность некоторой входной цепочки языку

Существует целый ряд математических формализмов, в той или иной степени удобных для задания языков - вообще, этап анализа входной программы наиболее разработан и лучше всего поддержан математическими теориями. Наиболее распространенным механизмом являются грамматики, которые задают все подходящие цепочки языка с помощью некоторых порождающих правил. Очевидное достоинство грамматик заключается в том, что существует множество систем, которые по заданной грамматике генерируют программу, проверяющую соответствие входной цепочки определяемому языку. Более того, полезную работу синтаксического анализатора (например, построение дерева разбора) можно проводить параллельно с самим распознаванием языка.

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

Определение грамматики

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

Для формального определения грамматики нам потребуются следующие обозначения. Если А есть алфавит, то A^\ast обозначает множество всех строк (включая пустую строку \varepsilon ), составленных из символов, входящих в А. Аналогично, A^{+} определяет множество всех строк, составленных из символов, входящих в А, но без пустой строки. Нетерминалы мы будем обозначать прописными буквами, а терминалы - строчными.

Итак, грамматика G определяется как следующая четверка: G = (V_{T}, V_{N}, P, S) , где

  • V_{T} - конечное множество терминальных символов;
  • V_{N} - не пересекающееся с V_{T} конечное множество нетерминальных символов;
  • P - конечный набор порождающих правил вида ( \alpha , \beta ), где \alpha \in V^+, \beta \in V^\ast
  • S - начальный символ, где S\in V_N

Например, грамматикой, порождающей язык {\{}0^{n}1^{n} \vert n \ge 0{\}}, является G_{0}: G_{0}= ({\{}0,1{\}}, {\{}S{\}}, P, S) , где P = S \to 0S1, S\to \varepsilon. Другой пример: рассмотрим грамматику, порождающую язык {\{} a^{m}b^{n} {  \vert  m,n \ge  0}{\}}. Такая грамматика имеет вид G_{1}= ({\{} a,b {\}}, {\{} S,A, B{\}}, P,~S) , где набор правил определяется следующим образом: P = S \to AB, A \to aA, A \to \varepsilon , B \to bB, B \to \varepsilon.

Определим также понятие выводимости: если \alpha \beta \gamma - цепочка, состоящая из символов языка G, а \beta \to \delta - правило языка G, то \alpha \beta \gamma =>_{G} \quad \alpha \delta \gamma  (\alpha \delta \gamma непосредственно выводима из \alpha \beta \gamma в G). Рефлексивное и транзитивное замыкание этого отношения обозначим как \alpha =>^{\ast }_{G}\beta (цепочка \beta выводима из \alpha ; имя грамматики можно опускать для краткости).