108 lines
3.2 KiB
C
108 lines
3.2 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#define OP_END 0
|
|
#define OP_INC_DP 1
|
|
#define OP_DEC_DP 2
|
|
#define OP_INC_VAL 3
|
|
#define OP_DEC_VAL 4
|
|
#define OP_OUT 5
|
|
#define OP_IN 6
|
|
#define OP_JMP_FWD 7
|
|
#define OP_JMP_BCK 8
|
|
|
|
#define PROGRAM_SIZE 1048576
|
|
#define MAX_SIZE 5024291
|
|
#define DATA_SIZE 1638375
|
|
|
|
#define STACK_PUSH(A) (stack[sp++] = A)
|
|
#define STACK_POP() (stack[--sp])
|
|
#define STACK_EMPTY() (sp == 0)
|
|
#define STACK_FULL() (sp == MAX_SIZE)
|
|
|
|
static inline void die(int code, char* message){
|
|
fprintf(stderr, message);
|
|
exit(code);
|
|
}
|
|
|
|
struct instruction_t{
|
|
unsigned short operator;
|
|
unsigned short operand;
|
|
};
|
|
|
|
static struct instruction_t program[PROGRAM_SIZE];
|
|
static unsigned short stack[MAX_SIZE];
|
|
static unsigned int sp = 0;
|
|
|
|
void compile(FILE* fp){
|
|
unsigned short pc = 0, jmp_pc;
|
|
int ip;
|
|
while ((ip = getc(fp)) != EOF && pc < MAX_SIZE){
|
|
switch (ip) {
|
|
case '>': program[pc].operator = OP_INC_DP; break;
|
|
case '<': program[pc].operator = OP_DEC_DP; break;
|
|
case '+': program[pc].operator = OP_INC_VAL; break;
|
|
case '-': program[pc].operator = OP_DEC_VAL; break;
|
|
case '.': program[pc].operator = OP_OUT; break;
|
|
case ',': program[pc].operator = OP_IN; break;
|
|
case '[':
|
|
program[pc].operator = OP_JMP_FWD;
|
|
if (STACK_FULL())
|
|
die(1, "Cannot jump forwards: Stack is full.\n");
|
|
STACK_PUSH(pc);
|
|
break;
|
|
case ']':
|
|
if (STACK_EMPTY())
|
|
die(1, "Cannot jump backwards: Stack is full.\n");
|
|
jmp_pc = STACK_POP();
|
|
program[pc].operator = OP_JMP_BCK;
|
|
program[pc].operand = jmp_pc;
|
|
program[jmp_pc].operand = pc;
|
|
break;
|
|
default:
|
|
pc--;
|
|
break;
|
|
}
|
|
pc++;
|
|
}
|
|
if(!STACK_EMPTY())
|
|
die(1, "Program ends with non-empty stack.");
|
|
if(pc == MAX_SIZE)
|
|
die(1, "Program exceeds maximum program size.");
|
|
program[pc].operator = OP_END;
|
|
}
|
|
|
|
void execute(){
|
|
unsigned short data[DATA_SIZE], pc = 0;
|
|
unsigned int ptr = DATA_SIZE;
|
|
while (--ptr) data[ptr] = 0;
|
|
while (program[pc].operator != OP_END && ptr < DATA_SIZE){
|
|
switch (program[pc].operator){
|
|
case OP_INC_DP: ptr++; break;
|
|
case OP_DEC_DP: ptr--; break;
|
|
case OP_INC_VAL: data[ptr]++; break;
|
|
case OP_DEC_VAL: data[ptr]--; break;
|
|
case OP_OUT: putchar(data[ptr]); break;
|
|
case OP_IN: data[ptr] = (unsigned int)getchar(); break;
|
|
case OP_JMP_FWD: if(!data[ptr]) { pc = program[pc].operand; } break;
|
|
case OP_JMP_BCK: if(data[ptr]) { pc = program[pc].operand; } break;
|
|
default: die(2, "Unknown instruction.");
|
|
}
|
|
pc++;
|
|
}
|
|
if(ptr == DATA_SIZE)
|
|
die(1, "Program used up too much memory.");
|
|
}
|
|
|
|
int main(int argc, const char * argv[]){
|
|
FILE *fp;
|
|
if(argc != 2)
|
|
die(1, "Wrong number of arguments supplied.\n");
|
|
if(!(fp = fopen(argv[1], "r")))
|
|
die(1, "File could not be opened.\n");
|
|
compile(fp);
|
|
fclose(fp);
|
|
execute();
|
|
return 0;
|
|
}
|