Files
2022-01-07 19:57:57 +01:00

717 lines
27 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

\documentclass[12pt,margin=0px]{article}
\usepackage{subcaption}
\usepackage{multirow}
\usepackage{listings}
\usepackage{hhline}
\usepackage{graphicx}
\usepackage{float}
\usepackage{fancyhdr}
\usepackage{amsthm}
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{makecell}
\usepackage[utf8]{inputenc}
\usepackage[thinlines]{easytable}
\usepackage[table,xcdraw]{xcolor}
\usepackage[normalem]{ulem}
\usepackage[a4paper, margin=1in]{geometry}
\usepackage{enumitem}
\usepackage{xcolor}
\newcommand\ddfrac[2]{\frac{\displaystyle #1}{\displaystyle #2}}
\definecolor{mygray}{rgb}{0.15, 0.15, 0.15}
\setlist[itemize,1]{label=$\bullet$}
\setlist[itemize,2]{label=$\circ$}
\setlist[itemize,3]{label=$\centerdot$}
\setlist[itemize,4]{label=$\cdot$}
\pagestyle{fancy}
\newcommand\blfootnote[1]{%
\begingroup
\renewcommand\thefootnote{}\footnote{#1}%
\addtocounter{footnote}{-1}%
\endgroup
}
\renewcommand{\figurename}{ábra}
\newenvironment{tetel}[1]{\paragraph{#1 \\}}{}
\newcommand{\N}{\mathbb{N}}
\newcommand{\Z}{\mathbb{Z}}
\newcommand{\R}{\mathbb{R}}
\newcommand{\Q}{\mathbb{Q}}
\newcommand{\C}{\mathbb{C}}
\makeatletter
\renewcommand\paragraph{%
\@startsection{paragraph}{4}{0mm}%
{-\baselineskip}%
{.5\baselineskip}%
{\normalfont\normalsize\bfseries}}
\makeatother
% A dokument itt kezdődik
\newcommand\lword[1]{\leavevmode\nobreak\hskip0pt plus\linewidth\penalty50\hskip0pt plus-\linewidth\nobreak #1}
\useunder{\uline}{\ul}{}
\fancyhead{}
\cfoot{9. tétel | \thepage. oldal}
\renewcommand{\headrulewidth}{0pt}
\renewcommand{\footrulewidth}{0.4pt}
\begin{document}
\thispagestyle{fancy}
\hyphenation{oddword}
\uchyph=0
\begin{center}
{\huge\bfseries\noindent 9. Programok fordítása és végrehajtása} \\
\end{center}
\section*{Bevezetés}
Amikor programot írunk, azt valamilyen programozási nyelven tesszük. Ezt a programozási nyelvtől függvényében vagy lefordítjuk a gép által értelmezhető kódra, vagy interpreterrel futtatjuk azt.
\section*{Fordítás és Interpretálás}
\subsection*{Fordítás}
A fordítás során általában egy magas szintű programozási nyelvből gépi kód keletkezik, amelyet a processzor már képes értelmezni és futtatni.\\
\noindent A következő elönyei vannak:
\begin{itemize}
\item \textbf{Gyors}, mivel a lexikális, szintaktikus és szemantikus elemzés fordítási időben, egyszer fut le, valamint ekkor optimalizáljuk a kódot.
\item \textbf{Fordítási időben sok hibát ki lehet szűrni}, ezáltal megkönnyítve a hibakeresést (debuggolást).
\item A gépi kód \textbf{nehezen visszafejthető}. (Reverse-engineering nehézkes)
\end{itemize}
Általában nagyobb programokhoz használjuk, ahol fontos a hatékonyság. A lefordított kódon később már nem (vagy csak nagyon nehezen) tudunk változtatni.\\
\noindent Hátránya, hogy a keletkezett kód nem platformfüggetlen, minden architektúrára külön-külön le kell fordítani.\\
\noindent \textbf{Például}: C, C++, Ada, Haskell
\begin{figure}[H]
\centering
\includegraphics[width=0.55\textwidth]{img/forditas_folyamatabra.png}
\caption{A fordítás folyamata}
\label{fig:forditas_folyamatabra}
\end{figure}
\subsection*{Interpretálás}
Az interpretálás során az értelmező a programkódot futás közben hajtja végre.\\
\noindent A következő elönyei vannak:
\begin{itemize}
\item Az interpretert mindössze \textbf{egyszer kell csak megírni} az adott rendszerre.
\item \textbf{Platformfüggetlen}.
\end{itemize}
\noindent Hátránya, hogy \textbf{nehéz} benne \textbf{a hibakeresés}. Sok olyan hiba maradhat a kódban, amit egy fordító kiszűrt volna (pl. típus egyezőség).\\
\noindent \textbf{Például}: PHP, JavaScript, ShellScript
\begin{figure}[H]
\centering
\includegraphics[width=0.5\textwidth]{img/interpretalas_folyamatabra.png}
\caption{Az interpretálás folyamata}
\label{fig:interpretalas_folyamatabra}
\end{figure}
\subsection*{Fordítás és Interpretálás együtt}
Egyes nyelvek (pl. Java) előfordítást használnak, melynek eredménye a \textit{bájtkód}, amely gépi kód egy virtuális gép számára.\\
\noindent A következő elönyei vannak:
\begin{itemize}
\item Elérhető a \textbf{fordítási idejű hibaellenőrzés és optimalizálás}.
\item \textbf{Platformfüggetlenség}.
\end{itemize}
\begin{figure}[H]
\centering
\includegraphics[width=0.6\textwidth]{img/bajtkod_folyamatabra.png}
\caption{Az interpretálás folyamata}
\label{fig:bajtkod_folyamatabra}
\end{figure}
\section*{Fordítási egység és a szerkesztés}
\noindent Fordítási egység a nyelvnek az az egysége, amely a fordítóprogram egyszeri lefuttatásával, a program többi részétől elkülönülten lefordítható. Ha programunkat fordítási egységekre tagoljuk, akkor elkerülhetjük azt, hogy egyetlen kisebb módosítás miatt a teljes programot újra kelljen fordítani.\\
\noindent Mivel a fordító a neki átadott forrásfájlokat teljes egészében feldolgozza, ezért a fordítási egységeket úgy tudjuk kialakítani, hogy a forrásprogramot nem egy fájlban helyezzük el, hanem fordítási egységenként tagoljuk. Ezzel a módszerrel egyből a forráskód logikai tagolása is megtörténik, így a forrásszöveg könnyebben áttekinthetővé és megérthetővé válik.\\
\noindent A tárgykód létrehozása két fázisban történik.
\begin{itemize}
\item Először a forrásfájlokat \textit{lefordítjuk}, ebből keletkezik az un. \textit{objektumkód} (pl.: .obj, .class). Ebben a gépi utasítások már megvannak, de hiányznak belőle a hivatkozások (pl változók, függvények), melyek más fájlokban vannak megvalósítva.
\textit{Fordítási egységnek} nevezzük azt, amiből egy objektumkód keletkezik.
\item Második lépésben a \textit{linker} (szerkesztő) feladata, hogy a hiányzó referenciákat kitöltse, hogy egyetlen fájlt generálva futtatható kódot kapjunk.\\\\
\noindent A linkelés lehet:
\begin{itemize}
\item \textbf{Statikus}: az object fájlokat fordítási időbe összeszerkesztjük a könyvtárakkal.
\item \textbf{Dinamikus}, betöltéskor (load-time): fordítási időben úgynevezett import könyvtárakat használunk, ezek a megosztott könyvtárakra vonatkozó hivatkozásokat tartalmaznak, amiket majd az operációs rendszer a program betöltésekor kapcsol hozzá a futtatható fájlhoz. Ha valamelyik hivatkozott megosztott könyvtár hiányzik, a programot nem lehet betölteni.
\item \textbf{Dinamikus, futtatáskor} (run-time): fordítási időben a megosztott könyvtárak betöltésére és az eljárások címeinek lekérdezésére vonatkozó rendszerhívások kerülnek a programba. A megosztott könyvtárak betöltése futás közben történik, amikor szükség van rájuk. Ezzel a megoldással lehetőség van arra, hogy a program a neki megfelelő verziójú könyvtárat megkeresse, vagy például a program indításkor ellenőrizze, hogy van-e egyáltalán ilyen. \end{itemize}
\end{itemize}
\section*{A fordítóprogram komponensei}
\begin{figure}[H]
\centering
\includegraphics[width=0.6\textwidth]{img/forditas_teljes_folyamata.png}
\caption{A fordítás lépései}
\label{fig:forditas_teljes_folyamatabra}
\end{figure}
\subsection*{Lexikális elemző}
\noindent A lexikális elemző feladata, hogy tokenekre bontsa a forráskódot.
\begin{itemize}
\item Bemenete maga a forráskód.
\item Adott egy a nyelvre jellemző reguláris (hármas típusú) nyelvtan. Ez adja meg, hogy milyen típusú tokenek szerepelhetnek a forrásban.
A tokenekhez tulajdonságokat rendelhet (pl. változó neve, literál értéke).
\item Kimenete ez a tokensorozat. Amennyiben az elemző olyan karaktersorozatot talál, amelynek nem feleltethető meg token, akkor az lexikális hibát vált ki.
\textit{Megjegyzés: Lexikális hibánál nem feltétlen szakad meg a fordítás folyamata, megpróbálhatjuk átugrani az adott részt és folytatni az elemzést, így ha több hiba is van, akkor azokat egyszerre jelezhetjük.}
\end{itemize}
\noindent A reguláris kifejezéseket \emph{véges determinisztikus automatákkal} ismerjük fel.\\
\noindent Amennyiben egy lexikális elemre az egyik automata elfogadó állapotba kerül, úgy felismertünk egy tokent. Egy karaktersorozatot egyszerre több automata is felismerhet.\\
\noindent Ha a felismert tokenek \emph{azonos hosszúak}, akkor \emph{a nyelv konfliktusos}. Ennek nem szabad előfordulnia. Az viszont lehetséges, hogy egy szót, és az ő prefixét is felismerte egy automata. Ekkor mindig a hosszabbat választjuk.
\subsection*{Szintaktikus elemző}
A szintaxis elemző bemenete a lexikális elemző kimenete. \\\\
Feladata, hogy
\begin{itemize}
\item \textit{szintaxisfát} építsen a tokenekből, a nyelvez tartozó egy környezetfüggetlen (kettes típusú) grammatika alapján, vagy ha ez lehetetlen, akkor
\item jelezze ezt \emph{szintaktikus hibaként}.
\end{itemize}
\subsubsection*{LR0 elemzés}
A lexikális elemző által előállított szimbólumsorozatot balról
jobbra olvassuk, a szimbólumokat az elemző vermébe tesszük.
\begin{itemize}
\item \emph{Léptetés}: egy új szimbólumot teszünk a bemenetről a verem tetejére.
\item \emph{Redukálás}: a verem tetején lévő szabály-jobboldalt helyettesítjük a szabály bal oldalán álló nemterminálissal
\end{itemize}
\noindent A háttérben egy véges determinisztikus automata működik:
az automata átmeneteit a verem tetejére kerülő szimbólumok határozzák meg
ha az automata végállapotba jut, redukálni kell
egyéb állapotban pedig léptetni.
\noindent Az automata bizonyos nyelvek esetén konfliktusos lehet: nem tudjuk eldönteni, hogy léptessünk vagy redukáljunk.
\subsubsection*{LR1 elemzés}
\noindent Az előző problémára kínál megoldást, kibővítve a lehetséges nyelvek halmazát.
\noindent Az ötlet, hogy \emph{olvassunk előre} egy szimbólumot.
\noindent Ha az aktuális állapot \emph{i}, és az előreolvasás eredménye az \emph{a} szimbólum:
\begin{itemize}
\item ha $ [A \rightarrow \alpha.a\beta, b] \in I_i $ és $read(I_i, a) = I_j$
akkor léptetni kell, és átlépni a \emph{j} állapotba.
\item ha $ [A \rightarrow \alpha., a] \in I_i (A \neq S'), $
akkor redukálni kell az $ A \rightarrow \alpha $ szabály szerint.
\item ha $ [S' \rightarrow S., \#] \in I_i $ és $ a = \# $, akkor el kell fogadni a szöveget, minden más esetben hibát kell jelezni.
Ha az \emph{i} állapotban \emph{A} kerül a verem tetejére:
ha\ $read(I_i,A) = I_j$, akkor át kell lépni a \emph{j} állapotba, egyébként hibát kell jelezni.
\end{itemize}
\subsubsection*{Jelmagyarázat/Kanonikus halmazok}
\paragraph{Closure/lezárás}
\noindent Ha $ I $ a grammatika egy $ LR(1) $ elemhalmaza, akkor $ closure(I) $ a legszűkebb olyan halmaz, amely az alábbi tulajdonságokkal rendelkezik:
$I \subseteq closure(I) $ ha $ [A \rightarrow \alpha.B\gamma,a] \in closure(I)$,
és $ B \rightarrow \beta $ a grammatika egy szabálya, akkor $ \forall b \in FIRST1(\gamma{}a) $ esetén $ [B \rightarrow .\beta,b] \in closure(I) $
\paragraph{Read/olvasás}
Ha $ I $ a grammatika egy $ LR(1) $ elemhalmaza, $ X $ pedig terminális vagy nemterminális szimbóluma, akkor $ read(I, X) $ a legszűkebb olyan halmaz, amely az alábbi tulajdonsággal rendelkezik:
Ha $ [A \rightarrow \alpha. X\beta,a] \in I $, akkor $ closure([ A \rightarrow \alpha X.\beta,a]) \subseteq read(I, X) $.
\paragraph{LR(1) kanonikus halmazok ($ I_n $)}
\begin{itemize}
\item
$ closure([S' \rightarrow .S, \#]) $ a grammatika egy kanonikus halmaza.
\item
Ha $ I $ a grammatika egy kanonikus elemhalmaza, $ X $ egy terminális vagy nemterminális szimbóluma, és $ read(I, X) $ nem üres, akkor $ read(I, X) $ is a grammatika egy kanonikus halmaza.
\item
Az első két szabállyal az összes kanonikus halmaz előáll.
\end{itemize}
\subsection*{Szemantikus elemző}
A szemantikus elemzés jellemzően a környezetfüggő ellenőrzéseket
valósítja meg.
%Dévai diáiról
\begin{itemize}
\item
deklarációk kezelése: változók, függvények, eljárások, operátorok, típusok
\item
láthatósági szabályok
\item
aritmetikai ellenőrzések
\item
a program szintaxisának környezetfüggő részei
\item
típusellenőrzés
\item
stb.
\end{itemize}
\noindent A szemantikus elemzéshez ki kell egészítenünk a grammatikát. Rendeljünk a szimbólumokhoz attribútumokat és a szabályokhoz akciókat! Egy adott szabályhoz tartozó feltételek csak a szabályban előforduló attribútumoktól függhetnek. (Ha egy feltétel nem teljesül, akkor szemantikus hibát kell jelezni!). A szemantikus rutinok csak annak a szabálynak az attribútumait használhatják és számíthatják ki, amelyikhez az őket reprezentáló akciószimbólum tartozik. Minden szintaxisfában minden attribútumértéket pontosan egy
szemantikus rutin határozhat meg. Az így létrejövő nyelvtant \emph{\textbf{attribútum fordítási grammatikának}} (ATG) hívjuk.
\noindent A \emph{jól definiált attribútum fordítási grammatika}, olyan attribútum fordítási grammatika, amelyre igaz, hogy a grammatika által definiált nyelv mondataihoz tartozó minden szintaxisfában minden attribútum értéke egyértelműen kiszámítható.
\newpage
\noindent Egy attribútumot kétféleképpen lehet meghatározni:
\begin{itemize}
\item\noindent \textbf{Szintézissel}: a szintaxisfában alulról felfelé terjed az információ, egy szülő attribútumát a gyerekekből számoljuk. Kitüntetettnek hívjuk azokat az attribútumokat, melyeket a lexikális elemző szolgáltat.
\item \textbf{Öröklődéssel}: a szintaxisfában felülről lefelé terjed az információ. A gyerekek attribútumait a szülőé határozza meg.
\end{itemize}
\noindent Az \emph{L-ATG} olyan attribútum fordítási grammatika, amelyben minden
$ A \rightarrow X_1X_2 . . . X_n $szabályban az attribútumértékek az alábbi sorrendben meghatározhatók:
\begin{itemize}
\item
A örökölt attribútumai
\item
$ X_1 $ örökölt attribútumai
\item
$ X_1 $ szintetizált attribútumai
\item
$ X_2 $ örökölt attribútumai
\item
$ X_2 $ szintetizált attribútumai
\item
\dots
\item
$ X_n $ örökölt attribútumai
\item
$ X_n $ szintetizált attribútumai
\item
A szintetizált attribútumai
\end{itemize}
\noindent Amennyiben a nyelvtanunk ennek eleget tesz, úgy hatékonyan meghatározható minden attribútum.
\noindent A szemantikus elemzéshez jellemzően szimbólumtáblát használunk, verem szerkezettel és keresőfával vagy hash-táblával. Minden blokk egy új szint a veremben, egy szimbólum keresése a verem tetejéről indul.
% Kódgenerálás assemblyben alapvető imperatív vezérlési szerkezetekhez.
\section*{Kódgenerálás alapvető vezérlési szerkezetekhez}
A kódgenerálás feladata, hogy a szintaktikusan és szemantikusan elemzett programot tárgykóddá alakítsa. Általában szorosan összekapcsolódik a
szemantikus elemzéssel.
\newpage
\subsection*{Értékadás}
\noindent assignment $ \rightarrow $ \emph{variable} \textbf{assignmentOperator} \emph{expression}\\
\noindent // a kifejezést az eax regiszterbe kiértékelő kód\\
\noindent \texttt{mov [variable],eax}
\subsection*{Egy ágú elágazás}
\noindent statement $ \rightarrow $ \textbf{if} condition \textbf{then} program \textbf{end}\\
\noindent // a feltételt az al regiszterbe kiértékelő kód\\
\texttt{
cmp al,1\\
je Then\\
jmp End\\
Then: \\
}
// a then-ág programjának kódja\\
\texttt{
End:\\
}
\noindent \emph{Megjegyzés}: a dupla ugrásra azért van szükség, mert a feltételes ugrás hatóköre limitált.
\subsection*{Több ágú elágazás}
statement $ \rightarrow $
\\if $ condition_1 $ then $ program_1 $
\\elseif $ condition_2 $ then $ program_2 $
\\\dots
\\elseif $ condition_n $ then $ program_n $
\\else $ program_{n+1} $ end\\
\noindent // az 1. feltétel kiértékelése az al regiszterbe\\
\texttt{
cmp al,1\\
jne near Condition\_2\\
}
// az 1. ág programjának kódja\\
\texttt{
jmp End\\
...\\
}
//az n-edik feltétel kiértékelése az al regiszterbe\\
\texttt{
Condition\_n: \\
cmp al,1\\
jne near Else\\
}
// az n-edik ág programjának kódja\\
\texttt{
jmp End\\
Else:\\
}
// az else ág programjának kódja\\
\texttt{
End:
}
\subsection*{Switch-case}
statement $ \rightarrow $ \textbf{switch} \emph{variable}
\\case $ value_1 $ : $ program_1 $
\\...
\\case $ value_n $ : $ program_n $\\
\noindent \texttt{cmp [variable], value\_1\\
je near Program\_1\\
cmp [variable], value\_2\\
je near Program\_2\\
. ..\\
cmp [variable], value\_n\\
je near Program\_n\\
jmp End\\
Program\_1:\\
}
// az 1. ág programjának kódja\\
\texttt{
. ..\\
Program\_n:\\
}
// az n-edik ág programjának kódja\\
\texttt{
End:
}
\subsection*{Ciklus}
\subsubsection*{Elől tesztelő}
statement $ \rightarrow $ \textbf{while} \emph{condition} statements \textbf{end}\\
\noindent \texttt{Begin:}\\
//a ciklusfeltétel kiértékelése az al regiszterbe\\
\texttt{cmp al,1\\
jne near End}\\
// a ciklusmag programjának kódja\\
\texttt{jmp Begin\\
End:}
\subsubsection*{Hátul tesztelő}
statement $ \rightarrow $ loop statements \textbf{while} \emph{condition}\\
\noindent
\texttt{Begin: }\\
//a ciklusmag programjának kódja\\
. ..\\
//a ciklusfeltétel kiértékelése az al regiszterbe\\
\texttt{
cmp al,1\\
je near Begin
}
\subsubsection*{For ciklus}
statement $ \rightarrow $ \textbf{for} variable \textbf{from} $ value_1 $ to $ value_2 $ statements \textbf{end}\\
\noindent // a "from" érték kiszámítása a [Változó] memóriahelyre\\
\texttt{Begin: }\\
// a "to" érték kiszámítása az eax regiszterbe\\
\texttt{cmp [variable],eax\\
ja near End}\\
// a ciklusmag kódja\\
\texttt{inc [variable]\\
jmp Begin\\
End:}
\subsection*{Statikus változók}
Kezdőérték nélküli változódefiníció fordítása:\\
\noindent \texttt{section .bss}\\
// a korábban definiált változók...\\
\texttt{Lab12: resd 1 ; 1 x 4 bájtnyi terület}\\
\noindent Kezdőértékkel adott változódefiníció fordítása:\\
\noindent \texttt{section .data}\\
// a korábban definiált változók...\\
\texttt{Lab12: dd 5 ; 4 bájton tárolva az 5-ös érték}
\subsection*{Logikai kifejezések}
\subsubsection*{kifejezés1 $ < $ kifejezés2 }
// a 2. kifejezés kiértékelése az eax regiszterbe\\
\texttt{push eax}\\
// az 1. kifejezés kiértékelése az eax regiszterbe\\
\texttt{pop ebx\\
cmp eax,ebx\\
jb Smaller\\
mov al,0 } // hamis\\
\texttt{jmp End\\
Smaller:\\
mov al,1 }// igaz\\
\texttt{End:}
\newpage
\subsubsection*{kifejezés1 $ \lbrace $ és, vagy, nem, kizáróvagy $ \rbrace $ kifejezés2 }
// a 2. kifejezés kiértékelése az al regiszterbe\\
\texttt{push ax} ; nem lehet 1 bájtot a verembe tenni!\\
// az 1. kifejezés kiértékelése az al regiszterbe\\
\texttt{pop bx} ; // bx-nek a bl részében van,\\
// ami nekünk fontos\\
\texttt{and al, bl}\\
\subsubsection*{ lusta "és" kiértékelés }
// az 1. kifejezés kiértékelése az al regiszterbe\\
\texttt{cmp al,0\\
je End\\
push ax}\\
// a 2. kifejezés kiértékelése az al regiszterbe\\
\texttt{mov bl,al\\
pop ax\\
and al,bl\\
End:}
\subsubsection*{ Alprogramok megvalósítása }
// az 1. kifejezés kiértékelése az al regiszterbe\\
\texttt{
cmp al,0\\
je End\\
push ax}\\
// a 2. kifejezés kiértékelése az al regiszterbe\\
\texttt{
mov bl,al\\
pop ax\\
and al,bl\\
End:}
\subsubsection*{ Alprogramok hívása }
// Alprogramok sémája\\
// utolsó paraméter kiértékelése eax-be\\
\texttt{push eax}\\
// ...\\
// 1. paraméter kiértékelése eax-be\\
\texttt{push eax\\
call alprogram\\
add esp,a paraméterek összhossza}
\newpage
\section*{Kódoptimalizáló}
Az optimalizálás feladata, hogy a keletkezett kód kisebb és gyorsabb legyen, úgy hogy a futás eredménye nem változik. A gyorsaság és a tömörség gyakran ellentmondanak egymásnak, és az egyik csak a másik rovására javítható.\\
\noindent Általában három lépésben szokás elvégezni:
\begin{itemize}
\item
Optimalizálási lépések végrehajtása az eredeti programon, vagy egyszerűsített változatán
\item
Kódgenerálás
\item
Gépfüggő optimalizálás végrehajtása a generált kódon
\end{itemize}
\subsection*{Lokális optimalizáció}
\noindent Egy programban egymást követő utasítások sorozatát \emph{alapblokknak} nevezzük,
\begin{itemize}
\item ha az első utasítás kivételével egyik utasítására sem lehet távolról átadni a vezérlést
\begin{itemize}
\item assembly programokban: ahová a \textbf{jmp}, \textbf{call}, \textbf{ret} utasítások "ugranak"
\item magas szintű nyelvekben: \emph{eljárások és ciklusok eleje}, \emph{elágazások ágainak első utasítása}, \emph{goto utasítások célpontjai}.
\end{itemize}
\item az utolsó utasítás kivételével nincs benne vezérlés-átadó utasítás
\begin{itemize}
\item assembly programokban: ahová a \textbf{jmp}, \textbf{call}, \textbf{ret} utasítások "ugranak"
\item magas szintű nyelvekben: \emph{elágazások és ciklusok vége}, \emph{eljárás vége}, \emph{goto utasítások célpontjai}.
\end{itemize}
\end{itemize}
\noindent Az utasítás-sorozat nem bővíthető a fenti két szabály megsértése nélkül.\\
\noindent Jelöljük meg:
\begin{itemize}
\item a program első utasítását
\item azokat az utasításokat, amelyekre távolról át lehet adni avezérlést
\item a vezérlés-átadó utasításokat követő utasításokat
\end{itemize}
\noindent Minden megjelölt utasításhoz tartozik egy alapblokk, ami a következő megjelölt utasításig (vagy az utolsó utasításig) tart.\\
\noindent \textbf{main: mov eax,[Label1]}\\
\texttt{cmp eax,[Label2]}\\
\texttt{jz True}\\
\textbf{dec dword [Label1]}\\
\texttt{inc dword [Label2]}\\
\texttt{jmp vege}\\
\textbf{True: inc dword [Label1]}\\
\texttt{dec dword [Label2]}\\
\textbf{End: ret}
\noindent Ha az optimalizálás az alapblokkok keretein belül történik, akkor garantált, hogy az átalakításnak nincs mellékhatása. Ez a \emph{lokális optimalizálás}.\\
\paragraph*{Tömörítés}
\noindent Cél: minél kevesebb konstans és konstans értékű változó legyen.\\
\noindent Konstansok összevonása: a fordítási időben kiértékelhető kifejezések kiszámítása.\\
\noindent \emph{Eredeti kód}: \texttt{a := 1 + b + 3 + 4;}\\
\noindent \emph{Optimalizált kód}: \texttt{a := 8 + b;}\\
\noindent \emph{Eredeti kód}:\\
\texttt{a := 6;}\\
\texttt{b := a / 2;}\\
\texttt{c := b + 5;}\\
\noindent \emph{Optimalizált kód}:\\
\texttt{a := 6;}\\
\texttt{b := 3;}\\
\texttt{c := 8;}\\
\noindent \emph{Eredeti kód}:\\
\texttt{x := 20 - (a * b);}\\
\texttt{y := (a * b) \^\ 2;}\\
\noindent \emph{Optimalizált kód}:\\
\texttt{t := a * b;}\\
\texttt{x := 20 - t;}\\
\texttt{y := t \^\ 2;}\\
\paragraph{Ablakoptimalizálás}
\noindent Ez egy módszer a lokális optimalizálás egyes fajtáihoz. Egyszerre csak néhány utasításnyi részt vizsgálunk a kódból. A vizsgált részt előre megadott mintákkal hasonlítjuk össze. Ha illeszkedik, akkor a mintához megadott szabály szerint átalakítjuk ezt az "ablakot" végigcsúsztatjuk a programon. Az átalakítások megadása:
\begin{center}
$ \lbrace$ minta $ \rightarrow $ helyettesítés $\rbrace$ szabályhalmazzal\\
(a mintában lehet paramétereket is használni)
\end{center}
\noindent Példák:
\begin{itemize}
\item
felesleges műveletek törlése: nulla hozzáadása vagy kivonása
\item
egyszerűsítések: nullával szorzás helyett a regiszter törlése
\item
regiszterbe töltés és ugyanoda visszaírás esetén a visszaírás elhagyható
\item
utasításismétlések törlése: ha lehetséges, az ismétlések törlése
\end{itemize}
\newpage
\noindent Példa: \\
\noindent Ablak mérete: 1 utasítás\\
Szabályhalmaz:\\
\{\texttt{mov reg,0 $\to$ xor reg,reg},\\
\texttt{add reg,0 $\to$ elhagyható}\}\\
\noindent \emph{Eredeti kód}:\\
\texttt{add eax,0}\\
\texttt{mov ebx,eax}\\
\texttt{mov ecx,0}\\
\noindent \emph{Optimalizált kód}:\\
\texttt{; elhagyott utasítás}\\
\texttt{mov ebx,eax}\\
\texttt{xor ecx,ecx}
\subsection*{Globális optimalizáció}
A teljes program szerkezetét meg kell vizsgálni. Ennek módszere az adatáram-analízis:
\begin{itemize}
\item
Mely változók értékeit számolja ki egy adott alapblokk?
\item
Mely változók értékeit melyik alapblokk használja fel?
\end{itemize}
\noindent Ez lehetővé teszi az
\begin{itemize}
\item azonos kifejezések többszöri kiszámításának kiküszöbölését akkor is, ha különböző alapblokkokban szerepelnek
\item a konstansok és változók továbbterjesztését alapblokkok között
\item elágazások, ciklusok optimalizálását
\end{itemize}
\paragraph*{Kódkiemelés}
\newenvironment{lbmatrix}{\begin{bmatrix*}[l]}{\end{bmatrix*}}
\noindent \emph{Eredeti kód}:
\begin{verbatim}
if( x < 10 )
{
b++;
a = 0;
}
else
{
b--;
a = 0;
}
\end{verbatim}
\newpage
\noindent \emph{Optimalizált kód}:\\
\noindent \textbf{a = 0;}
\begin{verbatim}
if( x < 10 )
{
b++;
}
else
{
b--;
}
\end{verbatim}
\section*{A szekvenciális és párhuzamos/elosztott végrehajtás összehasonlítása}
\subsection*{Szekvenciális végrehajtás:}
\noindent Ilyenkor a végrehajtás egy processzoron történik. Minden művelet atomi. Egy inputhoz egy output tartozik. Két szekvenciális program ekvivalens, ha ezek a párosok megegyeznek. Nem használja fel az összes rendelkezésre álló erőforrást.
\subsection*{Párhuzamos végrehajtás:}
\noindent Több processzoron hajtódik végre a program. A párhuzamos folyamatok egymással kommunikálva, szinkronban oldják meg az adott problémát. A konkurens program szétbontható elemi szekvenciális programokra, ezek a folyamatok. A folyamatok használhatnak közös erőforrásokat: pl. változók, adattípus objektumok, kommunikációs csatornák.
\noindent A kommunikációt általában kétféleképpen szokták megvalósítani.
\paragraph{Osztott memóriával.} Ekkor szinkronizálni kell, hogy ki mikor fér hozzá, hogy ne legyen ütközés.
\paragraph{Kommunikációs csatornával.} Garantálni kell, hogy ha egy folyamat üzenetet küld egy másiknak, akkor az meg is kapja azt, és jelezzen is vissza. Ügyelni kell, nehogy deadlock alakuljon ki.
\end{document}