summaryrefslogtreecommitdiff
path: root/numpy/f2py
diff options
context:
space:
mode:
authorPearu Peterson <pearu.peterson@gmail.com>2006-06-22 10:25:57 +0000
committerPearu Peterson <pearu.peterson@gmail.com>2006-06-22 10:25:57 +0000
commitd5a5da520b1eddd10a7dde79b0e7df281ee1abaa (patch)
treef19a3ce2d0e327bc02771dee39a4b0ccea7aeccf /numpy/f2py
parent1fe0237f46025a44779ad98974b9a587b6aa6ac8 (diff)
downloadnumpy-d5a5da520b1eddd10a7dde79b0e7df281ee1abaa.tar.gz
Cont. impl. Fortran parser.
Diffstat (limited to 'numpy/f2py')
-rw-r--r--numpy/f2py/lib/base_classes.py199
-rw-r--r--numpy/f2py/lib/block.py23
-rw-r--r--numpy/f2py/lib/block_statements.py535
-rw-r--r--numpy/f2py/lib/init.py50
-rw-r--r--numpy/f2py/lib/parsefortran.py19
-rw-r--r--numpy/f2py/lib/readfortran.py26
-rw-r--r--numpy/f2py/lib/statements.py645
-rw-r--r--numpy/f2py/lib/stmt.py68
-rw-r--r--numpy/f2py/lib/typedecl_statements.py162
9 files changed, 1666 insertions, 61 deletions
diff --git a/numpy/f2py/lib/base_classes.py b/numpy/f2py/lib/base_classes.py
new file mode 100644
index 000000000..24a86ebf6
--- /dev/null
+++ b/numpy/f2py/lib/base_classes.py
@@ -0,0 +1,199 @@
+
+__all__ = ['Statement','BeginStatement','EndStatement']
+
+import re
+import sys
+from readfortran import Line
+
+
+class Statement:
+ """
+ Statement instance has attributes:
+ parent - Parent BeginStatement or FortranParser instance
+ item - Line instance containing the statement line
+ isvalid - boolean, when False, the Statement instance will be ignored
+ """
+ modes = ['free90','fix90','fix77','pyf']
+
+ def __init__(self, parent, item):
+ self.parent = parent
+ self.reader = parent.reader
+ self.item = item
+
+ # If statement instance is constructed by error, set isvalid to False
+ self.isvalid = True
+
+ self.process_item()
+
+ def get_indent_tab(self,colon='',deindent=False):
+ if self.reader.isfix:
+ tab = ' '*6
+ else:
+ tab = ''
+ p = self.parent
+ while isinstance(p, Statement):
+ tab += ' '
+ p = p.parent
+ if deindent:
+ tab = tab[:-2]
+ if self.item is None:
+ return tab
+ s = self.item.label
+ if s:
+ c = ''
+ if self.reader.isfix:
+ c = ' '
+ tab = tab[len(c+s)+len(colon):]
+ if not tab: tab = ' '
+ tab = c + s + colon + tab
+ return tab
+
+class BeginStatement(Statement):
+ """ <blocktype> <name>
+
+ BeginStatement instances have additional attributes:
+ name
+ blocktype
+
+ Block instance has attributes:
+ content - list of Line or Statement instances
+ name - name of the block, unnamed blocks are named
+ with the line label
+ parent - Block or FortranParser instance
+ item - Line instance containing the block start statement
+ get_item, put_item - methods to retrive/submit Line instaces
+ from/to Fortran reader.
+ isvalid - boolean, when False, the Block instance will be ignored.
+
+ stmt_cls, end_stmt_cls
+
+ """
+ def __init__(self, parent, item=None):
+
+ self.content = []
+ self.get_item = parent.get_item # get line function
+ self.put_item = parent.put_item # put line function
+ if not hasattr(self, 'blocktype'):
+ self.blocktype = self.__class__.__name__.lower()
+ if not hasattr(self, 'name'):
+ # process_item may change this
+ self.name = '__'+self.blocktype.upper()+'__'
+
+ Statement.__init__(self, parent, item)
+ return
+
+ def process_item(self):
+ """ Process the line
+ """
+ item = self.item
+ if item is None: return
+ self.fill()
+ return
+
+ def tostr(self):
+ return self.blocktype.upper() + ' '+ self.name
+
+ def __str__(self):
+ l=[self.get_indent_tab(colon=':') + self.tostr()]
+ for c in self.content:
+ l.append(str(c))
+ return '\n'.join(l)
+
+ def process_subitem(self, item):
+ """
+ Check is item is blocks start statement, if it is, read the block.
+
+ Return True to stop adding items to given block.
+ """
+ line = item.get_line()
+
+ # First check for the end of block
+ cls = self.end_stmt_cls
+ if cls.match(line):
+ stmt = cls(self, item)
+ if stmt.isvalid:
+ self.content.append(stmt)
+ return True
+
+ # Look for statement match
+ for cls in self.classes:
+ if cls.match(line):
+ stmt = cls(self, item)
+ if stmt.isvalid:
+ self.content.append(stmt)
+ return False
+ self.handle_unknown_item(item)
+ return False
+
+ def handle_unknown_item(self, item):
+ print self.__class__.__name__,item,item.get_line()
+ self.content.append(item)
+ return
+
+ def fill(self, end_flag = False):
+ """
+ Fills blocks content until the end of block statement.
+ """
+
+ mode = self.reader.mode
+ classes = self.get_classes()
+ self.classes = [cls for cls in classes if mode in cls.modes]
+
+ item = self.get_item()
+ while item is not None:
+ if isinstance(item, Line):
+ if self.process_subitem(item):
+ end_flag = True
+ break
+ item = self.get_item()
+
+ if not end_flag:
+ message = self.reader.format_message(\
+ 'WARNING',
+ 'failed to find the end of block for %s'\
+ % (self.__class__.__name__),
+ self.item.span[0],self.item.span[1])
+ print >> sys.stderr, message
+ sys.stderr.flush()
+ return
+
+class EndStatement(Statement):
+ """
+ END [<blocktype> [<name>]]
+
+ EndStatement instances have additional attributes:
+ name
+ blocktype
+ """
+
+ def __init__(self, parent, item):
+ if not hasattr(self, 'blocktype'):
+ self.blocktype = self.__class__.__name__.lower()[3:]
+ Statement.__init__(self, parent, item)
+
+ def process_item(self):
+ item = self.item
+ line = item.get_line().replace(' ','')[3:]
+ blocktype = self.blocktype
+ if line.startswith(blocktype):
+ line = line[len(blocktype):].strip()
+ else:
+ if line:
+ # not the end of expected block
+ line = ''
+ self.isvalid = False
+ if line:
+ if not line==self.parent.name:
+ message = self.reader.format_message(\
+ 'WARNING',
+ 'expected the end of %r block but got end of %r, skipping.'\
+ % (self.parent.name, line),
+ item.span[0],item.span[1])
+ print >> sys.stderr, message
+ self.isvalid = False
+ self.name = self.parent.name
+
+ def __str__(self):
+ return self.get_indent_tab()[:-2] + 'END %s %s'\
+ % (self.blocktype.upper(),self.name or '')
+
diff --git a/numpy/f2py/lib/block.py b/numpy/f2py/lib/block.py
index 09d39d0e2..7d3b32666 100644
--- a/numpy/f2py/lib/block.py
+++ b/numpy/f2py/lib/block.py
@@ -21,7 +21,7 @@ import sys
from readfortran import Line
from splitline import string_replace_map
-from stmt import statements, end_stmts, block_stmts
+from stmt import statements #, end_stmts, block_stmts
class Block:
"""
@@ -34,6 +34,8 @@ class Block:
get_item, put_item - methods to retrive/submit Line instaces
from/to Fortran reader.
isvalid - boolean, when False, the Block instance will be ignored.
+
+ stmt_cls, end_stmt_cls
"""
classes = {}
@@ -52,7 +54,7 @@ class Block:
self.get_item = parent.get_item # get line function
self.put_item = parent.put_item # put line function
- self.content = []
+ self.content = [] # list of statement instances in block
self.name = None
self.item = item
@@ -65,6 +67,19 @@ class Block:
self.name = stmt.name
self.fill() # read block content
+ return
+
+ def init_class(self):
+ if hasattr(self.__class__, 'stmt_cls'):
+ return
+ name = self.__class__.__name__
+ assert name[-5:]=='Block',`name`
+ name = name[:-5]
+ import stmt
+ setattr(self.__class__,'stmt_cls',getattr(stmt,name))
+ setattr(self.__class__,'end_stmt_cls',getattr(stmt,'End'+name))
+ return
+
def get_name(self):
if self.__class__ is Block: return '__F2PY_MAIN__'
if not hasattr(self,'name') or self.name is None: return ''
@@ -137,7 +152,7 @@ class Block:
end_flag = True
break
elif not self.isstmt(item):
- # put unknown item's to content.
+ # put unknown items to content list.
self.content.append(item)
item = self.get_item()
if not end_flag:
@@ -247,7 +262,7 @@ class DoBlock(StatementBlock):
# ..
# 1 continue
if item.label==self.endlabel:
- # item may contain computational statemets
+ # item may contain computational statements
self.content.append(item)
# the same item label may be used for different block ends
self.put_item(item)
diff --git a/numpy/f2py/lib/block_statements.py b/numpy/f2py/lib/block_statements.py
new file mode 100644
index 000000000..e78ebe355
--- /dev/null
+++ b/numpy/f2py/lib/block_statements.py
@@ -0,0 +1,535 @@
+"""
+
+"""
+
+import re
+import sys
+
+from base_classes import BeginStatement, EndStatement, Statement
+from readfortran import Line
+
+# File block
+
+class EndSource(EndStatement):
+ """
+ """
+ match = staticmethod(lambda s: False)
+
+class BeginSource(BeginStatement):
+ """
+ """
+ match = staticmethod(lambda s: True)
+
+ end_stmt_cls = EndSource
+
+ def process_item(self):
+ self.name = self.reader.name
+ self.fill(end_flag = True)
+ return
+
+ def get_classes(self):
+ return program_unit
+
+ def process_subitem(self, item):
+ # MAIN block does not define start/end line conditions,
+ # so it should never end until all lines are read.
+ # However, sometimes F77 programs lack the PROGRAM statement,
+ # and here we fix that:
+ if self.reader.isfix77:
+ line = item.get_line()
+ if line=='end':
+ message = self.reader.format_message(\
+ 'WARNING',
+ 'assuming the end of undefined PROGRAM statement',
+ item.span[0],item.span[1])
+ print >> sys.stderr, message
+ p = Program(self)
+ p.content.extend(self.content)
+ p.content.append(EndProgram(p,item))
+ self.content[:] = [p]
+ return
+ return BeginStatement.process_subitem(self, item)
+
+# Module
+
+class EndModule(EndStatement):
+ match = re.compile(r'end(\s*module\s*\w*|)\Z', re.I).match
+
+class Module(BeginStatement):
+ """
+ MODULE <name>
+ ..
+ END [MODULE [name]]
+ """
+ match = re.compile(r'module\s*\w+\Z', re.I).match
+ end_stmt_cls = EndModule
+
+ def get_classes(self):
+ return access_spec + specification_part + module_subprogram_part
+
+ def process_item(self):
+ name = self.item.get_line().replace(' ','')[len(self.blocktype):].strip()
+ self.name = name
+ return BeginStatement.process_item(self)
+
+ #def __str__(self):
+ # s = self.get_indent_tab(deindent=True)
+ # s += 'MODULE '+ self.name
+ # return s
+
+# Python Module
+
+class EndPythonModule(EndStatement):
+ match = re.compile(r'end(\s*python\s*module\s*\w*|)\Z', re.I).match
+
+class PythonModule(BeginStatement):
+ """
+ PYTHON MODULE <name>
+ ..
+ END [PYTHON MODULE [name]]
+ """
+ modes = ['pyf']
+ match = re.compile(r'python\s*module\s*\w+\Z', re.I).match
+ end_stmt_cls = EndPythonModule
+
+ def get_classes(self):
+ return [Interface, Function, Subroutine, Module]
+
+ def process_item(self):
+ name = self.item.get_line().replace(' ','')[len(self.blocktype):].strip()
+ self.name = name
+ return BeginStatement.process_item(self)
+
+# Program
+
+class EndProgram(EndStatement):
+ """
+ END [PROGRAM [name]]
+ """
+ match = re.compile(r'end(\s*program\s*\w*|)\Z', re.I).match
+
+class Program(BeginStatement):
+ """ PROGRAM [name]
+ """
+ match = re.compile(r'program\s*\w*\Z', re.I).match
+ end_stmt_cls = EndProgram
+
+ def get_classes(self):
+ return specification_part + execution_part + internal_subprogram_part
+
+ def process_item(self):
+ name = self.item.get_line().replace(' ','')[len(self.blocktype):].strip()
+ if name:
+ self.name = name
+ return BeginStatement.process_item(self)
+
+# Interface
+
+class EndInterface(EndStatement):
+ match = re.compile(r'end\s*interface\s*\w*\Z', re.I).match
+ blocktype = 'interface'
+
+class Interface(BeginStatement):
+ """
+ INTERFACE [generic-spec] | ABSTRACT INTERFACE
+ END INTERFACE [generic-spec]
+ """
+ modes = ['free90', 'fix90', 'pyf']
+ match = re.compile(r'(interface\s*\w*|abstract\s*interface)\Z',re.I).match
+ end_stmt_cls = EndInterface
+ blocktype = 'interface'
+
+ def get_classes(self):
+ return interface_specification
+
+ def process_item(self):
+ line = self.item.get_line()
+ self.isabstract = line.startswith('abstract')
+ if self.isabstract:
+ self.generic_spec = ''
+ else:
+ self.generic_spec = line[len(self.blocktype):].strip()
+ self.name = self.generic_spec # XXX
+ return BeginStatement.process_item(self)
+
+ def tostr(self):
+ if self.isabstract:
+ return 'ABSTRACT INTERFACE'
+ return 'INTERFACE '+ str(self.generic_spec)
+
+
+# Subroutine
+
+class EndSubroutine(EndStatement):
+ """
+ END [SUBROUTINE [name]]
+ """
+ match = re.compile(r'end(\s*subroutine\s*\w*|)\Z', re.I).match
+
+class Subroutine(BeginStatement):
+ """
+ [prefix] SUBROUTINE <name> [ ( [<dummy-arg-list>] ) [<proc-language-binding-spec>]]
+ """
+ end_stmt_cls = EndSubroutine
+ match = re.compile(r'[\w\s]*subroutine\s*\w+', re.I).match
+
+ item_re = re.compile(r'(?P<prefix>[\w\s]*)\s*subroutine\s*(?P<name>\w+)', re.I).match
+ def process_item(self):
+ line = self.item.get_line()
+ m = self.item_re(line)
+ self.name = m.group('name')
+ line = line[m.end():].strip()
+ args = []
+ if line.startswith('('):
+ assert line.endswith(')'),`line`
+ for a in line.split(','):
+ args.append(a.strip())
+ self.args = args
+ return BeginStatement.process_item(self)
+
+ def get_classes(self):
+ return specification_part + execution_part + internal_subprogram_part
+
+# Function
+
+class EndFunction(EndStatement):
+ """
+ END [FUNCTION [name]]
+ """
+ match = re.compile(r'end(\s*function\s*\w*|)\Z', re.I).match
+
+class Function(BeginStatement):
+ """
+ [prefix] SUBROUTINE <name> [ ( [<dummy-arg-list>] ) [suffix]
+ """
+ end_stmt_cls = EndFunction
+ match = re.compile(r'([\w\s]+(\(\s*\w+\s*\)|)|)\s*function\s*\w+', re.I).match
+ item_re = re.compile(r'(?P<prefix>([\w\s](\(\s*\w+\s*\)|))*)\s*function\s*(?P<name>\w+)\s*\((?P<args>.*)\)\s*(?P<suffix>.*)\Z', re.I).match
+
+ def process_item(self):
+ line = self.item.get_line()
+ m = self.item_re(line)
+ if m is None:
+ self.isvalid = False
+ return
+ self.name = m.group('name')
+ self.prefix = m.group('prefix').strip()
+ self.suffix = m.group('suffix').strip()
+ args = []
+ for a in m.group('args').split(','):
+ args.append(a.strip())
+ self.args = args
+ return BeginStatement.process_item(self)
+
+ def tostr(self):
+ return '%s FUNCTION %s(%s) %s' % (self.prefix, self.name,
+ ', '.join(self.args), self.suffix)
+
+ def get_classes(self):
+ return specification_part + execution_part + internal_subprogram_part
+
+# SelectCase
+
+class EndSelect(EndStatement):
+ match = re.compile(r'end\s*select\s*\w*\Z', re.I).match
+ blocktype = 'select'
+
+class Select(BeginStatement):
+ """
+ [ <case-construct-name> : ] SELECT CASE ( <case-expr> )
+
+ """
+ match = re.compile(r'select\s*case\s*\(.*\)\Z',re.I).match
+ end_stmt_cls = EndSelect
+ name = ''
+ def tostr(self):
+ return 'SELECT CASE ( %s )' % (self.expr)
+ def process_item(self):
+ self.expr = self.item.get_line()[6:].lstrip()[4:].lstrip()[1:-1].strip()
+ self.name = self.item.label
+ return BeginStatement.process_item(self)
+
+ def get_classes(self):
+ return [Case] + execution_part_construct
+
+# IfThen
+
+class EndIfThen(EndStatement):
+ match = re.compile(r'end\s*if\s*\w*\Z', re.I).match
+ blocktype = 'if'
+
+class IfThen(BeginStatement):
+ """
+ [<if-construct-name> :] IF ( <scalar-logical-expr> ) THEN
+
+ IfThen instance has the following attributes:
+ expr
+ """
+
+ match = re.compile(r'if\s*\(.*\)\s*then\Z',re.I).match
+ end_stmt_cls = EndIfThen
+ name = ''
+
+ def tostr(self):
+ return 'IF (%s) THEN' % (self.expr)
+
+ def process_item(self):
+ item = self.item
+ line = item.get_line()[2:-4].strip()
+ assert line[0]=='(' and line[-1]==')',`line`
+ self.expr = line[1:-1].strip()
+ self.name = item.label
+ return BeginStatement.process_item(self)
+
+ def get_classes(self):
+ return [Else, ElseIf] + execution_part_construct
+
+class If(BeginStatement):
+ """
+ IF ( <scalar-logical-expr> ) action-stmt
+ """
+
+ match = re.compile(r'if\s*\(').match
+
+ def process_item(self):
+ item = self.item
+ mode = self.reader.mode
+ classes = self.get_classes()
+ classes = [cls for cls in classes if mode in cls.modes]
+
+ line = item.get_line()[2:]
+ i = line.find(')')
+ expr = line[1:i].strip()
+ line = line[i+1:].strip()
+ if line=='then':
+ self.isvalid = False
+ return
+ self.expr = expr[1:-1]
+
+ newitem = item.copy(line)
+ for cls in classes:
+ if cls.match(line):
+ stmt = cls(self, newitem)
+ if stmt.isvalid:
+ self.content.append(stmt)
+ return
+ self.handle_unknown_item(newitem)
+ return
+
+ def tostr(self):
+ assert len(self.content)==1,`self.content`
+ return 'IF (%s) %s' % (self.expr, str(self.content[0]).lstrip())
+
+ def __str__(self):
+ return self.get_indent_tab(colon=':') + self.tostr()
+
+ def get_classes(self):
+ return action_stmt
+
+# Do
+
+class EndDo(EndStatement):
+ """
+ """
+ match = re.compile(r'end\s*do\s*\w*\Z', re.I).match
+ blocktype = 'do'
+
+class Do(BeginStatement):
+ """
+ [ <do-construct-name> : ] DO label [loopcontrol]
+ [ <do-construct-name> : ] DO [loopcontrol]
+
+ """
+
+ match = re.compile(r'do\b\s*\d*',re.I).match
+ item_re = re.compile(r'do\b\s*(?P<label>\d*)\s*,?\s*(?P<loopcontrol>.*)\Z',re.I).match
+ end_stmt_cls = EndDo
+ name = ''
+
+ def tostr(self):
+ return 'DO %s %s' % (self.endlabel, self.loopcontrol)
+
+ def process_item(self):
+ item = self.item
+ line = item.get_line()
+ m = self.item_re(line)
+ self.endlabel = m.group('label').strip()
+ self.name = item.label
+ self.loopcontrol = m.group('loopcontrol').strip()
+ return BeginStatement.process_item(self)
+
+ def process_subitem(self, item):
+ r = False
+ if self.endlabel:
+ label = item.label
+ if label == self.endlabel:
+ r = True
+ if isinstance(self.parent, Do) and label==self.parent.endlabel:
+ # the same item label may be used for different block ends
+ self.put_item(item)
+ return BeginStatement.process_subitem(self, item) or r
+
+ def get_classes(self):
+ return execution_part_construct
+
+class EndType(EndStatement):
+ """
+ END TYPE [<type-name>]
+ """
+ match = re.compile(r'end\s*type\s*\w*\Z', re.I).match
+ blocktype = 'type'
+
+class Type(BeginStatement):
+ """
+ TYPE [ [, <type-attr-spec-list>] ::] <type-name> [ ( <type-param-name-list> ) ]
+ <type-attr-spec> = <access-spec> | EXTENDS ( <parent-type-name> )
+ | ABSTRACT | BIND(C)
+ """
+ match = re.compile(r'type\b\s*').match
+ end_stmt_cls = EndType
+
+ def process_item(self):
+ line = self.item.get_line()[4:].lstrip()
+ if line.startswith('('):
+ self.isvalid = False
+ return
+ attr_specs = []
+ i = line.find('::')
+ if i!=-1:
+ for s in line[:i].split(','):
+ s = s.strip()
+ if s: attr_specs.append(s)
+ line = line[i+2:].lstrip()
+ self.attr_specs = attr_specs
+ i = line.find('(')
+ if i!=-1:
+ self.name = line[:i].rstrip()
+ assert line[-1]==')',`line`
+ self.params = line[i+1:-1].lstrip()
+ else:
+ self.name = line
+ self.params = ''
+ return BeginStatement.process_item(self)
+
+ def tostr(self):
+ s = 'TYPE'
+ if self.attr_specs:
+ s += ', '.join(['']+self.attr_specs) + ' ::'
+ s += ' ' + self.name
+ if self.params:
+ s += ' ('+self.params+')'
+ return s
+
+ def get_classes(self):
+ return [Integer] + private_or_sequence + component_part + type_bound_procedure_part
+
+TypeDecl = Type
+
+###################################################
+
+from statements import *
+from typedecl_statements import *
+
+access_spec = [Public, Private]
+
+interface_specification = [Function, Subroutine,
+ ModuleProcedure
+ ]
+
+module_subprogram_part = [
+ Contains,
+ Function,
+ Subroutine
+ ]
+
+specification_stmt = [
+ # Access, Allocatable, Asynchronous, Bind, Common,
+ Data, Dimension,
+ Equivalence, #External, Intent
+ # Intrinsic, Namelist, Optional, Pointer, Protected,
+ Save, #Target, Volatile, Value
+ ]
+intrinsic_type_spec = [
+ Integer , Real, DoublePrecision, Complex, Character, Logical
+ ]
+declaration_type_spec = intrinsic_type_spec + [
+ TypeStmt,
+ Class
+ ]
+type_declaration_stmt = declaration_type_spec
+
+private_or_sequence = [
+ Private, #Sequence
+ ]
+
+component_part = declaration_type_spec + [
+ #Procedure
+ ]
+
+type_bound_procedure_part = [
+ Contains, Private, #Procedure, Generic, Final
+ ]
+
+#R214
+action_stmt = [
+ Allocate,
+ Assignment, #PointerAssignment,
+ Backspace,
+ Call,
+ Close,
+ Continue,
+ Cycle,
+ Deallocate,
+ Endfile, #EndFunction, EndProgram, EndSubroutine,
+ Exit,
+ # Flush, Forall,
+ Goto, If, #Inquire,
+ Nullify,
+ Open,
+ Print, Read,
+ Return,
+ Rewind,
+ Stop, #Wait, Where,
+ Write,
+ # arithmetic-if-stmt, computed-goto-stmt
+ ]
+
+executable_construct = action_stmt + [
+ # Associate, Case,
+ Do,
+ # Forall,
+ IfThen,
+ Select, #Where
+ ]
+execution_part_construct = executable_construct + [
+ Format, #Entry, Data
+ ]
+execution_part = execution_part_construct[:]
+
+#C201, R208
+for cls in [EndFunction, EndProgram, EndSubroutine]:
+ try: execution_part.remove(cls)
+ except ValueError: pass
+
+internal_subprogram = [Function, Subroutine]
+internal_subprogram_part = [
+ Contains,
+ ] + internal_subprogram
+
+declaration_construct = [
+ TypeDecl, #Entry, Enum,
+ Format,
+ Interface,
+ Parameter, #Procedure,
+ ] + specification_stmt + type_declaration_stmt # stmt-function-stmt
+implicit_part = [
+ Implicit, Parameter, Format, #Entry
+ ]
+specification_part = [
+ Use, #Import
+ ] + implicit_part + declaration_construct
+external_subprogram = [Function, Subroutine]
+main_program = [Program] + specification_part + execution_part + internal_subprogram_part
+program_unit = main_program + external_subprogram + [Module,
+ #BlockData
+ ]
diff --git a/numpy/f2py/lib/init.py b/numpy/f2py/lib/init.py
index a803a9580..75d9420c9 100644
--- a/numpy/f2py/lib/init.py
+++ b/numpy/f2py/lib/init.py
@@ -58,28 +58,28 @@ StatementBlock.classes['pyf'] = StatementBlock.classes['free90']
# Initialize stmt_cls attributes
-ProgramBlock.stmt_cls = Program
-ModuleBlock.stmt_cls = Module
-PythonModuleBlock.stmt_cls = PythonModule
-BlockDataBlock.stmt_cls = BlockData
-InterfaceBlock.stmt_cls = Interface
-SubroutineBlock.stmt_cls = Subroutine
-FunctionBlock.stmt_cls = Function
-TypeBlock.stmt_cls = Type
-
-IfThenBlock.stmt_cls = IfThen
-DoBlock.stmt_cls = Do
-SelectBlock.stmt_cls = Select
-
-ProgramBlock.end_stmt_cls = EndProgram
-ModuleBlock.end_stmt_cls = EndModule
-PythonModuleBlock.end_stmt_cls = EndPythonModule
-BlockDataBlock.end_stmt_cls = EndBlockData
-InterfaceBlock.end_stmt_cls = EndInterface
-SubroutineBlock.end_stmt_cls = EndSubroutine
-FunctionBlock.end_stmt_cls = EndFunction
-TypeBlock.end_stmt_cls = EndType
-
-IfThenBlock.end_stmt_cls = EndIfThen
-DoBlock.end_stmt_cls = EndDo
-SelectBlock.end_stmt_cls = EndSelect
+## ProgramBlock.stmt_cls = Program
+## ModuleBlock.stmt_cls = Module
+## PythonModuleBlock.stmt_cls = PythonModule
+## BlockDataBlock.stmt_cls = BlockData
+## InterfaceBlock.stmt_cls = Interface
+## SubroutineBlock.stmt_cls = Subroutine
+## FunctionBlock.stmt_cls = Function
+## TypeBlock.stmt_cls = Type
+
+## IfThenBlock.stmt_cls = IfThen
+## DoBlock.stmt_cls = Do
+## SelectBlock.stmt_cls = Select
+
+## ProgramBlock.end_stmt_cls = EndProgram
+## ModuleBlock.end_stmt_cls = EndModule
+## PythonModuleBlock.end_stmt_cls = EndPythonModule
+## BlockDataBlock.end_stmt_cls = EndBlockData
+## InterfaceBlock.end_stmt_cls = EndInterface
+## SubroutineBlock.end_stmt_cls = EndSubroutine
+## FunctionBlock.end_stmt_cls = EndFunction
+## TypeBlock.end_stmt_cls = EndType
+
+## IfThenBlock.end_stmt_cls = EndIfThen
+## DoBlock.end_stmt_cls = EndDo
+## SelectBlock.end_stmt_cls = EndSelect
diff --git a/numpy/f2py/lib/parsefortran.py b/numpy/f2py/lib/parsefortran.py
index 380c10ffd..71355a9ad 100644
--- a/numpy/f2py/lib/parsefortran.py
+++ b/numpy/f2py/lib/parsefortran.py
@@ -16,7 +16,7 @@ import traceback
from numpy.distutils.misc_util import yellow_text, red_text
from readfortran import FortranFileReader, FortranStringReader
-from block import Block
+from block_statements import BeginSource
class FortranParser:
@@ -37,8 +37,7 @@ class FortranParser:
def parse(self):
import init
try:
- main = Block(self)
- main.fill()
+ main = BeginSource(self)
return main
except KeyboardInterrupt:
raise
@@ -53,11 +52,11 @@ class FortranParser:
def test_pyf():
string = """
python module foo
- interface
+ interface tere
subroutine bar
real r
end subroutine bar
- end interface
+ end interface tere
end python module foo
"""
reader = FortranStringReader(string, True, True)
@@ -79,8 +78,15 @@ module foo
if (.true.) then
call smth
end if
+ aaa : if (.false.) then
+ else if (a) then aaa
+ else aaa
+ end if aaa
+ hey = 1
end subroutine bar
+ abstract interface
+ end interface
end module foo
"""
reader = FortranStringReader(string, True, False)
@@ -109,7 +115,7 @@ def simple_main():
parser = FortranParser(reader)
block = parser.parse()
- print block
+ #print block
def profile_main():
import hotshot, hotshot.stats
@@ -127,3 +133,4 @@ if __name__ == "__main__":
#test_pyf()
simple_main()
#profile_main()
+
diff --git a/numpy/f2py/lib/readfortran.py b/numpy/f2py/lib/readfortran.py
index 03a64534a..1d6335865 100644
--- a/numpy/f2py/lib/readfortran.py
+++ b/numpy/f2py/lib/readfortran.py
@@ -51,6 +51,21 @@ class Line:
self.label = label
self.reader = reader
self.strline = None
+ def copy(self, line = None, apply_map = False):
+ if line is None:
+ line = self.line
+ if apply_map and hasattr(self,'strlinemap'):
+ str_map = self.strlinemap
+ keys = str_map.keys()
+ flag = True
+ while flag:
+ flag = False
+ for k in keys:
+ if k in line:
+ flag = True
+ line = line.replace(k, str_map[k])
+ assert k not in line, `k,line`
+ return Line(line, self.span, self.label, self.reader)
def __repr__(self):
return self.__class__.__name__+'(%r,%s,%r)' \
% (self.line, self.span, self.label)
@@ -139,6 +154,8 @@ class FortranReaderBase:
self.fifo_item = []
self.source_lines = []
+ self.name = '%s mode=%s' % (source, mode)
+
def close_source(self):
# called when self.source.next() raises StopIteration.
pass
@@ -208,6 +225,15 @@ class FortranReaderBase:
break
# else ignore empty lines and comments
if not isinstance(item, Comment):
+ if isinstance(item, Line) and ';' in item.get_line():
+ items = []
+ for line in item.get_line().split(';'):
+ line = line.strip()
+ items.append(item.copy(line, apply_map=True))
+ items.reverse()
+ for newitem in items:
+ self.fifo_item.insert(0, newitem)
+ return fifo_item_pop(0)
return item
# collect subsequent comments to one comment instance
comments = []
diff --git a/numpy/f2py/lib/statements.py b/numpy/f2py/lib/statements.py
new file mode 100644
index 000000000..09b60d328
--- /dev/null
+++ b/numpy/f2py/lib/statements.py
@@ -0,0 +1,645 @@
+
+import re
+import sys
+
+from base_classes import Statement
+
+# Execution statements
+
+class Assignment(Statement):
+ """
+ <variable> = <expr>
+ <pointer variable> => <expr>
+ """
+
+ match = re.compile(r'\w(\s*\(\s*[^)]*\)|[\w%]*)*\s*=\>?',re.I).match
+ item_re = re.compile(r'(?P<variable>\w(\s*\(\s*[^)]*\)|[\w%]*)*)\s*(?P<sign>=\>?)\s*(?P<expr>.*)\Z',re.I).match
+
+ def process_item(self):
+ m = self.item_re(self.item.get_line())
+ self.variable = m.group('variable').replace(' ','')
+ self.sign = m.group('sign')
+ self.expr = m.group('expr')
+ return
+
+ def __str__(self):
+ return self.get_indent_tab() + '%s %s %s' \
+ % (self.variable, self.sign, self.expr)
+
+class Call(Statement):
+ """Call statement class
+ CALL <proc-designator> [([arg-spec-list])]
+
+ Call instance has attributes:
+ designator
+ arg_list
+ """
+ match = re.compile(r'call\b', re.I).match
+
+ def process_item(self):
+ item = self.item
+ line = item.get_line()[4:].strip()
+ i = line.find('(')
+ self.arg_list = []
+ if i==-1:
+ self.designator = line.strip()
+ else:
+ self.designator = line[:i].strip()
+ for n in line[i+1:-1].split(','):
+ n = n.strip()
+ if not n: continue
+ self.arg_list.append(n)
+ return
+
+ def __str__(self):
+ s = self.get_indent_tab() + 'CALL '+str(self.designator)
+ if self.arg_list:
+ s += '('+', '.join(map(str,self.arg_list))+ ')'
+ return s
+
+class Goto(Statement):
+ """
+ GO TO <label>
+
+ """
+ match = re.compile(r'go\s*to\b\s*\w*\Z', re.I).match
+
+ def process_item(self):
+ self.gotolabel = self.item.get_line()[2:].strip()[2:].strip()
+ return
+
+ def __str__(self):
+ return self.get_indent_tab() + 'GO TO %s' % (self.gotolabel)
+
+class Continue(Statement):
+ """
+ CONTINUE
+ """
+ match = re.compile(r'continue\Z',re.I).match
+
+ def process_item(self):
+ self.label = self.item.label
+ return
+
+ def __str__(self):
+ return self.get_indent_tab(deindent=True) + 'CONTINUE'
+
+
+class Return(Statement):
+ """
+ RETURN [scalar-int-expr]
+ """
+ match = re.compile(r'return\b',re.I).match
+
+ def process_item(self):
+ line = self.item.get_line()[6:].lstrip()
+ self.expr = line
+ return
+
+ def __str__(self):
+ return self.get_indent_tab() + 'RETURN %s' % (self.expr)
+
+class Stop(Statement):
+ """
+ STOP [stop-code]
+ """
+ match = re.compile(r'stop\b\s*\w*\Z',re.I).match
+
+ def process_item(self):
+ self.stopcode = self.item.get_line()[4:].lstrip()
+ return
+
+ def __str__(self):
+ return self.get_indent_tab() + 'STOP %s' % (self.stopcode)
+
+class Print(Statement):
+ """
+ PRINT <format> [, <output-item-list>]
+ <format> == <default-char-expr> | <label> | *
+ """
+ match = re.compile(r'print\b\s*[\w*]', re.I).match
+
+ def process_item(self):
+ item = self.item
+ line = item.get_line()[5:].lstrip()
+ items = line.split(',')
+ self.format = items[0].strip()
+ self.items = [s.strip() for s in items[1:]]
+ return
+
+ def __str__(self):
+ return self.get_indent_tab() + 'PRINT %s' % (', '.join([self.format]+self.items))
+
+class Read(Statement):
+ """
+Read0: READ ( io-control-spec-list ) [<input-item-list>]
+
+Read1: READ <format> [, <input-item-list>]
+ <format> == <default-char-expr> | <label> | *
+ """
+ match = re.compile(r'read\b\s*[\w(*]', re.I).match
+
+ def process_item(self):
+ item = self.item
+ line = item.get_line()[4:].lstrip()
+ if line.startswith('('):
+ self.__class__ = Read0
+ else:
+ self.__class__ = Read1
+ self.process_item()
+
+class Read0(Read):
+
+ def process_item(self):
+ item = self.item
+ line = item.get_line()[4:].lstrip()
+ i = line.find(')')
+ self.io_control_specs = line[1:i].strip()
+ self.items = [s.strip() for s in line[i+1:].split(',')]
+
+ def __str__(self):
+ return self.get_indent_tab() + 'READ (%s) %s' \
+ % (self.io_control_specs, ', '.join(self.items))
+
+class Read1(Read):
+
+ def process_item(self):
+ item = self.item
+ line = item.get_line()[4:].lstrip()
+ items = line.split(',')
+ self.format = items[0].strip()
+ self.items = [s.strip() for s in items[1:]]
+ return
+
+ def __str__(self):
+ return self.get_indent_tab() + 'READ %s' % (', '.join([self.format]+self.items))
+
+class Write(Statement):
+ """
+ WRITE ( io-control-spec-list ) [<output-item-list>]
+ """
+ match = re.compile(r'write\s*\(', re.I).match
+ def process_item(self):
+ item = self.item
+ line = item.get_line()[5:].lstrip()
+ i = line.find(')')
+ self.io_control_specs = line[1:i].strip()
+ self.items = [s.strip() for s in line[i+1:].split(',')]
+
+ def __str__(self):
+ return self.get_indent_tab() + 'WRITE (%s) %s' \
+ % (self.io_control_specs, ', '.join(self.items))
+
+class Contains(Statement):
+ """
+ CONTAINS
+ """
+ match = re.compile(r'contains\Z',re.I).match
+ def process_item(self):
+ return
+ def __str__(self): return self.get_indent_tab() + 'CONTAINS'
+
+class Allocate(Statement):
+ """
+ ALLOCATE ( [ <type-spec> :: ] <allocation-list> [ , <alloc-opt-list> ] )
+ """
+ match = re.compile(r'allocate\s*\(.*\)\Z',re.I).match
+ def process_item(self):
+ self.items = self.item.get_line()[8:].lstrip()[1:-1].strip()
+ def __str__(self): return self.get_indent_tab() \
+ + 'ALLOCATE ( %s )' % (self.items)
+
+class Deallocate(Statement):
+ """
+ DEALLOCATE ( <allocate-object-list> [ , <dealloc-opt-list> ] )
+ """
+ match = re.compile(r'deallocate\s*\(.*\)\Z',re.I).match
+ def process_item(self):
+ self.items = self.item.get_line()[10:].lstrip()[1:-1].strip()
+ def __str__(self): return self.get_indent_tab() \
+ + 'DEALLOCATE ( %s )' % (self.items)
+
+class ModuleProcedure(Statement):
+ """
+ [ MODULE ] PROCEDURE <procedure-name-list>
+ """
+ match = re.compile(r'(module\s*|)procedure\b',re.I).match
+ def process_item(self):
+ line = self.item.get_line()
+ m = self.match(line)
+ self.names = [s.strip() for s in line[m.end():].split(',')]
+ def __str__(self):
+ tab = self.get_indent_tab()
+ return tab + 'MODULE PROCEDURE %s' % (', '.join(self.names))
+
+class Access(Statement):
+ """
+ <access-spec> [ [::] <access-id-list>]
+ <access-spec> = PUBLIC | PRIVATE
+ """
+ match = re.compile(r'(public|private)\b',re.I).match
+ def process_item(self):
+ clsname = self.__class__.__name__.lower()
+ line = self.item.get_line()
+ if not line.startswith(clsname):
+ self.isvalid = False
+ return
+ line = line[len(clsname):].lstrip()
+ if line.startswith('::'):
+ line = line[2:].lstrip()
+ self.items = [s.strip() for s in line.split(',')]
+ def __str__(self):
+ clsname = self.__class__.__name__.upper()
+ tab = self.get_indent_tab()
+ if self.items:
+ return tab + clsname + ' :: ' + ', '.join(self.items)
+ return tab + clsname
+
+class Public(Access): pass
+class Private(Access): pass
+
+class Close(Statement):
+ """
+ CLOSE ( <close-spec-list> )
+ <close-spec> = [ UNIT = ] <file-unit-number>
+ | IOSTAT = <scalar-int-variable>
+ | IOMSG = <iomsg-variable>
+ | ERR = <label>
+ | STATUS = <scalar-default-char-expr>
+ """
+ match = re.compile(r'close\s*\(.*\)\Z',re.I).match
+ def process_item(self):
+ self.close_specs = self.item.get_line()[5:].lstrip()[1:-1].strip()
+ return
+ def __str__(self):
+ tab = self.get_indent_tab()
+ return tab + 'CLOSE (%s)' % (self.close_specs)
+
+class Cycle(Statement):
+ """
+ CYCLE [ <do-construct-name> ]
+ """
+ match = re.compile(r'cycle\b\s*\w*\Z',re.I).match
+ def process_item(self):
+ self.name = self.item.get_line()[5:].lstrip()
+ return
+ def __str__(self):
+ return self.get_indent_tab() + 'CYCLE ' + self.name
+
+class FilePositioningStatement(Statement):
+ """
+ REWIND <file-unit-number>
+ REWIND ( <position-spec-list> )
+ <position-spec-list> = [ UNIT = ] <file-unit-number>
+ | IOMSG = <iomsg-variable>
+ | IOSTAT = <scalar-int-variable>
+ | ERR = <label>
+ The same for BACKSPACE, ENDFILE.
+ """
+ match = re.compile(r'(rewind|backspace|endfile)\b',re.I).match
+
+ def process_item(self):
+ clsname = self.__class__.__name__.lower()
+ line = self.item.get_line()
+ if not line.startswith(clsname):
+ self.isvalid = False
+ return
+ line = line[len(clsname):].lstrip()
+ if line.startswith('('):
+ assert line[-1]==')',`line`
+ self.fileunit = None
+ self.position_specs = line[1:-1].strip()
+ else:
+ self.fileunit = line
+ self.position_specs = None
+ return
+
+ def __str__(self):
+ clsname = self.__class__.__name__.upper()
+ if self.fileunit is None:
+ return self.get_indent_tab() + clsname + ' (%s)' % (self.position_specs)
+ return self.get_indent_tab() + clsname + ' %s' % (self.fileunit)
+
+class Backspace(FilePositioningStatement): pass
+
+class Endfile(FilePositioningStatement): pass
+
+class Rewind(FilePositioningStatement): pass
+
+class Open(Statement):
+ """
+ OPEN ( <connect-spec-list> )
+ <connect-spec> = [ UNIT = ] <file-unit-number>
+ | ACCESS = <scalar-default-char-expr>
+ | ..
+ """
+ match = re.compile(r'open\s*\(.*\)\Z',re.I).match
+ def process_item(self):
+ self.connect_specs = self.item.get_line()[4:].lstrip()[1:-1].strip()
+ return
+ def __str__(self):
+ return self.get_indent_tab() + 'OPEN (%s)' % (self.connect_specs)
+
+class Format(Statement):
+ """
+ FORMAT <format-specification>
+ <format-specification> = ( [ <format-item-list> ] )
+
+ """
+ match = re.compile(r'format\s*\(.*\)\Z', re.I).match
+ def process_item(self):
+ item = self.item
+ if not item.label:
+ # R1001:
+ message = self.reader.format_message(\
+ 'WARNING',
+ 'R1001: FORMAT statement must be labeled but got %r.' \
+ % (item.label),
+ item.span[0],item.span[1])
+ print >> sys.stderr, message
+ line = item.get_line()[6:].lstrip()
+ assert line[0]+line[-1]=='()',`line`
+ self.specs = line[1:-1].strip()
+ return
+ def __str__(self):
+ return self.get_indent_tab() + 'FORMAT (%s)' % (self.specs)
+
+class Save(Statement):
+ """
+ SAVE [ [ :: ] <saved-entity-list> ]
+ <saved-entity> = <object-name>
+ | <proc-pointer-name>
+ | / <common-block-name> /
+ <proc-pointer-name> = <name>
+ <object-name> = <name>
+ """
+ match = re.compile(r'save\b',re.I).match
+ is_name = re.compile(r'\w+\Z').match
+ def process_item(self):
+ line = self.item.get_line()[4:].lstrip()
+ if line.startswith('::'):
+ line = line[2:].lstrip()
+ items = []
+ for s in line.split(','):
+ s = s.strip()
+ if not s: continue
+ if s.startswith('/'):
+ assert s.endswith('/'),`s`
+ n = s[1:-1].strip()
+ assert self.is_name(n)
+ items.append('/%s/' % ())
+ elif self.is_name(s):
+ items.append(s)
+ else:
+ self.isvalid = False
+ return
+ self.items = items
+ return
+ def __str__(self):
+ tab = self.get_indent_tab()
+ if not self.items:
+ return tab + 'SAVE'
+ return tab + 'SAVE :: %s' % (', '.join(self.items))
+
+class Data(Statement):
+ """
+ DATA <data-stmt-set> [ [ , ] <data-stmt-set> ]...
+ <data-stmt-set> = <data-stmt-object-list> / <data-stmt-value-list> /
+ <data-stmt-object> = <variable> | <data-implied-do>
+ <data-implied-do> = ( <data-i-do-object-list> , <data-i-do-variable> = <scalar-int-expr> , <scalar-int-expr> [ , <scalar-int-expr> ] )
+ <data-i-do-object> = <array-element> | <scalar-structure-component> | <data-implied-do>
+ <data-i-do-variable> = <scalar-int-variable>
+ <variable> = <designator>
+ <designator> = <object-name>
+ | <array-element>
+ | <array-section>
+ | <structure-component>
+ | <substring>
+ <array-element> = <data-ref>
+ <array-section> = <data-ref> [ ( <substring-range> ) ]
+
+ """
+ match = re.compile(r'data\b',re.I).match
+
+ def process_item(self):
+ line = self.item.get_line()[4:].lstrip()
+ stmts = []
+ while line:
+ i = line.find('/')
+ assert i!=-1,`line`
+ j = line.find('/',i+1)
+ assert j!=-1,`line`
+ stmts.append((line[:i].rstrip(),line[i+1:j].strip()))
+ line = line[j+1:].lstrip()
+ if line.startswith(','):
+ line = line[1:].lstrip()
+ self.stmts = stmts
+ return
+
+ def __str__(self):
+ tab = self.get_indent_tab()
+ l = []
+ for o,v in self.stmts:
+ l.append('%s / %s /' %(o,v))
+ return tab + 'DATA ' + ' '.join(l)
+
+class Nullify(Statement):
+ """
+ NULLIFY ( <pointer-object-list> )
+ <pointer-object> = <variable-name>
+ """
+ match = re.compile(r'nullify\s*\(.*\)\Z',re.I).match
+ def process_item(self):
+ self.item_list = self.item.get_line()[7:].lstrip()[1:-1].strip()
+ return
+ def __str__(self):
+ return self.get_indent_tab() + 'NULLIFY (%s)' % (self.item_list)
+
+class Use(Statement):
+ """
+ USE [ [ , <module-nature> ] :: ] <module-name> [ , <rename-list> ]
+ USE [ [ , <module-nature> ] :: ] <module-name> , ONLY : [ <only-list> ]
+ <module-nature> = INTRINSIC | NON_INTRINSIC
+ <rename> = <local-name> => <use-name>
+ | OPERATOR ( <local-defined-operator> ) => OPERATOR ( <use-defined-operator> )
+ <only> = <generic-spec> | <only-use-name> | <rename>
+ <only-use-name> = <use-name>
+ """
+ match = re.compile(r'use\b',re.I).match
+ def process_item(self):
+ line = self.item.get_line()[3:].lstrip()
+ nature = ''
+ if line.startswith(','):
+ i = line.find('::')
+ nature = line[1:i].strip()
+ line = line[i+2:].lstrip()
+ if line.startswith('::'):
+ line = line[2:].lstrip()
+ self.nature = nature
+ i = line.find(',')
+ self.isonly = False
+ if i==-1:
+ self.module = line
+ self.items = []
+ else:
+ self.module = line[:i].rstrip()
+ line = line[i+1:].lstrip()
+ if line.startswith('only') and line[4:].lstrip().startswith(':'):
+ self.isonly = True
+ line = line[4:].lstrip()[1:].lstrip()
+ self.items = [s.strip() for s in line.split(',')]
+
+ def __str__(self):
+ tab = self.get_indent_tab()
+ s = 'USE'
+ if self.nature:
+ s += ' ' + self.nature + ' ::'
+ s += ' ' + self.module
+ if self.isonly:
+ s += ' ONLY:'
+ elif self.items:
+ s += ','
+ if self.items:
+ s += ' ' + ', '.join(self.items)
+ return s
+
+class Exit(Statement):
+ """
+ EXIT [ <do-construct-name> ]
+ """
+ match = re.compile(r'exit\b\s*\w*\Z',re.I).match
+ def process_item(self):
+ self.exitname = self.item.get_line()[4:].lstrip()
+ return
+ def __str__(self):
+ return self.get_indent_tab() + 'EXIT ' + self.exitname
+
+class Parameter(Statement):
+ """
+ PARAMETER ( <named-constant-def-list> )
+ <named-constant-def> = <named-constant> = <initialization-expr>
+ """
+ match = re.compile(r'parameter\s*\(.*\)\Z', re.I).match
+ def process_item(self):
+ self.params = self.item.get_line()[9:].lstrip()[1:-1].strip()
+ return
+ def __str__(self):
+ return self.get_indent_tab() + 'PARAMETER (%s)' % (self.params)
+
+class Equivalence(Statement):
+ """
+ EQUIVALENCE <equivalence-set-list>
+ <equivalence-set> = ( <equivalence-object> , <equivalence-object-list> )
+ <equivalence-object> = <variable-name> | <array-element> | <substring>
+ """
+ match = re.compile(r'equivalence\s*\(.*\)\Z', re.I).match
+ def process_item(self):
+ items = []
+ for s in self.item.get_line()[12:].lstrip().split(','):
+ s = s.strip()
+ assert s[0]+s[-1]=='()',`s`
+ items.append(s)
+ self.items = items
+ def __str__(self):
+ return self.get_indent_tab() + 'EQUIVALENCE %s' % (', '.join(self.items))
+
+class Dimension(Statement):
+ """
+ DIMENSION [ :: ] <array-name> ( <array-spec> ) [ , <array-name> ( <array-spec> ) ]...
+
+ """
+ match = re.compile(r'dimension\b').match
+ def process_item(self):
+ line = self.item.get_line()[9:].lstrip()
+ if line.startswith('::'):
+ line = line[2:].lstrip()
+ self.items = [s.split() for s in line.split(',')]
+ return
+ def __str__(self):
+ return self.get_indent_tab() + 'DIMENSION %s' % (', '.join(self.items))
+
+# IF construct statements
+
+class Else(Statement):
+ """
+ ELSE [<if-construct-name>]
+ """
+ match = re.compile(r'else\s*\w*\Z',re.I).match
+
+ def process_item(self):
+ item = self.item
+ self.name = item.get_line()[4:].strip()
+ if self.name and not self.name==self.parent.name:
+ message = self.reader.format_message(\
+ 'WARNING',
+ 'expected if-construct-name %r but got %r, skipping.'\
+ % (self.parent.name, self.name),
+ item.span[0],item.span[1])
+ print >> sys.stderr, message
+ self.isvalid = False
+ return
+
+ def __str__(self):
+ return self.get_indent_tab(deindent=True) + 'ELSE ' + self.name
+
+class ElseIf(Statement):
+ """
+ ELSE IF ( <scalar-logical-expr> ) THEN [<if-construct-name>]
+ """
+ match = re.compile(r'else\s*if\s*\(.*\)\s*then\s*\w*\Z',re.I).match
+
+ def process_item(self):
+ item = self.item
+ line = item.get_line()[4:].lstrip()[2:].lstrip()
+ i = line.find(')')
+ assert line[0]=='('
+ self.expr = line[1:i]
+ self.name = line[i+1:].lstrip()[4:].strip()
+ if self.name and not self.name==self.parent.name:
+ message = self.reader.format_message(\
+ 'WARNING',
+ 'expected if-construct-name %r but got %r, skipping.'\
+ % (self.parent.name, self.name),
+ item.span[0],item.span[1])
+ print >> sys.stderr, message
+ self.isvalid = False
+ return
+
+ def __str__(self):
+ return self.get_indent_tab(deindent=True) + 'ELSE IF (%s) THEN %s' \
+ % (self.expr, self.name)
+
+# SelectCase construct statements
+
+class Case(Statement):
+ """
+ CASE <case-selector> [ <case-constract-name> ]
+ <case-selector> = ( <case-value-range-list> ) | DEFAULT
+ <case-value-range> = <case-value>
+ | <case-value> :
+ | : <case-value>
+ | <case-value> : <case-value>
+ <case-value> = <scalar-(int|char|logical)-initialization-expr>
+ """
+ match = re.compile(r'case\b\s*(\(.*\)|DEFAULT)\s*\w*\Z',re.I).match
+ def process_item(self):
+ assert self.parent.__class__.__name__=='Select',`self.parent.__class__`
+ line = self.item.get_line()[4:].lstrip()
+ if line.startswith('('):
+ i = line.find(')')
+ self.ranges = line[1:i].strip()
+ line = line[i+1:].lstrip()
+ else:
+ assert line.startswith('default'),`line`
+ self.ranges = ''
+ line = line[7:].lstrip()
+ self.name = line
+ if self.name and not self.name==self.parent.name:
+ message = self.reader.format_message(\
+ 'WARNING',
+ 'expected case-construct-name %r but got %r, skipping.'\
+ % (self.parent.name, self.name),
+ self.item.span[0],self.item.span[1])
+ print >> sys.stderr, message
+ self.isvalid = False
+ return
diff --git a/numpy/f2py/lib/stmt.py b/numpy/f2py/lib/stmt.py
index 285423511..552b194cc 100644
--- a/numpy/f2py/lib/stmt.py
+++ b/numpy/f2py/lib/stmt.py
@@ -1,8 +1,11 @@
+#!/usr/bin/env python
"""Single line Fortran statements.
"""
-__all__ = ['statements', 'end_stmts', 'block_stmts',
+__all__ = ['statements',
+ #'end_stmts',
+ 'block_stmts',
'IfThen', 'Program', 'Module', 'PythonModule',
'BlockData','Interface', 'Subroutine','Function',
'Type','Do','Select',
@@ -13,7 +16,15 @@ __all__ = ['statements', 'end_stmts', 'block_stmts',
import re
import sys
+
class Statement:
+ """
+ Statement instance has attributes:
+ parent - Block or FortranParser instance
+ item - Line instance containing the statement line
+ name - statement label
+ isvalid - boolean, when False, the Statement instance will be ignored
+ """
def __init__(self, parent, item, name=None):
self.parent = parent
@@ -42,7 +53,21 @@ class Statement:
tab = s + colon + tab
return tab
-# End statements
+
+# Base classes for block begin and end statements:
+
+class BeginStatement(Statement):
+ """ <blocktype> <name>
+
+ BeginStatement instances have the following attributes:
+ name
+ isvalid
+ """
+ def __init__(self, parent, item):
+ name = item.get_line().replace(' ','')[len(self.blocktype):].strip()
+ if not name:
+ name = '__'+self.blocktype.upper()+'__'
+ Statement.__init__(self, parent, item, name)
class EndStatement(Statement):
"""
@@ -78,12 +103,21 @@ class EndStatement(Statement):
return self.get_intent_tab()[:-2] + 'END %s %s'\
% (self.blocktype.upper(),self.name or '')
+##
+
+class Program(BeginStatement):
+ """ PROGRAM [name]
+ """
+ blocktype = 'program'
+ start_re = re.compile(r'program\s*\w*\Z', re.I).match
+
class EndProgram(EndStatement):
"""
END [PROGRAM [name]]
"""
- start_re = re.compile(r'end(\s*program\s*\w*|)\Z', re.I).match
blocktype = 'program'
+ start_re = re.compile(r'end(\s*program\s*\w*|)\Z', re.I).match
+
class EndModule(EndStatement):
"""
@@ -156,26 +190,8 @@ class EndDo(EndStatement):
start_re = re.compile(r'end\s*do\s*\w*', re.I).match
blocktype = 'do'
-# Begin statements
-class BeginStatement(Statement):
- """ <blocktype> <name>
-
- BeginStatement instances have the following attributes:
- name
- isvalid
- """
- def __init__(self, parent, item):
- name = item.get_line().replace(' ','')[len(self.blocktype):].strip()
- if not name:
- name = '__'+self.blocktype.upper()+'__'
- Statement.__init__(self, parent, item, name)
-class Program(BeginStatement):
- """ PROGRAM [name]
- """
- blocktype = 'program'
- start_re = re.compile(r'program\s*\w*\Z', re.I).match
class Module(BeginStatement):
"""
@@ -554,11 +570,11 @@ class Format(Statement):
def __str__(self):
return self.get_intent_tab() + 'FORMAT (%s)' % (self.spec)
-end_stmts = {'ModuleBlock':EndModule, 'PythonModuleBlock':EndPythonModule,
- 'TypeBlock':EndType,
- 'SubroutineBlock':EndSubroutine,'FunctionBlock':EndFunction,
- 'IfThenBlock':EndIfThen,'DoBlock':EndDo,'InterfaceBlock':EndInterface,
- 'SelectBlock':EndSelect}
+#end_stmts = {'ModuleBlock':EndModule, 'PythonModuleBlock':EndPythonModule,
+# 'TypeBlock':EndType,
+# 'SubroutineBlock':EndSubroutine,'FunctionBlock':EndFunction,
+# 'IfThenBlock':EndIfThen,'DoBlock':EndDo,'InterfaceBlock':EndInterface,
+# 'SelectBlock':EndSelect}
block_stmts = {'IfThenBlock':IfThen}
diff --git a/numpy/f2py/lib/typedecl_statements.py b/numpy/f2py/lib/typedecl_statements.py
new file mode 100644
index 000000000..66e162100
--- /dev/null
+++ b/numpy/f2py/lib/typedecl_statements.py
@@ -0,0 +1,162 @@
+
+import re
+from base_classes import Statement, BeginStatement, EndStatement
+
+# Intrinsic type specification statements
+
+class TypeDeclarationStatement(Statement):
+ """
+ <declaration-type-spec> [ [, <attr-spec>] :: ] <entity-decl-list>
+ <declaration-type-spec> = <intrinsic-type-spec>
+ | TYPE ( <derived-type-spec> )
+ | CLASS ( <derived-type-spec> )
+ | CLASS ( * )
+
+ <derived-type-spec> = <type-name> [ ( <type-param-spec-list> ) ]
+ <type-param-spec> = [ <keyword> = ] <type-param-value>
+ <type-param-value> = <scalar-int-expr> | * | :
+
+ <intrinsic-type-spec> = INTEGER [<kind-selector>]
+ | REAL [<kind-selector>]
+ | DOUBLE PRECISION
+ | COMPLEX [<kind-selector>]
+ | CHARACTER [<char-selector>]
+ | LOGICAL [<kind-selector>]
+
+ <kind-selector> = ( [ KIND = ] <scalar-int-initialization-expr> )
+ <char-selector> = <length-selector>
+ | ( LEN = <type-param-value>, KIND = <scalar-int-initialization-expr> )
+ | ( <type-param-value>, [ KIND = ] <scalar-int-initialization-expr> )
+ | ( KIND = <scalar-int-initialization-expr> [, LEN = <type-param-value>] )
+ <length-selector> = ( [ LEN = ] <type-param-value> )
+ | * <char-length> [ , ]
+ <char-length> = ( <type-param-value> ) | <scalar-int-literal-expr>
+
+ <attr-spec> = <access-spec> | ALLOCATABLE | ASYNCHRONOUS
+ | DIMENSION ( <array-spec> ) | EXTERNAL
+ | INTENT ( <intent-spec> ) | INTRINSIC
+ | <language-binding-spec> | OPTIONAL
+ | PARAMETER | POINTER | PROTECTED | SAVE
+ | TARGET | VALUE | VOLATILE
+ <entity-decl> = <object-name> [ ( <array-spec> ) ] [ * <char-length> ] [ <initialization> ]
+ | <function-name> [ * <char-length> ]
+ <initialization> = = <initialization-expr>
+ | => NULL
+ <access-spec> = PUBLIC | PRIVATE
+ <language-binding-spec> = BIND ( C [ , NAME = <scalar-char-initialization-expr>] )
+ <array-spec> = <explicit-shape-spec-list>
+ | <assumed-shape-spec-list>
+ | <deferred-shape-spec-list>
+ | <assumed-size-spec>
+ <explicit-shape-spec> = [ <lower-bound> : ] <upper-bound>
+ <assumed-shape-spec> = [ <lower-bound> ] :
+ <deferred-shape-spec> = :
+ <assumed-size-spec> = [ <explicit-shape-spec-list> , ] [ <lower-bound> : ] *
+ <bound> = <specification-expr>
+
+ """
+
+ def process_item(self):
+ item = self.item
+ clsname = self.__class__.__name__.lower()
+ line = item.get_line()
+ from block_statements import Function
+ if Function.match(line):
+ self.isvalid = False
+ return
+ if not line.startswith(clsname):
+ line = line[:len(clsname)].replace(' ','') + line[len(clsname):]
+
+ assert line.startswith(clsname),`line,clsname`
+ line = line[len(clsname):].lstrip()
+
+ if line.startswith('('):
+ i = line.find(')')
+ selector = line[:i+1].strip()
+ line = line[i+1:].lstrip()
+ elif line.startswith('*'):
+ selector = '*'
+ line = line[1:].lstrip()
+ if line.startswith('('):
+ i = line.find(')')
+ selector += line[:i+1].rstrip()
+ line = line[i+1:].lstrip()
+ else:
+ i = line.find(',')
+ if i!=-1:
+ selector += line[:i].rstrip()
+ line = line[i+1:].lstrip()
+ else:
+ i = line.find('::')
+ assert i!=-1,`line`
+ selector += line[:i].rstrip()
+ line = line[i+2:].lstrip()
+ else:
+ selector = ''
+ if line.startswith(','):
+ line = line[1:].lstrip()
+
+ self.raw_selector = selector
+ i = line.find('::')
+
+ if i==-1:
+ self.attrspec = ''
+ self.entity_decls = line
+ else:
+ self.attrspec = line[:i].rstrip()
+ self.entity_decls = line[i+2:].lstrip()
+ return
+
+ def __str__(self):
+ clsname = self.__class__.__name__.upper()
+ tab = self.get_indent_tab()
+ return tab + clsname + '%s, %s :: %s' \
+ % (self.raw_selector, self.attrspec, self.entity_decls)
+
+class Integer(TypeDeclarationStatement):
+ match = re.compile(r'integer\b',re.I).match
+
+class Real(TypeDeclarationStatement):
+ match = re.compile(r'real\b',re.I).match
+
+class DoublePrecision(TypeDeclarationStatement):
+ match = re.compile(r'double\s*precision\b',re.I).match
+
+class Complex(TypeDeclarationStatement):
+ match = re.compile(r'complex\b',re.I).match
+
+class Logical(TypeDeclarationStatement):
+ match = re.compile(r'logical\b',re.I).match
+
+class Character(TypeDeclarationStatement):
+ match = re.compile(r'character\b',re.I).match
+
+class Type(TypeDeclarationStatement):
+ match = re.compile(r'type\s*\(', re.I).match
+TypeStmt = Type
+
+class Class(TypeDeclarationStatement):
+ match = re.compile(r'class\s*\(', re.I).match
+
+
+class Implicit(Statement):
+ """
+ IMPLICIT <implicit-spec-list>
+ IMPLICIT NONE
+ <implicit-spec> = <declaration-type-spec> ( <letter-spec-list> )
+ <letter-spec> = <letter> [ - <letter> ]
+ """
+ match = re.compile(r'implicit\b').match
+ def process_item(self):
+ line = self.item.get_line()[8:].lstrip()
+ if line=='none':
+ self.items = []
+ return
+ self.items = [s.strip() for s in line.split()]
+ assert self.items
+
+ def __str__(self):
+ tab = self.get_indent_tab()
+ if not self.items:
+ return tab + 'IMPLICIT NONE'
+ return tab + 'IMPLICIT ' + ', '.join(self.items)