let rec type symbol = -- lexical type IdentSy String + NumSy Int + plusSy + minusSy + timesSy + divSy + eqSy + neSy + ltSy + leSy + gtSy + geSy + notSy + andSy + orSy + becomesSy + openSy + closeSy + semiSy + varSy + ifSy + thenSy + elseSy + fiSy + whileSy + doSy + odSy + beginSy + endSy + writeSy + eofSy + symbolErr String ------------------------------------------------------------------------------- and type Exp = Ident String + Num Int + -- syntactic types UExp symbol Exp + BExp symbol Exp Exp and type Dec = VarDec String + Decs Dec Dec and type Cmd = Assign Exp Exp + IfCmd Exp Cmd Cmd + WhileCmd Exp Cmd + Cmds Cmd Cmd + Block Dec Cmd + Write Exp and type PTree = exp Exp + dec Dec + cmd Cmd + PError String -- Parse Trees + MarkStack ------------------------------------------------------------------------------- in let parse inp = -- parse a program let rec lexical "" = eofSy, "" || -- lexical routine lexical s = if mem (hd s) [' '; '\n'; '\t'] then lexical (tl s) else case s in ':' . '=' . R : becomesSy,R || '<' . '>' . R : neSy, R || '<' . '=' . R : leSy, R || '>' . '=' . R : geSy, R || s: let w,r = takeword s in if isdigit(hd w) then NumSy(stoi w), r else assoc w (if isalpha(hd w) then [ ("if", ifSy); -- keywords ("then", thenSy); ("else", elseSy); ("fi", fiSy); ("while",whileSy); ("do", doSy); ("od", odSy); ("begin",beginSy); ("end", endSy); ("write",writeSy); ("var", varSy); ("not", notSy); ("and", andSy); ("or", orSy); (w, IdentSy w) ] else [ ("(", openSy); (")", closeSy); ("=", eqSy); (";", semiSy); ("+", plusSy); ("-", minusSy); ("*", timesSy);("/", divSy); ("<", ltSy); (">", gtSy); (w, symbolErr w) ] ), r end ------------------------------------------------------------------------------- -- type Cont = (list PTree) -> (list symbol) -> PTree -- parse stack input string answer -- -- type Parser = Cont -> Cont -- utility routines and finish [cmd T] [eofSy] = cmd T || -- finish :Cont finish parsing finish (PError m. _) _ = PError m || finish _ _ = PError " junk at end of parsing " and literal _ sym c T (s.rest)&(sym=s) = c T rest || literal message _ _ _ _ = PError (" missing " @ message) and cat (Parser1.Ps) c = Parser1 (cat Ps c) || -- cat (List Parser) :Parser cat [] c = c -- either (List (symbol#Parser)) :Parser an LL(1) choice operator and either [( _ ,Parser)] c T inp = Parser c T inp || -- last must go either ((sym1,Parser1).Ps) c T inp&(hd inp=sym1) = Parser1 c T inp || either ( _ .Ps) c T inp = either Ps c T inp and OprSeq ops NonTerm c = -- eg. x+y+z OprSeq syms Parser :Parser let rec opNT T (s.rest)&(mem s ops) = NonTerm (build s) T rest || opNT T inp = c T inp and build op (exp right.exp left.other) = opNT (exp(BExp op left right).other) in NonTerm opNT ------------------------------------------------------------------------------- in let rec -- syntax proper Expression = -- Expression let rec opd c T (IdentSy x . rest) = c (exp(Ident x). T) rest || opd c T (NumSy n . rest) = c (exp(Num n). T) rest || opd c T (sy . rest)&(mem sy [minusSy; plusSy; notSy]) = let c2 (exp e . T) = c (exp(UExp sy e). T) in factor c2 T rest || opd c T _ = PError " bad operand " and subexp = cat [literal "(" openSy; Expression; literal ")" closeSy] and factor = either [(openSy, subexp); (IdentSy "dontcare", opd)] and term = OprSeq [timesSy; divSy] factor and arithExp = OprSeq [plusSy; minusSy] term and relExp = OprSeq [eqSy; neSy; ltSy; leSy; gtSy; geSy] arithExp in OprSeq [andSy; orSy] relExp -- end of Expression ------------------------------------------------------------------------------- and Declarations dc = -- [ dec; dec; ... ] Declarations let rec Declaration c T (varSy. IdentSy x. rest) = c (dec(VarDec x).T) rest || Declaration c T inp = dc T inp and seq = cat [literal ";" semiSy; Declaration] group and group (dec D2. dec D1. T) = seq (dec(Decs D1 D2). T) in Declaration seq -- end of Declarations ------------------------------------------------------------------------------- and Command = -- Command let rec ifCommand c = let c2 (cmd gf.cmd gt.exp be. T) = c (cmd(IfCmd be gt gf).T) in cat [literal "if" ifSy; Expression; literal "then" thenSy; Commands; literal "else" elseSy; Commands; literal "fi" fiSy] c2 and whileCommand c = let c2 (cmd g . exp be . T) = c (cmd(WhileCmd be g) . T) in cat [literal "while" whileSy; Expression; literal "do" doSy; Commands; literal "od" odSy] c2 and blockCommand c T = let c2 (cmd g. dec d. MarkStack. T) = c (cmd(Block d g). T) || -- decs c2 (cmd g. MarkStack. T) = c (cmd g. T) -- no decs in cat [literal "begin" beginSy; Declarations; Commands; literal "end" endSy] c2 (MarkStack. T) -- avoid capture of any outer declarations! and assignment c = let c2 (exp Rhs. exp Lhs. T) = c (cmd(Assign Lhs Rhs).T) in cat [Expression; literal ":=" becomesSy; Expression] c2 and writeCommand c = let c2 (exp e.T) = c (cmd(Write e).T) in cat [literal "write" writeSy; Expression] c2 and Commands c = let rec seq T (semiSy.rest) = Commands group T rest || seq T inp = c T inp and group (cmd C2. cmd C1. T) = c (cmd(Cmds C1 C2). T) in Command seq in either [ (ifSy, ifCommand); (whileSy, whileCommand); (beginSy, blockCommand); (writeSy, writeCommand); (IdentSy "dontcare", assignment)] -- end of Command ------------------------------------------------------------------------------- in Command finish nil (choplist lexical inp) -- end of parse -- see L.Allison. Some Applications of Continuations. -- Computer Jrnl 31(1) 9-11 1988 --\fB Continuation Based Parser. \fP -- L.Allison, Department of Computer Science, Monash University, Australia