Skip to content

Commit

Permalink
Feature/add pragma support (#487)
Browse files Browse the repository at this point in the history
* Support _Pragma, a C99 alternative to #pragma

See https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html

* Test cases for _Pragma

* Add explanatory comment for _PRAGMA and PPPRAGMA
  • Loading branch information
jordr authored Jan 8, 2023
1 parent 5382e31 commit 4e16079
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 4 deletions.
1 change: 1 addition & 0 deletions pycparser/c_lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ def _make_tok_location(self, token):
'_BOOL', '_COMPLEX',
'_NORETURN', '_THREAD_LOCAL', '_STATIC_ASSERT',
'_ATOMIC', '_ALIGNOF', '_ALIGNAS',
'_PRAGMA',
)

keyword_map = {}
Expand Down
10 changes: 9 additions & 1 deletion pycparser/c_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -571,11 +571,19 @@ def p_pp_directive(self, p):
self._parse_error('Directives not supported yet',
self._token_coord(p, 1))

# This encompasses two types of C99-compatible pragmas:
# - The #pragma directive:
# # pragma character_sequence
# - The _Pragma unary operator:
# _Pragma ( " string_literal " )
def p_pppragma_directive(self, p):
""" pppragma_directive : PPPRAGMA
| PPPRAGMA PPPRAGMASTR
| _PRAGMA LPAREN unified_string_literal RPAREN
"""
if len(p) == 3:
if len(p) == 5:
p[0] = c_ast.Pragma(p[3], self._token_coord(p, 2))
elif len(p) == 3:
p[0] = c_ast.Pragma(p[2], self._token_coord(p, 2))
else:
p[0] = c_ast.Pragma("", self._token_coord(p, 1))
Expand Down
17 changes: 14 additions & 3 deletions tests/test_c_lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ def test_preprocessor_pragma(self):
#pragma "string"
#pragma somestring="some_other_string"
#pragma id 124124 and numbers 0235495
_Pragma("something else")
59
'''
# Check that pragmas are tokenized, including trailing string
Expand Down Expand Up @@ -389,9 +390,19 @@ def test_preprocessor_pragma(self):
tb = self.clex.token()
self.assertEqual(tb.type, 'PPPRAGMASTR')

t6 = self.clex.token()
self.assertEqual(t6.type, 'INT_CONST_DEC')
self.assertEqual(t6.lineno, 12)
t6a = self.clex.token()
t6l = self.clex.token()
t6b = self.clex.token()
t6r = self.clex.token()
self.assertEqual(t6a.type, '_PRAGMA')
self.assertEqual(t6l.type, 'LPAREN')
self.assertEqual(t6b.type, 'STRING_LITERAL')
self.assertEqual(t6b.value, '"something else"')
self.assertEqual(t6r.type, 'RPAREN')

t7 = self.clex.token()
self.assertEqual(t7.type, 'INT_CONST_DEC')
self.assertEqual(t7.lineno, 13)



Expand Down
5 changes: 5 additions & 0 deletions tests/test_c_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1736,6 +1736,7 @@ def test_pragma(self):
struct s {
#pragma baz
} s;
_Pragma("other \"string\"")
'''
s1_ast = self.parse(s1)
self.assertIsInstance(s1_ast.ext[0], Pragma)
Expand All @@ -1758,6 +1759,10 @@ def test_pragma(self):
self.assertEqual(s1_ast.ext[2].type.type.decls[0].string, 'baz')
self.assertEqual(s1_ast.ext[2].type.type.decls[0].coord.line, 13)

self.assertIsInstance(s1_ast.ext[3], Pragma)
self.assertEqual(s1_ast.ext[3].string.value, r'"other \"string\""')
self.assertEqual(s1_ast.ext[3].coord.line, 15)

def test_pragmacomp_or_statement(self):
s1 = r'''
void main() {
Expand Down

0 comments on commit 4e16079

Please sign in to comment.