pycparser 3.0__tar.gz → 3.11__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. {pycparser-3.0 → pycparser-3.11}/LICENSE +1 -1
  2. {pycparser-3.0/pycparser.egg-info → pycparser-3.11}/PKG-INFO +8 -8
  3. {pycparser-3.0 → pycparser-3.11}/README.rst +6 -7
  4. {pycparser-3.0 → pycparser-3.11}/examples/c-to-c.py +1 -1
  5. {pycparser-3.0 → pycparser-3.11}/examples/c_json.py +14 -16
  6. {pycparser-3.0 → pycparser-3.11}/examples/cdecl.py +10 -8
  7. {pycparser-3.0 → pycparser-3.11}/examples/construct_ast_from_scratch.py +0 -1
  8. {pycparser-3.0 → pycparser-3.11}/examples/func_defs_add_param.py +1 -1
  9. pycparser-3.11/examples/typed_usage.py +76 -0
  10. {pycparser-3.0 → pycparser-3.11}/examples/using_cpp_libc.py +0 -1
  11. {pycparser-3.0 → pycparser-3.11}/examples/using_gcc_E_libc.py +0 -1
  12. {pycparser-3.0 → pycparser-3.11}/pycparser/__init__.py +3 -4
  13. {pycparser-3.0 → pycparser-3.11}/pycparser/_ast_gen.py +18 -14
  14. {pycparser-3.0 → pycparser-3.11}/pycparser/_c_ast.cfg +19 -0
  15. {pycparser-3.0 → pycparser-3.11}/pycparser/ast_transforms.py +24 -14
  16. {pycparser-3.0 → pycparser-3.11}/pycparser/c_ast.py +71 -33
  17. {pycparser-3.0 → pycparser-3.11}/pycparser/c_generator.py +78 -41
  18. {pycparser-3.0 → pycparser-3.11}/pycparser/c_lexer.py +88 -73
  19. {pycparser-3.0 → pycparser-3.11}/pycparser/c_parser.py +246 -158
  20. {pycparser-3.0 → pycparser-3.11/pycparser.egg-info}/PKG-INFO +8 -8
  21. {pycparser-3.0 → pycparser-3.11}/pycparser.egg-info/SOURCES.txt +2 -0
  22. {pycparser-3.0 → pycparser-3.11}/pyproject.toml +3 -2
  23. {pycparser-3.0 → pycparser-3.11}/tests/c_files/c11.c +31 -2
  24. {pycparser-3.0 → pycparser-3.11}/tests/test_c_ast.py +1 -1
  25. {pycparser-3.0 → pycparser-3.11}/tests/test_c_generator.py +251 -10
  26. {pycparser-3.0 → pycparser-3.11}/tests/test_c_lexer.py +55 -8
  27. {pycparser-3.0 → pycparser-3.11}/tests/test_c_parser.py +625 -21
  28. {pycparser-3.0 → pycparser-3.11}/tests/test_examples.py +1 -1
  29. {pycparser-3.0 → pycparser-3.11}/tests/test_general.py +11 -3
  30. {pycparser-3.0 → pycparser-3.11}/tests/test_util.py +6 -2
  31. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/_fake_defines.h +2 -0
  32. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/_fake_typedefs.h +10 -0
  33. pycparser-3.11/utils/fake_libc_include/xcb/xcb.h +2 -0
  34. {pycparser-3.0 → pycparser-3.11}/MANIFEST.in +0 -0
  35. {pycparser-3.0 → pycparser-3.11}/examples/c_files/basic.c +0 -0
  36. {pycparser-3.0 → pycparser-3.11}/examples/c_files/funky.c +0 -0
  37. {pycparser-3.0 → pycparser-3.11}/examples/c_files/hash.c +0 -0
  38. {pycparser-3.0 → pycparser-3.11}/examples/c_files/memmgr.c +0 -0
  39. {pycparser-3.0 → pycparser-3.11}/examples/c_files/memmgr.h +0 -0
  40. {pycparser-3.0 → pycparser-3.11}/examples/c_files/pragmas.c +0 -0
  41. {pycparser-3.0 → pycparser-3.11}/examples/c_files/year.c +0 -0
  42. {pycparser-3.0 → pycparser-3.11}/examples/dump_ast.py +0 -0
  43. {pycparser-3.0 → pycparser-3.11}/examples/explore_ast.py +0 -0
  44. {pycparser-3.0 → pycparser-3.11}/examples/func_calls.py +0 -0
  45. {pycparser-3.0 → pycparser-3.11}/examples/func_defs.py +0 -0
  46. {pycparser-3.0 → pycparser-3.11}/examples/rewrite_ast.py +0 -0
  47. {pycparser-3.0 → pycparser-3.11}/examples/serialize_ast.py +0 -0
  48. {pycparser-3.0 → pycparser-3.11}/pycparser.egg-info/dependency_links.txt +0 -0
  49. {pycparser-3.0 → pycparser-3.11}/pycparser.egg-info/top_level.txt +0 -0
  50. {pycparser-3.0 → pycparser-3.11}/setup.cfg +0 -0
  51. {pycparser-3.0 → pycparser-3.11}/setup.py +0 -0
  52. {pycparser-3.0 → pycparser-3.11}/tests/__init__.py +0 -0
  53. {pycparser-3.0 → pycparser-3.11}/tests/c_files/cppd_with_stdio_h.c +0 -0
  54. {pycparser-3.0 → pycparser-3.11}/tests/c_files/empty.h +0 -0
  55. {pycparser-3.0 → pycparser-3.11}/tests/c_files/example_c_file.c +0 -0
  56. {pycparser-3.0 → pycparser-3.11}/tests/c_files/hdir/9/inc.h +0 -0
  57. {pycparser-3.0 → pycparser-3.11}/tests/c_files/memmgr.c +0 -0
  58. {pycparser-3.0 → pycparser-3.11}/tests/c_files/memmgr.h +0 -0
  59. {pycparser-3.0 → pycparser-3.11}/tests/c_files/memmgr_with_h.c +0 -0
  60. {pycparser-3.0 → pycparser-3.11}/tests/c_files/simplemain.c +0 -0
  61. {pycparser-3.0 → pycparser-3.11}/tests/c_files/year.c +0 -0
  62. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/X11/Intrinsic.h +0 -0
  63. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/X11/Xlib.h +0 -0
  64. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/X11/_X11_fake_defines.h +0 -0
  65. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/X11/_X11_fake_typedefs.h +0 -0
  66. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/_ansi.h +0 -0
  67. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/_syslist.h +0 -0
  68. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/aio.h +0 -0
  69. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/alloca.h +0 -0
  70. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/ar.h +0 -0
  71. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/argz.h +0 -0
  72. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/arpa/inet.h +0 -0
  73. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/asm-generic/int-ll64.h +0 -0
  74. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/assert.h +0 -0
  75. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/complex.h +0 -0
  76. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/cpio.h +0 -0
  77. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/ctype.h +0 -0
  78. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/dirent.h +0 -0
  79. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/dlfcn.h +0 -0
  80. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/emmintrin.h +0 -0
  81. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/endian.h +0 -0
  82. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/envz.h +0 -0
  83. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/errno.h +0 -0
  84. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/fastmath.h +0 -0
  85. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/fcntl.h +0 -0
  86. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/features.h +0 -0
  87. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/fenv.h +0 -0
  88. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/float.h +0 -0
  89. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/fmtmsg.h +0 -0
  90. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/fnmatch.h +0 -0
  91. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/ftw.h +0 -0
  92. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/getopt.h +0 -0
  93. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/glob.h +0 -0
  94. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/grp.h +0 -0
  95. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/iconv.h +0 -0
  96. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/ieeefp.h +0 -0
  97. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/immintrin.h +0 -0
  98. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/inttypes.h +0 -0
  99. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/iso646.h +0 -0
  100. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/langinfo.h +0 -0
  101. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/libgen.h +0 -0
  102. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/libintl.h +0 -0
  103. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/limits.h +0 -0
  104. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/linux/socket.h +0 -0
  105. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/linux/version.h +0 -0
  106. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/locale.h +0 -0
  107. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/malloc.h +0 -0
  108. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/math.h +0 -0
  109. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/mir_toolkit/client_types.h +0 -0
  110. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/monetary.h +0 -0
  111. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/mqueue.h +0 -0
  112. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/ndbm.h +0 -0
  113. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/net/if.h +0 -0
  114. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/netdb.h +0 -0
  115. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/netinet/in.h +0 -0
  116. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/netinet/tcp.h +0 -0
  117. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/newlib.h +0 -0
  118. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/nl_types.h +0 -0
  119. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/openssl/err.h +0 -0
  120. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/openssl/evp.h +0 -0
  121. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/openssl/hmac.h +0 -0
  122. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/openssl/ssl.h +0 -0
  123. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/openssl/x509v3.h +0 -0
  124. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/paths.h +0 -0
  125. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/poll.h +0 -0
  126. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/process.h +0 -0
  127. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/pthread.h +0 -0
  128. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/pwd.h +0 -0
  129. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/reent.h +0 -0
  130. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/regdef.h +0 -0
  131. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/regex.h +0 -0
  132. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sched.h +0 -0
  133. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/search.h +0 -0
  134. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/semaphore.h +0 -0
  135. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/setjmp.h +0 -0
  136. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/signal.h +0 -0
  137. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/smmintrin.h +0 -0
  138. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/spawn.h +0 -0
  139. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdalign.h +0 -0
  140. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdarg.h +0 -0
  141. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdatomic.h +0 -0
  142. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdbool.h +0 -0
  143. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stddef.h +0 -0
  144. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdint.h +0 -0
  145. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdio.h +0 -0
  146. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdlib.h +0 -0
  147. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdnoreturn.h +0 -0
  148. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/string.h +0 -0
  149. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/strings.h +0 -0
  150. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stropts.h +0 -0
  151. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/ioctl.h +0 -0
  152. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/ipc.h +0 -0
  153. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/mman.h +0 -0
  154. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/msg.h +0 -0
  155. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/poll.h +0 -0
  156. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/resource.h +0 -0
  157. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/select.h +0 -0
  158. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/sem.h +0 -0
  159. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/shm.h +0 -0
  160. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/socket.h +0 -0
  161. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/stat.h +0 -0
  162. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/statvfs.h +0 -0
  163. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/sysctl.h +0 -0
  164. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/time.h +0 -0
  165. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/times.h +0 -0
  166. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/types.h +0 -0
  167. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/uio.h +0 -0
  168. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/un.h +0 -0
  169. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/utsname.h +0 -0
  170. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/wait.h +0 -0
  171. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/syslog.h +0 -0
  172. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/tar.h +0 -0
  173. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/termios.h +0 -0
  174. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/tgmath.h +0 -0
  175. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/threads.h +0 -0
  176. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/time.h +0 -0
  177. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/trace.h +0 -0
  178. /pycparser-3.0/utils/fake_libc_include/ulimit.h → /pycparser-3.11/utils/fake_libc_include/uchar.h +0 -0
  179. /pycparser-3.0/utils/fake_libc_include/unctrl.h → /pycparser-3.11/utils/fake_libc_include/ulimit.h +0 -0
  180. /pycparser-3.0/utils/fake_libc_include/unistd.h → /pycparser-3.11/utils/fake_libc_include/unctrl.h +0 -0
  181. /pycparser-3.0/utils/fake_libc_include/utime.h → /pycparser-3.11/utils/fake_libc_include/unistd.h +0 -0
  182. /pycparser-3.0/utils/fake_libc_include/utmp.h → /pycparser-3.11/utils/fake_libc_include/utime.h +0 -0
  183. /pycparser-3.0/utils/fake_libc_include/utmpx.h → /pycparser-3.11/utils/fake_libc_include/utmp.h +0 -0
  184. /pycparser-3.0/utils/fake_libc_include/wchar.h → /pycparser-3.11/utils/fake_libc_include/utmpx.h +0 -0
  185. /pycparser-3.0/utils/fake_libc_include/wctype.h → /pycparser-3.11/utils/fake_libc_include/wchar.h +0 -0
  186. /pycparser-3.0/utils/fake_libc_include/wordexp.h → /pycparser-3.11/utils/fake_libc_include/wctype.h +0 -0
  187. /pycparser-3.0/utils/fake_libc_include/xcb/xcb.h → /pycparser-3.11/utils/fake_libc_include/wordexp.h +0 -0
  188. {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/zlib.h +0 -0
@@ -1,6 +1,6 @@
1
1
  pycparser -- A C parser in Python
2
2
 
3
- Copyright (c) 2008-2022, Eli Bendersky
3
+ Copyright (c) 2008-2027, Eli Bendersky
4
4
  All rights reserved.
5
5
 
6
6
  Redistribution and use in source and binary forms, with or without modification,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycparser
3
- Version: 3.0
3
+ Version: 3.11
4
4
  Summary: C parser in Python
5
5
  Author-email: Eli Bendersky <eliben@gmail.com>
6
6
  Maintainer-email: Eli Bendersky <eliben@gmail.com>
@@ -13,14 +13,15 @@ Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: Programming Language :: Python :: 3.13
15
15
  Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Programming Language :: Python :: 3.15
16
17
  Requires-Python: >=3.10
17
18
  Description-Content-Type: text/x-rst
18
19
  License-File: LICENSE
19
20
  Dynamic: license-file
20
21
 
21
- ===============
22
- pycparser v3.00
23
- ===============
22
+ =========
23
+ pycparser
24
+ =========
24
25
 
25
26
 
26
27
  .. image:: https://github.com/eliben/pycparser/workflows/pycparser-tests/badge.svg
@@ -86,7 +87,7 @@ standard (ISO/IEC 9899).
86
87
  How is pycparser licensed?
87
88
  --------------------------
88
89
 
89
- `BSD license <https://github.com/eliben/pycparser/blob/master/LICENSE>`_.
90
+ `BSD license <https://github.com/eliben/pycparser/blob/main/LICENSE>`_.
90
91
 
91
92
  Contact details
92
93
  ---------------
@@ -191,9 +192,8 @@ There are a few points to keep in mind when modifying **pycparser**:
191
192
 
192
193
  * The code for **pycparser**'s AST nodes is automatically generated from a
193
194
  configuration file - ``_c_ast.cfg``, by ``_ast_gen.py``. If you modify the AST
194
- configuration, make sure to re-generate the code. This can be done by running
195
- the ``_ast_gen.py`` script (from the repository root or the
196
- ``pycparser`` directory).
195
+ configuration or the generator, run ``make regen-ast`` from the repository
196
+ root to re-generate ``pycparser/c_ast.py`` and run ``make format``.
197
197
  * Read the docstring in the constructor of the ``CParser`` class for details
198
198
  on configuration and compatibility arguments.
199
199
 
@@ -1,6 +1,6 @@
1
- ===============
2
- pycparser v3.00
3
- ===============
1
+ =========
2
+ pycparser
3
+ =========
4
4
 
5
5
 
6
6
  .. image:: https://github.com/eliben/pycparser/workflows/pycparser-tests/badge.svg
@@ -66,7 +66,7 @@ standard (ISO/IEC 9899).
66
66
  How is pycparser licensed?
67
67
  --------------------------
68
68
 
69
- `BSD license <https://github.com/eliben/pycparser/blob/master/LICENSE>`_.
69
+ `BSD license <https://github.com/eliben/pycparser/blob/main/LICENSE>`_.
70
70
 
71
71
  Contact details
72
72
  ---------------
@@ -171,9 +171,8 @@ There are a few points to keep in mind when modifying **pycparser**:
171
171
 
172
172
  * The code for **pycparser**'s AST nodes is automatically generated from a
173
173
  configuration file - ``_c_ast.cfg``, by ``_ast_gen.py``. If you modify the AST
174
- configuration, make sure to re-generate the code. This can be done by running
175
- the ``_ast_gen.py`` script (from the repository root or the
176
- ``pycparser`` directory).
174
+ configuration or the generator, run ``make regen-ast`` from the repository
175
+ root to re-generate ``pycparser/c_ast.py`` and run ``make format``.
177
176
  * Read the docstring in the constructor of the ``CParser`` class for details
178
177
  on configuration and compatibility arguments.
179
178
 
@@ -13,7 +13,7 @@ import sys
13
13
  # your site-packages/ with setup.py
14
14
  sys.path.extend([".", ".."])
15
15
 
16
- from pycparser import parse_file, c_generator
16
+ from pycparser import c_generator, parse_file
17
17
 
18
18
 
19
19
  def translate_to_c(filename: str) -> None:
@@ -35,18 +35,18 @@
35
35
  # }
36
36
  # ------------------------------------------------------------------------------
37
37
  import json
38
- import sys
39
38
  import re
40
- from typing import Any, Callable, Dict, Optional, Set, TypeVar
39
+ import sys
40
+ from collections.abc import Callable
41
+ from typing import Any, TypeVar
41
42
 
42
43
  # This is not required if you've installed pycparser into
43
44
  # your site-packages/ with setup.py
44
45
  sys.path.extend([".", ".."])
45
46
 
46
- from pycparser import parse_file, c_ast
47
+ from pycparser import c_ast, parse_file
47
48
  from pycparser.c_parser import Coord
48
49
 
49
-
50
50
  RE_CHILD_ARRAY = re.compile(r"(.*)\[(.*)\]")
51
51
  RE_INTERNAL_ATTR = re.compile("__.*__")
52
52
 
@@ -61,7 +61,7 @@ _R = TypeVar("_R")
61
61
 
62
62
  def memodict(fn: Callable[[_T], _R]) -> Callable[[_T], _R]:
63
63
  """Fast memoization decorator for a function taking a single argument"""
64
- cache: Dict[_T, _R] = {}
64
+ cache: dict[_T, _R] = {}
65
65
 
66
66
  def memoized(arg: _T) -> _R:
67
67
  if arg in cache:
@@ -74,22 +74,22 @@ def memodict(fn: Callable[[_T], _R]) -> Callable[[_T], _R]:
74
74
 
75
75
 
76
76
  @memodict
77
- def child_attrs_of(klass: type[c_ast.Node]) -> Set[str]:
77
+ def child_attrs_of(klass: type[c_ast.Node]) -> set[str]:
78
78
  """
79
79
  Given a Node class, get a set of child attrs.
80
80
  Memoized to avoid highly repetitive string manipulation
81
81
 
82
82
  """
83
83
  non_child_attrs = set(klass.attr_names)
84
- all_attrs = set([i for i in klass.__slots__ if not RE_INTERNAL_ATTR.match(i)])
84
+ all_attrs: set[str] = {i for i in klass.__slots__ if not RE_INTERNAL_ATTR.match(i)}
85
85
  return all_attrs - non_child_attrs
86
86
 
87
87
 
88
- def to_dict(node: c_ast.Node) -> Dict[str, Any]:
88
+ def to_dict(node: c_ast.Node) -> dict[str, Any]:
89
89
  """Recursively convert an ast into dict representation."""
90
90
  klass = node.__class__
91
91
 
92
- result: Dict[str, Any] = {}
92
+ result: dict[str, Any] = {}
93
93
 
94
94
  # Metadata
95
95
  result["_nodetype"] = klass.__name__
@@ -115,10 +115,8 @@ def to_dict(node: c_ast.Node) -> Dict[str, Any]:
115
115
  result[array_name] = result.get(array_name, [])
116
116
  if array_index != len(result[array_name]):
117
117
  raise CJsonError(
118
- "Internal ast error. Array {} out of order. "
119
- "Expected index {}, got {}".format(
120
- array_name, len(result[array_name]), array_index
121
- )
118
+ f"Internal ast error. Array {array_name} out of order. "
119
+ f"Expected index {len(result[array_name])}, got {array_index}"
122
120
  )
123
121
  result[array_name].append(to_dict(child))
124
122
  else:
@@ -137,7 +135,7 @@ def to_json(node: c_ast.Node, **kwargs: Any) -> str:
137
135
  return json.dumps(to_dict(node), **kwargs)
138
136
 
139
137
 
140
- def file_to_dict(filename: str) -> Dict[str, Any]:
138
+ def file_to_dict(filename: str) -> dict[str, Any]:
141
139
  """Load C file into dict representation of ast"""
142
140
  ast = parse_file(filename, use_cpp=True)
143
141
  return to_dict(ast)
@@ -149,7 +147,7 @@ def file_to_json(filename: str, **kwargs: Any) -> str:
149
147
  return to_json(ast, **kwargs)
150
148
 
151
149
 
152
- def _parse_coord(coord_str: Optional[str]) -> Optional[Coord]:
150
+ def _parse_coord(coord_str: str | None) -> Coord | None:
153
151
  """Parse coord string (file:line[:column]) into Coord object."""
154
152
  if coord_str is None:
155
153
  return None
@@ -178,7 +176,7 @@ def _convert_to_obj(value: Any) -> Any:
178
176
  return value
179
177
 
180
178
 
181
- def from_dict(node_dict: Dict[str, Any]) -> c_ast.Node:
179
+ def from_dict(node_dict: dict[str, Any]) -> c_ast.Node:
182
180
  """Recursively build an ast from dict representation"""
183
181
  class_name = node_dict.pop("_nodetype")
184
182
 
@@ -34,13 +34,12 @@
34
34
  # -----------------------------------------------------------------
35
35
  import copy
36
36
  import sys
37
- from typing import Optional
38
37
 
39
38
  # This is not required if you've installed pycparser into
40
39
  # your site-packages/ with setup.py
41
40
  sys.path.extend([".", ".."])
42
41
 
43
- from pycparser import c_parser, c_ast
42
+ from pycparser import c_ast, c_parser
44
43
 
45
44
 
46
45
  def explain_c_declaration(
@@ -73,7 +72,7 @@ def explain_c_declaration(
73
72
  expand_struct=expand_struct,
74
73
  expand_typedef=expand_typedef,
75
74
  )
76
- except Exception as e:
75
+ except RuntimeError as e:
77
76
  return "Not a valid declaration: " + str(e)
78
77
 
79
78
  return _explain_decl_node(expanded)
@@ -174,16 +173,19 @@ def _expand_in_place(
174
173
  return decl
175
174
 
176
175
 
177
- def _find_struct(name: str, file_ast: c_ast.FileAST) -> Optional[c_ast.Struct]:
176
+ def _find_struct(name: str, file_ast: c_ast.FileAST) -> c_ast.Struct | None:
178
177
  """Receives a struct name and return declared struct object in file_ast"""
179
178
  for node in file_ast.ext:
180
- if isinstance(node, c_ast.Decl) and isinstance(node.type, c_ast.Struct):
181
- if node.type.name == name:
182
- return node.type
179
+ if (
180
+ isinstance(node, c_ast.Decl)
181
+ and isinstance(node.type, c_ast.Struct)
182
+ and node.type.name == name
183
+ ):
184
+ return node.type
183
185
  return None
184
186
 
185
187
 
186
- def _find_typedef(name: str, file_ast: c_ast.FileAST) -> Optional[c_ast.Typedef]:
188
+ def _find_typedef(name: str, file_ast: c_ast.FileAST) -> c_ast.Typedef | None:
187
189
  """Receives a type name and return typedef object in file_ast"""
188
190
  for node in file_ast.ext:
189
191
  if isinstance(node, c_ast.Typedef) and node.name == name:
@@ -14,7 +14,6 @@ sys.path.extend([".", ".."])
14
14
 
15
15
  from pycparser import c_ast, c_generator
16
16
 
17
-
18
17
  # target C code:
19
18
  # int main() {
20
19
  # return 0;
@@ -11,7 +11,7 @@ import sys
11
11
 
12
12
  sys.path.extend([".", ".."])
13
13
 
14
- from pycparser import c_parser, c_ast, c_generator
14
+ from pycparser import c_ast, c_generator, c_parser
15
15
 
16
16
  text = r"""
17
17
  void foo(int a, int b) {
@@ -0,0 +1,76 @@
1
+ # ------------------------------------------------------------------------------
2
+ # pycparser: typed_usage.py
3
+ #
4
+ # A minimal example of how static type checking helps use pycparser correctly.
5
+ #
6
+ # The important parts are the narrowings:
7
+ # - ast.ext[...] entries start out as generic AST nodes
8
+ # - Decl.coord is optional and must be checked before use
9
+ # - Decl.type must be narrowed before accessing node-specific attributes
10
+ #
11
+ # Run it from the root directory of pycparser.
12
+ # ------------------------------------------------------------------------------
13
+ import sys
14
+
15
+ # This is not required if you've installed pycparser into
16
+ # your site-packages/ with setup.py
17
+ sys.path.extend([".", ".."])
18
+
19
+ from pycparser import c_ast, c_parser
20
+
21
+ SAMPLE_DECL = "const unsigned int *value;"
22
+
23
+
24
+ def parse_single_decl(source: str) -> c_ast.Decl:
25
+ ast = c_parser.CParser().parse(source, filename="<stdin>")
26
+ node = ast.ext[-1]
27
+
28
+ # Without this guard, type checkers only know that ext entries are Nodes.
29
+ if not isinstance(node, c_ast.Decl):
30
+ raise TypeError("expected a declaration")
31
+
32
+ return node
33
+
34
+
35
+ def require_coord(node: c_ast.Node) -> c_parser.Coord:
36
+ coord = node.coord
37
+
38
+ # Without this guard, `coord.line` is a type error because coord may be None.
39
+ if coord is None:
40
+ raise ValueError("node has no source coordinate")
41
+
42
+ return coord
43
+
44
+
45
+ def describe_type(type_node: c_ast.Node) -> str:
46
+ # Without these isinstance checks, attributes such as `.type`, `.quals`,
47
+ # and `.names` are not safe to access.
48
+ if isinstance(type_node, c_ast.TypeDecl):
49
+ quals = " ".join(type_node.quals)
50
+ base = describe_type(type_node.type)
51
+ return f"{quals} {base}".strip()
52
+
53
+ if isinstance(type_node, c_ast.PtrDecl):
54
+ quals = " ".join(type_node.quals)
55
+ pointer = "pointer"
56
+ if quals:
57
+ pointer = f"{quals} {pointer}"
58
+ return f"{pointer} to {describe_type(type_node.type)}"
59
+
60
+ if isinstance(type_node, c_ast.IdentifierType):
61
+ return " ".join(type_node.names)
62
+
63
+ raise TypeError(f"unsupported declaration type: {type_node.__class__.__name__}")
64
+
65
+
66
+ def show_decl(source: str) -> None:
67
+ decl = parse_single_decl(source)
68
+ coord = require_coord(decl)
69
+ print(f"{decl.name}: {describe_type(decl.type)} at {coord}")
70
+
71
+
72
+ if __name__ == "__main__":
73
+ if len(sys.argv) > 1:
74
+ show_decl(sys.argv[1])
75
+ else:
76
+ show_decl(SAMPLE_DECL)
@@ -15,7 +15,6 @@ sys.path.extend([".", ".."])
15
15
 
16
16
  from pycparser import parse_file
17
17
 
18
-
19
18
  if __name__ == "__main__":
20
19
  if len(sys.argv) > 1:
21
20
  filename = sys.argv[1]
@@ -16,7 +16,6 @@ sys.path.extend([".", ".."])
16
16
 
17
17
  from pycparser import parse_file
18
18
 
19
-
20
19
  if __name__ == "__main__":
21
20
  if len(sys.argv) > 1:
22
21
  filename = sys.argv[1]
@@ -7,10 +7,9 @@
7
7
  # Eli Bendersky [https://eli.thegreenplace.net/]
8
8
  # License: BSD
9
9
  # -----------------------------------------------------------------
10
- __all__ = ["c_lexer", "c_parser", "c_ast"]
11
- __version__ = "3.00"
10
+ __all__ = ["c_ast", "c_lexer", "c_parser"]
11
+ __version__ = "3.11"
12
12
 
13
- import io
14
13
  from subprocess import check_output
15
14
 
16
15
  from . import c_parser
@@ -91,7 +90,7 @@ def parse_file(
91
90
  if use_cpp:
92
91
  text = preprocess_file(filename, cpp_path, cpp_args)
93
92
  else:
94
- with io.open(filename, encoding=encoding) as f:
93
+ with open(filename, encoding=encoding) as f:
95
94
  text = f.read()
96
95
 
97
96
  if parser is None:
@@ -2,10 +2,10 @@
2
2
  # _ast_gen.py
3
3
  #
4
4
  # Generates the AST Node classes from a specification given in
5
- # a configuration file. This module can also be run as a script to
6
- # regenerate c_ast.py from _c_ast.cfg (from the repo root or the
7
- # pycparser/ directory). Use 'make check' to reformat the generated
8
- # file after running this script.
5
+ # a configuration file. Run 'make regen-ast' from the repository root
6
+ # to regenerate c_ast.py from _c_ast.cfg and format the code.
7
+ # This module can also be run as a script (from the repo root or the
8
+ # pycparser/ directory); then run 'make format' from the repo root.
9
9
  #
10
10
  # The design of this module was inspired by astgen.py from the
11
11
  # Python 2.5 code-base.
@@ -13,8 +13,8 @@
13
13
  # Eli Bendersky [https://eli.thegreenplace.net/]
14
14
  # License: BSD
15
15
  # -----------------------------------------------------------------
16
- from string import Template
17
16
  import os
17
+ from string import Template
18
18
  from typing import IO
19
19
 
20
20
 
@@ -105,6 +105,8 @@ class NodeCfg:
105
105
  slots = "'coord', '__weakref__'"
106
106
  arglist = "(self, coord=None)"
107
107
 
108
+ # Keep coord and __weakref__ last: Node.__repr__ relies on their
109
+ # positions when iterating over the node's fields.
108
110
  src += f" __slots__ = ({slots})\n"
109
111
  src += f" def __init__{arglist}:\n"
110
112
 
@@ -142,8 +144,7 @@ class NodeCfg:
142
144
  src += f" yield self.{child}\n"
143
145
 
144
146
  for seq_child in self.seq_child:
145
- src += f" for child in (self.{seq_child} or []):\n"
146
- src += " yield child\n"
147
+ src += f" yield from self.{seq_child} or []\n"
147
148
 
148
149
  if not (self.child or self.seq_child):
149
150
  # Empty generator
@@ -164,9 +165,12 @@ _PROLOGUE_COMMENT = r"""#-------------------------------------------------------
164
165
  # This code was automatically generated from _c_ast.cfg
165
166
  #
166
167
  # Do not modify it directly. Modify the configuration file and
167
- # run the generator again.
168
+ # run 'make regen-ast' from the repository root to regenerate and format it.
168
169
  # ** ** *** ** **
169
170
  #
171
+ # The order of generated __slots__ is significant to Node.__repr__.
172
+ # ruff: noqa: RUF023
173
+ #
170
174
  # pycparser: c_ast.py
171
175
  #
172
176
  # AST Node classes.
@@ -178,14 +182,15 @@ _PROLOGUE_COMMENT = r"""#-------------------------------------------------------
178
182
  """
179
183
  _PROLOGUE_CODE = r'''
180
184
  import sys
181
- from typing import Any, ClassVar, IO, Optional
185
+ from typing import IO, Any, ClassVar
186
+
182
187
 
183
188
  def _repr(obj):
184
189
  """
185
190
  Get the representation of an object, with dedicated pprint-like format for lists.
186
191
  """
187
192
  if isinstance(obj, list):
188
- return '[' + (',\n '.join((_repr(e).replace('\n', '\n ') for e in obj))) + '\n]'
193
+ return '[' + (',\n '.join(_repr(e).replace('\n', '\n ') for e in obj)) + '\n]'
189
194
  else:
190
195
  return repr(obj)
191
196
 
@@ -194,7 +199,7 @@ class Node:
194
199
  """ Abstract base class for AST nodes.
195
200
  """
196
201
  attr_names: ClassVar[tuple[str, ...]] = ()
197
- coord: Optional[Any]
202
+ coord: Any | None
198
203
  def __repr__(self):
199
204
  """ Generates a python representation of the current node
200
205
  """
@@ -217,7 +222,6 @@ class Node:
217
222
  def children(self):
218
223
  """ A sequence of all children that are Nodes
219
224
  """
220
- pass
221
225
 
222
226
  def show(
223
227
  self,
@@ -227,7 +231,7 @@ class Node:
227
231
  showemptyattrs: bool = True,
228
232
  nodenames: bool = False,
229
233
  showcoord: bool = False,
230
- _my_node_name: Optional[str] = None,
234
+ _my_node_name: str | None = None,
231
235
  ):
232
236
  """ Pretty print the Node and all its attributes and
233
237
  children (recursively) to a buffer.
@@ -261,7 +265,7 @@ class Node:
261
265
 
262
266
  if self.attr_names:
263
267
  def is_empty(v):
264
- v is None or (hasattr(v, '__len__') and len(v) == 0)
268
+ return v is None or (hasattr(v, '__len__') and len(v) == 0)
265
269
  nvlist = [(n, getattr(self,n)) for n in self.attr_names \
266
270
  if showemptyattrs or not is_empty(getattr(self,n))]
267
271
  if attrnames:
@@ -2,6 +2,8 @@
2
2
  # pycparser: _c_ast.cfg
3
3
  #
4
4
  # Defines the AST Node classes used in pycparser.
5
+ # After editing, run 'make regen-ast' from the repository root to
6
+ # regenerate pycparser/c_ast.py and format the code.
5
7
  #
6
8
  # Each entry is a Node sub-class name, listing the attributes
7
9
  # and child nodes of the class:
@@ -48,6 +50,8 @@ Compound: [block_items**]
48
50
  CompoundLiteral: [type*, init*]
49
51
 
50
52
  # type: int, char, float, string, etc.
53
+ # value: source spelling. A string may retain adjacent quoted fragments to
54
+ # preserve escape boundaries, e.g. "\x1" "a".
51
55
  #
52
56
  Constant: [type, value]
53
57
 
@@ -123,6 +127,18 @@ FuncDecl: [args*, type*]
123
127
  #
124
128
  FuncDef: [decl*, param_decls**, body*]
125
129
 
130
+ # One association in a C11 generic selection.
131
+ # type: Typename, or None for the default association
132
+ # expr: the result expression for this association
133
+ #
134
+ GenericAssociation: [type*, expr*]
135
+
136
+ # A C11 _Generic expression. All associations are preserved in source order.
137
+ # expr: the controlling expression (not evaluated by C)
138
+ # associations: a nonempty sequence of GenericAssociation nodes
139
+ #
140
+ GenericSelection: [expr*, associations**]
141
+
126
142
  Goto: [name]
127
143
 
128
144
  ID: [name]
@@ -154,6 +170,9 @@ PtrDecl: [quals, type*]
154
170
 
155
171
  Return: [expr*]
156
172
 
173
+ # A static assertion declaration. The condition is preserved without evaluation.
174
+ # message: a string Constant, or None for the message-less extension
175
+ #
157
176
  StaticAssert: [cond*, message*]
158
177
 
159
178
  # name: struct tag name
@@ -7,7 +7,8 @@
7
7
  # License: BSD
8
8
  # ------------------------------------------------------------------------------
9
9
 
10
- from typing import Any, List, Tuple, cast
10
+ from copy import deepcopy
11
+ from typing import Any, cast
11
12
 
12
13
  from . import c_ast
13
14
 
@@ -99,7 +100,7 @@ def fix_switch_cases(switch_node: c_ast.Switch) -> c_ast.Switch:
99
100
 
100
101
 
101
102
  def _extract_nested_case(
102
- case_node: c_ast.Case | c_ast.Default, stmts_list: List[c_ast.Node]
103
+ case_node: c_ast.Case | c_ast.Default, stmts_list: list[c_ast.Node]
103
104
  ) -> None:
104
105
  """Recursively extract consecutive Case statements that are made nested
105
106
  by the parser and add them to the stmts_list.
@@ -111,8 +112,8 @@ def _extract_nested_case(
111
112
 
112
113
 
113
114
  def fix_atomic_specifiers(
114
- decl: c_ast.Decl | c_ast.Typedef,
115
- ) -> c_ast.Decl | c_ast.Typedef:
115
+ decl: c_ast.Decl | c_ast.Typedef | c_ast.Typename,
116
+ ) -> c_ast.Decl | c_ast.Typedef | c_ast.Typename:
116
117
  """Atomic specifiers like _Atomic(type) are unusually structured,
117
118
  conferring a qualifier upon the contained type.
118
119
 
@@ -127,17 +128,16 @@ def fix_atomic_specifiers(
127
128
  if not found:
128
129
  break
129
130
 
130
- # Make sure to add an _Atomic qual on the topmost decl if needed. Also
131
- # restore the declname on the innermost TypeDecl (it gets placed in the
132
- # wrong place during construction).
131
+ # Match the declaration's qualifiers to the innermost TypeDecl, as for
132
+ # ordinary declarations. Qualifiers moved onto pointers belong only on
133
+ # those PtrDecl nodes. Also restore the name lost with the wrapper TypeDecl.
133
134
  typ: Any = decl
134
135
  while not isinstance(typ, c_ast.TypeDecl):
135
136
  try:
136
137
  typ = typ.type
137
138
  except AttributeError:
138
139
  return decl
139
- if "_Atomic" in typ.quals and "_Atomic" not in decl.quals:
140
- decl.quals.append("_Atomic")
140
+ decl.quals = typ.quals[:]
141
141
  if typ.declname is None:
142
142
  typ.declname = decl.name
143
143
 
@@ -145,8 +145,8 @@ def fix_atomic_specifiers(
145
145
 
146
146
 
147
147
  def _fix_atomic_specifiers_once(
148
- decl: c_ast.Decl | c_ast.Typedef,
149
- ) -> Tuple[c_ast.Decl | c_ast.Typedef, bool]:
148
+ decl: c_ast.Decl | c_ast.Typedef | c_ast.Typename,
149
+ ) -> tuple[c_ast.Decl | c_ast.Typedef | c_ast.Typename, bool]:
150
150
  """Performs one 'fix' round of atomic specifiers.
151
151
  Returns (modified_decl, found) where found is True iff a fix was made.
152
152
  """
@@ -168,7 +168,17 @@ def _fix_atomic_specifiers_once(
168
168
 
169
169
  assert isinstance(parent, c_ast.TypeDecl)
170
170
  assert grandparent is not None
171
- cast(Any, grandparent).type = node.type
172
- if "_Atomic" not in node.type.quals:
173
- node.type.quals.append("_Atomic")
171
+ # Declaration specifiers are shared by comma-separated declarators. Copy
172
+ # the contained type before attaching qualifiers, coordinates, and a name.
173
+ typ = deepcopy(node.type)
174
+ if typ.coord is None:
175
+ # Preserve the declarator coord for _Atomic(T) so TypeDecl doesn't lose
176
+ # its location when we replace the wrapper Typename.
177
+ typ.coord = parent.coord
178
+ # Qualifiers outside _Atomic(T) apply to T itself. In particular, const in
179
+ # const _Atomic(int *) qualifies the pointer, not the pointed-to int.
180
+ typ.quals = parent.quals + typ.quals
181
+ if "_Atomic" not in typ.quals:
182
+ typ.quals.append("_Atomic")
183
+ cast(Any, grandparent).type = typ
174
184
  return decl, True