cgialib 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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