Limbaj de programare - Programming language

Codul sursă pentru un program de calculator simplu scris în limbajul de programare C . Liniile gri sunt comentarii care ajută la explicarea programului oamenilor într-un limbaj natural . Când este compilat și rulat , acesta va da rezultatul „ Bună ziua, lume! ”.

Un limbaj de programare este un limbaj formal care cuprinde un set de șiruri care produc diferite tipuri de ieșire a codului mașinii . Limbajele de programare sunt un fel de limbaj pentru computer și sunt utilizate în programarea computerelor pentru a implementa algoritmi .

Majoritatea limbajelor de programare constau în instrucțiuni pentru computere . Există mașini programabile care utilizează un set de instrucțiuni specifice , mai degrabă decât limbaje generale de programare . Încă de la începutul anilor 1800, programele au fost folosite pentru a direcționa comportamentul mașinilor precum războaiele Jacquard , cutiile de muzică și pianele . Programele pentru aceste mașini (cum ar fi sulurile unui pian de jucător) nu au produs un comportament diferit ca răspuns la intrări sau condiții diferite.

Au fost create mii de limbaje de programare diferite și se creează mai multe în fiecare an. Multe limbaje de programare sunt scrise într-o formă imperativă (adică ca o succesiune de operații de efectuat) în timp ce alte limbaje folosesc forma declarativă (adică este specificat rezultatul dorit, nu cum să-l realizăm).

Descrierea unui limbaj de programare este de obicei împărțită în cele două componente ale sintaxei (formă) și semantică (semnificație). Unele limbi sunt definite de un document de specificații (de exemplu, limbajul de programare C este specificat de un standard ISO ) în timp ce alte limbi (cum ar fi Perl ) au o implementare dominantă care este tratată ca referință . Unele limbi au ambele, limbajul de bază definit de un standard și extensiile preluate din implementarea dominantă fiind comune.

Teoria limbajului de programare este un subdomeniu al informaticii care se ocupă cu proiectarea, implementarea, analiza, caracterizarea și clasificarea limbajelor de programare.

Definiții

Un limbaj de programare este o notație pentru scrierea de programe , care sunt specificații ale unui calcul sau algoritm . Unii autori restricționează termenul „limbaj de programare” la acele limbaje care pot exprima toți algoritmii posibili. Trăsăturile considerate deseori importante pentru ceea ce constituie un limbaj de programare includ:

Funcția și ținta
Un limbaj de programare pentru computer este un limbaj folosit pentru a scrie programe pentru computer , care implică un computer care efectuează un fel de calcul sau algoritm și, eventual, controlează dispozitive externe, cum ar fi imprimante , unități de disc , roboți etc. De exemplu, programele PostScript sunt create frecvent de un alt program pentru a controla o imprimantă sau un afișaj de computer. Mai general, un limbaj de programare poate descrie calculul pe o mașină, posibil abstractă. Este general acceptat faptul că o specificație completă pentru un limbaj de programare include o descriere, eventual idealizată, a unei mașini sau a unui procesor pentru acel limbaj. În cele mai multe contexte practice, un limbaj de programare implică un computer; în consecință, limbajele de programare sunt de obicei definite și studiate în acest fel. Limbajele de programare diferă de limbajele naturale prin faptul că limbajele naturale sunt utilizate numai pentru interacțiunea dintre oameni, în timp ce limbajele de programare permit, de asemenea, oamenilor să comunice instrucțiunile mașinilor.
Abstracții
Limbajele de programare conțin de obicei abstracții pentru definirea și manipularea structurilor de date sau controlul fluxului de execuție . Necesitatea practică ca un limbaj de programare să susțină abstracții adecvate este exprimată prin principiul abstractizării . Acest principiu este formulat uneori ca o recomandare către programator de a utiliza în mod adecvat astfel de abstracții.
Puterea expresivă
Teoria calcul clasifică limbile de calculele care sunt capabile să exprime. Toate limbajele complete Turing pot implementa același set de algoritmi . ANSI / ISO SQL-92 și Charity sunt exemple de limbaje care nu sunt complete Turing, dar sunt adesea numite limbaje de programare.

Limbajele de markup precum XML , HTML sau troff , care definesc datele structurate , nu sunt de obicei considerate limbaje de programare. Cu toate acestea, limbajele de programare pot împărtăși sintaxa cu limbajele de markup dacă este definită o semantică de calcul. XSLT , de exemplu, este un limbaj complet Turing utilizând în întregime sintaxa XML. Mai mult, LaTeX , care este utilizat în cea mai mare parte pentru structurarea documentelor, conține și un subset complet Turing.

Termenul limbaj pentru computer este uneori folosit în mod interschimbabil cu limbajul de programare. Cu toate acestea, utilizarea ambilor termeni variază între autori, inclusiv sfera exactă a fiecăruia. O utilizare descrie limbajele de programare ca un subset de limbaje de calculator. În mod similar, limbajele utilizate în calcul care au un scop diferit de exprimarea programelor de calculator sunt limbaje de computer denumite generic. De exemplu, limbajele de markup sunt uneori denumite limbaje de calculator pentru a sublinia că nu sunt menite să fie utilizate pentru programare.

O altă utilizare privește limbajele de programare ca construcții teoretice pentru programarea mașinilor abstracte și limbajele de computer ca subsetul acestora care rulează pe computere fizice, care au resurse hardware finite. John C. Reynolds subliniază faptul că limbajele de specificare formală sunt la fel de multe limbaje de programare ca și limbajele destinate executării. El susține, de asemenea, că formatele de intrare textuale și chiar grafice care afectează comportamentul unui computer sunt limbaje de programare, în ciuda faptului că în mod obișnuit nu sunt complete Turing și remarcă faptul că ignoranța conceptelor de limbaj de programare este motivul multor defecte în formatele de intrare.

Istorie

Evoluții timpurii

Calculatoarele foarte timpurii, cum ar fi Colossus , au fost programate fără ajutorul unui program stocat , modificându-le circuitele sau setând bănci de controale fizice.

Puțin mai târziu, programele ar putea fi scrise în limbajul mașinii , unde programatorul scrie fiecare instrucțiune într-o formă numerică pe care hardware-ul o poate executa direct. De exemplu, instrucțiunea de adăugare a valorii în două locații de memorie poate consta din 3 numere: un „cod opțional” care selectează operația „adăugare” și două locații de memorie. Programele, în formă zecimală sau binară, au fost citite de pe cartele perforate , bandă de hârtie, bandă magnetică sau comutate pe comutatoare de pe panoul frontal al computerului. Limbajele mașinii au fost denumite ulterior limbaje de programare de primă generație (1GL).

Următorul pas a fost dezvoltarea așa-numitelor limbaje de programare de a doua generație (2GL) sau a limbajelor de asamblare , care erau încă strâns legate de arhitectura setului de instrucțiuni al computerului specific. Acestea au servit pentru a face programul mult mai ușor de citit de către oameni și au scutit programatorul de calculele de adresă obositoare și predispuse la erori.

Primele limbaje de programare la nivel înalt , sau limbaje de programare a treia generație (3GL), au fost scrise în anii 1950. Un limbaj de programare la nivel înalt timpuriu care a fost conceput pentru un computer a fost Plankalkül , dezvoltat pentru germanul Z3 de Konrad Zuse între 1943 și 1945. Cu toate acestea, nu a fost implementat decât în ​​1998 și 2000.

Short Code al lui John Mauchly , propus în 1949, a fost unul dintre primele limbaje de nivel înalt dezvoltate vreodată pentru un computer electronic . Spre deosebire de codul mașinii , instrucțiunile Short Code reprezentau expresii matematice într-o formă ușor de înțeles. Cu toate acestea, programul a trebuit tradus în codul mașinii de fiecare dată când a rulat, făcând procesul mult mai lent decât rularea codului mașinii echivalent.

La Universitatea din Manchester , Alick Glennie a dezvoltat Autocode la începutul anilor 1950. Ca limbaj de programare , a folosit un compilator pentru a converti automat limbajul în codul mașinii. Primul cod și compilator a fost dezvoltat în 1952 pentru computerul Mark 1 de la Universitatea din Manchester și este considerat a fi primul limbaj de programare compilat la nivel înalt.

Al doilea autocod a fost dezvoltat pentru Mark 1 de RA Brooker în 1954 și a fost numit „Mark 1 Autocode”. Brooker a dezvoltat, de asemenea, un autocod pentru Ferranti Mercury în anii 1950 împreună cu Universitatea din Manchester. Versiunea pentru EDSAC 2 a fost concepută de DF Hartley de la Universitatea din Cambridge Mathematical Laboratory în 1961. Cunoscută sub numele de EDSAC 2 Autocode, a fost o dezvoltare directă din Mercury Autocode adaptată pentru circumstanțele locale și a fost remarcată pentru optimizarea codului obiect și limbajul sursă diagnostice avansate pentru acea vreme. Un fir de dezvoltare contemporan, dar separat, Atlas Autocode a fost dezvoltat pentru mașina Atlas 1 a Universității din Manchester .

În 1954, FORTRAN a fost inventat la IBM de John Backus . A fost primul limbaj de programare de nivel general utilizat la scară largă care a avut o implementare funcțională, spre deosebire de doar un design pe hârtie. Este încă un limbaj popular pentru computere de înaltă performanță și este utilizat pentru programe care compară și clasifică cele mai rapide supercalculatoare din lume .

Un alt limbaj de programare timpuriu a fost conceput de Grace Hopper în SUA, numit FLOW-MATIC . Acesta a fost dezvoltat pentru UNIVAC I la Remington Rand în perioada 1955 până în 1959. Hopper a constatat că consumatorii de prelucrare a datelor de afaceri au fost inconfortabil cu notație matematică, iar la începutul anului 1955, ea si echipa ei au scris o specificație pentru o engleza limbaj de programare și puse în aplicare un prototip. Compilatorul FLOW-MATIC a devenit disponibil publicului la începutul anului 1958 și a fost substanțial complet în 1959. FLOW-MATIC a fost o influență majoră în proiectarea COBOL , deoarece numai el și descendentul său direct AIMACO erau în uz efectiv la acea vreme.

Rafinament

Utilizarea sporită a limbajelor de nivel înalt a introdus o cerință pentru limbajele de programare de nivel scăzut sau limbajele de programare a sistemului . Aceste limbi, în diferite grade, oferă facilități între limbile de asamblare și limbile de nivel înalt. Acestea pot fi utilizate pentru a efectua sarcini care necesită acces direct la facilitățile hardware, dar oferă totuși structuri de control la nivel superior și verificarea erorilor.

Perioada din anii '60 până la sfârșitul anilor '70 a adus dezvoltarea marilor paradigme lingvistice utilizate acum:

