This commit is contained in:
tovjemam 2025-01-04 22:25:25 +01:00
parent ddec1650e6
commit b713991e4b

View File

@ -145,13 +145,13 @@ Typy tokenů využité v~této práci jsou uvedeny v~tabulce~\ref{tab:tokens}.
\label{sec:ana} \label{sec:ana}
Následuje analýza syntaktická, během které je zadaná funkce zpracována do stromové struktury. 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. 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é V~této práci je použita metoda rekurzivního sestupu, která je relativně jednoduchá a~přehledná.
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 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. pomocí sady funkcí, které odpovídají jednotlivým pravidlům této gramatiky.
\newpage
Pro zpracování matematických lze sestavit gramatiku Pro zpracování matematických lze sestavit gramatiku
\begin{verbatim} \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í Výrazy v~\verb|<>| jsou neterminály, zatímco ostatní symboly jsou terminály odpovídající
tokenům z~lexikální analýzy. tokenům z~lexikální analýzy.
Tato gramatika je typu LL(1), což znamená, že je možné se při zpracování % 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 % vždy rozhoudnout pouze na základě jednoho symbolu ze~vstupu, což zjednodušuje
implementaci analyzátoru. % implementaci analyzátoru.
V~případě, že je zadaná funkce syntakticky správná, je během této analýzy možné 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 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. 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}} \subsection{Vstupní bod programu --- \texttt{main.c}}
Výkon programu začíná ve~funkci \texttt{main}, která má na starosti následující úkoly: 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} \subsubsection{Vytvoření uzlu}
Pro vytvoření uzlu je možné použít funkce, jejichž názvy začínají \texttt{node\_create\_}: 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} \subsubsection{Evaluace uzlu}
Uzel lze vyhodnotit v~daném bodě pomocí funkce 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, const struct expr_node *node,
double x, double *y); double x, double *y);
\end{lstlisting} \end{lstlisting}
která v~případě úspěchu vrací \texttt{EVAL\_OK} a~do \texttt{y} uloží funkční hodnotu. Pokud 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}. funkce není v~tomto bodě definována, je výsledkem \texttt{EVAL\_ERROR}.
\subsubsection{Uvolnění uzlu} \subsubsection{Uvolnění uzlu}
Uzel je možné uvolnit pomocí funkce 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. 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ů} \subsubsection{Získávání tokenů}
Aktuální token je možné získat pomocí funkce Aktuální token je možné získat pomocí funkce
\begin{lstlisting} \begin{lstlisting}
@ -416,7 +438,7 @@ Aktuální token je možné získat pomocí funkce
const struct lexer *lex); const struct lexer *lex);
\end{lstlisting} \end{lstlisting}
která na něj vrací ukazatel. 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} \begin{lstlisting}
void lex_next(struct lexer *lex); void lex_next(struct lexer *lex);
\end{lstlisting} \end{lstlisting}
@ -451,7 +473,7 @@ která ji vypíše do zásobníku \texttt{eb}.
\subsection{Syntaktický analyzátor --- modul \texttt{parser}} \subsection{Syntaktický analyzátor --- modul \texttt{parser}}
Modul \texttt{parser} využívá tokeny získané lexikálním analyzátorem k~syntaktické 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} \subsubsection{Postup analýzy}
Syntantický analyzátor je implementován pomocí rekurzivního sestupu. 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 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. 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 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. 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í, \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ž 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} \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}, 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. 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} \begin{itemize}
\item Vypisování chyb do zásobníku \texttt{error\_buffer} namísto standardního výstupu, jelikož \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í} \subsection{Použití}
Program se spouští příkazem \texttt{graph.exe} s~následujícími argumenty: 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 Předpis funkce, která má být vykreslena.
\item Název souboru, do kterého se má graf uložit. \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$, \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$. 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}. 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. Při úspěšném vykreslení vznikne soubor se zadaným názvem, který bude obsahovat graf funkce ve formátu PostScript.