Upload
blaz-sovdat
View
31
Download
1
Embed Size (px)
DESCRIPTION
High school thesis defence.
Citation preview
1 od 20
PREVAJALNIKI
Avtor: Blaž SovdatRazred: 4.RaMentor: mag. Boštjan Vouk
2 od 20
Kaj je prevajalnik?
Je program Izvorni program
preslika v semantično ekvivalenten ciljni program.
Rezultat prevajanja ni nujno izvršljiv program
3 od 20
Shema preprostega prevajalnika
Leksikalni analizator Parser (sintaksna analiza) Generator vmesne kode Optimizacija (neodvisna od arhitekture) Generator kode Optimizator
4 od 20
Leksikalni analizator
Neposreden ``stik'' z izvornim programom Nize vhodnih znakov grupira v lekseme Ignorira komentarje Drži sled za ``trenutno vrstico'' Razširja makroje Vrača simbole v obliki (ime, kazalec)
5 od 20
Leksikalni analizator
Izgradimo ga na podlagi vzorcev za lekseme Vzorce zapišemo z regularnimi izrazi Regularni izraz, ki opiše identifikatorje za C
(imena spremenljivk, funkciji, ...)
ID → (CRKA | ST)(CRKA | ST | _)* CRKA → A | … | z ST → 0 | … | 9
6 od 20
Leksikalni analizator
• Pri prepoznavi ključnih besed, kot je if, se pojavi problem, ker slednja ustreza tudi vzorcu za identifikator
• Problem rešimo tako, da ključne besede vnaprej vpišemo v simbolno tabelo
• Če nek niz ustreza več vzorcem, izberemo ``najdaljšega’’; npr. za elseif ne vrnemo (else,0), (if,1), temveč (elseif,0)
7 od 20
Leksikalni analizator
• Primer: izraz x := (a + b) * c;• Za zgornji izraz bi lahko dobili sekvenco simbolov
• (id,1), (assign,null), (paren,2), (id, 3), (aop, 4), (id, 5), (aop, 6), (id, 7), (term, null)
• Leksikalni analizator ne generira sekvenc ``sam po sebi’’
• Kliče ga parser, ki zahteva naslednji simbol z vhoda
• Zato moramo simbole prepoznati čim hitreje
8 od 20
Leksikalni analizator
• Sodelovanje parserja in leksikalnega analizatorja
9 od 20
Leksikalni analizator
• Za hitro prepoznavo simbolov lahko uporabimo Aho-Corasick algoritem
• Generalizacija KMP algoritma za iskanje vzorca v nizu; časovna kompleksnost O(n + m), kjer je n dolžina niza in m dolžina vzorca
• Za preproste prevajalnike kot je naš, je sprejemljivo tudi naivnejše iskanje
10 od 20
Leksikalni analizator
Na podlagi regularnih izrazov sestavimo tranzicijski diagram ali simuliramo končni avtomat
Leksikalne analizatorje lahko generiramo na podlagi opisa vzorcev
Primera takih orodij sta Lex in Flex
11 od 20
Simbolna tabela
Podatkovna struktura Ponavadi implementirana kot razpršena tabela
(hashtable) Hrani podatke o konstruktih izvornega programa
(tip spremenljivke, njena vrednost, …) Velike količine podatkov (tudi nekaj 100k vnosov) Hiter dostop Možnost redeklaracije spremenljivk (povezujemo
simbolne tabele v povezan seznam)
12 od 20
Simbolna tabela
• Naši primeri se poslužujejo kar razredov, ki jih nudita standardni knjižnici Jave in C++
• Kalkulator za simbolno tabelo uporablja Javanski razred Hashtable, prevajalnik pa ``vsebnik’’ std::map
• Slednji je realiziran z rdeče črnim drevesom (simbolna tabela ni nujno razpršena tabela)
13 od 20
Parser
Zgrajen na podlagi gramatike Dobi simbole, ki jih je vrnil leksikalni analizator Na podlagi slednjih preveri, če lahko gramatika
izpelje program (sintaktična pravilnost programa) Lahko vključuje preverjanje tipov Generira ustrezna poročila o napakah (npr.
Pričakoval ')' ) Sestavi drevo izpeljav
14 od 20
Parser
Primer LR gramatike za aritmetične izraze
E → E + T | E – T | T T → T * F | T / F | F F → (E) | id | num Primer niza, ki ga lahko generira zgornja
gramatika je '3+4' Imamo izpeljavo E => E + T => T + T
=> F + T => 3 + T => 3 + F => 3 + 4
15 od 20
Parser
• Vsi naši primeri implementirajo rekurziven LL(k) parser
• Za vsak nekončen simbol gramatike se implementira funkcijo
• Parser se za razširitev produkta odloča na podlagi enega znaka v naprej (lookahead)
• Če vhodni simbol ne ustreza nobenemu produktu, javi napako
• Gre za top-down pristop
16 od 20
Generator kode
• Za vsako produkcijo gramatike določimo dogodek
• Problem nastane pri generiranju kode za konstrukte, ki vključujejo pogojne in/ali nepogojne skoke
• Rešujemo z ``rezerviranjem’’ label, na katere smo generirali skoke
• Posledica je redundantna koda; odvečne labele in skoki, …
• Lahko rešimo s preprostimi optimizacijskimi metodami
17 od 20
Generiranje kode
• Naš prevajalnik porabi končno mnogo registrov• V realnosti imamo omejeno količino registrov,
recimo k• To je problem alokacije in dodeljevanja registrov• Je NP-poln (l. 1982 je Chaitin barvanje grafa
reduciral v alokacijo registrov)• Registre lahko alociramo z barvanjem grafa (iz kode
programa zgradimo graf)• Če je kromatično število grafa > k, potem je
potrebno generirati ``spill code.’’
18 od 20
Uporaba na drugih področjih
• Opisane tehnike niso omejene le na prevajalniško tehnologijo
• Z gramatikamo lahko opišemo protokol (lep primer je IRC protokol, opisan z ABFN) in zanj napišemo parser
• Prepoznava vzorcev v nizu je uporabna vsepovsod; npr. vsak urejevalnik besedil ima možnost iskanja niza v dokumentu
• Z gramatikami so poskusili opisati tudi naravni jezik (izkaže se, da je razred KNG gramatik je za to prešibek)
19 od 20
Gramatika našega jezika
program -> dcls block
block -> { stmts }
decls -> decls decl
decl -> type var
var -> id, var | id;
stmts -> stmts stmt
stmt -> expr
| if(bool) block
| if(bool) block else block
| while(bool) block
| break
| continue
| block
bool -> bool || join | joinjoin -> join && equ | equequ -> equ = rel j equ <> rel j relrel -> expr > expr j expr < exprexpr -> expr + term | expr - term | termterm -> term * un | term / un | term%un | unun -> -un | facfac -> (bool) | id | num | real
20 od 20
Primer izvornega programa
int i, j, m, n;
{
i := 2; m := 0; n := 1000;
while(i < n) {
j := i - 1;
while(j > 1) {
if(i % j != 0) { break; }
j := j - 1;
}
if(j = 1) { m := m + 1; }
i := i + 1;
}
}