Fiecare dintre aceste limbaje a generat descendenți, iar majoritatea limbajelor de programare moderne contează cel puțin unul din strămoșii lor.

Anii 1960 și 1970 au văzut, de asemenea, o dezbatere considerabilă cu privire la meritele programării structurate și dacă limbajele de programare ar trebui să fie concepute pentru a o susține. Edsger Dijkstra , într-o celebră scrisoare din 1968 publicată în Comunicările ACM , susținea că declarațiile Goto ar trebui eliminate din toate limbajele de programare „de nivel superior”.

Consolidare și creștere

O selecție de manuale care predau programarea, în limbi atât populare, cât și obscure. Acestea sunt doar câteva dintre miile de limbaje de programare și dialecte care au fost proiectate în istorie.

Anii 1980 au fost ani de relativă consolidare. C ++ a combinat programarea orientată pe obiecte și sisteme. Guvernul Statelor Unite a standardizat Ada , un limbaj de programare a sistemelor derivat din Pascal și destinat utilizării de către contractorii de apărare. În Japonia și în alte părți, s-au cheltuit sume mari investigând așa-numitele limbaje de „a cincea generație” care încorporează structuri de programare logică. Comunitatea funcțională a limbilor s-a mutat pentru a standardiza ML și Lisp. În loc să inventeze noi paradigme, toate aceste mișcări au elaborat ideile inventate în deceniile anterioare.

O tendință importantă în proiectarea limbajului pentru programarea sistemelor pe scară largă în anii 1980 a fost concentrarea sporită pe utilizarea modulelor sau a unităților de cod organizaționale la scară largă. Modula-2 , Ada și ML au dezvoltat toate sisteme de module notabile în anii 1980, care erau adesea conectate la structuri de programare generice .

Creșterea rapidă a internetului la mijlocul anilor 1990 a creat oportunități pentru noi limbi. Perl , inițial un instrument de script Unix lansat pentru prima dată în 1987, a devenit obișnuit în site-urile web dinamice . Java a devenit folosit pentru programarea pe partea de server, iar mașinile virtuale bytecode au devenit din nou populare în setările comerciale cu promisiunea lor de „ Scrie o dată, rulează oriunde ” ( UCSD Pascal fusese popular de o vreme la începutul anilor 1980). Aceste evoluții nu au fost fundamental noi; mai degrabă, au fost rafinamente ale multor limbaje și paradigme existente (deși sintaxa lor s-a bazat adesea pe familia C a limbajelor de programare).

Evoluția limbajului de programare continuă, atât în ​​industrie, cât și în cercetare. Direcțiile actuale includ verificarea securității și fiabilității , noi tipuri de modularitate ( mixini , delegați , aspecte ) și integrarea bazelor de date, cum ar fi LINQ Microsoft .

Limbajele de programare de a patra generație (4GL) sunt limbaje de programare pentru computer care au ca scop furnizarea unui nivel mai ridicat de abstractizare a detaliilor hardware interne ale computerului decât 3GL-urile. Limbajele de programare de generația a cincea (5GL) sunt limbaje de programare bazate pe rezolvarea problemelor folosind constrângerile date programului, mai degrabă decât folosind un algoritm scris de un programator.

Elemente

Toate limbajele de programare au câteva blocuri primitive pentru descrierea datelor și procesele sau transformările aplicate acestora (cum ar fi adăugarea a două numere sau selectarea unui articol dintr-o colecție). Aceste primitive sunt definite prin reguli sintactice și semantice care descriu structura și respectiv sensul lor.

Sintaxă

Copac Analizează de cod Python cu tokenizarea medalion
Evidențierea sintaxei este adesea utilizată pentru a ajuta programatorii să recunoască elemente ale codului sursă. Limba de mai sus este Python .

Forma de suprafață a unui limbaj de programare este cunoscută sub numele de sintaxă . Majoritatea limbajelor de programare sunt pur textuale; ei folosesc secvențe de text, inclusiv cuvinte, numere și punctuație, la fel ca limbile naturale scrise. Pe de altă parte, există unele limbaje de programare care au o natură mai grafică , folosind relații vizuale între simboluri pentru a specifica un program.

Sintaxa unui limbaj descrie combinațiile posibile de simboluri care formează un program corect din punct de vedere sintactic. Înțelesul dat unei combinații de simboluri este gestionat de semantică (fie formală, fie codificată într-o implementare de referință ). Deoarece majoritatea limbilor sunt textuale, acest articol discută despre sintaxa textuală.

Sintaxa limbajului de programare este de obicei definită folosind o combinație de expresii regulate (pentru structura lexicală ) și forma Backus-Naur (pentru structura gramaticală ). Mai jos este o gramatică simplă, bazată pe Lisp :

expression ::= atom | list
atom       ::= number | symbol
number     ::= [+-]?['0'-'9']+
symbol     ::= ['A'-'Z''a'-'z'].*
list       ::= '(' expression* ')'

Această gramatică specifică următoarele:

  • o expresie este fie un atom, fie o listă ;
  • un atom este fie un număr, fie un simbol ;
  • un număr este o secvență neîntreruptă de una sau mai multe cifre zecimale, precedată opțional de un semn plus sau minus;
  • un simbol este o literă urmată de zero sau mai multe caractere (cu excepția spațiului alb); și
  • o listă este o pereche de paranteze potrivite, cu zero sau mai multe expresii în interiorul ei.

