c++interpretervclc++builder-6brainfuck

Brainfuck interpreter strange output


I've decided to write a simple Brainfuck IDE in C++ using Borland's CppBuilder6. I've put on my for a RichEdit and made it look somewhat like notepad. Then I've added TEdit for input and TMemo for output. After some tests, I thought that RichEdit is bad component to use in my case and I changed it to TMemo.

In my code input = Edit2, code = Memo2, output = Memo1. I rewrote it two times and this version seems most correct; I've decided to not use pointers (i thought about it and even wrote pointer version, unfortunately it didn't work too so for simplifying I've removed pointers).

char *cells = (char*)calloc(65536,1); //Should i use malloc?
int cellp = 0;
void __fastcall BFIde::interpret() {
        char* pf = Memo2->Lines->Text.c_str(); //Weird output
        char* p = (char*)malloc(strlen(pf)+1);
        strcpy(p, pf); //Because pf is constant, i need to copy it into not constant string.
        int pp = 0;

        MessageBox(NULL,p,NULL,MB_OK); //To ensure that program is correct, but it ain't.

        while(p[pp]){
                switch(p[pp]){
                        case '>':
                                cellp++;
                                break;
                        case '<':
                                cellp--;
                                break;
                        case '+':
                                MessageBox(NULL, "Plus", NULL, MB_OK); //When executing test code, never gets shown.
                                cells[cellp]++;
                                break;
                        case '-':
                                cells[cellp]--;
                                break;
                        case '.':{ //It should look other, but I've replaced it to ensure that output is correct.
                                char arr[2]={cells[cellp],0};MessageBox(NULL, arr, NULL, MB_OK);}
                                break;
                        case ',': //Remove first character and pass it to program
                                if(Edit2->Text == "")cells[cellp] = 0;
                                else {cells[cellp] = Edit2->Text.c_str()[0];char* str;strcpy(str, Edit2->Text.c_str());Edit2->Text=str++;}
                                break;
                        case '[':{ //Propably works.
                                int bal = 1;
                                if (cells[cellp] == '\0') {
                                        do {
                                                pp++;
                                                if      (p[pp] == '[') bal++;
                                                else if (p[pp] == ']') bal--;
                                        } while ( bal != 0 );
                                }
                                break;
                        }
                        case ']':
                                int bal2 = 0;
                                do {
                                        if      (p[pp] == '[') bal2++;
                                        else if (p[pp] == ']') bal2--;
                                        pp--;
                                } while ( bal2 != 0 );
                                break;
                }
                pp++;
        }
        MessageBox(NULL, IntToStr(cellp).c_str(), NULL, MB_OK); //To check that something was parsed. Shows 0 everytime (not expected).
}

When i enter some code, eg. "+." and execute this function (via button), this shows series of messagebox. First: (line 8), second: 0 (line 55), and nothing more shows. Expected result was to write: First +., second Plus, and empty 3rd. What I've made wrong in my code? Maybe I've missed something.


Solution

  • There are memory-related errors in your code. The very first line of interpret() is taking a pointer to a temporary AnsiString that is freed immediately afterwards, so the subsequent lines of code are operating with a dangling pointer to invalid memory. Likewise, in your ',' handler, you are trying to copy data to an uninitialized pointer that is not pointing at valid memory. And you are not doing any bounds checking when accessing your cells[] array.

    There are also logic errors in your ']' handler. You are not checking the current cell data for 0 to decide which instruction to jump to next, and you are not seeking backwards correctly when looking for the opening '['.

    Try something more like this instead:

    static const int maxCells = 65536;
    
    class BFIde : public TForm
    {
    __published:
        TEdit *Edit2;
        TMemo *Memo1;
        TMemo *Memo2;
        TButton *Button1;
        void __fastcall Button1(TObject *Sender);
    private:
        char cells[maxCells];
        int cellp;
        char& cellData();
        void __fastcall interpret(const AnsiString &commands, AnsiString input);
    public:
        __fastcall BFIde(TComponent *Owner);
    };
    

    __fastcall BFIde::BFIde(TComponent *Owner)
        : TForm(Owner)
    {
    }
    
    char& __fastcall BFIde::cellData()
    {
        if ((cellp < 0) or (cellp >= maxCells))
            throw Exception("Accessing cells out of bounds");
        return cells[cellp];
    }
    
    void __fastcall BFIde::interpret(const AnsiString &commands, AnsiString input)
    {
        Memo1->Clear();
    
        memset(cells, 0, maxCells);
        cellp = 0;
    
        const char* start = commands.c_str();
        const char* p = start;
    
        while (*p)
        {
            switch (*p)
            {
                case '>':
                    ++cellp;
                    break;
    
                case '<':
                    --cellp;
                    break;
    
                case '+':
                    cellData()++;
                    break;
    
                case '-':
                    cellData()--;
                    break;
    
                case '.':
                {
                    char ch = cellData();
                    Memo1->SelStart = Memo1->GetTextLen();
                    Memo1->SelLength = 0;
                    Memo1->SelText = ch;
                    break;
                }
    
                case ',':
                {
                    char ch;
                    if (input.Length() == 0) {
                        ch = '\0';
                    }
                    else {
                        ch = input[1];
                        input.Delete(1, 1);
                    }
                    cellData() = ch;
                    break;
                }
    
                case '[':
                {
                    if (cellData() == '\0')
                    {
                        int bal = 1;
                        while (*++p)
                        {
                            if (*p == '[') {
                                ++bal;
                            }
                            else if (*p == ']')
                            {
                                if (--bal == 0)
                                    break;
                            }
                        }
                        if (bal != 0)
                            throw Exception("Unbalanced loop");
                    }
                    break;
                }
    
                case ']':
                {
                    if (cellData() != '\0')
                    {
                        int bal = 1;
                        while (p > start)
                        {
                            --p;
                            if (*p == ']') {
                                ++bal;
                            }
                            else if (*p == '[')
                            {
                                if (--bal == 0)
                                    break;
                            }
                        }
                        if (bal != 0)
                            throw Exception("Unbalanced loop");
                    }
                    break;
                }
            }
    
            ++p;
        }
    
        ShowMessage(cellp);
    }
    
    void __fastcall BFIde::Button1(TObject *Sender)
    {
        interpret(Memo2->Lines->Text,  Edit2->Text);
    }