#!/usr/bin/env python
# Copyright, 1999, Regents of the University of California
# Please see file Legal.htm
import string
from spark import GenericScanner,GenericParser
from semantics import *
#
# SCANNING
#
class Token:
def __init__(self, type, attr=None, filename="?", lineno="?"):
self.type = type
self.attr = attr
self.filename = filename
self.lineno = lineno
def __cmp__(self, o):
return cmp(self.type, o)
def __repr__ (self):
if self.attr:
s = repr(self.attr)
else:
s = repr(self.type)
return s
def info(self):
return "File " + repr(self.filename) + ", line " + repr(self.lineno)
def error(self):
print "Error concerning token", self, "(", self.info(), ")"
raise SystemExit, 1
keywords=['integer','real',
'doubleprecision',
'complex', 'doublecomplex',
'string', 'character', 'logical','type', 'kind',
'function', 'subroutine', 'module', 'interface', 'contains',
'intent', 'in', 'out', 'inout', 'optional', 'dimension', 'common',
'temporary', 'size', 'allocatable',
'end']
class FortranScanner(GenericScanner):
def __init__(self, column1_comments):
GenericScanner.__init__(self)
self.c = column1_comments
def tokenize(self, filename):
self.lineno = 1
self.filename = filename
f = open(filename, "r")
if self.c:
input = ''
line = f.readline()
while line:
if line[0] == 'C':
line = '!' + line[1:]
if line[0] == 'c':
line = '!' + line[1:]
input = input + line
line = f.readline()
else:
input = f.read()
f.close()
self.rv = []
GenericScanner.tokenize(self, input)
return self.rv
def new(self, type, attr=None):
"Create a new token."
return Token(type, attr, self.filename, self.lineno)
def t_continue(self, s):
r' &.*\n '
self.lineno = self.lineno + 1
pass
def t_nl(self, s):
r' \n '
self.lineno = self.lineno + 1
pass
def t_whitespace(self, s):
r' [ \t]+ '
pass
def t_comment(self, s):
r' \!.* '
self.rv.append(self.new(type='comment', attr=s))
def t_colon(self, s):
r' : '
self.rv.append(self.new(type=s))
def t_equal(self, s):
r' = '
self.rv.append(self.new(type=s))
def t_comma(self, s):
r' , '
self.rv.append(self.new(type=s))
def t_lparen(self, s):
r' \( '
self.rv.append(self.new(type=s))
def t_rparen(self, s):
r' \) '
self.rv.append(self.new(type=s))
def t_dp(self, s):
r' double[\ \t]*precision '
self.rv.append(self.new(type='doubleprecision'))
def t_dc(self, s):
r' double[\ \t]*complex '
self.rv.append(self.new(type='doublecomplex'))
def t_id(self, s):
r' [a-zA-Z_][a-zA-Z_0-9]* '
ls = string.lower(s)
if ls in keywords:
self.rv.append(self.new(type=ls))
else:
self.rv.append(self.new(type='id',attr=ls))
def t_op(self, s):
r' \+ | \* | \- | \/ '
self.rv.append(self.new(type=s))
def t_number(self, s):
r' \d+ '
t = self.new(type='number', attr=s)
self.rv.append(t)
def scan(f, column1_comments):
scanner = FortranScanner(column1_comments)
return scanner.tokenize(f)
#
# PARSING
#
class InterfaceParser(GenericParser):
def __init__(self, start='afile'):
GenericParser.__init__(self, start)
def error(self, token):
print token.error()
raise SystemExit, 1
def p_unchecked(self, args):
"""
unchecked ::= *
"""
return '1'
def p_rules0(self, args):
"""
dimspec ::= unchecked
dimspec ::= expr
term ::= factor
expr ::= term
factor ::= initializer
"""
return args[0]
def p_type0(self, args):
"""
procdec ::= subroutine
procdec ::= function
intentid ::= in
intentid ::= out
intentid ::= inout
intentid ::= temporary
typename ::= integer
typename ::= real
typename ::= complex
typename ::= logical
typename ::= doubleprecision
typename ::= character
"""
return args[0].type
def p_attr0(self, args):
"""
factor ::= number
factor ::= id
"""
return args[0].attr
def p_rules1(self, args):
"""
argspec ::= ( arglist )
"""
return args[1]
def p_typeid_1(self, args):
"""
typeid ::= typename kindspec
"""
return FortranType(name=args[0], kind=args[1])
def p_typeid_2(self, args):
"""
typeid ::= type ( id )
"""
return FortranType(name=args[0].type, kind=args[2].attr)
def p_kindspec_0(self, args):
"""
kindspec ::=
"""
return None
def p_kindspec_1(self, args):
"""
kindspec ::= * ( akind )
"""
return args[2]
def p_kindspec_2(self, args):
"""
kindspec ::= ( akind )
kindspec ::= * akind
"""
return args[1]
def p_akind(self, args):
"""
akind ::= number
akind ::= id
"""
return args[0].attr
def p_typeid_3(self, args):
"""
typeid ::= character * ( * )
"""
return FortranType(name=args[0].type, kind='*')
def p_typespec_1(self, args):
"""
typespec ::= typeid
"""
return FortranAttributes(type=args[0], intent='in', allocatable=0)
def p_typespec_2(self, args):
"""
typespec ::= typeid attributes : :
"""
attrs = args[1]
return FortranAttributes(type=args[0], intent=attrs.get('intent', 'in'), allocatable=attrs.get('allocatable', 0))
def p_attrlist_1 (self, args):
"""
attributes ::=
"""
return {}
def p_attrlist_2 (self, args):
"""
attributes ::= attributes , attribute
"""
aname, avalue = args[2]
args[0][aname] = avalue
return args[0]
def p_attribute_intent (self, args):
"""
attribute ::= intent ( intentid )
"""
return ("intent", args[2])
def p_attribute_optional (self, args):
"""
attribute ::= optional
"""
return ("optional", 1)
def p_attribute_allocatable (self, args):
"""
attribute ::= allocatable
"""
return ("allocatable", 1)
def p_parens (self, args):
"""
factor ::= ( expr )
"""
return '(' + args[1] + ')'
def p_binary (self, args):
"""
expr ::= expr + term
expr ::= expr - term
term ::= term * factor
term ::= term / factor
dimspec ::= expr : expr
"""
s = args[0] + args[1].type + args[2]
return s
def p_list_0 (self, args):
"""
argspec ::= ( )
declarations ::=
"""
return []
def p_declarations (self, args):
"""
declarations ::= declarations declaration
"""
for x in args[-1]:
args[0].append(x)
return args[0]
def p_list_1 (self, args):
"""
proclist ::= procspec
dimensions ::= dimspec
idlist ::= item
"""
return [args[0]]
def p_list_2 (self, args):
"""
proclist ::= proclist procspec
dimensions ::= dimensions , dimspec
idlist ::= idlist , item
"""
args[0].append(args[-1])
return args[0]
def p_arglist_1 (self, args):
"""
arglist ::= id
"""
return [args[0].attr]
def p_arglist_2 (self, args):
"""
arglist ::= arglist , id
comments ::= comments comment
"""
args[0].append(args[-1].attr)
return args[0]
def p_procspec (self, args):
"""
procspec ::= prochead declarations end_stmt
"""
return FortranProcedure(args[0], args[1])
def p_prochead (self, args):
"""
prochead ::= procdec id argspec comments
"""
return (args[0], args[1].attr, args[2], args[3])
def p_item_1 (self, args):
"""
item ::= id
item ::= id = expr
"""
x = FortranDeclaration(name=args[0].attr, dimlist=[])
if len(args) == 3:
x.value = args[2]
return x
def p_item_2 (self, args):
"""
item ::= id ( dimensions )
"""
return FortranDeclaration(name=args[0].attr, dimlist=args[2])
def p_declaration_1 (self, args):
"""
declaration ::= typespec idlist comments
"""
result = []
idlist = args[1]
typespec = args[0]
comment = string.join(args[2], '\n')
for x in idlist:
x.set_comment(comment)
x.set_info(typespec)
if hasattr(x, 'value'):
x.intent = 'valued'
result.append(x)
return result
def p_initializer (self, args):
"""
initializer ::= size ( id )
initializer ::= size ( id , number )
"""
if len(args) == 4:
return 'size(' + args[2].attr + ', 1)'
else:
return 'size(' + args[2].attr + ', ' + args[4].attr + ')'
def p_module (self, args):
"""
module_interface ::= module id comments proclist end_stmt
"""
t = """Fortran 90 constructs not yet supported.
A change to Pyfort no longer uses this statement to determine
the Python module name. Please see manual.
"""
self.error (t, args[1])
def p_emptyrhs (self, args):
"""
comments ::=
"""
return []
def p_end_stmt (self, args):
"""
end_stmt ::= end endtag comments
"""
return args[:-1]
def p_endtag_1 (self, args):
"""
endtag ::=
"""
return (None, None)
def p_endtag_2 (self, args):
"""
endtag ::= blockkey
"""
return (args[0], None)
def p_endtag_3 (self, args):
"""
endtag ::= blockkey id
"""
return (args[0], args[1])
def p_blockkey(self, args):
"""
blockkey ::= module
blockkey ::= interface
blockkey ::= subroutine
blockkey ::= function
"""
return args[0]
def verify_blockend (self, endinfo, key, id):
actual_key, actual_id = endinfo[1]
if actual_key and (actual_key.type != key):
print "end statement error"
self.error(actual_key)
if actual_id and (actual_id.attr != id):
print "end statement error"
self.error(actual_id)
def p_afile (self, args):
"""
afile ::= comments proclist comments
"""
return args[1]
def parse(tokens):
parser = InterfaceParser()
return parser.parse(tokens)
|