Nimede tabeli moodustamine FLEX-i abil

Skanner moodustab nn nimede tabeli (nametable), mis sisaldab kõiki töödeldava (skaneeritava) programmi identifikaatoreid; skaneerimisel asendatakse identifikaatorid viitega sellesse tabelisse (sellesse tuleb ka identifikaatori tüüp ja viit mäluosale, kus salvestatakse identifikaatori väärtus). Järgnevas on FLEX-i sisendfail, mis kirjeldab ka FLEX-i abil programmis esinevate identifikaatorite kogumist vektoriks (char array).

Allpoolesitatud näide on veel väga primitiivne, näiteks puudub siin kontroll, kas programmi tekstist leitud identifikaator juba ei esine tabelis (see tuleks enne uue nime lisamist kindlasti teha); samuti ei genereerita siin veel mingit väljundit (skaneerimise tulemusena saadavat lekseemide jada), kuid arvud (täis- ja reaalarvud) muudetakse juba arvudeks (lähtetekstis on nad sümbolite jadad) ja kahesümboliline omistusmärk := asendatakse ühe lekseemiga, kusjuures ':', '=' võivad esineda ka tavaliste eraldajatena. OMISTUS.

%option noyywrap
/* scanner for a toy Pascal-like language */
%{
/* include is to get the atof(), atoi() functions */
#include <math.h>
int num;
int i,j,k,n=0;
float realnum;
char c, nimed[50][10];
/* nametable; < 50 names are allowed in a program */
%}

DIGIT [0-9]
ID [a-z][a-z0-9]*
OMISTUS :=
ERALDAJA [=,;:"("")""{""}"]

%%

{DIGIT}+ {
num=atoi(yytext);
printf( "An integer: %s (%d)\n", yytext, num );
}

{DIGIT}+"."{DIGIT}* {
realnum=atof(yytext);
printf( "A float: %s (%g)\n", yytext, realnum );
}

if|then|begin|end|procedure|function|main|else {
printf( "A keyword: %s\n", yytext );
}

{ID} {
printf( "An identifier: %s\n", yytext);
/* here should be first a check - */
/* maybe the ident is already in the table! */
for (i=0;i < yyleng;i++ )
nimed[n][i] = yytext[i];
nimed[n][yyleng]=0x00;
/* 0x00 - string terminator! */
n++;
}

"+"|"-"|"*"|"/" printf( "An operator: %s\n", yytext );
"{"[^}\n]*"}" /* eat up one-line comments */

[ \t\n]+ /* eat up whitespace */

{OMISTUS} printf("Omistamine: %s\n",yytext);

{ERALDAJA} printf("Eraldaja: %s\n", yytext);
. printf( "Unrecognized character: %s\n", yytext );

%%

main( argc, argv )
int argc;
char **argv;
{
++argv, --argc; /* skip over program name */
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin;
yylex();

printf("Identifikaatorieid: %d\n", n);
for (i=0;i < n;i++)
{
k = 0;
c = nimed[i][k];
while (c != 0x00)
{
printf ("%c", c);
k++;
c = nimed[i][k];
};
printf("\n");
}
}

Selle teksti testimiseks (kui DOS-aknas oletuskataloog on FLEX-i programmi sisaldav kataloog \bin, see tekst on salvestatud failis pascal.lex ja selles kataloogis on ka Pascal-programmi näidis pastxt.pas) tuleb anda käsud:

flex pascal.lex
gcc lexyy.c -opasscan
passcan.exe < pastxt.pas > passcan.txt

Programmi töö tulemusega võib nüüd tutvuda käsuga

edit passcan.txt


Ülesandeid:

1. Lisa eelnevasse kontroll, mis välistab juba tabelis oleva identifikaatori teistkordse lisamise.
2. Faili passcan.txt sisu sarnaneb juba "päris" skanneri poolt tehtava väljundi, s.t. lekseemide jadaga. Täienda ylalesitatud FLEX-i programmi nii, et passcan.txt tuleks sisendprogrammile (ülal pastxt.pas) vastav lekseemide jada. Lekseemid on kõik kolmeväljalised kirjed.

Esimene väli TYPE määrab lekseemi tüübi; see võib olla:
ident -- s.t. lähteteksti identifikaator
const -- s.t. arvkonstant
'+', '-', '*', '/', '=', '(', ')', ':=',';' -- siin omistusmärki := käsitletakse ühe sümbolina !
begin, end, if, then -- võtmesõnad
Lekseemi teine väli SPEC on
identifikaatoritel - viit nimede tabelisse
arvkonstantidel - nende väärtus, s.t. see arv ise
ülejäänud lekseemide korral on see väli tühi
Lekseemi kolmas väli POS määrab lekseemi asukoha lähtetekstis, see on täisarvude paar RIDA, POSITSIOON


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

Tagasi loengute sisukorra juurde