[Numpy-svn] r3137 - in trunk/numpy/f2py/lib: . research/rat

numpy-svn at scipy.org numpy-svn at scipy.org
Fri Sep 8 04:29:40 EDT 2006


Author: pearu
Date: 2006-09-08 03:29:12 -0500 (Fri, 08 Sep 2006)
New Revision: 3137

Added:
   trunk/numpy/f2py/lib/analyzefortran.py
Modified:
   trunk/numpy/f2py/lib/block_statements.py
   trunk/numpy/f2py/lib/parsefortran.py
   trunk/numpy/f2py/lib/research/rat/rational.f90
   trunk/numpy/f2py/lib/statements.py
   trunk/numpy/f2py/lib/test_parser.py
   trunk/numpy/f2py/lib/typedecl_statements.py
Log:
Add analyze fortran hooks.

Added: trunk/numpy/f2py/lib/analyzefortran.py
===================================================================
--- trunk/numpy/f2py/lib/analyzefortran.py	2006-09-08 00:18:21 UTC (rev 3136)
+++ trunk/numpy/f2py/lib/analyzefortran.py	2006-09-08 08:29:12 UTC (rev 3137)
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+"""
+Defines FortranAnalyzer.
+
+Permission to use, modify, and distribute this software is given under the
+terms of the NumPy License. See http://scipy.org.
+NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
+
+Author: Pearu Peterson <pearu at cens.ioc.ee>
+Created: June 2006
+"""
+
+from numpy.distutils.misc_util import yellow_text, red_text
+
+class FortranAnalyzer:
+
+    def __init__(self, block):
+        """
+        block is a BeginSource instance with relevant attributes:
+          name - reader name
+          content - a list of statements
+        Statements are either block statements or simple statements.
+        Block statements have the following relevant attributes:
+          name - block name
+          blocktype - statement name (equal to lowered statement class name)
+          content - a list of statements
+        Block statements may have additional attributes:
+          BeginSource: top
+          Module:
+          PythonModule:
+          Program:
+          BlockData:
+          Interface: isabstract, generic_spec
+          Subroutine: prefix, args, suffix
+          Function: prefix, typedecl, args, suffix
+          Select: expr
+          Where: expr
+          Forall: specs
+          IfThen: expr
+          If: expr
+          Do: endlabel, loopcontrol
+          Associate: associations
+          Type: specs, params
+          Enum:
+        Simple statements have various attributes:
+          Assignment: variable, expr
+          PointerAssignment: variable, expr
+          Assign: items
+          Call: designator, items
+          Goto: label
+          ComputedGoto: items, expr
+          AssignedGoto: varname, items
+          Continue: label
+          Return: expr
+          Stop: code
+          Print: format, items
+          Read0: specs, items
+          Read1: format, items
+          Write: specs, items
+          Flush: specs
+          Wait: specs
+          Contains:
+          Allocate: spec, items
+          Deallocate: items
+          ModuleProcedure: items
+          Public | Private: items
+          Close: specs
+          Cycle: name
+          Rewind | Backspace | Endfile: specs
+          Open: specs
+          Format: specs
+          Save: items
+          Data: stmts
+          Nullify: items
+          Use: nature, name, isonly, items
+          Exit: name
+          Parameter: items
+          Equivalence: items
+          Dimension: items
+          Target: items
+          Pointer: items
+          Protected | Volatile | Value | Intrinsic | External | Optional: items
+          ArithmeticIf: expr, labels
+          Inquire: specs, items
+          Sequence:
+          Common: items
+          Intent: specs, items
+          Entry: name, items, result, binds
+          Import: items
+          Forall: specs, content
+          SpecificBinding: iname, attrs, name, bname
+          GenericBinding: aspec, spec, items
+          FinalBinding: items
+          Allocatable: items
+          Asynchronous: items
+          Bind: specs, items
+          Else: name
+          ElseIf: name, expr
+          Case: name, items
+          Else: name
+          ElseIf: name, expr
+          Case: name, items
+          Where: name, expr
+          ElseWhere: name, expr
+          Enumerator: items
+          FortranName: value
+          Threadsafe:
+          Depend: depends, items
+          Check: expr, value
+          CallStatement: expr
+          CallProtoArgument: specs
+          Pause: value
+        """
+        self.block = block
+        print block.item
+    def analyze(self):
+        
+        pass
+
+def simple_main():
+    import sys
+    from parsefortran import FortranParser
+    from readfortran import FortranFileReader
+    for filename in sys.argv[1:]:
+        reader = FortranFileReader(filename)
+        print yellow_text('Processing '+filename+' (mode=%r)' % (reader.mode))
+        parser = FortranParser(reader)
+        block = parser.parse()
+        analyzer = FortranAnalyzer(block)
+        r = analyzer.analyze()
+        print r
+
+if __name__ == "__main__":
+    simple_main()

