Tämä on hyvin yksinkertainen tulkki ohjelmointikielelle nimeltä brainfuck. Ylimääräisiä ominaisuuksia ei juurikaan ole, ei edes tarkistusta muistialueen ylityksistä tai muusta vastaavasta. Toiminnan pitäisi olla hyvinkin selkeä ja koodi varmasti kommentoi itse itsensä. Lisätietoja itse kielestä saa brainfuck-oppaasta.
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MUISTIN_KOKO 30000 int tiedostoja = 0; char ** tiedostolista = 0; FILE * tiedosto = 0; char * ohjelma = 0; char muisti[MUISTIN_KOKO]; void tulosta_ohjeet(char * ajonimi); int tiedosto_on_olemassa(char * nimi); void lisaa_tiedosto_listaan(char * nimi); int kelpo_merkki(char merkki); int lataa_ohjelma(char * nimi); int tarkista_syntaksi(char * nimi); void aja_ohjelma(char * nimi); void lopetusfunktio(); int main(int argumenttien_maara, char **argumentit) { int i; atexit(lopetusfunktio); if (argumenttien_maara < 2) { tulosta_ohjeet(argumentit[0]); return EXIT_FAILURE; } for (i = 1; i < argumenttien_maara; ++i) { if (tiedosto_on_olemassa(argumentit[i])) { lisaa_tiedosto_listaan(argumentit[i]); } else { printf("Virhe! Tiedostoa %s ei ollut tai sen avaaminen ei onnistunut!\n", argumentit[i]); tulosta_ohjeet(argumentit[0]); return EXIT_FAILURE; } } for (i = 0; i < tiedostoja; ++i) { if (lataa_ohjelma(tiedostolista[i]) && tarkista_syntaksi(tiedostolista[i])) { aja_ohjelma(tiedostolista[i]); } } return EXIT_SUCCESS; } void tulosta_ohjeet(char * ajonimi) { printf("Brainfuck-tulkki 0.1\nToiminta: %s tiedostot\n", ajonimi); } int tiedosto_on_olemassa(char * nimi) { tiedosto = fopen(nimi, "r"); if (!tiedosto) { return 0; } fclose(tiedosto); return 1; } void lisaa_tiedosto_listaan(char * nimi) { /* Laajennetaan listaa */ ++tiedostoja; tiedostolista = (char**)realloc(tiedostolista, tiedostoja * sizeof(char*)); if (!tiedostolista) { printf("Muisti loppui kesken tiedostolistan luonnin!\n"); exit(EXIT_FAILURE); } /* Varataan muistia ja laitetaan sinne tiedoston nimi */ tiedostolista[tiedostoja - 1] = (char*) malloc(strlen(nimi) + 1); if (!tiedostolista[tiedostoja - 1]) { printf("Muisti loppui kesken tiedostolistan luonnin!\n"); exit(EXIT_FAILURE); } strcpy(tiedostolista[tiedostoja - 1], nimi); } int kelpo_merkki(char merkki) { if (merkki == '<') return 1; if (merkki == '>') return 1; if (merkki == '+') return 1; if (merkki == '-') return 1; if (merkki == '.') return 1; if (merkki == ',') return 1; if (merkki == '[') return 1; if (merkki == ']') return 1; return 0; } int lataa_ohjelma(char * nimi) { size_t koko; int i, j; tiedosto = fopen(nimi, "r"); if (!tiedosto) { printf("Virhe! Tiedostoa '%s' ei saatu auki!\n", nimi); exit(EXIT_FAILURE); } /* Mitataan tiedosto */ fseek(tiedosto, 0, SEEK_END); koko = ftell(tiedosto); fseek(tiedosto, 0, SEEK_SET); /* Vapautetaan vanha koodi ja varataan uusi */ if (ohjelma) { free(ohjelma); } ohjelma = (char*)malloc(koko + 1); if (!ohjelma) { printf("Virhe! Ohjelmalle tiedostossa '%s' ei saatu muistia!\n", nimi); exit(EXIT_FAILURE); } /* Luetaan koko tiedosto */ if (fread(ohjelma, koko, 1, tiedosto) != 1) { printf("Virhe! Tiedostoa '%s' ei saatu luettua!\n", nimi); exit(EXIT_FAILURE); } ohjelma[koko] = 0; /* Poistetaan ohjelmaan kuulumattomat merkit */ for (i = j = 0; ohjelma[i] != 0; ++i) { if (kelpo_merkki(ohjelma[i])) { ohjelma[j] = ohjelma[i]; ++j; } } ohjelma[j] = 0; return 1; } int tarkista_syntaksi(char * nimi) { int i, sulkuja; if (!ohjelma) { return 0; } /* Lasketaan, että sulkuja on saman verran molempiin suuntiin */ for (i = sulkuja = 0; ohjelma[i] != 0; ++i) { if (ohjelma[i] == '[') { ++sulkuja; } else if (ohjelma[i] == ']') { --sulkuja; } } if (sulkuja != 0) { printf("Tiedoston '%s' syntaksissa on virhe!\n", nimi); } return sulkuja == 0; } void aja_ohjelma(char * nimi) { int kohta = 0, sulkuja; char *osoitin = muisti; if (!ohjelma) { return; } printf("Ajetaan '%s'\n", nimi); /* Nollataan muisti */ memset(muisti, 0, MUISTIN_KOKO); /* Tekstin lopussa on "nollamerkki", toistetaan siihen asti */ while (ohjelma[kohta] != 0) { switch (ohjelma[kohta]) { case '>': ++osoitin; break; case '<': --osoitin; break; case '+': ++*osoitin; break; case '-': --*osoitin; break; case '.': putchar(*osoitin); fflush(stdout); break; case ',': *osoitin = getchar(); break; case '[': if (*osoitin == 0) { /* Haetaan vastaava lopetussulku */ sulkuja = 1; while (sulkuja) { ++kohta; if (ohjelma[kohta] == '[') { ++sulkuja; } else if (ohjelma[kohta] == ']') { --sulkuja; } } } break; case ']': if (*osoitin != 0) { /* Haetaan vastaava aloitussulku */ sulkuja = 1; while (sulkuja) { --kohta; if (ohjelma[kohta] == ']') { ++sulkuja; } else if (ohjelma[kohta] == '[') { --sulkuja; } } } break; } /* Koodin seuraavaan merkkiin */ ++kohta; } printf("\nLoppu.\n"); } void lopetusfunktio() { int i; if (tiedostolista) { for (i = 0; i < tiedostoja; ++i) { if (tiedostolista[i]) { free(tiedostolista[i]); } } free(tiedostolista); } if (ohjelma) { free(ohjelma); } if (tiedosto) { fclose(tiedosto); } }
saisko QB:lle, tai EXE:kin kelpaa...
Mulla se sulkeutuu samantien käynnistyksen jälkeen.
EDIT: No nyt suoritin sen ohjelman suoraan komentorivin avulla. Tässä lukee vaan että "Brainfuck-tulkki 0.1".
Kyllä siinä varmasti lukee myös sen käyttöohje. Et vain taida osata.
En mä ainakaan nää ruudulla mitään muuta kun vain että "Brainfuck-tulkki 0.1". Olen koklannut montaa eri tapaa, muutakun ei siihen DOS-ikkunaan tule muuta.
@k-piste:~/ohjelmointi$ i586-mingw32msvc-gcc bft.c -o bft.exe -O2 @k-piste:~/ohjelmointi$ wine bft.exe Brainfuck-tulkki 0.1 Toiminta: bft.exe tiedostot @k-piste:~/ohjelmointi$ wine bft.exe koe.txt Ajetaan 'koe.txt' Oho, toimi. :o Loppu.
Aivan uunituore käännös suoraan tuosta koodista.
mullaki toi ohjelma vaan vilahtaa.
Ajaisit komentoriviltä, kuten tekstiohjelmat kuuluu.
mutta se vain ilmoittaa:
Brainfuck-tulkki 0.1
Toiminta: C:\brainfuck\brainfuck.exe tiedostot
Koettakaa nyt tajuta, että se on tulkki, ei IDE! Se vain tulkkaa kooditiedoston, se ajetaan juuri tuon ohjeen mukaisesti. Koodin voi kirjoittaa vaikka Muistiolla.
joo sen tajusin muuta millä tiedostonimellä se tiedosto pitää oikeen tallentaa? en löydä sitä mistään tuolta koodista!
Tiedostonimi annetaan parametrina, kuten tuosta ohjeesta nähdäkseni varsin selvästi ilmenee ja kuten näkee tuossa aiemmassa kommentissani olevasta esimerkistä.
mikä kumma on parametri?
Kun tuollaista kyselet, niin brainfuck ei taida olla sinulle alkuunkaan oikea kieli. ^^
no kyllä nyt haluaisin silti tietää miten saan tuon toimimaan
Samalla tavallahan tuo toimii ku mikä tahansa muuki komentoriviohjelma.
Enkö juuri kehottanut katsomaan tuosta vähän ylempää?
Metabolix kirjoitti:
@k-piste:~/ohjelmointi$ wine bft.exe koe.txt Ajetaan 'koe.txt'
Selvästikin siis (käytännön syistä Linuxissa winellä) ajetaan bft.exe parametrilla koe.txt, tuloksena tulostuu teksti "Ajetaan 'koe.txt'". Voisiko tästä ehkä päätellä jotakin?
ai siis että sen tiedoston pitää olla koe.txt? miksi sitten kun laitoin sen nimeksi koe.txt heti aluksi ennen kuin edes kysyin täältä mitään niin se ei toiminut?
Tallenna se minun puolestani vaikka porkkanaksi ja aja "brainfuck porkkana".
On selvä esimerkki, selviä ohjeita ja Google. Et voinut mitenkään itse selvittää, miten komentoriviohjelma toimii ja mikä on parametri? Ja johan minäkin sen tuossa edellisessä selitin, tottahan sinä sen siitä osaat lukea?
#ohjelmointiputka@IRCnet kirjoitti:
23°08'42" <@Blaze> varmaan saa paljo irti brainfuckista, jos ei osaa edes ottaa selvää, miten komentoriviohjelmat toimii
mul tulee aina:
C:\Dev-Cpp>brainfuck.exe testi.txt
Virhe! Tiedostoa 'testi.txt' ei saatu luettua!
No kai sinulla on sellainen tiedosto ja oikeassa paikassa? Kyllä tuon pitäisi toimia, tarkistapa vielä...
:DDD hajoon aina ku luen tätä keskustelua tässä koodivinkissä. mikä ihme siinä on niin vaikeeta :D
Sitä minäkin ihmettelin. Siis mikä siin on niin vaikeeta? :P
Itse olisin arvostanut dynaamista muistia noissa muuttujissa. Lisäksi tuon koodin olisi voinut pilkkoa pienellä parserilla ennen tulkkausta, nostaisi nopeutta melkoisesti. Muuten ihan jees.
grandi kirjoitti:
Itse olisin arvostanut dynaamista muistia noissa muuttujissa.
Tarkoitatko muistitaulua? BF:n spekseissä (ainakin kaikissa löytämissäni versioissa) sanotaan, että muistia on 30000 tavua, joten näin tulkki toimii.
grandi kirjoitti:
Lisäksi tuon koodin olisi voinut pilkkoa pienellä parserilla ennen tulkkausta, nostaisi nopeutta melkoisesti.
Tietenkin voisi. Vinkin ei ole kuitenkaan tarkoitus olla valmis, huipputasoinen tulkki vaan yksinkertainen esimerkki ja erityisesti tuki BF-oppaalle. Sitäpaitsi et varmasti jaksa tehdä BF:llä niin isoa ohjelmaa, että sen suoritusnopeudella olisi oikeasti merkitystä. ;)
Olen kyllä aloittanut (ihan alkuun vain) joskus myös BF-kääntäjän, joka jäsentää koodin ja tuottaa siitä aavistuksen optimaalisempaa C:tä. Se voi muuttaa esimerkiksi pätkän "+>+++>++>-<<<+++" seuraavaan muotoon:
p[0] += 4; p[1] += 3; p[2] += 2; p[3] -= 1;
teppuli kirjoitti:
mul tulee aina:
C:\Dev-Cpp>brainfuck.exe testi.txt
Virhe! Tiedostoa 'testi.txt' ei saatu luettua!
Itse kohtasin täsmälleen saman ongelman: jos lähdekooditiedosto oli tyhjä tekstitiedosto tai sisälsi yhdenkin rivivaihdon, sain saman virheilmoituksen kuin teppuli. Yhden rivin tiedostot toimivat hyvin. Voisiko ongelma olla tekstitiedoston merkistössä?
No, google löysi minulle toisen tulkin jonka kanssa ongelmaa ei esiintynyt, joten en alkanut pulman kanssa enempää voimistelemaan.
Aihe on jo aika vanha, joten et voi enää vastata siihen.