| |
|
|
| import sys, os |
| from cStringIO import StringIO |
| import re |
|
|
| from Plex import * |
| from Plex.Traditional import re as Re |
|
|
| class MyScanner(Scanner): |
| def __init__(self, info, name='<default>'): |
| Scanner.__init__(self, self.lexicon, info, name) |
|
|
| def begin(self, state_name): |
| |
| |
| |
| |
| Scanner.begin(self, state_name) |
|
|
| def sep_seq(sequence, sep): |
| pat = Str(sequence[0]) |
| for s in sequence[1:]: |
| pat += sep + Str(s) |
| return pat |
|
|
| def runScanner(data, scanner_class, lexicon=None): |
| info = StringIO(data) |
| outfo = StringIO() |
| if lexicon is not None: |
| scanner = scanner_class(lexicon, info) |
| else: |
| scanner = scanner_class(info) |
| while 1: |
| value, text = scanner.read() |
| if value is None: |
| break |
| elif value is IGNORE: |
| pass |
| else: |
| outfo.write(value) |
| return outfo.getvalue(), scanner |
|
|
| class LenSubsScanner(MyScanner): |
| """Following clapack, we remove ftnlen arguments, which f2c puts after |
| a char * argument to hold the length of the passed string. This is just |
| a nuisance in C. |
| """ |
| def __init__(self, info, name='<ftnlen>'): |
| MyScanner.__init__(self, info, name) |
| self.paren_count = 0 |
|
|
| def beginArgs(self, text): |
| if self.paren_count == 0: |
| self.begin('args') |
| self.paren_count += 1 |
| return text |
|
|
| def endArgs(self, text): |
| self.paren_count -= 1 |
| if self.paren_count == 0: |
| self.begin('') |
| return text |
|
|
| digits = Re('[0-9]+') |
| iofun = Re(r'\([^;]*;') |
| decl = Re(r'\([^)]*\)[,;'+'\n]') |
| any = Re('[.]*') |
| S = Re('[ \t\n]*') |
| cS = Str(',') + S |
| len_ = Re('[a-z][a-z0-9]*_len') |
|
|
| iofunctions = Str("s_cat", "s_copy", "s_stop", "s_cmp", |
| "i_len", "do_fio", "do_lio") + iofun |
|
|
| |
| keep_ftnlen = (Str('ilaenv_') | Str('s_rnge')) + Str('(') |
|
|
| lexicon = Lexicon([ |
| (iofunctions, TEXT), |
| (keep_ftnlen, beginArgs), |
| State('args', [ |
| (Str(')'), endArgs), |
| (Str('('), beginArgs), |
| (AnyChar, TEXT), |
| ]), |
| (cS+Re(r'[1-9][0-9]*L'), IGNORE), |
| (cS+Str('ftnlen')+Opt(S+len_), IGNORE), |
| (cS+sep_seq(['(', 'ftnlen', ')'], S)+S+digits, IGNORE), |
| (Bol+Str('ftnlen ')+len_+Str(';\n'), IGNORE), |
| (cS+len_, TEXT), |
| (AnyChar, TEXT), |
| ]) |
|
|
| def scrubFtnlen(source): |
| return runScanner(source, LenSubsScanner)[0] |
|
|
| def cleanSource(source): |
| |
| source = re.sub(r'[\t ]+\n', '\n', source) |
| |
| source = re.sub(r'(?m)^[\t ]*/\* *\.\. .*?\n', '', source) |
| |
| source = re.sub(r'\n\n\n\n+', r'\n\n\n', source) |
| return source |
|
|
| class LineQueue(object): |
| def __init__(self): |
| object.__init__(self) |
| self._queue = [] |
|
|
| def add(self, line): |
| self._queue.append(line) |
|
|
| def clear(self): |
| self._queue = [] |
|
|
| def flushTo(self, other_queue): |
| for line in self._queue: |
| other_queue.add(line) |
| self.clear() |
|
|
| def getValue(self): |
| q = LineQueue() |
| self.flushTo(q) |
| s = ''.join(q._queue) |
| self.clear() |
| return s |
|
|
| class CommentQueue(LineQueue): |
| def __init__(self): |
| LineQueue.__init__(self) |
|
|
| def add(self, line): |
| if line.strip() == '': |
| LineQueue.add(self, '\n') |
| else: |
| line = ' ' + line[2:-3].rstrip() + '\n' |
| LineQueue.add(self, line) |
|
|
| def flushTo(self, other_queue): |
| if len(self._queue) == 0: |
| pass |
| elif len(self._queue) == 1: |
| other_queue.add('/*' + self._queue[0][2:].rstrip() + ' */\n') |
| else: |
| other_queue.add('/*\n') |
| LineQueue.flushTo(self, other_queue) |
| other_queue.add('*/\n') |
| self.clear() |
|
|
| |
| def cleanComments(source): |
| lines = LineQueue() |
| comments = CommentQueue() |
| def isCommentLine(line): |
| return line.startswith('/*') and line.endswith('*/\n') |
|
|
| blanks = LineQueue() |
| def isBlank(line): |
| return line.strip() == '' |
|
|
| def SourceLines(line): |
| if isCommentLine(line): |
| comments.add(line) |
| return HaveCommentLines |
| else: |
| lines.add(line) |
| return SourceLines |
| def HaveCommentLines(line): |
| if isBlank(line): |
| blanks.add('\n') |
| return HaveBlankLines |
| elif isCommentLine(line): |
| comments.add(line) |
| return HaveCommentLines |
| else: |
| comments.flushTo(lines) |
| lines.add(line) |
| return SourceLines |
| def HaveBlankLines(line): |
| if isBlank(line): |
| blanks.add('\n') |
| return HaveBlankLines |
| elif isCommentLine(line): |
| blanks.flushTo(comments) |
| comments.add(line) |
| return HaveCommentLines |
| else: |
| comments.flushTo(lines) |
| blanks.flushTo(lines) |
| lines.add(line) |
| return SourceLines |
|
|
| state = SourceLines |
| for line in StringIO(source): |
| state = state(line) |
| comments.flushTo(lines) |
| return lines.getValue() |
|
|
| def removeHeader(source): |
| lines = LineQueue() |
|
|
| def LookingForHeader(line): |
| m = re.match(r'/\*[^\n]*-- translated', line) |
| if m: |
| return InHeader |
| else: |
| lines.add(line) |
| return LookingForHeader |
| def InHeader(line): |
| if line.startswith('*/'): |
| return OutOfHeader |
| else: |
| return InHeader |
| def OutOfHeader(line): |
| if line.startswith('#include "f2c.h"'): |
| pass |
| else: |
| lines.add(line) |
| return OutOfHeader |
|
|
| state = LookingForHeader |
| for line in StringIO(source): |
| state = state(line) |
| return lines.getValue() |
|
|
| def replaceSlamch(source): |
| """Replace slamch_ calls with appropiate macros""" |
| def repl(m): |
| s = m.group(1) |
| return dict(E='EPSILON', P='PRECISION', S='SAFEMINIMUM', |
| B='BASE')[s[0]] |
| source = re.sub(r'slamch_\("(.*?)"\)', repl, source) |
| source = re.sub(r'^\s+extern.*? slamch_.*?;$(?m)', '', source) |
| return source |
|
|
| |
|
|
| def scrubSource(source, nsteps=None, verbose=False): |
| steps = [ |
| ('scrubbing ftnlen', scrubFtnlen), |
| ('remove header', removeHeader), |
| ('clean source', cleanSource), |
| ('clean comments', cleanComments), |
| ('replace slamch_() calls', replaceSlamch), |
| ] |
|
|
| if nsteps is not None: |
| steps = steps[:nsteps] |
|
|
| for msg, step in steps: |
| if verbose: |
| print msg |
| source = step(source) |
|
|
| return source |
|
|
| if __name__ == '__main__': |
| filename = sys.argv[1] |
| outfilename = os.path.join(sys.argv[2], os.path.basename(filename)) |
| fo = open(filename, 'r') |
| source = fo.read() |
| fo.close() |
|
|
| if len(sys.argv) > 3: |
| nsteps = int(sys.argv[3]) |
| else: |
| nsteps = None |
|
|
| source = scrub_source(source, nsteps, verbose=True) |
|
|
| writefo = open(outfilename, 'w') |
| writefo.write(source) |
| writefo.close() |
|
|
|
|