let rec
    type Ide == String

and type symbol =                                               -- lexical type
       IdentSy Ide + NumSy Int + trueSy + falseSy + nilSy +
       listSy + stSy +
       letSy + recSy + inSy +
       openSy + closeSy + commaSy +
       lambdaSy + dotSy +
       ifSy + thenSy + elseSy +
       consSy +
       orSy +
       andSy +
       eqSy + neSy + ltSy + leSy + gtSy + geSy +
       plusSy + minusSy +
       timesSy + divSy +
       hdSy + tlSy + nullSy + notSy +
       eofSy   + symbolErr String

-------------------------------------------------------------------------------

and type Exp =
       Ident Ide + Num Int + Boolean Bool + NIL +            -- syntactic types
       LogicExp Ide Exp +
       Block Bool Dec Exp +
       LambdaExp Ide Exp +
       Apply Exp Exp +
       IfExp Exp Exp Exp +
       UExp symbol Exp + BExp symbol Exp Exp

and type Dec = Bind Ide Exp + Decs Dec Dec

and type PTree = exp Exp + dec Dec + PError String         -- Parse Trees

-------------------------------------------------------------------------------

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  :  consSy,   R ||               -- :: is cons
              '<' . '>' . 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 [                      -- keywords
                       ("true", trueSy); ("false", falseSy);
                       ("list", listSy); ("st", stSy);
                       ("let", letSy); ("rec", recSy); ("in", inSy);
                       ("lambda", lambdaSy);
                       ("if",   ifSy); ("then", thenSy); ("else", elseSy);
                       ("and", andSy); ("or",  orSy);
                       ("not", notSy);
                       ("hd", hdSy); ("tl", tlSy); ("null", nullSy);
                       ("nil", nilSy);
                       (w, IdentSy w)  ]
                      else [
                       (".", dotSy);
                       ("(", openSy); (")", closeSy);
                       ("=", eqSy);   (",", commaSy);
                       ("+", 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 [exp E] [eofSy] = exp E  ||     --   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
    unaryOps = [plusSy; minusSy; notSy; hdSy; tlSy; nullSy]
and binaryOps= [plusSy; minusSy; timesSy; divSy; consSy] @ relOps
and relOps   = [eqSy; neSy; leSy; ltSy; geSy; gtSy]
and literals = [trueSy; falseSy; nilSy]
and startsExp (IdentSy _) = true ||
    startsExp (NumSy _)   = true ||
    startsExp sy = mem sy (unaryOps @ literals @
                           [openSy; ifSy; listSy; letSy; lambdaSy])

and 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 (trueSy    . rest) = c (exp(Boolean true). T) rest  ||
        opd c T (falseSy   . rest) = c (exp(Boolean false).T) rest  ||
        opd c T (nilSy     . rest) = c (exp(NIL    ). T) rest  ||

        opd c T (ifSy . rest ) =                                 -- Conditional
           let rec
               c4 (exp Fe. exp Te. exp Se. T) = c(exp(IfExp Se Te Fe). T)
           and c3 T (elseSy . rest) = Expression c4 T rest
           and c2 T (thenSy . rest) = Expression c3 T rest
           in  Expression c2 T rest                            ||

        opd c T (lambdaSy . IdentSy x . dotSy . rest) =          -- abstraction
           let c2 (exp Body. T) = c (exp(LambdaExp x Body). T)
           in  Expression c2 T rest                            ||

        opd c T (listSy . IdentSy x . stSy . rest) =    -- comprehension
           let c2 (exp Constraint. T) = c(exp(LogicExp x Constraint). T)
           in  Expression c2 T  rest ||

        opd c T (letSy . Sy . rest) =                                  -- Block
           let rec
               isRec = Sy=recSy                     -- ? recursive declarations
           and c3 (exp Body . dec Local . T) = c(exp(Block isRec Local Body).T)
           and c2 T (inSy . rest) = Expression c3 T rest
           in  Declarations c2 T (if isRec then rest else Sy.rest)  ||

        opd c T (sy . rest)&(mem sy unaryOps) =              -- unary operators
           let c2 (exp e . T) = c (exp(UExp sy e). T)
           in  operand c2 T rest  ||

        opd c T _ = PError " bad operand "

    and operand = either [(openSy,
                           cat [literal "(" openSy; Expression;
                                literal ")" closeSy] );
                          (IdentSy "ignored!", opd)]

    and factor c T inp =                                 -- NB. f x y == (f x)y
        let rec
            c2 T (sy.rest) & ((startsExp sy)&~(mem sy binaryOps)) =
                       operand mkApply T (sy.rest) ||
            c2 T inp = c T inp
        and mkApply (exp Param . exp Fn . T) = c2 (exp(Apply Fn Param) . T)
        in operand c2 T inp

    and term      = OprSeq [timesSy; divSy] factor
    and arithExp  = OprSeq [plusSy; minusSy] term
    and relExp    = OprSeq [eqSy; neSy; ltSy; leSy; gtSy; geSy] arithExp
    and conj      = OprSeq [andSy] relExp
    and disj      = OprSeq [orSy]  conj
    and list      = OprSeq [consSy] disj

    in list

-------------------------------------------------------------------------------

and Declarations dc =   -- [ x=e, y=f, ... ]                       Declarations
    let rec
        Declaration c T (IdentSy x. eqSy. rest) =
           let c2 (exp RHS. T) = c (dec(Bind x RHS). T)
           in  Expression c2 T rest
    and moreDecs T (commaSy.rest) = Declaration mkDecs T rest || -- more
        moreDecs T inp = dc T inp                                -- no more
    and mkDecs (dec D2. dec D1. T) = moreDecs (dec(Decs D1 D2). T)
    in  Declaration moreDecs                             -- end of Declarations

-------------------------------------------------------------------------------

in Expression 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
