Created
April 27, 2023 15:08
-
-
Save tatut/d947e2d62a5a6fbb07d150f3ecf78948 to your computer and use it in GitHub Desktop.
Definite Clause Grammars, toy Logo interpreter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE> | |
<html> | |
<head> | |
<script src="swipl-bundle.js"></script> | |
<script type="text/prolog"> | |
:- use_module(library(dcg/basics)). | |
:- set_prolog_flag(double_quotes, chars). | |
turtle([]) --> []. % the empty program | |
turtle([Cmd|Cmds]) --> blanks, turtle_command(Cmd), blanks, turtle(Cmds). | |
turtle_command(Cmd) --> fd(Cmd) | rt(Cmd) | pen(Cmd) | repeat(Cmd). | |
fd(fd(N)) --> "fd", blanks, integer(N). | |
rt(rt(N)) --> "rt", blanks, integer(N). | |
pen(pen(R,G,B)) --> "pen", blanks, integer(R), blanks, integer(G), blanks, integer(B). | |
repeat(repeat(N,Cmds)) --> "repeat", blanks, integer(N), blanks, "[", turtle(Cmds), "]". | |
% Basic DCG state helper nonterminals | |
state(S), [S] --> [S]. | |
state(S0, S), [S] --> [S0]. | |
eval_all([]) --> []. | |
eval_all([Cmd|Cmds]) --> | |
eval(Cmd), | |
eval_all(Cmds). | |
eval(fd(N)) --> | |
% Previous state to new state | |
state(t(X1,Y1,C,Ang), t(X2,Y2,C,Ang)), | |
{ Rad is Ang * pi/180, | |
X2 is X1 + N * cos(Rad), | |
Y2 is Y1 + N * sin(Rad), | |
% Call JS interop on the JS global CTX | |
_ := 'CTX'.beginPath(), | |
_ := setcolor(C), | |
_ := 'CTX'.moveTo(X1,Y1), | |
_ := 'CTX'.lineTo(X2,Y2), | |
_ := 'CTX'.stroke() | |
}. | |
eval(rt(N)) --> | |
state(t(X,Y,C,Ang1), t(X,Y,C,Ang2)), | |
{ Ang2 is (Ang1 + N) mod 360 }. | |
eval(pen(R,G,B)) --> | |
state(t(X,Y,_,Ang), t(X,Y,[R,G,B],Ang)). | |
eval(repeat(0,_)) --> []. | |
eval(repeat(N,Cmds)) --> | |
eval_all(Cmds), | |
{ N1 is N - 1 }, | |
eval(repeat(N1, Cmds)). | |
run(ProgramString) :- | |
phrase(turtle(T), ProgramString), | |
writeln(parsed_program(T)), | |
phrase(eval_all(T), [t(160,100,[0, 200, 0],0)], [FinalState]). | |
</script> | |
<script> | |
new SWIPL({}).then((ok,_) => { | |
P = ok.prolog; | |
P.load_scripts(); | |
CTX = document.getElementById("logo").getContext('2d'); | |
}); | |
function setcolor([R,G,B]) { | |
CTX.strokeStyle = `rgb(${R},${G},${B})`; | |
} | |
function run() { | |
P.call(`run("${document.getElementById("program").value}")`) | |
} | |
</script> | |
</head> | |
<body> | |
<canvas id="logo" style="border: solid 1px black;" width="320" height="200"></canvas> | |
<div> | |
<input id="program" type="text" placeholder="Enter program"> | |
<button onclick="run()">Run</button> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See https://www.swi-prolog.org/pldoc/man?section=wasm on using SWI-Prolog from the browser.