Skip to content

Commit 315876a

Browse files
committed
Added typeof keyword
1 parent bb42bc8 commit 315876a

4 files changed

Lines changed: 62 additions & 10 deletions

File tree

pycparserext/ext_c_generator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,10 @@ def visit_AttributeSpecifier(self, n):
136136

137137
class GnuCGenerator(AsmAndAttributesMixin, CGeneratorBase):
138138
def visit_TypeOfDeclaration(self, n):
139-
return "__typeof__(%s)" % self.visit(n.declaration)
139+
return "%s(%s)" % (n.typeof_keyword, self.visit(n.declaration))
140140

141141
def visit_TypeOfExpression(self, n):
142-
return "__typeof__(%s)" % self.visit(n.expr)
142+
return "%s(%s)" % (n.typeof_keyword, self.visit(n.expr))
143143

144144
def visit_TypeList(self, n):
145145
return ', '.join(self.visit(ch) for ch in n.types)

pycparserext/ext_c_lexer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def add_lexer_keywords(cls, keywords):
6666
'__asm__', '__asm', 'asm']
6767

6868
_GNU_KEYWORDS = [
69-
'__typeof__',
69+
'__typeof__', 'typeof',
7070
'__real__', '__imag__',
7171
'__builtin_types_compatible_p',
7272
'__const',

pycparserext/ext_c_parser.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ def __iter__(self):
123123

124124

125125
class TypeOfDeclaration(c_ast.Node):
126-
def __init__(self, declaration, coord=None):
126+
def __init__(self, typeof_keyword, declaration, coord=None):
127+
self.typeof_keyword = typeof_keyword
127128
self.declaration = declaration
128129
self.coord = coord
129130

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

140-
attr_names = ()
141+
attr_names = ('typeof_keyword',)
141142

142143

143144
class TypeOfExpression(c_ast.Node):
144-
def __init__(self, expr, coord=None):
145+
def __init__(self, typeof_keyword, expr, coord=None):
146+
self.typeof_keyword = typeof_keyword
145147
self.expr = expr
146148
self.coord = coord
147149

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

158-
attr_names = ()
160+
attr_names = ('typeof_keyword',)
159161

160162

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

485487
def p_type_specifier_gnu_typeof_expr(self, p):
486488
""" type_specifier : __TYPEOF__ LPAREN expression RPAREN
489+
| TYPEOF LPAREN expression RPAREN
487490
"""
488491
if isinstance(p[3], c_ast.TypeDecl):
489492
pass
490493

491-
p[0] = TypeOfExpression(p[3])
494+
p[0] = TypeOfExpression(p[1], p[3])
492495

493496
def p_type_specifier_gnu_typeof_decl(self, p):
494497
""" type_specifier : __TYPEOF__ LPAREN parameter_declaration RPAREN
498+
| TYPEOF LPAREN parameter_declaration RPAREN
495499
"""
496-
p[0] = TypeOfDeclaration(p[3])
500+
p[0] = TypeOfDeclaration(p[1], p[3])
497501

498502
def p_unary_operator_gnu(self, p):
499503
""" unary_operator : __REAL__

test/test_pycparserext.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ def test_node_visitor():
476476
'Asm': [0, 1],
477477
# PreprocessorLine is OpenCL, not GNU
478478
'PreprocessorLine': [0, 0],
479-
'TypeOfDeclaration': [0, 2],
479+
'TypeOfDeclaration': [0, 4],
480480
'TypeOfExpression': [0, 1],
481481
'FuncDeclExt': [0, 1],
482482
}
@@ -514,6 +514,7 @@ def visit_FuncDeclExt(self, node):
514514
int func1(int a, int b) {
515515
__typeof__(a) _a = __builtin_types_compatible_p(long char, short int);
516516
__typeof__ (__typeof__ (char *)[4]) y;
517+
typeof (typeof (char *)[4]) z;
517518
asm("rdtsc" : "=A" (val));
518519
__attribute__((unused)) static int c;
519520
}
@@ -530,6 +531,53 @@ def visit_FuncDeclExt(self, node):
530531
assert visit_num[0] == visit_num[1], assert_msg
531532

532533

534+
def test_typeof_reproduction():
535+
src = """
536+
int func(int a, int b) {
537+
__typeof__(a) _a = a;
538+
typeof(b) _b = b;
539+
540+
__typeof__ (__typeof__ (char *)[4]) y;
541+
typeof (typeof (char *)[4]) z;
542+
}
543+
"""
544+
assert _round_trip_matches(src)
545+
546+
import pycparserext.ext_c_parser as ext_c_parser
547+
from pycparser.c_ast import NodeVisitor
548+
549+
# key is type of visit, value is
550+
# [actual # __typeof__, expected # __typeof__,
551+
# actual # typeof, expected # typeof]
552+
visits = {
553+
'TypeOfDeclaration': [0, 2, 0, 2],
554+
'TypeOfExpression': [0, 1, 0, 1],
555+
}
556+
557+
class TestVisitor(NodeVisitor):
558+
def visit_TypeOfDeclaration(self, node):
559+
idx = 0 if node.typeof_keyword == '__typeof__' else 2
560+
visits['TypeOfDeclaration'][idx] += 1
561+
NodeVisitor.generic_visit(self, node)
562+
563+
def visit_TypeOfExpression(self, node):
564+
idx = 0 if node.typeof_keyword == '__typeof__' else 2
565+
visits['TypeOfExpression'][idx] += 1
566+
NodeVisitor.generic_visit(self, node)
567+
568+
parser = ext_c_parser.GnuCParser()
569+
ast = parser.parse(src)
570+
ast.show()
571+
TestVisitor().visit(ast)
572+
for visit_type, visit_num in visits.items():
573+
assert_msg = '{}: Should have visited ({}, {}), got ({}, {})'.format(
574+
visit_type,
575+
visit_num[1], visit_num[3],
576+
visit_num[0], visit_num[2])
577+
assert visit_num[0] == visit_num[1] and \
578+
visit_num[2] == visit_num[3], assert_msg
579+
580+
533581
if __name__ == "__main__":
534582
import sys
535583
if len(sys.argv) > 1:

0 commit comments

Comments
 (0)