Următoarele sunt exemple de secvențe simbolice bine formate în această gramatică: 12345, ()și (a b c232 (1)).

Nu toate programele corecte din punct de vedere sintactic sunt corecte din punct de vedere semantic. Multe programe sintactic corecte sunt totuși prost formate, conform regulilor limbii; și poate (în funcție de specificațiile de limbă și de soliditatea implementării) duce la o eroare la traducere sau la execuție. În unele cazuri, astfel de programe pot prezenta un comportament nedefinit . Chiar și atunci când un program este bine definit într-o limbă, acesta poate avea totuși o semnificație care nu este intenționată de persoana care l-a scris.

Folosind limbajul natural ca exemplu, este posibil să nu fie posibilă atribuirea unui sens unei propoziții corecte din punct de vedere gramatical sau propoziția poate fi falsă:

  • Ideile verzi incolore dorm furios ”. este bine format din punct de vedere gramatical, dar nu are un sens general acceptat.
  • „Ioan este un burlac căsătorit”. este bine format din punct de vedere gramatical , dar exprimă un sens care nu poate fi adevărat.

Următorul fragment de limbaj C este corect din punct de vedere sintactic, dar efectuează operații care nu sunt definite semantic (operația *p >> 4nu are nicio semnificație pentru o valoare având un tip complex și p->imnu este definită deoarece valoarea lui peste indicatorul nul ):

complex *p = NULL;
complex abs_p = sqrt(*p >> 4 + p->im);

Dacă declarația de tip de pe prima linie ar fi omisă, programul ar declanșa o eroare la variabila nedefinită pîn timpul compilării. Cu toate acestea, programul ar fi încă corect din punct de vedere sintactic, deoarece declarațiile de tip furnizează doar informații semantice.

Gramatica necesară pentru a specifica un limbaj de programare poate fi clasificată după poziția sa în ierarhia Chomsky . Sintaxa majorității limbajelor de programare poate fi specificată folosind o gramatică de tip 2, adică sunt gramatici fără context . Unele limbi, inclusiv Perl și Lisp, conțin construcții care permit executarea în timpul fazei de analiză. Limbajele care au construcții care permit programatorului să modifice comportamentul parserului fac din analiza sintaxei o problemă indecidabilă și, în general, estompează distincția dintre analiză și execuție. Spre deosebire de sistemul macro Lisp și BEGINblocurile Perl , care pot conține calcule generale, macro-urile C sunt doar înlocuiri de șiruri și nu necesită executarea codului.

Semantică

Termenul de semantică se referă la semnificația limbilor, spre deosebire de forma lor ( sintaxă ).

Semantica statica

Semantica statică definește restricții asupra structurii textelor valide care sunt greu sau imposibil de exprimat în formalisme sintactice standard. Pentru limbajele compilate, semantica statică include în esență acele reguli semantice care pot fi verificate la momentul compilării. Exemplele includ verificarea faptului că fiecare identificator este declarat înainte de a fi utilizat (în limbile care necesită astfel de declarații) sau că etichetele de pe brațele unei declarații de caz sunt distincte. Multe restricții importante de acest tip, cum ar fi verificarea faptului că identificatorii sunt utilizați în contextul adecvat (de exemplu, nu se adaugă un număr întreg la un nume de funcție), sau că apelurile de subrutină au numărul și tipul adecvat de argumente, pot fi aplicate definindu-le ca reguli într-o logică numită sistem de tip . Alte forme de analize statice, cum ar fi analiza fluxului de date, pot face parte, de asemenea, din semantica statică. Limbaje de programare mai noi, cum ar fi Java și C #, au o analiză de atribuire definită , o formă de analiză a fluxului de date, ca parte a semanticii lor statice.

Semantica dinamica

Odată specificate datele, aparatul trebuie instruit să efectueze operațiuni asupra datelor. De exemplu, semantica poate defini strategia prin care expresiile sunt evaluate la valori sau modul în care structurile de control execută condiționat instrucțiuni . De semantica dinamice ( de asemenea , cunoscut sub numele de semantica de execuție ) a unei limbi străine definește modul în care și atunci când diferitele constructe ale unei limbi ar trebui să producă un comportament de program. Există multe modalități de a defini semantica de execuție. Limbajul natural este adesea folosit pentru a specifica semantica de execuție a limbajelor utilizate în mod obișnuit în practică. O cantitate semnificativă de cercetare academică a intrat în semantica formală a limbajelor de programare , care permit ca semantica de execuție să fie specificată într-un mod formal. Rezultatele din acest domeniu de cercetare au văzut o aplicare limitată la proiectarea și implementarea limbajului de programare în afara mediului academic.

Tip sistem

Un sistem de tip definește modul în care un limbaj de programare clasifică valorile și expresiile în tipuri , modul în care poate manipula aceste tipuri și modul în care acestea interacționează. Scopul unui sistem de tip este să verifice și să impună de obicei un anumit nivel de corectitudine în programele scrise în limba respectivă prin detectarea anumitor operațiuni incorecte. Orice sistem de tip decisiv implică un compromis: deși respinge multe programe incorecte, poate interzice și unele programe corecte, deși neobișnuite. Pentru a by - pass acestui dezavantaj, o serie de limbi au lacune de tip , de obicei , nu au fost controlate mulaje care pot fi utilizate de programator pentru a permite în mod explicit o operațiune nepermisă în mod normal , între diferite tipuri. În majoritatea limbajelor tipizate, sistemul de tipuri este utilizat doar pentru a scrie programe de verificare , dar o serie de limbaje, de obicei funcționale, deduc tipuri , eliberând programatorul de necesitatea de a scrie adnotări de tip. Proiectarea formală și studiul sistemelor de tip este cunoscut sub numele de teoria tipurilor .

