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] == '') {
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.
c++ interpreter vcl c++builder-6 brainfuck
|
show 1 more comment
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] == '') {
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.
c++ interpreter vcl c++builder-6 brainfuck
2
And what have you done so far to debug this yourself? StackOverflow is not a debugging service. You have an expected result, so step through your code with the debugger until it deviates from that expectation, and then you can figure out why it deviates. But I can tell you right now, your overzealous use ofText.c_str()
is very wrong, but especially the first one:char* pf = Memo2->Lines->Text.c_str(); char* p = (char*)malloc(strlen(pf)+1); strcpy(p, pf);
. Why do you think that is wrong? I will give you a hint - it has UNDEFINED BEHAVIOR!
– Remy Lebeau
Apr 25 '17 at 0:19
@RemyLebeau Have you ever used c++builder6 debugger?
– Krzysztof Szewczyk
Apr 25 '17 at 15:08
All the time. BCB6 is the compiler I have to use at my day job :-( But the issue you describe is not limited to just BCB6. You have errors in your code, so it would be broken in any compiler version.
– Remy Lebeau
Apr 25 '17 at 15:11
bcb6 debugger shown me error at end of caller procedure.
– Krzysztof Szewczyk
Apr 25 '17 at 15:19
There are errors in your code, starting with the very first line of yourinterpret()
function. Do you understand WHY that line of code is faulty? You are taking a pointer to temporary data that gets freed immediately after you take the pointer, so the subsequent lines of code are operating on invalid memory. There is another memory error in your','
handler - you are trying to copying data to an uninitialized pointer that is not pointing at valid memory.
– Remy Lebeau
Apr 25 '17 at 15:33
|
show 1 more comment
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] == '') {
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.
c++ interpreter vcl c++builder-6 brainfuck
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] == '') {
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.
c++ interpreter vcl c++builder-6 brainfuck
c++ interpreter vcl c++builder-6 brainfuck
edited Nov 22 '18 at 18:42
Zoe
11.4k74278
11.4k74278
asked Apr 22 '17 at 10:57
Krzysztof SzewczykKrzysztof Szewczyk
646627
646627
2
And what have you done so far to debug this yourself? StackOverflow is not a debugging service. You have an expected result, so step through your code with the debugger until it deviates from that expectation, and then you can figure out why it deviates. But I can tell you right now, your overzealous use ofText.c_str()
is very wrong, but especially the first one:char* pf = Memo2->Lines->Text.c_str(); char* p = (char*)malloc(strlen(pf)+1); strcpy(p, pf);
. Why do you think that is wrong? I will give you a hint - it has UNDEFINED BEHAVIOR!
– Remy Lebeau
Apr 25 '17 at 0:19
@RemyLebeau Have you ever used c++builder6 debugger?
– Krzysztof Szewczyk
Apr 25 '17 at 15:08
All the time. BCB6 is the compiler I have to use at my day job :-( But the issue you describe is not limited to just BCB6. You have errors in your code, so it would be broken in any compiler version.
– Remy Lebeau
Apr 25 '17 at 15:11
bcb6 debugger shown me error at end of caller procedure.
– Krzysztof Szewczyk
Apr 25 '17 at 15:19
There are errors in your code, starting with the very first line of yourinterpret()
function. Do you understand WHY that line of code is faulty? You are taking a pointer to temporary data that gets freed immediately after you take the pointer, so the subsequent lines of code are operating on invalid memory. There is another memory error in your','
handler - you are trying to copying data to an uninitialized pointer that is not pointing at valid memory.
– Remy Lebeau
Apr 25 '17 at 15:33
|
show 1 more comment
2
And what have you done so far to debug this yourself? StackOverflow is not a debugging service. You have an expected result, so step through your code with the debugger until it deviates from that expectation, and then you can figure out why it deviates. But I can tell you right now, your overzealous use ofText.c_str()
is very wrong, but especially the first one:char* pf = Memo2->Lines->Text.c_str(); char* p = (char*)malloc(strlen(pf)+1); strcpy(p, pf);
. Why do you think that is wrong? I will give you a hint - it has UNDEFINED BEHAVIOR!
– Remy Lebeau
Apr 25 '17 at 0:19
@RemyLebeau Have you ever used c++builder6 debugger?
– Krzysztof Szewczyk
Apr 25 '17 at 15:08
All the time. BCB6 is the compiler I have to use at my day job :-( But the issue you describe is not limited to just BCB6. You have errors in your code, so it would be broken in any compiler version.
– Remy Lebeau
Apr 25 '17 at 15:11
bcb6 debugger shown me error at end of caller procedure.
– Krzysztof Szewczyk
Apr 25 '17 at 15:19
There are errors in your code, starting with the very first line of yourinterpret()
function. Do you understand WHY that line of code is faulty? You are taking a pointer to temporary data that gets freed immediately after you take the pointer, so the subsequent lines of code are operating on invalid memory. There is another memory error in your','
handler - you are trying to copying data to an uninitialized pointer that is not pointing at valid memory.
– Remy Lebeau
Apr 25 '17 at 15:33
2
2
And what have you done so far to debug this yourself? StackOverflow is not a debugging service. You have an expected result, so step through your code with the debugger until it deviates from that expectation, and then you can figure out why it deviates. But I can tell you right now, your overzealous use of
Text.c_str()
is very wrong, but especially the first one: char* pf = Memo2->Lines->Text.c_str(); char* p = (char*)malloc(strlen(pf)+1); strcpy(p, pf);
. Why do you think that is wrong? I will give you a hint - it has UNDEFINED BEHAVIOR!– Remy Lebeau
Apr 25 '17 at 0:19
And what have you done so far to debug this yourself? StackOverflow is not a debugging service. You have an expected result, so step through your code with the debugger until it deviates from that expectation, and then you can figure out why it deviates. But I can tell you right now, your overzealous use of
Text.c_str()
is very wrong, but especially the first one: char* pf = Memo2->Lines->Text.c_str(); char* p = (char*)malloc(strlen(pf)+1); strcpy(p, pf);
. Why do you think that is wrong? I will give you a hint - it has UNDEFINED BEHAVIOR!– Remy Lebeau
Apr 25 '17 at 0:19
@RemyLebeau Have you ever used c++builder6 debugger?
– Krzysztof Szewczyk
Apr 25 '17 at 15:08
@RemyLebeau Have you ever used c++builder6 debugger?
– Krzysztof Szewczyk
Apr 25 '17 at 15:08
All the time. BCB6 is the compiler I have to use at my day job :-( But the issue you describe is not limited to just BCB6. You have errors in your code, so it would be broken in any compiler version.
– Remy Lebeau
Apr 25 '17 at 15:11
All the time. BCB6 is the compiler I have to use at my day job :-( But the issue you describe is not limited to just BCB6. You have errors in your code, so it would be broken in any compiler version.
– Remy Lebeau
Apr 25 '17 at 15:11
bcb6 debugger shown me error at end of caller procedure.
– Krzysztof Szewczyk
Apr 25 '17 at 15:19
bcb6 debugger shown me error at end of caller procedure.
– Krzysztof Szewczyk
Apr 25 '17 at 15:19
There are errors in your code, starting with the very first line of your
interpret()
function. Do you understand WHY that line of code is faulty? You are taking a pointer to temporary data that gets freed immediately after you take the pointer, so the subsequent lines of code are operating on invalid memory. There is another memory error in your ','
handler - you are trying to copying data to an uninitialized pointer that is not pointing at valid memory.– Remy Lebeau
Apr 25 '17 at 15:33
There are errors in your code, starting with the very first line of your
interpret()
function. Do you understand WHY that line of code is faulty? You are taking a pointer to temporary data that gets freed immediately after you take the pointer, so the subsequent lines of code are operating on invalid memory. There is another memory error in your ','
handler - you are trying to copying data to an uninitialized pointer that is not pointing at valid memory.– Remy Lebeau
Apr 25 '17 at 15:33
|
show 1 more comment
1 Answer
1
active
oldest
votes
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 = '';
}
else {
ch = input[1];
input.Delete(1, 1);
}
cellData() = ch;
break;
}
case '[':
{
if (cellData() == '')
{
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() != '')
{
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);
}
I didn't know about GetTextLen(), your code is ok. Thank you very much.
– Krzysztof Szewczyk
Apr 26 '17 at 14:00
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f43558399%2fbrainfuck-interpreter-strange-output%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
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 = '';
}
else {
ch = input[1];
input.Delete(1, 1);
}
cellData() = ch;
break;
}
case '[':
{
if (cellData() == '')
{
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() != '')
{
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);
}
I didn't know about GetTextLen(), your code is ok. Thank you very much.
– Krzysztof Szewczyk
Apr 26 '17 at 14:00
add a comment |
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 = '';
}
else {
ch = input[1];
input.Delete(1, 1);
}
cellData() = ch;
break;
}
case '[':
{
if (cellData() == '')
{
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() != '')
{
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);
}
I didn't know about GetTextLen(), your code is ok. Thank you very much.
– Krzysztof Szewczyk
Apr 26 '17 at 14:00
add a comment |
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 = '';
}
else {
ch = input[1];
input.Delete(1, 1);
}
cellData() = ch;
break;
}
case '[':
{
if (cellData() == '')
{
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() != '')
{
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);
}
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 = '';
}
else {
ch = input[1];
input.Delete(1, 1);
}
cellData() = ch;
break;
}
case '[':
{
if (cellData() == '')
{
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() != '')
{
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);
}
edited Apr 26 '17 at 17:32
answered Apr 25 '17 at 17:06
Remy LebeauRemy Lebeau
334k18253448
334k18253448
I didn't know about GetTextLen(), your code is ok. Thank you very much.
– Krzysztof Szewczyk
Apr 26 '17 at 14:00
add a comment |
I didn't know about GetTextLen(), your code is ok. Thank you very much.
– Krzysztof Szewczyk
Apr 26 '17 at 14:00
I didn't know about GetTextLen(), your code is ok. Thank you very much.
– Krzysztof Szewczyk
Apr 26 '17 at 14:00
I didn't know about GetTextLen(), your code is ok. Thank you very much.
– Krzysztof Szewczyk
Apr 26 '17 at 14:00
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f43558399%2fbrainfuck-interpreter-strange-output%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
And what have you done so far to debug this yourself? StackOverflow is not a debugging service. You have an expected result, so step through your code with the debugger until it deviates from that expectation, and then you can figure out why it deviates. But I can tell you right now, your overzealous use of
Text.c_str()
is very wrong, but especially the first one:char* pf = Memo2->Lines->Text.c_str(); char* p = (char*)malloc(strlen(pf)+1); strcpy(p, pf);
. Why do you think that is wrong? I will give you a hint - it has UNDEFINED BEHAVIOR!– Remy Lebeau
Apr 25 '17 at 0:19
@RemyLebeau Have you ever used c++builder6 debugger?
– Krzysztof Szewczyk
Apr 25 '17 at 15:08
All the time. BCB6 is the compiler I have to use at my day job :-( But the issue you describe is not limited to just BCB6. You have errors in your code, so it would be broken in any compiler version.
– Remy Lebeau
Apr 25 '17 at 15:11
bcb6 debugger shown me error at end of caller procedure.
– Krzysztof Szewczyk
Apr 25 '17 at 15:19
There are errors in your code, starting with the very first line of your
interpret()
function. Do you understand WHY that line of code is faulty? You are taking a pointer to temporary data that gets freed immediately after you take the pointer, so the subsequent lines of code are operating on invalid memory. There is another memory error in your','
handler - you are trying to copying data to an uninitialized pointer that is not pointing at valid memory.– Remy Lebeau
Apr 25 '17 at 15:33