Песочница →
Prolog. Программируем автоматы
Прочитав статью о Prolog, я решил написать небольшое дополнение к ней в виде 2 небольших задач.
Вот они:
1. Интерпретатор языка brainfuck
2. Машина Тьюринга
Для начала нам требуется SWI-Prolog и немного свободного времени.
Начнем с копи-паста из Википедии.
Brainfuck — один из известнейших эзотерических языков программирования, придуман Урбаном Мюллером в 1993 году для забавы. Язык имеет восемь команд, каждая из которых записывается одним символом. Исходный код программы на Brainfuck представляет собой последовательность этих символов без какого-либо дополнительного синтаксиса.
Машина, которой управляют команды Brainfuck, состоит из упорядоченного набора ячеек и указателя текущей ячейки, напоминая ленту и головку машины Тьюринга. Кроме того, подразумевается устройство общения с внешним миром (см. команды. и ,) через поток ввода и поток вывода.
Лента представленна в виде базы данных
data(Адресс, Значение).
Головка представлена адрессом ячейки
pos(Адресс).
Собственно код с комментариями:
Для проверки в терминале пишем:
freest@PC:$ swipl -s <path.tofile>
?-run('Path.to.Brainfuck.code').
Протеструем на примере из Вики.
Hello World! на brainfuck
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++
.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.
------.--------.>+.>.
Должно выйти что-то вроде этого:
freest@PC:/media/C6984667984655D9$ swipl -s bf.pro
% library(swi_hooks) compiled into pce_swi_hooks 0.00 sec, 2,224 bytes
% /media/C6984667984655D9/bf.pro compiled 0.00 sec, 4,676 bytes
Welcome to SWI-Prolog (Multi-threaded, 32 bits, Version 5.10.4)
Copyright © 1990-2011 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
?- run('a.txt').
Hello World!
true.
?-
Опять немного теории от Вики
Маши
Вот они:
1. Интерпретатор языка brainfuck
2. Машина Тьюринга
Для начала нам требуется SWI-Prolog и немного свободного времени.
Задача 1. Интерпритатор языка brainfuck
Начнем с копи-паста из Википедии.
Brainfuck — один из известнейших эзотерических языков программирования, придуман Урбаном Мюллером в 1993 году для забавы. Язык имеет восемь команд, каждая из которых записывается одним символом. Исходный код программы на Brainfuck представляет собой последовательность этих символов без какого-либо дополнительного синтаксиса.
Машина, которой управляют команды Brainfuck, состоит из упорядоченного набора ячеек и указателя текущей ячейки, напоминая ленту и головку машины Тьюринга. Кроме того, подразумевается устройство общения с внешним миром (см. команды. и ,) через поток ввода и поток вывода.
Команды и их описание:
- > перейти к следующей ячейке
- < перейти к предыдущей ячейке
- + увеличить значение в текущей ячейке на 1
- — уменьшить значение в текущей ячейке на 1
- . напечатать значение из текущей ячейки
- , ввести извне значение и сохранить в текущей ячейке
- [ если значение текущей ячейки нуль, перейти вперёд по тексту программы на ячейку, следующую за соответствующей ] (с учётом вложенности)
- ] если значение текущей ячейки не нуль, перейти назад по тексту программы на символ [ (с учётом вложенности)
Лента представленна в виде базы данных
data(Адресс, Значение).
Головка представлена адрессом ячейки
pos(Адресс).
Собственно код с комментариями:
% ,
cout:-
%получаем адресс текщей ячейки
pos(Addr),
%получаем значение
data(Addr,Value),
%выводим его на экран
put_char([Value]).
% .
cin:-
%получаем адресс текущей ячейки
pos(Addr),
%удаляем ячейку из базы
retract(data(Addr,_)),
%читаем символ
get_single_char(Value),
%записываем назад в базу
assert(data(Addr,Value)).
% + -
add(AddValue):-
%получаем адресс
pos(Addr),
%удаляем ячейку
retract(data(Addr,Value)),
%увеличиваем значение на 1
NewValue is Value+AddValue,
%заносим новую ячейку
assert(data(Addr,NewValue)).
% > <
addr(Side):-
%удаляем текущий адресс
retract(pos(Addr)),
%инкрементриуем значение адресса
NewAddr is Addr+Side,
%заносим новое значение в базу
assert(pos(NewAddr)),
%ячейка была в базу или создаем новую
(data(NewAddr,_),!;assert(data(NewAddr,0))).
% ]
goto:-
%получаем адресс
pos(Addr),
%получаем значение и проверяем на равность 0
data(Addr,Value),Value==0,!,
%если 0, то удаляем указатель на начало последнего цикла
retract(circle([_|L])),
%сохраняем хвост
assert(circle(L)).
goto:-
%иначе переходим в начало цикла
circle([[N,_]|_]),
seeing(Stream),
seek(Stream,N,bof,_).
% [
loop:-
%удаляем и получаем указатели на начало цикла
retract(circle(L)),
seeing(Stream),
%определяем позицию в файле
character_count(Stream,Pos),
%Получаем значение ячейки
%(если оно = 0, то не выполняем тело цикла)
pos(Addr),
data(Addr,Value),
assert(circle([[Pos,Value]|L])).
do:-
%читаем команду
get_char(X),
%выполняем ее
step(X),
%проверяем на конец файла
not(at_end_of_stream),!,
do.
do:-
%если конец, то закрываем файл
seeing(Stream),
close(Stream),
seen.
step('['):-loop,!.
step(']'):-goto,!.
%это правило предназначено для "проскакивания цикла"
%(если в него мы зашли с нулевым значением)
step(_):-circle([[_,StartValue]|_]),StartValue==0,!.
step('>'):-addr( 1),!.
step('<'):-addr(-1),!.
step(','):-cin,!.
step('.'):-cout,!.
step('+'):-add( 1),!.
step('-'):-add(-1),!.
step(_).
run(Path):-
see(Path),
%удаляем мусор (оставленный после работы предидущей программы)
retractall(pos(_)),
retractall(data(_,_)),
retractall(circle(_)),
%начинаем с первой ячейки
assert(pos(1)),
%с значением 0
assert(data(1,0)),
assert(circle([])),do.
Для проверки в терминале пишем:
freest@PC:$ swipl -s <path.tofile>
?-run('Path.to.Brainfuck.code').
Протеструем на примере из Вики.
Hello World! на brainfuck
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++
.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.
------.--------.>+.>.
Должно выйти что-то вроде этого:
freest@PC:/media/C6984667984655D9$ swipl -s bf.pro
% library(swi_hooks) compiled into pce_swi_hooks 0.00 sec, 2,224 bytes
% /media/C6984667984655D9/bf.pro compiled 0.00 sec, 4,676 bytes
Welcome to SWI-Prolog (Multi-threaded, 32 bits, Version 5.10.4)
Copyright © 1990-2011 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
?- run('a.txt').
Hello World!
true.
?-
Задача 2. Машина Тьюринга
Опять немного теории от Вики
Маши
20.01.2012 18:35+0400