(*
*) val empty = "empty"; fun emptyP x = x=empty; datatype Grammar = Gram of (string list) * (* Non Terminals *) (string list) * (* Terminals *) (string * (string list)) list * (* Productions *) string; (* Start symbol *) val g1 = Gram(["Expr","Term","Factor","Expr'","Term'"] ,["ident","+","-","*","div","(",")","num"] ,[("Expr",["Term","Expr'"]) ,("Expr'",["+","Term","Expr'"]) ,("Expr'",["-","Term","Expr'"]) ,("Expr'",[]) ,("Term",["Factor","Term'"]) ,("Term'",["*","Factor","Term'"]) ,("Term'",["div","Factor","Term'"]) ,("Term'",[]) ,("Factor",["(","Expr",")"]) ,("Factor",["num"]) ,("Factor",["ident"]) ] ,"Expr"); (* ********* Operations on Grammars *********************** *) fun termP (Gram(nts,ts,ps,s)) x = List.exists (fn y => y=x) ts; fun nontermP (Gram(nts,ts,ps,s)) x = List.exists (fn y => y=x) nts; fun rhssFor (Gram(nts,ts,ps,start)) symbol = let fun test (rhs,lhs) = rhs=symbol fun lhs (r,l) = l in List.map lhs (List.filter test ps) end; (* ******************* Operations on Tables ************************ *) (* a table is (string * ref item) list *) (* We can update the reference to indicate updating the table *) (* Create a table with all slots initialized *) fun init symbols initf = let fun f x = (x,ref (initf x)) in List.map f symbols end; (* Update the slot at "s" with the function "updatef" *) (* returns true if it makes a change, false otherwise *) fun update s updatef pairs = case List.find (fn (y,r) => s=y) pairs of SOME(_,r) => let val old = !r val new = updatef old in if new=old then false else (r := new; true) end | NONE => false (* ***** Create a Table for nullable symbols from a grammar **** *) fun nullTable (gram as(Gram(nts,ts,ps,start))) = let val allsymbols = nts @ ts val table = init allsymbols (fn _ => false) val changed = ref true fun onePass [] = false (* returns true if it makes a change *) | onePass (x::xs) = let val rhss = rhssFor gram x fun nullify b = List.exists (nullableRhs table) rhss val b1 = update x nullify table val b2 = onePass xs in b1 orelse b2 end in while (!changed) do (changed := false; changed := onePass allsymbols); table end and nullable table s = case List.find (fn (y,r) => y=s) table of NONE => false | SOME(_,r) => !r and nullableRhs table [] = true | nullableRhs table (x::xs) = (nullable table x) andalso (nullableRhs table xs); val NullT = nullTable g1; (* ************ normalizing lists of strings ************ *) val filter = List.filter; fun sort' comp [] ans = ans | sort' comp [x] ans = x :: ans | sort' comp (x::xs) ans = let fun LE x y = case comp(x,y) of GREATER => false | _ => true fun GT x y = case comp(x,y) of GREATER => true | _ => false val small = filter (GT x) xs val big = filter (LE x) xs in sort' comp small (x::(sort' comp big ans)) end; fun nub [] = [] | nub [x] = [x] | nub (x::y::xs) = if x=y then nub (x::xs) else x::(nub (y::xs)); fun norm x = nub (sort' String.compare x []) (* ********************************************************* *) fun firstTable (gram as(Gram(nts,ts,ps,start))) = let val termTable = init ts (fn x => [x]) val nontermTable = init nts (fn x => []) val table = termTable @ nontermTable val changed = ref true fun onePass [] = false (* returns true if it makes a change *) | onePass (x::xs) = let val rhss = rhssFor gram x fun first old = let val listOflists = map (firstRhs gram table) rhss val new = List.concat listOflists in norm(old @ new) end val b1 = update x first table val b2 = onePass xs in b1 orelse b2 end in while (!changed) do (changed := false; changed := onePass nts); table end and first table s = case List.find (fn (y,r) => y=s) table of NONE => [] | SOME(_,r) => !r and firstRhs gram table [] = [empty] | firstRhs gram table [x] = first table x | firstRhs gram table (x::xs) = let val temp = first table x in case List.find emptyP temp of NONE => temp | SOME _ => temp @ firstRhs gram table xs end; val FirstT = firstTable g1; (**)