Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (WinAPI, Konsole) » Brainfuck - Interpreter

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 < [ 2 ]
000
18.02.2007, 13:10 Uhr
Suba Esel



Ich schreib grad an einem Brainfuck - Compiler in C++, hab aber keinen blassen Schimmer, wie ich Schleifen machen soll.


C++:
#include <iostream>
#include <fstream>
#include <vector>

void Ausfuehren(std::vector<std::string> brainfuck);

int main()
{
    std::cout << "Brainfuck - Compiler\nFreeware" << std::endl;

    std::vector<std::string> programm;
    std::string temp;
    std::getline(std::cin, temp);
    programm.push_back(temp);
    Ausfuehren(programm);
}

void Ausfuehren(std::vector<std::string> brainfuck)
{
    int p[10000];
    int *current_value = &p[0];

    for(int i = 0; i < brainfuck.size(); ++i)
    {
        for(int j = 0; j < brainfuck[i].size(); ++j)
        {
            std::string zeile = brainfuck[i];
            switch(zeile[j])
            {
                case '>':
                ++current_value;
                break;

                case '<':
                --current_value;
                break;

                case '+':
                *current_value+=1;
                break;

                case '-':
                *current_value-=1;
                break;

                case '.':
                std::cout << char(*current_value);
                break;

                case ',':
                *current_value = getchar();
                break;

                case '[':
                // und jetzt?
            }
        }
    }
}




Testprogramm ohne Schleifen:

Code:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++.>++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++.+++++++..+++.>++++++++++++++++++++++++++++++++.<<+
++++++++++++++.>.+++.------.--------.>+.>++++++++++.




Testprogramm mit Schleifen:

Code:
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..++
+.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.



Die Programme geben beide "Hello World!" aus.

Ach ja, falls noch jemand ne Möglichkeit weiß, wie man die Eingabe auf ein Zeichen beschränken kann, wäre ich sehr dankbar, da das ganze ein array ist, wird sonst nämlich einfach in die nächsten Zellen geschrieben.
An sowas wie std::cin.width(1); std::cin >> *current_value; hab ich schon gedacht, allerdings lässt sich das cin, warum auch immer, so nicht anwenden.

Ach ja, noch was: gibts eine möglichkeit, wie man in der Konsole formatierten Text, also mit Zeilenumbrüchen, eingeben kann? Die werden ja sonst als "Enter" interpretiert, deshalb kann man das Programm oben auch so nicht einfügen.


Bearbeitung:

hab mir mal erlaubt den Threadtopic anzupassen


--
Simon

Dieser Post wurde am 21.02.2007 um 17:56 Uhr von FloSoft editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
18.02.2007, 14:13 Uhr
xxChillerzz




Zitat von Suba Esel:
Ach ja, falls noch jemand ne Möglichkeit weiß, wie man die Eingabe auf ein Zeichen beschränken kann, wäre ich sehr dankbar, da das ganze ein array ist, wird sonst nämlich einfach in die nächsten Zellen geschrieben.


Benutze die Funktion strlen aus der H <string.h>
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
18.02.2007, 14:20 Uhr
Blubber2063



Das was du da bastelst wird vermutlich eher ein Interpreter sein, denn du generierst ja keinen Code, wenn du Code generieren würdest, dann wären schleifen recht einfach, da es ja nur ein bedingter Sprung zur Schleifenstartadrese wäre. Was du brauchst, ist ein Stack. Auf dem legst du dann immer die Stelle des "[" ab. Wenn du dann auf eine "]" stößt, wirst du entweder zum obersten Stack Element zurückspringen(>0) oder aber du nimmst das oberste Element vom Stack und marschierst normal weiter.

Welche Eingabe willst du begrenzen und wieso ?

Achja und ein Intpreter ist für einen Anfänger schon recht happig, vor allem wenn man die Konzepte dafür nicht kennt. Allerdings ist Brainfuck ja recht simpel(Parsingtechnisch).

Dieser Post wurde am 18.02.2007 um 14:21 Uhr von Blubber2063 editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
18.02.2007, 15:07 Uhr
Suba Esel



@ xxChillerzz: gibt strlen nicht einfach nur die Länge des Strings zurück?

@ Blubber2063:
Was du jetzt mit der Schleife meintest, hab ich nur so halb verstanden, ich hatte mir das bis jetzt so gedacht:
Wenn der auf "[" stößt, lädt der alles bis zum nächsten "]" in einen temp - string und versucht den dann auszuführen, solange die aktuelle Zelle >0 ist, das klappt aber noch nicht so ganz. Außerdem war das nicht meine Idee, einer aus meiner Klasse (der ist ein bisschen irre) will partout BF programmieren und ich darf ihm den Interpreter schreiben
Naja egal, so hab ich wenigstens ne Programmieraufgabe
Mit Eingabe mein ich den Befehl ",": wenn ich meinetwegen in p[10] einlesen will und der User zwei Buchstaben eingibt wird in p[10] und in p[11] geschrieben, dass ist das Problem.
Oder meintest du die Konsoleneingabe? Wenn man jetzt ein BF - Programm hat und das da einfügt, sind da wahrscheinlich Zeilenumbrüche bei --> Fehler.
--
Simon
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
18.02.2007, 17:12 Uhr
Suba Esel



