[Numpy-svn] r2711 - trunk/numpy/f2py/lib

numpy-svn at scipy.org numpy-svn at scipy.org
Fri Jun 30 08:36:23 CDT 2006


Author: pearu
Date: 2006-06-30 08:36:13 -0500 (Fri, 30 Jun 2006)
New Revision: 2711

Added:
   trunk/numpy/f2py/lib/test_parser.py
Modified:
   trunk/numpy/f2py/lib/base_classes.py
   trunk/numpy/f2py/lib/block_statements.py
   trunk/numpy/f2py/lib/parsefortran.py
   trunk/numpy/f2py/lib/readfortran.py
   trunk/numpy/f2py/lib/splitline.py
   trunk/numpy/f2py/lib/statements.py
   trunk/numpy/f2py/lib/typedecl_statements.py
Log:
Writting parser unittests, fixed bugs.

Modified: trunk/numpy/f2py/lib/base_classes.py
===================================================================
--- trunk/numpy/f2py/lib/base_classes.py	2006-06-30 13:28:59 UTC (rev 2710)
+++ trunk/numpy/f2py/lib/base_classes.py	2006-06-30 13:36:13 UTC (rev 2711)
@@ -27,7 +27,7 @@
 
         self.process_item()
 
-    def get_indent_tab(self,colon='',deindent=False):
+    def get_indent_tab(self,colon=None,deindent=False):
         if self.reader.isfix:
             tab = ' '*6
         else:
@@ -41,6 +41,11 @@
         if self.item is None:
             return tab
         s = self.item.label
+        if colon is None:
+            if self.reader.isfix:
+                colon = ''
+            else:
+                colon = ':'
         if s:
             c = ''
             if self.reader.isfix:

Modified: trunk/numpy/f2py/lib/block_statements.py
===================================================================
--- trunk/numpy/f2py/lib/block_statements.py	2006-06-30 13:28:59 UTC (rev 2710)
+++ trunk/numpy/f2py/lib/block_statements.py	2006-06-30 13:36:13 UTC (rev 2711)
@@ -22,6 +22,9 @@
 
     end_stmt_cls = EndSource
 
+    def tostr(self):
+        return '!' + self.blocktype.upper() + ' '+ self.name
+
     def process_item(self):
         self.name = self.reader.name
         self.fill(end_flag = True)
@@ -383,7 +386,8 @@
     def tostr(self):
         return 'FORALL (%s)' % (self.specs)
     def get_classes(self):
-        return [Assignment, WhereStmt, WhereConstruct, ForallConstruct, ForallStmt]
+        return [GeneralAssignment, WhereStmt, WhereConstruct,
+                ForallConstruct, ForallStmt]
 
 ForallConstruct = Forall
 
@@ -569,14 +573,14 @@
         if line.startswith('('):
             self.isvalid = False
             return
-        attr_specs = []
+        specs = []
         i = line.find('::')
         if i!=-1:
             for s in line[:i].split(','):
                 s = s.strip()
-                if s: attr_specs.append(s)
+                if s: specs.append(s)
             line = line[i+2:].lstrip()
-        self.attr_specs = attr_specs
+        self.specs = specs
         i = line.find('(')
         if i!=-1:
             self.name = line[:i].rstrip()
@@ -592,15 +596,16 @@
 
     def tostr(self):
         s = 'TYPE'
-        if self.attr_specs:
-            s += ', '.join(['']+self.attr_specs) + ' ::'
+        if self.specs:
+            s += ', '.join(['']+self.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
+        return [Integer] + private_or_sequence + component_part +\
+               type_bound_procedure_part
 
 TypeDecl = Type
 
@@ -652,6 +657,8 @@
     DoublePrecision, Complex, DoubleComplex, Character, Logical, Byte
     ]
 
+derived_type_spec = [  ]
+type_spec = intrinsic_type_spec + derived_type_spec
 declaration_type_spec = intrinsic_type_spec + [ TypeStmt, Class ]
     
 type_declaration_stmt = declaration_type_spec
@@ -665,12 +672,13 @@
 type_bound_procedure_part = [Contains, Private] + proc_binding_stmt
 
 #R214
