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  logger = logging.getLogger('madgraph.ufo_parsers') 
 32   
 33   
 34   
 36      """Appropriate Error for a wrong parsing""" 
  37   
 39      """A base class for parsers for algebraic expressions coming from UFO.""" 
 40   
 41      parsed_string = "" 
 42   
 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           
 57   
 58       
 59      tokens = ( 
 60          'POWER', 'CSC', 'SEC', 'ACSC', 'ASEC', 
 61          'SQRT', 'CONJ', 'RE', 'IM', 'PI', 'COMPLEX', 'FUNCTION', 
 62          'VARIABLE', 'NUMBER' 
 63          ) 
 64      literals = "=+-*/()," 
 65   
 66       
 67   
 69          r'(?<!\w)csc(?=\()' 
 70          return t 
  72          r'(?<!\w)sec(?=\()' 
 73          return t 
  75          r'(?<!\w)acsc(?=\()' 
 76          return t 
  78          r'(?<!\w)asec(?=\()' 
 79          return t 
  81          r'cmath\.sqrt' 
 82          return t 
  84          r'cmath\.pi' 
 85          return t 
  87          r'complexconjugate' 
 88          return t 
  90          r'(?<!\w)im(?=\()' 
 91          return t 
  93          r'(?<!\w)re(?=\()' 
 94          return t 
  96          r'(?<!\w)complex(?=\()' 
 97          return t 
  99          r'(cmath\.){0,1}[a-zA-Z_][0-9a-zA-Z_]*(?=\()' 
100          return 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   
113          r'\n+' 
114          t.lexer.lineno += t.value.count("\n") 
 115   
117          logger.error("Illegal character '%s'" % t.value[0]) 
118          t.lexer.skip(1) 
 119   
120       
121 -    def build(self,**kwargs): 
 122          self.lexer = lex.lex(module=self, **kwargs) 
 123   
124       
125   
126       
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       
149   
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   
159          "expression : '-' expression %prec UMINUS" 
160          p[0] = '-' + p[2] 
 161   
163          "group : '(' expression ')'" 
164          p[0] = '(' + p[2] +')' 
 165   
167          "expression : group" 
168          p[0] = p[1] 
 169   
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   
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   
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   
194      """A parser for UFO algebraic expressions, outputting 
195      Fortran-style code.""" 
196   
197       
198       
199   
201          "expression : NUMBER" 
202          p[0] = ('%e' % float(p[1])).replace('e', 'd') 
 203   
205          "expression : VARIABLE" 
206          p[0] = p[1].lower() 
 207   
209          'expression : expression POWER expression' 
210          try: 
211              p3 = float(p[3].replace('d','e')) 
212               
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   
222          "expression : COMPLEX '(' expression ',' expression ')'" 
223          p[0] = '(' + p[3] + ',' + p[5] + ')' 
 224   
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   
244          '''expression : PI''' 
245          p[0] = 'pi' 
  246   
248      """A parser for UFO algebraic expressions, outputting 
249      C++-style code.""" 
250   
251       
252       
253   
255          "expression : NUMBER" 
256          p[0] = p[1] 
257           
258          if float(p[1]) == int(float(p[1])) and float(p[1]) < 1000: 
259              p[0] = str(int(float(p[1]))) + '.' 
 260   
262          "expression : VARIABLE" 
263          p[0] = p[1] 
 264   
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   
276          "expression : COMPLEX '(' expression ',' expression ')'" 
277          p[0] = 'std::complex<double>(' + p[3] + ',' + p[5] + ')' 
 278   
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   
298          '''expression : PI''' 
299          p[0] = 'M_PI' 
  300   
301   
302   
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