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,153 @@
1
+ # If there are additional platform specific options that
2
+ # belong in this file, please contribute them.
3
+
4
+ # Removes dots and zero pads
5
+ def expand_version(pre, version)
6
+ version.delete!('.')
7
+ (3 - version.length).times { version << '0' }
8
+ "#{pre}#{version}"
9
+ end
10
+
11
+ class Preprocessor::Parser
12
+
13
+ def configure(options, includes, compiler=nil, version=nil)
14
+
15
+ # __FILE__ and __LINE__ macros are define in preprocessor.y
16
+
17
+ # so '##' is used to paste tokens, not '/**/'
18
+ self.define('__STDC__', nil, '1')
19
+ self.define('__STDC_VERSION__', nil, '199901L')
20
+ comp_time = Time.now
21
+ self.define('__DATE__', nil, comp_time.strftime('%m %d %Y'))
22
+ self.define('__TIME__', nil, comp_time.strftime('%H:%M:%S'))
23
+
24
+ case RUBY_PLATFORM
25
+ when /i[0-9]86/
26
+ self.define('__i386__', nil, '1')
27
+ when /powerpc/
28
+ self.define('__ppc__', nil, '1')
29
+ # when /ia64/
30
+ # self.define('__ia64__', nil, '1')
31
+ else
32
+ warn "unrecognized platform: #{RUBY_PLATFORM}"
33
+ end
34
+
35
+ case RUBY_PLATFORM
36
+ #when /darwin/
37
+ #when /netbsd/
38
+ when /mswin32/
39
+ self.define('__WIN32', nil, '1')
40
+ when /cygwin/
41
+ self.define('__WIN32', nil, '1')
42
+ self.define('__CYGWIN__', nil, '1')
43
+ when /mingw/
44
+ self.define('__WIN32', nil, '1')
45
+ self.define('__MINGW32__', nil, '1')
46
+ #when /bccwin/
47
+ #when /os2/
48
+ #when /sparc/
49
+ #when /AIX/
50
+ end
51
+
52
+ case compiler # gcc is the default
53
+ when nil, 'gcc'
54
+
55
+ warn "invalid gcc version (got #{version} expecting major.minor.patch_level)" \
56
+ if version and not version =~ /\A(\d+)\.(\d+)(?:\.(\d+))?\Z/
57
+
58
+ # defaults to gcc 3.3.0
59
+ self.define('__GNUC__', nil, $1 || '3')
60
+ self.define('__GNUC_MINOR__', nil, $2 || '3')
61
+ self.define('__GNUC_PATCHLEVEL__', nil, $3 || '0') # default must be '0'
62
+
63
+ self.define('__complex__', nil, '_Complex')
64
+
65
+ # define all these as blank
66
+ empty_str = ''.freeze
67
+ self.define('__asm__', ['...'], empty_str)
68
+ self.define('__attribute__', ['...'], empty_str)
69
+
70
+ # this is now handled by the parser
71
+ #self.define('throw', ['...'], empty_str)
72
+
73
+ # note that __cdecl is included here
74
+ [ '__const__', '__extension__', '__inline__',
75
+ '__signed__', '__volatile__', '__cdecl' ].each do |kw|
76
+ self.define(kw, nil, empty_str)
77
+ end
78
+
79
+ self.define('__restrict_arr', nil, 'restrict')
80
+
81
+ # define psuedo-ANSI C keywords. Note these
82
+ # may be redefined later in the code
83
+ [ '__const', '__inline', '__restrict', '__signed', '__volatile' ].each do |kw|
84
+ self.define(kw, nil, kw[2, kw.length-2])
85
+ end
86
+
87
+ # for gcc 3.4+ compatibility
88
+ self.define('__GLIBC_HAVE_LONG_LONG', nil, '1')
89
+ self.define('__builtin_va_list', nil, 'int *')
90
+ self.define('SHLIB_COMPAT', ['...'], '(0)')
91
+
92
+ when 'vc++'
93
+ # win32 should already be defined
94
+
95
+ self.define('__cdecl', nil, ' ')
96
+ # make up a time stamp
97
+ self.define('__TIMESTAMP__', nil, comp_time.strftime('%a %b %d %H:%M:%S %y'))
98
+
99
+ # default version is 6.0 => 1200
100
+ version = version ? ((version.to_f + 6) * 100).to_i.to_s : '1200'
101
+ self.define('_MSC_VER', nil, version)
102
+
103
+ # Not sure if these should be added
104
+ #if RUBY_PLATFORM =~ /i[0-9]86/
105
+ # self.define('_M_IX86', nil, '500') # default
106
+ #else
107
+ # self.define('_M_MPPC', nil, '601') # default
108
+ # self.define('_M_PPC', nil, '604') # default
109
+ #end
110
+ when 'tinyc'
111
+ # tinyc compilers do not specify version numbers
112
+ self.define('__TINYC__', nil, '1')
113
+
114
+ when 'turboc'
115
+ warn "ignoring version number, defaulting to 3.0" if version
116
+ self.define('__TURBOC__', nil, '661') # 3.0
117
+
118
+ when 'borland'
119
+ version = version ? expand_version('0x', version) : '0x550'
120
+ self.define('__BORLANDC__', nil, version)
121
+
122
+ when 'intel'
123
+ version = version ? expand_version(nil, version) : '600'
124
+ self.define('__INTEL_COMPILER', nil, version)
125
+ self.define('__ICC', nil, version)
126
+
127
+ when 'mars'
128
+ version = version ? expand_version('0x', version) : '0x800'
129
+ self.define('__DMC__', nil, version)
130
+
131
+ when 'watcom'
132
+ version = version ? expand_version(version) << '0' : '1100'
133
+ self.define('__WATCOMC__', nil, version)
134
+
135
+ else
136
+ warn "unrecognized compiler: #{compiler}"
137
+ exit(2)
138
+ end # case
139
+
140
+ # options should be applied after the preprocessor is configured
141
+ options.each do |opt|
142
+ if opt[0] == :DEFINE
143
+ self.define(opt[1], opt[2], opt[3])
144
+ elsif opt[0] == :UNDEF
145
+ self.undef(opt[1])
146
+ else
147
+ raise "impossible"
148
+ end
149
+ end
150
+ includes.each { |f| self.include_arg(f) }
151
+ end
152
+ end
153
+
File without changes
@@ -3,8 +3,8 @@
3
3
  # THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
