- extra spaces are removed
- static class member modifier processing is fixed (moved from 'rettype' to 'func_modlist')
This commit is contained in:
parent
2935bb29e5
commit
0f5f60f7f5
@ -749,8 +749,9 @@ class PythonWrapperGenerator(object):
|
||||
if __name__ == "__main__":
|
||||
srcfiles = hdr_parser.opencv_hdr_list
|
||||
dstdir = "/Users/vp/tmp"
|
||||
if len(sys.argv) > 2:
|
||||
if len(sys.argv) > 1:
|
||||
dstdir = sys.argv[1]
|
||||
if len(sys.argv) > 2:
|
||||
srcfiles = sys.argv[2:]
|
||||
generator = PythonWrapperGenerator()
|
||||
generator.gen(srcfiles, dstdir)
|
||||
|
@ -20,7 +20,7 @@ where each element of <list_of_arguments> is 4-element list itself:
|
||||
[argtype, argname, default_value /* or "" if none */, <list_of_modifiers>]
|
||||
where the list of modifiers is yet another nested list of strings
|
||||
(currently recognized are "/O" for output argument, "/S" for static (i.e. class) methods
|
||||
and "/A value" for the plain C arrays with counters)
|
||||
and "/A value" for the plain C arrays with counters)
|
||||
"""
|
||||
|
||||
class CppHeaderParser(object):
|
||||
@ -31,18 +31,18 @@ class CppHeaderParser(object):
|
||||
self.PROCESS_FLAG = 2
|
||||
self.PUBLIC_SECTION = 3
|
||||
self.CLASS_DECL = 4
|
||||
|
||||
|
||||
def batch_replace(self, s, pairs):
|
||||
for before, after in pairs:
|
||||
s = s.replace(before, after)
|
||||
return s
|
||||
|
||||
|
||||
def get_macro_arg(self, arg_str, npos):
|
||||
npos2 = npos3 = arg_str.find("(", npos)
|
||||
if npos2 < 0:
|
||||
print "Error: no arguments for the macro at %d" % (self.lineno,)
|
||||
sys.exit(-1)
|
||||
balance = 1
|
||||
balance = 1
|
||||
while 1:
|
||||
t, npos3 = self.find_next_token(arg_str, ['(', ')'], npos3+1)
|
||||
if npos3 < 0:
|
||||
@ -54,9 +54,9 @@ class CppHeaderParser(object):
|
||||
balance -= 1
|
||||
if balance == 0:
|
||||
break
|
||||
|
||||
|
||||
return arg_str[npos2+1:npos3].strip(), npos3
|
||||
|
||||
|
||||
def parse_arg(self, arg_str, argno):
|
||||
"""
|
||||
Parses <arg_type> [arg_name]
|
||||
@ -67,12 +67,12 @@ class CppHeaderParser(object):
|
||||
"arg" + str(argno), and then argno is incremented.
|
||||
"""
|
||||
modlist = []
|
||||
|
||||
|
||||
# pass 0: extracts the modifiers
|
||||
if "CV_OUT" in arg_str:
|
||||
modlist.append("/O")
|
||||
arg_str = arg_str.replace("CV_OUT", "")
|
||||
|
||||
|
||||
if "CV_IN_OUT" in arg_str:
|
||||
modlist.append("/IO")
|
||||
arg_str = arg_str.replace("CV_IN_OUT", "")
|
||||
@ -82,25 +82,25 @@ class CppHeaderParser(object):
|
||||
if npos >= 0:
|
||||
isarray = True
|
||||
macro_arg, npos3 = self.get_macro_arg(arg_str, npos)
|
||||
|
||||
|
||||
modlist.append("/A " + macro_arg)
|
||||
arg_str = arg_str[:npos] + arg_str[npos3+1:]
|
||||
|
||||
|
||||
npos = arg_str.find("CV_CUSTOM_CARRAY")
|
||||
if npos >= 0:
|
||||
isarray = True
|
||||
macro_arg, npos3 = self.get_macro_arg(arg_str, npos)
|
||||
|
||||
|
||||
modlist.append("/CA " + macro_arg)
|
||||
arg_str = arg_str[:npos] + arg_str[npos3+1:]
|
||||
|
||||
arg_str = arg_str.strip()
|
||||
|
||||
arg_str = arg_str.strip()
|
||||
word_start = 0
|
||||
word_list = []
|
||||
npos = -1
|
||||
|
||||
#print self.lineno, ":\t", arg_str
|
||||
|
||||
|
||||
#print self.lineno, ":\t", arg_str
|
||||
|
||||
# pass 1: split argument type into tokens
|
||||
while 1:
|
||||
npos += 1
|
||||
@ -121,9 +121,9 @@ class CppHeaderParser(object):
|
||||
arg_type = ""
|
||||
arg_name = ""
|
||||
angle_stack = []
|
||||
|
||||
|
||||
#print self.lineno, ":\t", word_list
|
||||
|
||||
|
||||
# pass 2: decrypt the list
|
||||
wi = -1
|
||||
prev_w = ""
|
||||
@ -160,7 +160,7 @@ class CppHeaderParser(object):
|
||||
else:
|
||||
arg_type += w
|
||||
prev_w = w
|
||||
|
||||
|
||||
counter_str = ""
|
||||
add_star = False
|
||||
if ("[" in arg_name) and not ("operator" in arg_str):
|
||||
@ -177,24 +177,24 @@ class CppHeaderParser(object):
|
||||
modlist.append("/A " + counter_str.strip())
|
||||
arg_name = arg_name[:p1]
|
||||
add_star = True
|
||||
|
||||
|
||||
if not arg_name:
|
||||
if arg_type.startswith("operator"):
|
||||
arg_type, arg_name = "", arg_type
|
||||
else:
|
||||
arg_name = "arg" + str(argno)
|
||||
argno += 1
|
||||
|
||||
|
||||
while arg_type.endswith("_end_"):
|
||||
arg_type = arg_type[:-len("_end_")]
|
||||
|
||||
|
||||
if add_star:
|
||||
arg_type += "*"
|
||||
|
||||
|
||||
arg_type = self.batch_replace(arg_type, [("std::", ""), ("cv::", "")])
|
||||
|
||||
|
||||
return arg_type, arg_name, modlist, argno
|
||||
|
||||
|
||||
def parse_enum(self, decl_str):
|
||||
l = decl_str
|
||||
ll = l.split(",")
|
||||
@ -214,7 +214,7 @@ class CppHeaderParser(object):
|
||||
prev_val = val = pv[1].strip()
|
||||
decl.append(["const " + self.get_dotted_name(pv[0].strip()), val, [], []])
|
||||
return decl
|
||||
|
||||
|
||||
def parse_class_decl(self, decl_str):
|
||||
"""
|
||||
Parses class/struct declaration start in the form:
|
||||
@ -234,7 +234,7 @@ class CppHeaderParser(object):
|
||||
macro_arg, npos3 = self.get_macro_arg(l, npos)
|
||||
modlist.append("=" + macro_arg)
|
||||
l = l[:npos] + l[npos3+1:]
|
||||
|
||||
|
||||
l = self.batch_replace(l, [("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("public ", " "), ("::", ".")]).strip()
|
||||
ll = re.split(r'\s*[,:]?\s*', l)
|
||||
ll = [le for le in ll if le]
|
||||
@ -249,18 +249,18 @@ class CppHeaderParser(object):
|
||||
[~]<function_name>
|
||||
(<arg_type1> <arg_name1>[=<default_value1>] [, <arg_type2> <arg_name2>[=<default_value2>] ...])
|
||||
[const] {; | <function_body>}
|
||||
|
||||
|
||||
Returns the function declaration entry:
|
||||
[<function_name>, <rettype>, <the_list_of_argument_descriptions>] (see above)
|
||||
[<func name>, <return value C-type>, <list of modifiers>, <list of arguments>] (see above)
|
||||
"""
|
||||
|
||||
|
||||
if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or \
|
||||
("CV_WRAP" in decl_str) or ("CV_WRAP_AS" in decl_str)):
|
||||
return []
|
||||
|
||||
|
||||
top = self.block_stack[-1]
|
||||
func_modlist = []
|
||||
|
||||
|
||||
npos = decl_str.find("CV_EXPORTS_AS")
|
||||
if npos >= 0:
|
||||
arg, npos3 = self.get_macro_arg(decl_str, npos)
|
||||
@ -271,7 +271,7 @@ class CppHeaderParser(object):
|
||||
arg, npos3 = self.get_macro_arg(decl_str, npos)
|
||||
func_modlist.append("="+arg)
|
||||
decl_str = decl_str[:npos] + decl_str[npos3+1:]
|
||||
|
||||
|
||||
# filter off some common prefixes, which are meaningless for Python wrappers.
|
||||
# note that we do not strip "static" prefix, which does matter;
|
||||
# it means class methods, not instance methods
|
||||
@ -283,7 +283,7 @@ class CppHeaderParser(object):
|
||||
if decl_str.startswith("static") and (context == "class" or context == "struct"):
|
||||
decl_str = decl_str[len("static"):].lstrip()
|
||||
static_method = True
|
||||
|
||||
|
||||
args_begin = decl_str.find("(")
|
||||
if decl_str.startswith("CVAPI"):
|
||||
rtype_end = decl_str.find(")", args_begin+1)
|
||||
@ -295,7 +295,7 @@ class CppHeaderParser(object):
|
||||
if args_begin < 0:
|
||||
print "Error at %d: no args in '%s'" % (self.lineno, decl_str)
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
decl_start = decl_str[:args_begin].strip()
|
||||
# handle operator () case
|
||||
if decl_start.endswith("operator"):
|
||||
@ -304,9 +304,9 @@ class CppHeaderParser(object):
|
||||
print "Error at %d: no args in '%s'" % (self.lineno, decl_str)
|
||||
sys.exit(-1)
|
||||
decl_start = decl_str[:args_begin].strip()
|
||||
|
||||
|
||||
rettype, funcname, modlist, argno = self.parse_arg(decl_start, -1)
|
||||
|
||||
|
||||
if argno >= 0:
|
||||
classname = top[1]
|
||||
if rettype == classname or rettype == "~" + classname:
|
||||
@ -314,7 +314,7 @@ class CppHeaderParser(object):
|
||||
else:
|
||||
print "Error at %d. the function/method name is missing: '%s'" % (self.lineno, decl_start)
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
if ("::" in funcname) or funcname.startswith("~"):
|
||||
# if there is :: in function name (and this is in the header file),
|
||||
# it means, this is inline implementation of a class method.
|
||||
@ -322,9 +322,9 @@ class CppHeaderParser(object):
|
||||
# declaration.
|
||||
# Also, skip the destructors, as they are always wrapped
|
||||
return []
|
||||
|
||||
|
||||
funcname = self.get_dotted_name(funcname)
|
||||
|
||||
|
||||
arg_start = args_begin+1
|
||||
npos = arg_start-1
|
||||
balance = 1
|
||||
@ -333,7 +333,7 @@ class CppHeaderParser(object):
|
||||
args_decls = []
|
||||
args = []
|
||||
argno = 1
|
||||
|
||||
|
||||
while balance > 0:
|
||||
npos += 1
|
||||
t, npos = self.find_next_token(decl_str, ["(", ")", ",", "<", ">"], npos)
|
||||
@ -350,7 +350,7 @@ class CppHeaderParser(object):
|
||||
balance += 1
|
||||
if t == ")":
|
||||
balance -= 1
|
||||
|
||||
|
||||
if (t == "," and balance == 1 and angle_balance == 0) or balance == 0:
|
||||
# process next function argument
|
||||
a = decl_str[arg_start:npos].strip()
|
||||
@ -390,31 +390,31 @@ class CppHeaderParser(object):
|
||||
("OutputArrayOfArrays", "vector<Mat>"),
|
||||
("InputArray", "Mat"),
|
||||
("InputOutputArray", "Mat"),
|
||||
("OutputArray", "Mat")]).strip()
|
||||
("OutputArray", "Mat")]).strip()
|
||||
args.append([arg_type, arg_name, defval, modlist])
|
||||
npos = arg_start-1
|
||||
|
||||
|
||||
npos = decl_str.replace(" ", "").find("=0", npos)
|
||||
if npos >= 0:
|
||||
# skip pure virtual functions
|
||||
return []
|
||||
|
||||
|
||||
if static_method:
|
||||
rettype = " ".join([rettype, "/S"])
|
||||
|
||||
func_modlist.append("/S")
|
||||
|
||||
return [funcname, rettype, func_modlist, args]
|
||||
|
||||
def get_dotted_name(self, name):
|
||||
"""
|
||||
adds the dot-separated container class/namespace names to the bare function/class name, e.g. when we have
|
||||
|
||||
|
||||
namespace cv {
|
||||
class A {
|
||||
public:
|
||||
f(int);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
the function will convert "A" to "cv.A" and "f" to "cv.A.f".
|
||||
"""
|
||||
if not self.block_stack:
|
||||
@ -430,24 +430,24 @@ class CppHeaderParser(object):
|
||||
if block_name:
|
||||
n += block_name + "."
|
||||
return n + name
|
||||
|
||||
def parse_stmt(self, stmt, end_token):
|
||||
|
||||
def parse_stmt(self, stmt, end_token):
|
||||
"""
|
||||
parses the statement (ending with ';' or '}') or a block head (ending with '{')
|
||||
|
||||
|
||||
The function calls parse_class_decl or parse_func_decl when necessary. It returns
|
||||
<block_type>, <block_name>, <parse_flag>, <declaration>
|
||||
where the first 3 values only make sense for blocks (i.e. code blocks, namespaces, classes, enums and such)
|
||||
"""
|
||||
stack_top = self.block_stack[-1]
|
||||
context = stack_top[self.BLOCK_TYPE]
|
||||
|
||||
|
||||
stmt_type = ""
|
||||
if end_token == "{":
|
||||
stmt_type = "block"
|
||||
|
||||
|
||||
if context == "block":
|
||||
print "Error at %d: should not call parse_stmt inside blocks" % (self.lineno,)
|
||||
print "Error at %d: should not call parse_stmt inside blocks" % (self.lineno,)
|
||||
sys.exit(-1)
|
||||
|
||||
if context == "class" or context == "struct":
|
||||
@ -463,11 +463,11 @@ class CppHeaderParser(object):
|
||||
stack_top[self.PUBLIC_SECTION] = False
|
||||
stmt = stmt[colon_pos+1:].strip()
|
||||
break
|
||||
|
||||
|
||||
# do not process hidden class members and template classes/functions
|
||||
if not stack_top[self.PUBLIC_SECTION] or stmt.startswith("template"):
|
||||
return stmt_type, "", False, None
|
||||
|
||||
|
||||
if end_token == "{":
|
||||
if stmt.startswith("class") or stmt.startswith("struct"):
|
||||
stmt_type = stmt.split()[0]
|
||||
@ -478,16 +478,16 @@ class CppHeaderParser(object):
|
||||
if bases:
|
||||
decl[1] = ": " + " ".join(bases)
|
||||
return stmt_type, classname, True, decl
|
||||
|
||||
|
||||
if stmt.startswith("enum"):
|
||||
return "enum", "", True, None
|
||||
|
||||
|
||||
if stmt.startswith("namespace"):
|
||||
stmt_list = stmt.split()
|
||||
return stmt_list[0], stmt_list[1], True, None
|
||||
if stmt.startswith("extern") and "\"C\"" in stmt:
|
||||
return "namespace", "", True, None
|
||||
|
||||
|
||||
if end_token == "}" and context == "enum":
|
||||
decl = self.parse_enum(stmt)
|
||||
return "enum", "", False, decl
|
||||
@ -495,7 +495,7 @@ class CppHeaderParser(object):
|
||||
if end_token == ";" and stmt.startswith("typedef"):
|
||||
# TODO: handle typedef's more intelligently
|
||||
return stmt_type, "", False, None
|
||||
|
||||
|
||||
paren_pos = stmt.find("(")
|
||||
if paren_pos >= 0:
|
||||
# assume it's function or method declaration,
|
||||
@ -518,18 +518,18 @@ class CppHeaderParser(object):
|
||||
var_list = stmt.split(",")
|
||||
var_type, var_name1, modlist, argno = self.parse_arg(var_list[0], -1)
|
||||
var_list = [var_name1] + [i.strip() for i in var_list[1:]]
|
||||
|
||||
|
||||
for v in var_list:
|
||||
class_decl[3].append([var_type, v, "", var_modlist])
|
||||
return stmt_type, "", False, None
|
||||
|
||||
|
||||
# something unknown
|
||||
return stmt_type, "", False, None
|
||||
|
||||
|
||||
def find_next_token(self, s, tlist, p=0):
|
||||
"""
|
||||
Finds the next token from the 'tlist' in the input 's', starting from position 'p'.
|
||||
Returns the first occured token and its position, or ("", len(s)) when no token is found
|
||||
Returns the first occured token and its position, or ("", len(s)) when no token is found
|
||||
"""
|
||||
token = ""
|
||||
tpos = len(s)
|
||||
@ -551,55 +551,55 @@ class CppHeaderParser(object):
|
||||
f = open(hname, "rt")
|
||||
linelist = list(f.readlines())
|
||||
f.close()
|
||||
|
||||
|
||||
# states:
|
||||
SCAN = 0 # outside of a comment or preprocessor directive
|
||||
COMMENT = 1 # inside a multi-line comment
|
||||
DIRECTIVE = 2 # inside a multi-line preprocessor directive
|
||||
|
||||
|
||||
state = SCAN
|
||||
|
||||
|
||||
self.block_stack = [["file", hname, True, True, None]]
|
||||
block_head = ""
|
||||
self.lineno = 0
|
||||
|
||||
|
||||
for l0 in linelist:
|
||||
self.lineno += 1
|
||||
#print self.lineno
|
||||
|
||||
|
||||
l = l0.strip()
|
||||
|
||||
|
||||
if state == SCAN and l.startswith("#"):
|
||||
state = DIRECTIVE
|
||||
# fall through to the if state == DIRECTIVE check
|
||||
|
||||
|
||||
if state == DIRECTIVE:
|
||||
if not l.endswith("\\"):
|
||||
state = SCAN
|
||||
continue
|
||||
|
||||
|
||||
if state == COMMENT:
|
||||
pos = l.find("*/")
|
||||
if pos < 0:
|
||||
continue
|
||||
l = l[pos+2:]
|
||||
state = SCAN
|
||||
|
||||
|
||||
if state != SCAN:
|
||||
print "Error at %d: invlid state = %d" % (self.lineno, state)
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
while 1:
|
||||
token, pos = self.find_next_token(l, [";", "\"", "{", "}", "//", "/*"])
|
||||
|
||||
|
||||
if not token:
|
||||
block_head += " " + l
|
||||
break
|
||||
|
||||
|
||||
if token == "//":
|
||||
block_head += " " + l[:pos]
|
||||
break
|
||||
|
||||
|
||||
if token == "/*":
|
||||
block_head += " " + l[:pos]
|
||||
pos = l.find("*/", pos+2)
|
||||
@ -608,7 +608,7 @@ class CppHeaderParser(object):
|
||||
break
|
||||
l = l[pos+2:]
|
||||
continue
|
||||
|
||||
|
||||
if token == "\"":
|
||||
pos2 = pos + 1
|
||||
while 1:
|
||||
@ -619,15 +619,15 @@ class CppHeaderParser(object):
|
||||
if t2 == "\"":
|
||||
break
|
||||
pos2 += 2
|
||||
|
||||
|
||||
block_head += " " + l[:pos2+1]
|
||||
l = l[pos2+1:]
|
||||
continue
|
||||
|
||||
|
||||
stmt = (block_head + " " + l[:pos]).strip()
|
||||
stmt = " ".join(stmt.split()) # normalize the statement
|
||||
stack_top = self.block_stack[-1]
|
||||
|
||||
|
||||
decl = None
|
||||
if stack_top[self.PROCESS_FLAG]:
|
||||
# even if stack_top[PUBLIC_SECTION] is False, we still try to process the statement,
|
||||
@ -641,26 +641,26 @@ class CppHeaderParser(object):
|
||||
decls.append(decl)
|
||||
else:
|
||||
stmt_type, name, parse_flag = "block", "", False
|
||||
|
||||
|
||||
if token == "{":
|
||||
if stmt_type == "class":
|
||||
public_section = False
|
||||
else:
|
||||
public_section = True
|
||||
public_section = True
|
||||
self.block_stack.append([stmt_type, name, parse_flag, public_section, decl])
|
||||
|
||||
|
||||
if token == "}":
|
||||
if not self.block_stack:
|
||||
print "Error at %d: the block stack is empty" % (self.lineno,)
|
||||
self.block_stack[-1:] = []
|
||||
if pos+1 < len(l) and l[pos+1] == ';':
|
||||
pos += 1
|
||||
|
||||
|
||||
block_head = ""
|
||||
l = l[pos+1:]
|
||||
|
||||
|
||||
return decls
|
||||
|
||||
|
||||
def print_decls(self, decls):
|
||||
"""
|
||||
Prints the list of declarations, retrieived by the parse() method
|
||||
@ -668,7 +668,7 @@ class CppHeaderParser(object):
|
||||
for d in decls:
|
||||
print d[0], d[1], ";".join(d[2])
|
||||
for a in d[3]:
|
||||
print " ", a[0], a[1], a[2],
|
||||
print " ", a[0], a[1], a[2],
|
||||
if a[3]:
|
||||
print "; ".join(a[3])
|
||||
else:
|
||||
@ -676,7 +676,7 @@ class CppHeaderParser(object):
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = CppHeaderParser()
|
||||
decls = []
|
||||
decls = []
|
||||
for hname in opencv_hdr_list:
|
||||
decls += parser.parse(hname)
|
||||
parser.print_decls(decls)
|
||||
|
Loading…
x
Reference in New Issue
Block a user