cgialib 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,326 @@
1
+ # File: CPPLanguageScanner.rb
2
+ # Author: Jack Herrington
3
+ # Purpose: The CPPLanguageScanner object specialized to look for C++ language
4
+ # features.
5
+ # Date: 12/21/02
6
+
7
+ #require "Tokenizer"
8
+ #require "CLanguageScanner"
9
+
10
+ module LanguageParser
11
+ # Class : CPPLanguageScanner
12
+ #
13
+ # The scanner specialized for processing C++ headers.
14
+
15
+ class CPPLanguageScanner < CLanguageScanner
16
+
17
+ # initialize()
18
+ #
19
+ # Constructs the scanner object
20
+
21
+ def initialize()
22
+
23
+ super()
24
+
25
+ @classes = []
26
+
27
+ @prototypeClass = Prototype
28
+ @variableClass = ClassVariable
29
+ @languageClass = LanguageClass
30
+
31
+ end
32
+
33
+ attr_reader :classes # The classes found
34
+
35
+ attr_accessor :languageClass # The class to use when building class objects
36
+
37
+ attr_accessor :variableClass # The class to use when building variable objects
38
+
39
+ # parse( tokens )
40
+ #
41
+ # tokens - Tokens returned from CTokenizer
42
+ #
43
+ # Parses the tokens read from the CTokenizer
44
+
45
+ def parse( tokens )
46
+
47
+ # Handle the function prototypes in the base class
48
+
49
+ super( tokens )
50
+
51
+ # Set up the code buffer
52
+
53
+ codefrag = TokenStream.new()
54
+
55
+ # Set up the state machine flags
56
+
57
+ has_class = false
58
+ found_open = false
59
+ level = 0
60
+ comments = ""
61
+
62
+ # Look through the tokens for classes, and build up the full class bodies
63
+ # in codefrag. Then send the codefrags on to parse_class
64
+
65
+ tokens.each_index { |index|
66
+
67
+ tok = tokens[ index ]
68
+
69
+ if ( has_class )
70
+
71
+ comments = tokens.get_comments( index )
72
+
73
+ codefrag.push( tok )
74
+
75
+ if ( tok.to_s == "{" )
76
+
77
+ level += 1
78
+
79
+ found_open = true
80
+
81
+ end
82
+
83
+ level -= 1 if ( tok.to_s == "}" )
84
+
85
+ if ( tok.to_s == ";" && level == 0 )
86
+
87
+ parse_class( codefrag, comments ) if ( codefrag.length > 0 && found_open )
88
+
89
+ codefrag = TokenStream.new()
90
+
91
+ has_class = false
92
+ found_open = false
93
+
94
+ end
95
+
96
+ end
97
+
98
+ has_class = true if ( tok.to_s.downcase == "class" && level == 0 )
99
+
100
+ }
101
+
102
+ parse_class( codefrag, comments ) if ( codefrag.length > 0 && found_open )
103
+
104
+ end
105
+
106
+ # to_s()
107
+ #
108
+ # A pretty printer for the object
109
+
110
+ def to_s()
111
+
112
+ text = ""
113
+
114
+ classes.each { |cpp_class| text += cpp_class.to_s }
115
+
116
+ text
117
+
118
+ end
119
+
120
+ protected
121
+
122
+ # parse_class( codefrag, comments )
123
+ #
124
+ # codefrag - The class tokens
125
+ # comments - The comments before the class
126
+ #
127
+ # Parse the class tokens to find methods, instance variables, constants,
128
+ # etc.
129
+
130
+ def parse_class( codefrag, comments )
131
+
132
+ class_data = build_class()
133
+
134
+ proto = TokenStream.new()
135
+
136
+ level = 0
137
+
138
+ visibility = "public"
139
+
140
+ comments = TokenStream.new()
141
+
142
+ codefrag.each { |tok|
143
+
144
+ break if ( tok.to_s == "}" && level == 1 )
145
+
146
+ if ( level == 0 )
147
+
148
+ next if tok.to_s == ":" || tok.to_s == "public"
149
+ next if tok.to_s == "private" || tok.to_s == ","
150
+
151
+ next unless tok.is_a?( CodeToken )
152
+
153
+ if ( class_data.name.length == 0 )
154
+
155
+ class_data.name = tok.to_s
156
+
157
+ else
158
+
159
+ class_data.add_parent( tok.to_s ) unless ( tok.to_s == "{" )
160
+
161
+ end
162
+
163
+ else
164
+
165
+ if ( tok.to_s =~ /^public$/ )
166
+
167
+ visibility = "public"
168
+ comments = TokenStream.new()
169
+ proto = TokenStream.new()
170
+
171
+ elsif ( tok.to_s =~ /^private$/ )
172
+
173
+ visibility = "private"
174
+ comments = TokenStream.new()
175
+ proto = TokenStream.new()
176
+
177
+ elsif ( tok.to_s =~ /^protected$/ )
178
+
179
+ visibility = "protected"
180
+ comments = TokenStream.new()
181
+ proto = TokenStream.new()
182
+
183
+ elsif ( tok.is_a?( CommentToken ) )
184
+
185
+ comments.push( tok ) if ( level == 1 )
186
+
187
+ elsif ( tok.to_s == ":" && level == 1 )
188
+
189
+ elsif ( tok.to_s == ";" && level == 1 )
190
+
191
+ parse_method_prototype( class_data, visibility, proto, comments ) if proto.length > 0
192
+ comments = TokenStream.new()
193
+ proto = TokenStream.new()
194
+
195
+ elsif ( level == 1 )
196
+
197
+ proto.push( tok )
198
+
199
+ end
200
+
201
+ end
202
+
203
+ if ( tok.to_s == "{" )
204
+
205
+ parse_method_prototype( class_data, visibility, proto, comments ) if proto.length > 0
206
+ comments = TokenStream.new()
207
+
208
+ level += 1
209
+
210
+ end
211
+
212
+ }
213
+
214
+ @classes.push( class_data )
215
+
216
+ end
217
+
218
+ # parse_method_prototype( class_data, visibility, codefrag, comment )
219
+ #
220
+ # class_data - The current class object
221
+ # visibility - 'private', 'protected', or 'public'
222
+ # codefrag - The tokens of the prototype
223
+ # comment - The comments before the method declaration
224
+
225
+ def parse_method_prototype( class_data, visibility, codefrag, comment )
226
+
227
+ # Get down to just the code, no comments or whitespace
228
+
229
+ code = codefrag.code_only
230
+
231
+ # The primary switch is whether this is a method or an instance variable.
232
+ # That's decided on the existence of the paren.
233
+
234
+ if ( code.find( "(" ) )
235
+
236
+ # Get the prototype
237
+
238
+ proto = parse_prototype( codefrag, comment )
239
+
240
+ # Add in the visibility
241
+
242
+ proto.visibility = visibility
243
+
244
+ # Check for a static method
245
+
246
+ if ( proto.method_type =~ /^static/ )
247
+
248
+ proto.method_type.sub!( /^static\s+/, "" )
249
+ proto.static = true
250
+
251
+ end
252
+
253
+ # Add this method into the class
254
+
255
+ class_data.add_method( proto )
256
+
257
+ else
258
+
259
+ # Build the variable object
260
+
261
+ varItem = build_class_variable()
262
+
263
+ # Parse the declaration
264
+
265
+ varSpec = parse_declaration( codefrag )
266
+
267
+ # Look for static
268
+
269
+ static = false
270
+ if ( varSpec[ 'type' ] =~ /^static/ )
271
+
272
+ varSpec[ 'type' ].sub!( /^static\s+/, "" )
273
+ static = true
274
+
275
+ end
276
+
277
+ # Look for const
278
+
279
+ if ( varSpec[ 'type' ] =~ /^const/ )
280
+
281
+ varSpec[ 'type' ].sub!( /^const\s+/, "" )
282
+ const = true
283
+
284
+ end
285
+
286
+ # Fill the fields of the object mainly with the return from
287
+ # parse_declaration
288
+
289
+ varItem.name = varSpec[ 'name' ]
290
+ varItem.type = varSpec[ 'type' ]
291
+ varItem.value = varSpec[ 'value' ]
292
+ varItem.static = static
293
+ varItem.const = const
294
+ varItem.visibility = visibility
295
+ varItem.comment = comment
296
+
297
+ # Add the variable to the class
298
+
299
+ class_data.add_variable( varItem )
300
+
301
+ end
302
+
303
+ end
304
+
305
+ # build_class_variable()
306
+ #
307
+ # Returns a new class variable object
308
+
309
+ def build_class_variable
310
+
311
+ @variableClass.new()
312
+
313
+ end
314
+
315
+ # build_class()
316
+ #
317
+ # REturns a new class object
318
+
319
+ def build_class
320
+
321
+ @languageClass.new()
322
+
323
+ end
324
+
325
+ end
326
+ end