Improved parse tree, now building within main opencv build system

pull/1384/head
Hilton Bristow 12 years ago committed by hbristow
parent 5d1944bace
commit 808f9dbc93
  1. 45
      modules/matlab/CMakeLists.txt
  2. 12
      modules/matlab/generator/filters.py
  3. 20
      modules/matlab/generator/gen_matlab.py
  4. 12
      modules/matlab/generator/gen_matlab_caller.py
  5. 182
      modules/matlab/generator/parse_tree.py

@ -2,8 +2,8 @@
# CMake file for Matlab/Octave support
# ----------------------------------------------------------------------------
# make sure we're on a supported architecture with Matlab installed
if (IOS OR ANDROID OR NOT MATLAB_FOUND)
# make sure we're on a supported architecture with Matlab and python installed
if (IOS OR ANDROID OR NOT MATLAB_FOUND OR NOT PYTHONLIBS_FOUND)
ocv_module_disable(matlab)
endif()
@ -13,4 +13,43 @@ ocv_add_module(matlab BINDINGS opencv_core opencv_imgproc
opencv_highgui opencv_ml opencv_calib3d opencv_photo
opencv_nonfree opencv_calib)
add_subdirectory(test)
# Add all of the headers we wish to parse
set(opencv_hdrs
"${OPENCV_MODULE_opencv_core_LOCATION}/include/opencv2/core/core.hpp"
"${OPENCV_MODULE_opencv_flann_LOCATION}/include/opencv2/flann/miniflann.hpp"
"${OPENCV_MODULE_opencv_imgproc_LOCATION}/include/opencv2/imgproc/imgproc.hpp"
"${OPENCV_MODULE_opencv_video_LOCATION}/include/opencv2/video/background_segm.hpp"
"${OPENCV_MODULE_opencv_video_LOCATION}/include/opencv2/video/tracking.hpp"
"${OPENCV_MODULE_opencv_photo_LOCATION}/include/opencv2/photo/photo.hpp"
"${OPENCV_MODULE_opencv_highgui_LOCATION}/include/opencv2/highgui/highgui.hpp"
"${OPENCV_MODULE_opencv_ml_LOCATION}/include/opencv2/ml/ml.hpp"
"${OPENCV_MODULE_opencv_features2d_LOCATION}/include/opencv2/features2d/features2d.hpp"
"${OPENCV_MODULE_opencv_calib3d_LOCATION}/include/opencv2/calib3d/calib3d.hpp"
"${OPENCV_MODULE_opencv_objdetect_LOCATION}/include/opencv2/objdetect/objdetect.hpp"
"${OPENCV_MODULE_opencv_softcascade_LOCATION}/include/opencv2/softcascade/softcascade.hpp"
"${OPENCV_MODULE_opencv_contrib_LOCATION}/include/opencv2/contrib/contrib.hpp")
if(HAVE_opencv_nonfree)
list(APPEND opencv_hdrs "${OPENCV_MODULE_opencv_nonfree_LOCATION}/include/opencv2/nonfree/features2d.hpp"
"${OPENCV_MODULE_opencv_nonfree_LOCATION}/include/opencv2/nonfree/nonfree.hpp")
endif()
# add the python generator to the python path
set(PYPATH_CACHE $ENV{PYTHONPATH})
set(ENV{PYTHONPATH} ${OPENCV_MODULE_opencv_python_LOCATION}/src2 $ENV{PYTHONPATH})
# synthesise the matlab sources
execute_process(
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/generator/gen_matlab_caller.py
${opencv_hdrs} ${CMAKE_CURRENT_BINARY_DIR}/src)
# compile the matlab sources
file(GLOB SOURCE_FILES ${CMAKE_CURRENT_BINARY_DIR}/src)
foreach(SOURCE_FILE ${SOURCE_FILES})
# compile the source file using mex
endforeach()
# restore the pythonpath
set(ENV{PYTHONPATH} ${PYPATH_CACHE})

@ -2,6 +2,18 @@ from textwrap import TextWrapper
from string import split, join
def comment(text, wrap=80, escape='% ', escape_first='', escape_last=''):
'''comment filter
Takes a string in text, and wraps it to wrap characters in length with
preceding comment escape sequence on each line. escape_first and
escape_last can be used for languages which define block comments.
Examples:
C++ inline comment comment(80, '// ')
C block comment: comment(80, ' * ', '/*', ' */')
Matlab comment: comment(80, '% ')
Matlab block comment: comment(80, '', '%{', '%}')
Python docstrings: comment(80, '', '\'\'\'', '\'\'\'')
'''
tw = TextWrapper(width=wrap-len(escape))
if escape_first:
escape_first = escape_first+'\n'

@ -2,3 +2,23 @@
import sys, re, os.path
from string import Template
from hdr_parser import CppHeaderParser
from parse_tree import ParseTree, todict
class MatlabWrapperGenerator(object):
def gen(self, input_files, output_files):
# parse each of the files and store in a dictionary
# as a separate "namespace"
parser = CppHeaderParser()
ns = {}
for file in input_files:
# get the file name
name = os.path.splitext(os.path.basename(file))[0]
ns[name] = parser.parse(file)
# cleanify the parser output
parse_tree = ParseTree()
parse_tree.build(ns)
print parse_tree

@ -0,0 +1,12 @@
#/usr/bin/env python
import sys
from gen_matlab import MatlabWrapperGenerator
# get the IO from the command line arguments
input_files = sys.argv[1:-1]
output_dir = sys.argv[-1]
# create the generator
mwg = MatlabWrapperGenerator()
mwg.gen(input_files, output_dir)

