def resolve_local_type(var, node): """Resolve the var in any nodes before `node` Will search for `decl_stmt` or `params` Return type name if found. """ while node and node.previousSibling: node = node.previousSibling if domutil.is_element(node): # won't search beyond function. That will resolved as global variable if node.tagName == 'function': return None if node.tagName == 'decl_stmt': type_name,var_name,_ = syntaxutil.parse_decl_stmt(node) if var == var_name: return type_name elif node.tagName == 'parameter_list': # if reach function's parameter list, search params, if fail, then stop params = syntaxutil.parse_parameter_list(node) for type_name,var_name in params: if var == var_name: return type_name if node and node.parentNode: return resolve_local_type(var, node.parentNode) else: return None
def resolve_alive_vars(node, resolved): """Resolve all alive vars at this node. :return {var: type} """ result = {} if node.previousSibling: node = node.previousSibling if domutil.is_element(node): if node.tagName == 'decl_stmt': type_name,var_name,_ = syntaxutil.parse_decl_stmt(node) if var_name not in result: result[var_name] = type_name elif node.tagName == 'parameter_list': params = syntaxutil.parse_parameter_list(node) for type_name,var_name in params: if var_name not in result: result[var_name] = type_name elif node.parentNode: node = node.parentNode else: return {} more = resolve_alive_vars(node, resolved | result.keys()) for key in more: if key not in result: result[key] = more[key] return result
def func(directory): for root,_,files in os.walk(directory): for f in files: if f.endswith('.c'): filename = os.path.join(root, f) print(filename) with tempfile.TemporaryFile() as fp: with open(filename) as f: change_count = 0 for line in f: if line.strip().endswith(';') and ',' in line: if line.count('(') == line.count(')'): doc = domutil.get_doc_from_code(line) unit_nodes = doc.getElementsByTagName('unit') unit_node = unit_nodes.item(0) decl_stmt_node = domutil.get_first_child_by_tagname(unit_node, 'decl_stmt') if domutil.is_element(decl_stmt_node) and decl_stmt_node.tagName == 'decl_stmt': decl_nodes = domutil.get_children_by_tagname(decl_stmt_node, 'decl') if len(decl_nodes) > 1: change_count+=1 # result = syntaxutil.parse_decl_stmt_code(line) full_type = get_type(line) # FIXME job *job, *sj = deserializeJob(nextjob,remlen,&nextjob,SER_MESSAGE); if full_type and '(' not in line: variables = line.split(',')[:] var1 = variables[0] line = var1 + ';\n' + ';\n'.join([full_type + ' ' + var for var in variables[1:]]) fp.write(line.encode('utf8')) print('made '+str(change_count)+' changes to file: ' + filename) fp.seek(0) content = fp.read().decode('utf8') with open(filename, 'w') as f: f.write(content)
def parse_decl_stmt(node): """Parse a <decl_stmt> node. Assume only one variable can be in the statement(guranteed by decl spliter preprocessor). :return (type, name, init) """ assert(domutil.is_element(node) and node.tagName == 'decl_stmt') decl_node = domutil.get_first_child_by_tagname(node, 'decl') return parse_decl(decl_node)
def get_annotation_segment(node): """from HeliumStart to HeliumStop """ node_list = [node] while node.nextSibling: node = node.nextSibling node_list.append(node) if domutil.is_element(node) and node.tagName == 'comment': comment_text = domutil.get_text_content(node) if '@HeliumStop' in comment_text: break return node_list
def parse_parameter_list(node): """Parse a <parameter_list> of a function. :return ((type1,var1), (type2,var2), ...) """ assert(domutil.is_element(node) and node.tagName == 'parameter_list') result = [] for param_node in domutil.get_children_by_tagname(node, 'param'): decl_node = domutil.get_first_child_by_tagname(param_node, 'decl') if decl_node: type_name,var_name,_ = parse_decl(decl_node) result.append((type_name, var_name)) return result
def parse_for_init(node): """Parse init statement in for. Assume only one variable in decl. :return (type1,var1) """ assert(domutil.is_element(node) and node.tagName == 'init') decl_node = domutil.get_first_child_by_tagname(node, 'decl') if decl_node: type_name, var_name, _ = parse_decl(decl_node) return (type_name, var_name) else: return (None, None)
def parse_function(node): """parse a <function> node. :return (type_name, function_name, ((type1, param1), (type2, param2), ...)) """ assert(domutil.is_element(node) and node.tagName == 'function') type_node = domutil.get_first_child_by_tagname(node, 'type') name_node = domutil.get_first_child_by_tagname(node, 'name') parameter_list_node = domutil.get_first_child_by_tagname(node, 'parameter_list') type_name = domutil.get_text_content(type_node) name = domutil.get_text_content(name_node) params = parse_parameter_list(parameter_list_node) return (type_name, name, params)
def get_segment_nodes(doc): """Get nodes between //@HeliumStart and //@HeliumStop :return a list of nodes """ comment_node = get_comment_node_by_annotation(doc, '@HelumStart') if not comment_node: return [] results = [] node = comment_node while node.nextSibling: node = node.nextSibling if domutil.is_element(node): results.append(node) if '@HeliumStop' in domutil.get_text_content(node): return results return None
def get_input_nodes(doc): """Get nodes between //@HeliumInput and //@HeliumInputEnd :return a list of nodes """ comment_node = get_comment_node_by_annotation(doc, '@HeliumInput') if not comment_node: return [] results = [] node = comment_node while node.nextSibling: node = node.nextSibling if domutil.is_element(node): if node.tagName == 'decl_stmt': results.append(node) elif '@HeliumInputEnd' in domutil.get_text_content(node): return results return None
def parse_struct(node): """Parse a <struct> node Do not anonymous inner enum, union or structs. :return (name, [(type1, field1), (type1, field1), ...]) """ assert(domutil.is_element(node) and node.tagName == 'struct') name_node = domutil.get_first_child_by_tagname(node, 'name') block_node = domutil.get_first_child_by_tagname(node, 'block') if name_node: name = domutil.get_text_content(name_node) else: name = '' fields = [] for decl_stmt_node in domutil.get_children_by_tagname(block_node, 'decl_stmt'): decl = parse_decl_stmt(decl_stmt_node) fields.append(decl[0:2]) return (name, fields)
def get_undefined_vars(nodes, resolved): """Get undefined variable. :param nodes: a list of dom nodes :param resolved: a set of names as strings that is assumed to be defined :return a set of names """ result = set() for node in nodes: if domutil.is_element(node): if node.tagName == 'decl_stmt': _,var_name,_ = syntaxutil.parse_decl_stmt(node) resolved.add(var_name) elif node.tagName == 'expr': # in #ifdef, there may be `#elif defined(__sun)` if domutil.in_node(node, 'cpp:ifdef', level=2) or\ domutil.in_node(node, 'cpp:elif', level=2) or\ domutil.in_node(node, 'cpp:ifndef', level=2): continue name_set = syntaxutil.parse_expr(node) for name in name_set: # uint8_t, false, true, NULL if sys.resolve_single(name): continue # here we find the undefined variable if name not in resolved and name not in result: result.add(name) elif node.tagName == 'for': init_node = domutil.get_first_child_by_tagname(node, 'init') if init_node: _, var = syntaxutil.parse_for_init(init_node) if var: resolved.add(var) elif node.tagName == 'parameter_list': params = syntaxutil.parse_parameter_list(node) for _,name in params: resolved.add(name) elif node.tagName == 'cpp:define': value_node = domutil.get_first_child_by_tagname(node, 'cpp:value') text = domutil.get_text_content(value_node) match = re.findall(r'([A-Z_]{2,})', text) for m in match: if m not in resolved: result.add(m) new_result = get_undefined_vars(node.childNodes, resolved | result) result.update(new_result) return result
def parse_decl(node): """Parse a <decl> node. Assume only one variable can be in the statement(guranteed by decl spliter preprocessor). :return (type,name,init) """ assert(domutil.is_element(node) and node.tagName == 'decl') type_node = domutil.get_first_child_by_tagname(node, 'type') name_node = domutil.get_first_child_by_tagname(node, 'name') type_name = domutil.get_text_content(type_node) var_name = domutil.get_text_content(name_node) if '[' in var_name: new_var_name = var_name[:var_name.find('[')] new_type_name = type_name + var_name[var_name.find('['):] var_name = new_var_name type_name = new_type_name # TODO init return (type_name, var_name, None)
def parse_expr(node): """Parse a <expr> :retrn a set of variable names used. :bug it=(item*)ptr; the type cast will be recognized as name :bug there may be <expr> inside <expr> """ assert(domutil.is_element(node) and node.tagName == 'expr') name_nodes = domutil.get_children_by_tagname(node, 'name') names = set() for name_node in name_nodes: name = domutil.get_text_content(name_node) # TODO move array related code into util names.add(simplify_variable_name(name)) # for a->b double_name_node = domutil.get_first_child_by_tagnames(node, 'name', 'name') if double_name_node: name = domutil.get_text_content(double_name_node) names.add(simplify_variable_name(name)) return names
def parse_typedef(node): """Parse a <typedef> node <typedef>typedef <type>struct <name>A</name> *</type> <name>hello_t</name>;</typedef> <typedef>typedef <type><struct>struct <name>_stritem</name> <block> ... </struct></type> <name>item</name>;</typedef> :return (alias, original) """ assert(domutil.is_element(node) and node.tagName == 'typedef') type_node = domutil.get_first_child_by_tagname(node, 'type') # support <function_decl> in <typedef>, i.e. typdef void *func(int a, int b) # return: (func, '') if not type_node: function_decl_node = domutil.get_first_child_by_tagname(node, 'function_decl') name_node = domutil.get_first_child_by_tagname(function_decl_node, 'name') alias = domutil.get_text_content(name_node) return (alias.strip(), '') name_node = domutil.get_first_child_by_tagname(node, 'name') original = domutil.get_text_content_except(type_node, 'block') alias = domutil.get_text_content(name_node) return (alias.strip(), original.strip())
def resolve_undefined_vars(nodes, resolved): """Get undefined variable. Resolve its type. :param nodes: a list of dom nodes :param resolved: a set of names as strings that is assumed to be defined :return {var: type, ...} """ result = {} for node in nodes: if domutil.is_element(node): if node.tagName == 'decl_stmt': _,var_name,_ = syntaxutil.parse_decl_stmt(node) resolved.add(var_name) elif node.tagName == 'expr': # in #ifdef, there may be `#elif defined(__sun)` if domutil.in_node(node, 'cpp:ifdef', level=2) or\ domutil.in_node(node, 'cpp:elif', level=2) or\ domutil.in_node(node, 'cpp:ifndef', level=2): continue name_set = syntaxutil.parse_expr(node) for name in name_set: # uint8_t, false, true, NULL if sys.resolve_single(name): continue # here we find the undefined variable if name not in resolved and name not in result: type_name = resolve_local_type(name, node) if type_name: result[name] = type_name # if it is a global variable, do not print warning elif not local.check_global_variable(name): logger.warning('undefind variable ' + name + ' not resovled for local type.') elif node.tagName == 'for': init_node = domutil.get_first_child_by_tagname(node, 'init') if init_node: _, var = syntaxutil.parse_for_init(init_node) if var: resolved.add(var) new_result = resolve_undefined_vars(node.childNodes, resolved | result.keys()) result.update(new_result) return result
def instrument_segment(doc, segment): first_node = segment[0] last_node = segment[-1] parent = first_node.parentNode pre = doc.createElement('comment') pre.appendChild(doc.createTextNode('\n//@Pre\n')) parent.insertBefore(pre, first_node) post = doc.createElement('comment') post.appendChild(doc.createTextNode('\n//@Post\n')) parent.insertBefore(post, last_node.nextSibling) segment.insert(0, pre) segment.append(post) # loop invariant if config.get('instrument_loop') == 'true': for node in segment: if domutil.is_element(node) and node.tagName == 'for' or node.tagName == 'while': block_node = domutil.get_first_child_by_tagname(node, 'block') if not block_node: continue inner = doc.createElement('comment') inner.appendChild(doc.createTextNode('\n//@Inner\n')) block_node.insertBefore(inner, block_node.lastChild) return segment