fbpx

C++: Execute Brain****

Bjarne-stroustrup
 

RCBF is a set of Brainf*** compilers and interpreters written for Rosetta Code in a variety of languages.

Below are links to each of the versions of RCBF.

An implementation need only properly implement the following instructions:

Command Description
> Move the pointer to the right
< Move the pointer to the left
+ Increment the memory cell under the pointer
- Decrement the memory cell under the pointer
. Output the character signified by the cell at the pointer
, Input a character and store it in the cell at the pointer
[ Jump past the matching ] if the cell under the pointer is 0
] Jump back to the matching [ if the cell under the pointer is nonzero

Any cell size is allowed, EOF support is optional, as is whether you have bounded or unbounded memory.

This is an implementation of Brainf*** originally written in C++ by Mike Mol and Mike Neurohr, for Rosetta Code. It is licensed under the same license as Rosetta Code itself.

It may be fed BF instructions either through standard input (i.e. terminal keyboard input), or through a file named as the first command-line argument.

RCBF is intended for educational purposes only; There is no guarantee it won’t lock up your computer. (Though Mike M thinks he’s got that bug ironed out…) (We’ll no it wasn’t, but it should be now — RdB)

Works with: g++ version 4.1.3

plus the GNU C++ Standard Library

// RCBF -- A free Brainfuck interpreter written for Rosetta Code (http://rosettacode.org)
// Created by Mike Mol and Mike Neurohr, and under the same license as Rosetta Code.
// Repaired by Robert de Bath -- but Ghods is it slow!

// Test with this Hello World, it breaks BF interpreters
//  >++++++++[<+++++++++>-]<.>>+>+>++>[-]+<[>[->+<<++++>]<<]>.+++++++..+++.>
//  >+++++++.<<<[[-]<[-]>]<+++++++++++++++.>>.+++.------.--------.>>+.>++++.

#include <list>
#include <iostream>
#include <fstream>
#define CLOSE 0
#define SUCCESS 1
#define BRANCH_NOT_FOUND 2
#define ERROR_BRANCH_OPEN_NOT_MATCHED 3
#define ERROR_BRANCH_CLOSE_NOT_MATCHED 4
#define ERROR_FILE_LOAD_FAILED 5

using namespace std;

// Define our machine
typedef char instruction_t;
typedef char memorycell_t;

typedef list<instruction_t> memory_t;
typedef memory_t::iterator memptr_t;

typedef list<memorycell_t> code_t;
typedef code_t::iterator codeptr_t;

struct branch_s
{
	code_t::iterator open;
	code_t::iterator close;
};

typedef list<branch_s> branch_t;


// Our recursive execute
int execute(istream *source, code_t &code, codeptr_t &pos, memory_t &memory, memptr_t &ptr, branch_t &branches);

// Our Brainf**k instructions
int increment_ptr(memory_t &memory, memptr_t &ptr);
int decrement_ptr(memory_t &memory, memptr_t &ptr);
int increment(memptr_t &ptr);
int decrement(memptr_t &ptr);
int output(memptr_t &ptr);
int input(memptr_t &ptr);
int jump_forward(istream* source, code_t &code, codeptr_t &pos, memory_t &memory, memptr_t &ptr, branch_t &branches);
int jump_back(codeptr_t &pos, memptr_t &ptr, branch_t &branches);

// utility function
int read_forward_to_branch_close( istream* source, code_t &code, codeptr_t &pos, branch_t &branches );
int get_forward_jump( code_t &code, codeptr_t &pos, branch_t &branches );

// Our starting function
int main(int argc, char* argv[])
{
	// Set up our virtual machine

	//memory
	memory_t memory;
	memory.push_back(0);
	memptr_t ptr = memory.begin();

	code_t code;
	codeptr_t pos = code.begin();

	branch_t branches;

	// Set up our code source
	ifstream file;

	istream *source;

	// If we were given a file to read, open it.
	if ( 1 < argc )
	{
		file.open(argv[1]);

		// If the file failed to load, we need to abort.
		if ( !file.is_open() )
		{
			cerr << "File load failed" << endl;
			return ERROR_FILE_LOAD_FAILED;
		}

		source = &file;
	}
	else
	source = &cin;

	while ( true )
	{
		// A temp variable to store our instruction
		instruction_t instruction;

		codeptr_t end = code.end();

		if( end == pos )
		{
			// Read in from a file
			*source >> instruction;

			// Read in our instruction
			if ( source->eof() )
			{
				// If it's a file, close it.
				ifstream* sourcefile = dynamic_cast<ifstream*>(source);

				// dynamic_cast returns 0 if the cast isn't legal.
				if ( 0 != sourcefile )
				sourcefile->close();
				return CLOSE;
			}

			// append it to our code stack
			code.push_back(instruction);

			pos = code.end();
			--pos;
		}

		// interpret this instruction
		int condition = execute( source, code, pos, memory, ptr, branches );

		// Did we encounter an error?
		if ( SUCCESS != condition )
		// An error was encountered.  We're aborting.
		return condition;
	}

	return CLOSE;
}

// Where we actually interpret code
int execute(istream* source, code_t &code, codeptr_t &pos, memory_t &memory, memptr_t &ptr, branch_t &branches)
{
	int ReturnVal = SUCCESS;
	// Execute the instruction

	switch ( *pos )
	{
	case '>':
		ReturnVal = increment_ptr(memory, ptr );
		break;
	case '<':
		ReturnVal = decrement_ptr(memory, ptr );
		break;
	case '+':
		ReturnVal = increment( ptr );
		break;
	case '-':
		ReturnVal = decrement( ptr );
		break;
	case '.':
		ReturnVal = output( ptr );
		break;
	case ',':
		ReturnVal = input( ptr );
		break;
	case '[':
		ReturnVal = jump_forward(source, code, pos, memory, ptr, branches);
		break;
	case ']':
		ReturnVal = jump_back(pos, ptr, branches);
		break;
	}

	// Increment the code pointer
	++pos;

	return ReturnVal;
}
int increment_ptr( memory_t &memory, memptr_t &ptr)
{
	// If we're at the end of our memory, or if we don't have any
	memptr_t end = memory.end();

	++ptr;

	if ( ptr == end )
	{
		// add a little more, and initialize it.
		memory.push_back(0);

		// And reset our memory pointer to point to the last real cell
		ptr = memory.end();
		--ptr;
	}

	return SUCCESS;
}

int decrement_ptr( memory_t &memory, memptr_t &ptr)
{
	// if we're at the beginning of our memory
	memptr_t begin = memory.begin();
	if ( ptr == begin )
	{
		// Add a little more, and initialize it.
		memory.push_front(0);
		ptr = memory.begin();
	}
	else
	// Just a normal decrement will be fine.
	--ptr;

	return SUCCESS;
}

int increment(memptr_t &ptr)
{
	// Increment the value at the memory address
	*ptr = *ptr + 1;

	return SUCCESS;
}

int decrement(memptr_t &ptr)
{
	// Decrement the value at the memory address
	*ptr = *ptr - 1;

	return SUCCESS;
}

int output(memptr_t &ptr)
{
	cout << *ptr;
	return SUCCESS;
}

int input(memptr_t &ptr)
{
	*ptr = cin.get();
	return SUCCESS; 
}

int jump_forward(istream* source, code_t &code, codeptr_t &pos, memory_t &memory, memptr_t &ptr, branch_t &branches)
{
	// First, is this branch recorded?  It needs to be.
	branch_t::iterator branch = branches.begin();
	branch_t::iterator end = branches.end();

	while ( ( branch != end ) && ( branch->open != pos ) )
	++branch;

	// If we hit the end of the branch list, it wasn't recorded.
	if ( branch == end )
	{
		// record it.  We may need to jump back here.
		branch_s rec;

		// We set open and close to the same value to signify that we don't yet know where the actual close is.
		rec.open = rec.close = pos;
		branches.push_back(rec);
	}

	// Find the closing jump
	int forward_result = SUCCESS;
	codeptr_t jump = pos;
	while( BRANCH_NOT_FOUND == ( forward_result = get_forward_jump( code,  jump, branches ) ) )
	{
		// We haven't read far enough forward to find the corresponding closing branch
		int read_result = read_forward_to_branch_close( source, code, jump, branches );
		if ( SUCCESS != read_result )
		return read_result;
	}

	if ( SUCCESS != forward_result )
	return forward_result;

	// We only jump forward if there is a 0 at the current memory pointer
	if ( 0 == *ptr )
	pos = jump;

	return SUCCESS;

}

int jump_back(codeptr_t &pos, memptr_t &ptr, branch_t &branches)
{

	// Find the corresponding close jump.
	branch_t::iterator branch = branches.begin();
	branch_t::iterator end = branches.end();

	while ( (branch != end ) && ( branch->close != pos) )
	++branch;

	if( end == branch )
	// We ran out of branches to check.  Did it not get registered?
	return ERROR_BRANCH_CLOSE_NOT_MATCHED;

	// We only jump if our current memory cell is not 0.
	if ( 0 != *ptr )
	pos = branch->open;

	return SUCCESS;
}

int read_forward_to_branch_close( istream* source, code_t &code, codeptr_t &pos, branch_t &branches )
{
	codeptr_t tmppos = pos;
	branch_t::iterator begin = branches.begin();
	branch_t::iterator end = branches.end();

	while ( true )
	{
		// read in instruction
		instruction_t instruction;
		*source >> instruction;

		if ( source->eof() )
		{
			ifstream* sourcefile = dynamic_cast<ifstream*>(source);

			// If the source is really a file...
			if ( 0 != sourcefile )
			sourcefile->close();

			return ERROR_BRANCH_OPEN_NOT_MATCHED;
		}

		// Add it to our code memory
		code.push_back( instruction );

		// Is it a branch instruction?

		if ( '[' == instruction )
		{
			// It's another forward jump.  We'll record it, but we'll keep searching.
			branch_s rec;
			codeptr_t tmppos = code.end();
			rec.open = --tmppos;
			rec.close = rec.open;

			// Because we always encounter forward jumps before back jumps,
			// recording a forward jump will always mean adding another node
			// to the branches list
			branches.push_back(rec);
		}
		else if ( ']' == instruction )
		{
			// It's a backward jump.  Find the corresponding nest open
			branch_t::iterator branch = branches.end();
			--branch;

			// If the branch we're examining lacks a unique branch close, it's the one we're looking for.
			while ( ( begin != branch ) && ( branch->open != branch->close ) )
			--branch;

			if ( ( begin == branch ) && ( branch->open != branch->close ) )
			return ERROR_BRANCH_CLOSE_NOT_MATCHED;

			// Record the close jump
			branch->close = --(code.end());

			// We found a close jump, so we'll return; It might be the close jump the caller was looking for.
			return SUCCESS;
		}

	}
}

int get_forward_jump( code_t &code, codeptr_t &pos, branch_t &branches )
{
	branch_t::iterator branch = branches.begin();
	branch_t::iterator end = branches.end();
	while( ( end != branch ) && ( branch->open != pos ) )
	++branch;

	if( end == branch )
	// We ran out of branches.  This is bad.
	return ERROR_BRANCH_OPEN_NOT_MATCHED;

	if( branch->close != branch->open )
	{
		// We found our close branch.  Assign it to pos
		pos = branch->close;
		return SUCCESS;
	}

	// We never found a close branch
	return BRANCH_NOT_FOUND;
}

SOURCE

Content is available under GNU Free Documentation License 1.2.

Our team found a curious site for our readers that are fans of online gaming, a rather exciting site that provides the latest gaming technology. Casinodots.com is the site, they compile the best reviews of MGA casino utan svensk licens sites. This site might pique your curiosity and you can win extra money!