Something went wrong. Try again.
A prose-themed programming language optimized for minimizing symbols.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230% :- use_rendering(svgtree). % Only works in SWISH.swi-prolog.org
%%%%% Token Parser %%%%%%
% v3 (Heavily inspired by M2.1 - slide 59)factor(factor_digit(F)) --> digit(F).factor(factor_identifier(F)) --> identifier(F).factor(factor_expression(F)) --> ['('], expr(F), [')'].
term(term_factor(T)) --> factor(T).term(term_times(T1, T2)) --> [multiplication of], factor(T1), [with], term(T2).term(term_divide(T1, T2)) --> [division of], factor(T1), [with], term(T2).
expr(expr_term(E)) --> term(E).expr(expr_plus(E1, E2)) --> [addition of], term(E1), [with], expr(E2).expr(expr_minus(E1, E2)) --> [subtraction of], term(E1), [with], expr(E2).expr(expr_assign(A)) --> assignment(A).
boolean(true) --> [true].boolean(false) --> [false].boolean(not(B)) --> [not], boolean(B).boolean(equals(E1, E2)) --> expr(E1), [=], expr(E2).boolean(is_greater_than(E1, E2)) --> expr(E1), [is-greater-than], expr(E2).boolean(is_less_than(E1, E2)) --> expr(E1), [is-less-than], expr(E2).
assignment(assign(I, E)) --> identifier(I), [equals], expr(E).ternary(if(B, T, F)) --> [if], boolean(B), [then], command(T), [else], command(F), [endif].loop(while(B, C)) --> [while], boolean(B), [do], command(C), [endwhile].loop(for(I1, I2, C)) --> [for], identifier(I1), [from], identifier(I2), [do], command(C), [endfor].
command(C) --> assignment(C).command(C) --> ternary(C).command(C) --> loop(C).command(C) --> block(C).command(cmd(C1, C2)) --> assignment(C1), [;], command(C2).command(cmd(C1, C2)) --> ternary(C1), [;], command(C2).command(cmd(C1, C2)) --> loop(C1), [;], command(C2).command(cmd(C1, C2)) --> block(C1), [;], command(C2).
constant(const(I, N)) --> [const], identifier(I), [=], digit(N).variable(var(I)) --> [var], identifier(I).
declaration(D) --> constant(D).declaration(D) --> variable(D).declaration(decl(D1, D2)) --> constant(D1), [;], declaration(D2).declaration(decl(D1, D2)) --> variable(D1), [;], declaration(D2).
block(blk(D, C)) --> [begin], declaration(D), [;], command(C), [end].
program(prog(P)) --> block(P), ['.'].
/** * eval(+Node, +EnvIn, -EnvOut, -ValueOut) * * Evaluates the parse tree rooted at Node, with the environment EnvIn, * and returns the environment EnvOut and the value ValueOut. * * The environment is a list of pairs (Identifier, Value) where Identifier * is a string and Value is an integer. * */ eval(prog(P), EnvIn, EnvOut, ValueOut) :- eval(P, EnvIn, EnvOut, ValueOut).
eval(blk(D, C), EnvIn, EnvOut, ValueOut) :- eval(D, EnvIn, EnvDecl, _ValueOut), eval(C, EnvDecl, EnvOut, ValueOut).
eval(var(I), EnvIn, EnvOut, _) :- declare(I, EnvIn, EnvOut).eval(const(I, N), EnvIn, EnvOut, N) :- update(I, N, EnvIn, EnvOut).eval(decl(D1, D2), EnvIn, EnvOut, ValueOut) :- eval(D1, EnvIn, EnvTemp, _ValueOut), eval(D2, EnvTemp, EnvOut, ValueOut).
eval(cmd(C1, C2), EnvIn, EnvOut, ValueOut) :- eval(C1, EnvIn, EnvTemp, _ValueOut), eval(C2, EnvTemp, EnvOut, ValueOut).
eval(assign(I, E), EnvIn, EnvOut, ValueOut) :- eval(E, EnvIn, EnvTemp, ValueOut), update(I, ValueOut, EnvTemp, EnvOut).
eval(if(B, T, _), EnvIn, EnvOut, ValueOut) :- eval(B, EnvIn, EnvTemp, true), eval(T, EnvTemp, EnvOut, ValueOut).eval(if(B, _, F), EnvIn, EnvOut, ValueOut) :- eval(B, EnvIn, EnvTemp, false), eval(F, EnvTemp, EnvOut, ValueOut).
eval(while(B, C), EnvIn, EnvOut, ValueOut) :- eval(B, EnvIn, EnvTemp, true), eval(C, EnvTemp, EnvTemp2, _ValueOut), eval(while(B, C), EnvTemp2, EnvOut, ValueOut).eval(while(B, _), EnvIn, EnvOut, _ValueOut) :- eval(B, EnvIn, EnvOut, false).
eval(expr_plus(Term, Expression), EnvIn, EnvOut, ValueOut) :- eval(Term, EnvIn, EnvTemp, ValTerm), eval(Expression, EnvTemp, EnvOut, ValExpr), ValueOut is ValTerm + ValExpr.eval(expr_minus(Term, Expression), EnvIn, EnvOut, ValueOut) :- eval(Term, EnvIn, EnvTemp, ValTerm), eval(Expression, EnvTemp, EnvOut, ValExpr), ValueOut is ValTerm + (0 - ValExpr).eval(expr_term(T), EnvIn, EnvOut, ValueOut) :- eval(T, EnvIn, EnvOut, ValueOut).eval(expr_assign(A), EnvIn, EnvOut, ValueOut) :- eval(A, EnvIn, EnvOut, ValueOut).
eval(term_times(Factor, Term), EnvIn, Env2Out, ValueOut) :- eval(Factor, EnvIn, Env1Out, Val1Out), eval(Term, Env1Out, Env2Out, Val2Out), ValueOut is Val1Out * Val2Out.eval(term_divide(Factor, Term), EnvIn, Env2Out, ValueOut) :- eval(Factor, EnvIn, Env1Out, Val1Out), eval(Term, Env1Out, Env2Out, Val2Out), ValueOut is Val1Out * (1 / Val2Out).eval(term_factor(F), EnvIn, EnvOut, ValueOut) :- eval(F, EnvIn, EnvOut, ValueOut).
eval(factor_digit(D), EnvIn, EnvIn, D).eval(factor_identifier(I), EnvIn, EnvIn, Value) :- lookup(I, EnvIn, Value).eval(factor_expression(E), EnvIn, EnvOut, Value) :- eval(E, EnvIn, EnvOut, Value).
eval(true, EnvIn, EnvIn, true).eval(false, EnvIn, EnvIn, false).eval(not(B), EnvIn, EnvOut, false) :- eval(B, EnvIn, EnvOut, true).eval(not(B), EnvIn, EnvOut, true) :- eval(B, EnvIn, EnvOut, false).eval(equals(E1, E2), EnvIn, EnvOut, true) :- eval(E1, EnvIn, EnvTemp, ValueOut), eval(E2, EnvTemp, EnvOut, ValueOut).eval(equals(E1, E2), EnvIn, EnvOut, false) :- eval(E1, EnvIn, EnvTemp, ValueOut1), eval(E2, EnvTemp, EnvOut, ValueOut2), ValueOut1 =\= ValueOut2.
/** * lookup(+Identifier, +Env, -Value) * * Looks up the Value of Identifier in Env. */lookup(Identifier, [(Identifier, Value) | _], Value).lookup(Identifier, [(OtherIdentifier, _) | RemainingEnvironment], Value) :- Identifier \= OtherIdentifier, lookup(Identifier, RemainingEnvironment, Value).
/** * declare(+Identifier, +EnvIn, -EnvOut) * * Adds a new binding (Identifier, _) to EnvIn and returns EnvOut. * * If Identifier is already bound in EnvIn, it is not rebound. */declare(Identifier, [], [(Identifier, _)]).declare( Identifier, [(Identifier, Value) | RemainingEnvironment], [(Identifier, Value) | RemainingEnvironment]).declare(Identifier, [H | RemainingEnvironment], [H | NewEnvironment]) :- declare(Identifier, RemainingEnvironment, NewEnvironment).
/** * update(+Identifier, +Value, +EnvIn, -EnvOut) * * Updates the binding of Identifier in EnvIn to Value and returns EnvOut. */update(Identifier, Value, [], [(Identifier, Value)]).update( Identifier, Value, [(Identifier, _) | RemainingEnvironment], [(Identifier, Value) | RemainingEnvironment]).update( Identifier, Value, [(OtherIdentifier, OtherValue) | RemainingEnvironment], [(OtherIdentifier, OtherValue) | NewEnvironment]) :- Identifier \= OtherIdentifier, update(Identifier, Value, RemainingEnvironment, NewEnvironment).
/** * program_eval(+Program, +InitialX, +InitialY, -FinalZ) * * Evaluates the Program with the initial value of X and Y * and returns the final value of Z. */program_eval(P, X, Y, Z) :- update(x, X, [], EnvX), update(y, Y, EnvX, EnvY), eval(P, EnvY, EnvOut, _ValueOut), lookup(z, EnvOut, Z).
digit(0) --> [0].digit(1) --> [1].digit(2) --> [2].digit(3) --> [3].digit(4) --> [4].digit(5) --> [5].digit(6) --> [6].digit(7) --> [7].digit(8) --> [8].digit(9) --> [9].
identifier(WORD) --> { var(WORD), ! }, chars(CHARS), { atom_codes(WORD, CHARS) }.identifier(WORD) --> { nonvar(WORD) }, { atom_codes(WORD, CHARS) }, chars(CHARS).
chars([X|Y]) --> char(X), chars(Y).chars([]) --> [].
char(X) --> [X], { is_char(X) }.
is_char(X) :- X >= 0'a, X =< 0'z, !.is_char(X) :- X >= 0'A, X =< 0'Z, !.is_char(X) :- X >= 0'0, X =< 0'9, !.is_char(0'_).