diff options
author | Pearu Peterson <pearu.peterson@gmail.com> | 2006-09-08 08:29:12 +0000 |
---|---|---|
committer | Pearu Peterson <pearu.peterson@gmail.com> | 2006-09-08 08:29:12 +0000 |
commit | 8f6519144f53c8de74f54d7774397e4bbe84663d (patch) | |
tree | 333426a661ffa3de9a243831ec4573e32de9f354 /numpy/f2py | |
parent | 4963af21d20a3161d17f93b187b49cfdaa3664cd (diff) | |
download | numpy-8f6519144f53c8de74f54d7774397e4bbe84663d.tar.gz |
Add analyze fortran hooks.
Diffstat (limited to 'numpy/f2py')
-rw-r--r-- | numpy/f2py/lib/analyzefortran.py | 134 | ||||
-rw-r--r-- | numpy/f2py/lib/block_statements.py | 191 | ||||
-rw-r--r-- | numpy/f2py/lib/parsefortran.py | 1 | ||||
-rw-r--r-- | numpy/f2py/lib/research/rat/rational.f90 | 1 | ||||
-rw-r--r-- | numpy/f2py/lib/statements.py | 9 | ||||
-rw-r--r-- | numpy/f2py/lib/test_parser.py | 15 | ||||
-rw-r--r-- | numpy/f2py/lib/typedecl_statements.py | 6 |
7 files changed, 303 insertions, 54 deletions
diff --git a/numpy/f2py/lib/analyzefortran.py b/numpy/f2py/lib/analyzefortran.py new file mode 100644 index 000000000..4b2d3ca25 --- /dev/null +++ b/numpy/f2py/lib/analyzefortran.py @@ -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@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() diff --git a/numpy/f2py/lib/block_statements.py b/numpy/f2py/lib/block_statements.py index 767bd0893..446b1610c 100644 --- a/numpy/f2py/lib/block_statements.py +++ b/numpy/f2py/lib/block_statements.py @@ -8,40 +8,59 @@ import sys 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 @@ class HasUseStmt: 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 @@ class BeginSource(BeginStatement): 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 @@ class Module(BeginStatement, HasAttributes, 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 @@ class Module(BeginStatement, HasAttributes, 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 @@ class EndProgram(EndStatement): """ 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 Interface(BeginStatement, HasImplicitStmt, HasUseStmt, class SubProgramStatement(BeginStatement, ProgramBlock, HasImplicitStmt, HasAttributes, - HasUseStmt, HasVariables, HasTypeDecls + HasUseStmt, + HasVariables, HasTypeDecls ): """ [ <prefix> ] <FUNCTION|SUBROUTINE> <name> [ ( <args> ) ] [ <suffix> ] @@ -377,6 +429,9 @@ class SubProgramStatement(BeginStatement, ProgramBlock, 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,13 +439,9 @@ class SubProgramStatement(BeginStatement, ProgramBlock, variables[a] = Variable(self, a) if isinstance(self, Function): - variables[self.result] = Variable(self, self.result) - - [stmt.analyze() for stmt in filter_stmts(content, Use)] - HasUseStmt.initialize(self) - - [stmt.analyze() for stmt in filter_stmts(content, Implicit)] - HasImplicitStmt.initialize(self) + var = variables[self.result] = Variable(self, self.result) + if self.typedecl is not None: + var.set_type(self.typedecl) while content: stmt = content.pop(0) @@ -404,11 +455,24 @@ class SubProgramStatement(BeginStatement, ProgramBlock, 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,13 +792,15 @@ class EndType(EndStatement): 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() @@ -753,11 +819,11 @@ class Type(BeginStatement, HasVariables, HasAttributes): 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 @@ class Type(BeginStatement, HasVariables, HasAttributes): 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 @@ class Type(BeginStatement, HasVariables, HasAttributes): 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 diff --git a/numpy/f2py/lib/parsefortran.py b/numpy/f2py/lib/parsefortran.py index 00b53f0b0..280823a52 100644 --- a/numpy/f2py/lib/parsefortran.py +++ b/numpy/f2py/lib/parsefortran.py @@ -156,6 +156,7 @@ def simple_main(): parser = FortranParser(reader) parser.parse() parser.analyze() + print parser.block.topyf() #print parser.block def profile_main(): diff --git a/numpy/f2py/lib/research/rat/rational.f90 b/numpy/f2py/lib/research/rat/rational.f90 index 9cbc57e15..b0bdeb872 100644 --- a/numpy/f2py/lib/research/rat/rational.f90 +++ b/numpy/f2py/lib/research/rat/rational.f90 @@ -18,6 +18,7 @@ module rational end function rat_create subroutine rat_set(obj, n, d) + implicit none type(rat_struct) :: obj integer :: n,d print*,'In rat_set' diff --git a/numpy/f2py/lib/statements.py b/numpy/f2py/lib/statements.py index b3bd34e51..32e40d5b2 100644 --- a/numpy/f2py/lib/statements.py +++ b/numpy/f2py/lib/statements.py @@ -156,10 +156,12 @@ class Call(Statement): 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 @@ class Use(Statement): 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 @@ class Use(Statement): 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): diff --git a/numpy/f2py/lib/test_parser.py b/numpy/f2py/lib/test_parser.py index af54efdf2..f69957a76 100644 --- a/numpy/f2py/lib/test_parser.py +++ b/numpy/f2py/lib/test_parser.py @@ -283,10 +283,10 @@ class test_Statements(NumpyTestCase): 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 @@ class test_Statements(NumpyTestCase): '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 @@ class test_Statements(NumpyTestCase): 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() diff --git a/numpy/f2py/lib/typedecl_statements.py b/numpy/f2py/lib/typedecl_statements.py index 63b9a346e..492c094aa 100644 --- a/numpy/f2py/lib/typedecl_statements.py +++ b/numpy/f2py/lib/typedecl_statements.py @@ -390,10 +390,12 @@ class Implicit(Statement): 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 |