00001 '''
00002 Expression parser for fortran expressions:
00003 use rec decent
00004 '''
00005 import re
00006
00007 from _Setup import *
00008
00009 from PyIR.mutable_tree import _Mutable_T
00010
00011 from PyUtil.l_assembler import *
00012 from PyUtil.flatten import flatten
00013
00014 import fortScan as fs
00015 from op_prec import OpPrec
00016
00017 _id_re = re.compile(fs.id_re,re.I | re.X)
00018 _flonum_re = re.compile(fs.flonum_re,re.I | re.X)
00019 _int_re = re.compile(fs.int_re,re.I | re.X)
00020 _q_re = re.compile(fs.q_re,re.I | re.X)
00021 _qq_re = re.compile(fs.qq_re,re.I | re.X)
00022 _num_re = re.compile(fs.flonum_re + '|' + fs.int_re,re.I | re.X)
00023
00024 _quote_set = set(['"',"'"])
00025 _logicon_set = set(['.true.','.false.'])
00026 _optbl = (([':'] ,1),
00027 (['.eqv.',
00028 '.neqv.'],2),
00029 (['.or.'] ,3),
00030 (['.and.'] ,4),
00031 (['.le.',
00032 '.lt.',
00033 '.eq.',
00034 '.ne.',
00035 '.ge.',
00036 '.gt.',
00037 '<',
00038 '<=',
00039 '>',
00040 '>=',
00041 '==',
00042 '/='] ,5),
00043 (['//'] ,6),
00044 (['+','-'],7),
00045 (['*','/'],8),
00046 (['**'] ,9),
00047 )
00048
00049 _unary_ops = ['-',
00050 '+',
00051 '.not.',
00052 ]
00053
00054 def is_op(op):
00055 '''
00056 Check to see if op is in the _optbl
00057
00058 This routine is only necessary for
00059 unit test to check if all ops are covered
00060 '''
00061 op_l = op.lower()
00062 for (lst,prec) in _optbl:
00063 if op_l in lst:
00064 return True
00065 return False
00066
00067 class _Exp(_Mutable_T):
00068 'base class for Expression trees'
00069 _sons = []
00070 pass
00071
00072 class App(_Exp):
00073 'application expressions (ie f(x))'
00074 _sons = ['head','args']
00075 def __init__(self,head,args):
00076 self.head = head
00077 self.args = args
00078
00079 def __repr__(self):
00080 return 'App(%s,%s)' % (repr(self.head),repr(self.args))
00081
00082 def __str__(self):
00083 return '%s(%s)' % (str(self.head),
00084 ','.join([str(l) for l in self.args]))
00085 def map(self,fn):
00086 return App(self.head,[fn(a) for a in self.args])
00087
00088 class NamedParam(object):
00089 '''
00090 Class to implement named paramter expressions i.e. call foo(arg=10)
00091 these may occur either in a parameter statement or as an argument to a function or subroutine call
00092 '''
00093 _sons = ['myId','myRHS']
00094
00095 def __init__(self,anId,aRHS):
00096 self.myId = anId
00097 self.myRHS = aRHS
00098
00099 def __repr__(self):
00100 return 'NamedParam(%s,%s)' % (self.myId,repr(self.myRHS))
00101
00102 def __str__(self):
00103 return str(myId)+' = '+str(myRHS)
00104
00105 class Sel(_Exp):
00106 'selection expressions like foo(i,j)%k'
00107
00108 _sons = ['head']
00109
00110 def __init__(self,head,proj):
00111 self.head = head
00112 self.proj = proj
00113
00114 def __repr__(self):
00115 return 'Sel(%s,%s)' % (repr(self.head),repr(self.proj))
00116
00117 def __str__(self):
00118 return '%s%%%s' % (str(self.head),str(self.proj))
00119
00120 def map(self,fn):
00121 return Sel(fn(self.head),fn(self.proj))
00122
00123 class _AtomH(object):
00124 'helper class, captures the args of app or selection'
00125
00126 def __init__(self,arglist):
00127 self.arglist = arglist
00128
00129 def make(self):
00130 return (self.__class__.constr,self.arglist)
00131
00132 class _AppH(_AtomH):
00133 constr = App
00134
00135 class _SelH(_AtomH):
00136 constr = Sel
00137
00138 class Rslice(_Exp):
00139
00140 _sons = ['arg']
00141
00142 def __init__(self,e):
00143 self.arg = e
00144 def __repr__(self):
00145 return 'Rslice(%s)' % repr(self.arg)
00146 def __str__(self):
00147 return ':%s' % str(self.arg)
00148
00149 class Lslice(_Exp):
00150
00151 _sons = ['arg']
00152
00153 def __init__(self,e):
00154 self.arg = e
00155 def __repr__(self):
00156 return 'Lslice(%s)' % repr(self.arg)
00157 def __str__(self):
00158 return '%s:' % str(self.arg)
00159
00160 class Zslice(_Exp):
00161 def __init__(self): pass
00162 def __repr__(self):
00163 return 'Zslice()'
00164 def __str__(self):
00165 return ':'
00166
00167 class Unary(_Exp):
00168 _sons = ['exp']
00169
00170 class Umi(Unary):
00171 'unary minus'
00172 def __init__(self,exp):
00173 self.exp = exp
00174
00175 def __repr__(self):
00176 return 'Umi(%s)' % (repr(self.exp),)
00177
00178 def __str__(self):
00179 return '-%s' % (str(self.exp),)
00180
00181 def map(self,fn):
00182 return Umi(fn(self.exp))
00183
00184 class Upl(Unary):
00185 'unary plus'
00186 def __init__(self,exp):
00187 self.exp = exp
00188
00189 def __repr__(self):
00190 return 'Upl(%s)' % (repr(self.exp),)
00191
00192 def __str__(self):
00193 return '+%s' % (str(self.exp),)
00194
00195 def map(self,fn):
00196 return Upl(fn(self.exp))
00197
00198 class Not(Unary):
00199 'unary not'
00200
00201 def __init__(self,exp):
00202 self.exp = exp
00203
00204 def __repr__(self):
00205 return 'Not(%s)' % (repr(self.exp),)
00206
00207 def __str__(self):
00208 return '.not. %s' % (str(self.exp),)
00209
00210 def map(self,fn):
00211 return Not(fn(self.exp))
00212
00213 class ParenExp(Unary):
00214 'parenthesized expression'
00215 def __init__(self,exp):
00216 self.exp = exp
00217
00218 def __repr__(self):
00219 return 'ParenExp(%s)' % (repr(self.exp),)
00220
00221 def __str__(self):
00222 return '(%s)' % (str(self.exp),)
00223
00224 def map(self,fn):
00225 return ParenExp(fn(self.exp))
00226
00227 class Ops(_Exp):
00228 'some sequence of binops'
00229 _sons = ['a1','a2']
00230
00231 def __init__(self,op,a1,a2):
00232 self.op = op.lower()
00233 self.a1 = a1
00234 self.a2 = a2
00235
00236 def __repr__(self):
00237 return 'Ops(%s,%s,%s)' % (repr(self.op),repr(self.a1),repr(self.a2),)
00238
00239 def __str__(self):
00240 return '%s %s %s' % (str(self.a1),
00241 str(self.op),
00242 str(self.a2))
00243 def map(self,fn):
00244 return Ops(self.op,fn(self.a1),fn(self.a2))
00245
00246 def is_id(t):
00247 return _id_re.match(t)
00248
00249 def is_int(t):
00250 return _int_re.match(t)
00251
00252 def is_const(t):
00253 t1 = t.lower()
00254 return t1[0] in _quote_set or t1 in _logicon_set or _num_re.match(t1)
00255
00256 def isConstantExpression(anExpression):
00257 if isinstance(anExpression,str):
00258 return is_const(anExpression)
00259 elif isinstance(anExpression,Unary):
00260 return isConstantExpression(anExpression.exp)
00261 elif isinstance(anExpression,Ops):
00262 return (isConstantExpression(anExpression.a1) and isConstantExpression(anExpression.a2))
00263 else:
00264 return False
00265
00266 def _lc_const(t):
00267 t1 = t.lower()
00268 if t1 in _logicon_set:
00269 return t1
00270 return t
00271
00272 def is_unary(t):
00273 t1 = t.lower()
00274 return t1 in _unary_ops
00275
00276 def _squeeze(exp_list):
00277 ''' turn an expression list into an actual list
00278 with no embedded commas or lists
00279 '''
00280 (e1,rest) = exp_list
00281 return [e1] + [e2 for (dc,e2) in rest]
00282
00283 def _mkapp_e_r(aPatternMatchResult):
00284 'return an Rslice object'
00285 (colon,e) = aPatternMatchResult
00286 return Rslice(e)
00287
00288 def _mkapp_z(aPatternMatchResult):
00289 'return a Zslice object'
00290 return Zslice()
00291
00292 def _mkapp_e_l(aPatternMatchResult):
00293 'return an Lslice object'
00294 (e,colon) = aPatternMatchResult
00295 return Lslice(e)
00296
00297 def _mk_namedParamExp(a):
00298 'return named parameter binding'
00299 return NamedParam(a[0],a[2])
00300
00301 def _mkapp1(a):
00302 '''turn a recognized app into an App object'''
00303 (h,dc1,el,dc2) = a
00304 return App(h,_squeeze(el))
00305
00306 def _mkapp0(a):
00307 '''turn a recognized app with empty arglist into an App object'''
00308 (h,dc1,dc2) = a
00309 return App(h,[])
00310
00311 def _mkapp_ch(a):
00312 'turn a chain of apps into a single app'
00313 (h,lst) = a
00314 for l in lst:
00315 (cls,arg) = l.make()
00316 h = cls(h,arg)
00317 return h
00318
00319 def _mksel(a):
00320 'turn recognized selection into a Sel object'
00321 (h,dc,p) = a
00322 return Sel(h,p)
00323
00324 def _mkumi(um):
00325 'turn a recognized unary minus into a Umi object'
00326 (dc,e) = um
00327 return Umi(e)
00328
00329 def _mkupl(um):
00330 'turn a recognized unary plus into a Upl object'
00331 (dc,e) = upl
00332 return Upl(e)
00333
00334 def _mkunot(unot):
00335 (dc,e) = unot
00336 return Not(e)
00337
00338 _unary_tbl = {'+' : Upl,
00339 '-' : Umi,
00340 '.not.': Not,
00341 }
00342
00343 def _mkunary(e):
00344 (op,ee) = e
00345 return _unary_tbl[op.lower()](ee)
00346
00347 def _mkparen(parn):
00348 'turn a recognized parenthesized expression into a paren object'
00349 (dc,e,dc2) = parn
00350 return ParenExp(e)
00351
00352 def _mkexp(e):
00353 'convert a recognized exp into an Ops object'
00354 (a,oplst) = e
00355 for (op,a2) in oplst:
00356 a = Ops(op,a,_mkexp(a2))
00357 return a
00358
00359 int = pred(is_int)
00360 id = pred(is_id)
00361 const = pred(is_const)
00362 const = treat(const,_lc_const)
00363 unary = pred(is_unary)
00364
00365 def atom0(scan):
00366 '''eta expansion, since letrec unavail in python'''
00367 return disj(id,const,unaryExp,paren)(scan)
00368
00369 def atom(scan):
00370
00371 _app1_trail = seq(lit('('),cslist(_appExp),lit(')'))
00372 _app1_trail = treat(_app1_trail,lambda a: _AppH(a[1]))
00373
00374 _app0_trail = seq(lit('('),lit(')'))
00375 _app0_trail = treat(_app0_trail,lambda a: _AppH([]))
00376
00377 _sel_trail = seq(lit('%'),id)
00378 _sel_trail = treat(_sel_trail,lambda a: _SelH(a[1]))
00379
00380 _app_trail = disj(_app1_trail,_app0_trail,_sel_trail)
00381
00382 p0 = seq(atom0,star(_app_trail))
00383 p0 = treat(p0,_mkapp_ch)
00384
00385 return p0(scan)
00386
00387 '''
00388 FIXME:
00389 duplicated *_trail code, cannot factor out easily due to fwd ref
00390 '''
00391
00392 def lv_exp(scan):
00393 'proper syntax for an lvalue'
00394
00395 _app1_trail = seq(lit('('),cslist(_appExp),lit(')'))
00396 _app1_trail = treat(_app1_trail,lambda a: _AppH(a[1]))
00397
00398 _app0_trail = seq(lit('('),lit(')'))
00399 _app0_trail = treat(_app0_trail,lambda a: _AppH([]))
00400
00401 _sel_trail = seq(lit('%'),id)
00402 _sel_trail = treat(_sel_trail,lambda a: _SelH(a[1]))
00403
00404 _app_trail = disj(_app1_trail,_app0_trail,_sel_trail)
00405
00406 p0 = seq(id,star(_app_trail))
00407 p0 = treat(p0,_mkapp_ch)
00408
00409 return p0(scan)
00410
00411 Exp = OpPrec(atom,_optbl,('**',))
00412 Exp = treat(Exp,_mkexp)
00413
00414 ExpList = seq(Exp,star(seq(lit(','),Exp)))
00415
00416 _appExpR = seq(lit(':'),Exp)
00417 _appExpR = treat(_appExpR,_mkapp_e_r)
00418
00419 _appExpL = seq(Exp,lit(':'))
00420 _appExpL = treat(_appExpL,_mkapp_e_l)
00421
00422 _appExpZ = lit(':')
00423 _appExpZ = treat(_appExpZ,_mkapp_z)
00424
00425 _appExpA = seq(id,lit('='),Exp)
00426 _appExpA = treat(_appExpA,_mk_namedParamExp)
00427
00428 _appExp = disj(_appExpR,_appExpL,_appExpZ,_appExpA,Exp)
00429
00430 app1 = seq(id,lit('('),ExpList,lit(')'))
00431 app1 = treat(app1,_mkapp1)
00432
00433 app0 = seq(id,lit('('),lit(')'))
00434 app0 = treat(app0,_mkapp0)
00435
00436 app = disj(app1,app0)
00437
00438 unaryExp = seq(unary,atom)
00439 unaryExp = treat(unaryExp,_mkunary)
00440
00441 paren = seq(lit('('),Exp,lit(')'))
00442 paren = treat(paren,_mkparen)
00443
00444
00445
00446 app_id = disj(app,id)
00447 app_id_l = seq(app_id,star(seq(lit(','),app_id)))
00448 app_id_l = treat(app_id_l,_squeeze)
00449
00450
00451
00452
00453 def subst(a,pat,repl):
00454 if pat(a):
00455 return repl(a)
00456 elif isinstance(a,str):
00457 return a
00458 elif not a._sons:
00459 return a
00460 else:
00461 return a.map(lambda x:subst(x,pat,repl))