% Specifikace třídy dokumentu a základní velikosti písma.
\documentclass[12pt, a4paper]{article}

% Podpora češtiny
\usepackage[utf8]{inputenc}
\usepackage[IL2]{fontenc}
\usepackage[czech]{babel}

\usepackage{amsfonts}

% Okraje stránky
\usepackage[
    left=30mm, 
    right=30mm, 
    top=40mm, 
    bottom=30mm,
%    twoside, % Při oboustranné sazbě si zkuste nastavit right=25mm a left=35mm.
    % showframe % Vykreslí okraje stránky.
]{geometry}

% Americký styl odstavců (mně se tento styl líbí o poznání více)
\usepackage{parskip}

% Sazba obrázků
\usepackage{graphicx}
\graphicspath{{Images/}} % Při vkládání obrázků se bude prefixovat tato relativní cesta.

% \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}

% Titulní strana (prostředí minimálně odstraní číslo strany)
\begin{titlepage}
    \centering      % Odtud do konce prostředí bude vše na středu,
    \Large          % velkými písmeny
    \sffamily       % a bezpatkovým písmem.

    %Vložení obrázku (ze složky `Images`)
    \includegraphics[width=.7\textwidth]{fav}

    Semestrální práce z předmětu

    % Prázdná mezera mezi řádky znamená nový odstavec.
    Programování v jazyce C
    
    % Vertikální mezera 18 mm.
    \vspace{18mm}
    {\Huge\bfseries Vizualizace grafu matematické funkce}\\

    \vspace{18mm}
    \today                          % Čas je získán ze systému.


    \vfill                          % Vyplní prostor
    \raggedright                    % Vše bude zarováno do leva.
    \textsl{Autor:}\\               % Vtípek z přednášky + ukázka tvorby makra a přidání sémantiky do stylu textu.
    Zbyněk Vajchart\\               % Příkaz \\ provede násilný zlom řádky.
    A23B0144P\\
    \texttt{zbyv@students.zcu.cz}
\end{titlepage}

\tableofcontents
\newpage

% Ukázka odstranění čísla stránky -- první stránka obsahu ale má být číslovaná!
%\thispagestyle{empty}

% Sazba nové kapitoly (ve vašem případě zde bude zřejmě zkrácená verze "Zadání")
\section{Zadání}
Naprogramujte v jazyce ANSI C přenositelnou konzolovou aplikaci, která jako vstup načte
z~parametru na příkazové řádce matematickou funkci ve tvaru $y = f(x); x, y \in \mathbb{R}$,
provede její analýzu a~vytvoří soubor ve formátu PostScript s~grafem této funkce na
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}
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.
Výhoda tohoto rozdělení je popsána níže.

\subsubsection{Lexikální analýza}
Během lexikální analýzy je funkce rozdělena na jednotlivé, dále nedělitelné \textit{tokeny} (např. konstanty, operátory, proměnné).
Některé typy tokenů pak mají hodnotu, typicky třeba konstanty --- jejich hodnotou je číslo, které reprezentují.
Výhodou lexikální analýzy je, že zjednodušuje další zpracování funkce, protože z~pohledu syntaxe je jedno, zda
se v~zápisu funkce vyskytne např.~\texttt{2}, \texttt{1e10} nebo \texttt{pi} --- všechny tyto sekvence znaků
se při lexikální analýze převedou na token \textit{konstanta} s~odpovídající hodnotou. To samozřejmě platí i~pro
jiné typy tokenů. Během lexikální analýzy jsou také odstraněny bílé znaky, které nemají v~zápisu funkce žádný význam.
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
    \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
    \texttt{MULTIPLY}   & operátor násobení \texttt{*}           \\ \hline
    \texttt{DIVIDE}     & operátor dělení \texttt{*}           \\ \hline
    \texttt{POWER}      & operátor umocnění \verb|^|           \\ \hline
    \texttt{VARIABLE}   & proměnná \texttt{x}           \\ \hline
    \texttt{FUNCTION}   & název funkce           \\ \hline
    \texttt{LEFT\_PAREN}   & levá závorka \verb|(|           \\ \hline
    \texttt{RIGHT\_PAREN}   & pravá závorka \verb|)|           \\ \hline
    \texttt{COMMA}   & oddělovač argumentů \texttt{,}           \\ \hline
    \texttt{EOF}  & konec vstupu           \\ \hline
    \texttt{ERROR} & chyba (nerozpoznatelná sekvence)          \\ \hline
    \end{tabular}
\end{table}

\subsubsection{Syntaktická analýza}
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 této gramatiky.

Pro zpracování matematických lze sestavit gramatiku

\begin{verbatim}
<expression> = <term> { ( PLUS | MINUS ) <term> }
<term> = <unary> { ( MULTIPLY | DIVIDE ) <unary> }
<unary> = [ PLUS | MINUS ] <power>
<power> = <factor> [ POWER <unary> ]
<factor> = NUMBER | VARIABLE | <function> | <bracketed>
<bracketed> = LEFT_PAREN <expression> RIGHT_PAREN
<function> = FUNCTION
             LEFT_PAREN
             <expression> { [ COMMA ] <expression> }
             RIGHT_PAREN
\end{verbatim}

kde \verb|{}| značí iteraci, \verb|[]| volitelnost a~\texttt{|} jednu z~možností.
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}