-action_stmt = [ Allocate, Assignment, Assign, Backspace, Call, Close,
+action_stmt = [ Allocate, GeneralAssignment, Assign, Backspace, Call, Close,
     Continue, Cycle, Deallocate, Endfile, Exit, Flush, ForallStmt,
     Goto, If, Inquire, Nullify, Open, Print, Read, Return, Rewind,
     Stop, Wait, WhereStmt, Write, ArithmeticIf, ComputedGoto,
     AssignedGoto, Pause ]
-#PointerAssignment,EndFunction, EndProgram, EndSubroutine,
+# GeneralAssignment = Assignment + PointerAssignment
+# EndFunction, EndProgram, EndSubroutine - part of the corresponding blocks
 
 executable_construct = [ Associate, Do, ForallConstruct, IfThen,
     Select, WhereConstruct ] + action_stmt

Modified: trunk/numpy/f2py/lib/parsefortran.py
===================================================================
--- trunk/numpy/f2py/lib/parsefortran.py	2006-06-30 13:28:59 UTC (rev 2710)
+++ trunk/numpy/f2py/lib/parsefortran.py	2006-06-30 13:36:13 UTC (rev 2711)
@@ -22,22 +22,22 @@
 
     def __init__(self, reader):
         self.reader = reader
-        self.isfix77 = reader.isfix77
+        return
 
     def get_item(self):
         try:
-            item = self.reader.next(ignore_comments = True)
-            return item
+            return self.reader.next(ignore_comments = True)
         except StopIteration:
             pass
+        return
 
     def put_item(self, item):
         self.reader.fifo_item.insert(0, item)
+        return
 
     def parse(self):
         try:
-            main = BeginSource(self)
-            return main
+            return BeginSource(self)
         except KeyboardInterrupt:
             raise
         except:
@@ -50,6 +50,7 @@
                 reader = reader.reader
             traceback.print_exc(file=sys.stdout)
             self.reader.show_message(red_text('STOPPED PARSING'), sys.stdout)
+        return
 
 def test_pyf():
     string = """
@@ -121,7 +122,6 @@
     for filename in sys.argv[1:]:
         reader = FortranFileReader(filename)
         print yellow_text('Processing '+filename+' (mode=%r)' % (reader.mode))
-
         parser = FortranParser(reader)
         block = parser.parse()
         #print block
@@ -137,13 +137,13 @@
     stats.print_stats(30)
 
 def parse_all_f():
-    for filename in open('opt_all_f90.txt'):
+    for filename in open('opt_all_f.txt'):
         filename = filename.strip()
         reader = FortranFileReader(filename)
-        #print yellow_text('Processing '+filename+' (mode=%r)' % (reader.mode))
-
+        print yellow_text('Processing '+filename+' (mode=%r)' % (reader.mode))
         parser = FortranParser(reader)
         block = parser.parse()
+        print block
 
 if __name__ == "__main__":
     #test_f77()

Modified: trunk/numpy/f2py/lib/readfortran.py
===================================================================
--- trunk/numpy/f2py/lib/readfortran.py	2006-06-30 13:28:59 UTC (rev 2710)
+++ trunk/numpy/f2py/lib/readfortran.py	2006-06-30 13:36:13 UTC (rev 2711)
@@ -51,7 +51,7 @@
     """ Holds a Fortran source line.
     """
     
-    f2py_strmap_findall = re.compile(r'( _F2PY_STRING_CONSTANT_\d+_ |\(F2PY_EXPR_TUPLE_\d+\))').findall
+    f2py_strmap_findall = re.compile(r'(_F2PY_STRING_CONSTANT_\d+_|F2PY_EXPR_TUPLE_\d+)').findall
     
     def __init__(self, line, linenospan, label, reader):
         self.line = line.strip()
@@ -61,8 +61,12 @@
         self.strline = None
         self.is_f2py_directive = linenospan[0] in reader.f2py_comment_lines
 
+    def has_map(self):
+        return not not (hasattr(self,'strlinemap') and self.strlinemap)
+
     def apply_map(self, line):
-        if not hasattr(self,'strlinemap'): return line
+        if not hasattr(self,'strlinemap') or not self.strlinemap:
+            return line
         findall = self.f2py_strmap_findall
         str_map = self.strlinemap
         keys = findall(line)

Modified: trunk/numpy/f2py/lib/splitline.py
===================================================================
--- trunk/numpy/f2py/lib/splitline.py	2006-06-30 13:28:59 UTC (rev 2710)
+++ trunk/numpy/f2py/lib/splitline.py	2006-06-30 13:36:13 UTC (rev 2711)
@@ -28,7 +28,9 @@
     """
     return LineSplitter(line,lower=lower).split2()
 
-_f2py_str_findall = re.compile(r"'_F2PY_STRING_CONSTANT_\d+_'").findall
+_f2py_str_findall = re.compile(r"_F2PY_STRING_CONSTANT_\d+_").findall
+_is_name = re.compile(r'\w*\Z',re.I).match
+_is_simple_str = re.compile(r'\w*\Z',re.I).match
 
 def string_replace_map(line, lower=False,
                        _cache={'index':0,'pindex':0}):
@@ -41,31 +43,33 @@
     string_map = {}
     rev_string_map = {}
     for item in splitquote(line, lower=lower)[0]:
-        if isinstance(item, String):
+        if isinstance(item, String) and not _is_simple_str(item[1:-1]):
             key = rev_string_map.get(item)
             if key is None:
                 _cache['index'] += 1
                 index = _cache['index']
-                key = "'_F2PY_STRING_CONSTANT_%s_'" % (index)
-                string_map[key] = item
-                rev_string_map[item] = key
-            items.append(key)
+                key = "_F2PY_STRING_CONSTANT_%s_" % (index)
+                it = item[1:-1]
+                string_map[key] = it
+                rev_string_map[it] = key
+            items.append(item[0]+key+item[-1])
         else:
             items.append(item)
     newline = ''.join(items)
     items = []
     expr_keys = []
     for item in splitparen(newline):
-        if isinstance(item, ParenString):
+        if isinstance(item, ParenString) and not _is_name(item[1:-1]):
             key = rev_string_map.get(item)
             if key is None:
                 _cache['pindex'] += 1
                 index = _cache['pindex']
-                key = '(F2PY_EXPR_TUPLE_%s)' % (index)
-                string_map[key] = item
-                rev_string_map[item] = key
+                key = 'F2PY_EXPR_TUPLE_%s' % (index)
+                it = item[1:-1]
+                string_map[key] = it
+                rev_string_map[it] = key
                 expr_keys.append(key)
-            items.append(key)
+            items.append(item[0]+key+item[-1])
         else:
             items.append(item)
     found_keys = set()

Modified: trunk/numpy/f2py/lib/statements.py
===================================================================
--- trunk/numpy/f2py/lib/statements.py	2006-06-30 13:28:59 UTC (rev 2710)
+++ trunk/numpy/f2py/lib/statements.py	2006-06-30 13:36:13 UTC (rev 2711)
@@ -4,11 +4,55 @@
 
 from base_classes import Statement
 
+# Auxiliary tools
+
 is_name = re.compile(r'\w+\Z').match
 
+def split_comma(line, item):
+    newitem = item.copy(line, True)
+    apply_map = newitem.apply_map
+    items = []
+    for s in newitem.get_line().split(','):
+        s = apply_map(s).strip()
+        if not s: continue
+        items.append(s)
+    return items
+
+def specs_split_comma(line, item):
+    specs0 = split_comma(line, item)
+    specs = []
+    for spec in specs0:
+        i = spec.find('=')
+        if i!=-1:
+            kw = spec[:i].strip().upper()
+            v  = spec[i+1:].strip()
+            specs.append('%s = %s' % (kw, v))
+        else:
+            specs.append(spec)
+    return specs
+
+class StatementWithNamelist(Statement):
+    """
+    <statement> [ :: ] <name-list>
+    """
+    def process_item(self):
+        assert not self.item.has_map()
+        clsname = self.__class__.__name__.lower()
+        line = self.item.get_line()[len(clsname):].lstrip()
+        if line.startswith('::'):
+            line = line[2:].lstrip()
+        self.items = [s.strip() for s in line.split(',')]
+        return
+    def __str__(self):
+        clsname = self.__class__.__name__.upper()
+        s = ', '.join(self.items)
+        if s:
+            s = ' ' + s
+        return self.get_indent_tab() + clsname + s
+
 # Execution statements
 
-class Assignment(Statement):
+class GeneralAssignment(Statement):
     """
     <variable> = <expr>
     <pointer variable> => <expr>
@@ -19,15 +63,36 @@
 
     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')
+        if not m:
+            self.isvalid = False
+            return
+        self.sign = sign = m.group('sign')
+        if isinstance(self, Assignment) and sign != '=':
+            self.isvalid = False
+            return
+        elif isinstance(self, PointerAssignment) and sign != '=>':
+            self.isvalid = False
+            return
+        else:
+            if sign=='=>':
+                self.__class__ = PointerAssignment
+            else:
+                self.__class__ = Assignment            
+        apply_map = self.item.apply_map
+        self.variable = apply_map(m.group('variable').replace(' ',''))
+        self.expr = apply_map(m.group('expr'))
         return
 
     def __str__(self):
         return self.get_indent_tab() + '%s %s %s' \
                % (self.variable, self.sign, self.expr)
 
+class Assignment(GeneralAssignment):
+    pass
+
+class PointerAssignment(GeneralAssignment):
+    pass
+
 class Assign(Statement):
     """
     ASSIGN <label> TO <int-variable-name>
@@ -37,6 +102,7 @@
     def process_item(self):
         line = self.item.get_line()[6:].lstrip()
         i = line.find('to')
+        assert not self.item.has_map()
         self.items = [line[:i].rstrip(),line[i+2:].lstrip()]
         return
     def __str__(self):
@@ -46,8 +112,24 @@
     
 class Call(Statement):
     """Call statement class
-    CALL <proc-designator> [([arg-spec-list])]
+    CALL <procedure-designator> [ ( [ <actual-arg-spec-list> ] ) ]
 
+    <procedure-designator> = <procedure-name>
+                           | <proc-component-ref>
+                           | <data-ref> % <binding-name>
+
+    <actual-arg-spec> = [ <keyword> = ] <actual-arg>
+    <actual-arg> = <expr>
+                 | <variable>
+                 | <procedure-name>
+                 | <proc-component-ref>
+                 | <alt-return-spec>
+    <alt-return-spec> = * <label>
+
+    <proc-component-ref> = <variable> % <procedure-component-name>
+
+    <variable> = <designator>
+
     Call instance has attributes:
       designator
       arg_list
@@ -56,42 +138,41 @@
 
     def process_item(self):
         item = self.item
+        apply_map = item.apply_map
         line = item.get_line()[4:].strip()
         i = line.find('(')
-        self.arg_list = []
+        items = []
         if i==-1:
-            self.designator = line.strip()
+            self.designator = apply_map(line).strip()
         else:
             j = line.find(')')
             if j == -1 or len(line)-1 != j:
                 self.isvalid = False
                 return
-            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)
+            self.designator = apply_map(line[:i]).strip()
+            items = split_comma(line[i+1:-1], item)
+        self.items = items
         return
 
     def __str__(self):
         s = self.get_indent_tab() + 'CALL '+str(self.designator)
-        if self.arg_list:
-            s += '('+', '.join(map(str,self.arg_list))+ ')'
+        if self.items:
+            s += '('+', '.join(map(str,self.items))+ ')'
         return s
 
 class Goto(Statement):
     """
     GO TO <label>
-    
     """
-    match = re.compile(r'go\s*to\b\s*\w*\s*\Z', re.I).match
+    match = re.compile(r'go\s*to\s*\d+\s*\Z', re.I).match
 
     def process_item(self):
-        self.gotolabel = self.item.get_line()[2:].lstrip()[2:].lstrip()
+        assert not self.item.has_map()
+        self.label = self.item.get_line()[2:].lstrip()[2:].lstrip()
         return
 
     def __str__(self):
-        return self.get_indent_tab() + 'GO TO %s' % (self.gotolabel)
+        return self.get_indent_tab() + 'GO TO %s' % (self.label)
 
 class ComputedGoto(Statement):
     """
@@ -99,10 +180,14 @@
     """
     match = re.compile(r'go\s*to\s*\(',re.I).match
     def process_item(self):
+        apply_map = self.item.apply_map
         line = self.item.get_line()[2:].lstrip()[2:].lstrip()
         i = line.index(')')
-        self.items = [s.strip() for s in line[1:i].strip(',')]
-        self.expr = line[i+1:].lstrip()
+        self.items = split_comma(line[1:i], self.item)
+        line = line[i+1:].lstrip()
+        if line.startswith(','):
+            line = line[1:].lstrip()
+        self.expr = apply_map(line)
         return
     def __str__(self):
         return  self.get_indent_tab() + 'GO TO (%s) %s' \
@@ -113,20 +198,26 @@
     GO TO <int-variable-name> [ ( <label> [ , <label> ]... ) ]
     """
     modes = ['fix77']
-    match = re.compile(r'go\s*to\s*\w+\s*,?\s*\(',re.I).match
+    match = re.compile(r'go\s*to\s*\w+\s*\(?',re.I).match
     def process_item(self):
         line = self.item.get_line()[2:].lstrip()[2:].lstrip()
         i = line.find('(')
+        if i==-1:
+            self.varname = line
+            self.items = []
+            return
+        self.varname = line[:i].rstrip()
         assert line[-1]==')',`line`
-        varname = line[:i].rstrip()
-        if varname.endswith(','):
-            varname = varname[:-1].rstrip()
-        self.varname = varname
-        self.items = [s.strip() for s in line[i+1:-1].split(',')]
+        self
+        self.items = split_comma(line[i+1:-1], self.item)
         return
+
     def __str__(self):
-        return self.get_indent_tab() + 'GO TO %s (%s)' \
-               % (self.varname, ', '.join(self.items)) 
+        tab = self.get_indent_tab()
+        if self.items:
+            return tab + 'GO TO %s (%s)' \
+                   % (self.varname, ', '.join(self.items)) 
+        return tab + 'GO TO %s' % (self.varname)
 
 class Continue(Statement):
     """
@@ -149,25 +240,31 @@
     match = re.compile(r'return\b',re.I).match
 
     def process_item(self):
-        self.expr = self.item.get_line()[6:].lstrip()
+        self.expr = self.item.apply_map(self.item.get_line()[6:].lstrip())
         return
 
     def __str__(self):
-        return self.get_indent_tab() + 'RETURN %s' % (self.expr)
+        tab = self.get_indent_tab()
+        if self.expr:
+            return tab + 'RETURN %s' % (self.expr)
+        return tab + 'RETURN'
 
 class Stop(Statement):
     """
     STOP [ <stop-code> ]
     <stop-code> = <scalar-char-constant> | <1-5-digit>
     """
-    match = re.compile(r'stop\s*(\'\w*\'|\d+|)\Z',re.I).match
+    match = re.compile(r'stop\s*(\'\w*\'|"\w*"|\d+|)\Z',re.I).match
 
     def process_item(self):
-        self.stopcode = self.item.get_line()[4:].lstrip()
+        self.code = self.item.apply_map(self.item.get_line()[4:].lstrip())
         return
 
     def __str__(self):
-        return self.get_indent_tab() + 'STOP %s' % (self.stopcode)
+        tab = self.get_indent_tab()
+        if self.code:
+            return tab + 'STOP %s' % (self.code)
+        return tab + 'STOP'
 
 class Print(Statement):
     """
@@ -180,27 +277,35 @@
     <implied-do-control> = <do-variable> = <scalar-int-expr> , <scalar-int-expr> [ , <scalar-int-expr> ]
     <input-item> = <variable> | <io-implied-do>
     """
-    match = re.compile(r'print\s*(\'\w*\'|\d+|[*]|\b\w)', re.I).match
+    match = re.compile(r'print\s*(\'\w*\'|\"\w*\"|\d+|[*]|\b\w)', re.I).match
 
     def process_item(self):
         item = self.item
+        apply_map = item.apply_map
         line = item.get_line()[5:].lstrip()
-        items = line.split(',')
-        self.format = items[0].strip()
-        self.items = [s.strip() for s in items[1:]]
+        items = split_comma(line, item)
+        self.format = items[0]
+        self.items = items[1:]
         return
 
     def __str__(self):
-        return self.get_indent_tab() + 'PRINT %s' % (', '.join([self.format]+self.items))
+        return self.get_indent_tab() + 'PRINT %s' \
+               % (', '.join([self.format]+self.items))
 
 class Read(Statement):
     """
-Read0:    READ ( io-control-spec-list ) [<input-item-list>]
+Read0:    READ ( <io-control-spec-list> ) [ <input-item-list> ]
+
+    <io-control-spec-list> = [ UNIT = ] <io-unit>
+                             | [ FORMAT = ] <format>
+                             | [ NML = ] <namelist-group-name>
+                             | ADVANCE = <scalar-default-char-expr>
+                             ...
     
 Read1:    READ <format> [, <input-item-list>]
     <format> == <default-char-expr> | <label> | *
     """
-    match = re.compile(r'read\b\s*[\w(*]', re.I).match
+    match = re.compile(r'read\b\s*[\w(*\'"]', re.I).match
 
     def process_item(self):
         item = self.item
@@ -210,6 +315,7 @@
         else:
             self.__class__ = Read1
         self.process_item()
+        return
 
 class Read0(Read):
 
@@ -217,25 +323,29 @@
         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(',')]
+        self.specs = specs_split_comma(line[1:i], item)
+        self.items = split_comma(line[i+1:], item)
+        return
 
     def __str__(self):
-        return self.get_indent_tab() + 'READ (%s) %s' \
-               % (self.io_control_specs, ', '.join(self.items))
+        s = self.get_indent_tab() + 'READ (%s)' % (', '.join(self.specs))
+        if self.items:
+            return s + ' ' + ', '.join(self.items)
+        return s
 
 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:]]
+        items = split_comma(line, item)
+        self.format = items[0]
+        self.items = items[1:]
         return
 
     def __str__(self):
-        return self.get_indent_tab() + 'READ %s' % (', '.join([self.format]+self.items))
+        return self.get_indent_tab() + 'READ ' \
+               + ', '.join([self.format]+self.items)
 
 class Write(Statement):
     """
@@ -246,13 +356,19 @@
         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(',')]
