Another Complete Waste of Time...

Published January 04, 2005
Advertisement
I did an update to my BFI program. It is not currently uploaded, but I expect it will be before long, once I finish cleaning it up.

What has changed? Well, it's still a Brainf*** Interpreter. No, I didn't add any new tokens to the language in any sort of attempt to "improve it", although if I get a chance one day, I will add an interpreter directive that allows breakpoints(probably '!'), but that's an interpreter command, not a part of the language.

What I *DID* do is strip out the comments, do run-length encoding on the source of the BF program, and store the corresponding other end of the loop for all of the loop locations.

If you'd like to look at the source, here you go:

/* * BFI.cpp * An almost total rewrite of BFI.c Copyright (C) 2003 Thomas Cort * Changes Copyright (C) 2004, 2005 Ernest S. Pazera * * This source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this source; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include #include #include #include #include using namespace std;//data sizeconst size_t DATA_SIZE=32768;//shorthand command structurestruct command_t{	char token;//the token	union 	{		size_t count;//repeat count for the token(all but [ and ])		size_t position;//position after opposing token ([ and ] only)	};	size_t byte_position;//byte position within the file};//check for a valid sourcesize_t source_is_valid(const string& source_string){	size_t error_position=(size_t)-1;	//keep track of the nested level of [ and ]	size_t nested_level=0;	//loop through the source	for(std::string::const_iterator source_iterator=source_string.begin();source_iterator!=source_string.end();source_iterator++)	{		//look for [ or ]		switch(*source_iterator)		{		case '['://found start of loop			{				//increase nested level				nested_level++;			}break;		case ']'://found end of loop			{				//check for zero nested level				if(nested_level==0)				{					//zero nested level, ERROR!					//source is not valid					error_position=source_iterator-source_string.begin();					return(error_position);				}				else				{					//subtract one from the nested level					nested_level--;				}			}break;		}	}	//return validity	return(error_position);}int main(int argument_count, char **argument_list) {	//don't skip the whitespace	cin.unsetf(ios_base::skipws);	//check argument count	if(argument_count<2)	{		//show syntax		cout<<"Usage:\n\tbfi.exe Source1 [Source2]*\n"<	}	else	{		//at least one argument		//loop through arguments		for(int argument=1;argument		{			//message that source is loading			cout << "Now loading: \t\n" << argument_list[argument] << "...\n" << endl;			//open the file			fstream input_file(argument_list[argument]);			//read the file into a string			string source=string((istreambuf_iterator<char>(input_file)),(istreambuf_iterator<char>()));			//close the input file			input_file.close();			//validate source			size_t error_position=source_is_valid(source);			//if an error is detected, report it and skip to next file			if(error_position!=((size_t)-1))			{				//source is invalid				cout << "Mismatched ] at byte " << (unsigned int)error_position << "." << endl;				continue;			}			//the program			vector program;			//clear the program			program.clear();			//initialize command			command_t command;			command.token=0;			command.count=0;			//loop through the source			for(string::iterator source_iterator=source.begin();source_iterator!=source.end();source_iterator++)			{				//which token are we on?				switch(*source_iterator)				{				case '['://begin loop				case ']'://end loop					{						//do not run-length encode loops						command.token=(*source_iterator);						command.count=0;						command.byte_position=(size_t)(source_iterator-source.begin());						//add to program						program.push_back(command);					}break;				case '.'://output				case ','://input				case '>'://increment pointer				case '<'://decrement pointer				case '+'://increment byte				case '-'://decrement byte					{						//if the program is not empty and the token is the same as the last token...						if(!program.empty()&&program[program.size()-1].token==(*source_iterator))						{							//add to the count of the token							program[program.size()-1].count++;						}						else						{							//new token							command.token=(*source_iterator);							command.count=1;							command.byte_position=(size_t)(source_iterator-source.begin());							//add to program							program.push_back(command);						}					}break;				}			}			//program iterator			vector::iterator program_iterator;			//loop through program			for(program_iterator=program.begin();program_iterator!=program.end();program_iterator++)			{				//check for a start of loop				if((*program_iterator).token=='[')				{					//make a note of the position					size_t start_position=program_iterator-program.begin();					//start keeping track of the nested level					size_t nested_level=0;					//use a temporary iterator					vector::iterator temp=program_iterator;					//find the end of the loop					do					{						//adjust the nested level						nested_level+=(((*temp).token=='[')-((*temp).token==']'));						//if nested level, move to next token						if(nested_level)							temp++;					}while(nested_level);					//make note of the end position					size_t end_position=temp-program.begin();					//tell start position about the end position					(*program_iterator).position=end_position;					//tell end position about the start position					(*temp).position=start_position;				}				//check for increment or decrement byte				else if((*program_iterator).token=='+' && (*program_iterator).token=='-')				{					//it's a byte, so modulo 256					(*program_iterator).count%=256;				}			}			//go to start of program			program_iterator=program.begin();			//create a string to represent the data			string data(DATA_SIZE,0);			//point to the front of the data			string::iterator data_iterator=data.begin();			//reset error position			error_position=(size_t)(-1);			string error_message="";			//interpret until the source iterator reaches the end or there is an error			while(program_iterator!=program.end() && error_message.empty())			{				//what is the current instruction?				switch((*program_iterator).token)				{				case '+'://increase byte at data pointer					{						(*data_iterator)+=(*program_iterator).count;					}break;				case '-'://decrease byte at data pointer					{						(*data_iterator)-=(*program_iterator).count;					}break;				case '>'://increase data pointer 					{						//check for overflow						if((data.end()-data_iterator)>(*program_iterator).count)						{							//no overflow							data_iterator+=(*program_iterator).count;						}						else						{							//overflow							error_message="Data iterator overflow!";							error_position=(*program_iterator).byte_position;						}					}break;				case '<'://decrease data pointer					{						//check for underflow						if((data_iterator-data.begin())>=(*program_iterator).count)						{							//no underflow							data_iterator-=(*program_iterator).count;						}						else						{							//underflow							error_message="Data iterator underflow!";							error_position=(*program_iterator).byte_position;						}					}break;				case ','://read character from console					{						for(size_t i=0;i<(*program_iterator).count;i++)							cin>>(*data_iterator);					}break;				case '.'://write character to console					{						for(size_t i=0;i<(*program_iterator).count;i++)							cout<<(*data_iterator);					}break;				case '['://begin loop					{						//if byte is zero...						if(!(*data_iterator))						{							//move to stored position of the end of the loop							program_iterator=program.begin()+(*program_iterator).position;						}					}break;				case ']'://end loop					{						//if byte is non-zero						if(*data_iterator)						{							//move to stored position of the beginning of the loop							program_iterator=program.begin()+(*program_iterator).position;						}					}break;				}				//move to next instruction				program_iterator++;			}			//check for successful run			if(error_message.empty())			{				//success				cout << "\nSuccess!" << endl;			}			else			{				//error				cout << "\nRun-time error:" << endl;				cout << "\tError Message: " << error_message << endl;				cout << "\tLocation(Approximate): " << (unsigned int)error_position << endl;			}		}	}	//this is the one line I didn't change	return 0;}


0 likes 3 comments

Comments

Rob Loach
I made a brainfuck interpreter a while ago in PHP. I shouldn't of deleted it.
January 04, 2005 05:41 PM
johnhattan
I still haven't figured out if you're the busiest lazy person I know or the laziest busy person I know.

Of course, I also know a guy who's 36 years old and can identify all of the Pokemon, so I guess we all must have some kind of useless avocation.
January 04, 2005 05:45 PM
johnhattan
New Toy

Somebody's written a Chip8 emulator in Flash. I've never heard of Chip8, but it's apparently the first VM, done back in the 70's. http://newsdee.com/flip8/

Unlike Brainf*ck, people have made some cute games with it. Screenshots at http://www.spug.net/reviews/rchip8.htm
January 05, 2005 09:54 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement

Latest Entries

Music To My Ears

1738 views

Getting There...

1997 views

Guess Chess

1895 views

iPhone JetLag

1846 views

iPhone JetLag

1689 views
Advertisement