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;}