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 MadGraph Development team and Contributors 
  4  # 
  5  # This file is a part of the MadGraph 5 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 MadGraph license which should accompany this  
 10  # distribution. 
 11  # 
 12  # For more information, please visit: http://madgraph.phys.ucl.ac.be 
 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  logger = logging.getLogger('madgraph.ufo_parsers') 
 32   
 33  # PLY lexer class 
 34   
35 -class ModelError(MadGraph5Error):
36 """Appropriate Error for a wrong parsing"""
37
38 -class UFOExpressionParser:
39 """A base class for parsers for algebraic expressions coming from UFO.""" 40 41 parsed_string = "" 42
43 - def __init__(self, **kw):
44 """Ininitialize the lex and yacc""" 45 46 modname = self.__class__.__name__ 47 self.debugfile = os.path.devnull 48 self.tabmodule = os.path.join(root_path, "iolibs", modname + "_" + "parsetab.py") 49 lex.lex(module=self, debug=0) 50 yacc.yacc(module=self, debug=0, debugfile=self.debugfile, 51 tabmodule=self.tabmodule)
52
53 - def parse(self, buf):
54 """Parse the string buf""" 55 yacc.parse(buf) 56 return self.parsed_string
57 58 # List of tokens and literals 59 tokens = ( 60 'POWER', 'CSC', 'SEC', 'ACSC', 'ASEC', 61 'SQRT', 'CONJ', 'RE', 'IM', 'PI', 'COMPLEX', 'FUNCTION', 62 'VARIABLE', 'NUMBER' 63 ) 64 literals = "=+-*/()," 65 66 # Definition of tokens 67
68 - def t_CSC(self, t):
69 r'(?<!\w)csc(?=\()' 70 return t
71 - def t_SEC(self, t):
72 r'(?<!\w)sec(?=\()' 73 return t
74 - def t_ACSC(self, t):
75 r'(?<!\w)acsc(?=\()' 76 return t
77 - def t_ASEC(self, t):
78 r'(?<!\w)asec(?=\()' 79 return t
80 - def t_SQRT(self, t):
81 r'cmath\.sqrt' 82 return t
83 - def t_PI(self, t):
84 r'cmath\.pi' 85 return t
86 - def t_CONJ(self, t):
87 r'complexconjugate' 88 return t
89 - def t_IM(self, t):
90 r'(?<!\w)im(?=\()' 91 return t
92 - def t_RE(self, t):
93 r'(?<!\w)re(?=\()' 94 return t
95 - def t_COMPLEX(self, t):
96 r'(?<!\w)complex(?=\()' 97 return t
98 - def t_FUNCTION(self, t):
99 r'(cmath\.){0,1}[a-zA-Z_][0-9a-zA-Z_]*(?=\()' 100 return t
101 - def t_VARIABLE(self, t):
102 r'[a-zA-Z_][0-9a-zA-Z_]*' 103 return t
104 105 t_NUMBER = r'([0-9]+\.[0-9]*|\.[0-9]+|[0-9]+)([eE][+-]{0,1}[0-9]+){0,1}' 106 t_POWER = r'\*\*' 107 108 t_ignore = " \t" 109 110 re_cmath_function = re.compile("cmath\.(?P<name>[0-9a-zA-Z_]+)") 111
112 - def t_newline(self, t):
113 r'\n+' 114 t.lexer.lineno += t.value.count("\n")
115
116 - def t_error(self, t):
117 logger.error("Illegal character '%s'" % t.value[0]) 118 t.lexer.skip(1)
119 120 # Build the lexer
121 - def build(self,**kwargs):
122 self.lexer = lex.lex(module=self, **kwargs)
123 124 # Definitions for the PLY yacc parser 125 126 # Parsing rules 127 precedence = ( 128 ('left','='), 129 ('left','+','-'), 130 ('left','*','/'), 131 ('right','UMINUS'), 132 ('left','POWER'), 133 ('right','CSC'), 134 ('right','SEC'), 135 ('right','ACSC'), 136 ('right','ASEC'), 137 ('right','SQRT'), 138 ('right','CONJ'), 139 ('right','RE'), 140 ('right','IM'), 141 ('right','FUNCTION'), 142 ('right','COMPLEX') 143 ) 144 145 # Dictionary of parser expressions
146 - def p_statement_expr(self, p):
147 'statement : expression' 148 self.parsed_string = p[1]
149
150 - def p_expression_binop(self, p):
151 '''expression : expression '=' expression 152 | expression '+' expression 153 | expression '-' expression 154 | expression '*' expression 155 | expression '/' expression''' 156 p[0] = p[1] + p[2] + p[3]
157
158 - def p_expression_uminus(self, p):
159 "expression : '-' expression %prec UMINUS" 160 p[0] = '-' + p[2]
161
162 - def p_group_parentheses(self, p):
163 "group : '(' expression ')'" 164 p[0] = '(' + p[2] +')'
165
166 - def p_expression_group(self, p):
167 "expression : group" 168 p[0] = p[1]
169
170 - def p_expression_function1(self, p):
171 "expression : FUNCTION '(' expression ')'" 172 p1 = p[1] 173 re_groups = self.re_cmath_function.match(p1) 174 if re_groups: 175 p1 = re_groups.group("name") 176 p[0] = p1 + '(' + p[3] + ')'
177
178 - def p_expression_function2(self, p):
179 "expression : FUNCTION '(' expression ',' expression ')'" 180 p1 = p[1] 181 re_groups = self.re_cmath_function.match(p1) 182 if re_groups: 183 p1 = re_groups.group("name") 184 p[0] = p1 + '(' + p[3] + ',' + p[5] + ')'
185
186 - def p_error(self, p):
187 if p: 188 raise ModelError("Syntax error at '%s' in '%s'" % (p.value, self.f)) 189 else: 190 logger.error("Syntax error at EOF") 191 self.parsed_string = "Error"
192
193 -class UFOExpressionParserFortran(UFOExpressionParser):
194 """A parser for UFO algebraic expressions, outputting 195 Fortran-style code.""" 196 197 # The following parser expressions need to be defined for each 198 # output language/framework 199
200 - def p_expression_number(self, p):
201 "expression : NUMBER" 202 p[0] = ('%e' % float(p[1])).replace('e', 'd')
203
204 - def p_expression_variable(self, p):
205 "expression : VARIABLE" 206 p[0] = p[1].lower()
207
208 - def p_expression_power(self, p):
209 'expression : expression POWER expression' 210 try: 211 p3 = float(p[3].replace('d','e')) 212 # Chebck if exponent is an integer 213 if p3 == int(p3): 214 p3 = str(int(p3)) 215 p[0] = p[1] + "**" + p3 216 else: 217 p[0] = p[1] + "**" + p[3] 218 except: 219 p[0] = p[1] + "**" + p[3]
220
221 - def p_expression_complex(self, p):
222 "expression : COMPLEX '(' expression ',' expression ')'" 223 p[0] = '(' + p[3] + ',' + p[5] + ')'
224
225 - def p_expression_func(self, p):
226 '''expression : CSC group 227 | SEC group 228 | ACSC group 229 | ASEC group 230 | RE group 231 | IM group 232 | SQRT group 233 | CONJ group''' 234 if p[1] == 'csc': p[0] = '1d0/cos' + p[2] 235 elif p[1] == 'sec': p[0] = '1d0/sin' + p[2] 236 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')' 237 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')' 238 elif p[1] == 're': p[0] = 'dble' + p[2] 239 elif p[1] == 'im': p[0] = 'dimag' + p[2] 240 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'dsqrt' + p[2] 241 elif p[1] == 'complexconjugate': p[0] = 'conjg' + p[2]
242
243 - def p_expression_pi(self, p):
244 '''expression : PI''' 245 p[0] = 'pi'
246
247 -class UFOExpressionParserCPP(UFOExpressionParser):
248 """A parser for UFO algebraic expressions, outputting 249 C++-style code.""" 250 251 # The following parser expressions need to be defined for each 252 # output language/framework 253
254 - def p_expression_number(self, p):
255 "expression : NUMBER" 256 p[0] = p[1] 257 # Check number is an integer, if so add "." 258 if float(p[1]) == int(float(p[1])) and float(p[1]) < 1000: 259 p[0] = str(int(float(p[1]))) + '.'
260
261 - def p_expression_variable(self, p):
262 "expression : VARIABLE" 263 p[0] = p[1]
264
265 - def p_expression_power(self, p):
266 'expression : expression POWER expression' 267 p1=p[1] 268 p3=p[3] 269 if p[1][0] == '(' and p[1][-1] == ')': 270 p1 = p[1][1:-1] 271 if p[3][0] == '(' and p[3][-1] == ')': 272 p3 = p[3][1:-1] 273 p[0] = 'pow(' + p1 + ',' + p3 + ')'
274
275 - def p_expression_complex(self, p):
276 "expression : COMPLEX '(' expression ',' expression ')'" 277 p[0] = 'std::complex<double>(' + p[3] + ',' + p[5] + ')'
278
279 - def p_expression_func(self, p):
280 '''expression : CSC group 281 | SEC group 282 | ACSC group 283 | ASEC group 284 | RE group 285 | IM group 286 | SQRT group 287 | CONJ group''' 288 if p[1] == 'csc': p[0] = '1./cos' + p[2] 289 elif p[1] == 'sec': p[0] = '1./sin' + p[2] 290 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')' 291 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')' 292 elif p[1] == 're': p[0] = 'real' + p[2] 293 elif p[1] == 'im': p[0] = 'imag' + p[2] 294 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt' + p[2] 295 elif p[1] == 'complexconjugate': p[0] = 'conj' + p[2]
296
297 - def p_expression_pi(self, p):
298 '''expression : PI''' 299 p[0] = 'M_PI'
300 301 302 # Main program, allows to interactively test the parser 303 if __name__ == '__main__': 304 305 if len(sys.argv) == 1: 306 print "Please specify a parser: fortran or pythia8" 307 exit() 308 if sys.argv[1] == "fortran": 309 calc = UFOExpressionParserFortran() 310 elif sys.argv[1] == "c++": 311 calc = UFOExpressionParserCPP() 312 else: 313 print "Please specify a parser: tex, fortran or c++" 314 print "You gave", sys.argv 315 exit() 316 317 while 1: 318 try: 319 s = raw_input('calc > ') 320 except EOFError: 321 break 322 if not s: continue 323 print calc.parse(s) 324