01-Miért vannak programnyelvek?

Biztosan sokat hallottál már programnyelvekről, esetleg egy-két jól értesült ismerősöd egyenesen képes volt megmondani, hogy az X programnyelv jó, az Y meg vacak.

Én azt szeretném, ha ettől azért jobban értenél ehhez. A programnyelvek olyanok, mint a szerszámok: segítenek abban, hogy gyorsabban elérd a célod.

Ha valaki csak egyetlen programnyelvet ismer, az olyan, mintha egyetlen szerszáma egy kalapács lenne. Gondold el, mindent szögnek néz!

- Gézuka, légy szíves tedd fel ide ezt a képet!
- Máris felszögelem!

- Gézuka, légy szíves, ültesd el a virágot!
- Máris ások egy gödröt a kalapácsommal!

- Gézuka, légy szíves, tisztísd meg az ablakot!
- Máris megtisztítom, a KALAPÁCSommal! Olyan tiszta lesz, hogy sosem fog rajta a mocsok!

Na szóval érted. Egyetlen szerszám kevés. Ráadásul nincs is tökéletes szerszám, hisz mindegyik más-másra jó. A programnyelvekkel is így van ez, nincs mindenre jó programnyelv.

Mi azt a compiler (fordítóprogram)?

A helyzet az, hogy egy processzor, CPU, mikrokontroller, vagy bárhogy is nevezzük, igaziból semmiféle nyelven nem ért. Egyetlen dolgot csinál: kiszed a memóriából egy adatot, és a sok 0 meg 1 bit alapján fog valamit csinálni. A sok bitből megírt programot úgy is nevezik, hogy gépi kód, hiszen ezt tényleg csak a gép érti meg, az emberek közül nem sokan.

Szóval, ezt írtuk mi (a DM-es Trinketes rész ledvillogtató progija):

void setup() {
    pinMode(1, OUTPUT);
}

void loop() {
    digitalWrite(1, HIGH); 
    delay(100);
    digitalWrite(1, LOW); 
    delay(500);  
}

Ezt érti meg a Trinket (hexadecimálisan írtam, mert így rövidebb):

Miért pont tizenhatos?

A sok 0001101111010101-ben bárki elkeveredik. Ezért szokás bináris (kettes számrendszer) helyett hexadecimális (tizenhatos) számrendszerben írni a dolgokat. Hogy miért nem 10-esben, és miért pont 16-osban? Azért, mert négy bit tökéletesen leírható egyetlen hexadecimális számmal, így hexadecimálisan négyszer kevesebbet kell írni.
:100000001DC02CC02BC02AC029C03CC027C026C0A0
:1000100025C024C023C022C021C020C01FC00102AF
:100020000000040001020408102002020202020281
:1000300000000000380000000000370011241FBE3F
:10004000CFE5D2E0DEBFCDBF20E0A0E6B0E001C04A
:100050001D92A936B207E1F74BD155C1D1CF61E06E
:1000600081E0D7C061E081E00DD164EF71E080E014
:1000700090E076D060E081E005D164EF71E080E04F
:1000800090E06EC01F920F920FB60F9211242F9323
:100090003F938F939F93AF93BF9380916100909113
:1000A0006200A0916300B09164003091600023E091
:1000B000230F2D3720F40196A11DB11D05C026E8A0
:1000C000230F0296A11DB11D209360008093610053
:1000D00090936200A0936300B093640080916500E8
:1000E00090916600A0916700B09168000196A11DF3
:1000F000B11D8093650090936600A0936700B09354
:100100006800BF91AF919F918F913F912F910F9078
:100110000FBE0F901F9018953FB7F894809165001F
:1001200090916600A0916700B091680022B708B670
:1001300001FE05C02F3F19F00196A11DB11D3FBF63
:100140006627782F892F9A2F620F711D811D911DAF
:1001500042E0660F771F881F991F4A95D1F70895CF
:10016000CF92DF92EF92FF92CF93DF936B017C01EE
:10017000D3DFEB01C114D104E104F10479F0C2D062
:10018000CBDF6C1B7D0B683E7340A0F381E0C81A87
:10019000D108E108F108C851DC4FECCFDF91CF91D5
:1001A000FF90EF90DF90CF90089578948AB58260A9
:1001B0008ABD8AB581608ABD83B7826083BF83B7F9
:1001C000816083BF89B7826089BF80B7826080BF4A
:1001D00080B7816080BF8CB580648CBD329A319AC3
:1001E000309A379A0895823081F018F4813051F0B6
:1001F0000895833019F0843009F008958CB58F7D0F
:100200008CBD08958AB58F7702C08AB58F7D8ABD6F
:100210000895CF93DF9390E0FC01EC5DFF4F2491B4
:10022000FC01E65DFF4F8491882349F190E0880F3F
:10023000991FFC01EA5CFF4FA591B491805D9F4F2F
:10024000FC01C591D4919FB7611108C0F8948C91BD
:10025000209582238C93888182230AC0623051F4D6
:10026000F8948C91322F309583238C938881822B44
:10027000888304C0F8948C91822B8C939FBFDF916C
:10028000CF9108950F931F93CF93DF931F92CDB714
:10029000DEB7282F30E0F901E25EFF4F8491F901CB
:1002A000EC5DFF4F1491F901E65DFF4F04910023CF
:1002B000C1F0882319F0698396DF6981E02FF0E0AF
:1002C000EE0FFF1FE05DFF4FA591B4919FB7F8942B
:1002D0008C91611103C01095812301C0812B8C93F7
:1002E0009FBF0F90DF91CF911F910F9108950895B7
:1002F0005CDFFDDFB4DEC0E0D0E0B4DE2097E9F3E0
:0A0300007FDEFBCF0895F894FFCFD5
:00000001FF

