diff options
author | Pearu Peterson <pearu.peterson@gmail.com> | 2006-06-22 10:25:57 +0000 |
---|---|---|
committer | Pearu Peterson <pearu.peterson@gmail.com> | 2006-06-22 10:25:57 +0000 |
commit | d5a5da520b1eddd10a7dde79b0e7df281ee1abaa (patch) | |
tree | f19a3ce2d0e327bc02771dee39a4b0ccea7aeccf /numpy/f2py | |
parent | 1fe0237f46025a44779ad98974b9a587b6aa6ac8 (diff) | |
download | numpy-d5a5da520b1eddd10a7dde79b0e7df281ee1abaa.tar.gz |
Cont. impl. Fortran parser.
Diffstat (limited to 'numpy/f2py')
-rw-r--r-- | numpy/f2py/lib/base_classes.py | 199 | ||||
-rw-r--r-- | numpy/f2py/lib/block.py | 23 | ||||
-rw-r--r-- | numpy/f2py/lib/block_statements.py | 535 | ||||
-rw-r--r-- | numpy/f2py/lib/init.py | 50 | ||||
-rw-r--r-- | numpy/f2py/lib/parsefortran.py | 19 | ||||
-rw-r--r-- | numpy/f2py/lib/readfortran.py | 26 | ||||
-rw-r--r-- | numpy/f2py/lib/statements.py | 645 | ||||
-rw-r--r-- | numpy/f2py/lib/stmt.py | 68 | ||||
-rw-r--r-- | numpy/f2py/lib/typedecl_statements.py | 162 |
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) |