Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions pycparserext/ext_c_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ def visit_TypeOfExpression(self, n):
def visit_TypeList(self, n):
return ', '.join(self.visit(ch) for ch in n.types)

def visit_RangeExpression(self, n):
return '%s ... %s' % (self.visit(n.first), self.visit(n.last))


class GNUCGenerator(GnuCGenerator):
def __init__(self):
Expand Down
28 changes: 28 additions & 0 deletions pycparserext/ext_c_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,29 @@ def __iter__(self):
attr_names = ()


class RangeExpression(c_ast.Node):
def __init__(self, first, last, coord=None):
self.first = first
self.last = last
self.coord = coord

def children(self):
nodelist = []
if self.first is not None:
nodelist.append(("first", self.first))
if self.last is not None:
nodelist.append(("last", self.last))
return tuple(nodelist)

def __iter__(self):
if self.first is not None:
yield self.first
if self.last is not None:
yield self.last

attr_names = ()


# These are the same as pycparser's, but it does *not* declare __slots__--
# so we can poke in attributes at our leisure.
class TypeDeclExt(c_ast.TypeDecl):
Expand Down Expand Up @@ -512,6 +535,11 @@ def p_struct_declaration_list_1(self, p):
""" struct_declaration_list : empty """
p[0] = None

def p_range_designator(self, p):
""" designator : LBRACKET constant_expression ELLIPSIS constant_expression RBRACKET
"""
p[0] = RangeExpression(p[2], p[4], coord=self._coord(p.lineno(1)))

# }}}


Expand Down
64 changes: 64 additions & 0 deletions test/test_pycparserext.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,53 @@
import pytest


# Inspired from pycparser's compare_asts test function
def _compare_asts(first, second):
if type(first) is not type(second):
return False

if isinstance(first, tuple):
if first[0] != second[0]:
return False

return _compare_asts(first[1], second[1])

for attr in first.attr_names:
if getattr(first, attr) != getattr(second, attr):
return False

for i, c1 in enumerate(first.children()):
if not _compare_asts(c1, second.children()[i]):
return False
return True


def _round_trip_matches(src):
from pycparserext.ext_c_parser import GnuCParser
from pycparserext.ext_c_generator import GnuCGenerator

p = GnuCParser()

first_ast = p.parse(src)

gen = GnuCGenerator().visit(first_ast)

second_ast = p.parse(gen)

if not _compare_asts(first_ast, second_ast):
print('First AST:')
first_ast.show()

print('Generated code:')
print(gen)

print('Second AST:')
second_ast.show()

return False
return True


def test_asm_volatile_1():
src = """
void read_tsc(void) {
Expand Down Expand Up @@ -374,6 +421,23 @@ def test_double_pointer():
assert gen.visit(ast).find("func_with_p2pp(const char *, Error **)") != -1


def test_designated_initializers():
src = """
int a[6] = { [4] = 29, [2] = 15 };

int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };

int v1 = 5, v2 = 6;
int b[] = { [1] = v1, v2, [4] = v4 };

struct foo { int x; int y; };
struct foo bar[10] = { [1].y = 5, [2].x = 1, [0].x = 3 };

char char_map[256] = { [0 ... 255] = '?', ['0' ... '9'] = 'X' };
"""
assert _round_trip_matches(src)


def test_node_visitor():
from pycparser.c_ast import NodeVisitor

Expand Down