dbc 1.3.0 → 2.0.0

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,152 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Simple test script to run the parser on the given input file
4
+ #
5
+
6
+
7
+ if RUBY_VERSION =~ /\A1\.6/
8
+ warn("attempt to run with Ruby 1.6.* (should be using Ruby 1.8+)")
9
+ exit(1)
10
+ end
11
+
12
+ require 'optparse'
13
+
14
+ # allows us to run the regression test with local source base
15
+ # without installing caphir
16
+ if $0 != File.basename($0)
17
+ $:.unshift(File.join(File.dirname($0),'..','lib'))
18
+ end
19
+
20
+ require 'caphir/parsersettings'
21
+ require 'caphir/parser'
22
+
23
+
24
+ if $0 == __FILE__
25
+
26
+ settings = ParserSettings.new
27
+
28
+ # initialize with defaults
29
+ always_output = false
30
+
31
+ #
32
+ # define OptionParser
33
+ #
34
+
35
+ opts = OptionParser.new do |opts|
36
+ opts.banner = "Usage: parser.rb [options] [input file]"
37
+ opts.separator ""
38
+ opts.separator "Specific options:"
39
+
40
+ # Compiler like options
41
+ opts.on("-o", "--output file", String,
42
+ "Output to file (default STDOUT)") do |file|
43
+ opts.error("multiple output files give") if settings.dest_file
44
+ settings.dest_file = file
45
+ end
46
+ opts.on("-D macro(=value)", String, "Define macro") do |macro|
47
+ settings.define_macro(macro)
48
+ end
49
+ # allow user to undefine compiler specific macros
50
+ opts.on("-U macro", String, "Cancel the definintion of macro") do |macro|
51
+ settings.undefine_macro(macro)
52
+ end
53
+ opts.on("-I directory", String,
54
+ "Use directory to search for header files") do |inc_dir|
55
+ settings.add_include_path(inc_dir)
56
+ end
57
+ opts.on("--include file", String, "Include file before processing") do |file|
58
+ settings.includes << file
59
+ end
60
+ opts.on("--cc=compiler(-version)", String, "Specify target compiler") do |cc|
61
+ opts.error("invalid compiler #{cc}") unless cc =~ /\A[^-]+(?:-(\d\.)+)?\Z/
62
+ settings.compiler = $1
63
+ settings.version = $2
64
+ end
65
+ opts.on("-E", "Preprocess input file only") do
66
+ settings.preprocess_only = true
67
+ end
68
+ opts.on("-a", "--always-output", "Always output to destination file") do
69
+ always_output = true
70
+ end
71
+ opts.on("--no-overwrite", "Don't overwrite output file") do
72
+ settings.overwrite = false
73
+ end
74
+ opts.on("-h", "--help", "Print this message") do
75
+ puts opts
76
+ exit(0)
77
+ end
78
+
79
+ opts.separator ""
80
+ opts.separator "Reads from STDIN if input file is '-' or none is given."
81
+ opts.separator "-D and -U options are processed in the order given."
82
+
83
+ end
84
+
85
+ #
86
+ # Handle command line options
87
+ #
88
+
89
+ begin
90
+ opts.parse!(ARGV)
91
+ rescue
92
+ warn "#{$!} (-h will show vaild options)"
93
+ exit(2)
94
+ end
95
+
96
+ # make sure opts gets GC'ed
97
+ opts = nil
98
+
99
+
100
+ if ARGV.length > 1
101
+ warn "expecting one input file, got #{ARGV.length}"
102
+ exit(2)
103
+ end
104
+
105
+ unless ARGV.empty? || ARGV[0] == '-'
106
+ settings.src_file = ARGV[0]
107
+ unless File.file?(settings.src_file)
108
+ warn "file does not exist: #{settings.src_file}"
109
+ exit(2)
110
+ end
111
+ end
112
+
113
+ begin
114
+ settings.check
115
+ settings.execute
116
+ rescue
117
+ $stderr.puts $!
118
+ exit(2)
119
+ end
120
+
121
+
122
+ begin
123
+ out_str = ''
124
+
125
+ parser = Caphir::EventParser.new(settings)
126
+
127
+ if settings.preprocess_only
128
+ parser.each do |t|
129
+ out_str << t
130
+ end
131
+ else
132
+ parser.each do |function|
133
+ stmt = parser.in_stream.reset([])
134
+
135
+ out_str << stmt.collect! { |t| t.at(1) }.join
136
+ end
137
+ end
138
+
139
+ rescue CTokenizer::Error, CType::EvaluationError
140
+ warn $!
141
+ exit(-1)
142
+ ensure
143
+ if !$! or always_output
144
+ if settings.dest_file
145
+ File.open(settings.dest_file, 'w') { |f| f.write(out_str) }
146
+ else
147
+ $stdout.write(out_str)
148
+ end
149
+ end
150
+ end
151
+
152
+ end
@@ -6,327 +6,181 @@
6
6
  # See included LICENCE file.
