diff options
author | Pearu Peterson <pearu.peterson@gmail.com> | 2006-05-24 13:44:36 +0000 |
---|---|---|
committer | Pearu Peterson <pearu.peterson@gmail.com> | 2006-05-24 13:44:36 +0000 |
commit | fff3c3f3b186d5a7cbbd3f4440b8f99f2035e733 (patch) | |
tree | 0704f51f408b86ac190aa07501f875858c792423 /numpy | |
parent | f3d3c4bc5b59da6dc9cd0343aeaf523a71521408 (diff) | |
download | numpy-fff3c3f3b186d5a7cbbd3f4440b8f99f2035e733.tar.gz |
Impl. simple fortran parser.
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/f2py/lib/block.py | 146 | ||||
-rw-r--r-- | numpy/f2py/lib/parsefortran.py | 64 | ||||
-rw-r--r-- | numpy/f2py/lib/readfortran.py | 31 |
3 files changed, 231 insertions, 10 deletions
diff --git a/numpy/f2py/lib/block.py b/numpy/f2py/lib/block.py new file mode 100644 index 000000000..cea71a593 --- /dev/null +++ b/numpy/f2py/lib/block.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python +""" +Defines Block classes. + +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: May 2006 + +""" + +__all__ = ['Block','Module','PythonModule','Interface', + 'Subroutine','Function','Type'] + +import re + +from readfortran import Line + +class Block: + + classes = [] + + def __init__(self, parent): + self.parent = parent + self.content = [] + + self.get_item = parent.get_item + self.put_item = parent.put_item + self.name = None + + def get_name(self): + if self.__class__ is Block: return '__MAIN__' + if self.name is None: return '' + return self.name + + def __str__(self): + tab = '' + p = self.parent + while isinstance(p, Block): + tab += ' ' + p = p.parent + name = self.get_name() + l=[tab+'begin '+self.__class__.__name__ +' '+ name] + for c in self.content: + l.append(str(c)) + l.append(tab+'end '+self.__class__.__name__ +' '+ name) + return '\n'.join(l) + + def isendline(self, line): + if self.__class__ is Block: + # MAIN block does not define start/end line conditions, + # so it never ends. + return False + m = self.end_re.match(line) + if not m: return False + return True + + def fill(self): + item = self.get_item() + while item is not None: + if isinstance(item, Line): + line = item.line + if self.isendline(line): + break + # check if line contains subblock start + found_block = False + for cls in self.classes: + m = cls.start_re.match(line) + if m: + found_block = True + subblock = cls(self, m) + self.content.append(subblock) + subblock.fill() + break + if found_block: + item = self.get_item() + continue + # line contains something else + self.content.append(item) + item = self.get_item() + return + +class Program(Block): + classes = [] + start_re = re.compile(r'\s*program', re.I) + + +class Module(Block): + classes = [] + start_re = re.compile(r'\s*module\s(?P<name>\w+)', re.I) + end_re = re.compile(r'\s*end(\s*module(\s*(?P<name>\w+)|)|)\s*\Z') + def __init__(self, parent, start_re_match): + Block.__init__(self, parent) + self.name = start_re_match.group('name') + +class Interface(Block): + classes = [] + start_re = re.compile(r'\s*interface(\s*(?P<name>\w+)|)', re.I) + end_re = re.compile(r'\s*end(\s*interface(\s*(?P<name>\w+)|)|)\s*\Z') + def __init__(self, parent, start_re_match): + Block.__init__(self, parent) + self.name = start_re_match.group('name') + + +class PythonModule(Block): + classes = [] + start_re = re.compile(r'\s*python\s*module\s(?P<name>\w+)', re.I) + end_re = re.compile(r'\s*end(\s*python\s*module(\s*(?P<name>\w+)|)|)\s*\Z') + def __init__(self, parent, start_re_match): + Block.__init__(self, parent) + self.name = start_re_match.group('name') + +class Subroutine(Block): + classes = [] + start_re = re.compile(r'\s*subroutine\s*(?P<name>\w+)', re.I) + end_re = re.compile(r'\s*end(\s*subroutine(\s*(?P<name>.*)|)|)\s*\Z') + def __init__(self, parent, start_re_match): + Block.__init__(self, parent) + self.name = start_re_match.group('name') + +class Function(Block): + classes = [] + start_re = re.compile(r'\s*function\s*(?P<name>\w+)', re.I) + end_re = re.compile(r'\s*end(\s*function(\s*(?P<name>.*)|)|)\s*\Z') + def __init__(self, parent, start_re_match): + Block.__init__(self, parent) + self.name = start_re_match.group('name') + +class Type(Block): + classes = [] + start_re = re.compile(r'\s*type(?!\s*\()', re.I) + end_re = re.compile(r'\s*end(\s*type(\s*(?P<name>.*)|)|)\s*\Z') + def __init__(self, parent, start_re_match): + Block.__init__(self, parent) + self.name = 'notimpl'#start_re_match.group('name') + +# Initialize classes lists +Block.classes.extend([Program,PythonModule,Module,Interface,Subroutine,Function,Type]) +Module.classes.extend([PythonModule,Interface,Subroutine,Function,Type]) +PythonModule.classes.extend(Module.classes) +Interface.classes.extend([PythonModule,Module,Interface,Subroutine,Function,Type]) +Subroutine.classes.extend([PythonModule,Module,Interface,Subroutine,Function,Type]) +Subroutine.classes.extend(Function.classes) +Type.classes.extend([Type,Function,Subroutine,Interface]) diff --git a/numpy/f2py/lib/parsefortran.py b/numpy/f2py/lib/parsefortran.py new file mode 100644 index 000000000..d4dc3d594 --- /dev/null +++ b/numpy/f2py/lib/parsefortran.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +""" +Defines FortranParser. + +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: May 2006 +""" + +import re + +from readfortran import FortranFileReader, FortranStringReader +from block import Block + +class FortranParser: + + def __init__(self, reader): + self.reader = reader + + def get_item(self): + try: + return self.reader.next(ignore_comments = True) + except StopIteration: + pass + + def put_item(self, item): + self.reader.fifo_item.insert(0, item) + + def parse(self): + main = Block(self) + main.fill() + return main + +def test_pyf(): + string = """ +python module foo + interface + subroutine bar + real r + end subroutine bar + end interface +end python module +""" + reader = FortranStringReader(string, True, True) + reader = FortranFileReader(filename) + parser = FortranParser(reader) + block = parser.parse() + print block + +def simple_main(): + import sys + for filename in sys.argv[1:]: + print 'Processing',filename + reader = FortranFileReader(filename) + parser = FortranParser(reader) + block = parser.parse() + print block + +if __name__ == "__main__": + #test_pyf() + simple_main() diff --git a/numpy/f2py/lib/readfortran.py b/numpy/f2py/lib/readfortran.py index 9ce601058..503fa123a 100644 --- a/numpy/f2py/lib/readfortran.py +++ b/numpy/f2py/lib/readfortran.py @@ -4,15 +4,22 @@ Defines FortranReader classes for reading Fortran codes from files and strings. FortranReader handles comments and line continuations of both fix and free format Fortran codes. -Copyright 2006 Pearu Peterson all rights reserved, -Pearu Peterson <pearu@cens.ioc.ee> Permission to use, modify, and distribute this software is given under the terms of the NumPy License. See http://scipy.org. NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. -Pearu Peterson +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: May 2006 """ +__all__ = ['FortranFileReader', + 'FortranStringReader', + 'FortranReaderError', + 'Line', 'SyntaxErrorLine', + 'Comment', + 'MultiLine','SyntaxErrorMultiLine', + ] + import re import sys import tempfile @@ -45,7 +52,7 @@ class Line: def __repr__(self): return self.__class__.__name__+'(%r,%s,%r)' \ % (self.line, self.span, self.label) - def isempty(self): + def isempty(self, ignore_comments=False): return not (self.line.strip() or (self.label and self.label.strip())) class SyntaxErrorLine(Line, FortranReaderError): @@ -63,8 +70,8 @@ class Comment: def __repr__(self): return self.__class__.__name__+'(%r,%s)' \ % (self.comment, self.span) - def isempty(self): - return len(self.comment)<2 # comment includes comment character + def isempty(self, ignore_comments=False): + return ignore_comments or len(self.comment)<2 class MultiLine: """ Holds (prefix, line list, suffix) representing multiline @@ -81,7 +88,7 @@ class MultiLine: return self.__class__.__name__+'(%r,%r,%r,%s)' \ % (self.prefix,self.block,self.suffix, self.span) - def isempty(self): + def isempty(self, ignore_comments=False): return not (self.prefix or self.block or self.suffix) class SyntaxErrorMultiLine(MultiLine, FortranReaderError): @@ -158,7 +165,7 @@ class FortranReaderBase: def __iter__(self): return self - def next(self): + def next(self, ignore_comments = False): fifo_item_pop = self.fifo_item.pop while 1: try: @@ -167,7 +174,7 @@ class FortranReaderBase: item = self.get_source_item() if item is None: raise StopIteration - if not item.isempty(): + if not item.isempty(ignore_comments): break # else ignore empty lines and comments if not isinstance(item, Comment): @@ -183,7 +190,7 @@ class FortranReaderBase: item = fifo_item_pop(0) except IndexError: item = self.get_source_item() - if item is None or not item.isempty(): + if item is None or not item.isempty(ignore_comments): break if item is None: break # hold raising StopIteration for the next call. @@ -493,6 +500,8 @@ class FortranReaderBase: ## FortranReaderBase +# Fortran file and string readers: + class FortranFileReader(FortranReaderBase): def __init__(self, filename): @@ -509,6 +518,8 @@ class FortranStringReader(FortranReaderBase): source = StringIO(string) FortranReaderBase.__init__(self, source, isfree, isstrict) +# Testing: + def test_f77(): string_f77 = """ c12346 comment |