Interpret jazyka IFJ2011

Podobné dokumenty
Implementace překladače imperativního jazyka IFJ05

1 Úvod do kompilátorů

O datových typech a jejich kontrole

Obsah přednášky. programovacího jazyka. Motivace. Princip denotační sémantiky Sémantické funkce Výrazy Příkazy Vstup a výstup Kontinuace Program

Implementace seznamů do prostředí DELPHI pomocí lineárního seznamu

GENEROVÁNÍ KÓDU 9. SHRNUTÍ - PŘÍKLAD POSTUPU PŘEKLADU VSTUPNÍHO PROGRAMU (ZA POUŽITÍ DOSUD ZNÁMÝCH TECHNIK)

Virtuální počítač. Uživatelský program Překladač programovacího jazyka Operační systém Interpret makroinstrukcí Procesor. PGS K.

8) Jaké jsou důvody pro použití víceprůchodového překladače Dříve hlavně kvůli úspoře paměti, dnes spíše z důvodu optimalizace

PROGRAMOVACÍ JAZYKY A PŘEKLADAČE REALIZACE PŘEKLADAČE I

Roman Lukáš

Implementace LL(1) překladů

Úvod z historie. Kompilátory. Kompilace / Kompilátor Compile / Compiler. Pojem kompilátoru. Úvod z historie

Distanční opora předmětu: Programování v jazyce C Tématický blok č. 8: Dynamické datové struktury, ladění programů Autor: RNDr. Jan Lánský, Ph.D.

Problém, jehož různé instance je třeba často řešit Tyto instance lze vyjádřit větami v jednoduchém jazyce

Maturitní otázky z předmětu PROGRAMOVÁNÍ

2 Základní funkce a operátory V této kapitole se seznámíme s použitím funkce printf, probereme základní operátory a uvedeme nejdůležitější funkce.

Uplatnění metod na zvolený jazyk

Konstruktory překladačů

Algoritmus Minimax. Tomáš Kühr. Projektový seminář 1

Programovací jazyk Pascal

Vyučovací hodina. 1vyučovací hodina: 2vyučovací hodiny: Opakování z minulé hodiny. Procvičení nové látky

PROGRAMOVACÍ JAZYKY A PŘEKLADAČE LEXIKÁLNÍ ANALÝZA

Generování vnitřní reprezentace programu

for (int i = 0; i < sizeof(hodnoty) / sizeof(int); i++) { cout<<hodonoty[i]<< endl; } cin.get(); return 0; }

Čtvrtek 8. prosince. Pascal - opakování základů. Struktura programu:

Semestrální práce KIV/PC Řešení kolizí frekvencí sítě vysílačů Zdeněk Bečvář A14B0466P 10. ledna 2016