Őőőő... hát ez totál Mátrix! Egy szót nem értünk belőle, ugye? Igen nagy szerencse, hogy nem így kell programozni, bár volt idő az 1970-es években, amikor senki sem rettent meg ettől! Na azok az emberek igazán kockák voltak :)

Az általunk írt "könnyű" C nyelvű programból egy külön progi, a compiler (fordítóprogram) készíti el a gépi kódot. Eddig ezzel nem is kellett foglalkoznunk, csak elég volt megnyomni a "csináld" gombot, és az Arduino IDE lefordította, és be is töltötte a programot a Trinketbe.

Az első assember

Be kell valljam, azért az a sok szám nem csak abszolút maszlag. Ezekben logika van, az első pár számjegy megmondja, hogy mit kell csinálni (de ezek az utasítások nagyon alap dolgokat tudnak csak), utána pár számjegy megmondja, hogy mivel kell csinálni (például adj össze két számot), és így tovább.

Ez itt a ledvillogtató programunk belseje, assembly nyelven, mégpedig Atmel assembly nyelven.

Mi az hogy assembly?

Szó szerint ez azt jelenti, hogy részegység, és az autóiparban ma is így használják. Programozásban az assembly egy olyan könnyen megjegyezhető utasításokból álló programnyelvet jelent, ahol minden gépi kódú utasításhoz (ronda számsor) tartozik egy-egy könnyen megjegyezhető név (pld. ldi, rjmp), amiknek igaziból értelme is van, meglepő módon! (A C# nyelvben egészen más értelemben használják az assembly szót - ott nagyjából lib-et jelent.)
setup:
    ldi r22, 0x01   ; 1
    ldi r24, 0x01   ; 1
    rjmp pinMode    ; 0x212 <pinMode>

loop:
    ldi r22, 0x01   ; 1
    ldi r24, 0x01   ; 1
    rcall digitalWrite ; 0x284 <digitalWrite>
    ldi r22, 0xF4   ; 244
    ldi r23, 0x01   ; 1
    ldi r24, 0x00   ; 0
    ldi r25, 0x00   ; 0
    rcall delay   ; 0x160 <delay>
    ldi r22, 0x00   ; 0
    ldi r24, 0x01   ; 1
    rcall digitalWrite  ; 0x284 <digitalWrite>
    ldi r22, 0xF4   ; 244
    ldi r23, 0x01   ; 1
    ldi r24, 0x00   ; 0
    ldi r25, 0x00   ; 0
    rjmp delay      ; 0x160 <delay>

Ebből pedig a legalapabb fordítóprogram, az assembler csinál gépi kódot. Az alábbi ábrán egy kis darabot ki is emeltem:

Gépi kód        Assembly
61 e0           ldi r22, 0x01   ; 1
81 e0           ldi r24, 0x01   ; 1

Nem csalás, nem ámítás, a 61 e0 81 e0 tényleg itt van a teljes program gépi kódjában:

:100000001DC02CC02BC02AC029C03CC027C026C0A0
:1000100025C024C023C022C021C020C01FC00102AF
:100020000000040001020408102002020202020281
:1000300000000000380000000000370011241FBE3F
:10004000CFE5D2E0DEBFCDBF20E0A0E6B0E001C04A
:100050001D92A936B207E1F74BD155C1D1CF61E06E
:1000600081E0D7C061E081E00DD164EF71E080E014
:1000700090E076D060E081E005D164EF71E080E04F
:1000800090E06EC01F920F920FB60F9211242F9323
stb...

Tehát rakjuk össze

1) Annyira kocka vagy, hogy bináris/hexadecimális számok formájában vágod a gépi kódot.

Harry Porter, a relés számítógépes fickó elég kocka, a 14. másodperctől tényleg kapcsolókkal binárisan nyomja be a kódot a gépbe. Persze ezen nem kell sokat csodálkozni, az 1970-es években nem volt még billentyűzete a számítógépnek, így minden dolgot egy kapcsolósorral (a "mérnöki pult") írtak be a gépbe.

Harry Porter tényleg kapcsolókkal binárisan írja be a programot

2) Csak annyira, hogy mindent assembly-ben csinálsz, amit az assembler lefordít gépi kódra.

Ezen sem kell sokat csodálkozni, az 1990-es évekig nagyon sok mindent csináltak assemblyben, mert bár baromira macerás, de a leggyorsabban futó programokat így lehet elkészíteni.

A Terminátor assembly-t használ

3) Minden más esetben sokkal könnyebb egy igazi programozási nyelvet használni!

Remélem, ez eléggé meggyőzött: a programnyelvek a barátaink!

Mit tanultunk ebből?

A programnyelvek azért vannak, hogy könnyítsék és gyorsítsák a munkánkat, nem azért, hogy megrémisszenek.