Spaces:
Sleeping
Sleeping
from sympy.printing import pycode, ccode, fcode | |
from sympy.external import import_module | |
from sympy.utilities.decorator import doctest_depends_on | |
lfortran = import_module('lfortran') | |
cin = import_module('clang.cindex', import_kwargs = {'fromlist': ['cindex']}) | |
if lfortran: | |
from sympy.parsing.fortran.fortran_parser import src_to_sympy | |
if cin: | |
from sympy.parsing.c.c_parser import parse_c | |
class SymPyExpression: # type: ignore | |
"""Class to store and handle SymPy expressions | |
This class will hold SymPy Expressions and handle the API for the | |
conversion to and from different languages. | |
It works with the C and the Fortran Parser to generate SymPy expressions | |
which are stored here and which can be converted to multiple language's | |
source code. | |
Notes | |
===== | |
The module and its API are currently under development and experimental | |
and can be changed during development. | |
The Fortran parser does not support numeric assignments, so all the | |
variables have been Initialized to zero. | |
The module also depends on external dependencies: | |
- LFortran which is required to use the Fortran parser | |
- Clang which is required for the C parser | |
Examples | |
======== | |
Example of parsing C code: | |
>>> from sympy.parsing.sym_expr import SymPyExpression | |
>>> src = ''' | |
... int a,b; | |
... float c = 2, d =4; | |
... ''' | |
>>> a = SymPyExpression(src, 'c') | |
>>> a.return_expr() | |
[Declaration(Variable(a, type=intc)), | |
Declaration(Variable(b, type=intc)), | |
Declaration(Variable(c, type=float32, value=2.0)), | |
Declaration(Variable(d, type=float32, value=4.0))] | |
An example of variable definition: | |
>>> from sympy.parsing.sym_expr import SymPyExpression | |
>>> src2 = ''' | |
... integer :: a, b, c, d | |
... real :: p, q, r, s | |
... ''' | |
>>> p = SymPyExpression() | |
>>> p.convert_to_expr(src2, 'f') | |
>>> p.convert_to_c() | |
['int a = 0', 'int b = 0', 'int c = 0', 'int d = 0', 'double p = 0.0', 'double q = 0.0', 'double r = 0.0', 'double s = 0.0'] | |
An example of Assignment: | |
>>> from sympy.parsing.sym_expr import SymPyExpression | |
>>> src3 = ''' | |
... integer :: a, b, c, d, e | |
... d = a + b - c | |
... e = b * d + c * e / a | |
... ''' | |
>>> p = SymPyExpression(src3, 'f') | |
>>> p.convert_to_python() | |
['a = 0', 'b = 0', 'c = 0', 'd = 0', 'e = 0', 'd = a + b - c', 'e = b*d + c*e/a'] | |
An example of function definition: | |
>>> from sympy.parsing.sym_expr import SymPyExpression | |
>>> src = ''' | |
... integer function f(a,b) | |
... integer, intent(in) :: a, b | |
... integer :: r | |
... end function | |
... ''' | |
>>> a = SymPyExpression(src, 'f') | |
>>> a.convert_to_python() | |
['def f(a, b):\\n f = 0\\n r = 0\\n return f'] | |
""" | |
def __init__(self, source_code = None, mode = None): | |
"""Constructor for SymPyExpression class""" | |
super().__init__() | |
if not(mode or source_code): | |
self._expr = [] | |
elif mode: | |
if source_code: | |
if mode.lower() == 'f': | |
if lfortran: | |
self._expr = src_to_sympy(source_code) | |
else: | |
raise ImportError("LFortran is not installed, cannot parse Fortran code") | |
elif mode.lower() == 'c': | |
if cin: | |
self._expr = parse_c(source_code) | |
else: | |
raise ImportError("Clang is not installed, cannot parse C code") | |
else: | |
raise NotImplementedError( | |
'Parser for specified language is not implemented' | |
) | |
else: | |
raise ValueError('Source code not present') | |
else: | |
raise ValueError('Please specify a mode for conversion') | |
def convert_to_expr(self, src_code, mode): | |
"""Converts the given source code to SymPy Expressions | |
Attributes | |
========== | |
src_code : String | |
the source code or filename of the source code that is to be | |
converted | |
mode: String | |
the mode to determine which parser is to be used according to | |
the language of the source code | |
f or F for Fortran | |
c or C for C/C++ | |
Examples | |
======== | |
>>> from sympy.parsing.sym_expr import SymPyExpression | |
>>> src3 = ''' | |
... integer function f(a,b) result(r) | |
... integer, intent(in) :: a, b | |
... integer :: x | |
... r = a + b -x | |
... end function | |
... ''' | |
>>> p = SymPyExpression() | |
>>> p.convert_to_expr(src3, 'f') | |
>>> p.return_expr() | |
[FunctionDefinition(integer, name=f, parameters=(Variable(a), Variable(b)), body=CodeBlock( | |
Declaration(Variable(r, type=integer, value=0)), | |
Declaration(Variable(x, type=integer, value=0)), | |
Assignment(Variable(r), a + b - x), | |
Return(Variable(r)) | |
))] | |
""" | |
if mode.lower() == 'f': | |
if lfortran: | |
self._expr = src_to_sympy(src_code) | |
else: | |
raise ImportError("LFortran is not installed, cannot parse Fortran code") | |
elif mode.lower() == 'c': | |
if cin: | |
self._expr = parse_c(src_code) | |
else: | |
raise ImportError("Clang is not installed, cannot parse C code") | |
else: | |
raise NotImplementedError( | |
"Parser for specified language has not been implemented" | |
) | |
def convert_to_python(self): | |
"""Returns a list with Python code for the SymPy expressions | |
Examples | |
======== | |
>>> from sympy.parsing.sym_expr import SymPyExpression | |
>>> src2 = ''' | |
... integer :: a, b, c, d | |
... real :: p, q, r, s | |
... c = a/b | |
... d = c/a | |
... s = p/q | |
... r = q/p | |
... ''' | |
>>> p = SymPyExpression(src2, 'f') | |
>>> p.convert_to_python() | |
['a = 0', 'b = 0', 'c = 0', 'd = 0', 'p = 0.0', 'q = 0.0', 'r = 0.0', 's = 0.0', 'c = a/b', 'd = c/a', 's = p/q', 'r = q/p'] | |
""" | |
self._pycode = [] | |
for iter in self._expr: | |
self._pycode.append(pycode(iter)) | |
return self._pycode | |
def convert_to_c(self): | |
"""Returns a list with the c source code for the SymPy expressions | |
Examples | |
======== | |
>>> from sympy.parsing.sym_expr import SymPyExpression | |
>>> src2 = ''' | |
... integer :: a, b, c, d | |
... real :: p, q, r, s | |
... c = a/b | |
... d = c/a | |
... s = p/q | |
... r = q/p | |
... ''' | |
>>> p = SymPyExpression() | |
>>> p.convert_to_expr(src2, 'f') | |
>>> p.convert_to_c() | |
['int a = 0', 'int b = 0', 'int c = 0', 'int d = 0', 'double p = 0.0', 'double q = 0.0', 'double r = 0.0', 'double s = 0.0', 'c = a/b;', 'd = c/a;', 's = p/q;', 'r = q/p;'] | |
""" | |
self._ccode = [] | |
for iter in self._expr: | |
self._ccode.append(ccode(iter)) | |
return self._ccode | |
def convert_to_fortran(self): | |
"""Returns a list with the fortran source code for the SymPy expressions | |
Examples | |
======== | |
>>> from sympy.parsing.sym_expr import SymPyExpression | |
>>> src2 = ''' | |
... integer :: a, b, c, d | |
... real :: p, q, r, s | |
... c = a/b | |
... d = c/a | |
... s = p/q | |
... r = q/p | |
... ''' | |
>>> p = SymPyExpression(src2, 'f') | |
>>> p.convert_to_fortran() | |
[' integer*4 a', ' integer*4 b', ' integer*4 c', ' integer*4 d', ' real*8 p', ' real*8 q', ' real*8 r', ' real*8 s', ' c = a/b', ' d = c/a', ' s = p/q', ' r = q/p'] | |
""" | |
self._fcode = [] | |
for iter in self._expr: | |
self._fcode.append(fcode(iter)) | |
return self._fcode | |
def return_expr(self): | |
"""Returns the expression list | |
Examples | |
======== | |
>>> from sympy.parsing.sym_expr import SymPyExpression | |
>>> src3 = ''' | |
... integer function f(a,b) | |
... integer, intent(in) :: a, b | |
... integer :: r | |
... r = a+b | |
... f = r | |
... end function | |
... ''' | |
>>> p = SymPyExpression() | |
>>> p.convert_to_expr(src3, 'f') | |
>>> p.return_expr() | |
[FunctionDefinition(integer, name=f, parameters=(Variable(a), Variable(b)), body=CodeBlock( | |
Declaration(Variable(f, type=integer, value=0)), | |
Declaration(Variable(r, type=integer, value=0)), | |
Assignment(Variable(f), Variable(r)), | |
Return(Variable(f)) | |
))] | |
""" | |
return self._expr | |