Gjuha e programimit

[djathtas|parapamje| [Kodi burimor për një program kompjuterik në C. Vijat gri janë komente që shpjegojnë programin për njerëzit. Kur kompilohet dhe ekzekutohet, do të japë rezultatin "Përshëndetje, botë!" (*Hello, world!*).|311x311px]]
Një **gjuhë e programimit** është një sistem shënimesh që përdoret për të krijuar programe kompjuterike. Ajo përshkruhet duke përdorur sintaksën, që i referohet strukturës së saj, dhe semantikën, që përcakton kuptimin e saj. Këto përkufizime zakonisht bazohen në një gjuhë formale. Gjuhët e programimit shpesh përfshijnë elemente të tilla si sisteme tipesh, variabla dhe mekanizma për trajtimin e gabimeve. Për të ekzekutuar programet e shkruara në një gjuhë të caktuar, nevojitet një zbatim specifik i saj, siç është një përkthyes (interpreter) ose një përpilues (compiler). Përkthyesi interpreton dhe ekzekuton kodin burimor direkt, ndërsa përpiluesi gjeneron një skedar të ekzekutueshëm që mund të përdoret më vonë.

Arkitektura kompjuterike ka pasur një ndikim të madh në zhvillimin e gjuhëve të programimit. Gjuhët imperative, të cilat kryejnë operacione në një rend të përcaktuar, janë ndër më të zakonshmet dhe janë krijuar për të funksionuar në mënyrë optimale me arkitekturën popullore von Neumann. Në fillimet e tyre, gjuhët e programimit ishin ngushtësisht të lidhura me harduerin. Megjithatë, me kalimin e kohës, ato janë zhvilluar duke ofruar më shumë abstraksion, duke fshehur detajet e implementimit për të bërë procesin më të thjeshtë dhe më intuitiv.

Mijëra gjuhë programimi janë zhvilluar, shpesh të kategorizuara si imperative, funksionale, logjike ose të orientuara nga objektet, për t'iu përshtatur një gamë të gjerë nevojash dhe aplikimesh. Projektimi i gjuhëve të programimit shpesh përfshin kompromisa; për shembull, përdorimi i mekanizmave për trajtimin e përjashtimeve mund të thjeshtojë menaxhimin e gabimeve, por shpesh ndikon në performancën. Teoria e gjuhëve të programimit, një degë e shkencës kompjuterike, merret me studimin e projektimit, implementimit, analizës, karakteristikave dhe klasifikimit të këtyre gjuhëve.

## Përkufizimet 
Gjuhët e programimit dallojnë nga gjuhët natyrore pasi këto të fundit përdoren për komunikimin midis njerëzve, ndërsa gjuhët e programimit janë krijuar për të mundësuar që njerëzit t’u japin udhëzime makinave.&#x5B; '''' &#x5D;

Termi "gjuhë kompjuterike" shpesh përdoret ndërsjellë me "gjuhën e programimit". Megjithatë, kuptimi i këtyre termave mund të ndryshojë në varësi të autorëve.

Në disa raste, gjuhët e programimit konsiderohen një nëngrup i gjuhëve kompjuterike. Po ashtu, termi "gjuhë kompjuteri" mund të përdoret për të dalluar gjuhët që përdoren në kompjuter, por që nuk janë të klasifikuara si gjuhë programimi, si për shembull, gjuhët e shënjimit. Disa autorë e kufizojnë përdorimin e termit "gjuhë programimi" vetëm për gjuhët që janë të plota sipas modelit Turing. Shumica e gjuhëve praktike të programimit janë të plota sipas Turing-ut dhe, si të tilla, kanë ekuivalencë në atë që mund të llogarisin ose realizojnë.

Një tjetër perspektivë i trajton gjuhët e programimit si konstruksione teorike të krijuara për programimin e makinave abstrakte, ndërsa gjuhët kompjuterike konsiderohen si një nëngrup i tyre, që funksionon në kompjuterët fizikë me burime të kufizuara harduerike. John C. Reynolds argumenton se gjuhët e specifikimeve formale janë po aq gjuhë programimi sa ato të destinuara për ekzekutim. Ai gjithashtu sugjeron se formatet hyrëse, si ato tekstuale apo grafike që ndikojnë në sjelljen e një kompjuteri, janë gjuhë programimi, edhe pse zakonisht nuk janë të plota sipas modelit Turing. Reynolds thekson se mungesa e njohurive mbi konceptet e gjuhës së programimit është shpesh shkak për gabime në formatet hyrëse.

## Historia 
### Zhvillimet e hershme 
Kompjuterët e parë të programueshëm u shfaqën në fund të viteve 1940, duke sjellë edhe krijimin e gjuhëve të para të programimit. Në fillim, ata u programuan duke përdorur gjuhët e programimit të gjeneratës së parë (1GL), të cilat përfshinin udhëzime në gjuhën e makinës — komanda të thjeshta që procesori mund t'i ekzekutonte drejtpërdrejt. Ky lloj kodi ishte i ndërlikuar për t’u mirëmbajtur dhe i pamundur për t’u përdorur në sisteme të ndryshme kompjuterike. Për ta bërë procesin më të thjeshtë, u krijuan gjuhët e asamblesë (gjenerata e dytë – 2GL), të cilat zëvendësuan gjuhën e makinës me komanda më të kuptueshme për njerëzit. Megjithatë, edhe pse programimi u bë më i lehtë, këto gjuhë nuk zgjidhën problemin e transportueshmërisë midis sistemeve të ndryshme.

Në fillimet e epokës kompjuterike, burimet harduerike ishin të kufizuara dhe me kosto të lartë, ndërsa burimet njerëzore ishin më të përballueshme. Si rezultat, u preferuan gjuhët e programimit që ishin më afër harduerit, edhe pse ishin më të vështira për t'u përdorur, për të maksimizuar efikasitetin. Kjo situatë ndryshoi me prezantimin e gjuhëve të nivelit të lartë (gjenerata e tretë – 3GL), të cilat revolucionarizuan programimin. Këto gjuhë abstraguan detajet komplekse të harduerit dhe u fokusuan në lehtësimin e shprehjes së algoritmeve në mënyrë më të kuptueshme për njerëzit. Për shembull, shprehjet aritmetike mund të përshkruheshin në formë simbolike dhe të përktheheshin më pas në kod makine të ekzekutueshëm nga kompjuteri. Në vitin 1957, u krijua Fortran (FORmula TRANslation), e cila shpesh konsiderohet si gjuha e parë e përpiluar e nivelit të lartë. Fortran ka mbetur funksionale dhe e përdorur deri në shekullin e 21-të, duke dëshmuar qëndrueshmërinë dhe rëndësinë e saj historike.

### Vitet 1960 dhe 1970 
[parapamje|Dy persona që përdorin një [Kompjuterët mainframe|mainframe IBM 704 – hardueri i parë që mbështet aritmetikën me pikë lundruese – në vitin 1957. Fortran u projektua për këtë makinë.]]
Rreth viteve 1960, u zhvilluan kompjuterët e parë me qëllime të përgjithshme, të cilët mund të operoheshin vetëm nga profesionistë dhe kishin një kosto shumë të lartë. Udhëzimet dhe të dhënat futeshin nëpërmjet kartave të punimit, duke kufizuar ndërveprimin, pasi nuk ishte e mundur të shtohej hyrje gjatë ekzekutimit të programit. Si rezultat, gjuhët e programimit të krijuara gjatë kësaj periudhe u fokusuan në minimizimin e ndërveprimit me përdoruesit. Me shpikjen e mikroprocesorit në vitet 1970, kompjuterët u bënë shumë më të përballueshëm dhe të aksesueshëm. Këta kompjuterë të rinj mundësonin gjithashtu një ndërveprim më të madh me përdoruesit, çka u shoqërua me zhvillimin e gjuhëve të reja të programimit që mbështesnin këtë ndërveprim të përmirësuar.

Lisp, i zbatuar për herë të parë në vitin 1958, ishte gjuha e parë funksionale e programimit. Ndryshe nga Fortran, Lisp ofronte mbështetje për rekursion dhe shprehje të kushtëzuara, si dhe prezantoi koncepte si menaxhimi dinamik i memories përmes grumbullit dhe grumbullimin automatik të mbeturinave. Për disa dekada, Lisp mbizotëroi në zhvillimin e aplikacioneve të inteligjencës artificiale.Në vitin 1978, një tjetër gjuhë funksionale, ML (MetaLanguage), prezantoi inovacione të tjera si inferenca e llojeve dhe parametrat polimorfikë, duke i shtuar fleksibilitet dhe siguri përdorimit të gjuhëve funksionale.

