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
int
s. - "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); } }