end;
end;
end;
Тестирование выполнялось на результатах работы лексического анализатора, который работает безошибочно и был протестирован ранее.
Ошибка | Текст программы | Сообщения от анализатора |
В объявлении имени программы | prom var15; . . program var15. | Отсутствует служебное слово program или в нём ошибка |
В описании | program var15; n: integer; . . program var15; var,: integer; . . program var15; var n: integer . . var n integer . . var n:; | Отсутствует служебное слово var после заголовка программы Отсутствует идентификатор в описании Отсутствует точка с запятой после описания переменных Отсутствует двоеточие перед типом integer Отсутствует тип: integer |
В begin. end | . . begin; . . var n: integer; n: =$+00; . . until n<$-0A; | После begin недопустим символ точка с запятой Отсутствует служебное слово begin после описания переменных Отсутствует служебное слово end в конце программы |
В имени программы | ... program $+00;. | Неправильное имя программы. Ошибочное выражение: "$+00" |
В операторе присваивания | ... n: $+00; | Ошибка в операторе присваивания |
В выражении | ... n: =- (-XII);... | Ожидается константа, идентификатор или выражение |
В цикле | ... repeat n: =n- (-XII); n<$-0A;. | Ожидается служебное слово until |
В теле программы | ... n: =$+00. | Ожидается точка с запятой после оператора (после лексемы $+00) |
Главные процедуры лексического и синтаксического анализатора - это, соответственно, процедуры N5. Click и N6. Click главной формы программы. Из них вызываются остальные подпрограммы
Текст исходная программа выводится в окне в верхнем левом углу формы. Если лексический анализ текста (процедура N5. Click) выявил ошибку, то она выводится в окне сообщёний об ошибках и анализ прекращается.
Лексический анализатор выводит на форму таблицы констант, идентификаторов, терминальных символов и кодов лексем в областях вывода StringGrid1, StringGrid2, StringGrid3 и StringGrid4.
После синтаксического анализа переданной таблицы кодов лексем в окне сообщений об ошибках синтаксического анализатора содержатся сообщения от распознающих процедур разного уровня, затронутых обнаруженной ошибкой (см п.3.5)
Ошибок при двухфазном анализе не выявлено, если область вывода лексических ошибок пуста, а для синтаксических - содержит текст "Ошибок нет".
Внешний вид окна программы представлен на рис.7.
полностью совпадают с результатами тестирования лексического и синтаксического анализатора по отдельности, проведённых последовательно.
рис.7. Внешний вид окна программы
Данная программа предназначена для лексического и синтаксического анализа небольших (<1 МБ) текстов программ на заданном диалекте подмножества языка Pascal.
Программа написана на языке Delphi в среде разработки Delphi 7.
Программа предназначена для выявления наличия лексических и синтаксических ошибок во входном тексте программы.
Запуск файла lex1. exe.
Исходный текст программы, в текстовом файле ‘вар14. txt’ или в окне ввода исходного текста.
Сообщение о первой ошибке, выявленной лексическим анализом, а при отсутствии таковых - вывод сообщения о первой обнаруженной синтаксической ошибке, при отсутствии ошибок - соответствующее сообщение.
Программа состоит из файлов:
lex. pas
lex. ~dfm
Основная форма программы - в файле lex. dfm, алгоритм её работы - в файле lex. pas.
Список строк исходного текста программы загружается в массив SA. Процедура Select_lex выполняет выделение из текста лексем. Таблицы констант, идентификаторов, терминальных символов и кодов лексем хранятся в массивах Const_Tab, Id_Tab, Term_Tab и Code_Tab. Распознавателем идентификаторов является функция Ident, 16-ричных констант - функция Const16, логических констант - функция Boolconst. Распознавателем терминальных символов является функция Termin. Если лексема ошибочна, то она заносится в таблицу кодов лексем с типом E и выдаётся сообщение об ошибке (процедура Err_Lex). Все эти подпрограммы вызываются из процедуры TForm1. N5Click (соответствует выбору пункта меню Анализатор/Лексический). В ней производится обнуление всех таблиц, вызов функции выделения лексем и процедуры WriteLex (см. ниже).
Поиск идентификаторов, констант и терминальных символов в соответствующих таблицах производится, соответственно, процедурами Search_Ident, Search_Const и Search_Term, добавление в таблицы - процедурами Add_Ident, Add_Const и Add_Term. Все они вызываются из процедуры WriteLex, входными данными для которой являются результаты распознавания лексем, т.е. типы лексем. Запись в таблицу кодов лексем производится процедурой WriteCode, вывод всех таблиц на экран - процедурой vyvod.
Перевод констант в десятичную форму производится процедурой perevod.
Процедура начала синтаксического анализа N6. Click вызывает процедуру Syntax, которая, в свою очередь, вызывает процедуру Lex_Progr, далее реализуется синтаксический анализ методом рекурсивного спуска.
Текст программы лексическому анализатору передаётся из поля в верхнем правом углу главного окна при выборе пункта меню "Анализ/Лексический", куда он может вводиться с клавиатуры или загружать из файла "вар14. txt" (он обязательно должен находиться в каталоге с программой) при создании формы. Полученный список лексем передаётся синтаксическому анализатору, а найденные им ошибки - в поле в левой части окна.
1. Методические указания к лабораторным работам по СПО.
2. Курс лекций по дисциплине "Системное программное обеспечение".
3. А.Ю. Молчанов "Системное программное обеспечение", СПб, 2003 г.
4. Ю.Г. Карпов "Теория автоматов", СПб, 2002 г.
5. В.В. Фаронов“Delphi. Программирование на языке высокого уровня", Питер, 2004 г.
unit lex;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Menus, StdCtrls, Grids;
type
TVyh = Record // Тип таблицы кодов лексем
nomer: integer; // Номер
typ: char; // Тип лексемы
Num: integer; // Номер в таблице
Lex: String; // Лексема
numstr: integer; // Номер строки
end;
TTerm = Record // тип таблицы терминальных символов
nomer: integer; // номер
Lex: String; // Лексема
razd: byte; // Разделитель?
oper: byte; // Операция?
slug: byte; // Служебное слово?
Left: integer; // Левая ветвь дерева.
Right: integer; // Правая ветвь дерева.
Way: string;
end;
TConst = Record // Тип таблицы констант
nomer: integer; // Номер
value: string; // Само значение лексемы.
Typ: string; // Тип лексемы
Width: string; // Ширина константы
Val10: string; // 10-тичный формат константы
Left: integer; // Левая ветвь дерева.
Right: integer; // Правая ветвь дерева.
Way: string;
end;
TId = Record // таблица имен
nomer: integer; // номер лексемы
lex: string; // лексема
ssylka: integer; // ссылка на элемент цепочки
end;
TForm1 = class (TForm)
MainMenu1: TMainMenu;
N1: TMenuItem;
N2: TMenuItem;
N3: TMenuItem;
N4: TMenuItem;
N5: TMenuItem;
OpenDialog1: TOpenDialog;
Memo1: TMemo;
N6: TMenuItem;
StringGrid1: TStringGrid;
Label1: TLabel;
StringGrid2: TStringGrid;
Label2: TLabel;
StringGrid3: TStringGrid;
StringGrid4: TStringGrid;
Label3: TLabel;
Label4: TLabel;
Memo2: TMemo;
Label5: TLabel;
procedure N2Click (Sender: TObject);
procedure N3Click (Sender: TObject);
procedure N5Click (Sender: TObject);
procedure vyvod;
procedure Err_lex;
procedure Syntax;
procedure Err_Synt (text: string; l: integer);
function Lex_Progr: boolean;
function Lex_Prog_Name: boolean;
function Lex_Descr_List: boolean;
function Lex_descr: boolean;
function Lex_name_list: boolean;
function Lex_type: boolean;
function Lex_oper_list: boolean;
function Lex_oper: boolean;
function Lex_assign: boolean;
function Lex_Exp: boolean;
function Lex_simple_Exp: boolean;
function Lex_Term: boolean;
function Lex_mnozh: boolean;
function Lex_repeat_until: boolean;
function Lex_body: boolean;
procedure N6Click (Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const
MaxNum=100; // Максимальное число лексем
deleter= ['. ',' ',' (',') ','{','}',',','<','>','"','? ','! ','*','&','^', {'%','$',}' [','] ',': ','; ','=','-','+','/', '\',''''] ; // разделители лексем
words: Array [1. .14] of string [7] = ('program','var','then','begin','for','to','do','if','end','repeat','until','real','integer', 'else'); // Массив служебных слов
razdel: Array [1. .8] of char= (',','; ',': ',' (',') ',' [','] ','. '); // массив разделителей
operacii: Array [1. .11] of string [2] = (': =','>=','<=','<>','+','-','/','*','>','<','='); // массив операций
cifra= ['0'. '9'] ; // цифры
bukva= ['A'. 'F'] ;
var
Form1: TForm1;
FA,FName: textfile;
SA: array [1. .100] of string;
SS,Name,Constant: string;
Dlina: integer;
Code_tab: array [1. MaxNum] of TVyh; // Таблица кодов лексем
Term_tab: array [1. MaxNum] of TTerm; // Таблица терминальныз символов
Id_tab: array [1. MaxNum] of TId; // Таблица идентификаторов
Const_tab: array [1. .50] of TConst; // Таблица констант
Lexem,s,typel: string; // Лексема, Текст ошибки, Строка программы, Тип лексемы