Интерпретатор для подмножества языка разметки гипертекста HTML
Контрольная работа
Интерпретатор для подмножества языка
разметки гипертекста HTML
Содержание
Введение
. Лексический анализ
. Синтаксический анализ
. Визуальное представление
Заключение
Литература
Приложение А - Листинг программы
Введение
Целью данной работы является написание интерпретатора языка разметки HTML. Данная программа должна проверять
входную последовательность на корректность кода. В случае успешного просмотра
кода выводится сообщение о корректности и строится абстрактное синтаксическое
дерево. В ином случае выводится сообщение об ошибке.
В данной программе входная последовательность - это лексемы, совокупность
которых представляют собой язык гипертекстовой разметки HTML.
Теги - это элементы языка разметки гипертекста, в основном для задания
того, как будет отображаться текст.
Теги, разбираемые написанной программой:
. <html></html> - Указывает программе просмотра страниц, что
это HTML документ, а также указывает на начало веб-кода.
. <head></head> - определяет место, где помещается различная
информация, не отображаемая в теле документа. Здесь располагается тег названия
документа и теги для поисковых машин.
3. <title></title> - помещает название документа в оглавление
программы просмотра страниц.
. <body></body> - определяет видимую часть документа.
. <table></table> - создает таблицу.
. <tr></tr> - определяет строку в таблице.
. <td></td> - определяет отдельную ячейку в таблице.
В программе необходимо использовать как лексический, так и синтаксический
анализ.
Для лексического анализа используется Lex - программа для генерации лексических анализаторов.
Для синтаксического анализа должен быть использован метод рекурсивного
спуска. Метод рекурсивного спуска или нисходящий разбор - это один из методов
определения принадлежности входной строки к некоторому формальному языку
Актуальность данной работы связана с бурным развитием языков
программирования, а в частности языков веб-программирования, к которым в свою
очередь относится HTML. Также в
данной работе мы познакомимся с лексическим и синтаксическим анализом, улучшим
знания азов системного программирования.
1. Лексический анализ
Для описания гипертекстовой разметки языка HTML используются теги. HTML документ начинается с открывающего тега <html>
и заканчивается закрывающим - </html>. Документ должен содержать тело <body>, а голова может отсутствовать <head>.
Голова, как правило, должна содержать тег заголовка - <title></title>. В поле между открывающимся и закрывающимся
тегами описывается заголовок.
Тело обязательно должно присутствовать, хотя и может быть пустым. В теле
документа описывается вся структура документа, в нашем случае это теги таблицы
<table> и всё, что входят в формирование
таблицы.
Тег <tr> создает новый ряд (строку) ячеек
таблицы. Ячейки в ряду создаются с помощью тега <td>.
В открывающемся теге таблицы или любого тега входящего в формирование
таблицы, можно указать атрибуты:
1. align - определяет способ горизонтального выравнивания содержимого всех ячеек
данного ряда.
2. valign - определяет способ вертикального выравнивания содержимого
всех ячеек данного ряда.
. bgcolor -
определяет цвет фона для всех ячеек данного ряда.
Возможности гипертекстового языка разметки намного шире и больше, но для
поставленной цели, этого достаточно.
В начале необходимо описать все вышеперечисленные теги как лексемы в
файле с расширением htmllex.l для генератора Lex.
Текст файла:htmllex;_st=257;_en=258;_st =
259;_en =
260;_st=261;_en=262;_st=263;_en=264;_tabl_st=265;_tabl_en=271;=300;_ru=301;=302;_tabl_tr_st=303;_tabl_tr_en=304;_tabl_td_st=305;_tabl_td_en=306;_error=313;yylex:integer;lexlib; [0-9]
L [a-zA-Z]
P
[а-яА-Я]
%%
"<html>" returni(html_st);
"</html>" returni(html_en);
"<title>" returni(t_st);
"</title>" returni(t_en);
"<head>" returni(h_st);
"</head>" returni(h_en);
"<body>" returni(b_st);
"</body>" returni(b_en);
"<table" returni(b_tabl_st);
"</table>" returni(b_tabl_en);
"<tr" returni(b_tabl_tr_st);
"</tr>" returni(b_tabl_tr_en);
"<td" returni(b_tabl_td_st);
"</td>" returni(b_tabl_td_en);
{L}({L}|{D})* returni(id);
"'"({L}|{D})+"'" returni(param);
({L}|{D}|{P})* returni(str_ru);
\> returnc('>');
\= returnc('=');
" " ;
. returni(lex_error);
%%
end.
Все параметры описываются в кавычках. В разделе определений формируем
строки, необходимые для компиляции полноценного модуля лексического
анализатора.
Для этого указываем заголовок модуля и декларируем функцию yylex в интерфейсном разделе, так как
данная функция будет использоваться в других модулях.
В разделе правил, если входная последовательность соответствует одному из
них, то управление передается основной программе. Раздел правил и
пользовательский раздел отделяются строкой процента. Пользовательский раздел
программы используем для корректного завершения модуля лексического
анализатора. В нашем случае этот раздел состоит из одной строки “end.”, которая должна быть помещена в
результат для корректного завершения модуля.
2. Синтаксический анализ
В качестве метода синтаксического анализа задан «метод рекурсивного
спуска». Необходимо построить грамматику, описывающую заданные параметры. Текст
грамматики приведен ниже:
GOAL→HTML
HTML→<html>HEAD BODY</html>
HEAD→<head>TITLE</head>
|ε→ str_ru
|ε→<body> CONTENT
</body>→ TABLE0 CONTENT
|str_ru CONTENT
|id CONTENT
|ε→ <table ATTRIB> TR0
</table>→ <tr ATTRIB> TD0 </tr> TR_0
| TR_0 → TR0
| ε
TD0 → <td ATTRIB> str_ru </td> TD0 → id=param ATTRIB
|ε
3. Визуальное
представление
Для визуального представления входной последовательности используем
дерево.
Чтобы визуально отобразить дерево использовали стандартный компонент Embarcadero RAD Studio 2010 - TreeView. Так же происходит автоматическое экспортирование дерева из визуального
компонента в xml файл и обычный текстовый файл,
которые можно найти в директории с программой. Для построения абстрактного синтаксического
дерева по ходу работы нам удалось изучить данный компонент.
К узлам дерева крепятся листья, если же листа нет, то узел сам становится
листом (например, после тега <body>
идет тег <table>, если же таблицы не будет, то
узел <body>, станет листом дерева)
Что бы распознать родителя узла завели счетчик, который указывает на
родителя того или иного узла.
Внешний вид созданного интерпретатора соответствует изображению на
рисунке 1.
Рисунок 1 - Внешний вид
На форме расположены следующие объекты:
1. Кнопка “ОК”, которая запускает основную процедуру программы;
2. Кнопка “Отмена”, которая завершает работу программы;
. Кнопка “Очистить”, которая очищает исходные данные;
4. Memo1- область, в которой должен быть вписан исходный HTML код;
5. TreeView - область, в которой строится абстрактное дерево.
После завершения процесса анализа кода, программа примет вид
соответствующий рисунку 2.
Рисунок 2 - Завершение процесса анализа
Заключение
В ходе данной работы была написана программа, которая анализирует HTML код на правильность, в случае
успешного анализа строится абстрактное синтаксическое дерево, в противном
случае выводится ошибка. Программа функционирует в соответствии с поставленной
задачи.
При написании мы разобрались с алгоритмом рекурсивного спуска, получили
навыки построения грамматики и работы с лексическим анализатором Lex. Приобрели практические навыки в
области построения трансляторов.
алгоритм грамматика интерпретатор разметка
код
Приложение А
Листинг программы
unit Interpreate;
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms,, Lexlib, HTMLLEX, ComCtrls, StdCtrls, ExtCtrls ;= ^integer;=
class(TForm): TButton;: TMemo;: TGroupBox;: TMemo;: TGroupBox;: TTreeView;:
TMemo;: TButton;: TButton;: TStatusBar;: TMemo;FormShow(Sender:
TObject);Button1Click(Sender: TObject);FormCreate(Sender: TObject);fglav:
boolean;fhtml_st: boolean; //началоfh_st:
boolean; //head start - endft_st: boolean; //titleft_en: boolean;fh_en:
boolean;fb_st: boolean; //bodyfb_tabl_st: boolean; //body -
tablefparam:boolean;fb_tabl_tr_st: boolean;fb_tabl_td_st:
boolean;fb_tabl_td_en: boolean;push(i: integer);pop(var i:
integer);fb_tabl_tr_en: boolean;fb_tabl_en: boolean;fb_en: boolean;fhtml_en:
boolean;Button2Click(Sender: TObject); //конец: TList;
{ Private declarations }
{ Public declarations };: TForm2;: integer;_i,_t, // используем в title и table_tr,_td,_p:
integer;: array [1..4] of integer;
{$R *.dfm}TForm2.fhtml_en: boolean;token = html_en then:=
yylex;:= true;:= false;;TForm2.Button2Click(Sender:
TObject);.Clear;;TForm2.fb_en: boolean;(token = b_en) then:= true;:=
yylex;(token = str_ru) or (token = id)
then.Items.AddChild(TreeView1.Items.Item[tree_t], yytext);(tree_i);:= yylex;:=
fb_en;:= false;;TForm2.fb_tabl_en: boolean;token = b_tabl_en then:= true;:=
yylex;:= false;;TForm2.fb_tabl_tr_en:boolean;(token = b_tabl_tr_en) then:=
true;:= yylex;token = str_ru then:= yylex;:= fb_tabl_tr_en;:=
false;;TForm2.pop(var i: integer);: TPInt;:= stack.Items[stack.count-1];:=
zn^;.Delete(stack.count-1);;TForm2.push(i: integer);: TPInt;(zn);^ :=
i;.Add(zn);;TForm2.fb_tabl_td_en:boolean;:= true;token = b_tabl_st
then(tree_t);(tree_tr);(tree_td);(tree_p);_t := tree_i;:=
fb_tabl_st;(tree_p);(tree_td);(tree_tr);(tree_t);;token = b_tabl_td_en then:=
true;:= yylex;(token = str_ru) or (token =
b_tabl_st)then.Items.AddChild(TreeView1.Items.Item[tree_p], yytext);(tree_i);:=
yylex;:= result and fb_tabl_td_en;:= false;;TForm2.fb_tabl_td_st:boolean;:=
false;token = b_tabl_td_st then.Items.AddChild(TreeView1.Items.Item[tree_td],
'<td');(tree_i);:= yylex;_p := tree_i;:=
fparam;.Items.AddChild(TreeView1.Items.Item[tree_td], '></td>');(tree_i);_p
:= tree_i;:= result and fb_tabl_td_en;token = b_tabl_td_st then:= result and
fb_tabl_td_st;;TForm2.fb_tabl_tr_st: boolean;:= false;token = b_tabl_tr_st
then.Items.AddChild(TreeView1.Items.Item[tree_tr], '<tr');(tree_i);:=
yylex;_p := tree_i;:= fparam;.Items.AddChild(TreeView1.Items.Item[tree_tr],
'></tr>');(tree_i);_td := tree_i;:= result and fb_tabl_td_st and
fb_tabl_tr_en ;token = b_tabl_tr_st then:= result and
fb_tabl_tr_st;;TForm2.fparam:boolean;: string;:= '';token = ord('>') then:= true;:=
yylex;:= false;token = id then:= yytext;:= yylex;token = ord('=') then:= pr +
yytext;.Items.AddChild(TreeView1.Items.Item[tree_p], pr);(tree_i);:=
yylex;token = param then.Items.AddChild(TreeView1.Items.Item[tree_i],
yytext);(tree_i);:= yylex;:= fparam;;;;;TForm2.fb_tabl_st: boolean;token =
b_tabl_st then.Items.AddChild(TreeView1.Items.Item[tree_t],
'<table');(tree_i);:= yylex;_p := tree_i;:=
fparam;.Items.AddChild(TreeView1.Items.Item[tree_t],
'></table>');(tree_i);_tr := tree_i;:= result and fb_tabl_tr_st and
fb_tabl_en;token = b_tabl_st then:= result and fb_tabl_st(token = str_ru) or
(token = id) then.Items.AddChild(TreeView1.Items.Item[tree_t],
yytext);(tree_i);:= yylex;:= fb_tabl_st;;(token = str_ru) or (token = id)
then.Items.AddChild(TreeView1.Items.Item[tree_t], yytext);(tree_i);:= yylex;:=
fb_tabl_st;:= true;;TForm2.fb_st: boolean;token = b_st
then.Items.AddChild(TreeView1.Items.Item[0],
'<body></body>');(tree_i);_t := tree_i;:= yylex;:= fb_tabl_st and
fb_en;:= false;;TForm2.fh_en: boolean;token = h_en then:= yylex;:= true;:=
false;;TForm2.ft_en: boolean;(token = t_en) then:= true;:= yylex;token = str_ru
then.Items.AddChild(TreeView1.Items.Item[tree_t], yytext);(tree_i);:= yylex;:=
ft_en;:= false;;TForm2.ft_st: boolean;token = t_st then.Items.AddChild(TreeView1.Items.Item[tree_i],
'<title></title>');(tree_i);_t := tree_i;:= yylex;:= ft_en;:=
false;;TForm2.fh_st: boolean;token = h_st
then.Items.AddChild(TreeView1.Items.Item[0],
'<head></head>');(tree_i);:= yylex;:= ft_st and fh_en;:=
true;;TForm2.fhtml_st: boolean;token = html_st then.Items.Clear;.Items.Add(nil,
'<html></html>');:= yylex;:= fh_st and fb_st and
fhtml_en;result:=false;;TForm2.fglav: boolean;:=
fhtml_st;;TForm2.Button1Click(Sender: TObject);_i := 0;.Clear;;(memo1,memo2,memo3,memo4);:=0;:=yylex;fglav
and (token=0) then
begin.Panels[0].Text := 'Проверка кода выполнена успешно';
StatusBar1.Panels[1].Text := 'Дерево построено';.Panels[0].Text := 'Ошибка проверки кода';
StatusBar1.Panels[1].Text := 'Ошибка при построении дерева';
showmessage('Ошибка!');;;TForm2.FormCreate(Sender:
TObject);:= TList.Create;;TForm2.FormShow(Sender: TObject);.SetFocus;;.