Недавно решил я попробовать написать какой-нибудь интерпретатор и сделать это на языке C, остановился на языке brainfuck, потому, что его интерпретатор довольно прост в написании.
Что такое brainfuck?
Brainfuck это язык программирования известный своим минимализмом
И правда, в нем всего 8 комманд это "+", "-", ">", "<", "[", "]", ".", ",".
Инструкция | Действие |
"+" | Увеличивает значение в текущей ячейке на 1 |
"-" | Уменьшает значение текущей ячейки на 1 |
">" | Переход к следующей ячейке |
"<" | Переход к предыдущей ячейке |
"." | Вывод на экран содержания текущей ячейки |
"," | Ввод символа с клавиатуры в текущюю ячейку |
"[" и "]" | Операторы goto |
Написание самого интерпретатора
Чтобы интерпретатор работал надо подключить определённые библиотеки
stdio для printf, fopen
stdlib для exit
string для memset
#include <stdio.h> #include <stdlib.h> #include <string.h>
Дальше надо инициализировать массив памяти и определить инструкции:
char stack[30000]; //массив памяти int indexx = 0; // индекс текущей ячейки char * plus = "+"; char * minus = "-"; char * next = ">"; char * back = "<"; char * prt = "."; char * inp = ","; char * lp = "["; char * llp = "]"; int rc = 0; char * endl = "\n"; char * ex = "@";
Значек "@" будет использоваться как выход из программы
Следующий шаг это создать метод main и в его теле инициализировать массив
memset(stack, 0, 30000);
Далее проверку на кол-во аргументов командной строки
if (argc < 2) { bf_shell(); exit(0); }
Выходит если аргумент 1, то запускается brainfuck shell - ещё одна фича моего интерпретатора
Код brainfuck shell:
int bf_shell() { printf("Startimg BrainFuck Shell...\n"); char command[4096]; int i = 1; do { printf("BF> "); gets(command); for (int x = 0; x < sizeof(command); x++) { if (command[x] == *plus) { stack[indexx]++; } else if (command[x] == *minus) { stack[indexx]--; } else if (command[x] == *next) { indexx++; } else if (command[x] == *back) { indexx--; } else if (command[x] == *prt) { putchar(stack[indexx]); } else if (command[x] == *inp) { char t[2]; gets(t); stack[indexx] = (int)t[0]; }else if (command[x] == *endl) { i = 1; } else if (command[x] == *ex) { i = 0; } else if (command[x] == *lp) { if (!stack[indexx]) { rc++; while (rc) { i++; if (command[x] == *lp) { rc++; } if (command[x] == *llp) { rc--; } } } else continue; } else if (command[x] == *llp) { if (!stack[indexx]) { continue; } else { if (command[x] == *llp) { rc++; while (rc) { x--; if (command[x] == *lp) { rc--; } if(command[x] == *llp) { rc++; } } x--; } } } else { continue; } } } while (i); return 0; }
Дальше идёт тело метода main где интерпретатор интерпретирует символы из файла
FILE * file = fopen(argv[1], "r"); if (file == NULL) { printf("Cann't open file %s!\n", argv[1]); exit(1); } fseek(file, 0L, SEEK_END); long size = ftell(file); fseek(file, 0L, SEEK_SET); char buf[size]; fread(buf, sizeof(buf), 1, file);
И сам цикл интерпретации
for (int i = 0; i < sizeof(buf); i++) { if (buf[i] == *plus){ stack[indexx]++; } else if (buf[i] == *minus) { stack[indexx]--; } else if (buf[i] == *next) { indexx++; } else if (buf[i] == *back) { indexx--; } else if (buf[i] == *prt) { putchar(stack[indexx]); } else if (buf[i] == *inp) { char c; scanf("%c", &c); stack[indexx] = (int)c; } else if (buf[i] == *lp) { if (!stack[indexx]) { rc++; while (rc) { i++; if (buf[i] == *lp) { rc++; } if (buf[i] == *llp) { rc--; } } } else continue; } else if (buf[i] == *llp) { if(!stack[indexx]) { continue; } else { if (buf[i] == *llp) { rc++; while (rc) { i--; if (buf[i] == *lp) { rc--; } if (buf[i] == *llp) { rc++; } } i--; } } } else if (buf[i] == *ex) { return 0; } }
Исходник доступен на моем гитхабе
Учтите, что в исходниках все написано в теле метода main.
