def processfile(cfile): global extension node, ext = os.path.splitext(cfile) headername = node + ".h" print "mkheader - processing", cfile, "and" , headername infile = open(cfile, "rb") if infile is None: print "Enable to open", cfile sys.exit(0) varlist = [] # list of declarations funclist = [] # list of prototypes defdict = {} # define statements may be needed defflag = {} # flags for things to be inside header defline = {} # the original line linecount = 0 defcount = 0 # Pass 1 - Processing the C file # ------------------------------ # make a list of # - each function definition # - each global variable declaration (simple or array) # - make also a dictionary of define statements COMMENT = FALSE # This flag is true inside a comment INSBLK = FALSE # This one inside a function's body while(1): line = infile.readline() if not line: break linecount = linecount + 1 line = wstring.chop(line) # Removing line separators line = wstring.strip(line) # Removing spaces (with better strip) if len(line) == 0: continue # Empty line ignored # If we enter a comment block, remove it if not COMMENT: COMMENT = lexer.opencomment(line) if COMMENT: i = string.find(line, "/*") left = line[:i] while COMMENT: COMMENT = lexer.closecomment(line) if COMMENT: line = infile.readline() if not line: COMMENT = FALSE linecount = linecount + 1 if not COMMENT: i = string.find(line, "*/") right = line[i + 2:] line = left + right # If we are inside a compound block, skip the content # print linecount, ') [' + str(lexer.blocklevel) + ']', line if not INSBLK: INSBLK = lexer.openblock(line) if INSBLK: i = string.find(line, '{') left = line[:i] # Getting the code at left of { while(INSBLK): INSBLK = lexer.closeblock(line) if INSBLK: line = infile.readline() # Skipping the content linecount = linecount + 1 # print "skiping", lexer.blocklevel, wstring.chop(line) if not line: INSBLK = FALSE if not INSBLK: i = string.find(line, '}') right = line[i + 1:] # Getting the code at right of } line = left + right # "shortened" may change inside the call of the test functions if line is None: continue if line == "": continue # A define statement if line[0] == '#': # Define or pragma statement if line[0:7] == "#define": key, value = lexer.splitdefine(line) if key != None: defdict[key] = value # Add to dictionary defflag[key] = FALSE # By default not to be included in header defline[key] = line #print "define added", line, "value=", value continue if not lexer.isdefinition(line): continue #print "is typed", line # Simple keywords of type on the line if lexer.typeonly(line): while(1): next = infile.readline() if not next: break next = wstring.clean(next) if next == "": continue linecount = linecount + 1 line = line + ' ' + next break # A function prototype: ignore it if lexer.isprototype(line): continue # A function definition if lexer.isfunction(line) == TRUE: line = lexer.shortened #print "is function ", line # The heading may use several lines while string.find(line, ')') == -1: next = infile.readline() linecount = linecount + 1 if next == None: print "Error, function uncomplete" exit() next = wstring.chop(next) next = wstring.strip(next) line = line + next # Handling the old format with declarations on next lines if lexer.oldformat(line): #print "old format", line tlist = [] while(1): l = infile.readline() if not l: break linecount = linecount + 1 l = wstring.chop(l) l = wstring.strip(l) l = lexer.getdecl(l) if lexer.isvardef(l): tlist.append(l) else: break if '{' in l: break # Rebuilding the heading according to the new format line = lexer.argreplace(line, tlist) #print "args replace", line, "with list", tlist i = string.find(line, '{') if i != -1: line = line[:i] line = lexer.removecomment(line) line = lexer.addsemicolon(line) #print "append to funclist", line # There is no prototype for the main function funcname = lexer.getident(line) if funcname is None: print "Error in (" + linecount + ')', line sys.exit(0) funcname = string.lower(funcname) if funcname == "main": continue funclist.append(line) defcount = defcount + 1 #print line continue # An array declaration # is static, ignored # Removing from = to end of line # Adding each size parameter to defdict (done in processarray) # if initializer, become static for C++ line = lexer.getdecl(line) # removing extra codes if lexer.isarray(line): #print "is array", line # Udate defflag vlist = [] if lexer.multivar(line): vlist = lexer.splitvardef(line) #print "multivar", vlist else: vlist.append(line) for vardef in vlist: j = string.find(vardef, '=') k = string.find(vardef, ';') if k == -1: k = len(vardef) if j < k: vardef = vardef[:j] + ';' lexer.processarray(vardef, defdict, defflag) var = lexer.shortened #print "in main shortened", var var = lexer.addextern(var) varlist.append(var) #print "added array", var defcount = defcount + 1 #print line continue # A variable declaration if lexer.isvardef(line): #print "255 var", line vlist = [] if lexer.multivar(line): vlist = lexer.splitvardef(line) #print "multivar", vlist else: vlist.append(line) for vardef in vlist: j = string.find(vardef, '=') k = string.find(vardef, ';') if k == -1: k = len(vardef) if j < k: vardef = vardef[:j] + ';' var = lexer.addextern(vardef) varlist.append(var) #print "added var", var defcount = defcount + 1 #print line # end while infile.close() print linecount, "lines in", cfile # Pass 2 - Processing the header file # ----------------------------------- # I compare it with declarations extracted from the C source, # I replace changes from source into the header file. # I append missing declarations. # I join multi-lines declarations. # And I rewrite the header file. # Reading the file and removing end of file code if exists header = [] if os.path.exists(headername): hfile = open(headername, "rb") header = hfile.readlines() hfile.close # Removing EOF 0x1a ctrl-z is presents if len(header) != 0: l = header[-1] l = wstring.strip(l) if l < ' ': header = header[:-1] tmpheader = [] # For rebuilding the file defheader = {} # Define declarations inside header file rcount = 0 # Replacements kcount = 0 # Fully identical declaration matches = 0 # Declarations with same names COMMENT = FALSE # This flag is true inside a multiline comment INSDEF = FALSE # This one inside a define declaration INSBLK = FALSE # This one inside a compound block oldline = "" # Save line for multi-lines declarations for o in header: # Scanning the header file line = wstring.chop(o) # Remove annoying line separators if wstring.strip(line) == "": # Empty line, keep it tmpheader.append(line) continue # If we enter a comment block, append it and process other code if not COMMENT: if not lexer.embeddedcomment(line): COMMENT = lexer.opencomment(line) else: test = lexer.removecomment(line) if wstring.strip(test) == "": # Simple one-line comment tmpheader.append(line) continue # Inside comment, this is a multi-line comment if COMMENT: # Comment opened COMMENT = lexer.closecomment(line) # Always inside comment? # End of multi-line comment if not COMMENT: # Terminator reached i = string.find(line, "*/") if i == -1: print "Error in parsing header" sys.exit(0) tmpheader.append(line[:i+2]) line = line[i + 2:] # Keeping the code is exists # Start of multi-line comment if COMMENT: i = string.find(line, "/*") if i != -1: tmpheader.append(line[i:]) line = line[:i] else: tmpheader.append(line) # A line of the comment block continue line = wstring.strip(line) if line == "": continue # If we are inside a macro or pragma block, skip it if not INSDEF: INSDEF = lexer.opendef(line) if INSDEF: INSDEF = lexer.closedef(line) tmpheader.append(line) continue # If we are inside some block (struct, typedef), skip it if not INSBLK: INSBLK = lexer.openblock(line) if INSBLK: INSBLK = lexer.closeblock(line) tmpheader.append(line) continue # join declarations in splitted lines if (line[ -1 ] == ","): oldline = oldline + line continue else: if (oldline != ""): line = oldline + line oldline = "" # Define statements are memorized if line[0:7] == "#define": key, value = lexer.splitdefine(line) #print "in header", line, key, value if key != None: defheader[key] = value # Add to dictionary # Searching for var declarations in header file elif lexer.isvardecl(line): #print "var in header", line for n in varlist[:]: #print "in varlist", n #test = wstring.replace(line, "global", "static", FALSE) if lexer.samevar(line, n): # Same name #print "samevars", line, n matches = matches + 1 if lexer.vchanged(line, n): #print "vchanged" lexer.replace(line, n) # Replace, keep comments #print "replaced=", line line = lexer.shortened # old decl. in line replaced if DEBUG: print "replacing", n rcount = rcount + 1 else: kcount = kcount + 1 varlist.remove(n) break # exit for loop line = lexer.addextern(line) # adding "extern" if missing #print "new dec", line # Searching for function declaration elif lexer.isprototype(line): for n in funclist[:]: #print line, n if lexer.samefunction(line, n): # Same name matches = matches + 1 if lexer.fchanged(line, n): # Different returns or arguments lexer.replace(line, n) line = lexer.shortened if DEBUG: print "replacing", line rcount = rcount + 1 else: kcount = kcount + 1 funclist.remove(n) break # In all case, adding the line, either changed or not tmpheader.append(line) # Rewriting and completing the header file added = 0 k = defflag.keys() for d in k: #print "next key", d, defflag[d] if defflag[d] == TRUE: #print "defheader", defheader if not defheader.has_key(d): tmpheader.append(defline[d]) if DEBUG: print "adding", defline[d] for line in varlist: if lexer.isstatic(line): continue tmpheader.append(line) if DEBUG: print "adding", line added = added + 1 for line in funclist: tmpheader.append(line) if DEBUG: print "adding", line added = added + 1 # All done pos = headername.find(".") if (pos != -1): headername = headername[ : pos] headername += ".hpp" hfile = open(headername, "wb") for o in tmpheader: hfile.write(o + "\n") hfile.close() dummy, hname = os.path.split(headername) print "***", defcount, "declaration" + wstring.plural(defcount)+',' , matches, "in", hname + "," , kcount, "identical", rcount , "replaced", added, "added" print "" return
def processheader(headername): # Old header, .h or .hpp global classname node, dummy = os.path.splitext(headername) hpath = node + ".hpp" # Path of the new header .hpp dummy, classname = os.path.split(node) hname = classname + ".hpp" # Name of the new header print "mkclass - processing" , headername # Reading the file and removing end of file code if exists header = [] if os.path.exists(headername): hfile = open(headername, "rb") header = hfile.readlines() hfile.close # Removing EOF 0x1a ctrl-z is presents if len(header) != 0: l = header[-1] l = wstring.strip(l) if l < ' ': header = header[:-1] tmpheader = [] # For rebuilding the file sttname = "" COMMENT = FALSE # This flag is true inside a multiline comment INSDEF = FALSE # This one inside a define declaration INSBLK = FALSE # This one inside a compound block INSSTT = FALSE # this one inside a struct decl. INSTYP = FALSE # this one inside a typedef decl. TYPSTT = FALSE # inside a typedef of struct or enum # The first loop copies all defines, multiline macros, blocks # plus static vars and function for o in header: line = o if line == os.linesep: continue line = wstring.chop(line) # If we are inside a comment block, skip it if not COMMENT: COMMENT = lexer.opencomment(line) if COMMENT: COMMENT = lexer.closecomment(line) continue # macro statements are memorized if not INSDEF: INSDEF = lexer.opendef(line) if INSDEF: #print "opend def", line tmpheader.append(line) INSDEF = lexer.closedef(line) continue # instances of enum, struct are outside class if lexer.recordinstance(line): #print "record", line tmpheader.append(line) continue # Processing simple typedef if lexer.newtype(line): name = lexer.lastword(line) if name is None: print "Error no name in", line else: lexer.types.append(name) #print "typedef:", name #print "line", line tmpheader.append(line) continue # processing typdef of struct if not TYPSTT: if lexer.typedefstruct(line): TYPSTT = lexer.opentypedef(line) if TYPSTT: #print "inside typedef of struct", line name = None if lexer.typelevel == 0: # first line name = lexer.getident(line) if name != None: lexer.types.append(name) lexer.typstruct.append(name) #print "new type 1:", name, lexer.typstruct, line if TYPSTT: tmpheader.append(line) TYPSTT = lexer.closetypedef(line) if not TYPSTT: name = lexer.typename(line) if name != None: lexer.types.append(name) lexer.typstruct.append(name) #print "new type 2:" ,name, lexer.typstruct, line continue # processing compound typedef if not INSTYP: INSTYP = lexer.opentypedef(line) if INSTYP: #print "inside typedef", line name = None if lexer.typelevel == 0: # first line name = lexer.getident(line) if name != None: lexer.types.append(name) #print "new type 3:", name, line if INSTYP: tmpheader.append(line) INSTYP = lexer.closetypedef(line) if not INSTYP: name = lexer.typename(line) if name != None: lexer.types.append(name) #lexer.typstruct.append(name) #print "new type 4:" ,name, line continue # structs declarations and instances are kept outside class # as I consider they are ancestors of classes and objects if not INSSTT: INSSTT = lexer.openstruct(line) # test for start of struct if INSSTT: # found #print "inside struct", line name = None if lexer.structlevel == 0: name = lexer.structname(line) # get name if name != None: lexer.types.append(name) # add to types for good parsing lexer.typstruct.append(name) #print "new type 5:", name #print "line", line if INSSTT: # always inside struct INSSTT = lexer.closestruct(line) # test for end tmpheader.append(line) continue # Define are memorized if lexer.isdefine(line): tmpheader.append(line) continue # instances of typedef of struct are outside the class also # static vars remain global and are added to this list # the static modifier should be removed for C++ if lexer.isvardecl(line): #print "pass I - isvardecl", line if lexer.isglobal(line): line = lexer.removeglobal(line) tmpheader.append(lexer.addextern(line)) #print "global added", lexer.addextern(line) continue if lexer.istypstruct(line): tmpheader.append(line) continue # static function added to list if lexer.isglobal(line): if lexer.isprototype(line): tmpheader.append(line) # end of for # Second pass tmpheader.append("") tmpheader.append("class " + classname) tmpheader.append("{") tmpheader.append("public:") COMMENT = FALSE INSDEF = FALSE INSBLK = FALSE INSSTT = FALSE INSTYP = FALSE INUNION = FALSE # The second loop build a class and # copies all variables, functions, comments for o in header: line = wstring.chop(o) if line == None: break # Empty lines are kept if wstring.strip(line) == "": tmpheader.append("") continue # If we enter a comment block, append it and process other code if not COMMENT: if not lexer.embeddedcomment(line): COMMENT = lexer.opencomment(line) else: test = lexer.removecomment(line) if wstring.strip(test) == "": # Simple one-line comment tmpheader.append(line) continue # Inside comment, this is a multi-line comment if COMMENT: # Comment opened COMMENT = lexer.closecomment(line) # Always inside comment? # End of multi-line comment if not COMMENT: # Terminator reached i = string.find(line, "*/") if i == -1: print "Error in parsing header" sys.exit(0) tmpheader.append(line[:i+2]) line = line[i + 2:] # Keeping the code is exists # Start of multi-line comment if COMMENT: i = string.find(line, "/*") if i != -1: tmpheader.append(line[i:]) line = line[:i] else: tmpheader.append(line) # A line of the comment block continue line = wstring.strip(line) if line == "": continue # If we are inside a macro or pragma block, skip it if not INSDEF: INSDEF = lexer.opendef(line) if INSDEF: INSDEF = lexer.closedef(line) continue if lexer.isdefine(line): continue # struct declaration are now ignored if not INSSTT: INSSTT = lexer.openstruct(line) if INSSTT: # inside block sttname = "" #print "(inside struct)", line #if lexer.structlevel == 0: # start or decl. # name = lexer.structname(line) # get name of structure # if name != None: sttname = name #print "structname", sttname INSSTT = lexer.closestruct(line) # end of block? # if INSSTT: continue continue # while in struct continue # typedef are now ignored if not INSTYP: INSTYP = lexer.opentypedef(line) if INSTYP: #print "(in typedef)", line INSTYP = lexer.closetypedef(line) continue # union are stored without change if not INUNION: INUNION = lexer.openunion(line) if INUNION: #print "in union", line INUNION = lexer.closeunion(line) tmpheader.append(line) continue #print "(mkclass, test for func or var)", line # prototype is kept, remove extern if present if lexer.isprototype(line): if lexer.isglobal(line): continue line = lexer.removextern(line) pass elif lexer.isvardecl(line): # static vars remain global in C++ (convention) #print "pass II - var", line if lexer.isglobal(line): #print "global, pass" continue # ignore an instance of struct if lexer.istypstruct(line): #print "mkclass (detect inst. of typedef struct)", line continue # "struct" found # ignore an user's type of struct name = lexer.getident(line) #print "getident", name if name is None: continue if name in lexer.typstruct: #print "in struct", name continue # normal variable becomes attribute # inside class, remove "extern" line = lexer.removextern(line) #print "mkclass (new line):", line else: pass tmpheader.append(line) #print line # End of loop tmpheader.append("};") # Creating the new C++ header file with .hpp extension nh = open(hpath, "wb") for str in tmpheader: nh.write(str + "\n") nh.write("\n") nh.close() print "class", classname, "created into", hname