4
4
  # See included LICENCE file.
5
5
 
6
- require 'dbc/ctokenizer'
7
- require 'dbc/ctype'
6
+ require 'caphir/ctokenizer'
7
+ require 'caphir/ctype'
8
8
  require 'dbc/ocl'
9
9
 
10
10
  module DBC
@@ -25,50 +25,72 @@ module DBC
25
25
  str =~ /\A\/\*\*[ \t]*[\r\n]+(\s*\*?\s*(?:inv|pre|post|context).+)[ \t]*\*\/\Z/m
26
26
  $1
27
27
  end
28
-
29
- class Cache < CTokenizer::LexerBase
28
+
29
+ class Parser < CTokenizer::LexerBase
30
+ include CTokenizer::Scoped
30
31
  def initialize(str, file=nil, line=1)
31
32
  super(str, file, line)
32
- @token_cache = CTokenizer::Cache.new(super.file, super.line)
33
+
34
+ @scope = 0
35
+ @macro = false
36
+ @start_line = true # begining of file
37
+
38
+ @contract = nil
39
+ @conditions = {} # hash of contracts
40
+ # @ctype_parser.parse(source) -> parses source until a compelete
41
+ # top level C statement has been parsed. If the statement is a
42
+ # function definition it stops when the opening '{' is reached.
43
+ @ctype_parser = CType::Parser.new()
33
44
  end
34
45
 
35
- def scan(re)
36
- str = super
37
- @token_cache << [:UNKNOWN, str.freeze].freeze
38
- str
39
- end
46
+ attr_reader :conditions
40
47
 
