Написать интерпретатор языка Brainfuck для памяти на n ячеек. Ячейки хранят значения типа char.
Тесты
Название программы | Ввод (программа на Brainfuck) | Вывод | ||||
Hello World! |
|
|
||||
Числа Фибоначчи |
|
|||||
Факториалы |
|
Код на С++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
#include <iostream> using namespace std; int main() { int n; // Количество ячеек cin >> n; string tape(n,0); int pointer = 0; string program; cin >> program; for (unsigned int i = 0; i < program.length(); i++) { if (program[i] == '>') pointer++; if (program[i] == '<') pointer--; if (program[i] == '+') tape[pointer]++; if (program[i] == '-') tape[pointer]--; if (program[i] == '.') cout << tape[pointer]; if (program[i] == ',') cin >> tape[pointer]; if (program[i] == '[') { if (tape[pointer] == 0) { int counter = 1; while (counter > 0) { i++; if (program[i] == '[') counter++; if (program[i] == ']') counter--; } } } else if (program[i] == ']') { if (tape[pointer] != 0) { int counter = 1; while (counter > 0) { i--; if (program[i] == '[') counter--; if (program[i] == ']') counter++; } } } } return 0; } |
Код на Ideone. Код программы нужно вводить сплошным блоком текста — без переносов строки. Зато можно осуществлять «ввод данных для программы на Brainfuck» — то, для чего нужен оператор «,». Для этого нужно символы, которые «хотим ввести в программу на Brainfuck», нужно ввести в окно ввода Ideone на новой строке после кода программы.
Ещё один вариант кода. В нём можно вводить код программы на разных строках. Различие минимальное:
1 2 3 |
string program = "", tmp; while (cin >> tmp) program += tmp; |
Пройдя по второй ссылке можно посмотреть на один из вариантов вычисления чисел Фибоначчи на Brainfuck. Вычисляются числа, не превосходящие 100. Программа работает 🙂
Код на С
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
#include <stdio.h> #include <stdlib.h> char* read_string(size_t *size){ char *str; int c; size_t length = 0; str = realloc(NULL, sizeof(char)*(*size)); if(!str)return str; while((c=getchar()) != EOF && c != '\n'){ str[length++] = c; if(length == *size) { str = realloc(str, sizeof(char)*(*size += 10)); if(!str) return str; } } str[length++] = '\0'; size = length; return str; } int main() { int n; scanf("%d", &n); getchar(); char tape[10000]; for (int k = 0; k < n; k++) tape[k] = 0; int pointer = 0; size_t length = 100; char *program = read_string(&length); printf("%s\n", program); for (unsigned int i = 0; i < length; i++) { if (program[i] == '>') pointer++; if (program[i] == '<') pointer--; if (program[i] == '+') tape[pointer]++; if (program[i] == '-') tape[pointer]--; if (program[i] == '.') printf("%c", tape[pointer]); if (program[i] == ',') scanf("%c", &tape[pointer]); if (program[i] == '[') { if (tape[pointer] == 0) { int counter = 1; while (counter > 0) { i++; if (program[i] == '[') counter++; if (program[i] == ']') counter--; } } } else if (program[i] == ']') { if (tape[pointer] != 0) { int counter = 1; while (counter > 0) { i--; if (program[i] == '[') counter--; if (program[i] == ']') counter++; } } } } return 0; } |
Код на Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
import java.util.*; import java.lang.*; import java.io.*; class Main { public static void main (String[] args) throws java.lang.Exception { Scanner in = new Scanner(System.in); int n = Integer.parseInt(in.next()); char[] tape = new char[n]; for (int i = 0; i < n; i++) tape[i] = 0; int pointer = 0; String program = in.next(); for (int i = 0; i < program.length(); i++) { if (program.charAt(i) == '>') pointer++; if (program.charAt(i) == '<') pointer--; if (program.charAt(i) == '+') tape[pointer]++; if (program.charAt(i) == '-') tape[pointer]--; if (program.charAt(i) == '.') System.out.print(tape[pointer]); if (program.charAt(i) == ',') tape[pointer] = (char) System.in.read(); if (program.charAt(i) == '[') { if (tape[pointer] == 0) { int counter = 1; while (counter > 0) { i++; if (program.charAt(i) == '[') counter++; if (program.charAt(i) == ']') counter--; } } } else if (program.charAt(i) == ']') { if (tape[pointer] != 0) { int counter = 1; while (counter > 0) { i--; if (program.charAt(i) == '[') counter--; if (program.charAt(i) == ']') counter++; } } } } } } |
— А где текст задачи?
— Зачем смешали string и c-string (nts) в одной программе? Зачем это число n в начале?
— Ожидается два кода. Один со string, другой — без.
— «Решение. В лоб.» Все решения являются решением «в лоб». Только лбы разные 🙂
— Для тестов и демонстрации нужен хотя бы «Hello, world!» в отчёте. На ideon он есть, а здесь нету.
— Здесь, например, есть несколько интересных программ на этом языке. Например его интерпретатор написанный на нём же. Или написанный на нём транслятор с него же на Си. Числа Фибоначчи есть. Подберите или адаптируйте что-то эффектное.
Задача висит ещё с прошлого года.
Нужно исправить замечания к решению на С++.
«замечания к решению на С++»:
число n задаёт длину ленты, это пользовательский параметр
решение — С++ string
тесты и демонстрация добавлены были ещё в прошлом году
Нужно добавить решение на С или текущих исправлений достаточно?
— Я понимаю, что n длина ленты. Зачем программисту её задавать? Вы же не задаёте заранее объём памяти перед запуском своей программы? Просто используете память по мере необходимости.
— Нет смысла писать решение для char * с точки зрения оценки прошлого семестра. Смысл есть только с точки зрения публикации исчерпывающего решения.
В формулировке задачи было сказано: «Написать интерпретатор языка Brainfuck для памяти на n ячеек», поэтому я решил, что n — это пользовательский параметр. Но я согласен, что егоможно не задавать, поэтому зафиксировал память на 10000 ячеек. Этого должно хватить для указанных в тесте и доступных по Вашей ссылке программ.
Реализация на С также добавлена. Пришлось ввести вспомогательную функцию, позволяющую считывать строки неизвестной заранее длины. Она динамически наращивает память под считываемую строку и накапливает её длину.
Вы абсолютно правы. Я не прочитал условие, которое сам и написал. Виноват.
Что касается Ваших исправлений, то они не соответствуют тому, что я предлагал.
Я предлагал сделать так, чтобы лента всегда была достаточного размера. Если делать фиксированный размер (пусть и достаточно большой), то уж лучше оставить как было.
Поскольку я немного запутался, то сделал, как было.
Функция parseInt в Java-версии и дополнительное считывание символа в С-версии нужны, чтобы «съесть» перевод на новую строку после числа.