[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