@ -0,0 +1,182 @@
from string import join
from textwrap import fill
class ParseTree(object):
def __init__(self, namespaces=[]):
self.namespaces = namespaces
def __str__(self):
return join((ns.__str__() for ns in self.namespaces), '\n\n\n')
def build(self, namespaces):
babel = Translator()
for name, definitions in namespaces.items():
class_tree = {}
functions = []
constants = []
for defn in definitions:
obj = babel.translate(defn)
if type(obj) is Class or obj.clss:
self.insertIntoClassTree(obj, class_tree)
elif type(obj) is Function:
functions.append(obj)
elif type(obj) is Constant:
constants.append(obj)
else:
raise TypeError('Unexpected object type: '+str(type(obj)))
self.namespaces.append(Namespace(name, class_tree.values(), functions, constants))
def insertIntoClassTree(self, obj, class_tree):
cname = obj.name if type(obj) is Class else obj.clss
if not cname:
return
if not cname in class_tree:
# add a new class to the tree
class_tree[cname] = Class(cname)
# insert the definition into the class
val = class_tree[cname]
if type(obj) is Function:
val.functions.append(obj)
elif type(obj) is Constant:
val.constants.append(obj)
else:
raise TypeError('Unexpected object type: '+str(type(obj)))
class Translator(object):
def translate(self, defn):
# --- class ---
# classes have 'class' prefixed on their name
if 'class' in defn[0]:
return self.translateClass(defn)
# --- function ---
# functions either need to have input arguments, or not uppercase names
elif defn[3] or not self.translateName(defn[0]).isupper():
return self.translateFunction(defn)
# --- constant ---
else:
return self.translateConstant(defn)
def translateClass(self, defn):
return Class()
def translateFunction(self, defn, class_tree=None):
name = self.translateName(defn[0])
clss = self.translateClassName(defn[0])
rtp = defn[1]
args = defn[3]
req = []
opt = []
for arg in args:
if arg:
a = self.translateArgument(arg)
opt.append(a) if a.default else req.append(a)
return Function(name, clss, '', rtp, False, req, opt)
def translateConstant(self, defn):
const = True if 'const' in defn[0] else False
name = self.translateName(defn[0])
clss = self.translateClassName(defn[0])
tp = 'int'
val = defn[1]
return Constant(name, clss, tp, const, '', val)
def translateArgument(self, defn):
tp = defn[0]
name = defn[1]
default = tp+'()' if defn[2] else ''
return Argument(name, tp, False, '', default)
def translateName(self, name):
return name.split(' ')[-1].split('.')[-1]
def translateClassName(self, name):
parts = name.split('.')
return parts[1] if len(parts) == 3 else ''
class Namespace(object):
def __init__(self, name='', constants=None, classes=None, functions=None):
self.name = name
self.constants = constants if constants else []
self.classes = classes if classes else []
self.functions = functions if functions else []
def __str__(self):
return 'namespace '+self.name+' {\n\n'+\
(join((c.__str__() for c in self.constants), '\n')+'\n\n' if self.constants else '')+\
(join((f.__str__() for f in self.functions), '\n')+'\n\n' if self.functions else '')+\
(join((c.__str__() for c in self.classes), '\n\n') if self.classes else '')+'\n};'
class Class(object):
def __init__(self, name='', namespace='', constants=None, functions=None):
self.name = name
self.namespace = namespace
self.constants = constants if constants else []
self.functions = functions if functions else []
def __str__(self):
return 'class '+self.name+' {\n\t'+\
(join((c.__str__() for c in self.constants), '\n\t')+'\n\n\t' if self.constants else '')+\
(join((f.__str__() for f in self.functions), '\n\t') if self.functions else '')+'\n};'
class Function(object):
def __init__(self, name='', clss='', namespace='', rtp='', const=False, req=None, opt=None):
self.name = name
self.clss = clss
self.const = const
self.namespace = namespace
self.rtp = rtp
self.req = req if req else []
self.opt = opt if opt else []
def __str__(self):
return fill((self.rtp+' ' if self.rtp else '')+(self.clss+'::' if self.clss else '')+self.name+'('+\
join((arg.__str__() for arg in self.req+self.opt), ', ')+\
')'+(' const' if self.const else '')+';', 80, subsequent_indent=('\t\t' if self.clss else '\t'))
class Argument(object):
def __init__(self, name='', tp='', const=False, ref='', default=''):
self.name = name
self.tp = tp
self.ref = ref
self.const = const
self.default = default
def __str__(self):
return ('const ' if self.const else '')+self.tp+self.ref+\
' '+self.name+('='+self.default if self.default else '')
class Constant(object):
def __init__(self, name='', clss='', tp='', const=False, ref='', default=''):
self.name = name
self.clss = clss
self.tp = tp
self.ref = ref
self.const = const
self.default = default
def __str__(self):
return ('const ' if self.const else '')+self.tp+self.ref+\
' '+self.name+('='+self.default if self.default else '')+';'
def todict(obj, classkey=None):
if isinstance(obj, dict):
for k in obj.keys():
obj[k] = todict(obj[k], classkey)
return obj
elif hasattr(obj, "__iter__"):
return [todict(v, classkey) for v in obj]
elif hasattr(obj, "__dict__"):
data = dict([(key, todict(value, classkey))
for key, value in obj.__dict__.iteritems()
if not callable(value) and not key.startswith('_')])
if classkey is not None and hasattr(obj, "__class__"):
data[classkey] = obj.__class__.__name__
return data
else:
return obj
Loading…
Cancel
Save