Nízkoúrovňový programovací jazyk

Nízkoúrovňový programovací jazyk () je programovací jazyk, ktorý poskytuje len malú alebo žiadnu abstrakciu nad architektúrou inštrukčnej sady počítača – príkazy sú štrukturálne podobné inštrukciám procesora. Vo všeobecnosti ide buď o strojový kód alebo jazyk symbolických inštrukcií (). Kvôli nízkej úrovni (odtiaľ to slovo) abstrakcie medzi daným jazykom a strojovým jazykom sa nízkoúrovňové jazyky niekedy označujú ako „blízke k hardvéru“. Programy napísané v jazykoch nízkej úrovne majú tendenciu byť relatívne neprenosné, pretože sú optimalizované pre určitý typ architektúry systému.

Nízkoúrovňové jazyky sa môžu previesť na strojový kód bez kompilátora alebo interpretera. Programovacie jazyky druhej generácie používajú jednoduchší procesor nazývaný asembler a výsledný kód beží priamo na procesore. Program napísaný v nízkoúrovňovom jazyku môže byť spustený veľmi rýchlo a s nízkymi pamäťovými nárokmi. Ekvivalentný program vo vysokoúrovňovom jazyku môže byť menej efektívny a môže využívať viac pamäte. Nízkoúrovňové jazyky sú jednoduché, ale považujú sa za ťažko použiteľné kvôli mnohým technickým detailom, ktoré si programátor musí zapamätať. Pre porovnanie, vysokoúrovňový programovací jazyk izoluje sémantiku vykonávania programu vyplývajúcu z architektúry počítača od špecifikácie programu, čo zjednodušuje vývoj.

Strojový kód 

Strojový kód je jediný jazyk, ktorý môže počítač spracovať priamo bez predchádzajúcej transformácie. V súčasnosti programátori takmer nikdy nepíšu programy priamo v strojovom kóde, pretože to vyžaduje pozornosť k mnohým detailom, ktoré vysokoúrovňový jazyk spracováva automaticky. Okrem toho si vyžaduje zapamätanie alebo vyhľadávanie číselných kódov pre každú inštrukciu a je mimoriadne ťažké takto napísaný program upravovať.

Skutočný strojový kód je prúd nespracovaných, zvyčajne binárnych údajov. Programátor píšuci v „strojovom kóde“ bežne kóduje inštrukcie a údaje v čitateľnejšej forme, ako je desiatková, osmičková alebo šestnástková, ktoré sú preložené do interného formátu programom nazývaným zavádzač () alebo prepnuté do pamäte počítača z riadiaceho panela.

Hoci len málo programov je napísaných v strojových jazykoch, programátori sa často stanú zručnými v ich čítaní vďaka práci s výpismi z pamäti () alebo ladením na riadiacom paneli.

Príklad: Funkcia v hexadecimálnom vyjadrení 32-bitového strojového kódu procesora x86 na výpočet n-tého Fibonacciho čísla:
 8B542408 83FA0077 06B80000 0000C383
 FA027706 B8010000 00C353BB 01000000
 B9010000 008D0419 83FA0376 078BD989
 C14AEBF1 5BC3

Jazyk symbolických inštrukcií 
Jazyky druhej generácie poskytujú jednu úroveň abstrakcie nad strojovým kódom. V začiatkoch programovania na počítačoch ako TX-0 a PDP-1 bola prvá vec, ktorú „hackeri“ z MIT urobili, napísanie asemblerov – nástrojov, ktoré takto mierne abstrahovaný kód transformovali do nejakej reprezentácie strojového kódu. Jazyk symbolických inštrukcií má minimálnu formálnu špecifikáciu, pretože ide len o mapovanie ľudsky čitateľných symbolov, vrátane symbolických adries, na číselné kódy operácií, adresy, konštanty, reťazce atď. Typicky je jedna strojová inštrukcia reprezentovaná ako jeden riadok kódu v jazyku symbolických inštrukcií. Asemblery vytvárajú objektové súbory, ktoré môžu byť prepojené s inými objektovými súbormi alebo môžu byť načítané samostatne.

Príklad: Rovnaká kalkulačka Fibonacciho čísel ako vyššie, ale v jazyku x86-64 s použitím syntaxe AT&T:_fib:
        movl $1, %eax
        xorl %ebx, %ebx
.fib_loop:
        cmpl $1, %edi
        jbe .fib_done
        movl %eax, %ecx
        addl %ebx, %eax
        movl %ecx, %ebx
        subl $1, %edi
        jmp .fib_loop
.fib_done:
        retV tomto príklade kódu sú hardvérové funkcie procesora x86-64 (jeho registre) pomenované a upravované priamo. Funkcia načíta svoj vstup z %edi v súlade so systémom V ABI a vykoná svoj výpočet manipuláciou s hodnotami v registroch EAX, EBX a ECX, kým sa nedokončí a nevráti sa. Všimnite si, že v tomto jazyku symbolických inštrukcií neexistuje koncept vrátenia hodnoty. Po uložení výsledku do registra EAX príkaz RET jednoducho presunie spracovanie kódu na miesto kódu uložené v zásobníku (zvyčajne inštrukcia bezprostredne za inštrukciou, ktorá túto funkciu volala) a je na autorovi volajúceho kódu, aby vedel, že táto funkcia uloží svoj výsledok do EAX a odtiaľ je tento výsledok možné získať. Jazyk symbolických inštrukcií x86-64 nedefinuje žiadny štandard pre vracanie hodnôt z funkcie (a v skutočnosti nemá žiadnu koncepciu funkcie); je na volajúcom kóde, aby po návrate procedúry extrahoval výslednú hodnotu.

Rovnaká funkcia v jazyku C, vysokoúrovňovom jazyku, pre porovnanie:unsigned int fib(unsigned int n) {
  if (!n)
    return 0;
  else if (n <= 2)
    return 1;
  else {
    unsigned int a, c;
    for (a = c = 1; ; --n) {
      c += a;
      if (n <= 2) return c;
      a = c - a;
    }
  }
}Tento kód je svojou štruktúrou veľmi podobný príkladu v jazyku symbolických inštrukcií, existujú ale významné rozdiely, pokiaľ ide o mieru abstrakcie. Napríklad:

 Vstupný parameter n je abstrakciou, vďaka ktorej nie je potrebné špecifikovať presné miesto v pamäti, na ktorom sa hodnota nachádza. Automaticky o správnom mieste rozhodne až kompilátor jazyka C.
 Program v jazyku symbolických inštrukcií načítavá vstupný parameter zo zásobnika do registra a v každej iterácii cyklu znižuje hodnotu v tomto registri, bez toho aby menil hodnotu v pamäti na zásobníku. Kompilátor jazyka C by mohol, napríklad, načítať parameter do registra a postupovať rovnako, alebo by mohol aktualizovať hodnotu vždy keď je uložená. To, ktorú možnosť kompilátor vyberie je záleží na implementácii autorom kompilátora.

Takéto abstrakcie robia kód C kompilovateľný bez úprav na akejkoľvek architektúre, pre ktorú bol kompilátor C napísaný. Kód assembleru x86 je špecifický pre architektúru x86.

Referencie

Zdroj 

Programovacie jazyky