1
2
3
4
5
6
7
8
9
10
11
12
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
25 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
26 sys.path.append(os.path.join(root_path, os.path.pardir))
27
28 from madgraph import MadGraph5Error
29 import vendor.ply.lex as lex
30 import vendor.ply.yacc as yacc
31 import models.check_param_card as check_param_card
32
33 logger = logging.getLogger('madgraph.ufo_parsers')
34
35
36
38 """Appropriate Error for a wrong parsing"""
39
41 """A base class for parsers for algebraic expressions coming from UFO."""
42
43 parsed_string = ""
44 logical_equiv = {}
45
47 """Initialize the lex and yacc"""
48
49 modname = self.__class__.__name__
50 self.debugfile = os.path.devnull
51 self.tabmodule = os.path.join(root_path, "iolibs", modname + "_" + "parsetab.py")
52 lex.lex(module=self, debug=0)
53 self.y=yacc.yacc(module=self, debug=0, debugfile=self.debugfile,
54 tabmodule=self.tabmodule)
55
60
61
62 tokens = (
63 'LOGICAL','LOGICALCOMB','POWER', 'CSC', 'SEC', 'ACSC', 'ASEC',
64 'SQRT', 'CONJ', 'RE', 'RE2', 'IM', 'PI', 'COMPLEX', 'FUNCTION', 'IF','ELSE',
65 'VARIABLE', 'NUMBER','COND','REGLOG', 'ARG'
66 )
67 literals = "=+-*/(),"
68
69
70
72 r'(?<!\w)csc(?=\()'
73 return t
75 r'(?<!\w)sec(?=\()'
76 return t
78 r'(?<!\w)acsc(?=\()'
79 return t
81 r'(?<!\w)asec(?=\()'
82 return t
84 r'(?<!\w)reglog(?=\()'
85 return t
87 r'(?<!\w)cond(?=\()'
88 return t
92 r'(?<!\w)if\s'
93 return t
95 r'(?<!\w)else\s'
96 return t
98 r'==|!=|<=|>=|<|>'
99 return t
101 r'(?<!\w)and(?=[\s\(])|(?<!\w)or(?=[\s\(])'
102 return t
104 r'cmath\.sqrt'
105 return t
107 r'cmath\.pi'
108 return t
110 r'complexconjugate'
111 return t
113 r'(?<!\w)im(?=\()'
114 return t
116 r'(?<!\w)re(?=\()'
117 return t
119 r'\.real|\.imag'
120 return t
121
123 r'(?<!\w)complex(?=\()'
124 return t
126 r'(cmath\.){0,1}[a-zA-Z_][0-9a-zA-Z_]*(?=\()'
127 return t
129 r'[a-zA-Z_][0-9a-zA-Z_]*'
130 return t
131
132 t_NUMBER = r'([0-9]+\.[0-9]*|\.[0-9]+|[0-9]+)([eE][+-]{0,1}[0-9]+){0,1}j{0,1}'
133 t_POWER = r'\*\*'
134
135 t_ignore = " \t"
136
137 re_cmath_function = re.compile("cmath\.(?P<name>[0-9a-zA-Z_]+)")
138
140 r'\n+'
141 t.lexer.lineno += t.value.count("\n")
142
144 logger.error("Illegal character '%s'" % t.value[0])
145 t.lexer.skip(1)
146
147
148 - def build(self,**kwargs):
149 self.lexer = lex.lex(module=self, **kwargs)
150
151
152
153 precedence = (
154 ('right', 'LOGICALCOMB'),
155 ('right', 'LOGICAL'),
156 ('right','IF'),
157 ('right','ELSE'),
158 ('left','='),
159 ('left','+','-'),
160 ('left','*','/'),
161 ('left', 'RE2'),
162 ('right','UMINUS'),
163 ('left','POWER'),
164 ('right','REGLOG'),
165 ('right','ARG'),
166 ('right','CSC'),
167 ('right','SEC'),
168 ('right','ACSC'),
169 ('right','ASEC'),
170 ('right','SQRT'),
171 ('right','CONJ'),
172 ('right','RE'),
173 ('right','IM'),
174 ('right','FUNCTION'),
175 ('right','COMPLEX'),
176 ('right','COND'),
177 )
178
179
183
185 '''expression : expression '=' expression
186 | expression '+' expression
187 | expression '-' expression
188 | expression '*' expression
189 | expression '/' expression'''
190 p[0] = p[1] + p[2] + p[3]
191
193 '''boolexpression : expression LOGICAL expression'''
194 if p[2] not in self.logical_equiv:
195 p[0] = p[1] + p[2] + p[3]
196 else:
197 p[0] = p[1] + self.logical_equiv[p[2]] + p[3]
198
200 '''boolexpression : boolexpression LOGICALCOMB boolexpression'''
201 if p[2] not in self.logical_equiv:
202 p[0] = p[1] + p[2] + p[3]
203 else:
204 p[0] = p[1] + self.logical_equiv[p[2]] + p[3]
205
207 "expression : '-' expression %prec UMINUS"
208 p[0] = '-' + p[2]
209
211 "group : '(' expression ')'"
212 p[0] = '(' + p[2] +')'
213
215 "boolexpression : '(' boolexpression ')'"
216 p[0] = '(' + p[2] +')'
217
219 "expression : group"
220 p[0] = p[1]
221
223 "expression : FUNCTION '(' expression ')'"
224 p1 = p[1]
225 re_groups = self.re_cmath_function.match(p1)
226 if re_groups:
227 p1 = re_groups.group("name")
228 p[0] = p1 + '(' + p[3] + ')'
229
231 "expression : FUNCTION '(' expression ',' expression ')'"
232 p1 = p[1]
233 re_groups = self.re_cmath_function.match(p1)
234 if re_groups:
235 p1 = re_groups.group("name")
236 p[0] = p1 + '(' + p[3] + ',' + p[5] + ')'
237
239 if p:
240 raise ModelError("Syntax error at '%s' (%s)." %(p.value,p))
241 else:
242 logger.error("Syntax error at EOF")
243 self.parsed_string = "Error"
244
246 """A parser for UFO algebraic expressions, outputting
247 Fortran-style code."""
248
249
250
251
252 logical_equiv = {'==':'.EQ.',
253 '>=':'.GE.',
254 '<=':'.LE.',
255 '!=':'.NE.',
256 '>':'.GT.',
257 '<':'.LT.',
258 'or':'.OR.',
259 'and':'.AND.'}
260
262 "expression : NUMBER"
263 if p[1].endswith('j'):
264 p[0] = ('DCOMPLX(0d0, %e)' % float(p[1][:-1])).replace('e', 'd')
265 else:
266 p[0] = ('%e' % float(p[1])).replace('e', 'd')
267
269 "expression : VARIABLE"
270 p[0] = p[1].lower()
271
273 'expression : expression POWER expression'
274 try:
275 p3 = float(p[3].replace('d','e'))
276
277 if p3 == int(p3):
278 p3 = str(int(p3))
279 p[0] = p[1] + "**" + p3
280 else:
281 p[0] = p[1] + "**" + p[3]
282 except Exception:
283 p[0] = p[1] + "**" + p[3]
284
286 "expression : expression IF boolexpression ELSE expression "
287 p[0] = 'CONDIF(%s,DCMPLX(%s),DCMPLX(%s))' % (p[3], p[1], p[5])
288
290 "expression : expression IF expression ELSE expression "
291 p[0] = 'CONDIF(DCMPLX(%s).NE.(0d0,0d0),DCMPLX(%s),DCMPLX(%s))'\
292 %(p[3], p[1], p[5])
293
295 "expression : COND '(' expression ',' expression ',' expression ')'"
296 p[0] = 'COND(DCMPLX('+p[3]+'),DCMPLX('+p[5]+'),DCMPLX('+p[7]+'))'
297
299 "expression : COMPLEX '(' expression ',' expression ')'"
300 p[0] = '(' + p[3] + ',' + p[5] + ')'
301
303 '''expression : CSC group
304 | SEC group
305 | ACSC group
306 | ASEC group
307 | RE group
308 | IM group
309 | ARG group
310 | SQRT group
311 | CONJ group
312 | REGLOG group'''
313 if p[1] == 'csc': p[0] = '1d0/cos' + p[2]
314 elif p[1] == 'sec': p[0] = '1d0/sin' + p[2]
315 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')'
316 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')'
317 elif p[1] == 're': p[0] = 'dble' + p[2]
318 elif p[1] == 'im': p[0] = 'dimag' + p[2]
319 elif p[1] == 'arg': p[0] = 'arg(DCMPLX'+p[2]+')'
320 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt' + p[2]
321 elif p[1] == 'complexconjugate': p[0] = 'conjg(DCMPLX' + p[2]+')'
322 elif p[1] == 'reglog': p[0] = 'reglog(DCMPLX' + p[2] +')'
323
324
326 ''' expression : expression RE2 '''
327
328 if p[2] == '.real':
329 if p[1].startswith('('):
330 p[0] = 'dble' +p[1]
331 else:
332 p[0] = 'dble(%s)' % p[1]
333 elif p[2] == '.imag':
334 if p[1].startswith('('):
335 p[0] = 'dimag' +p[1]
336 else:
337 p[0] = 'dimag(%s)' % p[1]
338
340 '''expression : PI'''
341 p[0] = 'pi'
342
344 """A parser for UFO algebraic expressions, outputting
345 Fortran-style code for quadruple precision computation."""
346
347 mp_prefix = check_param_card.ParamCard.mp_prefix
348
349
350
351
353 "expression : NUMBER"
354
355 if p[1].endswith('j'):
356 p[0] = 'CMPLX(0.000000e+00_16, %e_16 ,KIND=16)' % float(p[1][:-1])
357 else:
358 p[0] = '%e_16' % float(p[1])
359
361 "expression : VARIABLE"
362
363 p[0] = (self.mp_prefix+p[1]).lower()
364
366 'expression : expression POWER expression'
367 try:
368 p3 = float(p[3].replace('_16',''))
369
370 if p3 == int(p3):
371 p3 = str(int(p3))
372 p[0] = p[1] + "**" + p3
373 else:
374 p[0] = p[1] + "**" + p[3]
375 except Exception:
376 p[0] = p[1] + "**" + p[3]
377
379 "expression : expression IF boolexpression ELSE expression "
380 p[0] = 'MP_CONDIF(%s,CMPLX(%s,KIND=16),CMPLX(%s,KIND=16))' % (p[3], p[1], p[5])
381
383 "expression : expression IF expression ELSE expression "
384 p[0] = 'MP_CONDIF(CMPLX(%s,KIND=16).NE.(0.0e0_16,0.0e0_16),CMPLX(%s,KIND=16),CMPLX(%s,KIND=16))'\
385 %(p[3], p[1], p[5])
386
388 "expression : COND '(' expression ',' expression ',' expression ')'"
389 p[0] = 'MP_COND(CMPLX('+p[3]+',KIND=16),CMPLX('+p[5]+\
390 ',KIND=16),CMPLX('+p[7]+',KIND=16))'
391
393 '''expression : CSC group
394 | SEC group
395 | ACSC group
396 | ASEC group
397 | RE group
398 | IM group
399 | ARG group
400 | SQRT group
401 | CONJ group
402 | REGLOG group'''
403 if p[1] == 'csc': p[0] = '1e0_16/cos' + p[2]
404 elif p[1] == 'sec': p[0] = '1e0_16/sin' + p[2]
405 elif p[1] == 'acsc': p[0] = 'asin(1e0_16/' + p[2] + ')'
406 elif p[1] == 'asec': p[0] = 'acos(1e0_16/' + p[2] + ')'
407 elif p[1] == 're': p[0] = 'real' + p[2]
408 elif p[1] == 'im': p[0] = 'imag' + p[2]
409 elif p[1] == 'arg': p[0] = 'mp_arg(CMPLX(' + p[2] + ',KIND=16))'
410 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt' + p[2]
411 elif p[1] == 'complexconjugate': p[0] = 'conjg(CMPLX(' + p[2] + ',KIND=16))'
412 elif p[1] == 'reglog': p[0] = 'mp_reglog(CMPLX(' + p[2] +',KIND=16))'
413
415 ''' expression : expression RE2 '''
416
417 if p[2] == '.real':
418 if p[1].startswith('('):
419 p[0] = 'real' +p[1]
420 else:
421 p[0] = 'real(%s)' % p[1]
422 elif p[2] == '.imag':
423 if p[1].startswith('('):
424 p[0] = 'imag' +p[1]
425 else:
426 p[0] = 'imag(%s)' % p[1]
427
428
430 '''expression : PI'''
431 p[0] = self.mp_prefix+'pi'
432
434 """A parser for UFO algebraic expressions, outputting
435 C++-style code."""
436
437 logical_equiv = {'==':'==',
438 '>=':'>=',
439 '<=':'<=',
440 '!=':'!=',
441 '>':'>',
442 '<':'<',
443 'or':'||',
444 'and':'&&'}
445
446
447
448
450 'expression : NUMBER'
451
452 if p[1].endswith('j'):
453 p[0] = 'std::complex<double>(0., %e)' % float(p[1][:-1])
454 else:
455 p[0] = ('%e' % float(p[1])).replace('e', 'd')
456
457
458 p[0] = p[1]
459
460 if float(p[1]) == int(float(p[1])) and float(p[1]) < 1000:
461 p[0] = str(int(float(p[1]))) + '.'
462
464 'expression : VARIABLE'
465 p[0] = p[1]
466
468 "expression : expression IF boolexpression ELSE expression "
469 p[0] = '(%s ? %s : %s)' % (p[3], p[1], p[5])
470
472 "expression : expression IF expression ELSE expression "
473 p[0] = '(%s ? %s : %s)' % (p[3], p[1], p[5])
474
476 "expression : COND '(' expression ',' expression ',' expression ')'"
477 p[0] = 'COND('+p[3]+','+p[5]+','+p[7]+')'
478
480 'expression : expression POWER expression'
481 p1=p[1]
482 p3=p[3]
483 if p[1][0] == '(' and p[1][-1] == ')':
484 p1 = p[1][1:-1]
485 if p[3][0] == '(' and p[3][-1] == ')':
486 p3 = p[3][1:-1]
487 p[0] = 'pow(' + p1 + ',' + p3 + ')'
488
490 "expression : COMPLEX '(' expression ',' expression ')'"
491 p[0] = 'std::complex<double>(' + p[3] + ',' + p[5] + ')'
492
494 '''expression : CSC group
495 | SEC group
496 | ACSC group
497 | ASEC group
498 | RE group
499 | IM group
500 | ARG group
501 | SQRT group
502 | CONJ group
503 | REGLOG group '''
504 if p[1] == 'csc': p[0] = '1./cos' + p[2]
505 elif p[1] == 'sec': p[0] = '1./sin' + p[2]
506 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')'
507 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')'
508 elif p[1] == 're': p[0] = 'real' + p[2]
509 elif p[1] == 'im': p[0] = 'imag' + p[2]
510 elif p[1] == 'arg':p[0] = 'arg' + p[2]
511 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt' + p[2]
512 elif p[1] == 'complexconjugate': p[0] = 'conj' + p[2]
513 elif p[1] == 'reglog': p[0] = 'reglog' + p[2]
514
516 ''' expression : expression RE2 '''
517
518 if p[2] == '.real':
519 if p[1].startswith('('):
520 p[0] = 'real' +p[1]
521 else:
522 p[0] = 'real(%s)' % p[1]
523 elif p[2] == '.imag':
524 if p[1].startswith('('):
525 p[0] = 'imag' +p[1]
526 else:
527 p[0] = 'imag(%s)' % p[1]
528
529
531 '''expression : PI'''
532 p[0] = 'M_PI'
533
534
535
536
537 if __name__ == '__main__':
538
539 if len(sys.argv) == 1:
540 print "Please specify a parser: fortran, mpfortran or c++"
541 exit()
542 if sys.argv[1] == "fortran":
543 calc = UFOExpressionParserFortran()
544 elif sys.argv[1] == "mpfortran":
545 calc = UFOExpressionParserMPFortran()
546 elif sys.argv[1] == "c++":
547 calc = UFOExpressionParserCPP()
548 elif sys.argv[1] == "aloha":
549 calc = UFOExpressionParserCPP()
550 else:
551 print "Please specify a parser: fortran, mpfortran or c++"
552 print "You gave", sys.argv[1]
553 exit()
554
555 while 1:
556 try:
557 s = raw_input('calc > ')
558 except EOFError:
559 break
560 if not s: continue
561 print calc.parse(s)
562