7
7
 
8
8
  if RUBY_VERSION =~ /\A1\.6/
9
- warn("attempting to run with Ruby 1.6.* (should be using Ruby 1.8+)")
10
- $stdin = STDIN
11
- $stdout = STDOUT
12
- $stderr = STDERR
9
+ warn("attempt to run with Ruby 1.6.* (should be using Ruby 1.8+)")
10
+ exit(1)
13
11
  end
14
12
 
15
- # create output directories if they don't exist
16
- def create_dest_dirs(dest_file)
17
- dest_dir = File.dirname(dest_file)
18
- dirs = []
19
- until File.directory?(dest_dir)
20
- # [ "/home/boson/fake", "/home/boson" ]
21
- # "/home/boson" exists so loop ends
22
- dirs << dest_dir
23
- dest_dir = File.dirname(dest_dir)
24
- end
25
- dirs.reverse_each do |d|
26
- Dir.mkdir(d)
27
- end
28
- nil
29
- end
30
-
31
- require 'getoptlong'
13
+ require 'optparse'
32
14
 
33
- command_dir = File.dirname($0)
34
- command = File.basename($0)
35
- if $0 != command
36
- $:.unshift(File.join(command_dir,'..','lib'))
15
+ # allows us to run the regression test with local source base
16
+ # without installing DBC
17
+ if $0 != File.basename($0)
18
+ $:.unshift(File.join(File.dirname($0),'..','lib'))
37
19
  end
38
- require 'dbc/searchpath'
39
- require 'dbc/preprocessor'
20
+
21
+ require 'caphir/parsersettings'
22
+ require 'caphir/parser'
40
23
  require 'dbc/expand_function'
41
- require 'dbc/ctype'
42
24
  require 'dbc/dbc'
43
25
 
44
- class GetoptLong
45
- def error(msg)
46
- raise GetoptLong::Error, msg
47
- end
48
- end
49
-
50
- opts = GetoptLong.new(
51
- [ "--always-output", "-a", GetoptLong::NO_ARGUMENT ],
52
- [ "--docs", "-d", GetoptLong::NO_ARGUMENT ],
53
- [ "--help", "-h", GetoptLong::NO_ARGUMENT ],
54
- [ "--no_line", "-n", GetoptLong::NO_ARGUMENT ],
55
- [ "--preprocess-only","-p", GetoptLong::NO_ARGUMENT ],
56
- # [ "--trace", "-t", GetoptLong::NO_ARGUMENT ],
57
- [ "--check_level", "-c", GetoptLong::REQUIRED_ARGUMENT ],
58
- [ "--output", "-o", GetoptLong::REQUIRED_ARGUMENT ],
59
- # cc compatibility options
60
- [ "--define", "-D", GetoptLong::REQUIRED_ARGUMENT ],
61
- [ "--include", "-I", GetoptLong::OPTIONAL_ARGUMENT ]
62
- )
63
-
64
26
  # initialize with defaults
65
- dest_file = nil
66
- src_file = nil
67
- search_path = SearchPath.new
68
- defines = []
69
- search_usr_include = true
27
+ settings = ParserSettings.new
70
28
 
71
29
  always_output = false
72
30
  check_level = nil
73
31
  docs = nil
74
32
  line_info = true
75
- preprocess_only = nil
76
33
 