41
48
  def shift
42
- t = super
43
- @token_cache << t
49
+ t = process_scope(super)
50
+ if t.at(0) == :COMMENT and start_of_line? and ocl = DBC.get_ocl(t.at(1))
51
+ self.error("no context for previous contract") if @contract
52
+ @contract = OCL::Parser.new(ocl, self.file, self.line - CTokenizer.line_count(ocl))
53
+ self.merge_current_contract() if @contract.context
54
+ end
44
55
  t
45
56
  end
46
57
 
47
- def reset
48
- cache = @token_cache
49
- @token_cache = CTokenizer::Cache.new(self.file, self.line)
50
- cache
51
- end
52
- end
53
-
54
- def DBC.parse(source)
55
- tokens = CTokenizer::SkipMacros.new(source)
56
- ctype_parser = CType::Parser.new()
57
-
58
- until tokens.empty?
59
- context = ctype_parser.parse(tokens)
60
- f_body = false
61
- unless tokens.scope == 0
62
- yield([], f_body)
63
- until tokens.scope == 0 or tokens.empty?
64
- # get back to group zero
65
- tokens.shift
58
+ def each_statement
59
+ until @source.empty?
60
+ context = @ctype_parser.parse(self)
61
+ # if scope != 0 then we are in a function body
62
+ if f_body = (@scope != 0)
63
+ # first yield function header
64
+ yield(nil)
65
+ until @scope == 0 or @source.empty?
66
+ # get back to group zero
67
+ # don't check for contract comments
68
+ process_scope(@source.shift)
69
+ end
70
+ end #if
71
+ # add type definitions
72
+ context.each do |ctxt|
73
+ CType[ctxt.identifier] = ctxt if ctxt.typedef?
66
74
  end
67
- f_body = true
68
- end
69
- yield(context, f_body)
70
- end
71
- end # DBC.parse
75
+ if @contract
76
+ # the contract should have no context
77
+ #raise "impossible" if @contract.context
78
+ self.error("expecting one context for contract") unless context.length == 1
79
+ @contract.context = context.first
80
+ self.merge_current_contract()
81
+ end # if
82
+ yield(f_body ? context.first : nil)
83
+ end # until
84
+ end # each_statement
85
+
86
+ def merge_current_contract()
87
+ context = @contract.context
88
+ context = context.short_name unless context.class == String
89
+ @conditions[context] = @contract
90
+ @contract = nil # done with current contract
91
+ end
92
+
93
+ end # class Parser
72
94
 
73
95
  def DBC.format_conditions(conditions)
74
96
  outstr = ''
@@ -95,7 +117,9 @@ module DBC
95
117
  until tokens.empty?
96
118
  t = tokens.shift
97
119
  # note: comments don't affect start_of_line?
98
- if t[0] == :COMMENT and tokens.start_of_line? and str = DBC.get_ocl(t[1])
120
+ if t.at(0) == :COMMENT and \
121
+ tokens.start_of_line? and \
122
+ str = DBC.get_ocl(t.at(1))
99
123
  context = nil
100
124
  # take out context information
101
125
  str.gsub!(/^[ \t]*\*?[ \t]*context[ \t]+(.+)$/) do
@@ -148,105 +172,17 @@ module DBC
148
172
  # try to insert the tag after then next opening braket
149
173
  if conditions.first[0] =~ /pre|post/ and not context
150
174
  until tokens.empty?
151
- t = tokens.shift
152
- outstr << t[1]
153
- break if t[1] == '{'
175
+ t = tokens.shift.at(1)
176
+ outstr << t
177
+ break if t == '{'
154
178
  end
155
179
  end
156
180
  outstr << doc_str
157
181
  else
158
- outstr << t[1]
182
+ outstr << t.at(1)
159
183
  end
160
184
  end
161
185
  outstr
162
186
  end
