![]() |
![]() |
![]() |
Анимация
JavaScript
|
Главная Библионтека гиперправиле с помощью терминальных порождающих метаправил, пользуясь метаправилами языка. Метаправила образуют контекстно-свободную грамматику, метапонятия которой являются нетерминалами, а терминальные метаправила (не содержащие заглавных букв) - терминалами. Заметим, что в этой грамматике отсутствует понятие начального символа. / В качестве примера рассмотрим (несколько упрощенное) метаправило: В этом метаправиле «::» заменяет «:», а «;» используется (как в гиперправиле) для разделения вариантов. Ни один из вариантов в (2) не является терминальным метаправилом, так что нельзя вывести порождающее правило Алгола 68 из (1), пользуясь только метаправилом (2). Однако другим метаправилом может быть следующее: и у нас также есть где одним из вариантов для SIZETY будет пустая строка. Исследуя все возможные варианты, находим, что метапонятие может генерировать бесконечное число терминальных метаправил в соответствии с бесконечным числом видов в языке. (Например, SIZETY может генерировать любое число LONG). Согласованная подстановка дает, например. ![]() что служит поэтому одним из бесконечного числа порождающих правил, которые можно вывести из (1). Заметим, однако, что ![]() не является порождающим правилом языка из-за того, что не соблюдается правило согласованной подстановки. Полный синтаксис Алгола 68 описывается с помощью двухуровневой грамматики. Двухуровневые грамматики используются также для описания семантики языков программирования [44]. Другой метод определения синтаксиса языка программирования - с помощью атрибутивной грамматики [34]. Сифоне, применил атрибутивную грамматику для описания подмножества Алгола 68 [5.1]. Рассмотрим назначение атрибутивных грамматик на примере одной из них, служащей для описания простого языка программирования. У этого языка такая же блочная структура, как у Алгола 60 или Алгола 68* и мы ассоциируем с каждым блоком список идентификаторов и их видов (или типов). Идентификаторы могут иметь один из двух видов int и bool и являются терминалами грамматики на этом уровне определения. Описания можно специфировать с помощью контекстно-свободных порождающих правил ![]() ![]() ![]() dec-*-int id dec-booi id Здесь мы отступили от нашей обычной практики пользоваться строчными буквами только для терминалов. Описав идентификатор, мы хотим запомнить его вид. Этот вид будет свойством описания, и можно видоизменить грамматику, чтобы это указать: ![]() То же самое относится к описанию идентификатора вида bool. MODE, MODEl, ID, IDl пишутся в скобках после терминала или нетерминала грамматики и представляют собой его признаки, или атрибуты. С нетерминалом dec ассоциируются два атрибута; значение точки мы вскоре объясним. В соответствии с модифицированным контекстно-свободным порождающим правилом между атрибутами устанавливаются два соотношения. Таким образом, идентификатором, ассоциируемым с описанием, будет идентификатор, появляющийся после int, а видом, ассоциируемым с описанием,- вид int. Теперь можем определить последовательность описаний: decs {,UST)dec (.W; MODE) UST=(ID: MODE) decs i.LIST)decs {.U$Tt);dec {.ID, MODE) USTUSTl + (ID. MODE) ID is not contained in LIST! Таким образом, LIST состоит из одной пары (ID, MODE) в случае одного описания (или первого описания) либо из последовательности идентификаторов и видов («+» означает конкатенацию). Ограничение гарантирует, что ни один из идентификаторов не будет описан дважды в одном и том же блоке. Теперь блок можно частично определить с помощью контекстно-свободного порождающего правила: block-begm decs; siats end Налагаем контекстно-зависимые требования: ![]() Языковой обстановкой, в которой выполняется stats, является среда самого блока, увеличенная на decs. Эта обстановка передается отдельным оператором ![]() ![]() и мы допускаем для упрощения, что stat принимает одну из форм: siat {ENV)id {MODEIJDI) : id {MODE2.1D2) MODE I = search (ID J. ENV) M0DE2=search (W2. ENV) M0DEJ=M0DE2 Функция search будет искать обстановку снаружи, чтобы найти соответствующее описание идентификатора, а следовательно, и его вид. Если подходящее описание найти нельзя, выдается сообщение об ошибке. Атрибуты применяются для описания контекстно-зависимых (или, правильнее, контекстно-несвободнтх) аспектов языка программирования. Их можно использовать для передачи информации из левой части порождающего правила в правую, как в (4). Такие атрибуты называются унаследованными. Атрибуты также можно использовать для передачи информации из правой части порождающего правила в левую, как в (3), тогда их называют синтезированными атрибутами. В приведенном выше примере в каждой паре скобок унаследованные атрибуты предшествуют синтезированным, элементы каждого списка разделяются запятыми, а два списка - точкой. Преимущество атрибутивных грамматик заключается в том, что они выглядят как контекстно-свободные, но могут специфицировать контекстно-зависимые конструкции языка. Фактически любой язык типа 0 можно описать с помощью атрибутивной грамматики. Поскольку языки программирования представляются как контекстно-свободные, к которым добавляются контекстные ограничения, атрибутивные грамматики хорошо подходят для их описания. Существуют, кроме того, методы автоматического получения эффективных анализаторов из соответствующих атрибутивных грамматик. Этот факт, а также их удобочитаемость свидетельствуют о том, что атрибутивные грамматики близки к осуществлению двух основных назначений определения языка, упомянутых в начале данного раздела. Среди других хорошо известных методов описания синтаксиса языков программирования следует упомянуть Vienna Definition Language для ПЛ/1 [42] и порождающие системы Ледгара [41]. 2.4. ПРОБЛЕМА РАЗБОРА Мы показали, как можно использовать грамматику для генерирования программ на заданном языке программирования. Однако компилятор должен решить не проблему генерирования программ, а проблему проверки строк символов, чтобы определить, принадлежат ли они данному языку, и если да, то распознать структуру строк в термина порождающих правил грамматики. Эта проблема известна как проблема разбора, и, прежде чем приступить к ее рассмотрению, введем новые понятия. Исследуем грамматику с порождающими правилами ![]() ![]() 0 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 |
![]() |