LEKSIČKA ANALIZA Prvi korak rada jezičnog procesora jest leksička analiza. Leksička analiza je jedini korak rada jezičnog procesora koji izravno pristupa znakovima teksta izvornog programa spremljenog u memoriji računala. Leksički analizator slijedno čita tekst izvornog programa znak po znak, stvara učinkovit zapis znakova izvornog programa znak po znak, stvara učinkovit zapis znakova izvornog programa, odbacuje znakove koji se ne koriste u daljnjim koracima rada jezičnog procesora, grupira znakove u leksičke jedinke, određuje klase leksičkim jedinkama, provjerava leksička pravila, pronalazi pogreške, određuje mjesto pogreški u izvornom programu, zapisuje parametre leksičkih jedinki u tablicu znakova i čuva tekstualnu strukturu izvornog programa. Ostvareni leksički analizator koristi dvije osnovne tablice. To su tablica uniformnih znakova i tablica znakova. Tablica znakova razlaže se na tri tablice: tablicu identifikatora, tablicu konstanti, te tablicu ključnih riječi, operatora i specijalnih znakova. Prvi korak prije pokretanja leksičke analize je dohvat potrebnih podataka. Iz datoteke source.txt se dohvaća izvorni kod koji će leksički analizator obraditi. Iz datoteke kljucne_rijeci.txt se dohvaća lista ključnih riječi, operatora i specijalnih znakova. break char const continue do else float for if int return void while { } [ ] < > ( ) ; - + * = / == *= += -= /= # & | && || ! <= >= % ++ -Tabela 1: Popis ključnih riječi , opera tora i speci jalnih zna kova 1 Navedene ključne riječi, operatore i specijalne znakove potrebno je poredati po veličini i spremiti u tablicu u memoriji. Navedena operacija se izvršava pozivom funkcije ucitajKROS(). Funkcija učitava ključne riječi, operatore i specijalne znakove iz datoteke. Funkcija vraća tablicu koja sadrži leksičke jedinke poredane od najduže prema najkraćoj, a poredak onih iste dužine nije bitan (duže jedinke imaju manji indeks u tablici). Slika 1: Pri mjer sorti rane KROS ta blice Nakon navedenih radnji može se početi sa leksičkom analizom. Klasa LeksickiAnalizator predstavlja leksički analizator. Koristi se na sljedeći način: LeksičkiAnalizator leksAnalizator(&tablicaKROS,&tablicaKON, &tablicaIDN, &tablicaUniformnih, datoteka); leksAnalizator.pokreni(); 2 Funkcija koja koristi leksički analizator treba imati tablice leksičkih jedinki čije se adrese prosljeđuju leksičkom analizatoru. U tablicu KROS moraju biti prethodno učitani sve ključne riječi, operatori i specijalni znakovi programskog jezika poredani silazno prema duljini ključne riječi/operatora/specijalnog znaka. Ostale tablice moraju biti prazne. Leksički analizator će popuniti tablice konstanti, identifikatora i uniformnih znakova iz pozivajuće funkcije. Uz adrese tablica leksičkih jedinki leksičkom analizatoru se prosljeđuje i putanja do datoteke iz koje će se učitati izvorni niz s kodom. Ako prilikom leksičke analize dođe do greške na standardni izlaz ispisuje se poruka o grešci. Ovisno o uspješnosti leksičke analize funkcija pokreni() vraća true ili false. LeksickiAnalizator::LeksickiAnalizator(Tablica *tablicaKROS, Tablica *tablicaKON, Tablica *tablicaIDN, TablicaUniformnihZnakova *tablicaUniformnih, string datoteka) Konstruktor stvara novi leksički analizator. Prima pokazivače na tablicu KROS, tablicu konstanti, identifikatora i uniformnih znakova. Niti jedan od pokazivača koje funkcija prima kao argumente ne smije pokazivati na NULL. Funkcija prima i string objekt koji sadrži putanju do datoteke u kojoj se nalazi niz koji sadrži izvorni kod programa. Ova metoda učitava niz iz te datoteke. LeksickiAnalizator::pokreni() Funkcija radi leksičku analizu niza znakova iz datoteke koja je predana ovom leksičkom analizatoru preko konstruktora. Prije same leksičke analize pomoću funkcije procistiNiz(string) uklanja nepotrebne znakove i komentare iz ulaznog niza. Funkcija gradi tablicu uniformnih znakova, te dodaje odgovarajuće leksičke jedinke u tablice identifikatora i konstanti. U slučaju da dođe do greške prilikom leksičke analize, leksički analizator nastavlja analizu i ispisuje poruku o grešci na standardni izlaz. U slučaju da leksička analiza ne uspije, funkcija vraća false, u protivnom true. Kao što je navedeno, prvi korak je pročišćavanje ulaznog niza. Leksički analizator izbacuje sve znakove koji se ne koriste u daljnim fazama rada jezičnog procesora. Pročišćavanje ulaznog niza izvršava se pozivom: procistiNiz(ulazniNiz); 3 Funkcija miče suvišne bjeline, tabove i znakove koji služe za grafičku stukturu ulaznog programa iz zadanog ulaznog niza. Funkcija Izbacuje sve jednolinijske i višelinijske komentare. Svaki podniz koji sadrži više uzastopnih tabova ili bjelina (ili oboje) zamjenjuje se jednom bjelinom. Funkcija mora vratiti string objekt koji sadrži niz preuređen na navedeni način. Grupiranje leksičkih jedinki Nakon pročišćavanja ulaznog niza, prelazi se na analizu pročišćenog niza. Niz znakova izvornog programa grupira se u leksičke jedinke. Tijekom grupiranja traži se najdulji prefiks koji je definiran. Najdulji prefiks može biti ključna riječ, operator ili specijalan znak, identifikator ili konstanta (float, int, char, string). a k o 1 9 8 8 = 2 0 0 ako1988 = 2009 Identifikator KROS INT Konstanta 9 (a) a k o 1 9 8 8 = 2 0 0 ako 1988 = 2009 KROS INT Konstanta KROS INT Konstanta 9 (b) Slika 2: Pri mjer nejednozna čnos ti , dobro (a ) i loše (b) grupi ranje znakova Na slici se vidi zašto je potrebno grupirati po najvećem prefiksu. Kada bi se znakovi grupirali po pravilu da se grupiraju čim se nađe prvi prefiks, dobila bi se kriva analiza ulaznog niza. Niz ako1988 je najdulji prefiks niza ako1988=2009 te se može zaključiti da je on identifikator. 4 Kako bi se izbjegla navedena nejednoznačnost, poziva se sljedećih šest funkcija koje će tražiti najveću duljinu prefiksa zadanog niza: Funkcije za traženje najvećeg prefiksa ulaznog niza: 1. int jeKROS(string niz); Funkcija traži da li se u tablici KROS nalazi ključna riječ, operator ili specijalni znak koji je prefiks zadanog niza, tj. funkcija traži najdulju leksičku jedinku iz tablice koja se nalazi na početku niza. Funkcija Vraća indeks te leksičke jedinke u tablici ili -1 ako niz ne započinje leksičkom jedinkom iz tablice. 2. int jeIntKON(string niz); Funkcija provjerava da li se na početku niza nalazi cjelobrojna konstanta i vraća njenu duljinu, tj. funkcija vraća duljinu najdulje moguće leksičke jedinke koja se nalazi na početku zadanog niza i predstavlja cjelobrojnu konstantu. Ako se na početku niza ne nalazi konstanta, funkcija vraća 0. Za tu operaciju korišten je konačni automat s četiri stanja: Slika 3: Kona čni automat za tra ženje dul jine prefiksa koji je cjelobrojna konstanta 5 Ako se automat na kraju izvođenja nalazi u prihvatljivom stanju, funkcija vraća duljinu cjelobrojne konstante. Ako se automat nalazi u neprihvatljivom stanju, funkcija vraća 0. Primje r izvođenja Funkcija vraća: Ulazni niz: + 1265 6 +1265 5 +123Ba654GG 4 +GZT 0 Tabela 2: Pri mjer izvođenja funkcije jeINTKon(string niz); 3. int jeFloatKON(string niz); Funkcija provjerava da li se na početku niza nalazi konstanta s posmačnim zarezom i vraća njenu duljinu, tj. funkcija vraća duljinu najdulje moguće leksičke jedinke koja se nalazi na početku zadanog niza i predstavlja konstantu s posmačnim zarezom. Ako se na početku niza ne nalazi konstanta, funkcija vraća 0. Kada automat dođe u prihvatljivo stanje, funkcija vraća duljinu konstante s posmačnim zarezom. Primje r izvođenja Funkcija vraća: Ulazni niz: 2.3 3 + 2.3dfg12.3 5 2.3e10a 6 Tabela 3: Pri mjer izvođenja funkcije jeFloatKON(string niz); 6 Za tu operaciju korišten je automat s 10 stanja: Slika 4: Kona čni automat za tra ženje dul jine prefiksa koji je kons tanta s pos ma čnim za rezom 4. int jeCharKON(string niz); Funkcija provjerava da li se na početku niza nalazi znakovna konstanta i vraća njenu duljinu, tj. funkcija vraća duljinu najdulje moguće leksičke jedinke koja se nalazi na početku zadanog niza i predstavlja znakovnu konstantu. U ovom slučaju najdulja moguća (i jedina moguća) duljina leksičke jedinke je 3. Znakvone konstante su sljedećeg oblika: <jednostrukiNavodnik><znak><jednostrukiNavodnik> Jednostruki navodnik je znak: ', a znak može biti bilo koji ASCII znak osim newlinea i taba. Escape sekvence (npr. \n, \\, \t, ...) nisu podržane i ne mogu se nalaziti unutar jednostrukih navodnika. Ako se na početku niza ne nalazi znakovna konstanta, funkcija vraća 0. 7 Za tu operaciju potreban je automat s 5 stanja: Slika 5: Kona čni automat za tra ženje dul jine prefiksa koji je znakovna kons tanta Ako se automat na kraju izvođenja nalazi u prihvatljivom stanju, funkcija vraća duljinu 3. Ako se automat nalazi u neprihvatljivom stanju, funkcija vraća 0. 5. int jeStringKON(string niz); Funkcija provjerava da li se na početku niza nalazi znakovni niz i vraća njegovu duljinu, tj. funkcija vraća duljinu najdulje moguće leksičke jedinke koja se nalazi na početku zadanog niza i predstavlja znakvoni niz. Znakovni nizovi su sljedećeg oblika: <dvostrukiNavodnici><nizZnakova><dvostrukiNavodnici> Dvostruki navodnici su znak: ", a niz znakova je niz bilo kojih ASCII znakova osim newlinea i taba. Escape sekvence (npr. \n, \\, \t, ...) nisu podržane i ne mogu se nalaziti unutar jednostrukih navodnika. Ako se na početku ulaznog niza ne nalazi leksička jedinka koja predstavlja znakovni niz, funkcija vraća 0. 8 Za tu operaciju potreban je automat s 4 stanja: Slika 6: Kona čni automat za tra ženje prefiksa koji je s tring Primje r izvođenja Ulazni niz: Funkcija vraća: ''abc'' 5 ''a'' 3 Tabela 4: Pri mjer izvođenja funkcije jeStringKON(string niz); Ako se automat na kraju izvođenja nalazi u prihvatljivom stanju, funkcija vraća duljinu stringa. Ako se automat nalazi u neprihvatljivom stanju, funkcija vraća 0. 6. int jeIDN(string niz); Funkcija provjerava da li se na početku niza nalazi identifikator i vraća njegovu duljinu, tj. funkcija vraća duljinu najdulje moguće leksičke jedinke koja se nalazi na početku zadanog niza i predstavlja identifikator. Ako se na početku niza ne nalazi identifikator, funkcija vraća 0. 9 Za tu operaciju potreban je automat s 3 stanja: Slika 7: Kona čni automat za tra ženje prefiksa koji je identi fika tor Automat započinje u stanju 0, i radi dok ima prijelaza. U stanju 0 nalazi se samo na početku, zatim prelazi u stanje 1 za prihatljivi znak, odnosno u 2 za neprihvatljivi. Automat uvijek završava rad stanjem 2. Prelaskom u stanje 2 funkcija vraća duljinu pronađenog prefiksa. Oporavak od pogreške Ako se ne može pronaći niti jedan mogući prefiks niza, potrebno je pokrenuti postupak oporavka od pogreške. Postupak oporavka od pogreške zasniva se na odbacivanju krajnje lijevog znaka niza koji nema niti jedan prefiks koji je definiran. Neka niz znakova w = a1 a2 -- an x nema nijedan prefiks koji je definiran. Postupak oporavka od pogreške odbaci znak a1 niza w, ispiše taj znak te nastavlja analizom ostatka niza a2 --- an x. Ako ni nakon odbačenog znaka a1 nijedan prefiks niza nije definiran, onda se nastavlja s izbacivanjem sljedećeg znaka. Odbacivanje se nastavlja sve dok ne ostane niz x koji ima definirani prefiks. Nejednoznačnost Glavni problem je tumačenje znakova + i - . Znakovi + i – mogu biti unarni ili binarni operatori. Navedena nejednoznačnost se rješava tako da se definira da ako navedeni znakovi dolaze poslije ' ( ' , ' = ' , ' = = ' ili ' != ' , onda se smatraju unarnim operatorima. 10 Popunjavanje tablica Na početku rada postoji jedna popunjena tablica te tri prazne. Popunjena je jedino tablica ključnih riječi, operatora i specijalnih znakova. Prazne tablice su tablica identifikatora, tablica konstanti te tablica uniformnih znakova. Osnovna tablica je tablica uniformnih znakova. U toj tablici zapisani su uniformni znakovi onim redoslijedom koim su leksičke jedinke zadane u izvornom programu. Nakon što leksički analizator odredi klasu leksičke jedinke, njezin uniformni znak zapisuje se u tablicu uniformnih znakova. Zapis u tablici sadrži dvije kazaljke za svaku leksičku jedinku. Prva kazaljka je sam uniformni znak leksičke jedinke. Ta kazaljka pokazuje na jednu od tri preostale tablice: tablicu identifikatora (uniformni znak IDN), tablicu konstanti (uniformni znak KON) ili tablicu ključnih riječi, operatora i specijalnih znakova (uniformni znak KROS). Druga kazaljka pokazuje na mjesto zapisa leksičke jedinke u tablici odabranoj primjenom prve kazaljke. Tablica uniformnih znakova Izvorni Uniformni program znak Kazaljka ako KROS 9 Leksička jedinka pripada KROS tablici, pozicija: 9. red ( KROS 21 Leksička jedinka pripada KROS tablici, pozicija: 21. red Kolicina IDN 1 Leksička jedinka pripada IDN tablici, pozicija: 1. red > KROS 19 Leksička jedinka pripada KROS tablici, pozicija: 19. re 30 KON 1 Leksička jedinka pripada KON tablici, pozicija: 1. red ) KROS Cijena IDN 22 ... 2 … = KROS 17 … 1500 KON 2 … ; KROS 26 … Tabela 5: Pri mjer popunja vanja tablice uniformnih znakova Tablice IDN i KON se popunjavaju u ovisnosti o duljini prefiksa ulaznog niza. Na primjer ako je zadovoljen uvjet: if(maxInt > maxFloat && maxInt > maxChar && maxInt > maxString) , 11 onda je navedeni prefiks tipa IN T te se sprema u tablicu konstanti. Na sličan način se određuju i ostale konstante. Tablica konstanti se sastoji od pročitane konstante te njezinog tipa. 1 20 INT 2 13.5 FLOAT 3 12345 INT Tabela 6: Pri mjer tablice kons tanti Nakon zapisa u jednu od tri navedene tablice vraća se indeks retka pojedine tablice u koji je leksička jedinka zapisana. Leksička jedinka se zapisuje na kraj tablice. Ako u tablici već postoji navedena leksička jedinka, onda se samo vraća njezin indeks. U tablicu uniformnih znakova se zapisuje samo uniformni znak pojedine leksičke jedinke, njezina pozicija u tablici konstanti, tablici identifikatora ili KROS tablici te broj linije izvornog programa gdje se nalazi. U slučaju kada funkcije za brojanje duljine prefiksa vraćaju da je duljina leksičke jedinke jednaka ključnoj riječi i identifikatoru, uzima se da je leksička jedinka ključna riječ te se u tablicu uniformnih znakova zapisuje uniformni znak KROS te njezina pozicija u KROS tablici. Nakon završetka analize cijelog ulaznog koda i popunjavanja svih tablica, sve tablice se ispisuju. Slika 8: Pri mjer ispisa tabli ce identifi katora Slika 9: Pri mjer ispisa tabli ce konstanti 12 Slika 10: Pri mjer ispisa tabli ce kl jučni h ri ječi , opera tora i specijalnih znakova 13 Slika 11: Pri mjer ispisa tabli ce uni formnih znakova 14
© Copyright 2024 Paperzz