Limbi tastate versus limbi netipate

O limbă este tastată dacă specificația fiecărei operațiuni definește tipurile de date cărora li se aplică operațiunea. De exemplu, datele reprezentate de "this text between the quotes"este un șir și, în multe limbaje de programare, împărțirea unui număr la un șir nu are nicio semnificație și nu vor fi executate. Operațiunea nevalidă poate fi detectată atunci când programul este compilat (verificare de tip „statică”) și va fi respinsă de compilator cu un mesaj de eroare de compilare sau poate fi detectată în timp ce programul rulează (verificare de tip „dinamică”), rezultând într-o excepție în timpul rulării . Multe limbi permit unei funcții numite handler de excepții să gestioneze această excepție și, de exemplu, returnează întotdeauna „-1” ca rezultat.

Un caz special al limbilor tastate sunt limbile cu un singur tip . Acestea sunt adesea limbaje de scriptare sau de marcare, cum ar fi REXX sau SGML , și au un singur tip de date - cel mai frecvent șiruri de caractere care sunt utilizate atât pentru datele simbolice, cât și pentru cele numerice.

În schimb, un limbaj netipat , cum ar fi majoritatea limbajelor de asamblare , permite efectuarea oricărei operații pe orice date, în general secvențe de biți de diferite lungimi. Limbile netipate la nivel înalt includ BCPL , Tcl și unele varietăți de Forth .

În practică, în timp ce puține limbi sunt considerate tipizate din teoria tipurilor (verificarea sau respingerea tuturor operațiunilor), majoritatea limbilor moderne oferă un grad de tastare. Multe limbaje de producție oferă mijloace de ocolire sau subvertizare a sistemului de tip, tranzacționând siguranța tipului pentru un control mai fin asupra execuției programului (vezi casting ).

Tastare statică versus dinamică

În tastarea statică , toate expresiile au tipurile lor determinate înainte de executarea programului, de obicei la compilare. De exemplu, 1 și (2 + 2) sunt expresii întregi; acestea nu pot fi transmise către o funcție care așteaptă un șir sau stocate într-o variabilă care este definită pentru a păstra date.

Limbi tastate poate static fi fie vădit tastat sau de tip dedus . În primul caz, programatorul trebuie să scrie în mod explicit tipuri la anumite poziții textuale (de exemplu, la declarațiile variabile ). În al doilea caz, compilatorul deduce tipurile de expresii și declarații bazate pe context. Majoritatea limbajelor tipizate standard, cum ar fi C ++ , C # și Java , sunt tastate în mod vădit. Inferența completă de tip a fost în mod tradițional asociată cu limbaje mai puțin obișnuite, cum ar fi Haskell și ML . Cu toate acestea, multe limbi în mod clar acceptate acceptă inferența parțială a tipului; de exemplu, C ++ , Java și C # toate deduc tipuri în anumite cazuri limitate. În plus, unele limbaje de programare permit ca anumite tipuri să fie convertite automat în alte tipuri; de exemplu, un int poate fi folosit în cazul în care programul așteaptă un float.

Tastarea dinamică , numită și tastarea latentă , determină tipul de siguranță al operațiilor în timpul rulării; cu alte cuvinte, tipurile sunt asociate cu valori în timp de execuție, mai degrabă decât cu expresii textuale . La fel ca în cazul limbajelor deduse de tip, limbajele tipizate dinamic nu necesită programatorului să scrie adnotări de tip explicit pe expresii. Printre altele, acest lucru poate permite unei singure variabile să se refere la valori de diferite tipuri în diferite puncte ale execuției programului. Cu toate acestea, erorile de tipnu pot fi detectate automat până când nu se execută de fapt o bucată de cod, ceea ce face ca depanarea să fie mai dificilă. Lisp , Smalltalk , Perl , Python , JavaScript și Ruby sunt exemple de limbaje tastate dinamic.

Tastare slabă și puternică

Tastarea slabă permite ca o valoare de un tip să fie tratată ca alta, de exemplu tratarea unui șir ca număr. Acest lucru poate fi ocazional util, dar poate permite, de asemenea, ca anumite tipuri de defecțiuni ale programului să nu fie detectate în timpul compilării și chiar în timpul rulării .

Tastarea puternică previne aceste defecțiuni ale programului. O încercare de a efectua o operație cu un tip greșit de valoare ridică o eroare. Limbile puternic tastate sunt adesea denumite sigure sau sigure .

O definiție alternativă pentru „slab tastat” se referă la limbi, cum ar fi Perl și JavaScript , care permit un număr mare de conversii de tip implicit. În JavaScript, de exemplu, expresia 2 * xconvertește în mod implicit xla un număr, iar această conversie reușește , chiar dacă xeste null, undefined, un Array, sau un șir de litere. Astfel de conversii implicite sunt adesea utile, dar pot masca erorile de programare. Puternicul și staticul sunt acum considerate în general concepte ortogonale, dar utilizarea în literatură diferă. Unii folosesc termenul puternic tastat pentru a însemna puternic, tipic static sau, chiar mai confuz, pentru a însemna pur și simplu tastat static . Astfel, C a fost numit atât puternic tastat, cât și slab, tipic static.

