Transleerimise etappide kirjeldamine

Nagu igasugusel programmeerimisel, on ka translaatorite kirjutamisel kvaliteetse (lihtsa, hästi struktureeritud, usaldatava ja modifitseeritava) programmi saamiseks vajalik adekvaatne metodoloogia.

Et lahendatavast probleemist täielikult aru saada, tuleb probleem ennekõike defineerida. Täpselt samuti tuleb enne translaatori kirjutamist defineerida algul selle sisendkeel, siis väljundkeel ja lõpuks kirjeldada keelte konstruktsioonide vastavus (translatsioon).

Osutub, et formaalsest sisendkeele kirjeldusest (sisendkeele grammatikast) on lihtne saada algul sisendkeele tunnistajat (recognizer) ja siis väljundkeele grammatika ja translatsiooni kirjelduse (vastavate grammatikate) lisamisel translaatorit; vastavad etapid on peaaegu mehhaanilised ja võimaldavad translaatori genereerida.

Programmi (näiteks translaatori) struktuuri (loogika) määrab selle programmi sisendi struktuur; sisend juhib programmi tööd (programmi läbimist) ja sellepärast peab programmi struktuur vastama sisendi struktuurile. Selle vastavuse saamiseks koostatakse algul sisendi tunnistaja - programm, mis kontrollib sisendi struktuuri (süntaksi) vastavust esitatud kirjeldusele (grammatikale); hiljem lisatakse sellele programmi poolt sooritatavad tegevused (sisendi teisendamine väljundiks).

Vaatleme lihtsat näidet. Olgu tarvis kirjutada programm, mis teisendab (transleerib) isikute nimekirja nii, et lisab igale nimele tema telefoninumbri (numbri annab mingi teine programm ), s.t. näiteks nimekiri

Kalle Kask
Katrin Kuusk
Peeter Puravik

teiseneks nimekirjaks

Kalle Kask 6202307
Katrin Kuusk 6202315
Peeter Puravik 6202410

Nimed on kõik eraldi ridadel; nimele vastava telefoninumbri annab automaatselt mingi teine programm vastusena päringule number(Isik).

Kui tähistada reavahetus sümboliga '\n' , võib sisendi struktuuri kirjeldada lihtsa regulaarse avaldisega

(nimi '\n')+

Mitteterminal nimi võib sisaldada suvalisi tähti ja ka tühikut (kuid esimene sümbol peab olema täht):

nimi täht (täht | )+
täht 'A'..'Z' | 'a'..'z'

ja teist produktsiooni esimesse asendades same kogu nime kirjelduse regulaarse avaldisena

nimi ('A'..'Z' | 'a'..'z')('A'..'Z' | 'a'..'z')| )+

Kogu sisendi kirjeldab regulaarne avaldis

(('A'..'Z' | 'a'..'z')('A'..'Z' | 'a'..'z')| )+ '\n')+

Sellise struktuuriga sisendi tunnistab järgnev programm (siin on kasutatud programmeerimiskeele Ada süntaksit). Programmis CH on märgitüüpi (character) muutuja, millele protseduur READ omistab sisendteksti järgmisese sümboli ja NIMI on alamprotseduur, mis loeb täht-tähelt real oleva nime muutujasse Isik; kahe kriipsu -- järel on kommentaarid.

type SYMBOL is ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 'z', 't', 'u', 'v', 'w', 'õ', 'ä', 'ö','ü', 'x', 'y', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Z', 'T', 'U', 'V', 'W', 'Õ', 'Ä', 'Ö', 'Ü', 'X', 'Y', ' ', '\n'};
subtype LETTER is SYMBOL range 'a'..' '; -- kõik tähed ja tühik
procedure SCAN(SISEND: in INFILE) is
begin
READ; while CH in SYMBOL loop -- (nimi '\n')+ NIMI; if CH = '\n'; READ; end if; end loop; if CH = '#' then ACCEPT -- # - sisendteksti lõpusümbol else RECORD_ERROR(0,POSITION) end if; end SCAN;

procedure NIMI is
--täht (täht | )+
begin
Isik = CH; while CH in LETTER loop READ; Isik = Isik + CH; end loop; end while; end NIMI;

Selline programm vaid kontrollib sisendi korrektsust, s.t. sisendi vastavust regulaarsele avaldisele

(('A'..'Z' | 'a'..'z')('A'..'Z' | 'a'..'z')| )+ '\n')+

Sellest sisendi struktuuri tunnistajast on lihtne saada teisendajat, mis lisab iga nime taha ka protseduuriga number(Isik) saadud telefoninumbri - selleks tuleb vaid alamprotseduuri NIMI lisada väljundit moodustavad tegevused:

procedure NIMI is
--täht (täht | )+
begin
Isik = CH; while CH in LETTER loop READ; Isik = Isik + CH; end loop; WRITE(Isik + ' ' + number(Isik) + '\n'); end while; end NIMI;

Siin kasutatud protseduuride READ (loeb failist INFILE järgmise sümboli ja omistab selle muutujale CH) ja WRITE (kirjutab järgmise rea faili OUTFILE) kirjeldused pole siin olulised (need on kirjeldatud kusagil mujal). Oluline on, et minimaalse muudatusega sisendit tunnistavasse programmi oli võimalik saada vajalikku teisendust sooritav programm. Sellist tehnoloogiat saab kasutada ja kasutataksegi järgnevas ka translaatori etappide (skanner, süntaksianalüsaator jne) programmeerimisel - oluline on sisendi struktuuri tunnistamine, sisendist aru saamine - sisendi struktuur määrab kogu programmi struktuuri.


Ülesandeid:
1. Kuidas peaks muutma eespool esitatud programmi, kui nimed on antud kujul:

Kask, Kalle
Kuusk, Katrin
Puravik, Peeter

s.t. ees- ja perekonnanimi on eraldatud komaga, koma võib esineda vaid üks kord; pärast koma on tühik; enne seda ja pärast seda peab olema tühikuteta string
2. Nimed algavad alati suurtähega, ülejäänud tähed on väiketähed. Täienda ülalesitatud programmi nii, et ta konrolliks ka seda tingimust.

Küsimused, probleemid: ©2004-2013 Jaak Henno