-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.rkt
108 lines (95 loc) · 3.34 KB
/
parser.rkt
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
99
100
101
102
103
104
105
106
107
108
#lang racket
(require "./lexer.rkt")
(provide parser)
(define tokens (lexer))
(define grammer (call-with-input-file "./grammer/grammer"
(lambda (in) (read in))))
; AST ( E . list( sub-AST ))
; Example:
; E
; |--|--|
; a F c
; |
; b
; (E . (token (F . token) token)
; pattern should be a symbol / list
; return (AST . remaining tokens) / #f
(define (parser-recur [pattern 'CompUnit] [tokens tokens])
; try to match pattern like: A -> BC
(define (seq-match pattern tokens)
(if (empty? pattern)
; get all matched
(cons '() tokens)
; get remaining pattern in the lexer
(let ([ret (parser-recur (car pattern) tokens)])
(if ret
(let ([remaining-ret (seq-match (cdr pattern) (cdr ret))])
(if remaining-ret
(cons (cons (car ret) (car remaining-ret))
(cdr remaining-ret))
#f))
#f))))
; try to match pattern like: A -> B | C
(define (alt-match pattern tokens)
(if (empty? pattern)
#f ; couldn't match any one
(let ([ret (parser-recur (car pattern) tokens)])
(if ret
ret
(alt-match (cdr pattern) tokens)))))
; try to match pattern like: A -> {B}
(define (repeat-match pattern tokens)
(if (empty? pattern)
; matched this repeat pattern
(cons '() tokens)
; try to remaining pattern in the lexer
(let ([ret (parser-recur pattern tokens)])
(if ret
; if matched, try to match one more
(let* ([matched (car ret)]
[tokens (cdr ret)]
[one-more (repeat-match pattern tokens)])
(cons
(cons matched (car one-more))
(cdr one-more)))
(cons '() tokens)))))
; try to match pattern like: A -> [B]
(define (opt-match pattern tokens)
(if (empty? pattern)
; matched this option pattern
(cons '() tokens)
; try to remaining pattern in the lexer
(let ([ret (parser-recur pattern tokens)])
(if ret
ret
(cons '() tokens)))))
(if (symbol? pattern)
; pattern is a single symbol
(cond
; tokens end early
[(empty? tokens) #f]
; if pattern is match with token (terminal)
[(equal? pattern (token-type (car tokens)))
(cons (car tokens) (cdr tokens))]
; got a non-terminal one
[(hash-has-key? grammer pattern)
(let ([ret (parser-recur (hash-ref grammer pattern) tokens)])
(if ret
(cons (cons pattern (car ret))
(cdr ret))
#f))]
; get a terminal one, but not match with (car tokens)
[else #f])
; if pattern is a list
(cond
[(empty? pattern) (cons '() tokens)]
[(equal? 'SEQ (car pattern)) (seq-match (cdr pattern) tokens)]
[(equal? 'ALT (car pattern)) (alt-match (cdr pattern) tokens)]
[(equal? 'REPEAT (car pattern)) (repeat-match (cdr pattern) tokens)]
[(equal? 'OPT (car pattern)) (opt-match (cdr pattern) tokens)])))
(define (parser [pattern 'CompUnit] [tokens tokens])
(let ([ast (parser-recur pattern tokens)])
(if ast
ast
(error "parser fail"))))
;(writeln (parser 'CompUnit tokens))