+        assert i != -1, `line`
+        self.specs = specs_split_comma(line[1:i], item)
+        self.items = split_comma(line[i+1:], item)
+        return
 
     def __str__(self):
-        return self.get_indent_tab() + 'WRITE (%s) %s' \
-               % (self.io_control_specs, ', '.join(self.items))        
+        s = self.get_indent_tab() + 'WRITE (%s)' % ', '.join(self.specs)
+        if self.items:
+            s += ' ' + ', '.join(self.items)
+        return s
 
+
+
 class Flush(Statement):
     """
     FLUSH <file-unit-number>
@@ -263,22 +379,22 @@
                  | ERR = <label>
     """
     match = re.compile(r'flush\b',re.I).match
+
     def process_item(self):
         line = self.item.get_line()[5:].lstrip()
         if not line:
             self.isvalid = False
             return
         if line.startswith('('):
-            if not line.endswith(')'):
-                self.isvalid = False
-                return
-            self.specs = line[1:-1].strip()
+            assert line[-1] == ')', `line`
+            self.specs = specs_split_comma(line[1:-1],self.item)
         else:
-            self.specs = line
+            self.specs = specs_split_comma(line,self.item)
         return
+
     def __str__(self):
         tab = self.get_indent_tab()
-        return tab + 'FLUSH (%s)' % (self.specs)
+        return tab + 'FLUSH (%s)' % (', '.join(self.specs))
 
 class Wait(Statement):
     """
@@ -294,11 +410,12 @@
     """
     match = re.compile(r'wait\s*\(.*\)\Z',re.I).match
     def process_item(self):
-        self.specs = self.item.get_line()[4:].lstrip()[1:-1].strip()
+        self.specs = specs_split_comma(\
+            self.item.get_line()[4:].lstrip()[1:-1], self.item)
         return
     def __str__(self):
         tab = self.get_indent_tab()
-        return tab + 'WAIT (%s)' % (self.specs)
+        return tab + 'WAIT (%s)' % (', '.join(self.specs))
 
 class Contains(Statement):
     """
@@ -311,22 +428,60 @@
 class Allocate(Statement):
     """
     ALLOCATE ( [ <type-spec> :: ] <allocation-list> [ , <alloc-opt-list> ] )
+    <alloc-opt> = STAT = <stat-variable>
+                | ERRMSG = <errmsg-variable>
+                | SOURCE = <source-expr>
+    <allocation> = <allocate-object> [ ( <allocate-shape-spec-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)
+        line = self.item.get_line()[8:].lstrip()[1:-1].strip()
+        item2 = self.item.copy(line, True)
+        line2 = item2.get_line()
+        i = line2.find('::')
+        if i != -1:
+            spec = item2.apply_map(line2[:i].rstrip())
+            from block_statements import type_spec
+            stmt = None
+            for cls in type_spec:
+                if cls.match(spec):
+                    stmt = cls(self, item2.copy(spec))
+                    if stmt.isvalid:
+                        break
+            if stmt is not None and stmt.isvalid:
+                spec = stmt
+            else:
+                print 'TODO: unparsed type-spec',`spec`
+            line2 = line2[i+2:].lstrip()
+        else:
+            spec = None
+        self.spec = spec
+        self.items = specs_split_comma(line2, item2)
+        return
 
+    def __str__(self):
+        t = ''
+        if self.spec:
+            t = self.spec.tostr() + ' :: '
+        return self.get_indent_tab() \
+               + 'ALLOCATE (%s%s)' % (t,', '.join(self.items))
+
 class Deallocate(Statement):
     """
     DEALLOCATE ( <allocate-object-list> [ , <dealloc-opt-list> ] )
+    <allocate-object> = <variable-name>
+                      | <structure-component>
+    <structure-component> = <data-ref>
+    <dealloc-opt> = STAT = <stat-variable>
+                    | ERRMSG = <errmsg-variable>
     """
     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()
+        line = self.item.get_line()[10:].lstrip()[1:-1].strip()
+        self.items = specs_split_comma(line, self.item)
+        return
     def __str__(self): return self.get_indent_tab() \
-        + 'DEALLOCATE ( %s )' % (self.items)
+        + 'DEALLOCATE (%s)' % (', '.join(self.items))
 
 class ModuleProcedure(Statement):
     """
@@ -336,15 +491,24 @@
     def process_item(self):
         line = self.item.get_line()
         m = self.match(line)
-        self.names = [s.strip() for s in line[m.end():].split(',')]
+        assert m,`line`
+        items = split_comma(line[m.end():].strip(), self.item)
+        for n in items:
+            if not is_name(n):
+                self.isvalid = False
+                return
+        self.items = items
+        return
+
     def __str__(self):
         tab = self.get_indent_tab()
-        return tab + 'MODULE PROCEDURE %s' % (', '.join(self.names))
+        return tab + 'MODULE PROCEDURE %s' % (', '.join(self.items))
 
 class Access(Statement):
     """
     <access-spec> [ [::] <access-id-list>]
     <access-spec> = PUBLIC | PRIVATE
+    <access-id> = <use-name> | <generic-spec>
     """
     match = re.compile(r'(public|private)\b',re.I).match
     def process_item(self):
@@ -356,12 +520,14 @@
         line = line[len(clsname):].lstrip()
         if line.startswith('::'):
             line = line[2:].lstrip()
-        self.items = [s.strip() for s in line.split(',')]
+        self.items = split_comma(line, self.item)
+        return
+
     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 + ' ' + ', '.join(self.items)
         return tab + clsname
 
 class Public(Access): pass
@@ -378,11 +544,12 @@
     """
     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()
+        line = self.item.get_line()[5:].lstrip()[1:-1].strip()
+        self.specs = specs_split_comma(line, self.item)
         return
     def __str__(self):
         tab = self.get_indent_tab()
-        return tab + 'CLOSE (%s)' % (self.close_specs)
+        return tab + 'CLOSE (%s)' % (', '.join(self.specs))
 
 class Cycle(Statement):
     """
@@ -393,7 +560,9 @@
         self.name = self.item.get_line()[5:].lstrip()
         return
     def __str__(self):
-        return self.get_indent_tab() + 'CYCLE ' + self.name
+        if self.name:
+            return self.get_indent_tab() + 'CYCLE ' + self.name
+        return self.get_indent_tab() + 'CYCLE'
 
 class FilePositioningStatement(Statement):
     """
@@ -416,18 +585,15 @@
         line = line[len(clsname):].lstrip()
         if line.startswith('('):
             assert line[-1]==')',`line`
-            self.fileunit = None
-            self.position_specs = line[1:-1].strip()
+            spec = line[1:-1].strip()
         else:
-            self.fileunit = line
-            self.position_specs = None
+            spec = line
+        self.specs = specs_split_comma(spec, self.item)
         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)
+        return self.get_indent_tab() + clsname + ' (%s)' % (', '.join(self.specs))
 
 class Backspace(FilePositioningStatement): pass
 
@@ -444,15 +610,34 @@
     """
     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()
+        line = self.item.get_line()[4:].lstrip()[1:-1].strip()
+        self.specs = specs_split_comma(line, self.item)
         return
     def __str__(self):
-        return self.get_indent_tab() + 'OPEN (%s)' % (self.connect_specs)
+        return self.get_indent_tab() + 'OPEN (%s)' % (', '.join(self.specs))
 
 class Format(Statement):
     """
     FORMAT <format-specification>
     <format-specification> = ( [ <format-item-list> ] )
+    <format-item> = [ <r> ] <data-edit-descr>
+                    | <control-edit-descr>
+                    | <char-string-edit-descr>
+                    | [ <r> ] ( <format-item-list> )
+    <data-edit-descr> = I <w> [ . <m> ]
+                        | B <w> [ . <m> ]
+                        ...
+    <r|w|m|d|e> = <int-literal-constant>
+    <v> = <signed-int-literal-constant>
+    <control-edit-descr> = <position-edit-descr>
+                         | [ <r> ] /
+                         | :
+                         ...
+    <position-edit-descr> = T <n>
+                            | TL <n>
+                            ...
+    <sign-edit-descr> = SS | SP | S
+    ...
     
     """
     match = re.compile(r'format\s*\(.*\)\Z', re.I).match
@@ -465,13 +650,13 @@
                         'R1001: FORMAT statement must be labeled but got %r.' \
                         % (item.label),
                         item.span[0],item.span[1])
-            print >> sys.stderr, message
+            self.show_message(message)
         line = item.get_line()[6:].lstrip()
         assert line[0]+line[-1]=='()',`line`
-        self.specs = line[1:-1].strip()
+        self.specs = split_comma(line[1:-1], item)
         return
     def __str__(self):
-        return self.get_indent_tab() + 'FORMAT (%s)' % (self.specs)
+        return self.get_indent_tab() + 'FORMAT (%s)' % (', '.join(self.specs))
 
 class Save(Statement):
     """
@@ -484,6 +669,7 @@
     """
     match = re.compile(r'save\b',re.I).match
     def process_item(self):
+        assert not self.item.has_map()
         line = self.item.get_line()[4:].lstrip()
         if line.startswith('::'):
             line = line[2:].lstrip()
@@ -507,7 +693,7 @@
         tab = self.get_indent_tab()
         if not self.items:
             return tab + 'SAVE'
-        return tab + 'SAVE :: %s' % (', '.join(self.items))
+        return tab + 'SAVE %s' % (', '.join(self.items))
 
 class Data(Statement):
     """
@@ -538,7 +724,10 @@
             if i==-1: return
             j = line.find('/',i+1)
             if j==-1: return
-            stmts.append((line[:i].rstrip(),line[i+1:j].strip()))
+            l1, l2 = line[:i].rstrip(),line[i+1:j].strip()
+            l1 = split_comma(l1, self.item)
+            l2 = split_comma(l2, self.item)
+            stmts.append((l1,l2))
             line = line[j+1:].lstrip()
             if line.startswith(','):
                 line = line[1:].lstrip()
@@ -550,7 +739,7 @@
         tab = self.get_indent_tab()
         l = []
         for o,v in self.stmts:
-            l.append('%s / %s /' %(o,v))
+            l.append('%s / %s /' %(', '.join(o),', '.join(v)))
         return tab + 'DATA ' + ' '.join(l)
 
 class Nullify(Statement):
@@ -560,10 +749,11 @@
     """
     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()
+        line = self.item.get_line()[7:].lstrip()[1:-1].strip()
+        self.items = split_comma(line, self.item)
         return
     def __str__(self):
-        return self.get_indent_tab() + 'NULLIFY (%s)' % (self.item_list)
+        return self.get_indent_tab() + 'NULLIFY (%s)' % (', '.join(self.items))
 
 class Use(Statement):
     """
@@ -581,32 +771,36 @@
         nature = ''
         if line.startswith(','):
             i = line.find('::')
-            nature = line[1:i].strip()
+            nature = line[1:i].strip().upper()
             line = line[i+2:].lstrip()
         if line.startswith('::'):
             line = line[2:].lstrip()
+        if nature and not is_name(nature):
+            self.isvalid = False
+            return
         self.nature = nature
         i = line.find(',')
         self.isonly = False
         if i==-1:
-            self.module = line
+            self.name = line
             self.items = []
         else:
-            self.module = line[:i].rstrip()
+            self.name = 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(',')]
+            self.items = split_comma(line, self.item)
+        return
 
     def __str__(self):
         tab = self.get_indent_tab()
         s = 'USE'
         if self.nature:
             s += ' ' + self.nature + ' ::'
-        s += ' ' + self.module
+        s += ' ' + self.name
         if self.isonly:
-            s += ' ONLY:'
+            s += ', ONLY:'
         elif self.items:
             s += ','
         if self.items:
@@ -619,10 +813,12 @@
     """
     match = re.compile(r'exit\b\s*\w*\s*\Z',re.I).match
     def process_item(self):
-        self.exitname = self.item.get_line()[4:].lstrip()
+        self.name = self.item.get_line()[4:].lstrip()
         return
     def __str__(self):
-        return self.get_indent_tab() + 'EXIT ' + self.exitname
+        if self.name:
+            return self.get_indent_tab() + 'EXIT ' + self.name
+        return self.get_indent_tab() + 'EXIT'
 
 class Parameter(Statement):
     """
@@ -631,10 +827,11 @@
     """
     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()
+        line = self.item.get_line()[9:].lstrip()[1:-1].strip()
+        self.items = split_comma(line, self.item)
         return
     def __str__(self):
-        return self.get_indent_tab() + 'PARAMETER (%s)' % (self.params)
+        return self.get_indent_tab() + 'PARAMETER (%s)' % (', '.join(self.items))
 
 class Equivalence(Statement):
     """
@@ -648,8 +845,10 @@
         for s in self.item.get_line()[11:].lstrip().split(','):
             s = s.strip()
             assert s[0]+s[-1]=='()',`s,self.item.get_line()`
-            items.append(s)
+            s = ', '.join(split_comma(s[1:-1], self.item))
+            items.append('('+s+')')
         self.items = items
+        return
     def __str__(self):
         return self.get_indent_tab() + 'EQUIVALENCE %s' % (', '.join(self.items))
 
@@ -663,7 +862,7 @@
         line = self.item.get_line()[9:].lstrip()
         if line.startswith('::'):
             line = line[2:].lstrip()
-        self.items = [s.strip() for s in line.split(',')]
+        self.items = split_comma(line, self.item)
         return
     def __str__(self):
         return self.get_indent_tab() + 'DIMENSION %s' % (', '.join(self.items))
@@ -678,7 +877,7 @@
         line = self.item.get_line()[6:].lstrip()
         if line.startswith('::'):
             line = line[2:].lstrip()
-        self.items = [s.strip() for s in line.split(',')]
+        self.items = split_comma(line, self.item)
         return
     def __str__(self):
         return self.get_indent_tab() + 'TARGET %s' % (', '.join(self.items))
@@ -695,64 +894,41 @@
         line = self.item.get_line()[7:].lstrip()
         if line.startswith('::'):
             line = line[2:].lstrip()
-        self.items = [s.strip() for s in line.split(',')]
+        self.items = split_comma(line, self.item)
         return
     def __str__(self):
         return self.get_indent_tab() + 'POINTER %s' % (', '.join(self.items))
 
-class Protected(Statement):
+class Protected(StatementWithNamelist):
     """
     PROTECTED [ :: ] <entity-name-list>
     """
     match = re.compile(r'protected\b',re.I).match
-    def process_item(self):
-        line = self.item.get_line()[9:].lstrip()
-        if line.startswith('::'):
-            line = line[2:].lstrip()
-        self.items = [s.strip() for s in line.split(',')]
-        return
-    def __str__(self):
-        return self.get_indent_tab() + 'PROTECTED %s' % (', '.join(self.items))
 
-class Volatile(Statement):
+
+class Volatile(StatementWithNamelist):
     """
     Volatile [ :: ] <object-name-list>
     """
     match = re.compile(r'volatile\b',re.I).match
-    def process_item(self):
-        line = self.item.get_line()[8:].lstrip()
-        if line.startswith('::'):
-            line = line[2:].lstrip()
-        self.items = [s.strip() for s in line.split(',')]
-        return
-    def __str__(self):
-        return self.get_indent_tab() + 'VOLATILE %s' % (', '.join(self.items))
 
-class Value(Statement):
+class Value(StatementWithNamelist):
     """
     VALUE [ :: ] <dummy-arg-name-list>
     """
     match = re.compile(r'value\b',re.I).match
-    def process_item(self):
-        line = self.item.get_line()[5:].lstrip()
-        if line.startswith('::'):
-            line = line[2:].lstrip()
-        self.items = [s.strip() for s in line.split(',')]
-        return
-    def __str__(self):
-        return self.get_indent_tab() + 'VALUE %s' % (', '.join(self.items))
 
 class ArithmeticIf(Statement):
     """
     IF ( <scalar-numeric-expr> ) <label> , <label> , <label>
     """
-    match = re.compile(r'if\s*\(.*\)\s*\w+\s*,\s*\w+\s*,\s*\w+\s*\Z', re.I).match
+    match = re.compile(r'if\s*\(.*\)\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\Z', re.I).match
     def process_item(self):
         line = self.item.get_line()[2:].lstrip()
         line,l2,l3 = line.rsplit(',',2)
         i = line.rindex(')')
         l1 = line[i+1:]
-        self.expr = line[1:i].strip()
+        self.expr = self.item.apply_map(line[1:i]).strip()
         self.labels = [l1.strip(),l2.strip(),l3.strip()]
         return
 
@@ -760,19 +936,11 @@
         return self.get_indent_tab() + 'IF (%s) %s' \
                % (self.expr,', '.join(self.labels))
 
-class Intrinsic(Statement):
+class Intrinsic(StatementWithNamelist):
     """
     INTRINSIC [ :: ] <intrinsic-procedure-name-list>
     """
     match = re.compile(r'intrinsic\b',re.I).match
-    def process_item(self):
-        line = self.item.get_line()[10:].lstrip()
-        if line.startswith('::'):
-            line = line[2:].lstrip()
-        self.items = [s.strip() for s in line.split(',')]
-        return
-    def __str__(self):
-        return self.get_indent_tab() + 'INTRINSIC ' + ', '.join(self.items)
 
 class Inquire(Statement):
     """
@@ -789,11 +957,15 @@
     def process_item(self):
         line = self.item.get_line()[7:].lstrip()
         i = line.index(')')
-        self.specs = line[1:i].strip()
-        self.items = line[i+1:].lstrip()
+        self.specs = specs_split_comma(line[1:i].strip(), self.item)
+        self.items = split_comma(line[i+1:].lstrip(), self.item)
         return
     def __str__(self):
-        return self.get_indent_tab() + 'INQUIRE (%s) %s' % (self.specs, self.items)
+        if self.items:
+            return self.get_indent_tab() + 'INQUIRE (%s) %s' \
+                   % (', '.join(self.specs), ', '.join(self.items))
+        return self.get_indent_tab() + 'INQUIRE (%s)' \
+                   % (', '.join(self.specs))
 
 class Sequence(Statement):
     """
@@ -804,19 +976,11 @@
         return
     def __str__(self): return self.get_indent_tab() + 'SEQUENCE'
 
-class External(Statement):
+class External(StatementWithNamelist):
     """
     EXTERNAL [ :: ] <external-name-list>
     """
     match = re.compile(r'external\b').match
-    def process_item(self):
-        line = self.item.get_line()[8:].lstrip()
-        if line.startswith('::'):
-            line = line[2:].lstrip()
-        self.items = [s.strip() for s in line.split(',')]
-        return
-    def __str__(self):
-        return self.get_indent_tab() + 'EXTERNAL ' + ', '.join(self.items)
 
 class Namelist(Statement):
     """
@@ -862,7 +1026,8 @@
     """
     match = re.compile(r'common\b',re.I).match
     def process_item(self):
-        line = self.item.get_line()[6:].lstrip()
+        item = self.item
+        line = item.get_line()[6:].lstrip()
         items = []
         while line:
             if not line.startswith('/'):
@@ -871,56 +1036,60 @@
             else:
                 i = line.find('/',1)
                 assert i!=-1,`line`
-                name = line[:i+1]
+                name = line[1:i].strip()
                 line = line[i+1:].lstrip()
             i = line.find('/')
             if i==-1:
-                items.append((name,line))
+                items.append((name,split_comma(line, item)))
                 line = ''
                 continue
             s = line[:i].rstrip()
             if s.endswith(','):
                 s = s[:-1].rstrip()
-            items.append((name,s))
-            line = line[i+1:].lstrip()
+            items.append((name,split_comma(s,item)))
+            line = line[i:].lstrip()
         self.items = items
         return
     def __str__(self):
         l = []
         for name,s in self.items:
-            l.append('%s %s' % (name,s))
+            s = ', '.join(s)
+            if name:
+                l.append('/ %s / %s' % (name,s))
+            else:
+                l.append(s)
         tab = self.get_indent_tab()
-        return tab + 'COMMON ' + ', '.join(l)
+        return tab + 'COMMON ' + ' '.join(l)
 
-class Optional(Statement):
+class Optional(StatementWithNamelist):
     """
     OPTIONAL [ :: ] <dummy-arg-name-list>
     <dummy-arg-name> = <name>
     """
     match = re.compile(r'optional\b',re.I).match
-    def process_item(self):
-        line = self.item.get_line()[8:].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() + 'OPTIONAL ' + ', '.join(self.items)
 
 class Intent(Statement):
     """
     INTENT ( <intent-spec> ) [ :: ] <dummy-arg-name-list>
     <intent-spec> = IN | OUT | INOUT
+
+    generalization for pyf-files:
+    INTENT ( <intent-spec-list> ) [ :: ] <dummy-arg-name-list>
+    <intent-spec> = IN | OUT | INOUT | CACHE | HIDE | OUT = <name>
     """
     match = re.compile(r'intent\s*\(',re.I).match
     def process_item(self):
         line = self.item.get_line()[6:].lstrip()
         i = line.find(')')
-        self.specs = [s.strip() for s in line[1:i].strip().split(',')]
+        self.specs = split_comma(line[1:i], self.item)
         line = line[i+1:].lstrip()
         if line.startswith('::'):
             line = line[2:].lstrip()
         self.items = [s.strip() for s in line.split(',')]
+        for n in self.items:
+            if not is_name(n):
+                self.isvalid = False
+                return
         return
     def __str__(self):
         return self.get_indent_tab() + 'INTENT (%s) %s' \
@@ -933,53 +1102,65 @@
              | RESULT ( <result-name> ) [ <proc-language-binding-spec> ]
     <proc-language-binding-spec> = <language-binding-spec>
     <language-binding-spec> = BIND ( C [ , NAME = <scalar-char-initialization-expr> ] )
+    <dummy-arg> = <dummy-arg-name> | *
     """
     match = re.compile(r'entry\b', re.I).match
     def process_item(self):
         line = self.item.get_line()[5:].lstrip()
-        i = line.find('(')
-        if i==-1:
-            self.entryname = line
-            self.items = []
-            self.suffix = ''
+        m = re.match(r'\w+', line)
+        name = line[:m.end()]
+        line = line[m.end():].lstrip()
+        if line.startswith('('):
+            i = line.find(')')
+            assert i!=-1,`line`
+            items = split_comma(line[1:i], self.item)
+            line = line[i+1:].lstrip()
         else:
-            self.entryname = line[:i].rstrip()
-            line = line[i:]
+            items = []
+        binds = []
+        result = ''
+        if line.startswith('bind'):
+            line = line[4:].lstrip()
             i = line.find(')')
-            self.items = [s.split() for s in line[1:i].split(',')]
-            self.suffix = line[i+1:].lstrip()
+            assert line.startswith('(') and i != -1,`line`
+            binds = split_comma(line[1:i], self.item)
+            line = line[i+1:].lstrip()
+        if line.startswith('result'):
+            line = line[6:].lstrip()
+            i = line.find(')')
+            assert line.startswith('(') and i != -1,`line`
+            result = line[1:i].strip()
+            assert is_name(result),`result,line`
+            line = line[i+1:].lstrip()
+        if line.startswith('bind'):
+            assert not binds
+            line = line[4:].lstrip()
+            i = line.find(')')
+            assert line.startswith('(') and i != -1,`line`
+            binds = split_comma(line[1:i], self.item)
+            line = line[i+1:].lstrip()
+        assert not line,`line`
+        self.name = name
+        self.items = items
+        self.result = result
+        self.binds = binds
         return
     def __str__(self):
         tab = self.get_indent_tab()
-        s = tab + 'ENTRY '+self.entryname
+        s = tab + 'ENTRY '+self.name
         if self.items:
             s += ' (%s)' % (', '.join(self.items))
-        if self.suffix:
-            if not self.items:
-                s += ' ()'
-            s += ' ' + self.suffix
+        if self.result:
+            s += ' RESULT (%s)' % (self.result)
+        if self.binds:
+            s += ' BIND (%s)' % (', '.join(self.binds))
         return s
 
-class Import(Statement):
+class Import(StatementWithNamelist):
     """
     IMPORT [ [ :: ] <import-name-list> ]
     """
-    match = re.compile(r'import\b',re.I).match
-    def process_item(self):
-        line = self.item.get_line()[6:].lstrip()
-        if line.startswith('::'):
-            line = line[2:].lstrip()
-        items = []
-        for s in line.split(','):
-            s = s.strip()
-            if not is_name(s):
-                self.isvalid = False
-                return
-            items.append(s)
-        self.items = items
-        return
-    def __str__(self):
-        return self.get_indent_tab() + 'IMPORT ' + ', '.join(self.items)
+    match = re.compile(r'import(\b|\Z)',re.I).match
 
 class Forall(Statement):
     """
@@ -995,7 +1176,7 @@
         i = line.index(')')
         self.specs = line[1:i].strip()
         line = line[i+1:].lstrip()
-        stmt = Assignment(self, self.item.copy(line))
+        stmt = GeneralAssignment(self, self.item.copy(line))
         if stmt.isvalid:
             self.content = [stmt]
         else:
@@ -1068,26 +1249,11 @@
         return tab + s
 
         
-class FinalBinding(Statement):
+class FinalBinding(StatementWithNamelist):
     """
     FINAL [ :: ] <final-subroutine-name-list>
     """
     match = re.compile(r'final\b', re.I).match
-    def process_item(self):
-        line = self.item.get_line()[5:].lstrip()
-        if line.startswith('::'):
-            line = line[2:].lstrip()
-        items = []
-        for s in line.split(','):
-            s = s.strip()
-            if not is_name(s):
-                self.isvalid = False
-                return
-            items.append(s)
-        self.items = items
-        return
-    def __str__(self):
-        return self.get_indent_tab() + 'FINAL ' + ', '.join(self.items)
 
 class Allocatable(Statement):
     """
@@ -1107,29 +1273,12 @@
     def __str__(self):
         return self.get_tab_indent() + 'ALLOCATABLE ' + ', '.join(self.items) 
 
-class Asynchronous(Statement):
+class Asynchronous(StatementWithNamelist):
     """
     ASYNCHRONOUS [ :: ] <object-name-list>
     """
     match = re.compile(r'asynchronous\b',re.I).match
 
-    def process_item(self):
-        line = self.item.get_line()[12:].lstrip()
-        if line.startswith('::'):
-            line = line[2:].lstrip()
-        items = []
-        for s in line.split(','):
-            s = s.strip()
-            if not is_name(s):
-                self.isvalid = False
-                return
-            items.append(s)
-        self.items = items
-        return
-
-    def __str__(self):
-        return self.get_indent_tab() + 'ASYNCHRONOUS ' + ', '.join(self.items)
-
 class Bind(Statement):
     """
     <language-binding-spec> [ :: ] <bind-entity-list>

