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 transform(cfile): global cpp global hpp global locals global linenumber global lastinclude global included global omitted global allclasses global allheaders global withoutpath # I guess the header file name node, ext = os.path.splitext(cfile) hppname = node + ".hpp" # I guess the class name to create an instance dummy, instance = os.path.split(node) instance = allheaders[hppname] print "mkcpp - converting", cfile, "with" , hppname infile = open(cfile, "rb") if infile is None: print "Enable to open", cfile sys.exit(0) cpp = [] hpp = [] varlist = [] funclist = [] staticlist = [] included = [] omitted = [] linenumber = 0 # Internal function: add a line to cpp file def addit(line): global linenumber line = wstring.chop(line) cpp.append(line) linenumber += 1 return # Processing the C file COMMENT = FALSE # This flag is true inside a comment INSBLK = FALSE # This one inside a function's body INSMAC = FALSE NOCASE = (os.name == "nt") | (os.name == "dos") while(1): line = infile.readline() if not line: break line = wstring.chop(line) # Removing line separators if len(wstring.strip(line)) == 0: addit("") continue # Empty line ignored # Updating include statements if len(line) > 11: # min is #include "a" if line[:9] == "#include ": # get last include linenumber lastinclude = linenumber i = string.find(line, '\"') # locate first " if i == -1: #print "no valid" addit(line) continue j = string.find(line, '\"', i + 1) # locate second " if j == -1: print "Error, quotes not closed" print line sys.exit(0) hpath = line[i + 1:j] if len(hpath) > 2: node, ext = os.path.splitext(hpath) hppath = node + ".hpp" if NOCASE: hppath = string.lower(hppath) # add this path to the list of included header files if hppath not in included: included.append(hppath) line = string.replace(line, hpath, hppath) #print "replaced", line addit(line) continue # If we enter a comment block, append it and # process other code on the same line 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 addit(line) continue # Inside a comment block if multi-lines if COMMENT: # Comment opened #print "inside c comment", line 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) addit(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: addit(line[i:]) line = line[:i] else: addit(line) # A line of the comment block continue if line is None: continue if wstring.strip(line) == "": addit(line) continue # If we are inside a macro or pragma block, skip it if not INSMAC: INSMAC = lexer.opendef(line) if INSMAC: INSMAC = lexer.closedef(line) addit(line) continue # Comment unterminated are removed if lexer.unterminated(line): line = lexer.removecomment(line) # Simple keywords of type on the line if lexer.typeonly(line): #print "type only", line while(1): next = infile.readline() if not next: break next = wstring.clean(next) if next == "": continue line = line + ' ' + next break #print "type only now", line # A function's prototype: remove it if lexer.isprototype(line): continue # A local one line typedef if lexer.linetypedef(line): addit(line) continue if lexer.linestruct(line): addit(line) continue # A function's definition if lexer.isfunction(line) == TRUE: #print "is function ", line # The heading may use several lines while string.find(line, ')') == -1: next = infile.readline() 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 nextline = line if lexer.oldformat(line): #print "old format", line tlist = [] counter = lexer.argscount(line) while(counter): l = infile.readline() if not l: break l = wstring.clean(l) l = lexer.getdecl(l) if lexer.isvardecl(l): tlist.append(l) counter = counter - 1 else: break if '{' in l: i = string.find(l, '{') nextline = l[i:] break # Rebuilding the heading according to the new format line = lexer.argreplace(line, tlist) #print "args replace", line, "with list", tlist # With the class prefix, a function becomes a method # but for the main function funcname = lexer.getident(line) if funcname is None: print "Error, no ident in", line sys.exit(0) funcname = string.lower(funcname) # add the class prefix, but for the main function # for wich classname (used further) must be defined if funcname != "main": line, classname = setmethod(line) else: classname = getclass("main") line = lexer.removestatic(line) addit(line) #print "Added method", line # Now making a list from the block, # for scanning variables inside local scope blocklist = [] # Adding the arguments in the list of local variables plist, pi, pj = lexer.getargs(line) arglist = [] if not plist is None: for p in plist: arglist.append(lexer.addsemicolon(p)) locals = [] processlocals(arglist) # Handling already skiped lines by giving the last line # read from the file, for following tests line = nextline if not INSBLK: INSBLK = '{' in line # reading next lines, skipping empty or comment lines while not INSBLK: line = infile.readline() if not line: print "Error, end of file in block" print line sys.exit(0) blocklist.append(line) INSBLK = lexer.openblock(line) while(INSBLK): INSBLK = lexer.closeblock(line) if INSBLK: #print "inside c block", line line = infile.readline() # Skipping the content if not line: INSBLK = FALSE else: blocklist.append(line) # Making a list of local variables into the "locals" list processlocals(blocklist) # Now performing replacements newblock = processblock(blocklist, classname) for line in newblock: addit(line) continue # Continue in main loop # An external declaration should be ignored # since all vars now have declaration in headers # this works if the declaration is a single line elif lexer.isextern(line): continue # An array declaration # - static: remain global, static removed # - with initializer: become static attribute definition # - without initializer: declared in class, removed here elif lexer.isarray(line): # print "is array", line # One line declaration, save it and continue i = string.find(line, ';') if i != -1: # one line global array with initializer or not if lexer.isstatic(line): line = lexer.removestatic(line) addit(line) continue # attribute with initalizer, transformed j = string.find(line, '='); if j != -1: ahead = line[:j] + ";" line = setmember(line) addit(line) staticlist.append(ahead[:i+1]) # other attribute, removed from source file # but added to list of attributes else: ahead = line varlist.append(ahead[:i + 1]) #print "one line", line[:i + 1] continue # Multiline array with assignment fulldecl = line + "\n" initflag = FALSE globalflag = lexer.isstatic(line) j = string.find(line, "=") if j != -1: ahead = line[:j] + ";" initflag = TRUE else: ahead = line ARRAY = lexer.openarray(line) #print "open?", ARRAY while ARRAY == FALSE: line = infile.readline() #line = lexer.removecomment(line) if wstring.clean(line) != "": fulldecl = fulldecl + line ARRAY = lexer.openarray(line) ARRAY = lexer.closearray(line) while(ARRAY): line = infile.readline() #line = lexer.removecomment(line) fulldecl = fulldecl + line ARRAY = lexer.closearray(line) varlist.append(ahead) if globalflag == TRUE: # a global array fulldecl = lexer.removestatic(fulldecl) addit(fulldecl) continue if initflag == TRUE: fulldecl = setmember(fulldecl) addit(fulldecl) staticlist.append(ahead) continue # A variable definition else: if lexer.isvardef(line): #print "var in source", line globalflag = lexer.isstatic(line) if globalflag: line = lexer.removestatic(line) nlist = [] if lexer.multivar(line): nlist = lexer.splitvardef(line) else: nlist.append(line) for n in nlist: j = string.find(n, '=') if j != -1: ahead = n[:j] + ";" if not globalflag: n = setmember(n) addit(n) staticlist.append(ahead) else: if globalflag: addit(n) ahead = n varlist.append(ahead) #print "append var", n #print line continue # Save a compound block not previously handled if not INSBLK: INSBLK = lexer.openblock(line) if INSBLK: INSBLK = lexer.closeblock(line) #print "open block >", line addit(line) while INSBLK: line = infile.readline() # Skipping the content if not line: break #print "block >", line addit(line) INSBLK = lexer.closeblock(line) continue # other statement #print "other", line addit(line) # end main while addit("") # add the instance of the class addit(instance + " " + instance + "Obj;\n") infile.close() # Processing the header file # It is rebuilt # Reading the file and removing end of file code if exists header = [] if os.path.exists(hppname): hfile = open(hppname, "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] hpp = [] # To rebuild the file defheader = {} # Define declarations inside header file rcount = 0 # Replacements COMMENT = FALSE # This flag is true while inside a comment block INSMAC = FALSE # This one inside a macro INSTYP = FALSE # This one inside a typedef or struct # Now the header file is rebuilt for o in header: # Scanning the header file line = wstring.chop(o) # Remove annoying line separators if wstring.strip(line) == "": # Empty line, keep it hpp.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 hpp.append(line) continue # Inside comment, this is a multi-line comment if COMMENT: # Comment opened #print "inside comment", line 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) hpp.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: hpp.append(line[i:]) line = line[:i] else: hpp.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 INSMAC: INSMAC = lexer.opendef(line) if INSMAC: #print "inside macro", line INSMAC = lexer.closedef(line) hpp.append(line) continue # If we are inside struct or typedef, skip it if not INSTYP: INSTYP = lexer.openrecord(line) if INSTYP: INSTYP = lexer.closerecord(line) hpp.append(line) continue # Define statement 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 # get the class name from the header if string.find(line, "class") != -1: classname = lexer.getclassname(line) if lexer.isprototype(line): if lexer.isglobal(line): line = lexer.removeglobal(line) hpp.append(line) continue if lexer.isvardecl(line): # print "var in header", line if not lexer.isextern(line): for n in staticlist[:]: #print "var in source", n if lexer.samevar(line, n): # Same name line = lexer.addstatic(line) staticlist.remove(n) break # exit for loop # In all case, adding the line, either changed or not hpp.append(line) # Adding one instance of this class # it must to be defined in the cpp source also # as: classname classnameObj; obj = classname + "Obj" hpp.append("extern " + classname + " " + obj + ';') # Rewriting the updated header file hfile = open(hppname, "wb") for o in hpp: hfile.write(o + "\n") hfile.close() # For each include directive # I get header path, and with it the class name # and I test if the class is in the list of classes used by this source # if not, I add the missing header in which this class is declared for hname in included: # get the path from an include directive if allheaders.has_key(hname): # if this path in allheaders? clname = allheaders[hname] # get the class name the header contains else: dummy, fname = os.path.split(hname) # get the filename if withoutpath.has_key(fname): # perhaps path missing in directive? clname = withoutpath[fname] # get the class from the second list else: print "*", fname, "not in list of headers" continue if clname in omitted: # is class in the list of used classes? omitted.remove(clname) # class already included, remove it #print "already included", clname continue # now adding all omitted include statements for cname in omitted: # get a class name if allclasses.has_key(cname): # is it in the dict hname = allclasses[cname] # get the header filename s = "#include \"" + hname + "\"" # build an include statement cpp.insert(lastinclude + 1, s) # insert it in last position print "added ", s # Creating the C++ code file node, ext = os.path.splitext(cfile) cppname = node + ".cpp" cppfile = open(cppname, "wb") for o in cpp: cppfile.write(o + "\n") cppfile.close() dummy, cppname = os.path.split(cppname) #dummy, hppname = os.path.split(hppname) print cppname, "created,", "and", hppname, "updated" print "" return