/* bfi.c - Don Yang (uguu.org) BF interpreter, limited tape, optimized +->< operators and [-] loop. Usage: bfi [BF program] [BF stdin] [BF stdout] Argument count: BF program stdin stdout 0 stdin unavailable stdout 1 arg1 stdin stdout 2 arg1 arg2 stdout 3 arg1 arg2 arg3 07/24/04 */ #include #define OVERFLOW_CHECK #define MAX_CODE_SIZE 0x10000 #define MAX_DATA_SIZE 0x10000 static char code[MAX_CODE_SIZE], *c; static int data[MAX_DATA_SIZE], operand[MAX_CODE_SIZE], *d; static char *paren[MAX_CODE_SIZE], *stack[MAX_CODE_SIZE]; static int i, j, op0, s; static int AddOpcode(int jj) { if( jj == (int)'+' || jj == (int)'-' || jj == (int)'<' || jj == (int)'>' || jj == (int)',' || jj == (int)'.' ) { if( jj == op0 ) { operand[(int)c - (int)code - 1]++; } else { operand[(int)c - (int)code] = 1; *(c++) = (char)(op0 = jj); if( op0 == (int)',' || op0 == (int)'.' ) op0 = 0; } } else if( jj == (int)'[' ) { stack[s++] = c; *(c++) = (char)(op0 = jj); } else if( jj == (int)']' ) { if( s == 0 ) { (void)puts("unbalanced []"); return -1; } paren[(int)stack[--s] - (int)code] = c; paren[(int)c - (int)code] = stack[s] - 1; *c = (char)(op0 = jj); if( c[-1] == '-' ) { if( c[-2] == '[' ) *(c -= 2) = '0'; } c++; } #ifdef OVERFLOW_CHECK if( c == code + MAX_CODE_SIZE ) { (void)puts("maximum code size exceeded"); return -1; } #endif return 0; } int main(int argc, char **argv) { FILE *prog, *infile, *outfile; /* Initialize code */ c = code; s = op0 = 0; infile = stdin; outfile = stdout; if( argc > 1 ) { if( (prog = fopen(argv[1], "rb")) == NULL ) return printf("Can not open %s\n", argv[1]); while( (j = fgetc(prog)) != EOF ) { if( AddOpcode(j) != 0 ) return -1; } (void)fclose(prog); if( argc > 2 ) { if( (infile = fopen(argv[2], "rb")) == NULL ) return printf("Can not open %s for input\n", argv[2]); if( argc > 3 ) { if( (outfile = fopen(argv[3], "wb+")) == NULL ) return printf("Can not open %s for output\n", argv[3]); } } } else { while( (j = getchar()) != EOF ) { if( AddOpcode(j) != 0 ) return -1; } } *c = '\0'; if( s > 0 ) return puts("unbalanced []"); /* Initialize data */ d = data; for(i = 0; i < MAX_DATA_SIZE; d[i++] = 0); /* Execute */ for(c = code; *c != '\0'; c++) { if( *c == '+' ) { *d += operand[(int)c - (int)code]; } else if( *c == '-' ) { *d -= operand[(int)c - (int)code]; } else if( *c == '.' ) { (void)fputc(*d, outfile); } else if( *c == ',' ) { *d = fgetc(infile); } else if( *c == '[' ) { if( *d == 0 ) c = paren[(int)c - (int)code]; } else if( *c == ']' ) { c = paren[(int)c - (int)code]; } else if( *c == '>' ) { d += operand[(int)c - (int)code]; #ifdef OVERFLOW_CHECK if( d >= data + MAX_DATA_SIZE ) return puts("past right end of data tape"); #endif } else if( *c == '<' ) { d -= operand[(int)c - (int)code]; #ifdef OVERFLOW_CHECK if( d < data ) return puts("past left end of data tape"); #endif } else if( *c == '0' ) { *d = 0; } } (void)fclose(infile); (void)fclose(outfile); return 0; }