Made debugging clearer: refactored error messages and return codes; warning on non-usable character in file

This commit is contained in:
Veit Heller
2014-10-05 14:58:19 +02:00
parent 7361fb26dc
commit 51e73424d9

View File

@@ -1,36 +1,36 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#define OP_END 0 #define END 0
#define OP_INC_DP 1 #define INC_DP 1
#define OP_DEC_DP 2 #define DEC_DP 2
#define OP_INC_VAL 3 #define INC_VAL 3
#define OP_DEC_VAL 4 #define DEC_VAL 4
#define OP_OUT 5 #define OUT 5
#define OP_IN 6 #define IN 6
#define OP_JMP_FWD 7 #define JMP_FWD 7
#define OP_JMP_BCK 8 #define JMP_BCK 8
#define PROGRAM_SIZE 1048576 #define PROGRAM_SIZE 1048576
#define MAX_SIZE 5024291 #define MAX_SIZE 5024291
#define DATA_SIZE 1638375 #define DATA_SIZE 1638375
#define STACK_PUSH(A) (stack[sp++] = A) #define PUSH(A) (stack[sp++] = A)
#define STACK_POP() (stack[--sp]) #define POP() (stack[--sp])
#define STACK_EMPTY() (sp == 0) #define EMPTY() (sp == 0)
#define STACK_FULL() (sp == MAX_SIZE) #define FULL() (sp == MAX_SIZE)
static inline void die(int code, const char* message){ static inline void die(int code, const char* message){
fprintf(stderr, "%s", message); fprintf(stderr, "%s", message);
exit(code); exit(code);
} }
struct instruction_t{ struct instruction{
unsigned int operator; unsigned int operator;
unsigned int operand; unsigned int operand;
}; };
static struct instruction_t program[PROGRAM_SIZE]; static struct instruction program[PROGRAM_SIZE];
static unsigned int stack[MAX_SIZE]; static unsigned int stack[MAX_SIZE];
static unsigned long sp = 0; static unsigned long sp = 0;
@@ -39,67 +39,69 @@ void compile(FILE* fp){
int ip; int ip;
while ((ip = getc(fp)) != EOF && pc < MAX_SIZE){ while ((ip = getc(fp)) != EOF && pc < MAX_SIZE){
switch (ip) { switch (ip) {
case '>': program[pc].operator = OP_INC_DP; break; case '>': program[pc].operator = INC_DP; break;
case '<': program[pc].operator = OP_DEC_DP; break; case '<': program[pc].operator = DEC_DP; break;
case '+': program[pc].operator = OP_INC_VAL; break; case '+': program[pc].operator = INC_VAL; break;
case '-': program[pc].operator = OP_DEC_VAL; break; case '-': program[pc].operator = DEC_VAL; break;
case '.': program[pc].operator = OP_OUT; break; case '.': program[pc].operator = OUT; break;
case ',': program[pc].operator = OP_IN; break; case ',': program[pc].operator = IN; break;
case '[': case '[':
program[pc].operator = OP_JMP_FWD; program[pc].operator = JMP_FWD;
if (STACK_FULL()) if (FULL())
die(1, "Cannot jump forwards: Stack is full.\n"); die(127, "nbfi:compile: Cannot jump forwards: Stack is full.\n");
STACK_PUSH(pc); PUSH(pc);
break; break;
case ']': case ']':
if (STACK_EMPTY()) if (EMPTY())
die(1, "Cannot jump backwards: Stack is full.\n"); die(127, "nbfi:compile: Cannot jump backwards: Stack is full.\n");
jmp_pc = STACK_POP(); jmp_pc = POP();
program[pc].operator = OP_JMP_BCK; program[pc].operator = JMP_BCK;
program[pc].operand = jmp_pc; program[pc].operand = jmp_pc;
program[jmp_pc].operand = pc; program[jmp_pc].operand = pc;
break; break;
default: default:
if(ip > 32 && ip < 128)
fprintf(stderr, "nbfi:compile: Warning: Unknown command: %c\n", ip);
pc--; pc--;
break; break;
} }
pc++; pc++;
} }
if(!STACK_EMPTY()) if(!EMPTY())
die(1, "Program ends with non-empty stack."); die(117, "nbfi:compile: Program ends with non-empty stack.");
if(pc == MAX_SIZE) if(pc == MAX_SIZE)
die(1, "Program exceeds maximum program size."); die(127, "nbfi:compile: Program exceeds maximum program size.");
program[pc].operator = OP_END; program[pc].operator = END;
} }
void execute(){ void execute(){
unsigned int data[DATA_SIZE], pc = 0; unsigned int data[DATA_SIZE], pc = 0;
unsigned int ptr = DATA_SIZE; unsigned int ptr = DATA_SIZE;
while (--ptr) data[ptr] = 0; while (--ptr) data[ptr] = 0;
while (program[pc].operator != OP_END && ptr < DATA_SIZE){ while (program[pc].operator != END && ptr < DATA_SIZE){
switch (program[pc].operator){ switch (program[pc].operator){
case OP_INC_DP: ptr++; break; case INC_DP: ptr++; break;
case OP_DEC_DP: ptr--; break; case DEC_DP: ptr--; break;
case OP_INC_VAL: data[ptr]++; break; case INC_VAL: data[ptr]++; break;
case OP_DEC_VAL: data[ptr]--; break; case DEC_VAL: data[ptr]--; break;
case OP_OUT: putchar((signed int)data[ptr]); break; case OUT: putchar((signed int)data[ptr]); break;
case OP_IN: data[ptr] = (unsigned int)getchar(); break; case IN: data[ptr] = (unsigned int)getchar(); break;
case OP_JMP_FWD: if(!data[ptr]) { pc = program[pc].operand; } break; case JMP_FWD: if(!data[ptr]) { pc = program[pc].operand; } break;
case OP_JMP_BCK: if(data[ptr]) { pc = program[pc].operand; } break; case JMP_BCK: if(data[ptr]) { pc = program[pc].operand; } break;
default: die(2, "Unknown instruction."); default: die(127, "nbfi:execute: Unknown instruction.\n");
} }
pc++; pc++;
} }
if(ptr == DATA_SIZE) if(ptr == DATA_SIZE)
die(1, "Program used up too much memory."); die(127, "nbfi:execute: Program used up too much memory.\n");
} }
int main(int argc, const char * argv[]){ int main(int argc, const char * argv[]){
FILE *fp; FILE *fp;
if(argc != 2) if(argc != 2)
die(1, "Wrong number of arguments supplied.\n"); die(127, "nbfi:parse: Wrong number of arguments supplied.\n");
if(!(fp = fopen(argv[1], "r"))) if(!(fp = fopen(argv[1], "r")))
die(1, "File could not be opened.\n"); die(1, "nbfi:parse: File could not be opened.\n");
compile(fp); compile(fp);
fclose(fp); fclose(fp);
execute(); execute();