|
1 "{ Package: 'stx:goodies/petitparser/compiler' }" |
|
2 |
|
3 "{ NameSpace: Smalltalk }" |
|
4 |
|
5 Object subclass:#PPCScannerCodeGenerator |
|
6 instanceVariableNames:'codeGen fsa backlinkStates backlinkTransitions arguments openSet |
|
7 joinPoints incommingTransitions methodCache id' |
|
8 classVariableNames:'' |
|
9 poolDictionaries:'' |
|
10 category:'PetitCompiler-Scanner' |
|
11 ! |
|
12 |
|
13 !PPCScannerCodeGenerator methodsFor:'accessing'! |
|
14 |
|
15 arguments |
|
16 ^ arguments |
|
17 ! |
|
18 |
|
19 arguments: anObject |
|
20 arguments := anObject |
|
21 ! ! |
|
22 |
|
23 !PPCScannerCodeGenerator methodsFor:'analysis'! |
|
24 |
|
25 analyzeBacklinks |
|
26 backlinkTransitions := fsa backTransitions. |
|
27 backlinkStates := IdentityDictionary new. |
|
28 |
|
29 backlinkTransitions do: [ :t | |
|
30 (self backlinksTo: (t destination)) add: t. |
|
31 ]. |
|
32 ! |
|
33 |
|
34 analyzeJoinPoints |
|
35 | joinTransitions | |
|
36 joinTransitions := fsa joinTransitions. |
|
37 joinTransitions := joinTransitions reject: [ :t | self isBacklinkDestination: t destination ]. |
|
38 joinPoints := IdentityDictionary new. |
|
39 |
|
40 joinTransitions do: [ :t | |
|
41 (joinPoints at: t destination ifAbsentPut: [ IdentitySet new ]) add: t. |
|
42 ] |
|
43 |
|
44 ! |
|
45 |
|
46 analyzeTransitions |
|
47 | transitions | |
|
48 transitions := fsa allTransitions. |
|
49 incommingTransitions := IdentityDictionary new. |
|
50 (self incommingTransitionsFor: fsa startState) add: #transitionStub. |
|
51 |
|
52 transitions do: [ :t | |
|
53 (self incommingTransitionsFor: t destination) add: t. |
|
54 ]. |
|
55 ! |
|
56 |
|
57 backlinksTo: state |
|
58 ^ backlinkStates at: state ifAbsentPut: [ OrderedCollection new ] |
|
59 ! |
|
60 |
|
61 closedJoinPoints |
|
62 | closed | |
|
63 closed := IdentitySet new. |
|
64 |
|
65 joinPoints keysAndValuesDo: [ :key :value | |
|
66 value isEmpty ifTrue: [ closed add: key ]. |
|
67 ]. |
|
68 |
|
69 ^ closed |
|
70 ! |
|
71 |
|
72 containsBacklink: state |
|
73 state transitions do: [ :t | |
|
74 (self isBacklink: t) ifTrue: [ ^ true ] |
|
75 ]. |
|
76 |
|
77 ^ false |
|
78 ! |
|
79 |
|
80 hasMultipleIncommings: state |
|
81 ^ (incommingTransitions at: state ifAbsent: [ self error: 'should not happen']) size > 1 |
|
82 ! |
|
83 |
|
84 incommingTransitionsFor: state |
|
85 ^ incommingTransitions at: state ifAbsentPut: [ IdentitySet new ] |
|
86 ! |
|
87 |
|
88 isBacklink: transition |
|
89 ^ backlinkTransitions includes: transition |
|
90 ! |
|
91 |
|
92 isBacklinkDestination: state |
|
93 ^ (self backlinksTo: state) isEmpty not |
|
94 ! |
|
95 |
|
96 isJoinPoint: state |
|
97 "Please note that joinPoints are removed as the compilaction proceeds" |
|
98 ^ joinPoints keys includes: state |
|
99 ! |
|
100 |
|
101 joinTransitionsTo: joinPoint "state" |
|
102 ^ joinPoints at: joinPoint ifAbsent: [ #() ] |
|
103 ! ! |
|
104 |
|
105 !PPCScannerCodeGenerator methodsFor:'code generation'! |
|
106 |
|
107 generate |
|
108 self assert: fsa isDeterministic. |
|
109 self assert: fsa isWithoutEpsilons. |
|
110 self assert: fsa checkConsistency. |
|
111 |
|
112 |
|
113 self analyzeBacklinks. |
|
114 self analyzeJoinPoints. |
|
115 self analyzeTransitions. |
|
116 |
|
117 openSet := IdentitySet new. |
|
118 |
|
119 codeGen startMethod: (codeGen idFor: fsa). |
|
120 codeGen codeComment: (Character codePoint: 13) asString, fsa asString. |
|
121 |
|
122 self generateFor: fsa startState. |
|
123 |
|
124 codeGen stopMethod. |
|
125 |
|
126 ^ self compileScannerClass new |
|
127 |
|
128 |
|
129 ! |
|
130 |
|
131 generate: aPEGFsa |
|
132 fsa := aPEGFsa. |
|
133 |
|
134 fsa compact. |
|
135 fsa checkSanity. |
|
136 |
|
137 ^ self generate |
|
138 ! |
|
139 |
|
140 generateFinalFor: state |
|
141 state isFinal ifFalse: [ ^ self ]. |
|
142 |
|
143 codeGen codeRecordMatch: state retval priority: state priority. |
|
144 ! |
|
145 |
|
146 generateFor: state |
|
147 " (self isJoinPoint: state) ifTrue: [ |
|
148 ^ codeGen codeComment: 'join point generation postponed...' |
|
149 ]. |
|
150 " |
|
151 codeGen cachedValue: (codeGen idFor: state) ifPresent: [ :method | |
|
152 "if state is already cached, it has multiple incomming links. |
|
153 In such a case, it is compiled as a method, thus return immediatelly" |
|
154 ^ codeGen codeAbsoluteReturn: method call |
|
155 ]. |
|
156 |
|
157 self generateStartMethod: state. |
|
158 " (self isBacklinkDestination: state) ifTrue: [ |
|
159 codeGen codeStartBlock. |
|
160 ]. |
|
161 " |
|
162 self generateFinalFor: state. |
|
163 self generateNextFor: state. |
|
164 self generateTransitionsFor: state. |
|
165 |
|
166 " (self isBacklinkDestination: state) ifTrue: [ |
|
167 codeGen codeEndBlockWhileTrue. |
|
168 ]. |
|
169 " |
|
170 self generateStopMethod: state. |
|
171 ! |
|
172 |
|
173 generateForSingleTransition: t from: state. |
|
174 |
|
175 (self isJoinPoint: t destination) ifTrue: [ self removeJoinTransition: t ]. |
|
176 |
|
177 codeGen codeAssertPeek: (t characterSet) orReturn: state priority. |
|
178 " (self isBacklink: t) ifTrue: [ |
|
179 codeGen add: 'true' |
|
180 ] ifFalse: [ |
|
181 self generateFor: t destination. |
|
182 ] |
|
183 " |
|
184 self generateFor: t destination |
|
185 ! |
|
186 |
|
187 generateForTransition: t from: state |
|
188 (self isJoinPoint: t destination) ifTrue: [ self removeJoinTransition: t ]. |
|
189 |
|
190 " (self isBacklink: t) ifTrue: [ |
|
191 codeGen codeAssertPeek: (t characterSet) ifTrue: [ |
|
192 codeGen add: 'true' |
|
193 ] |
|
194 ] ifFalse: [ |
|
195 codeGen codeAssertPeek: (t characterSet) ifTrue: [. |
|
196 self generateFor: t destination. |
|
197 ]. |
|
198 ]. |
|
199 " |
|
200 codeGen codeAssertPeek: (t characterSet) ifTrue: [. |
|
201 self generateFor: t destination. |
|
202 ]. |
|
203 codeGen codeIfFalse. |
|
204 ! |
|
205 |
|
206 generateNextFor: state |
|
207 state transitions isEmpty ifTrue: [ ^ self ]. |
|
208 codeGen codeNextChar. |
|
209 ! |
|
210 |
|
211 generateReturnFor: state |
|
212 codeGen codeNlReturnResult: state priority. |
|
213 ! |
|
214 |
|
215 generateStartMethod: state. |
|
216 id := codeGen idFor: state. |
|
217 |
|
218 codeGen codeComment: 'START - Generated from state: ', state asString. |
|
219 |
|
220 (self hasMultipleIncommings: state) ifTrue: [ |
|
221 codeGen startMethod: id. |
|
222 ] ifFalse: [ |
|
223 codeGen startInline: id. |
|
224 ] |
|
225 ! |
|
226 |
|
227 generateStopMethod: state |
|
228 | | |
|
229 (self hasMultipleIncommings: state) ifTrue: [ |
|
230 codeGen codeAbsoluteReturn: codeGen stopMethod call. |
|
231 ] ifFalse: [ |
|
232 codeGen code: codeGen stopInline call. |
|
233 ]. |
|
234 codeGen codeComment: 'STOP - Generated from state: ', state asString. |
|
235 ! |
|
236 |
|
237 generateTransitionsFor: state |
|
238 (state transitions size = 0) ifTrue: [ |
|
239 self generateReturnFor: state. |
|
240 ^ self |
|
241 ]. |
|
242 |
|
243 (state transitions size = 1) ifTrue: [ |
|
244 self generateForSingleTransition: state transitions anyOne from: state. |
|
245 ^ self |
|
246 ]. |
|
247 |
|
248 |
|
249 codeGen codeNl. |
|
250 state transitions do: [ :t | |
|
251 self generateForTransition: t from: state |
|
252 ]. |
|
253 |
|
254 codeGen indent. |
|
255 self generateReturnFor: state. |
|
256 codeGen dedent. |
|
257 codeGen codeNl. |
|
258 state transitions size timesRepeat: [ codeGen addOnLine: ']' ]. |
|
259 codeGen addOnLine: '.'. |
|
260 |
|
261 |
|
262 " self closedJoinPoints isEmpty ifFalse: [ |
|
263 | jp | |
|
264 self assert: self closedJoinPoints size == 1. |
|
265 |
|
266 jp := self closedJoinPoints anyOne. |
|
267 self removeJoinPoint: jp. |
|
268 self generateFor: jp. |
|
269 ] |
|
270 " |
|
271 ! ! |
|
272 |
|
273 !PPCScannerCodeGenerator methodsFor:'compiling'! |
|
274 |
|
275 compileScannerClass |
|
276 | builder | |
|
277 builder := PPCClassBuilder new. |
|
278 |
|
279 builder compiledClassName: arguments scannerName. |
|
280 builder compiledSuperclass: PPCScanner. |
|
281 builder methodDictionary: codeGen methodDictionary. |
|
282 builder constants: codeGen constants. |
|
283 |
|
284 ^ builder compileClass. |
|
285 ! ! |
|
286 |
|
287 !PPCScannerCodeGenerator methodsFor:'initialization'! |
|
288 |
|
289 initialize |
|
290 super initialize. |
|
291 |
|
292 codeGen := PPCFSACodeGen new. |
|
293 arguments := PPCArguments default. |
|
294 ! ! |
|
295 |
|
296 !PPCScannerCodeGenerator methodsFor:'support'! |
|
297 |
|
298 removeJoinPoint: state |
|
299 self assert: (joinPoints at: state) size = 0. |
|
300 joinPoints removeKey: state |
|
301 ! |
|
302 |
|
303 removeJoinTransition: t |
|
304 (self joinTransitionsTo: t destination) remove: t ifAbsent: [ self error: 'this should not happen' ]. |
|
305 ! ! |
|
306 |