Counter: 4150,
today: 1,
yesterday: 0
Chapter 5 の PROGRAM
PROGRAM
tiger.grm 修正後
structure A = Absyn
%%
%term
EOF
| ID of string
| INT of int | STRING of string
| COMMA | COLON | SEMICOLON | LPAREN | RPAREN | LBRACK | RBRACK
| LBRACE | RBRACE | DOT
| PLUS | MINUS | TIMES | DIVIDE | EQ | NEQ | LT | LE | GT | GE
| AND | OR | ASSIGN
| ARRAY | IF | THEN | ELSE | WHILE | FOR | TO | DO | LET | IN | END | OF
| BREAK | NIL
| FUNCTION | VAR | TYPE
| UNARYMINUS
%nonterm exp of A.exp
| program of A.exp
| lvalue of A.var
| novalue of A.exp
| sequensing of A.exp
| expsemilist of (A.exp * A.pos) list
| functionCall of A.exp
| explistopt of A.exp list
| explist of A.exp list
| opExpr of A.exp
| recordCreate of A.exp
| typeid of A.symbol
| idExpList of (A.symbol * A.exp * A.pos) list
| recField of (A.symbol * A.exp * A.pos)
| arrayCreate of A.exp
| assignment of A.exp
| ifThenElse of A.exp
| ifThen of A.exp
| whileClause of A.exp
| forClause of A.exp
| letexp of A.exp
| expseq of (A.exp * A.pos) list
| parentheses of A.exp
| decs of A.dec list
| dec of A.dec
| tydeclist of {name:A.symbol, pos:pos, ty:A.ty} list
| tydec of {name:A.symbol, pos:pos, ty:A.ty}
| ty of A.ty
| tyfields of A.field list
| tyfieldlist of A.field list
| tyfield of A.field
| vardec of A.dec
| fundec of A.fundec
| fundeclist of A.fundec list
(* | valuelessExp | stringCmp | precedenceOp | associativityOp
| arrRecAssign | extent *)
%pos int
%verbose
%start program
%eop EOF
%noshift EOF
%name Tiger
%keyword WHILE FOR TO BREAK LET IN END FUNCTION VAR TYPE ARRAY IF THEN ELSE
DO OF NIL
%prefer THEN ELSE LPAREN
%value ID ("bogus")
%value INT (1)
%value STRING ("")
(*%nonassoc ASSIGN DO OF THEN ELSE*)
%nonassoc ASSIGN
%left DO THEN OF
%left ELSE
%left OR
%left AND
%nonassoc EQ NEQ LT LE GT GE
%left PLUS MINUS
%left TIMES DIVIDE
%left UNARYMINUS
%%
program : exp (exp)
(***** Expressions *****)
exp: lvalue (A.VarExp lvalue)
| ID (A.VarExp (A.SimpleVar (Symbol.symbol ID, IDleft)))
| novalue (novalue)
| NIL (A.NilExp)
| sequensing (sequensing)
| INT (A.IntExp INT)
| STRING (A.StringExp (STRING, STRINGleft))
| functionCall (functionCall)
| opExpr (opExpr)
| recordCreate (recordCreate)
| arrayCreate (arrayCreate)
| assignment (assignment)
| ifThenElse (ifThenElse)
| ifThen (ifThen)
| whileClause (whileClause)
| forClause (forClause)
| BREAK (A.BreakExp BREAKleft)
| letexp (letexp)
| parentheses (parentheses)
lvalue : ID DOT ID (A.FieldVar (A.SimpleVar(Symbol.symbol ID1, ID1left), Symbol.symbol ID2, ID2left))
| ID LBRACK exp RBRACK (A.SubscriptVar (A.SimpleVar(Symbol.symbol ID, IDleft), exp, IDleft))
| lvalue DOT ID (A.FieldVar (lvalue, Symbol.symbol ID, IDleft)) (*fix*)
| lvalue LBRACK exp RBRACK (A.SubscriptVar (lvalue, exp, lvalueleft))
novalue : LPAREN RPAREN (A.SeqExp [])
sequensing : LPAREN expsemilist RPAREN (A.SeqExp expsemilist)
expsemilist : expsemilist SEMICOLON exp (expsemilist @ [(exp, expleft)])
| exp SEMICOLON exp ((exp1,exp1left) :: [(exp2, exp2left)]) (* Excl. Parentheses *)
functionCall : ID LPAREN explistopt RPAREN (A.CallExp {func=Symbol.symbol ID, args=explistopt, pos=IDleft})
explistopt : explist (explist)
| ([]) (* empty *)
explist : explist COMMA exp (explist @ [exp])
| exp ([exp])
opExpr : exp DIVIDE exp (A.OpExp {left=exp1,oper=A.DivideOp,right=exp2,pos=DIVIDEleft})
| exp TIMES exp (A.OpExp {left=exp1,oper=A.TimesOp ,right=exp2,pos=TIMESleft})
| exp MINUS exp (A.OpExp {left=exp1,oper=A.MinusOp ,right=exp2,pos=MINUSleft})
| exp PLUS exp (A.OpExp {left=exp1,oper=A.PlusOp ,right=exp2,pos=PLUSleft})
| exp EQ exp (A.OpExp {left=exp1, oper=A.EqOp, right=exp2, pos=EQleft})
| exp NEQ exp (A.OpExp {left=exp1, oper=A.NeqOp, right=exp2, pos=NEQleft})
| exp GE exp (A.OpExp {left=exp1, oper=A.GeOp, right=exp2, pos=GEleft})
| exp GT exp (A.OpExp {left=exp1, oper=A.GtOp, right=exp2, pos=GTleft})
| exp LE exp (A.OpExp {left=exp1, oper=A.LeOp, right=exp2, pos=LEleft})
| exp LT exp (A.OpExp {left=exp1, oper=A.LtOp, right=exp2, pos=LTleft})
| exp AND exp (A.IfExp {test=exp1, then'=exp2, else'=SOME (A.IntExp 0), pos=ANDleft})
| exp OR exp (A.IfExp {test=exp1, then'=A.IntExp 1, else'=SOME exp2, pos=ORleft})
| MINUS exp %prec UNARYMINUS (A.OpExp {left=A.IntExp 0, oper=A.MinusOp, right=exp1, pos=MINUSleft})
(*recordCreate : typeid LBRACE idExpList RBRACE () (* typeid *)*)
recordCreate : ID LBRACE idExpList RBRACE
(A.RecordExp {fields=idExpList, typ=Symbol.symbol ID, pos=IDleft}) (* typeid *)
| ID LBRACE RBRACE (A.RecordExp {fields=[], typ=Symbol.symbol ID, pos=IDleft}) (* empty record*)
typeid : ID (Symbol.symbol ID)
idExpList : recField ([recField])
| idExpList COMMA recField ( idExpList @ [recField]) (* Correct! *)
recField : ID EQ exp ((Symbol.symbol ID, exp, IDleft))
(*arrayCreate : typeid LBRACK exp RBRACK OF exp () (* typeid *)*)
arrayCreate : ID LBRACK exp RBRACK OF exp
(A.ArrayExp {typ=Symbol.symbol ID, size=exp1, init=exp2, pos=IDleft})
(* typeid *)
assignment : lvalue ASSIGN exp
(A.AssignExp {var=lvalue, exp=exp, pos=ASSIGNleft})
| ID ASSIGN exp
(A.AssignExp {var=(A.SimpleVar(Symbol.symbol ID, IDleft)), exp=exp, pos=ASSIGNleft})
ifThen : IF exp THEN exp
(A.IfExp {test=exp1, then'=exp2, pos=IFleft, else'=NONE})
ifThenElse : IF exp THEN exp ELSE exp
(A.IfExp {test=exp1, then'=exp2, else'=SOME exp3, pos=IFleft})
whileClause : WHILE exp DO exp
(A.WhileExp {test=exp1, body=exp2, pos=WHILEleft})
forClause : FOR ID ASSIGN exp TO exp DO exp
(A.ForExp {var=Symbol.symbol ID, lo=exp1,hi=exp2, body=exp3, escape=ref true, pos=FORleft})
letexp : LET decs IN expseq END
(A.LetExp {decs=decs, body=A.SeqExp expseq, pos=LETleft})
expseq : expsemilist (expsemilist)
| exp ([(exp,expleft)])
| ([(A.SeqExp [],defaultPos)]) (* novalue *)
parentheses : LPAREN exp RPAREN (exp)
(***** Declaration *****)
decs : ([]) (* empty *)
| decs dec (decs @ [dec])
dec : tydeclist (A.TypeDec tydeclist)
| vardec (vardec)
| fundeclist (A.FunctionDec fundeclist)
tydeclist : tydec tydeclist (tydeclist @ [tydec])
| tydec ([tydec])
tydec : TYPE typeid EQ ty ({name=typeid, ty=ty, pos=TYPEleft})
ty : typeid (A.NameTy (typeid, typeidleft))
| LBRACE tyfields RBRACE (A.RecordTy tyfields)
| ARRAY OF typeid (A.ArrayTy (typeid, typeidleft))
tyfields : ([]) (* empty *)
| tyfieldlist (tyfieldlist)
tyfieldlist : tyfieldlist COMMA tyfield (tyfieldlist @ [tyfield])
| tyfield ([tyfield])
tyfield : ID COLON typeid
({name=Symbol.symbol ID, typ=typeid, escape=ref true, pos=IDleft})
vardec : VAR ID ASSIGN exp
(A.VarDec {name=Symbol.symbol ID, typ=NONE, init=exp, escape=ref true, pos=VARleft})
| VAR ID COLON typeid ASSIGN exp
(A.VarDec {name=Symbol.symbol ID, typ=SOME (typeid,typeidleft), init=exp, escape=ref true, pos=VARleft})
fundeclist : fundec ([fundec])
| fundeclist fundec (fundeclist @ [fundec])
fundec : FUNCTION ID LPAREN tyfields RPAREN EQ exp
({name=Symbol.symbol ID, params=tyfields, result=NONE, body=exp, pos=FUNCTIONleft})
| FUNCTION ID LPAREN tyfields RPAREN COLON typeid EQ exp
({name=Symbol.symbol ID, params=tyfields, result=SOME (typeid,typeidleft), body=exp, pos=FUNCTIONleft})
env.sml
VarEntry の access フィールドはこの章では使ってないので削除してある。
今後必要になったときに追加か。
signature ENV =
sig
type access
type ty
datatype enventry = VarEntry of {ty:ty}
| FunEntry of {formals: ty list, result:ty}
val base_tenv : ty Symbol.table
val base_venv : enventry Symbol.table
end
structure Env : ENV = struct
type access = unit (* dummy *)
type ty = Types.ty
datatype enventry = VarEntry of {ty:ty}
| FunEntry of {formals: ty list, result:ty}
val base_tenv : ty Symbol.table =
let
val te1 = Symbol.empty
val te2 = Symbol.enter(te1,(Symbol.symbol "int"),Types.INT)
val te3 = Symbol.enter(te2,(Symbol.symbol "string"),Types.STRING)
in te3 end
val base_venv : enventry Symbol.table = Symbol.empty
end
semant.sml
変なコメントが残っていたり、エラー処理が未実装だったりするが
testcase 1〜48 は通ったよう。
(queens, merge はライブラリが無いのでエラーになる)
structure Semant : sig val transProg : Absyn.exp -> unit end =
struct
structure A = Absyn
type venv = Env.enventry Symbol.table
type tenv = Types.ty Symbol.table
type expty = {exp: Translate.exp, ty: Types.ty}
exception Unimplemented
val error = ErrorMsg.error
fun transTy (te, t) = raise Unimplemented
fun actual_ty ty =
case ty of
Types.NAME (t,r) =>
(case !r of NONE => (error 0 ("Cannot resolve type "^Symbol.name t);Types.UNIT)
| SOME t1 => actual_ty t1)
| _ => ty
fun checkInt ({exp=e,ty=t},p) =
case t of Types.INT => () | _ => error p "Integer required"
fun checkUnit ({exp=e,ty=t},p) =
case t of Types.UNIT => () | _ => error p "Unit required"
fun checkArray ({exp=e,ty=t},p) =
case t of Types.ARRAY _ => () | _ => error p "Array required"
fun checkSame (t1,t2,p) =
case (t1,t2) of
(Types.RECORD a, Types.RECORD b) => if a=b then () else error p "Type mismatched"
| (Types.RECORD _, Types.NIL ) => ()
| (Types.NIL , Types.RECORD _) => ()
| (Types.NIL , Types.NIL ) => ()
| (Types.NIL , _ ) => error p "Illegal nil"
| (_ , Types.NIL ) => error p "Illegal nil"
| (a , b ) => if a=b then () else error p "Type mismatched"
fun checkNotNil (t,p) =
case t of Types.NIL => error p "Other than nil required" | _ => ()
(*
fun checkString ({exp=e,ty=t},p) =
case t of Types.STRING => () | _ => error p "String required"
fun checkNil ({exp=e,ty=t},p) =
case t of Types.NIL => () | _ => error p "Nil required"
fun checkRecord ({exp=e,ty=t},p) =
case t of Types.RECORD _ => () | _ => error p "Record required"
*)
fun transExp (ve, te, e) =
let
fun analyze_var v =
case v of
A.SimpleVar (sym,p) =>
(case Symbol.look(ve,sym) of
SOME(Env.VarEntry{ty}) => {exp=(), ty=actual_ty ty}
| _ => (error p("Undefined variable "^Symbol.name sym);
{exp=(),ty=Types.INT} )
)
| A.FieldVar (v,sym,p) =>
let val {exp=_,ty=recty} = analyze_var v
val sytl =
case (actual_ty recty) of
Types.RECORD (a,u) => a
| _ => (error p "Record required";[])
val findt =
case List.find (fn (s,t) => sym=s) sytl of
SOME (s,t) => actual_ty t
| NONE => (error p "Record field not found";Types.UNIT)
in {exp=(),ty=findt} end
| A.SubscriptVar (v,e,p) =>
let val avar = analyze_var v
val {exp=_, ty=avarty} = avar
val subty = case actual_ty avarty of
Types.ARRAY (ty,_) => actual_ty ty
| _ => (error p "Array required"; Types.UNIT)
in checkArray (avar, p); {exp=(),ty=subty} end
and analyze_exp e = (* trexp *)
case e of
A.VarExp v => analyze_var v
| A.NilExp => {exp=(), ty=Types.NIL}
| A.IntExp i => {exp=(), ty=Types.INT}
| A.StringExp (s,p) => {exp=(), ty=Types.STRING}
| A.CallExp {func=sym , args=el , pos=p} =>
let
val argl = map analyze_exp el
val (fdecl,rt) =
case Symbol.look(ve,sym) of
SOME (Env.FunEntry {formals, result}) => (formals,result)
| _ => (error p ("Undefined function "^(Symbol.name sym));
([],Types.UNIT))
in
(* 相互参照がうまくいかない? *)
if (map #ty argl) = fdecl then ()
else error p "Function call type mismatch";
{exp=(), ty=actual_ty rt}
end
| A.OpExp {left=e1, oper=oprr, right=e2, pos=p} =>
let
val et1 = analyze_exp e1
val et2 = analyze_exp e2
fun cic () = (checkInt(et1, p); checkInt(et2, p);
{exp=(), ty=Types.INT})
val {exp=_, ty=t1} = et1
val {exp=_, ty=t2} = et2
fun cbc () = (checkSame (actual_ty t1, actual_ty t2, p);
{exp=(), ty=Types.INT})
in case oprr of
A.PlusOp => cic ()
| A.MinusOp => cic ()
| A.TimesOp => cic ()
| A.DivideOp => cic ()
| _ => cbc ()
end
| A.RecordExp {fields=fl, typ=sym , pos=p} =>
let val typ = case Symbol.look(te,sym) of
NONE => (error p "Not found record-type";
Types.UNIT)
| SOME t => t
in
(* field が全部あるか、そもそもその型が存在するか *)
{exp=(), ty=typ} (*仮*)
end
| A.SeqExp epl =>
let fun analyze_eplist r epl = (*いいかげん*)
case epl of
(e,p) :: tl => analyze_eplist (analyze_exp e) tl
| [] => r
in analyze_eplist {exp=(), ty=Types.UNIT} epl end
| A.AssignExp {var=v, exp=e, pos=p} =>
let val {exp=_, ty=vtype} = analyze_var v
val {exp=_, ty=etype} = analyze_exp e
val vt = actual_ty vtype
val et = actual_ty etype
in checkSame (vt,et,p); {exp=(),ty=vt} end
| A.IfExp {test=e1, then'=e2 , else'=eo, pos=p} =>
let val _ = checkInt(analyze_exp e1, p)
val {exp=et,ty=tt} = analyze_exp e2
val {exp=ee,ty=te} =
case eo of NONE => {exp=(), ty=Types.UNIT}
| SOME e3 => analyze_exp e3
in
if tt <> te then error p "Type mismatch" else ();
{exp=(), ty=tt}
end
| A.WhileExp {test=e1 , body=e2 , pos=p}
=> (checkInt(analyze_exp e1, p); checkUnit(analyze_exp e2, p);
{exp=(), ty=Types.UNIT})
| A.ForExp {var=sym, escape=_, lo=e1, hi=e2, body=e3, pos=p}
=> (checkInt(analyze_exp e1, p); checkInt(analyze_exp e2, p);
(* var は Int に設定して、body は unit 明示させるのかな *)
{exp=(), ty=Types.UNIT})
| A.BreakExp _ => {exp=(), ty=Types.UNIT}
| A.LetExp {decs=dl, body=e, pos=p} =>
let val {venv=ve2, tenv=te2} = transDecs(ve,te,dl)
in transExp (ve2,te2,e) end
| A.ArrayExp {typ=sym, size=e1, init=e2, pos=p} =>
let val {exp=e2e,ty=t2t} = analyze_exp e2
val t = case Symbol.look(te,sym) of
SOME t => (
case (actual_ty t) of
Types.ARRAY (st, _) =>
(checkSame (actual_ty st, actual_ty t2t, p);t )
| _ => (error p "Type system error";t)
)
| NONE => (error p ("Not Found "^(Symbol.name sym));
Types.ARRAY (Types.INT, ref ()))
in checkInt(analyze_exp e1, p); {exp=(), ty=t} end
in analyze_exp e end
and transDec (ve, te, d) =
case d of
A.FunctionDec fdl =>
let
fun checkDuplicate fdl =
let fun checkdup item l =
case List.find (fn {name,params,result,body,pos} => item=name) l of
SOME {name,params,result,body,pos} =>
error pos ("Function declaration "^Symbol.name name^" duplicated")
| NONE => ()
in case fdl of
{name,params,result,body,pos}::tl => (checkdup name tl; checkDuplicate tl)
| [] => ()
end
fun analyze_fundec_hdr ve te ({name=sym, params=fl, result=so, body=e, pos=p}) =
let
val SOME(result_ty) =
case so of SOME(rt,pos) => Symbol.look(te, rt)
| NONE => SOME(Types.UNIT)
fun transparam ({name, typ, pos, escape}) =
case Symbol.look(te, typ) of SOME t => {name=name, ty=t}
| NONE => raise Unimplemented
val params' = map transparam fl
val venv' =
Symbol.enter(ve, sym, Env.FunEntry
{formals=map #ty params',
result=result_ty})
in {tenv=te, venv=venv'} end
fun analyze_funlist_1st ve te fdl =
case fdl of
hd::tl => let val {tenv,venv}=analyze_fundec_hdr ve te hd in
analyze_funlist_1st venv tenv tl end
| [] => {venv=ve, tenv=te}
fun analyze_funlist_2nd ve te fdl =
let fun analyze_fundec_body ({name, params, result, body=e, pos}) =
let
fun transparam ({name, typ, pos, escape}) =
case Symbol.look(te, typ) of SOME t => {name=name, ty=t}
| NONE => raise Unimplemented
val params' = map transparam params
fun enterparam ({name,ty},venv) =
Symbol.enter(venv, name, Env.VarEntry{ty=ty})
val ve' = foldl enterparam ve params'
val {exp,ty} = transExp (ve', te, e)
val SOME(rtyp) = case result of SOME (t,p) => Symbol.look(te, t)
| NONE => SOME(Types.UNIT)
in
if actual_ty ty = actual_ty rtyp then ()
else error pos "Function return type error"
end
in case fdl of
hd::tl => (analyze_fundec_body hd; analyze_funlist_2nd ve te tl)
| [] => ()
end
val _ = checkDuplicate fdl
val {tenv=te2,venv=ve2} = analyze_funlist_1st ve te fdl
val _ = analyze_funlist_2nd ve2 te2 fdl
in {venv=ve2, tenv=te2} end
| A.VarDec {name=sym, escape=_, typ=symo, init=e, pos=p}
=>(case symo of
NONE =>
let val {exp,ty} = transExp (ve, te, e)
val _ = checkNotNil (ty,p)
in {tenv=te,venv=Symbol.enter(ve,sym,Env.VarEntry{ty=ty})} end
| SOME (s,p2) =>
let val {exp,ty} = transExp (ve, te, e)
val t = case Symbol.look(te,s) of
SOME t => (checkSame ((actual_ty t),(actual_ty ty),p2);t)
| NONE =>(error p2 "Type not exist"; Types.INT)
in {tenv=te,venv=Symbol.enter(ve,sym,Env.VarEntry{ty=t})} end
)
| A.TypeDec tyl =>
let
fun checkDuplicate tyl =
let fun checkdup item l =
case List.find (fn {name,ty,pos} => item=name) l of
SOME {name,ty,pos} =>
error pos ("Type declaration "^Symbol.name name^" duplicated")
| NONE => ()
in case tyl of
{name,ty,pos}::tl => (checkdup name tl; checkDuplicate tl)
| [] => ()
end
fun analyze_typelist_1st te tyl = (* とりあえず型名だけ登録 *)
let fun analyze_type_1st te {name=n, ty=t, pos=p} =
Symbol.enter (te, n, Types.NAME(n,ref NONE))
in case tyl of
hd::tl => analyze_typelist_1st (analyze_type_1st te hd) tl
| [] => te
end
fun analyze_type_f te2 ty =
case ty of
A.NameTy (sym,p) => Types.NAME(sym, ref(Symbol.look(te2, sym)))
| A.RecordTy fl =>
let fun analyze_field {name=sym1, escape=_, typ=sym2, pos=p} =
let val ty = case Symbol.look(te2, sym2) of
SOME t => t
| NONE =>(
error p ("Undefined type "^Symbol.name sym2);
Types.RECORD ([],ref ()) )
in (sym1,ty) end
fun analyze_fieldlist fl ft =
case fl of
hd::tl => analyze_fieldlist tl ((analyze_field hd)::ft)
| [] => ft
in Types.RECORD ((analyze_fieldlist fl []), ref ()) end
| A.ArrayTy (sym,_) =>
let val ty = case Symbol.look (te2, sym) of
SOME t => t
| NONE => raise Unimplemented
in Types.ARRAY (ty, ref ()) end (* actual_ty だとエラーチェックがおかしくなるが*)
fun analyze_typelist_2nd te2 tyl =
let fun analyze_type_2nd {name=n, ty=t, pos=p} =
let val typ = SOME(analyze_type_f te2 t)
in case Symbol.look(te2, n) of
SOME (Types.NAME (nt,r)) =>
if n=nt then r := typ else error p "System error"
| NONE => error p "System error"
| SOME _ => ()
end
in case tyl of
hd::tl => (analyze_type_2nd hd; analyze_typelist_2nd te2 tl)
| [] => ()
end
fun checkLoop te tyl =
let fun checkLoopItem name ty p visl =
case ty of
Types.NAME (sym, r) =>
if List.exists (fn n => n=ty) visl (* sym だけではだめ *)
then error p ("Type loop error (cyclic definition) "^Symbol.name sym)
else (case !r of NONE => error p "Type error"
| SOME t => checkLoopItem name t p (ty::visl))
| _ => () (* exact type *)
in case tyl of
{name,ty,pos}::tl =>
(case Symbol.look (te, name) of
NONE => error pos "Type system error"
| SOME t => checkLoopItem name t pos [];
checkLoop te tl
)
| [] => ()
end
val _ = checkDuplicate tyl
val tenv2 = analyze_typelist_1st te tyl
val _ = analyze_typelist_2nd tenv2 tyl
val _ = checkLoop tenv2 tyl
in {tenv=tenv2, venv=ve} end
and transDecs (ve, te, dl) =
case dl of
hd::tl => let val {venv=ve2,tenv=te2} = transDec (ve,te,hd)
in transDecs (ve2,te2,tl) end
| [] => {venv=ve, tenv=te}
fun transProg e =
let val tenv = Env.base_tenv
val venv = Env.base_venv
in transExp (venv, tenv, e); () end
end
translate.sml
教科書通りにダミーを仕込んでおくだけ。
(* currently dummy module @ chap5 ; will create at chap7 *)
structure Translate =
struct
type exp=unit
end
sources.cm
Group is
absyn.sml
errormsg.sml
table.sig
table.sml
symbol.sml
parse.sml
tiger.lex
tiger.grm
semant.sml
translate.sml
env.sml
types.sml
$/basis.cm
$/smlnj-lib.cm
$/ml-yacc-lib.cm