You are on page 1of 19

CUPRINS:

Sarcina ……………………………………………………………....................................………..….3

Notiuni teoretice ....................................................................................................................................3

Descrierea limbajului dat …………………………………...................................………………….9

Efectuarea sarcinii ………………………………...................................…………………….………9

Listingul programului ……………………...................................………………………………….16

Rezultatele programului …………………………...................................………………………….18

Concluzie …………………………………………...................................………………….……….19

Bibliografie……………………………………...................................………………………………19

2
Lucrarea de curs la disciplina
“Limbaje formale şi proiectarea compilatoarelor”

Tema: Analizatorul lexical

Sarcina:
1. În descrierea neformală a unui limbaj dată să se evidenţieze lexemele. Pentru fiecare tip de lexemă să
se construiască un automat finit, care acceptă lexeme corecte.
2. Determinaţi dacă automatele construite sunt deterministe.
3. Dacă automatul finit nu este detrminist, să se construiască pentru el un automat finit determinist
echivalent.
4. Construiţi schema analizatorului lexical pentru limbajul dat.
5. Testaţi lucrul analizatorului lexical pe 5 şiruri de intrare corecte şi 3 şiruri, care conţin lexeme
incorecte sau simboluri neacceptate de limbaj, construind pentru aceste şiruri:
 Vectorul sintaxic;
 Vectorul semantic;
 Completarea tabelului pentru fiecare tip de lexemă.
6. Elaboraţi un program pentru analizatorul lexical şi demonstraţi lucrul programului pentru şirurile de
intrare construite.
Notiuni teoretice:
Analiza lexicala
Rolul analizei lexicale este de a traduce textul programului intr-o secvenţă de atomi lexicali. In acest
mod se obţine un "text" mai uşor de prelucrat de către celelalte componente ale compilatorului, Irina
Athanasiu 3/1/2002 Limbaje formale şi automate 84 deoarece se realizează o abstractizare a unei infinităţi
de şiruri de intrare in atomi de tip - identificatori,constante, etc.
De asemenea prin eliminarea blancurilor şi a altor separatori irelevanţi (ca de exemplu comentarii),
textul prelucrat se poate reduce drastic. De cele mai multe ori analiza lexicală realizează şi alte activitati
auxiliare ca de exemplu păstrarea evidenţei numărului de linii citite. O astfel de informaţie este foarte
utilă pentru construirea mesajelor de eroare.
Cand se proiectează un analizor lexical se pune in general problema care este nivelul de complexitate
al atomilor lexicali consideraţi. De exemplu in cazul in care un limbaj utilizează numere complexe, se
pune problema dacă analizorul lexical va fi cel care va recunoaşte o constantă de forma: (<real>, <real>)
producand un atom lexical corespunzător sau recunoaşterea unei astfel de constante ramane in sarcina
nivelului analizei sintactice.
In general un analizor lexical este specificat sub forma :
p1 {actiune 1}
3
p2 {actiune 2}
...
pn {actiune n}
unde pi este o expresie regulata, iar actiune i este o secvenţă de operaţii care se execută pentru fiecare
subşir care corespunde modelului oferit de pi.
Să considerăm de exemplu şirurile de caractere 99.E10 şi 99.EQ.10, care pot să apara intr-un
program PL/I. In primul caz este vorba de numărul 99 x 1010, in al doilea caz de o expresie relaţională.
Dacă analiza se opreşte dupa identificarea punctului zecimal cu concluzia că s-a identificat un număr real
se observa că in primul caz oprirea se face prea devreme iar in al doilea caz prea tarziu.
O soluţie constă din identificarea acestor situaţii realizandu-se aşa numita căutare inainte. Astfel,
pentru cazul considerat, după recunoaşterea şirului 99.se mai cercetează cel puţin un caracter pentru
a se hotari dacă analiza trebuie să se incheie la 99 sau trebuie să continue pană la 99.E10 . O abordare mai
bună consta din căutarea sistematică a celui mai lung subşir care satisface unul din modelele p1,...,pn.
Dacă există mai multe modele de aceaşi lungime care sunt satisfăcute se va alege o convenţie de alegere :
de exemplu in ordinea p1,...,pn.
Un analizor lexical este de fapt implementarea unui automat finit. Ceea ce se schimbă de la
unanalizor lexical la altul este numai specificarea modelelor căutate şi a acţiunilor asociate.

