def __init__(self): # read enums filepath = 'db_ic.h' allData = self.readFile(filepath) cppheader = CppHeader(allData, argType='string') self.devices = cppheader.enums[0].get('values') data = allData.split('};')[2].split('\n') r = r"{(.*),(.*),(.*)}" for line in data: try: items = [x.strip() for x in re.search(r, line).groups()] self.addPropToDevice(items[0].strip(), 'phys_max', items[1].strip()) self.addPropToDevice(items[0].strip(), 'phys_min', items[2].strip()) except AttributeError: pass treeData = allData.split('};')[1] self.parseTree(treeData)
def parse_header(self, path: str, c_include_path: str): with open(path) as f: data = self.preprocess_header(f.read()) header = CppHeader(data, 'string') self.parse_typedefs(c_include_path, header.typedefs) self.parse_enums(c_include_path, header.enums) self.parse_classes_and_structs(c_include_path, header.classes) self.parse_functions(c_include_path, header.functions)
def parse_header(self, path: str, c_include_path: str): try: with self.context('header', path, c_include_path): with open(path) as f: data = self.preprocess_header(f.read()) header = CppHeader(data, 'string') self.parse_typedefs(c_include_path, header.typedefs) self.parse_enums(c_include_path, header.enums) self.parse_classes_and_structs(c_include_path, header.classes) self.parse_functions(c_include_path, header.functions) except Exception as e: raise ParseError(self.context) from e
def __init__(self, module_name, original_text): self.module_name = module_name self.original_text = original_text self.use_generated_header = True with open('temp.c', 'w') as f: f.write(original_text) self.cpp_header = CppHeader('temp.c') self.cpp_file = "{}.cpp".format(module_name) if os.path.isfile(self.cpp_file): os.remove(self.cpp_file) self.hpp_file = "{}.hpp".format(module_name) if os.path.isfile(self.hpp_file): os.remove(self.hpp_file) self.generate_cpp() self.generate_hpp()
def __init__(self, module_name, original_text): try: from CppHeaderParser import CppHeader except ImportError: raise ImportError("Requires CppHeaderParser to be installed.") self.module_name = module_name self.original_text = original_text self.use_generated_header = True with open('temp.c', 'w') as f: f.write(original_text) self.cpp_header = CppHeader('temp.c') self.cpp_file = "{}.cpp".format(module_name) if os.path.isfile(self.cpp_file): os.remove(self.cpp_file) self.hpp_file = "{}.hpp".format(module_name) if os.path.isfile(self.hpp_file): os.remove(self.hpp_file) self.generate_cpp() self.generate_hpp()
def read_robot_config(robot_name): header = CppHeader(header_path('SL_user.h', robot_name)) defines, enums = parse_defines(header, include_enums=True) defines = replace_defines(defines, _defines) defines.update(_defines) return { 'joints': [enums['RobotDOFs'][i + 1] for i in range(defines['N_DOFS'])], 'endeffectors': [ enums['RobotEndeffectors'][i + 1] for i in range(defines['N_ENDEFFS']) ], 'links': [enums['RobotLinks'][i + 1] for i in range(defines['N_LINKS'])], 'defines': defines, 'enums': enums, }
def _load(module): if len(_defines): return with open(header_path(), 'r') as fp: header_file = fp.read() header = CppHeader(header_file, argType='string') defines = parse_defines(header) setattr(modules[module], 'SEM_ID', ctypes.c_long) types = {'SEM_ID': ctypes.c_long} for struct_name in header.classes.keys(): fields = read_struct_format(header_file, struct_name, defines=defines) struct_type = type(struct_name, (CStruct, ), {'_fields_': fields}) setattr(modules[module], struct_name, struct_type) types[struct_name] = struct_type _defines.update(defines) _types.update(types)
def main(): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('--msg-dir', type=str, metavar='DIR', default='msg', help='Directory to write (updated) msg files to') parser.add_argument('HDR', help='Path to Ruckig input_parameter.hpp') args = parser.parse_args() msg_dir = os.path.abspath(args.msg_dir) if not os.path.isdir(msg_dir): sys.stderr.write( f"Can't seem to find the 'msg' dir at '{msg_dir}', aborting\n") sys.exit(1) parsed_h = CppHeader(args.HDR) if not parsed_h.enums: sys.stderr.write( f"No enums found in header (is this the correct header?), aborting\n" ) sys.exit(2) # we expect at least some enums we know in there flambda = lambda enum: enum['name'] in ['Result', 'DurationDiscretization'] if not list(filter(flambda, parsed_h.enums)): sys.stderr.write( "Probably not a Ruckig header (could not find any known enums), " "aborting\n") sys.exit(3) parse_stamp = datetime.datetime.now().isoformat() source_file = os.path.abspath(args.HDR) for enum in parsed_h.enums: sys.stdout.write(f"Processing '{enum['name']}': ") ename = enum['name'] efilename = f'{ename}.msg' edoxy = enum.get('doxygen', '').replace('//!', '').strip() etype = cpp_type_to_ros_msg_idl_type(enum['type']) # InternalState.msg already exists, and is not auto-generated if ename == 'InternalState': raise ValueError( "Conflict with existing InternalState message, aborting") enum_vals = [] for val in enum['values']: enum_vals.append({ 'name': to_snake_case(val['name']).upper(), 'doxy': val.get('doxygen', '').replace('///<', '').strip(), 'val': str(val['value']).replace(' ', '').strip(), 'type': etype, }) outputf = f'{msg_dir}/{efilename}' print(f"writing {len(enum_vals)} constants to '{outputf}' ..") with open(outputf, 'w') as fout: tdict = { 'source_file': source_file, 'stamp': parse_stamp, 'enum_name': ename, 'enum_doxy': edoxy, } write_msg_file(tdict, enum_vals, fout) print(f"Generated {len(parsed_h.enums)} messages")
def parse_and_extract_type_info(code): """ Parse header code and return declared types, used types, and any bases """ used_types = set() declared_types = OrderedDict() # Use CppHeader to extract cppheader = CppHeader(code, argType="string") # Collect used types from the code used_types = set() # Iterate over typedefs and collect types for typedef in cppheader.typedefs: if "dolfin::" in typedef: typedef = typedef.replace("dolfin::", "") # Store type information declared_types[typedef] = [] # Iterate over free functions and collect dependant types for function in cppheader.functions: # Check return type if function["rtnType"] != "void": used_types.update(strip_templates(function["rtnType"])) # Check argument types for argument in function["parameters"]: used_types.update(strip_templates(argument["type"])) # Iterate over classed and collect info for class_name, class_repr in cppheader.classes.items(): # Check if class is private if class_repr["parent"] is not None: continue # Get bases bases = set() for base in class_repr["inherits"]: bases.update(strip_templates(base["class"])) # Remove itself from any bases bases.difference_update([class_name]) # Register the class declared_types[class_name] = list(bases) # Iterate over public properties for prop in class_repr["properties"]["public"]: used_types.update(strip_templates(prop["type"])) # Iterate over methods and collect dependant types for method in class_repr["methods"]["public"]+\ class_repr["methods"]["protected"]: # Check return type if method["rtnType"] != "void": used_types.update(strip_templates(method["rtnType"])) # Check argument types for argument in method["parameters"]: used_types.update(strip_templates(argument["type"])) # Remove any self dependencies used_types = set(used_type for used_type in used_types if class_name not in used_type) return used_types, declared_types
if (len(sys.argv) < 4): print("gen.py output include_directory input files ...") exit(1) handle = "m" fout = sys.argv[1] includedir = sys.argv[2] fsin = sys.argv[3:] out = [] includes = [] for fname in fsin: includes.append(fname) hdr = CppHeader(os.path.join(includedir, fname)) # note .strip("::"), inconsistent behavior for classes vs enum/func for data in hdr.enums: ns = data["namespace"].strip("::") # bug? in parser out.append(create_enum_bindigs(data, [ns], handle) + ";") for data in hdr.classes.values(): ns = data["namespace"] # workaround: parser does not save debug in same way as for funcs data["debug"] = read_line(data["filename"], data["line_number"]) if "PY_SINGLETON_OBJECT" in data["debug"]: out.append( create_singleton_bindings("instance_" + data["name"], data, [ns], handle, False))
#!/usr/bin/env python import pprint import sys sys.path = ["../"] + sys.path from CppHeaderParser import CppHeader, CppParseError try: cppHeader = CppHeader("SampleClass.h") except CppParseError as e: print(e) sys.exit(1) print("CppHeaderParser view of %s" % cppHeader) sampleClass = cppHeader.classes["SampleClass"] print("Number of public methods %d" % (len(sampleClass["methods"]["public"]))) print("Number of private properties %d" % (len(sampleClass["properties"]["private"]))) meth3 = [m for m in sampleClass["methods"]["public"] if m["name"] == "meth3"][0] # get meth3 meth3ParamTypes = [t["type"] for t in meth3["parameters"]] # get meth3s parameters print("Parameter Types for public method meth3") pprint.pprint(meth3ParamTypes) print("\nReturn type for meth1:") print(cppHeader.classes["SampleClass"]["methods"]["public"][1]["rtnType"]) print("\nDoxygen for meth2:") print(cppHeader.classes["SampleClass"]["methods"]["public"][2]["doxygen"])
file.write(');\n') file.write('\tdisable_lib(id);\n') file.write('\t//Sanitize data here:\n') file.write('\t\n') if not ('void' in rtrn_type and '*' not in rtrn_type): file.write('\treturn ret;\n') file.write('}\n') sys.path = ["../"] + sys.path from CppHeaderParser import CppHeader, CppParseError file_name = sys.argv[1] try: cppHeader = CppHeader(file_name) except CppParseError as e: print(e) sys.exit(1) #print("CppHeaderParser view of %s" % cppHeader) print("\nFree functions are:") for func in cppHeader.functions: print("name %s" % func["name"]) print("type %s" % func["rtnType"]) #print(" %s" % func["parameters"]) for param in func["parameters"]: print("param name: %s" % param['name']) print("param is pointer: %s" % param['pointer']) print("param type: %s" % param['type'])
def createSIP(headerFile, sipDir, headerTemplate): print("Processing file: ", headerFile) def checkRanges(lineNumber): for r in skip_ranges: if r[0] <= lineNumber <= r[1]: return True return False def createMethods(s, methods, includeConstructors=True): for method in methods: if method['constructor'] and not includeConstructors: continue if checkRanges(method['line_number']): print("SKIP:", method['name'], method['line_number']) continue line = " " if method['virtual']: line += "virtual " if method['explicit']: line += "explicit " if not (method['constructor'] or method['destructor']): rtnType = method['rtnType'].replace('inline ', '') line += rtnType if not rtnType.endswith('*'): line += ' ' if method['destructor']: line += '~' line += method['name'] + '(' parameters = [] for param in method['parameters']: param_str = "" if param['constant']: param_str += 'const ' paramType = param['raw_type'] if paramType.startswith('::'): paramType = paramType[2:] param_str += paramType if param['pointer']: param_str += " *" elif param['reference']: param_str += " &" else: param_str += " " param_str += param['name'] if method['constructor'] and 'parent' in param['name'].lower(): param_str += " /TransferThis/" if 'defaultValue' in param: param_str += ' = ' + param['defaultValue'] parameters.append(param_str) line += ", ".join(parameters) line += ")" if method['const']: line += " const" line += ';\n' s.write(line) s.write("\n") headerFileStr = open(headerFile, 'r').read() ### Pre-Parse ### This is kind of like Qt's MOC - we're basically removing/replacing ### all of Qt's macro's to make the code straight C++. headerFileStr = headerFileStr.replace("Qt::UserRole", "32") ### We *really* don't need the following headerFileStr = headerFileStr.replace('Q_OBJECT', '') headerFileStr = headerFileStr.replace('Q_INVOKABLE', '') for macro in ('Q_PRIVATE_SLOT', 'Q_PROPERTY', 'Q_ENUMS', 'Q_FLAGS', 'Q_DECLARE_PUBLIC'): start = headerFileStr.find('{}('.format(macro)) declarations = [] while start >= 0: end = headerFileStr.find('\n', start) + 1 declarations.append(headerFileStr[start:end]) start = headerFileStr.find('{}('.format(macro), end) for declaration in declarations: headerFileStr = headerFileStr.replace(declaration, '') ### Remember which enums are declared via Q_DECLARE_FLAGS for later and then remove ### the declaration. declare_flags = {} start = headerFileStr.find("Q_DECLARE_FLAGS(") declarations = [] while start >= 0: end = headerFileStr.find(")", start) + 1 declarations.append(headerFileStr[start:end]) declareFlags = headerFileStr[start:end].replace( "Q_DECLARE_FLAGS(", '').replace(')', '') flags, enum = declareFlags.replace(' ', '').split(',') declare_flags[enum] = flags start = headerFileStr.find("Q_DECLARE_FLAGS(", end) for declaration in declarations: headerFileStr = headerFileStr.replace(declaration, '') ### Remember which enums have operators declared via Q_DECLARE_OPERATORS_FOR_FLAGS ### for later and then remove the declaration. declare_operators = {} start = headerFileStr.find("Q_DECLARE_OPERATORS_FOR_FLAGS(") declarations = [] while start >= 0: end = headerFileStr.find(")", start) + 1 declarations.append(headerFileStr[start:end]) declareOperators = headerFileStr[start:end].replace( "Q_DECLARE_OPERATORS_FOR_FLAGS(", '').replace(')', '') ns, flags = declareOperators.replace(' ', '').strip().split('::') for enum, f in declare_flags.items(): if f == flags: break else: raise Exception(ns, flags) declare_operators[ns] = enum start = headerFileStr.find("Q_DECLARE_OPERATORS_FOR_FLAGS(", end) for declaration in declarations: headerFileStr = headerFileStr.replace(declaration, '') ### Remember which classes are decalred as private via Q_DECLARE_PRIVATE and then ### remove the declaration declare_private = [] start = headerFileStr.find("Q_DECLARE_PRIVATE(") declarations = [] while start >= 0: end = headerFileStr.find(")", start) + 1 declarations.append(headerFileStr[start:end]) declarePrivate = headerFileStr[start:end].replace( "Q_DECLARE_PRIVATE(", '').replace(')', '') declare_private.append(declarePrivate) start = headerFileStr.find("Q_DECLARE_PRIVATE(", end) for declaration in declarations: headerFileStr = headerFileStr.replace(declaration, '') ### Remember which classes have copying disabled via Q_DECLARE_COPY and then ### remove the declaration disable_copy = [] start = headerFileStr.find("Q_DISABLE_COPY(") declarations = [] while start >= 0: end = headerFileStr.find(")", start) + 1 declarations.append(headerFileStr[start:end]) disableCopy = headerFileStr[start:end].replace("Q_DISABLE_COPY(", '').replace(')', '') disable_copy.append(disableCopy) start = headerFileStr.find("Q_DISABLE_COPY(", end) for declaration in declarations: headerFileStr = headerFileStr.replace(declaration, '') ### Read header file as lines rather than single string #with open(headerFile, 'r') as f: # headerLines=f.readlines() headerLines = headerFileStr.split('\n') ### Make a list of export symbols and exported objects... exports = [] export_symbols = [] for line in headerLines: if '_EXPORT' not in line or line.strip().startswith('//'): continue pieces = line.strip().replace(":", '').replace('{', '').split(' ') assert '_EXPORT' in pieces[1] export_symbols.append(pieces[1]) exports.append(pieces[2]) ### ... then remove symbols to simplify parsing for sym in set(export_symbols): headerFileStr = headerFileStr.replace(sym, '') ### Parse header try: cppHeader = CppHeader(headerFileStr, argType="string") except CppHeaderParser.CppParseError as e: print(e) exit(1) ### 'Process' pre-processor macros... conditionals = cppHeader.conditionals[1:-1] _conditionals = [] for n, line in enumerate(headerLines): if not line.strip().startswith(('#if', '#else', '#endif')): continue if line.strip() not in conditionals: continue try: assert line.strip() == conditionals[0] except AssertionError: print("CONDITIONALS:", n, line.strip(), conditionals) print(headerFileStr) raise _conditionals.append((conditionals.pop(0), n + 1)) defines = ['USE_QFILEDIALOG_OPTIONS'] skip = True start, stop = None, None skip_ranges = [] for condition, n in _conditionals: if condition.startswith('#if'): pieces = condition.strip().split() cond, name = pieces[:2] check = False if name == 'QT_VERSION': assert len(pieces) >= 4 operator, version = pieces[2:4] assert operator in ('>', '>=', '<', '<=') if 'QT_VERSION_CHECK' in version: version = ''.join(pieces[3:]) version = version.replace('QT_VERSION_CHECK(', '').replace(')', '') version = '0x' + ''.join(version.split(',')) + '00' check = eval("{}{}{}".format(QT_VERSION, operator, version)) if (name in defines or check) and cond == '#ifdef': skip = False elif (name in defines and cond == '#ifndef'): skip = True if skip: start = n elif condition.startswith('#else'): skip = not skip if skip: start = n else: stop = n elif condition.startswith('#endif'): if skip: stop = n if not skip: skip = True else: raise Exception if start and stop: skip_ranges.append((start, stop)) start, stop = None, None sipFile = os.path.splitext(os.path.split(headerFile)[1])[0] + '.sip' sipFile = os.path.abspath(os.path.join(sipDir, sipFile)) sipIncludes = [] exported_objects = [] s = StringIO() ### NAMESPACES namespace_funtions = {} for function in cppHeader.functions: if not len(function['namespace']): continue namespace = function['namespace'].replace(':', '') namespace_funtions.setdefault(namespace, []).append(function) for namespace, functions in namespace_funtions.items(): print(" namespace: ", namespace) s.write('namespace {} {{\n\n'.format(namespace)) ## TYPEHEADERCODE s.write("%TypeHeaderCode\n") s.write("#include \"{}\"\n".format(os.path.split(headerFile)[1])) s.write("%End\n\n") createMethods(s, functions) s.write('};\n\n') ### CLASSSES for className, classObject in cppHeader.classes.items(): if not className in exports: continue exported_objects.append(className) print(" object: ", className) ## DECLARATION declarationMethod = classObject['declaration_method'] declarationLine = "{} {} ".format(declarationMethod, className) inherits = classObject['inherits'] if len(inherits): declarationLine += ": " inheritStrings = [] for inherit in inherits: inheritStrings.append(inherit['access'] + " " + inherit['class']) if not inherit['class'].startswith('Q'): sipIncludes.append(inherit['class']) declarationLine += ', '.join(inheritStrings) declarationLine += " {" s.write(declarationLine) s.write('\n\n') ## TYPEHEADERCODE s.write("%TypeHeaderCode\n") s.write("#include \"{}\"\n".format(os.path.split(headerFile)[1])) s.write("%End\n\n") ## PUBLIC s.write("public:\n") for enum in classObject['enums']['public']: if checkRanges(enum['line_number']): print("SKIP:", enum.get('name', '[ENUM]'), enum['line_number']) continue s.write(" enum {} {{\n".format(enum.get('name', ''))) for value in enum['values']: _value = str(value['value']) if '+' in _value or '|' in _value: try: _value = eval(_value) except NameError: assert '|' in _value bits = _value.replace(' ', '').split('|') bits_vals = [] for v in enum['values']: if v['name'] in bits: bits_vals.append(str(v['value'])) _value = eval('|'.join(bits_vals)) s.write(" {}={},\n".format(value['name'], _value)) s.write(" };\n") if enum.get('name', None) in declare_flags: s.write(" typedef QFlags<{0}::{1}> {2};\n".format( className, enum['name'], declare_flags[enum['name']])) s.write('\n') methods = classObject['methods']['public'] createMethods(s, methods) ## PUBLIC SLOTS methods = classObject['methods']['public slots'] + classObject[ 'methods']['public Q_SLOTS'] if len(methods): s.write("public slots:\n") createMethods(s, methods) ## PROTECTED enums = classObject['enums']['protected'] methods = classObject['methods']['protected'] if len(methods) or len(enums): s.write("protected:\n") for enum in enums: s.write(" enum {} {{\n".format(enum.get('name', ''))) for value in enum['values']: _value = str(value['value']) if '+' in _value or '|' in _value: try: _value = eval(_value) except NameError: assert '|' in _value bits = _value.replace(' ', '').split('|') bits_vals = [] for v in enum['values']: if v['name'] in bits: bits_vals.append(str(v['value'])) _value = eval('|'.join(bits_vals)) s.write(" {}={},\n".format(value['name'], _value)) s.write(" };\n") if enum.get('name', None) in declare_flags: s.write(" typedef QFlags<{0}::{1}> {2};\n".format( className, enum['name'], declare_flags[enum['name']])) s.write('\n') createMethods(s, methods, includeConstructors=False) ## PROTECTED SLOTS methods = classObject['methods']['protected slots'] + classObject[ 'methods']['protected Q_SLOTS'] if len(methods): s.write("protected slots:\n") createMethods(s, methods) ## SIGNALS methods = classObject['methods']['signals'] + classObject['methods'][ 'Q_SIGNALS'] if len(methods): s.write("signals:\n") createMethods(s, methods) if className in declare_private or className in disable_copy: s.write("private:\n") if className in declare_private: s.write(' {0}(const {0} &);\n'.format(className)) if className in disable_copy: s.write(' {0} &operator=(const {0} &);\n'.format(className)) s.write("\n};\n\n") # if len(declare_operators): # for ns,enum in declare_operators.items(): # s.write("\nQFlags<{0}::{1}> operator|({0}::{1} f1, QFlags<{0}::{1}> f2);".format(ns,enum)) s.seek(0) sipFileStr = s.read().replace("Qt : : ", "Qt::") sipFileStr = sipFileStr.replace(' : : ', '::') if not len(sipFileStr) or sipFileStr.isspace(): return with open(sipFile, 'w') as ss: ss.write(headerTemplate.format(file_name=os.path.split(sipFile)[1])) ss.write('\n\n') if len(sipIncludes): for include in sipIncludes: if include in exported_objects: continue ss.write('%Include {}.sip\n'.format(include)) ss.write('\n') ss.write(sipFileStr)