dbc 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/dbcparse.rb +281 -0
- data/lib/dbc/ctokenizer.rb +379 -0
- data/lib/dbc/ctype.rb +2397 -0
- data/lib/dbc/dbc.rb +237 -0
- data/lib/dbc/define.rb +302 -0
- data/lib/dbc/expand_function.rb +132 -0
- data/lib/dbc/ocl.rb +2166 -0
- data/lib/dbc/parameters.rb +400 -0
- data/lib/dbc/parseerrorhandler.rb +19 -0
- data/lib/dbc/preprocessor.rb +1790 -0
- data/lib/dbc/searchpath.rb +40 -0
- metadata +49 -0
data/lib/dbc/dbc.rb
ADDED
@@ -0,0 +1,237 @@
|
|
1
|
+
# Copyright (c) 2004 Charles M Mills
|
2
|
+
# This document is licenced under The MIT Licence.
|
3
|
+
# THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|
4
|
+
# See included LICENCE file.
|
5
|
+
|
6
|
+
require 'dbc/ctokenizer'
|
7
|
+
require 'dbc/ctype'
|
8
|
+
require 'dbc/ocl'
|
9
|
+
|
10
|
+
module DBC
|
11
|
+
NONE = 0
|
12
|
+
PRE = 1
|
13
|
+
ALL = 2
|
14
|
+
|
15
|
+
def DBC.valid_check_level?(c)
|
16
|
+
case c
|
17
|
+
when NONE, PRE, ALL
|
18
|
+
true
|
19
|
+
else
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def DBC.get_ocl(str)
|
25
|
+
str =~ /\A\/\*\*[ \t]*[\r\n]+(.+)[ \t]*\*\/\Z/m
|
26
|
+
$1
|
27
|
+
end
|
28
|
+
|
29
|
+
class Cache < CTokenizer::LexerBase
|
30
|
+
def initialize(str, file=nil, line=1)
|
31
|
+
super(str, file, line)
|
32
|
+
@token_cache = CTokenizer::Cache.new(super.file, super.line)
|
33
|
+
end
|
34
|
+
|
35
|
+
def shift
|
36
|
+
t = super
|
37
|
+
@token_cache << t
|
38
|
+
t
|
39
|
+
end
|
40
|
+
|
41
|
+
def reset
|
42
|
+
cache = @token_cache
|
43
|
+
@token_cache = CTokenizer::Cache.new(self.file, self.line)
|
44
|
+
cache
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def DBC.parse(source)
|
49
|
+
tokens = CTokenizer::SkipMacros.new(source)
|
50
|
+
ctype_parser = CType::Parser.new()
|
51
|
+
|
52
|
+
until tokens.empty?
|
53
|
+
context = ctype_parser.parse(tokens)
|
54
|
+
f_body = false
|
55
|
+
unless tokens.scope == 0
|
56
|
+
yield([], f_body)
|
57
|
+
until tokens.scope == 0 or tokens.empty?
|
58
|
+
# get back to group zero
|
59
|
+
tokens.shift
|
60
|
+
end
|
61
|
+
f_body = true
|
62
|
+
end
|
63
|
+
yield(context, f_body)
|
64
|
+
end
|
65
|
+
end # DBC.parse
|
66
|
+
|
67
|
+
def DBC.format_conditions(conditions)
|
68
|
+
outstr = ''
|
69
|
+
conditions.each do |type, label, conds|
|
70
|
+
outstr << case type
|
71
|
+
when 'pre' then '\\pre'
|
72
|
+
when 'post' then '\\post'
|
73
|
+
when 'inv' then '\\invariant'
|
74
|
+
end << ' '
|
75
|
+
if label and not label.empty?
|
76
|
+
outstr << label << ': '
|
77
|
+
end
|
78
|
+
outstr << "\\code\n" << conds << "\n\\endcode\n"
|
79
|
+
end
|
80
|
+
outstr
|
81
|
+
end
|
82
|
+
|
83
|
+
# kinda ugly...
|
84
|
+
def DBC.parse_docs(tokens)
|
85
|
+
tokens = CTokenizer::SkipMacros.new(tokens)
|
86
|
+
ctype_parser = CType::Parser.new()
|
87
|
+
outstr = ''
|
88
|
+
|
89
|
+
until tokens.empty?
|
90
|
+
t = tokens.shift
|
91
|
+
# note: comments don't affect start_of_line?
|
92
|
+
if t[0] == :COMMENT and tokens.start_of_line? and str = DBC.get_ocl(t[1])
|
93
|
+
context = nil
|
94
|
+
# take out context information
|
95
|
+
str.gsub!(/^[ \t]*context[ \t]+(.+)$/) do
|
96
|
+
if context
|
97
|
+
source.error("multiple contexts given: '#{context.to_s}' and '#{$1}'")
|
98
|
+
end
|
99
|
+
context = ctype_parser.parse($1 << ';')
|
100
|
+
context = context.first
|
101
|
+
'' # replace with an empty string
|
102
|
+
end
|
103
|
+
conditions = []
|
104
|
+
str.scan(/^[ \t]*(pre|post|inv)[ \t]*([^:]*):|\Z/) do
|
105
|
+
conditions.push([$1, $2]) if $1
|
106
|
+
end
|
107
|
+
statements = str.split(/^[ \t]*(?:pre|post|inv)[^:]*:|\Z/)
|
108
|
+
statements.shift # remove first element
|
109
|
+
conditions.zip(statements) do |cond, stmt|
|
110
|
+
cond.push(stmt)
|
111
|
+
end
|
112
|
+
# condition is an array of arrays like so:
|
113
|
+
# [ ['pre', 'msg', 'statment'], ['post', 'msg', 'stmt'], ...]
|
114
|
+
|
115
|
+
doc_str = ''
|
116
|
+
# open Doxygen tag
|
117
|
+
doc_str << '/*!'
|
118
|
+
if context
|
119
|
+
doc_str << if context.function?
|
120
|
+
'\\fn' << context.to_init_s << "\n"
|
121
|
+
else
|
122
|
+
context = context.to_s
|
123
|
+
if context =~ /\A(?:struct|union|enum)\W/
|
124
|
+
'\\' << context << "\n"
|
125
|
+
else
|
126
|
+
'\\typedef' << context << "\n"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
doc_str << DBC.format_conditions(conditions) << '*/'
|
131
|
+
# if no context is given and we have function
|
132
|
+
# try to insert the tag after then next opening braket
|
133
|
+
if conditions.first[0] =~ /pre|post/ and not context
|
134
|
+
until tokens.empty?
|
135
|
+
t = tokens.shift
|
136
|
+
outstr << t[1]
|
137
|
+
break if t[1] == '{'
|
138
|
+
end
|
139
|
+
end
|
140
|
+
outstr << doc_str
|
141
|
+
else
|
142
|
+
outstr << t[1]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
outstr
|
146
|
+
end
|
147
|
+
|
148
|
+
class Parser < CTokenizer::LexerBase
|
149
|
+
include CTokenizer::Scoped
|
150
|
+
def initialize(str, file=nil, line=1)
|
151
|
+
super(str, file, line)
|
152
|
+
@token_cache = CTokenizer::Cache.new(super.file, super.line)
|
153
|
+
@scope = 0
|
154
|
+
@macro = false
|
155
|
+
@start_line = true # begining of file
|
156
|
+
end
|
157
|
+
|
158
|
+
def shift
|
159
|
+
process_scope(@token_cache.empty? ? super : @token_cache.shift)
|
160
|
+
end
|
161
|
+
|
162
|
+
def empty?
|
163
|
+
@token_cache.empty? and super
|
164
|
+
end
|
165
|
+
|
166
|
+
def file
|
167
|
+
if @token_cache.empty?
|
168
|
+
super
|
169
|
+
else
|
170
|
+
@token_cache.file
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def line
|
175
|
+
if @token_cache.empty?
|
176
|
+
super
|
177
|
+
else
|
178
|
+
@token_cache.line
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
end # Parser
|
183
|
+
|
184
|
+
class OCLParser < Parser
|
185
|
+
|
186
|
+
def initialize(str, file=nil, line=1)
|
187
|
+
super(str, file, line)
|
188
|
+
@conditions = {}
|
189
|
+
@ctype_parser = CType::Parser.new()
|
190
|
+
end
|
191
|
+
|
192
|
+
attr_reader :conditions
|
193
|
+
|
194
|
+
def shift
|
195
|
+
t = super
|
196
|
+
# note: comments don't affect start_of_line?
|
197
|
+
if t[0] == :COMMENT and start_of_line? and ocl = DBC.get_ocl(t[1])
|
198
|
+
parse_ocl(ocl)
|
199
|
+
end
|
200
|
+
t
|
201
|
+
end
|
202
|
+
|
203
|
+
private
|
204
|
+
def parse_ocl(str)
|
205
|
+
self.error("no context for previous contract") \
|
206
|
+
unless @token_cache.empty?
|
207
|
+
count = CTokenizer.line_count(str)
|
208
|
+
parser = OCL::Parser.new(str, self.file, self.line - count)
|
209
|
+
self.error("no conditions given") if parser.conditions.empty?
|
210
|
+
|
211
|
+
unless parser.context
|
212
|
+
@token_cache.reset(self.file, self.line)
|
213
|
+
# Use the Splitter to cache the tokens used by the type parser
|
214
|
+
splitter = CTokenizer::Splitter.new(@token_cache, @source)
|
215
|
+
splitter = CTokenizer::SkipMacros.new(splitter)
|
216
|
+
context = @ctype_parser.parse(splitter)
|
217
|
+
self.error("multiple contexts given") unless context.length == 1
|
218
|
+
parser.context = context.first
|
219
|
+
end
|
220
|
+
|
221
|
+
if parser.conditions.last.type =~ /\A(?:pre|post)/
|
222
|
+
# should be followed by a function
|
223
|
+
self.error("pre and post conditions must be in the context of a function") \
|
224
|
+
unless parser.context.function?
|
225
|
+
end
|
226
|
+
|
227
|
+
context_str = if parser.context.class == String
|
228
|
+
parser.context
|
229
|
+
else
|
230
|
+
parser.context.short_name
|
231
|
+
end
|
232
|
+
@conditions[context_str] = parser
|
233
|
+
end
|
234
|
+
end # OCLParser
|
235
|
+
|
236
|
+
end # DBC
|
237
|
+
|
data/lib/dbc/define.rb
ADDED
@@ -0,0 +1,302 @@
|
|
1
|
+
#
|
2
|
+
# DO NOT MODIFY!!!!
|
3
|
+
# This file is automatically generated by racc 1.4.4
|
4
|
+
# from racc grammer file "src/define.y".
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'racc/parser'
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
require 'dbc/parameters'
|
12
|
+
require 'dbc/parseerrorhandler'
|
13
|
+
|
14
|
+
|
15
|
+
module Preprocessor
|
16
|
+
|
17
|
+
class Define < Racc::Parser
|
18
|
+
|
19
|
+
module_eval <<'..end src/define.y modeval..id6f1b6c1f3b', 'src/define.y', 75
|
20
|
+
|
21
|
+
def initialize(params, tokens)
|
22
|
+
if params and not params.class == Parameters
|
23
|
+
@params = Parameters.new
|
24
|
+
params.each { |p| @params << p }
|
25
|
+
else
|
26
|
+
@params = params
|
27
|
+
end
|
28
|
+
@value = tokens.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
#attr_reader :file, :line
|
32
|
+
|
33
|
+
def takes_args?
|
34
|
+
@params != nil and not @params.empty?
|
35
|
+
end
|
36
|
+
|
37
|
+
# get the value of the macro
|
38
|
+
# 1) substitute macro function parameters if any
|
39
|
+
# note function parameters should NOT be resolved
|
40
|
+
# 2) stringify macro function parameters
|
41
|
+
# 3) concat tokens using ## operator
|
42
|
+
# 4) (happens after call to tokens) repeat 1) for each identifier
|
43
|
+
def value(stack)
|
44
|
+
if takes_args?
|
45
|
+
args = @params.get_args(stack)
|
46
|
+
end
|
47
|
+
evaluate(args)
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_s
|
51
|
+
@value
|
52
|
+
end
|
53
|
+
|
54
|
+
def inspect
|
55
|
+
"\#<#{self.class}:#{self.to_s}>"
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
def evaluate(args)
|
61
|
+
str = @value
|
62
|
+
@q = []
|
63
|
+
until str.empty?
|
64
|
+
@q << case str
|
65
|
+
# this works because all spaces, comments and newlines were
|
66
|
+
# replaced by a single space by the preprocessor
|
67
|
+
when /\A[ \t]*##[ \t]*/o
|
68
|
+
str = $'
|
69
|
+
['##', $&].freeze
|
70
|
+
when /\A#[ \t]*/o
|
71
|
+
str = $'
|
72
|
+
['#', '#'].freeze
|
73
|
+
else
|
74
|
+
token, str = CTokenizer.split_token(str)
|
75
|
+
if (args and token[0] == :IDENTIFIER and idx = @params.index(token[1]))
|
76
|
+
[:PARAMETER, args[idx]].freeze
|
77
|
+
else
|
78
|
+
token
|
79
|
+
end
|
80
|
+
end # case
|
81
|
+
end # until
|
82
|
+
@q << [false, false]
|
83
|
+
do_parse
|
84
|
+
end
|
85
|
+
|
86
|
+
include ParseErrorHandler
|
87
|
+
|
88
|
+
def next_token
|
89
|
+
@q.shift
|
90
|
+
end
|
91
|
+
|
92
|
+
..end src/define.y modeval..id6f1b6c1f3b
|
93
|
+
|
94
|
+
##### racc 1.4.4 generates ###
|
95
|
+
|
96
|
+
racc_reduce_table = [
|
97
|
+
0, 0, :racc_error,
|
98
|
+
1, 15, :_reduce_none,
|
99
|
+
1, 15, :_reduce_none,
|
100
|
+
0, 17, :_reduce_3,
|
101
|
+
1, 16, :_reduce_4,
|
102
|
+
2, 16, :_reduce_5,
|
103
|
+
1, 18, :_reduce_none,
|
104
|
+
1, 18, :_reduce_none,
|
105
|
+
1, 18, :_reduce_none,
|
106
|
+
1, 19, :_reduce_none,
|
107
|
+
3, 19, :_reduce_10,
|
108
|
+
1, 22, :_reduce_none,
|
109
|
+
1, 22, :_reduce_none,
|
110
|
+
1, 22, :_reduce_none,
|
111
|
+
1, 22, :_reduce_none,
|
112
|
+
1, 22, :_reduce_none,
|
113
|
+
1, 22, :_reduce_none,
|
114
|
+
1, 22, :_reduce_none,
|
115
|
+
1, 22, :_reduce_none,
|
116
|
+
1, 22, :_reduce_none,
|
117
|
+
2, 21, :_reduce_20,
|
118
|
+
1, 23, :_reduce_none,
|
119
|
+
1, 20, :_reduce_none ]
|
120
|
+
|
121
|
+
racc_reduce_n = 23
|
122
|
+
|
123
|
+
racc_shift_n = 27
|
124
|
+
|
125
|
+
racc_action_table = [
|
126
|
+
5, 6, 8, 10, 12, 14, 16, 18, 1, 23,
|
127
|
+
4, 5, 6, 8, 10, 12, 14, 16, 18, 1,
|
128
|
+
1, 4, 6, 8, 10, 12, 14, 16, 18, 1,
|
129
|
+
24, 26, 21 ]
|
130
|
+
|
131
|
+
racc_action_check = [
|
132
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
|
133
|
+
0, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
134
|
+
4, 9, 23, 23, 23, 23, 23, 23, 23, 23,
|
135
|
+
21, 23, 7 ]
|
136
|
+
|
137
|
+
racc_action_pointer = [
|
138
|
+
-3, nil, nil, nil, 9, nil, nil, 32, nil, 8,
|
139
|
+
nil, nil, nil, nil, nil, -3, nil, nil, nil, nil,
|
140
|
+
nil, 30, nil, 18, nil, nil, nil ]
|
141
|
+
|
142
|
+
racc_action_default = [
|
143
|
+
-3, -21, -9, -18, -19, -22, -11, -23, -17, -1,
|
144
|
+
-12, -2, -13, -4, -14, -6, -15, -7, -16, -8,
|
145
|
+
-20, -23, -5, -23, 27, -10, -19 ]
|
146
|
+
|
147
|
+
racc_goto_table = [
|
148
|
+
13, 7, 11, 9, 25, 20, nil, nil, nil, 22 ]
|
149
|
+
|
150
|
+
racc_goto_check = [
|
151
|
+
4, 1, 3, 2, 8, 9, nil, nil, nil, 4 ]
|
152
|
+
|
153
|
+
racc_goto_pointer = [
|
154
|
+
nil, 1, 3, 2, 0, nil, nil, nil, -19, 1 ]
|
155
|
+
|
156
|
+
racc_goto_default = [
|
157
|
+
nil, nil, nil, nil, nil, 15, 17, 19, 2, 3 ]
|
158
|
+
|
159
|
+
racc_token_table = {
|
160
|
+
false => 0,
|
161
|
+
Object.new => 1,
|
162
|
+
:STRINGIFY => 2,
|
163
|
+
:SPACE => 3,
|
164
|
+
:SYMBOL => 4,
|
165
|
+
:UNKNOWN => 5,
|
166
|
+
:CHARACTER => 6,
|
167
|
+
:STRING => 7,
|
168
|
+
:FLOAT => 8,
|
169
|
+
:INTEGER => 9,
|
170
|
+
:IDENTIFIER => 10,
|
171
|
+
:PARAMETER => 11,
|
172
|
+
"##" => 12,
|
173
|
+
"#" => 13 }
|
174
|
+
|
175
|
+
racc_use_result_var = true
|
176
|
+
|
177
|
+
racc_nt_base = 14
|
178
|
+
|
179
|
+
Racc_arg = [
|
180
|
+
racc_action_table,
|
181
|
+
racc_action_check,
|
182
|
+
racc_action_default,
|
183
|
+
racc_action_pointer,
|
184
|
+
racc_goto_table,
|
185
|
+
racc_goto_check,
|
186
|
+
racc_goto_default,
|
187
|
+
racc_goto_pointer,
|
188
|
+
racc_nt_base,
|
189
|
+
racc_reduce_table,
|
190
|
+
racc_token_table,
|
191
|
+
racc_shift_n,
|
192
|
+
racc_reduce_n,
|
193
|
+
racc_use_result_var ]
|
194
|
+
|
195
|
+
Racc_token_to_s_table = [
|
196
|
+
'$end',
|
197
|
+
'error',
|
198
|
+
'STRINGIFY',
|
199
|
+
'SPACE',
|
200
|
+
'SYMBOL',
|
201
|
+
'UNKNOWN',
|
202
|
+
'CHARACTER',
|
203
|
+
'STRING',
|
204
|
+
'FLOAT',
|
205
|
+
'INTEGER',
|
206
|
+
'IDENTIFIER',
|
207
|
+
'PARAMETER',
|
208
|
+
'"##"',
|
209
|
+
'"#"',
|
210
|
+
'$start',
|
211
|
+
'target',
|
212
|
+
'token_sequence',
|
213
|
+
'empty_target',
|
214
|
+
'token',
|
215
|
+
'token_expression',
|
216
|
+
'white_space',
|
217
|
+
'stringify_parameter',
|
218
|
+
'basic_token',
|
219
|
+
'parameter']
|
220
|
+
|
221
|
+
Racc_debug_parser = false
|
222
|
+
|
223
|
+
##### racc system variables end #####
|
224
|
+
|
225
|
+
# reduce 0 omitted
|
226
|
+
|
227
|
+
# reduce 1 omitted
|
228
|
+
|
229
|
+
# reduce 2 omitted
|
230
|
+
|
231
|
+
module_eval <<'.,.,', 'src/define.y', 23
|
232
|
+
def _reduce_3( val, _values, result )
|
233
|
+
result = ''
|
234
|
+
result
|
235
|
+
end
|
236
|
+
.,.,
|
237
|
+
|
238
|
+
module_eval <<'.,.,', 'src/define.y', 27
|
239
|
+
def _reduce_4( val, _values, result )
|
240
|
+
result = val[0].dup
|
241
|
+
result
|
242
|
+
end
|
243
|
+
.,.,
|
244
|
+
|
245
|
+
module_eval <<'.,.,', 'src/define.y', 28
|
246
|
+
def _reduce_5( val, _values, result )
|
247
|
+
result = val[0] << val[1]
|
248
|
+
result
|
249
|
+
end
|
250
|
+
.,.,
|
251
|
+
|
252
|
+
# reduce 6 omitted
|
253
|
+
|
254
|
+
# reduce 7 omitted
|
255
|
+
|
256
|
+
# reduce 8 omitted
|
257
|
+
|
258
|
+
# reduce 9 omitted
|
259
|
+
|
260
|
+
module_eval <<'.,.,', 'src/define.y', 39
|
261
|
+
def _reduce_10( val, _values, result )
|
262
|
+
result = val[0] + val[2]
|
263
|
+
result
|
264
|
+
end
|
265
|
+
.,.,
|
266
|
+
|
267
|
+
# reduce 11 omitted
|
268
|
+
|
269
|
+
# reduce 12 omitted
|
270
|
+
|
271
|
+
# reduce 13 omitted
|
272
|
+
|
273
|
+
# reduce 14 omitted
|
274
|
+
|
275
|
+
# reduce 15 omitted
|
276
|
+
|
277
|
+
# reduce 16 omitted
|
278
|
+
|
279
|
+
# reduce 17 omitted
|
280
|
+
|
281
|
+
# reduce 18 omitted
|
282
|
+
|
283
|
+
# reduce 19 omitted
|
284
|
+
|
285
|
+
module_eval <<'.,.,', 'src/define.y', 56
|
286
|
+
def _reduce_20( val, _values, result )
|
287
|
+
result = "\"#{val[1]}\""
|
288
|
+
result
|
289
|
+
end
|
290
|
+
.,.,
|
291
|
+
|
292
|
+
# reduce 21 omitted
|
293
|
+
|
294
|
+
# reduce 22 omitted
|
295
|
+
|
296
|
+
def _reduce_none( val, _values, result )
|
297
|
+
result
|
298
|
+
end
|
299
|
+
|
300
|
+
end # class Define
|
301
|
+
|
302
|
+
end # module Preprocessor
|