dbc 1.3.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/caphir.rb +152 -0
- data/bin/dbcparse.rb +139 -285
- data/lib/{dbc → caphir}/ctokenizer.rb +48 -41
- data/lib/caphir/ctype.rb +2640 -0
- data/lib/caphir/define.rb +488 -0
- data/lib/{dbc → caphir}/parseerrorhandler.rb +0 -0
- data/lib/caphir/parser.rb +125 -0
- data/lib/caphir/parsersettings.rb +175 -0
- data/lib/caphir/preprocessor.rb +2173 -0
- data/lib/caphir/preprocessor_conf.rb +153 -0
- data/lib/{dbc → caphir}/searchpath.rb +0 -0
- data/lib/dbc/dbc.rb +65 -129
- data/lib/dbc/expand_function.rb +43 -46
- data/lib/dbc/ocl.rb +600 -577
- metadata +13 -9
- data/lib/dbc/ctype.rb +0 -2569
- data/lib/dbc/define.rb +0 -282
- data/lib/dbc/parameters.rb +0 -434
- data/lib/dbc/preprocessor.rb +0 -2078
@@ -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
|
data/lib/dbc/dbc.rb
CHANGED
@@ -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 '
|
7
|
-
require '
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
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
|
153
|
-
break if t
|
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
|
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
|
|
data/lib/dbc/expand_function.rb
CHANGED
@@ -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 '
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
41
|
-
|
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.
|
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
|
-
|
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.
|
87
|
-
|
88
|
-
|
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
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
-
|
105
|
-
|
106
|
-
t
|
107
|
-
|
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
|
-
|
114
|
-
|
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
|