• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Interpreter brainfucka w C++

Object Storage Arubacloud
+5 głosów
846 wizyt
pytanie zadane 12 września 2015 w Nasze projekty przez Radfler VIP (101,030 p.)
edycja 21 kwietnia 2018 przez Radfler

Witam! Jakiś czas temu wpadł mi do głowy pomysł napisania interpretera jakiegoś języka. Wybrałem brainfucka, gdyż uznałem go za w miarę prostego (jak mogłoby się wydawać) i łatwego do zrozumienia. Kilka informacji na jego temat:

1. Jest napisany obiektowo (klasa brainfuck::interpreter/brainfuck::brainfuck_interpreter),

2. Obsługuje on wszystkie 8 podstawowych instrukcji: '>', '<', '+', '-', ',', '.', '[' oraz ']',

3. Wspiera on zagnieżdżone pętle (wiele amatorskich interpreterów tego nie obsługuje),

4. Udostępnia (mam nadzieję) przyjemny interfejs do obsługi błędów (klasa brainfuck::brainfuck_error oraz kody błędów brainfuck::brainfuck_errc).

Jakiś przykładzik (powinien działać, na razie nie mam możliwości weryfikacji):

#include <brainfuck>
#include <iostream>

int main() {
  brainfuck::interpreter interpreter("++."); // wyświetli '\002'
  interpreter.set_ostream(std::cout);
  interpreter.set_istream(std::cin);
  try {
    interpreter.execute();
  } catch(brainfuck::brainfuck_error& e) {
    std::clog << "what() -> " << e.what() << std::endl
              << "code() -> " << e.code() << std::endl;
  }
}

Kod: [[brak]]

Dodam, że kompletnie nie znam się na budowie interpreterów, projekt ten robiłem "na czuja".

3 odpowiedzi

+2 głosów
odpowiedź 12 września 2015 przez adrian17 Ekspert (344,860 p.)
edycja 12 września 2015 przez adrian17

Drobne uwagi:

#if __cplusplus < 201103L

MSVC15 i najpewniej też 13 implementuje wszystkie potrzebne dla tego projektu funkcjonalności C++11, ale z grzeczności nie chcą podbić tego makra do 201103L póki nie osiągną 100% zgodności. Z tym ifem projekt się nie skompiluje na VS.

this_pointer_type array = this->__this_pointer = new cell_type[30000] { };
...
delete[] array;

To powinno być raczej w konstruktorze/destruktorze, żeby user mógł sam zdecydować ile chce poświęcić miejsca. No i żeby w przypadku wyjątku klasa porządnie po sobie posprzątała. Edit: a najlepiej użyj std::vector.

"this->" jest praktycznie wszędzie niepotrzebne.

Nazwy zaczynające się od __ są zarezerwowane dla implementacji języka, nie powinno się więc ich używać. (Osobiście w ogóle bym nie oznaczał nazw pól prywatnych w żaden sposób, ale to kwestia gustu.) To samo z makrami.

typedef typename std::string::iterator __code_iterator;

MSVC wyrzuca tu błąd "typename cannot be used outside a template declaration". Wyrzucenie typename albo zamiana typedefa na using rozwiązuje problem. GCC i Clang nie mają problemu z tym kodem, ale nie mam pojęcia która strona ma rację.

istream_type& old = *this->__is;

Tutaj dereferencja wskaźnika nullptr jest nielegalna i skutkuje niezdefiniowanym zachowaniem. Niestety nie widzę by którakolwiek diagnostyka to wykrywała i jest to praktycznie niezauważalny bug. Przy okazji, po co w ogóle chcesz zwracać ten strumień? Ta klasa i tak nie jest jego właścicielem, więc gdyby kiedykolwiek była potrzeba, można zakładać że można go uzyskać od prawdziwego właściciela.

  : __is(nullptr), __os(nullptr) { }

Użyj inicjalizacji pól, będzie mniej duplikacji kodu w konstruktorach:

        istream_type* __is = nullptr;
        ostream_type* __os = nullptr;
