Introducere in Programare Java
Introducere in Programare Java
10
Am realizat aceast scurt introducere pentru a putea realiza o comparaie ntre actele de comunicare inter-uman i comunicarea dintre om i calculator. n aceast comunicare, putem vedea calculatorul ca pe un partener care e dispus s ne rezolve problemele. Pentru aceasta, trebuie s-i specificm modul n care s rezolve aceste probleme. Putem s realizm acest lucru utiliznd algoritmii. Dar algoritmii trebuie descrii ntr-un limbaj inteligibil pentru calculator. Putem vedea aceast comunicare ca un caz special al unei solicitri. Dac cerem ceva cuiva, atunci va trebui s folosim cuvinte, expresii pe care acesta s le neleag. Conform Dicionarului Explicativ al Limbii Romne, prin limb se nelege un sistem de comunicare alctuit din sunete articulate, specifice omului, prin care acesta i exprim gndurile sau dorinele. Astfel, un limbaj este un mijloc de comunicare a ideilor prin sunete i culoare, reprezentnd un mijloc de transmitere a informaiei ntre indivizii unei categorii [Nichi 2005]. Orice limbaj are la baz simboluri care formeaz limbajul respectiv. Astfel, limba vorbit are la baz sunete, limbajele scrise au la baz literele, limbajele vizuale au la baz simbolurile grafice. Semiotica este ramura tiinei care se ocup cu studiul simbolurilor. Revenind la comunicarea dintre om i calculator, trebuie s definim noiunea de limbaj de programare. Astfel, prin limbaj de programare nelegem o notaie sistematic prin care este descris un proces de calcul [Prv 1996]. Un proces de calcul este constituit dintr-o mulime de pai pe care o main i poate executa pentru a rezolva o anumit problem. Astfel, un limbaj de programare este un intermediar ntre realitatea reprezentrilor utilizatorului asupra problemei de rezolvat i realitatea calculatorului cu care lucreaz [erbnai 1987]. La rezolvarea unei probleme cu calculatorul, un programator trebuie s priveasc fiecare element al limbajului din 2 puncte de vedere: unul logic, al problemei; astfel programatorul trebuie s tie ce nelege s reprezinte din problem cu ajutorul elementului de limbaj unul fizic, al implementrii, care se refer la ceea ce realizeaz calculatorul la execuia elementului de limbaj considerat. Programul este un compromis ntre cele 2 puncte de vedre. Astfel, programatorul trebuie s-i reprezinte i s neleag urmtoarele universuri: universul problemei universul limbajului de programare universul calculatorului Aceste trei universuri sunt n general diferite. Pentru a realiza corespondena ntre acestea, exist definite diverse activiti ale informaticii. Figura 1 surprinde corespondena ntre universurile limbajelor de programare.
11
Elaborare program
Compilare
Figura 1.
Orice limbaj are 3 aspecte caracteristice: aspectul sintactic aspectul semantic aspectul pragmatic Sintaxa unui limbaj conine ansamblul regulilor prin care pornind de la simbolurile de baz care alctuiesc alfabetul limbajului, se construiesc structuri compuse [Nichi 2005]. Mulimea regulilor sintactice care descriu ansamblul propoziiilor sau a formulelor corecte din cadrul limbajului formeaz gramatica. Deci, sintaxa i gramatica ne ajut s identificm modul n care putem combina simbolurile de baz ale limbajului pentru a produce elemente acceptate de limbaj. Ele reprezint imperative riguroase, care pot fi formalizate matematic. Sintaxa se descrie teoretic cu ajutorul sistemelor formale. Urmtoarele elemente se utilizeaz pentru descrierea sintaxei unui limbaj: diagramele sintactice arbori de analiz metalimbaje (BNF Backus Naur Form, EBNF Extended Backus Naur Form, Asn.1) Prin semantic se nelege sensul construciilor sintactice. Ea reprezint un set de reguli ce determin semnificaia propoziiilor dintr-un limbaj. Este vorba de reguli de evaluare a acestor propoziii n termenii unor mulimi de valori cunoscute de limbajul respectiv. Astfel, semantica reprezint nelesul fiecrei formule corecte admise de gramatic. Pragmatica se refer la capacitatea de a utiliza construciile sintactice i semantice. Referitor la nelegerea aspectului pragmatic al limbajelor, putem s
12
se nchipuim urmtorul exemplu: o persoan poate cunoate foarte bine aspectele sintactice i semantice ale unui limbaj, dar nu are capacitatea de a utiliza corect aceste reguli. De asemenea, exist persoane care vorbesc (folosesc) o limb fr a cunoate aspectele sintactice i semantice ale acesteia. Pragmatica nu se poate formaliza. n capitolul 2 vom trece la prezentarea succint a formalizrii elementelor de limbaje de programare.
13
Cu ct un limbaj este mai apropiat de simbolurile efective, binare, cu care lucreaz calculatorul, limbajul este de nivel mai sczut. Figura 2 descrie ierarhizarea limbajelor de programare n funcie de nivel.
Limbaj de nivel superior Limbaj de asamblare asamblor
Compilator Interpretor
Figura 2.
Limbajul sau codul main reprezint un limbaj binar cu care lucreaz efectiv procesorul. De obicei, fiecare procesor are propriul su cod main, definit fizic de constructorul procesorului. Codul main aparine primei generaii de limbaje de programare. Limbajele de asamblare sau macroasamblare se situeaz deasupra codului main i sunt formate prin coresponden direct ntre succesiuni binare i termeni (eventual prescurtai) din vorbire. Limbajele de asamblare fac parte din generaia 2-a de limbaje de programare. Programele scrise n cod main sau limbaje de asamblare pot fi considerate optimale pentru calculator, deoarece acesta poate s execute n mod direct, fr o alt conversie un asemenea cod. Dezavantajele principale ale acestora rezid n dificultatea acestor limbaje. Productivitatea activitii de programare este foarte sczut. Limbajele din primele dou generaii sunt specifice pe procesor, adic gradul lor de portabilitate este foarte sczut. Prin portabilitate se nelege caracteristica unui program de a putea fi rulat pe diverse calculatoare (sau tipuri de calculatoare) fr modificri, sau cu modificri minimale. Limbajele de nivel superior aparin generaiilor 3-a, 4-a i 5-a de limbaje de programare. Aceste limbaje se apropie tot mai mult de nelegerea uman, de reprezentri specifice n termenii problemei de rezolvat. Limbajele de generaia 3 conin limbaje pentru prelucrarea datelor neorganizate n baze de date. Ele sunt limbaje de uz general, respectiv de programare automat. Aceste limbaje permit programatorului s exprime rezolvarea problemei ntr-un limbaj mai apropiat de limbajul natural. Includem n aceast categorie limbaje precum Fortran, C/C++, Pascal etc.
14
Limbajele de generaia 4 sunt destinate n special prelucrrii datelor organizate n baze de date. Ele sunt utilizate pentru realizarea de programe comerciale, a cror obiectiv principal este manipularea unor cantiti mari de date. Limbajele din generaia 4-a sunt de obicei uor de nvat i aplicat, i sunt destinate unor categorii mai mari de utilizatori. Aceste limbaje pun accentul mai mult pe funcionalitatea oferit dect pe tehnicile de programare. Limbajele din generaia 5-a sunt limbajele inteligenei artificiale. n aceast categorie putem include limbajele logice pentru manipulare de simboluri i limbajele de gestiune a bazelor de cunotine. Limbajele de nivel superior prin caracteristicile lor, asigur o productivitate corespunztoare a muncii de programare. Astfel, ele se caracterizeaz prin: faciliti legate de elaborarea programelor. Limbajul se apropie de multe ori de limbajul natural sau de dialecte ale acestuia sunt standardizate: se asigur astfel independena de main i deci portabilitatea exist o productivitate bun a elaborrii programelor. Pentru multe limbaje s-au dezvoltat metodologii de lucru n activitatea de dezvoltare a programelor pentru a se asigura posibilitatea de lucru n echip respectiv a se asigura extensibilitatea programelor. Ingineria programrii este ramura tiinei calculatoarelor care se ocup cu studiul metodelor de dezvoltare organizat a programelor informatice. Pentru execuia programelor scrise ntr-un limbaj de nivel superior, acestea trebuie convertite n cod de nivel inferior specific mainii pe care se dorete rularea programului. Programele care asigur aceste conversii se numesc programe de traducere. Programele de traducere sunt de 3 tipuri: compilatoare interpretoare traducere n dou faze. Compilatoarele traduc programul dintr-un limbaj surs (de ex. C) ntr-un limbaj obiect (de ex. cod main). Compilatoarele nu execut programul compilat. Limbajul obiect nu trebuie s fie n mod obligatoriul limbajul main. Un tip special de compilatoare sunt precompilatoarele care traduc o extensie a unui limbaj ntr-un limbaj de baz. De multe ori activitatea de compilare este realizat n mai multe faze. Vom insista asupra fazelor traducerii unui program surs n program obiect executabil n capitolul 2. Interpretoarele traduc instruciune cu instruciune un cod surs, i pe msur ce realizeaz traducerea unei instruciuni o i execut. Basic este un exemplu de limbaj interpretat. Avantajul interpretoarelor fa de compilatoare este c dac apare o eroare ntr-o instruciune ea se poate corecta pe loc. Limbajele interpretate sunt ns, de obicei, limbaje simple, i nu permit astfel realizarea unor programe foarte complexe.
15
Traducerea n dou faze presupune traducerea codului din cod surs ntr-un cod intermediar care apoi este rulat pe o main virtual. Limbajele care funcioneaz pe acest principiu se numesc limbaje pseudo-compilative. Exemple de limbaje pseudo-compilative sunt Java i limbajele din familia .NET.
16
spagetti, care reprezint un stil confuz de programare cu multe salturi necondiionate. Recomandm la nivel microscopic de programare utilizarea programrii structurate, adic folosirea n program doar a structurilor algoritmice fundamentale. Un program structurat este totdeauna mult mai lizibil i mai flexibil dect unul nestructurat. Exponentul principal al programrii structurate este Pascal.
17
prin care o clas este caz particular (specializat) al unei superclase. Astfel, prin compoziie i motenire se asigur reutilizarea codului. Principalul avantaj al programrii obiectuale fa de paradigmele anterioare este realizarea polimorfismului. Prin polimorfism se nelege proprietatea unui nume de a fi utilizat cu nelesuri diferite. Cea mai important form de polimorfism este polimorfismul de tip, prin care tipul referinei se adapteaz la tipul obiectului. Smalltalk este limbajul care a introdus paradigma obiectual. Acest limbaj a fost dezvoltat n limbajele Smalltalk80 i Smalltalk86. C++ reprezint extensia obiectual a limbajului structurat C. De asemenea Java implementeaz caracteristicile paradigmei obiectuale.
18
temporale sau monotonice care pot s furnizeze mecanisme de deducie folosite n limbajele logice. Prolog reprezint exemplul clasic de limbaj din aceast categorie. El reprezint transcrierea ntr-un limbaj de programare a logicii predicatelor de ordinul I. Limbajele logice stau la baza motoarelor de inferen din sistemele expert.
1 2
Rapid Application Development (RAD) environments, n lb. Englez Markup Languages, n lb. Englez
19
acestei categorii putem aminti XML, limbaj specializat pentru structurarea informaiei i HTML limbajul World Wide Web-ului. Programarea bazat pe ageni reprezint o nou paradigm de programare. Agenii reprezint un nivel de abstracie superior obiectelor, n sensul c agenii sunt entiti software autonome capabile de comportament pro-activ. Aceasta nseamn, pe de-o parte, faptul c agenii au o stare i un comportament propriu iar, pe de alt parte, faptul c acest comportament se poate executa din dorina agentului, fr s fie nevoie invocarea comportamentului de o alt entitate de program. Comportamentul agentului este ghidat mai mult de obiectivele, credinele i inteniile agentului dect de cereri explicite ale altor ageni. Teoria agenilor reprezint o nou idee de realizare a programelor software mai mult dect o baz care s conduc la realizarea de limbaje de programare specifice. Totui, exist limbaje specifice precum Telescript, Agents, AgentTcl etc. De multe ori pentru realizarea de sisteme cu ageni sau care respect principiile programrii cu ageni se utilizeaz limbaje de programare obiectuale generale (precum Java) care sunt extinse cu faciliti destinate agenilor. Se creeaz aa-numitele platforme multi-agent n care se pot crea (programa) ageni care s rezolve anumite sarcini. Amintim n cadrul platformelor multi-agent tool-urile FIPA-OS, JADE, IBM Aglets, etc. n cadrul paradigmei programrii cu ageni se utilizeaz i limbaje de reprezentare a cunotinelor agenilor i de facilitare a comunicrii inter-agent. n aceast categorie putem nscrie KQML, KIF i ACL.
An
1957-si 1960-s 1960-s
Autori
J. Backus (IBM) Comitet DOD
Predecesor
Scop
Calcule numerice
Fortran
20
APL Lisp Snobol PL/1 Simula67 Algol68 Pascal Prolog C Concurrent Pascal Euclid Modula Ada Smalltalk C++ Oberon Modula-3 Java 1960-si 1962 1966-si 1964-s 1967 1968-s 1971 1972 1974 1975 1977 1977 1979 1980 1984 1987 1988 1995
Tabelul 1.
n 1944 maina numit Mark I realizat de IBM a fost primul calculator capabil s execute o secven lung de operaii aritmetice i logice. n 1946 ENIAC (Electronic Numerical Integrator And Calculator) devine predecesorul primei generaii de calculatoare.
21
n 1959 apare a doua generaie de calculatoare, bazat pe utilizarea tranzistorilor. Calculatoarele din a 2-a generaie sunt de dimensiuni mai reduse, mai rapide, mai ieftine i mai fiabile.
Fortran
1960
Algol60
Cobol
Lisp
CPL PL/1
1970
Modula-2 Ada
1980
C cu clase
Smalltalk
ANSI C
Objective C
C++ Modula-3
1990
Ada9X
Figura 3.
n 1965 se introduc circuitele integrate, ceea ce reprezint un semnificativ salt tehnologic. n acest moment ncepem s vorbim de cea de-a 3-a generaie de calculatoare. Circuitele integrate au permis pentru prima oar obinerea unei viteze de calcul de peste un milion de operaii pe secund. Din 1970 putem vorbi de cea de-a 4-a generaie de calculatoare, prin dezvoltarea microprocesorului. Acesta era un dispozitiv de calcul independent, care, integrat n maini de calcul a condus la realizarea unor computere mai rapide, mai mici i mai ieftine.
22
Din acel moment pn n zilele noastre am asistat la o adevrat explozie tehnologic din punct de vedere hardware. Calculatoarele de azi sunt capabile de performane greu de imaginat cu cteva decenii n urm. Bazele proiectrii calculatoarelor au fost puse n 1940 de matematicianul John von Neumann, prin descrierea arhitecturii von Neumann pentru maini de calcul. Aceast arhitectur a influenat puternic modul de dezvoltare a artei programrii. Figura 4 descrie schematic structura unui calculator von Neumann. Limbajele de programare care au derivat din aceast arhitectur sunt cunoscute i sub numele de limbaje imperative, datorit faptului c permit programatorului s-i specifice cerinele printr-o secven de instruciuni care s indice exact ceea ce trebuie fcut pentru rezolvarea problemei.
intrari Unitate aritmetica si logica Unitate de control iesiri
Instructiuni
Date
Figura 4.
Punctele istorice pe care le-am marcat n paragrafele precedente au avut un impact major asupra dezvoltrii limbajelor de programare. Din momentul anilor 70, dezvoltarea limbajelor de programare a ncercat s in pasul cu dezvoltrile hardware, dar evoluia limbajelor de programare a luat o cale distinct. Vom descrie succint principalele limbaje de programare care au marcat aceast istorie. La mijlocul anilor 50, n cadrul firmei IBM, s-a studiat posibilitatea realizrii unui translator algebric. Astfel, echipa condus de John Backus a realizat n 1954 specificaia 0 a limbajului Fortran. Primul compilator de Fortran a fost realizat n 1957 odat cu specificaia 2-a a acestui limbaj. Acest limbaj a devenit foarte popular datorit faptului c firma IBM l-a oferit gratuit. Fortran reprezint primul limbaj de programare de nivel nalt. Are o sintax apropiat de scrierea matematic. In Fortran linia de cod surs are un format fix cu 4 cmpuri, tipul variabilelor este specificat printr-o convenie standard. Limbajul introduce instruciunile IF pentru ramificare i DO pentru realizarea de cicluri. Limbajul Algol cu versiunea de referin Algol60 a avut o contribuie remarcabil la dezvoltarea limbajelor de programare. Din Algol au derivat o serie de limbaje de programare. Proprietile principale ale unui limbaj din familia Algol sunt: este algoritmic
23
este imperativ (algoritmul este considerat o secven de modificri ale memoriei) are ca i uniti de baz blocul i procedura conine conceptele de tip i verificare a tipului are o specificare prin reguli sintactice este compilativ Algol nu a devenit foarte popular datorit faptului c nu a prevzut intrri i ieiri standard, nu avea un mecanism facil de transmitere a parametrilor prin nume i nu a fost susinut de IBM (care a promovat puternic limbajul Fortran) Tot la nceputul anilor 60 a aprut i cel de-al 3-lea limbaj de programare de 4 nivel nalt Cobol . Limbajul se impune repede pe pia datorit sprijinului puternic al guvernului SUA i devine cel mai utilizat limbaj de programare n deceniul 7. Cobol introduce descrierea datelor independent de main, punnd bazele sistemelor de gestiune a bazelor de date. Instruciunea if-then-else apare pentru prima dat n form complet n Cobol. Pentru creterea lizibilitii 5 programelor Cobol permite folosirea de cuvinte n plus . Linia Algol este continuat cu limbaje precum Algol-W, Algol68, Euler i mai apoi Pascal. Tot pe linia Algol-ului apare i limbajul Simula67 conceput pentru aplicaii n domeniul simulrii. Simula67 este primul limbaj care introduce clasa, considerat ca fiind un grup de declaraii i proceduri luate mpreun i tratate ca o unitate distinct de program. Tot n aceast perioad de nceput a limbajelor de programare apare limbajul Lisp, realizat de John McCarthy la MIT. Acest limbaj introduce un nou tip de programare, programarea funcional. n Lisp, datele i programele sunt reprezentate uniform sub forma expresiilor simbolice. Lisp utilizeaz forma prefixat a operatorilor, iar structura fundamental de control este recursivitatea. Lisp utilizeaz tehnica garbage collection n locul tergerii explicite a referinelor. Lisp rmne n continuare n actualitate fiind puternic aplicat n inteligena artificial, mai ales n SUA. Un alt limbaj important a fost PL/1. El mprumut concepte de la Fortran, Cobol i Algol68 i introduce pentru prima dat gestiunea excepiilor i multi-taskingul. PL/1 are un rol important n descrierea paralelismului. La sfritul anilor 60 Niklaus Wirth a realizat limbajul Pascal, urmrind realizarea unui limbaj de programare cu numr mic de concepte integrate. Astfel Pascal furnizeaz un mecanism de structurare a datelor, care permite un nivel superior de abstractizare. Hoare i Wirth au oferit n 1971 definirea axiomatic a limbajului. Limbajul Pascal permite verificarea programelor n faza de compilare. Pe lng aceste proprieti pozitive, totui Pascal are i lipsuri,
4 5
COmmon Business Oriented Language, n lb. Englez Syntactic sugar, n lb. Englez
24
precum controlul insuficient al utilizrii pointerilor, sau anomalii n mecanismul de definire a tipurilor. n Pascal nu se pot folosi tablouri de dimensiuni variabile, lucru posibil n Algol68. Anii 70 s-au caracterizat prin concentrarea eforturilor de mbuntire a stilului de programare n limbajele imperative. Tendine majore au fost: dezvoltarea tipului abstract de date, aprut odat cu conceptul de clas din Simula. Tipul abstract de date a fost dezvoltat n limbajele Euclid, modula i Ada. El este tratat din dou punte de vedere: relativ la proiectarea limbajului de programare i ca o proprietate a limbajului n sensul unei faciliti puse la dispoziia programatorului. Perfecionarea mecanismelor de gestiune a excepiilor. ncorporarea de mecanisme pentru descrierea proceselor paralele. Astfel, s-au dezvoltat concepte precum semaforul, monitorul sau sincronizarea prin transmitere de mesaje. Modula i Ada au faciliti pentru tratarea concurenei. Merit s amintim ca limbaje importante limbajul C, n care este scris sistemul de operare Unix, i limbajul Smalltalk care marcheaz nceputul programrii obiectuale. Ada este un limbaj important la sfritul anilor 70. Acest limbaj a fost promovat 6 de DOD n scopul de a unifica limbajele de programare n care sunt scrise aplicaiile militare. Ada este un limbaj de tip Pascal coninnd n plus faciliti pentru calcule numerice, intrri/ieiri nestandard, specificarea dependenei de main, gestiunea excepiilor, abstractizarea datelor i concuren. Proprietile limbajului acoper toat gama conceptelor moderne de modularitate, portabilitate, extensibilitate, abstractizare, faciliti de dezvoltare a programelor i de ntreinere. Anii 80 au fost marcai de dezvoltri n domeniul limbajelor pentru inteligen artificial i a paradigmei programrii obiectuale. Astfel, apare generaia 5-a de limbaje de programare prin Prolog, iar limbajul Smalltalk evolueaz i apare extensia C++ a limbajului de programare C. Tot n aceast perioad se standardizeaz o serie de limbaje de programare vechi (Fortran, Cobol i Pascal) i apare standardul ANSI pentru C. Se dezvolt limbaje de programare pentru manipularea datelor n aplicaii de gestiune precum dBase, FoxBase, FoxPro, Reflex sau Paradox. Aceste limbaje au o sintax simpl i sunt destinate cu preponderen utilizatorilor neprofesioniti. Aceast perioad este marcat de nceputul eforturilor pentru furnizarea unor medii de programare puternice pentru diferite limbaje. Apar mediile de programare Turbo, editoare de texte (WordStar, WordPerfect, MicrosoftWord), editoare pentru prelucrri de
25
tabele (Lotus, Borland Quattro, Excel), pachete de proiectare asistat CAD (AutoCAD, ORCAD) i utilitare de ntreinere. Anii 90 sunt marcai de apariia limbajelor de programare cu traducere n dou faze i de limbajul Java. Acesta implementeaz ntr-o manier mult mai clar i mai concis paradigma obiectual i, prin rulare pe maina virtual Java asigur portabilitatea programelor. n condiiile proliferrii paradigmei obiectuale, Java s-a impus rapid, probabil i datorit dezvoltrii fr precedent a Internetului. Totui, Java sufer la capitolul eficien la rulare, n sensul c programele complexe Java necesit resurse de calcul i de memorie sporite pentru o rulare eficient. Din acest punct de vedere, limbajul C++ rmne alegerea programatorilor atunci cnd criteriul de eficien este esenial. Succesul tehnologiilor Java, facilitile deosebite de programare pe care acest limbaj le ofer au impulsionat productorii de limbaje de programare s-i reconsidere oferta. Astfel, Microsoft a lansat pachetul .NET care, spre deosebire de pachetele MSVisual ofer o tratare n 2 faze a procesului de compilare execuie a programelor. Tehnologia obiectual a devenit preponderent n activitatea de programare, n strns legtur cu dezvoltarea bazelor de date relaionale i a serverelor puternice de date. Tehnologia obiectual a fost capabil s ofere un suport consistent acestor cerine, astfel c a reuit s se impun n dezvoltarea aplicaiilor comerciale. Preocuparea a fost standardizarea modului de 7 dezvoltare a software-ului. Astfel, eforturile OMG sunt remarcabile, i au 8 culminat cu standardizarea specificaiilor UML pentru proiectarea obiectual. UML este azi larg adoptat n firmele de software pentru descrierea procesului de dezvoltare a produselor soft, n toate fazele acestuia, de la culegerea cerinelor, analiz, proiectare, implementare pn la testare i integrarea produsului. n prezent tendinele dezvoltrii limbajelor de programare conduc spre standardizarea reprezentrii cunotinelor, definirea i nglobarea n limbaj a unui nivel semantic, utilizarea facilitilor inteligentei artificiale n realizarea aplicaiilor curente.
7 8
26 4. 5. 6.
Descriei tipurile de programe de traducere. Care sunt principiile programrii structurate? Descriei evoluia paradigmelor de programare n ceea ce privete trecerea de la procedur, la modul i mai apoi la obiect. 7. Descriei asemnrile i deosebirile dintre paradigma programrii funcionale i programarea logic. 8. De ce este impropriu s considerm XML un limbaj de programare? 9. Descriei caracteristicile eseniale ale limbajelor de programare din anii 60. 10. Descriei caracteristicile eseniale ale limbajelor de programare din anii 70. 11. Descriei principalele evoluii ale limbajelor de programare n anii 80 i 90.
2.1.1. Gramatici
Fie o mulime
numesc simboluri. Un simbol din A este reprezentat ntr-un limbaj printr-o liter, cifr sau semn, uneori printr-un ir finit de litere, cifre sau semne. Notm prin
A*
A*
A. A . Simbolurile se z = xy ,
A*
A*
i
din
A*
atunci irul
cu simbolurile din
y,
va fi de
A*.
din
A*
nzestrat cu operaia
de concatenare are o structur de monoid. Prin definiie, un limbaj formal peste alfabetul
este o submulime
a lui
A*.
i mulimea
P ( A*)
a prilor mulimii
A * , pe aceast
din urm mulime putem defini urmtoarele operaii de baz: a. b. c. d. e. f. intersecie: reuniune:
L1 L2
L = {x A* | x L}
L1 L2
n legtur cu un limbaj formal, se pune problema apartenenei unei construcii la limbaj, adic, n condiiile furnizrii unui cuvnt decide (demonstra) una din urmtoarele 2 concluzii:
Se spune c un limbaj L este decidabil, dac rspunsul la ntrebarea de mai sus este pozitiv. Conceptul de algoritm st la baza rezolvrii acestei probleme. Adic, trebuie s decidem rspunsul la ntrebarea de apartenen ntr-un timp finit folosind operaii precis definite. Problema apartenenei unui cuvnt la limbaj, n cazul limbajelor de programare trebuie s fie rezolvat de compilator, adic acesta trebuie s decid dac codul surs furnizat de programator satisface sau nu regulile limbajului, adic poate fi compilat sau nu. n cazul n care limbajul L este finit, atunci limbajul este decidabil. Dac L este infinit, trebuie s folosim alte metode pentru a rspunde la ntrebarea de decidabilitate. Specificarea limbajului nseamn fie enumerarea tuturor elementelor acestuia, fie enunarea unor reguli de construcie a elementelor limbajului. Noiunea de gramatic st la baza specificrii unui limbaj prin generarea tuturor cuvintelor sale. Prin definiie, un sistem formal este un cvadruplu ordonat alctuit din: alfabetul sistemului
S =< A, F ,, R >
F A*
29
R . O regul de deducie n de aritate n + 1 este o relaie din mulimea F F , care asociaz o formul unic x cu un n-tuplu y =< y1 , y 2 ,..., y n > . Spunem c x se
deduce din
y1 , y 2 ,..., y n
corecte
i scriem
yRx .
numite premise. Fie
Fie
formulele
y1 , y 2 ,..., y n ,
E0 .
Ei = Ei 1 U{x | y E ,
n 1
n i 1 astfel incat
yRx} . Ei
se
E0 =
succesiv a unor reguli de deducie asupra unor formule din mulimile Secvena acestor reguli de deducie alctuiete demonstraia teoremei Prin definiie, urmtorul caz particular de sistem formal: a. alfabetul disjuncte de simboluri terminale. b. c. d.
Ei .
x.
A al sistemului formal este finit i este alctuit din dou mulimi N i , alfabetul de simboluri neterminale respective alfabetul
Acest simbol se numete simbol de nceput. Regulile de deducii au la baz producii: O producie este o pereche
F = A * : toate irurile finite pe alfabet sunt formule corecte. conine un singur element, i anume un simbol neterminal S . ( , ) Q
de formule, notat cu
P Q P Q
cu
unde
se poate nlocui
i se obine tot o
G =< N , , P, S >
se numete gramatic.
Procesul de inferen n cazul gramaticilor se numete derivare. Spunem despre dou iruri
din
deriveaz imediat n
din
i o
30 producie
astfel nct
= 1 2
= 1 2 .
O asemenea
relaie de derivare reprezint o derivare ntr-un singur pas. Derivarea se poate defini pe k pai, n cazul
prin k derivri.
O relaie de derivare a lui din este nebanal, dac obinerea lui se realizeaz ntr-un numr nenul de pai. Relaia de derivare se numete general dac se obine din formule coincid. propoziiilor
L(G ) = {x}
cu proprietatea c
deriv general pe
x.
Dac limbajele generate de dou gramatici coincid, se spune c gramaticile sunt echivalente. Conform definiiei gramaticilor enunat de mai sus, Naom Chomsky le-a clasificat dup forma produciilor. Astfel, avem urmtoarele tipuri de gramatici: 1. Clasa gramaticilor de tip 0: reprezint cea mai general clas de gramatici, sunt cele care respect definiia general furnizat mai sus. 2. Clasa gramaticilor de tip 1: produciile sunt de forma: este un simbol neterminal, 3.
Aceste gramatici se mai numesc i dependente de context. Clasa gramaticilor de tip 2: produciile sunt de forma: A , unde A este un simbol neterminal, este ir oarecare. Aceste gramatici se mai numesc i independente de context. Clasa gramaticilor de tip 3 sau regulate: produciile sunt de forma
4.
A aB sau A a , unde A i B sunt simboluri neterminale iar a este simbol terminal. Corespunztor claselor de gramatici, avem clase de limbaje. Astfel, se poate defini o ierarhie Chomsky a limbajelor. Limbajul independent de context (de tip 2) este modelul limbajelor de programare. n ceea ce privete utilitatea studiului gramaticilor pentru scrierea compilatoarelor urmtoarea teorem este important: Orice limbaj dependent de context (i n consecin independent de context i regulat) este decidabil. Deci, limbajele de programare sunt decidabile.
31
n consecin, se constat faptul c o propoziie este compus prin alturarea unui subiect, verb i a unui obiect (atribut). Propoziia se termin cu simbolul terminal punct. Subiectul poate fi un articol alturat unui substantiv sau (simbolul |) un pronume de tip subiect. Pronumele de tip subiect poate fi unul din simbolurile terminale he sau she etc. Astfel, prin asemenea construcii se pot descrie toate regulile de producie din limbaj. De fapt, prin BNF descriem ntreaga gramatic pe baza creia apoi, putem genera limbajul corespunztor acesteia. Deci, pornind de la specificarea BNF a unei gramatici, putem folosi aceast specificare pentru a genera limbajul i pentru a recunoate sintagmele acceptate de gramatica definit. Procesul prin care, avnd dat la intrare o propoziie, determinm (decidem) dac propoziia respectiv este acceptabil, n contextul unei gramatici se numete parsare.
32
2.1.2.2. EBNF
De multe ori, specificarea BNF este greoaie din punct de vedere al lizibilitii, mai ales atunci cnd un simbol neterminal se poate repeta, de un numr finit sau infinit de ori, ntr-o construcie. De exemplu, putem considera definirea unui string ca fiind un ir de una sau mai multe cifre:
<string>::=<digit>|<digit><string>
Pentru a uura asemenea construcii, EBNF introduce urmtoarele metasimboluri: {} tot ce e inclus ntre acolade se poate repeta, sau poate lipsi [] tot ce e inclus ntre parantezele drepte poate lipsi (este opional) Astfel, construcia de mai sus poate fi scris:
<string>::=<digit>{<digit>}
De exemplu, pentru a defini un numr, care poate avea simbolul de semn, putem folosi urmtoarele construcii alternative:
<numer>::=<sign><unsigned>|<unsigned>
n BNF
sau
<number>=[<sign>]<unsigned>
n EBNF
EBNF introduce i alte meta-simboluri ajuttoare. Astfel avem: * nlocuiete acoladele, are semnificaia c simbolul precedent se poate repeta de un numr de 0 sau mai multe ori + simbolul precedent se poate repeta de 1 sau mai multe ori _ se subliniaz meta-simbolurile, atunci cnd acestea fac parte din alfabetul limbajului specificat
33
Figura 5 prezint cteva diagrame de sintax pentru elementele gramaticii de mai sus.
<sentence> <expression> =
<digit>
0 1 2 3 4 5 6 7 8 9
<string>
<digit>
Figura 5.
Diagrame de sintax.
sau nu?
Automatul este definit ca o main cu operaii simple, care primete irul de analizat pe un suport oarecare, l parcurge, i rspunsul final este dat de starea n care rmne unitatea de comand a automatului. Suportul pe care este furnizat irul este denumit generic band de intrare, iar variabila care parcurge irul de analizat n citire se numete cap de citire. Automatul poate folosi o memorie auxiliar pentru pstrarea unor informaii care s fie de folos la un moment dat, n procesul decizional.
34
Asemenea automate sunt definite prin grafuri. Nodurile grafului reprezint stri ale automatului, iar arcele reprezint tranziii ntre stri. Arcele sunt marcate cu condiii, cu semnificaia c, dac automatul se afl ntr-o anumit stare, i se ndeplinete condiia de pe un arc care iese din starea respectiv, atunci automatul va trece n starea de la cellalt capt al arcului selectat. Automatele pot fi: deterministe, dac dintr-o stare se poate realiza cel mult o singur micare nedeterministe, dac dintr-o stare exist mai multe micri posibile. Automatele nedeterministe corespund gramaticilor cu producii cu alternative. Un ir x este acceptat de un automat U dac, pornind de la configuraia iniial, prin micrile automatului se parcurge ntregul ir de intrare i automatul ajunge ntr-o configuraie final. Pentru exemplificare, vom considera automatul finit din figura 6.
b a a q0 q1
Figura 6.
Astfel, automatul din figura 6 are 2 stri: q0 i q1. q0 reprezint starea iniial, q1 reprezint starea final. Dac, pe banda de intrare se ntlnete irul a i automatul este n starea q0, atunci automatul trece n starea q1. Dac pe banda de intrare se ntlnete irul b i automatul este n starea q0, atunci automatul rmne n aceeai stare etc. Tabelul 2 prezint matricea de definire corespunztoare acestui automat. a b q0 q1 Tabelul 2. q1 q1 q0 q0
(q1,aba)
(q1,ba)
(q0,a)
Deci, pornindu-se din starea iniial q0, se parcurge irul de intrare i n final, la epuizarea acestuia, se ajunge n starea final q1, cu irul vid
35
Exemplul din figura 6 reprezint un automat finit determinist. n figura 7 prezentm un exemplu de automat finit nedeterminist. Tabelul 3 reprezint matricea de tranziii pentru acest automat. Caracteristic automatului nedeterminist este faptul c dintr-un nod pot iei mai multe sgei etichetate cu acelai simbol de intrare, precum i sgei etichetate cu tranziii independente de intrare.
a a 0 1 b 3
care reprezint
2 a
Figura 7.
Diagrama de tranziie a unui automat finit nedeterminist a 0 1 2 3 {0,1} {2} b {2,3} {3} -
{2} -
Tabelul 3.
Se poate stabili o relaie ntre automatele finite deterministe i cele nedeterministe. Astfel, pentru orice automat finit nedeterminist exist un automat finit determinist care accept acelai limbaj. Vom prezenta succint n cele ce urmeaz algoritmul de calcul al automatului finit determinist echivalent din punct de vedere al limbajului acceptat cu un automat finit nedeterminist. Considerm un automat finit nedeterminist care conine mulimea de stri Fie
Q.
Q1
pe aceeai
astfel:
36
Procedure AFN2AFD
Q1 {q0 }
while (mai exist stri nemarcate n
Q1 Q1
nemarcat din
q ' { p | p = ( M , )}
if
q ' Q1 Q1 Q1 {q '}
end if La mulimea de tranziii a automatului determinist adaug tranziia q end for end while end procedure
q'
Figura 8. Transformarea unui automat finit nedeterminist ntr-un automat determinist echivalent din punct de vedere al limbajului acceptat n algoritmul din figura 8 s-au realizat urmtoarele notaii: -
q0
q0
este nchiderea
(q, a )
considerarea simbolului de intrare a. - nchiderea tranzitiv a unei mulimi de stri este mulimea tuturor strilor la care se poate ajunge considernd stri din mulimea de intrare i tranziii doar prin irul vid. Algoritmul prezentat este iterativ i se bazeaz pe cutarea strilor noului automat prin includerea de stri din vechiul automat i marcarea nodurilor deja create. Vom exemplifica aplicarea acestui algoritm pe automatul nedeterminist din figura 7.
q0
nodul 0 mpreun cu toate nodurile n care se poate ajunge din acest nod considernd doar tranziii vide. Deci
q0
nod din noul automat determinist. Marcm acest nod, i ncercm s determinm alte noduri ale automatului determinist. Pentru aceasta vom considera, pe rnd, fiecare simbol de intrare acceptat de automat. Fie pentru nceput simbolul a. Construim mulimea destinaie, pornind de la noduri din
q0
automatul nedeterminist prin simbolul a. Obinem nchiderea tranzitiv a lui noduri din
M = {0,1,2} .
Considerm
q'
q ' = [0,1,2] .
q0
n nodul
q ' . Continum algoritmul prin considerarea celui de-al doilea simbol de intrare,
b. Considernd toate nodurile care urmeaz din noduri ale lui dezvolta mulimea
q0
prin b, vom
M = {3} .
este mulimea
vid. Deci, vom aduga starea mulime vid n automatul determinist i vom lega aceast stare de starea iniial prin tranziia pe simbolul de intrare b. Continum algoritmul prin marcarea unei noi stri,
[0,1,2] ,
i reluarea
acelorai pai. Figura 9 conine automatul finit determinist obinut. Transformarea unui automat finit nedeterminist ntr-un automat finit determinist este important deoarece lucrul cu automatele nedeterministe este dificil, datorit traiectoriilor paralele pe care le poate lua calculul n aceste automate. Dar noi trebuie s privim aceste automate n contextul studiului gramaticilor, care definesc limbajele de programare. Astfel, pornind de la o gramatic, se poate genera un automat finit care s accepte gramatica respectiv. Dac automatul finit obinut pentru o gramatic este nedeterminist, vom aplica procedura din figura 8 pentru a construi automatul finit determinist echivalent. Automatele deterministe ne indic modul n care trebuie s tratm un ir de intrare pentru a identifica dac acesta este acceptat sau nu de automat. Astfel, la construirea compilatoarelor, analizorul sintactic folosete logica automatului pentru a spune dac o construcie de intrare e valid sau nu, i n caz afirmativ, consider mai departe aceast construcie.
38
a [2]
a
a b [0,1,2]
a
[2,3]
b
[0,2]
b
a,b
[3]
[0]
Figura 9.
n practic, ori de cte ori avem de implementat un parser, adic un program care interpreteaz la intrare iruri de caractere cu anumite proprieti, prin descrierea automatului corespunztor putem identifica traiectoriile posibile de intrare i implementa un analizor corect i eficient. n ANSI C exist biblioteca de expresii regulate folosite pentru generare de abloane de iruri de caractere, care urmeaz exact regulile semantice de descriere ale automatelor.
2.2. Compilatoare
n procesul de comunicare om-calculator intervine un program intermediar, translatorul, care asigur traducerea programelor scrise de utilizator din cod surs ntr-un alt limbaj mai apropiat de calculator. Dac limbajul int este codul main, translatorul se numete compilator. Astfel, execuia unui program surs se realizeaz, n cadrul limbajelor compilative, n 2 faze: compilare, care traduce codul surs n program obiect execuie, care ruleaz codul obiect pe calculator, folosind datele iniiale ale programului i produce rezultate Compilatorul unui limbaj de asamblare se numete asamblor. n practic, pe lng compilatoarele obinuite, exist i alte tipuri de compilatoare. Astfel, preprocesoarele sunt translatoare care traduc dintr-un limbaj de nivel nalt n alt limbaj de nivel nalt. Preprocesorul limbajului C++ reprezint un bun exemplu.
2.2. Compilatoare
39
Cross-compilatoarele sunt compilatoare scrise pentru un calculator gazd, n vederea generrii de cod pentru alt calculator. Cross-compilatoarele sunt folosite la scrierea de cod pentru diverse dispozitive inteligente, care conin procesoare. n cazul limbajelor interpretative, compilatorul este de tip special, adic incremental. Astfel, programul surs este spart de ctre compilator n poriuni mici numite incremente, care au o oarecare independen sintactic i semantic. Incrementele sunt traduse de compilator. Pe msur ce compilatorul traduce un increment, calculatorul execut incrementul tradus. n mod tradiional, un compilator realizeaz un ir de transformri asupra codului surs n reprezentri din ce n ce mai apropiate de codul main. Figura 10 prezint fazele unui compilator.
Program sursa Sir de atomi lexicali Arbore sintactic Cod intermediar Cod intermediar optimizat Program obiect
Analiza lexicala
Analiza sintactica
Analiza semantica
Optimizare de cod
Generare de cod
Tratarea erorilor
Gestiunea tabelelor
Figura 10.
Analiza lexical grupeaz caracterele din program n subiruri numite atomi lexicali care reprezint cuvintele cheie, operatori, constante, identificatori i delimitatori. irul de atomi lexicali este preluat de analiza sintactic. Aceasta depisteaz structuri sintactice cum ar fi expresii, liste, instruciuni, proceduri. Aceste structuri sunt plasate ntr-un arbore sintactic conform relaiilor existente ntre aceste structuri. Analiza semantic folosete structura programului pentru extragerea informaiilor privind obiectele purttoare de date (variabile, proceduri, funcii), verificarea consistenei utilizrii lor. Pe msura parcurgerii arborelui sintactic, analiza semantic construiete o reprezentare a codului surs n cod intermediar. Acesta este de obicei un ir de instruciuni simple cu format fix. Ordinea operaiilor din codul intermediar respect ordinea de execuie a acestora pe calculator. Codul intermediar este prelucrat n faza de optimizare pentru eliminarea redundanelor de calcule, a calculelor i variabilelor inutile, pentru o execuie mai eficient.
40
Generarea de cod aloc celule de memorie pentru memorarea datelor la execuie. Se aloc registre i se produce cod obiect echivalent cu programul n limbaj intermediar. Gestiunea tabelelor este de fapt, o colecie de proceduri care creeaz i actualizeaz datele cu care lucreaz celelalte faze. n aceast tabel, pe lng informaii proprii compilatorului se gsesc i tabele ale identificatorilor, constantelor, cuvintelor cheie. Uneori avem o tabel unic, numit tabela simbolurilor. Tratarea erorilor este o colecie de proceduri care sunt activate ori de cte ori se depisteaz o greeal n program. De obicei, utilizatorul primete un mesaj de diagnostic. Dac greeala este identificat n faza de analiz sintactic, compilatorul poate s-i urmeze analiza pentru a detecta i alte erori. Structura prezentat este mai mult conceptual. Compilatoarele concrete de multe ori prezint abateri fa de aceast structur. Unele componente pot lipsi, sau funcionalitatea lor poate fi preluat de alte componente, sau ordinea activrii componentelor poate fi diferit. Realizarea compilatoarelor presupune un volum mare de munc. Exist unelte software specializate care asigur faciliti de dezvoltare a compilatoarelor. Astfel, avem uneltele LEX i YACC sub Unix care permit descrierea sintactic i semantic a unui compilator, conform regulilor limbajului, utiliznd automatele de acceptare a construciilor de intrare. Programatorul trebuie s descrie regulile limbajului i sintaxa propoziiilor acceptate n format de expresii regulate, iar mai apoi construcia int asociat fiecrei sintagme de limbaj surs. Utilitarele genereaz un cod C care apoi compilat, reprezint de fapt compilatorul pentru limbajul surs considerat. Datele de intrare pentru asemenea unelte sunt: specificaia limbajului surs, n ceea ce privete descrierea lexicului i a sintaxei specificaia limbajului int i a regulilor semantice de traducere specificaia mainii int Dac n trecut, timpul de elaborare a unui compilator era destul de mare, azi, utiliznd asemenea tool-uri moderne putem realiza rapid compilatoare pentru diverse limbaje.
41
4. 5.
Cum se specific un automat? Care sunt tipurile de automate? Explicai importana studierii automatelor cu privire la studiul limbajelor de programare. Explicai structura (fazele) unui compilator. Ce se ntmpl n fiecare faz? Se d urmtoare specificare EBNF pentru un calculator de buzunar:
(a) (b) (c) <expression>::=<number>{<operator><expression>} <sentence>::=<number>{<operator><sentence>}= <number>::={<sin>}<unsigned>
Se decid care din urmtoarele numere sunt acceptate sau nu de gramatica specificat mai sus: (a) 1 (b) 1. (c) 1.1 (d) .1 (e) 12.34 7. S se scrie automatul finit determinist care accept urmtorul limbaj: {a, b, ab, abab, } 8. Fie gramatica regulat G=<{B, S}, {a, b}, P, S> unde
Descriei limbajul aferent acestei gramatici n BNF. Trasai automatul finit care accept aceast limbajul asociat gramaticii. Aplicai procedura de conversie a automatului nedeterminist n automat finit determinist i listai automatul determinist echivalent.