So, hab jetzt einen neuen Ansatz - funktioniert aber noch immer nicht

In der clrscr.hpp ist FloSofts clrscr() - Funktion.


C++:
#include <iostream>
#include <fstream>
#include <vector>
#include "clrscr.hpp"

void Aufteilen(std::vector<std::string> brainfuck);
void Ausfuehren(std::string temp);
int p[10000];
int *current_value = &p[0];

int main()
{
    std::cout << "Brainfuck - Compiler\nFreeware" << std::endl;
    std::cin.get();

    std::vector<std::string> programm;

    while(true)
    {
        clrscr();
        std::cout << "Welche Datei soll compiliert werden?" << std::endl;
        std::string eingabe;
        std::getline(std::cin, eingabe);
        clrscr();

        std::ifstream in(eingabe.c_str());

        if(in)
        {
            while(!in.eof())
            {
                std::string temp;
                std::getline(in,temp);
                programm.push_back(temp);
            }
            break;
        }
        else
        {
            std::cout << "Die Datei \"" << eingabe << "\" existiert nicht." << std::endl;
            std::cin.get();
        }
    }
    Aufteilen(programm);
    std::cin.sync();
    std::cin.get();
}

void Aufteilen(std::vector<std::string> brainfuck)
{
    for(int i = 0; i < brainfuck.size(); ++i)
    {
        Ausfuehren(brainfuck[i]);
    }
}


void Ausfuehren(std::string temp)
{
    for(int i = 0; i < temp.size(); ++i)
    {
        switch(temp[i])
        {
            case '>':
            ++current_value;
            break;

            case '<':
            --current_value;
            break;

            case '+':
            *current_value+=1;
            break;

            case '-':
            *current_value-=1;
            break;

            case '.':
            std::cout << char(*current_value);
            break;

            case ',':
            *current_value = getchar();
            break;

            case '[':
            ++*current_value;
            std::string part_of_part = "";
            while(++*current_value != ']')
            {
                part_of_part+=*current_value;
            }
            while(*current_value)
            {
                Ausfuehren(part_of_part);
            }
            break;
        }
    }
}


--
Simon
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
18.02.2007, 17:42 Uhr
Blubber2063



Ohne das jetzt mit 100% Sicherheit zu sagen, aber dein Grundproblem ist, das du keine Lexikalische Analyse fährst. Oder ums mal verständlicher Auszudrücken, was du machs ist Zeilenweise zu arbeiten, die Zeilen existieren aber nur für den User zum lesen. Daher wäre es vielleicht besser alles in einen std::string zu packen. Bzw der Effizienz wegen das ganze über nen Stringstream zu realisieren. Du scheiterst hier daran das, dass Ende der Schleife in der nächsten Zeile stehen könnte.

Daher nimm dir einen Stack, für die Schleifen(Falls du nicht weisst was ein Stack ist mach dich mal schlau).
Als Stack kannst du eine Liste benutzen.





C++:
void Ausfuehren(std::string temp)
{
    std::list<int> stack;
    in klc;
    for(int i = 0; i < temp.size(); ++i)
    {
        switch(temp[i])
        {
            case '>':
            ++current_value;
            break;

            case '<':
            --current_value;
            break;

            case '+':
            *current_value+=1;
            break;

            case '-':
            *current_value-=1;
            break;

            case '.':
            std::cout << char(*current_value);
            break;

            case ',':
            *current_value = getchar();
            break;

            case '[':
            if (*current_value != 0)
              stack.push_back(i);
            else{
             klc = 0;
              while(temp[i] != ']' && klc == 0 ){
                if (temp[i] == '[')
                  klc++;
                if (temp[i] == ']')
                  klc--;
                i++;
              }
            }
            break;
            
            case ']':
            if (*current_value != 0)
              i = stack.back();
            else
              stack.pop_back();
        }
    }
}


Aber denk dran das setzt vorraus das du den ganzen Code in string Variable übergibst.
Und es ist wesentlich effizienter als den String für die Klammern zu kopieren und funktioniert für beliebig viele Klammern.

