提交 0f5f60f7 编写于 作者: A Andrey Pavlenko

- extra spaces are removed

- static class member modifier processing is fixed (moved from 'rettype' to 'func_modlist')
上级 2935bb29
......@@ -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)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册