Enigma-2D
Jump to navigation
Jump to search
Enigma-2D is the name of a 2D programming language made by User:Alegend, on February 14, 2010. It is a mix of Minimal-2D, and BF. It only has 12 commands:
Opcodes
| Opcode | Action |
|---|---|
< |
Move the data pointer left |
> |
Move the data pointer right |
+ |
Add to the value in the data pointer |
- |
Subtract from the value in the data pointer |
. |
Outputs the value in the data pointer |
, |
Asks for input from the user |
U |
Tells the program to switch to the up direction of processing instructions |
D |
Tells the program to switch to the down direction of processing instructions |
L |
Tells the program to switch to the left direction of processing instructions |
R |
Tells the program to switch to the right direction of processing instructions |
[ |
Jump past the matching ] if the cell under the data pointer is 0 |
] |
Jump back to the matching [ if the cell under the data pointer is nonzero |
The program, when it starts, automatically starts processing directions to the right.
Implementations
This language has been implemented in C, with some unspecified details assumed:
- Data elements are
ints. - "End of data" from input is represented as -1.
- Invalid characters must not be reached by the interpreter.
- Spaces are considered a valid no-op.
- The program ends when the instruction processor falls off the edge of the 2D field.
#include <stdio.h>
#include <stdlib.h>
// Counted string
typedef struct {
char *data;
size_t len;
} str;
// Counted array of counted strings
typedef struct {
str *arr;
size_t len;
} arr_strs;
arr_strs make_jagged_array(char *restrict in, size_t len) {
char *linestart = in;
size_t num_lines = 1;
for (size_t i = 0; i < len; i++) {
if (in[i] == '\r' || in[i] == '\n') {
num_lines++;
if (in[i] == '\r' && i + 1 < len && in[i + 1] == '\n') {
i++;
}
}
}
str *jagg = malloc(sizeof(str) * num_lines);
int line = 0;
for (size_t i = 0; i < len; i++) {
char c = *in;
if (c == '\r' || c == '\n') {
jagg[line++] = (str) {.data = linestart, .len = in - linestart};
if (c == '\r' && i + 1 < len && *(in + 1) == '\n') { in++; i++; }
linestart = in + 1;
}
in++;
}
jagg[line++] = (str) {.data = linestart, .len = in - linestart};
return (arr_strs) {.arr = jagg, .len = line};
}
typedef struct {
int row, col, dir_row, dir_col;
int data_pointer, data_allocated;
int *data;
arr_strs script;
} interpreter_state;
void interpreter_error(char *error, interpreter_state *restrict s) {
char *direction = "???";
if (s->dir_row == 1 && s->dir_col == 0) direction = "Down";
else if (s->dir_row == -1 && s->dir_col == 0) direction = "Up";
else if (s->dir_row == 0 && s->dir_col == 1) direction = "Right";
else if (s->dir_row == 0 && s->dir_col == -1) direction = "Left";
fprintf(stderr, "\n---Error---\n%s\nLine %d char %d\nDirection: %s\nData pointer: %d\nData cells (hex):\n", error, s->row, s->col, direction, s->data_pointer);
for (int i = 0; i < s->data_allocated; i++) {
fprintf(stderr, "\t%08X: %08X\n", i, s->data[i]);
}
}
int ensure_data(interpreter_state *restrict s) {
if (s->data_pointer < 0) {
interpreter_error("Tried to write to a negative address", s);
return 0;
}
if (s->data_pointer >= s->data_allocated) {
int orig_allocated = s->data_allocated;
s->data_allocated = s->data_pointer + 1;
s->data = realloc(s->data, s->data_allocated * sizeof(*s->data));
if (s->data == NULL) {
interpreter_error("Out of memory", s);
return 0;
}
while (orig_allocated < s->data_allocated) {
s->data[orig_allocated++] = 0;
}
}
return 1;
}
int within_bounds(interpreter_state *restrict s) {
if (s->row < 0 || s->col < 0) return 0;
if (s->row >= s->script.len) return 0;
if (s->dir_row == 0 && s->col >= s->script.arr[s->row].len) return 0;
return 1;
}
int interpret_once(interpreter_state *restrict s) {
switch (s->script.arr[s->row].data[s->col]) {
case '<':
s->data_pointer--;
break;
case '>':
s->data_pointer++;
break;
case '+':
if (!ensure_data(s)) return 0;
s->data[s->data_pointer]++;
break;
case '-':
if (!ensure_data(s)) return 0;
s->data[s->data_pointer]--;
break;
case '.':
if (!ensure_data(s)) return 0;
putchar(s->data[s->data_pointer]);
break;
case ',':
if (!ensure_data(s)) return 0;
s->data[s->data_pointer] = getchar();
break;
case 'U':
s->dir_row = -1;
s->dir_col = 0;
break;
case 'D':
s->dir_row = 1;
s->dir_col = 0;
break;
case 'L':
s->dir_row = 0;
s->dir_col = -1;
break;
case 'R':
s->dir_row = 0;
s->dir_col = 1;
break;
case '[':
if (!ensure_data(s)) return 0;
if (s->data[s->data_pointer] == 0) {
int num_brackets = 1;
do {
s->row += s->dir_row;
s->col += s->dir_col;
if (!within_bounds(s)) break;
char c = s->script.arr[s->row].data[s->col];
if (c == '[') num_brackets++;
else if (c == ']') num_brackets--;
} while (num_brackets > 0);
if (!within_bounds(s)) {
interpreter_error("Fell off the end of the script looking for a \"]\"", s);
return 0;
}
}
break;
case ']':
if (!ensure_data(s)) return 0;
if (s->data[s->data_pointer] != 0) {
int num_brackets = 1;
do {
s->row -= s->dir_row;
s->col -= s->dir_col;
if (!within_bounds(s)) break;
char c = s->script.arr[s->row].data[s->col];
if (c == ']') num_brackets++;
else if (c == '[') num_brackets--;
} while (num_brackets > 0);
if (!within_bounds(s)) {
interpreter_error("Fell off the end of the script looking for a \"[\"", s);
return 0;
}
}
break;
case ' ':
break;
default:
interpreter_error("Invalid opcode", s);
return 0;
}
return 1;
}
void interpret(arr_strs script) {
interpreter_state s = {.dir_col = 1, .script = script};
while (within_bounds(&s)) {
if (s.col < s.script.arr[s.row].len)
if (!interpret_once(&s))
break;
s.row += s.dir_row;
s.col += s.dir_col;
}
if (s.data != NULL) free(s.data);
}
int main(int argc, char **argv) {
if (argc < 2) {
puts("At least give me some files to execute.");
return 0;
}
for (int i = 1; i < argc; i++) {
FILE *f = fopen(argv[i], "rb");
if (!f) {
fprintf(stderr, "Could not open the script \"%s\": ", argv[i]);
perror(NULL);
continue;
}
fseek(f, 0, SEEK_END);
long f_len = ftell(f);
fseek(f, 0, SEEK_SET);
char *script_raw = malloc(f_len);
fread(script_raw, 1, f_len, f);
fclose(f);
arr_strs script = make_jagged_array(script_raw, f_len);
interpret(script);
free(script.arr);
free(script_raw);
}
}