Смекни!
smekni.com

Разработка конвертора из текстового формата nroff в гипертекстовый формат HTML (стр. 3 из 13)

А теперь представим тот же документ, но уже в формате HTML.

<HTML>

<BODY>

Это пример текстового документа<BR>

Здесь показаны некоторые возможности

форматирования текста <BR>

<BR>

Пропуск строки<BR>

<BR>

Работа с расположением текста:

<P align="left">Выровнять по левому краю

<P align="center">Выровнять по центру

<P align="right">Выровнять по правому краю</p>

<BR>

Есть также команды, позволяющие работать со

шрифтами:<BR>

Обычный шрифт<BR>

<FON T face="Arial">Другой(вызванный)шрифт

</font><BR>

<U>Подчеркнутый текст</u>

<P align="center"><U>Подчеркнутый

отцентрированный текст</u></p>

</body>

</html>

Также как и с предыдущим форматом, поясню некоторые команды и конструкции языка.

<HTML> … </html> - эти тэги говорят о том, что мы имеем дело с документом в формате HTML

<BODY> … </body> - между этими тэгами находятся все команды, а также текст HTML-документа.

<BR> - начало новой строки

<P> … </p> - начало и конец нового абзаца

align=”left” (center, right) – используется для указания типа выравнивания текста: по левому краю, центру или правому краю.

<FONT> … </font> - между этими тэгами текст выводится другим шрифтом, указанным в конструкции:

face=”font_name”

<U> … </u> - выводит подчеркнутый текст

Аналогично с форматом nroff, возможности HTML намного шире представленных в этом примере.

Стоит также отметить тот факт, что в целом формат HTML богаче формата nroff. В связи с этим при разработке программы-транслятора использовалась лишь та часть HTML, которая необходима для создания конструкций, аналогичных конструкциям созданным в формате nroff.

Контекстно-зависимые и контекстно-независимые грамматики.

Задача разработки транслятора соприкасается с дисциплиной, именуемой лингвистическое обеспечение САПР, некоторые положения которой мы и рассмотрим.

Прежде всего стоит отметить, что различают два основных типа грамматик: контекстно-зависимые и контекстно-независимые.

Если порождающее правило имеет следующий вид:

aAb ::= axb,

то порождающее правило называется контекстно-зависимым, то есть замена нетерминального символа A на последовательность x может иметь место только в контекстах a и b. Соответственно, и грамматика, содержащая подобное правило, называется контекстно-зависимой.

Если порождающее правило имеет вид:

A ::= x, где A – нетерминальный символ, а x - терминальный или нетерминальный. То есть, если левая часть порождающего правила состоит из одного нетерминального символа, который в итоге (через ряд промежуточных шагов) может заменяться на последовательность x, стоящую в правой части, независимо от контекста, в котором этот нетерминальный символ встречается, то такое правило и, соответственно, грамматика называются контекстно-независимыми.

В нашей задаче грамматика является контекстно-независимой (или как ее еще называют контекстно-свободной), поэтому более подробно стоит остановиться именно на ее описании.

Контекстно-свободные грамматики.

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

Слова из словаря языка играют роль терминальных символов (терминалов). Контекстно-свободная грамматика может также содержать любое конечное число терминалов. В языках программирования терминалами являются фактически используемые в них слова и символы: do, else, + и т.п.

Правила грамматики иногда называются продукциями и в общем виде выглядят так:

Один_нетерминал à любая конечная цепочка из терминалов и нетерминалов.

При этом цепочка справа от стрелки может быть и пустой. Например,

<A> à x

Иногда подобные правила называют эпсилон-правилами. Контекстно-свободная грамматика может содержать любое конечное множество продукций. В качестве иллюстрации вернусь к описанию языка программирования. Продукция тогда выглядит так:

<оператор> à IF <логическое_выражение> THEN <оператор>

Один из нетерминалов выделен как начальный нетерминал или начальный символ, с которого должны начинаться выводы цепочек языка. Для языков программирования таким нетерминалом может быть <программа>. Обычно начальный символ обозначают <S>.

Итак, контекстно-свободная грамматика будет задаваться:

1) конечным множеством нетерминалов;

2) конечным множеством терминалов, которое не пересекается с множеством нетерминалов;

3) конечным множеством правил вида <A> à a, где A – нетерминал, а a - цепочка терминалов и нетерминалов (возможно, пустая); нетерминал <A> называется левой частью правила, а a - правой частью;

4) одним нетерминальным символом, выделенным в качестве начального.

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

Для описания грамматик очень часто используют способ записи, получивший название формы Бэкуса-Науэра или БНФ. Здесь символ à заменяется символом ::=, за которым может следовать любое число правых частей, разделенных вертикальной чертой |. Здесь также нетерминалы заключаются в угловые скобки.

Правила грамматики используют для того, чтобы задавать способы подстановки или замены цепочек. Подстановка осуществляется путем замены некоторого нетерминала в какой-нибудь заданной цепочке терминалов и нетерминалов на правую часть правила, левой частью которого является этот нетерминал. Иногда говорят, что в таком случае правило применяется к нетерминалу цепочки.

Последовательность некоторых подстановок называется выводом. Каждая цепочка, встречающаяся в выводе, называется промежуточной цепочкой этого вывода.

Множество терминальных цепочек, которые можно вывести из начального символа грамматики, называется языком. Говорят, что язык определяется, грамматикой, порождается ею или выводится в ней. Язык, порождаемый контекстно-свободной грамматикой, также называется контекстно-свободным языком.

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

Дерево вывода цепочки контекстно-свободного языка сложно описать кратко, поэтому покажу пример подобного дерева.

Пусть дана следующая грамматика (начальный нетерминал <S>):

1. <S> à a<A><B>c

2. <S> à x

3. <A> à c<S><B>

4. <A> à <A>b

5. <B> à b<B>

6. <B> à a

Пусть дана цепочка: a<A><B>c, тогда вывод будет выглядеть следующим образом:

<S> (1) ==> a<A><B>c (2) ==> a<A>b<B>c (3) ==> ac<S><B>b<B>c (4) ==> ac<S>ab<B>c (5) ==> acab<B>c (6) ==> acabac (7).

Теперь для каждой из семи пронумерованных цепочек построю дерево.

(1) <S>

(2) <S>

a <A> <B> c

(3) <S>

a <A> <B> c

<A> b

(4) <S>

a <A> <B> c

<A> b

c <S> <B>

(5) <S>

a <A> <B> c

<A> b

c <S> <B>

a

(6) <S>

a <A> <B> c

<A> b

c <S> <B>

x a

(7) <S>

a <A> <B> c

<A> b a

c <S> <B>

x a

Окончательный вариант дерева называется деревом вывода терминальной цепочки acabac.

Когда одна цепочка может иметь несколько деревьев вывода, говорят, что соответствующая грамматика неоднозначна.

Таким образом, резюмируя вышесказанное, можно подытожить:

1. Каждой цепочке, выводимой в данной контекстно-свободной грамматике, соответствует одно или несколько деревьев вывода.

2. Каждому дереву соответствует один или более выводов.

3. Каждому дереву соответствует единственный правый и единственный левый выводы.

4. Если каждой цепочке, выводимой в данной контекстно-свободной грамматике, соответствует единственное дерево вывода, эта грамматика называется однозначной; в противном случае ее называют неоднозначной.

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

Если правая часть каждого правила грамматики содержит не более одного нетерминала, причем этот нетерминал является самым правым символом правой части, грамматика называется праволинейной.

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

Нетерминалы, которые не появляются ни в одной цепочке, выводимой из начального символа, называются недостижимыми нетерминалами.

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

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