Sunteți pe pagina 1din 33

Capitolul 1.

Introducere n limbaje de programare


Acest capitol introduce problematica limbajelor de programare. Pentru nceput vom evidenia necesitatea studierii limbajelor pentru a putea realiza comunicarea om-calculator. Pornind de la comunicarea interuman prin intermediul limbilor (vorbite, scrise, vizuale), vom defini conceptul de limbaj de programare. Apoi vom insista asupra unor noiuni introductive de limbaje de programare. Astfel, vom realiza o clasificare a limbajelor de programare, insistnd asupra tipurilor de limbaje, asupra gradului lor de abstractizare respectiv de apropiere de descrierea i rezolvarea anumitor tipuri de probleme. Vom continua prin a realiza o scurt incursiune n istoria limbajelor de programare, evideniind evoluia lor n timp, concomitent cu evoluia paradigmelor de gndire n informatic. Partea final a capitolului puncteaz cteva aspecte caracteristice care trebuie studiate i menionate la referirea unui limbaj de programare.

1.1. Definirea limbajelor de programare


Comunicarea interuman este indispensabil n viaa de zi cu zi. Pentru realizarea acesteia, oamenii folosesc diverse modaliti, limbajele reprezentnd poate cea mai important facilitate de comunicare. Una din primele aptitudini importante pe care un copil o dobndete este s vorbeasc. El nva limba matern. De obicei, aceasta i este suficient pentru comunicarea de zi cu zi cu ali indivizi din propria societate. Dac ns, un individ cltorete, el are nevoie s cunoasc i alte limbi pentru a se putea descurca, pentru a putea comunica cu ali oameni din alte societi ale lumii. Cu toate c, n principiu, oamenii atribuie nelesuri similare pentru lucruri similare, ei vorbesc (exprim) aceste nelesuri n limbi diferite. Diferena se manifest att la nivelul sunetelor i nlnuirii acestora pentru a forma cuvintele ct i la nivelul simbolurilor grafice folosite. A nva s vorbim ntr-o alt limb presupune a nva s rostim cuvintele din limba respectiv, s le nlnuim de o manier potrivit conform regulilor gramaticale a limbii nvate i s folosim simbolurile specifice acestei limbi pentru a descrie vizual sintagmele de comunicare. Dac nu mnuim corespunztor aceste elemente, atunci cnd vom fi pui n situaia de a comunica cu cineva care nelege doar limba respectiv, vom eua n ncercarea noastr.

10

Capitolul 1. Introducere n limbaje de programare

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.

1.1. Definirea limbajelor de programare


Universul problemei Simulare Universul calculatorului

11

Elaborare program

Compilare

Universul limbajului de programare

Figura 1.

Universurile unui limbaj de programare [erbnai 1987].

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

Capitolul 1. Introducere n limbaje de programare

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.

1.2. Clasificarea limbajelor


Referitor la limbaje, putem s vorbim de o clasificare general a acestora. Astfel, limbajele pot fi naturale sau artificiale. Referindu-ne strict la limbajele de programare, acestea pot fi clasificate din perspectiva paradigmelor de programare sau a nivelului de abstractizare a limbajului. n aceast seciune vom descrie succint clasificarea general a limbajelor i vom insista asupra clasificrii limbajelor de programare.

1.2.1. Clasificarea general a limbajelor


Pe plan general, exist 2 tipuri de limbaje: naturale i artificiale. Limbajele naturale sunt cele istorice, precum limba romn, englez etc. Limbajele artificiale au fost create de oameni n diverse scopuri. Astfel exist: jargoane profesionale, folosite la comunicarea n cadrul diverselor grupuri profesionale. Exist astfel un limbaj matematic, medical, economic, bursier etc. limbaje pentru comunicare ntre dispozitive. Aceste limbaje se mai numesc i protocoale. Ele ajut la stocarea i transmiterea informaiei ntre diverse componente ale unor medii (de obicei artificiale). De exemplu, pentru comunicarea n reelele de calculatoare se folosete protocolul TCP/IP sau alte protocoale de reea (de nivel mai mult sau mai puin abstract). Pentru comunicarea la nivel software se pot folosi limbaje bazate pe descrieri specifice de domeniu, descrise n XML. limbaje de pentru comunicarea dintre om i dispozitive. Din aceast categorie fac parte limbajele de programare.

