From b713991e4b97180f09300e96cb85b794d6882336 Mon Sep 17 00:00:00 2001 From: tovjemam Date: Sat, 4 Jan 2025 22:25:25 +0100 Subject: [PATCH] doku 4 --- dokumentace/PC_graph.tex | 60 +++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/dokumentace/PC_graph.tex b/dokumentace/PC_graph.tex index e17009e..2f5106e 100644 --- a/dokumentace/PC_graph.tex +++ b/dokumentace/PC_graph.tex @@ -145,13 +145,13 @@ Typy tokenů využité v~této práci jsou uvedeny v~tabulce~\ref{tab:tokens}. \label{sec:ana} 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. +V~této práci je použita metoda rekurzivního sestupu, která je relativně jednoduchá a~přehledná. 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 této gramatiky. +\newpage + Pro zpracování matematických lze sestavit gramatiku \begin{verbatim} @@ -171,9 +171,9 @@ 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. +% 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 @@ -210,6 +210,8 @@ každého modulu je (až na výjimky) nezávislá na implementaci ostatních mod Každý modul včetně jeho rozhraní je popsán v~následujících podsekcích. +\newpage + \subsection{Vstupní bod programu --- \texttt{main.c}} Výkon programu začíná ve~funkci \texttt{main}, která má na starosti následující úkoly: @@ -299,11 +301,29 @@ toho její číselnou hodnotu. \subsubsection{Vytvoření uzlu} Pro vytvoření uzlu je možné použít funkce, jejichž názvy začínají \texttt{node\_create\_}: -\texttt{node\_create\_const} (konstanta), \texttt{node\_create\_x} (proměnná), \texttt{node\_create\_add} (sčítání), -\texttt{node\_create\_sub} (odečítání), \texttt{node\_create\_mult} (násobení), \texttt{node\_create\_div} (dělení), -\texttt{node\_create\_pow} (umocnění), \texttt{node\_create\_neg} (negace), \texttt{node\_create\_fn} (funkce). -Většina těchto funkcí přijímá jako argumenty ukazatele na uzly, které se mají stát operandy vytvářeného uzlu. +\begin{lstlisting} + struct expr_node *node_create_const(double val); + struct expr_node *node_create_x(void); + struct expr_node *node_create_add( + struct expr_node *left, struct expr_node *right); + struct expr_node *node_create_sub( + struct expr_node *left, struct expr_node *right); + struct expr_node *node_create_mult( + struct expr_node *left, struct expr_node *right); + struct expr_node *node_create_div( + struct expr_node *left, struct expr_node *right); + struct expr_node *node_create_pow( + struct expr_node *base, struct expr_node *power); + struct expr_node *node_create_neg( + struct expr_node *unop); + struct expr_node *node_create_fn( + size_t fn_idx, struct expr_node **args); + +\end{lstlisting} + +Tyto funkce vrací dynamicky alokovaný uzel, který je třeba po použití uvolnit (v~případě, že se uzel stane potomkem jiného uzlu, je +automaticky uvolněn s~tímto uzlem). \subsubsection{Evaluace uzlu} Uzel lze vyhodnotit v~daném bodě pomocí funkce @@ -312,8 +332,8 @@ Uzel lze vyhodnotit v~daném bodě pomocí funkce const struct expr_node *node, double x, double *y); \end{lstlisting} -která v~případě úspěchu vrací \texttt{EVAL\_OK} a~do \texttt{y} uloží funkční hodnotu. Pokud -funkce není v tomto bodě definována, je výsledkem \texttt{EVAL\_ERROR}. +která v~případě úspěchu vrací \texttt{EVAL\_OK} a~do \texttt{y} uloží výslednou hodnotu. Pokud +funkce není v~tomto bodě definována, je výsledkem \texttt{EVAL\_ERROR}. \subsubsection{Uvolnění uzlu} Uzel je možné uvolnit pomocí funkce @@ -409,6 +429,8 @@ inicializuje lexikální analyzátor \texttt{lex} pro zpracování řetězce \te Deinicializace není třeba, protože při inicializaci ani činnosti tohoto modulu není prováděna žádná alokace paměti. +\newpage + \subsubsection{Získávání tokenů} Aktuální token je možné získat pomocí funkce \begin{lstlisting} @@ -416,7 +438,7 @@ Aktuální token je možné získat pomocí funkce const struct lexer *lex); \end{lstlisting} která na něj vrací ukazatel. -Pro získání dalšího tokenu je třeba zavolat funkci +Pro načtení dalšího tokenu je třeba zavolat funkci \begin{lstlisting} void lex_next(struct lexer *lex); \end{lstlisting} @@ -451,7 +473,7 @@ která ji vypíše do zásobníku \texttt{eb}. \subsection{Syntaktický analyzátor --- modul \texttt{parser}} Modul \texttt{parser} využívá tokeny získané lexikálním analyzátorem k~syntaktické -analýze a~vytváří stromu zadaného výrazu. +analýze a~vytváří strom zadaného výrazu. \subsubsection{Postup analýzy} Syntantický analyzátor je implementován pomocí rekurzivního sestupu. @@ -467,7 +489,7 @@ se skládá z~prefixu \texttt{parse\_} a~názvu neterminálu: Pokud je tedy výrazem například sečtení tří podvýrazů, jsou vytvořeny dva uzly sčítání: operandy prvního z nich jsou dva tyto podvýrazy a operandy druhého jsou první uzel a~třetí podvýraz. Poslední uzel je návratovou hodnotou. \item Funkce \texttt{parse\_term} postupuje obdobně jako \texttt{parse\_expression}, ale pro násobení a~dělení. Volá \texttt{parse\_unary}. - \item \texttt{parse\_unary} zjistí, zda je dalším tokenem unární operátor. V~případě, že se jedná o~mínus vytvoří uzel pro negaci, + \item \texttt{parse\_unary} zjistí, zda je dalším tokenem unární operátor. V~případě, že se jedná o~mínus, vytvoří uzel pro negaci, jehož operandem se stane návratová hodnota \texttt{parse\_power}, jinak je tato funkce zavolána přímo. \item \texttt{parse\_power} nejprve zavolá \texttt{parse\_factor} a~poté zjistí, zda následuje operátor umocnění. V~případě, že ano, vytvoří uzel pro umocnění, jehož levým operandem je návratová hodnota \texttt{parse\_factor} a~pro zpracování pravého operandu zavolá znovu \texttt{parse\_unary}, jelikož @@ -558,7 +580,7 @@ Tato funkce vypíše do souboru \texttt{file} příkazy jazyka PostScript: \subsection{Použití v~\texttt{KIV/UPG}}\label{sec:upg} Moduly umožňující vyhodnocení funkcí byly využity i v~rámci semestrální práce z předmětu \texttt{KIV/UPG}, kde sloužily k~animaci elektrických nábojů v~čase. -Z tohoto důvodu se v~práci nachází některé nadbytečné funkce: +Z tohoto důvodu se v~práci nachází některé \uv{nadbytečné} funkce: \begin{itemize} \item Vypisování chyb do zásobníku \texttt{error\_buffer} namísto standardního výstupu, jelikož @@ -580,13 +602,13 @@ Tímto vznikne spustitelný soubor \texttt{graph.exe}. \subsection{Použití} Program se spouští příkazem \texttt{graph.exe} s~následujícími argumenty: -\begin{itemize} +\begin{enumerate} \item Předpis funkce, která má být vykreslena. \item Název souboru, do kterého se má graf uložit. \item Volitelně: Rozsah grafu ve tvaru $x_d\texttt{:}x_h\texttt{:}y_d\texttt{:}y_h$, - kde $x_d$ a~$x_h$ jsou dolní a~horní mez osy $x$ a~$y_d$ a~$y_h$ jsou dolní a~horní mez osy $y$. + kde $x_d$ a~$x_h$ jsou dolní a~horní meze osy $x$ a~$y_d$ a~$y_h$ jsou dolní a~horní meze osy $y$. V případě, že tento argument není uveden, použije se výchozí rozsah $x_d = y_d = -10$ a~$x_h = y_h = 10$. -\end{itemize} +\end{enumerate} Návratová hodnota programu odopovídá některému z chybových kódů uvedených v~tabulce~\ref{tab:errors}. Při úspěšném vykreslení vznikne soubor se zadaným názvem, který bude obsahovat graf funkce ve formátu PostScript.