77
- overwrite = true # unused
34
+ #
35
+ # define OptionParser
36
+ #
37
+ opts = OptionParser.new do |opts|
38
+ opts.banner = "Usage: dbcparse.rb [options] [input file]"
39
+ opts.separator ""
40
+ opts.separator "Specific options:"
41
+
42
+ # Compiler like options
43
+ opts.on("-o", "--output file", String, \
44
+ "Output to file (default STDOUT)") do |file|
45
+ opts.error("multiple output files give") if settings.dest_file
46
+ settings.dest_file = file
47
+ end
48
+ opts.on("-D macro(=value)", String, "Define macro") do |macro|
49
+ settings.define_macro(macro)
50
+ end
51
+ # allow user to undefine compiler specific macros
52
+ opts.on("-U macro", String, "Cancel the definintion of macro") do |macro|
53
+ settings.undefine_macro(macro)
54
+ end
55
+ opts.on("-I directory", String,
56
+ "Use directory to search for header files") do |inc_dir|
57
+ settings.add_include_path(inc_dir)
58
+ end
59
+ opts.on("--include file", String, "Include file before processing") do |file|
60
+ settings.includes << file
61
+ end
62
+ opts.on("--cc=compiler(-version)", String, "Specify target compiler") do |cc|
63
+ opts.error("invalid compiler #{cc}") unless cc =~ /\A([^-]+)(?:-(\d\.)+)?\Z/
64
+ settings.compiler = $1
65
+ settings.version = $2
66
+ end
67
+ opts.on("-E", "Preprocess input file only") do
68
+ settings.preprocess_only = true
69
+ end
70
+ opts.on("-c", "--check-level [0,1,2]", Integer,
71
+ "Set check level (default 2)") do |level|
72
+ opts.error("invalid check level '#{level}'") unless DBC.valid_check_level?(level)
73
+ check_level = level
74
+ end
75
+ opts.on("-a", "--always-output", "Always output to destination file") do
76
+ always_output = true
77
+ end
78
+ opts.on("-d", "--docs", "Generate Doxygen documentation") do
79
+ docs = true
80
+ end
81
+ opts.on("--no-overwrite", "Don't overwrite output file") do
82
+ settings.overwrite = false
83
+ end
84
+ opts.on("--no-line", "Don't output '\#line' directives") do
85
+ line_info = false
86
+ end
87
+ opts.on("-h", "--help", "Print this message") do
88
+ puts opts
89
+ exit(0)
90
+ end
91
+
92
+ opts.separator ""
93
+ opts.separator "Check levels: 0 = none, 1 = preconditions only, 2 = all conditions."
94
+ opts.separator "Reads from STDIN if input file is '-' or none is given."
95
+ opts.separator "-D and -U options are processed in the order given."
96
+ end
97
+
98
+ #
99
+ # Handle command line options
100
+ #
78
101
 
79
102
  begin
80
- i = 1
81
- opts.each do |opt, arg|
82
- case opt
83
- when "--check_level"
84
- check_level = arg.to_i
85
- unless DBC.valid_check_level?(check_level)
86
- opts.error("invalid check level: #{arg}")
87
- end
88
- when "--include"
89
- # should support including file in the future
90
- if arg
91
- begin
92
- search_path.unshift(arg)
93
- rescue
94
- opts.error($!)
95
- end
96
- else
97
- # -I with no argument means don't search /usr/include
98
- search_usr_include = false
99
- end
100
- when "--define"
101
- unless arg =~ /\A([A-Za-z_]\w*)(?:\(([\w,\s]*)\))?(?:=(.*))?\Z/
102
- opts.error("macro names must be identifiers: #{arg}")
103
- end
104
- macro = $1
105
- opts.error("cannot use 'defined' as a macro name") if macro == 'defined'
106
- value = $3 || '1'
107
- params = $2.split(/\s*,\s*/) if $2
108
- defines << [macro,params,value]
109
- when "--output"
110
- if dest_file
111
- opts.error("multiple output files give")
112
- end
113
- dest_file = arg
114
- when "--always-output" then always_output = true
115
- when "--docs" then docs = true
116
- when "--no_line" then line_info = false
117
- when "--preprocess-only" then preprocess_only = true
118
- when "--help"
119
- puts "Converts OCL design by contract tags to C code."
120
- puts "Usage:"
121
- puts "\t#{command} [options] [commands] input_file"
122
- puts "Options:"
123
- puts "\t-a, --always-output : always output to destination file"
124
- puts "\t-d, --docs : generate Doxygen documentation"
125
- puts "\t-h, --help : print this message"
126
- puts "\t-n, --no_line : do not output '\#line' directives"
127
- puts "\t-p, --preprocess-only : preprocess input files only"
128
- puts "Commands:"
129
- puts "\t-o, --output <file>"
130
- puts "\t-c, --check_level <0,1,2>"
131
- puts "\t-D, --define <macro(=value)>"
132
- puts "\t-I, --include <directory>"
133
- puts ""
134
- puts "Check levels: 0 = none, 1 = preconditions only, 2 = all conditions."
135
- puts "Reads from STDIN if input file is '-' or none is given."
136
- puts "Outputs to STDOUT if no output file is given."
137
- exit(0)
138
- else raise GetoptLong::InvalidOption, "unrecognized option '#{opt}'"
139
- end # case
140
- i += 1
141
- end # each
142
- rescue GetoptLong::InvalidOption, GetoptLong::Error
143
- msg = $!.message
144
- warn "<command line>:#{i}: #{msg} (-h will show vaild options)"
145
- exit(2)
103
+ opts.parse!(ARGV)
104
+ rescue
105
+ warn "#{$!} (-h will show vaild options)"
106
+ exit(2)
146
107
  end
