Tigerインタプリタで逐次実行できるようにしたい
#OCaml
from タイガーブック
以下のように( ) で囲った式を ; で区切ることで、複数の式を逐次実行することができる。
(print("hello"); print("world"); 4649)
code:diff
diff --git a/lib/eval.ml b/lib/eval.ml
index e1d7083..d34e630 100644
--- a/lib/eval.ml
+++ b/lib/eval.ml
@@ -28,6 +28,13 @@ let rec f expr env: val_t * table =
| Some else' -> f else' env
| None -> (UnitVal, env))
| _ -> failwith "type error")
+ | Syntax.SeqExp exprs ->
+ (match exprs with
+ | [] -> (UnitVal, env)
+ | expr::[] -> f expr env
+ | expr::exprs ->
+ let _, env = f expr env in
+ f (Syntax.SeqExp exprs) env)
| Syntax.CallExp { id; args } ->
(let func = List.assoc id env in
match func with
diff --git a/lib/lexer.mll b/lib/lexer.mll
index 7d1ebed..34e720c 100644
--- a/lib/lexer.mll
+++ b/lib/lexer.mll
@@ -38,6 +38,7 @@ rule token = parse
| ")" { Parser.RPAREN }
| "," { Parser.COMMA }
| ":" { Parser.COLON }
+ | ";" { Parser.SEMICOLON }
| digit+ { Parser.INT(int_of_string(Lexing.lexeme lexbuf)) }
| letter (letter|digit)* { Parser.ID(Lexing.lexeme lexbuf) }
| "\"" { string_literal (Buffer.create 0) lexbuf }
diff --git a/lib/parser.mly b/lib/parser.mly
index 5405e28..63b8283 100644
--- a/lib/parser.mly
+++ b/lib/parser.mly
@@ -10,7 +10,7 @@
%token EQ NEQ LT LE GT GE
%token LET IN END IF THEN ELSE
%token VAR FUNCTION ASSIGN
-%token LPAREN RPAREN COMMA COLON
+%token LPAREN RPAREN COMMA COLON SEMICOLON
%token EOF
// あとで使う
@@ -40,9 +40,8 @@ program: exp EOF { $1 }
exp:
INT { Syntax.IntExp($1) }
| STRING { Syntax.StringExp($1) }
-| LPAREN RPAREN { Syntax.UnitExp }
| ID { Syntax.VarExp($1) }
-| LPAREN exp RPAREN { $2 }
+| LPAREN exps RPAREN { Syntax.SeqExp($2) }
| exp PLUS exp { Syntax.OpExp { left = $1; op = Syntax.PlusOp; right = $3} }
| exp MINUS exp { Syntax.OpExp { left = $1; op = Syntax.MinusOp; right = $3} }
| exp TIMES exp { Syntax.OpExp { left = $1; op = Syntax.TimesOp; right = $3} }
@@ -59,6 +58,11 @@ exp:
| IF exp THEN exp { Syntax.IfExp { test = $2; then' = $4; else' = None } }
| IF exp THEN exp ELSE exp { Syntax.IfExp { test = $2; then' = $4; else' = Some ($6) } }
+exps:
+ { [] } // 空の場合
+| exps exp { $1 @ $2 }
+| exps SEMICOLON exp { $1 @ $3 }
+
args:
{ [] } // 空の場合
| exp { $1 }
diff --git a/lib/syntax.ml b/lib/syntax.ml
index 4ce1f99..1570bda 100644
--- a/lib/syntax.ml
+++ b/lib/syntax.ml
@@ -21,6 +21,7 @@ and op_t =
| CallExp of { id: string; args: t list } (* 関数呼び出し *)
| OpExp of { left: t; op: op_t; right: t } (* 二項演算子 *)
| IfExp of { test: t; then': t; else': t option } (* if文 *)
+ | SeqExp of t list (* 式の逐次実行 *)
and dec_t =
| VarDec of symbol * t (* 変数宣言 *)
diff --git a/test/tiger_test.expected b/test/tiger_test.expected
index 46a52c8..de9525b 100644
--- a/test/tiger_test.expected
+++ b/test/tiger_test.expected
@@ -31,3 +31,5 @@ Hello World!!
Goodbye World!!
result: 55
result: -30
+ABC
+result: ()
diff --git a/test/tiger_test.ml b/test/tiger_test.ml
index a09b543..2d2ffa3 100644
--- a/test/tiger_test.ml
+++ b/test/tiger_test.ml
@@ -305,7 +305,7 @@ let () =
(* 負の整数リテラル *)
let () =
let src = {|
- let var a := -10
+ let var a := 20
in -10 + -a
end
|}
@@ -313,3 +313,20 @@ let () =
print_string "result: ";
Tiger.Eval.print_val (eval src);
print_newline ()
+
+(* 逐次実行 *)
+let () =
+ let src = {|
+ (print("A");
+ print("B");
+ print("C");
+ print("\n"))
+ |}
+ in ignore(eval src)
+
+(* Unit を返す *)
+let () =
+ let src = "( )" in
+ print_string "result: ";
+ Tiger.Eval.print_val (eval src);
+ print_newline ()