-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathparser.sc
91 lines (74 loc) · 3.23 KB
/
parser.sc
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
;;;;library for Simple Parser Combinator
(library (core parser)
(export satisfy/p equal/p parser digit/p alpha/p parse-string
eof/p many/p or/p some/p integer/p any/p
)
(import (chezscheme))
(define (satisfy/p procedure)
(lambda (l)
(cond
[(null? l) 'parse-fail]
[(procedure (car l)) (list 'parse-success (car l)
(cdr l))]
[else 'parse-fail])))
(define any/p (satisfy/p (lambda (_) #t)))
(define (equal/p v) (satisfy/p (lambda (x) (equal? x v))))
(define digit/p (satisfy/p (lambda (x) (char<=? #\0 x #\9))))
(define alpha/p (satisfy/p (lambda (x) (char-alphabetic? x))))
(define (eof/p l) (if (null? l) (list 'parse-success #f '())
'parse-fail))
(define (or/p p . parsers)
(lambda (l)
(let ([res (p l)])
(cond [(eq? res 'parse-fail) (if (null? parsers) 'parse-fail
((apply or/p parsers) l))]
[else res]))))
(define (many/p p)
(or/p
(parser [a p]
[r (many/p p)]
(cons a r))
(parser '())))
(define (some/p p)
(parser [a p]
[r (many/p p)]
(cons a r)))
(define (chars->integer lst)
(car (fold-right (lambda (x y)
(let ([factor (cdr y)]
[acc (car y)])
(cons (+ acc (* factor (- (char->integer x) (char->integer #\0))))
(* factor 10))))
(cons 0 1) lst)))
(define integer/p
(let ([integer-without-sign/p
(parser [a (many/p digit/p)]
(chars->integer a))])
(or/p (parser [sign (or/p (equal/p #\+) (equal/p #\-))]
[int integer-without-sign/p]
(if (equal? sign #\-) (- int)
int))
integer-without-sign/p)))
(define-syntax parser
(syntax-rules ()
[(_ return-value) (lambda (l)
(list 'parse-success return-value l))]
[(_ [var val] rest ...)
(lambda (l)
(let ([res (val l)])
(cond [(eq? 'parse-fail res) 'parse-fail]
[(eq? 'parse-success (car res))
(let ([var (cadr res)])
((parser rest ...) (caddr res)))]))
)]))
(define (parse-string p str . failure-thunk)
(define fail (if (null? failure-thunk)
(lambda () (error 'parser "parse failed"))
(car failure-thunk)
))
(define res (p (string->list str)))
(cond [(eq? res 'parse-fail) (fail)]
[(eq? (car res) 'parse-success)
(cadr res)]))
)
(import (core parser))