Unora dintre programatorii profesioniști li se poate părea ciudat că C ar putea fi „slab, tastat static”. Cu toate acestea, observați că utilizarea indicatorului generic, indicatorul void * , permite aruncarea de indicatori către alți indicatori fără a fi nevoie să faceți o distribuție explicită. Acest lucru este extrem de similar cu aruncarea într-un fel a unei matrice de octeți la orice tip de tip de date în C, fără a utiliza o distribuție explicită, cum ar fi (int)sau (char).

Bibliotecă standard și sistem de execuție

Majoritatea limbajelor de programare au o bibliotecă de bază asociată (uneori cunoscută sub numele de „bibliotecă standard”, mai ales dacă este inclusă ca parte a standardului de limbă publicat), care este pusă la dispoziție în mod convențional de toate implementările limbajului. Bibliotecile de bază includ de obicei definiții pentru algoritmi, structuri de date și mecanisme de intrare și ieșire utilizate în mod obișnuit.

Linia dintre o limbă și biblioteca sa de bază diferă de la o limbă la alta. În unele cazuri, proiectanții de limbă pot trata biblioteca ca o entitate separată de limbă. Cu toate acestea, biblioteca de bază a unei limbi este adesea tratată ca parte a limbii de către utilizatorii săi, iar unele specificații lingvistice necesită chiar ca această bibliotecă să fie pusă la dispoziție în toate implementările. Într-adevăr, unele limbi sunt concepute astfel încât semnificațiile anumitor constructe sintactice nu pot fi descrise nici măcar fără a face referire la biblioteca de bază. De exemplu, în Java , un literal șir este definit ca o instanță a java.lang.Stringclasei; în mod similar, în Smalltalk , o expresie de funcție anonimă (un „bloc”) construiește o instanță a BlockContextclasei bibliotecii . În schimb, Scheme conține mai multe subseturi coerente care sunt suficiente pentru a construi restul limbajului ca macro-uri de bibliotecă, astfel încât proiectanții de limbă nici măcar nu se deranjează să spună ce porțiuni ale limbajului trebuie implementate ca structuri de limbă și care trebuie implementate ca părți a unei biblioteci.

Design si implementare

Limbajele de programare împărtășesc proprietăți cu limbajele naturale legate de scopul lor ca vehicule de comunicare, având o formă sintactică separată de semantica sa și arătând familii de limbi de limbi conexe ramificate unul de altul. Însă, în calitate de constructe artificiale, ele diferă și în moduri fundamentale de limbile care au evoluat prin utilizare. O diferență semnificativă este că un limbaj de programare poate fi descris și studiat pe deplin în întregime, deoarece are o definiție precisă și finită. În schimb, limbile naturale au semnificații schimbătoare date de utilizatorii lor în diferite comunități. În timp ce limbajele construite sunt, de asemenea, limbaje artificiale proiectate de la bază cu un scop specific, le lipsește definiția semantică precisă și completă pe care o are un limbaj de programare.

Multe limbaje de programare au fost proiectate de la zero, modificate pentru a răspunde noilor nevoi și combinate cu alte limbaje. Mulți au căzut în cele din urmă în desuetudine. Deși au existat încercări de a proiecta un limbaj de programare „universal” care să servească tuturor scopurilor, toate acestea nu au reușit să fie acceptate în general ca ocupând acest rol. Necesitatea diverselor limbaje de programare apare din diversitatea contextelor în care sunt utilizate limbile:

  • Programele variază de la scripturi minuscule scrise de hobbyiști individuali la sisteme uriașe scrise de sute de programatori .
  • Programatorii au o gamă largă de expertize, de la începători care au nevoie de simplitate mai presus de orice, până la experți care se pot simți confortabili cu o complexitate considerabilă.
  • Programele trebuie să echilibreze viteza, dimensiunea și simplitatea pe sisteme care variază de la microcontrolere la supercomputere .
  • Programele pot fi scrise o singură dată și nu se pot schimba timp de generații sau pot suferi modificări continue.
  • Programatorii pot diferi pur și simplu în gusturi: pot fi obișnuiți să discute probleme și să le exprime într-un anumit limbaj.

O tendință comună în dezvoltarea limbajelor de programare a fost aceea de a adăuga mai multă capacitate de a rezolva probleme folosind un nivel mai ridicat de abstractizare . Cele mai vechi limbaje de programare erau legate foarte strâns de hardware-ul de bază al computerului. Pe măsură ce s-au dezvoltat noi limbaje de programare, au fost adăugate caracteristici care permit programatorilor să exprime idei care sunt mai îndepărtate de traducerea simplă în instrucțiuni hardware subiacente. Deoarece programatorii sunt mai puțin legați de complexitatea computerului, programele lor pot face mai multe calcule cu mai puțin efort din partea programatorului. Acest lucru le permite să scrie mai multe funcționalități pe unitate de timp.

Programarea în limbaj natural a fost propusă ca o modalitate de a elimina necesitatea unui limbaj specializat pentru programare. Cu toate acestea, acest obiectiv rămâne îndepărtat și beneficiile sale sunt deschise dezbaterii. Edsger W. Dijkstra a luat poziția că utilizarea unui limbaj formal este esențială pentru a preveni introducerea unor constructe fără sens și a respins programarea limbajului natural ca fiind „prostească”. Alan Perlis a respins în mod similar ideea. Abordări hibride au fost luate în Structured English și SQL .

