fortExp.py

Go to the documentation of this file.
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 # utility list
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 # simple subtree replacement function
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))

Generated on Wed Jan 28 02:45:32 2009 for OpenADFortTk (SourceProcessing) by  doxygen 1.5.7.1