Лаб 4 - Матописание

This commit is contained in:
2025-05-27 13:32:11 +03:00
parent 09da4c5c62
commit 207b428ad9
16 changed files with 438 additions and 0 deletions

5
lab4/report/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
**/*
!.gitignore
!report.tex
!img
!img/**

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
lab4/report/img/scheme.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

433
lab4/report/report.tex Normal file
View File

@@ -0,0 +1,433 @@
\documentclass[a4paper, final]{article}
%\usepackage{literat} % Нормальные шрифты
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
\usepackage{tabularx}
\usepackage[T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[russian]{babel}
\usepackage{amsmath}
\usepackage[left=25mm, top=20mm, right=20mm, bottom=20mm, footskip=10mm]{geometry}
\usepackage{ragged2e} %для растягивания по ширине
\usepackage{setspace} %для межстрочно го интервала
\usepackage{moreverb} %для работы с листингами
\usepackage{indentfirst} % для абзацного отступа
\usepackage{moreverb} %для печати в листинге исходного кода программ
\usepackage{pdfpages} %для вставки других pdf файлов
\usepackage{tikz}
\usepackage{graphicx}
\usepackage{afterpage}
\usepackage{longtable}
\usepackage{float}
% \usepackage[paper=A4,DIV=12]{typearea}
\usepackage{pdflscape}
% \usepackage{lscape}
\usepackage{array}
\usepackage{multirow}
\renewcommand\verbatimtabsize{4\relax}
\renewcommand\listingoffset{0.2em} %отступ от номеров строк в листинге
\renewcommand{\arraystretch}{1.4} % изменяю высоту строки в таблице
\usepackage[font=small, singlelinecheck=false, justification=centering, format=plain, labelsep=period]{caption} %для настройки заголовка таблицы
\usepackage{listings} %листинги
\usepackage{xcolor} % цвета
\usepackage{hyperref}% для гиперссылок
\usepackage{enumitem} %для перечислений
\newcommand{\specialcell}[2][l]{\begin{tabular}[#1]{@{}l@{}}#2\end{tabular}}
\setlist[enumerate,itemize]{leftmargin=1.2cm} %отступ в перечислениях
\hypersetup{colorlinks,
allcolors=[RGB]{010 090 200}} %красивые гиперссылки (не красные)
% подгружаемые языки — подробнее в документации listings (это всё для листингов)
\lstloadlanguages{ SQL}
% включаем кириллицу и добавляем кое−какие опции
\lstset{tabsize=2,
breaklines,
basicstyle=\footnotesize,
columns=fullflexible,
flexiblecolumns,
numbers=left,
numberstyle={\footnotesize},
keywordstyle=\color{blue},
inputencoding=cp1251,
extendedchars=true
}
\lstdefinelanguage{MyC}{
language=SQL,
% ndkeywordstyle=\color{darkgray}\bfseries,
% identifierstyle=\color{black},
% morecomment=[n]{/**}{*/},
% commentstyle=\color{blue}\ttfamily,
% stringstyle=\color{red}\ttfamily,
% morestring=[b]",
% showstringspaces=false,
% morecomment=[l][\color{gray}]{//},
keepspaces=true,
escapechar=\%,
texcl=true
}
\textheight=24cm % высота текста
\textwidth=16cm % ширина текста
\oddsidemargin=0pt % отступ от левого края
\topmargin=-1.5cm % отступ от верхнего края
\parindent=24pt % абзацный отступ
\parskip=5pt % интервал между абзацами
\tolerance=2000 % терпимость к "жидким" строкам
\flushbottom % выравнивание высоты страниц
% Настройка листингов
\lstset{
language=python,
extendedchars=\true,
inputencoding=utf8,
keepspaces=true,
% captionpos=b, % подписи листингов снизу
}
\begin{document} % начало документа
% НАЧАЛО ТИТУЛЬНОГО ЛИСТА
\begin{center}
\hfill \break
\hfill \break
\normalsize{МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ\\
федеральное государственное автономное образовательное учреждение высшего образования «Санкт-Петербургский политехнический университет Петра Великого»\\[10pt]}
\normalsize{Институт компьютерных наук и кибербезопасности}\\[10pt]
\normalsize{Высшая школа технологий искусственного интеллекта}\\[10pt]
\normalsize{Направление: 02.03.01 <<Математика и компьютерные науки>>}\\
\hfill \break
\hfill \break
\hfill \break
\hfill \break
\large{Лабораторная работа №4}\\
\large{<<Доработка компилятора языка MiLan>>}\\
\large{по дисциплине}\\
\large{<<Математическая логика и теория автоматов>>}\\
\large{Вариант 8}\\
% \hfill \break
\hfill \break
\end{center}
\small{
\begin{tabular}{lrrl}
\!\!\!Студент, & \hspace{2cm} & & \\
\!\!\!группы 5130201/20102 & \hspace{2cm} & \underline{\hspace{3cm}} &Тищенко А. А. \\\\
\!\!\!Преподаватель & \hspace{2cm} & \underline{\hspace{3cm}} & Востров А. В. \\\\
&&\hspace{4cm}
\end{tabular}
\begin{flushright}
<<\underline{\hspace{1cm}}>>\underline{\hspace{2.5cm}} 2025г.
\end{flushright}
}
\hfill \break
% \hfill \break
\begin{center} \small{Санкт-Петербург, 2025} \end{center}
\thispagestyle{empty} % выключаем отображение номера для этой страницы
% КОНЕЦ ТИТУЛЬНОГО ЛИСТА
\newpage
\tableofcontents
\newpage
\section*{Введение}
\addcontentsline{toc}{section}{Введение}
Лабораторная №4 заключается в доработке компилятора языка MiLan согласно варианту работы.
\textit{Вариант 8}: В компилятор необходимо добавить поддержку операций инкремента и декремента, как постфиксных, так и префиксных: \texttt{++i}, \texttt{--i}, \texttt{i++}, \texttt{i--}. С точки зрения действия на операнд i между префиксными и постфиксными операциями разницы нет. Если эти выражения являются частью более сложного выражения, то при префиксной форме сначала изменяется операнд i, и уже измененный результат используется в выражении. При постфиксной форме операторов инкремента или декремента сначала операнд i используется в выражении, а потом уже изменяется.
\newpage
\section {Математическое описание}
\subsection{Обзор языка MiLan}
Язык Милан — учебный язык программирования, описанный в учебнике~\cite{karpov}.
Программа на Милане представляет собой последовательность операторов, заключенных между ключевыми словами \texttt{begin} и \texttt{end}. Операторы отделяются друг от друга точкой с запятой. После последнего оператора в блоке точка с запятой не ставится. Компилятор \texttt{CMilan} не учитывает регистр символов в именах переменных и ключевых словах.
В базовую версию языка Милан входят следующие конструкции: константы, идентификаторы, арифметические операции над целыми числами, операторы чтения чисел со стандартного ввода и печати чисел на стандартный вывод, оператор присваивания, условный оператор, оператор цикла с предусловием.
Программа может содержать комментарии, которые могут быть многострочными. Комментарий начинается символами \texttt{/*} и заканчивается символами \texttt{*/}. Вложенные комментарии не допускаются.
В данной лабораторной рассматривается добавление поддержки операций инкремента и декремента, как постфиксных, так и префиксных: \texttt{++i}, \texttt{--i}, \texttt{i++}, \texttt{i--}. С точки зрения действия на операнд i между префиксными и постфиксными операциями разницы нет. Если эти выражения являются частью более сложного выражения, то при префиксной форме сначала изменяется операнд i, и уже измененный результат используется в выражении. При постфиксной форме операторов инкремента или декремента сначала операнд i используется в выражении, а потом уже изменяется.
\subsection{Лексический анализ}
В реальных трансляторах языков программирования (ЯП) первой фазой является так называемый лексический анализ входной программы — предварительная
обработка входного текста с выделением в нем структурно значимых единиц — лексем. На Рис.~\ref{fig:scheme} представлена схема транслятора.
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/scheme.png}
\caption{Схема транслятора.}
\label{fig:scheme}
\end{figure}
Лексемы — минимальные единицы языка, которые имеют смысл.
Значение лексемы, определяющее подстроку символов входной цепочки, соответствующих распознанному классу лексемы. В зависимости от класса, значение
лексемы может быть преобразовано во внутреннее представление уже на этапе лексического анализа.
Класс лексемы, определяющий общее название для категории элементов, обладающих общими свойствами (идентификатор, целое число, строка символов...).
Лексический анализатор обрабатывает входную цепочку, а на его вход подаются
символы, сгруппированные по категориям. Поэтому перед лексическим анализом
осуществляется дополнительная обработка, сопоставляющая с каждым символом его
класс, что позволяет сканеру манипулировать единым понятием для целой группы
символов.
Лексический анализатор (лексер) — это конечный автомат, который преобразует входную строку символов в последовательность токенов. Формально его можно описать следующим образом:
Пусть заданы:
\begin{itemize}
\item $\Sigma$ — входной алфавит (множество допустимых символов)
\item $T$ — множество типов токенов
\item $D$ — множество допустимых значений токенов
\end{itemize}
Тогда лексический анализатор реализует отображение:
\[
F_{\text{lexer}} : \Sigma^* \rightarrow (T \times D)^*
\]
где:
\begin{itemize}
\item $\Sigma^*$ — множество всех возможных строк над алфавитом $\Sigma$
\item $(T \times D)^*$ — множество последовательностей пар (тип токена, значение)
\end{itemize}
Процесс лексического анализа можно представить как \textbf{детерминированный конечный автомат (ДКА)}:
\[
M = (Q, \Sigma, \delta, q_0, F),
\]
где:
\begin{itemize}
\item $Q$ — множество состояний автомата
\item $\delta : Q \times \Sigma \rightarrow Q$ — функция переходов
\item $q_0 \in Q$ — начальное состояние
\item $F \subseteq Q$ — множество конечных состояний
\end{itemize}
Для каждого распознанного токена $t_i$ выполняется:
\[
t_i = (\text{type}, \text{value}), \quad \text{где } \text{type} \in T, \text{value} \in D
\]
\subsection{Синтаксический анализ}
Синтаксический анализ — процесс сопоставления линейной последовательности лексем естественного или формального языка с его формальной грамматикой.
Результатом обычно является дерево разбора. Обычно применяется совместно с лексическим анализом.
Синтаксический анализатор выражений (парсер) — часть программы,
выполняющая чтение и анализ выражения.
Существует два типа алгоритмов синтаксического анализа: нисходящий и восходящий:
\begin{itemize}
\item Нисходящий парсер — продукции грамматики раскрываются, начиная со стартового символа, до получения требуемой последовательности токенов.
\item Восходящий парсер — продукции восстанавливаются из правых частей, начиная с токенов и кончая стартовым символом.
\end{itemize}
Грамматика языка MiLan использует нисходящий парсер. При восстановлении
синтаксического дерева при нисходящем разборе слева направо последовательно анализирует все поддеревья, принадлежащие самому левому нетерминалу. Когда самым
левым становится другой нетерминал, анализируется уже он.
Компилятор CMilan включает три компонента (Рис.~\ref{fig:compiler}):
\begin{enumerate}
\item лексический анализатор;
\item синтаксический анализатор;
\item генератор команд виртуальной машины Милана.
\end{enumerate}
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/compiler.png}
\caption{Компоненты компилятора CMilan.}
\label{fig:compiler}
\end{figure}
\subsection{Грамматика языка MiLan}
Грамматика языка Милан является контекстно-свободной, так как удовлетворяет определению КС-грамматики, т.е. продукции грамматики имеют вид $A \rightarrow \beta$, где $A$ одиночный нетерминал, а $\beta$ произвольная цепочка из терминалов и нетерминалов. Более того, грамматика языка Милан является LL(1) грамматикой, так как необходимо просмотреть поток всего на один символ вперед при принятии решения о том, какое правило грамматики необходимо применить. В данной работе в грамматику были добавлены операции инкремента и декремента, однако это не повлияло на LL(1) свойство грамматики.
Грамматика языка Милан, расширенная операцией инкремента и декремента, в форме Бэкуса-Наура приведена ниже:
\begin{verbatim}
<program> ::= begin <statementList> end
<statementList> ::= <statement> ; <statementList>
| epsilon
<statement> ::= <ident> := <expression>
| if <relation> then
<statementList> [else <statementList>] fi
| while <relation> do <statementList> od
| write ( <expression> )
<expression> ::= <term> {<addop> <term>}
<term> ::= <factor> {<mulop> <factor>}
<factor> ::= <ident>
| <ident> ++
| <ident> --
| ++ <ident>
| -- <ident>
| <number>
| ( <expression> )
<relation> ::= <expression> <cmpi> <expression>
<addop> ::= +|-
<mulop> ::= *|/
<cmpi> ::= =|!=|<|<=|>|>=
<ident> ::= <letter> {<letter> | <digit>}
<letter> ::= a|b|c | ...| z|A|B|C | ...| Z
<digit> ::= 0|1|2|3|4|5|6|7|8|9
\end{verbatim}
Изменения коснулись только правила \texttt{<factor>}, в котором были добавлены 4 новые продукции, описывающие операции постфиксного и префиксного инкремента и декремента.
Синтаксические диаграммы для всех нетерминалов грамматики приведены на Рис.~\ref{fig:syntax_diagram_program} — Рис.~\ref{fig:syntax_diagram_digit}. Обновлённая синтаксическая диаграмма для нетерминала \texttt{<factor>} приведена на Рис.~\ref{fig:syntax_diagram_factor}.
\begin{figure}[h!]
\centering
\includegraphics[width=0.9\linewidth]{img/syntax_diagram_program.png}
\caption{Синтаксическая диаграмма для нетерминала \texttt{<program>}.}
\label{fig:syntax_diagram_program}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/syntax_diagram_statementList.png}
\caption{Синтаксическая диаграмма для нетерминала \texttt{<statementList>}.}
\label{fig:syntax_diagram_statementList}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/syntax_diagram_statement.png}
\caption{Синтаксическая диаграмма для нетерминала \texttt{<statement>}.}
\label{fig:syntax_diagram_statement}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.7\linewidth]{img/syntax_diagram_expression.png}
\caption{Синтаксическая диаграмма для нетерминала \texttt{<expression>}.}
\label{fig:syntax_diagram_expression}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/syntax_diagram_relation.png}
\caption{Синтаксическая диаграмма для нетерминала \texttt{<relation>}.}
\label{fig:syntax_diagram_relation}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.5\linewidth]{img/syntax_diagram_addop.png}
\caption{Синтаксическая диаграмма для нетерминала \texttt{<addop>}.}
\label{fig:syntax_diagram_addop}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.5\linewidth]{img/syntax_diagram_mulop.png}
\caption{Синтаксическая диаграмма для нетерминала \texttt{<mulop>}.}
\label{fig:syntax_diagram_mulop}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.65\linewidth]{img/syntax_diagram_factor.png}
\caption{Синтаксическая диаграмма для нетерминала \texttt{<factor>}, дополненная операциями инкремента и декремента (отмечены зеленым цветом).}
\label{fig:syntax_diagram_factor}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.6\linewidth]{img/syntax_diagram_ident.png}
\caption{Синтаксическая диаграмма для нетерминала \texttt{<ident>}.}
\label{fig:syntax_diagram_ident}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/syntax_diagram_letter.png}
\caption{Синтаксическая диаграмма для нетерминала \texttt{<letter>}.}
\label{fig:syntax_diagram_letter}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=1\linewidth]{img/syntax_diagram_digit.png}
\caption{Синтаксическая диаграмма для нетерминала \texttt{<digit>}.}
\label{fig:syntax_diagram_digit}
\end{figure}
\newpage
\phantom{text}
\section{Особенности реализации}
\subsection{Token}
\newpage
\section{Результаты работы программы}
Результаты работы программы представлены на Рис.~\ref{fig:result1}.
% \begin{figure}[h!]
% \centering
% \includegraphics[width=1\linewidth]{img/result1.png}
% \caption{Результаты работы программы.}
% \label{fig:result1}
% \end{figure}
% % \newpage
% \begin{figure}[h!]
% \centering
% \includegraphics[width=0.5\linewidth]{img/wrong.png}
% \caption{Реакция программы на некорректный пользовательский ввод.}
% \label{fig:wrong}
% \end{figure}
На Рис.~\ref{fig:wrong} представлена реакция программы на некорректный пользовательский ввод.
\newpage
\section*{Заключение}
\addcontentsline{toc}{section}{Заключение}
В ходе выполнения лабораторной работы была построена контекстно-свободная грамматика для подмножества немецкого языка, описывающая простое прошедшее время Претерит. На основе разработанной грамматики была реализована программа, которая проверяет принадлежность входной строки заданному языку и генерирует случайные корректные предложения. Для анализа предложений использовался алгоритм LL(1)-разбора, основанный на построении множеств FIRST и FOLLOW для всех нетерминалов грамматики и создании таблицы синтаксического анализа.
Из достоинств выполнения лабораторной работы можно выделить возможность задания грамматики в отдельном текстовом файле, что позволяет легко изменять и расширять её без модификации программного кода. Также программа автоматически проверяет, что введенная грамматика является LL(1)-грамматикой. В противном случае, программа выводит сообщение об ошибке, в указывается на конкретные правила грамматики, между выбором которых возникает неоднозначность.
К недостаткам текущей реализации можно отнести ограниченность словарного запаса, что сужает разнообразие генерируемых предложений. Также алгоритм генерации не контролирует длину предложений, что может приводить к избыточно длинным или коротким конструкциям. В текущей версии система не учитывает некоторые грамматические особенности немецкого языка, например, склонение прилагательных и согласование артиклей с родом существительных.
Функционал программы несложно масштабировать. Грамматику легко расширять, добавляя новые слова и правила в текстовый файл без необходимости изменения программного кода. Класс Grammar может служить хорошей основой для создания полноценного LL(k) анализатора.
На выполнение лабораторной работы ушло около 12 часов. Работа была выполнена в среде разработки Visual Studio Code. Программа написана на Python версии 3.13.
\newpage
\section*{Список литературы}
\addcontentsline{toc}{section}{Список литературы}
\vspace{-1.5cm}
\begin{thebibliography}{0}
\bibitem{vostrov}
Востров, А.В. Курс лекций по дисциплине <<Математическая логика>>. URL \url{https://tema.spbstu.ru/compiler/} (дата обращения 01.05.2025 г.)
\bibitem{aho}
А. Ахо, М. Лам, Р. Сети, Дж. Ульман, Компиляторы: принципы, технологии и инструментарий, 2-е изд. М.: Вильямс, 2011.
\bibitem{karpov}
Ю.Г. Карпов, Теория и технология программирования. Основы построения трансляторов. СПб.: БХВ-Петербург, 2005.
\end{thebibliography}
\end{document}