Proiectanții și utilizatorii unui limbaj trebuie să construiască o serie de artefacte care guvernează și permit practica programării. Cele mai importante dintre aceste artefacte sunt specificarea și implementarea limbajului .

Specificație

Specificația unui limbaj de programare este un artefact pe care utilizatorii de limbă și implementatorii îl pot folosi pentru a conveni dacă o bucată de cod sursă este un program valid în acel limbaj și, dacă da, care va fi comportamentul său.

O specificație a limbajului de programare poate lua mai multe forme, inclusiv următoarele:

  • O definiție explicită a sintaxei, semanticii statice și semanticii de execuție a limbajului. În timp ce sintaxa este specificată în mod obișnuit folosind o gramatică formală, definițiile semantice pot fi scrise în limbaj natural (de exemplu, ca în limbajul C ), sau o semantică formală (de exemplu, ca în specificațiile standard ML și Scheme ).
  • O descriere a comportamentului unui traducător pentru limbă (de exemplu, specificațiile C ++ și Fortran ). Sintaxa și semantica limbajului trebuie deduse din această descriere, care poate fi scrisă într-un limbaj natural sau formal.
  • O implementare de referință sau model , uneori scrisă în limba specificată (de exemplu, Prolog sau ANSI REXX ). Sintaxa și semantica limbajului sunt explicite în comportamentul implementării de referință.

Implementare

O implementare a unui limbaj de programare oferă o modalitate de a scrie programe în acel limbaj și de a le executa pe una sau mai multe configurații de hardware și software. Există, în linii mari, două abordări ale implementării limbajului de programare: compilarea și interpretarea . În general, este posibil să implementați un limbaj folosind oricare dintre tehnici.

Ieșirea unui compilator poate fi executată de hardware sau de un program numit interpret. În unele implementări care utilizează abordarea interpretorului nu există o graniță distinctă între compilare și interpretare. De exemplu, unele implementări ale BASIC compilează și apoi execută sursa o linie la un moment dat.

Programele care sunt executate direct pe hardware rulează de obicei mult mai repede decât cele care sunt interpretate în software.

O tehnică pentru îmbunătățirea performanței programelor interpretate este compilarea just-in-time . Aici mașina virtuală , chiar înainte de execuție, traduce blocurile de bytecode care urmează să fie utilizate la codul mașinii, pentru executarea directă pe hardware.

Limbi de proprietate

Deși majoritatea limbajelor de programare cele mai frecvent utilizate au specificații și implementări complet deschise, multe limbaje de programare există doar ca limbaje de programare proprietare, cu implementarea disponibilă doar de la un singur furnizor, care poate pretinde că un astfel de limbaj de proprietate este proprietatea lor intelectuală. Limbajele de programare proprietare sunt în mod obișnuit limbaje specifice domeniului sau limbaje de scriptare interne pentru un singur produs; unele limbi de proprietate sunt folosite numai intern în cadrul unui furnizor, în timp ce altele sunt disponibile utilizatorilor externi.

Unele limbaje de programare există la granița dintre proprietar și deschis; de exemplu, Oracle Corporation afirmă drepturi de proprietate asupra unor aspecte ale limbajului de programare Java , și Microsoft e C # limbaj de programare, care are implementări deschise de cele mai multe părți ale sistemului, de asemenea , are Common Language Runtime (CLR) ca un mediu închis.

Multe limbi de proprietate sunt utilizate pe scară largă, în ciuda naturii lor de proprietate; Exemplele includ MATLAB , VBScript și Wolfram Language . Unele limbi pot face trecerea de la închis la deschis; de exemplu, Erlang a fost inițial un limbaj de programare intern al Ericsson.

Utilizare

Au fost create mii de limbaje de programare diferite, în principal în domeniul calculelor. Proiectele software individuale utilizează de obicei cinci limbaje de programare sau mai mult.

Limbajele de programare diferă de majoritatea celorlalte forme de exprimare umană prin faptul că necesită un grad mai mare de precizie și completitudine. Atunci când utilizează un limbaj natural pentru a comunica cu alte persoane, autorii și vorbitorii umani pot fi ambigui și pot face mici erori și se așteaptă totuși ca intenția lor să fie înțeleasă. Cu toate acestea, în mod figurat, computerele „fac exact ceea ce li se spune să facă” și nu pot „înțelege” ce cod intenționează să scrie programatorul. Combinația dintre definiția limbajului, un program și intrările programului trebuie să specifice complet comportamentul extern care apare atunci când programul este executat, în domeniul de control al acelui program. Pe de altă parte, ideile despre un algoritm pot fi comunicate oamenilor fără precizia necesară pentru execuție utilizând pseudocod , care intercalează limbajul natural cu codul scris într-un limbaj de programare.

Un limbaj de programare oferă un mecanism structurat pentru definirea bucăților de date, precum și operațiunile sau transformările care pot fi efectuate automat pe acele date. Un programator folosește abstracțiile prezente în limbaj pentru a reprezenta conceptele implicate într-un calcul. Aceste concepte sunt reprezentate ca o colecție a celor mai simple elemente disponibile (numite primitive ). Programarea este procesul prin care programatorii combină aceste primitive pentru a compune noi programe sau pentru a le adapta pe cele existente la noi utilizări sau la un mediu în schimbare.

