Skip to content

Commit a453ab0

Browse files
committed
parsing(c_parser): added support for unary ops and paren expr
- Added support for unary operators: - unary plus(+), unary minus(-), pre/post increment(++), pre/post decrement(--) and logical NOT(!) - Added support for parenthesized expression - Added corresponding tests - Added tests for unary operators - Added tests for parenthesized expression - Added tests for Exceptions raised in parsing binary operators, variable declarations and unary operators - Improved error messages of Exceptions raised in parsing binary operators, variable declarations and unary operators Other notes: - Dereferencing operator(*), Address operator(&) and bitwise NOT(~) are the unary operators that have not been implemented because of unavailability of such nodes or classes in SymPy - If unary operators are the children of binary operator in AST, it is not possible to parse yet!
1 parent 5db74b0 commit a453ab0

File tree

2 files changed

+432
-32
lines changed

2 files changed

+432
-32
lines changed

sympy/parsing/c/c_parser.py

Lines changed: 120 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@
4646
from sympy.codegen.ast import (Variable, IntBaseType, FloatBaseType, String,
4747
Integer, Float, FunctionPrototype, FunctionDefinition, FunctionCall,
4848
none, Return, Assignment, Type)
49+
from sympy.codegen.cnodes import (PreDecrement, PostDecrement,
50+
PreIncrement, PostIncrement)
4951
from sympy.core import Add, Mod, Mul, Pow, Rel
50-
from sympy.logic.boolalg import And, as_Boolean, Or
52+
from sympy.logic.boolalg import And, as_Boolean, Not, Or
5153
from sympy import Symbol, sympify, true, false
5254
import sys
5355
import tempfile
@@ -287,7 +289,7 @@ def transform_var_decl(self, node):
287289
value = val
288290

289291
else:
290-
raise NotImplementedError("Only bool, int " \
292+
raise NotImplementedError("Only bool, int "
291293
"and float are supported")
292294

293295
elif (child.kind == cin.CursorKind.CALL_EXPR):
@@ -298,34 +300,33 @@ def transform_var_decl(self, node):
298300
)
299301