Modified: trunk/numpy/f2py/lib/block_statements.py
===================================================================
--- trunk/numpy/f2py/lib/block_statements.py	2006-09-08 00:18:21 UTC (rev 3136)
+++ trunk/numpy/f2py/lib/block_statements.py	2006-09-08 08:29:12 UTC (rev 3137)
@@ -8,40 +8,59 @@
 from base_classes import BeginStatement, EndStatement, Statement,\
      AttributeHolder, ProgramBlock
 from readfortran import Line
-from utils import filter_stmts, parse_bind, parse_result
+from utils import filter_stmts, parse_bind, parse_result, AnalyzeError
 
 class HasImplicitStmt:
 
-    a = AttributeHolder(implicit_rules = None)
+    a = AttributeHolder(implicit_rules = {})
 
     def get_type(self, name):
         implicit_rules = self.a.implicit_rules
-        if implicit_rules=={}:
-            raise ValueError,'Implicit rules mapping is null'
+        if implicit_rules is None:
+            raise AnalyzeError,'Implicit rules mapping is null'
         l = name[0].lower()
         if implicit_rules.has_key(l):
             return implicit_rules[l]
-        # default rules
+        # default rules:
         if l in 'ijklmn':
-            return implicit_rules['default_integer']
-        return implicit_rules['default_real']
+            l = 'default_integer'
+        else:
+            l = 'default_real'
+        t = implicit_rules.get(l, None)
+        if t is None:
+            if l[8:]=='real':
+                implicit_rules[l] = t = Real(self, self.item.copy('real'))
+            else:
+                implicit_rules[l] = t = Integer(self, self.item.copy('integer'))
+        return t
 
-    def initialize(self):
+    def topyf(self, tab='  '):
         implicit_rules = self.a.implicit_rules
-        if implicit_rules is not None:
-            return
-        self.a.implicit_rules = implicit_rules = {}
-        real = Real(self, self.item.copy('real'))
-        assert real.isvalid
-        integer = Integer(self, self.item.copy('integer'))
-        assert integer.isvalid
-        implicit_rules['default_real'] = real
-        implicit_rules['default_integer'] = integer
-        return
+        if implicit_rules is None:
+            return tab + 'IMPLICIT NONE\n'
+        items = {}
+        for c,t in implicit_rules.items():
+            if c.startswith('default'):
+                continue
+            st = t.tostr()
+            if items.has_key(st):
+                items[st].append(c)
+            else:
+                items[st] = [c]
+        if not items:
+            return tab + '! default IMPLICIT rules apply\n'
+        s = 'IMPLICIT'
+        ls = []
+        for st,l in items.items():
+            l.sort()
+            ls.append(st + ' (%s)' % (', '.join(l)))
+        s += ' ' + ', '.join(ls)
+        return tab + s + '\n'
 
 class HasUseStmt:
 
-    a = AttributeHolder(use = {})
+    a = AttributeHolder(use = {},
+                        use_provides = {})
 
     def get_entity(self, name):
         for modname, modblock in self.top.a.module.items():
@@ -49,23 +68,40 @@
                 if getattr(stmt,'name','') == name:
                     return stmt
         return
-    
-    def initialize(self):
-        
-        return
 
+    def topyf(self):
+        pass
+
 class HasVariables:
 
     a = AttributeHolder(variables = {})
 
+    def topyf(self,tab=''):
+        s = ''
+        for name, var in self.a.variables.items():
+            s += tab + str(var) + '\n'
+        return s
+
 class HasTypeDecls:
 
     a = AttributeHolder(type_decls = {})
 
+    def topyf(self, tab=''):
+        s = ''
+        for name, stmt in self.a.type_decls.items():
+            s += stmt.topyf(tab='  '+tab)
+        return s
+
 class HasAttributes:
 
     a = AttributeHolder(attributes = [])
 
+    def topyf(self, tab=''):
+        s = ''
+        for attr in self.a.attributes:
+            s += tab + attr + '\n'
+        return s
+
 class HasModuleProcedures:
 
     a = AttributeHolder(module_procedures = [])
