Commit 1ce77b12 authored by Damien.Morard's avatar Damien.Morard
Browse files

Add brainfuck prolog

parent 023a6adb
% ---------------------------------------------------------------- %
% ---------------------------- Syntax ---------------------------- %
% ---------------------------------------------------------------- %
% Symbol of our syntax
bf(">").
bf("<").
bf("+").
bf("-").
bf(".").
bf(",").
% Program syntax
prog([], X, X).
% prog(["[", P, "]" | T]) :-
% prog(P), prog(T).
prog(["["|T], X, Y) :-
Xp is X+1,
prog(T, Xp, Y).
prog(["]"|T], X, Y) :-
Yp is Y+1,
prog(T, X, Yp).
prog([H|T], X, Y) :-
bf(H), prog(T, X, Y).
progP(P) :-
prog(P, 0, 0).
% ---------------------------------------------------------------- %
% -------------------------- Semantic ---------------------------- %
% ---------------------------------------------------------------- %
% Return the value depends on the pointer
findVal([H|_], 0, H).
findVal([_|T], P, Res) :-
findVal(T, Pp, Res), P is Pp + 1.
% Count number of elements in a list (need it to know number of instruction in a prog)
count([], 0).
count([_|T], Res) :-
count(T, R), Res is R + 1.
% Inc the value in the table at the position Pt
incValue([H|T], 0, [Hp|T]) :-
Hp is H + 1.
incValue([H|T], Pt, [H|Res]) :-
incValue(T, Ptp, Res),
Pt is Ptp + 1.
% Dec the value in the table at the position Pt
decValue([0|T], 0, [0|T]).
decValue([H|T], 0, [Hp|T]) :-
H > 0,
Hp is H - 1.
decValue([H|T], Pt, [H|Res]) :-
decValue(T, Ptp, Res), Pt is Ptp + 1.
% ---------------------------------------------------------------- %
% Giving a position Pi, we return a Program where only the elements after Pi in the prog
% Element in Pi position is not returned. (Put 1 instead of 0 if you want element in Pi position)
cutProgram(P, 0, P).
cutProgram([_|T], Pi, SubP) :-
Pip is Pi - 1,
cutProgram(T, Pip, SubP).
% Return the close bracket depending on the open bracket.
% Does not necessarily return the first close bracket
posCloseBracket(["]"|_], 1, 0).
posCloseBracket(["["|T], Nb, Res) :-
Nbp is Nb + 1,
posCloseBracket(T, Nbp, R),
Res is R + 1.
posCloseBracket(["]"|T], Nb, Res) :-
Nbp is Nb - 1,
posCloseBracket(T, Nbp, R),
Res is R + 1.
posCloseBracket([H|T], Nb, Res) :-
H \= "[",
H \= "]",
posCloseBracket(T, Nb, R),
Res is R + 1.
% posCB find the next bracket depending on the position of Pi and the open bracket
% Normally Pi point on an open bracket instruction.
% To return the position of the next good bracket, we count from Pi the number
% of elements we browse until we find the good close bracket.
% We add this result with Pi and we obtain the position of the next close bracket
% in the program P
posCB(P, Pi, Res) :-
cutProgram(P, Pi, SubP),
posCloseBracket(SubP, 0 , SubR),
Res is Pi + SubR.
% ---------------------------------------------------------------- %
% Reverse a list with a define nb of elements
reverse([H|_], 0, [H]).
reverse([H], _, [H]).
reverse([H|_], 1, [H]).
reverse([H|T], Nb, Res) :-
Nb > 1,
Nbp is Nb - 1,
reverse(T, Nbp, Resp),
append(Resp, [H], Res).
% Return the open bracket depending on the close bracket.
% Does not necessarily return the first open bracket
posOpenBracket(["["|_], 1, 0).
posOpenBracket(["]"|T], Nb, Res) :-
Nbp is Nb + 1,
posOpenBracket(T, Nbp, R),
Res is R + 1.
posOpenBracket(["["|T], Nb, Res) :-
Nbp is Nb - 1,
posOpenBracket(T, Nbp, R),
Res is R + 1.
posOpenBracket([H|T], Nb, Res) :-
H \= "[",
H \= "]",
posOpenBracket(T, Nb, R),
Res is R + 1.
% posOB find the last bracket depending on the position of the close bracket
% P is a Program, Pi the position of the close bracket in the program, and Res
% the result
% Example: posOB(["+", "-", "[", "[", "+", "+", "]", "]"], 7, Res).
% Res = 2. % Not 3
% The method to find the last bracket is to reverse P (which is a program
% and representend by a list in Prolog). However we cut the list at the Pi position,
% keep elements before and after this we reverse the list.
% Finally we try to find the first open bracket (in the reverse list) and we return its position.
posOB(P, Pi, Res) :-
reverse(P, Pi+1, Prog),
posOpenBracket(Prog, 0, R),
Res is Pi - R.
% ---------------------------------------------------------------- %
% When it's finished
eval(_, _, _, _, "").
% When we have ">", we have two case. If we have already declared
% the case in the table, we just move the pointer on it
% Otherwise we need to increase the size of our table and initialize with 0.
eval(Pi, Pt, Tab, Prog, ">") :-
Pip is Pi + 1,
Ptp is Pt + 1,
count(Tab, Nb),
Ptp + 1 =< Nb,
findVal(Prog, Pip, Inst),
eval(Pip, Ptp, Tab, Prog, Inst).
eval(Pi, Pt, Tab, Prog, ">") :-
Pip is Pi + 1,
Ptp is Pt + 1,
count(Tab, Nb),
Ptp + 1 > Nb,
append(Tab, [0], Tabp),
findVal(Prog, Pip, Inst),
eval(Pip, Ptp, Tabp, Prog, Inst).
% When we have "<", we have two cases.
% If we have Pt on 0, we stay on 0 as many times as needed
% Otherwise we decrement Pt by 1.
eval(Pi, Pt, Tab, Prog, "<") :-
Pt > 0,
Pip is Pi + 1,
Ptp is Pt - 1,
findVal(Prog, Pip, Inst),
eval(Pip, Ptp, Tab, Prog, Inst).
eval(Pi, Pt, Tab, Prog, "<") :-
Pip is Pi + 1,
Pt == 0,
findVal(Prog, Pip, Inst),
eval(Pip, Pt, Tab, Prog, Inst).
% We increment the value at the position Pt on Tab
eval(Pi, Pt, Tab, Prog, "+") :-
Pip is Pi + 1,
incValue(Tab, Pt, Tabp),
findVal(Prog, Pip, Inst),
eval(Pip, Pt, Tabp, Prog, Inst).
% We decrement the value at the position Pt on Tab
eval(Pi, Pt, Tab, Prog, "-") :-
Pip is Pi + 1,
decValue(Tab, Pt, Tabp),
findVal(Prog, Pip, Inst),
eval(Pip, Pt, Tabp, Prog, Inst).
% We print the result
eval(Pi, Pt, Tab, Prog, ".") :-
Pip is Pi + 1,
findVal(Prog, Pip, Inst),
print(Tab),
eval(Pip, Pt, Tab, Prog, Inst).
% Case where Value on Pt (in the table) is different from 0
eval(Pi, Pt, Tab, Prog, "[") :-
findVal(Tab, Pt, Res),
Res \= 0,
Pip is Pi + 1,
findVal(Prog, Pip, Inst),
eval(Pip, Pt, Tab, Prog, Inst).
% Case where Value on Pt (in the table) is 0
eval(Pi, Pt, Tab, Prog, "[") :-
findVal(Tab, Pt, Res),
Res == 0,
posCB(Prog, Pi, NextPos),
NextP is NextPos + 1,
findVal(Prog, NextP, Inst),
eval(NextP, Pt, Tab, Prog, Inst).
% Case where Value on Pt (in the table) is different from 0
eval(Pi, Pt, Tab, Prog, "]") :-
findVal(Tab, Pt, Res),
Res \= 0,
posOB(Prog, Pi, NextPos),
NextP is NextPos + 1,
findVal(Prog, NextP, Inst),
eval(NextP, Pt, Tab, Prog, Inst).
% Case where Value on Pt (in the table) is 0
eval(Pi, Pt, Tab, Prog, "]") :-
findVal(Tab, Pt, Res),
Res == 0,
Pip is Pi + 1,
findVal(Prog, Pip, Inst),
eval(Pip, Pt, Tab, Prog, Inst).
% Function to call to test his own program
% I introduced "" to know when it's the end of the file
evalp(Prog, Tab) :-
progP(Prog),
append(Prog, [""], ProgEOF),
findVal(Prog, 0, Inst),
eval(0, 0, Tab, ProgEOF, Inst).
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment