
ЛР2 Саляхов
.docxМинистерство образования и науки Российской Федерации
Федеральное государственное бюджетное образовательное учреждение высшего образования
«Уфимский университет науки и технологий»
Кафедра ТК
Отчет по лабораторной работе № 2
«Системное программное обеспечение»
Тема: «Проектирование лексического анализатора» Вариант 11
Выполнил:
студент группы ИВТ-429Б
Саляхов А.Ф.
Проверил:
доцент кафедры ТК
Ракипова А.С.
Уфа 2024
Цель работы:
Изучение основных понятий теории регулярных грамматик, ознакомление с назначением и принципами работы лексических анализаторов (сканеров), получение практических навыков построения сканера на примере заданного простейшего входного языка.
Задание:
Написать программу, которая выполняет лексический анализ входного текста в соответствии с заданием и порождает таблицу лексем с указанием их типов и значений. Текст на входном языке задаётся в виде символьного (текстового) файла. Программа должна выдавать сообщение о наличии во входном тексте ошибок, которые могут быть обнаружены на этапе лексического анализа. Длину идентификаторов и строковых констант можно считать ограниченной 32 символами. Программа должна допускать наличие комментариев неограниченной длинны во входном файле. Форму организации комментариев предлагается выбрать самостоятельно.
Вариант 11:
Входной язык содержит операторы условия типа if ... then .. else и if .. then, разделённые символом ; (точка с запятой). Операторы условия содержат идентификаторы, знаки сравнения <, >, =, шестнадцатеричные числа, знак присваивания (:=)
Описание КС - грамматики входного языка:
G ({1,2,3,4,5,6,7,8,9,0,A,B,C,D,E,F,e,f,h,i,n,l,s,t,#,’:’,’=’, ‘;’, ‘<‘, ‘>’}, ({A,B,C,D,E,F,G,H,I,J,K,L,M,N,R,T,i,O,s},P)
P:
A→ i B→Af C→t D→Ch E→De F→En G→e R→/*
|
H→Gl I→Hs J→Ie K→; L→ < | > | = M→ : N→ M= T→*/
|
O→ 1∣2∣3∣4∣5∣6∣7∣8∣9∣0∣O1∣O2∣O3∣O4∣O5∣O6∣O7∣O8∣O9∣O0∣OA∣OB∣OC∣OD∣OE∣OF
i→h*|i*|A*|B*|C*|D*|E*|F*|G*|H*|I*|J*
s→i#|B#|F#|J#|K#|L#|N#|Q#|S#|A#|C#|D#|E#|G#|H#|I#|
i* - множество всех символов
h*- множество всех символов, крoме терминальных символов
A*- множество всех символов, кроме #, f
B*- множество всех символов, кроме #
C*- множество всех символов, кроме #, h
D*- множество всех символов, кроме #, e
E*- множество всех символов, кроме #, n
F*- множество всех символов, кроме #
G*- множество всех символов, кроме #, i
H*- множество всех символов, кроме #, s
I*- множество всех символов, кроме #, e
J*- множество всех символов, кроме #
Схема цепочки:
Код программы:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cctype>
using namespace std;
struct Lexeme {
string value;
string type;
string chain;
int lineNumber;
};
string determineLexemeType(const string& lexeme) {
if (!lexeme.empty() && isdigit(lexeme[0])) {
bool isHex = true;
for (char ch : lexeme) {
if (!isxdigit(ch)) {
isHex = false;
break;
}
}
if (isHex) return "Шестнадцатеричное число";
}
// Проверки для других типов
if (lexeme == "if" || lexeme == "then" || lexeme == "else") return "Оператор условия";
if (lexeme == "<" || lexeme == ">" || lexeme == "=") return "Знак сравнения";
if (lexeme == ":=") return "Оператор присваивания";
if (lexeme == ";") return "Разделитель";
if (isalpha(lexeme[0])) return "Идентификатор";
return "Неизвестная лексема";
}
string generateChain(const string& lexeme) {
string chain = "h";
char State = 'h';
for (char ch : lexeme) {
switch (State) {
case 'h':
if (ch == 'i') State = 'A';
else if (ch == 't') State = 'C';
else if (ch == ':') State = 'M';
else if (ch == 'e') State = 'G';
else if (ch == ';') State = 'K';
else if (ch == '>' || ch == '<' || ch == '=') State = 'L';
else if (isdigit(ch)) State = 'O'; // Обработка для чисел
else State = 'i';
break;
case 'A':
if (ch == 'f') State = 'B';
else State = 'i';
break;
case 'C':
if (ch == 'h') State = 'D';
else State = 'i';
break;
case 'M':
if (ch == '=') State = 'N';
else State = 'e';
break;
case 'O':
if (isdigit(ch) || (toupper(ch) >= 'A' && toupper(ch) <= 'F')) State = 'O'; // Обработка для шестнадцатеричных чисел
break;
default:
break;
}
chain += State;
}
chain += "s";
return chain;
}
void reportUnknownLexeme(const string& lexeme, int lineNumber) {
cout << "Неизвестная лексема \"" << lexeme << "\" в строке " << lineNumber << endl;
}
vector<Lexeme> lexicalAnalysis(const string& text) {
vector<Lexeme> lexemes;
string current;
bool inComment = false;
int lineNumber = 0;
for (size_t i = 0; i < text.length(); i++) {
char ch = text[i];
if (ch == '\n') lineNumber++;
if (!inComment && ch == '/' && text[i + 1] == '*') {
inComment = true;
i++;
continue;
}
if (inComment && ch == '*' && text[i + 1] == '/') {
inComment = false;
i++;
continue;
}
if (inComment) continue;
if (isspace(ch) || ch == ';' || ch == '<' || ch == '>' || ch == '=' || ch == ':') {
if (!current.empty()) {
string type = determineLexemeType(current);
if (type == "Неизвестная лексема") {
reportUnknownLexeme(current, lineNumber);
}
else {
lexemes.push_back({ current, type, generateChain(current), lineNumber });
}
current.clear();
}
if (ch == ';' || ch == '<' || ch == '>' || ch == '=') {
string lexemeStr(1, ch);
string type = determineLexemeType(lexemeStr);
if (type == "Неизвестная лексема") {
reportUnknownLexeme(lexemeStr, lineNumber);
}
else {
lexemes.push_back({ lexemeStr, type, generateChain(lexemeStr), lineNumber });
}
}
if (ch == ':' && text[i + 1] == '=') {
lexemes.push_back({ ":=", "Оператор присваивания", generateChain(":="), lineNumber });
i++;
}
}
else {
current += ch;
}
}
if (!current.empty()) {
string type = determineLexemeType(current);
if (type == "Неизвестная лексема") {
reportUnknownLexeme(current, lineNumber);
}
else {
lexemes.push_back({ current, type, generateChain(current), lineNumber });
}
}
return lexemes;
}
int main() {
setlocale(LC_ALL, "Russian");
ifstream file("D:/EclipseWorkspace/12345/src/input.txt");
if (!file) {
cerr << "Не удалось открыть файл." << endl;
return 1;
}
string line, text;
while (getline(file, line)) {
text += line + '\n';
}
file.close();
vector<Lexeme> lexemes = lexicalAnalysis(text);
cout << "Лексема\t\tТип лексемы\t\tЦепочка" << endl;
cout << "--------------------------------------------------------" << endl;
for (const auto& lex : lexemes) {
cout << lex.value << "\t\t" << lex.type << "\t\t" << lex.chain << endl;
}
return 0;
}
Исходный текст для обработки:
Пример выполнения программы:
Вывод: в ходе выполнения лабораторной работы были изучены основные понятия теории регулярных грамматик, ознакомились с назначением и принципами работы лексических анализаторов (сканеров), получили практические навыки построения сканера на примере заданного простейшего входного языка.