ALGOL (Gjuha ALGOritmike), e prezantuar në vitet 1958 dhe 1960, u bë një standard në literaturën kompjuterike për përshkrimin e algoritmeve. Edhe pse nuk pati një sukses të madh tregtar, ndikimi i saj ishte i jashtëzakonshëm. Gjuhët më të njohura imperative, si C, Pascal, Ada, C++, Java dhe C#, rrjedhin drejtpërdrejt ose tërthorazi nga ALGOL 60. Risitë e tij, si transportueshmëria më e madhe dhe përdorimi i parë i gramatikës pa kontekst BNF (Backus-Naur Form), u miratuan nga shumë gjuhë programimi të mëvonshme. Simula, e cila rrjedh gjithashtu nga ALGOL, ishte gjuha e parë që mbështeste programimin e orientuar nga objekti, duke prezantuar koncepte si nëntipet, dërgimin dinamik dhe trashëgiminë. Simula arriti një sukses të konsiderueshëm tregtar. Një tjetër pasardhës i rëndësishëm i ALGOL është  C, që ka mbetur jashtëzakonisht popullor edhe në shekullin e 21-të. C ofron qasje në operacionet e nivelit të ulët të makinerive, më shumë sesa shumica e gjuhëve bashkëkohore. Fuqia dhe efikasiteti i tij burojnë, pjesërisht, nga përdorimi i treguesve, por kjo gjithashtu e bën të sfidueshme shkrimin e kodit të saktë dhe të besueshëm.

Prolog, e projektuar në vitin 1972, ishte gjuha e parë e programimit logjik. Ajo përdor shënimin logjik formal për të komunikuar me një kompjuter. Në programimin logjik, programuesi përcakton rezultatin e dëshiruar, ndërsa interpretuesi i gjuhës përcakton mënyrën për ta arritur atë, duke përdorur rregulla dhe inferenca logjike. Kjo qasje unike e ndan Prolog-un nga gjuhët tradicionale të programimit, duke e bërë atë të dobishëm për zgjidhjen e problemeve komplekse, si ato në inteligjencën artificiale dhe sistemet ekspertë.

### 1980–2000 
djathtas|parapamje| Një përzgjedhje e vogël e teksteve të gjuhës programuese
Gjatë viteve 1980, shpikja e kompjuterit personal ndryshoi rrënjësisht rolet dhe përdorimin e gjuhëve të programimit. Kjo dekadë solli gjuhë të reja dhe inovacione të rëndësishme në fushën e programimit. Ndër to ishte C++, një zgjerim i gjuhës C që ruante përputhshmërinë me të, por shtonte konceptet e programimit të orientuar nga objekti, si klasat dhe trashëgimia. Gjuhë të tjera, si Ada, prezantuan mbështetje për konkurencën, një tipar i nevojshëm për programet që duhej të ekzekutonin detyra të shumta paralelisht. Në të njëjtën periudhë, qeveria japoneze investoi ndjeshëm në zhvillimin e të ashtuquajturave gjuhë të gjeneratës së pestë, të cilat kombinonin mbështetjen për konkurencën me konstruktet e programimit logjik. Megjithatë, këto gjuhë nuk arritën suksesin e pritur dhe u tejkaluan nga gjuhë të tjera më fleksibile dhe praktike që mbështesnin konkurencën.

Në vitet 1990, rritja e shpejtë e internetit dhe World Wide Web çoi në krijimin e gjuhëve të reja të programimit për të mbështetur zhvillimin e faqeve të internetit dhe rrjeteve. Java e bazuar në C++, u zhvillua për të ofruar transportueshmëri më të madhe ndërmjet sistemeve dhe për të garantuar siguri më të lartë, veçori që ishin thelbësore për aplikacionet në internet. Si rezultat, Java pati një sukses të gjerë, veçanërisht në fushën e zhvillimit të platformave dhe aplikacioneve të ndërveprueshme. Një tjetër zhvillim i rëndësishëm ishte krijimi i gjuhëve skriptuese të shtypura në mënyrë dinamike, si Python, JavaScript, PHP dhe Ruby. Këto gjuhë u dizajnuan për të ndihmuar në zhvillimin e shpejtë të programeve të vogla që mund të koordinonin aplikacionet ekzistuese. Për shkak të integrimit të tyre të lehtë me HTML, këto gjuhë u bënë të njohura për krijimin e faqeve të internetit të vendosura në serverë, duke u bërë shtyllat kryesore të zhvillimit të uebit modern. 

### 2000 e deri më sot 
Gjatë viteve 2000, zhvillimi i gjuhëve të reja të programimit me popullaritet të gjerë u ngadalësua, ndërsa fokusi u zhvendos drejt optimizimit të teknikave dhe parimeve ekzistuese. Një zhvillim i rëndësishëm ishte programimi i orientuar drejt shërbimit, i cili synonte të shfrytëzonte sistemet e shpërndara ku komponentët komunikojnë përmes një rrjeti. Shërbimet funksionojnë në procese të veçanta dhe ndajnë ngjashmëri me objektet në programimin e orientuar nga objekti, por janë më të përshtatshme për mjedise të shpërndara. Gjuhë si C# dhe F# bashkuan elemente nga programimi imperativ dhe funksional, duke ofruar fleksibilitet më të madh për zhvilluesit. Pas vitit 2010, disa gjuhë të reja si **Rust**, **Go**, **Swift**, **Zig**, dhe **Carbon** u shfaqën për të konkurruar në zhvillimin e softuerit kritik për performancën, një fushë ku më parë dominonte C. Këto gjuhë ofruan siguri dhe efikasitet të lartë, duke trajtuar dobësitë tradicionale të C, si menaxhimi manual i memories. Për sa i përket metodave të shtypjes, shumica e këtyre gjuhëve të reja preferojnë shtypjen statike për të garantuar sigurinë dhe performancën. Megjithatë, disa gjuhë të tjera, si **Ring** dhe **Julia**, u fokusuan në shtypjen dinamike për të ruajtur fleksibilitetin dhe për të thjeshtuar zhvillimin e prototipeve. Këto zgjedhje pasqyrojnë nevojat e ndryshme të komuniteteve të zhvilluesve dhe aplikacioneve që ato synojnë të mbështesin.

Disa nga gjuhët e reja të programimit janë klasifikuar si gjuhë programimi vizuale, të cilat lejojnë përdoruesit të krijojnë programe duke përdorur ndërfaqe grafike dhe lëvizje të objekteve, në vend të shkrimit të kodit të pastër tekstual. Disa shembuj të njohur janë **Scratch**, **LabVIEW**, dhe **PWCT**. Këto gjuhë janë të veçanta sepse mundësojnë zhvilluesit, përfshirë ata pa shumë përvojë programimi, të krijojnë aplikacione dhe projekte të ndryshme pa pasur nevojë për të kuptuar sintaksën e komplikuar të gjuhëve tradicionale të programimit. Përveç këtyre, disa gjuhë të tjera, si **Balerina**, ofrojnë një qasje hibrid, ku përdoruesit mund të përdorin një kombinim të programimit tekstual dhe vizual. Ky qasje mund të ndihmojë në mësimin e programimit, duke ofruar mundësi fleksibël për zhvilluesit të krijojnë projekte më të avancuara pa u ndjerë të kufizuar nga njëri prej stileve. Kjo prirje ka çuar gjithashtu në zhvillimin e projekteve që ndihmojnë në krijimin e **VPL-ve** (Gjuhë Programimi Vizuale), si **Blockly** nga Google, një mjet që përdor blloqe vizuale për të krijuar kode. Përveç kësaj, motorë të njohur lojërash si **Unreal** dhe **Unity** kanë shtuar mbështetje për **skriptimin vizual**, duke mundësuar krijimin e lojërave dhe aplikacioneve interaktive pa pasur nevojë për të shkruar shumë kod. Këto zhvillime kanë bërë që krijimi i softuerëve dhe lojërave të jetë më i lehtë dhe më i aksesueshëm për një audiencë të gjerë.