@@ -136,6 +172,15 @@
                 return
         return BeginStatement.process_subitem(self, item)
 
+    def topyf(self, tab=''): # XXXX
+        s = ''
+        for name, stmt in self.a.module.items():
+            s += stmt.topyf()
+        for name, stmt in self.a.external_subprogram.items():
+            s += stmt.topyf()
+        for name, stmt in self.a.blockdata.items():
+            s += stmt.topyf()
+        return s
 # Module
 
 class EndModule(EndStatement):
@@ -166,12 +211,6 @@
     def analyze(self):
         content = self.content[:]
 
-        [stmt.analyze() for stmt in filter_stmts(content, Use)]
-        HasUseStmt.initialize(self)
-
-        [stmt.analyze() for stmt in filter_stmts(content, Implicit)]
-        HasImplicitStmt.initialize(self)
-
         while content:
             stmt = content.pop(0)
             if isinstance(stmt, Contains):
@@ -188,6 +227,17 @@
 
         return
 
+    def topyf(self, tab=''):
+        s = tab + 'MODULE '+self.name + '\n'
+        s +=  HasImplicitStmt.topyf(self, tab=tab+'  ')
+        s +=  HasTypeDecls.topyf(self, tab=tab+'  ')
+        s +=  HasVariables.topyf(self, tab=tab+'  ')
+        s +=  tab + '  CONTAINS\n'
+        for name, stmt in self.a.module_subprogram.items():
+            s += stmt.topyf(tab=tab+'    ')
+        s += tab + 'END MODULE ' + self.name + '\n'
+        return s
+
 # Python Module
 
 class EndPythonModule(EndStatement):
@@ -219,7 +269,8 @@
     """
     match = re.compile(r'end(\s*program\s*\w*|)\Z', re.I).match
 
-class Program(BeginStatement, ProgramBlock, HasAttributes,
+class Program(BeginStatement, ProgramBlock,
+              HasAttributes,
               HasImplicitStmt, HasUseStmt):
     """ PROGRAM [name]
     """
@@ -312,7 +363,8 @@
 
 class SubProgramStatement(BeginStatement, ProgramBlock,
                           HasImplicitStmt, HasAttributes,
-                          HasUseStmt, HasVariables, HasTypeDecls
+                          HasUseStmt,
+                          HasVariables, HasTypeDecls
                           ):
     """
     [ <prefix> ] <FUNCTION|SUBROUTINE> <name> [ ( <args> ) ] [ <suffix> ]
@@ -377,6 +429,9 @@
     def analyze(self):
         content = self.content[:]
 
+        if self.prefix:
+            self.a.attributes.extend(prefix.upper().split())
+
         variables = self.a.variables
         for a in self.args:
             assert not variables.has_key(a)
@@ -384,14 +439,10 @@
             variables[a] = Variable(self, a)
 
         if isinstance(self, Function):
-            variables[self.result] = Variable(self, self.result)
+            var = variables[self.result] = Variable(self, self.result)
+            if self.typedecl is not None:
+                var.set_type(self.typedecl)
 
-        [stmt.analyze() for stmt in filter_stmts(content, Use)]
-        HasUseStmt.initialize(self)
-
-        [stmt.analyze() for stmt in filter_stmts(content, Implicit)]
-        HasImplicitStmt.initialize(self)
-
         while content:
             stmt = content.pop(0)
             if isinstance(stmt, Contains):
@@ -404,11 +455,24 @@
                 continue
             else:
                 stmt.analyze()
+
         if content:
             self.show_message('Not analyzed content: %s' % content)
 
         return
 
+    def topyf(self, tab=''):
+        s = tab + self.__class__.__name__.upper()
+        s += ' ' + self.name + ' (%s)' % (', '.join(self.args))
+        if isinstance(self, Function) and self.result != self.name:
+            s += ' RESULT (%s)' % (self.result)
+        s += '\n'
+        s +=  HasImplicitStmt.topyf(self, tab=tab+'  ')
+        s +=  HasTypeDecls.topyf(self, tab=tab+'  ')
+        s +=  HasVariables.topyf(self, tab=tab+'  ')
+        s += tab + 'END ' + self.__class__.__name__.upper() + ' ' + self.name + '\n'
+        return s
+
 class EndSubroutine(EndStatement):
     """
     END [SUBROUTINE [name]]
@@ -728,14 +792,16 @@
 
 class Type(BeginStatement, HasVariables, HasAttributes):
     """