147
108
 
148
- if [check_level, preprocess_only, docs].nitems > 1
149
- warn %q{conflicting options: only one of the following may be selected:
150
- --check_level
109
+ # make sure opts gets gc'ed
110
+ opts = nil
111
+
112
+ if [check_level, settings.preprocess_only, docs].nitems > 1
113
+ warn %q{conflicting options: only one of the following may be selected:
114
+ --check-level
151
115
  --preprocess-only
152
116
  --docs}
153
- exit(2)
117
+ exit(2)
154
118
  end
155
119
 
156
120
  # default condition is all
157
121
  check_level = DBC::ALL unless check_level
158
122
 
159
123
  if ARGV.length > 1
160
- warn "expecting one input file, got #{ARGV.length}"
161
- exit(2)
124
+ warn "expecting one input file, got #{ARGV.length}"
125
+ exit(2)
162
126
  end
163
127
 
164
128
  unless ARGV.empty? || ARGV[0] == '-'
165
- src_file = ARGV[0]
166
- unless File.file?(src_file)
167
- warn "file does not exist: #{src_file}"
168
- exit(2)
169
- end
170
- end
171
-
172
- if dest_file
173
- if File.exists?(dest_file) and not overwrite
174
- warn "destination file '#{dest_file}' exists"
175
- exit(2)
176
- end
177
- # this is always bad - so don't allow it even if overwrite is true
178
- if src_file and File.expand_path(dest_file) == File.expand_path(src_file)
179
- warn "destination file and source file are the same"
180
- exit(2)
181
- end
182
- begin
183
- create_dest_dirs(dest_file)
184
- rescue
185
- warn "could not create destination directory: #{$?}"
186
- exit(2)
187
- end
188
- end
189
-
190
- if src_file
191
- begin
192
- text = File.open(src_file, 'r') do |in_file|
193
- in_file.read
194
- end
195
- rescue
196
- warn "could not open '#{src_file}': #{$?}"
197
- exit(2)
198
- end
199
- else
200
- text = STDIN.read
201
- end
202
-
203
- ### Compatibility with various compilers ###
204
-
205
- # the following are added to the end of the search path
206
- if search_usr_include
207
- if File.exists?('/usr/include')
208
- search_path << '/usr/include'
209
- # search for /usr/lib/gcc*/<system>/<version>/include
210
- Dir['/usr/lib/gcc*/*/*/include'].each do |gcc_inc|
211
- search_path << gcc_inc if File.directory?(gcc_inc)
212
- end
213
- else
214
- if env_include = ENV['INCLUDE']
215
- env_include.split(';').each do |p|
216
- # any anci c installation should have stdlib.h or stdio.h
217
- if File.exists?(File.join(p, 'stdlib.h'))
218
- search_path << p
219
- end
220
- end # each
221
- end
222
- end # if File.exists?('/usr/include')
129
+ settings.src_file = ARGV[0]
130
+ unless File.file?(settings.src_file)
131
+ warn "file does not exist: #{settings.src_file}"
132
+ exit(2)
133
+ end
223
134
  end
224
135
 
225
- search_path_limited = search_path.dup
226
- # Add directory of file to the begining of the search_path
227
- # search_path_limited does not include the directory of the file being parsed
228
- search_path.unshift( src_file ? File.dirname(src_file) : '.' )
229
-
230
- case RUBY_PLATFORM
231
- when /i[0-9]86|cygwin|mingw/
232
- defines << ['__i386__', nil, nil]
233
- # I have found that these setting work best with GNU C libs
234
- # experiance may vary :)
235
- defines << ['__GLIBC_HAVE_LONG_LONG', nil, '1']
236
- when /powerpc|darwin/
237
- defines << ['__ppc__', nil, nil]
238
- else
239
- warn "unrecognized platform: #{RUBY_PLATFORM}"
136
+ begin
137
+ settings.check
138
+ settings.execute
139
+ rescue
140
+ $stderr.puts $!
141
+ exit(2)
240
142
  end
241
143
 
242
- # for gcc compatibility
243
- defines << ['__asm__', ['...'], ' ']
244
- defines << ['__attribute__', ['...'], ' ']
245
- defines << ['__const__', nil, 'const']
246
- defines << ['__extension__', nil, ' ']
247
- defines << ['__inline__', nil, ' ']
248
- defines << ['__signed__', nil, 'signed']
249
- defines << ['__volatile__', nil, 'volatile']
250
-
251
- # for gcc 3.4+ compatibility
252
- defines << ['__builtin_va_list', nil, 'int *']
253
- defines << ['SHLIB_COMPAT', ['...'], '(0)']
254
-
255
- # so '##' is used to paste tokens, not '/**/'
256
- defines << ['__STDC__', nil, '1']
257
- #############################################
258
144
 
259
145
  begin
260
- if docs
261
- out_str = DBC.parse_docs(CTokenizer::Lexer.new(text, src_file))
262
- elsif preprocess_only
263
- out_str = ''
264
- preproc = Preprocessor::Parser.new( search_path,
265
- search_path_limited,
266
- text, src_file )
267
-
268
- defines.each { |d,p,v| preproc.define(d, p, v) }
269
- preproc.each do |t|
270
- out_str << t.at(1)
271
- end
272
- else
273
- if check_level == DBC::NONE
274
- out_str = text
275
- else
276
- # Cache Tokens => Preprocessor => Parse OCL => Parse C Types
277
- # Cached tokens are output, not Preprocessed tokens
278
- out_str = ''
279
- # cache statements
280
- cache = DBC::Cache.new(text, src_file)
281
- # preprocesses all tokens
282
- preproc = Preprocessor::Parser.new( search_path,
283
- search_path_limited,
284
- cache )
285
-
286
- # define tokens passed
287
- defines.each { |d| preproc.define(*d) }
288
-
289
- # extracts DBC condtions
290
- source = DBC::OCLParser.new(preproc)
291
-
292
- # extract all C Statements
293
- DBC.parse(source) do |context, f_body|
294
- stmt = cache.reset
295
- line = stmt.line
296
- stmt = stmt.cache
297
- # remove end of file token if it exists
298
- stmt.pop unless stmt.empty? or stmt.last[0]
299
-
300
- # define C types
301
- context.each do |ctxt|
302
- CType[ctxt.identifier] = ctxt if ctxt.typedef?
303
- end
304
-
305
- if f_body and preproc.base?
306
- unless context.first
307
- raise CTokenizer.error(nil, line, "unmatched braket")
308
- end
309
- out_str << expand_function( source.conditions,
310
- context.first,
311
- stmt, line, line_info )
312
- else
313
- stmt.each do |t|
314
- out_str << t.at(1)
315
- end
316
- end
317
- end # do
318
- end #if
319
- end # if
146
+ out_str = ''
147
+
148
+ if docs
149
+ out_str = DBC.parse_docs(CTokenizer::Lexer.new(
150
+ settings.source, settings.src_file))
151
+ elsif check_level == DBC::NONE
152
+ out_str = settings.source
153
+ else
154
+ parser = Caphir::EventParser.new(settings, DBC::Parser)
155
+
156
+ if settings.preprocess_only
157
+ parser.each do |t|
158
+ out_str << t
159
+ end
160
+ else
161
+ parser.each do |function|
162
+ line = parser.in_stream.last_line
163
+ stmt = parser.in_stream.reset([])
164
+
165
+ if function and parser.preproc.base?
166
+ out_str << expand_function( parser.handler.conditions,
167
+ function, stmt, line, line_info)
168
+ else
169
+ out_str << stmt.collect! { |t| t.at(1) }.join
170
+ end
171
+ end
172
+ end
173
+ end
320
174
  rescue CTokenizer::Error, CType::EvaluationError
321
- warn $!
322
- exit(-1)
175
+ warn $!
176
+ exit(-1)
323
177
  ensure
324
- if !$! or always_output
325
- if dest_file
326
- File.open(dest_file, 'w') { |f| f.write(out_str) }
327
- else
328
- $stdout.write(out_str)
329
- end
330
- end
178
+ if !$! or always_output
179
+ if settings.dest_file
180
+ File.open(settings.dest_file, 'w') { |f| f.write(out_str) }
181
+ else
182
+ $stdout.write(out_str)
183
+ end
184
+ end
331
185
  end
332
186