## Elementet 
Çdo gjuhë programimi përfshin elemente themelore që janë të nevojshme për përshkrimin e të dhënave dhe operacioneve që mund të aplikohet mbi to. Këto elemente përfshijnë veprime të thjeshta si shtimi i dy numrave ose zgjedhja e një elementi nga një koleksion (si një listë ose një tabelë). Këto operacione, së bashku me përfaqësimin e të dhënave, janë themeli i çdo programi. Këto elemente janë të drejtuara dhe të kontrolluara nga rregulla sintaksore dhe semantike. **Sintaksa** i referohet strukturës formale të gjuhës, pra mënyrës se si duhet të organizohen elementet (si përdorimi i parantezave, fjala kyçe, etj.), ndërsa **semantika** përcakton kuptimin e këtyre elementeve, ose si ato interpretohen nga kompjuteri gjatë ekzekutimit të programit. Kjo ndihmon në sigurimin që programi të mund të përkthehet dhe të ekzekutohet siç është planifikuar, duke shmangur gabimet dhe paqartësitë..

### Sintaksë 
*Artikulli kryesor:* Sintaksa e gjuhëve të programimit[parapamje|375x375px| Analizoni pemën e [Python|kodit Python me tokenizimin e futur]]
[parapamje|292x292px| [Sintaksa e gjuhëve të programimit|Theksimi i sintaksës shpesh përdoret për të ndihmuar programuesit në njohjen e elementeve të kodit burimor. Gjuha e mësipërme është Python.]]
Forma sipërfaqësore e një gjuhe programimi quhet **sintaksa** e saj. Sintaksa përcakton strukturën e saktë të gjuhës, duke përfshirë sekuencën dhe përdorimin e elementeve si fjalët, numrat, dhe shenjat e pikësimit. Shumica e gjuhëve të programimit janë **tekstuale**, dhe për këtë arsye përdorin sekuenca të tekstit (fjale, numra, simbole, dhe shenja pikësimi) për të ndërtuar programet, ashtu siç ndodh me gjuhët natyrore të shkruara. Nga ana tjetër, disa gjuhë programimi janë **grafike**, të cilat përdorin simbole vizuale dhe marrëdhënie vizuale midis këtyre simboleve për të krijuar programet. Në vend të një strukture tekstuale, këto gjuhë përdorin blloqe dhe ikona për të përfaqësuar operacione dhe kontrolle, duke e bërë kodimin më të aksesueshëm dhe më të kuptueshëm për përdoruesit, për shembull, në gjuhë si **Scratch** dhe **LabVIEW**.

**Sintaksa** e një gjuhe programimi përshkruan kombinimet e mundshme të simboleve që formojnë një program sintaksor të saktë. Ajo përcakton rregullat që duhen ndjekur për të krijuar strukturat e lejuara të kodit në një gjuhë, si përdorimi i fjalëve kyçe, operatorëve dhe elementeve të tjerë. Kjo është e ngjashme me gramatikën e një gjuhe natyrore, e cila përcakton se si duhet të formohen fjalitë në mënyrë që ato të jenë të kuptueshme.

Nga ana tjetër, **semantika** merret me kuptimin e këtyre kombinimeve simbolesh. Semantika përcakton se çfarë ndodhi kur një program i shkruar sipas një sintakse të caktuar ekzekutohet. Kjo mund të jetë një **semantikë formale**, që është një përcaktim rigoroz i kuptimit të një gjuhe, ose mund të jetë e koduar në mënyrë praktike përmes një zbatimi të caktuar të gjuhës (si përkthyes ose përpilues).

Për shumicën e gjuhëve programimi, që janë **tekstuale**, sintaksa dhe semantika janë të lidhura ngushtë me mënyrën se si kodet janë shkruar dhe interpretuar. Ky artikull, siç e thotë, do të fokusohet kryesisht në **sintaksën tekstuale**, duke përshkruar rregullat dhe strukturat që mund të përdoren për të krijuar një program të vlefshëm.Sintaksa e një gjuhe programimi përcaktohet zakonisht duke përdorur një kombinim të shprehjeve të rregullta për të përshkruar strukturën leksikore dhe format Backus-Naur për të përcaktuar strukturën gramatikore. Më poshtë është një shembull gramatikor i thjeshtuar, i frymëzuar nga Lisp:

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

Kjo gramatikë specifikon sa vijon:

* një *shprehje* është ose një *atom* ose një *listë*;
* një *atom* është ose një *numër* ose një *simbol*;
* një *numër* është një sekuencë e pandërprerë e një ose më shumë shifrave dhjetore, që mund të paraprihet nga një shenjë plus ose minus;
* një *simbol* është një shkronjë e ndjekur nga zero ose më shumë nga çdo karakter alfabetik (me përjashtim të hapësirës së bardhë); dhe
* një *listë* është një çift kllapash të përputhur, me zero ose më shumë *shprehje* brenda saj.

Më poshtë janë shembuj të sekuencave simbolike të formuara mirë në këtë gramatikë: `12345`, `()` dhe `(a b c232 (1))`.

Jo të gjitha programet që kanë sintaksë të saktë janë gjithashtu semantikisht të sakta. Megjithatë, shumë programe me sintaksë të saktë mund të jenë të keqformuluara sipas rregullave të gjuhës, dhe mund (në varësi të specifikimeve të gjuhës dhe saktësisë së implementimit) të çojnë në gabime gjatë përkthimit ose ekzekutimit. Në disa raste, këto programe mund të shkaktojnë sjellje të papërcaktuar. Edhe kur një program është i mirëpërcaktuar brenda një gjuhe, ai mund të ketë ende një kuptim që nuk është ai që ka pasur parasysh autori i tij.

Duke përdorur gjuhën natyrore si shembull, mund të ndodhë që një fjalie të saktë gramatikisht të mos ketë kuptim të qartë, ose fjalia mund të jetë e pavërtetë. Pavarësisht se ka një strukturë të drejtë gramatikore, mund të mos ketë një lidhje logjike ose semantike mes fjalëve, duke e bërë të pamundur kuptimin e saj. Po ashtu, një fjali mund të jetë gramatikisht e saktë, por e pavërtetë në kontekstin faktik, duke krijuar një kontradiktë me realitetin.

* " Idetë e gjelbërta pa ngjyrë flenë furishëm." është i mirëformuar nga ana gramatikore, por nuk ka kuptim përgjithësisht të pranuar.
* “Gjoni është një beqar i martuar”. është i mirëformuar nga ana gramatikore, por shpreh një kuptim që nuk mund të jetë i vërtetë.

Fragmenti i mëposhtëm i gjuhës C është sintaksikisht i saktë, por kryen operacione që nuk kanë kuptim semantik. Për shembull, operacioni `*p >> 4` nuk ka kuptim për një vlerë që ka një lloj kompleks, ndërsa `p->im` nuk është i përcaktuar sepse vlera e `p` është një tregues null:
 
```c
complex *p = NULL;
complex abs_p = sqrt(*p >> 4 + p->im);
```

Për të ilustruar këtë, supozojmë që `p` është një tregues (pointer). Nëse `p` është null, përdorimi i tij për të aksesuar një anëtar të strukturës (si `p->im`) do të shkaktojë një gabim ekzekutimi, sepse nuk ka një objekt të vlefshëm që treguesi të referohet. Po ashtu, operacioni `*p >> 4` tenton të bëjë një lëvizje bit pas bit, që mund të ketë kuptim për disa tipe të dhënash (si numrat e thjeshtë), por jo për tipet komplekse.Nëse deklarata e tipit në rreshtin e parë hiqet, programi do të shkaktonte një gabim gjatë përpilimit për shkak të përdorimit të variablës `p` pa e deklaruar më parë, pasi kompajleri do të nuk mund të dijë se çfarë lloji të dhënash është ai. Megjithatë, programi do të ishte ende sintaksikisht i saktë nëse do të ishin të dhëna deklaratat për të tjerë elementë, pasi sintaksa lidhet me rregullat e formës dhe strukturës së kodit (p.sh., përdorimi i operatorëve dhe renditja e fjalëve kyçe), dhe jo me llojet e variablave.Deklaratat e tipit ofrojnë informacion semantik, duke i treguar përpiluesit se cilat lloje të dhënash duhet të ketë variabli, dhe kjo është thelbësore për kontrollin e gabimeve semantike, si dhe për alokimin e kujtesës dhe realizimin e operacioneve. Pa deklaratën e tipit, përpiluesi nuk mund të verifikojë nëse operacionet janë të përshtatshme për tipin e dhënash dhe mund të rezultojnë gabime semantike.

