author | vranyj1 |
Wed, 17 Nov 2010 21:57:55 +0000 | |
changeset 20 | 4ea23addc2c4 |
parent 16 | 55254a6f8404 |
child 26 | b2c091b8cea1 |
permissions | -rw-r--r-- |
1 | 1 |
"{ Package: 'stx:goodies/smaCC' }" |
2 |
||
3 |
"{ NameSpace: SmaCC }" |
|
4 |
||
5 |
Object subclass:#SmaCCEdge |
|
6 |
instanceVariableNames:'toNode characters' |
|
7 |
classVariableNames:'IsExpressions' |
|
8 |
poolDictionaries:'' |
|
9 |
category:'SmaCC-Scanner Generator' |
|
10 |
! |
|
11 |
||
12 |
SmaCCEdge comment:'SmaCCEdge represents a transition in a Finite Automata (directed graph). It is labeled with the characters (possibly none, indicating an epsilon transition) that cause the transition. |
|
13 |
||
14 |
Instance Variables: |
|
15 |
characters <SortedCollection of: Character> The characters that cause the transition. Note that there are no duplicates and all characters are sorted. |
|
16 |
toNode <SmaCCNode> The node that this is transitioning to.' |
|
17 |
! |
|
18 |
||
19 |
||
20 |
!SmaCCEdge class methodsFor:'instance creation'! |
|
21 |
||
22 |
to: aNode on: aStringOrNil |
|
23 |
| edge | |
|
24 |
edge := self new. |
|
25 |
edge to: aNode on: aStringOrNil. |
|
26 |
^edge |
|
27 |
! ! |
|
28 |
||
29 |
!SmaCCEdge class methodsFor:'class initialization'! |
|
30 |
||
31 |
generateCharacterSetFor: aSelector |
|
32 |
| stream | |
|
33 |
stream := WriteStream on: UnicodeString new. |
|
34 |
0 to: SmaCCGrammar maximumCharacterValue |
|
35 |
do: |
|
36 |
[:i | |
|
37 |
| ch | |
|
38 |
ch := Character value: i. |
|
39 |
(ch perform: aSelector) ifTrue: [stream nextPut: ch]]. |
|
40 |
^stream contents |
|
41 |
||
42 |
"Modified: / 26-05-2006 / 22:16:27 / janfrog" |
|
43 |
! |
|
44 |
||
45 |
initializeIsExpressions |
|
16
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
46 |
"Creates a map from sets of characters to selectors that start with 'is' on Character. This allows generated scanners to take |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
47 |
full advantage of selectors that are already implemented on Character" |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
48 |
|
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
49 |
|selectors| |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
50 |
|
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
51 |
IsExpressions := Dictionary new. |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
52 |
selectors := OrderedCollection new. |
1 | 53 |
|
16
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
54 |
"This code ensures that any extension isXXX methods will not |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
55 |
be taken" |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
56 |
Character methodDictionary do: |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
57 |
[:method| | selector | |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
58 |
selector := method selector. |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
59 |
((selector startsWith:'is') and:[method numArgs = 0 and:[method package == Character package]]) |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
60 |
ifTrue:[selectors add:selector]]. |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
61 |
|
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
62 |
selectors do:[:sel | |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
63 |
|string| |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
64 |
|
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
65 |
string := self generateCharacterSetFor:sel. |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
66 |
string isEmpty ifFalse:[ |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
67 |
IsExpressions at:string put:sel |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
68 |
] |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
69 |
] |
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
70 |
|
55254a6f8404
Generated scanners how uses Character>>is* methods on iff they
vranyj1
parents:
15
diff
changeset
|
71 |
"Modified: / 15-02-2010 / 16:57:28 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
1 | 72 |
! ! |
73 |
||
74 |
!SmaCCEdge methodsFor:'accessing'! |
|
75 |
||
76 |
mergeWith: anEdge |
|
77 |
characters := String withAll: ((characters , anEdge characters) asSet |
|
78 |
asSortedCollection: [:a :b | a asInteger < b asInteger]) |
|
79 |
! |
|
80 |
||
81 |
to |
|
82 |
^toNode |
|
83 |
! ! |
|
84 |
||
85 |
!SmaCCEdge methodsFor:'comparing'! |
|
86 |
||
87 |
< anEdge |
|
88 |
"required for ST/X, where SortedCollection uses < to compare" |
|
89 |
||
90 |
^self to id < anEdge to id |
|
91 |
! |
|
92 |
||
93 |
<= anEdge |
|
94 |
^self to id <= anEdge to id |
|
95 |
! |
|
96 |
||
97 |
= anEdge |
|
98 |
self class = anEdge class ifFalse: [^false]. |
|
99 |
^self to = anEdge to and: [self characters = anEdge characters] |
|
100 |
! |
|
101 |
||
102 |
hash |
|
103 |
^(self to hash bitShift: 14) bitXor: characters hash |
|
104 |
! ! |
|
105 |
||
106 |
!SmaCCEdge methodsFor:'compiling'! |
|
107 |
||
108 |
closestIsExpression |
|
109 |
"Attempts to find the #is selector that most closely matches the character set that this edge transitions on." |
|
110 |
||
111 |
| expressions closest | |
|
112 |
expressions := IsExpressions keys |
|
113 |
select: [:each | (each reject: [:ch | self includesCharacter: ch]) isEmpty]. |
|
114 |
expressions isEmpty ifTrue: [^nil]. |
|
115 |
closest := IsExpressions |
|
116 |
at: (expressions asSortedCollection: [:a :b | a size > b size]) first. |
|
117 |
(self minMaxPairsWithout: closest) size |
|
118 |
<= (self minMaxPairsWithout: nil) size ifFalse: [^nil]. |
|
119 |
^closest |
|
120 |
! |
|
121 |
||
122 |
expression |
|
123 |
| stream isSelector | |
|
124 |
stream := WriteStream on: (String new: 128). |
|
125 |
stream nextPut: $(. |
|
126 |
characters size = SmaCCGrammar maximumCharacterValue |
|
127 |
ifTrue: [self outputInvertedMatchOn: stream] |
|
128 |
ifFalse: |
|
129 |
[isSelector := self outputClosestIsMethodOn: stream. |
|
130 |
self outputExpressionOn: stream without: isSelector]. |
|
131 |
stream nextPut: $). |
|
132 |
^stream contents |
|
133 |
! |
|
134 |
||
135 |
minMaxPairsWithout: aSelector |
|
136 |
"Converts a list of characters into a collection of pairs representing the minimum and maximum of each sequence. |
|
137 |
The list is first filtered to include only those characters that fail aSelector." |
|
138 |
||
139 |
| start last pairs charsLeft | |
|
140 |
charsLeft := aSelector isNil |
|
141 |
ifTrue: [characters] |
|
142 |
ifFalse: [characters reject: [:ch | ch perform: aSelector]]. |
|
143 |
pairs := OrderedCollection new. |
|
144 |
charsLeft isEmpty ifTrue: [^pairs]. |
|
145 |
last := charsLeft first. |
|
146 |
start := nil. |
|
147 |
charsLeft do: |
|
148 |
[:each | |
|
149 |
last asInteger + 1 = each asInteger |
|
150 |
ifFalse: |
|
151 |
[start notNil ifTrue: [pairs add: (Array with: start with: last)]. |
|
152 |
start := each]. |
|
153 |
last := each]. |
|
154 |
pairs add: (Array with: start with: last). |
|
155 |
^pairs |
|
156 |
! |
|
157 |
||
158 |
outputClosestIsMethodOn: stream |
|
159 |
| expr | |
|
160 |
expr := self closestIsExpression. |
|
161 |
expr isNil ifFalse: [stream nextPutAll: 'currentCharacter ' , expr]. |
|
162 |
^expr |
|
163 |
! |
|
164 |
||
165 |
outputExpressionFor: aPair on: stream |
|
166 |
aPair first == aPair last |
|
167 |
ifTrue: [^self outputMatchSingleCharacter: aPair first on: stream]. |
|
168 |
aPair first = (Character value: 0) |
|
169 |
ifTrue: [^self outputMatchLessThan: aPair last on: stream]. |
|
170 |
aPair last = (Character value: SmaCCGrammar maximumCharacterValue) |
|
171 |
ifTrue: [^self outputMatchGreaterThan: aPair first on: stream]. |
|
172 |
self outputMatchRange: aPair on: stream |
|
173 |
! |
|
174 |
||
175 |
outputExpressionOn: aStream without: aSelector |
|
176 |
| pairs | |
|
177 |
pairs := self minMaxPairsWithout: aSelector. |
|
178 |
pairs isEmpty ifTrue: [^self]. |
|
179 |
aSelector notNil ifTrue: [aStream nextPutAll: ' or: [']. |
|
180 |
pairs do: [:each | self outputExpressionFor: each on: aStream] |
|
181 |
separatedBy: [aStream nextPutAll: ' or: [']. |
|
182 |
aStream next: pairs size - 1 put: $]. |
|
183 |
aSelector notNil ifTrue: [aStream nextPut: $]] |
|
184 |
! |
|
185 |
||
186 |
outputInvertedMatchOn: aStream |
|
187 |
| char | |
|
188 |
char := Character value: ((0 to: SmaCCGrammar maximumCharacterValue) |
|
189 |
detect: [:each | (characters includes: (Character value: each)) not]). |
|
190 |
aStream |
|
191 |
nextPutAll: 'currentCharacter ~~ '; |
|
192 |
nextPutAll: char storeString |
|
193 |
! |
|
194 |
||
195 |
outputMatchGreaterThan: aCharacter on: stream |
|
196 |
stream |
|
197 |
nextPutAll: 'currentCharacter >= '; |
|
198 |
nextPutAll: aCharacter storeString |
|
199 |
! |
|
200 |
||
201 |
outputMatchLessThan: aCharacter on: stream |
|
202 |
stream |
|
203 |
nextPutAll: 'currentCharacter <= '; |
|
204 |
nextPutAll: aCharacter storeString |
|
205 |
! |
|
206 |
||
207 |
outputMatchRange: aPair on: stream |
|
208 |
stream |
|
209 |
nextPutAll: '(currentCharacter between: '; |
|
210 |
nextPutAll: aPair first storeString; |
|
211 |
nextPutAll: ' and: '; |
|
212 |
nextPutAll: aPair last storeString; |
|
213 |
nextPutAll: ')' |
|
214 |
! |
|
215 |
||
216 |
outputMatchSingleCharacter: aCharacter on: stream |
|
217 |
stream |
|
218 |
nextPutAll: 'currentCharacter == '; |
|
219 |
nextPutAll: aCharacter storeString |
|
220 |
! ! |
|
221 |
||
222 |
!SmaCCEdge methodsFor:'initialize-release'! |
|
223 |
||
224 |
to: aNode on: aStringOrNil |
|
225 |
toNode := aNode. |
|
226 |
characters := aStringOrNil |
|
227 |
! ! |
|
228 |
||
229 |
!SmaCCEdge methodsFor:'printing'! |
|
230 |
||
231 |
printOn: aStream |
|
232 |
aStream |
|
233 |
nextPutAll: '---'; |
|
234 |
nextPutAll: (characters ifNil: ['""']); |
|
235 |
nextPutAll: '--->'; |
|
236 |
nextPutAll: toNode printString |
|
237 |
! ! |
|
238 |
||
239 |
!SmaCCEdge methodsFor:'private'! |
|
240 |
||
241 |
characters |
|
242 |
^characters |
|
243 |
! |
|
244 |
||
245 |
removeCharacters: aCollection |
|
246 |
characters := characters |
|
247 |
reject: [:each | self does: aCollection includeCharacter: each] |
|
248 |
! ! |
|
249 |
||
250 |
!SmaCCEdge methodsFor:'public'! |
|
251 |
||
252 |
conflictsWith: anEdge |
|
253 |
^characters anySatisfy: [:each | anEdge characters includes: each] |
|
254 |
! |
|
255 |
||
256 |
does: aString includeCharacter: aCharacter |
|
257 |
| start stop mid | |
|
258 |
start := 1. |
|
259 |
stop := aString size. |
|
260 |
stop = 0 ifTrue: [^false]. |
|
261 |
||
262 |
[mid := (start + stop) // 2. |
|
263 |
mid == start] whileFalse: |
|
264 |
[(aString at: mid) asInteger < aCharacter asInteger |
|
265 |
ifTrue: [start := mid] |
|
266 |
ifFalse: [stop := mid]]. |
|
267 |
^(aString at: start) == aCharacter or: [(aString at: stop) == aCharacter] |
|
268 |
! |
|
269 |
||
270 |
includesCharacter: aCharacter |
|
271 |
^self does: characters includeCharacter: aCharacter |
|
272 |
! |
|
273 |
||
274 |
isEmpty |
|
275 |
^characters isEmpty |
|
276 |
! |
|
277 |
||
278 |
isEpsilonTransition |
|
279 |
^characters isNil |
|
280 |
! ! |
|
281 |
||
282 |
!SmaCCEdge class methodsFor:'documentation'! |
|
283 |
||
284 |
version |
|
285 |
^ '$Header: /opt/data/cvs/stx/goodies/smaCC/SmaCC__SmaCCEdge.st,v 1.2 2006-05-28 20:08:49 vranyj1 Exp $' |
|
15 | 286 |
! |
287 |
||
288 |
version_SVN |
|
289 |
^ '$Id$' |
|
1 | 290 |
! ! |