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
4 changes: 2 additions & 2 deletions pycparserext/ext_c_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,10 @@ def visit_AttributeSpecifier(self, n):

class GnuCGenerator(AsmAndAttributesMixin, CGeneratorBase):
def visit_TypeOfDeclaration(self, n):
return "__typeof__(%s)" % self.visit(n.declaration)
return "%s(%s)" % (n.typeof_keyword, self.visit(n.declaration))

def visit_TypeOfExpression(self, n):
return "__typeof__(%s)" % self.visit(n.expr)
return "%s(%s)" % (n.typeof_keyword, self.visit(n.expr))

def visit_TypeList(self, n):
return ', '.join(self.visit(ch) for ch in n.types)
Expand Down
2 changes: 1 addition & 1 deletion pycparserext/ext_c_lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def add_lexer_keywords(cls, keywords):
'__asm__', '__asm', 'asm']

_GNU_KEYWORDS = [
'__typeof__',
'__typeof__', 'typeof',
'__real__', '__imag__',
'__builtin_types_compatible_p',
'__const',
Expand Down
16 changes: 10 additions & 6 deletions pycparserext/ext_c_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ def __iter__(self):


class TypeOfDeclaration(c_ast.Node):
def __init__(self, declaration, coord=None):
def __init__(self, typeof_keyword, declaration, coord=None):
self.typeof_keyword = typeof_keyword
self.declaration = declaration
self.coord = coord

Expand All @@ -137,11 +138,12 @@ def __iter__(self):
if self.declaration is not None:
yield self.declaration

attr_names = ()
attr_names = ('typeof_keyword',)


class TypeOfExpression(c_ast.Node):
def __init__(self, expr, coord=None):
def __init__(self, typeof_keyword, expr, coord=None):
self.typeof_keyword = typeof_keyword
self.expr = expr
self.coord = coord

Expand All @@ -155,7 +157,7 @@ def __iter__(self):
if self.expr is not None:
yield self.expr

attr_names = ()
attr_names = ('typeof_keyword',)


class RangeExpression(c_ast.Node):
Expand Down Expand Up @@ -484,16 +486,18 @@ def p_type_qualifier_gnu(self, p):

def p_type_specifier_gnu_typeof_expr(self, p):
""" type_specifier : __TYPEOF__ LPAREN expression RPAREN
| TYPEOF LPAREN expression RPAREN
"""
if isinstance(p[3], c_ast.TypeDecl):
pass

p[0] = TypeOfExpression(p[3])
p[0] = TypeOfExpression(p[1], p[3])

def p_type_specifier_gnu_typeof_decl(self, p):
""" type_specifier : __TYPEOF__ LPAREN parameter_declaration RPAREN
| TYPEOF LPAREN parameter_declaration RPAREN
"""
p[0] = TypeOfDeclaration(p[3])
p[0] = TypeOfDeclaration(p[1], p[3])

def p_unary_operator_gnu(self, p):
""" unary_operator : __REAL__
Expand Down
50 changes: 49 additions & 1 deletion test/test_pycparserext.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ def test_node_visitor():
'Asm': [0, 1],
# PreprocessorLine is OpenCL, not GNU
'PreprocessorLine': [0, 0],
'TypeOfDeclaration': [0, 2],
'TypeOfDeclaration': [0, 4],
'TypeOfExpression': [0, 1],
'FuncDeclExt': [0, 1],
}
Expand Down Expand Up @@ -514,6 +514,7 @@ def visit_FuncDeclExt(self, node):
int func1(int a, int b) {
__typeof__(a) _a = __builtin_types_compatible_p(long char, short int);
__typeof__ (__typeof__ (char *)[4]) y;
typeof (typeof (char *)[4]) z;
asm("rdtsc" : "=A" (val));
__attribute__((unused)) static int c;
}
Expand All @@ -530,6 +531,53 @@ def visit_FuncDeclExt(self, node):
assert visit_num[0] == visit_num[1], assert_msg


def test_typeof_reproduction():
src = """
int func(int a, int b) {
__typeof__(a) _a = a;
typeof(b) _b = b;

__typeof__ (__typeof__ (char *)[4]) y;
typeof (typeof (char *)[4]) z;
}
"""
assert _round_trip_matches(src)

import pycparserext.ext_c_parser as ext_c_parser
from pycparser.c_ast import NodeVisitor

# key is type of visit, value is
# [actual # __typeof__, expected # __typeof__,
# actual # typeof, expected # typeof]
visits = {
'TypeOfDeclaration': [0, 2, 0, 2],
'TypeOfExpression': [0, 1, 0, 1],
}

class TestVisitor(NodeVisitor):
def visit_TypeOfDeclaration(self, node):
idx = 0 if node.typeof_keyword == '__typeof__' else 2
visits['TypeOfDeclaration'][idx] += 1
NodeVisitor.generic_visit(self, node)

def visit_TypeOfExpression(self, node):
idx = 0 if node.typeof_keyword == '__typeof__' else 2
visits['TypeOfExpression'][idx] += 1
NodeVisitor.generic_visit(self, node)

parser = ext_c_parser.GnuCParser()
ast = parser.parse(src)
ast.show()
TestVisitor().visit(ast)
for visit_type, visit_num in visits.items():
assert_msg = '{}: Should have visited ({}, {}), got ({}, {})'.format(
visit_type,
visit_num[1], visit_num[3],
visit_num[0], visit_num[2])
assert visit_num[0] == visit_num[1] and \
visit_num[2] == visit_num[3], assert_msg


if __name__ == "__main__":
import sys
if len(sys.argv) > 1:
Expand Down