Last active
December 18, 2015 05:39
-
-
Save hexx/5734520 to your computer and use it in GitHub Desktop.
This file contains 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
:- module ml. | |
:- interface. | |
:- import_module io. | |
:- pred main(io::di, io::uo) is cc_multi. | |
:- implementation. | |
:- import_module bool, int, string, list, pair, assoc_list, lex, regex. | |
main(!IO) :- | |
Lexer = lex.init(lexemes, lex.read_from_stdin, ignore(space)), | |
State0 = lex.start(Lexer, !.IO), | |
tokenize(State0, State, [], Tokens), | |
!:IO = lex.stop(State), | |
print("Tokens:\n ", Tokens, !IO), | |
( expr(Expr, Tokens, []) -> | |
print("Syntax tree:\n ", Expr, !IO), | |
( eval([], Expr, Value) -> | |
print("Value:\n ", Value, !IO) | |
; | |
io.write_string("Evaluation error\n", !IO) | |
) | |
; | |
io.write_string("Syntax error\n", !IO) | |
). | |
:- pred print(string::in, T::in, io::di, io::uo) is det. | |
print(Message, Result, !IO) :- | |
io.write_string(Message, !IO), | |
io.print(Result, !IO), | |
io.nl(!IO), | |
io.nl(!IO). | |
%-----------------------------------------------------------------------------% | |
% Lexical analysis | |
%-----------------------------------------------------------------------------% | |
:- type token | |
---> num_token(int) | |
; plus_token | |
; minus_token | |
; times_token | |
; bool_token(bool) | |
; lt_token | |
; if_token | |
; then_token | |
; else_token | |
; let_token | |
; in_token | |
; assign_token | |
; ident_token(string) | |
; fun_token | |
; arrow_token | |
; rec_token | |
; l_paren | |
; r_paren | |
; space. | |
:- func lexemes = list(lexeme(token)). | |
lexemes = [ | |
( nat -> (func(Match) = num_token(string.det_to_int(Match))) ), | |
( "+" -> return(plus_token) ), | |
( "-" -> return(minus_token) ), | |
( "*" -> return(times_token) ), | |
( "true" -> return(bool_token(yes)) ), | |
( "false" -> return(bool_token(no)) ), | |
( "<" -> return(lt_token) ), | |
( "if" -> return(if_token) ), | |
( "then" -> return(then_token) ), | |
( "else" -> return(else_token) ), | |
( "let" -> return(let_token) ), | |
( "=" -> return(assign_token) ), | |
( "in" -> return(in_token) ), | |
( "fun" -> return(fun_token) ), | |
( "->" -> return(arrow_token) ), | |
( "rec" -> return(rec_token) ), | |
( "(" -> return(l_paren) ), | |
( ")" -> return(r_paren) ), | |
( identifier -> (func(Match) = ident_token(Match)) ), | |
( whitespace -> return(space) ) | |
]. | |
:- pred tokenize(lexer_state(token, io)::di, lexer_state(token, io)::uo, list(token)::in, list(token)::out) is det. | |
tokenize(!LS, Xs, Ys) :- | |
tokenize1(!LS, Xs, Ys1), Ys = list.reverse(Ys1). | |
:- pred tokenize1(lexer_state(token, io)::di, lexer_state(token, io)::uo, list(token)::in, list(token)::out) is det. | |
tokenize1(!LS, Xs, Ys) :- | |
lex.read(Result, !LS), | |
( | |
Result = ok(Token), | |
tokenize1(!LS, [Token | Xs], Ys) | |
; | |
Result = eof, | |
Ys = Xs | |
; | |
Result = error(_, _), | |
Ys = Xs | |
). | |
%-----------------------------------------------------------------------------% | |
% Syntactic analysis | |
%-----------------------------------------------------------------------------% | |
:- type expr | |
---> num(int) | |
; bool(bool) | |
; plus(expr, expr) | |
; minus(expr, expr) | |
; times(expr, expr) | |
; lt(expr, expr) | |
; if(expr, expr, expr) | |
; var(string) | |
; let(string, expr, expr) | |
; fun(string, expr) | |
; app(expr, expr) | |
; rec_fun(string, string, expr, expr). | |
:- pred expr(expr::out, list(token)::in, list(token)::out) is nondet. | |
expr(E) --> | |
factor(E). | |
:- pred simple_expr(expr::out, list(token)::in, list(token)::out) is nondet. | |
simple_expr(E) --> | |
( | |
bool_expr(E) | |
; | |
num_expr(E) | |
; | |
if_expr(E) | |
; | |
let_expr(E) | |
; | |
var_expr(E) | |
; | |
fun_expr(E) | |
; | |
app_expr(E) | |
; | |
rec_fun_expr(E) | |
; | |
paren_expr(E) | |
). | |
:- pred factor(expr::out, list(token)::in, list(token)::out) is nondet. | |
factor(E) --> | |
factor2(E0), infix_expr(E0, E). | |
:- pred infix_expr(expr::in, expr::out, list(token)::in, list(token)::out) is nondet. | |
infix_expr(E0, E) --> | |
( | |
( [lt_token] -> factor2(E1), infix_expr(lt(E0, E1), E) ) | |
; | |
{ E = E0 } | |
). | |
:- pred factor2(expr::out, list(token)::in, list(token)::out) is nondet. | |
factor2(E) --> | |
factor3(E0), infix_expr2(E0, E). | |
:- pred infix_expr2(expr::in, expr::out, list(token)::in, list(token)::out) is nondet. | |
infix_expr2(E0, E) --> | |
( | |
( [plus_token] -> factor3(E1), infix_expr2(plus(E0, E1), E) ) | |
; | |
( [minus_token] -> factor3(E1), infix_expr2(minus(E0, E1), E) ) | |
; | |
{ E = E0 } | |
). | |
:- pred factor3(expr::out, list(token)::in, list(token)::out) is nondet. | |
factor3(E) --> | |
simple_expr(E0), infix_expr3(E0, E). | |
:- pred infix_expr3(expr::in, expr::out, list(token)::in, list(token)::out) is nondet. | |
infix_expr3(E0, E) --> | |
( | |
( [times_token] -> simple_expr(E1), infix_expr3(times(E0, E1), E) ) | |
; | |
{ E = E0 } | |
). | |
:- pred num_expr(expr::out, list(token)::in, list(token)::out) is semidet. | |
num_expr(E) --> | |
[num_token(X)], { E = num(X) }. | |
:- pred bool_expr(expr::out, list(token)::in, list(token)::out) is semidet. | |
bool_expr(E) --> | |
[bool_token(X)], { E = bool(X) }. | |
:- pred if_expr(expr::out, list(token)::in, list(token)::out) is nondet. | |
if_expr(E) --> | |
[if_token], expr(X), [then_token], expr(Y), [else_token], expr(Z), { E = if(X, Y, Z) }. | |
:- pred var_expr(expr::out, list(token)::in, list(token)::out) is semidet. | |
var_expr(E) --> | |
[ident_token(X)], { E = var(X) }. | |
:- pred let_expr(expr::out, list(token)::in, list(token)::out) is nondet. | |
let_expr(E) --> | |
[let_token], [ident_token(X)], [assign_token], expr(Y), [in_token], expr(Z), { E = let(X, Y, Z) }. | |
:- pred fun_expr(expr::out, list(token)::in, list(token)::out) is nondet. | |
fun_expr(E) --> | |
[fun_token], [ident_token(X)], [arrow_token], expr(Y), { E = fun(X, Y) }. | |
:- pred app_expr(expr::out, list(token)::in, list(token)::out) is nondet. | |
app_expr(E) --> | |
var_expr(E1), expr(Y), { E = app(E1, Y) }. | |
:- pred rec_fun_expr(expr::out, list(token)::in, list(token)::out) is nondet. | |
rec_fun_expr(E) --> | |
[let_token], [rec_token], [ident_token(X)], [assign_token], | |
[fun_token], [ident_token(Y)], [arrow_token], expr(E1), [in_token], expr(E2), | |
{ E = rec_fun(X, Y, E1, E2) }. | |
:- pred paren_expr(expr::out, list(token)::in, list(token)::out) is nondet. | |
paren_expr(E) --> | |
[l_paren], expr(E), [r_paren]. | |
%-----------------------------------------------------------------------------% | |
% Evaluation | |
%-----------------------------------------------------------------------------% | |
:- type env == assoc_list(string, value). | |
:- type value | |
---> num_value(int) | |
; bool_value(bool) | |
; fun_value(env, string, expr) | |
; rec_fun_value(env, string, string, expr) | |
; error. | |
:- pred eval(env::in, expr::in, value::out) is nondet. | |
eval(Env, Expr, Value) :- | |
( | |
Expr = num(X), | |
Value = num_value(X) | |
; | |
Expr = bool(X), | |
Value = bool_value(X) | |
; | |
Expr = plus(X, Y), eval(Env, X, V1), eval(Env, Y, V2), | |
V1 = num_value(N1), V2 = num_value(N2), | |
Value = num_value(N1 + N2) | |
; | |
Expr = minus(X, Y), eval(Env, X, V1), eval(Env, Y, V2), | |
V1 = num_value(N1), V2 = num_value(N2), | |
Value = num_value(N1 - N2) | |
; | |
Expr = times(X, Y), eval(Env, X, V1), eval(Env, Y, V2), | |
V1 = num_value(N1), V2 = num_value(N2), | |
Value = num_value(N1 * N2) | |
; | |
Expr = lt(X, Y), eval(Env, X, V1), eval(Env, Y, V2), | |
V1 = num_value(N1), V2 = num_value(N2), | |
Value = bool_value(pred_to_bool(N1 < N2)) | |
; | |
Expr = if(X, Y, Z), eval(Env, X, V1), | |
( | |
V1 = bool_value(yes), eval(Env, Y, Value) | |
; | |
V1 = bool_value(no), eval(Env, Z, Value) | |
) | |
; | |
Expr = var(X), assoc_list.search(Env, X, Value) | |
; | |
Expr = let(X, Y, Z), eval(Env, Y, V), eval([pair(X, V) | Env], Z, Value) | |
; | |
Expr = fun(X, Y), | |
Value = fun_value(Env, X, Y) | |
; | |
Expr = app(X, Y), eval(Env, X, V1), eval(Env, Y, V2), | |
( | |
fun_value(E, F, B) = V1, | |
eval([pair(F, V2)|E], B, Value) | |
; | |
rec_fun_value(Env1, F1, F2, B) = V1, | |
eval([pair(F1, V1)|[pair(F2, V2)|Env1]], B, Value) | |
) | |
; | |
Expr = rec_fun(X, Y, E1, E2), eval([pair(X, rec_fun_value(Env, X, Y, E1)) | Env], E2, Value) | |
). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment