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.
- data/History.txt +4 -0
- data/Manifest.txt +35 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +49 -0
- data/Rakefile +28 -0
- data/bin/testgen +10 -0
- data/config/website.yml.sample +2 -0
- data/features/development.feature +13 -0
- data/features/steps/common.rb +174 -0
- data/features/steps/env.rb +6 -0
- data/lib/cgialib/lp/CLanguageScanner.rb +446 -0
- data/lib/cgialib/lp/CPPLanguageScanner.rb +326 -0
- data/lib/cgialib/lp/CTokenizer.rb +481 -0
- data/lib/cgialib/lp/Language.rb +293 -0
- data/lib/cgialib/lp/Tokenizer.rb +281 -0
- data/lib/cgialib/lp.rb +10 -0
- data/lib/cgialib/template/ut/c.rb +41 -0
- data/lib/cgialib/template/ut.rb +6 -0
- data/lib/cgialib/template.rb +6 -0
- data/lib/cgialib.rb +9 -0
- data/lib/testgen/cli.rb +210 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +82 -0
- data/spec/cgialib_spec.rb +11 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/testgen_cli_spec.rb +15 -0
- data/tasks/rspec.rake +21 -0
- data/website/index.html +86 -0
- data/website/index.txt +79 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +159 -0
- data/website/template.html.erb +50 -0
- metadata +112 -0
@@ -0,0 +1,446 @@
|
|
1
|
+
# File: CLanguageScanner.rb
|
2
|
+
# Author: Jack Herrington
|
3
|
+
# Purpose: The CLanguageScanner object specialized to look for C prototypes
|
4
|
+
# Date: 12/21/02
|
5
|
+
|
6
|
+
#require "Tokenizer"
|
7
|
+
#require "Language"
|
8
|
+
|
9
|
+
module LanguageParser
|
10
|
+
# class : CLanguageScanner
|
11
|
+
#
|
12
|
+
# This is the CLanguageScanner specialized to read prototypes for C
|
13
|
+
# functions.
|
14
|
+
|
15
|
+
class CLanguageScanner < LanguageScanner
|
16
|
+
|
17
|
+
# initialize()
|
18
|
+
#
|
19
|
+
# Constructs the C language scanner class
|
20
|
+
|
21
|
+
def initialize()
|
22
|
+
|
23
|
+
# Create the prototype array
|
24
|
+
|
25
|
+
@prototypes = []
|
26
|
+
|
27
|
+
# Create the defines array
|
28
|
+
|
29
|
+
@defines = {}
|
30
|
+
|
31
|
+
# Set the prototype class to build to the default
|
32
|
+
# prototype class
|
33
|
+
|
34
|
+
@prototypeClass = Prototype
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :prototypes # The array of prototypes found
|
39
|
+
attr_accessor :prototypeClass # The prototype class to build
|
40
|
+
attr_reader :defines # The array of '#defines' found
|
41
|
+
|
42
|
+
def to_s()
|
43
|
+
|
44
|
+
text = "Prototypes:\n"
|
45
|
+
|
46
|
+
@prototypes.each { |proto|
|
47
|
+
text += " #{proto}\n"
|
48
|
+
}
|
49
|
+
|
50
|
+
text += "\nDefines:\n"
|
51
|
+
|
52
|
+
@defines.each { |key,value|
|
53
|
+
text += " #{key} = '#{value}'\n"
|
54
|
+
}
|
55
|
+
|
56
|
+
text
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
# parse( tokens )
|
61
|
+
#
|
62
|
+
# tokens - An array of tokens built by a Tokenizer
|
63
|
+
#
|
64
|
+
# This method reads the stream of tokens built by a Tokenizer
|
65
|
+
# and fills the @prototypes array with the prototypes
|
66
|
+
# that are found.
|
67
|
+
|
68
|
+
def parse( tokens )
|
69
|
+
|
70
|
+
# This is the code fragment leading up to the interior
|
71
|
+
# of the function
|
72
|
+
|
73
|
+
codefrag = TokenStream.new()
|
74
|
+
|
75
|
+
# 'level' is the level of bracket nesting.
|
76
|
+
|
77
|
+
level = 0
|
78
|
+
|
79
|
+
# This will be true if we are looking at precompiler tokens
|
80
|
+
|
81
|
+
hold_until_return = false
|
82
|
+
|
83
|
+
# This will be true if we are looking for a '#define'
|
84
|
+
|
85
|
+
parsing_define = false
|
86
|
+
define_name = nil
|
87
|
+
define_value = nil
|
88
|
+
|
89
|
+
# Look through each token
|
90
|
+
|
91
|
+
tokens.each { |tok|
|
92
|
+
|
93
|
+
if ( parsing_define )
|
94
|
+
|
95
|
+
unless ( define_name )
|
96
|
+
|
97
|
+
define_name = tok.to_s if ( tok.is_a?( CodeToken ) )
|
98
|
+
|
99
|
+
else
|
100
|
+
|
101
|
+
if ( tok.to_s =~ /^\n/ )
|
102
|
+
|
103
|
+
define_value.strip!
|
104
|
+
@defines[ define_name ] = define_value.to_s
|
105
|
+
|
106
|
+
parsing_define = false
|
107
|
+
define_name = nil
|
108
|
+
define_value = nil
|
109
|
+
|
110
|
+
else
|
111
|
+
|
112
|
+
define_value.push( tok )
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
next
|
119
|
+
|
120
|
+
elsif ( hold_until_return )
|
121
|
+
|
122
|
+
hold_until_return = false if ( tok.to_s =~ /^\n/ )
|
123
|
+
next
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
if tok.to_s =~ /^#define$/
|
128
|
+
|
129
|
+
# This is a #define macro, so we need to start parsing
|
130
|
+
# it
|
131
|
+
|
132
|
+
parsing_define = true
|
133
|
+
define_name = nil
|
134
|
+
define_value = TokenStream.new()
|
135
|
+
|
136
|
+
elsif tok.to_s =~ /^#/
|
137
|
+
|
138
|
+
# This is a precompiler directive, so
|
139
|
+
# we should ignore all of the tokens
|
140
|
+
# until a return
|
141
|
+
|
142
|
+
hold_until_return = true
|
143
|
+
|
144
|
+
elsif tok.to_s == "{"
|
145
|
+
|
146
|
+
# If we are at level zero then we are
|
147
|
+
# opening a function for code, so we
|
148
|
+
# should interpret what we have
|
149
|
+
# up until now.
|
150
|
+
|
151
|
+
if level == 0
|
152
|
+
|
153
|
+
parse_prototype( codefrag )
|
154
|
+
|
155
|
+
codefrag = TokenStream.new()
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
# Now increment the level
|
160
|
+
|
161
|
+
level += 1
|
162
|
+
|
163
|
+
elsif tok.to_s == "}"
|
164
|
+
|
165
|
+
# Decrement the level
|
166
|
+
|
167
|
+
level -= 1
|
168
|
+
|
169
|
+
elsif tok.to_s == ";"
|
170
|
+
|
171
|
+
# If we see a ";" and we are at level
|
172
|
+
# zero then we have a constant
|
173
|
+
# declaration
|
174
|
+
|
175
|
+
codefrag = TokenStream.new() if ( level == 0 )
|
176
|
+
|
177
|
+
else
|
178
|
+
|
179
|
+
# Otherwise push the fragment
|
180
|
+
|
181
|
+
codefrag.push( tok ) if level == 0
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
}
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
protected
|
190
|
+
|
191
|
+
# clean_comment( comment )
|
192
|
+
#
|
193
|
+
# comment - The comment text
|
194
|
+
#
|
195
|
+
# This removes the actual comment prefixes from the comment
|
196
|
+
# text (e.g. /*, */, //)
|
197
|
+
|
198
|
+
def clean_comment( comment )
|
199
|
+
|
200
|
+
if ( comment =~ /^\/\*/ )
|
201
|
+
|
202
|
+
comment.sub!( /^\/\*/, "" )
|
203
|
+
comment.sub!( /\*\/$/, "" )
|
204
|
+
|
205
|
+
else
|
206
|
+
|
207
|
+
comment.gsub!( /^\/\//, "" )
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
comment.strip!()
|
212
|
+
comment
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
# parse_declaration( codefrag )
|
217
|
+
#
|
218
|
+
# codefrag - The code token array
|
219
|
+
#
|
220
|
+
# This turns the set of tokens that represent a declaration
|
221
|
+
# ("int *a[]") into a name ("a"), a type "int *", and an
|
222
|
+
# array boolean (true).
|
223
|
+
|
224
|
+
def parse_declaration( codefrag )
|
225
|
+
|
226
|
+
code = codefrag.code_only
|
227
|
+
|
228
|
+
# Check for an equals with a value
|
229
|
+
|
230
|
+
value = nil
|
231
|
+
|
232
|
+
if ( code.find( "=" ) )
|
233
|
+
|
234
|
+
value = code.pop
|
235
|
+
code.pop
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
# By default this will not be an array
|
240
|
+
|
241
|
+
array = false
|
242
|
+
|
243
|
+
# Here we are backtracking from the end to find the name
|
244
|
+
# within the declaration
|
245
|
+
|
246
|
+
while( code.length > 0 )
|
247
|
+
|
248
|
+
frag = code.last
|
249
|
+
|
250
|
+
array = true if ( frag == "[" )
|
251
|
+
|
252
|
+
break unless ( frag == "[" || frag == "]" )
|
253
|
+
|
254
|
+
code.delete_at( code.length - 1 )
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
# We assume that the name is the last non-whitespace,
|
259
|
+
# non-array token
|
260
|
+
|
261
|
+
name = code.last
|
262
|
+
|
263
|
+
code.delete_at( code.length - 1 )
|
264
|
+
|
265
|
+
# Then we build the type from the remainder
|
266
|
+
|
267
|
+
type = ""
|
268
|
+
|
269
|
+
type = code.map { |tok| tok.to_s }.join( " " )
|
270
|
+
|
271
|
+
type.strip!
|
272
|
+
|
273
|
+
# Look for special cases
|
274
|
+
|
275
|
+
if name.to_s == "void"
|
276
|
+
|
277
|
+
name = CodeToken.new( "" )
|
278
|
+
type = "void"
|
279
|
+
|
280
|
+
end
|
281
|
+
|
282
|
+
if name.to_s == "*" || name.to_s == "&"
|
283
|
+
|
284
|
+
type += " #{name.to_s}"
|
285
|
+
name = CodeToken.new( "" )
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
# Then we return a structure that contains the declaration
|
290
|
+
# data
|
291
|
+
|
292
|
+
return { 'name' => name, 'type' => type, 'array' => array, 'value' => value }
|
293
|
+
|
294
|
+
end
|
295
|
+
|
296
|
+
# parse_prototype( codefrag, comment )
|
297
|
+
#
|
298
|
+
# codefrag - The tokens leading up to a function definition
|
299
|
+
# comment - A comment if one was found
|
300
|
+
#
|
301
|
+
# This turns the series of tokens leading up to the function
|
302
|
+
# definition and turns it into a prototype object which it
|
303
|
+
# adds to the prototype list.
|
304
|
+
|
305
|
+
def parse_prototype( codefrag, comment = nil )
|
306
|
+
|
307
|
+
# Contains any comments found within the tokens
|
308
|
+
|
309
|
+
comments = TokenStream.new()
|
310
|
+
|
311
|
+
# Add the comment if there is one
|
312
|
+
|
313
|
+
comments.push( clean_comment( comment.to_s() ) ) if ( comment )
|
314
|
+
|
315
|
+
# This will be true when we have found the first
|
316
|
+
# code token
|
317
|
+
|
318
|
+
found_code = false
|
319
|
+
|
320
|
+
# True when our iterator is within the arguments tokens
|
321
|
+
|
322
|
+
in_arguments = false
|
323
|
+
|
324
|
+
# Start contains the tokens before the arguments
|
325
|
+
|
326
|
+
start = TokenStream.new()
|
327
|
+
|
328
|
+
# args contains the sets of arguments tokens
|
329
|
+
|
330
|
+
args = TokenStream.new()
|
331
|
+
|
332
|
+
# cur_arg contains the tokens of the argument
|
333
|
+
# currently being parsed
|
334
|
+
|
335
|
+
cur_arg = TokenStream.new()
|
336
|
+
|
337
|
+
# Iterate through the codefrag tokens
|
338
|
+
|
339
|
+
codefrag.each { |tok|
|
340
|
+
|
341
|
+
# Set found_code to true when we find a CodeToken
|
342
|
+
|
343
|
+
found_code = true if ( tok.is_a?( CodeToken ) )
|
344
|
+
|
345
|
+
# Add the comment if the token is a comment
|
346
|
+
|
347
|
+
if tok.is_a?( CommentToken )
|
348
|
+
|
349
|
+
comments.push( clean_comment( tok.to_s() ) )
|
350
|
+
next
|
351
|
+
|
352
|
+
end
|
353
|
+
|
354
|
+
# Go to the next token if we have not found code
|
355
|
+
|
356
|
+
next unless ( found_code )
|
357
|
+
|
358
|
+
if tok.to_s == "("
|
359
|
+
|
360
|
+
# Look for the start of the arguments
|
361
|
+
|
362
|
+
in_arguments = true
|
363
|
+
cur_arg = TokenStream.new()
|
364
|
+
|
365
|
+
elsif tok.to_s == ")"
|
366
|
+
|
367
|
+
# Look for the end of the arguments, when
|
368
|
+
# we find it we dump out of the iterator
|
369
|
+
|
370
|
+
args.push( cur_arg ) if cur_arg.length > 0
|
371
|
+
break
|
372
|
+
|
373
|
+
elsif in_arguments == false
|
374
|
+
|
375
|
+
# If we are not in the arguments then
|
376
|
+
# push these code tokens into the start
|
377
|
+
# fragment list
|
378
|
+
|
379
|
+
start.push( tok )
|
380
|
+
|
381
|
+
else
|
382
|
+
|
383
|
+
# We are in the arguments, so look for
|
384
|
+
# the comments that seperate the arguments
|
385
|
+
|
386
|
+
if tok.to_s == ","
|
387
|
+
|
388
|
+
args.push( cur_arg ) if cur_arg.length > 0
|
389
|
+
cur_arg = TokenStream.new()
|
390
|
+
|
391
|
+
else
|
392
|
+
|
393
|
+
cur_arg.push( tok )
|
394
|
+
end
|
395
|
+
|
396
|
+
end
|
397
|
+
|
398
|
+
}
|
399
|
+
|
400
|
+
# Have the base class build the new prototype
|
401
|
+
|
402
|
+
proto = build_prototype()
|
403
|
+
|
404
|
+
# Parse the starting declaration and set the prototype
|
405
|
+
|
406
|
+
start_decl = parse_declaration( start )
|
407
|
+
|
408
|
+
proto.method_name = start_decl['name']
|
409
|
+
proto.method_type = start_decl['type']
|
410
|
+
|
411
|
+
# Parse the arguments and add them to the prototype
|
412
|
+
|
413
|
+
args.each { |arg|
|
414
|
+
|
415
|
+
arg_decl = parse_declaration( arg )
|
416
|
+
|
417
|
+
proto.add_argument( arg_decl[ 'name' ], arg_decl['type'] )
|
418
|
+
|
419
|
+
}
|
420
|
+
|
421
|
+
# Add the comments
|
422
|
+
|
423
|
+
comments.each { |comment| proto.add_comment( comment.to_s ) }
|
424
|
+
|
425
|
+
# Add this prototype to the array of found prototypes
|
426
|
+
|
427
|
+
if ( proto.method_type != "class" )
|
428
|
+
|
429
|
+
@prototypes.push( proto )
|
430
|
+
|
431
|
+
end
|
432
|
+
|
433
|
+
proto
|
434
|
+
|
435
|
+
end
|
436
|
+
|
437
|
+
# build_prototype()
|
438
|
+
#
|
439
|
+
# Builds and returns a prototype object
|
440
|
+
|
441
|
+
def build_prototype()
|
442
|
+
@prototypeClass.new()
|
443
|
+
end
|
444
|
+
|
445
|
+
end
|
446
|
+
end
|