#!/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)