#!/usr/bin/python # # c2mod.py: Converts C code into XML modules # Adopted from Eric Work's asap2mod.py # # 2008/01/08 fixed cleanLine and processCFile # removed processFile import math import sys, os import getopt, re from xml.dom.minidom import getDOMImplementation # compiled regular expressions reHeader = re.compile(r'#(.*)') reComment = re.compile(r'//(.*)') reSpacing = re.compile(r'\s+') reBegin = re.compile(r'begin (\w+)') reEnd = re.compile(r'end') # prints a warning when a parse error occurs # lineIn (string): the invalid line # funcState (dictionary): state of the parse function def printParseWarn(lineIn, funcState): # print warning message sys.stderr.write( 'Warning: Malformed line, %(fileName)s:%(lineNumber)d\n' % funcState) sys.stderr.write('=> %s\n' % lineIn) # prints an error when a file can't be opened # fileName (string): file which caused the error def printOpenError(fileName): # print error message sys.stderr.write('Error: Unable to open "%s"\n' % fileName) sys.exit(1) # prints an error when a required key is missing # elem (string): element involved # attr (string): attribute involved def printMissKey(elem, attr): # print error message sys.stderr.write( 'Error: No value for element "%s", attribute "%s"\n' % (elem, attr)) sys.exit(2) # cleans line formatting # lineIn (string): original string # ret (string): formatted string def cleanLine(lineIn): # convert everything to lowercase lineOut = lineIn.lower() # remove headers and comments lineOut = reHeader.sub('', lineOut).strip() lineOut = reComment.sub('', lineOut).strip() # collapse whitespace lineOut = reSpacing.sub(' ', lineOut).strip() return lineOut def processCFile(fileName): # open file for processing try: fileIn = open(fileName, 'r') except IOError: printOpenError(fileName) # prepare function state funcState = { 'fileName' : fileName, 'lineNumber' : 1, 'moduleName' : 'module', 'moduleTotal': 0 } # process line by line for lineIn in fileIn: # clean and parse line lineOut = cleanLine(lineIn) if lineOut: # check if begin line matBegin = reBegin.match(lineOut) if matBegin: # get module name modName = matBegin.group(1) # create xml document domImpl = getDOMImplementation() xmlDoc = domImpl.createDocument(None, 'module', None) moduleElem = xmlDoc.documentElement # create header elements headerObj = Header(modName) headerObj.writeXml(moduleElem) # create array elements arrayObj = Array() # update function state funcState['moduleName'] = modName # check if end line elif reEnd.match(lineOut): # create output file modName = funcState['moduleName'] fileOut = modName + '.mod' # open output file try: fileObj = open(fileOut, 'w') except IOError: printOpenError(fileOut) # write array elements to xml arrayObj.writeXml(moduleElem) # output xml to file xmlDoc.writexml(fileObj, addindent = ' ', newl = '\n') # print modules created inputTotal = arrayObj.inputTotal outputTotal = arrayObj.outputTotal print 'Module "%s" created with %d input(s) and %d output(s).' \ % (modName, inputTotal, outputTotal) # update function state funcState['moduleTotal'] += 1 # parse line else: arrayObj.parseCLine(lineOut, funcState) # increment line number funcState['lineNumber'] += 1 # print number of modules created print 'Total %d module(s) created.' % (funcState['moduleTotal']) # gets the document node for an element # xmlElem (Node): node attached to a document object # ret (Document): parent document object def getXmlDocument(xmlElem): # find the root xmlDoc = xmlElem while xmlDoc.parentNode: xmlDoc = xmlDoc.parentNode return xmlDoc # input config line type class Input: def __init__(self, mask, num): self.mask = mask self.num = num def writeXml(self, xmlRoot): # get xml document xmlDoc = getXmlDocument(xmlRoot) # append input element inputElem = xmlDoc.createElement('input') xmlRoot.appendChild(inputElem) # append input attributes inputElem.setAttribute('num', self.num) inputElem.setAttribute('mask', self.mask) # output code line type class Output: def __init__(self, mask): self.mask = mask def writeXml(self, xmlRoot): # get xml document xmlDoc = getXmlDocument(xmlRoot) # append output element outputElem = xmlDoc.createElement('output') xmlRoot.appendChild(outputElem) # append output attributes outputElem.setAttribute('mask', self.mask) # processor data type class Processor: def __init__(self, procX, procY): # initialize instance variables self.loc = { 'x': procX, 'y': procY } self.config = [] self.code = {} def addInput(self, mask, num, modName): cfgObj = Input(mask, num) listObj = self.getCodeList(modName + '.assy') listObj.append(cfgObj) def addOutput(self, mask, num, modName): codeObj = Output(mask) listObj = self.getCodeList(modName + '.assy') listObj.append(codeObj) def getCodeList(self, fileName): # create list object if non-existent if not self.code.has_key(fileName): self.code[fileName] = [] return self.code[fileName] def writeXml(self, xmlRoot): # get xml document xmlDoc = getXmlDocument(xmlRoot) # append processor element procElem = xmlDoc.createElement('processor') xmlRoot.appendChild(procElem) # append processor attributes procElem.setAttribute('loc', '%(x)s,%(y)s' % self.loc) # append config elements for cfgObj in self.config: cfgObj.writeXml(procElem) # loop through code files for codeFile in self.code: # append code element codeElem = xmlDoc.createElement('code') procElem.appendChild(codeElem) # append code attributes codeElem.setAttribute('file', codeFile) # append code line elements for codeObj in self.code[codeFile]: codeObj.writeXml(codeElem) # module header data type class Header: def __init__(self, modName): # initialize instance variables self.name = modName self.desc = None self.icon = None def writeXml(self, xmlRoot): # get xml document xmlDoc = getXmlDocument(xmlRoot) # append module attributes xmlRoot.setAttribute('name', self.name) if self.icon: xmlRoot.setAttribute('icon', self.icon) # append description element if self.desc: descElem = xmlDoc.createElement('description') descText = xmlDoc.createTextNode(self.desc) descElem.appendChild(descText) xmlRoot.appendChild(descElem) # processor array data type class Array: reParseBufs = re.compile(r'[\w\s]+ (ibuf|obuf)(\d+)') # input and output directions maskList = ['n', 'e', 'w', 's', 'u', 'r', 'l', 'd'] def __init__(self): # initialize instance variables self.input = [] self.output = [] self.routes = [] # not used self.size = {} self.proc = {} self.inputTotal = 0 self.outputTotal = 0 def getProcessor(self, procX, procY): # create processor object if non-existent procKey = '%s,%s' % (procX, procY) if not self.proc.has_key(procKey): self.proc[procKey] = Processor(procX, procY) return self.proc[procKey] def parseCLine(self, lineIn, funcState): # find buffer declarations matParseBufs = self.reParseBufs.match(lineIn) if matParseBufs: bufferType = matParseBufs.group(1) bufferNumber = matParseBufs.group(2) yIn = int(math.floor(self.inputTotal/8.0)) yOut = int(math.floor(self.outputTotal/8.0)) # check if input buffer if bufferType == 'ibuf': # create input location inputLoc = {} inputLoc['x'] = 0 inputLoc['y'] = yIn inputLoc['mask'] = self.maskList[self.inputTotal % 8] inputLoc['name'] = 'ibuf' + str(bufferNumber) self.input.append(inputLoc) # create/modify processor element procObj = self.getProcessor(inputLoc['x'], inputLoc['y']) modName = funcState['moduleName'] procObj.addInput(inputLoc['mask'], bufferNumber, modName) self.inputTotal += 1 # check if output buffer elif bufferType == 'obuf': # create output location outputLoc = {} outputLoc['x'] = 0 outputLoc['y'] = yOut outputLoc['mask'] = self.maskList[self.outputTotal % 8] outputLoc['name'] = 'obuf' + str(bufferNumber) self.output.append(outputLoc) # create/modify processor element procObj = self.getProcessor(outputLoc['x'], outputLoc['y']) modName = funcState['moduleName'] procObj.addOutput(outputLoc['mask'], bufferNumber, modName) self.outputTotal += 1 # set size value self.size['x'] = 1 if self.inputTotal > self.outputTotal: self.size['y'] = int(math.ceil(self.inputTotal/8.0)) else: self.size['y'] = int(math.ceil(self.outputTotal/8.0)) def writeXml(self, xmlRoot): # get xml document xmlDoc = getXmlDocument(xmlRoot) # check for input if self.input: # append input locations for inputLoc in self.input: # append input element inputElem = xmlDoc.createElement('input') xmlRoot.appendChild(inputElem) # append input attributes if inputLoc.has_key('x') and inputLoc.has_key('y'): inputElem.setAttribute('loc', '%(x)s,%(y)s' % inputLoc) else: printMissKey('input', 'loc') if inputLoc.has_key('mask'): inputElem.setAttribute('mask', inputLoc['mask']) else: printMissKey('input', 'mask') if inputLoc.has_key('name'): inputElem.setAttribute('name', inputLoc['name']) else: printMissKey('input', 'name') # check for output if self.output: # append output locations for outputLoc in self.output: # append output element outputElem = xmlDoc.createElement('output') xmlRoot.appendChild(outputElem) # append output attributes if outputLoc.has_key('x') and outputLoc.has_key('y'): outputElem.setAttribute('loc', '%(x)s,%(y)s' % outputLoc) else: printMissKey('output', 'loc') if outputLoc.has_key('mask'): outputElem.setAttribute('mask', outputLoc['mask']) else: printMissKey('output', 'mask') if outputLoc.has_key('name'): outputElem.setAttribute('name', outputLoc['name']) else: printMissKey('output', 'name') # append array element arrayElem = xmlDoc.createElement('array') xmlRoot.appendChild(arrayElem) # append array attributes if self.size.has_key('x') and self.size.has_key('y'): arrayElem.setAttribute('size', '%(x)sx%(y)s' % self.size) else: printMissKey('array', 'size') # append processor elements in order procKeyList = self.proc.keys() procKeyList.sort() for procKey in procKeyList: self.proc[procKey].writeXml(arrayElem) # check if being executed if __name__ == '__main__': # prints the program usage message def printUsage(): # extract application short name appName = os.path.basename(sys.argv[0]) print '\nUsage:', appName, '[OPTION] [FILE] ...\n' print 'Options:' print ' -h prints this application usage message' print ' FILE path to C file' # exit application sys.exit(0) # parse command-line arguments try: cmdOpts, cmdArgs = getopt.getopt(sys.argv[1:], 'h:') except getopt.error, errMsg: print 'Error:', str(errMsg).capitalize() printUsage() # process command-line arguments for opt, arg in cmdOpts: if opt == '-h': printUsage() # check that we are given a filename if not cmdArgs: printUsage() fileIn = cmdArgs[0] # process C file processCFile(fileIn)