-    TYPE [ [, <type-attr-spec-list>] ::] <type-name> [ ( <type-param-name-list> ) ]
+    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
-    is_name = re.compile(r'\w+\Z').match
 
+    a = AttributeHolder(extends = None,
+                        parameters = [])
+
     def process_item(self):
         line = self.item.get_line()[4:].lstrip()
         if line.startswith('('):
@@ -753,11 +819,11 @@
         if i!=-1:
             self.name = line[:i].rstrip()
             assert line[-1]==')',`line`
-            self.params = line[i+1:-1].lstrip()
+            self.params = split_comma(line[i+1:-1].lstrip())
         else:
             self.name = line
-            self.params = ''
-        if not self.is_name(self.name):
+            self.params = []
+        if not is_name(self.name):
             self.isvalid = False
             return
         return BeginStatement.process_item(self)
@@ -768,7 +834,7 @@
             s += ', '.join(['']+self.specs) + ' ::'
         s += ' ' + self.name
         if self.params:
-            s += ' ('+self.params+')'
+            s += ' ('+', '.join(self.params)+')'
         return s
 
     def get_classes(self):
@@ -777,10 +843,45 @@
 
     def analyze(self):
         BeginStatement.analyze(self)
-        assert isinstance(self.parent,HasTypeDecls)
+        for spec in self.specs:
+            i = spec.find('(')
+            if i!=-1:
+                assert spec.endswith(')'),`spec`
+                s = spec[:i].rstrip().upper()
+                n = spec[i+1:-1].strip()
+                if s=='EXTENDS':
+                    self.a.extends = n
+                    continue
+                elif s=='BIND':
+                    args,rest = parse_bind(spec)
+                    assert not rest,`rest`
+                    spec = 'BIND(%s)' % (', '.join(args))
+                else:
+                    spec = '%s(%s)' % (s,n)
+                    self.warning('Unknown type-attr-spec %r' % (spec))
+            else:
+                spec = spec.upper()
+                if spec not in ['PUBLIC', 'PRIVATE', 'ABSTRACT']:
+                    self.warning('Unknown type-attr-spec %r' % (spec))
+            self.a.attributes.append(spec)
+        self.a.parameters.extend(self.params)
+        assert isinstance(self.parent,HasTypeDecls),`self.parent.__class__`
         self.parent.a.type_decls[self.name] = self
         return
 
+    def topyf(self, tab=''):
+        s = tab + 'TYPE'
+        if self.a.extends is not None:
+            s += ', EXTENDS(%s) ::' % (self.a.extends) 
+        s += ' ' + self.name
+        if self.a.parameters:
+            s += ' (%s)' % (', '.join(self.a.parameters))
+        s += '\n'
+        s += HasAttributes.topyf(self, tab=tab+'  ')
+        s += HasVariables.topyf(self, tab=tab+'  ')
+        s += tab + 'END TYPE ' + self.name + '\n'
+        return s
+
 TypeDecl = Type
 
 # Enum

Modified: trunk/numpy/f2py/lib/parsefortran.py
===================================================================
--- trunk/numpy/f2py/lib/parsefortran.py	2006-09-08 00:18:21 UTC (rev 3136)
+++ trunk/numpy/f2py/lib/parsefortran.py	2006-09-08 08:29:12 UTC (rev 3137)
@@ -156,6 +156,7 @@
         parser = FortranParser(reader)
         parser.parse()
         parser.analyze()
+        print parser.block.topyf()
         #print parser.block
 
 def profile_main():

Modified: trunk/numpy/f2py/lib/research/rat/rational.f90
===================================================================
--- trunk/numpy/f2py/lib/research/rat/rational.f90	2006-09-08 00:18:21 UTC (rev 3136)
+++ trunk/numpy/f2py/lib/research/rat/rational.f90	2006-09-08 08:29:12 UTC (rev 3137)
@@ -18,6 +18,7 @@
     end function rat_create
 
      subroutine rat_set(obj, n, d)
+       implicit none
        type(rat_struct) :: obj
        integer :: n,d
        print*,'In rat_set'

Modified: trunk/numpy/f2py/lib/statements.py
===================================================================
--- trunk/numpy/f2py/lib/statements.py	2006-09-08 00:18:21 UTC (rev 3136)
+++ trunk/numpy/f2py/lib/statements.py	2006-09-08 08:29:12 UTC (rev 3137)
@@ -156,10 +156,12 @@
 
     def analyze(self):
         a = self.programblock.a
+        variables = a.variables
         if hasattr(a, 'external'):
             external = a.external
             if self.designator in external:
                 print 'Need to analyze:',self
+        print self
         return
 
 class Goto(Statement):
@@ -853,7 +855,7 @@
                 fn = get_module_file(self.name, d)
                 if fn is not None:
                     break
-            if 1 and fn is not None:
+            if fn is not None:
                 from readfortran import FortranFileReader
                 from parsefortran import FortranParser
                 self.info('looking module information from %r' % (fn))
@@ -866,6 +868,11 @@
 
         if not modules.has_key(self.name):
             self.warning('no information about the use module %r' % (self.name))
+            return
+
+        use_provides = self.parent.a.use_provides
+        
+        
         return
 
 class Exit(Statement):

Modified: trunk/numpy/f2py/lib/test_parser.py
===================================================================
--- trunk/numpy/f2py/lib/test_parser.py	2006-09-08 00:18:21 UTC (rev 3136)
+++ trunk/numpy/f2py/lib/test_parser.py	2006-09-08 08:29:12 UTC (rev 3137)
@@ -283,10 +283,10 @@
         assert_equal(parse(Optional,'optional a , b'),'OPTIONAL a, b')
 
     def check_intent(self):
-        assert_equal(parse(Intent,'intent (in) a'),'INTENT (in) a')
-        assert_equal(parse(Intent,'intent(in)::a'),'INTENT (in) a')
-        assert_equal(parse(Intent,'intent(in) a , b'),'INTENT (in) a, b')
-        assert_equal(parse(Intent,'intent (in, out) a'),'INTENT (in, out) a')
+        assert_equal(parse(Intent,'intent (in) a'),'INTENT (IN) a')
+        assert_equal(parse(Intent,'intent(in)::a'),'INTENT (IN) a')
+        assert_equal(parse(Intent,'intent(in) a , b'),'INTENT (IN) a, b')
+        assert_equal(parse(Intent,'intent (in, out) a'),'INTENT (IN, OUT) a')
 
     def check_entry(self):
         assert_equal(parse(Entry,'entry a'), 'ENTRY a')
@@ -297,7 +297,7 @@
                      'ENTRY a BIND (C, NAME = "a b")')
         assert_equal(parse(Entry,'entry a result (b)'), 'ENTRY a RESULT (b)')
         assert_equal(parse(Entry,'entry a bind(d) result (b)'),
-                     'ENTRY a RESULT (b) BIND (d)')
+                     'ENTRY a RESULT (b) BIND (D)')
         assert_equal(parse(Entry,'entry a result (b) bind( c )'),
                      'ENTRY a RESULT (b) BIND (C)')
         assert_equal(parse(Entry,'entry a(b,*) result (g)'),
@@ -475,6 +475,9 @@
         assert_equal(parse(Implicit,'implicit'),'IMPLICIT NONE')
         assert_equal(parse(Implicit,'implicit integer (i-m)'),
                      'IMPLICIT INTEGER ( i-m )')
-
+        assert_equal(parse(Implicit,'implicit integer (i-m,p,q-r)'),
+                     'IMPLICIT INTEGER ( i-m, p, q-r )')
+        assert_equal(parse(Implicit,'implicit integer (i-m), real (z)'),
+                     'IMPLICIT INTEGER ( i-m ), REAL ( z )')
 if __name__ == "__main__":
     NumpyTest().run()

Modified: trunk/numpy/f2py/lib/typedecl_statements.py
===================================================================
--- trunk/numpy/f2py/lib/typedecl_statements.py	2006-09-08 00:18:21 UTC (rev 3136)
+++ trunk/numpy/f2py/lib/typedecl_statements.py	2006-09-08 08:29:12 UTC (rev 3137)
@@ -390,10 +390,12 @@
         implicit_rules = self.parent.a.implicit_rules
         if not self.items:
             if implicit_rules:
-                raise AnalyzeError,'IMPLICIT NONE implies emtpy implicit_rules'\
-                      ' but got %r' % (implicit_rules) 
+                self.warning('overriding previously set implicit rule mapping'\
+                      ' %r.' % (implicit_rules))
+            self.parent.a.implicit_rules = None
             return
         if implicit_rules is None:
+            self.warning('overriding previously set IMPLICIT NONE')
             self.parent.a.implicit_rules = implicit_rules = {}
         for stmt,specs in self.items:
             s,e = specs




More information about the Numpy-svn mailing list