2th/AuthorImplementation.c
Jump to navigation
Jump to search
// Easy implementation of a 2th interpreter.
#include <stdio.h>
#include <stdlib.h>
#define NUM_CELLS 10000
int isDigit(char x) {
return '0' <= x && x <= '9';
}
// Function for finding bracket matches.
// I know this is a slow approach to use a while loop to find the matching bracket...
// (It is preferred to prepare a match table before hand)
int matchJump(int i, const char *program, size_t programLength, int dir) {
dir = (dir > 0)? 1 : -1; // direction to search in
int level = -dir;
int i0 = i; // saving original value of i for error message
while (level != 0 && 0 < i && i < programLength) {
i += dir;
switch (program[i]) {
case '[': level--; break;
case ']': level++; break;
}
}
if (level == 0) {
return i;
}
else {
printf("SYNTAX ERROR: unmatched opening bracket '[' at index %d", i0);
return -1;
}
}
// Interprets your 2th program string.
void interpret2thProgram(const char *program, size_t programLength) {
char tape[NUM_CELLS] = { 0 }; // data tape
char r = 0; // the register
size_t t = 0; // data pointer index
size_t i = 0; // instruction pointer index
size_t m = 0; // mode flag for if we are in register mode
size_t n = 1; // multiplier for run-length encoding
size_t resetN; // extra flag for whether to reset n to 1 (removes redundancy from the switch cases)
while (i < programLength) {
resetN = 1;
switch(program[i]) {
case '+': // Increment
if (m) { r += n; } else { tape[t] += n; }
i++;
break;
case '-': // Decrement
if (m) { r -= n; } else { tape[t] -= n; }
i++;
break;
case '<': // Move left
t -= n;
if (t < 0) { t = 0; }
i++;
break;
case '>': // Move right
t += n;
if (t >= NUM_CELLS) { t = NUM_CELLS - 1; }
i++;
break;
case '%': // enter cell mode
m = 1;
i++;
break;
case '^': // enter register mode
m = 0;
i++;
break;
case '[': // Jump past matching bracket if current cell/R is 0 (depending on mode)
if ((m && r == 0) || (!m && tape[t] == 0)) {
i = matchJump(i, program, programLength, 1);
if (i < 0) exit(1);
}
i++;
break;
case ']': // Jump back to the matching bracket if current cell/R is not 0 (depending on mode)
if ((m && r != 0) || (!m && tape[t] != 0)) {
i = matchJump(i, program, programLength, -1);
if (i < 0) exit(1);
}
i++;
break;
case '?':
// Get a character of input
if (m) { r = getchar(); } else { tape[t] = getchar(); }
i++;
break;
case '.':
// Set a character of output
if (m) { putchar(r); } else { putchar(tape[t]); }
i++;
break;
default:
if (isDigit(program[i])) {
// Read a number for the (run length encoding) multiplier, n
n = 0;
while (isDigit(program[i])) {
n = (n * 10) + (program[i] - '0');
i++;
}
// This combines making sure that (n != 0) and that we do not reset n if it is valid:
resetN = (n == 0);
} else {
// Ignore other characters
i++;
}
break;
}
// this happens unless a number (digits) was read:
if (resetN) {
n = 1;
}
}
}
int main(int argc, char **argv) {
if (argc != 2) {
printf("%s: error: expected exactly 1 argument, the program string\n", argv[0]);
exit(1);
}
interpret2thProgram(argv[1], strlen(argv[1]));
}