163
-
164
- class Parser < CTokenizer::LexerBase
165
- include CTokenizer::Scoped
166
- def initialize(str, file=nil, line=1)
167
- super(str, file, line)
168
- @token_cache = CTokenizer::Cache.new(super.file, super.line)
169
- @scope = 0
170
- @macro = false
171
- @start_line = true # begining of file
172
- end
173
-
174
- def shift
175
- process_scope(@token_cache.empty? ? super : @token_cache.shift)
176
- end
177
-
178
- def empty?
179
- @token_cache.empty? and super
180
- end
181
-
182
- def file
183
- if @token_cache.empty?
184
- super
185
- else
186
- @token_cache.file
187
- end
188
- end
189
-
190
- def line
191
- if @token_cache.empty?
192
- super
193
- else
194
- @token_cache.line
195
- end
196
- end
197
-
198
- end # Parser
199
-
200
- class OCLParser < Parser
201
-
202
- def initialize(str, file=nil, line=1)
203
- super(str, file, line)
204
- @conditions = {}
205
- @ctype_parser = CType::Parser.new()
206
- end
207
-
208
- attr_reader :conditions
209
-
210
- def shift
211
- t = super
212
- # note: comments don't affect start_of_line?
213
- if t.at(0) == :COMMENT and start_of_line? and ocl = DBC.get_ocl(t[1])
214
- parse_ocl(ocl)
215
- end
216
- t
217
- end
218
-
219
- private
220
- def parse_ocl(str)
221
- self.error("no context for previous contract") \
222
- unless @token_cache.empty?
223
- parser = OCL::Parser.new(str, self.file, self.line - CTokenizer.line_count(str))
224
- self.error("no conditions given") if parser.conditions.empty?
225
-
226
- unless parser.context
227
- @token_cache.reset(self.file, self.line)
228
- # Use the Splitter to cache the tokens used by the type parser
229
- splitter = CTokenizer::Splitter.new(@token_cache, @source)
230
- splitter = CTokenizer::SkipMacros.new(splitter)
231
- context = @ctype_parser.parse(splitter)
232
- self.error("multiple contexts given") unless context.length == 1
233
- parser.context = context.first
234
- end
235
-
236
- if parser.conditions.last.type =~ /\A(?:pre|post)/
237
- # should be followed by a function
238
- self.error("pre and post conditions must be in the context of a function") \
239
- unless parser.context.function?
240
- end
241
-
242
- context_str = if parser.context.class == String
243
- parser.context
244
- else
245
- parser.context.short_name
246
- end
247
- @conditions[context_str] = parser
248
- end
249
- end # OCLParser
250
-
251
187
  end # DBC
252
188
 
@@ -3,7 +3,7 @@
3
3
  # THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
4
4
  # See included LICENCE file.
5
5
 
6
- require 'dbc/ctokenizer'
6
+ require 'caphir/ctokenizer'
7
7
 
8
8
  def expand_function(conditions, context, body, start_line, line_info)
9
9
  raise 'should be a function' unless context.function?
@@ -11,11 +11,13 @@ def expand_function(conditions, context, body, start_line, line_info)
11
11
  context_str = context.short_name
12
12
  f_cond = conditions[context_str]
13
13
 
14
- pre_text = '' # preconditions
15
- post_text = '' # postconditions
16
- inv_text = '' # invariants
17
- init_text = '' # initializations
18
- final_text = '' # stuff at the end
14
+ outstr = ''
15
+ outstr << "\n"
16
+
17
+ pre_text = '' # preconditions
18
+ post_text = '' # postconditions
19
+ inv_text = '' # invariants
20
+ final_text = '' # stuff at the end
19
21
 
20
22
  if f_cond
21
23
  # get the conditions
@@ -37,8 +39,9 @@ def expand_function(conditions, context, body, start_line, line_info)
37
39
  rescue CType::EvaluationError
38
40
  raise CType::EvaluationError, "#{line_info}: in #{context_str}, #{$!} for #{identifier}"
39
41
  end