Gramatika e një gjuhe programimi mund të klasifikohet në përputhje me hierarkinë Chomsky. Shumica e gjuhëve programuese përdorin gramatika të tipit 2 (gramatika pa kontekst). Disa gjuhë, si Perl dhe Lisp, përfshijnë konstruksione që mundësojnë ekzekutimin gjatë analizimit, duke bërë që analiza sintaksore të jetë një çështje e pazgjidhshme dhe duke ndikuar në diferencimin mes analizimit dhe ekzekutimit. Në krahasim me makrot në Lisp dhe Perl, të cilat lejojnë llogaritje të drejtpërdrejta, makrot në C janë thjesht zëvendësime vargjesh dhe nuk kërkojnë ekzekutimin e kodit.

### Semantika 
Termi "semantikë" i referohet kuptimit të gjuhëve, në kontrast me formën e tyre (sintaksën). Ndërsa sintaksa merret me rregullat e organizimit të simboleve dhe strukturës gramatikore, semantika fokusohet në interpretimin dhe kuptimin e këtyre simboleve dhe strukturave brenda një konteksti të caktuar.

|- id="371"
! id="372" class="sidebar-heading" style="background: #eef; text-align: center;" |Related concepts
|- id="374"
| id="375" class="sidebar-content" |
* Propositional calculus
* Predicate logic
* Boolean algebra
* Truth table
* Truth function
* Boolean function
* Functional completeness
* Scope (logic)

|- id="402"
! id="403" class="sidebar-heading" style="background: #eef; text-align: center;" |Applications
|- id="405"
| id="406" class="sidebar-content" |
* Digital logic
* Programming languages
* Mathematical logic
* Philosophy of logic

|- id="421"
| id="422" class="sidebar-below hlist" style="background: #eef; text-align: center;" | Category
|- id="425"
| id="426" class="sidebar-navbar" |
|}

#### Semantika statike 
Semantika statike përcakton kufizime në strukturën e teksteve të vlefshme që janë të vështira ose të pamundura për t'u shprehur në formalizmat standarde sintaksore. Për gjuhët e përpiluara, semantika statike përfshin rregullat semantike që mund të kontrollohen në kohën e përpilimit. Shembuj përfshijnë kontrollin nëse çdo identifikues është deklaruar përpara se të përdoret (në gjuhët që kërkojnë deklarata të tilla) ose që etiketat në krahët e një deklarate rasti janë të dallueshme. Kufizime të tjera të rëndësishme të semantikës statike përfshijnë verifikimin e përdorimit të identifikuesve në kontekstin e duhur (si mos shtimi i një numri të plotë në emrin e një funksioni) dhe sigurohen që thirrjet nënrutinë të kenë numrin dhe llojin e duhur të argumenteve. Këto rregulla mund të zbatohen nëpërmjet sistemeve të tipave. Analiza e rrjedhës së të dhënave është gjithashtu një pjesë e semantikës statike, siç shihet në gjuhët si Java dhe C#, të cilat përfshijnë analiza të caktimit si pjesë të semantikës së tyre statike.

#### Semantika Dinamike 
Pas specifikimit të të dhënave, makina duhet të udhëzohet të kryejë operacione mbi to. Për shembull, semantika mund të përcaktojë strategjinë se si shprehjet vlerësohen në vlera, ose mënyrën se si strukturat e kontrollit ekzekutojnë deklaratat me kusht. Semantika dinamike (e njohur gjithashtu si semantika e ekzekutimit) e një gjuhe përcakton mënyrën dhe momentin që konstruktet e ndryshme të gjuhës duhet të prodhojnë një sjellje programore. Ka shumë mënyra për të përcaktuar semantikën e ekzekutimit. Gjuha natyrore përdoret shpesh për të specifikuar semantikën e ekzekutimit të gjuhëve që përdoren zakonisht në praktikë. Një pjesë e konsiderueshme e kërkimit akademik është e dedikuar semantikës formale të gjuhëve të programimit, e cila mundëson specifikimin e semantikës së ekzekutimit në një mënyrë formale. Rezultatet nga ky kërkim kanë gjetur aplikime të kufizuara në dizajnimin dhe implementimin e gjuhëve të programimit jashtë fushës akademike.

### Sistemi i tipit 
*Artikulli kryesor: Sistemi i tipit*

Një lloj i të dhënave përfaqëson një grup të caktuar vlerash, së bashku me operacionet që mund të kryhen mbi ato vlera. Ky koncept është thelbësor për funksionimin e një gjuhe programimi, pasi sistemi i tipave të saj përcakton se cilat janë llojet e të dhënave të disponueshme dhe se si mund të përdoren ato. Sistemi i tipit gjithashtu definon llojin e një shprehjeje dhe përcakton rregullat për ekuivalencën dhe përputhshmërinë e tipave, të cilat janë të rëndësishme për të siguruar që operacionet të kryhen në mënyrë të saktë dhe të sigurt. Përcaktimi i këtyre llojeve dhe operacioneve është thelbësor për optimizimin e performancës dhe për shmangien e gabimeve gjatë ekzekutimit të programeve, duke siguruar që shprehjet dhe funksionet të operojnë brenda kufizimeve të caktuara të tipit. Gjithashtu, menaxhimi i tipave ndihmon në organizimin e të dhënave dhe mundëson mbikëqyrje më të mirë të tyre në nivel programimi.

Sipas teorisë së tipit, një gjuhë konsiderohet të jetë e shtypur plotësisht nëse specifikimi i çdo operacioni përcakton qartë llojet e të dhënave për të cilat ky operacion është i zbatueshëm. Kjo do të thotë që për çdo operacion, duhet të përcaktohet një lloj i caktuar i të dhënave mbi të cilat mund të aplikohet operacioni, duke siguruar kështu kontroll të plotë mbi përdorimin e tipeve.Në kontrast, një gjuhë e pashtypshme, si shumica e gjuhëve të asamblesë, i lejon operacionet të kryhen mbi çdo lloj të dhëne, shpesh duke përdorur sekuenca bitash me gjatësi të ndryshme, pa pasur ndonjë kufizim të fortë mbi llojin e të dhënave. Në praktikë, megjithatë, ndërsa shumë gjuhë nuk janë plotësisht të shtypura, shumica ofrojnë një shkallë të shtypjes, duke ofruar disa nivele të kontrollit të tipeve për të siguruar që operacionet të ekzekutohen në mënyrë të sigurt dhe të parashikueshme.

Për shkak se lloje të ndryshme të të dhënave (si numrat e plotë dhe numrat me presje të lëvizshme) përfaqësojnë vlera të ndryshme në memorie, mund të ndodhin rezultate të papritura nëse përdoret një lloj kur pritet një tjetër. Për shembull, një operacion mbi një numër të plotë dhe një numër me presje të lëvizshme mund të sjellë rezultatet që nuk janë të parashikuara, nëse nuk janë trajtuar siç duhet llojet e të dhënave. Kontrollimi i tipit mund të kapë këtë gabim, duke e identifikuar atë që në fazën e përpilimit, që është më efikas dhe më i shpejtë. Nëse kontrolli i tipit bëhet në kohën e ekzekutimit, kjo mund të jetë më e kushtueshme dhe të vonojë ekzekutimin e programit. Me një sistem të shtypjes të fortë, gabimet e tipit mund të identifikohen gjithmonë, përveç nëse variablat janë hedhur në mënyrë eksplicite në një lloj tjetër. Në të kundërt, në sisteme të shtypjes të dobët, mund të ndodhë që lloje të ndryshme të të dhënave të konvertohen automatikisht pa pasur nevojë për ndërhyrjen e programuesit. Ky fenomen është i njohur si transmetimi i nënkuptuar i tipave. Megjithatë, sa më shumë raste që lejojnë këtë lloj konvertimi automatik, aq më shumë mundësi ka që gabimet e tipit të kalojnë pa u vënë re, duke bërë që programi të funksionojë në mënyrë të papritur ose të gabuar, çka e bën më të vështirë zbulimin e gabimeve tipike.