Das sollte jetzt auch Schleifen können, beachte aber dein Brainfuck Interpreter ist nicht Fehlertollerant. D.h. du parst den Code nicht(Zahl der öffnenden Klammern = Zahl der schließenden Klammern) und nicht so das sowas bei rauskommt ][.

Und dann solltest du schon nachprüfen ob die Index Grenzen deines Arrays eingehalten werden. Schließlich sollte der einzige Fall wenn ein Interpreter "abstürtzt" der Fall nicht terminierender Rekursion sein.

Aber wie gesagt ist halt Flickenschusterei, eigentlich müsstest du das Programm parsen, einen abstrakten Syntaxbaum draus bauen und den dann evaluieren. Ohne Parsing ist das halt unfein.

Dieser Post wurde am 18.02.2007 um 17:59 Uhr von Blubber2063 editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
20.02.2007, 17:48 Uhr
Suba Esel



Sorry, aber ich kapier ehrlich gesagt überhaupt nicht, was dein Programm macht. Der Stack ist doch im Prinzip ein für das Prog reservierter Speicher, oder? Ist list ~ vector?

Zitat:
eigentlich müsstest du das Programm parsen, einen abstrakten Syntaxbaum draus bauen und den dann evaluieren

was heißt das auf Deutsch? Parsen scheint ja zu sein, dass Anzah l"[" gleich Anzahl "]", aber der Rest....^^

Ich hab mir das jetzt so überlegt, hab aber noch irgendwo einen (Denk?)fehler drin:


C++:
void Verketten(std::vector<std::string> brainfuck)
{
    std::string temp = "";
    for(int i = 0; i < brainfuck.size(); ++i)
    {
        temp += brainfuck[i];
    }
    Ausfuehren(temp);
}
.
.
.
case '[':
            std::string part_of_part = "";
            for(int j = i+1; prgm[j] != ']';++j)
            {
                part_of_part += prgm[j];
            }
            while(*current_value)
            {
            Ausfuehren(part_of_part);
            }
            break;


--
Simon

Dieser Post wurde am 20.02.2007 um 17:49 Uhr von Suba Esel editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
20.02.2007, 18:59 Uhr
J-jayz-Z
Perl Crack ala Carte
(Operator)


Das funktioniert in etwa so:
Du liest das Programm ein (ohne etwas damit zu machen) und schaust dir an, ob es syntaktisch korrekt ist. Wenn du eine bestimmte Syntaxart erkennt (wie zum beispiel [] für eine Schleife) merkst du dir den content der schleife. Diesen parst du wieder. Daraus entsteht dann beispielsweise ein


Code:
main
|
--Schleife
    |
     --- Schleife
    |    |
    |     --- Output
    |
     --- Output



Es ist sehr unschön gleich beim einlesen eine Aktion auszuführen. Erst einlesen, dann auswerten, dann ausführen oder eben Fehlermeldung ausgeben.
--
perl -Mstrict -Mwarnings -e 'package blub; sub new { bless {} } sub bar {my $self=shift; $self->{bla}="66756e2d736f66742e6465"; return $self->{bla};} my $foo=blub->new();print "Hallo ";print pack("H*",$foo->bar()); print "\n"'
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
20.02.2007, 23:04 Uhr
Blubber2063



Grundsätzlich ist der Stack ein Stapelspeicher der nach dem LIFO Prinzip arbeitet(LastInFirstOut).

Ein Programm arbeitet unter den meisten Architekturen mit einem Stack für Unterprogrammeaufrufe. Das ist allerdings nichts weiter als ein Zeiger auf Speicher der dann passend verschoben und mit Inhalten gefüllt wird. Dieser wird normalerweise vom Betriebsystem für jeden Prozess angelegt.

Man verwendet die Datenstruktur des Stacks aber auch in hohen Programmiersprachen, da er ein recht nützliches Konzept darstellt.

Eine liste ist kein Vector, der Unterschied:

Ein Vektor ist ein Array der dynamisch wächst, falls seine Kapazität überschritten wird:
Vorteil:
schneller Elementzugriff über relative Adressierung.
Nachteil:
beim vergrößern wird meist der Inhalt des Vectors in einen neuen Array copiert -> sehr Zeitaufwendig.
Eine Liste, ist eine Verkettung von Elementen. Beispiel:
a -> b -> c -> d
wobei hier immer in jedem Element ein Zeiger auf das nächste Steht.
Vorteil: Speicher muss nicht zusammenhängend sein, also nur durch die Kapazität des zur verfügung stehenden Speichers begrenzt.
Nachteil:
Elementzugriff(Suche) verbraucht im Schnitt n schritte, wobei n die Anzahl der Elemente in der Liste ist.

Du kannst also theoretisch auch einen Vektor für den Stack nehmen, da man sich bei einem Stack normalerweise aber nur für das erste oder letzte Element interessiert ist die Liste hier durchaus besser geeignet.

Zum Parser ist nach J-jayz-Z Ausführungen nur noch anzumerken, das Parser sich nach Grammattiken richten(formale Beschreibung einer Sprache), für Programmiersprachen werden normalerweise Kontextfreie Grammatiken benutzt und draus resultierende Parser.
Falls dich der Themenkomplex interssiert hier ein paar Stichworte die du mal googeln kannst.
Chomsky Hierarchie
LL 1 Grammatik
Rekursive Decent Parser
Kontextfreie Grammatiken
Reguläre Grammattiken
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
21.02.2007, 17:51 Uhr
Suba Esel



Ich hab das jetzt wie folgt geschafft:


C++:
while(*current_value)
{
Ausfuehren(part_of_part);
}
[b]i = j;[/b]
break;



Damit funktionierts tadellos.
--
Simon

Dieser Post wurde am 21.02.2007 um 17:52 Uhr von Suba Esel editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 < [ 2 ]     [ C / C++ (WinAPI, Konsole) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: