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.
- {pycparser-3.0 → pycparser-3.11}/LICENSE +1 -1
- {pycparser-3.0/pycparser.egg-info → pycparser-3.11}/PKG-INFO +8 -8
- {pycparser-3.0 → pycparser-3.11}/README.rst +6 -7
- {pycparser-3.0 → pycparser-3.11}/examples/c-to-c.py +1 -1
- {pycparser-3.0 → pycparser-3.11}/examples/c_json.py +14 -16
- {pycparser-3.0 → pycparser-3.11}/examples/cdecl.py +10 -8
- {pycparser-3.0 → pycparser-3.11}/examples/construct_ast_from_scratch.py +0 -1
- {pycparser-3.0 → pycparser-3.11}/examples/func_defs_add_param.py +1 -1
- pycparser-3.11/examples/typed_usage.py +76 -0
- {pycparser-3.0 → pycparser-3.11}/examples/using_cpp_libc.py +0 -1
- {pycparser-3.0 → pycparser-3.11}/examples/using_gcc_E_libc.py +0 -1
- {pycparser-3.0 → pycparser-3.11}/pycparser/__init__.py +3 -4
- {pycparser-3.0 → pycparser-3.11}/pycparser/_ast_gen.py +18 -14
- {pycparser-3.0 → pycparser-3.11}/pycparser/_c_ast.cfg +19 -0
- {pycparser-3.0 → pycparser-3.11}/pycparser/ast_transforms.py +24 -14
- {pycparser-3.0 → pycparser-3.11}/pycparser/c_ast.py +71 -33
- {pycparser-3.0 → pycparser-3.11}/pycparser/c_generator.py +78 -41
- {pycparser-3.0 → pycparser-3.11}/pycparser/c_lexer.py +88 -73
- {pycparser-3.0 → pycparser-3.11}/pycparser/c_parser.py +246 -158
- {pycparser-3.0 → pycparser-3.11/pycparser.egg-info}/PKG-INFO +8 -8
- {pycparser-3.0 → pycparser-3.11}/pycparser.egg-info/SOURCES.txt +2 -0
- {pycparser-3.0 → pycparser-3.11}/pyproject.toml +3 -2
- {pycparser-3.0 → pycparser-3.11}/tests/c_files/c11.c +31 -2
- {pycparser-3.0 → pycparser-3.11}/tests/test_c_ast.py +1 -1
- {pycparser-3.0 → pycparser-3.11}/tests/test_c_generator.py +251 -10
- {pycparser-3.0 → pycparser-3.11}/tests/test_c_lexer.py +55 -8
- {pycparser-3.0 → pycparser-3.11}/tests/test_c_parser.py +625 -21
- {pycparser-3.0 → pycparser-3.11}/tests/test_examples.py +1 -1
- {pycparser-3.0 → pycparser-3.11}/tests/test_general.py +11 -3
- {pycparser-3.0 → pycparser-3.11}/tests/test_util.py +6 -2
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/_fake_defines.h +2 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/_fake_typedefs.h +10 -0
- pycparser-3.11/utils/fake_libc_include/xcb/xcb.h +2 -0
- {pycparser-3.0 → pycparser-3.11}/MANIFEST.in +0 -0
- {pycparser-3.0 → pycparser-3.11}/examples/c_files/basic.c +0 -0
- {pycparser-3.0 → pycparser-3.11}/examples/c_files/funky.c +0 -0
- {pycparser-3.0 → pycparser-3.11}/examples/c_files/hash.c +0 -0
- {pycparser-3.0 → pycparser-3.11}/examples/c_files/memmgr.c +0 -0
- {pycparser-3.0 → pycparser-3.11}/examples/c_files/memmgr.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/examples/c_files/pragmas.c +0 -0
- {pycparser-3.0 → pycparser-3.11}/examples/c_files/year.c +0 -0
- {pycparser-3.0 → pycparser-3.11}/examples/dump_ast.py +0 -0
- {pycparser-3.0 → pycparser-3.11}/examples/explore_ast.py +0 -0
- {pycparser-3.0 → pycparser-3.11}/examples/func_calls.py +0 -0
- {pycparser-3.0 → pycparser-3.11}/examples/func_defs.py +0 -0
- {pycparser-3.0 → pycparser-3.11}/examples/rewrite_ast.py +0 -0
- {pycparser-3.0 → pycparser-3.11}/examples/serialize_ast.py +0 -0
- {pycparser-3.0 → pycparser-3.11}/pycparser.egg-info/dependency_links.txt +0 -0
- {pycparser-3.0 → pycparser-3.11}/pycparser.egg-info/top_level.txt +0 -0
- {pycparser-3.0 → pycparser-3.11}/setup.cfg +0 -0
- {pycparser-3.0 → pycparser-3.11}/setup.py +0 -0
- {pycparser-3.0 → pycparser-3.11}/tests/__init__.py +0 -0
- {pycparser-3.0 → pycparser-3.11}/tests/c_files/cppd_with_stdio_h.c +0 -0
- {pycparser-3.0 → pycparser-3.11}/tests/c_files/empty.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/tests/c_files/example_c_file.c +0 -0
- {pycparser-3.0 → pycparser-3.11}/tests/c_files/hdir/9/inc.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/tests/c_files/memmgr.c +0 -0
- {pycparser-3.0 → pycparser-3.11}/tests/c_files/memmgr.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/tests/c_files/memmgr_with_h.c +0 -0
- {pycparser-3.0 → pycparser-3.11}/tests/c_files/simplemain.c +0 -0
- {pycparser-3.0 → pycparser-3.11}/tests/c_files/year.c +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/X11/Intrinsic.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/X11/Xlib.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/X11/_X11_fake_defines.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/X11/_X11_fake_typedefs.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/_ansi.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/_syslist.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/aio.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/alloca.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/ar.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/argz.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/arpa/inet.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/asm-generic/int-ll64.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/assert.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/complex.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/cpio.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/ctype.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/dirent.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/dlfcn.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/emmintrin.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/endian.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/envz.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/errno.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/fastmath.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/fcntl.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/features.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/fenv.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/float.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/fmtmsg.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/fnmatch.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/ftw.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/getopt.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/glob.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/grp.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/iconv.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/ieeefp.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/immintrin.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/inttypes.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/iso646.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/langinfo.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/libgen.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/libintl.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/limits.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/linux/socket.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/linux/version.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/locale.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/malloc.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/math.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/mir_toolkit/client_types.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/monetary.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/mqueue.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/ndbm.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/net/if.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/netdb.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/netinet/in.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/netinet/tcp.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/newlib.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/nl_types.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/openssl/err.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/openssl/evp.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/openssl/hmac.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/openssl/ssl.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/openssl/x509v3.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/paths.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/poll.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/process.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/pthread.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/pwd.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/reent.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/regdef.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/regex.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sched.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/search.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/semaphore.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/setjmp.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/signal.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/smmintrin.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/spawn.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdalign.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdarg.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdatomic.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdbool.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stddef.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdint.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdio.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdlib.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stdnoreturn.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/string.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/strings.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/stropts.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/ioctl.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/ipc.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/mman.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/msg.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/poll.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/resource.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/select.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/sem.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/shm.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/socket.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/stat.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/statvfs.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/sysctl.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/time.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/times.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/types.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/uio.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/un.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/utsname.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/sys/wait.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/syslog.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/tar.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/termios.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/tgmath.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/threads.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/time.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/trace.h +0 -0
- /pycparser-3.0/utils/fake_libc_include/ulimit.h → /pycparser-3.11/utils/fake_libc_include/uchar.h +0 -0
- /pycparser-3.0/utils/fake_libc_include/unctrl.h → /pycparser-3.11/utils/fake_libc_include/ulimit.h +0 -0
- /pycparser-3.0/utils/fake_libc_include/unistd.h → /pycparser-3.11/utils/fake_libc_include/unctrl.h +0 -0
- /pycparser-3.0/utils/fake_libc_include/utime.h → /pycparser-3.11/utils/fake_libc_include/unistd.h +0 -0
- /pycparser-3.0/utils/fake_libc_include/utmp.h → /pycparser-3.11/utils/fake_libc_include/utime.h +0 -0
- /pycparser-3.0/utils/fake_libc_include/utmpx.h → /pycparser-3.11/utils/fake_libc_include/utmp.h +0 -0
- /pycparser-3.0/utils/fake_libc_include/wchar.h → /pycparser-3.11/utils/fake_libc_include/utmpx.h +0 -0
- /pycparser-3.0/utils/fake_libc_include/wctype.h → /pycparser-3.11/utils/fake_libc_include/wchar.h +0 -0
- /pycparser-3.0/utils/fake_libc_include/wordexp.h → /pycparser-3.11/utils/fake_libc_include/wctype.h +0 -0
- /pycparser-3.0/utils/fake_libc_include/xcb/xcb.h → /pycparser-3.11/utils/fake_libc_include/wordexp.h +0 -0
- {pycparser-3.0 → pycparser-3.11}/utils/fake_libc_include/zlib.h +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pycparser
|
|
3
|
-
Version: 3.
|
|
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
|
|
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/
|
|
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
|
|
195
|
-
|
|
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
|
|
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/
|
|
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
|
|
175
|
-
|
|
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
|
|
|
@@ -35,18 +35,18 @@
|
|
|
35
35
|
# }
|
|
36
36
|
# ------------------------------------------------------------------------------
|
|
37
37
|
import json
|
|
38
|
-
import sys
|
|
39
38
|
import re
|
|
40
|
-
|
|
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
|
|
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:
|
|
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]) ->
|
|
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 =
|
|
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) ->
|
|
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:
|
|
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 {}"
|
|
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) ->
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
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) ->
|
|
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
|
|
181
|
-
|
|
182
|
-
|
|
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) ->
|
|
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:
|
|
@@ -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)
|
|
@@ -7,10 +7,9 @@
|
|
|
7
7
|
# Eli Bendersky [https://eli.thegreenplace.net/]
|
|
8
8
|
# License: BSD
|
|
9
9
|
# -----------------------------------------------------------------
|
|
10
|
-
__all__ = ["
|
|
11
|
-
__version__ = "3.
|
|
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
|
|
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.
|
|
6
|
-
# regenerate c_ast.py from _c_ast.cfg
|
|
7
|
-
#
|
|
8
|
-
#
|
|
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"
|
|
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
|
|
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
|
|
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(
|
|
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:
|
|
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:
|
|
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
|
|
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:
|
|
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
|
-
#
|
|
131
|
-
#
|
|
132
|
-
#
|
|
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
|
-
|
|
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
|
-
) ->
|
|
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
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|