Programele pentru un computer ar putea fi executate într-un proces batch fără interacțiune umană sau un utilizator ar putea tasta comenzi într-o sesiune interactivă a unui interpret . În acest caz, „comenzile” sunt pur și simplu programe, a căror execuție este înlănțuită. Când un limbaj își poate rula comenzile printr-un interpret (cum ar fi un shell Unix sau altă interfață din linia de comandă ), fără a compila, acesta se numește limbaj de scriptare .

Măsurarea utilizării limbii

Determinarea care este cel mai utilizat limbaj de programare este dificilă, deoarece definiția utilizării variază în funcție de context. Un limbaj poate ocupa numărul mai mare de ore de programare, unul diferit are mai multe linii de cod, iar un al treilea poate consuma cel mai mult timp CPU. Unele limbi sunt foarte populare pentru anumite tipuri de aplicații. De exemplu, COBOL este încă puternic în centrul de date corporativ, adesea pe mainframe-uri mari ; Fortran în aplicații științifice și inginerești; Ada în aplicații aerospațiale, de transport, militare, în timp real și încorporate; și C în aplicații încorporate și sisteme de operare. Alte limbi sunt utilizate în mod regulat pentru a scrie multe tipuri diferite de aplicații.

S-au propus diferite metode de măsurare a popularității limbajului, fiecare supus unei părtiniri diferite asupra a ceea ce se măsoară:

  • numărând numărul de anunțuri de locuri de muncă care menționează limba
  • numărul de cărți vândute care predau sau descriu limba
  • estimări ale numărului de linii de cod existente scrise în limbă - care pot subestima limbile care nu se găsesc adesea în căutările publice
  • număr de referințe lingvistice (adică la numele limbii) găsite folosind un motor de căutare web.

Combinând și calculând media informațiilor de pe diverse site-uri de internet, stackify.com a raportat cele mai populare zece limbaje de programare ca (în ordine descrescătoare după popularitatea generală): Java , C , C ++ , Python , C # , JavaScript , VB .NET , R , PHP și MATLAB .

Dialecte, arome și implementări

Un dialect al unui limbaj de programare sau al unui limbaj de schimb de date este o variație (relativ mică) sau o extensie a limbajului care nu își schimbă natura intrinsecă. Cu limbi precum Scheme și Forth , standardele pot fi considerate insuficiente, inadecvate sau ilegitime de către implementatori, așa că adesea se vor abate de la standard, făcând un nou dialect . În alte cazuri, un dialect este creat pentru a fi utilizat într -o limbă specifică domeniului , adesea un subset. În lumea Lisp , majoritatea limbilor care utilizează sintaxa de bază a expresiei S și semantica asemănătoare cu Lisp sunt considerate dialecte Lisp, deși variază în mod sălbatic, la fel ca, de exemplu, Racket și Clojure . Deoarece este obișnuit ca o limbă să aibă mai multe dialecte, poate deveni destul de dificil pentru un programator fără experiență să găsească documentația potrivită. BASIC limbaj de programare are multe dialecte .

Explozia dialectelor Forth a dus la zicala „Dacă ai văzut un Forth ... ai văzut un Forth”.

Taxonomii

Nu există o schemă de clasificare generală pentru limbajele de programare. Un limbaj de programare dat nu are de obicei un singur limbaj strămoș. Limbile apar în mod obișnuit prin combinarea elementelor mai multor limbi predecesoare cu idei noi aflate în circulație în acel moment. Ideile care își au originea într-o limbă se vor difuza într-o familie de limbi înrudite, apoi vor sări brusc peste lacune familiale pentru a apărea într-o familie complet diferită.

Sarcina este complicată și mai mult de faptul că limbile pot fi clasificate pe mai multe axe. De exemplu, Java este atât un limbaj orientat obiect (deoarece încurajează organizarea orientată obiect), cât și un limbaj concurent (deoarece conține construcții încorporate pentru a rula mai multe fire în paralel). Python este un limbaj de script orientat pe obiecte .

În linii mari, limbajele de programare se împart în paradigme de programare și o clasificare în funcție de domeniul de utilizare intenționat, cu limbaje de programare cu scop general distinse de limbaje de programare specifice domeniului . În mod tradițional, limbajele de programare au fost considerate ca descriind calculul în termeni de propoziții imperative, adică emiterea de comenzi. Acestea sunt în general numite limbaje de programare imperative . O mulțime de cercetări în limbaje de programare au vizat estomparea distincției dintre un program ca un set de instrucțiuni și un program ca o afirmație despre răspunsul dorit, care este principala caracteristică a programării declarative . Paradigme mai rafinate includ programarea procedurală , programarea orientată pe obiecte , programarea funcțională și programarea logică ; unele limbi sunt hibrizi de paradigme sau multi-paradigmatice. Un limbaj de asamblare nu este atât o paradigmă, cât un model direct al unei arhitecturi de mașini subiacente. În funcție de scop, limbajele de programare ar putea fi considerate de uz general, limbaje de programare a sistemului , limbaje de scriptare, limbaje specifice domeniului sau limbaje concurente / distribuite (sau o combinație a acestora). Unele limbi cu scop general au fost concepute în mare parte cu obiective educaționale.

Un limbaj de programare poate fi, de asemenea, clasificat după factori care nu au legătură cu paradigma de programare. De exemplu, majoritatea limbajelor de programare folosesc cuvinte cheie în limba engleză , în timp ce o minoritate nu . Alte limbi pot fi clasificate ca deliberat ezoterice sau nu.

Vezi si

Referințe

Lecturi suplimentare

linkuri externe