#!/usr/bin/env python
help = """Script helps to convert C/C++ sources to C/C++ -like Python sources.
It does few simple edit operations, like removing semicolons and type declarations. After it you must edit code manually, but you'll spend less time to do it.
Utility Will make mistaces and Will not generate ready for use code, so, it won't help you, unless if you know either C/C++ and Python
For better result, it is recomented to format your code to ANSI style before doing conversion.
NO ANY BACKUPS ARE CREATED. YOU MAY PERMANENTLY CORRUPT YOR SOURCES
Usage:
cpp2python.py DIR|FILE
cpp2python.py -v|--version|-h|--help
When directory name is given - tries to find source files by C/C++ suffixes, when file name is given - processes given file
Author: Andrei Kopats
License: GPL
"""
import sys
import os.path
import re
def is_source(filename):
suffixes = ('.cpp', '.c', '.cxx', '.c++', '.cc', '.h', '.hpp', '.hxx', '.h++')
for s in suffixes:
if filename.endswith(s):
return True
return False
def process_line(line):
""" remove semicolons
codecode(param, param);
V
codecode(param, param)
"""
line = re.sub(';$', '', line) # remove semicolon from the end of line
""" remove strings containing opening bracket
if (blabla)
{
codecode
V
if (blabla)
codecode
"""
line = re.sub('\s*{\n$', '', line)
""" remove closing brackets. Empty line preserved
if (blabla)
{
codecode
V
if (blabla)
codecode
"""
line = re.sub('\s*}$', '', line)
""" replace inline comment sign
// here is comment
V
# here is comment
"""
line = re.sub('//', '#', line)
""" replace /* comment sign
/* here is comment
V
''' here is comment
"""
line = re.sub('/\*', "'''", line)
""" replace */ comment sign
here is comment */
V
here is comment '''
"""
line = re.sub('\*/', "'''", line)
""" replace '||' with 'or'
boolvar || anotherboolvar
V
boolvar or anotherboolvar
"""
line = re.sub('\|\|', 'or', line)
""" replace '&&' with 'and'
boolvar && anotherboolvar
V
boolvar and anotherboolvar
"""
line = re.sub('&&', 'and', line)
""" replace '!' with 'not '
if !boolvar
V
if not boolvar
"""
line = re.sub('!([^=\n])', 'not \\1', line)
""" replace '->' with '.'
object->method()
V
object.method()
"""
line = re.sub('->', '.', line)
""" replace 'false' with 'False'
b = false
V
b = False
"""
line = re.sub('false', 'False', line)
""" replace 'true' with 'True'
b = true
V
b = True
"""
line = re.sub('true', 'True', line)
""" remove "const" word from the middle of string
const int result = a.exec();
V
int result = a.exec();
"""
line = re.sub('const ', ' ', line)
""" remove "const" word from the end of string
const int result = a.exec();
V
int result = a.exec();
"""
line = re.sub(' const$', '', line)
""" remove brackets around if statement and add colon
if (i = 4)
V
if i = 4:
"""
line = re.sub('if\s*\((.*)\)$', 'if \\1:', line)
""" remove brackets around if statement and add colon
if (i = 4)
V
if i = 4:
"""
line = re.sub('if\s*\((.*)\)$', 'if \\1:', line)
#return line
""" remove type from method definition and add a colon and "def"
-bool pMonkeyStudio::isSameFile( const QString& left, const QString& right )
+pMonkeyStudio::isSameFile( const QString& left, const QString& right ):
"""
line = re.sub('^[\w:&<>\*]+\s+([\w:]+)\(([^\)]*\))$', 'def \\1(self, \\2:', line)
""" after previous replacement fix "(self, )" to "(self)"
-def internal_projectCustomActionTriggered(self, ):
+def internal_projectCustomActionTriggered(self):
"""
line = re.sub('\(\s*self,\s*\)', '(self)', line)
""" remove type name from function parameters (second and farther)
-def internal_currentProjectChanged(self, XUPProjectItem* currentProject, XUPProjectItem* previousProject ):
+def internal_currentProjectChanged(self, currentProject, previousProject ):
"""
line = re.sub(',\s*[\w\d:&\*<>]+\s+([\w\d:&\*]+)', ', \\1', line)
""" remove type name from variable declaration and initialisation
-pAbstractChild* document = currentDocument()
+document = currentDocument()
"""
line = re.sub('[\w\d:&\*]+\s+([\w\d]+)\s*= ', '\\1 = ', line)
""" remove class name from method definition
-pMonkeyStudio::isSameFile( const QString& left, const QString& right ):
+pMonkeyStudio::isSameFile( const QString& left, const QString& right ):
"""
line = re.sub('^def [\w\d]+::([\w\d]+\([^\)]*\):)$', 'def \\1', line)
""" replace '::' with '.'
YourNameSpace::YourFunction(bla, bla)
V
YourNameSpace.YourFunction(bla, bla)
"""
line = re.sub('::', '.', line)
""" replace 'else if' with 'elif'
else if (blabla)
V
elif (blabla)
"""
line = re.sub('else\s+if', 'elif', line)
""" replace 'else' with 'else:'
if blabala:
pass
else
pass
V
if blabala:
pass
else:
pass
"""
line = re.sub('else\s*$', 'else:\n', line)
""" Remove "new" keyword
-i = new Class
+i = Class
"""
line = re.sub(' new ', ' ', line)
""" Replace "this" with "self"
-p = SomeClass(this)
+p = SomeClass(self)
"""
line = re.sub('([^\w])this([^\w])', '\\1self\\2', line)
""" Replace Qt foreach macro with Python for
-foreach ( QMdiSubWindow* window, a.subWindowList() )
+foreach ( QMdiSubWindow* window, a.subWindowList() )
"""
line = re.sub('foreach\s*\(\s*[\w\d:&\*]+\s+([\w\d]+)\s*,\s*([\w\d\.\(\)]+)\s*\)', 'for \\1 in \\2:', line)
""" Replace Qt signal emit statement
-emit signalName(param, param)
+signalName.emit(param, param)
"""
line = re.sub('emit ([\w\d]+)', '\\1.emit', line)
""" Replace Qt connect call
-connect( combo, SIGNAL( activated( int ) ), self, SLOT( comboBox_activated( int ) ) )
+combo.activated.connect(self.comboBox_activated)
"""
line = re.sub('connect\s*\(\s*([^,]+)\s*,\s*' + \
'SIGNAL\s*\(\s*([\w\d]+)[^\)]+\)\s*\)\s*,'+ \
'\s*([^,]+)\s*,\s*' + \
'S[A-Z]+\s*\(\s*([\w\d]+)[^\)]+\)\s*\)\s*\)',
'\\1.\\2.connect(\\3.\\4)', line)
return line
def process_file(filename):
with open(filename, 'rw+') as file:
lines = file.readlines() # probably would die on sources more than 100 000 lines :D
file.seek(0)
file.truncate(0)
for line in lines:
file.write(process_line(line))
if __name__ == '__main__':
if '--help' in sys.argv or \
'-h' in sys.argv or \
'--version' in sys.argv or \
'-v' in sys.argv:
print help
sys.exit(0)
if len (sys.argv) != 2:
print >> sys.stderr, 'Invalid parameters count. Must be 1'
print help
sys.exit(-1)
if os.path.isdir(sys.argv[1]):
for root, dirs, files in os.walk(sys.argv[1]):
for file in files:
filename = root + '/' + file
if is_source(filename):
process_file(filename)
elif os.path.isfile(sys.argv[1]):
process_file(sys.argv[1])
else:
print >> sys.stderr, 'Not a file or directory', sys.argv[1]
sys.exit(-1)