#### Llojet e mbështetura zakonisht 
Gjuhët e hershme të programimit shpesh mbështesnin vetëm tipe numerike të thjeshta, si numrat e plotë (të nënshkruar dhe të panënshkruar) dhe numrat me presje lëvizëse (për të mbështetur operacionet mbi numra realë që nuk janë numra të plotë). Këto tipe lejonin që të kryheshin operacione aritmetike të thjeshta mbi vlera numerike, por ishin të kufizuara në aspekte të caktuara të përpunimit të të dhënave. Shumica e gjuhëve të programimit moderne mbështesin lloje të shumta numerikë, siç janë variacione të notave të presjes lëvizëse (shpesh të quajtura `float` dhe `double`), si dhe numra të plotë të ndryshëm, në varësi të madhësisë dhe saktësisë që kërkohet nga programuesi. Një problem i zakonshëm që mund të ndodhë gjatë përdorimit të tipeve numerikë është tejkalimi i numrit të plotë, i cili ndodh kur një numër ruhet në një lloj që është shumë i vogël për ta përfaqësuar atë. Kjo mund të shkaktojë rezultate të pasakta ose gabime në ekzekutimin e programit. Një mënyrë e zakonshme për paraqitjen e numrave negativë me tipe numerikë të shënjuar është përdorimi i komplementit të dyshit, megjithëse në disa raste përdoret edhe komplementi i njëshit. Përveç tipeve numerikë, gjuhët e programimit mbështesin edhe lloje të tjera të të dhënave, si **Boolean**, i cili mund të marrë vetëm vlerat "e vërtetë" ose "e rremë", dhe **karakterin**, i cili tradicionalisht përfaqësohet si një bajt dhe është i mjaftueshëm për të ruajtur të gjithë karakteret e kodimit ASCII. Këto tipe janë thelbësore për menaxhimin e logjikës dhe përpunimin e të dhënave që përfshijnë tekst dhe vendime.

**Vargjet** janë një lloj të dhënash, ku elementët e tyre, në shumë gjuhë programimi, duhet të përbëhen nga një lloj i vetëm dhe të kenë një gjatësi fikse. Në disa gjuhë të tjera, vargjet mund të përcaktohen si referenca ndaj të dhënave të ruajtura në vende të tjera në memorje, duke mundësuar që ato të kenë elemente të llojeve të ndryshme. Varigjet, si një strukturë të dhënash, mund të mbështeten si ose si një lloj tjetër primitiv, në varësi të gjuhës së programimit. Ato mund të kenë një gjatësi fikse, ku çdo pozicion në varg është i caktuar dhe nuk mund të ndryshohet, ose mund të kenë gjatësi të ndryshueshme, që lejon fleksibilitet më të madh, por kjo mund të rrisë kërkesat për hapësirën e ruajtjes dhe kompleksitetin e menaxhimit të të dhënave. Përveç vargjeve, gjuhët e programimit mbështesin dhe lloje të tjera të të dhënash, të tilla si **listat**, të cilat janë sekuenca të elementeve të një lloji të caktuar, dhe **vargje shoqëruese** (të pa renditura), të cilat mund të aksesohen përmes çelësave. Gjithashtu, ka **regjistrime** — një strukturë të dhënash ku të dhënat janë të organizuara me emra për çdo fushë, duke mundësuar një menaxhim më të lehtë dhe më të qartë. **Tuples** janë të ngjashme me regjistrimet, por nuk kanë emra për fushat, dhe përdoren për të ruajtur një grup vlerash të ndryshme.'*** **Treguesit*' janë një lloj tjetër të dhënash që ruajnë adresat e kujtesës, duke iu referuar vendndodhjeve specifike në grumbullin e të dhënave ku janë ruajtur të dhëna të tjera. Treguesit janë të rëndësishëm për manipulimin e drejtpërdrejtë të memorjes dhe për lidhjen e strukturave të ndryshme të të dhënave.

Lloji më i thjeshtë i përcaktuar nga përdoruesi është një tip rendor, vlerat e të cilit mund të përfaqësohen me një grup numrash të plotë pozitivë. Ky tip rendor mund të përdoret për të përfaqësuar elemente që kanë një renditje të caktuar, siç janë prioritetet në një listë ose pozitat në një rend. Që nga mesi i viteve 1980, shumica e gjuhëve të programimit kanë mbështetur gjithashtu lloje abstrakte të të dhënave, të cilat ofrojnë një nivel më të lartë të organizimit. Në këtë qasje, përfaqësimi i të dhënave dhe operacionet që mund të kryhen mbi to janë të fshehura nga përdoruesi, i cili mund të aksesojë vetëm ndërfaqen që është e ofruar. Kjo abstraksion i mundëson përdoruesit të punojë me të dhëna pa u shqetësuar për mënyrën e përfaqësimit të brendshëm ose implementimin e operacioneve. Përfitimet e abstraksionit të të dhënave përfshijnë besueshmërinë e shtuar, pasi detajet e brendshme janë të mbrojtura nga ndërfaqja dhe nuk mund të ndikojnë direkt në përdoruesin. Gjithashtu, kjo redukton kompleksitetin e kodit, pasi përdoruesi mund të fokusohet vetëm në përdorimin e operacioneve të ofruara pa e ditur se si janë implementuar ato. Abstraksioni gjithashtu zvogëlon mundësinë e përplasjes së emrave dhe lejon ndryshimin e strukturës bazë të të dhënave pa qenë e nevojshme që klientët të ndryshojnë kodin e tyre, duke mundësuar më shumë fleksibilitet dhe mirëmbajtje më të lehtë të sistemit.

#### Shtypje statike dhe dinamike 
Në shtypjen statike, të gjitha shprehjet e programit i përcaktojnë llojet e tyre përpara se programi të ekzekutohet, zakonisht gjatë fazës së përpilimit. Kjo do të thotë që të gjitha variablat dhe shprehjet janë të lidhura me një lloj të caktuar të dhënash para se programi të fillojë të ekzekutohet. Gjuhët programimi më të përdorura që mbështesin shtypjen statike kërkojnë që llojet e variablave të specifikohen në mënyrë eksplicite, që do të thotë se programuesi duhet të shpallë llojin e çdo variabli në mënyrë të qartë. Në disa gjuhë, llojet mund të jenë të nënkuptuara, që do të thotë se përpiluesi mund të konkludojë llojin e variablave në bazë të kontekstit ku ato përdoren. Një shembull i këtij koncepti është kur përpiluesi mund të deduktojë llojin e një variabli nga mënyra se si përdoret në program, siç ndodh në gjuhë si Python ose JavaScript. Megjithatë, kjo mund të sjellë një anë negative, pasi gabimet që lidhen me tipin e të dhënave mund të kalojnë pa u zbuluar, pasi nuk është e nevojshme të përcaktohet një lloj i qartë për çdo variabël. Konkluzioni i plotë i tipit, ku lloji i çdo shprehjeje dhe variabli është i përcaktuar qartë dhe pa mundësi për interpretim, është tradita e gjuhëve funksionale si Haskell dhe ML. Në këto gjuhë, sistemi i tipit është shumë i fortë dhe i qartë, duke siguruar një kontroll të plotë mbi llojet e të dhënave që përdoren gjatë zhvillimit të programit.

Me shtypjen dinamike, tipi i variablit nuk është i përcaktuar përpara ekzekutimit, por varion në bazë të vlerës që mban. Kjo ofron fleksibilitet për programuesin, pasi një variabël mund të mbajë vlera të ndryshme gjatë kohës. Megjithatë, kjo ul besueshmërinë dhe mundësinë për të zbuluar gabimet, pasi kontrolli i tipit bëhet vetëm në kohën e ekzekutimit. Disa gjuhë, si Python, lejojnë variabla të një lloji bashkimi, që mund të kenë çdo lloj vlere, duke i shkurtuar rregullat e shtypjes statike.

### Konkurrenca 
Në informatikë, shumë udhëzime mund të ekzekutohen njëkohësisht. Shumë gjuhë programimi mbështesin konkurencën në nivelin e instruksioneve dhe nënprogrameve.  Me avancimin e përpunuesve të shumëfishtë, programuesit duhet të dizajnojnë softuer që përdor shumë procesorë për të arritur performancë më të lartë. Gjuhët si Python dhe Ruby, që janë të interpretuara, nuk mbështesin përdorimin e shumë procesorëve njëkohësisht.  Ndërsa gjuhë të tjera mbështesin menaxhimin e të dhënave të ndara midis temave të ndryshme duke përdorur semaforë, monitorë për kontrollin e aksesit në të dhënat e përbashkëta, ose kalimin e mesazheve midis temave për të koordinuar ekzekutimin.