40
- init_text << "\t" << p_type.to_init_s(var_used)
41
- init_text << ' = ' << identifier << ";\n"
42
+ # initializations
43
+ outstr << "\t" << p_type.to_init_s(var_used)
44
+ outstr << ' = ' << identifier << ";\n"
42
45
  end
43
46
  end
44
47
 
@@ -54,26 +57,18 @@ def expand_function(conditions, context, body, start_line, line_info)
54
57
  inv_text << exp_str
55
58
  end; end
56
59
  end
57
-
58
- void_return_type = (context.base_type.to_s == 'void')
59
-
60
- unless void_return_type or \
61
- (post_text.empty? and inv_text.empty?)
62
- init_text << "\t" << context.base_type.to_init_s('ocl__ret_val') << ";\n"
63
- end
64
60
 
65
- outstr = ''
66
-
67
61
  if pre_text.empty? and post_text.empty? and inv_text.empty?
68
62
  # we're done early
69
- body.each do |t|
70
- outstr << t.at(1)
71
- end
72
- return outstr
63
+ return body.collect! { |t| t.at(1) }.join
73
64
  end
74
65
 
75
- outstr << "\n" << init_text
66
+ void_return_type = (context.base_type.to_s == 'void')
76
67
 
68
+ unless void_return_type or (post_text.empty? and inv_text.empty?)
69
+ outstr << "\t" << context.base_type.to_init_s('ocl__ret_val') << ";\n"
70
+ end
71
+
77
72
  # output invariants and preconditions
78
73
  outstr << "\t/* Invariants: */\n" << inv_text unless inv_text.empty?
79
74
  outstr << "\t/* Preconditions: */\n" << pre_text unless pre_text.empty?
@@ -83,37 +78,39 @@ def expand_function(conditions, context, body, start_line, line_info)
83
78
 
84
79
  # output function body
85
80
  if post_text.empty? and inv_text.empty?
86
- body.each do |t|
87
- outstr << t.at(1)
88
- start_line += CTokenizer.line_count(t.at(1))
89
- end
81
+ outstr << body.collect! do |t|
82
+ start_line += CTokenizer.line_count(t = t.at(1))
83
+ t
84
+ end.join
90
85
  else
91
86
  output_label = false
92
- body = body.dup
93
- until body.empty?
94
- t = body.shift
95
- start_line += CTokenizer.line_count(t.at(1))
96
- # replace return statements with goto statements.
97
- # if a value is returned this value is saved in ocl__ret_val
98
- if t.at(1) == 'return'
99
- output_label = true
100
- if void_return_type
101
- outstr << 'goto ocl__return_here'
87
+ if void_return_type
88
+ outstr << body.collect do |t|
89
+ start_line += CTokenizer.line_count( t = t.at(1) )
90
+ if t == 'return'
91
+ output_label = true
92
+ 'goto ocl__return_here'
102
93
  else
94
+ t
95
+ end
96
+ end.join # do
97
+ else
98
+ until body.empty?
99
+ start_line += CTokenizer.line_count( t = body.shift.at(1) )
100
+ if t == 'return'
101
+ output_label = true
103
102
  outstr << '{ ocl__ret_val = ( '
104
- loop do
105
- raise "syntax error" if body.empty?
106
- t = body.shift
107
- start_line += CTokenizer.line_count(t.at(1))
108
- break if t.at(1) == ';'
109
- outstr << t.at(1)
103
+ until body.empty?
104
+ start_line += CTokenizer.line_count( t = body.shift.at(1) )
105
+ break if t == ';'
106
+ outstr << t
110
107
  end
111
108
  outstr << ' ); goto ocl__return_here; }'
109
+ else
110
+ outstr << t
112
111
  end
113
- else # output all other tokens
114
- outstr << t.at(1)
115
- end
116
- end
112
+ end # until
113
+ end # if
117
114
  outstr << "\nocl__return_here:\n" if output_label
118
115
  # must explicitly return the return value unless return value is void
119
116
  final_text << "\treturn ocl__ret_val;\n" unless void_return_type