inceput subsir
--------------------------------
| buffer de intrare
--------------------------------
\ cap de citire
\
+-----------+
| simulator |--------------+
| automat | |
+-----------+ |
||
+-----------+ +-----------+
| tabela | | tabela |
| de | | proceduri |
| tranzitii | | tratare |
+-----------+ | actiuni |
+-----------+
4
Interfata analizorului lexical
Dupa cum se ştie analizorul lexical funcţioneză ca un modul in cadrul unui compilator sau a oricărui
program care realizează prelucrări ce necesită identificarea unor şiruri ce pot fi descrise de o gramatică
regulată. In funcţionarea sa analizorul lexical interacţionează cu celelalte component ale compilatorului
prin intermediul unei interfeţe specifice :
+---------------+ insert_s +-------------------+
| | +---------> | |
| Program sursa | | | tabela de simboli |
| | | +------| |
+---------------+ | | +-------------------+
| /|\ | |
| |revenire | \|/ lookup_s
| | +------------------+
| +-------| |
| | Analizor lexical |<------+
+-----------| | | lookup_c
avans_intrare() +------------------+ |
anlex | | | insert_c |
+--------------------+ | | | +---------------------+
|||||||
| Analizor sintactic |<--+ | +---| tabela de constante |
|||||
+--------------------+ | +---------------------+
\|/ eroare
+---------------+
||
| Tratare erori |
||
+---------------+
Interacţiunea cu fişierul sursă se face prin intermediul a două subprograme : avans_intrare (care
preia caracterul următor din programul sursa) şi revenire (care realizeza revenirea inapoi in textul sursă,
dacă intotdeauna revenirea se face cu un singur caracter se poate utiliza o funcţie de tip ungetc).
Tabela de simboli este o structură de date al carui rol este de a memora informaţii referitoare la
atomii lexicali de tip identificator recunoscuţi de către analizorul lexical. Informaţiile referitoare la acesti
simboli sunt utilizate atat in cadrul analizei sintactice cat şi in faza de generare de cod.
5
Introducerea simbolilor in tabela de simboli se face de către analizorul lexical, completarea
informaţiilor realizandu-se de către analizorul sintactic care va adăuga informaţii ca de exemplu tipul
simbolului (procedura, variabila, eticheta, etc) şi modul de utilizare. Legatura cu tabela de simboli se face
prin intermediul a doua proceduri : insert_s şi lookup_s. Procedura insert_s are ca argumente un şir de
caractere şi codul atomului lexical reprezentat de şir. Rezultatul procedurii este adresa in tabela de
simboli la care s-a facut memorarea simbolului. Procedura lookup_s are ca argument un şir iar ca rezultat
adresa in tabela de simboli la care se găseşte simbolul reprezentat de şirul respectiv. Dacă in tabela nu
există şirul căutat rezultatul este 0.
Pentru cuvintele cheie de obicei se face o tratare speciala, de exemplu se poate initializa tabela de
simboli cu intrari corespunzătoare tuturor cuvintelor cheie din limbajul respectiv executand apeluri de
forma :
insert_s("if", cod_if);
insert_s("else", cod_else);
etc. inainte de a se incepe execuţia efectivă a compilatorului. In acest caz recunoaşterea cuvintelor cheie
se va face apoi intr-un mod similar cu a oricarui alt identificator. Se observă deci de ce in majoritatea
limbajelor de programare cuvintele cheie nu pot să fie utilizate ca nume cu altă semnificaţie. O astfel de
tratare are avantajul ca in cazul in care se face o declaraţie de tip de forma:
typedef int intreg;
după introducerea in tabela de simboli a cuvintului intreg de către analizorul lexical, analizorul sintactic
va putea să completeze apoi intrarea in tabela de simboli cu informaţiile corespunzătoare numelui unui
tip. In acest mod in următoarele intalniri ale acestui cuvant analizorul lexical va putea să transmită ca
ieşire atomul lexical corespunzător unui nume de tip.
In cazul constantelor analizorul lexical realizează recunoaşterea acestora şi memorează valorile
corespunzătoare in tabela de constante pentru a permite utilizarea ulterioară in cadrul generării de cod.
Analizorul sintactic apelează de obicei analizorul lexical ca pe o funcţie care are ca valoare codul
atomului lexical recunoscut de către analizorul lexical. In general intre analizorul lexical şi analizorul
sintactic trebuie să se mai transfere şi alte informaţii ca de exemplu adresa in tabela de simboli sau in
tabela de constante a unui identificator, cuvantul cheie respectiv constanta identificata de către analizorul
lexical. Aceste informaţii reprezintă atributele atomului lexical.
Un compilator recunoaşte erori in toate fazele sale: analiza lexicală, sintactică şi in generarea de
cod. Dacă se intalneşte o eroare, se pune problema localizării sale cat mai precise şi apoi a modului in
care se continua analiza astfel incat in continuare să se semnaleze cat mai puţine erori care decurg din
aceasta.
Un aspect important al interfetei analizorului lexical o constituie interfaţa cu sistemul de operare
corespunzătoare citirii textului programului sursă. In general este bine ca interfaţa cu sistemul de operare
6
să fie cat mai bine separată de restul compilatorului pentru a se obţine un cod portabil prin păstrarea
aspectelor dependente de maşină in cadrul funcţiilor care formează aceasta interfaţă.
Din timpul consumat de către procesul de compilare o parte foarte importantă se consumă in
cadrul analizei lexicale. La randul sau partea cea mai consumatoare de timp este de obicei partea legată de
operaţiile de citire. In mod standard obţinerea unui caracter in execuţia unui program presupune copierea
acestuia in mai multe etape - de pe disc in zona tampon a sistemului de operare, din această zonă in zona
prevazută in program, de unde apoi se face copierea in variabila care memorează caracterul curent.
Chiar şi in cazul unui analizor lexical foarte simplu care ar trebui să recunoască şirurile : xxyy, xx
şi y dacă in şirul de intrare se intalneste şirul xxy trebuie să se mai citească incă un caracter pentru a se
putea stabili dacă este vorba de atomul lexical xxyy sau de atomii lexicali xx şi y. Se observă ca in acest
caz utilizarea unei proceduri de tip ungetc() nu este suficientă.
In general o colecţie de funcţii care asigură citirea textului sursă pentru analizorul lexical trebuie
să satisfacă următoarele condiţii:
- funcţiile trebuie să fie cat mai rapide, realizand un număr minim de copieri pentru caracterele
parcurse;
- existenţa unui mecanism care să permită examinarea unor caractere in avans şi revenirea pe
şirul de intrare;
- să admită atomi lexicali suficient de lungi;
Pentru a obţine o utilizare eficientă a operaţiilor legate de accesul la disc este necesar ca
dimensiunea bufferuluisă fie adaptată modului de alocare a spatiului pe disc. Astfel, pentru sistemul de
operare MS-DOS utilizarea unui buffer mai mic decat 512 octeţi nu are nici o justificare (o operaţie de
citire va citii cel puţin un sector de pe disc). De preferat este ca bufferul să fie un multiplu al unităţii de
alocare a spatiului pe disc.

