This repository has been archived on 2026-05-18. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
miscutils/pcfconv.py

740 lines
35 KiB
Python
Executable File

#!/usr/bin/python
# pcfconf.py : A utility to convert mathetmatical formulas
# from one language to another. it currently only supports
# Microsoft PowerToy Calculator save files for reading,
# and Python for writing. But it can be easily extended
# to handle other file formats; see SOURCE DOC below
# for details.
# TODO: Set default data type (short, int, long, double, float)
# it currently defaults to int or float, depending on
# what's in the file
# Implement some sanity checking on function arguments, to
# make sure only arguments present in the arg list or the
# parent object's body, are referenced. Currently, there
# are no such checks.
################# SOURCE DOC ##############################################
############## (read here if you want to extend this program) #############
# The actual conversion is done by XXXXConverter classes that
# do the actual conversion. They are passed a generic list of the following
# form:
#
# [ [TYPE, NAME, VALUE] ]
#
# where TYPE is either "VAR" or "FUNC". If TYPE is "VAR", then the rest of
# the values are obvious (the name and value of the variable). If TYPE is
# "FUNC", then VALUE is actually another list of the form:
#
# [ARGS, CODE]
#
# where ARGS is yet another list containing the names of the function's arguments,
# and CODE is the original PowerToyCalc code for the function.
#
# To extend this program with a new filetype, scan down to the "PROCESSOR CLASSES"
# comment. At this point there is no programmatic reason to inherit your classes
# from GenericProcessor, but GenericProcessor is to be considered the base class
# for all new file processors; if GenericProcessor has a method, your class
# must have it as well. Use the PythonProcessor class as a guide to how the existing
# code works, if you need to. But as long as the converter winds up printing usable
# code to the output file, and errors to sys.__stderr__ (via the *err functions), then
# you're doing it right. Once you've done that, add it to the "PROCESSORS" dictionary
# in the global variables section. The format of the dictionary is obvious.
#
# To extend this program with a new target language, scan down to the "GENERATOR
# CLASSES" comment. The general process for processor classes applies here; if it's
# in the base class, it needs to be in your new subclass. Use the PythonConverter
# class as a guide to how to write your own converter, if necessary. The converter just
# needs to return usable output to the processor class, which prints it to whatever
# output file has been specified. Once you've done that, add it to the "CONVERTERS"
# dictionary in the global variables section. The format of the dictionary is obvious.
#
# Got it? easy.
import sys
import getopt
import math
# Functions that will be used throughout the module.
def syntaxerr (linenum, line, err):
sys.__stderr__.write("%d : %s : %s\n" % (linenum, err, line))
def generalerr (err):
sys.__stderr__.write("%s\n" % err)
def debugmsg (err):
global DEBUG
if ( DEBUG ) :
sys.__stderr__.write("DEBUG: %s\n" % err)
def cloneList (list1):
list2 = []
for item in list1:
list2.append(item)
return list2
################## CONVERTER CLASSES #######################
class GenericConverter:
def __init__ (self, langopts, contextName=""):
"""contextname is the name of the class, context, or namespace that should be
generated for the incoming data. langopts is a dictionary containing
the language specific options that the processor should follow."""
return
def convertFile (self, data):
"""data is the data to interpret to your native language"""
generalerr("convertFile is not implemented in GenericConverter")
return 1
def convertCalls (self, code):
"""For the given block of code, translate any calls to things like atan() and
acos() to functions that exist in your language's internal math library."""
global MATHSYMS
ourlist = cloneList(MATHSYMS)
ourlist.append(",")
ourlist.append(" ")
ourlist.append("\t")
# we do our best here to ensure we don't change someone's defined function that
# happens to have the name of one of ours inside of it. For example, if someone
# makes a function MYacos(), then a replace on "acos" with "math.acos" would result
# in the code being MYmath.acos(), which is guaranteed to do nothing but explode.
# So we try to make sure that we're only replacing exact matches, by checking that
# it follows any of the items in MATHSYMS, a comma(,), " ", or \t. The downside
# to this is that it winds up being pretty slow.
for call in self.__subs__.keys():
for symbol in ourlist :
toreplace = "%s%s" % (symbol, call)
replacer = "%s%s" % (symbol, self.__subs__[call])
if ( toreplace in code ):
debugmsg("Replacing %s with %s in code line %s" % (toreplace, replacer, code))
code = code.replace(toreplace, replacer)
return code
def supportedTranslations (self):
"""return a string that lists all of the translations your language's
converter supports"""
generalerr("supportedTranslations is not implemetned in GenericConverter")
class CPPConverter:
class CPPVariable:
def __init__ (self, name, initValue, baseType, namespace):
self.__name__ = name
self.__value__ = initValue
self.__vartype__ = baseType
self.__namespace__ = namespace
def __str__ (self, defonly = False):
retStr = ""
if ( isinstance(self.__value__, list) or isinstance(self.__value__, tuple) ):
if ( defonly ):
return "%s %s[%d];" % (self.__vartype__, self.__name__, len(self.__value__))
# if we're not doing definitions, then assignments only occur in the constructor
for i in range(0, len(self.__value__)-1):
retStr += "\tthis->%s[%d] = %s;\n" % (self.__name__, i, self.__value__[i])
else:
if ( defonly ):
return "%s %s;" % (self.__vartype__, self.__name__)
retStr = "\tthis->%s = %s;" % (self.__name__, self.__value__)
return retStr
class CPPFunction:
def __init__ (self, namespace, argtype, rettype, name, arguments, code):
self.__rettype__ = rettype
self.__argtype__ = argtype
self.__name__ = name
self.__namespace__ = namespace
self.__args__ = arguments
self.__code__ = code
def replaceVars (self, varlist):
"""Find any instance of a variable in our code that is not in our argument list,
and is a member variable of our parent class"""
codeCopy = self.__code__
ourlist = cloneList(MATHSYMS)
ourlist.append(",")
ourlist.append(" ")
for var in varlist :
if ( var.__name__ in self.__args__ ):
continue
for symbol in ourlist:
toreplace = "%s%s" % (symbol, var.__name__)
replacer = "this->%s" % (var.__name__)
debugmsg("Searching for \" %s\" in code block %s" % (toreplace, codeCopy))
if ( toreplace in codeCopy ):
debugmsg("Replacing \"%s\" with \"%s\" in %s" % (toreplace, replacer, codeCopy))
codeCopy = codeCopy.replace(toreplace, replacer)
self.__code__ = codeCopy
def __str__ (self, defonly=False):
if ( defonly ):
str = "%s %s (" % (self.__rettype__, self.__name__)
else:
str = "%s %s::%s (" % (self.__rettype__, self.__namespace__, self.__name__)
argcnt = 0
for item in self.__args__:
if ( argcnt > 0 ):
str += ", "
str += "%s %s" % (self.__argtype__, item)
argcnt += 1
str += ")"
if ( defonly ):
return str+";"
str += "\n{\n\treturn (%s);\n}\n" % (self.__code__)
return str
class CPPClass:
def __init__ (self, namespace, variables, functions, langopts):
self.__namespace__ = namespace
self.__vars__ = variables
self.__funcs__ = functions
self.__langopts__ = langopts
def toASCII (self):
hdrstr = ""
impstr = ""
# generate definition
hdrstr = "#ifndef __%s__\n" % self.__namespace__
hdrstr += "#define __%s__\n" % self.__namespace__
hdrstr += "#include <math.h>\n\n"
hdrstr += "class %s {\n" % self.__namespace__
hdrstr += "public:\n"
hdrstr += "\t%s::%s(void);\n" % (self.__namespace__, self.__namespace__)
for func in self.__funcs__:
hdrstr += "\t%s\n" % func.__str__(True)
hdrstr += "protected:\n"
for var in self.__vars__ :
hdrstr += "\t%s\n" % (var.__str__(True))
hdrstr += "}\n"
hdrstr += "#endif /* __%s__ */\n" % self.__namespace__
# generate implementation
if ( self.__langopts__["writefiles"].lower() == "true" ):
impstr = "#include \"%s.h\"\n\n" % self.__namespace__
impstr += "\n"
# generate the constructor
impstr += "void %s::%s(void)\n{\n" % (self.__namespace__, self.__namespace__)
# assignments happen in the constructor, not the class def
for var in self.__vars__ :
impstr += "%s\n" % str(var)
impstr += "}\n"
for func in self.__funcs__:
impstr += "%s\n" % str(func)
if ( self.__langopts__["writefiles"].lower() == "true" ):
# write the definition to the header file
ofile = open(("%s.h" % self.__namespace__), "w")
ofile.write(hdrstr)
ofile.close()
# write the implementation to the C file
ofile = open(("%s.c" % self.__namespace__), "w")
ofile.write(impstr)
ofile.close()
return ""
return hdrstr+"\n"+impstr
def __init__ (self, langopts, namespace="PTC"):
self.__namespace__ = namespace
self.__langopts__ = { "deftype" : "double",
"defrettype" : "double",
"writefiles" : "false" }
self.__funclist__ = []
self.__varlist__ = []
self.__subs__ = {}
for key in langopts.keys():
self.__langopts__[key] = langopts[key]
return
def convertFile (self, data):
for item in data:
debugmsg("Processing item %s" % (item))
if ( item[0] == "VAR" ):
self.__varlist__.append( CPPConverter.CPPVariable(item[1],
item[2], self.__langopts__["deftype"], self.__namespace__ ))
else:
self.__funclist__.append( CPPConverter.CPPFunction(self.__namespace__,
self.__langopts__["deftype"], self.__langopts__["defrettype"],
item[1], item[2][0], item[2][1]))
for func in self.__funclist__ :
func.replaceVars(self.__varlist__)
defclass = CPPConverter.CPPClass(self.__namespace__, self.__varlist__, self.__funclist__, self.__langopts__)
return defclass.toASCII()
def supportedTranslations (self):
return "The entire C++ math.h library is supported. You are almost guaranteed 100% conversion."
class CConverter:
class CVariable:
def __init__ (self, name, initValue, baseType, namespace):
self.__name__ = name
self.__value__ = initValue
self.__vartype__ = baseType
self.__namespace__ = namespace
def __str__ (self, defonly = False):
retStr = ""
if ( isinstance(self.__value__, list) or isinstance(self.__value__, tuple) ):
if ( defonly ):
return "%s %s_%s[%d];" % (self.__vartype__, self.__namespace__, self.__name__, len(self.__value__))
retStr = "%s %s_%s[%d] = {" % (self.__vartype__, self.__namespace__, self.__name__, len(self.__value__))
for i in self.__value__:
retStr += "%s, " % i
retStr += "};"
else:
if ( defonly ):
return "%s %s_%s;" % (self.__vartype__, self.__namespace__, self.__name__)
retStr = "%s %s_%s = %s;" % (self.__vartype__, self.__namespace__, self.__name__, self.__value__)
return retStr
class CFunction:
def __init__ (self, namespace, argtype, rettype, name, arguments, code):
self.__rettype__ = rettype
self.__argtype__ = argtype
self.__name__ = name
self.__namespace__ = namespace
self.__args__ = arguments
self.__code__ = code
def replaceVars (self, varlist):
"""Find any instance of a variable in our code that is not in our argument list,
and is a member variable of our parent class"""
codeCopy = self.__code__
ourlist = cloneList(MATHSYMS)
ourlist.append(",")
ourlist.append(" ")
for var in varlist :
if ( var.__name__ in self.__args__ ):
continue
for symbol in ourlist:
toreplace = "%s%s" % (symbol, var.__name__)
replacer = "%s_%s" % (self.__namespace__, var.__name__)
debugmsg("Searching for \" %s\" in code block %s" % (toreplace, codeCopy))
if ( toreplace in codeCopy ):
debugmsg("Replacing \"%s\" with \"%s\" in %s" % (toreplace, replacer, codeCopy))
codeCopy = codeCopy.replace(toreplace, replacer)
self.__code__ = codeCopy
def __str__ (self, defonly=False):
str = "%s %s_%s (" % (self.__rettype__, self.__namespace__, self.__name__)
argcnt = 0
for item in self.__args__:
if ( argcnt > 0 ):
str += ", "
str += "%s %s" % (self.__argtype__, item)
argcnt += 1
str += ")"
if ( defonly ):
return str+";"
str += "\n{\n\treturn (%s);\n}\n" % (self.__code__)
return str
class CInclude:
def __init__ (self, namespace, variables, functions):
self.__namespace__ = namespace
self.__vars__ = variables
self.__funcs__ = functions
def toASCII (self, writefiles):
hdrstr = ""
impstr = ""
# generate definition
hdrstr = "#ifndef __%s__\n" % self.__namespace__
hdrstr += "#define __%s__\n" % self.__namespace__
hdrstr += "#include <math.h>\n\n"
for var in self.__vars__ :
hdrstr += "extern %s\n" % (var.__str__(True))
hdrstr += "\n"
for func in self.__funcs__:
hdrstr += "extern %s\n" % func.__str__(True)
hdrstr += "#endif /* __%s__ */" % self.__namespace__
# generate implementation
if ( writefiles.lower() == "true" ):
impstr = "#include \"%s.h\"\n\n" % self.__namespace__
for var in self.__vars__ :
impstr += "%s\n" % (str(var))
impstr += "\n"
for func in self.__funcs__:
impstr += "%s\n" % str(func)
if ( writefiles.lower() == "true" ):
# write the definition to the header file
ofile = open(("%s.h" % self.__namespace__), "w")
ofile.write(hdrstr)
ofile.close()
# write the implementation to the C file
ofile = open(("%s.c" % self.__namespace__), "w")
ofile.write(impstr)
ofile.close()
return ""
return hdrstr+"\n"+impstr
def __init__ (self, langopts, namespace="PTC"):
self.__namespace__ = namespace
self.__langopts__ = { "deftype" : "double",
"defrettype" : "double",
"writefiles" : "false" }
self.__funclist__ = []
self.__varlist__ = []
# thankfully C doesn't require any substitutions; we just include math.h and
# everything is groovy.
self.__subs__ = {}
for key in langopts.keys():
self.__langopts__[key] = langopts[key]
return
def convertFile (self, data):
# forcibly process all the variables first, then do the functions.
# We do it in this specific order so we can do some variable replacement.
for item in data:
debugmsg("Processing item %s" % (item))
if ( item[0] == "VAR" ):
self.__varlist__.append( CConverter.CVariable(item[1],
item[2], self.__langopts__["deftype"], self.__namespace__ ))
else:
self.__funclist__.append( CConverter.CFunction(self.__namespace__,
self.__langopts__["deftype"], self.__langopts__["defrettype"],
item[1], item[2][0], item[2][1]))
for func in self.__funclist__ :
func.replaceVars(self.__varlist__)
defclass = CConverter.CInclude(self.__namespace__, self.__varlist__, self.__funclist__)
return defclass.toASCII(self.__langopts__["writefiles"])
def supportedTranslations (self):
return "The entire C math.h library is supported. You are almost guaranteed 100% conversion."
class PythonConverter:
# what the class needs to know:
# - the name of the class being generated. All data found in the .pcf file is
# placed into a generated class of the given name. Variables are listed as
# instance variables, and functions are of course generated as member functions.
# - list of functions
# - list of variables
class PythonVariable:
def __init__ (self, name, initValue, baseType):
# note that initValue can be a list when the baseType constructor
# requires more than one argument
self.__name__ = name
self.__value__ = initValue
self.__vartype__ = baseType
def __str__ (self):
retStr = ""
if ( isinstance(self.__value__, list) or isinstance(self.__value__, tuple) ):
retStr = "%s = %s(" % (self.__name__, self.__vartype__)
for i in self.__value__:
retStr += "%s, " % i
retStr += ")"
else:
retStr = "__%s__ = %s(%s)" % (self.__name__, self.__vartype__, self.__value__)
return retStr
class PythonFunction:
def __init__ (self, name, arguments, code):
self.__name__ = name
self.__args__ = arguments
self.__code__ = code
def replaceVars (self, varlist):
"""Find any instance of a variable in our code that is not in our argument list,
and is a member variable of our parent class"""
codeCopy = self.__code__
ourlist = cloneList(MATHSYMS)
ourlist.append(",")
ourlist.append(" ")
for var in varlist :
if ( var.__name__ in self.__args__ ):
continue
for symbol in ourlist:
toreplace = "%s%s" % (symbol, var.__name__)
replacer = "self.__%s__" % (var.__name__)
debugmsg("Searching for \" %s\" in code block %s" % (toreplace, codeCopy))
if ( toreplace in codeCopy ):
debugmsg("Replacing \"%s\" with \"%s\" in %s" % (toreplace, replacer, codeCopy))
codeCopy = codeCopy.replace(toreplace, replacer)
self.__code__ = codeCopy
def __str__ (self):
str = "def %s (self, " % (self.__name__)
argcnt = 0
for item in self.__args__:
if ( argcnt > 0 ):
str += ", "
str += "%s" % (item)
argcnt += 1
str += "): return (%s)" % (self.__code__)
return str
class PythonClass:
def __init__ (self, name, variables, functions):
self.__name__ = name
self.__vars__ = variables
self.__funcs__ = functions
def toASCII (self, tabstop):
# return all elements in a string suitable for printing to stdout
# "tabstop" specifies the tabstop to use. Pass "\t" or "" with a number of
# spaces per tabstop. There will be one additional space per tabstop
# because it makes it easier for me to write that way.
retstr = "import math\n"
retstr += "class %s:\n" % self.__name__
retstr += "%s def __init__(self):\n" % (tabstop)
for var in self.__vars__ :
retstr += "%s self.%s\n" % ((tabstop*2), str(var))
retstr += "%s return\n" % ((tabstop *2))
for func in self.__funcs__:
retstr += "%s %s\n" % (tabstop, str(func))
return retstr
def __init__ (self, langopts, className="PowerToyCapsule"):
self.__className__ = className
self.__langopts__ = langopts
self.__funclist__ = []
self.__varlist__ = []
self.__subs__ = {}
for item in dir(math):
if ( "__" in item ):
continue
self.__subs__[item] = "math.%s" % item
return
def convertFile (self, data):
# forcibly process all the variables first, then do the functions.
# We do it in this specific order so we can do some variable replacement.
for item in data:
debugmsg("Processing item %s" % (item))
if ( item[0] == "VAR" ):
if ( "." in item[2] ):
self.__varlist__.append( PythonConverter.PythonVariable(item[1], item[2], "float") )
else:
self.__varlist__.append( PythonConverter.PythonVariable(item[1], item[2], "int") )
else:
self.__funclist__.append( PythonConverter.PythonFunction(item[1], item[2][0], item[2][1]) )
for func in self.__funclist__ :
func.replaceVars(self.__varlist__)
defclass = PythonConverter.PythonClass(self.__className__, self.__varlist__, self.__funclist__)
return defclass.toASCII(" ")
def supportedTranslations (self):
retstr = ""
for call in self.__subs__.keys():
retstr += "%s " % call
return retstr
############################# PROCESSOR CLASSES ###################
class GenericProcessor:
def __init__ (self, converters):
# "converters" is a dictionary of language types and the corresponding classes that
# convert for that type
self.__converters__ = converters
def convertFile (self, filename, outfile, language, ignoreErrors, recovery, translate, langopts):
debugmsg("convertFile is not implemented in the GenericConverter base class.")
return 1
class MSPowerToyProcessor(GenericProcessor):
def convertFile (self, filename, outfile, language, ignoreErrors, recovery, translate, langopts):
global MATHSYMS
# get the right converter for our language type
convclass = self.__converters__[language]
converter = convclass(langopts)
data = []
if ( filename == "-" ):
ifile = sys.__stdin__
else:
ifile = open(filename, "rb")
if ( not ifile ):
generalerr("Unable to open input file %s, aborting." % filename)
linenum = 1
line = ifile.readline()
while ( line and (len(line) != 0) and line != "\x00"):
debugmsg("Operating on line %d with length %d : %s" % (linenum, len(line), line))
dataTYPE = ""
dataNAME = ""
dataVALUELITERAL = 0
dataVALUELIST = [[], ""]
# if there are parenthesis present on the LEFT side of the =, then the line is a function
# replace the BS nulls that PowerToyCalc puts into these files for some reason
line = line.replace("\x00", "").replace("\r", "").replace("\n", "")
# strip out the parts
parts = line.split("=")
debugmsg("Operating on parts %s" % parts)
# strip out all arithmetic operators and spaces, and drop the bare contents into a
# temporary string
if ( len(parts) > 1 ):
temp = parts[1]
for oper in MATHSYMS:
temp = temp.replace(oper, "")
# this final string will be used to test if any of the data in it is non-constant
# e.g., are there just numbers, or are there alphanumerics in there too?
temp = temp.replace(" ", "")
else:
sys.__stderr__.write("%s : %d : syntax error : no value in variable assignment : %s\n" \
% (filename, linenum, line))
if ( ignoreErrors ):
sys.__stderr__.write("%s : %d : defaulting value to 0 to continue\n" % (filename, linenum))
temp = "0"
else:
if ( ifile != sys.__stdin__ ):
ifile.close()
return 1
# if they are present on the right side of the equals, it's a variable
# If the variable has non-constant values to the right of =, then define that as a
# function with no arguments that returns the contents of the right side of the
# equals
if ( temp.isdigit() ):
# it's a variable, regardless of the presence of (), because it's just digits
dataTYPE = "VAR"
dataNAME = parts[0].replace(" ", "")
dataVALUELITERAL = parts[1].replace(" ", "")
elif ( "(" in parts[0] and ")" in parts[0] ):
# it's a function (though it may have been defined as a variable with non-constant
# values, such as the results of other functions, in PowerToyCalc. We define such
# variables as funtions in the converter because they may have data in them
# that needs to be re-calculated every time they are used, and a function is the
# only way to do that. We're actually beyond PowerToyCalc in that, because
# the user has to manually change a variable in PowerToyCalc to update it, we
# don't.)
dataTYPE = "FUNC"
dataNAME = parts[0].split("(")[0].split(")")[0].replace(" ", "")
dataVALUELIST[0] = parts[0].replace(" ", "").split("(")[1].replace(")", "").split(",")
if ( translate ):
dataVALUELIST[1] = converter.convertCalls(parts[1])
else:
dataVALUELIST[1] = parts[1]
else:
# if it didn't fit into the two top categories, I dunno WTF it is
sys.__stderr__.write("%s : %d : syntax error, no value in variable assignment : %s\n" % (filename, linenum, line))
# unless we're ignoring all errors, stop processing!
if ( ignoreErrors ):
if ( recovery ):
sys.__stderr__.write("%s : %d : defaulting value to 0 to continue\n" % (filename, linenum))
dataTYPE = "VAR"
dataNAME = parts[0].replace(" ", "")
dataVALUELITERAL = "0"
else:
line = ifile.readline()
continue
else:
if ( ifile != sys.__stdin__ ):
ifile.close()
return 1
if ( dataTYPE == "FUNC" ):
newlist=[dataTYPE, dataNAME, dataVALUELIST]
else:
newlist=[dataTYPE, dataNAME, dataVALUELITERAL]
debugmsg("Adding new list : %s" % newlist)
data.append(newlist)
line = ifile.readline()
linenum += 1
# out of the main conversion loop
if ( ifile != sys.__stdin__ ):
ifile.close()
if ( outfile == "-" ):
sys.__stdout__.write(converter.convertFile(data))
else:
try:
ofile = file(outfile, "w")
ofile.write(converter.convertFile(data))
ofile.close()
except IOError, e:
sys.__stderr__.write("Failed to open output file %s : %s" % (outfile, e))
return 1
return 0
################ GLOBALS ########################
DEBUG=False
MATHSYMS=["*", "+", "-", "=", "/", ">>", "<<", "%", "(", ")"]
CONVERTERS = { "python" : PythonConverter,
"C" : CConverter,
"C++" : CPPConverter }
PROCESSORS = { "mspcf" : [MSPowerToyProcessor, "MS Powertoy Calculator variable / function save data"]}
SHORTOPTS = "hf:l:t:o:erTSdO:"
LONGOPTS = ["help", "filename=", "language=", "filetype=",
"outfile=", "ignore-err", "recovery", "translate",
"supp-trans", "debug", "langopts="]
USAGE = \
"""Interpret mathematical formulae from various formats (such as
MS PowerToy Calculator saves) to usable source code for one of
a number of languages.
usage: pcfconv.py (opts)
options:
-h | --help : print this help
-f | --filename : filename to read from. If unspecified,
stdin is read by default.
-o | --outfile : filename to write to. If unspecified,
the text is written to stdout.
-t | --filetype : type of file being processed. If unspecified,
MS Powertoy Calculator is the default.
The interpreter cannot currently accurately
determine filetypes on its own.
-l | --language : language to write out. If unspecified,
python is the default output language.
-e | --ignore-err : ignore syntax errors in the source file
when one is encountered and continue
processing (note that the error will
still be reported to stderr)
-r | --recovery : Attempt to recover from any ignored
errors, in the best way the interpreter
can see fit. This could be dangerous.
Don't blame the interpreter if this
results in a divide by zero, you've
been warned!
-T | --translate : Setting this option will force the interpreter
to attempt to translate calls to math functions,
such as cos, acos, tan and log10, etc, to the
internal math functions of whatever host language
you're converting to. If this is unset - which
is the default - such calls will be left as-is,
and if necessary, you will have to change them
yourself. Note that some functions may not
be interpreted properly by your host language.
-S | --supp-trans : Print out what function translations (handled
by the -T option) are supported by the converter
for your host language
-d | --debug : Print debug output (normally supressed.)
-O | --langopts : A comma separated list of options for the
language processor for your given language,
with each option conforming to option=value. For
a list of options for each language processor,
refer to the complete documentation.
Languages currently supported: \n"""
USAGE += "\t" + (" ".join(CONVERTERS.keys())) + "\n"
USAGE += """Filetypes currently supported:\n"""
for proc in PROCESSORS.keys() :
USAGE += "\t%s : %s\n" % (proc, PROCESSORS[proc][1])
USAGE += """\npcfconv.py by Andrew Kesterson, 2008, released under the AKLabs
License. Go to http://www.aklabs.net/source/license.txt for the
full text of this license. Email the author andrew@aklabs.net for
all questions and bug reports.
"""
######################## MAIN LOGIC #############################
def main (argc, argv):
global DEBUG
infile = "-"
outfile = "-"
language = "python"
filetype = "mspcf"
ignoreErrors = False
recovery = False
translate = False
supp_trans = False
langopts = {}
opts = getopt.getopt(argv, SHORTOPTS, LONGOPTS)
for pair in opts[0]:
if ( pair[0] == "-h" or pair[0] == "--help" ):
sys.__stderr__.write(USAGE)
return 1
elif ( pair[0] == "-d" or pair[0] == "--debug" ):
DEBUG=True
elif ( pair[0] == "-l" or pair[0] == "--language" ):
language = pair[1]
elif ( pair[0] == "-f" or pair[0] == "--filename" ):
infile = pair[1]
elif ( pair[0] == "-o" or pair[0] == "--outfile" ):
outfile = pair[1]
elif ( pair[0] == "-e" or pair[0] == "--ignore-err" ):
ignoreErrors = True
elif ( pair[0] == "-r" or pair[0] == "--recovery" ):
recovery = True
elif ( pair[0] == "-t" or pair[0] == "--filetype" ):
filetype = pair[1]
elif ( pair[0] == "-T" or pair[0] == "--translate" ):
translate = True
elif ( pair[0] == "-S" or pair[0] == "--supp-trans" ):
supp_trans = True
elif ( pair[0] == "-O" or pair[0] == "--langopts" ):
splitopts = pair[1].split("=")
for i in range(0, len(splitopts)-1, 2):
#print "Assigning language option %s = %s" % (splitopts[i], splitopts[i+1])
langopts[splitopts[i]] = splitopts[i+1]
procclass = PROCESSORS[filetype][0]
proc = procclass(CONVERTERS)
if ( supp_trans ):
convclass = CONVERTERS[language]
conv = convclass(langopts)
print conv.supportedTranslations()
return 0
return proc.convertFile(infile, outfile, language, ignoreErrors, recovery, translate, langopts)
if ( __name__ == "__main__" ):
sys.exit(main(len(sys.argv[1:])-1, sys.argv[1:]))