### Trajtimi me përjashtim 
Shumë gjuhë programimi përfshijnë mbajtës të përjashtimeve, një pjesë të kodit që aktivizohet nga gabimet gjatë ekzekutimit dhe mund t'i trajtojë ato në dy mënyra kryesore:

* Përfundimi: mbyllja dhe dorëzimi i kontrollit te sistemi operativ. Ky opsion konsiderohet më i thjeshtë.
* Rifillimi: rifillimi i programit afër vendit ku ndodhi përjashtimi. Kjo mund të shkaktojë një përsëritje të përjashtimit, përveç nëse mbajtësi i përjashtimit është në gjendje të modifikojë vlerat për të parandaluar përsëritjen e përjashtimit.

Disa gjuhë programimi mbështesin dedikimin e një blloku kodi për t'u ekzekutuar, pavarësisht nëse ndodh një përjashtim përpara se të arrihet kodi. Ky proces quhet **finalizim**. Blloku i finalizimit është i dizajnuar për të kryer detyra të nevojshme si pastrimi i burimeve (p.sh., mbyllja e skedarëve ose çlirimi i memorjes) përpara se programi të përfundojë, pavarësisht nëse një përjashtim ka ndodhur gjatë ekzekutimit të programit.

Ekziston një shkëmbim ndërmjet aftësisë së rritur për të trajtuar përjashtimet dhe ndikimit në performancë. Për shembull, në gjuhën C, edhe pse gabimet e indeksit të grupeve janë të zakonshme, ato nuk kontrollohen për arsye të performancës. Ndërsa programuesit mund të shkruajnë kod për të kapur përjashtime, kjo mund të ndikojë negativisht në performancën e programit. Në disa gjuhë, si C, bibliotekat standarde përdorin vlerat e kthimit për të treguar një përjashtim, në vend që të përdorin mekanizma të përjashtimeve të ndërtuara. Disa gjuhë dhe përpilues të tyre ofrojnë mundësinë për të aktivizuar ose çaktivizuar trajtimin e gabimeve, përkohësisht ose përgjithmonë, për të optimizuar performancën kur nuk është e nevojshme trajtimi i përjashtimeve.

## Projektimi dhe zbatimi 
Një nga ndikimet më të rëndësishme në hartimin e gjuhës së programimit ka qenë arkitektura e kompjuterit. Gjuhët imperative, që janë lloji më i përdorur, janë projektuar për të performuar mirë në arkitekturën von Neumann, arkitekturën më të zakonshme kompjuterike. Në këtë arkitekturë, memoria ruan të dhënat dhe instruksionet, ndërsa procesori (CPU) ekzekuton instruksionet mbi të dhënat. Memoria dhe CPU janë të ndara, dhe të dhënat duhet të dërgohen nëpërmjet tubacioneve në CPU. Elementet kyç në këto gjuhë janë variablat, caktimi dhe përsëritja, të cilat janë më efikase sesa rekursioni në këto makina.

Shumë gjuhë programimi janë krijuar që në fillim, janë ndryshuar dhe përmirësuar për t'iu përshtatur nevojave të reja, dhe janë shpesh të kombinuara me aspekte të gjuhëve të tjera. Megjithatë, shumica e tyre kanë rënë në mospërdorim me kalimin e kohës për shkak të zhvillimeve teknologjike dhe ndryshimeve në kërkesat e industrisë. Lindja e gjuhëve të programimit në vitet 1950 ishte e motivuar nga dëshira për të krijuar një gjuhë të përgjithshme, universale, që mund të përdorej për çdo kompjuter dhe qëllim, duke eliminuar nevojën për të shkruar kod të veçantë për makina të ndryshme. Megjithatë, gjatë viteve 1960, ideja e krijimit të një gjuhe universale u refuzua për shkak të kompleksitetit dhe diversitetit të kërkesave që kishin aplikacionet e ndryshme. Programuesit filluan të kuptonin se një gjuhë programimi e përbashkët dhe e përshtatshme për çdo qëllim nuk mund të mbulonte në mënyrë të efektshme të gjitha nevojat e industrisë dhe shkencës. Kjo çoi në krijimin e shumë gjuhëve të specializuara, të cilat ofrojnë mundësi më të mëdha për optimizimin e performancës dhe përmbushjen e kërkesave specifike të aplikacioneve.

### Shkëmbimet 
Cilësitë e dëshirueshme të gjuhëve të programimit përfshijnë **lexueshmërinë**, **shkrueshmërinë** dhe **besueshmërinë**. Këto veçori janë thelbësore për të përmirësuar efikasitetin e zhvillimit të softuerit. Lexueshmëria siguron që kodet të jenë të lehta për t'u kuptuar dhe interpretuar, duke i mundësuar programuesve të kuptojnë shpejt funksionimin e një programi. Shkrueshmëria e bën të lehtë krijimin dhe modifikimin e kodit, duke përmirësuar produktivitetin e zhvilluesve. Besueshmëria siguron që programet të funksionojnë siç pritet, duke zvogëluar mundësinë e gabimeve dhe përmirësuar stabilitetin e softuerit. Këto cilësi kontribuojnë në zvogëlimin e kostos së trajnimit të programuesve, kohës së nevojshme për të shkruar dhe mirëmbajtur kodin, si dhe përpilimit të tij. Po ashtu, ato mund të rrisin performancën e programit gjatë ekzekutimit, duke e bërë më efikas dhe më të qëndrueshëm.

* Megjithëse gjuhët e hershme të programimit shpesh i jepnin përparësi efikasitetit mbi lexueshmërinë, kjo e fundit është rritur në rëndësi që nga vitet 1970. Pasja e operacioneve të shumta për të arritur të njëjtin rezultat mund të jetë e dëmshme për lexueshmërinë, siç është operatorët e mbingarkesës, kështu që i njëjti operator mund të ketë kuptime të shumëfishta. Një veçori tjetër e rëndësishme për lexueshmërinë është ortogonaliteti, duke kufizuar numrin e konstrukteve që një programues duhet të mësojë. Një strukturë sintaksore që kuptohet lehtësisht dhe fjalë të veçanta që janë menjëherë të dukshme gjithashtu mbështet lexueshmërinë.
* Shkrimshmëria është lehtësia e përdorimit për të shkruar kodin për të zgjidhur problemin e dëshiruar. Së bashku me të njëjtat veçori thelbësore për lexueshmërinë,  abstraksioni – ndërfaqet që mundësojnë fshehjen e detajeve nga klienti – dhe ekspresiviteti – duke mundësuar programe më koncize – ndihmojnë gjithashtu programuesin të shkruajë kodin. Gjuhët më të hershme të programimit ishin të lidhura shumë ngushtë me harduerin themelor të kompjuterit, por me kalimin e kohës mbështetja për abstraksion është rritur, duke i lejuar programuesit të shprehin ide që janë më të largëta nga përkthimi i thjeshtë në udhëzimet themelore të harduerit. Për shkak se programuesit janë më pak të lidhur me kompleksitetin e kompjuterit, programet e tyre mund të bëjnë më shumë llogaritje me më pak përpjekje nga programuesi.  Shumica e gjuhëve të programimit vijnë me një bibliotekë standarde të funksioneve të përdorura zakonisht.
* Besueshmëria do të thotë që një program funksionon siç specifikohet në një gamë të gjerë rrethanash. Kontrollimi i tipit, trajtimi i përjashtimeve dhe aliasing i kufizuar (emra të shumë variablave që aksesojnë të njëjtin rajon të memories) të gjitha mund të përmirësojnë besueshmërinë e një programi.

Dizajni i gjuhës së programimit shpesh përfshin **kompromis** mes veçorive dhe performancës. Për shembull, veçoritë që përmirësojnë **besueshmërinë** e kodit, si kontrollet e rrepta të tipit ose trajtimi i përjashtimeve, shpesh kanë një kosto në **performancën** e ekzekutimit, duke e bërë kodin më të ngadalshëm. Po ashtu, një **shkrueshmëri** më e madhe, e mundësuar nga përdorimi i një numri të madh operatorësh dhe abstraksionesh, mund të bëjë më të lehtë shkrimin e kodit, por gjithashtu mund të ndikojë negativisht në **lexueshmërinë** e tij, duke e bërë më të vështirë kuptimin dhe mirëmbajtjen nga programues të tjerë ose nga vetë programuesi pas disa kohësh. Ky lloj kompromisi është i pranishëm gjithmonë në zhvillimin e gjuhëve të programimit dhe është një faktor i rëndësishëm që duhet të merren parasysh gjatë hartimit të një gjuhe.

