Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

3468

.pdf
Скачиваний:
4
Добавлен:
15.11.2022
Размер:
5.57 Mб
Скачать

ЛАБОРАТОРНАЯ РАБОТА № 11. РАЗРАБОТКА КОМПИЛЯТОРОВ. ПРОЕКТИРОВАНИЕ ЛЕКСИЧЕСКОГО АНАЛИЗАТОРА

Цель работы: изучение основных понятий теории регулярных грамматик, ознакомление с назначением и принципами работы лексических анализаторов (сканеров), получение практических навыков построения сканера на примере заданного простейшего входного языка.

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

Краткие теоретические сведения

Лексема (лексическая единица языка) - это структурная единица языка, которая состоит из элементарных символов языка и не содержит в своем составе других структурных единиц языка.

Пример разбора предложения на лексемы представлен на рис. 86.

Рис. 86. Пример разбора предложения на лексемы

211

Лексемами языков программирования являются:

идентификаторы,

константы,

ключевые слова языка,

знаки операций и т. п.

Состав лексем каждого языка программирования определяется синтаксисом этого языка.

Лексический анализатор (или сканер) - это часть ком-

пилятора, которая читает исходную программу и выделяет в ее тексте лексемы входного языка (рис 87).

Рис. 87. Работа ЛА

Причины включения ЛА в компилятор

1.Упрощает работу с текстом исходной программы на этапе синтаксического разбора и сокращает объем обрабатываемой информации, так как ЛА:

– структурирует исходный текст;

– отбрасывает всю незначащую информацию.

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

212

3. Сканер отделяет сложный по конструкции синтаксический анализатор от работы непосредственно с текстом исходной программы, структура которого может варьироваться в зависимости от версии входного языка (для перехода от одной версии языка к другой достаточно только перестроить относительно простой ЛА).

ЛА исключает из текста:

комментарии;

незначащие пробелы;

символы табуляции и перевода строки.

ЛА выделяет лексемы:

идентификаторы;

строковые, символьные и числовые константы;

ключевые (служебные) слова входного языка;

знаки операций и разделители.

Результатом работы лексического анализатора является таблица лексем, в которой представлена следующая информация (рис. 88).

 

уникальный условный код,

дополнительная

лексема

зависящий от типа

служебная

 

лексемы

информация

Рис. 88. Пример информации в таблице лексем

Информация о некоторых типах лексем, найденных в исходной программе, должна помещаться в таблицу идентифи-

каторов.

Таблица лексем и таблица идентификаторов - это две принципиально разные таблицы, обрабатываемые ЛА.

Информация о некоторых типах лексем, найденных в исходной программе, должна помещаться в таблицу идентифи-

каторов.

213

Таблица лексем и таблица идентификаторов - это две принципиально разные таблицы, обрабатываемые ЛА.

Лексемы в таблице лексем обязательно располагаются в том же порядке, как и в исходной программе (порядок лексем

вней не меняется).

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

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

Втерминах ЛА - это выделение тех строк в общем потоке входных символов, для которых надо выполнять распознавание.

Пример оператора на языке С

k = i+++++j;

Существует только одна единственно верная трактовка этого оператора:

k = i++ + ++j; k = (i++) + (++j);

Неверные варианты могут быть обнаружены только на этапе семантического анализа

вариант:

k = (i++)++ + j;

является синтаксически правильным, но семантикой языка С не допускается.

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

...

begin

for i:=1 to N do

fg := fg * 0.5;

...

214

 

Лексемы программы

Таблица 10

 

 

Лексема

Тип лексемы

Значение

begin

Ключевое слово

X1

for

Ключевое слово

X2

i

Идентификатор

i : 1

:=

Знак присваивания

S1

1

Целочисленная константа

1

to

Ключевое слово

X3

N

Идентификатор

N : 2

do

Ключевое слово

X4

fg

Идентификатор

fg : 3

:=

Знак присваивания

S1

fg

Идентификатор

fg : 3

*

Знак арифметической операции

A1

0.5

Вещественная константа

0.5

;

Разделитель операторов

S2

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

Таким образом, алгоритм работы простейшего сканера можно описать так:

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

215

для выбранной части входного потока выполняется функция распознавания лексемы;

при успешном распознавании информация о выделенной лексеме заносится в таблицу лексем, и алгоритм возвращается к первому этапу;

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

Работа программы-сканера продолжается до тех пор, пока не будут просмотрены все символы программы на исходном языке из входного потока.

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

Варианты заданий

1.Входной язык содержит арифметические выражения, разделенные символом ;(точка с запятой). Арифметические выражения состоят из идентификаторов, десятичных чисел с плавающей точкой, знака присваивания (:=), знаков операций +, -, *, / и круглых скобок.

2.Входной язык содержит логические выражения, разделенные символом ;(точка с запятой). Логические выражения состоят из идентификаторов, констант true и false, знака присваивания (:=), знаков операций or, xor, and, not и круглых скобок.