Analiza lexicala
Această fază a compilatorului realizează traducerea textului programului intr-o forma mai uşor
deprelucrat de către celelalte componente. Analizorul lexical consideră textul primit la intrare ca fiind
format din unităţi lexicale pe care le recunoaşte producand atomi lexicali. Un atom lexical poate să fie de
exemplu, un cuvant cheie al limbajului (for, while, etc) dar şi un număr sau un nume. Nu există o
corespondenţă biunivocă intre şirurile de intrare şi atomii lexicali. Adică, dacă pentru atomul lexical
corespunzător cuvantului cheie while există un singur şir de intrare, pentru atomul lexical corespunzător
unui număr intreg pot să existe foarte multe şiruri de intrare. Una dintre deciziile ce trebuie luate la
inceputul proiectării unui compilator constă din stabilirea atomilor lexicali. De exemplu, se pune
problema dacă să existe cate un atom lexical pentru fiecare operator de comparaţie (<, <=, >, >=) sau să
existe un unic atom lexical - corespunzător operaţiei de comparaţie. In primul caz generarea de cod poate
7
să fie mai simplă. Pe de altă parte existenţa unui număr mare de atomi lexicali poate complica in mod
exagerat analiza sintactică. In general, operatorii care au aceeaşi prioritate şi asociativitate pot să fie
grupaţi impreună.
Rolul unui analizor lexical este de a traduce şirurile de intrare in atomi lexicali. Un atom lexical
este reprezentat printr-un cod numeric care specifica clasa acestuia şi o serie de atribute care sunt specific
fiecărei clase. Astfel, poate să existe clasa operatorilor relaţionali pentru care un atribut trebuie să se
specifice tipul concret al operatorului. Tipul atomului lexical este necesar pentru analiza sintactică in timp
ce valoarea atributului este semnificativă pentru analiza semantică şi generarea de cod. Pentru un atom
lexical de tip număr atributele vor descrie tipul numărului şi valoarea acestuia.
Un analizor lexical apare in general ca o funcţie care interacţionează cu restul compilatorului
printr-o interfaţă simplă : ori de cate ori analizorul sintactic are nevoie de un nou atom lexical va apela
analizorul lexical care ii va da atomul lexical următor.