Programimi në **gjuhë natyrore** është propozuar si një mundësi për të eleminuar nevojën për një gjuhë të specializuar programimi, duke përdorur gjuhën e përditshme të njerëzve për të shkruar programe kompjuterike. Megjithatë, ky qëllim mbetet ende i largët, dhe përfitimet e tij janë subjekt i debatit të vazhdueshëm. **Edsger W. Dijkstra**, një nga figurat më të njohura në teorinë e programimit, mbrojti qëndrimin se përdorimi i një **gjuhë formale** është thelbësor për të parandaluar përdorimin e **konstrukteve të pakuptimta** dhe për të siguruar saktësinë dhe qartësinë e programeve. Në një mendim të ngjashëm, **Alan Perlis** gjithashtu shprehu dyshime ndaj idesë së përdorimit të gjuhëve natyrore për programim, duke konsideruar se ato nuk mund të ofronin të njëjtin nivel kontrolli dhe preciziteti që ofron një gjuhë formale programimi.

### Specifikimi 
**Specifikimi i një gjuhe programimi** është një përshkrim që përcakton rregullat dhe sjelljen e një gjuhe, duke mundësuar përdoruesve dhe zbatuesve të bien dakord nëse një kod burimor është i vlefshëm dhe çfarë do të ndodhë kur ekzekutohet. Ai siguron përputhshmërinë dhe qartësinë në interpretimin e programit.

Specifikimi i gjuhës programuese mund të marrë disa forma te ndryshme, duke përfshirë këto:

* Një përkufizim i qartë i sintaksës, semantikës statike dhe semantikës së ekzekutimit të gjuhës. Ndërsa sintaksa zakonisht specifikohet duke përdorur një gramatikë formale, përkufizimet semantike mund të shkruhen në gjuhë natyrore (p.sh., si në gjuhën C ), ose një semantikë formale (p.sh., si në specifikimet standarde ML  dhe Skema  ).
* Një përshkrim i sjelljes së një përkthyesi për gjuhën (p.sh., specifikimet C++ dhe Fortran ). Sintaksa dhe semantika e gjuhës duhet të nxirren nga ky përshkrim, i cili mund të shkruhet në gjuhë natyrale ose formale.
* Një referenc ose nje model implementimi, ndonjëherë i shkruar në gjuhën që specifikohet (p.sh. Prolog ose ANSI REXX). Sintaksa dhe semantika e gjuhës janë të qarta në sjelljen e zbatimit të referencës.

### Zbatimi 
**Zbatimi i një gjuhe programimi** është procesi i shndërrimit të një programi nga kodi burimor në kodin e makinës që mund të ekzekutohet nga hardueri. Kjo bëhet shpesh nga një **përpilues**, i cili përkthen kodin burimor në një gjuhë të ndërmjetme dhe pastaj në kodin e makinës, i njohur si **ekzekutues**. Pasi programi të përpilohet, ai ekzekutohet më shpejt se metodat e tjera të zbatimit. Disa përpilues ofrojnë **optimizim** për të ulur përdorimin e kujtesës ose llogaritjeve gjatë ekzekutimit, por kjo mund të rrisë kohën e përpilimit.

Një metodë tjetër zbatimi është **interpretimi**, ku një interpretues përkthen çdo linjë të kodit në kodin e makinës pak para se të ekzekutohet. Edhe pse kjo mund të ndihmojë në **korrigjimin e gabimeve**, ekzekutimi është shumë më i ngadalshëm, 10 deri 100 herë më shumë se një program i përpiluar. **Metodat hibride**, si përpilimi vetëm në kohë, ofrojnë disa përfitime të të dy metodave, duke përpiluar softuerin në një gjuhë të ndërmjetme dhe pastaj në kodin e makinës menjëherë para ekzekutimit.

## Gjuhët e pronarit 
Shumica e **gjuhëve të programimit** më të përdorura kanë specifikime dhe zbatime plotësisht të hapura, por ka edhe **gjuhë të programimit pronësore** që janë të disponueshme vetëm nga një shitës i vetëm, i cili mund të pretendoni se janë pronë intelektuale. Këto gjuhë janë shpesh të **specifikuara për domenin** ose përdoren për **skriptim të brendshëm** në produkte të caktuara. Disa prej tyre përdoren vetëm brenda kompanive, ndërsa të tjera mund të jenë të disponueshme edhe për përdoruesit e jashtëm.&#x5B; '** &#x5D;

Disa **gjuhë programimi** ekzistojnë në një pikë të mesme mes **pronësisë** dhe **hapjes**. Për shembull, **Oracle Corporation** ka të drejta pronësore për disa aspekte të gjuhës **Java**, duke përfshirë specifikimet dhe libraritë e saj, ndërsa gjuhën **C#** të **Microsoft**, megjithëse ka implementime të hapura të shumicës së pjesëve të sistemit, gjithashtu ka një komponent të mbyllur, siç është **Common Language Runtime (CLR)**, i cili kontrollon ekzekutimin e kodit dhe menaxhon ndërveprimin me aplikacionet dhe shërbimet e tjera. Ky kombinim i hapjes dhe mbylljes e bën përdorimin dhe zhvillimin e këtyre gjuhëve të ndryshëm dhe të ndikuar nga faktorë të ndryshëm tregtarë dhe teknikë.

Shumë gjuhë të pronarit përdoren gjerësisht, pavarësisht nga natyra e tyre pronësore; Shembujt përfshijnë MATLAB, VBScript dhe Wolfram Language. Disa gjuhë mund të bëjnë kalimin nga e mbyllur në të hapur; për shembull, Erlang ishte fillimisht gjuha e brendshme e programimit të Ericsson.

Gjuhët e programimit me burim të hapur janë veçanërisht të dobishme për aplikacionet e shkencës së hapur, duke rritur kapacitetin për replikimin dhe ndarjen e kodit dhe duke e bere me te lehte per njerzimin.

## Përdorimi 
Janë krijuar mijëra gjuhë të ndryshme programimi, kryesisht në fushën e informatikës (IT). Projektet individuale të softuerit zakonisht përdorin pesë gjuhë programimi ose edhe më shumë.

Gjuhët e programimit kërkojnë një shkallë shumë më të madhe saktësie dhe plotësie se sa shumica e formave të tjera të shprehjes njerëzore. Kur komunikojmë me njerëz në gjuhën natyrore, mund të përdorim paqartësi dhe gabime të vogla, dhe ende mund të kuptohemi. Kompjuterët, nga ana tjetër, ekzekutojnë gjithçka me saktësi të plotë dhe nuk mund të "kuptojnë" qëllimin e një programi nëse kodi nuk është shkruar saktësisht si duhet. Pra, çdo pjesë e një gjuhe programimi duhet të përcaktojë qartë sjelljen e programit në momentin e ekzekutimit. Kjo e bën më të rëndësishëm përdorimin e sintaksës dhe semantikës të saktë për të shmangur gabimet. Për të shpjeguar idetë për algoritme tek njerëzit, mund të përdoret **pseudokodi'*, i cili është një përzierje e gjuhës natyrore dhe elementeve të një gjuhe programimi. Ky kombinim i lejon programuesve të komunikojnë konceptet e algoritmëve pa pasur nevojë për saktësinë e plotë që kërkohet për ekzekutimin real në një kompjuter.

Një gjuhë programimi siguron një mekanizëm të strukturuar për përcaktimin e pjesëve të të dhënave dhe operacionet ose transformimet që mund të kryhen automatikisht në ato të dhëna. Një programues përdor abstraksionet e pranishme në gjuhë për të përfaqësuar konceptet e përfshira në një llogaritje. Këto koncepte përfaqësohen si një koleksion i elementeve më të thjeshtë të disponueshëm (të quajtur primitivë ). *Programimi* është procesi me anë të të cilit programuesit kombinojnë këto primitive për të kompozuar programe të reja, ose përshtatur ato ekzistuese për përdorime të reja ose një mjedis në ndryshim.