{krivka, 11. října 2009

Implementace interpretu imperativního jazyka IFJ12

Lexikální analýza. Rozhraní lexikálního analyzátoru. Miroslav Beneš Dušan Kolář. M. Beneš, D. Kolář: Lexikální analýza 1. Lexikální analýza 2

Náznak ukázky syntaxe a sémantiky pro projekt. 1 Syntaktické prvky. Poslední aktualizace: 8.

Zápis programu v jazyce C#

Syntaktická analýza. Implementace LL(1) překladů. Šárka Vavrečková. Ústav informatiky, FPF SU Opava

Lexikální analýza. Miroslav Beneš Dušan Kolář

ALGORITMIZACE A PROGRAMOVÁNÍ

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Sémantika Tabulka symbolů Intermediální kód Typová kontrola, přetypování Statická a dynamická sémantika. Sémantická analýza.

Reprezentace aritmetického výrazu - binární strom reprezentující aritmetický výraz

for (i = 0, j = 5; i < 10; i++) { // tělo cyklu }

Teoretické minimum z PJV

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

Programování v C++ 1, 1. cvičení

20. Projekt Domácí mediotéka

Automaty a gramatiky(bi-aag) Motivace. 1. Základní pojmy. 2 domácí úkoly po 6 bodech 3 testy za bodů celkem 40 bodů

PREPROCESOR POKRAČOVÁNÍ

Algoritmizace prostorových úloh

IB109 Návrh a implementace paralelních systémů. Kolektivní komunikační primitava. RNDr. Jiří Barnat, Ph.D.

{ikroustek,

Další aspekty architektur CISC a RISC Aktuálnost obsahu registru

Lexikální analýza Teorie programovacích jazyků

Dynamické programování

Programování. Psaní čistého kódu. Martin Urza

Spojová implementace lineárních datových struktur

Pascal. Katedra aplikované kybernetiky. Ing. Miroslav Vavroušek. Verze 7

Obsah. Předmluva 13 Zpětná vazba od čtenářů 14 Zdrojové kódy ke knize 15 Errata 15

Západočeská univerzita v Plzni Dokumentace překladače PL/0 v PHP Předmět KIV/FJP

Implementace numerických metod v jazyce C a Python

Distribuovaná synchronizace. Paralelní a distribuované systémy. 11. Přednáška Vzájemné vyloučení. Centralizovaný algoritmus - fronta procesů

PROGRAMOVACÍ JAZYKY A PŘEKLADAČE LL SYNTAKTICKÁ ANALÝZA DOKONČENÍ, IMPLEMENTACE.

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

Úvod do programování

- znakové konstanty v apostrofech, např. a, +, (znak mezera) - proměnná zabírá 1 byte, obsahuje kód příslušného znaku

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Poslední nenulová číslice faktoriálu

Semestrální práce implementuje univerzální tokenizer založený na stavovém automatu. Jsou implementovány následující automaty:

IB108 Sada 1, Příklad 1 Vypracovali: Tomáš Krajča (255676), Martin Milata (256615)

1. D Y N A M I C K É DAT O V É STRUKTUR Y

Abstraktní datové typy FRONTA

Martin Milata, Pokud je alespoň jeden rozměr čokolády sudý (s výjimkou tabulky velikosti 1x2, která už je od

Základní stavební prvky algoritmu

Semestrální práce z předmětu Teorie programovacích jazyků

Seminář z IVT Algoritmizace. Slovanské gymnázium Olomouc Tomáš Kühr

Algoritmizace prostorových úloh

PA152. Implementace databázových systémů

Úvod do jazyka C. Ing. Jan Fikejz (KST, FEI) Fakulta elektrotechniky a informatiky Katedra softwarových technologií

Tematický celek Proměnné. Proměnné slouží k dočasnému uchovávání hodnot během provádění aplikace Deklarace proměnných

zswi/pc-testování.d 10. května

Tabulka symbolů. Vazba (binding) Vazba - příklad. Deklarace a definice. Miroslav Beneš Dušan Kolář

Kolekce ArrayList. Deklarace proměnných. Import. Vytvoření prázdné kolekce. napsal Pajclín

Semestrální práce z předmětu. Jan Bařtipán / A03043 bartipan@studentes.zcu.cz

Dynamické datové typy a struktury

Přednáška 7. Celočíselná aritmetika. Návratový kód. Příkazy pro větvení výpočtu. Cykly. Předčasné ukončení cyklu.

Paměť počítače. alg2 1

GENEROVÁNI KÓDU jazyk Mila

Úvod do programovacích jazyků (Java)

Struktura programu v době běhu

PROGRAMOVACÍ JAZYKY A PŘEKLADAČE FORMALISMY PRO SYNTAXÍ ŘÍZENÝ PŘEKLAD: PŘEKLADOVÉ A ATRIBUTOVÉ GRAMATIKY.

1. Uživatelská úprava příkazů I.

7. Popis konečného automatu

OSTRAVSKÁ UNIVERZITA V OSTRAVĚ

Tento počítač. 1 Seznámení s programem. 2 Spuštění programu. Adresářové operace Popis programu Tento počítač, podstata adresářových operací.

PROGRAMOVACÍ JAZYKY A PŘEKLADAČE STRUKTURA PŘEKLADAČE

Poslední aktualizace: 14. října 2011

Helios RED a Internetový obchod

přirozený algoritmus seřadí prvky 1,3,2,8,9,7 a prvky 4,5,6 nechává Metody řazení se dělí:

NPRG030 Programování I, 2016/17 1 / :58:13

VYSOKÉ UČENÍ TECHNICKÉ V BRNĚ BRNO UNIVERSITY OF TECHNOLOGY

Základy programování (IZP)

Programování. Debugging a testování. Martin Urza

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

PRG036 Technologie XML

Transkript:

Dokumentace projektu Interpret jazyka IFJ2011 Tým číslo 093, varianta b/3/i: 20 % bodů: Cupák Michal (xcupak04) vedoucí týmu 20 % bodů: Číž Miloslav (xcizmi00) 20 % bodů: Černá Tereza (xcerna01) 20 % bodů: Hradecký Michal (xhrade08) 20 % bodů: Latta Martin (xlatta00) 11. 12. 2011 VYSOKÉ UČENÍ TEHNICKÉ V BRNĚ, FAKULTA INFORMAČNÍCH TECHNOLOGIÍ

Obsah 1. Implementace... 2 1.1 Lexikální analyzátor... 2 1.2 Tabulka symbolů... 3 1.3 Syntaktický analyzátor... 4 1.4 Interpret... 5 1.5 Řetězcové algoritmy... 6 2. Práce v týmu... 6 2.1 Organizace... 6 2.2 Problémy... 6 2.3 Rozdělení práce... 7 3. Metriky... 7 4. Použité zdroje... 7 1

1. Implementace Překladač se skládá z částí popsaných na přednáškách předmětu IFJ a je spojen do celku programem zapsaným v souboru main.c. 1.1 Lexikální analyzátor Lexikální analyzátor je částí projektu zpracovávající bezprostředně zdrojový kód vstupního programu. Je důležitý především svou funkcí scanner_dalsi_token, která načítá a vrací následující typ tokenu včetně jeho řetězcové reprezentace (komentáře v souboru jsou automaticky přeskakovány). Funkce rovněž vrací pozici tokenu v souboru kvůli případnému chybovému výpisu. Chyba alokace paměti pro interní řetězec je indikována vrácením speciálního typu tokenu TYP_CHYBA_ALOKACE. Zbývající dvě funkce lexikálního analyzátoru slouží k otevření a zavření zdrojového souboru. Lexikální analyzátor je implementován jako konečný automat, jehož funkce je popsána níže uvedeným grafem. Automat rozezná základní typ tokenu, načež se může stát, že ten bude dále upřesněn např. klíčové slovo se nejprve načte jako identifikátor a až posléze se porovnáním s každým z množiny daných řetězců dospěje k tomu, že se jedná o klíčové slovo. Podobným způsobem se řeší korektnost načteného řetězcového literálu. Tento způsob implementace byl zvolen za cílem redukovat jinak zbytečně velký počet stavů konečného automatu. Načítání teoreticky nekonečného řetězce je vyřešeno alokací místa v paměti o určité konstantní velikosti (tedy klasický načítací buffer). Na toto místo se postupně načítají znaky a při dosažení hranice vymezeného prostoru je paměťový prostor navýšen opět o konstantní velikost. Obrázek 1 - konečný automat lexikálního analyzátoru 2

1.2 Tabulka symbolů Tabulka symbolů slouží v programu k ukládání informací o proměnných a funkcích. Využívá se jak v syntaktické a sémantické analýze, tak při interpretaci. Skládá se ze dvou částí implementovaných jako binární vyhledávací stromy, kde klíčem uzlu je textový řetězec. Tyto dvě části jsou: globální tabulka symbolů uchovává informace o funkcích lokální tabulka symbolů uchovává informace o proměnných Obrázek 2 tabulka symbolů každá položka globální tabulky obsahuje jedinečný identifikátor funkce a počet jejích parametrů, aby bylo možné během syntaktické analýzy určit, kolik parametrů se má při volání funkce doplnit, popř. ignorovat. Dále má každá položka svou vlastní lokální tabulku, tzn. každá funkce si uchovává informace o svých proměnných (do těchto proměnných se počítají i parametry funkce). Tabulka jakožto abstraktní datový typ definuje množinu funkcí pro práci s ní, např. pro vkládání, vyhledávání pomocí klíče, nebo výpis celé tabulky včetně všech lokálních tabulek pro případné ladění. Obdobně se do lokální tabulky ukládají identifikátory proměnných, stejně jako jejich datové typy a hodnoty (tyto informace se však využijí až při interpretaci). Lokální tabulka rovněž nabízí funkce pro vkládání, vyhledávání, ukládání hodnot, výpis, apod. 3

1.3 Syntaktický analyzátor Syntaktický analyzátor kontroluje syntaktickou správnost zdrojového programu a řídí jeho překlad do námi navrženého tříadresného kódu (přeskakujeme tedy generování abstraktního syntaktického stromu). Kvůli jednoduchosti sémantické analýzy jazyka IFJ2011 se navíc stará i o ni (kontrola datových typů a již deklarovaných proměnných). Tato část programu je nejsložitější a proto je rozdělena na dvě úzce provázané části: obecný syntaktický analyzátor syntaktický analyzátor výrazů Obecný syntaktický analyzátor (dále jen obecný SA) zpracovává obdržené tokeny rekurzivním sestupem podle následující LL gramatiky: START -> FUNC ; FUNC -> function id-funkce ( PARAMS ) DEKLARACE PRIKAZY end FUNC FUNC -> e PARAMS -> id PARZBYT PARAMS -> e PARZBYT ->, id PARZBYT PARZBYT -> e DEKLARACE -> e DEKLARACE -> local id LOCALZBYT LOCALZBYT -> ; DEKLARACE LOCALZBYT -> = literal ; DEKLARACE FORMAT -> retezec FORMAT -> cislo FPARAM -> literal-id FPARAMZBYT FPARAM -> e FPARAMZBYT ->, literal-id FPARAMZBYT FPARAMZBYT -> e PRIKAZY -> e PRIKAZY -> id = IDRZBYT PRIKAZY -> write ( VV ) ; PRIKAZY PRIKAZY -> if VYRAZ then PRIKAZY else PRIKAZY end ; PRIKAZY PRIKAZY -> while VYRAZ do PRIKAZY end ; PRIKAZY PRIKAZY -> return VYRAZ ; PRIKAZY IDRZBYT -> read ( FORMAT ) ; PRIKAZY IDRZBYT -> VYRAZ ; PRIKAZY IDRZBYT -> id-funkce ( FPARAM ) ; PRIKAZY VV -> VYRAZ VZ VV -> e VZ ->, VYRAZ VZ VZ -> e 4

Syntaktický analyzátor výrazů (dále jen SA výrazů) pracuje zdola-nahoru, a to metodou precedenční syntaktické analýzy. Využívá k tomu níže uvedenou gramatiku a precedenční tabulku. SA výrazů je volán obecným SA vždy, když je na vstupu očekáván výraz. SA výrazů tento výraz analyzuje ze syntaktického i sémantického hlediska a vytvoří příslušné instrukce tříadresného kódu. Obecnému SA vrátí výsledek výrazu (přesněji vrátí odkaz na místo vytvořené v tabulce symbolů, kam se při samotné interpretaci uloží výsledek daného výrazu). I -> CISLO I -> RETEZEC I -> TRUE I -> FALSE I -> NIL I -> ID E -> I E -> (E) E -> E ^ E E -> E * E E -> E / E E -> E + E E -> E E E -> E.. E E -> E < E E -> E > E E -> E <= E E -> E >= E E -> E == E E -> E ~= E Obrázek 3 - precedenční tabulka 1.4 Interpret Interpret zajišťuje provádění vygenerovaného tříadresného kódu. Jako součást projektu přímo navazuje na syntaktický analyzátor (optimalizátor i generátor vnitřního kódu jsme se rozhodli vynechat, abychom zachovali jednoduchost). V případě úspěchu syntaktické analýzy je interpretu předán lineární seznam instrukcí námi navrženého tříadresného kódu, jenž může obsahovat následující instrukce: INSTRUKCE_MOCNINA INSTRUKCE_NASOBENI INSTRUKCE_DELENI INSTRUKCE_SOUCET INSTRUKCE_ROZDIL INSTRUKCE_KONKATENACE INSTRUKCE_MENSI INSTRUKCE_VETSI INSTRUKCE_MENSI_ROVNO INSTRUKCE_VETSI_ROVNO INSTRUKCE_NEROVNOST INSTRUKCE_ROVNOST INSTRUKCE_TYPE INSTRUKCE_SUBSTR INSTRUKCE_FIND INSTRUKCE_SORT INSTRUKCE_PRIRAZENI INSTRUKCE_CALL INSTRUKCE_RETURN INSTRUKCE_PUSH INSTRUKCE_POP INSTRUKCE_LABEL INSTRUKCE_GOTO INSTRUKCE_GOTOIF INSTRUKCE_READ_POCET INSTRUKCE_KONEC INSTRUKCE_WRITE INSTRUKCE_READ_L INSTRUKCE_READ_A INSTRUKCE_READ_N 5

Každá instrukce dále obsahuje tři obecné ukazatele dvě adresy operandů a jednu adresu výsledku. Jedná se většinou o adresy proměnných v lokální tabulce, ale může jít i o jiný typ ukazatele (např. ukazatel do globální tabulky v případě volání funkce). Důležité je, že každá instrukce očekává přesně daný typ ukazatelů, který se nesmí porušit. Předávání parametrů při volání funkcí je řešeno pomocí zásobníku, na který se ukládají kopie uzlů lokální tabulky (tedy hodnoty proměnných). Stejným zásobníkem je řešeno i předávání návratových hodnot (před každým příkazem return ve funkci se tedy provádí instrukce INSTRUKCE_PUSH nad návratovou hodnotou a po každém volání se provádí INSTRUKCE_POP). Volání funkcí navíc vyžaduje zajištění návratu na správnou adresu po příkazu return, k čemuž slouží zásobník návratových adres, do nějž lze zároveň ukládat ukazatele na kopie lokálních tabulek vznikajících při případném rekurzívním volání. 1.5 Řetězcové algoritmy Řazení pole znaků je řešeno algoritmem Shell sort, pracuje tedy in situ a není nutné alokovat další prostor pro samotné řazení, jenom je nutné mít právo přepisování předané paměti. Nestabilita této metody nám nevadí, jelikož se neřadí složitější struktury, ale pouze znaky. K vyhledávání podřetězci byl využit Boyer-Mooreův algoritmus. Inspirací nám byla verze ze studijní opory k předmětu IAL, nicméně jsme ji napsali podle vlastního pochopení této metody. 2. Práce v týmu 2.1 Organizace Náš tým pořádal nepravidelná setkání průměrně jednou každý týden. To nám pomohlo pravidelně diskutovat aktuální problémy, programovat ve více lidech apod. Jako nástroj komunikace mimo školu jsme používali IM program. Zdrojové kódy jsme sdíleli přes program Dropbox, který se ale příliš neosvědčil, zejména kvůli zmatku v souborech. Příště bychom použili některý z programů specializovaných na správu verzí. Se značnou částí návrhu nám pomohla konzultace s odborným asistentem. Rozdělování práce neprobíhalo striktně, všichni členové týmu si pomáhali navzájem. Při práci na projektu jsme navíc zjistili, jak důležité je testování, kterým jsme strávili podstatnou a velmi poučnou část projektu. Rovněž návrh a dodržování rozhraní v rámci programu byli velmi důležité. Velmi nám pomohlo soustředit se na dokončení určité části překladače do termínu pokusného odevzdání, protože bychom se nejspíš potýkali s mnohem většími časovými problémy, kdybychom začali na programu pracovat později. Dále jsme se snažili psát čitelný a dostatečně komentovaný kód dodržující zavedená pravidla tvoření identifikátorů napomáhající k větší přehlednosti a vůbec dodržovat obecné zásady efektivního programování. Do jisté míry jsme se snažili zachovávat i zapouzdřenost jednotlivých částí programu, i když se nám to ne vždy povedlo. 2.2 Problémy Projekt byl pro nás problematický především v tom, že jsme až do pozdního stadia semestru neznali princip všech částí překladače, přičemž v té době jsme ho již měli velkou část implementovanou. Z toho plynuly problémy se změnou rozhraní nebo i celé funkčnosti již napsaných částí, přepisování nebo i zahazování již napsaných částí kódu. To vše umocňoval časový stres těsně před odevzdáním, kdy jsme projektu museli všichni věnovat dvě až šest hodin denně, abychom vše stihli. Stejně tak jsme se potýkali s nevhodným návrhem některých částí překladače, což byla většinou čistě naše chyba. V závěru jsme museli řešit například nevhodně navržené předávání parametrů funkcím, přičemž jsme nakonec dospěli ke klasickému předávání pomocí zásobníku. Jeho implementace se nicméně nezdařila příliš 6

efektivně, protože nám návrh lokální tabulky neumožňuje vkládat na zásobník pouze hodnoty, což by postačovalo, ale nutí nás ukládat celé uzly lokální tabulky. Příště bychom tedy datovou strukturu, představující proměnnou, zcela oprostili od způsobu implementace lokální tabulky. 2.3 Rozdělení práce Úkoly v týmu byly zhruba rozděleny takto: Martin Latta - obecný syntaktický analyzátor, celková syntaktická analýza Michal Cupák - syntaktický analyzátor pro výrazy, organizace a vedení týmu Michal Hradecký interpret, pom. práce na ostatních částech Miloslav Číž - lexikální analyzátor, tabulka symbolů, dokumentace Tereza Černá řetězcové algoritmy, tabulka symbolů, pom. práce na ostatních částech 3. Metriky počet všech zdrojových souborů: 20 celkový počet řádků: 5555 velikost spustitelného programu (bez debugovacích informací, Linux 64bit): 83 376 bytů velikost spustitelného programu (bez debugovacích informací, Windows 64bit): 90 409 bytů 4. Použité zdroje přednášky a studijní opora předmětu IFJ přednášky a studijní opora předmětu IAL konzultace s odborným asistentem 7