Obsah
1. BaCon: transpřekladač BASICu do C
4. Struktura programů vytvořených v BaConu
5. Čísla řádků v původním zdrojovém kódu BASICu
9. Podprogramy založené na příkazech GOSUB a RETURN
10. Struktura programové smyčky typu WHILE-WEND
11. Struktura programové smyčky FOR se záporným krokem
12. Vnořené programové smyčky a manipulace s polem – bubble sort
13. Využití maker preprocesoru jazyka C: zápis příkazů malými písmeny
14. Operace s asociativními poli
18. Repositář s demonstračními příklady
19. Dřívější články o interpretrech a překladačích programovacího jazyka BASIC
1. BaCon: transpřekladač BASICu do C
Na stránkách Roota jsme se již několikrát zabývali programovacím jazykem BASIC, a to jak jeho dnes již zastaralými „retro“ interpretry pocházejícími většinou z první poloviny osmdesátých let minulého století, tak i některými novějšími reinkarnacemi tohoto jazyka (odkazy na tyto články jsou uvedeny v devatenácté kapitole). Současně jsme si již mnohokrát ukázali možnosti nabízené některými transpilery, tj. překladači, které negenerují přímo strojový kód či bajtkód pro nějaký virtuální stroj (JVM, Python VM atd.), ale transformují zdrojový kód z jednoho programovacího jazyka do jazyka jiného. To s sebou přináší mnohé problémy, které mohou být způsobeny rozdílným typovým systémem, zcela odlišnou sémantikou obou jazyků, ztrátou informací o souborech a řádcích v původním zdrojovém kódu, menší čitelnost transpilovaného kódu atd. Ovšem mnohdy výhody převažují – přenositelnost na všechny platformy podporované cílovým jazykem, není nutné vytvářet optimalizující překladač, návaznost na existující ekosystém atd.
Obrázek 1: Nové (tedy alespoň relativně) vydání BBC BASICu, který již oslavil čtyřicet let od svého vzniku.
V podobě BaConu se obě výše uvedené technologie spojily, protože BaCon je transpřekladačem BASICu do jazyka C. Potenciální možnosti cílové platformy (C běží prakticky na jakémkoli typu mikrořadiče i mikroprocesoru) se tak spojují s možnostmi BASICu. Ty jsou však, jak uvidíme v dalších kapitolách, z dnešního pohledu již poněkud omezené a netypické, takže cílová skupina uživatelů je (podle názoru autora článku) relativně malá.
Obrázek 2: Kombinace zdrojového kódu v BBC BASICu s assemblerem. Podobný koncept byl podporován i v Turbo Pascalu i mnoha variantách programovacího jazyka C.
Obrázek 3: Program zapsaný v AppleSoft BASICu spuštěný na počítači Apple II.
2. Překlad BaConu
Všechny další kapitoly ukazují možnosti BaConu na několika demonstračních příkladech. Abychom mohli tyto příklady (trans)přeložit, je pochopitelně nutné mít k dispozici vlastní transpřekladač. Jeho zdrojové kódy lze získat z adresy http://basic-converter.org/#downloads. Po stažení a rozbalení archivu se překlad spustí příkazem:
$ make bacon
S průběhem:
rm -f build/* build-cpp/* Converting 'bacon.bac'... done, 9872 lines were processed in 189 seconds. Creating lexical analyzer... done. Compiling 'bacon.bac'... make[1]: Entering directory '/home/ptisnovs/temp/bacon_trunk/build' gcc -g -O2 -fno-var-tracking-assignments -c bacon.bac.c gcc -o bacon bacon.bac.o -lm make[1]: Leaving directory '/home/ptisnovs/temp/bacon_trunk/build' Done, program 'bacon' ready. strip build/bacon Skipping BaConGUI for GTK. Skipping BaConGUI for FLTK. Run 'make install' or 'sudo make install' to install BaCon on your system.
Výsledkem bude nový spustitelný soubor bacon umístěný v podadresáři build.
$ make bacongui-gtk $ make bacongui-fltk
3. „Hello world“ v BaConu
Možnosti a některá omezení BaConu si ukážeme na několika demonstračních příkladech. Začneme pochopitelně naprostou klasikou, tedy programem typu „Hello world“, který lze v BaConu (a jakémkoli jiném BASICu vhodném toho jména) zapsat příkazem PRINT. Příkazy REM pouze uvozují poznámky:
REM ***************************** REM REM Program "Hello world" REM REM Uprava pro BaCon REM REM ***************************** PRINT "Hello, world!"
Alternativně lze REM nahradit za apostrof:
' ***************************** ' ' Program "Hello world" ' ' Uprava pro BaCon ' ' ***************************** PRINT "Hello, world!"
4. Struktura programů vytvořených v BaConu
Překlad, resp. přesněji řečeno transpřeklad, se provede příkazem:
$ ./bacon hello.bac
přičemž je nutné, aby zdrojové kódy měly příponu .bac (což lze snadno upravit zásahem do zdrojových kódů BaConu). Výsledkem by měl být spustitelný soubor. Pokud však chcete vidět, jak vypadá kód transpilovaný do C, použijte příkaz:
$ ./bacon -p hello.bac
Výsledkem bude několik souborů, které ukazují, že se vlastně vytvoří plnohodnotný C projekt s vlastním Makefile:
-rwxrwxr-x 1 ptisnovs ptisnovs 33888 Nov 30 15:10 hello -rw-rw-r-- 1 ptisnovs ptisnovs 153 Nov 27 08:53 hello.bac -rw-rw-r-- 1 ptisnovs ptisnovs 1337 Nov 30 15:10 hello.bac.c -rw-rw-r-- 1 ptisnovs ptisnovs 39 Nov 30 15:10 hello.bac.float.h -rw-rw-r-- 1 ptisnovs ptisnovs 13654 Nov 30 15:10 hello.bac.functions.h -rw-rw-r-- 1 ptisnovs ptisnovs 30376 Nov 30 15:10 hello.bac.generic.h -rw-rw-r-- 1 ptisnovs ptisnovs 292 Nov 30 15:10 hello.bac.h -rw-rw-r-- 1 ptisnovs ptisnovs 6324 Nov 30 15:10 hello.bac.lex -rw-rw-r-- 1 ptisnovs ptisnovs 76909 Nov 30 15:10 hello.bac.lex.c -rwxrwxr-x 1 ptisnovs ptisnovs 40176 Nov 30 15:10 hello.bac.lex.exe -rw-rw-r-- 1 ptisnovs ptisnovs 0 Nov 30 15:10 hello.bac.log -rw-rw-r-- 1 ptisnovs ptisnovs 26096 Nov 30 15:10 hello.bac.o -rw-rw-r-- 1 ptisnovs ptisnovs 38 Nov 30 15:10 hello.bac.string.h -rw-rw-r-- 1 ptisnovs ptisnovs 229 Nov 30 15:10 Makefile.bacon
Hlavičkový soubor hello.bac.h neobsahuje (prozatím) žádné důležité deklarace:
/* Created with BaCon 4.4.1 - (c) Peter van Eerten - MIT License */ #include "hello.bac.generic.h" #include "hello.bac.functions.h" #line 1 "hello.bac" #line 2 "hello.bac" #line 3 "hello.bac" #line 4 "hello.bac" #line 5 "hello.bac" #line 6 "hello.bac" #line 7 "hello.bac" #line 9 "hello.bac"
Naproti tomu hello.bac.c obsahuje implementaci funkce main s kódem pro inicializaci (my ho vlastně nepoužijeme) a taktéž strojově přeložený příkaz PRINT do podoby s řetězcovým literálem:
__b2c__assign = (char *) "Hello, world!"; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); }
Podívejme se na celý soubor hello.bac.c:
/* Created with BaCon 4.4.1 - (c) Peter van Eerten - MIT License */ #include "hello.bac.h" #include "hello.bac.string.h" #include "hello.bac.float.h" /****************************/ /* Main program starts here */ /****************************/ int main (int argc, char **argv) { setvbuf (stdout, NULL, _IOLBF, 0); if (argc > 0) { __b2c__me_var__b2c__string_var = strdup (argv[0]); } if (argc == 2 && !strcmp (argv[1], "-bacon")) { fprintf (stderr, "Converted by %s.\n", COMPILED_BY_WHICH_BACON__b2c__string_var); exit (EXIT_SUCCESS); } /* Setup the reserved variable 'ARGUMENT' */ __b2c__argument (&ARGUMENT__b2c__string_var, argc, argv); /* By default seed random generator */ srandom ((unsigned int) time (NULL)); /* Determine current moment and keep it for timer function */ __b2c__timer (1); /* Setup error signal handling */ signal (SIGILL, __b2c__catch_signal); signal (SIGABRT, __b2c__catch_signal); signal (SIGFPE, __b2c__catch_signal); signal (SIGSEGV, __b2c__catch_signal); /* Rest of the program */ #line 1 "hello.bac" #line 2 "hello.bac" #line 3 "hello.bac" #line 4 "hello.bac" #line 5 "hello.bac" #line 6 "hello.bac" #line 7 "hello.bac" #line 9 "hello.bac" __b2c__assign = (char *) "Hello, world!"; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fputs ("\n", stdout); return (0); }
5. Čísla řádků v původním zdrojovém kódu BASICu
V céčkovém kódu vygenerovaném BaConem jste si mohli povšimnout několika direktiv ve tvaru:
#line 1 "hello.bac"
Tyto direktivy informují překladač o tom, jakým způsobem má uživatele informovat o případných chybách, ke kterým může během překladu dojít (a dochází, jak ostatně uvidíme dále). Uživatele totiž většinou nezajímá to, že chyba nastala v souboru hello.bac.c, který je vygenerován; zajímá ho, že se chyba týká například třetího řádku ze vstupního souboru hello.bac.
6. Základní operace s poli
Už v originálním BASICu bylo možné pracovat s jednorozměrnými poli, která mohla obsahovat číselné hodnoty (původně jen reálná čísla, později se rozlišovalo mezi reálnými a celými čísly). Pole se definovala a současně i alokovala příkazem DIM a některé BASICy umožňovaly dokonce realokaci pole příkazem REDIM. V BaConu se pole definuje a alokuje odlišně – zadáním názvu pole a počtu prvků. Před tuto deklaraci se většinou ještě zadává klíčové slovo LOCAL znamenající, že pole bude vytvořeno lokální v rámci funkce main (nebo subrutiny, kde je pole definováno). K přístupu k prvkům pole se používají hranaté závorky (jako v C, Javě, atd.) a nikoli závorky kulaté, jako v klasickém BASICu:
REM ***************************** REM REM Prace s jednorozmernymi poli REM REM Uprava pro BaCon REM REM ***************************** LOCAL A[10] FOR I=0 TO 10 A[I]=10*I NEXT I REM TISK POLE FOR I=0 TO 10 PRINT A[I] NEXT I
Po překladu se ve vygenerovaném hlavičkovém souboru objeví definice, deklarace a současně i inicializace pole:
... ... ... long A[(uint64_t) 10 + 0] = { 0 }; ... ... ... long I; ... ... ...
Samotná práce s poli se přeloží do prakticky totožného kódu jako v BaConu:
... ... ... for (I = 0; I <= 10; I += 1) { A[(uint64_t) I] = (long) (10 * I); } for (I = 0; I <= 10; I += 1) { fputs (STR__b2c__string_var (A[(uint64_t) I]), stdout); fputs ("\n", stdout); } return (0);
7. Dvourozměrná pole
Podobným způsobem jako s jednorozměrnými poli se v BaConu pracuje s poli dvourozměrnými, samozřejmě s tím dodatkem, že si opět musíme dát pozor na rozměry pole a vztah mezi rozměrem pole a koncovou hodnotou počitadel v programové smyčce. V dalším demonstračním příkladu se pracuje s polem s 6×6 prvky:
REM ***************************** REM REM Prace s dvourozmernymi poli REM REM Uprava pro BaCon REM REM ***************************** LOCAL M[6][6] FOR I=0 TO 5 FOR J=0 TO 5 M[I][J]=I*J NEXT J NEXT I REM TISK POLE FOR I=0 TO 5 FOR J=0 TO 5 PRINT M[I][J], " "; NEXT J PRINT NEXT I
Definice a inicializace dvourozměrného pole v transpřeloženém céčku vypadá takto:
long M[(uint64_t) 6 + 0][(uint64_t) 6 + 0] = { 0 }; long I; long J;
Práce s polem v céčkovém programu prakticky přesně odpovídá BASICovému protějšku (pokud zanedbáme neustálé testy, zda byl program přerušen uživatelem):
for (I = 0; I <= 5; I += 1) { for (J = 0; J <= 5; J += 1) { M[(uint64_t) I][(uint64_t) J] = (long) (I * J); } if (__b2c__break_ctr) { __b2c__break_ctr--; if (!__b2c__break_ctr) { if (__b2c__break_flag == 1) break; else continue; } else break; } } for (I = 0; I <= 5; I += 1) { for (J = 0; J <= 5; J += 1) { fputs (STR__b2c__string_var (M[(uint64_t) I][(uint64_t) J]), stdout); __b2c__assign = (char *) " "; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fflush (stdout); } if (__b2c__break_ctr) { __b2c__break_ctr--; if (!__b2c__break_ctr) { if (__b2c__break_flag == 1) break; else continue; } else break; } fputs ("\n", stdout); } return (0);
8. Příkaz GOTO a LABEL
Klasické BASICy kromě programové smyčky FOR-NEXT obsahovaly i podporu pro skoky na čísla řádků. Pro tento účel se používal příkaz GOTO a všechny řádky programu byly očíslovány, viz následující příklad:
1 REM ***************************** 2 REM Vypocet nejvetsiho spolecneho 3 REM delitele. 4 REM 5 REM Uprava pro Atari BASIC 6 REM 7 REM ***************************** 8 REM 9 REM 10 PRINT "X="; 20 INPUT X 30 PRINT "Y="; 40 INPUT Y 50 IF X=Y THEN PRINT "GCD: ";X:END 60 IF X>Y THEN X=X-Y:GOTO 50 70 IF X<Y THEN Y=Y-X:GOTO 50 998 REM finito 999 STOP
V BaConu se čísla řádků nepoužívají, ovšem příkaz GOTO je stále podporován (jinak by se ani nejednalo o BASIC :-). Cíl skoku je pojmenován příkazem LABEL. Předchozí příklad by se do BaConu mohl převzat následujícím způsobem:
REM ***************************** REM REM Vypocet nejvetsiho spolecneho REM delitele. REM REM Uprava pro BaCon REM REM ***************************** PRINT "X="; INPUT X PRINT "Y="; INPUT Y LABEL LOOP IF X=Y THEN PRINT "GCD: ";X STOP END IF IF X>Y THEN X=X-Y GOTO LOOP END IF IF X<Y THEN Y=Y-X GOTO LOOP END IF
Po překladu do jazyka C se taktéž použije příkaz goto, který tento jazyk (plně) podporuje, podobně jako odkazy na cíle skoků (labels). Viz též zvýrazněné řádky:
... ... ... __b2c__input (&__b2c__assign, "\n"); X = atol (__b2c__assign); free (__b2c__assign); __b2c__assign = NULL; __b2c__assign = (char *) "Y="; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fflush (stdout); __b2c__input (&__b2c__assign, "\n"); Y = atol (__b2c__assign); free (__b2c__assign); __b2c__assign = NULL; LOOP: ; __b2c__label_floatarray_LOOP = 0; __b2c__label_stringarray_LOOP = 0; if ((X) == Y) { __b2c__assign = (char *) "GCD: "; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fputs (STR__b2c__string_var (X), stdout); fputs ("\n", stdout); kill (getpid (), SIGSTOP); } if ((X) > Y) { X = (long) (X - Y); goto LOOP; } if ((X) < Y) { Y = (long) (Y - X); goto LOOP; } return (0);
9. Podprogramy založené na příkazech GOSUB a RETURN
V klasických interpretrech programovacího jazyka BASIC je možné používat podprogramy (subrutiny). Skok do podprogramu je realizován příkazem GOSUB, který provede skok a současně si zapamatuje řádek (přesněji řečeno příkaz), na který se má vrátit. Návrat z podprogramu je realizován příkazem RETURN. Nejprve si ukažme, jak jsou tyto příkazy použity v Atari BASICu, tedy klasickém interpretru tohoto jazyka z éry osmibitových mikropočítačů:
1 REM ***************************** 2 REM Vypocet konstanty Pi. 3 REM 4 REM Uprava pro Atari BASIC 5 REM 6 REM ***************************** 7 REM 8 REM 9 REM 10 N=1 20 FOR I=1 TO 10 25 GOSUB 1000:REM VYPOCET PI 30 PRINT I,N,PI 35 N=N*2 40 NEXT I 998 REM finito 999 STOP 1000 REM 1001 REM SUBRUTINA PRO VYPOCET PI 1002 REM 1010 PI=4 1020 FOR J=3 TO N+2 STEP 2 1030 PI=PI*(J-1)/J*(J+1)/J 1040 NEXT J 1050 RETURN
V BaConu se, jak již víme, čísla řádků nepoužívají. Namísto toho použijeme návěští (label). Upravený zdrojový kód tedy bude vypadat následovně:
REM ***************************** REM REM Vypocet konstanty Pi. REM REM Uprava pro BaCon REM REM ***************************** LOCAL N=1 FOR I=1 TO 10 REM vypocet PI GOSUB PI_COMP PRINT "I=",I," N=",N," PI=", PI_VAL N=N*2 NEXT I REM finito END REM ***************************** REM SUBRUTINA PRO VYPOCET PI REM ***************************** LABEL PI_COMP PI_VAL = 4.0 FOR J=3 TO N+2 STEP 2 PI_VAL=PI_VAL*(J-1)/J*(J+1)/J NEXT J RETURN
Zajímavé bude zjistit, jak se vlastně příkazy GOSUB a RETURN přeloží. Zde již není situace tak jednoduchá, jako v případě použití GOTO, které je přímo podporováno i céčkem. U dvojice GOSUB a RETURN je nutné explicitně realizovat zásobník návratových adres (jedná se zde o pole návratových adres); samotné cíle skoků jsou počítány a využívá se zde dvojice (nechvalně známých) funkcí setjmp a longjmp:
for (I = 1; I <= 10; I += 1) { __b2c__gosub_buffer_ptr++; if (__b2c__gosub_buffer_ptr >= 64) { ERROR = 31; if (!__b2c__catch_set) RUNTIMEERROR ("GOSUB", 12, "PI.bac", ERROR); else if (!setjmp (__b2c__jump)) goto __B2C__PROGRAM__EXIT; } if (!setjmp (__b2c__gosub_buffer[__b2c__gosub_buffer_ptr])) goto PI_COMP; __b2c__gosub_buffer_ptr--; if (__b2c__gosub_buffer_ptr < -1) __b2c__gosub_buffer_ptr = -1; __b2c__assign = (char *) "I="; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fputs (STR__b2c__string_var (I), stdout); __b2c__assign = (char *) " N="; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fputs (STR__b2c__string_var (N), stdout); __b2c__assign = (char *) " PI="; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fputs (STR__b2c__string_var (PI_VAL), stdout); fputs ("\n", stdout); N = (long) (N * 2); } exit (EXIT_SUCCESS); PI_COMP: ; __b2c__label_floatarray_PI_COMP = 0; __b2c__label_stringarray_PI_COMP = 0; PI_VAL = (double) (4.0); for (J = 3; J <= N + 2; J += 2) { PI_VAL = (double) (PI_VAL * (J - 1) / (double) J * (J + 1) / (double) J); } if (__b2c__gosub_buffer_ptr >= 0) longjmp (__b2c__gosub_buffer[__b2c__gosub_buffer_ptr], 1); __B2C__PROGRAM__EXIT: return (0);
10. Struktura programové smyčky typu WHILE-WEND
V mnoha klasických BASICech byl podporován jen jeden typ programové smyčky, a to konkrétně počítané smyčky typu FOR-NEXT. Později byla přidána podpora pro další strukturované příkazy, což mj. znamenalo přidání syntaxe pro programovou smyčku WHILE, jejíž ukončující příkaz se jmenoval WEND. I tento typ smyčky je v BaConu podporován, takže si můžeme upravit program pro výpočet konstanty Pi tak, aby tuto smyčku využíval (a to dokonce dvakrát):
REM ***************************** REM REM Výpočet hodnoty konstanty PI REM postavený na smyčce REM typu WHILE-WEND. REM REM Uprava pro BaCon REM ***************************** N=1 WHILE N<=2000 GOSUB COMPUTE_PI PRINT N," ", PI_VAL N=N*2 WEND REM SUBRUTINA PRO VYPOCET PI LABEL COMPUTE_PI PI_VAL=4.0 J=3 WHILE J<=N+2 PI_VAL=PI_VAL*(J-1)/J*(J+1)/J J=J+2 WEND RETURN
Výše uvedený program se transpřeloží do céčka takovým způsobem, že se využije v céčku „nativní“ programová smyčka while, jejíž sémantika je naprosto totožná s dvojicí WHILE-WEND:
N = (long) (1); while (N <= 2000) { __b2c__gosub_buffer_ptr++; if (__b2c__gosub_buffer_ptr >= 64) { ERROR = 31; if (!__b2c__catch_set) RUNTIMEERROR ("GOSUB", 12, "while_wend_pi.bac", ERROR); else if (!setjmp (__b2c__jump)) goto __B2C__PROGRAM__EXIT; } if (!setjmp (__b2c__gosub_buffer[__b2c__gosub_buffer_ptr])) goto COMPUTE_PI; __b2c__gosub_buffer_ptr--; if (__b2c__gosub_buffer_ptr < -1) __b2c__gosub_buffer_ptr = -1; fputs (STR__b2c__string_var (N), stdout); __b2c__assign = (char *) " "; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fputs (STR__b2c__string_var (PI_VAL), stdout); fputs ("\n", stdout); N = (long) (N * 2); } COMPUTE_PI: ; __b2c__label_floatarray_COMPUTE_PI = 0; __b2c__label_stringarray_COMPUTE_PI = 0; PI_VAL = (double) (4.0); J = (long) (3); while (J <= N + 2) { PI_VAL = (double) (PI_VAL * (J - 1) / (double) J * (J + 1) / (double) J); J = (long) (J + 2); } if (__b2c__gosub_buffer_ptr >= 0) longjmp (__b2c__gosub_buffer[__b2c__gosub_buffer_ptr], 1); __B2C__PROGRAM__EXIT: return (0);
11. Struktura programové smyčky FOR se záporným krokem
Vraťme se nyní k programové smyčce, kterou nalezneme v prakticky všech interpretrech programovacího jazyka BASIC (kterých je minimálně několik desítek, ale možná i stovek). V této smyčce je umožněno použít záporný krok, tj. hodnota počitadla je postupně snižována a nikoli zvyšována. Podívejme se opět na jednoduchý demonstrační příklad, konkrétně na výpočet faktoriálu. Programová smyčka se záporným krokem je zde zvýrazněna:
REM ***************************** REM REM Vypocet faktorialu REM REM Uprava pro BaCon REM REM ***************************** FOR N=0 TO 20 GOSUB FACTORIAL PRINT N," ",FACT NEXT N END REM VYPOCET FAKTORIALU LABEL FACTORIAL FACT=1 FOR I=N TO 1 STEP -1 FACT=FACT*I NEXT I RETURN
A takto bude vypadat výsledek vygenerovaný transpřekladačem BaConu. Příslušná smyčka se záporným krokem je zvýrazněna:
... ... ... for (N = 0; N <= 20; N += 1) { __b2c__gosub_buffer_ptr++; if (__b2c__gosub_buffer_ptr >= 64) { ERROR = 31; if (!__b2c__catch_set) RUNTIMEERROR ("GOSUB", 10, "factorial.bac", ERROR); else if (!setjmp (__b2c__jump)) goto __B2C__PROGRAM__EXIT; } if (!setjmp (__b2c__gosub_buffer[__b2c__gosub_buffer_ptr])) goto FACTORIAL; __b2c__gosub_buffer_ptr--; if (__b2c__gosub_buffer_ptr < -1) __b2c__gosub_buffer_ptr = -1; fputs (STR__b2c__string_var (N), stdout); __b2c__assign = (char *) " "; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fputs (STR__b2c__string_var (FACT), stdout); fputs ("\n", stdout); } exit (EXIT_SUCCESS); FACTORIAL: ; __b2c__label_floatarray_FACTORIAL = 0; __b2c__label_stringarray_FACTORIAL = 0; FACT = (long) (1); for (I = N; I >= 1; I += -1) { FACT = (long) (FACT * I); } if (__b2c__gosub_buffer_ptr >= 0) longjmp (__b2c__gosub_buffer[__b2c__gosub_buffer_ptr], 1); __B2C__PROGRAM__EXIT: return (0);
12. Vnořené programové smyčky a manipulace s polem – bubble sort
V dalším demonstračním příkladu je ukázáno použití vnořených programových smyček a taktéž využití „strukturovaného“ příkazu IF, jenž je možné použít společně s programovým blokem. Je tedy nutné nějakým způsobem příkaz IF ukončit, což je zajištěno příkazem END IF (ukončení programové smyčky FOR zajišťuje příkaz NEXT, což již ostatně víme z předchozích kapitol):
REM ***************************** REM REM Bubble sort REM REM Uprava pro BaCon REM REM ***************************** GLOBAL A[20] FOR I=0 TO 20 A[I]=INT(RANDOM(100)) NEXT I GOSUB PRINT_ARRAY FOR I=19 TO 0 STEP -1 PRINT "."; FOR J=0 TO I IF A[J]>A[J+1] THEN X=A[J] A[J]=A[J+1] A[J+1]=X END IF NEXT J NEXT I PRINT "" PRINT "SORTED:" GOSUB PRINT_ARRAY END LABEL PRINT_ARRAY REM TISK OBSAHU POLE FOR I=0 TO 20 PRINT I," ", A[I] NEXT I RETURN
Překlad tohoto demonstračního příkladu do jazyka C je poměrně idiomatický, samozřejmě s tím rozdílem, že v céčku se bloky zapisují do složených závorek a tedy není nutné používat klíčová slova pro ukončení bloků:
... ... ... for (I = 19; I >= 0; I += -1) { __b2c__assign = (char *) "."; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fflush (stdout); for (J = 0; J <= I; J += 1) { if ((A[(uint64_t) J]) > A[(uint64_t) J + 1]) { X = (long) (A[(uint64_t) J]); A[(uint64_t) J] = (long) (A[(uint64_t) J + 1]); A[(uint64_t) J + 1] = (long) (X); } } if (__b2c__break_ctr) { __b2c__break_ctr--; if (!__b2c__break_ctr) { if (__b2c__break_flag == 1) break; else continue; } else break; } } ... ... ...
13. Využití maker preprocesoru jazyka C: zápis příkazů malými písmeny
Nyní se dostáváme k zajímavé vlastnosti BaConu, konkrétně k možnosti využití standardních céčkovských maker přímo ve zdrojových kódech BaConu. Tato makra se přímo předávají preprocesoru céčka a BaCon s nimi nijak dál nemanipuluje. K čemu se však tato možnost hodí? Pokud nám nevyhovuje, že se klíčová slova v BaConu zapisují velkými písmeny, můžeme si nadefinovat příslušná makra, jejichž jména jsou zapsána malými písmeny. Vše ilustruje následující zdrojový kód s několika makry, která jsou následně použita namísto původních klíčových slov:
REM ***************************** REM REM Bubble sort REM REM Uprava pro BaCon REM REM ***************************** #define dim GLOBAL #define for FOR #define to TO #define next NEXT #define gosub GOSUB #define return RETURN #define print PRINT #define if IF #define then THEN #define end END dim A[20] for I=0 to 20 A[I]=INT(RANDOM(100)) next I gosub PRINT_ARRAY for I=19 TO 0 STEP -1 print "."; for J=0 to I if A[J]>A[J+1] then X=A[J] A[J]=A[J+1] A[J+1]=X end if next J next I print "" print "SORTED:" gosub PRINT_ARRAY end LABEL PRINT_ARRAY REM TISK OBSAHU POLE for I=0 TO 20 print I," ", A[I] next I return
Výsledek transpřekladu, z něhož je patrné, jakým způsobem se makra expandovala:
# 1 "macros.bac" # 1 "<built-in>" # 1 "<command-line>" # 31 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 32 "<command-line>" 2 # 1 "macros.bac" REM ***************************** REM REM Bubble sort REM REM Uprava pro BaCon REM REM ***************************** # 21 "macros.bac" GLOBAL A[20] FOR I=0 TO 20 A[I]=INT(RANDOM(100)) NEXT I GOSUB PRINT_ARRAY FOR I=19 TO 0 STEP -1 PRINT "."; FOR J=0 TO I IF A[J]>A[J+1] THEN X=A[J] A[J]=A[J+1] A[J+1]=X END IF NEXT J NEXT I PRINT "" PRINT "SORTED:" GOSUB PRINT_ARRAY END LABEL PRINT_ARRAY REM TISK OBSAHU POLE FOR I=0 TO 20 PRINT I," ", A[I] NEXT I RETURN
14. Operace s asociativními poli
V BaConu mohou vývojáři nalézt i poměrně „moderní“ prvky. Jedná se například o podporu operací s asociativními poli (slovníky). Prvky uložené do asociativních polí mohou být libovolného typu, ovšem klíče mohou být pouze řetězce – zatímco v moderních programovacích jazycích většinou nejsme nijak omezeni typem klíčů. Asociativní pole je nejdříve nutné deklarovat příkazem:
DECLARE map ASSOC int
kde map je jméno nové proměnné a int je typ prvků uložených ve slovníku. Pro přístup k prvkům se používá syntaxe:
mapa(klíč)
V případě, že se pokusíme o přečtení neexistujícího prvku, vrátí se „nulová hodnota“ daného datového typu (nula pro celá čísla, prázdný řetězec pro řetězce atd.) To je ostatně ukázáno v dalším demonstračním příkladu:
REM ***************************** REM REM Operace s asociativnim polem. REM REM Uprava pro BaCon REM REM ***************************** DECLARE map ASSOC int map("foo") = 1 map("bar") = 42 map("baz") = -1 PRINT map("foo") PRINT map("bar") PRINT map("baz") PRINT map("xyzzy")
V přeloženém programu nalezneme volání funkcí __b2c__…, které interně s asociativními poli pracují:
... ... ... /* Rest of the program */ __b2c__assoc_map = __b2c__hash_new (); __b2c__assoc_map_eval = 1; __b2c__hash_add (__b2c__assoc_map, &__b2c__assoc_map_eval, "foo"); __b2c__assoc_map_eval = 42; __b2c__hash_add (__b2c__assoc_map, &__b2c__assoc_map_eval, "bar"); __b2c__assoc_map_eval = -1; __b2c__hash_add (__b2c__assoc_map, &__b2c__assoc_map_eval, "baz"); fputs (STR__b2c__string_var (map ("foo")), stdout); fputs ("\n", stdout); fputs (STR__b2c__string_var (map ("bar")), stdout); fputs ("\n", stdout); fputs (STR__b2c__string_var (map ("baz")), stdout); fputs ("\n", stdout); fputs (STR__b2c__string_var (map ("xyzzy")), stdout); fputs ("\n", stdout); return (0);
Další demonstrační příklad ukazuje použití asociativních polí, v nichž jsou uloženy řetězce. Jak je v BASICu zvykem, jsou funkce, proměnné atd. pracující s řetězci ukončeny znakem dolar ($), jenž je součástí názvu dané funkce/proměnné:
REM ***************************** REM REM Operace s asociativnim polem. REM REM Uprava pro BaCon REM REM ***************************** DECLARE map$ ASSOC STRING map$("foo") = "FOO" map$("bar") = "BAR" map$("baz") = "" PRINT map$("foo") PRINT map$("bar") PRINT map$("baz") PRINT map$("xyzzy")
Pro úplnost si ukažme způsob překladu tohoto demonstračního příkladu do céčka. Povšimněte si, že funkce __b2c__hash_??? nyní obsahují koncovku _str, což mimochodem naznačuje další omezení na známé datové typy prvků:
... ... ... __b2c__assoc_map__b2c__string_var = __b2c__hash_new (); __b2c__hash_add_str (__b2c__assoc_map__b2c__string_var, "FOO", "foo"); __b2c__hash_add_str (__b2c__assoc_map__b2c__string_var, "BAR", "bar"); __b2c__hash_add_str (__b2c__assoc_map__b2c__string_var, "", "baz"); __b2c__assign = (char *) map__b2c__string_var ("foo"); if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fputs ("\n", stdout); __b2c__assign = (char *) map__b2c__string_var ("bar"); if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fputs ("\n", stdout); __b2c__assign = (char *) map__b2c__string_var ("baz"); if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fputs ("\n", stdout); __b2c__assign = (char *) map__b2c__string_var ("xyzzy"); if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fputs ("\n", stdout); return (0);
15. Operace se záznamy
Kromě asociativních polí je možné v BaConu deklarovat i datový typ záznam (record, struct). Samotná deklarace datového typu a současně i proměnné typu záznam vypadá následovně:
RECORD user LOCAL id LOCAL name$ LOCAL surname$ END RECORD
Pro přístup k prvkům se používá dnes již zcela standardní céčková notace:
REM ***************************** REM REM Operace se zaznamem. REM REM Uprava pro BaCon REM REM ***************************** RECORD user LOCAL id LOCAL name$ LOCAL surname$ END RECORD user.id = 42 user.name$ = "Linus" user.surname$ = "Torvalds" PRINT user.id, " ", user.name$, " ", user.surname$
Podívejme se nyní na způsob transpřekladu deklarace typu a proměnné typu záznam do programovacího jazyka C. Jedná se o přímočarou transformaci:
typedef struct { long id; char *name__b2c__string_var; char *surname__b2c__string_var; } user_TYPE;
Samotné operace se záznamy jsou v céčku opět prakticky stejné, jako v BaConu, takže zde měl transpřekladač poměrně jednoduchou práci:
user.name__b2c__string_var = NULL; user.surname__b2c__string_var = NULL; user.id = (long) (42); user.name__b2c__string_var = __b2c_Swap_String (&user.name__b2c__string_var, "Linus"); user.surname__b2c__string_var = __b2c_Swap_String (&user.surname__b2c__string_var, "Torvalds"); fputs (STR__b2c__string_var (user.id), stdout); __b2c__assign = (char *) " "; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } __b2c__assign = (char *) user.name__b2c__string_var; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } __b2c__assign = (char *) " "; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } __b2c__assign = (char *) user.surname__b2c__string_var; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fputs ("\n", stdout); return (0);
16. Pole záznamů
Kromě jednotlivých záznamů lze v BaConu pracovat i s poli záznamů. Syntaxe pro deklarace takového pole se poněkud liší od deklarace běžných polí:
RECORD users[10] LOCAL id LOCAL name$ LOCAL surname$ END RECORD
Z následujícího demonstračního příkladu je patrné, jak se s poli záznamů pracuje:
REM ***************************** REM REM Operace se s vice zaznamy. REM REM Uprava pro BaCon REM REM ***************************** RECORD users[10] LOCAL id LOCAL name$ LOCAL surname$ END RECORD users[0].id = 0 users[0].name$ = "Linus" users[0].surname$ = "Torvalds" users[1].id = 1 users[1].name$ = "Ken" users[1].surname$ = "Iverson" users[2].id = 2 users[2].name$ = "Rob" users[2].surname$ = "Pike" FOR i=0 TO 2 PRINT users[i].id, " ", users[i].name$, " ", users[i].surname$ NEXT i
Opět se podívejme na způsob transpřekladu předchozího demonstračního příkladu do assembleru. Samotný datový typ „pole záznamů“ vypadá v programovacím jazyku C následovně:
typedef struct { long id; char *name__b2c__string_var; char *surname__b2c__string_var; } users_TYPE; typedef users_TYPE users_type; users_TYPE users[(uint64_t) 10 + 0] = { 0 };
Následuje výpis části céčkového programu, který vznikl transpřekladem zdrojového kódu v BaConu:
... ... ... users[(uint64_t) 0].id = (long) (0); users[(uint64_t) 0].name__b2c__string_var = __b2c_Swap_String (&users[(uint64_t) 0].name__b2c__string_var, "Linus"); users[(uint64_t) 0].surname__b2c__string_var = __b2c_Swap_String (&users[(uint64_t) 0].surname__b2c__string_var, "Torvalds"); users[(uint64_t) 1].id = (long) (1); users[(uint64_t) 1].name__b2c__string_var = __b2c_Swap_String (&users[(uint64_t) 1].name__b2c__string_var, "Ken"); users[(uint64_t) 1].surname__b2c__string_var = __b2c_Swap_String (&users[(uint64_t) 1].surname__b2c__string_var, "Iverson"); users[(uint64_t) 2].id = (long) (2); users[(uint64_t) 2].name__b2c__string_var = __b2c_Swap_String (&users[(uint64_t) 2].name__b2c__string_var, "Rob"); users[(uint64_t) 2].surname__b2c__string_var = __b2c_Swap_String (&users[(uint64_t) 2].surname__b2c__string_var, "Pike"); for (i = 0; i <= 2; i += 1) { fputs (STR__b2c__string_var (users[(uint64_t) i].id), stdout); __b2c__assign = (char *) " "; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } __b2c__assign = (char *) users[(uint64_t) i].name__b2c__string_var; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } __b2c__assign = (char *) " "; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } __b2c__assign = (char *) users[(uint64_t) i].surname__b2c__string_var; if (__b2c__assign != NULL) { fputs (__b2c__assign, stdout); } fputs ("\n", stdout); } return (0);
17. Závěrečné zhodnocení
V tomto článku jsme se seznámili se základními vlastnostmi transpřekladače BaCon. V mnoha ohledech dokáže tento transpřekladač poměrně slušně „emulovat“ chování klasických BASICů. Najdeme zde však několik rozdílů, a to jak v syntaxi, tak i v chování. Především se nepoužívají čísla řádků (což je většinou dobře), takže musel být vytvořen nový příkaz LABEL umožňující definici pojmenovaných návěští. Výsledek je však čitelnější, než použití čísel řádků, i když se některé původní konstrukce typu ON GOTO a ON GOSUB nemohou používat v původní podobě.
Důležitější je však odlišné chování BaConu v porovnání s klasickými interpretry programovacího jazyka BASIC. Zatímco původní interpretry reagovaly na chybně zadaný příkaz ihned po dokončení aktuálního programového řádku (odeslání řádku RETURNem nebo ENTERem), v BaConu se chyby objeví buď až při transpřekladu nebo dokonce až ve chvíli, kdy je program kompilován překladačem céčka. Kvůli tomuto chování BaCon ztrácí – alespoň podle názoru autora článku – příjemné ovládání s okamžitými zpětnými odpověďmi počítače (i proto byl ostatně BASIC tak oblíben).
18. Repositář s demonstračními příklady
Zdrojové kódy všech popsaných demonstračních příkladů určených pro programovací jazyk BaCon byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/8bit-fame. V případě, že nebudete chtít klonovat celý repositář (ten je ovšem stále velmi malý, dnes má velikost zhruba několik desítek kilobajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:
Výsledky transpřekladu do programovacího jazyka C:
# | Soubor | Stručný popis souboru | Cesta |
---|---|---|---|
1 | 1d_array.bac.c | výsledek transpřekladu zdrojového souboru 1d_array.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/1d_array.bac.c |
2 | 1d_array.bac.h | výsledek transpřekladu zdrojového souboru 1d_array.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/1d_array.bac.h |
3 | 2d_array.bac.c | výsledek transpřekladu zdrojového souboru 2d_array.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/2d_array.bac.c |
4 | 2d_array.bac.h | výsledek transpřekladu zdrojového souboru 2d_array.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/2d_array.bac.h |
5 | bubble_sort.bac.c | výsledek transpřekladu zdrojového souboru bubble_sort.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/bubble_sort.bac.c |
6 | bubble_sort.bac.h | výsledek transpřekladu zdrojového souboru bubble_sort.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/bubble_sort.bac.h |
7 | factorial.bac.c | výsledek transpřekladu zdrojového souboru factorial.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/factorial.bac.c |
8 | factorial.bac.h | výsledek transpřekladu zdrojového souboru factorial.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/factorial.bac.h |
9 | GCD.bac.c | výsledek transpřekladu zdrojového souboru GCD.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/GCD.bac.c |
10 | GCD.bac.h | výsledek transpřekladu zdrojového souboru GCD.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/GCD.bac.h |
11 | hello.bac.c | výsledek transpřekladu zdrojového souboru hello.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/hello.bac.c |
12 | hello.bac.h | výsledek transpřekladu zdrojového souboru hello.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/hello.bac.h |
13 | PI.bac.c | výsledek transpřekladu zdrojového souboru PI do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/PI.bac.c |
14 | PI.bac.h | výsledek transpřekladu zdrojového souboru PI do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/PI.bac.h |
15 | while_wend_pi.bac.c | výsledek transpřekladu zdrojového souboru while_wend_pi.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/while_wend_pi.bac.c |
16 | while_wend_pi.bac.h | výsledek transpřekladu zdrojového souboru while_wend_pi.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/while_wend_pi.bac.h |
17 | macros.bac.c | výsledek transpřekladu zdrojového souboru macros.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/macros.bac.c |
18 | macros.bac.h | výsledek transpřekladu zdrojového souboru macros.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/macros.bac.h |
19 | assoc_array_int.bac.c | výsledek transpřekladu zdrojového souboru assoc_array_int.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/assoc_array_int.bac.c |
20 | assoc_array_int.bac.h | výsledek transpřekladu zdrojového souboru assoc_array_int.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/assoc_array_int.bac.h |
21 | assoc_array_string.bac.c | výsledek transpřekladu zdrojového souboru assoc_array_string.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/assoc_array_string.bac.c |
22 | assoc_array_string.bac.h | výsledek transpřekladu zdrojového souboru assoc_array_string.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/assoc_array_string.bac.h |
23 | record.bac.c | výsledek transpřekladu zdrojového souboru record.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/record.bac.c |
24 | record.bac.h | výsledek transpřekladu zdrojového souboru record.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/record.bac.h |
25 | records.bac.c | výsledek transpřekladu zdrojového souboru records.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/records.bac.c |
26 | records.bac.h | výsledek transpřekladu zdrojového souboru records.bac do C | https://github.com/tisnik/8bit-fame/blob/master/BaCon/records.bac.h |
19. Dřívější články o interpretrech a překladačích programovacího jazyka BASIC
S programovacím jazykem BASIC, ať již se jedná o zastaralé „retro“ interpretry či o novější reinkarnace tohoto jazyka, jsme se na stránkách Roota již několikrát setkali. Jedná se především o následující články:
- Programovací jazyk BASIC na osmibitových mikropočítačích
https://www.root.cz/clanky/programovaci-jazyk-basic-na-osmibitovych-mikropocitacich/ - Programovací jazyk BASIC na osmibitových mikropočítačích (2)
https://www.root.cz/clanky/programovaci-jazyk-basic-na-osmibitovych-mikropocitacich-2/ - Programovací jazyk BASIC na osmibitových mikropočítačích (3)
https://www.root.cz/clanky/programovaci-jazyk-basic-na-osmibitovych-mikropocitacich-3/ - Programovací jazyk BASIC na osmibitových mikropočítačích (dokončení)
https://www.root.cz/clanky/programovaci-jazyk-basic-na-osmibitovych-mikropocitacich-dokonceni/ - Programovací jazyk BASIC na počítačích kompatibilních s IBM PC
https://www.root.cz/clanky/programovaci-jazyk-basic-na-pocitacich-kompatibilnich-s-ibm-pc/ - Programovací jazyk BASIC na počítačích kompatibilních s IBM PC v současnosti
https://www.root.cz/clanky/programovaci-jazyk-basic-na-pocitacich-kompatibilnich-s-ibm-pc-v-soucasnosti/ - PC-BASIC: reinkarnace populárního i zatracovaného GW-BASICu
https://www.root.cz/clanky/pc-basic-reinkarnace-popularniho-i-zatracovaneho-gw-basicu/ - Basic-256: další moderní reinkarnace BASICu určená pro výuku programování
https://www.root.cz/clanky/basic-256-dalsi-moderni-reinkarnace-basicu-urcena-pro-vyuku-programovani/ - BBC BASIC i QBasic oslavují svá kulatá výročí
https://www.root.cz/clanky/bbc-basic-i-qbasic-oslavuji-sva-kulata-vyroci/ - Základy práce s grafickou plochou v jazyku Basic-256
https://www.root.cz/clanky/zaklady-prace-s-grafickou-plochou-v-jazyku-basic-256/ - Small Basic: moderní reinkarnace BASICu určená pro výuku programování
https://www.root.cz/clanky/small-basic-moderni-reinkarnace-basicu-urcena-pro-vyuku-programovani/ - Vestavěné objekty Small Basicu: práce s grafikou, časovačem, reakce na události
https://www.root.cz/clanky/vestavene-objekty-small-basicu-prace-s-grafikou-casovacem-reakce-na-udalosti/ - Programovací jazyk BASIC na herní konzoli Atari 2600
https://www.root.cz/clanky/programovaci-jazyk-basic-na-herni-konzoli-atari-2600/ - Tvorba her pro Atari 2600 v Batari BASICu: úkol pro hardcode programátory
https://www.root.cz/clanky/tvorba-her-pro-atari-2600-v-batari-basicu-ukol-pro-hardcode-programatory/ - Tvorba her pro Atari 2600 v Batari BASICu: standardní kernel a zvuky
https://www.root.cz/clanky/tvorba-her-pro-atari-2600-v-batari-basicu-standardni-kernel-a-zvuky/ - Tvorba her pro Atari 2600 v Batari BASICu: ovládání čipu TIA
https://www.root.cz/clanky/tvorba-her-pro-atari-2600-v-batari-basicu-ovladani-cipu-tia/
20. Odkazy na Internetu
- Stránka projektu BaCon
http://basic-converter.org/ - Dokumentace BaConu
http://basic-converter.org/doc_frame.html - Zdrojové kódy i binární obrazy BaConu
http://basic-converter.org/#downloads - Stránka projektu Basic-256
https://basic256.org/ - So You Want to Learn to Program – BASIC-256 (Third Edition)
http://syw2l.org/?page_id=407 - Why Another BASIC?
https://basic256.org/2019/06/27/why-another-basic/ - Stránka projektu Small Basic
https://smallbasic-publicwebsite.azurewebsites.net/ - List of Programs Made with Small Basic
https://social.technet.microsoft.com/wiki/contents/articles/14013.list-of-programs-made-with-small-basic.aspx - Expert to Expert: The Basics of SmallBasic
https://channel9.msdn.com/blogs/charles/expert-to-expert-the-basics-of-smallbasic - The Developer’s Reference Guide to Small Basic
https://social.technet.microsoft.com/wiki/contents/articles/16767.the-developers-reference-guide-to-small-basic.aspx - Small Basic – Talking to Raspberry Pi
https://techcommunity.microsoft.com/t5/small-basic-blog/small-basic-talking-to-raspberry-pi/ba-p/337844 - Small Basic – Arduino
https://techcommunity.microsoft.com/t5/small-basic-blog/small-basic-arduino/ba-p/337762 - Small Basic + micro:bit
https://techcommunity.microsoft.com/t5/small-basic-blog/small-basic-micro-bit/ba-p/1968424 - #1 Learn Small Basic Programming – Introduction
https://www.youtube.com/watch?v=e_BaEPCa8OQ - #2 Learn Small Basic Programming – Input, Output & Variables
https://www.youtube.com/watch?v=VWekYLa33OI - #3 Learn Small Basic Programming – String Concatenation
https://www.youtube.com/watch?v=iWvIaOaT474 - Small Basic – The Programmer's Guide
https://www.i-programmer.info/programming/other-languages/5196-small-basic-the-programmers-guide.html - Rosetta Code: Category:Microsoft Small Basic
https://rosettacode.org/wiki/Category:Microsoft_Small_Basic - Fifty Years of BASIC, the Programming Language That Made Computers Personal
https://time.com/69316/basic/ - BBC BASIC i QBasic oslavují svá kulatá výročí
https://www.root.cz/clanky/bbc-basic-i-qbasic-oslavuji-sva-kulata-vyroci/ - GWBASIC User's Manual
http://www.antonis.de/qbebooks/gwbasman/index2.html - GFA-BASIC
http://sites.google.com/site/gfabasic16/ - E-mail od tvůrce GW-Basicu
http://www.classiccmp.org/pipermail/cctech/2005-April/042999.html - General Electric GE-400
http://www.feb-patrimoine.com/PROJET/ge400/ge-400.htm - GE-400 Time-sharing information systems:
http://www.computerhistory.org/collections/accession/102646147 - A brief history of the development of BASIC (pravděpodobně již nefunkční odkaz)
http://www.phys.uu.nl/~bergmann/history.html - History of BASIC (PDF)
http://www.q7basic.org/History%20of%20BASIC.pdf - Dartmouth College Computation Center. 1964.-The original Dartmouth BASIC manual
http://www.bitsavers.org/pdf/dartmouth/BASIC_Oct64.pdf - The Original BASIC
http://www.truebasic.com/ - BASIC – Beginners All-purpose Symbolic Instruction Code
http://hopl.murdoch.edu.au/showlanguage.prx?exp=176 - The History of the Mainframe Computer
http://www.vikingwaters.com/htmlpages/MFHistory.htm - Dartmouth Time Sharing System
http://en.wikipedia.org/wiki/Dartmouth_Time_Sharing_System - General Electric (Wikipedia)
http://en.wikipedia.org/wiki/General_Electric - GE 225 vs. IBM 1401
http://ed-thelen.org/GE225-IBM1401.html - A GE-225 is found
http://ed-thelen.org/comp-hist/GE225.html - G.E. 200 Series Computers
http://www.smecc.org/g_e__200_series_computers.htm - DTSS – Dartmouth Time Sharing System
http://dtss.dartmouth.edu/index.php - John G. Kemeny: BASIC and DTSS: Everyone a Programmer
http://dtss.dartmouth.edu/everyoneaprogrammer.php - GE-200 series (Wikipedia)
http://en.wikipedia.org/wiki/GE-200_series - GE-400 series (Wikipedia)
http://en.wikipedia.org/wiki/GE-400_series - GE-600 series (Wikipedia)
http://en.wikipedia.org/wiki/GE-600_series - ZX Basic Manual
http://www.worldofspectrum.org/ZXBasicManual/ - ZX81 BASIC Programming
http://www.worldofspectrum.org/ZX81BasicProgramming/ - Sinclair BASIC History
http://scratchpad.wikia.com/wiki/Sinclair_BASIC_History - Sinclair BASIC (Wikipedia CZ)
http://cs.wikipedia.org/wiki/Sinclair_BASIC - Sinclair BASIC (Wikipedia EN)
http://en.wikipedia.org/wiki/Sinclair_BASIC - Beta BASIC (Wikipedia EN)
http://en.wikipedia.org/wiki/Beta_BASIC - Beta BASIC (Wikipedia CZ)
http://cs.wikipedia.org/wiki/Beta_BASIC - BETA BASIC NEWSLETTER No 8
http://spectrum128.ru/help/BetaBasicNewsletter8.pdf - R. T. RUSSELL: The home of BBC BASIC
http://www.rtrussell.co.uk/ - R. T. RUSSELL: A History of BBC BASIC
http://www.cix.co.uk/~rrussell/bbcbasic/history.html - SuperBASIC (Wikipedia EN)
http://en.wikipedia.org/wiki/SuperBASIC - SuperBASIC (Wikipedia CZ)
http://en.wikipedia.org/wiki/SuperBASIC - Laser Basic/Laser Compiler
http://www.sincuser.f9.co.uk/049/laser.htm - Laser BASIC (Wikipedia CZ)
http://cs.wikipedia.org/wiki/Laser_BASIC - BBC BASIC
http://www.bbcbasic.co.uk/bbcbasic.html - BBC BASIC
http://mdfs.net/Software/BBCBasic/ - BBC BASIC (Z80) for the ZX Spectrum
http://mdfs.net/Software/BBCBasic/Spectrum/ - BBC BASIC (Wikipedia CZ)
http://en.wikipedia.org/wiki/BBC_BASIC - BeebWiki – 8-bit Acorn Computer Wiky
http://beebwiki.jonripley.com/Main_Page - Porovnání osmibitů
http://porovnani8bitu.spaces.live.com/ - Rosetta Code – Main Page
http://rosettacode.org/wiki/Main_Page - Rosetta Code – Category Basic
http://rosettacode.org/wiki/Category:BASIC - QBasicJedi
http://www.freewebs.com/qbasicjedi/ - QBasic/QuickBasic Downloads
http://www.freewebs.com/qbasicjedi/qbdownloads.html - QuickBASIC (Wikipedia CZ)
http://cs.wikipedia.org/wiki/QuickBASIC - QBasic.com
http://www.qbasic.com/ - QBasic (Wikipedia)
http://cs.wikipedia.org/wiki/QBasic - Dialling with QBASIC
http://www.mysundial.ca/tsp/qbasic.html - BASIC (Wikipedia EN)
http://en.wikipedia.org/wiki/BASIC - BASIC (Wikipedia CZ)
http://cs.wikipedia.org/wiki/BASIC - Turbo BASIC (Wikipedia CZ)
http://cs.wikipedia.org/wiki/Turbo_BASIC - More BASIC Computer Games
http://www.atariarchives.org/morebasicgames/ - How to build an interpreter in Java, Part 1: The BASICs
http://www.javaworld.com/jw-05–1997/jw-05-indepth.html - Apple I
http://applemuseum.bott.org/sections/computers/a1.html - The Apple 1 history
http://apple2history.org/history/ah02.html - The Apple 2 history
http://apple2history.org/history/ah03.html - INTEGER BASIC Reference
http://www.landsnail.com/a2ref2.htm - APPLESOFT Reference
http://www.landsnail.com/a2ref.htm - Apple II Programming
http://home.swbell.net/rubywand/csa2pfaq.html - Applesoft Lite: Applesoft BASIC for the Replica-1
http://cowgod.org/replica1/applesoft/ - Simons' BASIC
http://en.wikipedia.org/wiki/Simons'_BASIC - Simon's Basic
http://www.lemon64.com/?mainurl=http%3A//www.lemon64.com/museum/list.php%3Flineoffset%3D54%26genre%3Dmanualmisc - BASIC
http://www.c64-wiki.com/index.php/BASIC - C64 Wiki: Simons Basic
http://www.c64-wiki.de/index.php/Simons_Basic - Simons' Basic (evaluation)
http://www.atarimagazines.com/creative/v9n11/60_Simons_Basic.php - Bill Gates' Personal Easter Eggs in 8 Bit BASIChttp://www.pagetable.com/?p=43
- Kladivo na programy (je tam třeba popsán způsob nahrávání a ochran programů protí kopírování a crackování)
http://www.grandjihlava.cz/tmp/kladivo.pdf - Didaktik Gama návod k obsluze
http://www.grandjihlava.cz/tmp/navod.pdf - Můj přítel Didaktik Gama
http://www.grandjihlava.cz/tmp/priteldidaktik.pdf - Tip & trip pro Didaktik
http://www.grandjihlava.cz/tmp/tiptrikdidaktik.pdf - Muzeum československých mikropočítačů
http://cs-pocitace.ic.cz/