Analiza sintactica
Analiza sintactică descompune textul programului sursa in componentele sale "gramaticale",
construind un arbore care reflectă această structură. Să considerăm de exemplu expresia :
A*B+C*D
Această expresie poate să fie descrisă de următorul tip de arbore numit arbore sintactic:
+
/\
/\
/\
**
/\/\
/\/\
ABCD
In acest arbore au fost evidenţiate relaţiile (din punctul de vedere al modului de evaluare) intre
componentele expresiei. Dacă se doreşte insă să se evidenţieze structura expresiei din punctul de vedere
al unităţilor sintactice din care este formată, atunci se va utiliza pentru reprezentarea expresiei un arbore
de derivare (parse tree). Pentru exemplul considerat un arbore de derivare ar putea să fie de forma:

expresie
/|\
expresie + expresie
///\\\
8
///\\\
///\\
expresie * expresie expresie * expresie
||||
nume nume nume nume
||||
ABCD
Orice analizor sintactic realizează traducerea unui şir de atomi lexicali intr-un astfel de arbore de
derivare care descrie relaţia ierarhică intre o descriere generală a propoziţiei analizate (rădăcina arborelui)
şi şirul de atomi lexicali din care este format (frunzele). Un analizor sintactic poate să construiască efectiv
o structură de date de tip arbore (cu pointeri şi inregistrări) sau poate să sintetizeze informaţiile din care se
poate face construcţia acestuia.

Analiza semantica
Această fază este de obicei incorporată in faza de analiză sintactică. Rolul acestei faze constă din
verificarea din punct de vedere semantic a structurilor recunoscute drept corecte din punct de vedere
sintactic. Majoritatea verificărilor realizate de către această fază se referă la tipurile construcţiilor. De
asemenea această fază completează arborele de derivare cu o serie de informaţii necesare generării de
cod.

Varianta II

