Pico-Algoli leksiline analüsaator

Ka Pico-Algoli leksiline analüsaator saadakse keelt genereerivale grammatikale ja tunnistavale programmile väljundtegevuste lisamisega

Leksilise analüsaatori (skanneri) töö tulemuseka on kaks andmestruktuuri: lähtetekstile vastav lekseemide jada ja nn nimede tabel, kus säilitatakse info programmi muutujate (identifikaatorite) kohta.

Kõik lekseemid on kolmeväljalised kirjed (record).
Lekseemi esimene väli, klass, kirjeldab, millisesse lekseemiklassi vastav lekseem kuulub; kõigi identifikaatorite klass on IDENT (s.t. ühesugune kõigil identifikaatoritel, sest transleerimise järgneval etapil, süntaksianalüüsil, identifikaatori kuju ei ole enam oluline); arvkonstantide (arvude) klass on NUMBER, operatsioonimärkide ja keele võtmesõnade klass - see märk või võtmesõna.
Lekseemi teine väli, spetsifikatsioon, on identifikaatorite korral viit nimede tablisse SYMTAB, kus säilitatakse identifikaatori tüüpi, nimekuju (alpha) ja viit mäluväljadele, kus salvestatakse identifikaatori väärtus. Arvkonstantide spetsifikatsioon on vastav väärtus ja operatsioonimärkide ja võtmesõnade spetsifikatsioon on tühi.
Lekseemi kolmas väli on selle positsioon lähtetekstis; protseduur READ salvestab selle iga uue lähteteksti sümboli lugemisel globaalses muutujas POSITION

PROGRAMM (ERALDAJA | IDENT OUT_IDENT ERALDAJA | CONST OUT_INTEGER ERALDAJA )*

IDENT TÄHT TREAT_LET_DIG (TÄHT TREAT_LET_DIG | NUM TREAT_LET_DIG )*

CONST NUM TREATINT1 NUM TREATINT2 *

ERALDAJA | OP | := OUT_OPERATOR(':=') | ' TÄHT TREAT_LET_DIG * ' OUT_KEYWORD
OP + OUT_OPERATOR(+) | - OUT_OPERATOR(-) | * OUT_OPERATOR(*) | / OUT_OPERATOR(/) | = OUT_OPERATOR(=) | ( OUT_OPERATOR('(') | )OUT_OPERATOR(')') | ; OUT_OPERATOR(;) | . OUT_OPERATOR(.)

TÄHT a GENERATE(a) | b GENERATE(b) | ... | z GENERATE(z)
NUM 0 GENERATE(0) | 1 GENERATE(1) | 2 GENERATE(2) | ... | 9 GENERATE(9)

Leksiline analüsaator kasutab uute lekseemide lisamisel nelja globaalset alamprotseduuri:

procedure OUT_IDENT

(C: in STRING
S: in TEXTPOSITION);

-- protseduur kirjutab väljundfaili LEXOUT lekseemi, mille klass on IDENT, spetsifikatsioon CS.

procedure OUT_CONSTANT

(C: in INTEGER
S: in TEXTPOSITION);

-- protseduur kirjutab väljundfaili LEXOUT lekseemi, mille klass on CONST, spetsifikatsioon CS.

procedure OUT_KEYWORD

(C: in STRING
S: in TEXTPOSITION);
v

-- protseduur kirjutab väljundfaili LEXOUT lekseemi, mille klass on C (s.t. võtmesõna ise!), spetsifikatsioon on tühi ja positsioon lähtetekstis S.

procedure OUT_KEYWORD

(C: in STRING
S: in TEXTPOSITION);

-- protseduur kirjutab väljundfaili LEXOUT lekseemi, mille klass on C (s.t. võtmesõna ise!), spetsifikatsioon on tühi ja positsioon lähtetekstis S.

procedure OUT_OPERATOR

(C: in STRING
S: in TEXTPOSITION);

-- protseduur kirjutab väljundfaili LEXOUT lekseemi, mille klass on C (s.t. eraldaja ise; ka omistusmärk ':=' asendatakse ühe sümboliga!), spetsifikatsioon on tühi ja positsioon lähtetekstis S.

Funktsioon LOOKUPSYMTAB kontrollib, kas sisendtekstis leitud identifikaator on juba kantud nimede tabelisse ja kui on, annab vastava reanumbri; kui ei ole, lisab tabelisse uue rea; maxc on praegune ridade arv tabelis; tabeli lubatud (maksimaalne) ridade arv on maxsymbtab, kui maxc > maxsymbtab, tuleb veateade.

function LOOKUPSYMTAB

(C: in STRING;
maxc: in out INTEGER) return ADR: INTEGER
is
begin
step i from 1 to maxc
do
if SYMTAB[i].alpha = C
-- s.t. see identifikaator on juba esinenud ja tabelis!
return i
end if
end step
if maxc + 1 > maxsymtab
then ERRORSYMTAB;
return 0
end if
maxc = maxc+1;
SYMTAB[maxc].alpha= C;
-- tabelisse lisatakse uus identifikaator!
return maxc;
end LOOKUPSYMTAB

Protseduur LOOKUPKEYTAB on analoogiline, kuid see kontrollib, kas sisendtekstis leitud sõna kuulub lähtekeele reserveeritud sõnade tabelisse KEYTAB.

Peaprogramm on täiesti analoogiline varemvaadelduga, alaprogrammidesse on lisatud vastavad väljundtegevused:

procedure SCANNER(SISEND: in FILE) is

begin

READ;

while CH in SYMBOL

loop

--
PROGRAMM (ERALDAJA | IDENT ERALDAJA | CONST ERALDAJA )*
case CH is

when LETTER WORD;ERALDAJA;

when DIGIT NUMBER;ERALDAJA;

when MÄRK ERALDAJA;

end case;

end loop;
if CH='#' then ACCEPT
else RECORD_ERROR(0,POSITION)
-- # - sisendteksti lõpusümbol
-- veakood 0: lubamatu sümbol
end SCAN;

procedure WORD is
--
PROGRAMM (ERALDAJA | IDENT ERALDAJA | CONST ERALDAJA )*
begin
TREAT_LET_DIG(CH);READ
while CH in LETTER or CD in DIGIT

loop

TREAT_LET_DIG(CH);READ;

end loop;

end while;

end WORD;

procedure NUMBER is

begin

FIRST_DIGIT(CH);READ
_
while CH in DIGIT

loop

NEXT_DIGIT(CH);READ;
end loop;

end while;

end NUMBER;

procedure ERALDAJA is

begin

case CH is

when '+'|'-'|'*'|'/'|'='|';'|'('|')' OUT_OPERATOR(CH);READ;

when ':' READ;

if CH = '=' then OUT_OPERATOR(':='); READ

else RECORD_ERROR(1,POSITION);

-- veakood 1: oodati sümbolit '='
end case;

end ERALDAJA;



Ülesandeid:


Küsimused, probleemid:
jaak@cc.ttu.ee

Tagasi loengute sisukorra juurde