ヘッダ解析 †
#! /usr/bin/ruby
$QUICK_RUBY_VERSION = RUBY_VERSION.split('.').inject(0){|vv,v| vv * 100 + v.to_i }
class HeaderParser
def initialize
@treat_as_void = (['void']).uniq
@local_as_void = @treat_as_void
@c_strippables = ['(?:__attribute__\s*\(+.*?\)+)']
@treat_externs = :exclude
@module_name = 'hoge'
end
def parse(source)
print "### 1 ###\n"
print source
# let's clean up the encoding in case they've done anything weird with the characters we might find
source = source.force_encoding("ISO-8859-1").encode("utf-8", :replace => nil) if ($QUICK_RUBY_VERSION > 10900)
print "### 2 ###\n"
print source
# void must be void for cmock _ExpectAndReturn calls to process properly, not some weird typedef which equates to void
# to a certain extent, this action assumes we're chewing on pre-processed header files, otherwise we'll most likely just get stuff from @treat_as_void
@local_as_void = @treat_as_void
void_types = source.scan(/typedef\s+(?:\(\s*)?void(?:\s*\))?\s+([\w\d]+)\s*;/)
if void_types
@local_as_void += void_types.flatten.uniq.compact
end
# smush multiline macros into single line (checking for continuation character at end of line '\')
source.gsub!(/\s*\\\s*/m, ' ')
print "### 3 ###\n"
print source
#remove comments (block and line, in three steps to ensure correct precedence)
source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks
print "### 4 ###\n"
print source
source.gsub!(/\/\*.*?\*\//m, '') # remove block comments
print "### 5 ###\n"
print source
source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain)
print "### 6 ###\n"
print source
# remove assembler pragma sections
source.gsub!(/^\s*#\s*pragma\s+asm\s+.*?#\s*pragma\s+endasm/m, '')
print "### 7 ###\n"
print source
# remove gcc's __attribute__ tags
source.gsub!(/__attribute(?:__)?\s*\(\(+.*\)\)+/, '')
print "### 8 ###\n"
print source
# remove preprocessor statements and extern "C"
source.gsub!(/^\s*#.*/, '')
print "### 9 ###\n"
print source
source.gsub!(/extern\s+\"C\"\s+\{/, '')
print "### 10 ###\n"
print source
# enums, unions, structs, and typedefs can all contain things (e.g. function pointers) that parse like function prototypes, so yank them
# forward declared structs are removed before struct definitions so they don't mess up real thing later. we leave structs keywords in function prototypes
source.gsub!(/^[\w\s]*struct[^;\{\}\(\)]+;/m, '') # remove forward declared structs
print "### 11 ###\n"
print source
=begin
source.gsub!(/^[\w\s]*(enum|union|struct|typepdef)[\w\s]*\{[^\}]+\}[\w\s\*\,]*;/m, '') # remove struct, union, and enum definitions and typedefs with braces
print "### 12 ###\n"
print source
source.gsub!(/(\W)(?:register|auto|static|restrict)(\W)/, '\1\2') # remove problem keywords
print "### 13 ###\n"
print source
source.gsub!(/\s*=\s*['"a-zA-Z0-9_\.]+\s*/, '') # remove default value statements from argument lists
print "### 14 ###\n"
print source
source.gsub!(/^(?:[\w\s]*\W)?typedef\W[^;]*/m, '') # remove typedef statements
print "### 15 ###\n"
print source
source.gsub!(/\)(\w)/, ') \1') # add space between parenthese and alphanumeric
print "### 16 ###\n"
print source
source.gsub!(/(^|\W+)(?:#{@c_strippables.join('|')})(?=$|\W+)/,'\1') unless @c_strippables.empty? # remove known attributes slated to be stripped
print "### 17 ###\n"
print source
#scan for functions which return function pointers, because they are a pain
source.gsub!(/([\w\s\*]+)\(*\(\s*\*([\w\s\*]+)\s*\(([\w\s\*,]*)\)\)\s*\(([\w\s\*,]*)\)\)*/) do |m|
functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}"
@typedefs << "typedef #{$1.strip}(*#{functype})(#{$4});"
"#{functype} #{$2.strip}(#{$3});"
end
print "### 18 ###\n"
print source
=end
#drop extra white space to make the rest go faster
source.gsub!(/^\s+/, '') # remove extra white space from beginning of line
print "### 19 ###\n"
print source
source.gsub!(/\s+$/, '') # remove extra white space from end of line
print "### 20 ###\n"
print source
source.gsub!(/\s*\(\s*/, '(') # remove extra white space from before left parens
print "### 21 ###\n"
print source
source.gsub!(/\s*\)\s*/, ')') # remove extra white space from before right parens
print "### 22 ###\n"
print source
source.gsub!(/\s+/, ' ') # remove remaining extra white space
print "### 23 ###\n"
print source
source.gsub!(/\s+;/, ';') # [Add] remove remaining extra white space
=begin
#split lines on semicolons and remove things that are obviously not what we are looking for
src_lines = source.split(/\s*;\s*/)
src_lines.delete_if {|line| line.strip.length == 0} # remove blank lines
src_lines.delete_if {|line| !(line =~ /[\w\s\*]+\(+\s*\*[\*\s]*[\w\s]+(?:\[[\w\s]*\]\s*)+\)+\s*\((?:[\w\s\*]*,?)*\s*\)/).nil?} #remove function pointer arrays
if (@treat_externs == :include)
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:inline)\s+/).nil?} # remove inline functions
else
src_lines.delete_if {|line| !(line =~ /(?:^|\s+)(?:extern|inline)\s+/).nil?} # remove inline and extern functions
end
src_lines.delete_if {|line| !(line =~ /\{/).nil? } # remove lines with opening braces { because this isn't a declaration, it's a definition!
src_lines.map!{|line| line.gsub(/.*\}/,'')} #remove braces left at the beginning of lines
src_lines.delete_if {|line| line.empty? } #drop empty lines
=end
end
def getMemberInfo(member)
info = {}
info["name"] = member.split(' ')[-1].gsub('*', '')
type = ""
member.split(' ')[0..-2].map do |item|
type += " " if type.length != 0
type += item
end
type += " *" if member.index('*') and !type.index('*')
info["type"] = type
return info
end
def getMemberName(member)
member.split(' ')[-1].gsub('*', '').gsub(/\[.*\]/, '')
end
def isArrayOrPointerMember?(member)
return true if member.index('*') or member.index('[')
end
def getStructTree(parseSrc, name)
src_lines = parseSrc.split(/\s*typedef struct\s*/)
src_lines.delete_if {|line| line.strip.length == 0}
list = []
src_lines.each do |line|
structDef = {"name"=>"", "members"=>[]}
structElements = line.split(/[{};]/, 0)
structElements.delete_if {|line| line == " "}
structElements.each_with_index do |ele, i|
ele.gsub!(/^\s+/, '') # remove extra white space from beginning of line
structDef["name"] = ele if i == (structElements.length-1)
if i != 0 and i != (structElements.length-1) then
structDef["members"].push(ele)
end
end
list.push(structDef)
end
p list
list.each do |item|
return item if item["name"] == name
end
end
end
parser = HeaderParser.new()
src = parser.parse(File.read(ARGV[0]))
print "\n\n### PARSE ###\n"
print src
print "\n### PARSE END ###\n"
tree = parser.getStructTree(src, ARGV[1])
p tree
p parser.getMemberName(tree["members"][1])
EXCLUDE_MEMBERS = ["id1", "id2"]
TEST_CMD_VAR_NAME = "test_cmd"
FLAG_BASE_NAME = "_enable"
autoCode = "int " + tree["name"] + "_test(void)\n" + "{\n"
autoCode += " " + tree["name"] + " " + TEST_CMD_VAR_NAME + ";\n\n"
tree["members"].each do |item|
memName = parser.getMemberName(item)
next if EXCLUDE_MEMBERS.include?(memName)
next if memName.index(FLAG_BASE_NAME)
autoCode += " " + item + ";\n"
end
autoCode += "\n"
autoCode += " int idx;\n\n"
autoCode += " idx = 0;\n\n"
IDX_COMMENT_OFFSET = 50
idx = 0
tree["members"].each do |item|
memName = parser.getMemberName(item)
next if EXCLUDE_MEMBERS.include?(memName)
next if memName.index(FLAG_BASE_NAME)
ptr = ""
if parser.isArrayOrPointerMember?(item) then
ptr = memName
else
ptr = "&" + memName
end
memsetStr = " " + "memset(" + ptr + ", idx++, " + "sizeof(" + memName + "));"
if memsetStr.length < IDX_COMMENT_OFFSET
memsetStr += " " * (IDX_COMMENT_OFFSET - memsetStr.length)
else
memsetStr += " "
end
memsetStr += "/* " + idx.to_s + " */\n"
autoCode += memsetStr
idx += 1
end
autoCode += "\n"
autoCode += " " + TEST_CMD_VAR_NAME + ".id1 = 1;\n"
autoCode += " " + TEST_CMD_VAR_NAME + ".id2 = 4;\n"
autoCode += "\n"
tree["members"].each do |item|
memName = parser.getMemberName(item)
autoCode += " " + TEST_CMD_VAR_NAME + "." + memName + " = 1;\n" if memName.index(FLAG_BASE_NAME)
end
autoCode += "\n"
tree["members"].each do |item|
subStr = ""
memName = parser.getMemberName(item)
next if EXCLUDE_MEMBERS.include?(memName)
next if memName.index(FLAG_BASE_NAME)
if parser.isArrayOrPointerMember?(item) then
subStr = " memcpy(" + TEST_CMD_VAR_NAME + "." + memName + ", " + memName + ", sizeof(" + memName + "));\n"
else
subStr = " test_cmd." + memName + " = " + memName + ";\n"
end
autoCode += subStr
end
autoCode += "\n}"
print "\n\n### PROGRAM START ###\n"
print autoCode
print "\n\n### PROGRAM END ###\n"
最新の20件
2021-03-31
2020-06-09
2020-05-30
2019-12-02
2018-10-18
2018-07-05
2018-01-11
2015-12-07
2015-08-03
2015-07-20
2012-07-19
2012-06-30
2012-06-23
2012-01-25
2011-11-09
2011-11-08
2011-10-02
今日の3件
- counter: 272
- today: 1
- yesterday: 0
- online: 1