Brainfuck и почему это просто?

от автора

Недавно решил я попробовать написать какой-нибудь интерпретатор и сделать это на языке 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.


ссылка на оригинал статьи https://habr.com/ru/post/677692/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *