Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A prototype for solve dividing two integers #66

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 93 additions & 3 deletions pyclibrary/c_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,91 @@
__all__ = ['win_defs', 'CParser']


def wrap_int(t):
logger.debug('wrap_int: {} {}'.format(t.dump(), type(t)))
t[0] = "CInt({})".format(int(t[0], 0))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we return a string from here? I would expect this function to return a CInt instance.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realise this should be part of a bigger rewrite, so no need to change in this PR.

return t

class CInt(int):
def __new__(cls, base=10, *args, **kwargs):
return super(CInt, cls).__new__(cls, base, *args, **kwargs)

def __truediv__(self, other):
if isinstance(other, CInt):
is_positive = self >= 0 and other >= 0
return CInt(int(self) // int(other)) if is_positive else -CInt(-int(self) // int(other))
else:
return super(CInt, self).__truediv__(other)

def __rtruediv__(self, other):
if isinstance(other, CInt):
is_positive = self >= 0 and other >= 0
return CInt(int(other) // int(self)) if is_positive else -CInt(-int(other) // int(self))
else:
return super(CInt, self).__rtruediv__(other)

def __mod__(self, other):
if isinstance(other, CInt):
is_positive = self >= 0 and other >= 0
return CInt(int(self) % int(other)) if is_positive else -CInt(-int(self) % int(other))
else:
return super(CInt, self).__mod__(other)

def __rmod__(self, other):
if isinstance(other, CInt):
is_positive = self >= 0 and other >= 0
return CInt(int(other) % int(self)) if is_positive else -CInt(-int(other) % int(self))
else:
return super(CInt, self).__rmod__(other)

def __sub__(self, other):
if isinstance(other, CInt):
return CInt(int(self) - int(other))
else:
return super(CInt, self).__sub__(other)

def __rsub__(self, other):
if isinstance(other, CInt):
return CInt(int(other) - int(self))
else:
return super(CInt, self).__rsub__(other)

def __add__(self, other):
if isinstance(other, CInt):
return CInt(int(self) + int(other))
else:
return super(CInt, self).__add__(other)

def __radd__(self, other):
if isinstance(other, CInt):
return CInt(int(other) + int(self))
else:
return super(CInt, self).__radd__(other)

def __mul__(self, other):
if isinstance(other, CInt):
return CInt(int(self) * int(other))
else:
return super(CInt, self).__mul__(other)

def __rmul__(self, other):
if isinstance(other, CInt):
return CInt(int(other) * int(self))
else:
return super(CInt, self).__rmul__(other)

def __str__(self):
return "CInt({})".format(super(CInt, self).__str__())

def __repr__(self):
return "CInt({})".format(super(CInt, self).__repr__())

def __neg__(self):
return CInt(-int(self))

def __pos__(self):
return CInt(+int(self))

class Type(tuple):
"""
Representation of a C type. CParser uses this class to store the parsed
Expand Down Expand Up @@ -1508,7 +1593,7 @@ def eval(self, expr, *args):
expr = expr.strip()
cast = (lparen + self.type_spec + self.abstract_declarator +
rparen).suppress()
expr = (quotedString | number | cast).transformString(expr)
expr = (quotedString | number_in_expr | cast).transformString(expr)
if expr == '':
return None
return eval(expr, *args)
Expand Down Expand Up @@ -1650,11 +1735,16 @@ def print_parse_results(pr, depth=0, name=''):
int_strip = lambda t: t[0].rstrip('UL')
hexint = Regex(r'[+-]?\s*0[xX][{}]+[UL]*'.format(hexnums)).setParseAction(int_strip)
decint = Regex(r'[+-]?\s*[0-9]+[UL]*').setParseAction(int_strip)
integer = (hexint | decint)
octal = Regex(r'[+-]?\s*0[0-7]+[UL]*').setParseAction(lambda t: int_strip(t).replace('0', '0o', 1))
integer = (hexint | octal | decint)
integer.setParseAction(wrap_int)
# in eval expr would not match identifier, it would match a number cause error
integer_in_expr = (hexint | octal | decint)
# The floating regex is ugly but it is because we do not want to match
# integer to it.
floating = Regex(r'[+-]?\s*((((\d(\.\d*)?)|(\.\d+))[eE][+-]?\d+)|((\d\.\d*)|(\.\d+)))')
number = (floating | integer)
number = (floating |integer)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coding style: use spaces around binary operators

number_in_expr = (floating |integer_in_expr)

# Miscelaneous
bi_operator = oneOf("+ - / * | & || && ! ~ ^ % == != > < >= <= -> . :: << >> = ? :")
Expand Down
5 changes: 5 additions & 0 deletions tests/headers/macros/macro_values.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
#define MACRO_H2 - 0x000001U
#define MACRO_H3 0X000002UL

// Octal values
#define MACRO_OCT1 + 010
#define MACRO_OCT2 -03000U
#define MACRO_OCT3 02UL

// Bit shifted hexadecimal values
#define MACRO_SH1 (0x000000 << 1)
#define MACRO_SH2 (0x000001U << 2)
Expand Down
12 changes: 12 additions & 0 deletions tests/headers/variables.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ float x1 = (5 + 3 * 0x1) / 8.0;
// Test type casting handling.
int x2 = (typeCast)0x544 <<16;

// Test int div 9 / 2 should be 4
float x3 = 9.0 / 2.0;
int x4 = 9 / 2;
float x5 = 9 / 2;
int x6_1 = 9;
int x6_2 = 2;
float x6 = x6_1 / x6_2;
float x7 = x6_1 / 2.0;
float x8 = (9 / 2) * 2 + 9 % 2;
int x9 = -9 / 2; // -4
int x10 = -9 % 2; // -1

// Test array
float array[2] = {0x1, 3.1415e6};
static const int * const (**intJunk[4]);
Expand Down
29 changes: 29 additions & 0 deletions tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,17 @@ def test_values(self):
macros['MACRO_H3'] == '0X000002UL' and
values['MACRO_H3'] == 2)

# Octal integer
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great tests!

assert ('MACRO_OCT1' in macros and
macros['MACRO_OCT1'] == '+ 010' and
values['MACRO_OCT1'] == 0o10)
assert ('MACRO_OCT2' in macros and
macros['MACRO_OCT2'] == '-03000U' and
values['MACRO_OCT2'] == -0o3000)
assert ('MACRO_OCT3' in macros and
macros['MACRO_OCT3'] == '02UL' and
values['MACRO_OCT3'] == 0o2)

# Bit shifted hexadecimal integer
assert ('MACRO_SH1' in macros and
macros['MACRO_SH1'] == '(0x000000 << 1)' and
Expand Down Expand Up @@ -566,6 +577,24 @@ def test_variables(self):
assert ('x2' in variables and
variables['x2'] == (88342528, Type('int')))

# Test int div 9 / 2 should be 4
assert ('x3' in variables and
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
assert ('x3' in variables and
assert (

the indexing will anyway if the key does not exist in the dict. No need to test it separately.

variables['x3'] == (4.5, Type('float')))
assert ('x4' in variables and
variables['x4'] == (4, Type('int')))
assert ('x5' in variables and
variables['x5'] == (4., Type('float')))
assert ('x6' in variables and
variables['x6'] == (4., Type('float')))
assert ('x7' in variables and
variables['x7'] == (4.5, Type('float')))
assert ('x8' in variables and
variables['x8'] == (9., Type('float')))
assert ('x9' in variables and
variables['x9'] == (-4, Type('int')))
assert ('x10' in variables and
variables['x10'] == (-1, Type('int')))

# Test array handling
assert ('array' in variables and
variables['array'] == ([1, 3141500.0], Type('float', [2])))
Expand Down