-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlr-dfa.rkt
179 lines (143 loc) · 7.46 KB
/
lr-dfa.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#lang racket
(require "machine.rkt")
(require "token.rkt")
(provide start-rule)
(provide lr-dfa-start-state)
(provide lr-dfa-reduce)
(provide lr-dfa-shift)
(provide print-rule)
(provide rule)
(provide rule?)
(provide rule-lhs)
(provide rule-rhs)
(define NULL 'null)
;==============================================================================================
;==== Structs
;==============================================================================================
;(struct: rule ([lhs : Symbol] [rhs : (Listof Symbol)]))
(struct rule (lhs rhs) #:transparent)
;(struct: lritem ([dot : Integer] [rule : (Listof rule)]))
(struct lritem (dot rule))
;(struct: reduce ([rule : rule] [lookahead : Symbol]))
(struct reduce (rule lookahead) #:transparent)
;==============================================================================================
;==== Print Functions
;==============================================================================================
;(: print-rule : rule -> Symbol)
(define (print-rule rule) (printf "~a -> ~a" (rule-lhs rule) (rule-rhs rule)))
(define (print-rules rules)
(for-each (lambda (rule) (print-rule rule)) rules))
;(: print-lritem : lritem -> Symbol)
(define (print-lritem lritem) (printf "~a : " (lritem-dot lritem)) (print-rule (lritem-rule lritem)))
;(: print-lritems : (Listof lritem) -> Symbol)
(define (print-lritems lritems) (for-each (lambda (x) (print-lritem x)) lritems))
(define (print-reduce reduce) (print-rule (reduce-rule reduce)) (printf " : ~a~n" (reduce-lookahead reduce)))
(define (print-reduces reduces) (for-each (lambda (x) (print-reduce x)) reduces))
;==============================================================================================
;==== Shift/Reduce
;==============================================================================================
;(: lr-dfa-shift : Symbol Symbol -> Symbol)
(define (lr-dfa-shift state sym)
(define next-state (dfa-process-sym lr-dfa state sym))
next-state)
;(: lr-dfa-reduce-helper : (Listof reduce) Symbol -> [ rule | Boolean ])
(define (lr-dfa-reduce-helper reduces next-sym)
(define rule-to-reduce (memf (lambda (reduce) (equal? next-sym (reduce-lookahead reduce))) reduces))
(cond
[(list? rule-to-reduce) (reduce-rule (first rule-to-reduce))]
[else #f]))
;(: lr-dfa-reduce : Symbol Symbol -> [ rule | Boolean ])
(define (lr-dfa-reduce state next-sym)
(cond
[(is-state-accepting lr-dfa state) (lr-dfa-reduce-helper (get-m-md-As lr-dfa state reduce?) next-sym)]
[else #f]))
;==============================================================================================
;==== Parse LR Table Files
;==============================================================================================
;(: string->strings : String -> (Listof Symbol)
;Converts a string to a list of strings
(define (string->strings str)
(regexp-split #px" " str))
;(: string->symbols : String -> (Listof Symbol)
;Converts a string to a list of symbols
(define (string->symbols str)
(map string->symbol (string->strings str)))
;(: symbols->rule : (Listof Symbol) -> rule
;Converts a list of symbols to a rule
(define (symbols->rule syms)
(rule (first syms) (rest syms)))
;(: strip-n-lines : Number (Listof String) -> (Listof String)
;Removes n strings off the top of lines
(define (strip-n-lines n lines)
(cond
[(<= n 0) lines]
[else (strip-n-lines (- n 1) (rest lines))]))
;(: rmv-beginning : (Listof String) -> (Listof String)
;Removes the terminals and non-terminals from the generated table file
(define (rmv-beginning lines)
(define rmv-terminals (strip-n-lines (+ 1 (string->number (first lines))) lines))
(define rmv-non-terminals (strip-n-lines (+ 2 (string->number (first rmv-terminals))) rmv-terminals))
rmv-non-terminals)
;(: get-rules : Number (Listof String) -> (Listof rule)
;Converts n rules from the list of string lines
(define (get-rules n lines)
(cond
[(<= n 0) empty]
[else (cons (symbols->rule (string->symbols (first lines))) (get-rules (- n 1) (rest lines)))]))
;(: m-set-start : Symbol -> machine
;Creates a machine with only a starting state
(define (m-set-start start)
(machine (list start) start empty empty empty))
;(: m-add-shift : machine Symbol Symbol String (Listof rule) -> machine
;Adds a transition to the machine m, reation is a string number so we need to append "g" on the front
(define (m-add-shift m from input reaction)
(define to (string->symbol (string-append "g" reaction)))
(machine (if (list? (member to (machine-states m))) (machine-states m) (cons to (machine-states m)))
(machine-start m)
(machine-accepting m)
(cons (transition from input to) (machine-transitions m))
(machine-md m)))
;(: m-add-reduce : machine Symbol Symbol String (Listof rule) -> machine
;Adds a md-A to the machine m, state is that state on which to reduce, input is the lookahead, reaction is
;the list-ref for into rules for the rule to reduce by.
(define (m-add-reduce m state input reaction rules)
(define rule (list-ref rules (string->number reaction)))
(machine (machine-states m)
(machine-start m)
(if (list? (member state (machine-accepting m))) (machine-accepting m) (cons state (machine-accepting m)))
(machine-transitions m)
(cons (list state (list (reduce rule input))) (machine-md m))))
;(: add-to-m : machine String (Listof rule) -> machine
;Parses the string line, which represents a shift/reduce rull in the lrtable. It then adds it to the machine
(define (add-to-m m line rules)
(define state (string->symbol (string-append "g" (list-ref line 0))))
(define input (string->symbol (list-ref line 1)))
(define action (string->symbol (list-ref line 2)))
(define reaction (list-ref line 3))
(cond
[(equal? action 'shift) (m-add-shift m state input reaction)]
[else (m-add-reduce m state input reaction rules)]))
;(: get-lr-dfa : Number (Listof String) (Listof rule) -> machine
;Parses all the shift/reduce rules in the lrtable and creates a machine out of them
(define (get-lr-dfa n lines rules)
(define (get-table-helper m n lines rules)
(cond
[(<= n 0) m]
[else (get-table-helper (add-to-m m (string->strings (first lines)) rules) (- n 1) (rest lines) rules)]))
(define start-state (string->symbol (string-append "g" (first (string->strings (first lines))))))
(get-table-helper (m-set-start start-state) n lines rules))
;==============================================================================================
;==== Creation
;==============================================================================================
(define file-lines (rmv-beginning (file->lines "lrtable"))) ;open the file as list of string lines
(define rules (get-rules (string->number (first file-lines)) (strip-n-lines 1 file-lines))) ;get the rules
(define new-file-lines (strip-n-lines (+ 2 (string->number (first file-lines))) file-lines)) ;remove the rules from the list of strings
(define lr-dfa (get-lr-dfa (string->number (first new-file-lines)) (strip-n-lines 1 new-file-lines) rules)) ;parse the shift/reduce lines, create the dfa
;(print-machine lr-dfa)
(define start-rule (first rules))
(define lr-dfa-start-state 'g0)
;==============================================================================================
;==== Testing
;==============================================================================================
;(lr-first 'A terminals non-terminals rules)
;(lr-nfa (lritem 0 start-rule) (list NULL) terminals non-terminals rules)