File: prec-parse.sml

package info (click to toggle)
mlton 20210117%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 58,464 kB
  • sloc: ansic: 27,682; sh: 4,455; asm: 3,569; lisp: 2,879; makefile: 2,347; perl: 1,169; python: 191; pascal: 68; javascript: 7
file content (98 lines) | stat: -rw-r--r-- 3,061 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
(*
 *  A really stupid but (hopefully) working precedence parser 
 *
 *  --Allen Leung (leunga@cs.nyu.edu)
 *) 

signature PRECEDENCE_PARSER =
sig

   type precedence_stack

   datatype fixity = INFIX of int 
                   | INFIXR of int 
                   | NONFIX 
   datatype 'a token  = ID  of string
                      | EXP of 'a

   exception PrecedenceError

   val empty : precedence_stack 
   val declare : precedence_stack * string * fixity -> precedence_stack
   val parse   : { stack         : precedence_stack,
                   app           : 'a * 'a -> 'a,
                   tuple         : 'a list -> 'a,
                   id            : string -> 'a,
                   error         : string -> unit,
                   toString      : 'a -> string,
                   kind          : string
                 } -> 'a token list -> 'a
end

structure PrecedenceParser : PRECEDENCE_PARSER =
struct


   datatype fixity = INFIX of int 
                   | INFIXR of int 
                   | NONFIX 
   datatype 'a token  = ID of string
                      | EXP of 'a

   type precedence_stack = (string * fixity) list

   val empty = []
   fun declare(stack,id,fixity) = (id,fixity)::stack

   exception PrecedenceError

   fun parse {stack,tuple,app,id,toString,error,kind} tokens =
   let fun fixity x =
       let fun f [] = NONFIX
             | f ((y,fix)::S) = if x = y then fix else f S
       in  f stack end

       val toks = map (fn ID x => (id x,fixity x)
                        | EXP e => (e,NONFIX)) tokens

       fun err(msg) =
             (error(msg^" in "^kind^": "^
                   List.foldr (fn ((x,_),"") => toString x
                                | ((x,_),s) => toString x^" "^s) ""
                               toks);
              raise PrecedenceError)
       fun err'(msg, x) = err(msg^" "^toString x)

       (* 
        * Parse with precedence. 
        *)
       fun scan(p, tokens) =
           case tokens of
             (f,NONFIX)::(x,NONFIX)::rest =>
                 scan(p, (app(f,x), NONFIX)::rest) (* application *)
           | [(x,NONFIX)] => (x, [])
           | (x,INFIX _)::_ => err'("dangling infix symbol", x)
           | (x,INFIXR _)::_ => err'("dangling infixr symbol", x)
           | (left,NONFIX)::(rest as (f,INFIX q)::rest') =>
                if p >= q then 
                  (left, rest)
                else
                   let val (right, rest) = scan(q,rest')
                   in  scan(p,(app(f,tuple[left,right]),NONFIX)::rest)
                   end
           | (left,NONFIX)::(rest as (f,INFIXR q)::rest') =>
                if p > q then
                   (left, rest)
                else
                   let val (right, rest) = scan(q,rest')
                   in  scan(p,(app(f,tuple[left,right]),NONFIX)::rest)
                   end
           | _ => err("parse error")

       fun scanAll [(x,INFIX _)] = x
         | scanAll [(x,INFIXR _)] = x
         | scanAll tokens = #1(scan(~1,tokens))
             
   in  scanAll toks end

end