1.2.2. Clasificarea limbajelor de programare din perspectiva nivelului de abstractizare


Din punct de vedere al nivelului, limbajele se nscriu n 2 mari categorii: limbaje de nivel inferior limbaje de nivel superior

1.2. Clasificarea limbajelor

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

Microprocesor Cod masina

Figura 2.

Ierarhizarea limbajelor de programare n funcie de nivel.

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

Capitolul 1. Introducere n limbaje de programare

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.

1.2. Clasificarea limbajelor

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.

1.2.3. Paradigmele limbajelor de programare


Prin paradigm se nelege n general modelul sau arhetipul unui proces sau sistem. Paradigmele de programare sunt colecii individualizate de caracteristici de evaluare i criterii de abstractizare care determin i difereniaz clasele de limbaje de programare [Prv 1996]. Exemple de astfel de criterii sunt structura programului, starea execuiei, metodologia programrii etc. Clasificrile limbajelor de programare dup paradigme difer de la autor la autor. Vom prezenta n cele ce urmeaz cteva paradigme de programare considerate mai importante n istoria limbajelor de programare [Nichi 2005]. Trebuie s menionm c ideile cuprinse n limbajele de programare sunt n continu schimbare, datorit faptului c, permanent, apar limbaje noi, care de multe ori nu pot fi clasificate conform criteriilor existente.

1.2.3.1. Paradigma programrii procedurale


Clasificnd limbajele dup aceast paradigm, ele se mpart n limbaje procedurale i limbaje neprocedurale. Limbajele procedurale se caracterizeaz prin faptul c utilizatorul descrie pas cu pas algoritmul de rezolvare a problemei, printr-un ir de instruciuni care formeaz o procedur, rutin, subrutin sau funcie. Din acest punct de vedere, programul este o mulime ierarhic de blocuri i proceduri. Exponentul clasic al acestei paradigme este ALGOL60. Din aceast categorie amintim limbajele Pascal, C, PL/I, Ada etc. n limbajele neprocedurale, utilizatorul nu mai descrie algoritmul de rezolvare, el doar indic sistemului ce anume dorete. n acest caz, sistemul este responsabil s gseasc calea de rezolvare a problemei.

1.2.3.2. Paradigma programrii structurate


Programarea structurat este n strns legtur cu programarea procedural. Muli autori consider aceste dou paradigme ca fiind de fapt una singur. Fundamentul programrii structurate este urmtorul enun: orice procedur care are o singur intrare i o singur ieire poate fi reprezentat prin cele trei structuri fundamentale din algoritmic: structura liniar, structura ramificat i structura repetitiv. Astfel, s-a demonstrat c instruciunile de salt necondiionat din programe nu mai sunt necesare, i astfel se poate ordona activitatea de scriere de cod. Alternativa la programarea structurat este programarea stil

16

Capitolul 1. Introducere n limbaje de programare

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.

1.2.3.3. Paradigma programrii modulare


Programarea modular const n descompunerea programului n module independente, atomice. Principala idee este ncapsularea. Astfel, datele interne modulului sunt ascunse utilizatorului. Accesul la date se poate realiza doar prin interfa. n acest context, un modul are dou componente: interfaa i implementarea. Paradigma programrii modulare extinde programarea procedural i structurat prin introducerea unui nivel superior de abstractizare: modulul. Se face astfel un pas important ctre programarea obiectual. Cele mai cunoscute limbaje modulare sunt Modula i Ada.

1.2.3.4. Paradigma programrii obiectuale


n aceast seciune vom descrie doar succint caracteristicile paradigmei obiectuale. Partea a doua a prezentei lucrri conine o dezvoltare i o prezentare mai larg a conceptelor i metodelor de programare obiectual. Un obiect definete o entitate care conine informaie i are un comportament. Alte obiecte pot face uz de comportamentul obiectului pentru a obine informaia ataat obiectului. n programarea obiectual, orice entitate din lumea real poate fi considerat un obiect. Programul este considerat ca un ansamblu de obiecte care interacioneaz ntre ele. n cadrul paradigmei obiectuale, obiectele reprezint ncapsularea datelor cu codul. Deci obiectele au o structur i o stare. Fiecare obiect definete operaiile care pot accesa i manipula aceast stare. Obiectele sunt uniti atomice n programe. Datele interne ale obiectelor se mai numesc proprieti, iar partea de cod formeaz metodele. Comunicarea ntre obiecte se face prin mesaje. Astfel, un apel de metoda a unui obiect poate fi considerat ca o transmitere de mesaj ctre obiectul apelat. Obiectele de acelai tip pot fi grupate n clase. Din acest punct de vedere, putem considera obiectele ca i instanieri ale claselor. Clasele pot fi relaionate unele cu altele, prin diverse tipuri de relaii. Astfel, avem relaiile de agregare prin care o clas se compune din alte clase, sau de generalizare/specializare,