300302
# when val is combination of more than two expr and
301-
# integer(or float)
302-
elif (child.kind == cin.CursorKind.BINARY_OPERATOR):
303+
# integer(or float) i.e. it has binary operator
304+
# Or var decl has parenthesis in the rhs(as a parent Clang node)
305+
# Or it has unary operator
306+
# Or it has boolean literal on rhs i.e. true or false
307+
elif (child.kind == cin.CursorKind.BINARY_OPERATOR
308+
or child.kind == cin.CursorKind.PAREN_EXPR
309+
or child.kind == cin.CursorKind.UNARY_OPERATOR
310+
or child.kind == cin.CursorKind.CXX_BOOL_LITERAL_EXPR):
303311
if (node.type.kind == cin.TypeKind.INT):
304312
type = IntBaseType(String('integer'))
305313
elif (node.type.kind == cin.TypeKind.FLOAT):
306314
type = FloatBaseType(String('real'))
307315
elif (node.type.kind == cin.TypeKind.BOOL):
308316
type = Type(String('bool'))
309317
else:
310-
raise NotImplementedError("Only bool, int " \
318+
raise NotImplementedError("Only bool, int "
311319
"and float are supported")
312320
value = val
313321

314-
elif (child.kind == cin.CursorKind.CXX_BOOL_LITERAL_EXPR):
315-
if (node.type.kind == cin.TypeKind.INT):
316-
type = IntBaseType(String('integer'))
317-
value = Integer(val)
318-
elif (node.type.kind == cin.TypeKind.FLOAT):
319-
type = FloatBaseType(String('real'))
320-
value = Float(val)
321-
elif (node.type.kind == cin.TypeKind.BOOL):
322-
type = Type(String('bool'))
323-
value = sympify(val)
324-
else:
325-
raise NotImplementedError("Only bool, int " \
326-
"and float are supported")
327322
else:
328-
raise NotImplementedError()
323+
raise NotImplementedError("Given "
324+
"variable declaration \"{}\" "
325+
"is not possible to parse yet!"
326+
.format(" ".join(
327+
t.spelling for t in node.get_tokens()
328+
)
329+
))
329330

330331
except StopIteration:
331332

@@ -339,7 +340,7 @@ def transform_var_decl(self, node):
339340
type = Type(String('bool'))
340341
value = false
341342
else:
342-
raise NotImplementedError("Only bool, int " \
343+
raise NotImplementedError("Only bool, int "
343344
"and float are supported")
344345

345346
return Variable(
@@ -735,6 +736,72 @@ def transform_decl_stmt(self, node):
735736

736737
return statement
737738

739+
def transform_paren_expr(self, node):
740+
"""Transformation function for Parenthesized expressions
741+
742+
Returns the result from its children nodes
743+
744+
"""
745+
return self.transform(next(node.get_children()))
746+
747+
def transform_unary_operator(self, node):
748+
"""Transformation function for handling unary operators
749+
750+
Returns
751+
=======
752+
753+
unary_expression: Codegen AST node
754+
simplified unary expression represented as Codegen AST
755+
756+
Raises
757+
======
758+
759+
NotImplementedError
760+
If dereferencing operator(*), address operator(&) or
761+
bitwise NOT operator(~) is encountered
762+
763+
"""
764+
# supported operators list
765+
operators_list = ['+', '-', '++', '--', '!']
766+
tokens = [token for token in node.get_tokens()]
767+
768+
# it can be either pre increment/decrement or any other operator from the list
769+
if tokens[0].spelling in operators_list:
770+
child = self.transform(next(node.get_children()))
771+
# (decl_ref) e.g.; int a = ++b; or simply ++b;
772+
if isinstance(child, str):
773+
if tokens[0].spelling == '+':
774+
return Symbol(child)
775+
if tokens[0].spelling == '-':
776+
return Mul(Symbol(child), -1)
777+
if tokens[0].spelling == '++':
778+
return PreIncrement(Symbol(child))
779+
if tokens[0].spelling == '--':
780+
return PreDecrement(Symbol(child))
781+
if tokens[0].spelling == '!':
782+
return Not(Symbol(child))
783+
# e.g.; int a = -1; or int b = -(1 + 2);
784+
else:
785+
if tokens[0].spelling == '+':
786+
return child
787+
if tokens[0].spelling == '-':
788+
return Mul(child, -1)
789+
if tokens[0].spelling == '!':
790+
return Not(sympify(bool(child)))
791+
792+
# it can be either post increment/decrement
793+
# since variable name is obtained in token[0].spelling
794+
elif tokens[1].spelling in ['++', '--']:
795+
child = self.transform(next(node.get_children()))
796+
if tokens[1].spelling == '++':
797+
return PostIncrement(Symbol(child))
798+
if tokens[1].spelling == '--':
799+
return PostDecrement(Symbol(child))
800+
else:
801+
raise NotImplementedError("Dereferencing operator, "
802+
"Address operator and bitwise NOT operator "
803+
"have not been implemented yet!")
804+
738805
def transform_binary_operator(self, node):
739806
"""Transformation function for handling binary operators
740807
@@ -747,9 +814,10 @@ def transform_binary_operator(self, node):
747814
Raises
748815
======
749816
750-
NotImplementedError if shift or
751-
bitwise operator
752-
is passed
817+
NotImplementedError
818+
If a bitwise operator or
819+
unary operator(which is a child of any binary
820+
operator in Clang AST) is encountered
753821
754822
"""
755823
# get all the tokens of assignment
@@ -782,8 +850,13 @@ def transform_binary_operator(self, node):
782850
# keep adding the expression to the
783851
# combined variables stack unless
784852
# '(' is found
785-
while (len(operators_stack) != 0
853+
while (operators_stack
786854
and operators_stack[-1] != '('):
855+
if len(combined_variables_stack) < 2:
856+
raise NotImplementedError(
857+
"Unary operators as a part of "
858+
"binary operators is not "
859+
"supported yet!")
787860
rhs = combined_variables_stack.pop()
788861
lhs = combined_variables_stack.pop()
789862
operator = operators_stack.pop()
@@ -796,11 +869,15 @@ def transform_binary_operator(self, node):
796869

797870
# token is an operator (supported)
798871
elif token.spelling in operators_list:
799-
while (len(operators_stack) != 0
872+
while (operators_stack
800873
and self.priority_of(token.spelling)
801874
<= self.priority_of(
802875
operators_stack[-1])):
803-
876+
if len(combined_variables_stack) < 2:
877+
raise NotImplementedError(
878+
"Unary operators as a part of "
879+
"binary operators is not "
880+
"supported yet!")
804881
rhs = combined_variables_stack.pop()
805882
lhs = combined_variables_stack.pop()
806883
operator = operators_stack.pop()
@@ -810,11 +887,16 @@ def transform_binary_operator(self, node):
810887

811888
# push current operator
812889
operators_stack.append(token.spelling)
813-
else:
890+
891+
# token is a bitwise operator
892+
elif token.spelling in ['&', '|', '^', '<<', '>>']:
814893
raise NotImplementedError(
815-
"Shift operator " \
816-
"and bitwise operator are not " \
894+
"Bitwise operator has not been "
817895
"implemented yet!")
896+
else:
897+
raise NotImplementedError(
898+
"Given token {} is not implemented yet!"
899+
.format(token.spelling))
818900

819901
# token is an identifier(variable)
820902
elif token.kind == cin.TokenKind.IDENTIFIER:
@@ -832,10 +914,17 @@ def transform_binary_operator(self, node):
832914
combined_variables_stack.append(
833915
[token.spelling, 'boolean'])
834916
else:
835-
raise NotImplementedError()
917+
raise NotImplementedError(
918+
"Given token {} is not implemented yet!"
919+
.format(token.spelling))
836920

837921
# process remaining operators
838-
while (len(operators_stack) != 0):
922+
while operators_stack:
923+
if len(combined_variables_stack) < 2:
924+
raise NotImplementedError(
925+
"Unary operators as a part of "
926+
"binary operators is not "
927+
"supported yet!")
839928
rhs = combined_variables_stack.pop()
840929
lhs = combined_variables_stack.pop()
841930
operator = operators_stack.pop()

0 commit comments

Comments
 (0)