BrainF**k的解释器
Windows Only!
按照语法编写了这个“解释器”。
功能:
1.解释并运行一个后缀为 '.bf' 的文件;
2.提供错误指示,目前包括 RE 和 CE ;
3.提供 'help' 的指令帮助;
4.提供文件打开的功能;
源码:
#include <conio.h>
#include <windows.h>
#include <bits/stdc++.h>
using namespace std;
typedef bool ( * Functions )();
typedef pair<int, int> pii;
const char *LoadingBar[11] =
{
" ",
"- ",
"-- ",
"--- ",
"---- ",
"----- ",
"------ ",
"------- ",
"-------- ",
"--------- ",
"----------" };
const int MAXN = 1e6 + 5;
pii pos[MAXN];
int stk[MAXN], cp[MAXN], top;
int val[MAXN] = {}, ed[MAXN];
char code[MAXN], buf[MAXN];
int len, cnt;
namespace Error
{
void PrintPosition( const int cur, char ptr )
{
int r = pos[cur].first;
int beg = ed[r - 1] + 1, eed = ed[r];
for( int i = max( beg, cur - 3 ) ; i <= min( eed, cur + 3 ) ; i ++ ) putchar( code[i] );
putchar( '\n' ); for( int i = max( beg, cur - 3 ) ; i < cur ; i ++ ) putchar( ' ' );
putchar( ptr ), putchar( '\n' );
}
void RE( const int cur )
{
printf( "Runtime error on: Line %d, Character %d.\n", pos[cur].first, pos[cur].second );
printf( "Error: out of memory.\n" );
PrintPosition( cur, 'x' ), putchar( '\n' );
}
void CE( const int cur, bool type )
{
printf( "Compilation error on: Line %d, Character %d.\n", pos[cur].first, pos[cur].second );
printf( "Mismatched %s bracket.\n", type ? "right" : "left" );
PrintPosition( cur, '?' ), putchar( '\n' );
}
void UF()
{
puts( "Unknown file name." );
}
void UC()
{
puts( "Unknown command. Please put in \'help\' for help." );
}
void UnknownFormat()
{
puts( "Unknown format, please input \'help\' for help." );
}
};
using namespace Error;
namespace Function
{
bool Compile()
{
bool flag; int lst = 0;
printf( "Processing: [%s]: 0%%\n", LoadingBar[0] );
for( int i = 1 ; i <= len ; i ++ )
{
if( code[i] == '[' ) stk[++ top] = i;
if( code[i] == ']' )
{
cp[i] = stk[top], cp[stk[top --]] = i;
if( top < 0 ) { CE( i, 1 ); return false; }
}
flag = false;
while( lst < 10 && lst + 1 < 10.0 * i / len ) flag = true, lst ++;
if( flag ) printf( "Processing: [%s]: %.1lf%%\n", LoadingBar[lst], 100.0 * i / len );
}
if( top ) { CE( stk[1], 0 ); return false; }
puts( "Done!\n" );
return true;
}
FILE* GetFile( string Name )
{
int L = Name.size(); len = cnt = 0;
for( int i = 0 ; i < L ; i ++ ) buf[i] = Name[i];
buf[L] = '.', buf[L + 1] = 'b', buf[L + 2] = 'f';
FILE *source = fopen( buf, "r" );
for( int i = 0 ; i < L + 5 ; i ++ ) buf[i] = '\0';
return source;
}
int GetCode( string Name )
{
FILE *source = GetFile( Name );
if( source == NULL ) { UF(); return 0; }
while( ~ fscanf( source, "%s", buf + 1 ) )
{
cnt ++;
for( int i = 1 ; buf[i] && buf[i] != '\r' && buf[i] != '\n' ; i ++ )
code[++ len] = buf[i], pos[len] = pii( cnt, i );
for( int i = 1 ; buf[i] ; i ++ ) buf[i] = '\0';
ed[cnt] = len;
}
fclose( source );
return 1;
}
bool CheckOrder( string A, string B )
{
if( A.length() < B.length() ) return false;
for( int i = 0 ; i < B.length() ; i ++ )
if( A[i] != B[i] ) return false;
return true;
}
};
using namespace Function;
struct Interface
{
public :
int act();
};
struct Basic : public Interface
{
private :
bool Help()
{
puts(
"Command - Use\n\
help Show the usable commands.\n\
quit Quit the program.\n\
exit Exactly the same as command \"quit\".\n\
run Compile and run a file with suffix \".bf\".\n\
Format:\n\
run [File Name]\n\
open Open a file with suffix \".bf\".\n\
Format:\n\
open [File Name]\n\
clean Clean the screen.\n" );
return false;
}
bool Run()
{
puts( "Running..." );
Sleep( 300 );
int ptr = 0;
memset( val, 0, sizeof val );
clock_t start = clock();
for( int i = 1 ; i <= len ; i ++ )
{
if( code[i] == '>' ) { ptr ++; if( ptr == MAXN ) { RE( i ); return false; } }
else if( code[i] == '<' ) { ptr --; if( ptr < 0 ) { RE( i ); return false; } }
else if( code[i] == '+' ) val[ptr] ++;
else if( code[i] == '-' ) val[ptr] --;
else if( code[i] == '.' ) putchar( val[ptr] );
else if( code[i] == ',' ) val[ptr] = getchar();
else if( code[i] == '[' ) { if( val[ptr] == 0 ) i = cp[i]; }
else if( code[i] == ']' ) { if( val[ptr] ) i = cp[i]; }
}
clock_t ed = clock();
puts( "\n--------------------------------------------------" );
printf( "Run Time: %lfs\n\n", ( double ) ( ed - start ) / CLOCKS_PER_SEC );
return true;
}
void CompileAndRun( const string order )
{
string name;
stringstream ss( order );
ss >> name;
if( ! ( ss >> name ) ) { UnknownFormat(); return ; }
if( ss >> name ) { UnknownFormat(); return ; }
if( ! GetCode( name ) ) return ;
if( Compile() ) Run();
}
void OpenFile( const string order )
{
string name;
stringstream ss( order );
ss >> name;
if( ! ( ss >> name ) ) { UnknownFormat(); return ; }
if( ss >> name ) { UnknownFormat(); return ; }
FILE *source = GetFile( name );
if( source == NULL ) { UF(); return ; }
fclose( source );
system( ( "notepad " + name + ".bf" ).c_str() );
}
public :
int act()
{
string comm;
while( true )
{
system( "cls" );
cout << "BrainFuck Environment : Version : 1.1.0" << endl;
while( true )
{
cout << "BFE > ";
getline( cin, comm, '\n' );
if( comm == "debug" ) return 2;
else if( comm == "quit" || comm == "exit" ) goto quit;
else if( CheckOrder( comm, "run" ) ) CompileAndRun( comm );
else if( CheckOrder( comm, "open" ) ) OpenFile( comm );
else if( comm == "clean" ) break;
else if( comm == "help" ) Help();
else UC();
}
}
quit :
return 0;
}
}base;
struct Debuger : public Interface
{
private :
void Help()
{
puts(
"Command - Use\n\
help Show the usable Commands.\n\
quit Quit the debuger.\n\
exit Exactly the same as command \"quit\".\n\
load Load a file with suffix \".bf\" into buffer.\n\
Format:\n\
load [File Name]" );
}
void Load( const string order )
{
string name;
stringstream ss( order );
ss >> name;
if( ! ( ss >> name ) ) { UnknownFormat(); return ; }
if( ss >> name ) { UnknownFormat(); return ; }
FILE *source = GetFile( name );
if( source == NULL ) { UF(); return ; }
GetCode( name );
}
public :
int act()
{
string comm;
while( true )
{
system( "cls" );
cout << "Brain Fuck Environment :: Debuger : Version : 0.0.0" << endl;
while( true )
{
cout << "Debuger > ";
getline( cin, comm, '\n' );
if( CheckOrder( comm, "help" ) ) Help();
else if( CheckOrder( comm, "quit" ) ) goto quit;
else if( CheckOrder( comm, "exit" ) ) goto quit;
else if( CheckOrder( comm, "load" ) ) Load( comm );
}
}
quit :
return 1;
}
}debug;
struct End : public Interface
{
public :
int act() { exit( 0 ); return 0; }
}finish;
int main()
{
system( "@echo off" );
int cur = 1;
while( true )
{
if( cur == 0 ) cur = finish.act();
if( cur == 1 ) cur = base.act();
if( cur == 2 ) cur = debug.act();
}
return 0;
}