1.2. Clasificarea limbajelor

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.

1.2.3.5. Paradigma programrii funcionale


n cadrul acestei paradigme programul este descris ca un ansamblu de funcii apelate, n general, recursiv. Ele pot interveni n structurile de date ale limbajului dar i n cadrul codului, fiind permise funcii de funcii (se accept operaia de compunere de funcii). Printre caracteristicile acestor limbaje amintim faptul c ele nu au instruciuni de atribuire i nu genereaz efecte secundare la apelul unei funcii. Prin efect secundar la apelul unei funcii nelegem existena unui efect al rulrii funciei asupra apelantului ei. Fundamentul matematic al limbajelor funcionale l constituie scrierea funciilor ca i expresii lambda. Exemplul tipic de limbaj funcional este LISP. El se bazeaz pe gestiunea listelor. Un alt limbaj din aceast familie este ML, limbaj generic utilizat la studiul teoretic al programrii funcionale.

1.2.3.6. Paradigma programrii logice


n programarea logic un program este alctuit din fapte i reguli pe baza crora programul urmeaz s genereze concluzii. Limbajele din aceast paradigm se mai numesc limbaje declarative deoarece specificarea unui program nseamn specificarea unor declaraii. Programul nu instruiete calculatorul cum s rezolve problema, ci spune calculatorului cum dorim s arate soluia problemei. n sensul programrii logice, programul indic procesorului metodele i informaiile necesare pentru extragerea unei soluii de forma dorit. Baza matematic a acestor limbaje o constituie sistemele logice formale. De obicei, acestea se bazeaz pe logica predicatelor de ordinul I, care poate fi extins sau mbogit cu alte axiome. Astfel, se pot obine logici modale,

18

Capitolul 1. Introducere n limbaje de programare

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.3.7. Paradigma programrii concurente i distribuite


Aceast paradigm se bazeaz pe faptul c dou sau mai multe programe, respectiv pri ale aceluiai program se execut n paralel pe acelai procesor sau pe procesoare diferite. Astfel, aceast paradigm nu mai respect principiul linearitii n execuia instruciunilor componente ale unui program. Execuia aciunilor unui program poate fi independent sau pot depinde de execuia instruciunilor altui program care se execut n paralel. Astfel, pentru sincronizarea execuiei programelor se folosesc tehnici de sincronizare i serializare, semafoare respectiv semnturi de timp. Astfel, se asigur comunicarea ntre procese, accesul concurent la resurse, partajarea resurselor. Aspectul de distribuire se refer la utilizarea concomitent resurselor din mai multe locaii, respectiv la mprirea sarcinilor de executat i realizarea acestora de mai multe entiti de procesare. Limbajele concurente sunt de obicei extensii ale limbajelor din alte paradigme. Astfel, exist extensii concurente pentru C, Pascal, Fortran, Prolog. Exemple de limbaje concurente sunt CSP, Linda, Occam, Parlog.

1.2.3.8. Alte paradigme de programare


Muli autori consider i alte paradigme de programare. Astfel, pentru programarea la nivelul bazelor de date avem limbaje de programare precum SQL sau dBase. Acestea sunt destinate asigurrii unei gestiuni corecte i consistente a bazelor de date. Unii autori consider programarea vizual ca o paradigm de programare. n cadrul acestei paradigme ei ncadreaz mediile de dezvoltare rapid a 1 programelor . De obicei, ns aceste medii sunt destinate realizrii activitii de programare pentru un anume limbaj, i astfel, considerm c ele nu reprezint o nou paradigm de limbaje de programare. 2 Limbajele bazate pe marcatori sunt folosite de obicei pentru structurarea i reprezentarea informaiei i mai puin pentru realizarea activitii de programare. Ele se bazeaz pe SGML, un limbaj standardizat, independent de platform, utilizat la realizarea help-urilor i a componentelor sale. n cadrul