Programet për një kompjuter mund të ekzekutohen në një proces grupor pa ndërveprim njerëzor, ose një përdorues mund të shtypë komanda në një sesion ndërveprues të një përkthyesi . Në këtë rast "komandat" janë thjesht programe, ekzekutimi i të cilave është i lidhur me zinxhirë së bashku. Kur një gjuhë mund të ekzekutojë komandat e saj përmes një përkthyesi (siç është një guaskë Unix ose një ndërfaqe tjetër e linjës komanduese ), pa kompilim, ajo quhet gjuhë skriptimi.

### Matja e përdorimit të gjuhës 
Përcaktimi i gjuhës së programimit më të përdorur është kompleks dhe varet nga konteksti, pasi përdorimi mund të matet në disa mënyra të ndryshme: sa orë programimi janë investuar, sa rreshta kodi janë shkruar, ose sa shumë resurse CPU janë përdorur. Disa gjuhë janë të njohura për përdorime specifike. Për shembull:

* **COBOL** është ende shumë i përdorur në sistemet e mëdha të menaxhimit të të dhënave dhe mainframe-të në korporata.
* **Fortran** është i njohur për aplikimet shkencore dhe inxhinierike, veçanërisht në fushat që kërkojnë llogaritje të mëdha numerike.
* **Ada** përdoret në aplikacione kritike si ato të hapësirës ajrore, transportit, aplikacione ushtarake, dhe ato me kërkesa të forta për kohë reale.
* **C** është një gjuhë e njohur për zhvillimin e sistemeve operative dhe aplikacioneve të integruara.

Përveç këtyre, ka shumë gjuhë të tjera që përdoren për zhvillimin e aplikacioneve të ndryshme në shumë fusha.

Janë propozuar metoda të ndryshme për matjen e popullaritetit të gjuhëve, secila subjekt i një metode dhe paragjyikimi të ndryshëm mbi atë që matet:

* duke numëruar numrin e shpalljeve për punë që përmendin gjuhën 
* numri i librave të shitur që mësojnë ose përshkruajnë gjuhën 
* vlerësimet e numrit të rreshtave ekzistues të kodit të shkruar në gjuhëtë cilat mund të nënvlerësojnë gjuhët që nuk gjenden shpesh në kërkimet publike
* numërimi i referencave gjuhësore (dmth., për emrin e gjuhës) të gjetura duke përdorur një motor kërkimi në internet.

Duke kombinuar informacionin nga faqe të ndryshme interneti, stackify.com raportoi dhjetë gjuhët më të njohura të programimit (radhitja ku eshte bere sipas popullaritetit të përgjithshëm): Java, C, C++, Python, C#, JavaScript, VB. NET, R, PHP dhe MATLAB.

Që nga qershori 2024, pesë gjuhët kryesore të programimit të matura nga indeksi TIOBE janë Python, C++, C, Java dhe C#. TIOBE ofron një listë me 100 gjuhët kryesore të programimit sipas popullaritetit dhe përditëson këtë listë çdo muaj me gjuhet me atraktive dhe nder gjuhet me te paguara.

## Dialekte, shije dhe zbatime 
Një **dialekt** i një gjuhe programimi është një variacion i vogël ose zgjerim i një gjuhe që nuk ndryshon natyrën e saj të brendshme. Dialektet krijohen shpesh kur standardet e një gjuhe janë të pamjaftueshme, të papërfshira ose të paqartë për zbatuesit. Kështu, zhvilluesit mund të krijojnë variacione që përmbushin nevojat e tyre, por që ndodhin të devijojnë nga standardi, duke formuar një dialekt të ri. Për shembull, në gjuhët **Scheme** dhe **Forth**, disa implementime mund të krijojnë variacione që janë specifike për përdorimin e tyre, duke e bërë standardizimin një sfidë. Po ashtu, në gjuhën **Lisp**, shumë gjuhë që përdorin sintaksën e ngjashme me atë të Lisp konsiderohen dialekte, si **Racket** dhe **Clojure**, megjithëse ato mund të ndryshojnë shumë nga njëra-tjetra. Në raste të tjera, një dialekt mund të krijohet për një **gjuhë specifike të domenit**, duke e kufizuar përdorimin e tij në një fushë të ngushtë, siç mund të ndodhë në zhvillimin e softuerëve për qëllime të caktuara. Kjo mund të bëjë që të bëhet më e vështirë për një programues të papërvojë të gjejë dokumentacionin e saktë për gjuhën që përdor, duke qenë se ka shumë variante të mundshme të kodit.

## Klasifikimet 
Gjuhët e programimit vendosen në katër kategori kryesore: imperative, funksionale, logjike dhe objekte të orientuara.

* Gjuhët imperative janë krijuar për të zbatuar një algoritëm në një rend të caktuar; ato përfshijnë gjuhë programimi vizuale si .NET për gjenerimin e ndërfaqeve grafike të përdoruesit. Gjuhët e shkrimit, të cilat interpretohen pjesërisht ose plotësisht në vend që të përpilohen, ndonjëherë konsiderohen si një kategori e veçantë, por plotësojnë përkufizimin e gjuhëve imperative. 
* Gjuhët funksionale të programimit funksionojnë duke aplikuar në mënyrë të njëpasnjëshme funksione në parametrat e dhënë. Megjithëse vlerësohen nga shumë studiues për thjeshtësinë dhe elegancën e tyre, problemet me efikasitetin i kanë penguar ato të miratohen gjerësisht. 
* Gjuhët logjike janë të dizajnuara në mënyrë që softueri, në vend të programuesit, të vendosë se në çfarë rendi do të ekzekutohen instruksionet. 
* Programimi i orientuar nga objekti – tiparet karakteristike të të cilit janë abstragimi i të dhënave, trashëgimia dhe shpërndarja dinamike – mbështetet nga gjuhët më të njohura imperative dhe disa gjuhë funksionale. 

Megjithëse gjuhët e shënjimit nuk janë gjuhë programimi, disa kanë shtesa që mbështesin programim të kufizuar. Për më tepër, ka gjuhë me qëllime të veçanta që nuk krahasohen lehtësisht me gjuhët e tjera të programimit, keshtu qe duhet te kemi kujdes.

## Shiko gjithashtu 
* Programimi kompjuterik
* Shkenca kompjuterike
* Gjuhë programimi
* Programimi i Shpërndarë
* Lista e gjuhëve programore
* Programimi i orientuar në objekte
* Programimi logjik
* Ruby (gjuhë programuese)
* Gjuha e modelimit
* Inxhinieria e softuerit

## Referime 
## Further reading
* 
* Raphael Finkel: *Advanced Programming Language Design*, Addison Wesley 1995.
* Daniel P. Friedman, Mitchell Wand, Christopher T. Haynes: *Essentials of Programming Languages*, The MIT Press 2001.
* David Gelernter, Suresh Jagannathan: *Programming Linguistics*, The MIT Press 1990.
* Ellis Horowitz (ed.): *Programming Languages, a Grand Tour* (3rd ed.), 1987.
* Ellis Horowitz: *Fundamentals of Programming Languages*, 1989.
* Shriram Krishnamurthi: *Programming Languages: Application and Interpretation*, online publication .
*
* Bruce J. MacLennan: *Principles of Programming Languages: Design, Evaluation, and Implementation*, Oxford University Press 1999.
* John C. Mitchell: *Concepts in Programming Languages*, Cambridge University Press 2002.
*
* Benjamin C. Pierce: *Types and Programming Languages*, The MIT Press 2002.
* Terrence W. Pratt and Marvin Victor Zelkowitz: *Programming Languages: Design and Implementation* (4th ed.), Prentice Hall 2000.
* Peter H. Salus. *Handbook of Programming Languages* (4 vols.). Macmillan 1998.
* Ravi Sethi: *Programming Languages: Concepts and Constructs*, 2nd ed., Addison-Wesley 1996.
* Michael L. Scott: *Programming Language Pragmatics*, Morgan Kaufmann Publishers 2005.
* 
* Franklyn Turbak and David Gifford with Mark Sheldon: *Design Concepts in Programming Languages*, The MIT Press 2009.
* Peter Van Roy and Seif Haridi. *Concepts, Techniques, and Models of Computer Programming*, The MIT Press 2004.
* David A. Watt. *Programming Language Concepts and Paradigms*. Prentice Hall 1990.
* David A. Watt and Muffy Thomas. *Programming Language Syntax and Semantics*. Prentice Hall 1991.
* David A. Watt. *Programming Language Processors*. Prentice Hall 1993.
* David A. Watt. *Programming Language Design Concepts''. John Wiley & Sons 2004.
*