Explorați Cărți electronice
Categorii
Explorați Cărți audio
Categorii
Explorați Reviste
Categorii
Explorați Documente
Categorii
=================================================================
Presupunem definite urmatoarele tipuri de date: GR (gramatica regulata),
GIC (gramatica independenta de context), AS (automat stiva), AFD (automat
finit determinist), AFN (automat finit nedeterminist), AFNL (automat finit
nedeterminist cu lambda miscari).
Urmatoarele probleme vor cere implementarea unor algoritmi ce lucreaza cu
gramatici si automate, pe care le vor primi ca parametri de iesire (pointeri
in limbajul C, referinte in limbajul C++), de exemplu:
void f(GIC *gs, AS *ad){...}
respectiv:
void f(GIC &gs, AS &ad){...}
Enunturile vor folosi C++, dar se poate lucra si in C.
In cazul cand se cere construirea unor automate sau gramatici noi din unele
vechi, cele noi va respecta aceleasi conventii de implementare ca si cele
vechi - de exemplu daca la automatele vechi starile sunt numere naturale
succesive 0, 1, 2, ... iar starea initiala este 0, atunci si la automatele
noi starile sunt numere naturale succesive 0, 1, 2, ... iar starea initiala
este 0; astfel va fi posibila compunerea functiilor scrise la diverse
probleme pentru a aplica transformari succesive unor automate sau gramatici
date (deci pentru a compune algoritmii).
In cele ce urmeaza notam cu & pe lambda (cuvantul vid).
1. (puncte: a se vedea in text)
Scrieti functiile:
int gr2afn(GR &gs, AFN &ad);
(3 puncte)
int afd2gr(AFD &as, GR &gd);
(2 puncte)
Functia "gr2afn" construieste automatul "ad" echivalent cu gramatica "gs",
iar functia "afd2gr" construieste gramatica "gd" echivalenta cu automatul
"as"; functiile returneaza 1=succes, 0=esec.
Scrieti un program demonstrativ care citeste o gramatica si afisaza
automatul echivalent, apoi citeste un automat si afisaza gramatica
echivalenta.
Observatii:
- in functie de algoritmul folosit, se pot scrie variante ale functiilor de
mai sus in care parametrul-automat sa fie de oricare din tipurile AFD, AFN,
AFNL;
- daca automatele au fost implementate cu stari = numere naturale si alfabet
de intrare = setulul ASCII, iar gramaticile au fost implementate cu
terminale si neterminale stringuri, trebuie adoptata o corespondenta
intre o multime de cuvinte (reprezentand multimea neterminalelor sau cea a
terminalelor) si o multime de numere de forma 0, ..., n sau o multime de
caractere ASCII;
2. (puncte: a se vedea in text)
Scrieti functiile:
int gic2asv(GIC &gs, AS &ad);
(3 punct)
int asv2gic(AS &as, GIC &gd);
(7 puncte)
Functia "gic2asv" construieste automatul "ad" a.i. L&(ad)=L(gs), iar functia
"asv2gic" construieste gramatica "gd" a.i. L(gd)=L&(as); functiile returneaza
1=succes, 0=esec.
Scrieti un program demonstrativ care citeste o gramatica si afisaza
automatul rezultat, apoi citeste un automat si afisaza gramatica rezultata.
Observatie: in functie de algoritmul folosit, se pot scrie variante ale
functiilor de mai sus in care limbajul se considera acceptat de automat cu
stare finala (functiile se vor numi atunci "gic2asf", respectiv "asf2gic").
3. (puncte: 4)
Scrieti functiile:
intr-un ciclu va citi secvente "s" si va spune daca apartin sau nu limbajului
generat de gramatica; din ciclu se va iesi la citirea secventei vide (care se
va procesa inainte de iesire).
Observatii:
- pentru inca un punct: daca se foloseste algoritmul top-down clasic, functia
poate avea parametrii int gic_rtd(GIC &g, char **s, int *a, int &n) si
va furniza in vectorul "a" analiza stanga obtinuta (sirul indicilor
productiilor) iar in "n" lungimea acesteia;
- daca tipul GIC este implementat simplist cu simboluri caractere, nu
cuvinte, de exemplu neterminale = litere mari, terminale = litere mici,
functia va avea parametrii int gic_rtd(GIC &g, char *s) (sau
int gic_rtd(GIC &g, char *s, int *a, int &n)) iar secventele "s" citite
si procesate vor fi stringuri.
12. (puncte: 5)
Scrieti o functie de analiza sintactica:
int gic_rbu(GIC &g, char **s);
care returneaza 1/0 dupa cum "s" apartine/nu apartine limbajului generat de
"g"; putem presupune gramatica "g" proprie (i.e. fara simboluri neutilizate,
lambda-productii, redenumiri); se va folosi metoda bottom-up (clasica sau un
backtracking recursiv: se cauta toate aparitiile membrului drept al vreunei
productii in "s", pentru fiecare aparitie se inlocuieste cu membrul stang,
apoi se reia cautarea/inlocuirea cu noua secventa, pana obtinem simbolul de
start sau constatam ca pe traseul curent nu se poate obtine simbolul de
start).
Scrieti un program demonstrativ care va citi o gramatica, o va afisa, apoi
intr-un ciclu va citi secvente "s" si va spune daca apartin sau nu limbajului
generat de gramatica; din ciclu se va iesi la citirea secventei vide (care se
va procesa inainte de iesire).
Observatii:
- pentru inca un punct: daca se foloseste algoritmul bottom-up clasic,
functia poate avea parametrii int gic_rbu(GIC &g, char **s, int *a, int &n)
si va furniza in vectorul "a" analiza dreapta obtinuta (sirul indicilor
productiilor) iar in "n" lungimea acesteia;
- daca tipul GIC este implementat simplist cu simboluri caractere, nu
cuvinte, de exemplu neterminale = litere mari, terminale = litere mici,
functia va avea parametrii int gic_rbu(GIC &g, char *s) (sau
int gic_rbu(GIC &g, char *s, int *a, int &n)) iar secventele "s"
citite si procesate vor fi stringuri.
DANIEL DRAGULICI
mai, 2007