1 2

Rapid Application Development (RAD) environments, n lb. Englez Markup Languages, n lb. Englez

1.2. Clasificarea limbajelor

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.

1.3. Istoricul i evoluia limbajelor de programare


n aceast seciune vom descrie principalele borne care au marcat istoria limbajelor de programare, mpreun cu elementele de noutate aduse de fiecare limbaj important din punct de vedere a evoluiei istoriei informaticii. Tabelul 1 prezint o legarea principalelor limbaje de programare de momentul apariiei. Figura 3 conine arborele limbajelor de programare, reflectnd influenele i genealogia limbajelor de programare. Acestea sunt preluate dup [Prv 1996]. Dezvoltarea limbajelor de programare este strns legat de evoluia tiinei calculatoarelor. Astfel, pe msur ce mainile de calcul devin tot mai sofisticate i performante, evolueaz i limbajele i paradigmele de programare, oferind noi faciliti utilizatorilor de maini de calcul. Limbaj
Fortran Algol60 Cobol

An
1957-si 1960-s 1960-s

Autori
J. Backus (IBM) Comitet DOD

Predecesor

Scop
Calcule numerice

Fortran

Calcule numerice Prelucrri de date economice

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

Capitolul 1. Introducere n limbaje de programare


K. Iverson (Harvard) J. McCarthy (MIT) R. Griswold (Bell) IBM O.J. Dahl Comitet N. Wirth (ETH Zurich) Univ. Marsilia D. Ritchie (Bell) P.B. Hansen (CalTech) Comitet N. Wirth J. Ichbiah (CIIBull) Xerox PARC B. Stroustrup N. Wirth DEC, Olivetti Sun Algol60, BCPL Pascal Pascal Pascal Pascal, Simula67 Simula67 C Pascal, Modula Modula Fortran, Algol60, Cobol Algol60 Algol60 Algol60 Prelucrri de tablouri Prelucrri de liste Prelucrri de iruri de caractere Uz general Simulare Uz general Uz general, scop educaional Programare logic Programare de sistem Programare concurent Programare de sistem verificabil Programare de sistem n timp real Uz general, aplicaii hibride Programare orientat obiect Programare orientat obiect Programare orientat obiect Limbaj puternic modular, orientat obiect Limbaj orientat obiect, traducere n dou faze
3

Tabelul 1.

Principalele limbaje de programare .

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.

si nseamn specificare i implementare, iar s nseamn numai specificare

1.3. Istoricul i evoluia limbajelor de programare

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

BCPL Algol68 Pascal Prolog C Simula67

1970

Modula-2 Ada
1980

C cu clase

Smalltalk

ANSI C

Objective C

C++ Modula-3
1990

Ada9X

Figura 3.

Arborele genealogic al limbajelor de programare.

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

Capitolul 1. Introducere n limbaje de programare

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

Memorie: programe si date

Figura 4.

Arhitectura von Neumann

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

1.3. Istoricul i evoluia limbajelor de programare -

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

Capitolul 1. Introducere n limbaje de programare

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

United States Department of Defense

1.3. Istoricul i evoluia limbajelor de programare

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.

1.4. ntrebri propuse


1. 2. 3. Ce este un limbaj de programare? Descriei universul limbajelor de programare. Descriei cele 3 aspecte caracteristice ale unui limbaj de programare. Descriei caracteristicile generaiilor de limbaje de programare.

7 8

Object Management Group Unified Modeling Language

26 4. 5. 6.

Capitolul 1. Introducere n limbaje de programare

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.

Capitolul 2. Fundamentele limbajelor de programare


n acest capitol vom introduce aspectele formale ale limbajelor de programare. Astfel, vom defini limbajele abstracte, ca i fundament pentru dezvoltarea tehnicilor de parsare i a compilatoarelor. Seciunea 2-a a capitolului va prezenta paii i operaiile pe care le suport un cod surs pentru a fi transformat n cod main, prin operaia de compilare.

2.1. Limbaje abstracte


n acest capitol vom prezenta succint formalizarea exhaustiv a teoriei limbajelor de programare. Materiale precum [Aho 1977], [erbnai 1987] conin o tratare detaliat a acestui subiect. Teoria limbajelor de programare este necesar pentru specificarea formal corect a limbajelor i reprezint un fundament pentru teoria compilrii.

