summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorPearu Peterson <pearu.peterson@gmail.com>2006-05-24 13:44:36 +0000
committerPearu Peterson <pearu.peterson@gmail.com>2006-05-24 13:44:36 +0000
commitfff3c3f3b186d5a7cbbd3f4440b8f99f2035e733 (patch)
tree0704f51f408b86ac190aa07501f875858c792423 /numpy
parentf3d3c4bc5b59da6dc9cd0343aeaf523a71521408 (diff)
downloadnumpy-fff3c3f3b186d5a7cbbd3f4440b8f99f2035e733.tar.gz
Impl. simple fortran parser.
Diffstat (limited to 'numpy')
-rw-r--r--numpy/f2py/lib/block.py146
-rw-r--r--numpy/f2py/lib/parsefortran.py64
-rw-r--r--numpy/f2py/lib/readfortran.py31
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