3.Входной язык содержит операторы условия типа if then else и if then, разделенные символом ;(точка с запятой). Операторы условия содержат идентификаторы, знаки

216

сравнения <, >, =, десятичные числа с плавающей точкой, знак присваивания (:=).

4.Входной язык содержит операторы цикла типа for do, разделенные символом ;(точка с запятой). Операторы цикла содержат идентификаторы, знаки сравнения <, >, =, десятичные числа с плавающей точкой, знак присваивания (:=).

5.Входной язык содержит арифметические выражения, разделенные символом ;(точка с запятой). Арифметические выражения состоят из идентификаторов, римских чисел, знака присваивания (:=), знаков операций +, -, *, / и круглых скобок.

6.Входной язык содержит логические выражения, разделенные символом ;(точка с запятой). Логические выражения состоят из идентификаторов, констант 0 и 1, знака присваивания (:=), знаков операций or, xor, and, not и круглых скобок.

7.Входной язык содержит операторы условия типа if then else и if then, разделенные символом ;(точка с запятой). Операторы условия содержат идентификаторы, знаки сравнения <, >, =, римские числа, знак присваивания (:=).

8.Входной язык содержит операторы цикла типа for do, разделенные символом ;(точка с запятой). Операторы цикла содержат идентификаторы, знаки сравнения <, >, =, римские числа, знак присваивания (:=).

9.Входной язык содержит арифметические выражения, разделенные символом ;(точка с запятой). Арифметические выражения состоят из идентификаторов, шестнадцатеричных чисел, знака присваивания (:=), знаков операций +, -, *, / и круглых скобок.

10.Входной язык содержит логические выражения, разделенные символом ;(точка с запятой). Логические выражения состоят из идентификаторов, шестнадцатеричных чисел, знака присваивания (:=), знаков операций or, xor, and, not и круглых скобок.

217

11.Входной язык содержит операторы условия типа if

then else и if then, разделенные символом ;(точка с запятой). Операторы условия содержат идентификаторы, знаки сравнения <, >, =, шестнадцатеричные числа, знак присваивания (:=).

12.Входной язык содержит операторы цикла типа for do, разделенные символом ;(точка с запятой). Операторы цикла содержат идентификаторы, знаки сравнения <, >, =, шестнадцатеричные числа, знак присваивания (:=).

Примечание:

- римскими числами считать последовательности больших латинских букв X, V и I;

- шестнадцатеричными числами считать последовательность цифр и символов ‘a’, ‘b’, ‘c’,’d’, ’e’ и ‘f’, начинающуюся с цифры (например: 89, 45ac9, 0abc4);

Ход выполнения работы:

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

2.Текст на входном языке задается в виде символьного (текстового) файла.

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

4.Длину идентификаторов и строковых констант считать ограниченной 32 символами.

Пример листинга программы:

//Основное окно программы Form1 using System;

using System.Collections.Generic; using System.Collections;

218

using System.ComponentModel; using System.Data;

using System.Drawing; using System.Linq; using System.Text;

using System.Windows.Forms; using System.IO;

namespace spo2_1

{

public partial class Form1 : Form

{

FileStream FS; bool fl = false; int al2count;

//переменные для хранения номера значения лексемы int number;

int number_i; int number_pr; int number_ao;

int number_sk; int number_kn; int number_vsfunk;

bool spec;

//массив для хранения таблицы идентификаторов element[] mas = new element [50];

//массив для хранения элементов таблицы идентификаторов

ArrayList al = new ArrayList(); //ArrayList al2 = new ArrayList(); //массив для храниеия значений лексем

leksem [] al2 = new leksem [1000]; bool find;

219

//массивы со значениями ключевых слов, операторов, методов, скобок

string[] keyword = { "uint", "int", "string", "char", "long", "ulong","bool" };

string[] keyword_all = { "using", "namespace", "public", "class", "static", "object", "try", "catch", "const", "void", "object", "ArrayList", "new", "for",

"false", "private", "foreach", "in", "if", "true", "else","do","break","while","continue"}; string[] arifm_op = {"+","-","*","/" };

string[] b_class = { "EventArgs", "Convert", "Thread", "ParameterizedThreadStart" };

string[] vs_funk = { "ToString", "ToInt32","InitializeComponent","Length","Add", "Value", "Cells","Rows" };

string[] log_op = { "!=", "==", "||", "&&","++","-=","+=" }; string[] sr_op = { ">", "<", "<=", ">=" ,"%"};

string[] ct = { "0","1", "2", "3", "4", "5", "6", "7", "8", "9","100","1000000"};

string[] sk = { "[", "]", "(", ")" }; string[] fun = { "sender", "e" };

string[] str; public Form1()

{

InitializeComponent();

}

//обработка откратия файла

private void button1_Click(object sender, EventArgs e)

{

//переменная для хранения имени файла string s;

//расширения выбираемых в диалоге файлов

220

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]