2.1.1. Gramatici
Fie o mulime

nevid, finit, numit alfabet. Elementele acestei mulimi se

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*

mulimea aranjamentelor cu repetiie ale simbolurilor din

Astfel, un element din

A*

este un ir finit de simboluri din

A. A . Simbolurile se z = xy ,

pot repeta n ir. Mulimea

A*

conine i irul vid; vom nota acest ir cu

Numrul de simboluri dintr-un ir din observ c dac avem dou iruri

A*
i

se numete lungimea irului. Se

din

A*

atunci irul

obinut prin alturarea simbolurilor din asemenea, element al mulimii irurile

cu simbolurile din

y,

va fi de

A*.

Operaia prin care se obine irul

din

se numete concatenare. Mulimea

A*

nzestrat cu operaia

de concatenare are o structur de monoid. Prin definiie, un limbaj formal peste alfabetul

este o submulime

a lui

A*.

28 Fiind dat un alfabet

Capitolul 2. Fundamentele limbajelor de programare

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

complementare: produs: stea:

L1 L2 = {x1 x2 | x1 L1 , x2 L2 } . Notm cu L2 = LL,...

L* = {} L L2 ... Ln ... ~ ~ ~ reflectare: L = {x | x L} unde x este imaginea reflectat a lui x


x A * , dac se x L sau x L .
poate

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 >

mulimea decidabil a formulelor corecte, mulimea decidabil a axiomelor,

F A*

2.1. Limbaje abstracte mulimea finit a regulilor de deducie (inferen)

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 = { y1 , y 2 ,..., y n } . Atunci, E0n


cu formule din

reprezint mulimea tuturor n-tuplelor

E0 .

Atunci, aplicnd succesiv regulile de deducie din

putem obine mulimile

Ei = Ei 1 U{x | y E ,
n 1

n i 1 astfel incat

yRx} . Ei
se

Dac mulimea premiselor e vid, adic numesc teoreme. Dac

E0 =

atunci elementele lui

este o teorem, atunci ea s-a obinut prin aplicarea

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

Regula de producie asociat

unei producii este o regul de rescriere, adic i sunt 2 iruri din

P Q P Q
cu

unde

F . Aceasta nseamn c n orice formul corect

care conine subirul

se poate nlocui

i se obine tot o

formul corect. Notm cu

mulimea finit de producii.

n aceste condiii, sistemul formal

G =< N , , P, S >

se numete gramatic.

Procesul de inferen n cazul gramaticilor se numete derivare. Spunem despre dou iruri

din

deriveaz imediat n

cadrul unei gramatici date, dac exist dou iruri

din

i o

30 producie

Capitolul 2. Fundamentele limbajelor de programare

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

este obinut din

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

ntr-un numr nenul de pai sau dac cele 2

Prin definiie, un limbaj generat de o gramatic

este mulimea tuturor

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.

este ir oarecare, diferit de simbolul vid.

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.

2.1. Limbaje abstracte

31

2.1.2. Specificarea limbajelor de programare


2.1.2.1. BNF
Pentru descrierea limbajelor de programare se folosesc meta-limbaje. Acestea furnizeaz reguli prin care se pot specifica irurile acceptate de un limbaj de programare. BNF (Backus Naur Form) reprezint cel mai utilizat limbaj de specificare a limbajelor de programare. n fond, BND descrie o gramatic independent de context. n BNF, simbolurile neterminare se scriu ntre paranteze unghiulare i se definesc recursiv, prin meta-formule. De asemenea, semnul ::= face parte din limbajul de specificare. El se poate traduce prin: se definete astfel. Simbolul | nseamn alegere, n sensul c permite utilizarea uneia din cele 2 alternative alturate simbolului. Astfel, n BNF, simbolurile <, >, ::=, | se numesc meta-simboluri. Pentru a exemplifica utilizarea BNF, vom descrie n acest limbaj de specificare sintaxa de compunere a unei propoziii simple ntr-un limbaj informal. Astfel, avem urmtoarea definiie BNF:
<sentence>::=<subject><verb><object>. <subject>::=<article><noun>|<subject pronoun> <verb>::=sees|hits <object>::=<article><noun>|<object pronoun> <article>::=a|the <subject pronoun>::=he|she <object pronoun>::=him|her

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

