mirror of
https://github.com/TMD44/elte-ik-pti-bsc-zarovizsga.git
synced 2025-08-13 22:39:04 +02:00
717 lines
27 KiB
TeX
717 lines
27 KiB
TeX
\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}
|
||
|
||
|
||
|