Constantele binare în limbajul de programare PL/I se definesc ca numere întregi, de precizie fixă
sau flotante. Numărul întreg este o secvenţă arbitrară de cifre binare (0,1), urmată de litera B. Numărul de
precizie fixă este o secvenţă arbitrară de cifre binare cu punct zecimal. La sfîrşitul numărului zecimal se
scrie litera B. Numărul flotant binar se defineşte ca un număr binar întreg sau flotant, urmat de litera E şi
coeficientul exponenţial. Coeficientul exponenţial este o secvenţă arbitrară de cifre zecimale cu semn.
Semnul “+” nu este obligatoriu. La sfîrşitul numărului flotant de asemenea se scrie litera B.
Programele propuse spre analizare se definesc cu ajutorul următoarelor producţii:

< programa >  < secvenţă de numere binare >


< secvenţă de numere binare >  < număr binar >
< secvenţă de numere binare >  < număr binar > < separator> < secvenţă de numere binare >
< număr binar > < număr întreg >
< număr binar > < număr de precizie fixă >

9
< număr binar > < număr flotant >
< separator>  +
< separator>  < separator> <blanc>
< separator>  <blanc> < separator>
Utilizind abreviaturile: R – < program >, L – < secvenţă de numere binare >,
N – < număr binar>, S – < separator>, i-< număr întreg>,
p – < număr de precizie fixă>, f – < număr flotant >, _ - < blanc >,
fragmentul de mai sus se transcrie in felul urmator:
Gramatica: G = {VN,VT, P, R}
VN= {R, L, N, S}
VT = {+, _, i, p, f}
P ={
1. R → L
2. L → N
3. L → N S L
4. N → i
5. N → p
6. N → f
7. S → +
8. S → S _
9. S → _ S }

1. Tabelul şi codul lexemelor pentru limbajul dat:

Lexemele Codul

+ 1

<numar intreg> 2

<numar cu precizie fixa> 3

<numar flotant> 4

10
Automatele finite, care acceptă lexemele corecte pentru separatori, numere intregi, numere cu
precizie fixa si numere flotante:

AF pentru separatori (determinist):


AF = (Q, ∑ ¿¿ , δ , q0, F) _
Q = {q0, q1} _ +
∑ ¿¿ = {+, _} q0 q1
δ (q0, _) = {q0}
δ (q0, +) = {q1}
δ (q1, _) = {q1}
F = {q1}
AF pentru numere intregi (determinist):

b ={0,1}
AF = (Q, ∑ ¿¿ , δ ,q0, F) b B
q0 q1
Q = {q0, q1}
∑ ¿¿ = {b, B}
δ (q0, b) = { q0}
δ (q0, B) = { q1}
F = { q1 }

AF pentru numere de precizie fixa (determinist):

b={0,1}
AF = (Q, ∑ ¿¿ , δ ,q0, F)
Q = {q0, q1, q2, q3, q4} b
∑ ¿¿ = { . , b, B} q1
δ (q0, . ) = {q1} . b
δ (q0, b) = {q3} q0 q2 q4
B
δ (q1, b) = {q2}
δ (q2, b) = {q2} b .
q3
δ (q2, B) = {q4}
δ (q3, b) = {q3} b
δ (q3, . ) = {q2}
F= {q4}

11
AF pentru numere flotante (determinist):

