-
Notifications
You must be signed in to change notification settings - Fork 0
/
Scanner.scm
107 lines (105 loc) · 2.5 KB
/
Scanner.scm
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
;;; fcl scanner
(define-structure (Token
(constructor token.new (name payl))
)
name ; symbol
payl ; string|number
)
(define (Token.unpack token)
(list (token-name token) (token-payl token))
)
; scan : string,number->[Token]
(define (scan input0)
; take-while : string,number,predicate -> list
(define (take-while str i e)
(let loop ((a i))
(let ((c (string-ref str a)))
(if (e c)
(cons c (loop (+ a 1)))
'()
)
)
)
)
; takenum : string,number -> numeric-string
(define (takenum str i)
(list->string
(take-while str i char-numeric?)
)
)
; takealnum : string,number -> string
(define (takealnum str i)
(list->string
(take-while str i char-alphanumeric?)
)
)
(define (nextindex str i c)
(let loop ((a i))
(if (< a (string-length str))
(if (eq? (string-ref str a) c)
a
(loop (+ a 1))
)
(string-length str)
)
)
)
(call/cc
(lambda (cont)
(let scan-loop ((input input0) (i 0) (l 1))
(define j (string-length input))
;(if debug.scan (fmt "scan |" (substring input i j)))
(if (< i j)
(let ((c (string-ref input i)))
(cond
((char-whitespace? c) (scan-loop input (+ i 1) (if (eq? c #\newline) (+ l 1) l)))
((eq? c #\%) (scan-loop input (+ (nextindex input (+ i 1) #\%) 1) l))
((char-numeric? c)
(let* ((n (takenum input i)) (len (string-length n)))
(if debug.scan (fmt "got number" n))
(cons (token.new 'number (string->number (substring input i (+ i len)))) (scan-loop input (+ i len) l))
)
)
((char-alphabetic? c)
(let* ((w (takealnum input i)) (len (string-length w)))
(if debug.scan (fmt "got word" w))
(cons (token.new 'word (substring input i (+ i len))) (scan-loop input (+ i len) l))
)
)
(else
(cons
(token.new
(case c
((#\=) 'equal)
((#\;) 'semicolon)
((#\,) 'comma)
((#\() 'left-par)
((#\)) 'right-par)
((#\*) 'star)
((#\/) 'slash)
((#\+) 'plus)
((#\-) 'minus)
((#\|) 'bar)
((#\~) 'tilde)
((#\!) 'bang)
((#\>) 'greater)
((#\<) 'less)
((#\:) 'colon)
(else
(fmt "unknown symbol" c "in line" l)
(cont '!scan-error)
)
)
'()
)
(scan-loop input (+ i 1) l)
)
)
)
)
(cons (token.new 'eof '()) '())
)
)
)
)
)