dbc 1.3.0 → 2.0.0

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