Package madgraph :: Package iolibs :: Module ufo_expression_parsers
[hide private]
[frames] | no frames]

Source Code for Module madgraph.iolibs.ufo_expression_parsers

  1  ################################################################################ 
  2  # 
  3  # Copyright (c) 2009 The MadGraph5_aMC@NLO Development team and Contributors 
  4  # 
  5  # This file is a part of the MadGraph5_aMC@NLO project, an application which  
  6  # automatically generates Feynman diagrams and matrix elements for arbitrary 
  7  # high-energy processes in the Standard Model and beyond. 
  8  # 
  9  # It is subject to the MadGraph5_aMC@NLO license which should accompany this  
 10  # distribution. 
 11  # 
 12  # For more information, visit madgraph.phys.ucl.ac.be and amcatnlo.web.cern.ch 
 13  # 
 14  ################################################################################ 
 15   
 16  """Parsers for algebraic expressions coming from UFO, outputting into 
 17  different languages/frameworks (Fortran and Pythia8). Uses the PLY 3.3 
 18  Lex + Yacc framework""" 
 19   
 20  import logging 
 21  import os 
 22  import re 
 23  import sys 
 24  import copy 
 25   
 26  root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] 
 27  sys.path.append(os.path.join(root_path, os.path.pardir)) 
 28   
 29  import madgraph.various.misc as misc 
 30   
 31  from madgraph import MadGraph5Error 
 32  import vendor.ply.lex as lex 
 33  import vendor.ply.yacc as yacc 
 34  import models.check_param_card as check_param_card 
 35   
 36  logger = logging.getLogger('madgraph.ufo_parsers') 
 37   
 38  # PLY lexer class 
 39   
40 -class ModelError(MadGraph5Error):
41 """Appropriate Error for a wrong parsing"""
42
43 -class UFOExpressionParser(object):
44 """A base class for parsers for algebraic expressions coming from UFO.""" 45 46 parsed_string = "" 47 logical_equiv = {} 48
49 - def __init__(self, **kw):
50 """Initialize the lex and yacc""" 51 52 modname = self.__class__.__name__ 53 self.debugfile = os.path.devnull 54 self.tabmodule = os.path.join(root_path, "iolibs", modname + "_" + "parsetab.py") 55 lex.lex(module=self, debug=0) 56 self.y=yacc.yacc(module=self, debug=0, debugfile=self.debugfile, 57 tabmodule=self.tabmodule)
58
59 - def parse(self, buf):
60 """Parse the string buf""" 61 self.y.parse(buf) 62 return self.parsed_string
63 64 # List of tokens and literals 65 tokens = ( 66 'LOGICAL','LOGICALCOMB','POWER', 'CSC', 'SEC', 'ACSC', 'ASEC', 'TAN', 'ATAN', 67 'SQRT', 'CONJ', 'RE', 'RE2', 'IM', 'PI', 'COMPLEX', 'FUNCTION', 'IF','ELSE', 68 'VARIABLE', 'NUMBER','COND','REGLOG', 'REGLOGP', 'REGLOGM','RECMS','ARG' 69 ) 70 literals = "=+-*/()," 71 72 # Definition of tokens 73
74 - def t_CSC(self, t):
75 r'(?<!\w)csc(?=\()' 76 return t
77 - def t_SEC(self, t):
78 r'(?<!\w)sec(?=\()' 79 return t
80 - def t_ACSC(self, t):
81 r'(?<!\w)acsc(?=\()' 82 return t
83 - def t_TAN(self, t):
84 r'(?<!\w)tan(?=\()|(?<!\w)cmath.tan(?=\()' 85 return t
86 - def t_ATAN(self, t):
87 r'(?<!\w)atan(?=\()|(?<!\w)cmath.atan(?=\()' 88 return t
89 - def t_ASEC(self, t):
90 r'(?<!\w)asec(?=\()' 91 return t
92 - def t_REGLOG(self, t):
93 r'(?<!\w)reglog(?=\()' 94 return t
95 - def t_REGLOGP(self, t):
96 r'(?<!\w)reglogp(?=\()' 97 return t
98 - def t_REGLOGM(self, t):
99 r'(?<!\w)reglogm(?=\()' 100 return t
101 - def t_RECMS(self, t):
102 r'(?<!\w)recms(?=\()' 103 return t
104 - def t_COND(self, t):
105 r'(?<!\w)cond(?=\()' 106 return t
107 - def t_ARG(self,t):
108 r'(?<!\w)arg(?=\()' 109 return t
110 - def t_IF(self, t):
111 r'(?<!\w)if\s' 112 return t
113 - def t_ELSE(self, t):
114 r'(?<!\w)else\s' 115 return t
116 - def t_LOGICAL(self, t):
117 r'==|!=|<=|>=|<|>' 118 return t
119 - def t_LOGICALCOMB(self, t):
120 r'(?<!\w)and(?=[\s\(])|(?<!\w)or(?=[\s\(])' 121 return t
122 - def t_SQRT(self, t):
123 r'cmath\.sqrt' 124 return t
125 - def t_PI(self, t):
126 r'cmath\.pi' 127 return t
128 - def t_CONJ(self, t):
129 r'complexconjugate' 130 return t
131 - def t_IM(self, t):
132 r'(?<!\w)im(?=\()' 133 return t
134 - def t_RE(self, t):
135 r'(?<!\w)re(?=\()' 136 return t
137 - def t_RE2(self, t):
138 r'\.real|\.imag' 139 return t
140
141 - def t_COMPLEX(self, t):
142 r'(?<!\w)complex(?=\()' 143 return t
144 - def t_FUNCTION(self, t):
145 r'(cmath\.){0,1}[a-zA-Z_][0-9a-zA-Z_]*(?=\()' 146 return t
147 - def t_VARIABLE(self, t):
148 r'[a-zA-Z_][0-9a-zA-Z_]*' 149 return t
150 151 t_NUMBER = r'([0-9]+\.[0-9]*|\.[0-9]+|[0-9]+)([eE][+-]{0,1}[0-9]+){0,1}j{0,1}' 152 t_POWER = r'\*\*' 153 154 t_ignore = " \t" 155 156 re_cmath_function = re.compile("cmath\.(?P<name>[0-9a-zA-Z_]+)") 157
158 - def t_newline(self, t):
159 r'\n+' 160 t.lexer.lineno += t.value.count("\n")
161
162 - def t_error(self, t):
163 logger.error("Illegal character '%s'" % t.value[0]) 164 t.lexer.skip(1)
165 166 # Build the lexer
167 - def build(self,**kwargs):
168 self.lexer = lex.lex(module=self, **kwargs)
169 170 # Definitions for the PLY yacc parser 171 # Parsing rules 172 precedence = ( 173 ('right', 'LOGICALCOMB'), 174 ('right', 'LOGICAL'), 175 ('right','IF'), 176 ('right','ELSE'), 177 ('left','='), 178 ('left','+','-'), 179 ('left','*','/'), 180 ('left', 'RE2'), 181 ('right','UMINUS'), 182 ('left','POWER'), 183 ('right','REGLOG'), 184 ('right','REGLOGP'), 185 ('right','REGLOGM'), 186 ('right','RECMS'), 187 ('right','ARG'), 188 ('right','CSC'), 189 ('right','SEC'), 190 ('right','ACSC'), 191 ('right','ASEC'), 192 ('right','SQRT'), 193 ('right','CONJ'), 194 ('right','RE'), 195 ('right','IM'), 196 ('right','FUNCTION'), 197 ('right','COMPLEX'), 198 ('right','COND'), 199 ) 200 201 # Dictionary of parser expressions
202 - def p_statement_expr(self, p):
203 'statement : expression' 204 self.parsed_string = p[1]
205
206 - def p_expression_binop(self, p):
207 '''expression : expression '=' expression 208 | expression '+' expression 209 | expression '-' expression 210 | expression '*' expression 211 | expression '/' expression''' 212 p[0] = p[1] + p[2] + p[3]
213
214 - def p_expression_logical(self, p):
215 '''boolexpression : expression LOGICAL expression''' 216 if p[2] not in self.logical_equiv: 217 p[0] = p[1] + p[2] + p[3] 218 else: 219 p[0] = p[1] + self.logical_equiv[p[2]] + p[3]
220
221 - def p_expression_logicalcomb(self, p):
222 '''boolexpression : boolexpression LOGICALCOMB boolexpression''' 223 if p[2] not in self.logical_equiv: 224 p[0] = p[1] + p[2] + p[3] 225 else: 226 p[0] = p[1] + self.logical_equiv[p[2]] + p[3]
227
228 - def p_expression_uminus(self, p):
229 "expression : '-' expression %prec UMINUS" 230 p[0] = '-' + p[2]
231
232 - def p_group_parentheses(self, p):
233 "group : '(' expression ')'" 234 p[0] = '(' + p[2] +')'
235
236 - def p_group_parentheses_boolexpr(self, p):
237 "boolexpression : '(' boolexpression ')'" 238 p[0] = '(' + p[2] +')'
239
240 - def p_expression_group(self, p):
241 "expression : group" 242 p[0] = p[1]
243
244 - def p_expression_function1(self, p):
245 "expression : FUNCTION '(' expression ')'" 246 p1 = p[1] 247 re_groups = self.re_cmath_function.match(p1) 248 if re_groups: 249 p1 = re_groups.group("name") 250 p[0] = p1 + '(' + p[3] + ')'
251
252 - def p_expression_function2(self, p):
253 "expression : FUNCTION '(' expression ',' expression ')'" 254 p1 = p[1] 255 re_groups = self.re_cmath_function.match(p1) 256 if re_groups: 257 p1 = re_groups.group("name") 258 p[0] = p1 + '(' + p[3] + ',' + p[5] + ')'
259
260 - def p_error(self, p):
261 if p: 262 raise ModelError("Syntax error at '%s' (%s)." %(p.value,p)) 263 else: 264 logger.error("Syntax error at EOF") 265 self.parsed_string = "Error"
266
267 -class UFOExpressionParserFortran(UFOExpressionParser):
268 """A parser for UFO algebraic expressions, outputting 269 Fortran-style code.""" 270 271 # The following parser expressions need to be defined for each 272 # output language/framework 273 274 logical_equiv = {'==':'.EQ.', 275 '>=':'.GE.', 276 '<=':'.LE.', 277 '!=':'.NE.', 278 '>':'.GT.', 279 '<':'.LT.', 280 'or':'.OR.', 281 'and':'.AND.'} 282
283 - def p_expression_number(self, p):
284 "expression : NUMBER" 285 if p[1].endswith('j'): 286 p[0] = ('DCMPLX(0d0, %e)' % float(p[1][:-1])).replace('e', 'd') 287 else: 288 p[0] = ('%e' % float(p[1])).replace('e', 'd')
289
290 - def p_expression_variable(self, p):
291 "expression : VARIABLE" 292 p[0] = p[1].lower()
293
294 - def p_expression_power(self, p):
295 'expression : expression POWER expression' 296 try: 297 p3 = float(p[3].replace('d','e')) 298 # Chebck if exponent is an integer 299 if p3 == int(p3): 300 p3 = str(int(p3)) 301 p[0] = p[1] + "**" + p3 302 else: 303 p[0] = p[1] + "**" + p[3] 304 except Exception: 305 p[0] = p[1] + "**" + p[3]
306
307 - def p_expression_if(self,p):
308 "expression : expression IF boolexpression ELSE expression " 309 p[0] = 'CONDIF(%s,DCMPLX(%s),DCMPLX(%s))' % (p[3], p[1], p[5])
310
311 - def p_expression_ifimplicit(self,p):
312 "expression : expression IF expression ELSE expression " 313 p[0] = 'CONDIF(DCMPLX(%s).NE.(0d0,0d0),DCMPLX(%s),DCMPLX(%s))'\ 314 %(p[3], p[1], p[5])
315
316 - def p_expression_cond(self, p):
317 "expression : COND '(' expression ',' expression ',' expression ')'" 318 p[0] = 'COND(DCMPLX('+p[3]+'),DCMPLX('+p[5]+'),DCMPLX('+p[7]+'))'
319
320 - def p_expression_recms(self, p):
321 "expression : RECMS '(' boolexpression ',' expression ')'" 322 p[0] = 'RECMS('+p[3]+',DCMPLX('+p[5]+'))'
323
324 - def p_expression_complex(self, p):
325 "expression : COMPLEX '(' expression ',' expression ')'" 326 p[0] = 'DCMPLX(' + p[3] + ',' + p[5] + ')'
327
328 - def p_expression_func(self, p):
329 '''expression : CSC group 330 | SEC group 331 | ACSC group 332 | ASEC group 333 | RE group 334 | IM group 335 | ARG group 336 | SQRT group 337 | CONJ group 338 | REGLOG group 339 | REGLOGP group 340 | REGLOGM group 341 | TAN group 342 | ATAN group''' 343 344 if p[1] == 'csc': p[0] = '1d0/sin' + p[2] 345 elif p[1] == 'sec': p[0] = '1d0/cos' + p[2] 346 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')' 347 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')' 348 elif p[1] in ['atan', 'cmath.atan'] : p[0] = 'atan(dble' + p[2]+')' 349 elif p[1] in ['tan', 'cmath.tan'] : p[0] = 'tan(dble' + p[2]+')' 350 elif p[1] == 're': p[0] = 'dble' + p[2] 351 elif p[1] == 'im': p[0] = 'dimag' + p[2] 352 elif p[1] == 'arg': p[0] = 'arg(DCMPLX'+p[2]+')' 353 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt(dcmplx' + p[2]+')' 354 elif p[1] == 'complexconjugate': p[0] = 'conjg(DCMPLX' + p[2]+')' 355 elif p[1] == 'reglog': p[0] = 'reglog(DCMPLX' + p[2] +')' 356 elif p[1] == 'reglogp': p[0] = 'reglogp(DCMPLX' + p[2] + ')' 357 elif p[1] == 'reglogm': p[0] = 'reglogm(DCMPLX' + p[2] + ')'
358 359
360 - def p_expression_real(self, p):
361 ''' expression : expression RE2 ''' 362 363 if p[2] == '.real': 364 if p[1].startswith('('): 365 p[0] = 'dble' +p[1] 366 else: 367 p[0] = 'dble(%s)' % p[1] 368 elif p[2] == '.imag': 369 if p[1].startswith('('): 370 p[0] = 'dimag' +p[1] 371 else: 372 p[0] = 'dimag(%s)' % p[1]
373
374 - def p_expression_pi(self, p):
375 '''expression : PI''' 376 p[0] = 'pi'
377
378 -class UFOExpressionParserMPFortran(UFOExpressionParserFortran):
379 """A parser for UFO algebraic expressions, outputting 380 Fortran-style code for quadruple precision computation.""" 381 382 mp_prefix = check_param_card.ParamCard.mp_prefix 383 384 # The following parser expressions need to be defined for each 385 # output language/framework 386
387 - def p_expression_number(self, p):
388 "expression : NUMBER" 389 390 if p[1].endswith('j'): 391 p[0] = 'CMPLX(0.000000e+00_16, %e_16 ,KIND=16)' % float(p[1][:-1]) 392 else: 393 p[0] = '%e_16' % float(p[1])
394
395 - def p_expression_variable(self, p):
396 "expression : VARIABLE" 397 # All the multiple_precision variables are defined with the prefix _MP_" 398 p[0] = (self.mp_prefix+p[1]).lower()
399
400 - def p_expression_power(self, p):
401 'expression : expression POWER expression' 402 try: 403 p3 = float(p[3].replace('_16','')) 404 # Check if exponent is an integer 405 if p3 == int(p3): 406 p3 = str(int(p3)) 407 p[0] = p[1] + "**" + p3 408 else: 409 p[0] = p[1] + "**" + p[3] 410 except Exception: 411 p[0] = p[1] + "**" + p[3]
412
413 - def p_expression_if(self,p):
414 "expression : expression IF boolexpression ELSE expression " 415 p[0] = 'MP_CONDIF(%s,CMPLX(%s,KIND=16),CMPLX(%s,KIND=16))' % (p[3], p[1], p[5])
416
417 - def p_expression_ifimplicit(self,p):
418 "expression : expression IF expression ELSE expression " 419 p[0] = 'MP_CONDIF(CMPLX(%s,KIND=16).NE.(0.0e0_16,0.0e0_16),CMPLX(%s,KIND=16),CMPLX(%s,KIND=16))'\ 420 %(p[3], p[1], p[5])
421
422 - def p_expression_complex(self, p):
423 "expression : COMPLEX '(' expression ',' expression ')'" 424 p[0] = 'CMPLX(' + p[3] + ',' + p[5] + ',KIND=16)'
425
426 - def p_expression_cond(self, p):
427 "expression : COND '(' expression ',' expression ',' expression ')'" 428 p[0] = 'MP_COND(CMPLX('+p[3]+',KIND=16),CMPLX('+p[5]+\ 429 ',KIND=16),CMPLX('+p[7]+',KIND=16))'
430
431 - def p_expression_recms(self, p):
432 "expression : RECMS '(' boolexpression ',' expression ')'" 433 p[0] = 'MP_RECMS('+p[3]+',CMPLX('+p[5]+',KIND=16))'
434
435 - def p_expression_func(self, p):
436 '''expression : CSC group 437 | SEC group 438 | ACSC group 439 | ASEC group 440 | RE group 441 | IM group 442 | ARG group 443 | SQRT group 444 | CONJ group 445 | REGLOG group 446 | REGLOGP group 447 | REGLOGM group 448 | TAN group 449 | ATAN group''' 450 451 if p[1] == 'csc': p[0] = '1e0_16/cos' + p[2] 452 elif p[1] == 'sec': p[0] = '1e0_16/sin' + p[2] 453 elif p[1] == 'acsc': p[0] = 'asin(1e0_16/' + p[2] + ')' 454 elif p[1] == 'asec': p[0] = 'acos(1e0_16/' + p[2] + ')' 455 elif p[1] in ['atan', 'cmath.atan'] : p[0] = 'atan(real' + p[2]+')' 456 elif p[1] in ['tan', 'cmath.tan']: p[0] = 'tan(real' + p[2]+')' 457 elif p[1] == 're': p[0] = 'real' + p[2] 458 elif p[1] == 'im': p[0] = 'imag' + p[2] 459 elif p[1] == 'arg': p[0] = 'mp_arg(CMPLX(' + p[2] + ',KIND=16))' 460 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt(CMPLX(' + p[2] + ',KIND=16))' 461 elif p[1] == 'complexconjugate': p[0] = 'conjg(CMPLX(' + p[2] + ',KIND=16))' 462 elif p[1] == 'reglog': p[0] = 'mp_reglog(CMPLX(' + p[2] +',KIND=16))' 463 elif p[1] == 'reglogp': p[0] = 'mp_reglogp(CMPLX(' + p[2] + ',KIND=16))' 464 elif p[1] == 'reglogm': p[0] = 'mp_reglogm(CMPLX(' + p[2] + ',KIND=16))'
465
466 - def p_expression_real(self, p):
467 ''' expression : expression RE2 ''' 468 469 if p[2] == '.real': 470 if p[1].startswith('('): 471 p[0] = 'real' +p[1] 472 else: 473 p[0] = 'real(%s)' % p[1] 474 elif p[2] == '.imag': 475 if p[1].startswith('('): 476 p[0] = 'imag' +p[1] 477 else: 478 p[0] = 'imag(%s)' % p[1]
479 480
481 - def p_expression_pi(self, p):
482 '''expression : PI''' 483 p[0] = self.mp_prefix+'pi'
484
485 -class UFOExpressionParserCPP(UFOExpressionParser):
486 """A parser for UFO algebraic expressions, outputting 487 C++-style code.""" 488 489 logical_equiv = {'==':'==', 490 '>=':'>=', 491 '<=':'<=', 492 '!=':'!=', 493 '>':'>', 494 '<':'<', 495 'or':'||', 496 'and':'&&'} 497 498 # The following parser expressions need to be defined for each 499 # output language/framework 500
501 - def p_expression_number(self, p):
502 'expression : NUMBER' 503 504 if p[1].endswith('j'): 505 p[0] = 'std::complex<double>(0., %e)' % float(p[1][:-1]) 506 else: 507 p[0] = ('%e' % float(p[1])).replace('e', 'd') 508 509 510 p[0] = p[1] 511 # Check number is an integer, if so add "." 512 if float(p[1]) == int(float(p[1])) and float(p[1]) < 1000: 513 p[0] = str(int(float(p[1]))) + '.'
514
515 - def p_expression_variable(self, p):
516 'expression : VARIABLE' 517 p[0] = p[1]
518
519 - def p_expression_if(self,p):
520 "expression : expression IF boolexpression ELSE expression " 521 p[0] = '(%s ? %s : %s)' % (p[3], p[1], p[5])
522
523 - def p_expression_ifimplicit(self,p):
524 "expression : expression IF expression ELSE expression " 525 p[0] = '(%s ? %s : %s)' % (p[3], p[1], p[5])
526
527 - def p_expression_cond(self, p):
528 "expression : COND '(' expression ',' expression ',' expression ')'" 529 p[0] = 'COND('+p[3]+','+p[5]+','+p[7]+')'
530
531 - def p_expression_recms(self, p):
532 "expression : RECMS '(' boolexpression ',' expression ')'" 533 p[0] = 'RECMS('+p[3]+','+p[5]+')'
534
535 - def p_expression_power(self, p):
536 'expression : expression POWER expression' 537 p1=p[1] 538 p3=p[3] 539 if p[1][0] == '(' and p[1][-1] == ')': 540 p1 = p[1][1:-1] 541 if p[3][0] == '(' and p[3][-1] == ')': 542 p3 = p[3][1:-1] 543 p[0] = 'pow(' + p1 + ',' + p3 + ')'
544
545 - def p_expression_complex(self, p):
546 "expression : COMPLEX '(' expression ',' expression ')'" 547 p[0] = 'std::complex<double>(' + p[3] + ',' + p[5] + ')'
548
549 - def p_expression_func(self, p):
550 '''expression : CSC group 551 | SEC group 552 | ACSC group 553 | ASEC group 554 | TAN group 555 | ATAN group 556 | RE group 557 | IM group 558 | ARG group 559 | SQRT group 560 | CONJ group 561 | REGLOG group 562 | REGLOGP group 563 | REGLOGM group''' 564 if p[1] == 'csc': p[0] = '1./cos' + p[2] 565 elif p[1] == 'sec': p[0] = '1./sin' + p[2] 566 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')' 567 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')' 568 elif p[1] in ['atan', 'cmath.atan']: p[0] = 'atan' +p[2] 569 elif p[1] in ['tan', 'cmath.tan']: p[0] = 'tan' +p[2] 570 elif p[1] == 're': p[0] = 'real' + p[2] 571 elif p[1] == 'im': p[0] = 'imag' + p[2] 572 elif p[1] == 'arg':p[0] = 'arg' + p[2] 573 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt' + p[2] 574 elif p[1] == 'complexconjugate': p[0] = 'conj' + p[2] 575 elif p[1] == 'reglog': p[0] = 'reglog' + p[2] 576 elif p[1] == 'reglogp': p[0] = 'reglogp' + p[2] 577 elif p[1] == 'reglogm': p[0] = 'reglogm' + p[2]
578
579 - def p_expression_real(self, p):
580 ''' expression : expression RE2 ''' 581 582 if p[2] == '.real': 583 if p[1].startswith('('): 584 p[0] = 'real' +p[1] 585 else: 586 p[0] = 'real(%s)' % p[1] 587 elif p[2] == '.imag': 588 if p[1].startswith('('): 589 p[0] = 'imag' +p[1] 590 else: 591 p[0] = 'imag(%s)' % p[1]
592 593
594 - def p_expression_pi(self, p):
595 '''expression : PI''' 596 p[0] = 'M_PI'
597
598 -class UFOExpressionParserPythonIF(UFOExpressionParser):
599 """An ad hoc parser for UFO algebraic expressions with if statement, outputting 600 Python-style code, with the conditional 'if' expressions simplified using 601 pre-defined set of variables specified when instanciating this parser.""" 602 603 logical_equiv = {'==':'==', 604 '>=':'>=', 605 '<=':'<=', 606 '!=':'!=', 607 '>':'>', 608 '<':'<', 609 'or':' or ', 610 'and':' and '} 611
612 - def __init__(self, *args,**kw):
613 """Initialize the lex and yacc""" 614 615 self.changes_performed = 0 616 617 if len(args) > 0: 618 if isinstance(args[0],dict): 619 self.defined_variables = copy.copy(args[0]) 620 elif isinstance(args[0],str): 621 try: 622 self.defined_variables = eval(args[0]) 623 except: 624 raise ModelError, 'The expression "%s"'%str(args[0])+\ 625 " given as defined variables for the UFOExpressionParserPythonIF"+\ 626 " does not have a correct syntax." 627 if not isinstance(self.defined_variables, dict): 628 raise ModelError, 'The argument "%s"'%str(args[0])+\ 629 " given as defined variables for the UFOExpressionParserPythonIF"+\ 630 " is not a dictionary." 631 else: 632 raise ModelError, "The argument %s"%str(args[0])+\ 633 " given as defined variables for the UFOExpressionParserPythonIF"+\ 634 " must be either a dictionary or a string." 635 args = args[1:] 636 for key, value in self.defined_variables.items(): 637 if not isinstance(key,str) or \ 638 not any(isinstance(value,t) for t in [float,complex,int]): 639 # This is not a valid environment variable for the parser 640 del self.defined_variables[key] 641 642 else: 643 # If the user doesn't specify any defined variable for this parser, this means 644 # that it shouldn't do anything, not even simplify trivial conditional expressions 645 # such as '1 if True else 2' 646 self.defined_variables = None 647 648 super(UFOExpressionParserPythonIF,self).__init__(*args, **kw)
649
650 - def parse(self, *args, **kw):
651 """ Wrapper around the parse function so as to also return the number 652 of if substitutions made.""" 653 self.changes_performed = 0 654 new_expression = super(UFOExpressionParserPythonIF,self).parse(*args, **kw) 655 return new_expression, self.changes_performed
656
657 - def p_expression_number(self, p):
658 "expression : NUMBER" 659 p[0] = p[1]
660
661 - def p_expression_variable(self, p):
662 "expression : VARIABLE" 663 p[0] = p[1]
664
665 - def p_expression_power(self, p):
666 'expression : expression POWER expression' 667 p[0] = p[1] + "**" + p[3]
668
669 - def p_expression_if(self,p):
670 "expression : expression IF boolexpression ELSE expression " 671 if self.defined_variables is None: 672 p[0] = '%s if %s else %s'%(p[1],p[3],p[5]) 673 return 674 try: 675 p[0] = '%s'%p[1] if eval(p[3],self.defined_variables) else '%s'%p[5] 676 self.changes_performed += 1 677 except Exception: 678 p[0] = '%s if %s else %s'%(p[1],p[3],p[5])
679
680 - def p_expression_ifimplicit(self,p):
681 "expression : expression IF expression ELSE expression " 682 if self.defined_variables is None: 683 p[0] = '%s if %s!=0.0 else %s'%(p[1],p[3],p[5]) 684 return 685 try: 686 p[0] = '%s'%p[1] if eval(p[3]+'!= 0.0',self.defined_variables) else '%s'%p[5] 687 self.changes_performed += 1 688 except Exception: 689 p[0] = '%s if %s!=0.0 else %s'%(p[1],p[3],p[5])
690
691 - def p_expression_cond(self, p):
692 "expression : COND '(' expression ',' expression ',' expression ')'" 693 # We assume the cond syntax is used by the Model builder when he doesn't want it to 694 # get simplified, ever. 695 p[0] = 'cond('+p[3]+','+p[5]+','+p[7]+')'
696
697 - def p_expression_complex(self, p):
698 "expression : COMPLEX '(' expression ',' expression ')'" 699 p[0] = 'complex(' + p[3] + ',' + p[5] + ')'
700
701 - def p_expression_recms(self, p):
702 "expression : RECMS '(' boolexpression ',' expression ')'" 703 p[0] = 'recms('+p[3]+','+p[5]+')'
704
705 - def p_expression_func(self, p):
706 '''expression : CSC group 707 | SEC group 708 | ACSC group 709 | ASEC group 710 | RE group 711 | IM group 712 | ARG group 713 | SQRT group 714 | TAN group 715 | ATAN group 716 | CONJ group 717 | REGLOG group 718 | REGLOGP group 719 | REGLOGM group''' 720 if p[1] == 'csc': p[0] = 'csc' + p[2] 721 elif p[1] == 'sec': p[0] = 'sec' + p[2] 722 elif p[1] == 'acsc': p[0] = 'acsc' + p[2] 723 elif p[1] == 'asec': p[0] = 'asec' + p[2] 724 elif p[1] in ['tan','cmath.tan']: p[0] = 'tan' + p[2] 725 elif p[1] in ['atan','cmath.atan']: p[0] = 'atan' + p[2] 726 elif p[1] == 're': p[0] = 're' + p[2] 727 elif p[1] == 'im': p[0] = 'im' + p[2] 728 elif p[1] == 'arg': p[0] = 'arg' + p[2] 729 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'cmath.sqrt' + p[2] 730 elif p[1] == 'complexconjugate': p[0] = 'complexconjugate' + p[2] 731 elif p[1] == 'reglog': p[0] = 'reglog' + p[2] 732 elif p[1] == 'reglogp': p[0] = 'reglogp' + p[2] 733 elif p[1] == 'reglogm': p[0] = 'reglogm' + p[2]
734
735 - def p_expression_real(self, p):
736 ''' expression : expression RE2 ''' 737 p[0] = p[1]+p[2]
738
739 - def p_expression_pi(self, p):
740 '''expression : PI''' 741 p[0] = 'cmath.pi'
742 743 744 745 # Main program, allows to interactively test the parser 746 if __name__ == '__main__': 747 748 if len(sys.argv) == 1: 749 print "Please specify a parser: fortran, mpfortran or c++" 750 exit() 751 if sys.argv[1] == "fortran": 752 calc = UFOExpressionParserFortran() 753 elif sys.argv[1] == "mpfortran": 754 calc = UFOExpressionParserMPFortran() 755 elif sys.argv[1] == "c++": 756 calc = UFOExpressionParserCPP() 757 elif sys.argv[1] == "aloha": 758 calc = UFOExpressionParserCPP() 759 elif sys.argv[1] == "pythonif": 760 if len(sys.argv) > 2: 761 calc = UFOExpressionParserPythonIF(sys.argv[2]) 762 else: 763 calc = UFOExpressionParserPythonIF() 764 else: 765 print "Please specify a parser: fortran, mpfortran, c++ or pythonif" 766 print "You gave", sys.argv[1] 767 if len(sys.argv) > 2: 768 print "with the second argument",sys.argv[2] 769 exit() 770 771 while 1: 772 try: 773 s = raw_input('calc > ') 774 except EOFError: 775 break 776 if not s: continue 777 print calc.parse(s) 778