Enigma-2D

From Esolang
Jump to: navigation, search

Enigma-2D is the name of a 2D programming language made by Alegend, on February 14, 2010. It is a mix of Minimal-2D, and BF. It only has 12 commands:

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);
       }
   }