typedef std::istream istream_type;

To jest moim zdaniem przesada, ale jak chcesz.

interpreter.h też powinien się znajdować w folderze include/.

A, i nigdy nie widziałem by ktoś robił wcięcie kodu po #ifndef w nagłówkach.

komentarz 12 września 2015 przez Radfler VIP (101,030 p.)

1. Nie używam MSVC, nie wiedziałem o tym :v

2. Jeżeli chodzi o to

this_pointer_type array = this->__this_pointer = new cell_type[30000] { };
...
delete[] array;

to raczej tak to zostawię. W dokumentacji wyczytałem (http://www.muppetlabs.com/~breadbox/bf/), że tablica powinna mieć rozmiar 30000 bajtów.

3. Preferuję stosowanie 'this->' ;)

4. Wolę oznaczać pola prywatne jakimś prefixem (taki zwyczaj), a co do '__' to coś się domyślałem, ale dziękuję za informację.

5. Z tego co wiem używanie typename jest w takim przypadku legalne (tu akurat nie musiałem go używać) http://en.cppreference.com/w/cpp/language/dependent_name.

6. Tu rzeczywiście tego błędu nie zauważyłem. I w sumie teraz trochę to przemyślełem zwracanie strumienia to trochę bezsensowny pomysł >.<

7. No nie pomyślałem o tym, nie za często korzystam z tej możliwości (http://en.cppreference.com/w/cpp/language/data_members),

8. Przecież 'interpreter.h' jest w 'include/'?

9. A wcięcia zacząłem robić od jakiegoś czasu (taki eksperyment).

Dziękuję za komentarz ;)

komentarz 12 września 2015 przez adrian17 Ekspert (344,860 p.)
edycja 12 września 2015 przez adrian17
2. Co nie zmienia faktu, że lepszym miejscem na to jest konstruktor/destruktor. Przy okazji nie będzie wtedy trzeba wielokrotnie alokować pamięci gdyby ktoś chciał uruchomić ten sam interpreter kilka razy - wystarczy ją wyzerować przed użyciem.

3, 4. Jak chcesz.

5. Masz na myśli "The keyword typename can be used even outside of templates."? To faktycznie, wina MSVC. W wolnym czasie z ciekawości poszukam w ich issue trackerze czy to znany problem, pewnie tak ale kto wie.

Edit: o, chyba nawet znalazłem odpowiedni zapis w standardzie.

8. Ups, miałem na myśli brainfuck.h.

9. Te wcięcia wiele sensu nie mają głównie dlatego, że i tak wiadomo że cały kod poza tymi trzema liniami preprocesora byłby wcięty, to po co to robić?
+1 głos
odpowiedź 12 września 2015 przez hit02 Nałogowiec (33,970 p.)

Hah. Rzeczywiście, brainfuck jest bardzo prostym językiem. Sam kiedyś zrobiłem interpreter, a następnie kompilator oczywiście z obsługą zagnieżdżonych pętli i ewentualnego braku nawiasu domykającego. cheeky

Dosyć ciekawe jest to, że ten język bardzo wspomaga w poznaniu zasad tworzenia właśnie takich narzędzi, jak interpretery i kompilatory. smiley

0 głosów
odpowiedź 12 września 2015 przez Magicone Nałogowiec (45,100 p.)
Gdzie są testy ja sie pytam? BTW. zrobione wczoraj: https://github.com/magic96/BFI

Podobne pytania

0 głosów
1 odpowiedź 155 wizyt
pytanie zadane 4 czerwca 2016 w C i C++ przez C☺ndzi Stary wyjadacz (12,100 p.)
+1 głos
1 odpowiedź 163 wizyt
pytanie zadane 20 kwietnia 2016 w C i C++ przez polewa Nowicjusz (230 p.)
0 głosów
0 odpowiedzi 127 wizyt
pytanie zadane 26 lipca 2023 w Offtop przez reaktywny Nałogowiec (40,990 p.)

92,576 zapytań

141,426 odpowiedzi

319,651 komentarzy

61,961 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...