Capitolul 2. Fundamentele limbajelor de programare

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

2.1.2.3. Diagrame de sintax


Reprezint o descriere alternativ vizual, a specificrii unui limbaj. Au fost introduse la specificarea limbajului Pascal. Diagramele de sintax reprezint grafuri orientate avnd ca noduri simbolurile din limbaj iar sgeile indic succesiunea acceptat a acestora. S considerm o gramatic specificat n limbaj EBNF.

2.1. Limbaje abstracte

33

<sentence>::=<expression>= <expression>::=<number>[<operator><expression>] <number>::=[<sign>]<unsigned> <operator>::=*|+|-|/ <sign>::=+|<unsigned>::=<string>[.<string>]|.<string> <string>::=<digit>{<digit>} <digit>::=0|1|2|3|4|5|6|7|8|9

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.

2.1.3. Automate de acceptare


Un automat de acceptare este folosit pentru a rspunde la ntrebarea: un ir aparine limbajului

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

Capitolul 2. Fundamentele limbajelor de programare

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.

Diagrama de tranziii a unui automat finit cu 2 stri

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

Matricea automatului din figura 6 (q1, )

Pentru acest automat, irul aaba este un ir acceptat deoarece: (q0,aaba)

(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

2.1. Limbaje abstracte

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.

Matricea automatului finit din figura 7

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.

mulimea de simboluri de intrare acceptate de automat.

Vom construi automatul determinist cu mulimea de stri mulime de simboluri de intrare

Q1

pe aceeai

astfel:

36
Procedure AFN2AFD

Capitolul 2. Fundamentele limbajelor de programare

Q1 {q0 }
while (mai exist stri nemarcate n

Q1 Q1

q [q1 , q2 ,..., qk ] o stare Se marcheaz q for a do M 0 / For i = 1, k M M ( qi , a )


End for

nemarcat din

q ' { p | p = ( M , )}
if

- nchiderea tranzitiv a lui

q ' Q1 Q1 Q1 {q '}

end if La mulimea de tranziii a automatului determinist adaug tranziia q end for end while end procedure

q'

prin simbolul de intrare a

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

reprezint starea iniial din automatul nedeterminist.

q0

este nchiderea

tranzitiv a strii iniiale. -

(q, a )

reprezint starea care urmeaz lui q n automatul nedeterminist prin

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.

2.1. Limbaje abstracte Deci, starea iniial

37 este nodul 0. nchiderea tranzitiv a acestui nod conine

q0

nodul 0 mpreun cu toate nodurile n care se poate ajunge din acest nod considernd doar tranziii vide. Deci

q0

este [0,2]. Acesta va reprezenta primul

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

ca fiind mulimea tuturor nodurilor

q0

i considernd tranziii acceptate de

automatul nedeterminist prin simbolul a. Obinem nchiderea tranzitiv a lui noduri din

M = {0,1,2} .

Considerm

, adic toate nodurile la care se poate ajunge din

prin tranziii vide succesive. Dup considerarea acestei operaii,

mulimea nou format

q'

conine aceleai noduri ca i

. Extindem mulimea n automatul

de noduri ale noului automat cu acest nou nod

q ' = [0,1,2] .

determinist adugm tranziia prin simbolul de intrare a din nodul

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} .

nchiderea tranzitiv a lui

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

Capitolul 2. Fundamentele limbajelor de programare

a [2]
a

a b [0,1,2]
a

[2,3]
b

[0,2]
b
a,b

[3]

[0]

Figura 9.

Automatul finit determinist echivalent automatului din figura 7.

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.

Fazele unui compilator [erbnai 1987].

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

Capitolul 2. Fundamentele limbajelor de programare

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.

2.3. ntrebri propuse


1. 2. Descriei clasificarea gramaticilor dup Naom Chomsky. De ce limbajul independent de context reprezint modelul unui limbaj de programare?

2.3. ntrebri propuse 3.

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>

Sunt aceste reguli de specificare corecte? 6. Fie urmtoarele producii:


<unsigned>::=<string>[.<string>] <string>::=<digit>{<digit>} <digit>::=0|1|2|3|4|5|6|7|8|9

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

P = {S , S aB, B aB, B bB, B a, B b} .

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.