b ={0, 1}
c ={0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
b
AF = (Q, ∑ ¿¿ , δ , q0, F)
Q = (q0, q1, q2, q3, q4, q5, q6, q7)
∑ ¿¿ = { . , b, c, +, -, E, B} q1 b q2
δ (q0, . ) = {q1} q5
δ (q0, b) = {q3} . +
δ (q1, b) = {q2} E
δ (q2, b) = {q2} q0 . q4 -
δ q7
(q2, E) = {q4} c
δ (q3, . ) = {q2} b E B
δ q3
(q3, b) = {q3} c q6
δ (q3, E) = {q4} b
δ (q4, - ) = {q5} c
δ (q4, +) = {q5}
δ (q4, c) = {q6}
δ (q5, c) = {q6}
δ (q6, c) = {q6}
δ (q6, B) = {q7}
F = {q7}
2. Automatele finite construite pentru separatori, numere intregi, numere de precizie fixa si
numere flotante sunt deterministe, deoarece toate funcţiile de tranziţie sunt de forma:
δ (q , a )=q i sau δ (q , a )=∅

12
4. Schema analizatorului lexical pentru limbajul dat:

intrare

Next, i

Completarea vectorului
__ DA sintactic
AF pentru
+ separator NU

ERROR – illegal separator

Cautarea dupa TN,


0,1 DA Completarea vect. Sint şi Sem.
AF pentru
. numere NU
ERROR – illegal bit number

alt ERROR – unknown symbol


simbol

EOF
Iesire

5. Şiruri acceptate de limbaj:

şirul de intrare 1: 01101B _ + _ _ 101.11B _ + 0111E-54B _ + _ 001.010B

i p f
1 01101B 101.11B 0111E-54B
2 001.010B

13
Vectorul 2 1 3 1 4 1 3
sintactic
Vectorul 1 1 1 2
semantic

şirul de intrare 2: 1001.001B _ + _ 11E29B _ + _ _ _ 010.110E-112B + .0001B +11011B

i p f
1 11011B 1001.001B 11E29B
2 .0001B 010.110E-112B

Vectorul 3 1 4 1 4 1 3 1 2
sintactic
Vectorul 1 1 2 2 1
semantic

şirul de intrare 3: .011101B _ + 110001B + 000100B + _ 1.001E71B _ _ + 01011B + _ _ _ 101.B

i p f
1 110001B .011101B 1.001E71B
2 000100B 101.B
3 01011B

Vectorul 3 1 2 1 2 1 4 1 4 1 3
sintactic
Vectorul 1 1 2 1 3 2
semantic

şirul de intrare 4: 011.10001E+15B _ + 001.001B + _ 010B + 101E-55

i p f
1 010B 001.001B 011.10001E+15B
2 101E-55

Vectorul 4 1 3 1 2 1 4
sintactic
Vectorul 1 1 1 2
semantic

şirul de intrare 5: 110.01E22B _ _ + _ _ _ 010.111E-3B _ + _ _ _ 1001.001B _ + 1010E12B _ + _


0111.111B
14
Vectorul 4 1 4 1 3 1 4 1 3
sintactic
Vectorul 1 2 1 3 2
semantic

Şiruri neacceptate de limbaj:

şirul de intrare 6: 1001.B _ _ + _ + _ .011E4B _ _ + _ 101EB + _ 210B


ERROR(1) – illegal separator (‘_ _ + _ + _’)
ERROR(2) – illegal bit number (‘101EB’)
ERROR(3) – unknown symbol (‘210B’)

i p f
1 1001.B .011E4B

Vectorul 3 -1 4 1 -1 1 -1
sintactic
Vectorul 1 1
semantic

şirul de intrare 7: 110.01.1B _ + 110.01B + 11021B + _ + _ 01.E+-24B _ + 11B


ERROR(1) – illegal bit number (‘110.01.1B’)
ERROR(2) – illegal bit number (‘11021B’)
ERROR(3) – illegal separator (‘+ _ + _’)
ERROR(4) – illegal bit number (’01.E+-24B’)

i p f
1 11B 110.01B

Vectorul -1 1 3 1 -1 -1 -1 1 2
sintactic
Vectorul 1 1
semantic

şirul de intrare 8: 101.011E-247B _ + _ .11101E1AB + _ _ + 110B _ _ _ + . _ + 71011BE


ERROR(1) – illegal bit number (‘ .11101E1AB’)
ERROR(2) – illegal separator (‘+ _ _ +’)
ERROR(3) – illegal bit number (‘ . ’)
i p f ERROR(4) – unknown symbol
1 1001.001B 110.01E22B (‘71011BE’)
2 0111.111B 010.111E-3B
3 i p 1010E12Bf
15
1 110B 101.011E-247B

Vectorul 4 1 -1 -1 2 1 -1 1 -1
sintactic
Vectorul 1 1
semantic

6. Listingul programului:
#include<stdio.h>
#include<conio.h>
#include<string.h>
int control(char *q)
{ int k=0;
int e=0;
int gf=0;
for(int i=0;i<strlen(q);i++)
{ if (q[i]=='E') e=1;
if ((q[i]=='E')&&(q[i]=='B'))
{ gf=2; break;}
if ((q[i]>49)&&(q[i]<56)&&(e==0))
{gf=3; break; }
if (q[i]=='.')
{ k++; break; }
if (k==2)
{gf=2; break; }
if (q[i]=='A')
{ gf=4; break;}
}
return gf;
}
int f1(char *s,int *q)
{ int i;
int j=0;
int k=1;
int h=0;
char w[20];
for (i=0;i<strlen(s);i++)
{

if ((s[i]=='+')&&(s[i]!='E'))

if (q[j-1]==1)
{ q[j++]=-1;
printf("\nERROR:illegal separator\n"); }
else
q[j++]=1;

else
if (s[i]!='_')
w[h++]=s[i];
if ((s[i]=='B')||(s[i]=='\0'))
{
16
w[h]='\0';
h=0;
int e=0;
// puts(w);
/// verificam daca nu este gresit ceva
k=1;
if (control(w)!=0)
{ q[j++];continue; }
for (int f=0;f<strlen(w);f++)
{
if ((w[f]=='.')||(w[f]=='E')||(w[f]=='B'))
{ k++; }
if (w[f]=='E')
{ e=1; break; }

}
if (e==1)
q[j++]=4;
else
q[j++]=k

return j;

}
void f2(int *q,int n)
{
int l[5]={0,0,0,0};
printf("\n");
for (int i=0;i<n;i++)
if (q[i]<2){ printf(" "); continue; }
else
{ l[q[i]]+=1;

printf(" %d",l[q[i]]);

}
}
void main()
{ clrscr();
char s[]={'0','1','1','0','1','B','_','+','_','+','_','1','0','1','.','1','1',
'B','_','+','0','1','.','1','E','-','5','4','B','_','+','_','0','0','1','.',
'0','1','0','B'};
puts("Introduceti un sir:");
gets(s);

int q[10];
int n=f1(s,q);
17
printf("\nVectorul sintactic\n");
for (int i=0;i<n;i++)
printf(" %d",q[i]);
printf("\nVectorul semantic\n");
f2(q,n);
getch();

Rezultatele programului:

Introducem un sir corect

Introducem un sir gresit:

18
Concluzie:

Efectuind acest proiect de curs am studiat si am aplicat in practica notiuni, definitii, si tehnici
necesare pentru proiectarea unui analizator lexical. Pentru fiecare tip de lexemă am construit cite un
automat finit.
Am construit schema de lucru a unui analizator lexical. Am elaborat un program pentru
analizatorul lexical dat, acesta reprezintind de fapt proiectarea unui mic tip de compilator, dupa care am
testat lucrul acestuia pentru siruri corecte si incorecte cu erorile descrise. Astfel am întărit conoştinţele în
ceea ce priveşte programarea limbajelor formale.

Bibliografie (resurse internet):

1. Лекции по конструированию компиляторов (рус.)


http://www.codenet.ru/progr/compil/cons/001.php

2. Ахо А., Ульман Дж. Теория синтаксического анализа, перевода и компиляции. Т. 1:
Синтаксический анализ. М.: Мир, 1978. -- 612 с.

19
3. Irina Athanasiu „Limbaje formale”

4. Ciclu de prelegeri citit la facultate la disciplina “L.F.P.C”.

20

You might also like