From 5235189966a7caa843a8eb26c22fd9ce5624f639 Mon Sep 17 00:00:00 2001 From: det-fys Date: Sat, 28 Dec 2024 14:31:14 +0100 Subject: [PATCH] doku 2 --- .gitignore | 7 ++ dokumentace/PC_graph.tex | 178 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 175 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index beab05e..96bb226 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,10 @@ build/ *.svg *.ps *.pdf +*.aux +*.fdb_latexmk +*.fls +*.log +*.out +*.synctex.gz +*.toc diff --git a/dokumentace/PC_graph.tex b/dokumentace/PC_graph.tex index cb7e816..cea8471 100644 --- a/dokumentace/PC_graph.tex +++ b/dokumentace/PC_graph.tex @@ -25,13 +25,34 @@ \usepackage{graphicx} \graphicspath{{Images/}} % Při vkládání obrázků se bude prefixovat tato relativní cesta. -% \usepackage{inconsolata} +% \usepackage{zi4} +% \usepackage{courier} + % Při použití tohoto balíku začnou fungovat odkazy v textu. % Zkuste třeba kliknout na odkazy v textu (např. "1.1" na straně 2) nebo v seznamu obrázků/tabulek. % `hidelinks` skryje ošklivé výchozí rámečky kolem odkazů. \usepackage[hidelinks]{hyperref} +\usepackage{listings} +% \usepackage{minted} +\usepackage{xcolor} + +% Define code snippet settings +\lstset{ + language=C, % Set the programming language for the code snippet + basicstyle=\ttfamily, % Set the font for the code + keywordstyle=\color{blue}, % Set color for keywords + commentstyle=\color{green!60!black}, % Set color for comments + stringstyle=\color{red}, % Set color for strings + % numbers=left, % Show line numbers + % numberstyle=\tiny\color{gray}, % Style for line numbers + breaklines=true, % Enable line breaks + % frame=single, + showstringspaces=false % Don't show spaces in strings +} + + % Začátek dokumentu \begin{document} @@ -81,8 +102,8 @@ zvoleném definičním oboru. Celé zadání je k~dispozici na \url{https://www.kiv.zcu.cz/studies/predmety/pc/data/works/sw2024-02.pdf}. \section{Analýza úlohy} -Úloha se skládá ze dvou hlavních problémů: matematickou funkci je nejprve třeba analyzovat a~poté -použít výstup této analýzy ke zjištění jejích hodnot v~jednotlivých bodech a~vykreslení grafu. +Práce se zabývá dvěma hlavními úlohami: matematickou funkci je nejprve třeba analyzovat a~poté +použít výstup této analýzy k její evaluaci a~vykreslení grafu. \subsection{Analýza funkce} Analýzu zadané matematické funkce je vhodné rozdělit do dvou částí --- analýzu lexikální a~syntaktickou. @@ -99,9 +120,10 @@ Typy tokenů využité v~této práci jsou uvedeny v~tabulce~\ref{tab:tokens}. \begin{table}[] \centering + \caption{Použité typy tokenů}\label{tab:tokens} \begin{tabular}{|l|l|} \hline - označení & popis \\ \hline + \textbf{označení} & \textbf{popis} \\ \hline \texttt{NUMBER} & konstanta \\ \hline \texttt{PLUS} & operátor sčítání \texttt{+} \\ \hline \texttt{MINUS} & operátor odečítání nebo negace \texttt{-} \\ \hline @@ -116,21 +138,19 @@ Typy tokenů využité v~této práci jsou uvedeny v~tabulce~\ref{tab:tokens}. \texttt{EOF} & konec vstupu \\ \hline \texttt{ERROR} & chyba (nerozpoznatelná sekvence) \\ \hline \end{tabular} - \caption{Použité typy tokenů} - \label{tab:tokens} \end{table} \subsubsection{Syntaktická analýza} -Následuje analýza syntaktická, během které je zadaná funkce zpracována do stromové struktury, kterou je pak možné -využít pro vyhodnocování funkce v~jednotlivých bodech. +Následuje analýza syntaktická, během které je zadaná funkce zpracována do stromové struktury. Existuje mnoho způsobů, jak tuto analýzu provést, mezi základní patří např.~rekurzivní sestup nebo algoritmus shunting-yard. V~této práci je použita metoda rekurzivního sestupu, která je relativně jednoduchá a~přehledná --- program je možné mechanicky vytvořit z~gramatiky zpracovávaného jazyka. Mezi její další výhody patří, že se oproti algoritmu shunting-yard dokáže lépe vypořádat s~unárními operátory. Analyzátor rekurzivním sestupem lze obecně vytvořit z~gramatiky popisující zpracovávaný jazyk -pomocí sady funkcí, které odpovídají jednotlivým pravidlům gramatiky. To je v~tomto případě -snadné, protože pro zpracování matematického výrazu lze sestavit gramatiku +pomocí sady funkcí, které odpovídají jednotlivým pravidlům této gramatiky. + +Pro zpracování matematických lze sestavit gramatiku \begin{verbatim} = { ( PLUS | MINUS ) } @@ -149,4 +169,142 @@ kde \verb|{}| značí iteraci, \verb|[]| volitelnost a~\texttt{|} jednu z~možno Výrazy v~\verb|<>| jsou neterminály, zatímco ostatní symboly jsou terminály odpovídající tokenům z~lexikální analýzy. +Tato gramatika je typu LL(1), což znamená, že je možné se při zpracování +vždy rozhoudnout pouze na základě jednoho symbolu ze~vstupu, což zjednodušuje +implementaci analyzátoru. + +V~případě, že je zadaná funkce syntakticky správná, je během této analýzy možné +vytvořit stromovou strukturu, kde bude každý uzel +reprezentovat jednu hodnotu nebo matematickou operaci a~jeho potomci budou odpovídat +jejím operandům. +Tuto strukturu lze pak využít pro vyhodnocování zadané funkce v~jednotlivých bodech, +což je klíčové pro vykreslení grafu. Příklad stromové struktury pro funkci $\sin(2x)+ 1$ +je zobrazen na obrázku~\ref{fig:graph}. + +\begin{figure}[] + \centering + \includegraphics[width=0.6\textwidth]{graph} + \caption{Strom výrazu $\sin(2x) + 1$}\label{fig:graph} +\end{figure} + +\subsection{Vykreslení grafu} +Graf je možné vykreslit pomocí lomené čáry. To lze v~jazyce PostScript realizovat vytvořením +cesty pomocí příkazů \texttt{moveto} a~\texttt{lineto} a~jejím vykreslením příkazem \texttt{stroke}. + +Body, které budou tvořit lomenou čáru, budou zřejmě ve tvaru $(x, f(x))$, kde $f(x)$ je hodnota +zadané funkce v~bodě $x$. Zbývá otázka, jaké hodnoty vybrat pro $x$. Jednou z možností je zvolit +pevně danou šířku kroku, např.~$d = 0.1$, a vyhodnocovat funkci v~bodech $x = x_d + kd$, +kde $k$ postupně nabývá hodnot $0, 1, 2, \ldots$, dokud $x_d + kd \leq x_h$, a kde $x_d$ je dolní +a~$x_h$ horní mez zadaného intervalu pro vykreslení grafu. Nevýhodou tohoto přístupu je, že +nebere v~potaz délku zadaného intervalu, což může vést k~příliš malému počtu bodů v~případě malého intervalu a~naopak. +Lepší variantou je tedy namísto pevného kroku $d$ zvolit pevný počet bodů~$n$, +které budou tvořit lomenou čáru. V~takovém případě je krok možné určit jako $d = (x_h - x_d) / n$. + +V implementaci je také třeba vyřešit body, kde funkce není definována. + +\section{Popis implementace} +Program je rozdělen do několika modulů. Každý z~nich má vlastní rozhraní, a~implementace +každého modulu je nezávislá na implementaci ostatních modulů. + +Každý modul je popsán v~následujících podsekcích včetně popisu jeho rozhraní. + +\subsection{Vstupní bod programu --- \texttt{main.c}} + +Výkon programu začíná ve~funkci \texttt{main}, která má na starosti následující úkoly: + +\begin{itemize} + \item Ověření správného počtu vstupních argumentů. V~případě, že je počet argumentů + neplatný, program vypíše návod k~použití pomocí funkce \texttt{print\_usage} a~ukončí se. + \item Načtení rozsahu pro vykreslení grafu pomocí funkce \texttt{parse\_range}. Pokud + tento argument není uveden, použije se výchozí rozsah $x_d = y_d = -10$ a~$x_h = y_h = 10$. + \item Zpracování zadané funkce pomocí modulu \texttt{parser}, který vytvoří strom + reprezentující tuto funkci. + \item Vykreslení grafu funkce na zadaném rozsahu pomocí modulu \texttt{ps\_graph} + do zadaného souboru. K~tomuto účelu je zavolána funkce \texttt{export\_to\_file}. + \item \textit{Pokud je program zkompilován s~definicí makra \texttt{ENABLE\_GRAPHVIZ\_EXPORT}, je + strom výrazu vyexportován do souboru ve formátu \texttt{dot}.} + \item Uvolnění alokovaných zdrojů a vrácení návratového kódu. +\end{itemize} + +\subsection{Chyby --- modul \texttt{error\_buffer}} + +\subsection{Lexikální analyzátor --- modul \texttt{lexer}} +Lexikální analyzátor se stará o~tokenizaci vstupního řetězce. + +\subsubsection{Výčet \texttt{token\_type}} +Typy tokenů jsou reprezentovány výčtem \texttt{token\_type}, který obsahuje +všechny typy tokenů uvedené v~tabulce~\ref{tab:tokens}. +Názvy typů odpovídají označením v~tabulce s~prefixem \texttt{TOK\_}. + +\subsubsection{Struktura \texttt{token}} +Token je reprezentován strukturou \texttt{token}, která obsahuje typ tokenu a~případně +jeho hodnotu, pokud je to vzhledem k~jeho typu relevantní. + +\subsubsection{Struktura \texttt{lexer}} +Struktura \texttt{lexer} obsahuje stav lexikálního analyzátoru, tj.~ukazatel na zpracovávaný +řetězec, ukazatel na aktuální pozici v~tomto řetězci, aktuální token a~další informace potřebné pro zpracování. + +\subsubsection{Inicializace} +Funkce +\begin{lstlisting} + void lex_init(struct lexer *lex, const char *str, const char *variable_name); +\end{lstlisting} + +% \texttt{void lex\_init(struct lexer *lex, const char *str, const char *variable\_name);} +inicializuje lexikální analyzátor \texttt{lex} pro zpracování řetězce \texttt{str}. +\texttt{variable\_name} je název proměnné, která se ve vstupním řetězci může vyskytnout. + +Deinicializace není třeba, protože při inicializaci ani činnosti tohoto modulu není prováděna žádná alokace paměti. + +\subsubsection{Získávání tokenů} +Aktuální token je možné získat pomocí funkce +\begin{lstlisting} + struct token *lex_token(struct lexer *lex); +\end{lstlisting} +která na něj vrací ukazatel. +Pro získání dalšího tokenu je třeba zavolat funkci +\begin{lstlisting} + void lex_next(struct lexer *lex); +\end{lstlisting} + +\subsubsection{Chyba při lexikální analýze} +Pokud nastane během lexikální analýzy chyba, tzn.~v~řetězci se vyskytne sekvence znaků, +kterou nelze převést na token, je vytvořen token typu \texttt{TOK\_ERROR}. +V~tomto případě je možné pomocí funkce +\begin{lstlisting} + enum error_code lex_get_error( + const struct lexer *lex); +\end{lstlisting} +získat chybový kód. +Pro získání textové reprezentace chyby lze využít funkci +\begin{lstlisting} + const char *lex_get_error_text( + const struct lexer *lex); +\end{lstlisting} + +\subsubsection{Diagnostika} +Pro diagnostické účely je možné získat textovou reprezentaci typu tokenu funkcí +\begin{lstlisting} + const char *lex_token_str(enum token_type token); +\end{lstlisting} + +V~případě, že nastane chyba při dalším zpracování, je možné přehledně vypsat +aktuální pozici v~řetězci pomocí funkce +\begin{lstlisting} + void lex_print_position(const struct lexer *lex, struct error_buffer *eb); +\end{lstlisting} +která ji vypíše do zásobníku \texttt{eb}. + +\subsection{Syntaktický analyzátor --- modul \texttt{parser}} + + + +\subsection{Strom výrazu --- modul \texttt{tree}} + +\subsection{Vykreslení grafu --- modul \texttt{ps\_graph}} + +\section{Uživatelská příručka} + +\section{Závěr} + \end{document}