Added: trunk/numpy/f2py/lib/test_parser.py
===================================================================
--- trunk/numpy/f2py/lib/test_parser.py	2006-06-30 13:28:59 UTC (rev 2710)
+++ trunk/numpy/f2py/lib/test_parser.py	2006-06-30 13:36:13 UTC (rev 2711)
@@ -0,0 +1,310 @@
+
+from numpy.testing import *
+from block_statements import *
+from readfortran import Line, FortranStringReader
+
+def toLine(line, label=''):
+    if label:
+        line = label + ' : ' + line
+    reader = FortranStringReader(line, True, False)
+    return reader.next()
+
+def parse(cls, line, label=''):
+    item = toLine(line, label=label)
+    if not cls.match(item.get_line()):
+        raise ValueError, '%r does not match %s pattern' % (line, cls.__name__)
+    stmt = cls(item, item)
+
+    if stmt.isvalid:
+        return str(stmt)
+    raise ValueError, 'parsing %r with %s pattern failed' % (line, cls.__name__)
+
+class test_Statements(NumpyTestCase):
+
+    def check_assignment(self):
+        assert_equal(parse(Assignment,'a=b'), 'a = b')
+        assert_equal(parse(PointerAssignment,'a=>b'), 'a => b')
+        assert_equal(parse(Assignment,'a (2)=b(n,m)'), 'a(2) = b(n,m)')
+        assert_equal(parse(Assignment,'a % 2(2,4)=b(a(i))'), 'a%2(2,4) = b(a(i))')
+
+    def check_assign(self):
+        assert_equal(parse(Assign,'assign 10 to a'),'ASSIGN 10 TO a')
+
+    def check_call(self):
+        assert_equal(parse(Call,'call a'),'CALL a')
+        assert_equal(parse(Call,'call a()'),'CALL a')
+        assert_equal(parse(Call,'call a(1)'),'CALL a(1)')
+        assert_equal(parse(Call,'call a(1,2)'),'CALL a(1, 2)')
+        assert_equal(parse(Call,'call a % 2 ( n , a+1 )'),'CALL a % 2(n, a+1)')
+
+    def check_goto(self):
+        assert_equal(parse(Goto,'go to 19'),'GO TO 19')
+        assert_equal(parse(Goto,'goto 19'),'GO TO 19')
+        assert_equal(parse(ComputedGoto,'goto (1, 2 ,3) a+b(2)'),
+                     'GO TO (1, 2, 3) a+b(2)')
+        assert_equal(parse(ComputedGoto,'goto (1, 2 ,3) , a+b(2)'),
+                     'GO TO (1, 2, 3) a+b(2)')
+        assert_equal(parse(AssignedGoto,'goto a'),'GO TO a')
+        assert_equal(parse(AssignedGoto,'goto a ( 1 )'),'GO TO a (1)')
+        assert_equal(parse(AssignedGoto,'goto a ( 1 ,2)'),'GO TO a (1, 2)')
+
+    def check_continue(self):
+        assert_equal(parse(Continue,'continue'),'CONTINUE')
+
+    def check_return(self):
+        assert_equal(parse(Return,'return'),'RETURN')
+        assert_equal(parse(Return,'return a'),'RETURN a')
+        assert_equal(parse(Return,'return a+1'),'RETURN a+1')
+        assert_equal(parse(Return,'return a(c, a)'),'RETURN a(c, a)')
+
+    def check_stop(self):
+        assert_equal(parse(Stop,'stop'),'STOP')
+        assert_equal(parse(Stop,'stop 1'),'STOP 1')
+        assert_equal(parse(Stop,'stop "a"'),'STOP "a"')
+        assert_equal(parse(Stop,'stop "a b"'),'STOP "a b"')
+
+    def check_print(self):
+        assert_equal(parse(Print, 'print*'),'PRINT *')
+        assert_equal(parse(Print, 'print "a b( c )"'),'PRINT "a b( c )"')
+        assert_equal(parse(Print, 'print 12, a'),'PRINT 12, a')
+        assert_equal(parse(Print, 'print 12, a , b'),'PRINT 12, a, b')
+        assert_equal(parse(Print, 'print 12, a(c,1) , b'),'PRINT 12, a(c,1), b')
+
+    def check_read(self):
+        assert_equal(parse(Read, 'read ( 10 )'),'READ (10)')
+        assert_equal(parse(Read, 'read ( 10 ) a '),'READ (10) a')
+        assert_equal(parse(Read, 'read ( 10 ) a , b'),'READ (10) a, b')
+        assert_equal(parse(Read, 'read *'),'READ *')
+        assert_equal(parse(Read, 'read 12'),'READ 12')
+        assert_equal(parse(Read, 'read "a b"'),'READ "a b"')
+        assert_equal(parse(Read, 'read "a b",a'),'READ "a b", a')
+        assert_equal(parse(Read, 'read * , a'),'READ *, a')
+        assert_equal(parse(Read, 'read "hey a" , a'),'READ "hey a", a')
+        assert_equal(parse(Read, 'read * , a  , b'),'READ *, a, b')
+        assert_equal(parse(Read, 'read ( unit  =10 )'),'READ (UNIT = 10)')
+        
+    def check_write(self):
+        assert_equal(parse(Write, 'write ( 10 )'),'WRITE (10)')
+        assert_equal(parse(Write, 'write ( 10 , a )'),'WRITE (10, a)')
+        assert_equal(parse(Write, 'write ( 10 ) b'),'WRITE (10) b')
+        assert_equal(parse(Write, 'write ( 10 ) a(1) , b+2'),'WRITE (10) a(1), b+2')
+        assert_equal(parse(Write, 'write ( unit=10 )'),'WRITE (UNIT = 10)')
+
+    def check_flush(self):
+        assert_equal(parse(Flush, 'flush 10'),'FLUSH (10)')
+        assert_equal(parse(Flush, 'flush (10)'),'FLUSH (10)')
+        assert_equal(parse(Flush, 'flush (UNIT = 10)'),'FLUSH (UNIT = 10)')
+        assert_equal(parse(Flush, 'flush (10, err=  23)'),'FLUSH (10, ERR = 23)')
+
+    def check_wait(self):
+        assert_equal(parse(Wait, 'wait(10)'),'WAIT (10)')
+        assert_equal(parse(Wait, 'wait(10,err=129)'),'WAIT (10, ERR = 129)')
+
+    def check_contains(self):
+        assert_equal(parse(Contains, 'contains'),'CONTAINS')
+
+    def check_allocate(self):
+        assert_equal(parse(Allocate, 'allocate (a)'), 'ALLOCATE (a)')
+        assert_equal(parse(Allocate, \
+                           'allocate (a, stat=b)'), 'ALLOCATE (a, STAT = b)')
+        assert_equal(parse(Allocate, 'allocate (a,b(:1))'), 'ALLOCATE (a, b(:1))')
+        assert_equal(parse(Allocate, \
+                           'allocate (real(8)::a)'), 'ALLOCATE (REAL(8) :: a)')
+    def check_deallocate(self):
+        assert_equal(parse(Deallocate, 'deallocate (a)'), 'DEALLOCATE (a)')
+        assert_equal(parse(Deallocate, 'deallocate (a, stat=b)'), 'DEALLOCATE (a, STAT = b)')
+
+    def check_moduleprocedure(self):
+        assert_equal(parse(ModuleProcedure,\
+                           'ModuleProcedure a'), 'MODULE PROCEDURE a')
+        assert_equal(parse(ModuleProcedure,\
+                           'module procedure a , b'), 'MODULE PROCEDURE a, b')
+
+    def check_access(self):
+        assert_equal(parse(Public,'Public'),'PUBLIC')
+        assert_equal(parse(Public,'public a'),'PUBLIC a')
+        assert_equal(parse(Public,'public :: a'),'PUBLIC a')
+        assert_equal(parse(Public,'public a,b,c'),'PUBLIC a, b, c')
+        assert_equal(parse(Public,'public :: a(:,:)'),'PUBLIC a(:,:)')
+        assert_equal(parse(Private,'private'),'PRIVATE')
+        assert_equal(parse(Private,'private :: a'),'PRIVATE a')
+
+    def check_close(self):
+        assert_equal(parse(Close,'close (12)'),'CLOSE (12)')
+        assert_equal(parse(Close,'close (12, err=99)'),'CLOSE (12, ERR = 99)')
+        assert_equal(parse(Close,'close (12, status = a(1,2))'),'CLOSE (12, STATUS = a(1,2))')
+
+    def check_cycle(self):
+        assert_equal(parse(Cycle,'cycle'),'CYCLE')
+        assert_equal(parse(Cycle,'cycle ab'),'CYCLE ab')
+
+    def check_rewind(self):
+        assert_equal(parse(Rewind,'rewind 1'),'REWIND (1)')
+        assert_equal(parse(Rewind,'rewind (1)'),'REWIND (1)')
+        assert_equal(parse(Rewind,'rewind (1, err =  123)'),'REWIND (1, ERR = 123)')
+
+    def check_backspace(self):
+        assert_equal(parse(Backspace,'backspace 1'),'BACKSPACE (1)')
+        assert_equal(parse(Backspace,'backspace (1)'),'BACKSPACE (1)')
+        assert_equal(parse(Backspace,'backspace (1, err =  123)'),'BACKSPACE (1, ERR = 123)')
+
+    def check_endfile(self):
+        assert_equal(parse(Endfile,'endfile 1'),'ENDFILE (1)')
+        assert_equal(parse(Endfile,'endfile (1)'),'ENDFILE (1)')
+        assert_equal(parse(Endfile,'endfile (1, err =  123)'),'ENDFILE (1, ERR = 123)')
+
+    def check_open(self):
+        assert_equal(parse(Open,'open (1)'),'OPEN (1)')
+        assert_equal(parse(Open,'open (1, err =  123)'),'OPEN (1, ERR = 123)')
+
+    def check_format(self):
+        assert_equal(parse(Format,'1: format ()'),'1: FORMAT ()')
+        assert_equal(parse(Format,'199 format (1)'),'199: FORMAT (1)')
+        assert_equal(parse(Format,'2 format (1 , SS)'),'2: FORMAT (1, ss)')
+
+    def check_save(self):
+        assert_equal(parse(Save,'save'), 'SAVE')
+        assert_equal(parse(Save,'save :: a'), 'SAVE a')
+        assert_equal(parse(Save,'save a,b'), 'SAVE a, b')
+
+    def check_data(self):
+        assert_equal(parse(Data,'data a /b/'), 'DATA a / b /')
+        assert_equal(parse(Data,'data a , c /b/'), 'DATA a, c / b /')
+        assert_equal(parse(Data,'data a /b ,c/'), 'DATA a / b, c /')
+        assert_equal(parse(Data,'data a /b/ c,e /d/'), 'DATA a / b / c, e / d /')
+        assert_equal(parse(Data,'data a(1,2) /b/'), 'DATA a(1,2) / b /')
+        assert_equal(parse(Data,'data a /b, c(1)/'), 'DATA a / b, c(1) /')
+
+    def check_nullify(self):
+        assert_equal(parse(Nullify,'nullify(a)'),'NULLIFY (a)')
+        assert_equal(parse(Nullify,'nullify(a  ,b)'),'NULLIFY (a, b)')
+
+    def check_use(self):
+        assert_equal(parse(Use, 'use a'), 'USE a')
+        assert_equal(parse(Use, 'use :: a'), 'USE a')
+        assert_equal(parse(Use, 'use, intrinsic:: a'), 'USE INTRINSIC :: a')
+        assert_equal(parse(Use, 'use :: a ,only: b'), 'USE a, ONLY: b')
+        assert_equal(parse(Use, 'use :: a , only: b=>c'), 'USE a, ONLY: b=>c')
+        assert_equal(parse(Use, 'use :: a , b=>c'), 'USE a, b=>c')
+        assert_equal(parse(Use,\
+                           'use :: a , only: operator(+) , b'),\
+                     'USE a, ONLY: operator(+), b')
+
+    def check_exit(self):
+        assert_equal(parse(Exit,'exit'),'EXIT')
+        assert_equal(parse(Exit,'exit ab'),'EXIT ab')        
+
+    def check_parameter(self):
+        assert_equal(parse(Parameter,'parameter (a = b(1,2))'),
+                     'PARAMETER (a = b(1,2))')
+        assert_equal(parse(Parameter,'parameter (a = b(1,2) , b=1)'),
+                     'PARAMETER (a = b(1,2), b=1)')
+
+    def check_equivalence(self):
+        assert_equal(parse(Equivalence,'equivalence (a , b)'),'EQUIVALENCE (a, b)')
+        assert_equal(parse(Equivalence,'equivalence (a , b) , ( c, d(1) , g  )'),
+                     'EQUIVALENCE (a, b), (c, d(1), g)')
+
+    def check_dimension(self):
+        assert_equal(parse(Dimension,'dimension a(b)'),'DIMENSION a(b)')
+        assert_equal(parse(Dimension,'dimension::a(b)'),'DIMENSION a(b)')
+        assert_equal(parse(Dimension,'dimension a(b)  , c(d)'),'DIMENSION a(b), c(d)')
+        assert_equal(parse(Dimension,'dimension a(b,c)'),'DIMENSION a(b,c)')
+
+    def check_target(self):
+        assert_equal(parse(Target,'target a(b)'),'TARGET a(b)')
+        assert_equal(parse(Target,'target::a(b)'),'TARGET a(b)')
+        assert_equal(parse(Target,'target a(b)  , c(d)'),'TARGET a(b), c(d)')
+        assert_equal(parse(Target,'target a(b,c)'),'TARGET a(b,c)')
+
+    def check_pointer(self):
+        assert_equal(parse(Pointer,'pointer a=b'),'POINTER a=b')
+        assert_equal(parse(Pointer,'pointer :: a=b'),'POINTER a=b')
+        assert_equal(parse(Pointer,'pointer a=b, c=d(1,2)'),'POINTER a=b, c=d(1,2)')
+
+    def check_protected(self):
+        assert_equal(parse(Protected,'protected a'),'PROTECTED a')
+        assert_equal(parse(Protected,'protected::a'),'PROTECTED a')
+        assert_equal(parse(Protected,'protected a , b'),'PROTECTED a, b')
+
+    def check_volatile(self):
+        assert_equal(parse(Volatile,'volatile a'),'VOLATILE a')
+        assert_equal(parse(Volatile,'volatile::a'),'VOLATILE a')
+        assert_equal(parse(Volatile,'volatile a , b'),'VOLATILE a, b')
+
+    def check_value(self):
+        assert_equal(parse(Value,'value a'),'VALUE a')
+        assert_equal(parse(Value,'value::a'),'VALUE a')
+        assert_equal(parse(Value,'value a , b'),'VALUE a, b')
+
+    def check_arithmeticif(self):
+        assert_equal(parse(ArithmeticIf,'if (a) 1,2,3'),'IF (a) 1, 2, 3')
+        assert_equal(parse(ArithmeticIf,'if (a(1)) 1,2,3'),'IF (a(1)) 1, 2, 3')
+        assert_equal(parse(ArithmeticIf,'if (a(1,2)) 1,2,3'),'IF (a(1,2)) 1, 2, 3')
+
+    def check_intrinsic(self):
+        assert_equal(parse(Intrinsic,'intrinsic a'),'INTRINSIC a')
+        assert_equal(parse(Intrinsic,'intrinsic::a'),'INTRINSIC a')
+        assert_equal(parse(Intrinsic,'intrinsic a , b'),'INTRINSIC a, b')
+
+    def check_inquire(self):
+        assert_equal(parse(Inquire, 'inquire (1)'),'INQUIRE (1)')
+        assert_equal(parse(Inquire, 'inquire (1, err=123)'),'INQUIRE (1, ERR = 123)')
+        assert_equal(parse(Inquire, 'inquire (iolength=a) b'),'INQUIRE (IOLENGTH = a) b')
+        assert_equal(parse(Inquire, 'inquire (iolength=a) b  ,c(1,2)'),
+                     'INQUIRE (IOLENGTH = a) b, c(1,2)')
+
+    def check_sequence(self):
+        assert_equal(parse(Sequence, 'sequence'),'SEQUENCE')
+
+    def check_external(self):
+        assert_equal(parse(External,'external a'),'EXTERNAL a')
+        assert_equal(parse(External,'external::a'),'EXTERNAL a')
+        assert_equal(parse(External,'external a , b'),'EXTERNAL a, b')
+
+    def check_common(self):
+        assert_equal(parse(Common, 'common a'),'COMMON a')
+        assert_equal(parse(Common, 'common a , b'),'COMMON a, b')
+        assert_equal(parse(Common, 'common a , b(1,2)'),'COMMON a, b(1,2)')
+        assert_equal(parse(Common, 'common // a'),'COMMON a')
+        assert_equal(parse(Common, 'common / name/ a'),'COMMON / name / a')
+        assert_equal(parse(Common, 'common / name/ a  , c'),'COMMON / name / a, c')
+        assert_equal(parse(Common, 'common / name/ a /foo/ c(1) ,d'),
+                     'COMMON / name / a / foo / c(1), d')
+        assert_equal(parse(Common, 'common / name/ a, /foo/ c(1) ,d'),
+                     'COMMON / name / a / foo / c(1), d')
+
+    def check_optional(self):
+        assert_equal(parse(Optional,'optional a'),'OPTIONAL a')
+        assert_equal(parse(Optional,'optional::a'),'OPTIONAL a')
+        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')
+
+    def check_entry(self):
+        assert_equal(parse(Entry,'entry a'), 'ENTRY a')
+        assert_equal(parse(Entry,'entry a()'), 'ENTRY a')
+        assert_equal(parse(Entry,'entry a(b)'), 'ENTRY a (b)')
+        assert_equal(parse(Entry,'entry a(b,*)'), 'ENTRY a (b, *)')
+        assert_equal(parse(Entry,'entry a bind(c , name="a b")'),
+                     '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)')
+        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)'),
+                     'ENTRY a (b, *) RESULT (g)')
+
+    def check_import(self):
+        assert_equal(parse(Import,'import'),'IMPORT')
+        assert_equal(parse(Import,'import a'),'IMPORT a')
+        assert_equal(parse(Import,'import::a'),'IMPORT a')
+        assert_equal(parse(Import,'import a , b'),'IMPORT a, b')
+
+if __name__ == "__main__":
+    NumpyTest().run()

Modified: trunk/numpy/f2py/lib/typedecl_statements.py
===================================================================
--- trunk/numpy/f2py/lib/typedecl_statements.py	2006-06-30 13:28:59 UTC (rev 2710)
+++ trunk/numpy/f2py/lib/typedecl_statements.py	2006-06-30 13:36:13 UTC (rev 2711)
@@ -61,6 +61,7 @@
 
     def process_item(self):
         item = self.item
+        apply_map = item.apply_map
         clsname = self.__class__.__name__.lower()
         line = item.get_line()
         from block_statements import Function
@@ -81,14 +82,14 @@
 
         if line.startswith('('):
             i = line.find(')')
-            selector = line[:i+1].strip()
+            selector = apply_map(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()
+                selector += apply_map(line[:i+1].rstrip())
                 line = line[i+1:].lstrip()
             else:
                 m = re.match(r'\d+(_\w+|)|[*]',line)



More information about the Numpy-svn mailing list