././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4693286 pycparser-3.0/0000775000175000017500000000000015134160755012713 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/LICENSE0000664000175000017500000000300714716121044013711 0ustar00elibenelibenpycparser -- A C parser in Python Copyright (c) 2008-2022, Eli Bendersky All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/MANIFEST.in0000664000175000017500000000034315134157072014447 0ustar00elibenelibenrecursive-include examples *.c *.h *.py recursive-include tests *.c *.h *.py recursive-include pycparser *.py *.cfg recursive-include utils/fake_libc_include *.h include README.* include LICENSE include CHANGES include setup.* ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4693158 pycparser-3.0/PKG-INFO0000644000175000017500000002004515134160755014007 0ustar00elibenelibenMetadata-Version: 2.4 Name: pycparser Version: 3.0 Summary: C parser in Python Author-email: Eli Bendersky Maintainer-email: Eli Bendersky License-Expression: BSD-3-Clause Project-URL: Homepage, https://github.com/eliben/pycparser Classifier: Development Status :: 5 - Production/Stable Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Programming Language :: Python :: 3.14 Requires-Python: >=3.10 Description-Content-Type: text/x-rst License-File: LICENSE Dynamic: license-file =============== pycparser v3.00 =============== .. image:: https://github.com/eliben/pycparser/workflows/pycparser-tests/badge.svg :align: center :target: https://github.com/eliben/pycparser/actions ---- .. contents:: :backlinks: none .. sectnum:: Introduction ============ What is pycparser? ------------------ **pycparser** is a parser for the C language, written in pure Python. It is a module designed to be easily integrated into applications that need to parse C source code. What is it good for? -------------------- Anything that needs C code to be parsed. The following are some uses for **pycparser**, taken from real user reports: * C code obfuscator * Front-end for various specialized C compilers * Static code checker * Automatic unit-test discovery * Adding specialized extensions to the C language One of the most popular uses of **pycparser** is in the `cffi `_ library, which uses it to parse the declarations of C functions and types in order to auto-generate FFIs. **pycparser** is unique in the sense that it's written in pure Python - a very high level language that's easy to experiment with and tweak. To people familiar with Lex and Yacc, **pycparser**'s code will be simple to understand. It also has no external dependencies (except for a Python interpreter), making it very simple to install and deploy. Which version of C does pycparser support? ------------------------------------------ **pycparser** aims to support the full C99 language (according to the standard ISO/IEC 9899). Some features from C11 are also supported, and patches to support more are welcome. **pycparser** supports very few GCC extensions, but it's fairly easy to set things up so that it parses code with a lot of GCC-isms successfully. See the `FAQ `_ for more details. What grammar does pycparser follow? ----------------------------------- **pycparser** very closely follows the C grammar provided in Annex A of the C99 standard (ISO/IEC 9899). How is pycparser licensed? -------------------------- `BSD license `_. Contact details --------------- For reporting problems with **pycparser** or submitting feature requests, please open an `issue `_, or submit a pull request. Installing ========== Prerequisites ------------- **pycparser** is being tested with modern versions of Python on Linux, macOS and Windows. See `the CI dashboard `__ for details. **pycparser** has no external dependencies. Installation process -------------------- The recommended way to install **pycparser** is with ``pip``:: > pip install pycparser Using ===== Interaction with the C preprocessor ----------------------------------- In order to be compilable, C code must be preprocessed by the C preprocessor - ``cpp``. A compatible ``cpp`` handles preprocessing directives like ``#include`` and ``#define``, removes comments, and performs other minor tasks that prepare the C code for compilation. For all but the most trivial snippets of C code **pycparser**, like a C compiler, must receive preprocessed C code in order to function correctly. If you import the top-level ``parse_file`` function from the **pycparser** package, it will interact with ``cpp`` for you, as long as it's in your PATH, or you provide a path to it. Note also that you can use ``gcc -E`` or ``clang -E`` instead of ``cpp``. See the ``using_gcc_E_libc.py`` example for more details. Windows users can download and install a binary build of Clang for Windows `from this website `_. What about the standard C library headers? ------------------------------------------ C code almost always ``#include``\s various header files from the standard C library, like ``stdio.h``. While (with some effort) **pycparser** can be made to parse the standard headers from any C compiler, it's much simpler to use the provided "fake" standard includes for C11 in ``utils/fake_libc_include``. These are standard C header files that contain only the bare necessities to allow valid parsing of the files that use them. As a bonus, since they're minimal, it can significantly improve the performance of parsing large C files. The key point to understand here is that **pycparser** doesn't really care about the semantics of types. It only needs to know whether some token encountered in the source is a previously defined type. This is essential in order to be able to parse C correctly. See `this blog post `_ for more details. Note that the fake headers are not included in the ``pip`` package nor installed via the package build (`#224 `_). Basic usage ----------- Take a look at the |examples|_ directory of the distribution for a few examples of using **pycparser**. These should be enough to get you started. Please note that most realistic C code samples would require running the C preprocessor before passing the code to **pycparser**; see the previous sections for more details. .. |examples| replace:: ``examples`` .. _examples: examples Advanced usage -------------- The public interface of **pycparser** is well documented with comments in ``pycparser/c_parser.py``. For a detailed overview of the various AST nodes created by the parser, see ``pycparser/_c_ast.cfg``. There's also a `FAQ available here `_. In any case, you can always drop me an `email `_ for help. Modifying ========= There are a few points to keep in mind when modifying **pycparser**: * The code for **pycparser**'s AST nodes is automatically generated from a configuration file - ``_c_ast.cfg``, by ``_ast_gen.py``. If you modify the AST configuration, make sure to re-generate the code. This can be done by running the ``_ast_gen.py`` script (from the repository root or the ``pycparser`` directory). * Read the docstring in the constructor of the ``CParser`` class for details on configuration and compatibility arguments. Package contents ================ Once you unzip the ``pycparser`` package, you'll see the following files and directories: README.rst: This README file. LICENSE: The pycparser license setup.py: Legacy installation script (build metadata lives in ``pyproject.toml``). pyproject.toml: Package metadata and build configuration. examples/: A directory with some examples of using **pycparser** pycparser/: The **pycparser** module source code. tests/: Unit tests. utils/fake_libc_include: Minimal standard C library include files that should allow to parse any C code. Note that these headers now include C11 code, so they may not work when the preprocessor is configured to an earlier C standard (like ``-std=c99``). utils/internal/: Internal utilities for my own use. You probably don't need them. Contributors ============ Some people have contributed to **pycparser** by opening issues on bugs they've found and/or submitting patches. The list of contributors is in the CONTRIBUTORS file in the source distribution. After **pycparser** moved to Github I stopped updating this list because Github does a much better job at tracking contributions. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769005202.0 pycparser-3.0/README.rst0000664000175000017500000001650715134160222014400 0ustar00elibeneliben=============== pycparser v3.00 =============== .. image:: https://github.com/eliben/pycparser/workflows/pycparser-tests/badge.svg :align: center :target: https://github.com/eliben/pycparser/actions ---- .. contents:: :backlinks: none .. sectnum:: Introduction ============ What is pycparser? ------------------ **pycparser** is a parser for the C language, written in pure Python. It is a module designed to be easily integrated into applications that need to parse C source code. What is it good for? -------------------- Anything that needs C code to be parsed. The following are some uses for **pycparser**, taken from real user reports: * C code obfuscator * Front-end for various specialized C compilers * Static code checker * Automatic unit-test discovery * Adding specialized extensions to the C language One of the most popular uses of **pycparser** is in the `cffi `_ library, which uses it to parse the declarations of C functions and types in order to auto-generate FFIs. **pycparser** is unique in the sense that it's written in pure Python - a very high level language that's easy to experiment with and tweak. To people familiar with Lex and Yacc, **pycparser**'s code will be simple to understand. It also has no external dependencies (except for a Python interpreter), making it very simple to install and deploy. Which version of C does pycparser support? ------------------------------------------ **pycparser** aims to support the full C99 language (according to the standard ISO/IEC 9899). Some features from C11 are also supported, and patches to support more are welcome. **pycparser** supports very few GCC extensions, but it's fairly easy to set things up so that it parses code with a lot of GCC-isms successfully. See the `FAQ `_ for more details. What grammar does pycparser follow? ----------------------------------- **pycparser** very closely follows the C grammar provided in Annex A of the C99 standard (ISO/IEC 9899). How is pycparser licensed? -------------------------- `BSD license `_. Contact details --------------- For reporting problems with **pycparser** or submitting feature requests, please open an `issue `_, or submit a pull request. Installing ========== Prerequisites ------------- **pycparser** is being tested with modern versions of Python on Linux, macOS and Windows. See `the CI dashboard `__ for details. **pycparser** has no external dependencies. Installation process -------------------- The recommended way to install **pycparser** is with ``pip``:: > pip install pycparser Using ===== Interaction with the C preprocessor ----------------------------------- In order to be compilable, C code must be preprocessed by the C preprocessor - ``cpp``. A compatible ``cpp`` handles preprocessing directives like ``#include`` and ``#define``, removes comments, and performs other minor tasks that prepare the C code for compilation. For all but the most trivial snippets of C code **pycparser**, like a C compiler, must receive preprocessed C code in order to function correctly. If you import the top-level ``parse_file`` function from the **pycparser** package, it will interact with ``cpp`` for you, as long as it's in your PATH, or you provide a path to it. Note also that you can use ``gcc -E`` or ``clang -E`` instead of ``cpp``. See the ``using_gcc_E_libc.py`` example for more details. Windows users can download and install a binary build of Clang for Windows `from this website `_. What about the standard C library headers? ------------------------------------------ C code almost always ``#include``\s various header files from the standard C library, like ``stdio.h``. While (with some effort) **pycparser** can be made to parse the standard headers from any C compiler, it's much simpler to use the provided "fake" standard includes for C11 in ``utils/fake_libc_include``. These are standard C header files that contain only the bare necessities to allow valid parsing of the files that use them. As a bonus, since they're minimal, it can significantly improve the performance of parsing large C files. The key point to understand here is that **pycparser** doesn't really care about the semantics of types. It only needs to know whether some token encountered in the source is a previously defined type. This is essential in order to be able to parse C correctly. See `this blog post `_ for more details. Note that the fake headers are not included in the ``pip`` package nor installed via the package build (`#224 `_). Basic usage ----------- Take a look at the |examples|_ directory of the distribution for a few examples of using **pycparser**. These should be enough to get you started. Please note that most realistic C code samples would require running the C preprocessor before passing the code to **pycparser**; see the previous sections for more details. .. |examples| replace:: ``examples`` .. _examples: examples Advanced usage -------------- The public interface of **pycparser** is well documented with comments in ``pycparser/c_parser.py``. For a detailed overview of the various AST nodes created by the parser, see ``pycparser/_c_ast.cfg``. There's also a `FAQ available here `_. In any case, you can always drop me an `email `_ for help. Modifying ========= There are a few points to keep in mind when modifying **pycparser**: * The code for **pycparser**'s AST nodes is automatically generated from a configuration file - ``_c_ast.cfg``, by ``_ast_gen.py``. If you modify the AST configuration, make sure to re-generate the code. This can be done by running the ``_ast_gen.py`` script (from the repository root or the ``pycparser`` directory). * Read the docstring in the constructor of the ``CParser`` class for details on configuration and compatibility arguments. Package contents ================ Once you unzip the ``pycparser`` package, you'll see the following files and directories: README.rst: This README file. LICENSE: The pycparser license setup.py: Legacy installation script (build metadata lives in ``pyproject.toml``). pyproject.toml: Package metadata and build configuration. examples/: A directory with some examples of using **pycparser** pycparser/: The **pycparser** module source code. tests/: Unit tests. utils/fake_libc_include: Minimal standard C library include files that should allow to parse any C code. Note that these headers now include C11 code, so they may not work when the preprocessor is configured to an earlier C standard (like ``-std=c99``). utils/internal/: Internal utilities for my own use. You probably don't need them. Contributors ============ Some people have contributed to **pycparser** by opening issues on bugs they've found and/or submitting patches. The list of contributors is in the CONTRIBUTORS file in the source distribution. After **pycparser** moved to Github I stopped updating this list because Github does a much better job at tracking contributions. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4636858 pycparser-3.0/examples/0000775000175000017500000000000015134160755014531 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/examples/c-to-c.py0000664000175000017500000000164015134157072016164 0ustar00elibeneliben# ------------------------------------------------------------------------------ # pycparser: c-to-c.py # # Example of using pycparser.c_generator, serving as a simplistic translator # from C to AST and back to C. # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ------------------------------------------------------------------------------ import sys # This is not required if you've installed pycparser into # your site-packages/ with setup.py sys.path.extend([".", ".."]) from pycparser import parse_file, c_generator def translate_to_c(filename: str) -> None: """Simply use the c_generator module to emit a parsed AST.""" ast = parse_file(filename, use_cpp=True) generator = c_generator.CGenerator() print(generator.visit(ast)) if __name__ == "__main__": if len(sys.argv) > 1: translate_to_c(sys.argv[1]) else: print("Please provide a filename as argument") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4639175 pycparser-3.0/examples/c_files/0000775000175000017500000000000015134160755016135 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/examples/c_files/basic.c0000664000175000017500000000006214716121044017351 0ustar00elibenelibenint foo() {} int main() { foo(); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/examples/c_files/funky.c0000664000175000017500000000030114716121044017420 0ustar00elibenelibenchar foo(void) { return '1'; } int maxout_in(int paste, char** matrix) { char o = foo(); return (int) matrix[1][2] * 5 - paste; } int main() { auto char* multi = "a multi"; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/examples/c_files/hash.c0000664000175000017500000000726514716121044017227 0ustar00elibeneliben/* ** C implementation of a hash table ADT */ typedef enum tagReturnCode {SUCCESS, FAIL} ReturnCode; typedef struct tagEntry { char* key; char* value; } Entry; typedef struct tagNode { Entry* entry; struct tagNode* next; } Node; typedef struct tagHash { unsigned int table_size; Node** heads; } Hash; static unsigned int hash_func(const char* str, unsigned int table_size) { unsigned int hash_value; unsigned int a = 127; for (hash_value = 0; *str != 0; ++str) hash_value = (a*hash_value + *str) % table_size; return hash_value; } ReturnCode HashCreate(Hash** hash, unsigned int table_size) { unsigned int i; if (table_size < 1) return FAIL; // // Allocate space for the Hash // if (((*hash) = malloc(sizeof(**hash))) == NULL) return FAIL; // // Allocate space for the array of list heads // if (((*hash)->heads = malloc(table_size*sizeof(*((*hash)->heads)))) == NULL) return FAIL; // // Initialize Hash info // for (i = 0; i < table_size; ++i) { (*hash)->heads[i] = NULL; } (*hash)->table_size = table_size; return SUCCESS; } ReturnCode HashInsert(Hash* hash, const Entry* entry) { unsigned int index = hash_func(entry->key, hash->table_size); Node* temp = hash->heads[index]; HashRemove(hash, entry->key); if ((hash->heads[index] = malloc(sizeof(Node))) == NULL) return FAIL; hash->heads[index]->entry = malloc(sizeof(Entry)); hash->heads[index]->entry->key = malloc(strlen(entry->key)+1); hash->heads[index]->entry->value = malloc(strlen(entry->value)+1); strcpy(hash->heads[index]->entry->key, entry->key); strcpy(hash->heads[index]->entry->value, entry->value); hash->heads[index]->next = temp; return SUCCESS; } const Entry* HashFind(const Hash* hash, const char* key) { unsigned int index = hash_func(key, hash->table_size); Node* temp = hash->heads[index]; while (temp != NULL) { if (!strcmp(key, temp->entry->key)) return temp->entry; temp = temp->next; } return NULL; } ReturnCode HashRemove(Hash* hash, const char* key) { unsigned int index = hash_func(key, hash->table_size); Node* temp1 = hash->heads[index]; Node* temp2 = temp1; while (temp1 != NULL) { if (!strcmp(key, temp1->entry->key)) { if (temp1 == hash->heads[index]) hash->heads[index] = hash->heads[index]->next; else temp2->next = temp1->next; free(temp1->entry->key); free(temp1->entry->value); free(temp1->entry); free(temp1); temp1 = NULL; return SUCCESS; } temp2 = temp1; temp1 = temp1->next; } return FAIL; } void HashPrint(Hash* hash, void (*PrintFunc)(char*, char*)) { unsigned int i; if (hash == NULL || hash->heads == NULL) return; for (i = 0; i < hash->table_size; ++i) { Node* temp = hash->heads[i]; while (temp != NULL) { PrintFunc(temp->entry->key, temp->entry->value); temp = temp->next; } } } void HashDestroy(Hash* hash) { unsigned int i; if (hash == NULL) return; for (i = 0; i < hash->table_size; ++i) { Node* temp = hash->heads[i]; while (temp != NULL) { Node* temp2 = temp; free(temp->entry->key); free(temp->entry->value); free(temp->entry); temp = temp->next; free(temp2); } } free(hash->heads); hash->heads = NULL; free(hash); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/examples/c_files/memmgr.c0000664000175000017500000001240314716121044017556 0ustar00elibeneliben//---------------------------------------------------------------- // Statically-allocated memory manager // // by Eli Bendersky (eliben@gmail.com) // // This code is in the public domain. //---------------------------------------------------------------- #include "memmgr.h" typedef ulong Align; union mem_header_union { struct { // Pointer to the next block in the free list // union mem_header_union* next; // Size of the block (in quantas of sizeof(mem_header_t)) // ulong size; } s; // Used to align headers in memory to a boundary // Align align_dummy; }; typedef union mem_header_union mem_header_t; // Initial empty list // static mem_header_t base; // Start of free list // static mem_header_t* freep = 0; // Static pool for new allocations // static byte pool[POOL_SIZE] = {0}; static ulong pool_free_pos = 0; void memmgr_init() { base.s.next = 0; base.s.size = 0; freep = 0; pool_free_pos = 0; } static mem_header_t* get_mem_from_pool(ulong nquantas) { ulong total_req_size; mem_header_t* h; if (nquantas < MIN_POOL_ALLOC_QUANTAS) nquantas = MIN_POOL_ALLOC_QUANTAS; total_req_size = nquantas * sizeof(mem_header_t); if (pool_free_pos + total_req_size <= POOL_SIZE) { h = (mem_header_t*) (pool + pool_free_pos); h->s.size = nquantas; memmgr_free((void*) (h + 1)); pool_free_pos += total_req_size; } else { return 0; } return freep; } // Allocations are done in 'quantas' of header size. // The search for a free block of adequate size begins at the point 'freep' // where the last block was found. // If a too-big block is found, it is split and the tail is returned (this // way the header of the original needs only to have its size adjusted). // The pointer returned to the user points to the free space within the block, // which begins one quanta after the header. // void* memmgr_alloc(ulong nbytes) { mem_header_t* p; mem_header_t* prevp; // Calculate how many quantas are required: we need enough to house all // the requested bytes, plus the header. The -1 and +1 are there to make sure // that if nbytes is a multiple of nquantas, we don't allocate too much // ulong nquantas = (nbytes + sizeof(mem_header_t) - 1) / sizeof(mem_header_t) + 1; // First alloc call, and no free list yet ? Use 'base' for an initial // denegerate block of size 0, which points to itself // if ((prevp = freep) == 0) { base.s.next = freep = prevp = &base; base.s.size = 0; } for (p = prevp->s.next; ; prevp = p, p = p->s.next) { // big enough ? if (p->s.size >= nquantas) { // exactly ? if (p->s.size == nquantas) { // just eliminate this block from the free list by pointing // its prev's next to its next // prevp->s.next = p->s.next; } else // too big { p->s.size -= nquantas; p += p->s.size; p->s.size = nquantas; } freep = prevp; return (void*) (p + 1); } // Reached end of free list ? // Try to allocate the block from the pool. If that succeeds, // get_mem_from_pool adds the new block to the free list and // it will be found in the following iterations. If the call // to get_mem_from_pool doesn't succeed, we've run out of // memory // else if (p == freep) { if ((p = get_mem_from_pool(nquantas)) == 0) { #ifdef DEBUG_MEMMGR_FATAL printf("!! Memory allocation failed !!\n"); #endif return 0; } } } } // Scans the free list, starting at freep, looking the the place to insert the // free block. This is either between two existing blocks or at the end of the // list. In any case, if the block being freed is adjacent to either neighbor, // the adjacent blocks are combined. // void memmgr_free(void* ap) { mem_header_t* block; mem_header_t* p; // acquire pointer to block header block = ((mem_header_t*) ap) - 1; // Find the correct place to place the block in (the free list is sorted by // address, increasing order) // for (p = freep; !(block > p && block < p->s.next); p = p->s.next) { // Since the free list is circular, there is one link where a // higher-addressed block points to a lower-addressed block. // This condition checks if the block should be actually // inserted between them // if (p >= p->s.next && (block > p || block < p->s.next)) break; } // Try to combine with the higher neighbor // if (block + block->s.size == p->s.next) { block->s.size += p->s.next->s.size; block->s.next = p->s.next->s.next; } else { block->s.next = p->s.next; } // Try to combine with the lower neighbor // if (p + p->s.size == block) { p->s.size += block->s.size; p->s.next = block->s.next; } else { p->s.next = block; } freep = p; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/examples/c_files/memmgr.h0000664000175000017500000000550214716121044017565 0ustar00elibeneliben//---------------------------------------------------------------- // Statically-allocated memory manager // // by Eli Bendersky (eliben@gmail.com) // // This code is in the public domain. //---------------------------------------------------------------- #ifndef MEMMGR_H #define MEMMGR_H // // Memory manager: dynamically allocates memory from // a fixed pool that is allocated statically at link-time. // // Usage: after calling memmgr_init() in your // initialization routine, just use memmgr_alloc() instead // of malloc() and memmgr_free() instead of free(). // Naturally, you can use the preprocessor to define // malloc() and free() as aliases to memmgr_alloc() and // memmgr_free(). This way the manager will be a drop-in // replacement for the standard C library allocators, and can // be useful for debugging memory allocation problems and // leaks. // // Preprocessor flags you can define to customize the // memory manager: // // DEBUG_MEMMGR_FATAL // Allow printing out a message when allocations fail // // DEBUG_MEMMGR_SUPPORT_STATS // Allow printing out of stats in function // memmgr_print_stats When this is disabled, // memmgr_print_stats does nothing. // // Note that in production code on an embedded system // you'll probably want to keep those undefined, because // they cause printf to be called. // // POOL_SIZE // Size of the pool for new allocations. This is // effectively the heap size of the application, and can // be changed in accordance with the available memory // resources. // // MIN_POOL_ALLOC_QUANTAS // Internally, the memory manager allocates memory in // quantas roughly the size of two ulong objects. To // minimize pool fragmentation in case of multiple allocations // and deallocations, it is advisable to not allocate // blocks that are too small. // This flag sets the minimal amount of quantas for // an allocation. If the size of a ulong is 4 and you // set this flag to 16, the minimal size of an allocation // will be 4 * 2 * 16 = 128 bytes // If you have a lot of small allocations, keep this value // low to conserve memory. If you have mostly large // allocations, it is best to make it higher, to avoid // fragmentation. // // Notes: // 1. This memory manager is *not thread safe*. Use it only // for single thread/task applications. // #define DEBUG_MEMMGR_SUPPORT_STATS 1 #define POOL_SIZE 8 * 1024 #define MIN_POOL_ALLOC_QUANTAS 16 typedef unsigned char byte; typedef unsigned long ulong; // Initialize the memory manager. This function should be called // only once in the beginning of the program. // void memmgr_init(); // 'malloc' clone // void* memmgr_alloc(ulong nbytes); // 'free' clone // void memmgr_free(void* ap); // Prints statistics about the current state of the memory // manager // void memmgr_print_stats(); #endif // MEMMGR_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/examples/c_files/pragmas.c0000664000175000017500000000021414716121044017721 0ustar00elibenelibenint i; #pragma joe int main() { int a = 1; #pragma inmain for (int i = 0; i < 3; i++) { #pragma infor a += i; } return a; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/examples/c_files/year.c0000664000175000017500000000212514716121044017232 0ustar00elibeneliben#include #include #include void convert(int thousands, int hundreds, int tens, int ones) { char *num[] = {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"}; char *for_ten[] = {"", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"}; char *af_ten[] = {"Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Ninteen"}; printf("\nThe year in words is:\n"); printf("%s thousand", num[thousands]); if (hundreds != 0) printf(" %s hundred", num[hundreds]); if (tens != 1) printf(" %s %s", for_ten[tens], num[ones]); else printf(" %s", af_ten[ones]); } int main() { int year; int n1000, n100, n10, n1; printf("\nEnter the year (4 digits): "); scanf("%d", &year); if (year > 9999 || year < 1000) { printf("\nError !! The year must contain 4 digits."); exit(EXIT_FAILURE); } n1000 = year/1000; n100 = ((year)%1000)/100; n10 = (year%100)/10; n1 = ((year%10)%10); convert(n1000, n100, n10, n1); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/examples/c_json.py0000664000175000017500000001543215134157072016361 0ustar00elibeneliben# ------------------------------------------------------------------------------ # pycparser: c_json.py # # by Michael White (@mypalmike) # # This example includes functions to serialize and deserialize an ast # to and from json format. Serializing involves walking the ast and converting # each node from a python Node object into a python dict. Deserializing # involves the opposite conversion, walking the tree formed by the # dict and converting each dict into the specific Node object it represents. # The dict itself is serialized and deserialized using the python json module. # # The dict representation is a fairly direct transformation of the object # attributes. Each node in the dict gets one metadata field referring to the # specific node class name, _nodetype. Each local attribute (i.e. not linking # to child nodes) has a string value or array of string values. Each child # attribute is either another dict or an array of dicts, exactly as in the # Node object representation. The "coord" attribute, representing the # node's location within the source code, is serialized/deserialized from # a Coord object into a string of the format "filename:line[:column]". # # Example TypeDecl node, with IdentifierType child node, represented as a dict: # "type": { # "_nodetype": "TypeDecl", # "coord": "c_files/funky.c:8", # "declname": "o", # "quals": [], # "type": { # "_nodetype": "IdentifierType", # "coord": "c_files/funky.c:8", # "names": [ # "char" # ] # } # } # ------------------------------------------------------------------------------ import json import sys import re from typing import Any, Callable, Dict, Optional, Set, TypeVar # This is not required if you've installed pycparser into # your site-packages/ with setup.py sys.path.extend([".", ".."]) from pycparser import parse_file, c_ast from pycparser.c_parser import Coord RE_CHILD_ARRAY = re.compile(r"(.*)\[(.*)\]") RE_INTERNAL_ATTR = re.compile("__.*__") class CJsonError(Exception): pass _T = TypeVar("_T") _R = TypeVar("_R") def memodict(fn: Callable[[_T], _R]) -> Callable[[_T], _R]: """Fast memoization decorator for a function taking a single argument""" cache: Dict[_T, _R] = {} def memoized(arg: _T) -> _R: if arg in cache: return cache[arg] result = fn(arg) cache[arg] = result return result return memoized @memodict def child_attrs_of(klass: type[c_ast.Node]) -> Set[str]: """ Given a Node class, get a set of child attrs. Memoized to avoid highly repetitive string manipulation """ non_child_attrs = set(klass.attr_names) all_attrs = set([i for i in klass.__slots__ if not RE_INTERNAL_ATTR.match(i)]) return all_attrs - non_child_attrs def to_dict(node: c_ast.Node) -> Dict[str, Any]: """Recursively convert an ast into dict representation.""" klass = node.__class__ result: Dict[str, Any] = {} # Metadata result["_nodetype"] = klass.__name__ # Local node attributes for attr in klass.attr_names: result[attr] = getattr(node, attr) # Coord object if node.coord: result["coord"] = str(node.coord) else: result["coord"] = None # Child attributes for child_name, child in node.children(): # Child strings are either simple (e.g. 'value') or arrays (e.g. 'block_items[1]') match = RE_CHILD_ARRAY.match(child_name) if match: array_name, array_index = match.groups() array_index = int(array_index) # arrays come in order, so we verify and append. result[array_name] = result.get(array_name, []) if array_index != len(result[array_name]): raise CJsonError( "Internal ast error. Array {} out of order. " "Expected index {}, got {}".format( array_name, len(result[array_name]), array_index ) ) result[array_name].append(to_dict(child)) else: result[child_name] = to_dict(child) # Any child attributes that were missing need "None" values in the json. for child_attr in child_attrs_of(klass): if child_attr not in result: result[child_attr] = None return result def to_json(node: c_ast.Node, **kwargs: Any) -> str: """Convert ast node to json string""" return json.dumps(to_dict(node), **kwargs) def file_to_dict(filename: str) -> Dict[str, Any]: """Load C file into dict representation of ast""" ast = parse_file(filename, use_cpp=True) return to_dict(ast) def file_to_json(filename: str, **kwargs: Any) -> str: """Load C file into json string representation of ast""" ast = parse_file(filename, use_cpp=True) return to_json(ast, **kwargs) def _parse_coord(coord_str: Optional[str]) -> Optional[Coord]: """Parse coord string (file:line[:column]) into Coord object.""" if coord_str is None: return None vals = coord_str.split(":") vals.extend(["", "", ""]) filename, line, column = vals[:3] line_num = int(line) if line else 0 column_num = int(column) if column else None return Coord(filename, line_num, column_num) def _convert_to_obj(value: Any) -> Any: """ Convert an object in the dict representation into an object. Note: Mutually recursive with from_dict. """ match value: case dict(): return from_dict(value) case list(): return [_convert_to_obj(item) for item in value] case _: # String return value def from_dict(node_dict: Dict[str, Any]) -> c_ast.Node: """Recursively build an ast from dict representation""" class_name = node_dict.pop("_nodetype") klass = getattr(c_ast, class_name) # Create a new dict containing the key-value pairs which we can pass # to node constructors. objs = {} for key, value in node_dict.items(): if key == "coord": objs[key] = _parse_coord(value) else: objs[key] = _convert_to_obj(value) # Use keyword parameters, which works thanks to beautifully consistent # ast Node initializers. return klass(**objs) def from_json(ast_json: str) -> c_ast.Node: """Build an ast from json string representation""" return from_dict(json.loads(ast_json)) # ------------------------------------------------------------------------------ if __name__ == "__main__": if len(sys.argv) > 1: # Some test code... # Do trip from C -> ast -> dict -> ast -> json, then print. ast_dict = file_to_dict(sys.argv[1]) ast = from_dict(ast_dict) print(to_json(ast, sort_keys=True, indent=4)) else: print("Please provide a filename as argument") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/examples/cdecl.py0000664000175000017500000001530015134157072016152 0ustar00elibeneliben# ----------------------------------------------------------------- # pycparser: cdecl.py # # Example of the CDECL tool using pycparser. CDECL "explains" C type # declarations in plain English. # # The AST generated by pycparser from the given declaration is traversed # recursively to build the explanation. Note that the declaration must be a # valid external declaration in C. As shown below, typedef can be optionally # expanded. # # For example: # # c_decl = 'typedef int Node; const Node* (*ar)[10];' # # explain_c_declaration(c_decl) # => ar is a pointer to array[10] of pointer to const Node # # struct and typedef can be optionally expanded: # # explain_c_declaration(c_decl, expand_typedef=True) # => ar is a pointer to array[10] of pointer to const int # # c_decl = 'struct P {int x; int y;} p;' # # explain_c_declaration(c_decl) # => p is a struct P # # explain_c_declaration(c_decl, expand_struct=True) # => p is a struct P containing {x is a int, y is a int} # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ----------------------------------------------------------------- import copy import sys from typing import Optional # This is not required if you've installed pycparser into # your site-packages/ with setup.py sys.path.extend([".", ".."]) from pycparser import c_parser, c_ast def explain_c_declaration( c_decl: str, expand_struct: bool = False, expand_typedef: bool = False ) -> str: """Parses the declaration in c_decl and returns a text explanation as a string. The last external node of the string is used, to allow earlier typedefs for used types. expand_struct=True will spell out struct definitions recursively. expand_typedef=True will expand typedef'd types. """ parser = c_parser.CParser() try: node = parser.parse(c_decl, filename="") except c_parser.ParseError: e = sys.exc_info()[1] return "Parse error:" + str(e) if not isinstance(node, c_ast.FileAST) or not isinstance(node.ext[-1], c_ast.Decl): return "Not a valid declaration" try: expanded = expand_struct_typedef( node.ext[-1], node, expand_struct=expand_struct, expand_typedef=expand_typedef, ) except Exception as e: return "Not a valid declaration: " + str(e) return _explain_decl_node(expanded) def _explain_decl_node(decl_node: c_ast.Decl) -> str: """Receives a c_ast.Decl note and returns its explanation in English. """ storage = " ".join(decl_node.storage) + " " if decl_node.storage else "" return decl_node.name + " is a " + storage + _explain_type(decl_node.type) def _explain_type(decl: c_ast.Node) -> str: """Recursively explains a type decl node""" match decl: case c_ast.TypeDecl(): quals = " ".join(decl.quals) + " " if decl.quals else "" return quals + _explain_type(decl.type) case c_ast.Typename() | c_ast.Decl(): return _explain_type(decl.type) case c_ast.IdentifierType(): return " ".join(decl.names) case c_ast.PtrDecl(): quals = " ".join(decl.quals) + " " if decl.quals else "" return quals + "pointer to " + _explain_type(decl.type) case c_ast.ArrayDecl(): arr = "array" if decl.dim is not None: arr += f"[{decl.dim.value}]" return arr + " of " + _explain_type(decl.type) case c_ast.FuncDecl(): if decl.args is not None: params = [_explain_type(param) for param in decl.args.params] args = ", ".join(params) else: args = "" return f"function({args}) returning " + _explain_type(decl.type) case c_ast.Struct(): decls = [_explain_decl_node(mem_decl) for mem_decl in decl.decls] members = ", ".join(decls) struct_name = f" {decl.name}" if decl.name else "" contents = f"containing {{{members}}}" if members else "" return f"struct{struct_name} " + contents case _: return "" def expand_struct_typedef( cdecl: c_ast.Decl, file_ast: c_ast.FileAST, expand_struct: bool = False, expand_typedef: bool = False, ) -> c_ast.Decl: """Expand struct & typedef and return a new expanded node.""" decl_copy = copy.deepcopy(cdecl) _expand_in_place(decl_copy, file_ast, expand_struct, expand_typedef) return decl_copy def _expand_in_place( decl: c_ast.Node, file_ast: c_ast.FileAST, expand_struct: bool = False, expand_typedef: bool = False, ) -> c_ast.Node: """Recursively expand struct & typedef in place, throw RuntimeError if undeclared struct or typedef are used """ match decl: case c_ast.Decl() | c_ast.TypeDecl() | c_ast.PtrDecl() | c_ast.ArrayDecl(): decl.type = _expand_in_place( decl.type, file_ast, expand_struct, expand_typedef ) case c_ast.Struct(): if not decl.decls: struct = _find_struct(decl.name, file_ast) if struct is None: raise RuntimeError(f"using undeclared struct {decl.name}") decl.decls = struct.decls for i, mem_decl in enumerate(decl.decls): decl.decls[i] = _expand_in_place( mem_decl, file_ast, expand_struct, expand_typedef ) if not expand_struct: decl.decls = [] case c_ast.IdentifierType() if decl.names[0] not in ("int", "char"): typedef = _find_typedef(decl.names[0], file_ast) if typedef is None: raise RuntimeError(f"using undeclared type {decl.names[0]}") if expand_typedef: return typedef.type case _: pass return decl def _find_struct(name: str, file_ast: c_ast.FileAST) -> Optional[c_ast.Struct]: """Receives a struct name and return declared struct object in file_ast""" for node in file_ast.ext: if isinstance(node, c_ast.Decl) and isinstance(node.type, c_ast.Struct): if node.type.name == name: return node.type return None def _find_typedef(name: str, file_ast: c_ast.FileAST) -> Optional[c_ast.Typedef]: """Receives a type name and return typedef object in file_ast""" for node in file_ast.ext: if isinstance(node, c_ast.Typedef) and node.name == name: return node return None if __name__ == "__main__": if len(sys.argv) > 1: c_decl = sys.argv[1] else: c_decl = "char *(*(**foo[][8])())[];" print("Explaining the declaration: " + c_decl + "\n") print(explain_c_declaration(c_decl) + "\n") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/examples/construct_ast_from_scratch.py0000664000175000017500000000332615134157072022532 0ustar00elibeneliben# ----------------------------------------------------------------- # pycparser: construct_ast_from_scratch.py # # Tiny example of writing an AST from scratch to C code. # # Andre Ribeiro [https://github.com/Andree37] # License: BSD # ----------------------------------------------------------------- import sys # This is not required if you've installed pycparser into # your site-packages/ with setup.py sys.path.extend([".", ".."]) from pycparser import c_ast, c_generator # target C code: # int main() { # return 0; # } def empty_main_function_ast() -> c_ast.FuncDef: constant_zero = c_ast.Constant(type="int", value="0") return_node = c_ast.Return(expr=constant_zero) compound_node = c_ast.Compound(block_items=[return_node]) type_decl_node = c_ast.TypeDecl( declname="main", quals=[], type=c_ast.IdentifierType(names=["int"]), align=[] ) func_decl_node = c_ast.FuncDecl(args=c_ast.ParamList([]), type=type_decl_node) func_def_node = c_ast.Decl( name="main", quals=[], storage=[], funcspec=[], type=func_decl_node, init=None, bitsize=None, align=[], ) main_func_node = c_ast.FuncDef( decl=func_def_node, param_decls=None, body=compound_node ) return main_func_node def generate_c_code(my_ast: c_ast.Node) -> str: generator = c_generator.CGenerator() return generator.visit(my_ast) if __name__ == "__main__": main_function_ast = empty_main_function_ast() print("|----------------------------------------|") main_function_ast.show(offset=2) print("|----------------------------------------|") main_c_code = generate_c_code(main_function_ast) print(f"C code: \n{main_c_code}") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/examples/dump_ast.py0000664000175000017500000000165615134157072016725 0ustar00elibeneliben# ----------------------------------------------------------------- # pycparser: dump_ast.py # # Basic example of parsing a file and dumping its parsed AST. # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ----------------------------------------------------------------- import argparse import sys # This is not required if you've installed pycparser into # your site-packages/ with setup.py sys.path.extend([".", ".."]) from pycparser import parse_file if __name__ == "__main__": argparser = argparse.ArgumentParser("Dump AST") argparser.add_argument( "filename", default="examples/c_files/basic.c", nargs="?", help="name of file to parse", ) argparser.add_argument( "--coord", help="show coordinates in the dump", action="store_true" ) args = argparser.parse_args() ast = parse_file(args.filename, use_cpp=False) ast.show(showcoord=args.coord) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/examples/explore_ast.py0000664000175000017500000001251115134157072017426 0ustar00elibeneliben# ----------------------------------------------------------------- # pycparser: explore_ast.py # # This example demonstrates how to "explore" the AST created by # pycparser to understand its structure. The AST is a n-nary tree # of nodes, each node having several children, each with a name. # Just read the code, and let the comments guide you. The lines # beginning with #~ can be uncommented to print out useful # information from the AST. # It helps to have the pycparser/_c_ast.cfg file in front of you. # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ----------------------------------------------------------------- import sys # This is not required if you've installed pycparser into # your site-packages/ with setup.py sys.path.extend([".", ".."]) from pycparser import c_parser # This is some C source to parse. Note that pycparser must begin # at the top level of the C file, i.e. with either declarations # or function definitions (this is called "external declarations" # in C grammar lingo) # # Also, a C parser must have all the types declared in order to # build the correct AST. It doesn't matter what they're declared # to, so I've inserted the dummy typedef in the code to let the # parser know Hash and Node are types. You don't need to do it # when parsing real, correct C code. text = r""" typedef int Node, Hash; void HashPrint(Hash* hash, void (*PrintFunc)(char*, char*)) { unsigned int i; if (hash == NULL || hash->heads == NULL) return; for (i = 0; i < hash->table_size; ++i) { Node* temp = hash->heads[i]; while (temp != NULL) { PrintFunc(temp->entry->key, temp->entry->value); temp = temp->next; } } } """ # Create the parser and ask to parse the text. parse() will throw # a ParseError if there's an error in the code # parser = c_parser.CParser() ast = parser.parse(text, filename="") # Uncomment the following line to see the AST in a nice, human # readable way. show() is the most useful tool in exploring ASTs # created by pycparser. See the c_ast.py file for the options you # can pass it. # ast.show(showcoord=True) # OK, we've seen that the top node is FileAST. This is always the # top node of the AST. Its children are "external declarations", # and are stored in a list called ext[] (see _c_ast.cfg for the # names and types of Nodes and their children). # As you see from the printout, our AST has two Typedef children # and one FuncDef child. # Let's explore FuncDef more closely. As I've mentioned, the list # ext[] holds the children of FileAST. Since the function # definition is the third child, it's ext[2]. Uncomment the # following line to show it: # ast.ext[2].show() # A FuncDef consists of a declaration, a list of parameter # declarations (for K&R style function definitions), and a body. # First, let's examine the declaration. function_decl = ast.ext[2].decl # function_decl, like any other declaration, is a Decl. Its type child # is a FuncDecl, which has a return type and arguments stored in a # ParamList node # function_decl.type.show() # function_decl.type.args.show() # The following displays the name and type of each argument: # for param_decl in function_decl.type.args.params: # print(f"Arg name: {param_decl.name}") # print('Type:') # param_decl.type.show(offset=6) # The body is of FuncDef is a Compound, which is a placeholder for a block # surrounded by {} (You should be reading _c_ast.cfg parallel to this # explanation and seeing these things with your own eyes). # Let's see the block's declarations: function_body = ast.ext[2].body # The following displays the declarations and statements in the function # body # for decl in function_body.block_items: # decl.show() # We can see a single variable declaration, i, declared to be a simple type # declaration of type 'unsigned int', followed by statements. # block_items is a list, so the third element is the For statement: for_stmt = function_body.block_items[2] # for_stmt.show() # As you can see in _c_ast.cfg, For's children are 'init, cond, # next' for the respective parts of the 'for' loop specifier, # and stmt, which is either a single stmt or a Compound if there's # a block. # # Let's dig deeper, to the while statement inside the for loop: while_stmt = for_stmt.stmt.block_items[1] # while_stmt.show() # While is simpler, it only has a condition node and a stmt node. # The condition: while_cond = while_stmt.cond # while_cond.show() # Note that it's a BinaryOp node - the basic constituent of # expressions in our AST. BinaryOp is the expression tree, with # left and right nodes as children. It also has the op attribute, # which is just the string representation of the operator. # print(while_cond.op) # while_cond.left.show() # while_cond.right.show() # That's it for the example. I hope you now see how easy it is to explore the # AST created by pycparser. Although on the surface it is quite complex and has # a lot of node types, this is the inherent complexity of the C language every # parser/compiler designer has to cope with. # Using the tools provided by the c_ast package it's easy to explore the # structure of AST nodes and write code that processes them. # Specifically, see the cdecl.py example for a non-trivial demonstration of what # you can do by recursively going through the AST. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/examples/func_calls.py0000664000175000017500000000257215134157072017220 0ustar00elibeneliben# ----------------------------------------------------------------- # pycparser: func_calls.py # # Using pycparser for printing out all the calls of some function # in a C file. # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ----------------------------------------------------------------- import sys # This is not required if you've installed pycparser into # your site-packages/ with setup.py sys.path.extend([".", ".."]) from pycparser import c_ast, parse_file # A visitor with some state information (the funcname it's looking for) class FuncCallVisitor(c_ast.NodeVisitor): def __init__(self, funcname: str) -> None: self.funcname = funcname def visit_FuncCall(self, node: c_ast.FuncCall) -> None: if isinstance(node.name, c_ast.ID) and node.name.name == self.funcname: print(f"{self.funcname} called at {node.name.coord}") # Visit args in case they contain more func calls. if node.args is not None: self.visit(node.args) def show_func_calls(filename: str, funcname: str) -> None: ast = parse_file(filename, use_cpp=True) v = FuncCallVisitor(funcname) v.visit(ast) if __name__ == "__main__": if len(sys.argv) > 2: filename = sys.argv[1] func = sys.argv[2] else: filename = "examples/c_files/basic.c" func = "foo" show_func_calls(filename, func) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/examples/func_defs.py0000664000175000017500000000243215134157072017036 0ustar00elibeneliben# ----------------------------------------------------------------- # pycparser: func_defs.py # # Using pycparser for printing out all the functions defined in a # C file. # # This is a simple example of traversing the AST generated by # pycparser. Call it from the root directory of pycparser. # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ----------------------------------------------------------------- import sys # This is not required if you've installed pycparser into # your site-packages/ with setup.py sys.path.extend([".", ".."]) from pycparser import c_ast, parse_file # A simple visitor for FuncDef nodes that prints the names and # locations of function definitions. class FuncDefVisitor(c_ast.NodeVisitor): def visit_FuncDef(self, node: c_ast.FuncDef) -> None: print(f"{node.decl.name} at {node.decl.coord}") def show_func_defs(filename: str) -> None: # Note that cpp is used. Provide a path to your own cpp or # make sure one exists in PATH. ast = parse_file(filename, use_cpp=True, cpp_args=r"-Iutils/fake_libc_include") v = FuncDefVisitor() v.visit(ast) if __name__ == "__main__": if len(sys.argv) > 1: filename = sys.argv[1] else: filename = "examples/c_files/memmgr.c" show_func_defs(filename) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/examples/func_defs_add_param.py0000664000175000017500000000273215134157072021031 0ustar00elibeneliben# ----------------------------------------------------------------- # pycparser: func_defs_add_param.py # # Example of rewriting AST nodes to add parameters to function # definitions. Adds an "int _hidden" to every function. # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ----------------------------------------------------------------- import sys sys.path.extend([".", ".."]) from pycparser import c_parser, c_ast, c_generator text = r""" void foo(int a, int b) { } void bar() { } """ class ParamAdder(c_ast.NodeVisitor): def visit_FuncDecl(self, node: c_ast.FuncDecl) -> None: ty = c_ast.TypeDecl( declname="_hidden", quals=[], align=[], type=c_ast.IdentifierType(["int"]) ) newdecl = c_ast.Decl( name="_hidden", quals=[], align=[], storage=[], funcspec=[], type=ty, init=None, bitsize=None, coord=node.coord, ) if node.args is not None: node.args.params.append(newdecl) else: node.args = c_ast.ParamList(params=[newdecl]) if __name__ == "__main__": parser = c_parser.CParser() ast = parser.parse(text) print("AST before change:") ast.show(offset=2) v = ParamAdder() v.visit(ast) print("\nAST after change:") ast.show(offset=2) print("\nCode after change:") generator = c_generator.CGenerator() print(generator.visit(ast)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/examples/rewrite_ast.py0000664000175000017500000000123415134157072017431 0ustar00elibeneliben# ----------------------------------------------------------------- # pycparser: rewrite_ast.py # # Tiny example of rewriting a AST node # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ----------------------------------------------------------------- import sys sys.path.extend([".", ".."]) from pycparser import c_parser text = r""" void func(void) { x = 1; } """ if __name__ == "__main__": parser = c_parser.CParser() ast = parser.parse(text) print("Before:") ast.show(offset=2) assign = ast.ext[0].body.block_items[0] assign.lvalue.name = "y" assign.rvalue.value = 2 print("After:") ast.show(offset=2) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/examples/serialize_ast.py0000664000175000017500000000154415134157072017743 0ustar00elibeneliben# ----------------------------------------------------------------- # pycparser: serialize_ast.py # # Simple example of serializing AST # # Hart Chu [https://github.com/CtheSky] # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ----------------------------------------------------------------- import pickle import sys import tempfile sys.path.extend([".", ".."]) from pycparser import c_parser text = r""" void func(void) { x = 1; } """ if __name__ == "__main__": parser = c_parser.CParser() ast = parser.parse(text) with tempfile.NamedTemporaryFile(delete=False, suffix=".pickle") as f: dump_filename = f.name pickle.dump(ast, f, protocol=pickle.HIGHEST_PROTOCOL) print(f"Dumped to {dump_filename}") # Deserialize. with open(dump_filename, "rb") as f: ast = pickle.load(f) ast.show() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/examples/using_cpp_libc.py0000664000175000017500000000144615134157072020066 0ustar00elibeneliben# ----------------------------------------------------------------- # pycparser: using_cpp_libc.py # # Shows how to use 'cpp' (the C pre-processor binary) and "fake" libc includes # to parse a file that includes standard C headers. # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ----------------------------------------------------------------- import sys # This is not required if you've installed pycparser into # your site-packages/ with setup.py sys.path.extend([".", ".."]) from pycparser import parse_file if __name__ == "__main__": if len(sys.argv) > 1: filename = sys.argv[1] else: filename = "examples/c_files/year.c" ast = parse_file( filename, use_cpp=True, cpp_path="cpp", cpp_args=r"-Iutils/fake_libc_include" ) ast.show() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/examples/using_gcc_E_libc.py0000664000175000017500000000165715134157072020310 0ustar00elibeneliben# ------------------------------------------------------------------------------- # pycparser: using_gcc_E_libc.py # # Similar to the using_cpp_libc.py example, but uses 'gcc -E' instead # of 'cpp'. The same can be achieved with Clang instead of gcc. If you have # Clang installed, simply replace 'gcc' with 'clang' here. # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ------------------------------------------------------------------------------- import sys # This is not required if you've installed pycparser into # your site-packages/ with setup.py sys.path.extend([".", ".."]) from pycparser import parse_file if __name__ == "__main__": if len(sys.argv) > 1: filename = sys.argv[1] else: filename = "examples/c_files/year.c" ast = parse_file( filename, use_cpp=True, cpp_path="gcc", cpp_args=["-E", r"-Iutils/fake_libc_include"], ) ast.show() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4642105 pycparser-3.0/pycparser/0000775000175000017500000000000015134160755014723 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769005217.0 pycparser-3.0/pycparser/__init__.py0000664000175000017500000000541515134160241017027 0ustar00elibeneliben# ----------------------------------------------------------------- # pycparser: __init__.py # # This package file exports some convenience functions for # interacting with pycparser # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ----------------------------------------------------------------- __all__ = ["c_lexer", "c_parser", "c_ast"] __version__ = "3.00" import io from subprocess import check_output from . import c_parser CParser = c_parser.CParser def preprocess_file(filename, cpp_path="cpp", cpp_args=""): """Preprocess a file using cpp. filename: Name of the file you want to preprocess. cpp_path: cpp_args: Refer to the documentation of parse_file for the meaning of these arguments. When successful, returns the preprocessed file's contents. Errors from cpp will be printed out. """ path_list = [cpp_path] if isinstance(cpp_args, list): path_list += cpp_args elif cpp_args != "": path_list += [cpp_args] path_list += [filename] try: # Note the use of universal_newlines to treat all newlines # as \n for Python's purpose text = check_output(path_list, universal_newlines=True) except OSError as e: raise RuntimeError( "Unable to invoke 'cpp'. " + "Make sure its path was passed correctly\n" + f"Original error: {e}" ) return text def parse_file( filename, use_cpp=False, cpp_path="cpp", cpp_args="", parser=None, encoding=None ): """Parse a C file using pycparser. filename: Name of the file you want to parse. use_cpp: Set to True if you want to execute the C pre-processor on the file prior to parsing it. cpp_path: If use_cpp is True, this is the path to 'cpp' on your system. If no path is provided, it attempts to just execute 'cpp', so it must be in your PATH. cpp_args: If use_cpp is True, set this to the command line arguments strings to cpp. Be careful with quotes - it's best to pass a raw string (r'') here. For example: r'-I../utils/fake_libc_include' If several arguments are required, pass a list of strings. encoding: Encoding to use for the file to parse parser: Optional parser object to be used instead of the default CParser When successful, an AST is returned. ParseError can be thrown if the file doesn't parse successfully. Errors from cpp will be printed out. """ if use_cpp: text = preprocess_file(filename, cpp_path, cpp_args) else: with io.open(filename, encoding=encoding) as f: text = f.read() if parser is None: parser = CParser() return parser.parse(text, filename) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/pycparser/_ast_gen.py0000664000175000017500000002603415134157072017057 0ustar00elibeneliben# ----------------------------------------------------------------- # _ast_gen.py # # Generates the AST Node classes from a specification given in # a configuration file. This module can also be run as a script to # regenerate c_ast.py from _c_ast.cfg (from the repo root or the # pycparser/ directory). Use 'make check' to reformat the generated # file after running this script. # # The design of this module was inspired by astgen.py from the # Python 2.5 code-base. # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ----------------------------------------------------------------- from string import Template import os from typing import IO class ASTCodeGenerator: def __init__(self, cfg_filename="_c_ast.cfg"): """Initialize the code generator from a configuration file. """ self.cfg_filename = cfg_filename self.node_cfg = [ NodeCfg(name, contents) for (name, contents) in self.parse_cfgfile(cfg_filename) ] def generate(self, file: IO[str]) -> None: """Generates the code into file, an open file buffer.""" src = Template(_PROLOGUE_COMMENT).substitute(cfg_filename=self.cfg_filename) src += _PROLOGUE_CODE for node_cfg in self.node_cfg: src += node_cfg.generate_source() + "\n\n" file.write(src) def parse_cfgfile(self, filename): """Parse the configuration file and yield pairs of (name, contents) for each node. """ with open(filename, "r") as f: for line in f: line = line.strip() if not line or line.startswith("#"): continue colon_i = line.find(":") lbracket_i = line.find("[") rbracket_i = line.find("]") if colon_i < 1 or lbracket_i <= colon_i or rbracket_i <= lbracket_i: raise RuntimeError(f"Invalid line in {filename}:\n{line}\n") name = line[:colon_i] val = line[lbracket_i + 1 : rbracket_i] vallist = [v.strip() for v in val.split(",")] if val else [] yield name, vallist class NodeCfg: """Node configuration. name: node name contents: a list of contents - attributes and child nodes See comment at the top of the configuration file for details. """ def __init__(self, name, contents): self.name = name self.all_entries = [] self.attr = [] self.child = [] self.seq_child = [] for entry in contents: clean_entry = entry.rstrip("*") self.all_entries.append(clean_entry) if entry.endswith("**"): self.seq_child.append(clean_entry) elif entry.endswith("*"): self.child.append(clean_entry) else: self.attr.append(entry) def generate_source(self): src = self._gen_init() src += "\n" + self._gen_children() src += "\n" + self._gen_iter() src += "\n" + self._gen_attr_names() return src def _gen_init(self): src = f"class {self.name}(Node):\n" if self.all_entries: args = ", ".join(self.all_entries) slots = ", ".join(f"'{e}'" for e in self.all_entries) slots += ", 'coord', '__weakref__'" arglist = f"(self, {args}, coord=None)" else: slots = "'coord', '__weakref__'" arglist = "(self, coord=None)" src += f" __slots__ = ({slots})\n" src += f" def __init__{arglist}:\n" for name in self.all_entries + ["coord"]: src += f" self.{name} = {name}\n" return src def _gen_children(self): src = " def children(self):\n" if self.all_entries: src += " nodelist = []\n" for child in self.child: src += f" if self.{child} is not None:\n" src += f' nodelist.append(("{child}", self.{child}))\n' for seq_child in self.seq_child: src += f" for i, child in enumerate(self.{seq_child} or []):\n" src += f' nodelist.append((f"{seq_child}[{{i}}]", child))\n' src += " return tuple(nodelist)\n" else: src += " return ()\n" return src def _gen_iter(self): src = " def __iter__(self):\n" if self.all_entries: for child in self.child: src += f" if self.{child} is not None:\n" src += f" yield self.{child}\n" for seq_child in self.seq_child: src += f" for child in (self.{seq_child} or []):\n" src += " yield child\n" if not (self.child or self.seq_child): # Empty generator src += " return\n" + " yield\n" else: # Empty generator src += " return\n" + " yield\n" return src def _gen_attr_names(self): src = " attr_names = (" + "".join(f"{nm!r}, " for nm in self.attr) + ")" return src _PROLOGUE_COMMENT = r"""#----------------------------------------------------------------- # ** ATTENTION ** # This code was automatically generated from _c_ast.cfg # # Do not modify it directly. Modify the configuration file and # run the generator again. # ** ** *** ** ** # # pycparser: c_ast.py # # AST Node classes. # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD #----------------------------------------------------------------- """ _PROLOGUE_CODE = r''' import sys from typing import Any, ClassVar, IO, Optional def _repr(obj): """ Get the representation of an object, with dedicated pprint-like format for lists. """ if isinstance(obj, list): return '[' + (',\n '.join((_repr(e).replace('\n', '\n ') for e in obj))) + '\n]' else: return repr(obj) class Node: __slots__ = () """ Abstract base class for AST nodes. """ attr_names: ClassVar[tuple[str, ...]] = () coord: Optional[Any] def __repr__(self): """ Generates a python representation of the current node """ result = self.__class__.__name__ + '(' indent = '' separator = '' for name in self.__slots__[:-2]: result += separator result += indent result += name + '=' + (_repr(getattr(self, name)).replace('\n', '\n ' + (' ' * (len(name) + len(self.__class__.__name__))))) separator = ',' indent = '\n ' + (' ' * len(self.__class__.__name__)) result += indent + ')' return result def children(self): """ A sequence of all children that are Nodes """ pass def show( self, buf: IO[str] = sys.stdout, offset: int = 0, attrnames: bool = False, showemptyattrs: bool = True, nodenames: bool = False, showcoord: bool = False, _my_node_name: Optional[str] = None, ): """ Pretty print the Node and all its attributes and children (recursively) to a buffer. buf: Open IO buffer into which the Node is printed. offset: Initial offset (amount of leading spaces) attrnames: True if you want to see the attribute names in name=value pairs. False to only see the values. showemptyattrs: False if you want to suppress printing empty attributes. nodenames: True if you want to see the actual node names within their parents. showcoord: Do you want the coordinates of each Node to be displayed. """ lead = ' ' * offset if nodenames and _my_node_name is not None: buf.write(lead + self.__class__.__name__+ ' <' + _my_node_name + '>: ') else: buf.write(lead + self.__class__.__name__+ ': ') if self.attr_names: def is_empty(v): v is None or (hasattr(v, '__len__') and len(v) == 0) nvlist = [(n, getattr(self,n)) for n in self.attr_names \ if showemptyattrs or not is_empty(getattr(self,n))] if attrnames: attrstr = ', '.join(f'{name}={value}' for name, value in nvlist) else: attrstr = ', '.join(f'{value}' for _, value in nvlist) buf.write(attrstr) if showcoord: buf.write(f' (at {self.coord})') buf.write('\n') for (child_name, child) in self.children(): child.show( buf, offset=offset + 2, attrnames=attrnames, showemptyattrs=showemptyattrs, nodenames=nodenames, showcoord=showcoord, _my_node_name=child_name) class NodeVisitor: """ A base NodeVisitor class for visiting c_ast nodes. Subclass it and define your own visit_XXX methods, where XXX is the class name you want to visit with these methods. For example: class ConstantVisitor(NodeVisitor): def __init__(self): self.values = [] def visit_Constant(self, node): self.values.append(node.value) Creates a list of values of all the constant nodes encountered below the given node. To use it: cv = ConstantVisitor() cv.visit(node) Notes: * generic_visit() will be called for AST nodes for which no visit_XXX method was defined. * The children of nodes for which a visit_XXX was defined will not be visited - if you need this, call generic_visit() on the node. You can use: NodeVisitor.generic_visit(self, node) * Modeled after Python's own AST visiting facilities (the ast module of Python 3.0) """ _method_cache = None def visit(self, node: Node): """ Visit a node. """ if self._method_cache is None: self._method_cache = {} visitor = self._method_cache.get(node.__class__.__name__, None) if visitor is None: method = 'visit_' + node.__class__.__name__ visitor = getattr(self, method, self.generic_visit) self._method_cache[node.__class__.__name__] = visitor return visitor(node) def generic_visit(self, node: Node): """ Called if no explicit visitor function exists for a node. Implements preorder visiting of the node. """ for _, c in node.children(): self.visit(c) ''' if __name__ == "__main__": base_dir = os.path.dirname(os.path.abspath(__file__)) cfg_path = os.path.join(base_dir, "_c_ast.cfg") out_path = os.path.join(base_dir, "c_ast.py") ast_gen = ASTCodeGenerator(cfg_path) with open(out_path, "w") as out: ast_gen.generate(out) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/pycparser/_c_ast.cfg0000664000175000017500000001023714716121044016630 0ustar00elibeneliben#----------------------------------------------------------------- # pycparser: _c_ast.cfg # # Defines the AST Node classes used in pycparser. # # Each entry is a Node sub-class name, listing the attributes # and child nodes of the class: # * - a child node # ** - a sequence of child nodes # - an attribute # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD #----------------------------------------------------------------- # ArrayDecl is a nested declaration of an array with the given type. # dim: the dimension (for example, constant 42) # dim_quals: list of dimension qualifiers, to support C99's allowing 'const' # and 'static' within the array dimension in function declarations. ArrayDecl: [type*, dim*, dim_quals] ArrayRef: [name*, subscript*] # op: =, +=, /= etc. # Assignment: [op, lvalue*, rvalue*] Alignas: [alignment*] BinaryOp: [op, left*, right*] Break: [] Case: [expr*, stmts**] Cast: [to_type*, expr*] # Compound statement in C99 is a list of block items (declarations or # statements). # Compound: [block_items**] # Compound literal (anonymous aggregate) for C99. # (type-name) {initializer_list} # type: the typename # init: InitList for the initializer list # CompoundLiteral: [type*, init*] # type: int, char, float, string, etc. # Constant: [type, value] Continue: [] # name: the variable being declared # quals: list of qualifiers (const, volatile) # funcspec: list function specifiers (i.e. inline in C99) # storage: list of storage specifiers (extern, register, etc.) # type: declaration type (probably nested with all the modifiers) # init: initialization value, or None # bitsize: bit field size, or None # Decl: [name, quals, align, storage, funcspec, type*, init*, bitsize*] DeclList: [decls**] Default: [stmts**] DoWhile: [cond*, stmt*] # Represents the ellipsis (...) parameter in a function # declaration # EllipsisParam: [] # An empty statement (a semicolon ';' on its own) # EmptyStatement: [] # Enumeration type specifier # name: an optional ID # values: an EnumeratorList # Enum: [name, values*] # A name/value pair for enumeration values # Enumerator: [name, value*] # A list of enumerators # EnumeratorList: [enumerators**] # A list of expressions separated by the comma operator. # ExprList: [exprs**] # This is the top of the AST, representing a single C file (a # translation unit in K&R jargon). It contains a list of # "external-declaration"s, which is either declarations (Decl), # Typedef or function definitions (FuncDef). # FileAST: [ext**] # for (init; cond; next) stmt # For: [init*, cond*, next*, stmt*] # name: Id # args: ExprList # FuncCall: [name*, args*] # type (args) # FuncDecl: [args*, type*] # Function definition: a declarator for the function name and # a body, which is a compound statement. # There's an optional list of parameter declarations for old # K&R-style definitions # FuncDef: [decl*, param_decls**, body*] Goto: [name] ID: [name] # Holder for types that are a simple identifier (e.g. the built # ins void, char etc. and typedef-defined types) # IdentifierType: [names] If: [cond*, iftrue*, iffalse*] # An initialization list used for compound literals. # InitList: [exprs**] Label: [name, stmt*] # A named initializer for C99. # The name of a NamedInitializer is a sequence of Nodes, because # names can be hierarchical and contain constant expressions. # NamedInitializer: [name**, expr*] # a list of comma separated function parameter declarations # ParamList: [params**] PtrDecl: [quals, type*] Return: [expr*] StaticAssert: [cond*, message*] # name: struct tag name # decls: declaration of members # Struct: [name, decls**] # type: . or -> # name.field or name->field # StructRef: [name*, type, field*] Switch: [cond*, stmt*] # cond ? iftrue : iffalse # TernaryOp: [cond*, iftrue*, iffalse*] # A base type declaration # TypeDecl: [declname, quals, align, type*] # A typedef declaration. # Very similar to Decl, but without some attributes # Typedef: [name, quals, storage, type*] Typename: [name, quals, align, type*] UnaryOp: [op, expr*] # name: union tag name # decls: declaration of members # Union: [name, decls**] While: [cond*, stmt*] Pragma: [string] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/pycparser/ast_transforms.py0000664000175000017500000001341315134157072020342 0ustar00elibeneliben# ------------------------------------------------------------------------------ # pycparser: ast_transforms.py # # Some utilities used by the parser to create a friendlier AST. # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ------------------------------------------------------------------------------ from typing import Any, List, Tuple, cast from . import c_ast def fix_switch_cases(switch_node: c_ast.Switch) -> c_ast.Switch: """The 'case' statements in a 'switch' come out of parsing with one child node, so subsequent statements are just tucked to the parent Compound. Additionally, consecutive (fall-through) case statements come out messy. This is a peculiarity of the C grammar. The following: switch (myvar) { case 10: k = 10; p = k + 1; return 10; case 20: case 30: return 20; default: break; } Creates this tree (pseudo-dump): Switch ID: myvar Compound: Case 10: k = 10 p = k + 1 return 10 Case 20: Case 30: return 20 Default: break The goal of this transform is to fix this mess, turning it into the following: Switch ID: myvar Compound: Case 10: k = 10 p = k + 1 return 10 Case 20: Case 30: return 20 Default: break A fixed AST node is returned. The argument may be modified. """ assert isinstance(switch_node, c_ast.Switch) if not isinstance(switch_node.stmt, c_ast.Compound): return switch_node # The new Compound child for the Switch, which will collect children in the # correct order new_compound = c_ast.Compound([], switch_node.stmt.coord) # The last Case/Default node last_case: c_ast.Case | c_ast.Default | None = None # Goes over the children of the Compound below the Switch, adding them # either directly below new_compound or below the last Case as appropriate # (for `switch(cond) {}`, block_items would have been None) for child in switch_node.stmt.block_items or []: if isinstance(child, (c_ast.Case, c_ast.Default)): # If it's a Case/Default: # 1. Add it to the Compound and mark as "last case" # 2. If its immediate child is also a Case or Default, promote it # to a sibling. new_compound.block_items.append(child) _extract_nested_case(child, new_compound.block_items) last_case = new_compound.block_items[-1] else: # Other statements are added as children to the last case, if it # exists. if last_case is None: new_compound.block_items.append(child) else: last_case.stmts.append(child) switch_node.stmt = new_compound return switch_node def _extract_nested_case( case_node: c_ast.Case | c_ast.Default, stmts_list: List[c_ast.Node] ) -> None: """Recursively extract consecutive Case statements that are made nested by the parser and add them to the stmts_list. """ if isinstance(case_node.stmts[0], (c_ast.Case, c_ast.Default)): nested = case_node.stmts.pop() stmts_list.append(nested) _extract_nested_case(cast(Any, nested), stmts_list) def fix_atomic_specifiers( decl: c_ast.Decl | c_ast.Typedef, ) -> c_ast.Decl | c_ast.Typedef: """Atomic specifiers like _Atomic(type) are unusually structured, conferring a qualifier upon the contained type. This function fixes a decl with atomic specifiers to have a sane AST structure, by removing spurious Typename->TypeDecl pairs and attaching the _Atomic qualifier in the right place. """ # There can be multiple levels of _Atomic in a decl; fix them until a # fixed point is reached. while True: decl, found = _fix_atomic_specifiers_once(decl) if not found: break # Make sure to add an _Atomic qual on the topmost decl if needed. Also # restore the declname on the innermost TypeDecl (it gets placed in the # wrong place during construction). typ: Any = decl while not isinstance(typ, c_ast.TypeDecl): try: typ = typ.type except AttributeError: return decl if "_Atomic" in typ.quals and "_Atomic" not in decl.quals: decl.quals.append("_Atomic") if typ.declname is None: typ.declname = decl.name return decl def _fix_atomic_specifiers_once( decl: c_ast.Decl | c_ast.Typedef, ) -> Tuple[c_ast.Decl | c_ast.Typedef, bool]: """Performs one 'fix' round of atomic specifiers. Returns (modified_decl, found) where found is True iff a fix was made. """ parent: Any = decl grandparent: Any = None node: Any = decl.type while node is not None: if isinstance(node, c_ast.Typename) and "_Atomic" in node.quals: break try: grandparent = parent parent = node node = node.type except AttributeError: # If we've reached a node without a `type` field, it means we won't # find what we're looking for at this point; give up the search # and return the original decl unmodified. return decl, False assert isinstance(parent, c_ast.TypeDecl) assert grandparent is not None cast(Any, grandparent).type = node.type if "_Atomic" not in node.type.quals: node.type.quals.append("_Atomic") return decl, True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/pycparser/c_ast.py0000664000175000017500000010027215134157072016366 0ustar00elibeneliben# ----------------------------------------------------------------- # ** ATTENTION ** # This code was automatically generated from _c_ast.cfg # # Do not modify it directly. Modify the configuration file and # run the generator again. # ** ** *** ** ** # # pycparser: c_ast.py # # AST Node classes. # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ----------------------------------------------------------------- import sys from typing import Any, ClassVar, IO, Optional def _repr(obj): """ Get the representation of an object, with dedicated pprint-like format for lists. """ if isinstance(obj, list): return "[" + (",\n ".join((_repr(e).replace("\n", "\n ") for e in obj))) + "\n]" else: return repr(obj) class Node: __slots__ = () """ Abstract base class for AST nodes. """ attr_names: ClassVar[tuple[str, ...]] = () coord: Optional[Any] def __repr__(self): """Generates a python representation of the current node""" result = self.__class__.__name__ + "(" indent = "" separator = "" for name in self.__slots__[:-2]: result += separator result += indent result += ( name + "=" + ( _repr(getattr(self, name)).replace( "\n", "\n " + (" " * (len(name) + len(self.__class__.__name__))), ) ) ) separator = "," indent = "\n " + (" " * len(self.__class__.__name__)) result += indent + ")" return result def children(self): """A sequence of all children that are Nodes""" pass def show( self, buf: IO[str] = sys.stdout, offset: int = 0, attrnames: bool = False, showemptyattrs: bool = True, nodenames: bool = False, showcoord: bool = False, _my_node_name: Optional[str] = None, ): """Pretty print the Node and all its attributes and children (recursively) to a buffer. buf: Open IO buffer into which the Node is printed. offset: Initial offset (amount of leading spaces) attrnames: True if you want to see the attribute names in name=value pairs. False to only see the values. showemptyattrs: False if you want to suppress printing empty attributes. nodenames: True if you want to see the actual node names within their parents. showcoord: Do you want the coordinates of each Node to be displayed. """ lead = " " * offset if nodenames and _my_node_name is not None: buf.write(lead + self.__class__.__name__ + " <" + _my_node_name + ">: ") else: buf.write(lead + self.__class__.__name__ + ": ") if self.attr_names: def is_empty(v): v is None or (hasattr(v, "__len__") and len(v) == 0) nvlist = [ (n, getattr(self, n)) for n in self.attr_names if showemptyattrs or not is_empty(getattr(self, n)) ] if attrnames: attrstr = ", ".join(f"{name}={value}" for name, value in nvlist) else: attrstr = ", ".join(f"{value}" for _, value in nvlist) buf.write(attrstr) if showcoord: buf.write(f" (at {self.coord})") buf.write("\n") for child_name, child in self.children(): child.show( buf, offset=offset + 2, attrnames=attrnames, showemptyattrs=showemptyattrs, nodenames=nodenames, showcoord=showcoord, _my_node_name=child_name, ) class NodeVisitor: """A base NodeVisitor class for visiting c_ast nodes. Subclass it and define your own visit_XXX methods, where XXX is the class name you want to visit with these methods. For example: class ConstantVisitor(NodeVisitor): def __init__(self): self.values = [] def visit_Constant(self, node): self.values.append(node.value) Creates a list of values of all the constant nodes encountered below the given node. To use it: cv = ConstantVisitor() cv.visit(node) Notes: * generic_visit() will be called for AST nodes for which no visit_XXX method was defined. * The children of nodes for which a visit_XXX was defined will not be visited - if you need this, call generic_visit() on the node. You can use: NodeVisitor.generic_visit(self, node) * Modeled after Python's own AST visiting facilities (the ast module of Python 3.0) """ _method_cache = None def visit(self, node: Node): """Visit a node.""" if self._method_cache is None: self._method_cache = {} visitor = self._method_cache.get(node.__class__.__name__, None) if visitor is None: method = "visit_" + node.__class__.__name__ visitor = getattr(self, method, self.generic_visit) self._method_cache[node.__class__.__name__] = visitor return visitor(node) def generic_visit(self, node: Node): """Called if no explicit visitor function exists for a node. Implements preorder visiting of the node. """ for _, c in node.children(): self.visit(c) class ArrayDecl(Node): __slots__ = ("type", "dim", "dim_quals", "coord", "__weakref__") def __init__(self, type, dim, dim_quals, coord=None): self.type = type self.dim = dim self.dim_quals = dim_quals self.coord = coord def children(self): nodelist = [] if self.type is not None: nodelist.append(("type", self.type)) if self.dim is not None: nodelist.append(("dim", self.dim)) return tuple(nodelist) def __iter__(self): if self.type is not None: yield self.type if self.dim is not None: yield self.dim attr_names = ("dim_quals",) class ArrayRef(Node): __slots__ = ("name", "subscript", "coord", "__weakref__") def __init__(self, name, subscript, coord=None): self.name = name self.subscript = subscript self.coord = coord def children(self): nodelist = [] if self.name is not None: nodelist.append(("name", self.name)) if self.subscript is not None: nodelist.append(("subscript", self.subscript)) return tuple(nodelist) def __iter__(self): if self.name is not None: yield self.name if self.subscript is not None: yield self.subscript attr_names = () class Assignment(Node): __slots__ = ("op", "lvalue", "rvalue", "coord", "__weakref__") def __init__(self, op, lvalue, rvalue, coord=None): self.op = op self.lvalue = lvalue self.rvalue = rvalue self.coord = coord def children(self): nodelist = [] if self.lvalue is not None: nodelist.append(("lvalue", self.lvalue)) if self.rvalue is not None: nodelist.append(("rvalue", self.rvalue)) return tuple(nodelist) def __iter__(self): if self.lvalue is not None: yield self.lvalue if self.rvalue is not None: yield self.rvalue attr_names = ("op",) class Alignas(Node): __slots__ = ("alignment", "coord", "__weakref__") def __init__(self, alignment, coord=None): self.alignment = alignment self.coord = coord def children(self): nodelist = [] if self.alignment is not None: nodelist.append(("alignment", self.alignment)) return tuple(nodelist) def __iter__(self): if self.alignment is not None: yield self.alignment attr_names = () class BinaryOp(Node): __slots__ = ("op", "left", "right", "coord", "__weakref__") def __init__(self, op, left, right, coord=None): self.op = op self.left = left self.right = right self.coord = coord def children(self): nodelist = [] if self.left is not None: nodelist.append(("left", self.left)) if self.right is not None: nodelist.append(("right", self.right)) return tuple(nodelist) def __iter__(self): if self.left is not None: yield self.left if self.right is not None: yield self.right attr_names = ("op",) class Break(Node): __slots__ = ("coord", "__weakref__") def __init__(self, coord=None): self.coord = coord def children(self): return () def __iter__(self): return yield attr_names = () class Case(Node): __slots__ = ("expr", "stmts", "coord", "__weakref__") def __init__(self, expr, stmts, coord=None): self.expr = expr self.stmts = stmts self.coord = coord def children(self): nodelist = [] if self.expr is not None: nodelist.append(("expr", self.expr)) for i, child in enumerate(self.stmts or []): nodelist.append((f"stmts[{i}]", child)) return tuple(nodelist) def __iter__(self): if self.expr is not None: yield self.expr for child in self.stmts or []: yield child attr_names = () class Cast(Node): __slots__ = ("to_type", "expr", "coord", "__weakref__") def __init__(self, to_type, expr, coord=None): self.to_type = to_type self.expr = expr self.coord = coord def children(self): nodelist = [] if self.to_type is not None: nodelist.append(("to_type", self.to_type)) if self.expr is not None: nodelist.append(("expr", self.expr)) return tuple(nodelist) def __iter__(self): if self.to_type is not None: yield self.to_type if self.expr is not None: yield self.expr attr_names = () class Compound(Node): __slots__ = ("block_items", "coord", "__weakref__") def __init__(self, block_items, coord=None): self.block_items = block_items self.coord = coord def children(self): nodelist = [] for i, child in enumerate(self.block_items or []): nodelist.append((f"block_items[{i}]", child)) return tuple(nodelist) def __iter__(self): for child in self.block_items or []: yield child attr_names = () class CompoundLiteral(Node): __slots__ = ("type", "init", "coord", "__weakref__") def __init__(self, type, init, coord=None): self.type = type self.init = init self.coord = coord def children(self): nodelist = [] if self.type is not None: nodelist.append(("type", self.type)) if self.init is not None: nodelist.append(("init", self.init)) return tuple(nodelist) def __iter__(self): if self.type is not None: yield self.type if self.init is not None: yield self.init attr_names = () class Constant(Node): __slots__ = ("type", "value", "coord", "__weakref__") def __init__(self, type, value, coord=None): self.type = type self.value = value self.coord = coord def children(self): nodelist = [] return tuple(nodelist) def __iter__(self): return yield attr_names = ( "type", "value", ) class Continue(Node): __slots__ = ("coord", "__weakref__") def __init__(self, coord=None): self.coord = coord def children(self): return () def __iter__(self): return yield attr_names = () class Decl(Node): __slots__ = ( "name", "quals", "align", "storage", "funcspec", "type", "init", "bitsize", "coord", "__weakref__", ) def __init__( self, name, quals, align, storage, funcspec, type, init, bitsize, coord=None ): self.name = name self.quals = quals self.align = align self.storage = storage self.funcspec = funcspec self.type = type self.init = init self.bitsize = bitsize self.coord = coord def children(self): nodelist = [] if self.type is not None: nodelist.append(("type", self.type)) if self.init is not None: nodelist.append(("init", self.init)) if self.bitsize is not None: nodelist.append(("bitsize", self.bitsize)) return tuple(nodelist) def __iter__(self): if self.type is not None: yield self.type if self.init is not None: yield self.init if self.bitsize is not None: yield self.bitsize attr_names = ( "name", "quals", "align", "storage", "funcspec", ) class DeclList(Node): __slots__ = ("decls", "coord", "__weakref__") def __init__(self, decls, coord=None): self.decls = decls self.coord = coord def children(self): nodelist = [] for i, child in enumerate(self.decls or []): nodelist.append((f"decls[{i}]", child)) return tuple(nodelist) def __iter__(self): for child in self.decls or []: yield child attr_names = () class Default(Node): __slots__ = ("stmts", "coord", "__weakref__") def __init__(self, stmts, coord=None): self.stmts = stmts self.coord = coord def children(self): nodelist = [] for i, child in enumerate(self.stmts or []): nodelist.append((f"stmts[{i}]", child)) return tuple(nodelist) def __iter__(self): for child in self.stmts or []: yield child attr_names = () class DoWhile(Node): __slots__ = ("cond", "stmt", "coord", "__weakref__") def __init__(self, cond, stmt, coord=None): self.cond = cond self.stmt = stmt self.coord = coord def children(self): nodelist = [] if self.cond is not None: nodelist.append(("cond", self.cond)) if self.stmt is not None: nodelist.append(("stmt", self.stmt)) return tuple(nodelist) def __iter__(self): if self.cond is not None: yield self.cond if self.stmt is not None: yield self.stmt attr_names = () class EllipsisParam(Node): __slots__ = ("coord", "__weakref__") def __init__(self, coord=None): self.coord = coord def children(self): return () def __iter__(self): return yield attr_names = () class EmptyStatement(Node): __slots__ = ("coord", "__weakref__") def __init__(self, coord=None): self.coord = coord def children(self): return () def __iter__(self): return yield attr_names = () class Enum(Node): __slots__ = ("name", "values", "coord", "__weakref__") def __init__(self, name, values, coord=None): self.name = name self.values = values self.coord = coord def children(self): nodelist = [] if self.values is not None: nodelist.append(("values", self.values)) return tuple(nodelist) def __iter__(self): if self.values is not None: yield self.values attr_names = ("name",) class Enumerator(Node): __slots__ = ("name", "value", "coord", "__weakref__") def __init__(self, name, value, coord=None): self.name = name self.value = value self.coord = coord def children(self): nodelist = [] if self.value is not None: nodelist.append(("value", self.value)) return tuple(nodelist) def __iter__(self): if self.value is not None: yield self.value attr_names = ("name",) class EnumeratorList(Node): __slots__ = ("enumerators", "coord", "__weakref__") def __init__(self, enumerators, coord=None): self.enumerators = enumerators self.coord = coord def children(self): nodelist = [] for i, child in enumerate(self.enumerators or []): nodelist.append((f"enumerators[{i}]", child)) return tuple(nodelist) def __iter__(self): for child in self.enumerators or []: yield child attr_names = () class ExprList(Node): __slots__ = ("exprs", "coord", "__weakref__") def __init__(self, exprs, coord=None): self.exprs = exprs self.coord = coord def children(self): nodelist = [] for i, child in enumerate(self.exprs or []): nodelist.append((f"exprs[{i}]", child)) return tuple(nodelist) def __iter__(self): for child in self.exprs or []: yield child attr_names = () class FileAST(Node): __slots__ = ("ext", "coord", "__weakref__") def __init__(self, ext, coord=None): self.ext = ext self.coord = coord def children(self): nodelist = [] for i, child in enumerate(self.ext or []): nodelist.append((f"ext[{i}]", child)) return tuple(nodelist) def __iter__(self): for child in self.ext or []: yield child attr_names = () class For(Node): __slots__ = ("init", "cond", "next", "stmt", "coord", "__weakref__") def __init__(self, init, cond, next, stmt, coord=None): self.init = init self.cond = cond self.next = next self.stmt = stmt self.coord = coord def children(self): nodelist = [] if self.init is not None: nodelist.append(("init", self.init)) if self.cond is not None: nodelist.append(("cond", self.cond)) if self.next is not None: nodelist.append(("next", self.next)) if self.stmt is not None: nodelist.append(("stmt", self.stmt)) return tuple(nodelist) def __iter__(self): if self.init is not None: yield self.init if self.cond is not None: yield self.cond if self.next is not None: yield self.next if self.stmt is not None: yield self.stmt attr_names = () class FuncCall(Node): __slots__ = ("name", "args", "coord", "__weakref__") def __init__(self, name, args, coord=None): self.name = name self.args = args self.coord = coord def children(self): nodelist = [] if self.name is not None: nodelist.append(("name", self.name)) if self.args is not None: nodelist.append(("args", self.args)) return tuple(nodelist) def __iter__(self): if self.name is not None: yield self.name if self.args is not None: yield self.args attr_names = () class FuncDecl(Node): __slots__ = ("args", "type", "coord", "__weakref__") def __init__(self, args, type, coord=None): self.args = args self.type = type self.coord = coord def children(self): nodelist = [] if self.args is not None: nodelist.append(("args", self.args)) if self.type is not None: nodelist.append(("type", self.type)) return tuple(nodelist) def __iter__(self): if self.args is not None: yield self.args if self.type is not None: yield self.type attr_names = () class FuncDef(Node): __slots__ = ("decl", "param_decls", "body", "coord", "__weakref__") def __init__(self, decl, param_decls, body, coord=None): self.decl = decl self.param_decls = param_decls self.body = body self.coord = coord def children(self): nodelist = [] if self.decl is not None: nodelist.append(("decl", self.decl)) if self.body is not None: nodelist.append(("body", self.body)) for i, child in enumerate(self.param_decls or []): nodelist.append((f"param_decls[{i}]", child)) return tuple(nodelist) def __iter__(self): if self.decl is not None: yield self.decl if self.body is not None: yield self.body for child in self.param_decls or []: yield child attr_names = () class Goto(Node): __slots__ = ("name", "coord", "__weakref__") def __init__(self, name, coord=None): self.name = name self.coord = coord def children(self): nodelist = [] return tuple(nodelist) def __iter__(self): return yield attr_names = ("name",) class ID(Node): __slots__ = ("name", "coord", "__weakref__") def __init__(self, name, coord=None): self.name = name self.coord = coord def children(self): nodelist = [] return tuple(nodelist) def __iter__(self): return yield attr_names = ("name",) class IdentifierType(Node): __slots__ = ("names", "coord", "__weakref__") def __init__(self, names, coord=None): self.names = names self.coord = coord def children(self): nodelist = [] return tuple(nodelist) def __iter__(self): return yield attr_names = ("names",) class If(Node): __slots__ = ("cond", "iftrue", "iffalse", "coord", "__weakref__") def __init__(self, cond, iftrue, iffalse, coord=None): self.cond = cond self.iftrue = iftrue self.iffalse = iffalse self.coord = coord def children(self): nodelist = [] if self.cond is not None: nodelist.append(("cond", self.cond)) if self.iftrue is not None: nodelist.append(("iftrue", self.iftrue)) if self.iffalse is not None: nodelist.append(("iffalse", self.iffalse)) return tuple(nodelist) def __iter__(self): if self.cond is not None: yield self.cond if self.iftrue is not None: yield self.iftrue if self.iffalse is not None: yield self.iffalse attr_names = () class InitList(Node): __slots__ = ("exprs", "coord", "__weakref__") def __init__(self, exprs, coord=None): self.exprs = exprs self.coord = coord def children(self): nodelist = [] for i, child in enumerate(self.exprs or []): nodelist.append((f"exprs[{i}]", child)) return tuple(nodelist) def __iter__(self): for child in self.exprs or []: yield child attr_names = () class Label(Node): __slots__ = ("name", "stmt", "coord", "__weakref__") def __init__(self, name, stmt, coord=None): self.name = name self.stmt = stmt self.coord = coord def children(self): nodelist = [] if self.stmt is not None: nodelist.append(("stmt", self.stmt)) return tuple(nodelist) def __iter__(self): if self.stmt is not None: yield self.stmt attr_names = ("name",) class NamedInitializer(Node): __slots__ = ("name", "expr", "coord", "__weakref__") def __init__(self, name, expr, coord=None): self.name = name self.expr = expr self.coord = coord def children(self): nodelist = [] if self.expr is not None: nodelist.append(("expr", self.expr)) for i, child in enumerate(self.name or []): nodelist.append((f"name[{i}]", child)) return tuple(nodelist) def __iter__(self): if self.expr is not None: yield self.expr for child in self.name or []: yield child attr_names = () class ParamList(Node): __slots__ = ("params", "coord", "__weakref__") def __init__(self, params, coord=None): self.params = params self.coord = coord def children(self): nodelist = [] for i, child in enumerate(self.params or []): nodelist.append((f"params[{i}]", child)) return tuple(nodelist) def __iter__(self): for child in self.params or []: yield child attr_names = () class PtrDecl(Node): __slots__ = ("quals", "type", "coord", "__weakref__") def __init__(self, quals, type, coord=None): self.quals = quals self.type = type self.coord = coord def children(self): nodelist = [] if self.type is not None: nodelist.append(("type", self.type)) return tuple(nodelist) def __iter__(self): if self.type is not None: yield self.type attr_names = ("quals",) class Return(Node): __slots__ = ("expr", "coord", "__weakref__") def __init__(self, expr, coord=None): self.expr = expr self.coord = coord def children(self): nodelist = [] if self.expr is not None: nodelist.append(("expr", self.expr)) return tuple(nodelist) def __iter__(self): if self.expr is not None: yield self.expr attr_names = () class StaticAssert(Node): __slots__ = ("cond", "message", "coord", "__weakref__") def __init__(self, cond, message, coord=None): self.cond = cond self.message = message self.coord = coord def children(self): nodelist = [] if self.cond is not None: nodelist.append(("cond", self.cond)) if self.message is not None: nodelist.append(("message", self.message)) return tuple(nodelist) def __iter__(self): if self.cond is not None: yield self.cond if self.message is not None: yield self.message attr_names = () class Struct(Node): __slots__ = ("name", "decls", "coord", "__weakref__") def __init__(self, name, decls, coord=None): self.name = name self.decls = decls self.coord = coord def children(self): nodelist = [] for i, child in enumerate(self.decls or []): nodelist.append((f"decls[{i}]", child)) return tuple(nodelist) def __iter__(self): for child in self.decls or []: yield child attr_names = ("name",) class StructRef(Node): __slots__ = ("name", "type", "field", "coord", "__weakref__") def __init__(self, name, type, field, coord=None): self.name = name self.type = type self.field = field self.coord = coord def children(self): nodelist = [] if self.name is not None: nodelist.append(("name", self.name)) if self.field is not None: nodelist.append(("field", self.field)) return tuple(nodelist) def __iter__(self): if self.name is not None: yield self.name if self.field is not None: yield self.field attr_names = ("type",) class Switch(Node): __slots__ = ("cond", "stmt", "coord", "__weakref__") def __init__(self, cond, stmt, coord=None): self.cond = cond self.stmt = stmt self.coord = coord def children(self): nodelist = [] if self.cond is not None: nodelist.append(("cond", self.cond)) if self.stmt is not None: nodelist.append(("stmt", self.stmt)) return tuple(nodelist) def __iter__(self): if self.cond is not None: yield self.cond if self.stmt is not None: yield self.stmt attr_names = () class TernaryOp(Node): __slots__ = ("cond", "iftrue", "iffalse", "coord", "__weakref__") def __init__(self, cond, iftrue, iffalse, coord=None): self.cond = cond self.iftrue = iftrue self.iffalse = iffalse self.coord = coord def children(self): nodelist = [] if self.cond is not None: nodelist.append(("cond", self.cond)) if self.iftrue is not None: nodelist.append(("iftrue", self.iftrue)) if self.iffalse is not None: nodelist.append(("iffalse", self.iffalse)) return tuple(nodelist) def __iter__(self): if self.cond is not None: yield self.cond if self.iftrue is not None: yield self.iftrue if self.iffalse is not None: yield self.iffalse attr_names = () class TypeDecl(Node): __slots__ = ("declname", "quals", "align", "type", "coord", "__weakref__") def __init__(self, declname, quals, align, type, coord=None): self.declname = declname self.quals = quals self.align = align self.type = type self.coord = coord def children(self): nodelist = [] if self.type is not None: nodelist.append(("type", self.type)) return tuple(nodelist) def __iter__(self): if self.type is not None: yield self.type attr_names = ( "declname", "quals", "align", ) class Typedef(Node): __slots__ = ("name", "quals", "storage", "type", "coord", "__weakref__") def __init__(self, name, quals, storage, type, coord=None): self.name = name self.quals = quals self.storage = storage self.type = type self.coord = coord def children(self): nodelist = [] if self.type is not None: nodelist.append(("type", self.type)) return tuple(nodelist) def __iter__(self): if self.type is not None: yield self.type attr_names = ( "name", "quals", "storage", ) class Typename(Node): __slots__ = ("name", "quals", "align", "type", "coord", "__weakref__") def __init__(self, name, quals, align, type, coord=None): self.name = name self.quals = quals self.align = align self.type = type self.coord = coord def children(self): nodelist = [] if self.type is not None: nodelist.append(("type", self.type)) return tuple(nodelist) def __iter__(self): if self.type is not None: yield self.type attr_names = ( "name", "quals", "align", ) class UnaryOp(Node): __slots__ = ("op", "expr", "coord", "__weakref__") def __init__(self, op, expr, coord=None): self.op = op self.expr = expr self.coord = coord def children(self): nodelist = [] if self.expr is not None: nodelist.append(("expr", self.expr)) return tuple(nodelist) def __iter__(self): if self.expr is not None: yield self.expr attr_names = ("op",) class Union(Node): __slots__ = ("name", "decls", "coord", "__weakref__") def __init__(self, name, decls, coord=None): self.name = name self.decls = decls self.coord = coord def children(self): nodelist = [] for i, child in enumerate(self.decls or []): nodelist.append((f"decls[{i}]", child)) return tuple(nodelist) def __iter__(self): for child in self.decls or []: yield child attr_names = ("name",) class While(Node): __slots__ = ("cond", "stmt", "coord", "__weakref__") def __init__(self, cond, stmt, coord=None): self.cond = cond self.stmt = stmt self.coord = coord def children(self): nodelist = [] if self.cond is not None: nodelist.append(("cond", self.cond)) if self.stmt is not None: nodelist.append(("stmt", self.stmt)) return tuple(nodelist) def __iter__(self): if self.cond is not None: yield self.cond if self.stmt is not None: yield self.stmt attr_names = () class Pragma(Node): __slots__ = ("string", "coord", "__weakref__") def __init__(self, string, coord=None): self.string = string self.coord = coord def children(self): nodelist = [] return tuple(nodelist) def __iter__(self): return yield attr_names = ("string",) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/pycparser/c_generator.py0000664000175000017500000005026515134157072017573 0ustar00elibeneliben# ------------------------------------------------------------------------------ # pycparser: c_generator.py # # C code generator from pycparser AST nodes. # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ------------------------------------------------------------------------------ from typing import Callable, List, Optional from . import c_ast class CGenerator: """Uses the same visitor pattern as c_ast.NodeVisitor, but modified to return a value from each visit method, using string accumulation in generic_visit. """ indent_level: int reduce_parentheses: bool def __init__(self, reduce_parentheses: bool = False) -> None: """Constructs C-code generator reduce_parentheses: if True, eliminates needless parentheses on binary operators """ # Statements start with indentation of self.indent_level spaces, using # the _make_indent method. self.indent_level = 0 self.reduce_parentheses = reduce_parentheses def _make_indent(self) -> str: return " " * self.indent_level def visit(self, node: c_ast.Node) -> str: method = "visit_" + node.__class__.__name__ return getattr(self, method, self.generic_visit)(node) def generic_visit(self, node: Optional[c_ast.Node]) -> str: if node is None: return "" else: return "".join(self.visit(c) for c_name, c in node.children()) def visit_Constant(self, n: c_ast.Constant) -> str: return n.value def visit_ID(self, n: c_ast.ID) -> str: return n.name def visit_Pragma(self, n: c_ast.Pragma) -> str: ret = "#pragma" if n.string: ret += " " + n.string return ret def visit_ArrayRef(self, n: c_ast.ArrayRef) -> str: arrref = self._parenthesize_unless_simple(n.name) return arrref + "[" + self.visit(n.subscript) + "]" def visit_StructRef(self, n: c_ast.StructRef) -> str: sref = self._parenthesize_unless_simple(n.name) return sref + n.type + self.visit(n.field) def visit_FuncCall(self, n: c_ast.FuncCall) -> str: fref = self._parenthesize_unless_simple(n.name) args = self.visit(n.args) if n.args is not None else "" return fref + "(" + args + ")" def visit_UnaryOp(self, n: c_ast.UnaryOp) -> str: match n.op: case "sizeof": # Always parenthesize the argument of sizeof since it can be # a name. return f"sizeof({self.visit(n.expr)})" case "p++": operand = self._parenthesize_unless_simple(n.expr) return f"{operand}++" case "p--": operand = self._parenthesize_unless_simple(n.expr) return f"{operand}--" case _: operand = self._parenthesize_unless_simple(n.expr) return f"{n.op}{operand}" # Precedence map of binary operators: precedence_map = { # Should be in sync with c_parser.CParser.precedence # Higher numbers are stronger binding "||": 0, # weakest binding "&&": 1, "|": 2, "^": 3, "&": 4, "==": 5, "!=": 5, ">": 6, ">=": 6, "<": 6, "<=": 6, ">>": 7, "<<": 7, "+": 8, "-": 8, "*": 9, "/": 9, "%": 9, # strongest binding } def visit_BinaryOp(self, n: c_ast.BinaryOp) -> str: # Note: all binary operators are left-to-right associative # # If `n.left.op` has a stronger or equally binding precedence in # comparison to `n.op`, no parenthesis are needed for the left: # e.g., `(a*b) + c` is equivalent to `a*b + c`, as well as # `(a+b) - c` is equivalent to `a+b - c` (same precedence). # If the left operator is weaker binding than the current, then # parentheses are necessary: # e.g., `(a+b) * c` is NOT equivalent to `a+b * c`. lval_str = self._parenthesize_if( n.left, lambda d: not ( self._is_simple_node(d) or self.reduce_parentheses and isinstance(d, c_ast.BinaryOp) and self.precedence_map[d.op] >= self.precedence_map[n.op] ), ) # If `n.right.op` has a stronger -but not equal- binding precedence, # parenthesis can be omitted on the right: # e.g., `a + (b*c)` is equivalent to `a + b*c`. # If the right operator is weaker or equally binding, then parentheses # are necessary: # e.g., `a * (b+c)` is NOT equivalent to `a * b+c` and # `a - (b+c)` is NOT equivalent to `a - b+c` (same precedence). rval_str = self._parenthesize_if( n.right, lambda d: not ( self._is_simple_node(d) or self.reduce_parentheses and isinstance(d, c_ast.BinaryOp) and self.precedence_map[d.op] > self.precedence_map[n.op] ), ) return f"{lval_str} {n.op} {rval_str}" def visit_Assignment(self, n: c_ast.Assignment) -> str: rval_str = self._parenthesize_if( n.rvalue, lambda n: isinstance(n, c_ast.Assignment) ) return f"{self.visit(n.lvalue)} {n.op} {rval_str}" def visit_IdentifierType(self, n: c_ast.IdentifierType) -> str: return " ".join(n.names) def _visit_expr(self, n: c_ast.Node) -> str: match n: case c_ast.InitList(): return "{" + self.visit(n) + "}" case c_ast.ExprList() | c_ast.Compound(): return "(" + self.visit(n) + ")" case _: return self.visit(n) def visit_Decl(self, n: c_ast.Decl, no_type: bool = False) -> str: # no_type is used when a Decl is part of a DeclList, where the type is # explicitly only for the first declaration in a list. # s = n.name if no_type else self._generate_decl(n) if n.bitsize: s += " : " + self.visit(n.bitsize) if n.init: s += " = " + self._visit_expr(n.init) return s def visit_DeclList(self, n: c_ast.DeclList) -> str: s = self.visit(n.decls[0]) if len(n.decls) > 1: s += ", " + ", ".join( self.visit_Decl(decl, no_type=True) for decl in n.decls[1:] ) return s def visit_Typedef(self, n: c_ast.Typedef) -> str: s = "" if n.storage: s += " ".join(n.storage) + " " s += self._generate_type(n.type) return s def visit_Cast(self, n: c_ast.Cast) -> str: s = "(" + self._generate_type(n.to_type, emit_declname=False) + ")" return s + " " + self._parenthesize_unless_simple(n.expr) def visit_ExprList(self, n: c_ast.ExprList) -> str: visited_subexprs = [] for expr in n.exprs: visited_subexprs.append(self._visit_expr(expr)) return ", ".join(visited_subexprs) def visit_InitList(self, n: c_ast.InitList) -> str: visited_subexprs = [] for expr in n.exprs: visited_subexprs.append(self._visit_expr(expr)) return ", ".join(visited_subexprs) def visit_Enum(self, n: c_ast.Enum) -> str: return self._generate_struct_union_enum(n, name="enum") def visit_Alignas(self, n: c_ast.Alignas) -> str: return "_Alignas({})".format(self.visit(n.alignment)) def visit_Enumerator(self, n: c_ast.Enumerator) -> str: if not n.value: return "{indent}{name},\n".format( indent=self._make_indent(), name=n.name, ) else: return "{indent}{name} = {value},\n".format( indent=self._make_indent(), name=n.name, value=self.visit(n.value), ) def visit_FuncDef(self, n: c_ast.FuncDef) -> str: decl = self.visit(n.decl) self.indent_level = 0 body = self.visit(n.body) if n.param_decls: knrdecls = ";\n".join(self.visit(p) for p in n.param_decls) return decl + "\n" + knrdecls + ";\n" + body + "\n" else: return decl + "\n" + body + "\n" def visit_FileAST(self, n: c_ast.FileAST) -> str: s = "" for ext in n.ext: match ext: case c_ast.FuncDef(): s += self.visit(ext) case c_ast.Pragma(): s += self.visit(ext) + "\n" case _: s += self.visit(ext) + ";\n" return s def visit_Compound(self, n: c_ast.Compound) -> str: s = self._make_indent() + "{\n" self.indent_level += 2 if n.block_items: s += "".join(self._generate_stmt(stmt) for stmt in n.block_items) self.indent_level -= 2 s += self._make_indent() + "}\n" return s def visit_CompoundLiteral(self, n: c_ast.CompoundLiteral) -> str: return "(" + self.visit(n.type) + "){" + self.visit(n.init) + "}" def visit_EmptyStatement(self, n: c_ast.EmptyStatement) -> str: return ";" def visit_ParamList(self, n: c_ast.ParamList) -> str: return ", ".join(self.visit(param) for param in n.params) def visit_Return(self, n: c_ast.Return) -> str: s = "return" if n.expr: s += " " + self.visit(n.expr) return s + ";" def visit_Break(self, n: c_ast.Break) -> str: return "break;" def visit_Continue(self, n: c_ast.Continue) -> str: return "continue;" def visit_TernaryOp(self, n: c_ast.TernaryOp) -> str: s = "(" + self._visit_expr(n.cond) + ") ? " s += "(" + self._visit_expr(n.iftrue) + ") : " s += "(" + self._visit_expr(n.iffalse) + ")" return s def visit_If(self, n: c_ast.If) -> str: s = "if (" if n.cond: s += self.visit(n.cond) s += ")\n" s += self._generate_stmt(n.iftrue, add_indent=True) if n.iffalse: s += self._make_indent() + "else\n" s += self._generate_stmt(n.iffalse, add_indent=True) return s def visit_For(self, n: c_ast.For) -> str: s = "for (" if n.init: s += self.visit(n.init) s += ";" if n.cond: s += " " + self.visit(n.cond) s += ";" if n.next: s += " " + self.visit(n.next) s += ")\n" s += self._generate_stmt(n.stmt, add_indent=True) return s def visit_While(self, n: c_ast.While) -> str: s = "while (" if n.cond: s += self.visit(n.cond) s += ")\n" s += self._generate_stmt(n.stmt, add_indent=True) return s def visit_DoWhile(self, n: c_ast.DoWhile) -> str: s = "do\n" s += self._generate_stmt(n.stmt, add_indent=True) s += self._make_indent() + "while (" if n.cond: s += self.visit(n.cond) s += ");" return s def visit_StaticAssert(self, n: c_ast.StaticAssert) -> str: s = "_Static_assert(" s += self.visit(n.cond) if n.message: s += "," s += self.visit(n.message) s += ")" return s def visit_Switch(self, n: c_ast.Switch) -> str: s = "switch (" + self.visit(n.cond) + ")\n" s += self._generate_stmt(n.stmt, add_indent=True) return s def visit_Case(self, n: c_ast.Case) -> str: s = "case " + self.visit(n.expr) + ":\n" for stmt in n.stmts: s += self._generate_stmt(stmt, add_indent=True) return s def visit_Default(self, n: c_ast.Default) -> str: s = "default:\n" for stmt in n.stmts: s += self._generate_stmt(stmt, add_indent=True) return s def visit_Label(self, n: c_ast.Label) -> str: return n.name + ":\n" + self._generate_stmt(n.stmt) def visit_Goto(self, n: c_ast.Goto) -> str: return "goto " + n.name + ";" def visit_EllipsisParam(self, n: c_ast.EllipsisParam) -> str: return "..." def visit_Struct(self, n: c_ast.Struct) -> str: return self._generate_struct_union_enum(n, "struct") def visit_Typename(self, n: c_ast.Typename) -> str: return self._generate_type(n.type) def visit_Union(self, n: c_ast.Union) -> str: return self._generate_struct_union_enum(n, "union") def visit_NamedInitializer(self, n: c_ast.NamedInitializer) -> str: s = "" for name in n.name: if isinstance(name, c_ast.ID): s += "." + name.name else: s += "[" + self.visit(name) + "]" s += " = " + self._visit_expr(n.expr) return s def visit_FuncDecl(self, n: c_ast.FuncDecl) -> str: return self._generate_type(n) def visit_ArrayDecl(self, n: c_ast.ArrayDecl) -> str: return self._generate_type(n, emit_declname=False) def visit_TypeDecl(self, n: c_ast.TypeDecl) -> str: return self._generate_type(n, emit_declname=False) def visit_PtrDecl(self, n: c_ast.PtrDecl) -> str: return self._generate_type(n, emit_declname=False) def _generate_struct_union_enum( self, n: c_ast.Struct | c_ast.Union | c_ast.Enum, name: str ) -> str: """Generates code for structs, unions, and enums. name should be 'struct', 'union', or 'enum'. """ if name in ("struct", "union"): assert isinstance(n, (c_ast.Struct, c_ast.Union)) members = n.decls body_function = self._generate_struct_union_body else: assert name == "enum" assert isinstance(n, c_ast.Enum) members = None if n.values is None else n.values.enumerators body_function = self._generate_enum_body s = name + " " + (n.name or "") if members is not None: # None means no members # Empty sequence means an empty list of members s += "\n" s += self._make_indent() self.indent_level += 2 s += "{\n" s += body_function(members) self.indent_level -= 2 s += self._make_indent() + "}" return s def _generate_struct_union_body(self, members: List[c_ast.Node]) -> str: return "".join(self._generate_stmt(decl) for decl in members) def _generate_enum_body(self, members: List[c_ast.Enumerator]) -> str: # `[:-2] + '\n'` removes the final `,` from the enumerator list return "".join(self.visit(value) for value in members)[:-2] + "\n" def _generate_stmt(self, n: c_ast.Node, add_indent: bool = False) -> str: """Generation from a statement node. This method exists as a wrapper for individual visit_* methods to handle different treatment of some statements in this context. """ if add_indent: self.indent_level += 2 indent = self._make_indent() if add_indent: self.indent_level -= 2 match n: case ( c_ast.Decl() | c_ast.Assignment() | c_ast.Cast() | c_ast.UnaryOp() | c_ast.BinaryOp() | c_ast.TernaryOp() | c_ast.FuncCall() | c_ast.ArrayRef() | c_ast.StructRef() | c_ast.Constant() | c_ast.ID() | c_ast.Typedef() | c_ast.ExprList() ): # These can also appear in an expression context so no semicolon # is added to them automatically # return indent + self.visit(n) + ";\n" case c_ast.Compound(): # No extra indentation required before the opening brace of a # compound - because it consists of multiple lines it has to # compute its own indentation. # return self.visit(n) case c_ast.If(): return indent + self.visit(n) case _: return indent + self.visit(n) + "\n" def _generate_decl(self, n: c_ast.Decl) -> str: """Generation from a Decl node.""" s = "" if n.funcspec: s = " ".join(n.funcspec) + " " if n.storage: s += " ".join(n.storage) + " " if n.align: s += self.visit(n.align[0]) + " " s += self._generate_type(n.type) return s def _generate_type( self, n: c_ast.Node, modifiers: List[c_ast.Node] = [], emit_declname: bool = True, ) -> str: """Recursive generation from a type node. n is the type node. modifiers collects the PtrDecl, ArrayDecl and FuncDecl modifiers encountered on the way down to a TypeDecl, to allow proper generation from it. """ # ~ print(n, modifiers) match n: case c_ast.TypeDecl(): s = "" if n.quals: s += " ".join(n.quals) + " " s += self.visit(n.type) nstr = n.declname if n.declname and emit_declname else "" # Resolve modifiers. # Wrap in parens to distinguish pointer to array and pointer to # function syntax. # for i, modifier in enumerate(modifiers): match modifier: case c_ast.ArrayDecl(): if i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl): nstr = "(" + nstr + ")" nstr += "[" if modifier.dim_quals: nstr += " ".join(modifier.dim_quals) + " " if modifier.dim is not None: nstr += self.visit(modifier.dim) nstr += "]" case c_ast.FuncDecl(): if i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl): nstr = "(" + nstr + ")" args = ( self.visit(modifier.args) if modifier.args is not None else "" ) nstr += "(" + args + ")" case c_ast.PtrDecl(): if modifier.quals: quals = " ".join(modifier.quals) suffix = f" {nstr}" if nstr else "" nstr = f"* {quals}{suffix}" else: nstr = "*" + nstr if nstr: s += " " + nstr return s case c_ast.Decl(): return self._generate_decl(n.type) case c_ast.Typename(): return self._generate_type(n.type, emit_declname=emit_declname) case c_ast.IdentifierType(): return " ".join(n.names) + " " case c_ast.ArrayDecl() | c_ast.PtrDecl() | c_ast.FuncDecl(): return self._generate_type( n.type, modifiers + [n], emit_declname=emit_declname ) case _: return self.visit(n) def _parenthesize_if( self, n: c_ast.Node, condition: Callable[[c_ast.Node], bool] ) -> str: """Visits 'n' and returns its string representation, parenthesized if the condition function applied to the node returns True. """ s = self._visit_expr(n) if condition(n): return "(" + s + ")" else: return s def _parenthesize_unless_simple(self, n: c_ast.Node) -> str: """Common use case for _parenthesize_if""" return self._parenthesize_if(n, lambda d: not self._is_simple_node(d)) def _is_simple_node(self, n: c_ast.Node) -> bool: """Returns True for nodes that are "simple" - i.e. nodes that always have higher precedence than operators. """ return isinstance( n, (c_ast.Constant, c_ast.ID, c_ast.ArrayRef, c_ast.StructRef, c_ast.FuncCall), ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/pycparser/c_lexer.py0000664000175000017500000006110315134157072016715 0ustar00elibeneliben# ------------------------------------------------------------------------------ # pycparser: c_lexer.py # # CLexer class: lexer for the C language # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ------------------------------------------------------------------------------ import re from dataclasses import dataclass from enum import Enum from typing import Callable, Dict, List, Optional, Tuple @dataclass(slots=True) class _Token: type: str value: str lineno: int column: int class CLexer: """A standalone lexer for C. Parameters for construction: error_func: Called with (msg, line, column) on lexing errors. on_lbrace_func: Called when an LBRACE token is produced (used for scope tracking). on_rbrace_func: Called when an RBRACE token is produced (used for scope tracking). type_lookup_func: Called with an identifier name; expected to return True if it is a typedef name and should be tokenized as TYPEID. Call input(text) to initialize lexing, and then keep calling token() to get the next token, until it returns None (at end of input). """ def __init__( self, error_func: Callable[[str, int, int], None], on_lbrace_func: Callable[[], None], on_rbrace_func: Callable[[], None], type_lookup_func: Callable[[str], bool], ) -> None: self.error_func = error_func self.on_lbrace_func = on_lbrace_func self.on_rbrace_func = on_rbrace_func self.type_lookup_func = type_lookup_func self._init_state() def input(self, text: str, filename: str = "") -> None: """Initialize the lexer to the given input text. filename is an optional name identifying the file from which the input comes. The lexer can modify it if #line directives are encountered. """ self._init_state() self._lexdata = text self._filename = filename def _init_state(self) -> None: self._lexdata = "" self._filename = "" self._pos = 0 self._line_start = 0 self._pending_tok: Optional[_Token] = None self._lineno = 1 @property def filename(self) -> str: return self._filename def token(self) -> Optional[_Token]: # Lexing strategy overview: # # - We maintain a current position (self._pos), line number, and the # byte offset of the current line start. The lexer is a simple loop # that skips whitespace/newlines and emits one token per call. # - A small amount of logic is handled manually before regex matching: # # * Preprocessor-style directives: if we see '#', we check whether # it's a #line or #pragma directive and consume it inline. #line # updates lineno/filename and produces no tokens. #pragma can yield # both PPPRAGMA and PPPRAGMASTR, but token() returns a single token, # so we stash the PPPRAGMASTR as _pending_tok to return on the next # token() call. Otherwise we return PPHASH. # * Newlines update lineno/line-start tracking so tokens can record # accurate columns. # # - The bulk of tokens are recognized in _match_token: # # * _regex_rules: regex patterns for identifiers, literals, and other # complex tokens (including error-producing patterns). The lexer # uses a combined _regex_master to scan options at the same time. # * _fixed_tokens: exact string matches for operators and punctuation, # resolved by longest match. # # - Error patterns call the error callback and advance minimally, which # keeps lexing resilient while reporting useful diagnostics. text = self._lexdata n = len(text) if self._pending_tok is not None: tok = self._pending_tok self._pending_tok = None return tok while self._pos < n: match text[self._pos]: case " " | "\t": self._pos += 1 case "\n": self._lineno += 1 self._pos += 1 self._line_start = self._pos case "#": if _line_pattern.match(text, self._pos + 1): self._pos += 1 self._handle_ppline() continue if _pragma_pattern.match(text, self._pos + 1): self._pos += 1 toks = self._handle_pppragma() if len(toks) > 1: self._pending_tok = toks[1] if len(toks) > 0: return toks[0] continue tok = self._make_token("PPHASH", "#", self._pos) self._pos += 1 return tok case _: if tok := self._match_token(): return tok else: continue def _match_token(self) -> Optional[_Token]: """Match one token at the current position. Returns a Token on success, or None if no token could be matched and an error was reported. This method always advances _pos by the matched length, or by 1 on error/no-match. """ text = self._lexdata pos = self._pos # We pick the longest match between: # - the master regex (identifiers, literals, error patterns, etc.) # - fixed operator/punctuator literals from the bucket for text[pos] # # The longest match is required to ensure we properly lex something # like ".123" (a floating-point constant) as a single entity (with # FLOAT_CONST), rather than a PERIOD followed by a number. # # The fixed-literal buckets are already length-sorted, so within that # bucket we can take the first match. However, we still compare its # length to the regex match because the regex may have matched a longer # token that should take precedence. best = None if m := _regex_master.match(text, pos): tok_type = m.lastgroup # All master-regex alternatives are named; lastgroup shouldn't be None. assert tok_type is not None value = m.group(tok_type) length = len(value) action, msg = _regex_actions[tok_type] best = (length, tok_type, value, action, msg) if bucket := _fixed_tokens_by_first.get(text[pos]): for entry in bucket: if text.startswith(entry.literal, pos): length = len(entry.literal) if best is None or length > best[0]: best = ( length, entry.tok_type, entry.literal, _RegexAction.TOKEN, None, ) break if best is None: msg = f"Illegal character {repr(text[pos])}" self._error(msg, pos) self._pos += 1 return None length, tok_type, value, action, msg = best if action == _RegexAction.ERROR: if tok_type == "BAD_CHAR_CONST": msg = f"Invalid char constant {value}" # All other ERROR rules provide a message. assert msg is not None self._error(msg, pos) self._pos += max(1, length) return None if action == _RegexAction.ID: tok_type = _keyword_map.get(value, "ID") if tok_type == "ID" and self.type_lookup_func(value): tok_type = "TYPEID" tok = self._make_token(tok_type, value, pos) self._pos += length if tok.type == "LBRACE": self.on_lbrace_func() elif tok.type == "RBRACE": self.on_rbrace_func() return tok def _make_token(self, tok_type: str, value: str, pos: int) -> _Token: """Create a Token at an absolute input position. Expects tok_type/value and the absolute byte offset pos in the current input. Does not advance lexer state; callers manage _pos themselves. Returns a Token with lineno/column computed from current line tracking. """ column = pos - self._line_start + 1 tok = _Token(tok_type, value, self._lineno, column) return tok def _error(self, msg: str, pos: int) -> None: column = pos - self._line_start + 1 self.error_func(msg, self._lineno, column) def _handle_ppline(self) -> None: # Since #line directives aren't supposed to return tokens but should # only affect the lexer's state (update line/filename for coords), this # method does a bit of parsing on its own. It doesn't return anything, # but its side effect is to update self._pos past the directive, and # potentially update self._lineno and self._filename, based on the # directive's contents. # # Accepted #line forms from preprocessors: # - "#line 66 \"kwas\\df.h\"" # - "# 9" # - "#line 10 \"include/me.h\" 1 2 3" (extra numeric flags) # - "# 1 \"file.h\" 3" # Errors we must report: # - "#line \"file.h\"" (filename before line number) # - "#line df" (garbage instead of number/string) # # We scan the directive line once (after an optional 'line' keyword), # validating the order: NUMBER, optional STRING, then any NUMBERs. # The NUMBERs tail is only accepted if a filename STRING was present. text = self._lexdata n = len(text) line_end = text.find("\n", self._pos) if line_end == -1: line_end = n line = text[self._pos : line_end] pos = 0 line_len = len(line) def skip_ws() -> None: nonlocal pos while pos < line_len and line[pos] in " \t": pos += 1 skip_ws() if line.startswith("line", pos): pos += 4 def success(pp_line: Optional[str], pp_filename: Optional[str]) -> None: if pp_line is None: self._error("line number missing in #line", self._pos + line_len) else: self._lineno = int(pp_line) if pp_filename is not None: self._filename = pp_filename self._pos = line_end + 1 self._line_start = self._pos def fail(msg: str, offset: int) -> None: self._error(msg, self._pos + offset) self._pos = line_end + 1 self._line_start = self._pos skip_ws() if pos >= line_len: success(None, None) return if line[pos] == '"': fail("filename before line number in #line", pos) return m = re.match(_decimal_constant, line[pos:]) if not m: fail("invalid #line directive", pos) return pp_line = m.group(0) pos += len(pp_line) skip_ws() if pos >= line_len: success(pp_line, None) return if line[pos] != '"': fail("invalid #line directive", pos) return m = re.match(_string_literal, line[pos:]) if not m: fail("invalid #line directive", pos) return pp_filename = m.group(0).lstrip('"').rstrip('"') pos += len(m.group(0)) # Consume arbitrary sequence of numeric flags after the directive while True: skip_ws() if pos >= line_len: break m = re.match(_decimal_constant, line[pos:]) if not m: fail("invalid #line directive", pos) return pos += len(m.group(0)) success(pp_line, pp_filename) def _handle_pppragma(self) -> List[_Token]: # Parse a full #pragma line; returns a list of tokens with 1 or 2 # tokens - PPPRAGMA and an optional PPPRAGMASTR. If an empty list is # returned, it means an error occurred, or we're at the end of input. # # Examples: # - "#pragma" -> PPPRAGMA only # - "#pragma once" -> PPPRAGMA, PPPRAGMASTR("once") # - "# pragma omp parallel private(th_id)" -> PPPRAGMA, PPPRAGMASTR("omp parallel private(th_id)") # - "#\tpragma {pack: 2, smack: 3}" -> PPPRAGMA, PPPRAGMASTR("{pack: 2, smack: 3}") text = self._lexdata n = len(text) pos = self._pos while pos < n and text[pos] in " \t": pos += 1 if pos >= n: self._pos = pos return [] if not text.startswith("pragma", pos): self._error("invalid #pragma directive", pos) self._pos = pos + 1 return [] pragma_pos = pos pos += len("pragma") toks = [self._make_token("PPPRAGMA", "pragma", pragma_pos)] while pos < n and text[pos] in " \t": pos += 1 start = pos while pos < n and text[pos] != "\n": pos += 1 if pos > start: toks.append(self._make_token("PPPRAGMASTR", text[start:pos], start)) if pos < n and text[pos] == "\n": self._lineno += 1 pos += 1 self._line_start = pos self._pos = pos return toks ## ## Reserved keywords ## _keywords: Tuple[str, ...] = ( "AUTO", "BREAK", "CASE", "CHAR", "CONST", "CONTINUE", "DEFAULT", "DO", "DOUBLE", "ELSE", "ENUM", "EXTERN", "FLOAT", "FOR", "GOTO", "IF", "INLINE", "INT", "LONG", "REGISTER", "OFFSETOF", "RESTRICT", "RETURN", "SHORT", "SIGNED", "SIZEOF", "STATIC", "STRUCT", "SWITCH", "TYPEDEF", "UNION", "UNSIGNED", "VOID", "VOLATILE", "WHILE", "__INT128", "_BOOL", "_COMPLEX", "_NORETURN", "_THREAD_LOCAL", "_STATIC_ASSERT", "_ATOMIC", "_ALIGNOF", "_ALIGNAS", "_PRAGMA", ) _keyword_map: Dict[str, str] = {} for keyword in _keywords: # Keywords from new C standard are mixed-case, like _Bool, _Alignas, etc. if keyword.startswith("_") and len(keyword) > 1 and keyword[1].isalpha(): _keyword_map[keyword[:2].upper() + keyword[2:].lower()] = keyword else: _keyword_map[keyword.lower()] = keyword ## ## Regexes for use in tokens ## # valid C identifiers (K&R2: A.2.3), plus '$' (supported by some compilers) _identifier = r"[a-zA-Z_$][0-9a-zA-Z_$]*" _hex_prefix = "0[xX]" _hex_digits = "[0-9a-fA-F]+" _bin_prefix = "0[bB]" _bin_digits = "[01]+" # integer constants (K&R2: A.2.5.1) _integer_suffix_opt = ( r"(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?" ) _decimal_constant = ( "(0" + _integer_suffix_opt + ")|([1-9][0-9]*" + _integer_suffix_opt + ")" ) _octal_constant = "0[0-7]*" + _integer_suffix_opt _hex_constant = _hex_prefix + _hex_digits + _integer_suffix_opt _bin_constant = _bin_prefix + _bin_digits + _integer_suffix_opt _bad_octal_constant = "0[0-7]*[89]" # comments are not supported _unsupported_c_style_comment = r"\/\*" _unsupported_cxx_style_comment = r"\/\/" # character constants (K&R2: A.2.5.2) # Note: a-zA-Z and '.-~^_!=&;,' are allowed as escape chars to support #line # directives with Windows paths as filenames (..\..\dir\file) # For the same reason, decimal_escape allows all digit sequences. We want to # parse all correct code, even if it means to sometimes parse incorrect # code. # # The original regexes were taken verbatim from the C syntax definition, # and were later modified to avoid worst-case exponential running time. # # simple_escape = r"""([a-zA-Z._~!=&\^\-\\?'"])""" # decimal_escape = r"""(\d+)""" # hex_escape = r"""(x[0-9a-fA-F]+)""" # bad_escape = r"""([\\][^a-zA-Z._~^!=&\^\-\\?'"x0-7])""" # # The following modifications were made to avoid the ambiguity that allowed # backtracking: (https://github.com/eliben/pycparser/issues/61) # # - \x was removed from simple_escape, unless it was not followed by a hex # digit, to avoid ambiguity with hex_escape. # - hex_escape allows one or more hex characters, but requires that the next # character(if any) is not hex # - decimal_escape allows one or more decimal characters, but requires that the # next character(if any) is not a decimal # - bad_escape does not allow any decimals (8-9), to avoid conflicting with the # permissive decimal_escape. # # Without this change, python's `re` module would recursively try parsing each # ambiguous escape sequence in multiple ways. e.g. `\123` could be parsed as # `\1`+`23`, `\12`+`3`, and `\123`. _simple_escape = r"""([a-wyzA-Z._~!=&\^\-\\?'"]|x(?![0-9a-fA-F]))""" _decimal_escape = r"""(\d+)(?!\d)""" _hex_escape = r"""(x[0-9a-fA-F]+)(?![0-9a-fA-F])""" _bad_escape = r"""([\\][^a-zA-Z._~^!=&\^\-\\?'"x0-9])""" _escape_sequence = ( r"""(\\(""" + _simple_escape + "|" + _decimal_escape + "|" + _hex_escape + "))" ) # This complicated regex with lookahead might be slow for strings, so because # all of the valid escapes (including \x) allowed # 0 or more non-escaped characters after the first character, # simple_escape+decimal_escape+hex_escape got simplified to _escape_sequence_start_in_string = r"""(\\[0-9a-zA-Z._~!=&\^\-\\?'"])""" _cconst_char = r"""([^'\\\n]|""" + _escape_sequence + ")" _char_const = "'" + _cconst_char + "'" _wchar_const = "L" + _char_const _u8char_const = "u8" + _char_const _u16char_const = "u" + _char_const _u32char_const = "U" + _char_const _multicharacter_constant = "'" + _cconst_char + "{2,4}'" _unmatched_quote = "('" + _cconst_char + "*\\n)|('" + _cconst_char + "*$)" _bad_char_const = ( r"""('""" + _cconst_char + """[^'\n]+')|('')|('""" + _bad_escape + r"""[^'\n]*')""" ) # string literals (K&R2: A.2.6) _string_char = r"""([^"\\\n]|""" + _escape_sequence_start_in_string + ")" _string_literal = '"' + _string_char + '*"' _wstring_literal = "L" + _string_literal _u8string_literal = "u8" + _string_literal _u16string_literal = "u" + _string_literal _u32string_literal = "U" + _string_literal _bad_string_literal = '"' + _string_char + "*" + _bad_escape + _string_char + '*"' # floating constants (K&R2: A.2.5.3) _exponent_part = r"""([eE][-+]?[0-9]+)""" _fractional_constant = r"""([0-9]*\.[0-9]+)|([0-9]+\.)""" _floating_constant = ( "((((" + _fractional_constant + ")" + _exponent_part + "?)|([0-9]+" + _exponent_part + "))[FfLl]?)" ) _binary_exponent_part = r"""([pP][+-]?[0-9]+)""" _hex_fractional_constant = ( "(((" + _hex_digits + r""")?\.""" + _hex_digits + ")|(" + _hex_digits + r"""\.))""" ) _hex_floating_constant = ( "(" + _hex_prefix + "(" + _hex_digits + "|" + _hex_fractional_constant + ")" + _binary_exponent_part + "[FfLl]?)" ) class _RegexAction(Enum): TOKEN = 0 ID = 1 ERROR = 2 @dataclass(frozen=True) class _RegexRule: # tok_type: name of the token emitted for a match # regex_pattern: the raw regex (no anchors) to match at the current position # action: TOKEN for normal tokens, ID for identifiers, ERROR to report # error_message: message used for ERROR entries tok_type: str regex_pattern: str action: _RegexAction error_message: Optional[str] _regex_rules: List[_RegexRule] = [ _RegexRule( "UNSUPPORTED_C_STYLE_COMMENT", _unsupported_c_style_comment, _RegexAction.ERROR, "Comments are not supported, see https://github.com/eliben/pycparser#3using.", ), _RegexRule( "UNSUPPORTED_CXX_STYLE_COMMENT", _unsupported_cxx_style_comment, _RegexAction.ERROR, "Comments are not supported, see https://github.com/eliben/pycparser#3using.", ), _RegexRule( "BAD_STRING_LITERAL", _bad_string_literal, _RegexAction.ERROR, "String contains invalid escape code", ), _RegexRule("WSTRING_LITERAL", _wstring_literal, _RegexAction.TOKEN, None), _RegexRule("U8STRING_LITERAL", _u8string_literal, _RegexAction.TOKEN, None), _RegexRule("U16STRING_LITERAL", _u16string_literal, _RegexAction.TOKEN, None), _RegexRule("U32STRING_LITERAL", _u32string_literal, _RegexAction.TOKEN, None), _RegexRule("STRING_LITERAL", _string_literal, _RegexAction.TOKEN, None), _RegexRule("HEX_FLOAT_CONST", _hex_floating_constant, _RegexAction.TOKEN, None), _RegexRule("FLOAT_CONST", _floating_constant, _RegexAction.TOKEN, None), _RegexRule("INT_CONST_HEX", _hex_constant, _RegexAction.TOKEN, None), _RegexRule("INT_CONST_BIN", _bin_constant, _RegexAction.TOKEN, None), _RegexRule( "BAD_CONST_OCT", _bad_octal_constant, _RegexAction.ERROR, "Invalid octal constant", ), _RegexRule("INT_CONST_OCT", _octal_constant, _RegexAction.TOKEN, None), _RegexRule("INT_CONST_DEC", _decimal_constant, _RegexAction.TOKEN, None), _RegexRule("INT_CONST_CHAR", _multicharacter_constant, _RegexAction.TOKEN, None), _RegexRule("CHAR_CONST", _char_const, _RegexAction.TOKEN, None), _RegexRule("WCHAR_CONST", _wchar_const, _RegexAction.TOKEN, None), _RegexRule("U8CHAR_CONST", _u8char_const, _RegexAction.TOKEN, None), _RegexRule("U16CHAR_CONST", _u16char_const, _RegexAction.TOKEN, None), _RegexRule("U32CHAR_CONST", _u32char_const, _RegexAction.TOKEN, None), _RegexRule("UNMATCHED_QUOTE", _unmatched_quote, _RegexAction.ERROR, "Unmatched '"), _RegexRule("BAD_CHAR_CONST", _bad_char_const, _RegexAction.ERROR, None), _RegexRule("ID", _identifier, _RegexAction.ID, None), ] _regex_actions: Dict[str, Tuple[_RegexAction, Optional[str]]] = {} _regex_pattern_parts: List[str] = [] for _rule in _regex_rules: _regex_actions[_rule.tok_type] = (_rule.action, _rule.error_message) _regex_pattern_parts.append(f"(?P<{_rule.tok_type}>{_rule.regex_pattern})") # The master regex is a single alternation of all token patterns, each wrapped # in a named group. We match once at the current position and then use # `lastgroup` to recover which token kind fired; this avoids iterating over all # regexes on every character while keeping the same token-level semantics. _regex_master: re.Pattern[str] = re.compile("|".join(_regex_pattern_parts)) @dataclass(frozen=True) class _FixedToken: tok_type: str literal: str _fixed_tokens: List[_FixedToken] = [ _FixedToken("ELLIPSIS", "..."), _FixedToken("LSHIFTEQUAL", "<<="), _FixedToken("RSHIFTEQUAL", ">>="), _FixedToken("PLUSPLUS", "++"), _FixedToken("MINUSMINUS", "--"), _FixedToken("ARROW", "->"), _FixedToken("LAND", "&&"), _FixedToken("LOR", "||"), _FixedToken("LSHIFT", "<<"), _FixedToken("RSHIFT", ">>"), _FixedToken("LE", "<="), _FixedToken("GE", ">="), _FixedToken("EQ", "=="), _FixedToken("NE", "!="), _FixedToken("TIMESEQUAL", "*="), _FixedToken("DIVEQUAL", "/="), _FixedToken("MODEQUAL", "%="), _FixedToken("PLUSEQUAL", "+="), _FixedToken("MINUSEQUAL", "-="), _FixedToken("ANDEQUAL", "&="), _FixedToken("OREQUAL", "|="), _FixedToken("XOREQUAL", "^="), _FixedToken("EQUALS", "="), _FixedToken("PLUS", "+"), _FixedToken("MINUS", "-"), _FixedToken("TIMES", "*"), _FixedToken("DIVIDE", "/"), _FixedToken("MOD", "%"), _FixedToken("OR", "|"), _FixedToken("AND", "&"), _FixedToken("NOT", "~"), _FixedToken("XOR", "^"), _FixedToken("LNOT", "!"), _FixedToken("LT", "<"), _FixedToken("GT", ">"), _FixedToken("CONDOP", "?"), _FixedToken("LPAREN", "("), _FixedToken("RPAREN", ")"), _FixedToken("LBRACKET", "["), _FixedToken("RBRACKET", "]"), _FixedToken("LBRACE", "{"), _FixedToken("RBRACE", "}"), _FixedToken("COMMA", ","), _FixedToken("PERIOD", "."), _FixedToken("SEMI", ";"), _FixedToken("COLON", ":"), ] # To avoid scanning all fixed tokens on every character, we bucket them by the # first character. When matching at position i, we only look at the bucket for # text[i], and we pre-sort that bucket by token length so the first match is # also the longest. This preserves longest-match semantics (e.g. '>>=' before # '>>' before '>') while reducing the number of comparisons. _fixed_tokens_by_first: Dict[str, List[_FixedToken]] = {} for _entry in _fixed_tokens: _fixed_tokens_by_first.setdefault(_entry.literal[0], []).append(_entry) for _bucket in _fixed_tokens_by_first.values(): _bucket.sort(key=lambda item: len(item.literal), reverse=True) _line_pattern: re.Pattern[str] = re.compile(r"([ \t]*line\W)|([ \t]*\d+)") _pragma_pattern: re.Pattern[str] = re.compile(r"[ \t]*pragma\W") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/pycparser/c_parser.py0000664000175000017500000025730615134157072017106 0ustar00elibeneliben# ------------------------------------------------------------------------------ # pycparser: c_parser.py # # Recursive-descent parser for the C language. # # Eli Bendersky [https://eli.thegreenplace.net/] # License: BSD # ------------------------------------------------------------------------------ from dataclasses import dataclass from typing import ( Any, Dict, List, Literal, NoReturn, Optional, Tuple, TypedDict, cast, ) from . import c_ast from .c_lexer import CLexer, _Token from .ast_transforms import fix_switch_cases, fix_atomic_specifiers @dataclass class Coord: """Coordinates of a syntactic element. Consists of: - File name - Line number - Column number """ file: str line: int column: Optional[int] = None def __str__(self) -> str: text = f"{self.file}:{self.line}" if self.column: text += f":{self.column}" return text class ParseError(Exception): pass class CParser: """Recursive-descent C parser. Usage: parser = CParser() ast = parser.parse(text, filename) The `lexer` parameter lets you inject a lexer class (defaults to CLexer). The parameters after `lexer` are accepted for backward compatibility with the old PLY-based parser and are otherwise unused. """ def __init__( self, lex_optimize: bool = True, lexer: type[CLexer] = CLexer, lextab: str = "pycparser.lextab", yacc_optimize: bool = True, yacctab: str = "pycparser.yacctab", yacc_debug: bool = False, taboutputdir: str = "", ) -> None: self.clex: CLexer = lexer( error_func=self._lex_error_func, on_lbrace_func=self._lex_on_lbrace_func, on_rbrace_func=self._lex_on_rbrace_func, type_lookup_func=self._lex_type_lookup_func, ) # Stack of scopes for keeping track of symbols. _scope_stack[-1] is # the current (topmost) scope. Each scope is a dictionary that # specifies whether a name is a type. If _scope_stack[n][name] is # True, 'name' is currently a type in the scope. If it's False, # 'name' is used in the scope but not as a type (for instance, if we # saw: int name; # If 'name' is not a key in _scope_stack[n] then 'name' was not defined # in this scope at all. self._scope_stack: List[Dict[str, bool]] = [dict()] self._tokens: _TokenStream = _TokenStream(self.clex) def parse( self, text: str, filename: str = "", debug: bool = False ) -> c_ast.FileAST: """Parses C code and returns an AST. text: A string containing the C source code filename: Name of the file being parsed (for meaningful error messages) debug: Deprecated debug flag (unused); for backwards compatibility. """ self._scope_stack = [dict()] self.clex.input(text, filename) self._tokens = _TokenStream(self.clex) ast = self._parse_translation_unit_or_empty() tok = self._peek() if tok is not None: self._parse_error(f"before: {tok.value}", self._tok_coord(tok)) return ast # ------------------------------------------------------------------ # Scope and declaration helpers # ------------------------------------------------------------------ def _coord(self, lineno: int, column: Optional[int] = None) -> Coord: return Coord(file=self.clex.filename, line=lineno, column=column) def _parse_error(self, msg: str, coord: Coord | str | None) -> NoReturn: raise ParseError(f"{coord}: {msg}") def _push_scope(self) -> None: self._scope_stack.append(dict()) def _pop_scope(self) -> None: assert len(self._scope_stack) > 1 self._scope_stack.pop() def _add_typedef_name(self, name: str, coord: Optional[Coord]) -> None: """Add a new typedef name (ie a TYPEID) to the current scope""" if not self._scope_stack[-1].get(name, True): self._parse_error( f"Typedef {name!r} previously declared as non-typedef in this scope", coord, ) self._scope_stack[-1][name] = True def _add_identifier(self, name: str, coord: Optional[Coord]) -> None: """Add a new object, function, or enum member name (ie an ID) to the current scope """ if self._scope_stack[-1].get(name, False): self._parse_error( f"Non-typedef {name!r} previously declared as typedef in this scope", coord, ) self._scope_stack[-1][name] = False def _is_type_in_scope(self, name: str) -> bool: """Is *name* a typedef-name in the current scope?""" for scope in reversed(self._scope_stack): # If name is an identifier in this scope it shadows typedefs in # higher scopes. in_scope = scope.get(name) if in_scope is not None: return in_scope return False def _lex_error_func(self, msg: str, line: int, column: int) -> None: self._parse_error(msg, self._coord(line, column)) def _lex_on_lbrace_func(self) -> None: self._push_scope() def _lex_on_rbrace_func(self) -> None: self._pop_scope() def _lex_type_lookup_func(self, name: str) -> bool: """Looks up types that were previously defined with typedef. Passed to the lexer for recognizing identifiers that are types. """ return self._is_type_in_scope(name) # To understand what's going on here, read sections A.8.5 and # A.8.6 of K&R2 very carefully. # # A C type consists of a basic type declaration, with a list # of modifiers. For example: # # int *c[5]; # # The basic declaration here is 'int c', and the pointer and # the array are the modifiers. # # Basic declarations are represented by TypeDecl (from module c_ast) and the # modifiers are FuncDecl, PtrDecl and ArrayDecl. # # The standard states that whenever a new modifier is parsed, it should be # added to the end of the list of modifiers. For example: # # K&R2 A.8.6.2: Array Declarators # # In a declaration T D where D has the form # D1 [constant-expression-opt] # and the type of the identifier in the declaration T D1 is # "type-modifier T", the type of the # identifier of D is "type-modifier array of T" # # This is what this method does. The declarator it receives # can be a list of declarators ending with TypeDecl. It # tacks the modifier to the end of this list, just before # the TypeDecl. # # Additionally, the modifier may be a list itself. This is # useful for pointers, that can come as a chain from the rule # p_pointer. In this case, the whole modifier list is spliced # into the new location. def _type_modify_decl(self, decl: Any, modifier: Any) -> c_ast.Node: """Tacks a type modifier on a declarator, and returns the modified declarator. Note: the declarator and modifier may be modified """ modifier_head = modifier modifier_tail = modifier # The modifier may be a nested list. Reach its tail. while modifier_tail.type: modifier_tail = modifier_tail.type # If the decl is a basic type, just tack the modifier onto it. if isinstance(decl, c_ast.TypeDecl): modifier_tail.type = decl return modifier else: # Otherwise, the decl is a list of modifiers. Reach # its tail and splice the modifier onto the tail, # pointing to the underlying basic type. decl_tail = decl while not isinstance(decl_tail.type, c_ast.TypeDecl): decl_tail = decl_tail.type modifier_tail.type = decl_tail.type decl_tail.type = modifier_head return decl # Due to the order in which declarators are constructed, # they have to be fixed in order to look like a normal AST. # # When a declaration arrives from syntax construction, it has # these problems: # * The innermost TypeDecl has no type (because the basic # type is only known at the uppermost declaration level) # * The declaration has no variable name, since that is saved # in the innermost TypeDecl # * The typename of the declaration is a list of type # specifiers, and not a node. Here, basic identifier types # should be separated from more complex types like enums # and structs. # # This method fixes these problems. def _fix_decl_name_type( self, decl: c_ast.Decl | c_ast.Typedef | c_ast.Typename, typename: List[Any], ) -> c_ast.Decl | c_ast.Typedef | c_ast.Typename: """Fixes a declaration. Modifies decl.""" # Reach the underlying basic type typ = decl while not isinstance(typ, c_ast.TypeDecl): typ = typ.type decl.name = typ.declname typ.quals = decl.quals[:] # The typename is a list of types. If any type in this # list isn't an IdentifierType, it must be the only # type in the list (it's illegal to declare "int enum ..") # If all the types are basic, they're collected in the # IdentifierType holder. for tn in typename: if not isinstance(tn, c_ast.IdentifierType): if len(typename) > 1: self._parse_error("Invalid multiple types specified", tn.coord) else: typ.type = tn return decl if not typename: # Functions default to returning int if not isinstance(decl.type, c_ast.FuncDecl): self._parse_error("Missing type in declaration", decl.coord) typ.type = c_ast.IdentifierType(["int"], coord=decl.coord) else: # At this point, we know that typename is a list of IdentifierType # nodes. Concatenate all the names into a single list. typ.type = c_ast.IdentifierType( [name for id in typename for name in id.names], coord=typename[0].coord ) return decl def _add_declaration_specifier( self, declspec: Optional["_DeclSpec"], newspec: Any, kind: "_DeclSpecKind", append: bool = False, ) -> "_DeclSpec": """See _DeclSpec for the specifier dictionary layout.""" if declspec is None: spec: _DeclSpec = dict( qual=[], storage=[], type=[], function=[], alignment=[] ) else: spec = declspec if append: spec[kind].append(newspec) else: spec[kind].insert(0, newspec) return spec def _build_declarations( self, spec: "_DeclSpec", decls: List["_DeclInfo"], typedef_namespace: bool = False, ) -> List[c_ast.Node]: """Builds a list of declarations all sharing the given specifiers. If typedef_namespace is true, each declared name is added to the "typedef namespace", which also includes objects, functions, and enum constants. """ is_typedef = "typedef" in spec["storage"] declarations = [] # Bit-fields are allowed to be unnamed. if decls[0].get("bitsize") is None: # When redeclaring typedef names as identifiers in inner scopes, a # problem can occur where the identifier gets grouped into # spec['type'], leaving decl as None. This can only occur for the # first declarator. if decls[0]["decl"] is None: if ( len(spec["type"]) < 2 or len(spec["type"][-1].names) != 1 or not self._is_type_in_scope(spec["type"][-1].names[0]) ): coord = "?" for t in spec["type"]: if hasattr(t, "coord"): coord = t.coord break self._parse_error("Invalid declaration", coord) # Make this look as if it came from "direct_declarator:ID" decls[0]["decl"] = c_ast.TypeDecl( declname=spec["type"][-1].names[0], type=None, quals=None, align=spec["alignment"], coord=spec["type"][-1].coord, ) # Remove the "new" type's name from the end of spec['type'] del spec["type"][-1] # A similar problem can occur where the declaration ends up # looking like an abstract declarator. Give it a name if this is # the case. elif not isinstance( decls[0]["decl"], (c_ast.Enum, c_ast.Struct, c_ast.Union, c_ast.IdentifierType), ): decls_0_tail = cast(Any, decls[0]["decl"]) while not isinstance(decls_0_tail, c_ast.TypeDecl): decls_0_tail = decls_0_tail.type if decls_0_tail.declname is None: decls_0_tail.declname = spec["type"][-1].names[0] del spec["type"][-1] for decl in decls: assert decl["decl"] is not None if is_typedef: declaration = c_ast.Typedef( name=None, quals=spec["qual"], storage=spec["storage"], type=decl["decl"], coord=decl["decl"].coord, ) else: declaration = c_ast.Decl( name=None, quals=spec["qual"], align=spec["alignment"], storage=spec["storage"], funcspec=spec["function"], type=decl["decl"], init=decl.get("init"), bitsize=decl.get("bitsize"), coord=decl["decl"].coord, ) if isinstance( declaration.type, (c_ast.Enum, c_ast.Struct, c_ast.Union, c_ast.IdentifierType), ): fixed_decl = declaration else: fixed_decl = self._fix_decl_name_type(declaration, spec["type"]) # Add the type name defined by typedef to a # symbol table (for usage in the lexer) if typedef_namespace: if is_typedef: self._add_typedef_name(fixed_decl.name, fixed_decl.coord) else: self._add_identifier(fixed_decl.name, fixed_decl.coord) fixed_decl = fix_atomic_specifiers( cast(c_ast.Decl | c_ast.Typedef, fixed_decl) ) declarations.append(fixed_decl) return declarations def _build_function_definition( self, spec: "_DeclSpec", decl: c_ast.Node, param_decls: Optional[List[c_ast.Node]], body: c_ast.Node, ) -> c_ast.Node: """Builds a function definition.""" if "typedef" in spec["storage"]: self._parse_error("Invalid typedef", decl.coord) declaration = self._build_declarations( spec=spec, decls=[dict(decl=decl, init=None, bitsize=None)], typedef_namespace=True, )[0] return c_ast.FuncDef( decl=declaration, param_decls=param_decls, body=body, coord=decl.coord ) def _select_struct_union_class(self, token: str) -> type: """Given a token (either STRUCT or UNION), selects the appropriate AST class. """ if token == "struct": return c_ast.Struct else: return c_ast.Union # ------------------------------------------------------------------ # Token helpers # ------------------------------------------------------------------ def _peek(self, k: int = 1) -> Optional[_Token]: """Return the k-th next token without consuming it (1-based).""" return self._tokens.peek(k) def _peek_type(self, k: int = 1) -> Optional[str]: """Return the type of the k-th next token, or None if absent (1-based).""" tok = self._peek(k) return tok.type if tok is not None else None def _advance(self) -> _Token: tok = self._tokens.next() if tok is None: self._parse_error("At end of input", self.clex.filename) else: return tok def _accept(self, token_type: str) -> Optional[_Token]: """Conditionally consume next token, only if it's of token_type. If it is of the expected type, consume and return it. Otherwise, leaves the token intact and returns None. """ tok = self._peek() if tok is not None and tok.type == token_type: return self._advance() return None def _expect(self, token_type: str) -> _Token: tok = self._advance() if tok.type != token_type: self._parse_error(f"before: {tok.value}", self._tok_coord(tok)) return tok def _mark(self) -> int: return self._tokens.mark() def _reset(self, mark: int) -> None: self._tokens.reset(mark) def _tok_coord(self, tok: _Token) -> Coord: return self._coord(tok.lineno, tok.column) def _starts_declaration(self, tok: Optional[_Token] = None) -> bool: tok = tok or self._peek() if tok is None: return False return tok.type in _DECL_START def _starts_expression(self, tok: Optional[_Token] = None) -> bool: tok = tok or self._peek() if tok is None: return False return tok.type in _STARTS_EXPRESSION def _starts_statement(self) -> bool: tok_type = self._peek_type() if tok_type is None: return False if tok_type in _STARTS_STATEMENT: return True return self._starts_expression() def _starts_declarator(self, id_only: bool = False) -> bool: tok_type = self._peek_type() if tok_type is None: return False if tok_type in {"TIMES", "LPAREN"}: return True if id_only: return tok_type == "ID" return tok_type in {"ID", "TYPEID"} def _peek_declarator_name_info(self) -> Tuple[Optional[str], bool]: mark = self._mark() tok_type, saw_paren = self._scan_declarator_name_info() self._reset(mark) return tok_type, saw_paren def _parse_any_declarator( self, allow_abstract: bool = False, typeid_paren_as_abstract: bool = False ) -> Tuple[Optional[c_ast.Node], bool]: # C declarators are ambiguous without lookahead. For example: # int foo(int (aa)); -> aa is a name (ID) # typedef char TT; # int bar(int (TT)); -> TT is a type (TYPEID) in parens name_type, saw_paren = self._peek_declarator_name_info() if name_type is None or ( typeid_paren_as_abstract and name_type == "TYPEID" and saw_paren ): if not allow_abstract: tok = self._peek() coord = self._tok_coord(tok) if tok is not None else self.clex.filename self._parse_error("Invalid declarator", coord) decl = self._parse_abstract_declarator_opt() return decl, False if name_type == "TYPEID": if typeid_paren_as_abstract: decl = self._parse_typeid_noparen_declarator() else: decl = self._parse_typeid_declarator() else: decl = self._parse_id_declarator() return decl, True def _scan_declarator_name_info(self) -> Tuple[Optional[str], bool]: saw_paren = False while self._accept("TIMES"): while self._peek_type() in _TYPE_QUALIFIER: self._advance() tok = self._peek() if tok is None: return None, saw_paren if tok.type in {"ID", "TYPEID"}: self._advance() return tok.type, saw_paren if tok.type == "LPAREN": saw_paren = True self._advance() tok_type, nested_paren = self._scan_declarator_name_info() if nested_paren: saw_paren = True depth = 1 while True: tok = self._peek() if tok is None: return None, saw_paren if tok.type == "LPAREN": depth += 1 elif tok.type == "RPAREN": depth -= 1 self._advance() if depth == 0: break continue self._advance() return tok_type, saw_paren return None, saw_paren def _starts_direct_abstract_declarator(self) -> bool: return self._peek_type() in {"LPAREN", "LBRACKET"} def _is_assignment_op(self) -> bool: tok = self._peek() return tok is not None and tok.type in _ASSIGNMENT_OPS def _try_parse_paren_type_name( self, ) -> Optional[Tuple[c_ast.Typename, int, _Token]]: """Parse and return a parenthesized type name if present. Returns (typ, mark, lparen_tok) when the next tokens look like '(' type_name ')', where typ is the parsed type name, mark is the token-stream position before parsing, and lparen_tok is the LPAREN token. Returns None if no parenthesized type name is present. """ mark = self._mark() lparen_tok = self._accept("LPAREN") if lparen_tok is None: return None if not self._starts_declaration(): self._reset(mark) return None typ = self._parse_type_name() if self._accept("RPAREN") is None: self._reset(mark) return None return typ, mark, lparen_tok # ------------------------------------------------------------------ # Top-level # ------------------------------------------------------------------ # BNF: translation_unit_or_empty : translation_unit | empty def _parse_translation_unit_or_empty(self) -> c_ast.FileAST: if self._peek() is None: return c_ast.FileAST([]) return c_ast.FileAST(self._parse_translation_unit()) # BNF: translation_unit : external_declaration+ def _parse_translation_unit(self) -> List[c_ast.Node]: ext = [] while self._peek() is not None: ext.extend(self._parse_external_declaration()) return ext # BNF: external_declaration : function_definition # | declaration # | pp_directive # | pppragma_directive # | static_assert # | ';' def _parse_external_declaration(self) -> List[c_ast.Node]: tok = self._peek() if tok is None: return [] if tok.type == "PPHASH": self._parse_pp_directive() return [] if tok.type in {"PPPRAGMA", "_PRAGMA"}: return [self._parse_pppragma_directive()] if self._accept("SEMI"): return [] if tok.type == "_STATIC_ASSERT": return self._parse_static_assert() if not self._starts_declaration(tok): # Special handling for old-style function definitions that have an # implicit return type, e.g. # # foo() { # return 5; # } # # These get an implicit 'int' return type. decl = self._parse_id_declarator() param_decls = None if self._peek_type() != "LBRACE": self._parse_error("Invalid function definition", decl.coord) spec: _DeclSpec = dict( qual=[], alignment=[], storage=[], type=[c_ast.IdentifierType(["int"], coord=decl.coord)], function=[], ) func = self._build_function_definition( spec=spec, decl=decl, param_decls=param_decls, body=self._parse_compound_statement(), ) return [func] # From here on, parsing a standard declatation/definition. spec, saw_type, spec_coord = self._parse_declaration_specifiers( allow_no_type=True ) name_type, _ = self._peek_declarator_name_info() if name_type != "ID": decls = self._parse_decl_body_with_spec(spec, saw_type) self._expect("SEMI") return decls decl = self._parse_id_declarator() if self._peek_type() == "LBRACE" or self._starts_declaration(): param_decls = None if self._starts_declaration(): param_decls = self._parse_declaration_list() if self._peek_type() != "LBRACE": self._parse_error("Invalid function definition", decl.coord) if not spec["type"]: spec["type"] = [c_ast.IdentifierType(["int"], coord=spec_coord)] func = self._build_function_definition( spec=spec, decl=decl, param_decls=param_decls, body=self._parse_compound_statement(), ) return [func] decl_dict: "_DeclInfo" = dict(decl=decl, init=None, bitsize=None) if self._accept("EQUALS"): decl_dict["init"] = self._parse_initializer() decls = self._parse_init_declarator_list(first=decl_dict) decls = self._build_declarations(spec=spec, decls=decls, typedef_namespace=True) self._expect("SEMI") return decls # ------------------------------------------------------------------ # Declarations # # Declarations always come as lists (because they can be several in one # line). When returning parsed declarations, a list is always returned - # even if it contains a single element. # ------------------------------------------------------------------ def _parse_declaration(self) -> List[c_ast.Node]: decls = self._parse_decl_body() self._expect("SEMI") return decls # BNF: decl_body : declaration_specifiers decl_body_with_spec def _parse_decl_body(self) -> List[c_ast.Node]: spec, saw_type, _ = self._parse_declaration_specifiers(allow_no_type=True) return self._parse_decl_body_with_spec(spec, saw_type) # BNF: decl_body_with_spec : init_declarator_list # | struct_or_union_or_enum_only def _parse_decl_body_with_spec( self, spec: "_DeclSpec", saw_type: bool ) -> List[c_ast.Node]: decls = None if saw_type: if self._starts_declarator(): decls = self._parse_init_declarator_list() else: if self._starts_declarator(id_only=True): decls = self._parse_init_declarator_list(id_only=True) if decls is None: ty = spec["type"] s_u_or_e = (c_ast.Struct, c_ast.Union, c_ast.Enum) if len(ty) == 1 and isinstance(ty[0], s_u_or_e): decls = [ c_ast.Decl( name=None, quals=spec["qual"], align=spec["alignment"], storage=spec["storage"], funcspec=spec["function"], type=ty[0], init=None, bitsize=None, coord=ty[0].coord, ) ] else: decls = self._build_declarations( spec=spec, decls=[dict(decl=None, init=None, bitsize=None)], typedef_namespace=True, ) else: decls = self._build_declarations( spec=spec, decls=decls, typedef_namespace=True ) return decls # BNF: declaration_list : declaration+ def _parse_declaration_list(self) -> List[c_ast.Node]: decls = [] while self._starts_declaration(): decls.extend(self._parse_declaration()) return decls # BNF: declaration_specifiers : (storage_class_specifier # | type_specifier # | type_qualifier # | function_specifier # | alignment_specifier)+ def _parse_declaration_specifiers( self, allow_no_type: bool = False ) -> Tuple["_DeclSpec", bool, Optional[Coord]]: """Parse declaration-specifier sequence. allow_no_type: If True, allow a missing type specifier without error. Returns: (spec, saw_type, first_coord) where spec is a dict with qual/storage/type/function/alignment entries, saw_type is True if a type specifier was consumed, and first_coord is the coord of the first specifier token (used for diagnostics). """ spec = None saw_type = False first_coord = None while True: tok = self._peek() if tok is None: break if tok.type == "_ALIGNAS": if first_coord is None: first_coord = self._tok_coord(tok) spec = self._add_declaration_specifier( spec, self._parse_alignment_specifier(), "alignment", append=True ) continue if tok.type == "_ATOMIC" and self._peek_type(2) == "LPAREN": if first_coord is None: first_coord = self._tok_coord(tok) spec = self._add_declaration_specifier( spec, self._parse_atomic_specifier(), "type", append=True ) saw_type = True continue if tok.type in _TYPE_QUALIFIER: if first_coord is None: first_coord = self._tok_coord(tok) spec = self._add_declaration_specifier( spec, self._advance().value, "qual", append=True ) continue if tok.type in _STORAGE_CLASS: if first_coord is None: first_coord = self._tok_coord(tok) spec = self._add_declaration_specifier( spec, self._advance().value, "storage", append=True ) continue if tok.type in _FUNCTION_SPEC: if first_coord is None: first_coord = self._tok_coord(tok) spec = self._add_declaration_specifier( spec, self._advance().value, "function", append=True ) continue if tok.type in _TYPE_SPEC_SIMPLE: if first_coord is None: first_coord = self._tok_coord(tok) tok = self._advance() spec = self._add_declaration_specifier( spec, c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)), "type", append=True, ) saw_type = True continue if tok.type == "TYPEID": if saw_type: break if first_coord is None: first_coord = self._tok_coord(tok) tok = self._advance() spec = self._add_declaration_specifier( spec, c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)), "type", append=True, ) saw_type = True continue if tok.type in {"STRUCT", "UNION"}: if first_coord is None: first_coord = self._tok_coord(tok) spec = self._add_declaration_specifier( spec, self._parse_struct_or_union_specifier(), "type", append=True ) saw_type = True continue if tok.type == "ENUM": if first_coord is None: first_coord = self._tok_coord(tok) spec = self._add_declaration_specifier( spec, self._parse_enum_specifier(), "type", append=True ) saw_type = True continue break if spec is None: self._parse_error("Invalid declaration", self.clex.filename) if not saw_type and not allow_no_type: self._parse_error("Missing type in declaration", first_coord) return spec, saw_type, first_coord # BNF: specifier_qualifier_list : (type_specifier # | type_qualifier # | alignment_specifier)+ def _parse_specifier_qualifier_list(self) -> "_DeclSpec": spec = None saw_type = False saw_alignment = False first_coord = None while True: tok = self._peek() if tok is None: break if tok.type == "_ALIGNAS": if first_coord is None: first_coord = self._tok_coord(tok) spec = self._add_declaration_specifier( spec, self._parse_alignment_specifier(), "alignment", append=True ) saw_alignment = True continue if tok.type == "_ATOMIC" and self._peek_type(2) == "LPAREN": if first_coord is None: first_coord = self._tok_coord(tok) spec = self._add_declaration_specifier( spec, self._parse_atomic_specifier(), "type", append=True ) saw_type = True continue if tok.type in _TYPE_QUALIFIER: if first_coord is None: first_coord = self._tok_coord(tok) spec = self._add_declaration_specifier( spec, self._advance().value, "qual", append=True ) continue if tok.type in _TYPE_SPEC_SIMPLE: if first_coord is None: first_coord = self._tok_coord(tok) tok = self._advance() spec = self._add_declaration_specifier( spec, c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)), "type", append=True, ) saw_type = True continue if tok.type == "TYPEID": if saw_type: break if first_coord is None: first_coord = self._tok_coord(tok) tok = self._advance() spec = self._add_declaration_specifier( spec, c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)), "type", append=True, ) saw_type = True continue if tok.type in {"STRUCT", "UNION"}: if first_coord is None: first_coord = self._tok_coord(tok) spec = self._add_declaration_specifier( spec, self._parse_struct_or_union_specifier(), "type", append=True ) saw_type = True continue if tok.type == "ENUM": if first_coord is None: first_coord = self._tok_coord(tok) spec = self._add_declaration_specifier( spec, self._parse_enum_specifier(), "type", append=True ) saw_type = True continue break if spec is None: self._parse_error("Invalid specifier list", self.clex.filename) if not saw_type and not saw_alignment: self._parse_error("Missing type in declaration", first_coord) if spec.get("storage") is None: spec["storage"] = [] if spec.get("function") is None: spec["function"] = [] return spec # BNF: type_qualifier_list : type_qualifier+ def _parse_type_qualifier_list(self) -> List[str]: quals = [] while self._peek_type() in _TYPE_QUALIFIER: quals.append(self._advance().value) return quals # BNF: alignment_specifier : _ALIGNAS '(' type_name | constant_expression ')' def _parse_alignment_specifier(self) -> c_ast.Node: tok = self._expect("_ALIGNAS") self._expect("LPAREN") if self._starts_declaration(): typ = self._parse_type_name() self._expect("RPAREN") return c_ast.Alignas(typ, self._tok_coord(tok)) expr = self._parse_constant_expression() self._expect("RPAREN") return c_ast.Alignas(expr, self._tok_coord(tok)) # BNF: atomic_specifier : _ATOMIC '(' type_name ')' def _parse_atomic_specifier(self) -> c_ast.Node: self._expect("_ATOMIC") self._expect("LPAREN") typ = self._parse_type_name() self._expect("RPAREN") typ.quals.append("_Atomic") return typ # BNF: init_declarator_list : init_declarator (',' init_declarator)* def _parse_init_declarator_list( self, first: Optional["_DeclInfo"] = None, id_only: bool = False ) -> List["_DeclInfo"]: decls = ( [first] if first is not None else [self._parse_init_declarator(id_only=id_only)] ) while self._accept("COMMA"): decls.append(self._parse_init_declarator(id_only=id_only)) return decls # BNF: init_declarator : declarator ('=' initializer)? def _parse_init_declarator(self, id_only: bool = False) -> "_DeclInfo": decl = self._parse_id_declarator() if id_only else self._parse_declarator() init = None if self._accept("EQUALS"): init = self._parse_initializer() return dict(decl=decl, init=init, bitsize=None) # ------------------------------------------------------------------ # Structs/unions/enums # ------------------------------------------------------------------ # BNF: struct_or_union_specifier : struct_or_union ID? '{' struct_declaration_list? '}' # | struct_or_union ID def _parse_struct_or_union_specifier(self) -> c_ast.Node: tok = self._advance() klass = self._select_struct_union_class(tok.value) if self._peek_type() in {"ID", "TYPEID"}: name_tok = self._advance() if self._peek_type() == "LBRACE": self._advance() if self._accept("RBRACE"): return klass( name=name_tok.value, decls=[], coord=self._tok_coord(name_tok) ) decls = self._parse_struct_declaration_list() self._expect("RBRACE") return klass( name=name_tok.value, decls=decls, coord=self._tok_coord(name_tok) ) return klass( name=name_tok.value, decls=None, coord=self._tok_coord(name_tok) ) if self._peek_type() == "LBRACE": brace_tok = self._advance() if self._accept("RBRACE"): return klass(name=None, decls=[], coord=self._tok_coord(brace_tok)) decls = self._parse_struct_declaration_list() self._expect("RBRACE") return klass(name=None, decls=decls, coord=self._tok_coord(brace_tok)) self._parse_error("Invalid struct/union declaration", self._tok_coord(tok)) # BNF: struct_declaration_list : struct_declaration+ def _parse_struct_declaration_list(self) -> List[c_ast.Node]: decls = [] while self._peek_type() not in {None, "RBRACE"}: items = self._parse_struct_declaration() if items is None: continue decls.extend(items) return decls # BNF: struct_declaration : specifier_qualifier_list struct_declarator_list? ';' # | static_assert # | pppragma_directive def _parse_struct_declaration(self) -> Optional[List[c_ast.Node]]: if self._peek_type() == "SEMI": self._advance() return None if self._peek_type() in {"PPPRAGMA", "_PRAGMA"}: return [self._parse_pppragma_directive()] spec = self._parse_specifier_qualifier_list() assert "typedef" not in spec.get("storage", []) decls = None if self._starts_declarator() or self._peek_type() == "COLON": decls = self._parse_struct_declarator_list() if decls is not None: self._expect("SEMI") return self._build_declarations(spec=spec, decls=decls) if len(spec["type"]) == 1: node = spec["type"][0] if isinstance(node, c_ast.Node): decl_type = node else: decl_type = c_ast.IdentifierType(node) self._expect("SEMI") return self._build_declarations( spec=spec, decls=[dict(decl=decl_type, init=None, bitsize=None)] ) self._expect("SEMI") return self._build_declarations( spec=spec, decls=[dict(decl=None, init=None, bitsize=None)] ) # BNF: struct_declarator_list : struct_declarator (',' struct_declarator)* def _parse_struct_declarator_list(self) -> List["_DeclInfo"]: decls = [self._parse_struct_declarator()] while self._accept("COMMA"): decls.append(self._parse_struct_declarator()) return decls # BNF: struct_declarator : declarator? ':' constant_expression # | declarator (':' constant_expression)? def _parse_struct_declarator(self) -> "_DeclInfo": if self._accept("COLON"): bitsize = self._parse_constant_expression() return { "decl": c_ast.TypeDecl(None, None, None, None), "init": None, "bitsize": bitsize, } decl = self._parse_declarator() if self._accept("COLON"): bitsize = self._parse_constant_expression() return {"decl": decl, "init": None, "bitsize": bitsize} return {"decl": decl, "init": None, "bitsize": None} # BNF: enum_specifier : ENUM ID? '{' enumerator_list? '}' # | ENUM ID def _parse_enum_specifier(self) -> c_ast.Node: tok = self._expect("ENUM") if self._peek_type() in {"ID", "TYPEID"}: name_tok = self._advance() if self._peek_type() == "LBRACE": self._advance() enums = self._parse_enumerator_list() self._expect("RBRACE") return c_ast.Enum(name_tok.value, enums, self._tok_coord(tok)) return c_ast.Enum(name_tok.value, None, self._tok_coord(tok)) self._expect("LBRACE") enums = self._parse_enumerator_list() self._expect("RBRACE") return c_ast.Enum(None, enums, self._tok_coord(tok)) # BNF: enumerator_list : enumerator (',' enumerator)* ','? def _parse_enumerator_list(self) -> c_ast.Node: enum = self._parse_enumerator() enum_list = c_ast.EnumeratorList([enum], enum.coord) while self._accept("COMMA"): if self._peek_type() == "RBRACE": break enum = self._parse_enumerator() enum_list.enumerators.append(enum) return enum_list # BNF: enumerator : ID ('=' constant_expression)? def _parse_enumerator(self) -> c_ast.Node: name_tok = self._expect("ID") if self._accept("EQUALS"): value = self._parse_constant_expression() else: value = None enum = c_ast.Enumerator(name_tok.value, value, self._tok_coord(name_tok)) self._add_identifier(enum.name, enum.coord) return enum # ------------------------------------------------------------------ # Declarators # ------------------------------------------------------------------ # BNF: declarator : pointer? direct_declarator def _parse_declarator(self) -> c_ast.Node: decl, _ = self._parse_any_declarator( allow_abstract=False, typeid_paren_as_abstract=False ) assert decl is not None return decl # BNF: id_declarator : declarator with ID name def _parse_id_declarator(self) -> c_ast.Node: return self._parse_declarator_kind(kind="id", allow_paren=True) # BNF: typeid_declarator : declarator with TYPEID name def _parse_typeid_declarator(self) -> c_ast.Node: return self._parse_declarator_kind(kind="typeid", allow_paren=True) # BNF: typeid_noparen_declarator : declarator without parenthesized name def _parse_typeid_noparen_declarator(self) -> c_ast.Node: return self._parse_declarator_kind(kind="typeid", allow_paren=False) # BNF: declarator_kind : pointer? direct_declarator(kind) def _parse_declarator_kind(self, kind: str, allow_paren: bool) -> c_ast.Node: ptr = None if self._peek_type() == "TIMES": ptr = self._parse_pointer() direct = self._parse_direct_declarator(kind, allow_paren=allow_paren) if ptr is not None: return self._type_modify_decl(direct, ptr) return direct # BNF: direct_declarator : ID | TYPEID | '(' declarator ')' # | direct_declarator '[' ... ']' # | direct_declarator '(' ... ')' def _parse_direct_declarator( self, kind: str, allow_paren: bool = True ) -> c_ast.Node: if allow_paren and self._accept("LPAREN"): decl = self._parse_declarator_kind(kind, allow_paren=True) self._expect("RPAREN") else: if kind == "id": name_tok = self._expect("ID") else: name_tok = self._expect("TYPEID") decl = c_ast.TypeDecl( declname=name_tok.value, type=None, quals=None, align=None, coord=self._tok_coord(name_tok), ) return self._parse_decl_suffixes(decl) def _parse_decl_suffixes(self, decl: c_ast.Node) -> c_ast.Node: """Parse a chain of array/function suffixes and attach them to decl.""" while True: if self._peek_type() == "LBRACKET": decl = self._type_modify_decl(decl, self._parse_array_decl(decl)) continue if self._peek_type() == "LPAREN": func = self._parse_function_decl(decl) decl = self._type_modify_decl(decl, func) continue break return decl # BNF: array_decl : '[' array_specifiers? assignment_expression? ']' def _parse_array_decl(self, base_decl: c_ast.Node) -> c_ast.Node: return self._parse_array_decl_common(base_type=None, coord=base_decl.coord) def _parse_array_decl_common( self, base_type: Optional[c_ast.Node], coord: Optional[Coord] = None ) -> c_ast.Node: """Parse an array declarator suffix and return an ArrayDecl node. base_type: Base declarator node to attach (None for direct-declarator parsing, TypeDecl for abstract declarators). coord: Coordinate to use for the ArrayDecl. If None, uses the '[' token. """ lbrack_tok = self._expect("LBRACKET") if coord is None: coord = self._tok_coord(lbrack_tok) def make_array_decl(dim, dim_quals): return c_ast.ArrayDecl( type=base_type, dim=dim, dim_quals=dim_quals, coord=coord ) if self._accept("STATIC"): dim_quals = ["static"] + (self._parse_type_qualifier_list() or []) dim = self._parse_assignment_expression() self._expect("RBRACKET") return make_array_decl(dim, dim_quals) if self._peek_type() in _TYPE_QUALIFIER: dim_quals = self._parse_type_qualifier_list() or [] if self._accept("STATIC"): dim_quals = dim_quals + ["static"] dim = self._parse_assignment_expression() self._expect("RBRACKET") return make_array_decl(dim, dim_quals) times_tok = self._accept("TIMES") if times_tok: self._expect("RBRACKET") dim = c_ast.ID(times_tok.value, self._tok_coord(times_tok)) return make_array_decl(dim, dim_quals) dim = None if self._starts_expression(): dim = self._parse_assignment_expression() self._expect("RBRACKET") return make_array_decl(dim, dim_quals) times_tok = self._accept("TIMES") if times_tok: self._expect("RBRACKET") dim = c_ast.ID(times_tok.value, self._tok_coord(times_tok)) return make_array_decl(dim, []) dim = None if self._starts_expression(): dim = self._parse_assignment_expression() self._expect("RBRACKET") return make_array_decl(dim, []) # BNF: function_decl : '(' parameter_type_list_opt | identifier_list_opt ')' def _parse_function_decl(self, base_decl: c_ast.Node) -> c_ast.Node: self._expect("LPAREN") if self._accept("RPAREN"): args = None else: args = ( self._parse_parameter_type_list() if self._starts_declaration() else self._parse_identifier_list_opt() ) self._expect("RPAREN") func = c_ast.FuncDecl(args=args, type=None, coord=base_decl.coord) if self._peek_type() == "LBRACE": if func.args is not None: for param in func.args.params: if isinstance(param, c_ast.EllipsisParam): break name = getattr(param, "name", None) if name: self._add_identifier(name, param.coord) return func # BNF: pointer : '*' type_qualifier_list? pointer? def _parse_pointer(self) -> Optional[c_ast.Node]: stars = [] times_tok = self._accept("TIMES") while times_tok: quals = self._parse_type_qualifier_list() or [] stars.append((quals, self._tok_coord(times_tok))) times_tok = self._accept("TIMES") if not stars: return None ptr = None for quals, coord in stars: ptr = c_ast.PtrDecl(quals=quals, type=ptr, coord=coord) return ptr # BNF: parameter_type_list : parameter_list (',' ELLIPSIS)? def _parse_parameter_type_list(self) -> c_ast.ParamList: params = self._parse_parameter_list() if self._peek_type() == "COMMA" and self._peek_type(2) == "ELLIPSIS": self._advance() ell_tok = self._advance() params.params.append(c_ast.EllipsisParam(self._tok_coord(ell_tok))) return params # BNF: parameter_list : parameter_declaration (',' parameter_declaration)* def _parse_parameter_list(self) -> c_ast.ParamList: first = self._parse_parameter_declaration() params = c_ast.ParamList([first], first.coord) while self._peek_type() == "COMMA" and self._peek_type(2) != "ELLIPSIS": self._advance() params.params.append(self._parse_parameter_declaration()) return params # BNF: parameter_declaration : declaration_specifiers declarator? # | declaration_specifiers abstract_declarator_opt def _parse_parameter_declaration(self) -> c_ast.Node: spec, _, spec_coord = self._parse_declaration_specifiers(allow_no_type=True) if not spec["type"]: spec["type"] = [c_ast.IdentifierType(["int"], coord=spec_coord)] if self._starts_declarator(): decl, is_named = self._parse_any_declarator( allow_abstract=True, typeid_paren_as_abstract=True ) if is_named: return self._build_declarations( spec=spec, decls=[dict(decl=decl, init=None, bitsize=None)] )[0] return self._build_parameter_declaration(spec, decl, spec_coord) decl = self._parse_abstract_declarator_opt() return self._build_parameter_declaration(spec, decl, spec_coord) def _build_parameter_declaration( self, spec: "_DeclSpec", decl: Optional[c_ast.Node], spec_coord: Optional[Coord] ) -> c_ast.Node: if ( len(spec["type"]) > 1 and len(spec["type"][-1].names) == 1 and self._is_type_in_scope(spec["type"][-1].names[0]) ): return self._build_declarations( spec=spec, decls=[dict(decl=decl, init=None, bitsize=None)] )[0] decl = c_ast.Typename( name="", quals=spec["qual"], align=None, type=decl or c_ast.TypeDecl(None, None, None, None), coord=spec_coord, ) return self._fix_decl_name_type(decl, spec["type"]) # BNF: identifier_list_opt : identifier_list | empty def _parse_identifier_list_opt(self) -> Optional[c_ast.Node]: if self._peek_type() == "RPAREN": return None return self._parse_identifier_list() # BNF: identifier_list : identifier (',' identifier)* def _parse_identifier_list(self) -> c_ast.Node: first = self._parse_identifier() params = c_ast.ParamList([first], first.coord) while self._accept("COMMA"): params.params.append(self._parse_identifier()) return params # ------------------------------------------------------------------ # Abstract declarators # ------------------------------------------------------------------ # BNF: type_name : specifier_qualifier_list abstract_declarator_opt def _parse_type_name(self) -> c_ast.Typename: spec = self._parse_specifier_qualifier_list() decl = self._parse_abstract_declarator_opt() coord = None if decl is not None: coord = decl.coord elif spec["type"]: coord = spec["type"][0].coord typename = c_ast.Typename( name="", quals=spec["qual"][:], align=None, type=decl or c_ast.TypeDecl(None, None, None, None), coord=coord, ) return cast(c_ast.Typename, self._fix_decl_name_type(typename, spec["type"])) # BNF: abstract_declarator_opt : pointer? direct_abstract_declarator? def _parse_abstract_declarator_opt(self) -> Optional[c_ast.Node]: if self._peek_type() == "TIMES": ptr = self._parse_pointer() if self._starts_direct_abstract_declarator(): decl = self._parse_direct_abstract_declarator() else: decl = c_ast.TypeDecl(None, None, None, None) assert ptr is not None return self._type_modify_decl(decl, ptr) if self._starts_direct_abstract_declarator(): return self._parse_direct_abstract_declarator() return None # BNF: direct_abstract_declarator : '(' parameter_type_list_opt ')' # | '(' abstract_declarator ')' # | '[' ... ']' def _parse_direct_abstract_declarator(self) -> c_ast.Node: lparen_tok = self._accept("LPAREN") if lparen_tok: if self._starts_declaration() or self._peek_type() == "RPAREN": params = self._parse_parameter_type_list_opt() self._expect("RPAREN") decl = c_ast.FuncDecl( args=params, type=c_ast.TypeDecl(None, None, None, None), coord=self._tok_coord(lparen_tok), ) else: decl = self._parse_abstract_declarator_opt() self._expect("RPAREN") assert decl is not None elif self._peek_type() == "LBRACKET": decl = self._parse_abstract_array_base() else: self._parse_error("Invalid abstract declarator", self.clex.filename) return self._parse_decl_suffixes(decl) # BNF: parameter_type_list_opt : parameter_type_list | empty def _parse_parameter_type_list_opt(self) -> Optional[c_ast.ParamList]: if self._peek_type() == "RPAREN": return None return self._parse_parameter_type_list() # BNF: abstract_array_base : '[' array_specifiers? assignment_expression? ']' def _parse_abstract_array_base(self) -> c_ast.Node: return self._parse_array_decl_common( base_type=c_ast.TypeDecl(None, None, None, None), coord=None ) # ------------------------------------------------------------------ # Statements # ------------------------------------------------------------------ # BNF: statement : labeled_statement | compound_statement # | selection_statement | iteration_statement # | jump_statement | expression_statement # | static_assert | pppragma_directive def _parse_statement(self) -> c_ast.Node | List[c_ast.Node]: tok_type = self._peek_type() match tok_type: case "CASE" | "DEFAULT": return self._parse_labeled_statement() case "ID" if self._peek_type(2) == "COLON": return self._parse_labeled_statement() case "LBRACE": return self._parse_compound_statement() case "IF" | "SWITCH": return self._parse_selection_statement() case "WHILE" | "DO" | "FOR": return self._parse_iteration_statement() case "GOTO" | "BREAK" | "CONTINUE" | "RETURN": return self._parse_jump_statement() case "PPPRAGMA" | "_PRAGMA": return self._parse_pppragma_directive() case "_STATIC_ASSERT": return self._parse_static_assert() case _: return self._parse_expression_statement() # BNF: pragmacomp_or_statement : pppragma_directive* statement def _parse_pragmacomp_or_statement(self) -> c_ast.Node | List[c_ast.Node]: if self._peek_type() in {"PPPRAGMA", "_PRAGMA"}: pragmas = self._parse_pppragma_directive_list() stmt = self._parse_statement() return c_ast.Compound(block_items=pragmas + [stmt], coord=pragmas[0].coord) return self._parse_statement() # BNF: block_item : declaration | statement def _parse_block_item(self) -> c_ast.Node | List[c_ast.Node]: if self._starts_declaration(): return self._parse_declaration() return self._parse_statement() # BNF: block_item_list : block_item+ def _parse_block_item_list(self) -> List[c_ast.Node]: items = [] while self._peek_type() not in {"RBRACE", None}: item = self._parse_block_item() if isinstance(item, list): if item == [None]: continue items.extend(item) else: items.append(item) return items # BNF: compound_statement : '{' block_item_list? '}' def _parse_compound_statement(self) -> c_ast.Node: lbrace_tok = self._expect("LBRACE") if self._accept("RBRACE"): return c_ast.Compound(block_items=None, coord=self._tok_coord(lbrace_tok)) block_items = self._parse_block_item_list() self._expect("RBRACE") return c_ast.Compound( block_items=block_items, coord=self._tok_coord(lbrace_tok) ) # BNF: labeled_statement : ID ':' statement # | CASE constant_expression ':' statement # | DEFAULT ':' statement def _parse_labeled_statement(self) -> c_ast.Node: tok_type = self._peek_type() match tok_type: case "ID": name_tok = self._advance() self._expect("COLON") if self._starts_statement(): stmt = self._parse_pragmacomp_or_statement() else: stmt = c_ast.EmptyStatement(self._tok_coord(name_tok)) return c_ast.Label(name_tok.value, stmt, self._tok_coord(name_tok)) case "CASE": case_tok = self._advance() expr = self._parse_constant_expression() self._expect("COLON") if self._starts_statement(): stmt = self._parse_pragmacomp_or_statement() else: stmt = c_ast.EmptyStatement(self._tok_coord(case_tok)) return c_ast.Case(expr, [stmt], self._tok_coord(case_tok)) case "DEFAULT": def_tok = self._advance() self._expect("COLON") if self._starts_statement(): stmt = self._parse_pragmacomp_or_statement() else: stmt = c_ast.EmptyStatement(self._tok_coord(def_tok)) return c_ast.Default([stmt], self._tok_coord(def_tok)) case _: self._parse_error("Invalid labeled statement", self.clex.filename) # BNF: selection_statement : IF '(' expression ')' statement (ELSE statement)? # | SWITCH '(' expression ')' statement def _parse_selection_statement(self) -> c_ast.Node: tok = self._advance() match tok.type: case "IF": self._expect("LPAREN") cond = self._parse_expression() self._expect("RPAREN") then_stmt = self._parse_pragmacomp_or_statement() if self._accept("ELSE"): else_stmt = self._parse_pragmacomp_or_statement() return c_ast.If(cond, then_stmt, else_stmt, self._tok_coord(tok)) return c_ast.If(cond, then_stmt, None, self._tok_coord(tok)) case "SWITCH": self._expect("LPAREN") expr = self._parse_expression() self._expect("RPAREN") stmt = self._parse_pragmacomp_or_statement() return fix_switch_cases(c_ast.Switch(expr, stmt, self._tok_coord(tok))) case _: self._parse_error("Invalid selection statement", self._tok_coord(tok)) # BNF: iteration_statement : WHILE '(' expression ')' statement # | DO statement WHILE '(' expression ')' ';' # | FOR '(' (declaration | expression_opt) ';' # expression_opt ';' expression_opt ')' statement def _parse_iteration_statement(self) -> c_ast.Node: tok = self._advance() match tok.type: case "WHILE": self._expect("LPAREN") cond = self._parse_expression() self._expect("RPAREN") stmt = self._parse_pragmacomp_or_statement() return c_ast.While(cond, stmt, self._tok_coord(tok)) case "DO": stmt = self._parse_pragmacomp_or_statement() self._expect("WHILE") self._expect("LPAREN") cond = self._parse_expression() self._expect("RPAREN") self._expect("SEMI") return c_ast.DoWhile(cond, stmt, self._tok_coord(tok)) case "FOR": self._expect("LPAREN") if self._starts_declaration(): decls = self._parse_declaration() init = c_ast.DeclList(decls, self._tok_coord(tok)) cond = self._parse_expression_opt() self._expect("SEMI") next_expr = self._parse_expression_opt() self._expect("RPAREN") stmt = self._parse_pragmacomp_or_statement() return c_ast.For(init, cond, next_expr, stmt, self._tok_coord(tok)) init = self._parse_expression_opt() self._expect("SEMI") cond = self._parse_expression_opt() self._expect("SEMI") next_expr = self._parse_expression_opt() self._expect("RPAREN") stmt = self._parse_pragmacomp_or_statement() return c_ast.For(init, cond, next_expr, stmt, self._tok_coord(tok)) case _: self._parse_error("Invalid iteration statement", self._tok_coord(tok)) # BNF: jump_statement : GOTO ID ';' | BREAK ';' | CONTINUE ';' # | RETURN expression? ';' def _parse_jump_statement(self) -> c_ast.Node: tok = self._advance() match tok.type: case "GOTO": name_tok = self._expect("ID") self._expect("SEMI") return c_ast.Goto(name_tok.value, self._tok_coord(tok)) case "BREAK": self._expect("SEMI") return c_ast.Break(self._tok_coord(tok)) case "CONTINUE": self._expect("SEMI") return c_ast.Continue(self._tok_coord(tok)) case "RETURN": if self._accept("SEMI"): return c_ast.Return(None, self._tok_coord(tok)) expr = self._parse_expression() self._expect("SEMI") return c_ast.Return(expr, self._tok_coord(tok)) case _: self._parse_error("Invalid jump statement", self._tok_coord(tok)) # BNF: expression_statement : expression_opt ';' def _parse_expression_statement(self) -> c_ast.Node: expr = self._parse_expression_opt() semi_tok = self._expect("SEMI") if expr is None: return c_ast.EmptyStatement(self._tok_coord(semi_tok)) return expr # ------------------------------------------------------------------ # Expressions # ------------------------------------------------------------------ # BNF: expression_opt : expression | empty def _parse_expression_opt(self) -> Optional[c_ast.Node]: if self._starts_expression(): return self._parse_expression() return None # BNF: expression : assignment_expression (',' assignment_expression)* def _parse_expression(self) -> c_ast.Node: expr = self._parse_assignment_expression() if not self._accept("COMMA"): return expr exprs = [expr, self._parse_assignment_expression()] while self._accept("COMMA"): exprs.append(self._parse_assignment_expression()) return c_ast.ExprList(exprs, expr.coord) # BNF: assignment_expression : conditional_expression # | unary_expression assignment_op assignment_expression def _parse_assignment_expression(self) -> c_ast.Node: if self._peek_type() == "LPAREN" and self._peek_type(2) == "LBRACE": self._advance() comp = self._parse_compound_statement() self._expect("RPAREN") return comp expr = self._parse_conditional_expression() if self._is_assignment_op(): op = self._advance().value rhs = self._parse_assignment_expression() return c_ast.Assignment(op, expr, rhs, expr.coord) return expr # BNF: conditional_expression : binary_expression # | binary_expression '?' expression ':' conditional_expression def _parse_conditional_expression(self) -> c_ast.Node: expr = self._parse_binary_expression() if self._accept("CONDOP"): iftrue = self._parse_expression() self._expect("COLON") iffalse = self._parse_conditional_expression() return c_ast.TernaryOp(expr, iftrue, iffalse, expr.coord) return expr # BNF: binary_expression : cast_expression (binary_op cast_expression)* def _parse_binary_expression( self, min_prec: int = 0, lhs: Optional[c_ast.Node] = None ) -> c_ast.Node: if lhs is None: lhs = self._parse_cast_expression() while True: tok = self._peek() if tok is None or tok.type not in _BINARY_PRECEDENCE: break prec = _BINARY_PRECEDENCE[tok.type] if prec < min_prec: break op = tok.value self._advance() rhs = self._parse_cast_expression() while True: next_tok = self._peek() if next_tok is None or next_tok.type not in _BINARY_PRECEDENCE: break next_prec = _BINARY_PRECEDENCE[next_tok.type] if next_prec > prec: rhs = self._parse_binary_expression(next_prec, rhs) else: break lhs = c_ast.BinaryOp(op, lhs, rhs, lhs.coord) return lhs # BNF: cast_expression : '(' type_name ')' cast_expression # | unary_expression def _parse_cast_expression(self) -> c_ast.Node: result = self._try_parse_paren_type_name() if result is not None: typ, mark, lparen_tok = result if self._peek_type() == "LBRACE": # (type){...} is a compound literal, not a cast. Examples: # (int){1} -> compound literal, handled in postfix # (int) x -> cast, handled below self._reset(mark) else: expr = self._parse_cast_expression() return c_ast.Cast(typ, expr, self._tok_coord(lparen_tok)) return self._parse_unary_expression() # BNF: unary_expression : postfix_expression # | '++' unary_expression # | '--' unary_expression # | unary_op cast_expression # | 'sizeof' unary_expression # | 'sizeof' '(' type_name ')' # | '_Alignof' '(' type_name ')' def _parse_unary_expression(self) -> c_ast.Node: tok_type = self._peek_type() if tok_type in {"PLUSPLUS", "MINUSMINUS"}: tok = self._advance() expr = self._parse_unary_expression() return c_ast.UnaryOp(tok.value, expr, expr.coord) if tok_type in {"AND", "TIMES", "PLUS", "MINUS", "NOT", "LNOT"}: tok = self._advance() expr = self._parse_cast_expression() return c_ast.UnaryOp(tok.value, expr, expr.coord) if tok_type == "SIZEOF": tok = self._advance() result = self._try_parse_paren_type_name() if result is not None: typ, _, _ = result return c_ast.UnaryOp(tok.value, typ, self._tok_coord(tok)) expr = self._parse_unary_expression() return c_ast.UnaryOp(tok.value, expr, self._tok_coord(tok)) if tok_type == "_ALIGNOF": tok = self._advance() self._expect("LPAREN") typ = self._parse_type_name() self._expect("RPAREN") return c_ast.UnaryOp(tok.value, typ, self._tok_coord(tok)) return self._parse_postfix_expression() # BNF: postfix_expression : primary_expression postfix_suffix* # | '(' type_name ')' '{' initializer_list ','? '}' def _parse_postfix_expression(self) -> c_ast.Node: result = self._try_parse_paren_type_name() if result is not None: typ, mark, _ = result # Disambiguate between casts and compound literals: # (int) x -> cast # (int) {1} -> compound literal if self._accept("LBRACE"): init = self._parse_initializer_list() self._accept("COMMA") self._expect("RBRACE") return c_ast.CompoundLiteral(typ, init) else: self._reset(mark) expr = self._parse_primary_expression() while True: if self._accept("LBRACKET"): sub = self._parse_expression() self._expect("RBRACKET") expr = c_ast.ArrayRef(expr, sub, expr.coord) continue if self._accept("LPAREN"): if self._peek_type() == "RPAREN": self._advance() args = None else: args = self._parse_argument_expression_list() self._expect("RPAREN") expr = c_ast.FuncCall(expr, args, expr.coord) continue if self._peek_type() in {"PERIOD", "ARROW"}: op_tok = self._advance() name_tok = self._advance() if name_tok.type not in {"ID", "TYPEID"}: self._parse_error( "Invalid struct reference", self._tok_coord(name_tok) ) field = c_ast.ID(name_tok.value, self._tok_coord(name_tok)) expr = c_ast.StructRef(expr, op_tok.value, field, expr.coord) continue if self._peek_type() in {"PLUSPLUS", "MINUSMINUS"}: tok = self._advance() expr = c_ast.UnaryOp("p" + tok.value, expr, expr.coord) continue break return expr # BNF: primary_expression : ID | constant | string_literal # | '(' expression ')' | offsetof def _parse_primary_expression(self) -> c_ast.Node: tok_type = self._peek_type() if tok_type == "ID": return self._parse_identifier() if ( tok_type in _INT_CONST or tok_type in _FLOAT_CONST or tok_type in _CHAR_CONST ): return self._parse_constant() if tok_type in _STRING_LITERAL: return self._parse_unified_string_literal() if tok_type in _WSTR_LITERAL: return self._parse_unified_wstring_literal() if tok_type == "LPAREN": self._advance() expr = self._parse_expression() self._expect("RPAREN") return expr if tok_type == "OFFSETOF": off_tok = self._advance() self._expect("LPAREN") typ = self._parse_type_name() self._expect("COMMA") designator = self._parse_offsetof_member_designator() self._expect("RPAREN") coord = self._tok_coord(off_tok) return c_ast.FuncCall( c_ast.ID(off_tok.value, coord), c_ast.ExprList([typ, designator], coord), coord, ) self._parse_error("Invalid expression", self.clex.filename) # BNF: offsetof_member_designator : identifier_or_typeid # ('.' identifier_or_typeid | '[' expression ']')* def _parse_offsetof_member_designator(self) -> c_ast.Node: node = self._parse_identifier_or_typeid() while True: if self._accept("PERIOD"): field = self._parse_identifier_or_typeid() node = c_ast.StructRef(node, ".", field, node.coord) continue if self._accept("LBRACKET"): expr = self._parse_expression() self._expect("RBRACKET") node = c_ast.ArrayRef(node, expr, node.coord) continue break return node # BNF: argument_expression_list : assignment_expression (',' assignment_expression)* def _parse_argument_expression_list(self) -> c_ast.Node: expr = self._parse_assignment_expression() exprs = [expr] while self._accept("COMMA"): exprs.append(self._parse_assignment_expression()) return c_ast.ExprList(exprs, expr.coord) # BNF: constant_expression : conditional_expression def _parse_constant_expression(self) -> c_ast.Node: return self._parse_conditional_expression() # ------------------------------------------------------------------ # Terminals # ------------------------------------------------------------------ # BNF: identifier : ID def _parse_identifier(self) -> c_ast.Node: tok = self._expect("ID") return c_ast.ID(tok.value, self._tok_coord(tok)) # BNF: identifier_or_typeid : ID | TYPEID def _parse_identifier_or_typeid(self) -> c_ast.Node: tok = self._advance() if tok.type not in {"ID", "TYPEID"}: self._parse_error("Expected identifier", self._tok_coord(tok)) return c_ast.ID(tok.value, self._tok_coord(tok)) # BNF: constant : INT_CONST | FLOAT_CONST | CHAR_CONST def _parse_constant(self) -> c_ast.Node: tok = self._advance() if tok.type in _INT_CONST: u_count = 0 l_count = 0 for ch in tok.value[-3:]: if ch in ("l", "L"): l_count += 1 elif ch in ("u", "U"): u_count += 1 if u_count > 1: raise ValueError("Constant cannot have more than one u/U suffix.") if l_count > 2: raise ValueError("Constant cannot have more than two l/L suffix.") prefix = "unsigned " * u_count + "long " * l_count return c_ast.Constant(prefix + "int", tok.value, self._tok_coord(tok)) if tok.type in _FLOAT_CONST: if tok.value[-1] in ("f", "F"): t = "float" elif tok.value[-1] in ("l", "L"): t = "long double" else: t = "double" return c_ast.Constant(t, tok.value, self._tok_coord(tok)) if tok.type in _CHAR_CONST: return c_ast.Constant("char", tok.value, self._tok_coord(tok)) self._parse_error("Invalid constant", self._tok_coord(tok)) # BNF: unified_string_literal : STRING_LITERAL+ def _parse_unified_string_literal(self) -> c_ast.Node: tok = self._expect("STRING_LITERAL") node = c_ast.Constant("string", tok.value, self._tok_coord(tok)) while self._peek_type() == "STRING_LITERAL": tok2 = self._advance() node.value = node.value[:-1] + tok2.value[1:] return node # BNF: unified_wstring_literal : WSTRING_LITERAL+ def _parse_unified_wstring_literal(self) -> c_ast.Node: tok = self._advance() if tok.type not in _WSTR_LITERAL: self._parse_error("Invalid string literal", self._tok_coord(tok)) node = c_ast.Constant("string", tok.value, self._tok_coord(tok)) while self._peek_type() in _WSTR_LITERAL: tok2 = self._advance() node.value = node.value.rstrip()[:-1] + tok2.value[2:] return node # ------------------------------------------------------------------ # Initializers # ------------------------------------------------------------------ # BNF: initializer : assignment_expression # | '{' initializer_list ','? '}' # | '{' '}' def _parse_initializer(self) -> c_ast.Node: lbrace_tok = self._accept("LBRACE") if lbrace_tok: if self._accept("RBRACE"): return c_ast.InitList([], self._tok_coord(lbrace_tok)) init_list = self._parse_initializer_list() self._accept("COMMA") self._expect("RBRACE") return init_list return self._parse_assignment_expression() # BNF: initializer_list : initializer_item (',' initializer_item)* ','? def _parse_initializer_list(self) -> c_ast.Node: items = [self._parse_initializer_item()] while self._accept("COMMA"): if self._peek_type() == "RBRACE": break items.append(self._parse_initializer_item()) return c_ast.InitList(items, items[0].coord) # BNF: initializer_item : designation? initializer def _parse_initializer_item(self) -> c_ast.Node: designation = None if self._peek_type() in {"LBRACKET", "PERIOD"}: designation = self._parse_designation() init = self._parse_initializer() if designation is not None: return c_ast.NamedInitializer(designation, init) return init # BNF: designation : designator_list '=' def _parse_designation(self) -> List[c_ast.Node]: designators = self._parse_designator_list() self._expect("EQUALS") return designators # BNF: designator_list : designator+ def _parse_designator_list(self) -> List[c_ast.Node]: designators = [] while self._peek_type() in {"LBRACKET", "PERIOD"}: designators.append(self._parse_designator()) return designators # BNF: designator : '[' constant_expression ']' # | '.' identifier_or_typeid def _parse_designator(self) -> c_ast.Node: if self._accept("LBRACKET"): expr = self._parse_constant_expression() self._expect("RBRACKET") return expr if self._accept("PERIOD"): return self._parse_identifier_or_typeid() self._parse_error("Invalid designator", self.clex.filename) # ------------------------------------------------------------------ # Preprocessor-like directives # ------------------------------------------------------------------ # BNF: pp_directive : '#' ... (unsupported) def _parse_pp_directive(self) -> NoReturn: tok = self._expect("PPHASH") self._parse_error("Directives not supported yet", self._tok_coord(tok)) # BNF: pppragma_directive : PPPRAGMA PPPRAGMASTR? # | _PRAGMA '(' string_literal ')' def _parse_pppragma_directive(self) -> c_ast.Node: if self._peek_type() == "PPPRAGMA": tok = self._advance() if self._peek_type() == "PPPRAGMASTR": str_tok = self._advance() return c_ast.Pragma(str_tok.value, self._tok_coord(str_tok)) return c_ast.Pragma("", self._tok_coord(tok)) if self._peek_type() == "_PRAGMA": tok = self._advance() lparen = self._expect("LPAREN") literal = self._parse_unified_string_literal() self._expect("RPAREN") return c_ast.Pragma(literal, self._tok_coord(lparen)) self._parse_error("Invalid pragma", self.clex.filename) # BNF: pppragma_directive_list : pppragma_directive+ def _parse_pppragma_directive_list(self) -> List[c_ast.Node]: pragmas = [] while self._peek_type() in {"PPPRAGMA", "_PRAGMA"}: pragmas.append(self._parse_pppragma_directive()) return pragmas # BNF: static_assert : _STATIC_ASSERT '(' constant_expression (',' string_literal)? ')' def _parse_static_assert(self) -> List[c_ast.Node]: tok = self._expect("_STATIC_ASSERT") self._expect("LPAREN") cond = self._parse_constant_expression() msg = None if self._accept("COMMA"): msg = self._parse_unified_string_literal() self._expect("RPAREN") return [c_ast.StaticAssert(cond, msg, self._tok_coord(tok))] _ASSIGNMENT_OPS = { "EQUALS", "XOREQUAL", "TIMESEQUAL", "DIVEQUAL", "MODEQUAL", "PLUSEQUAL", "MINUSEQUAL", "LSHIFTEQUAL", "RSHIFTEQUAL", "ANDEQUAL", "OREQUAL", } # Precedence of operators (lower number = weather binding) # If this changes, c_generator.CGenerator.precedence_map needs to change as # well _BINARY_PRECEDENCE = { "LOR": 0, "LAND": 1, "OR": 2, "XOR": 3, "AND": 4, "EQ": 5, "NE": 5, "GT": 6, "GE": 6, "LT": 6, "LE": 6, "RSHIFT": 7, "LSHIFT": 7, "PLUS": 8, "MINUS": 8, "TIMES": 9, "DIVIDE": 9, "MOD": 9, } _STORAGE_CLASS = {"AUTO", "REGISTER", "STATIC", "EXTERN", "TYPEDEF", "_THREAD_LOCAL"} _FUNCTION_SPEC = {"INLINE", "_NORETURN"} _TYPE_QUALIFIER = {"CONST", "RESTRICT", "VOLATILE", "_ATOMIC"} _TYPE_SPEC_SIMPLE = { "VOID", "_BOOL", "CHAR", "SHORT", "INT", "LONG", "FLOAT", "DOUBLE", "_COMPLEX", "SIGNED", "UNSIGNED", "__INT128", } _DECL_START = ( _STORAGE_CLASS | _FUNCTION_SPEC | _TYPE_QUALIFIER | _TYPE_SPEC_SIMPLE | {"TYPEID", "STRUCT", "UNION", "ENUM", "_ALIGNAS", "_ATOMIC"} ) _EXPR_START = { "ID", "LPAREN", "PLUSPLUS", "MINUSMINUS", "PLUS", "MINUS", "TIMES", "AND", "NOT", "LNOT", "SIZEOF", "_ALIGNOF", "OFFSETOF", } _INT_CONST = { "INT_CONST_DEC", "INT_CONST_OCT", "INT_CONST_HEX", "INT_CONST_BIN", "INT_CONST_CHAR", } _FLOAT_CONST = {"FLOAT_CONST", "HEX_FLOAT_CONST"} _CHAR_CONST = { "CHAR_CONST", "WCHAR_CONST", "U8CHAR_CONST", "U16CHAR_CONST", "U32CHAR_CONST", } _STRING_LITERAL = {"STRING_LITERAL"} _WSTR_LITERAL = { "WSTRING_LITERAL", "U8STRING_LITERAL", "U16STRING_LITERAL", "U32STRING_LITERAL", } _STARTS_EXPRESSION = ( _EXPR_START | _INT_CONST | _FLOAT_CONST | _CHAR_CONST | _STRING_LITERAL | _WSTR_LITERAL ) _STARTS_STATEMENT = { "LBRACE", "IF", "SWITCH", "WHILE", "DO", "FOR", "GOTO", "BREAK", "CONTINUE", "RETURN", "CASE", "DEFAULT", "PPPRAGMA", "_PRAGMA", "_STATIC_ASSERT", "SEMI", } class _TokenStream: """Wraps a lexer to provide convenient, buffered access to the underlying token stream. The lexer is expected to be initialized with the input string already. """ def __init__(self, lexer: CLexer) -> None: self._lexer = lexer self._buffer: List[Optional[_Token]] = [] self._index = 0 def peek(self, k: int = 1) -> Optional[_Token]: """Peek at the k-th next token in the stream, without consuming it. Examples: k=1 returns the immediate next token. k=2 returns the token after that. """ if k <= 0: return None self._fill(k) return self._buffer[self._index + k - 1] def next(self) -> Optional[_Token]: """Consume a single token and return it.""" self._fill(1) tok = self._buffer[self._index] self._index += 1 return tok # The 'mark' and 'reset' methods are useful for speculative parsing with # backtracking; when the parser needs to examine a sequence of tokens # and potentially decide to try a different path on the same sequence, it # can call 'mark' to obtain the current token position, and if the first # path fails restore the position with `reset(pos)`. def mark(self) -> int: return self._index def reset(self, mark: int) -> None: self._index = mark def _fill(self, n: int) -> None: while len(self._buffer) < self._index + n: tok = self._lexer.token() self._buffer.append(tok) if tok is None: break # Declaration specifiers are represented by a dictionary with entries: # - qual: a list of type qualifiers # - storage: a list of storage class specifiers # - type: a list of type specifiers # - function: a list of function specifiers # - alignment: a list of alignment specifiers class _DeclSpec(TypedDict): qual: List[Any] storage: List[Any] type: List[Any] function: List[Any] alignment: List[Any] _DeclSpecKind = Literal["qual", "storage", "type", "function", "alignment"] class _DeclInfo(TypedDict): # Declarator payloads used by declaration/initializer parsing: # - decl: the declarator node (may be None for abstract/implicit cases) # - init: optional initializer expression # - bitsize: optional bit-field width expression (for struct declarators) decl: Optional[c_ast.Node] init: Optional[c_ast.Node] bitsize: Optional[c_ast.Node] ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1769005549.469172 pycparser-3.0/pycparser.egg-info/0000775000175000017500000000000015134160755016415 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769005549.0 pycparser-3.0/pycparser.egg-info/PKG-INFO0000644000175000017500000002004515134160755017511 0ustar00elibenelibenMetadata-Version: 2.4 Name: pycparser Version: 3.0 Summary: C parser in Python Author-email: Eli Bendersky Maintainer-email: Eli Bendersky License-Expression: BSD-3-Clause Project-URL: Homepage, https://github.com/eliben/pycparser Classifier: Development Status :: 5 - Production/Stable Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Programming Language :: Python :: 3.14 Requires-Python: >=3.10 Description-Content-Type: text/x-rst License-File: LICENSE Dynamic: license-file =============== pycparser v3.00 =============== .. image:: https://github.com/eliben/pycparser/workflows/pycparser-tests/badge.svg :align: center :target: https://github.com/eliben/pycparser/actions ---- .. contents:: :backlinks: none .. sectnum:: Introduction ============ What is pycparser? ------------------ **pycparser** is a parser for the C language, written in pure Python. It is a module designed to be easily integrated into applications that need to parse C source code. What is it good for? -------------------- Anything that needs C code to be parsed. The following are some uses for **pycparser**, taken from real user reports: * C code obfuscator * Front-end for various specialized C compilers * Static code checker * Automatic unit-test discovery * Adding specialized extensions to the C language One of the most popular uses of **pycparser** is in the `cffi `_ library, which uses it to parse the declarations of C functions and types in order to auto-generate FFIs. **pycparser** is unique in the sense that it's written in pure Python - a very high level language that's easy to experiment with and tweak. To people familiar with Lex and Yacc, **pycparser**'s code will be simple to understand. It also has no external dependencies (except for a Python interpreter), making it very simple to install and deploy. Which version of C does pycparser support? ------------------------------------------ **pycparser** aims to support the full C99 language (according to the standard ISO/IEC 9899). Some features from C11 are also supported, and patches to support more are welcome. **pycparser** supports very few GCC extensions, but it's fairly easy to set things up so that it parses code with a lot of GCC-isms successfully. See the `FAQ `_ for more details. What grammar does pycparser follow? ----------------------------------- **pycparser** very closely follows the C grammar provided in Annex A of the C99 standard (ISO/IEC 9899). How is pycparser licensed? -------------------------- `BSD license `_. Contact details --------------- For reporting problems with **pycparser** or submitting feature requests, please open an `issue `_, or submit a pull request. Installing ========== Prerequisites ------------- **pycparser** is being tested with modern versions of Python on Linux, macOS and Windows. See `the CI dashboard `__ for details. **pycparser** has no external dependencies. Installation process -------------------- The recommended way to install **pycparser** is with ``pip``:: > pip install pycparser Using ===== Interaction with the C preprocessor ----------------------------------- In order to be compilable, C code must be preprocessed by the C preprocessor - ``cpp``. A compatible ``cpp`` handles preprocessing directives like ``#include`` and ``#define``, removes comments, and performs other minor tasks that prepare the C code for compilation. For all but the most trivial snippets of C code **pycparser**, like a C compiler, must receive preprocessed C code in order to function correctly. If you import the top-level ``parse_file`` function from the **pycparser** package, it will interact with ``cpp`` for you, as long as it's in your PATH, or you provide a path to it. Note also that you can use ``gcc -E`` or ``clang -E`` instead of ``cpp``. See the ``using_gcc_E_libc.py`` example for more details. Windows users can download and install a binary build of Clang for Windows `from this website `_. What about the standard C library headers? ------------------------------------------ C code almost always ``#include``\s various header files from the standard C library, like ``stdio.h``. While (with some effort) **pycparser** can be made to parse the standard headers from any C compiler, it's much simpler to use the provided "fake" standard includes for C11 in ``utils/fake_libc_include``. These are standard C header files that contain only the bare necessities to allow valid parsing of the files that use them. As a bonus, since they're minimal, it can significantly improve the performance of parsing large C files. The key point to understand here is that **pycparser** doesn't really care about the semantics of types. It only needs to know whether some token encountered in the source is a previously defined type. This is essential in order to be able to parse C correctly. See `this blog post `_ for more details. Note that the fake headers are not included in the ``pip`` package nor installed via the package build (`#224 `_). Basic usage ----------- Take a look at the |examples|_ directory of the distribution for a few examples of using **pycparser**. These should be enough to get you started. Please note that most realistic C code samples would require running the C preprocessor before passing the code to **pycparser**; see the previous sections for more details. .. |examples| replace:: ``examples`` .. _examples: examples Advanced usage -------------- The public interface of **pycparser** is well documented with comments in ``pycparser/c_parser.py``. For a detailed overview of the various AST nodes created by the parser, see ``pycparser/_c_ast.cfg``. There's also a `FAQ available here `_. In any case, you can always drop me an `email `_ for help. Modifying ========= There are a few points to keep in mind when modifying **pycparser**: * The code for **pycparser**'s AST nodes is automatically generated from a configuration file - ``_c_ast.cfg``, by ``_ast_gen.py``. If you modify the AST configuration, make sure to re-generate the code. This can be done by running the ``_ast_gen.py`` script (from the repository root or the ``pycparser`` directory). * Read the docstring in the constructor of the ``CParser`` class for details on configuration and compatibility arguments. Package contents ================ Once you unzip the ``pycparser`` package, you'll see the following files and directories: README.rst: This README file. LICENSE: The pycparser license setup.py: Legacy installation script (build metadata lives in ``pyproject.toml``). pyproject.toml: Package metadata and build configuration. examples/: A directory with some examples of using **pycparser** pycparser/: The **pycparser** module source code. tests/: Unit tests. utils/fake_libc_include: Minimal standard C library include files that should allow to parse any C code. Note that these headers now include C11 code, so they may not work when the preprocessor is configured to an earlier C standard (like ``-std=c99``). utils/internal/: Internal utilities for my own use. You probably don't need them. Contributors ============ Some people have contributed to **pycparser** by opening issues on bugs they've found and/or submitting patches. The list of contributors is in the CONTRIBUTORS file in the source distribution. After **pycparser** moved to Github I stopped updating this list because Github does a much better job at tracking contributions. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769005549.0 pycparser-3.0/pycparser.egg-info/SOURCES.txt0000664000175000017500000001316215134160755020304 0ustar00elibenelibenLICENSE MANIFEST.in README.rst pyproject.toml setup.cfg setup.py examples/c-to-c.py examples/c_json.py examples/cdecl.py examples/construct_ast_from_scratch.py examples/dump_ast.py examples/explore_ast.py examples/func_calls.py examples/func_defs.py examples/func_defs_add_param.py examples/rewrite_ast.py examples/serialize_ast.py examples/using_cpp_libc.py examples/using_gcc_E_libc.py examples/c_files/basic.c examples/c_files/funky.c examples/c_files/hash.c examples/c_files/memmgr.c examples/c_files/memmgr.h examples/c_files/pragmas.c examples/c_files/year.c pycparser/__init__.py pycparser/_ast_gen.py pycparser/_c_ast.cfg pycparser/ast_transforms.py pycparser/c_ast.py pycparser/c_generator.py pycparser/c_lexer.py pycparser/c_parser.py pycparser.egg-info/PKG-INFO pycparser.egg-info/SOURCES.txt pycparser.egg-info/dependency_links.txt pycparser.egg-info/top_level.txt tests/__init__.py tests/test_c_ast.py tests/test_c_generator.py tests/test_c_lexer.py tests/test_c_parser.py tests/test_examples.py tests/test_general.py tests/test_util.py tests/c_files/c11.c tests/c_files/cppd_with_stdio_h.c tests/c_files/empty.h tests/c_files/example_c_file.c tests/c_files/memmgr.c tests/c_files/memmgr.h tests/c_files/memmgr_with_h.c tests/c_files/simplemain.c tests/c_files/year.c tests/c_files/hdir/9/inc.h utils/fake_libc_include/_ansi.h utils/fake_libc_include/_fake_defines.h utils/fake_libc_include/_fake_typedefs.h utils/fake_libc_include/_syslist.h utils/fake_libc_include/aio.h utils/fake_libc_include/alloca.h utils/fake_libc_include/ar.h utils/fake_libc_include/argz.h utils/fake_libc_include/assert.h utils/fake_libc_include/complex.h utils/fake_libc_include/cpio.h utils/fake_libc_include/ctype.h utils/fake_libc_include/dirent.h utils/fake_libc_include/dlfcn.h utils/fake_libc_include/emmintrin.h utils/fake_libc_include/endian.h utils/fake_libc_include/envz.h utils/fake_libc_include/errno.h utils/fake_libc_include/fastmath.h utils/fake_libc_include/fcntl.h utils/fake_libc_include/features.h utils/fake_libc_include/fenv.h utils/fake_libc_include/float.h utils/fake_libc_include/fmtmsg.h utils/fake_libc_include/fnmatch.h utils/fake_libc_include/ftw.h utils/fake_libc_include/getopt.h utils/fake_libc_include/glob.h utils/fake_libc_include/grp.h utils/fake_libc_include/iconv.h utils/fake_libc_include/ieeefp.h utils/fake_libc_include/immintrin.h utils/fake_libc_include/inttypes.h utils/fake_libc_include/iso646.h utils/fake_libc_include/langinfo.h utils/fake_libc_include/libgen.h utils/fake_libc_include/libintl.h utils/fake_libc_include/limits.h utils/fake_libc_include/locale.h utils/fake_libc_include/malloc.h utils/fake_libc_include/math.h utils/fake_libc_include/monetary.h utils/fake_libc_include/mqueue.h utils/fake_libc_include/ndbm.h utils/fake_libc_include/netdb.h utils/fake_libc_include/newlib.h utils/fake_libc_include/nl_types.h utils/fake_libc_include/paths.h utils/fake_libc_include/poll.h utils/fake_libc_include/process.h utils/fake_libc_include/pthread.h utils/fake_libc_include/pwd.h utils/fake_libc_include/reent.h utils/fake_libc_include/regdef.h utils/fake_libc_include/regex.h utils/fake_libc_include/sched.h utils/fake_libc_include/search.h utils/fake_libc_include/semaphore.h utils/fake_libc_include/setjmp.h utils/fake_libc_include/signal.h utils/fake_libc_include/smmintrin.h utils/fake_libc_include/spawn.h utils/fake_libc_include/stdalign.h utils/fake_libc_include/stdarg.h utils/fake_libc_include/stdatomic.h utils/fake_libc_include/stdbool.h utils/fake_libc_include/stddef.h utils/fake_libc_include/stdint.h utils/fake_libc_include/stdio.h utils/fake_libc_include/stdlib.h utils/fake_libc_include/stdnoreturn.h utils/fake_libc_include/string.h utils/fake_libc_include/strings.h utils/fake_libc_include/stropts.h utils/fake_libc_include/syslog.h utils/fake_libc_include/tar.h utils/fake_libc_include/termios.h utils/fake_libc_include/tgmath.h utils/fake_libc_include/threads.h utils/fake_libc_include/time.h utils/fake_libc_include/trace.h utils/fake_libc_include/ulimit.h utils/fake_libc_include/unctrl.h utils/fake_libc_include/unistd.h utils/fake_libc_include/utime.h utils/fake_libc_include/utmp.h utils/fake_libc_include/utmpx.h utils/fake_libc_include/wchar.h utils/fake_libc_include/wctype.h utils/fake_libc_include/wordexp.h utils/fake_libc_include/zlib.h utils/fake_libc_include/X11/Intrinsic.h utils/fake_libc_include/X11/Xlib.h utils/fake_libc_include/X11/_X11_fake_defines.h utils/fake_libc_include/X11/_X11_fake_typedefs.h utils/fake_libc_include/arpa/inet.h utils/fake_libc_include/asm-generic/int-ll64.h utils/fake_libc_include/linux/socket.h utils/fake_libc_include/linux/version.h utils/fake_libc_include/mir_toolkit/client_types.h utils/fake_libc_include/net/if.h utils/fake_libc_include/netinet/in.h utils/fake_libc_include/netinet/tcp.h utils/fake_libc_include/openssl/err.h utils/fake_libc_include/openssl/evp.h utils/fake_libc_include/openssl/hmac.h utils/fake_libc_include/openssl/ssl.h utils/fake_libc_include/openssl/x509v3.h utils/fake_libc_include/sys/ioctl.h utils/fake_libc_include/sys/ipc.h utils/fake_libc_include/sys/mman.h utils/fake_libc_include/sys/msg.h utils/fake_libc_include/sys/poll.h utils/fake_libc_include/sys/resource.h utils/fake_libc_include/sys/select.h utils/fake_libc_include/sys/sem.h utils/fake_libc_include/sys/shm.h utils/fake_libc_include/sys/socket.h utils/fake_libc_include/sys/stat.h utils/fake_libc_include/sys/statvfs.h utils/fake_libc_include/sys/sysctl.h utils/fake_libc_include/sys/time.h utils/fake_libc_include/sys/times.h utils/fake_libc_include/sys/types.h utils/fake_libc_include/sys/uio.h utils/fake_libc_include/sys/un.h utils/fake_libc_include/sys/utsname.h utils/fake_libc_include/sys/wait.h utils/fake_libc_include/xcb/xcb.h././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769005549.0 pycparser-3.0/pycparser.egg-info/dependency_links.txt0000664000175000017500000000000115134160755022463 0ustar00elibeneliben ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769005549.0 pycparser-3.0/pycparser.egg-info/top_level.txt0000664000175000017500000000001215134160755021140 0ustar00elibenelibenpycparser ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769005240.0 pycparser-3.0/pyproject.toml0000664000175000017500000000177315134160270015627 0ustar00elibeneliben[build-system] requires = ["setuptools>=69", "wheel"] build-backend = "setuptools.build_meta" [project] name = "pycparser" version = "3.00" description = "C parser in Python" readme = "README.rst" license = "BSD-3-Clause" license-files = ["LICENSE"] requires-python = ">=3.10" authors = [{name = "Eli Bendersky", email = "eliben@gmail.com"}] maintainers = [{name = "Eli Bendersky", email = "eliben@gmail.com"}] classifiers = [ "Development Status :: 5 - Production/Stable", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", ] [project.urls] Homepage = "https://github.com/eliben/pycparser" [tool.setuptools] packages = ["pycparser"] [tool.setuptools.package-data] pycparser = ["*.cfg"] [tool.ruff.lint] ignore = ["F403", "F405"] [tool.ty.src] exclude = ["setup.py", "utils/internal/memprofiling.py"] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4694781 pycparser-3.0/setup.cfg0000664000175000017500000000011115134160755014525 0ustar00elibeneliben[metadata] license_file = LICENSE [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/setup.py0000664000175000017500000000004615134157072014423 0ustar00elibenelibenfrom setuptools import setup setup() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4646964 pycparser-3.0/tests/0000775000175000017500000000000015134160755014055 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/tests/__init__.py0000664000175000017500000000000014716121044016145 0ustar00elibeneliben././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1769005549.464993 pycparser-3.0/tests/c_files/0000775000175000017500000000000015134160755015461 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1757423768.0 pycparser-3.0/tests/c_files/c11.c0000664000175000017500000000252715060024230016200 0ustar00elibeneliben#include #include #include #include #include #include #include #include /* C11 thread locals */ _Thread_local int flag; thread_local int flag2; _Atomic int flag3; _Atomic(int) flag4; _Atomic(_Atomic(int) *) flag5; atomic_bool flag6; _Alignas(32) int q32; _Alignas(long long) int qll; alignas(64) int qqq; static_assert(sizeof(flag) == sizeof(flag2), "Really unexpected size difference"); noreturn void func2(void) { abort(); } _Noreturn void func(void) { func2(); } int main() { _Static_assert(sizeof(flag) == sizeof(flag2), "Unexpected size difference"); _Static_assert(sizeof(flag) == sizeof(flag2)); static_assert(sizeof(flag) == sizeof(flag2), "Unexpected size difference"); static_assert(sizeof(flag) == sizeof(flag3), "Unexpected size difference"); static_assert(sizeof(flag) == sizeof(flag4), "Unexpected size difference"); static_assert(_Alignof(int) == sizeof(int), "Unexpected int alignment"); static_assert(alignof(int) == sizeof(int), "Unexpected int alignment"); wchar_t *w = L"12345"; char16_t *c16 = u"12345"; char32_t *c32 = U"12345"; char *u8 = u8"12345"; wchar_t wc = L'1'; char16_t c16c = u'1'; char32_t c32c = U'1'; char u8c = u8'1'; printf("Flag: %d\n", flag); printf("Flag2: %d\n", flag2); func(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/tests/c_files/cppd_with_stdio_h.c0000664000175000017500000010602314716121044021312 0ustar00elibeneliben#line 1 "example_c_file.c" #line 1 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 19 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 25 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 1 "D:\eli\cpp_stuff\libc_include/_ansi.h" #line 11 "D:\eli\cpp_stuff\libc_include/_ansi.h" #line 1 "D:\eli\cpp_stuff\libc_include/newlib.h" #line 3 "D:\eli\cpp_stuff\libc_include/newlib.h" #line 16 "D:\eli\cpp_stuff\libc_include/_ansi.h" #line 1 "D:\eli\cpp_stuff\libc_include/sys/config.h" #line 1 "D:\eli\cpp_stuff\libc_include/machine/ieeefp.h" #line 52 "D:\eli\cpp_stuff\libc_include/machine/ieeefp.h" #line 58 "D:\eli\cpp_stuff\libc_include/machine/ieeefp.h" #line 83 "D:\eli\cpp_stuff\libc_include/machine/ieeefp.h" #line 86 "D:\eli\cpp_stuff\libc_include/machine/ieeefp.h" #line 89 "D:\eli\cpp_stuff\libc_include/machine/ieeefp.h" #line 95 "D:\eli\cpp_stuff\libc_include/machine/ieeefp.h" #line 5 "D:\eli\cpp_stuff\libc_include/sys/config.h" #line 11 "D:\eli\cpp_stuff\libc_include/sys/config.h" #line 143 "D:\eli\cpp_stuff\libc_include/sys/config.h" #line 157 "D:\eli\cpp_stuff\libc_include/sys/config.h" #line 195 "D:\eli\cpp_stuff\libc_include/sys/config.h" #line 207 "D:\eli\cpp_stuff\libc_include/sys/config.h" #line 17 "D:\eli\cpp_stuff\libc_include/_ansi.h" #line 21 "D:\eli\cpp_stuff\libc_include/_ansi.h" #line 30 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 1 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 19 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 26 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 30 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 35 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 39 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 42 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 53 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 56 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 67 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 76 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 98 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 108 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 126 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 131 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 170 "D:\eli\cpp_stuff\libc_include/stddef.h" typedef long unsigned int size_t; #line 243 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 246 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 290 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 302 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 310 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 361 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 365 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 418 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 422 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 427 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 35 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 1 "D:\eli\cpp_stuff\libc_include/stdarg.h" #line 19 "D:\eli\cpp_stuff\libc_include/stdarg.h" #line 26 "D:\eli\cpp_stuff\libc_include/stdarg.h" #line 30 "D:\eli\cpp_stuff\libc_include/stdarg.h" typedef char* __builtin_va_list; typedef __builtin_va_list __gnuc_va_list; #line 50 "D:\eli\cpp_stuff\libc_include/stdarg.h" #line 66 "D:\eli\cpp_stuff\libc_include/stdarg.h" #line 80 "D:\eli\cpp_stuff\libc_include/stdarg.h" #line 98 "D:\eli\cpp_stuff\libc_include/stdarg.h" #line 38 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 44 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 1 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 6 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 1 "D:\eli\cpp_stuff\libc_include/_ansi.h" #line 11 "D:\eli\cpp_stuff\libc_include/_ansi.h" #line 21 "D:\eli\cpp_stuff\libc_include/_ansi.h" #line 14 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 1 "D:\eli\cpp_stuff\libc_include/sys/_types.h" #line 8 "D:\eli\cpp_stuff\libc_include/sys/_types.h" #line 1 "D:\eli\cpp_stuff\libc_include/machine/_types.h" #line 4 "D:\eli\cpp_stuff\libc_include/machine/_types.h" #line 1 "D:\eli\cpp_stuff\libc_include/machine/_default_types.h" #line 4 "D:\eli\cpp_stuff\libc_include/machine/_default_types.h" #line 15 "D:\eli\cpp_stuff\libc_include/machine/_default_types.h" #line 17 "D:\eli\cpp_stuff\libc_include/machine/_default_types.h" #line 1 "D:\eli\cpp_stuff\libc_include/limits.h" #line 1 "D:\eli\cpp_stuff\libc_include/newlib.h" #line 3 "D:\eli\cpp_stuff\libc_include/newlib.h" #line 5 "D:\eli\cpp_stuff\libc_include/limits.h" #line 19 "D:\eli\cpp_stuff\libc_include/limits.h" #line 1 "D:\eli\cpp_stuff\libc_include/sys/config.h" #line 11 "D:\eli\cpp_stuff\libc_include/sys/config.h" #line 143 "D:\eli\cpp_stuff\libc_include/sys/config.h" #line 157 "D:\eli\cpp_stuff\libc_include/sys/config.h" #line 195 "D:\eli\cpp_stuff\libc_include/sys/config.h" #line 207 "D:\eli\cpp_stuff\libc_include/sys/config.h" #line 25 "D:\eli\cpp_stuff\libc_include/limits.h" #line 79 "D:\eli\cpp_stuff\libc_include/limits.h" #line 23 "D:\eli\cpp_stuff\libc_include/machine/_default_types.h" typedef signed char __int8_t ; typedef unsigned char __uint8_t ; typedef signed short __int16_t; typedef unsigned short __uint16_t; typedef __int16_t __int_least16_t; typedef __uint16_t __uint_least16_t; typedef signed int __int32_t; typedef unsigned int __uint32_t; typedef __int32_t __int_least32_t; typedef __uint32_t __uint_least32_t; #line 8 "D:\eli\cpp_stuff\libc_include/machine/_types.h" #line 13 "D:\eli\cpp_stuff\libc_include/sys/_types.h" #line 1 "D:\eli\cpp_stuff\libc_include/sys/lock.h" typedef int _LOCK_T; typedef int _LOCK_RECURSIVE_T; #line 14 "D:\eli\cpp_stuff\libc_include/sys/_types.h" typedef long _off_t; typedef short __dev_t; typedef unsigned short __uid_t; typedef unsigned short __gid_t; typedef long long _off64_t; #line 43 "D:\eli\cpp_stuff\libc_include/sys/_types.h" typedef long _fpos_t; typedef int _ssize_t; #line 1 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 19 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 26 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 30 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 35 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 39 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 42 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 53 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 56 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 67 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 76 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 98 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 108 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 126 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 131 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 170 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 243 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 246 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 290 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 302 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 310 "D:\eli\cpp_stuff\libc_include/stddef.h" typedef unsigned int wint_t; #line 361 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 365 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 418 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 422 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 427 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 64 "D:\eli\cpp_stuff\libc_include/sys/_types.h" typedef struct { int __count; union { wint_t __wch; unsigned char __wchb[4]; } __value; } _mbstate_t; typedef _LOCK_RECURSIVE_T _flock_t; typedef void *_iconv_t; #line 15 "D:\eli\cpp_stuff\libc_include/sys/reent.h" typedef unsigned long __ULong; struct _reent; #line 43 "D:\eli\cpp_stuff\libc_include/sys/reent.h" struct _Bigint { struct _Bigint *_next; int _k, _maxwds, _sign, _wds; __ULong _x[1]; }; struct __tm { int __tm_sec; int __tm_min; int __tm_hour; int __tm_mday; int __tm_mon; int __tm_year; int __tm_wday; int __tm_yday; int __tm_isdst; }; #line 68 "D:\eli\cpp_stuff\libc_include/sys/reent.h" struct _on_exit_args { void * _fnargs[32]; void * _dso_handle[32]; __ULong _fntypes; #line 77 "D:\eli\cpp_stuff\libc_include/sys/reent.h" __ULong _is_cxa; }; struct _atexit { struct _atexit *_next; int _ind; void (*_fns[32])(void); struct _on_exit_args _on_exit_args; }; #line 104 "D:\eli\cpp_stuff\libc_include/sys/reent.h" struct __sbuf { unsigned char *_base; int _size; }; #line 134 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 141 "D:\eli\cpp_stuff\libc_include/sys/reent.h" struct __sFILE { unsigned char *_p; int _r; int _w; short _flags; short _file; struct __sbuf _bf; int _lbfsize; char * _cookie; int(*_read)(); #line 176 "D:\eli\cpp_stuff\libc_include/sys/reent.h" int(*_write)(); #line 178 "D:\eli\cpp_stuff\libc_include/sys/reent.h" _fpos_t(*_seek)(); int(*_close)(); struct __sbuf _ub; unsigned char *_up; int _ur; unsigned char _ubuf[3]; unsigned char _nbuf[1]; struct __sbuf _lb; int _blksize; int _offset; struct _reent *_data; _flock_t _lock; }; typedef struct __sFILE __FILE; struct _glue { struct _glue *_next; int _niobs; __FILE *_iobs; }; #line 284 "D:\eli\cpp_stuff\libc_include/sys/reent.h" struct _rand48 { unsigned short _seed[3]; unsigned short _mult[3]; unsigned short _add; }; #line 313 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 344 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 350 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 420 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 452 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 474 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 478 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 482 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 494 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 496 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 503 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 505 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 508 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 531 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 533 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 536 "D:\eli\cpp_stuff\libc_include/sys/reent.h" struct _reent { int _errno; #line 571 "D:\eli\cpp_stuff\libc_include/sys/reent.h" __FILE *_stdin, *_stdout, *_stderr; int _inc; char _emergency[25]; int _current_category; char *_current_locale; int __sdidinit; void(*__cleanup)(); struct _Bigint *_result; int _result_k; struct _Bigint *_p5s; struct _Bigint **_freelist; int _cvtlen; char *_cvtbuf; union { struct { unsigned int _unused_rand; char * _strtok_last; char _asctime_buf[26]; struct __tm _localtime_buf; int _gamma_signgam; unsigned long long _rand_next; struct _rand48 _r48; _mbstate_t _mblen_state; _mbstate_t _mbtowc_state; _mbstate_t _wctomb_state; char _l64a_buf[8]; char _signal_buf[24]; int _getdate_err; _mbstate_t _mbrlen_state; _mbstate_t _mbrtowc_state; _mbstate_t _mbsrtowcs_state; _mbstate_t _wcrtomb_state; _mbstate_t _wcsrtombs_state; } _reent; #line 619 "D:\eli\cpp_stuff\libc_include/sys/reent.h" struct { unsigned char * _nextf[30]; unsigned int _nmalloc[30]; } _unused; } _new; struct _atexit *_atexit; struct _atexit _atexit0; void (**(_sig_func))(int); #line 637 "D:\eli\cpp_stuff\libc_include/sys/reent.h" struct _glue __sglue; __FILE __sf[3]; }; #line 689 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 751 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 791 "D:\eli\cpp_stuff\libc_include/sys/reent.h" extern struct _reent *_impure_ptr; extern struct _reent * _global_impure_ptr; void _reclaim_reent(); #line 46 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 1 "D:\eli\cpp_stuff\libc_include/sys/types.h" #line 17 "D:\eli\cpp_stuff\libc_include/sys/types.h" #line 1 "D:\eli\cpp_stuff\libc_include/_ansi.h" #line 11 "D:\eli\cpp_stuff\libc_include/_ansi.h" #line 21 "D:\eli\cpp_stuff\libc_include/_ansi.h" #line 21 "D:\eli\cpp_stuff\libc_include/sys/types.h" #line 1 "D:\eli\cpp_stuff\libc_include/machine/_types.h" #line 4 "D:\eli\cpp_stuff\libc_include/machine/_types.h" #line 26 "D:\eli\cpp_stuff\libc_include/sys/types.h" #line 33 "D:\eli\cpp_stuff\libc_include/sys/types.h" #line 1 "D:\eli\cpp_stuff\libc_include/sys/_types.h" #line 8 "D:\eli\cpp_stuff\libc_include/sys/_types.h" #line 43 "D:\eli\cpp_stuff\libc_include/sys/_types.h" #line 62 "D:\eli\cpp_stuff\libc_include/sys/types.h" #line 1 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 19 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 26 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 30 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 35 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 39 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 42 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 53 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 56 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 67 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 76 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 98 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 108 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 126 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 131 "D:\eli\cpp_stuff\libc_include/stddef.h" typedef long int ptrdiff_t; #line 170 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 243 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 246 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 290 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 302 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 310 "D:\eli\cpp_stuff\libc_include/stddef.h" typedef int wchar_t; #line 361 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 365 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 418 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 422 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 427 "D:\eli\cpp_stuff\libc_include/stddef.h" #line 70 "D:\eli\cpp_stuff\libc_include/sys/types.h" #line 1 "D:\eli\cpp_stuff\libc_include/machine/types.h" #line 9 "D:\eli\cpp_stuff\libc_include/machine/types.h" typedef long int __off_t; typedef int __pid_t; typedef long int __loff_t; #line 71 "D:\eli\cpp_stuff\libc_include/sys/types.h" #line 79 "D:\eli\cpp_stuff\libc_include/sys/types.h" typedef unsigned char u_char; typedef unsigned short u_short; typedef unsigned int u_int; typedef unsigned long u_long; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long clock_t; typedef long time_t; struct timespec { time_t tv_sec; long tv_nsec; }; struct itimerspec { struct timespec it_interval; struct timespec it_value; }; typedef long daddr_t; typedef char * caddr_t; #line 131 "D:\eli\cpp_stuff\libc_include/sys/types.h" typedef unsigned short ino_t; #line 160 "D:\eli\cpp_stuff\libc_include/sys/types.h" typedef _off_t off_t; typedef __dev_t dev_t; typedef __uid_t uid_t; typedef __gid_t gid_t; typedef int pid_t; typedef long key_t; typedef _ssize_t ssize_t; typedef unsigned int mode_t; typedef unsigned short nlink_t; #line 200 "D:\eli\cpp_stuff\libc_include/sys/types.h" #line 209 "D:\eli\cpp_stuff\libc_include/sys/types.h" typedef long fd_mask; #line 221 "D:\eli\cpp_stuff\libc_include/sys/types.h" typedef struct _types_fd_set { fd_mask fds_bits[(((64)+(((sizeof (fd_mask) * 8))-1))/((sizeof (fd_mask) * 8)))]; } _types_fd_set; #line 236 "D:\eli\cpp_stuff\libc_include/sys/types.h" typedef unsigned long clockid_t; typedef unsigned long timer_t; typedef unsigned long useconds_t; typedef long suseconds_t; #line 1 "D:\eli\cpp_stuff\libc_include/sys/features.h" #line 20 "D:\eli\cpp_stuff\libc_include/sys/features.h" #line 257 "D:\eli\cpp_stuff\libc_include/sys/types.h" #line 266 "D:\eli\cpp_stuff\libc_include/sys/types.h" #line 273 "D:\eli\cpp_stuff\libc_include/sys/types.h" #line 47 "D:\eli\cpp_stuff\libc_include/stdio.h" typedef __FILE FILE; typedef _fpos_t fpos_t; #line 1 "D:\eli\cpp_stuff\libc_include/sys/stdio.h" #line 1 "D:\eli\cpp_stuff\libc_include/sys/lock.h" #line 5 "D:\eli\cpp_stuff\libc_include/sys/stdio.h" #line 1 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 6 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 43 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 68 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 77 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 104 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 134 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 141 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 284 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 313 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 344 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 350 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 420 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 452 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 474 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 478 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 482 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 494 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 496 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 503 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 505 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 508 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 531 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 533 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 536 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 571 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 619 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 637 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 689 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 751 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 791 "D:\eli\cpp_stuff\libc_include/sys/reent.h" #line 6 "D:\eli\cpp_stuff\libc_include/sys/stdio.h" #line 11 "D:\eli\cpp_stuff\libc_include/sys/stdio.h" #line 66 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 96 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 163 "D:\eli\cpp_stuff\libc_include/stdio.h" FILE * tmpfile(); char * tmpnam(); int fclose(); int fflush(); FILE * freopen(); void setbuf(); int setvbuf(); int fprintf(); #line 179 "D:\eli\cpp_stuff\libc_include/stdio.h" int fscanf(); #line 181 "D:\eli\cpp_stuff\libc_include/stdio.h" int printf(); #line 183 "D:\eli\cpp_stuff\libc_include/stdio.h" int scanf(); #line 185 "D:\eli\cpp_stuff\libc_include/stdio.h" int sscanf(); #line 187 "D:\eli\cpp_stuff\libc_include/stdio.h" int vfprintf(); #line 189 "D:\eli\cpp_stuff\libc_include/stdio.h" int vprintf(); #line 191 "D:\eli\cpp_stuff\libc_include/stdio.h" int vsprintf(); #line 193 "D:\eli\cpp_stuff\libc_include/stdio.h" int fgetc(); char * fgets(); int fputc(); int fputs(); int getc(); int getchar(); char * gets(); int putc(); int putchar(); int puts(); int ungetc(); size_t fread(); size_t fwrite(); int fgetpos(); int fseek(); int fsetpos(); long ftell(); void rewind(); void clearerr(); int feof(); int ferror(); void perror(); FILE * fopen(); int sprintf(); #line 227 "D:\eli\cpp_stuff\libc_include/stdio.h" int remove(); int rename(); int fseeko(); off_t ftello(); int asiprintf(); #line 241 "D:\eli\cpp_stuff\libc_include/stdio.h" char * asniprintf(); #line 243 "D:\eli\cpp_stuff\libc_include/stdio.h" char * asnprintf(); #line 245 "D:\eli\cpp_stuff\libc_include/stdio.h" int asprintf(); #line 247 "D:\eli\cpp_stuff\libc_include/stdio.h" int diprintf(); #line 250 "D:\eli\cpp_stuff\libc_include/stdio.h" int fcloseall(); int fiprintf(); #line 254 "D:\eli\cpp_stuff\libc_include/stdio.h" int fiscanf(); #line 256 "D:\eli\cpp_stuff\libc_include/stdio.h" int iprintf(); #line 258 "D:\eli\cpp_stuff\libc_include/stdio.h" int iscanf(); #line 260 "D:\eli\cpp_stuff\libc_include/stdio.h" int siprintf(); #line 262 "D:\eli\cpp_stuff\libc_include/stdio.h" int siscanf(); #line 264 "D:\eli\cpp_stuff\libc_include/stdio.h" int snprintf(); #line 266 "D:\eli\cpp_stuff\libc_include/stdio.h" int sniprintf(); #line 268 "D:\eli\cpp_stuff\libc_include/stdio.h" char * tempnam(); int vasiprintf(); #line 271 "D:\eli\cpp_stuff\libc_include/stdio.h" char * vasniprintf(); #line 273 "D:\eli\cpp_stuff\libc_include/stdio.h" char * vasnprintf(); #line 275 "D:\eli\cpp_stuff\libc_include/stdio.h" int vasprintf(); #line 277 "D:\eli\cpp_stuff\libc_include/stdio.h" int vdiprintf(); #line 279 "D:\eli\cpp_stuff\libc_include/stdio.h" int vfiprintf(); #line 281 "D:\eli\cpp_stuff\libc_include/stdio.h" int vfiscanf(); #line 283 "D:\eli\cpp_stuff\libc_include/stdio.h" int vfscanf(); #line 285 "D:\eli\cpp_stuff\libc_include/stdio.h" int viprintf(); #line 287 "D:\eli\cpp_stuff\libc_include/stdio.h" int viscanf(); #line 289 "D:\eli\cpp_stuff\libc_include/stdio.h" int vscanf(); #line 291 "D:\eli\cpp_stuff\libc_include/stdio.h" int vsiprintf(); #line 293 "D:\eli\cpp_stuff\libc_include/stdio.h" int vsiscanf(); #line 295 "D:\eli\cpp_stuff\libc_include/stdio.h" int vsniprintf(); #line 297 "D:\eli\cpp_stuff\libc_include/stdio.h" int vsnprintf(); #line 299 "D:\eli\cpp_stuff\libc_include/stdio.h" int vsscanf(); #line 301 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 307 "D:\eli\cpp_stuff\libc_include/stdio.h" FILE * fdopen(); int fileno(); int getw(); int pclose(); FILE * popen(); int putw(); void setbuffer(); int setlinebuf(); int getc_unlocked(); int getchar_unlocked(); void flockfile(); int ftrylockfile(); void funlockfile(); int putc_unlocked(); int putchar_unlocked(); #line 331 "D:\eli\cpp_stuff\libc_include/stdio.h" int dprintf(); #line 337 "D:\eli\cpp_stuff\libc_include/stdio.h" FILE * fmemopen(); FILE * open_memstream(); int vdprintf(); #line 345 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 351 "D:\eli\cpp_stuff\libc_include/stdio.h" int _asiprintf_r(); #line 354 "D:\eli\cpp_stuff\libc_include/stdio.h" char * _asniprintf_r(); #line 356 "D:\eli\cpp_stuff\libc_include/stdio.h" char * _asnprintf_r(); #line 358 "D:\eli\cpp_stuff\libc_include/stdio.h" int _asprintf_r(); #line 360 "D:\eli\cpp_stuff\libc_include/stdio.h" int _diprintf_r(); #line 362 "D:\eli\cpp_stuff\libc_include/stdio.h" int _dprintf_r(); #line 364 "D:\eli\cpp_stuff\libc_include/stdio.h" int _fclose_r(); int _fcloseall_r(); FILE * _fdopen_r(); int _fflush_r(); char * _fgets_r(); int _fiprintf_r(); #line 371 "D:\eli\cpp_stuff\libc_include/stdio.h" int _fiscanf_r(); #line 373 "D:\eli\cpp_stuff\libc_include/stdio.h" FILE * _fmemopen_r(); FILE * _fopen_r(); int _fprintf_r(); #line 377 "D:\eli\cpp_stuff\libc_include/stdio.h" int _fputc_r(); int _fputs_r(); size_t _fread_r(); int _fscanf_r(); #line 382 "D:\eli\cpp_stuff\libc_include/stdio.h" int _fseek_r(); long _ftell_r(); size_t _fwrite_r(); int _getc_r(); int _getc_unlocked_r(); int _getchar_r(); int _getchar_unlocked_r(); char * _gets_r(); int _iprintf_r(); #line 392 "D:\eli\cpp_stuff\libc_include/stdio.h" int _iscanf_r(); #line 394 "D:\eli\cpp_stuff\libc_include/stdio.h" int _mkstemp_r(); char * _mktemp_r(); FILE * _open_memstream_r(); void _perror_r(); int _printf_r(); #line 400 "D:\eli\cpp_stuff\libc_include/stdio.h" int _putc_r(); int _putc_unlocked_r(); int _putchar_unlocked_r(); int _putchar_r(); int _puts_r(); int _remove_r(); int _rename_r(); #line 408 "D:\eli\cpp_stuff\libc_include/stdio.h" int _scanf_r(); #line 410 "D:\eli\cpp_stuff\libc_include/stdio.h" int _siprintf_r(); #line 412 "D:\eli\cpp_stuff\libc_include/stdio.h" int _siscanf_r(); #line 414 "D:\eli\cpp_stuff\libc_include/stdio.h" int _sniprintf_r(); #line 416 "D:\eli\cpp_stuff\libc_include/stdio.h" int _snprintf_r(); #line 418 "D:\eli\cpp_stuff\libc_include/stdio.h" int _sprintf_r(); #line 420 "D:\eli\cpp_stuff\libc_include/stdio.h" int _sscanf_r(); #line 422 "D:\eli\cpp_stuff\libc_include/stdio.h" char * _tempnam_r(); FILE * _tmpfile_r(); char * _tmpnam_r(); int _ungetc_r(); int _vasiprintf_r(); #line 428 "D:\eli\cpp_stuff\libc_include/stdio.h" char * _vasniprintf_r(); #line 430 "D:\eli\cpp_stuff\libc_include/stdio.h" char * _vasnprintf_r(); #line 432 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vasprintf_r(); #line 434 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vdiprintf_r(); #line 436 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vdprintf_r(); #line 438 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vfiprintf_r(); #line 440 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vfiscanf_r(); #line 442 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vfprintf_r(); #line 444 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vfscanf_r(); #line 446 "D:\eli\cpp_stuff\libc_include/stdio.h" int _viprintf_r(); #line 448 "D:\eli\cpp_stuff\libc_include/stdio.h" int _viscanf_r(); #line 450 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vprintf_r(); #line 452 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vscanf_r(); #line 454 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vsiprintf_r(); #line 456 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vsiscanf_r(); #line 458 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vsniprintf_r(); #line 460 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vsnprintf_r(); #line 462 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vsprintf_r(); #line 464 "D:\eli\cpp_stuff\libc_include/stdio.h" int _vsscanf_r(); #line 466 "D:\eli\cpp_stuff\libc_include/stdio.h" ssize_t __getdelim(); ssize_t __getline(); #line 493 "D:\eli\cpp_stuff\libc_include/stdio.h" int __srget_r(); int __swbuf_r(); #line 500 "D:\eli\cpp_stuff\libc_include/stdio.h" FILE * funopen(); #line 514 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 518 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 520 "D:\eli\cpp_stuff\libc_include/stdio.h" typedef ssize_t cookie_read_function_t(void *__cookie, char *__buf, size_t __n); typedef ssize_t cookie_write_function_t(void *__cookie, const char *__buf, size_t __n); typedef int cookie_seek_function_t(void *__cookie, off_t *__off, int __whence); typedef int cookie_close_function_t(void *__cookie); typedef struct { #line 535 "D:\eli\cpp_stuff\libc_include/stdio.h" cookie_read_function_t *read; cookie_write_function_t *write; cookie_seek_function_t *seek; cookie_close_function_t *close; } cookie_io_functions_t; FILE * fopencookie(); #line 542 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 549 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 574 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 580 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 603 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 613 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 621 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 626 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 657 "D:\eli\cpp_stuff\libc_include/stdio.h" #line 4 "example_c_file.c" #line 8 "example_c_file.c" char tav = 'b'; char maav = L"'guruguru\n"; char* moral = "ain't I \\\"\\\t\" a nice string?\"\""; char* comment_inside = "but you will /* see it */!!!!"; char* i_have_newlines = "line one\nline two\nline three"; int main() { auto char* multi = "a multi"; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/tests/c_files/empty.h0000664000175000017500000000016214716121044016760 0ustar00elibeneliben#define PERFECTLY #define NORMAL #define TO #define HAVE #define HEADER #define WITH #define ONLY #define DEFINES ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/tests/c_files/example_c_file.c0000664000175000017500000000037214716121044020554 0ustar00elibenelibenchar tav = 'b'; char* moral = "ain't I \\\"\\\t\" a nice string?\"\""; char* comment_inside = "but you will /* see it */!!!!"; char* i_have_newlines = "line one\nline two\nline three"; int main() { auto char* multi = "a multi"; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4618373 pycparser-3.0/tests/c_files/hdir/0000775000175000017500000000000015134160755016407 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4650245 pycparser-3.0/tests/c_files/hdir/9/0000775000175000017500000000000015134160755016557 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/tests/c_files/hdir/9/inc.h0000664000175000017500000000001714716121044017470 0ustar00elibenelibenextern int ie; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/tests/c_files/memmgr.c0000664000175000017500000001273514716121044017112 0ustar00elibeneliben//---------------------------------------------------------------- // Statically-allocated memory manager // // by Eli Bendersky (eliben@gmail.com) // // This code is in the public domain. //---------------------------------------------------------------- #include "memmgr.h" typedef ulong Align; union mem_header_union { struct { // Pointer to the next block in the free list // union mem_header_union* next; // Size of the block (in quantas of sizeof(mem_header_t)) // ulong size; } s; // Used to align headers in memory to a boundary // Align align_dummy; }; typedef union mem_header_union mem_header_t; // Initial empty list // static mem_header_t base; // Start of free list // static mem_header_t* freep = 0; // Static pool for new allocations // static byte pool[POOL_SIZE] = {0}; static ulong pool_free_pos = 0; void memmgr_init() { base.s.next = 0; base.s.size = 0; freep = 0; pool_free_pos = 0; } static mem_header_t* get_mem_from_pool(ulong nquantas) { ulong total_req_size; mem_header_t* h; if (nquantas < MIN_POOL_ALLOC_QUANTAS) nquantas = MIN_POOL_ALLOC_QUANTAS; total_req_size = nquantas * sizeof(mem_header_t); if (pool_free_pos + total_req_size <= POOL_SIZE) { h = (mem_header_t*) (pool + pool_free_pos); h->s.size = nquantas; memmgr_free((void*) (h + 1)); pool_free_pos += total_req_size; } else { return 0; } return freep; } // Allocations are done in 'quantas' of header size. // The search for a free block of adequate size begins at the point 'freep' // where the last block was found. // If a too-big block is found, it is split and the tail is returned (this // way the header of the original needs only to have its size adjusted). // The pointer returned to the user points to the free space within the block, // which begins one quanta after the header. // void* memmgr_alloc(ulong nbytes) { mem_header_t* p; mem_header_t* prevp; // Calculate how many quantas are required: we need enough to house all // the requested bytes, plus the header. The -1 and +1 are there to make sure // that if nbytes is a multiple of nquantas, we don't allocate too much // ulong nquantas = (nbytes + sizeof(mem_header_t) - 1) / sizeof(mem_header_t) + 1; // First alloc call, and no free list yet ? Use 'base' for an initial // denegerate block of size 0, which points to itself // if ((prevp = freep) == 0) { base.s.next = freep = prevp = &base; base.s.size = 0; } for (p = prevp->s.next; ; prevp = p, p = p->s.next) { // big enough ? if (p->s.size >= nquantas) { // exactly ? if (p->s.size == nquantas) { // just eliminate this block from the free list by pointing // its prev's next to its next // prevp->s.next = p->s.next; } else // too big { p->s.size -= nquantas; p += p->s.size; p->s.size = nquantas; } freep = prevp; return (void*) (p + 1); } // Reached end of free list ? // Try to allocate the block from the pool. If that succeeds, // get_mem_from_pool adds the new block to the free list and // it will be found in the following iterations. If the call // to get_mem_from_pool doesn't succeed, we've run out of // memory // else if (p == freep) { if ((p = get_mem_from_pool(nquantas)) == 0) { #ifdef DEBUG_MEMMGR_FATAL printf("!! Memory allocation failed !!\n"); #endif return 0; } } } } // Scans the free list, starting at freep, looking the the place to insert the // free block. This is either between two existing blocks or at the end of the // list. In any case, if the block being freed is adjacent to either neighbor, // the adjacent blocks are combined. // void memmgr_free(void* ap) { mem_header_t* block; mem_header_t* p; // acquire pointer to block header block = ((mem_header_t*) ap) - 1; // Find the correct place to place the block in (the free list is sorted by // address, increasing order) // for (p = freep; !(block > p && block < p->s.next); p = p->s.next) { // Since the free list is circular, there is one link where a // higher-addressed block points to a lower-addressed block. // This condition checks if the block should be actually // inserted between them // if (p >= p->s.next && (block > p || block < p->s.next)) break; } // Try to combine with the higher neighbor // if (block + block->s.size == p->s.next) { block->s.size += p->s.next->s.size; block->s.next = p->s.next->s.next; } else { block->s.next = p->s.next; } // Try to combine with the lower neighbor // if (p + p->s.size == block) { p->s.size += block->s.size; p->s.next = block->s.next; } else { p->s.next = block; } freep = p; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/tests/c_files/memmgr.h0000664000175000017500000000566614716121044017124 0ustar00elibeneliben//---------------------------------------------------------------- // Statically-allocated memory manager // // by Eli Bendersky (eliben@gmail.com) // // This code is in the public domain. //---------------------------------------------------------------- #ifndef MEMMGR_H #define MEMMGR_H // // Memory manager: dynamically allocates memory from // a fixed pool that is allocated statically at link-time. // // Usage: after calling memmgr_init() in your // initialization routine, just use memmgr_alloc() instead // of malloc() and memmgr_free() instead of free(). // Naturally, you can use the preprocessor to define // malloc() and free() as aliases to memmgr_alloc() and // memmgr_free(). This way the manager will be a drop-in // replacement for the standard C library allocators, and can // be useful for debugging memory allocation problems and // leaks. // // Preprocessor flags you can define to customize the // memory manager: // // DEBUG_MEMMGR_FATAL // Allow printing out a message when allocations fail // // DEBUG_MEMMGR_SUPPORT_STATS // Allow printing out of stats in function // memmgr_print_stats When this is disabled, // memmgr_print_stats does nothing. // // Note that in production code on an embedded system // you'll probably want to keep those undefined, because // they cause printf to be called. // // POOL_SIZE // Size of the pool for new allocations. This is // effectively the heap size of the application, and can // be changed in accordance with the available memory // resources. // // MIN_POOL_ALLOC_QUANTAS // Internally, the memory manager allocates memory in // quantas roughly the size of two ulong objects. To // minimize pool fragmentation in case of multiple allocations // and deallocations, it is advisable to not allocate // blocks that are too small. // This flag sets the minimal amount of quantas for // an allocation. If the size of a ulong is 4 and you // set this flag to 16, the minimal size of an allocation // will be 4 * 2 * 16 = 128 bytes // If you have a lot of small allocations, keep this value // low to conserve memory. If you have mostly large // allocations, it is best to make it higher, to avoid // fragmentation. // // Notes: // 1. This memory manager is *not thread safe*. Use it only // for single thread/task applications. // #define DEBUG_MEMMGR_SUPPORT_STATS 1 #define POOL_SIZE 8 * 1024 #define MIN_POOL_ALLOC_QUANTAS 16 typedef unsigned char byte; typedef unsigned long ulong; // Initialize the memory manager. This function should be called // only once in the beginning of the program. // void memmgr_init(); // 'malloc' clone // void* memmgr_alloc(ulong nbytes); // 'free' clone // void memmgr_free(void* ap); // Prints statistics about the current state of the memory // manager // void memmgr_print_stats(); #endif // MEMMGR_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/tests/c_files/memmgr_with_h.c0000664000175000017500000000770614716121044020456 0ustar00elibeneliben#line 1 "memmgr.c" #line 1 "./memmgr.h" typedef unsigned char byte; typedef unsigned long ulong; void memmgr_init(); void* memmgr_alloc(ulong nbytes); void memmgr_free(void* ap); void memmgr_print_stats(); #line 9 "memmgr.c" typedef ulong Align; union mem_header_union { struct { union mem_header_union* next; ulong size; } s; Align align_dummy; }; typedef union mem_header_union mem_header_t; static mem_header_t base; static mem_header_t* freep = 0; static byte pool[8 * 1024] = {0}; static ulong pool_free_pos = 0; void memmgr_init() { base.s.next = 0; base.s.size = 0; freep = 0; pool_free_pos = 0; } void memmgr_print_stats() { mem_header_t* p; printf("------ Memory manager stats ------\n\n"); printf( "Pool: free_pos = %lu (%lu bytes left)\n\n", pool_free_pos,8 * 1024 - pool_free_pos); p = (mem_header_t*) pool; while (p < (mem_header_t*) (pool + pool_free_pos)) { printf( " * Addr: 0x%8lu; Size: %8lu\n", p, p->s.size); p += p->s.size; } printf("\nFree list:\n\n"); if (freep) { p = freep; while (1) { printf( " * Addr: 0x%8lu; Size: %8lu; Next: 0x%8lu\n", p, p->s.size, p->s.next); p = p->s.next; if (p == freep) break; } } else { printf("Empty\n"); } printf("\n"); } static mem_header_t* get_mem_from_pool(ulong nquantas) { ulong total_req_size; mem_header_t* h; if (nquantas < 16) nquantas = 16; total_req_size = nquantas * sizeof(mem_header_t); if (pool_free_pos + total_req_size <= 8 * 1024) { h = (mem_header_t*) (pool + pool_free_pos); h->s.size = nquantas; memmgr_free((void*) (h + 1)); pool_free_pos += total_req_size; } else { return 0; } return freep; } void* memmgr_alloc(ulong nbytes) { mem_header_t* p; mem_header_t* prevp; ulong nquantas = (nbytes + sizeof(mem_header_t) - 1) / sizeof(mem_header_t) + 1; if ((prevp = freep) == 0) { base.s.next = freep = prevp = &base; base.s.size = 0; } for (p = prevp->s.next; ; prevp = p, p = p->s.next) { if (p->s.size >= nquantas) { if (p->s.size == nquantas) { prevp->s.next = p->s.next; } else { p->s.size -= nquantas; p += p->s.size; p->s.size = nquantas; } freep = prevp; return (void*) (p + 1); } else if (p == freep) { if ((p = get_mem_from_pool(nquantas)) == 0) { return 0; } } } } void memmgr_free(void* ap) { mem_header_t* block; mem_header_t* p; block = ((mem_header_t*) ap) - 1; for (p = freep; !(block > p && block < p->s.next); p = p->s.next) { if (p >= p->s.next && (block > p || block < p->s.next)) break; } if (block + block->s.size == p->s.next) { block->s.size += p->s.next->s.size; block->s.next = p->s.next->s.next; } else { block->s.next = p->s.next; } if (p + p->s.size == block) { p->s.size += block->s.size; p->s.next = block->s.next; } else { p->s.next = block; } freep = p; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/tests/c_files/simplemain.c0000664000175000017500000000010014716121044017743 0ustar00elibeneliben#include "hdir\emptydir\..\9\inc.h" int main() { return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/tests/c_files/year.c0000664000175000017500000000240114716121044016553 0ustar00elibeneliben#include #include #include #include /* C99 bools */ _Bool just_a_flag = false; bool another_flag = true; void convert(int thousands, int hundreds, int tens, int ones) { char *num[] = {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"}; char *for_ten[] = {"", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"}; char *af_ten[] = {"Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Ninteen"}; printf("\nThe year in words is:\n"); printf("%s thousand", num[thousands]); if (hundreds != 0) printf(" %s hundred", num[hundreds]); if (tens != 1) printf(" %s %s", for_ten[tens], num[ones]); else printf(" %s", af_ten[ones]); va_list jajaja; } int main() { int year; int n1000, n100, n10, n1; printf("\nEnter the year (4 digits): "); scanf("%d", &year); if (year > 9999 || year < 1000) { printf("\nError !! The year must contain 4 digits."); exit(EXIT_FAILURE); } n1000 = year/1000; n100 = ((year)%1000)/100; n10 = (year%100)/10; n1 = ((year%10)%10); convert(n1000, n100, n10, n1); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/tests/test_c_ast.py0000664000175000017500000001131215134157072016553 0ustar00elibenelibenimport sys import unittest import weakref sys.path.insert(0, "..") import pycparser.c_ast as c_ast from pycparser.c_parser import Coord class Test_c_ast(unittest.TestCase): def test_BinaryOp(self): b1 = c_ast.BinaryOp( op="+", left=c_ast.Constant(type="int", value="6"), right=c_ast.ID(name="joe"), ) self.assertIsInstance(b1.left, c_ast.Constant) self.assertEqual(b1.left.type, "int") self.assertEqual(b1.left.value, "6") self.assertIsInstance(b1.right, c_ast.ID) self.assertEqual(b1.right.name, "joe") def test_weakref_works_on_nodes(self): c1 = c_ast.Constant(type="float", value="3.14") wr = weakref.ref(c1) cref = wr() self.assertIsNotNone(cref) assert cref is not None self.assertEqual(cref.type, "float") self.assertEqual(weakref.getweakrefcount(c1), 1) def test_weakref_works_on_coord(self): coord = Coord(file="a", line=2) wr = weakref.ref(coord) cref = wr() self.assertIsNotNone(cref) assert cref is not None self.assertEqual(cref.line, 2) self.assertEqual(weakref.getweakrefcount(coord), 1) class TestNodeVisitor(unittest.TestCase): class ConstantVisitor(c_ast.NodeVisitor): def __init__(self): self.values = [] def visit_Constant(self, node): self.values.append(node.value) def test_scalar_children(self): b1 = c_ast.BinaryOp( op="+", left=c_ast.Constant(type="int", value="6"), right=c_ast.ID(name="joe"), ) cv = self.ConstantVisitor() cv.visit(b1) self.assertEqual(cv.values, ["6"]) b2 = c_ast.BinaryOp( op="*", left=c_ast.Constant(type="int", value="111"), right=b1 ) b3 = c_ast.BinaryOp(op="^", left=b2, right=b1) cv = self.ConstantVisitor() cv.visit(b3) self.assertEqual(cv.values, ["111", "6", "6"]) def tests_list_children(self): c1 = c_ast.Constant(type="float", value="5.6") c2 = c_ast.Constant(type="char", value="t") b1 = c_ast.BinaryOp(op="+", left=c1, right=c2) b2 = c_ast.BinaryOp(op="-", left=b1, right=c2) comp = c_ast.Compound(block_items=[b1, b2, c1, c2]) cv = self.ConstantVisitor() cv.visit(comp) self.assertEqual(cv.values, ["5.6", "t", "5.6", "t", "t", "5.6", "t"]) def test_repr(self): c1 = c_ast.Constant(type="float", value="5.6") c2 = c_ast.Constant(type="char", value="t") b1 = c_ast.BinaryOp(op="+", left=c1, right=c2) b2 = c_ast.BinaryOp(op="-", left=b1, right=c2) comp = c_ast.Compound(block_items=[b1, b2, c1, c2]) expected = ( "Compound(block_items=[BinaryOp(op='+',\n" " left=Constant(type='float',\n" " value='5.6'\n" " ),\n" " right=Constant(type='char',\n" " value='t'\n" " )\n" " ),\n" " BinaryOp(op='-',\n" " left=BinaryOp(op='+',\n" " left=Constant(type='float',\n" " value='5.6'\n" " ),\n" " right=Constant(type='char',\n" " value='t'\n" " )\n" " ),\n" " right=Constant(type='char',\n" " value='t'\n" " )\n" " ),\n" " Constant(type='float',\n" " value='5.6'\n" " ),\n" " Constant(type='char',\n" " value='t'\n" " )\n" " ]\n" " )" ) self.assertEqual(repr(comp), expected) if __name__ == "__main__": unittest.main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/tests/test_c_generator.py0000664000175000017500000004261415134157072017763 0ustar00elibenelibenimport os import sys import unittest # Run from the root dir sys.path.insert(0, ".") from pycparser import c_parser, c_generator, c_ast, parse_file from tests.test_util import cpp_supported, cpp_path, cpp_args _c_parser = c_parser.CParser() def compare_asts(ast1, ast2): """Compares two ASTs recursively just enough for the purpose of testing. Since this function is recursive it also accepts non-ast parameters, in which case it compares them literally (with ==) or recursively (for tuples or lists). """ # After the initial `if`, all the `elif` clauses assume that the types of # ast1 and ast2 are the same. if type(ast1) is not type(ast2): return False elif isinstance(ast1, (list, tuple)): if len(ast1) != len(ast2): return False for i in range(len(ast1)): if not compare_asts(ast1[i], ast2[i]): return False return True elif isinstance(ast1, c_ast.Node): for attr in ast1.attr_names: attr1 = getattr(ast1, attr) attr2 = getattr(ast2, attr) if not compare_asts(attr1, attr2): return False children1 = ast1.children() children2 = ast2.children() if len(children1) != len(children2): return False for i in range(len(children1)): if not compare_asts(children1[i], children2[i]): return False return True else: return ast1 == ast2 def parse_to_ast(src): return _c_parser.parse(src) class TestFunctionDeclGeneration(unittest.TestCase): class _FuncDeclVisitor(c_ast.NodeVisitor): def __init__(self): self.stubs = [] def visit_FuncDecl(self, node): gen = c_generator.CGenerator() self.stubs.append(gen.visit(node)) def test_partial_funcdecl_generation(self): src = r""" void noop(void); void *something(void *thing); int add(int x, int y);""" ast = parse_to_ast(src) v = TestFunctionDeclGeneration._FuncDeclVisitor() v.visit(ast) self.assertEqual(len(v.stubs), 3) self.assertTrue(r"void noop(void)" in v.stubs) self.assertTrue(r"void *something(void *thing)" in v.stubs) self.assertTrue(r"int add(int x, int y)" in v.stubs) class TestCtoC(unittest.TestCase): def _run_c_to_c(self, src, *args, **kwargs): ast = parse_to_ast(src) generator = c_generator.CGenerator(*args, **kwargs) return generator.visit(ast) def _assert_ctoc_correct(self, src, *args, **kwargs): """Checks that the c2c translation was correct by parsing the code generated by c2c for src and comparing the AST with the original AST. Additional arguments are passed to CGenerator.__init__. """ src2 = self._run_c_to_c(src, *args, **kwargs) self.assertTrue( compare_asts(parse_to_ast(src), parse_to_ast(src2)), "{!r} != {!r}".format(src, src2), ) return src2 def test_trivial_decls(self): self._assert_ctoc_correct("int a;") self._assert_ctoc_correct("int b, a;") self._assert_ctoc_correct("int c, b, a;") self._assert_ctoc_correct("auto int a;") self._assert_ctoc_correct("register int a;") self._assert_ctoc_correct("_Thread_local int a;") def test_complex_decls(self): self._assert_ctoc_correct("int** (*a)(void);") self._assert_ctoc_correct("int** (*a)(void*, int);") self._assert_ctoc_correct("int (*b)(char * restrict k, float);") self._assert_ctoc_correct("int (*b)(char * _Atomic k, float);") self._assert_ctoc_correct("int (*b)(char * _Atomic volatile k, float);") self._assert_ctoc_correct("int test(const char* const* arg);") self._assert_ctoc_correct("int test(const char** const arg);") def test_alignment(self): self._assert_ctoc_correct("_Alignas(32) int b;") self._assert_ctoc_correct("int _Alignas(32) a;") self._assert_ctoc_correct("_Alignas(32) _Atomic(int) b;") self._assert_ctoc_correct("_Atomic(int) _Alignas(32) b;") self._assert_ctoc_correct("_Alignas(long long) int a;") self._assert_ctoc_correct("int _Alignas(long long) a;") self._assert_ctoc_correct(r""" typedef struct node_t { _Alignas(64) void* next; int data; } node; """) self._assert_ctoc_correct(r""" typedef struct node_t { void _Alignas(64) * next; int data; } node; """) def test_ternary(self): self._assert_ctoc_correct(""" int main(void) { int a, b; (a == 0) ? (b = 1) : (b = 2); }""") def test_casts(self): self._assert_ctoc_correct(r""" int main() { int b = (int) f; int c = (int*) f; }""") self._assert_ctoc_correct(r""" int main() { int a = (int) b + 8; int t = (int) c; } """) def test_initlist(self): self._assert_ctoc_correct("int arr[] = {1, 2, 3};") def test_exprs(self): self._assert_ctoc_correct(""" int main(void) { int a; int b = a++; int c = ++a; int d = a--; int e = --a; }""") def test_statements(self): # note two minuses here self._assert_ctoc_correct(r""" int main() { int a; a = 5; ; b = - - a; return a; }""") def test_struct_decl(self): self._assert_ctoc_correct(r""" typedef struct node_t { struct node_t* next; int data; } node; """) def test_krstyle(self): self._assert_ctoc_correct(r""" int main(argc, argv) int argc; char** argv; { return 0; } """) def test_switchcase(self): self._assert_ctoc_correct(r""" int main() { switch (myvar) { case 10: { k = 10; p = k + 1; break; } case 20: case 30: return 20; default: break; } } """) def test_nest_initializer_list(self): self._assert_ctoc_correct(r""" int main() { int i[1][1] = { { 1 } }; }""") def test_nest_named_initializer(self): self._assert_ctoc_correct(r"""struct test { int i; struct test_i_t { int k; } test_i; int j; }; struct test test_var = {.i = 0, .test_i = {.k = 1}, .j = 2}; """) def test_expr_list_in_initializer_list(self): self._assert_ctoc_correct(r""" int main() { int i[1] = { (1, 2) }; }""") def test_issue36(self): self._assert_ctoc_correct(r""" int main() { }""") def test_issue37(self): self._assert_ctoc_correct(r""" int main(void) { unsigned size; size = sizeof(size); return 0; }""") def test_issue66(self): # A non-existing body must not be generated # (previous valid behavior, still working) self._assert_ctoc_correct(r""" struct foo; """) # An empty body must be generated # (added behavior) self._assert_ctoc_correct(r""" struct foo {}; """) def test_issue83(self): self._assert_ctoc_correct(r""" void x(void) { int i = (9, k); } """) def test_issue84(self): self._assert_ctoc_correct(r""" void x(void) { for (int i = 0;;) i; } """) def test_issue246(self): self._assert_ctoc_correct(r""" int array[3] = {[0] = 0, [1] = 1, [1+1] = 2}; """) def test_noreturn(self): self._assert_ctoc_correct(r""" _Noreturn int x(void) { abort(); } """) def test_exprlist_with_semi(self): self._assert_ctoc_correct(r""" void x() { if (i < j) tmp = C[i], C[i] = C[j], C[j] = tmp; if (i <= j) i++, j--; } """) def test_exprlist_with_compound(self): self._assert_ctoc_correct(r""" void test(){ (sizeof (0), ({ if (0) ; else ; })); } """) def test_exprlist_with_subexprlist(self): self._assert_ctoc_correct(r""" void x() { (a = b, (b = c, c = a)); } """) def test_comma_operator_funcarg(self): self._assert_ctoc_correct(r""" void f(int x) { return x; } int main(void) { f((1, 2)); return 0; } """) def test_comma_op_in_ternary(self): self._assert_ctoc_correct(r""" void f() { (0, 0) ? (0, 0) : (0, 0); } """) def test_comma_op_assignment(self): self._assert_ctoc_correct(r""" void f() { i = (a, b, c); } """) def test_pragma(self): self._assert_ctoc_correct(r""" #pragma foo void f() { #pragma bar i = (a, b, c); if (d) #pragma qux j = e; if (d) #pragma qux #pragma quux j = e; } typedef struct s { #pragma baz } s; """) def test_compound_literal(self): self._assert_ctoc_correct('char **foo = (char *[]){ "x", "y", "z" };') self._assert_ctoc_correct("int i = ++(int){ 1 };") self._assert_ctoc_correct("struct foo_s foo = (struct foo_s){ 1, 2 };") def test_enum(self): self._assert_ctoc_correct(r""" enum e { a, b = 2, c = 3 }; """) self._assert_ctoc_correct(r""" enum f { g = 4, h, i }; """) def test_enum_typedef(self): self._assert_ctoc_correct("typedef enum EnumName EnumTypedefName;") def test_generate_struct_union_enum_exception(self): generator = c_generator.CGenerator() self.assertRaises( AssertionError, generator._generate_struct_union_enum, n=c_ast.Struct( name="TestStruct", decls=[], ), name="", ) def test_array_decl(self): self._assert_ctoc_correct("int g(const int a[const 20]){}") ast = parse_to_ast("const int a[const 20];") generator = c_generator.CGenerator() self.assertEqual(generator.visit(ast.ext[0].type), "const int [const 20]") self.assertEqual(generator.visit(ast.ext[0].type.type), "const int") def test_ptr_decl(self): src = "const int ** const x;" self._assert_ctoc_correct(src) ast = parse_to_ast(src) generator = c_generator.CGenerator() self.assertEqual(generator.visit(ast.ext[0].type), "const int ** const") self.assertEqual(generator.visit(ast.ext[0].type.type), "const int *") self.assertEqual(generator.visit(ast.ext[0].type.type.type), "const int") def test_atomic_qual(self): self._assert_ctoc_correct("_Atomic int x;") self._assert_ctoc_correct("_Atomic int* x;") self._assert_ctoc_correct("int* _Atomic x;") # _Atomic specifier gets turned into qualifier. s1 = "_Atomic(int) x;" c1 = self._run_c_to_c(s1) self.assertEqual(c1, "_Atomic int x;\n") self._assert_ctoc_correct(s1) s2 = "_Atomic(int*) x;" c2 = self._run_c_to_c(s2) self.assertEqual(c2, "int * _Atomic x;\n") self._assert_ctoc_correct(s2) s3 = "_Atomic(_Atomic(int)*) x;" c3 = self._run_c_to_c(s3) self.assertEqual(c3, "_Atomic int * _Atomic x;\n") self._assert_ctoc_correct(s3) # TODO: Regeneration with multiple qualifiers is not fully supported. # REF: https://github.com/eliben/pycparser/issues/433 # self._assert_ctoc_correct('auto const _Atomic(int *) a;') s4 = "typedef _Atomic(int) atomic_int;" c4 = self._run_c_to_c(s4) self.assertEqual(c4, "typedef _Atomic int atomic_int;\n") self._assert_ctoc_correct(s4) s5 = "typedef _Atomic(_Atomic(_Atomic(int (*)(void)) *) *) t;" c5 = self._run_c_to_c(s5) self.assertEqual(c5, "typedef int (* _Atomic * _Atomic * _Atomic t)(void);\n") self._assert_ctoc_correct(s5) self._assert_ctoc_correct(r""" typedef struct node_t { _Atomic(void*) a; _Atomic(void) *b; _Atomic void *c; } node; """) def test_nested_sizeof(self): src = "1" for _ in range(30): src = "sizeof(" + src + ")" src = "int x = " + src + ";" self._assert_ctoc_correct(src) def test_static_assert(self): self._assert_ctoc_correct('_Static_assert(sizeof(int) == sizeof(int), "123");') self._assert_ctoc_correct( 'int main() { _Static_assert(sizeof(int) == sizeof(int), "123"); } ' ) self._assert_ctoc_correct("_Static_assert(sizeof(int) == sizeof(int));") def test_reduce_parentheses_binaryops(self): c1 = "int x = a + b + c + d;" self.assertEqual(self._run_c_to_c(c1), "int x = ((a + b) + c) + d;\n") self.assertEqual( self._run_c_to_c(c1, reduce_parentheses=True), "int x = a + b + c + d;\n" ) # codes with minimum number of (necessary) parenthesis: test_snippets = [ "int x = a*b*c*d;", "int x = a+b*c*d;", "int x = a*b+c*d;", "int x = a*b*c+d;", "int x = (a+b)*c*d;", "int x = (a+b)*(c+d);", "int x = (a+b)/(c-d);", "int x = a+b-c-d;", "int x = a+(b-c)-d;", ] for src in test_snippets: src2 = self._assert_ctoc_correct(src, reduce_parentheses=True) self.assertTrue( src2.count("(") == src.count("("), msg="{!r} did not have minimum number of parenthesis, should be like {!r}.".format( src2, src ), ) class TestCasttoC(unittest.TestCase): def _find_file(self, name): test_dir = os.path.dirname(__file__) name = os.path.join(test_dir, "c_files", name) assert os.path.exists(name) return name def test_to_type(self): src = "int *x;" generator = c_generator.CGenerator() test_fun = c_ast.FuncCall(c_ast.ID("test_fun"), c_ast.ExprList([])) ast1 = parse_to_ast(src) int_ptr_type = ast1.ext[0].type int_type = int_ptr_type.type self.assertEqual( generator.visit(c_ast.Cast(int_ptr_type, test_fun)), "(int *) test_fun()" ) self.assertEqual( generator.visit(c_ast.Cast(int_type, test_fun)), "(int) test_fun()" ) @unittest.skipUnless(cpp_supported(), "cpp only works on Unix") def test_to_type_with_cpp(self): generator = c_generator.CGenerator() test_fun = c_ast.FuncCall(c_ast.ID("test_fun"), c_ast.ExprList([])) memmgr_path = self._find_file("memmgr.h") ast2 = parse_file( memmgr_path, use_cpp=True, cpp_path=cpp_path(), cpp_args=cpp_args() ) void_ptr_type = ast2.ext[-3].type.type void_type = void_ptr_type.type self.assertEqual( generator.visit(c_ast.Cast(void_ptr_type, test_fun)), "(void *) test_fun()" ) self.assertEqual( generator.visit(c_ast.Cast(void_type, test_fun)), "(void) test_fun()" ) def test_nested_else_if_line_breaks(self): generator = c_generator.CGenerator() test_ast1 = c_ast.If(None, None, None) test_ast2 = c_ast.If(None, None, c_ast.If(None, None, None)) test_ast3 = c_ast.If( None, None, c_ast.If(None, None, c_ast.If(None, None, None)) ) test_ast4 = c_ast.If( None, c_ast.Compound([]), c_ast.If( None, c_ast.Compound([]), c_ast.If(None, c_ast.Compound([]), None) ), ) self.assertEqual(generator.visit(test_ast1), "if ()\n \n") self.assertEqual(generator.visit(test_ast2), "if ()\n \nelse\n if ()\n \n") self.assertEqual( generator.visit(test_ast3), "if ()\n \nelse\n if ()\n \nelse\n if ()\n \n", ) self.assertEqual( generator.visit(test_ast4), "if ()\n{\n}\nelse\n if ()\n{\n}\nelse\n if ()\n{\n}\n", ) if __name__ == "__main__": unittest.main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/tests/test_c_lexer.py0000664000175000017500000004611215134157072017111 0ustar00elibenelibenimport re import sys import unittest from typing import Optional sys.path.insert(0, "..") from pycparser.c_lexer import CLexer, _Token def require_token(tok: Optional[_Token]) -> _Token: # In tests we know token() should produce a token here; this helper asserts # that and narrows Optional[_Token] to _Token, avoiding repeated casts/guards. assert tok is not None return tok def token_list(clex): return list(iter(clex.token, None)) def token_types(clex): return [i.type for i in token_list(clex)] class TestCLexerNoErrors(unittest.TestCase): """Test lexing of strings that are not supposed to cause errors. Therefore, the error_func passed to the lexer raises an exception. """ def error_func(self, msg, line, column): self.fail(msg) def on_lbrace_func(self): pass def on_rbrace_func(self): pass def type_lookup_func(self, typ): if typ.startswith("mytype"): return True else: return False def setUp(self): self.clex = CLexer( self.error_func, lambda: None, lambda: None, self.type_lookup_func ) def assertTokensTypes(self, str, types): self.clex.input(str) self.assertEqual(token_types(self.clex), types) def test_trivial_tokens(self): self.assertTokensTypes("1", ["INT_CONST_DEC"]) self.assertTokensTypes("-", ["MINUS"]) self.assertTokensTypes("volatile", ["VOLATILE"]) self.assertTokensTypes("...", ["ELLIPSIS"]) self.assertTokensTypes("++", ["PLUSPLUS"]) self.assertTokensTypes("case int", ["CASE", "INT"]) self.assertTokensTypes("caseint", ["ID"]) self.assertTokensTypes("$dollar cent$", ["ID", "ID"]) self.assertTokensTypes("i ^= 1;", ["ID", "XOREQUAL", "INT_CONST_DEC", "SEMI"]) def test_id_typeid(self): self.assertTokensTypes("myt", ["ID"]) self.assertTokensTypes("mytype", ["TYPEID"]) self.assertTokensTypes("mytype6 var", ["TYPEID", "ID"]) def test_integer_constants(self): self.assertTokensTypes("12", ["INT_CONST_DEC"]) self.assertTokensTypes("12u", ["INT_CONST_DEC"]) self.assertTokensTypes("12l", ["INT_CONST_DEC"]) self.assertTokensTypes("199872Ul", ["INT_CONST_DEC"]) self.assertTokensTypes("199872lU", ["INT_CONST_DEC"]) self.assertTokensTypes("199872LL", ["INT_CONST_DEC"]) self.assertTokensTypes("199872ull", ["INT_CONST_DEC"]) self.assertTokensTypes("199872llu", ["INT_CONST_DEC"]) self.assertTokensTypes("1009843200000uLL", ["INT_CONST_DEC"]) self.assertTokensTypes("1009843200000LLu", ["INT_CONST_DEC"]) self.assertTokensTypes("077", ["INT_CONST_OCT"]) self.assertTokensTypes("0123456L", ["INT_CONST_OCT"]) self.assertTokensTypes("0xf7", ["INT_CONST_HEX"]) self.assertTokensTypes("0b110", ["INT_CONST_BIN"]) self.assertTokensTypes("0x01202AAbbf7Ul", ["INT_CONST_HEX"]) self.assertTokensTypes("'12'", ["INT_CONST_CHAR"]) self.assertTokensTypes("'123'", ["INT_CONST_CHAR"]) self.assertTokensTypes("'1AB4'", ["INT_CONST_CHAR"]) self.assertTokensTypes(r"'1A\n4'", ["INT_CONST_CHAR"]) # no 0 before x, so ID catches it self.assertTokensTypes("xf7", ["ID"]) # - is MINUS, the rest a constnant self.assertTokensTypes("-1", ["MINUS", "INT_CONST_DEC"]) def test_special_names(self): self.assertTokensTypes("sizeof offsetof", ["SIZEOF", "OFFSETOF"]) def test_new_keywords(self): self.assertTokensTypes("_Bool", ["_BOOL"]) self.assertTokensTypes("_Atomic", ["_ATOMIC"]) self.assertTokensTypes("_Alignas _Alignof", ["_ALIGNAS", "_ALIGNOF"]) def test_floating_constants(self): self.assertTokensTypes("1.5f", ["FLOAT_CONST"]) self.assertTokensTypes("01.5", ["FLOAT_CONST"]) self.assertTokensTypes(".15L", ["FLOAT_CONST"]) self.assertTokensTypes("0.", ["FLOAT_CONST"]) # but just a period is a period self.assertTokensTypes(".", ["PERIOD"]) self.assertTokensTypes("3.3e-3", ["FLOAT_CONST"]) self.assertTokensTypes(".7e25L", ["FLOAT_CONST"]) self.assertTokensTypes("6.e+125f", ["FLOAT_CONST"]) self.assertTokensTypes("666e666", ["FLOAT_CONST"]) self.assertTokensTypes("00666e+3", ["FLOAT_CONST"]) # but this is a hex integer + 3 self.assertTokensTypes("0x0666e+3", ["INT_CONST_HEX", "PLUS", "INT_CONST_DEC"]) def test_hexadecimal_floating_constants(self): self.assertTokensTypes("0xDE.488641p0", ["HEX_FLOAT_CONST"]) self.assertTokensTypes("0x.488641p0", ["HEX_FLOAT_CONST"]) self.assertTokensTypes("0X12.P0", ["HEX_FLOAT_CONST"]) def test_char_constants(self): self.assertTokensTypes(r"""'x'""", ["CHAR_CONST"]) self.assertTokensTypes(r"""L'x'""", ["WCHAR_CONST"]) self.assertTokensTypes(r"""u8'x'""", ["U8CHAR_CONST"]) self.assertTokensTypes(r"""u'x'""", ["U16CHAR_CONST"]) self.assertTokensTypes(r"""U'x'""", ["U32CHAR_CONST"]) self.assertTokensTypes(r"""'\t'""", ["CHAR_CONST"]) self.assertTokensTypes(r"""'\''""", ["CHAR_CONST"]) self.assertTokensTypes(r"""'\?'""", ["CHAR_CONST"]) self.assertTokensTypes(r"""'\0'""", ["CHAR_CONST"]) self.assertTokensTypes(r"""'\012'""", ["CHAR_CONST"]) self.assertTokensTypes(r"""'\x2f'""", ["CHAR_CONST"]) self.assertTokensTypes(r"""'\x2f12'""", ["CHAR_CONST"]) self.assertTokensTypes(r"""L'\xaf'""", ["WCHAR_CONST"]) def test_on_rbrace_lbrace(self): braces = [] def on_lbrace(): braces.append("{") def on_rbrace(): braces.append("}") clex = CLexer(self.error_func, on_lbrace, on_rbrace, self.type_lookup_func) clex.input("hello { there } } and again }}{") token_list(clex) self.assertEqual(braces, ["{", "}", "}", "}", "}", "{"]) def test_string_literal(self): self.assertTokensTypes('"a string"', ["STRING_LITERAL"]) self.assertTokensTypes('L"ing"', ["WSTRING_LITERAL"]) self.assertTokensTypes('u8"ing"', ["U8STRING_LITERAL"]) self.assertTokensTypes('u"ing"', ["U16STRING_LITERAL"]) self.assertTokensTypes('U"ing"', ["U32STRING_LITERAL"]) self.assertTokensTypes('"i am a string too \t"', ["STRING_LITERAL"]) self.assertTokensTypes( r'''"esc\ape \"\'\? \0234 chars \rule"''', ["STRING_LITERAL"] ) self.assertTokensTypes( r'''"hello 'joe' wanna give it a \"go\"?"''', ["STRING_LITERAL"] ) self.assertTokensTypes( '"\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123"', ["STRING_LITERAL"], ) # Note: a-zA-Z and '.-~^_!=&;,' are allowed as escape chars to support #line # directives with Windows paths as filenames (..\..\dir\file) self.assertTokensTypes(r'"\x"', ["STRING_LITERAL"]) self.assertTokensTypes( r'"\a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z\A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z"', ["STRING_LITERAL"], ) self.assertTokensTypes(r'"C:\x\fa\x1e\xited"', ["STRING_LITERAL"]) # The lexer is permissive and allows decimal escapes (not just octal) self.assertTokensTypes(r'"jx\9"', ["STRING_LITERAL"]) self.assertTokensTypes(r'"fo\9999999"', ["STRING_LITERAL"]) def test_mess(self): self.assertTokensTypes( r"[{}]()", ["LBRACKET", "LBRACE", "RBRACE", "RBRACKET", "LPAREN", "RPAREN"] ) self.assertTokensTypes( r"()||!C&~Z?J", [ "LPAREN", "RPAREN", "LOR", "LNOT", "ID", "AND", "NOT", "ID", "CONDOP", "ID", ], ) self.assertTokensTypes( r"+-*/%|||&&&^><>=<===!=", [ "PLUS", "MINUS", "TIMES", "DIVIDE", "MOD", "LOR", "OR", "LAND", "AND", "XOR", "GT", "LT", "GE", "LE", "EQ", "NE", ], ) self.assertTokensTypes( r"++--->?.,;:", [ "PLUSPLUS", "MINUSMINUS", "ARROW", "CONDOP", "PERIOD", "COMMA", "SEMI", "COLON", ], ) def test_exprs(self): self.assertTokensTypes("bb-cc", ["ID", "MINUS", "ID"]) self.assertTokensTypes("foo & 0xFF", ["ID", "AND", "INT_CONST_HEX"]) self.assertTokensTypes( "(2+k) * 62", [ "LPAREN", "INT_CONST_DEC", "PLUS", "ID", "RPAREN", "TIMES", "INT_CONST_DEC", ], ) self.assertTokensTypes("x | y >> z", ["ID", "OR", "ID", "RSHIFT", "ID"]) self.assertTokensTypes( "x <<= z << 5", ["ID", "LSHIFTEQUAL", "ID", "LSHIFT", "INT_CONST_DEC"] ) self.assertTokensTypes( "x = y > 0 ? y : -6", [ "ID", "EQUALS", "ID", "GT", "INT_CONST_OCT", "CONDOP", "ID", "COLON", "MINUS", "INT_CONST_DEC", ], ) self.assertTokensTypes("a+++b", ["ID", "PLUSPLUS", "PLUS", "ID"]) def test_statements(self): self.assertTokensTypes( "for (int i = 0; i < n; ++i)", [ "FOR", "LPAREN", "INT", "ID", "EQUALS", "INT_CONST_OCT", "SEMI", "ID", "LT", "ID", "SEMI", "PLUSPLUS", "ID", "RPAREN", ], ) self.assertTokensTypes( "self: goto self;", ["ID", "COLON", "GOTO", "ID", "SEMI"] ) self.assertTokensTypes( """ switch (typ) { case TYPE_ID: m = 5; break; default: m = 8; }""", [ "SWITCH", "LPAREN", "ID", "RPAREN", "LBRACE", "CASE", "ID", "COLON", "ID", "EQUALS", "INT_CONST_DEC", "SEMI", "BREAK", "SEMI", "DEFAULT", "COLON", "ID", "EQUALS", "INT_CONST_DEC", "SEMI", "RBRACE", ], ) def test_preprocessor_line(self): self.assertTokensTypes("#abracadabra", ["PPHASH", "ID"]) str = r""" 546 #line 66 "kwas\df.h" id 4 dsf # 9 armo #line 10 "..\~..\test.h" tok1 #line 99999 "include/me.h" tok2 """ # ~ self.clex.filename self.clex.input(str) t1 = require_token(self.clex.token()) self.assertEqual(t1.type, "INT_CONST_DEC") self.assertEqual(t1.lineno, 2) t2 = require_token(self.clex.token()) self.assertEqual(t2.type, "ID") self.assertEqual(t2.value, "id") self.assertEqual(t2.lineno, 66) self.assertEqual(self.clex.filename, r"kwas\df.h") for i in range(3): t = require_token(self.clex.token()) self.assertEqual(t.type, "ID") self.assertEqual(t.value, "armo") self.assertEqual(t.lineno, 9) self.assertEqual(self.clex.filename, r"kwas\df.h") t4 = require_token(self.clex.token()) self.assertEqual(t4.type, "ID") self.assertEqual(t4.value, "tok1") self.assertEqual(t4.lineno, 10) self.assertEqual(self.clex.filename, r"..\~..\test.h") t5 = require_token(self.clex.token()) self.assertEqual(t5.type, "ID") self.assertEqual(t5.value, "tok2") self.assertEqual(t5.lineno, 99999) self.assertEqual(self.clex.filename, r"include/me.h") def test_preprocessor_line_funny(self): str = r""" #line 10 "..\6\joe.h" 10 """ self.clex.input(str) t1 = require_token(self.clex.token()) self.assertEqual(t1.type, "INT_CONST_DEC") self.assertEqual(t1.lineno, 10) self.assertEqual(self.clex.filename, r"..\6\joe.h") def test_preprocessor_pragma(self): str = """ 42 #pragma #pragma helo me #pragma once # pragma omp parallel private(th_id) #\tpragma {pack: 2, smack: 3} #pragma "nowit.h" #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 self.clex.input(str) t1 = require_token(self.clex.token()) self.assertEqual(t1.type, "INT_CONST_DEC") t2 = require_token(self.clex.token()) self.assertEqual(t2.type, "PPPRAGMA") t3 = require_token(self.clex.token()) self.assertEqual(t3.type, "PPPRAGMA") t4 = require_token(self.clex.token()) self.assertEqual(t4.type, "PPPRAGMASTR") self.assertEqual(t4.value, "helo me") for i in range(3): self.clex.token() t5 = require_token(self.clex.token()) self.assertEqual(t5.type, "PPPRAGMASTR") self.assertEqual(t5.value, "omp parallel private(th_id)") for i in range(5): ta = require_token(self.clex.token()) self.assertEqual(ta.type, "PPPRAGMA") tb = require_token(self.clex.token()) self.assertEqual(tb.type, "PPPRAGMASTR") t6a = require_token(self.clex.token()) t6l = require_token(self.clex.token()) t6b = require_token(self.clex.token()) t6r = require_token(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 = require_token(self.clex.token()) self.assertEqual(t7.type, "INT_CONST_DEC") self.assertEqual(t7.lineno, 13) # Keeps all the errors the lexer spits in one place, to allow # easier modification if the error syntax changes. # ERR_ILLEGAL_CHAR = "Illegal character" ERR_OCTAL = "Invalid octal constant" ERR_UNMATCHED_QUOTE = "Unmatched '" ERR_INVALID_CCONST = "Invalid char constant" ERR_STRING_ESCAPE = "String contains invalid escape" ERR_FILENAME_BEFORE_LINE = "filename before line" ERR_LINENUM_MISSING = "line number missing" ERR_INVALID_LINE_DIRECTIVE = "invalid #line directive" ERR_COMMENT = "Comments are not supported" class TestCLexerErrors(unittest.TestCase): """Test lexing of erroneous strings. Works by passing an error function that saves the error in an attribute for later perusal. """ def error_func(self, msg, line, column): self.error = msg def on_lbrace_func(self): pass def on_rbrace_func(self): pass def type_lookup_func(self, typ): return False def setUp(self): self.clex = CLexer( self.error_func, self.on_lbrace_func, self.on_rbrace_func, self.type_lookup_func, ) self.error = "" def assertLexerError(self, str, error_like): # feed the string to the lexer self.clex.input(str) # Pulls all tokens from the string. Errors will # be written into self.error by the error_func # callback # token_types(self.clex) # compare the error to the expected self.assertTrue( re.search(error_like, self.error), f"\nExpected error matching: {error_like}\nGot: {self.error}", ) # clear last error, for the sake of subsequent invocations self.error = "" def test_trivial_tokens(self): self.assertLexerError("@", ERR_ILLEGAL_CHAR) self.assertLexerError("`", ERR_ILLEGAL_CHAR) self.assertLexerError("\\", ERR_ILLEGAL_CHAR) def test_integer_constants(self): self.assertLexerError("029", ERR_OCTAL) self.assertLexerError("012345678", ERR_OCTAL) def test_char_constants(self): self.assertLexerError("'", ERR_UNMATCHED_QUOTE) self.assertLexerError("'b\n", ERR_UNMATCHED_QUOTE) self.assertLexerError("'\\xaa\n'", ERR_UNMATCHED_QUOTE) self.assertLexerError(r"'123\12a'", ERR_INVALID_CCONST) self.assertLexerError(r"'123\xabg'", ERR_INVALID_CCONST) self.assertLexerError("''", ERR_INVALID_CCONST) self.assertLexerError("'abcjx'", ERR_INVALID_CCONST) self.assertLexerError(r"'\*'", ERR_INVALID_CCONST) def test_string_literals(self): self.assertLexerError(r'"jx\`"', ERR_STRING_ESCAPE) self.assertLexerError(r'"hekllo\* on ix"', ERR_STRING_ESCAPE) self.assertLexerError(r'L"hekllo\* on ix"', ERR_STRING_ESCAPE) # Should not suffer from slow backtracking self.assertLexerError( r'"\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\`\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123"', ERR_STRING_ESCAPE, ) self.assertLexerError( r'"\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\x23\`\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23\xf1\x23"', ERR_STRING_ESCAPE, ) # Should not suffer from slow backtracking when there's no end quote self.assertLexerError( r'"\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\`\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\123\12\123456', ERR_ILLEGAL_CHAR, ) self.assertLexerError( r'"\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\`\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x23\x2\x23456', ERR_ILLEGAL_CHAR, ) def test_preprocessor(self): self.assertLexerError('#line "ka"', ERR_FILENAME_BEFORE_LINE) self.assertLexerError("#line df", ERR_INVALID_LINE_DIRECTIVE) self.assertLexerError("#line \n", ERR_LINENUM_MISSING) # a compatible preprocessor must remove comments. self.assertLexerError("//", ERR_COMMENT) self.assertLexerError("/*", ERR_COMMENT) if __name__ == "__main__": unittest.main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/tests/test_c_parser.py0000775000175000017500000035211115134157072017270 0ustar00elibeneliben#!/usr/bin/env python import os import io import unittest from pycparser import c_parser from pycparser.c_ast import * ParseError = c_parser.ParseError _c_parser = c_parser.CParser() def expand_decl(decl): """Converts the declaration into a nested list.""" typ = type(decl) if typ == TypeDecl: return ["TypeDecl", expand_decl(decl.type)] elif typ == IdentifierType: return ["IdentifierType", decl.names] elif typ == ID: return ["ID", decl.name] elif typ in [Struct, Union]: decls = [expand_decl(d) for d in decl.decls or []] return [typ.__name__, decl.name, decls] elif typ == Enum: if decl.values is None: values = None else: assert isinstance(decl.values, EnumeratorList) values = [enum.name for enum in decl.values.enumerators] return ["Enum", decl.name, values] elif typ == Alignas: return ["Alignas", expand_init(decl.alignment)] elif typ == StaticAssert: if decl.message: return ["StaticAssert", decl.cond.value, decl.message.value] else: return ["StaticAssert", decl.cond.value] else: nested = expand_decl(decl.type) if typ == Decl: r = ["Decl"] if decl.quals: r.append(decl.quals) if decl.align: r.append(expand_decl(decl.align[0])) r.extend([decl.name, nested]) return r elif typ == Typename: # for function parameters if decl.quals: return ["Typename", decl.quals, nested] else: return ["Typename", nested] elif typ == ArrayDecl: dimval = decl.dim.value if decl.dim else "" return ["ArrayDecl", dimval, decl.dim_quals, nested] elif typ == PtrDecl: if decl.quals: return ["PtrDecl", decl.quals, nested] else: return ["PtrDecl", nested] elif typ == Typedef: return ["Typedef", decl.name, nested] elif typ == FuncDecl: if decl.args: params = [expand_decl(param) for param in decl.args.params] else: params = [] return ["FuncDecl", params, nested] def expand_init(init): """Converts an initialization into a nested list""" typ = type(init) if typ == NamedInitializer: des = [expand_init(dp) for dp in init.name] return (des, expand_init(init.expr)) elif typ in (InitList, ExprList): return [expand_init(expr) for expr in init.exprs] elif typ == Constant: return ["Constant", init.type, init.value] elif typ == ID: return ["ID", init.name] elif typ == Decl: return ["Decl", init.name] elif typ == UnaryOp: return ["UnaryOp", init.op, expand_decl(init.expr)] elif typ == BinaryOp: return ["BinaryOp", expand_init(init.left), init.op, expand_init(init.right)] elif typ == Compound: blocks = [] if init.block_items: blocks = [expand_init(i) for i in init.block_items] return ["Compound", blocks] elif typ == Typename: return expand_decl(init) else: # Fallback to type name return [typ.__name__] class TestCParser_base(unittest.TestCase): def parse(self, txt, filename=""): return self.cparser.parse(txt, filename) def setUp(self): self.cparser = _c_parser def assert_coord(self, node, line, column=None, file=None): self.assertEqual(node.coord.line, line) if column is not None: self.assertEqual(node.coord.column, column) if file: self.assertEqual(node.coord.file, file) class TestCParser_fundamentals(TestCParser_base): def get_decl(self, txt, index=0): """Given a source and an index returns the expanded declaration at that index. FileAST holds a list of 'external declarations'. index is the offset of the desired declaration in that list. """ t = self.parse(txt).ext[index] return expand_decl(t) def get_decl_init(self, txt, index=0): """Returns the expanded initializer of the declaration at index. """ t = self.parse(txt).ext[index] return expand_init(t.init) def test_FileAST(self): t = self.parse("int a; char c;") self.assertIsInstance(t, FileAST) self.assertEqual(len(t.ext), 2) # empty file t2 = self.parse("") self.assertIsInstance(t2, FileAST) self.assertEqual(len(t2.ext), 0) def test_empty_toplevel_decl(self): code = "int foo;;" t = self.parse(code) self.assertIsInstance(t, FileAST) self.assertEqual(len(t.ext), 1) self.assertEqual( self.get_decl(code), ["Decl", "foo", ["TypeDecl", ["IdentifierType", ["int"]]]], ) def test_initial_semi(self): t = self.parse(";") self.assertEqual(len(t.ext), 0) t = self.parse(";int foo;") self.assertEqual(len(t.ext), 1) self.assertEqual( expand_decl(t.ext[0]), ["Decl", "foo", ["TypeDecl", ["IdentifierType", ["int"]]]], ) def test_coords(self): """Tests the "coordinates" of parsed elements - file name, line and column numbers, with modification inserted by #line directives. """ self.assert_coord(self.parse("int a;").ext[0], 1, 5) t1 = """ int a; int b;\n\n int c; """ f1 = self.parse(t1, filename="test.c") self.assert_coord(f1.ext[0], 2, 13, "test.c") self.assert_coord(f1.ext[1], 3, 13, "test.c") self.assert_coord(f1.ext[2], 6, 13, "test.c") t1_1 = """ int main() { k = p; printf("%d", b); return 0; }""" f1_1 = self.parse(t1_1, filename="test.c") self.assert_coord(f1_1.ext[0].body.block_items[0], 3, 13, "test.c") self.assert_coord(f1_1.ext[0].body.block_items[1], 4, 13, "test.c") t1_2 = """ int main () { int p = (int) k; }""" f1_2 = self.parse(t1_2, filename="test.c") # make sure that the Cast has a coord (issue 23) self.assert_coord(f1_2.ext[0].body.block_items[0].init, 3, 21, file="test.c") t2 = """ #line 99 int c; """ self.assert_coord(self.parse(t2).ext[0], 99, 13) t3 = """ int dsf; char p; #line 3000 "in.h" char d; """ f3 = self.parse(t3, filename="test.c") self.assert_coord(f3.ext[0], 2, 13, "test.c") self.assert_coord(f3.ext[1], 3, 14, "test.c") self.assert_coord(f3.ext[2], 3000, 14, "in.h") t4 = """ #line 20 "restore.h" int maydler(char); #line 30 "includes/daween.ph" long j, k; #line 50000 char* ro; """ f4 = self.parse(t4, filename="myb.c") self.assert_coord(f4.ext[0], 20, 13, "restore.h") self.assert_coord(f4.ext[1], 30, 14, "includes/daween.ph") self.assert_coord(f4.ext[2], 30, 17, "includes/daween.ph") self.assert_coord(f4.ext[3], 50000, 13, "includes/daween.ph") t5 = """ int #line 99 c; """ self.assert_coord(self.parse(t5).ext[0], 99, 9) # coord for ellipsis t6 = """ int foo(int j, ...) { }""" self.assert_coord(self.parse(t6).ext[0].decl.type.args.params[1], 3, 17) def test_forloop_coord(self): t = """\ void foo() { for(int z=0; z<4; z++){} } """ s = self.parse(t, filename="f.c") forloop = s.ext[0].body.block_items[0] self.assert_coord(forloop.init, 2, 13, "f.c") self.assert_coord(forloop.cond, 2, 26, "f.c") self.assert_coord(forloop.next, 3, 17, "f.c") def test_simple_decls(self): self.assertEqual( self.get_decl("int a;"), ["Decl", "a", ["TypeDecl", ["IdentifierType", ["int"]]]], ) self.assertEqual( self.get_decl("unsigned int a;"), ["Decl", "a", ["TypeDecl", ["IdentifierType", ["unsigned", "int"]]]], ) self.assertEqual( self.get_decl("_Bool a;"), ["Decl", "a", ["TypeDecl", ["IdentifierType", ["_Bool"]]]], ) self.assertEqual( self.get_decl("float _Complex fcc;"), ["Decl", "fcc", ["TypeDecl", ["IdentifierType", ["float", "_Complex"]]]], ) self.assertEqual( self.get_decl("char* string;"), ["Decl", "string", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]]], ) self.assertEqual( self.get_decl("long ar[15];"), [ "Decl", "ar", ["ArrayDecl", "15", [], ["TypeDecl", ["IdentifierType", ["long"]]]], ], ) self.assertEqual( self.get_decl("long long ar[15];"), [ "Decl", "ar", [ "ArrayDecl", "15", [], ["TypeDecl", ["IdentifierType", ["long", "long"]]], ], ], ) self.assertEqual( self.get_decl("unsigned ar[];"), [ "Decl", "ar", ["ArrayDecl", "", [], ["TypeDecl", ["IdentifierType", ["unsigned"]]]], ], ) self.assertEqual( self.get_decl("int strlen(char* s);"), [ "Decl", "strlen", [ "FuncDecl", [ [ "Decl", "s", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) self.assertEqual( self.get_decl("int strcmp(char* s1, char* s2);"), [ "Decl", "strcmp", [ "FuncDecl", [ [ "Decl", "s1", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]], ], [ "Decl", "s2", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]], ], ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) # function return values and parameters may not have type information self.assertEqual( self.get_decl("extern foobar(foo, bar);"), [ "Decl", "foobar", [ "FuncDecl", [["ID", "foo"], ["ID", "bar"]], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) def test_int128(self): self.assertEqual( self.get_decl("__int128 a;"), ["Decl", "a", ["TypeDecl", ["IdentifierType", ["__int128"]]]], ) def test_nested_decls(self): # the fun begins self.assertEqual( self.get_decl("char** ar2D;"), [ "Decl", "ar2D", ["PtrDecl", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]]], ], ) self.assertEqual( self.get_decl("int (*a)[1][2];"), [ "Decl", "a", [ "PtrDecl", [ "ArrayDecl", "1", [], [ "ArrayDecl", "2", [], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ], ) self.assertEqual( self.get_decl("int *a[1][2];"), [ "Decl", "a", [ "ArrayDecl", "1", [], [ "ArrayDecl", "2", [], ["PtrDecl", ["TypeDecl", ["IdentifierType", ["int"]]]], ], ], ], ) self.assertEqual( self.get_decl("char* const* p;"), [ "Decl", "p", [ "PtrDecl", ["PtrDecl", ["const"], ["TypeDecl", ["IdentifierType", ["char"]]]], ], ], ) self.assertEqual( self.get_decl("const char* const* p;"), [ "Decl", ["const"], "p", [ "PtrDecl", ["PtrDecl", ["const"], ["TypeDecl", ["IdentifierType", ["char"]]]], ], ], ) self.assertEqual( self.get_decl("char* * const p;"), [ "Decl", "p", [ "PtrDecl", ["const"], ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]], ], ], ) self.assertEqual( self.get_decl("char ***ar3D[40];"), [ "Decl", "ar3D", [ "ArrayDecl", "40", [], [ "PtrDecl", [ "PtrDecl", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]], ], ], ], ], ) self.assertEqual( self.get_decl("char (***ar3D)[40];"), [ "Decl", "ar3D", [ "PtrDecl", [ "PtrDecl", [ "PtrDecl", [ "ArrayDecl", "40", [], ["TypeDecl", ["IdentifierType", ["char"]]], ], ], ], ], ], ) self.assertEqual( self.get_decl("int (*const*const x)(char, int);"), [ "Decl", "x", [ "PtrDecl", ["const"], [ "PtrDecl", ["const"], [ "FuncDecl", [ [ "Typename", ["TypeDecl", ["IdentifierType", ["char"]]], ], ["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]], ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ], ) self.assertEqual( self.get_decl("int (*x[4])(char, int);"), [ "Decl", "x", [ "ArrayDecl", "4", [], [ "PtrDecl", [ "FuncDecl", [ [ "Typename", ["TypeDecl", ["IdentifierType", ["char"]]], ], ["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]], ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ], ) self.assertEqual( self.get_decl("char *(*(**foo [][8])())[];"), [ "Decl", "foo", [ "ArrayDecl", "", [], [ "ArrayDecl", "8", [], [ "PtrDecl", [ "PtrDecl", [ "FuncDecl", [], [ "PtrDecl", [ "ArrayDecl", "", [], [ "PtrDecl", [ "TypeDecl", ["IdentifierType", ["char"]], ], ], ], ], ], ], ], ], ], ], ) # explore named and unnamed function pointer parameters, # with and without qualifiers # unnamed w/o quals self.assertEqual( self.get_decl("int (*k)(int);"), [ "Decl", "k", [ "PtrDecl", [ "FuncDecl", [["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]]], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ) # unnamed w/ quals self.assertEqual( self.get_decl("int (*k)(const int);"), [ "Decl", "k", [ "PtrDecl", [ "FuncDecl", [ [ "Typename", ["const"], ["TypeDecl", ["IdentifierType", ["int"]]], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ) # named w/o quals self.assertEqual( self.get_decl("int (*k)(int q);"), [ "Decl", "k", [ "PtrDecl", [ "FuncDecl", [["Decl", "q", ["TypeDecl", ["IdentifierType", ["int"]]]]], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ) # named w/ quals self.assertEqual( self.get_decl("int (*k)(const volatile int q);"), [ "Decl", "k", [ "PtrDecl", [ "FuncDecl", [ [ "Decl", ["const", "volatile"], "q", ["TypeDecl", ["IdentifierType", ["int"]]], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ) self.assertEqual( self.get_decl("int (*k)(_Atomic volatile int q);"), [ "Decl", "k", [ "PtrDecl", [ "FuncDecl", [ [ "Decl", ["_Atomic", "volatile"], "q", ["TypeDecl", ["IdentifierType", ["int"]]], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ) self.assertEqual( self.get_decl("int (*k)(const volatile int* q);"), [ "Decl", "k", [ "PtrDecl", [ "FuncDecl", [ [ "Decl", ["const", "volatile"], "q", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["int"]]]], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ) # restrict qualifier self.assertEqual( self.get_decl("int (*k)(restrict int* q);"), [ "Decl", "k", [ "PtrDecl", [ "FuncDecl", [ [ "Decl", ["restrict"], "q", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["int"]]]], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ) def test_func_decls_with_array_dim_qualifiers(self): # named function parameter self.assertEqual( self.get_decl("int zz(int p[static 10]);"), [ "Decl", "zz", [ "FuncDecl", [ [ "Decl", "p", [ "ArrayDecl", "10", ["static"], ["TypeDecl", ["IdentifierType", ["int"]]], ], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) # anonymous function parameter self.assertEqual( self.get_decl("int zz(int [static 10]);"), [ "Decl", "zz", [ "FuncDecl", [ [ "Typename", [ "ArrayDecl", "10", ["static"], ["TypeDecl", ["IdentifierType", ["int"]]], ], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) self.assertEqual( self.get_decl("int zz(int [static const restrict 10]);"), [ "Decl", "zz", [ "FuncDecl", [ [ "Typename", [ "ArrayDecl", "10", ["static", "const", "restrict"], ["TypeDecl", ["IdentifierType", ["int"]]], ], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) self.assertEqual( self.get_decl("int zz(int p[const 10]);"), [ "Decl", "zz", [ "FuncDecl", [ [ "Decl", "p", [ "ArrayDecl", "10", ["const"], ["TypeDecl", ["IdentifierType", ["int"]]], ], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) self.assertEqual( self.get_decl("int zz(int p[restrict][5]);"), [ "Decl", "zz", [ "FuncDecl", [ [ "Decl", "p", [ "ArrayDecl", "", ["restrict"], [ "ArrayDecl", "5", [], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) self.assertEqual( self.get_decl("int zz(int p[const restrict static 10][5]);"), [ "Decl", "zz", [ "FuncDecl", [ [ "Decl", "p", [ "ArrayDecl", "10", ["const", "restrict", "static"], [ "ArrayDecl", "5", [], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) # unnamed function parameter self.assertEqual( self.get_decl("int zz(int [const 10]);"), [ "Decl", "zz", [ "FuncDecl", [ [ "Typename", [ "ArrayDecl", "10", ["const"], ["TypeDecl", ["IdentifierType", ["int"]]], ], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) self.assertEqual( self.get_decl("int zz(int [restrict][5]);"), [ "Decl", "zz", [ "FuncDecl", [ [ "Typename", [ "ArrayDecl", "", ["restrict"], [ "ArrayDecl", "5", [], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) self.assertEqual( self.get_decl("int zz(int [const restrict volatile 10][5]);"), [ "Decl", "zz", [ "FuncDecl", [ [ "Typename", [ "ArrayDecl", "10", ["const", "restrict", "volatile"], [ "ArrayDecl", "5", [], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) def test_qualifiers_storage_specifiers(self): def assert_qs(txt, index, quals, storage): d = self.parse(txt).ext[index] self.assertEqual(d.quals, quals) self.assertEqual(d.storage, storage) assert_qs("extern int p;", 0, [], ["extern"]) assert_qs("_Thread_local int p;", 0, [], ["_Thread_local"]) assert_qs("const long p = 6;", 0, ["const"], []) assert_qs("_Atomic int p;", 0, ["_Atomic"], []) assert_qs("_Atomic restrict int* p;", 0, ["_Atomic", "restrict"], []) d1 = "static const int p, q, r;" for i in range(3): assert_qs(d1, i, ["const"], ["static"]) d2 = "static char * const p;" assert_qs(d2, 0, [], ["static"]) pdecl = self.parse(d2).ext[0].type self.assertIsInstance(pdecl, PtrDecl) self.assertEqual(pdecl.quals, ["const"]) def test_atomic_specifier(self): self.assertEqual( self.get_decl("_Atomic(int) ai;"), ["Decl", ["_Atomic"], "ai", ["TypeDecl", ["IdentifierType", ["int"]]]], ) self.assertEqual( self.get_decl("_Atomic(int*) ai;"), [ "Decl", "ai", ["PtrDecl", ["_Atomic"], ["TypeDecl", ["IdentifierType", ["int"]]]], ], ) self.assertEqual( self.get_decl("_Atomic(_Atomic(int)*) aai;"), [ "Decl", ["_Atomic"], "aai", ["PtrDecl", ["_Atomic"], ["TypeDecl", ["IdentifierType", ["int"]]]], ], ) # Multiple declarations with _Atomic(...) s = "_Atomic(int) foo, bar;" self.assertEqual( self.get_decl(s, 0), ["Decl", ["_Atomic"], "foo", ["TypeDecl", ["IdentifierType", ["int"]]]], ) self.assertEqual( self.get_decl(s, 1), ["Decl", ["_Atomic"], "bar", ["TypeDecl", ["IdentifierType", ["int"]]]], ) # typedefs with _Atomic specifiers. s = "typedef _Atomic(int) atomic_int;" self.assertEqual( self.get_decl(s, 0), ["Typedef", "atomic_int", ["TypeDecl", ["IdentifierType", ["int"]]]], ) s = "typedef _Atomic(_Atomic(_Atomic(int (*)(void)) *) *) t;" self.assertEqual( self.get_decl(s, 0), [ "Typedef", "t", [ "PtrDecl", ["_Atomic"], [ "PtrDecl", ["_Atomic"], [ "PtrDecl", ["_Atomic"], [ "FuncDecl", [ [ "Typename", ["TypeDecl", ["IdentifierType", ["void"]]], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ], ], ) def test_sizeof(self): e = """ void foo() { int a = sizeof k; int b = sizeof(int); int c = sizeof(int**);; char* p = "just to make sure this parses w/o error..."; int d = sizeof(int()); } """ compound = self.parse(e).ext[0].body s1 = compound.block_items[0].init self.assertIsInstance(s1, UnaryOp) self.assertEqual(s1.op, "sizeof") self.assertIsInstance(s1.expr, ID) self.assertEqual(s1.expr.name, "k") s2 = compound.block_items[1].init self.assertEqual( expand_decl(s2.expr), ["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]], ) s3 = compound.block_items[2].init self.assertEqual( expand_decl(s3.expr), [ "Typename", ["PtrDecl", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["int"]]]]], ], ) def test_alignof(self): r = self.parse("int a = _Alignof(int);") self.assertEqual( expand_decl(r.ext[0]), ["Decl", "a", ["TypeDecl", ["IdentifierType", ["int"]]]], ) self.assertEqual( expand_init(r.ext[0].init), [ "UnaryOp", "_Alignof", ["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]], ], ) self.assertEqual( expand_decl(self.parse("_Alignas(_Alignof(int)) char a;").ext[0]), [ "Decl", [ "Alignas", [ "UnaryOp", "_Alignof", ["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]], ], ], "a", ["TypeDecl", ["IdentifierType", ["char"]]], ], ) self.assertEqual( expand_decl(self.parse("_Alignas(4) char a;").ext[0]), [ "Decl", ["Alignas", ["Constant", "int", "4"]], "a", ["TypeDecl", ["IdentifierType", ["char"]]], ], ) self.assertEqual( expand_decl(self.parse("_Alignas(int) char a;").ext[0]), [ "Decl", ["Alignas", ["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]]], "a", ["TypeDecl", ["IdentifierType", ["char"]]], ], ) def test_alignas_with_typedef_in_struct(self): # Issue #472 s = """ typedef int test_int; typedef struct { _Alignas(int) test_int a1; } test_struct; """ ast = self.parse(s) field = ast.ext[1].type.type.decls[0] self.assertEqual(field.name, "a1") self.assertTrue(hasattr(field, "align") and field.align is not None) self.assertEqual( expand_decl(field), [ "Decl", ["Alignas", ["Typename", ["TypeDecl", ["IdentifierType", ["int"]]]]], "a1", ["TypeDecl", ["IdentifierType", ["test_int"]]], ], ) def test_offsetof(self): def expand_ref(n): if isinstance(n, StructRef): return ["StructRef", expand_ref(n.name), expand_ref(n.field)] elif isinstance(n, ArrayRef): return ["ArrayRef", expand_ref(n.name), expand_ref(n.subscript)] elif isinstance(n, ID): return ["ID", n.name] elif isinstance(n, Constant): return ["Constant", n.type, n.value] else: raise TypeError("Unexpected type " + n.__class__.__name__) e = """ void foo() { int a = offsetof(struct S, p); a.b = offsetof(struct sockaddr, sp) + strlen(bar); int a = offsetof(struct S, p.q.r); int a = offsetof(struct S, p[5].q[4][5]); } """ compound = self.parse(e).ext[0].body s1 = compound.block_items[0].init self.assertIsInstance(s1, FuncCall) self.assertIsInstance(s1.name, ID) self.assertEqual(s1.name.name, "offsetof") self.assertIsInstance(s1.args.exprs[0], Typename) self.assertIsInstance(s1.args.exprs[1], ID) s3 = compound.block_items[2].init self.assertIsInstance(s3.args.exprs[1], StructRef) self.assertEqual( expand_ref(s3.args.exprs[1]), ["StructRef", ["StructRef", ["ID", "p"], ["ID", "q"]], ["ID", "r"]], ) s4 = compound.block_items[3].init self.assertIsInstance(s4.args.exprs[1], ArrayRef) self.assertEqual( expand_ref(s4.args.exprs[1]), [ "ArrayRef", [ "ArrayRef", [ "StructRef", ["ArrayRef", ["ID", "p"], ["Constant", "int", "5"]], ["ID", "q"], ], ["Constant", "int", "4"], ], ["Constant", "int", "5"], ], ) def test_compound_statement(self): e = """ void foo() { } """ compound = self.parse(e).ext[0].body self.assertIsInstance(compound, Compound) self.assert_coord(compound, 2) # The C99 compound literal feature # def test_compound_literals(self): ps1 = self.parse(r""" void foo() { p = (long long){k}; tc = (struct jk){.a = {1, 2}, .b[0] = t}; }""") compound = ps1.ext[0].body.block_items[0].rvalue self.assertEqual( expand_decl(compound.type), ["Typename", ["TypeDecl", ["IdentifierType", ["long", "long"]]]], ) self.assertEqual(expand_init(compound.init), [["ID", "k"]]) compound = ps1.ext[0].body.block_items[1].rvalue self.assertEqual( expand_decl(compound.type), ["Typename", ["TypeDecl", ["Struct", "jk", []]]] ) self.assertEqual( expand_init(compound.init), [ ([["ID", "a"]], [["Constant", "int", "1"], ["Constant", "int", "2"]]), ([["ID", "b"], ["Constant", "int", "0"]], ["ID", "t"]), ], ) def test_parenthesized_compounds(self): e = self.parse(r""" void foo() { int a; ({}); ({ 1; }); ({ 1; 2; }); int b = ({ 1; }); int c, d = ({ int x = 1; x + 2; }); a = ({ int x = 1; 2 * x; }); }""") body = e.ext[0].body.block_items self.assertIsInstance(body[1], Compound) self.assertEqual(body[1].block_items, None) self.assertIsInstance(body[2], Compound) self.assertEqual(len(body[2].block_items), 1) self.assertIsInstance(body[2].block_items[0], Constant) self.assertIsInstance(body[3], Compound) self.assertEqual(len(body[3].block_items), 2) self.assertIsInstance(body[3].block_items[0], Constant) self.assertIsInstance(body[3].block_items[1], Constant) self.assertIsInstance(body[4], Decl) self.assertEqual( expand_init(body[4].init), ["Compound", [["Constant", "int", "1"]]] ) self.assertIsInstance(body[5], Decl) self.assertEqual(body[5].init, None) self.assertIsInstance(body[6], Decl) self.assertEqual( expand_init(body[6].init), [ "Compound", [ ["Decl", "x"], ["BinaryOp", ["ID", "x"], "+", ["Constant", "int", "2"]], ], ], ) self.assertIsInstance(body[7], Assignment) self.assertIsInstance(body[7].rvalue, Compound) self.assertEqual( expand_init(body[7].rvalue), [ "Compound", [ ["Decl", "x"], ["BinaryOp", ["Constant", "int", "2"], "*", ["ID", "x"]], ], ], ) def test_enums(self): e1 = "enum mycolor op;" e1_type = self.parse(e1).ext[0].type.type self.assertIsInstance(e1_type, Enum) self.assertEqual(e1_type.name, "mycolor") self.assertEqual(e1_type.values, None) e2 = "enum mysize {large=20, small, medium} shoes;" e2_type = self.parse(e2).ext[0].type.type self.assertIsInstance(e2_type, Enum) self.assertEqual(e2_type.name, "mysize") e2_elist = e2_type.values self.assertIsInstance(e2_elist, EnumeratorList) for e2_eval in e2_elist.enumerators: self.assertIsInstance(e2_eval, Enumerator) self.assertEqual(e2_elist.enumerators[0].name, "large") self.assertEqual(e2_elist.enumerators[0].value.value, "20") self.assertEqual(e2_elist.enumerators[2].name, "medium") self.assertEqual(e2_elist.enumerators[2].value, None) # enum with trailing comma (C99 feature) e3 = """ enum { red, blue, green, } color; """ e3_type = self.parse(e3).ext[0].type.type self.assertIsInstance(e3_type, Enum) e3_elist = e3_type.values self.assertIsInstance(e3_elist, EnumeratorList) for e3_eval in e3_elist.enumerators: self.assertIsInstance(e3_eval, Enumerator) self.assertEqual(e3_elist.enumerators[0].name, "red") self.assertEqual(e3_elist.enumerators[0].value, None) self.assertEqual(e3_elist.enumerators[1].name, "blue") self.assertEqual(e3_elist.enumerators[2].name, "green") def test_typedef(self): # without typedef, error s1 = """ node k; """ self.assertRaises(ParseError, self.parse, s1) # now with typedef, works s2 = """ typedef void* node; node k; """ ps2 = self.parse(s2) self.assertEqual( expand_decl(ps2.ext[0]), [ "Typedef", "node", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["void"]]]], ], ) self.assertEqual( expand_decl(ps2.ext[1]), ["Decl", "k", ["TypeDecl", ["IdentifierType", ["node"]]]], ) s3 = """ typedef int T; typedef T *pT; pT aa, bb; """ ps3 = self.parse(s3) self.assertEqual( expand_decl(ps3.ext[3]), ["Decl", "bb", ["TypeDecl", ["IdentifierType", ["pT"]]]], ) s4 = """ typedef char* __builtin_va_list; typedef __builtin_va_list __gnuc_va_list; """ ps4 = self.parse(s4) self.assertEqual( expand_decl(ps4.ext[1]), [ "Typedef", "__gnuc_va_list", ["TypeDecl", ["IdentifierType", ["__builtin_va_list"]]], ], ) s5 = """typedef struct tagHash Hash;""" ps5 = self.parse(s5) self.assertEqual( expand_decl(ps5.ext[0]), ["Typedef", "Hash", ["TypeDecl", ["Struct", "tagHash", []]]], ) s6 = """typedef int (* const * const T)(void);""" ps6 = self.parse(s6) self.assertEqual( expand_decl(ps6.ext[0]), [ "Typedef", "T", [ "PtrDecl", ["const"], [ "PtrDecl", ["const"], [ "FuncDecl", [["Typename", ["TypeDecl", ["IdentifierType", ["void"]]]]], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ], ) def test_struct_union(self): s1 = """ struct { int id; char* name; } joe; """ self.assertEqual( expand_decl(self.parse(s1).ext[0]), [ "Decl", "joe", [ "TypeDecl", [ "Struct", None, [ ["Decl", "id", ["TypeDecl", ["IdentifierType", ["int"]]]], [ "Decl", "name", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]], ], ], ], ], ], ) s2 = """ struct node p; """ self.assertEqual( expand_decl(self.parse(s2).ext[0]), ["Decl", "p", ["TypeDecl", ["Struct", "node", []]]], ) s21 = """ union pri ra; """ self.assertEqual( expand_decl(self.parse(s21).ext[0]), ["Decl", "ra", ["TypeDecl", ["Union", "pri", []]]], ) s3 = """ struct node* p; """ self.assertEqual( expand_decl(self.parse(s3).ext[0]), ["Decl", "p", ["PtrDecl", ["TypeDecl", ["Struct", "node", []]]]], ) s4 = """ struct node; """ self.assertEqual( expand_decl(self.parse(s4).ext[0]), ["Decl", None, ["Struct", "node", []]] ) s5 = """ union { struct { int type; } n; struct { int type; int intnode; } ni; } u; """ self.assertEqual( expand_decl(self.parse(s5).ext[0]), [ "Decl", "u", [ "TypeDecl", [ "Union", None, [ [ "Decl", "n", [ "TypeDecl", [ "Struct", None, [ [ "Decl", "type", [ "TypeDecl", ["IdentifierType", ["int"]], ], ] ], ], ], ], [ "Decl", "ni", [ "TypeDecl", [ "Struct", None, [ [ "Decl", "type", [ "TypeDecl", ["IdentifierType", ["int"]], ], ], [ "Decl", "intnode", [ "TypeDecl", ["IdentifierType", ["int"]], ], ], ], ], ], ], ], ], ], ], ) s6 = """ typedef struct foo_tag { void* data; } foo, *pfoo; """ s6_ast = self.parse(s6) self.assertEqual( expand_decl(s6_ast.ext[0]), [ "Typedef", "foo", [ "TypeDecl", [ "Struct", "foo_tag", [ [ "Decl", "data", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["void"]]]], ] ], ], ], ], ) self.assertEqual( expand_decl(s6_ast.ext[1]), [ "Typedef", "pfoo", [ "PtrDecl", [ "TypeDecl", [ "Struct", "foo_tag", [ [ "Decl", "data", [ "PtrDecl", ["TypeDecl", ["IdentifierType", ["void"]]], ], ] ], ], ], ], ], ) s7 = r""" struct _on_exit_args { void * _fnargs[32]; void * _dso_handle[32]; long _fntypes; #line 77 "D:\eli\cpp_stuff\libc_include/sys/reent.h" long _is_cxa; }; """ s7_ast = self.parse(s7, filename="test.c") self.assert_coord(s7_ast.ext[0].type.decls[2], 6, 22, "test.c") self.assert_coord( s7_ast.ext[0].type.decls[3], 78, 22, r"D:\eli\cpp_stuff\libc_include/sys/reent.h", ) s8 = """ typedef enum tagReturnCode {SUCCESS, FAIL} ReturnCode; typedef struct tagEntry { char* key; char* value; } Entry; typedef struct tagNode { Entry* entry; struct tagNode* next; } Node; typedef struct tagHash { unsigned int table_size; Node** heads; } Hash; """ s8_ast = self.parse(s8) self.assertEqual( expand_decl(s8_ast.ext[3]), [ "Typedef", "Hash", [ "TypeDecl", [ "Struct", "tagHash", [ [ "Decl", "table_size", ["TypeDecl", ["IdentifierType", ["unsigned", "int"]]], ], [ "Decl", "heads", [ "PtrDecl", [ "PtrDecl", ["TypeDecl", ["IdentifierType", ["Node"]]], ], ], ], ], ], ], ], ) def test_struct_enum(self): s1 = """ struct Foo { enum Bar { A = 1 }; }; """ self.assertEqual( expand_decl(self.parse(s1).ext[0]), ["Decl", None, ["Struct", "Foo", [["Decl", None, ["Enum", "Bar", ["A"]]]]]], ) s2 = """ struct Foo { enum Bar { A = 1, B, C } bar; enum Baz { D = A } baz; } foo; """ self.assertEqual( expand_decl(self.parse(s2).ext[0]), [ "Decl", "foo", [ "TypeDecl", [ "Struct", "Foo", [ [ "Decl", "bar", ["TypeDecl", ["Enum", "Bar", ["A", "B", "C"]]], ], ["Decl", "baz", ["TypeDecl", ["Enum", "Baz", ["D"]]]], ], ], ], ], ) def test_struct_with_extra_semis_inside(self): s1 = """ struct { int a;; } foo; """ s1_ast = self.parse(s1) self.assertEqual( expand_decl(s1_ast.ext[0]), [ "Decl", "foo", [ "TypeDecl", [ "Struct", None, [["Decl", "a", ["TypeDecl", ["IdentifierType", ["int"]]]]], ], ], ], ) s2 = """ struct { int a;;;; float b, c; ;; char d; } foo; """ s2_ast = self.parse(s2) self.assertEqual( expand_decl(s2_ast.ext[0]), [ "Decl", "foo", [ "TypeDecl", [ "Struct", None, [ ["Decl", "a", ["TypeDecl", ["IdentifierType", ["int"]]]], ["Decl", "b", ["TypeDecl", ["IdentifierType", ["float"]]]], ["Decl", "c", ["TypeDecl", ["IdentifierType", ["float"]]]], ["Decl", "d", ["TypeDecl", ["IdentifierType", ["char"]]]], ], ], ], ], ) def test_struct_with_initial_semi(self): s1 = """ struct { ;int a; } foo; """ s1_ast = self.parse(s1) self.assertEqual( expand_decl(s1_ast.ext[0]), [ "Decl", "foo", [ "TypeDecl", [ "Struct", None, [["Decl", "a", ["TypeDecl", ["IdentifierType", ["int"]]]]], ], ], ], ) def test_anonymous_struct_union(self): s1 = """ union { union { int i; long l; }; struct { int type; int intnode; }; } u; """ self.assertEqual( expand_decl(self.parse(s1).ext[0]), [ "Decl", "u", [ "TypeDecl", [ "Union", None, [ [ "Decl", None, [ "Union", None, [ [ "Decl", "i", ["TypeDecl", ["IdentifierType", ["int"]]], ], [ "Decl", "l", ["TypeDecl", ["IdentifierType", ["long"]]], ], ], ], ], [ "Decl", None, [ "Struct", None, [ [ "Decl", "type", ["TypeDecl", ["IdentifierType", ["int"]]], ], [ "Decl", "intnode", ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ], ], ], ], ], ) s2 = """ struct { int i; union { int id; char* name; }; float f; } joe; """ self.assertEqual( expand_decl(self.parse(s2).ext[0]), [ "Decl", "joe", [ "TypeDecl", [ "Struct", None, [ ["Decl", "i", ["TypeDecl", ["IdentifierType", ["int"]]]], [ "Decl", None, [ "Union", None, [ [ "Decl", "id", ["TypeDecl", ["IdentifierType", ["int"]]], ], [ "Decl", "name", [ "PtrDecl", [ "TypeDecl", ["IdentifierType", ["char"]], ], ], ], ], ], ], ["Decl", "f", ["TypeDecl", ["IdentifierType", ["float"]]]], ], ], ], ], ) # ISO/IEC 9899:201x Committee Draft 2010-11-16, N1539 # section 6.7.2.1, par. 19, example 1 s3 = """ struct v { union { struct { int i, j; }; struct { long k, l; } w; }; int m; } v1; """ self.assertEqual( expand_decl(self.parse(s3).ext[0]), [ "Decl", "v1", [ "TypeDecl", [ "Struct", "v", [ [ "Decl", None, [ "Union", None, [ [ "Decl", None, [ "Struct", None, [ [ "Decl", "i", [ "TypeDecl", ["IdentifierType", ["int"]], ], ], [ "Decl", "j", [ "TypeDecl", ["IdentifierType", ["int"]], ], ], ], ], ], [ "Decl", "w", [ "TypeDecl", [ "Struct", None, [ [ "Decl", "k", [ "TypeDecl", [ "IdentifierType", ["long"], ], ], ], [ "Decl", "l", [ "TypeDecl", [ "IdentifierType", ["long"], ], ], ], ], ], ], ], ], ], ], ["Decl", "m", ["TypeDecl", ["IdentifierType", ["int"]]]], ], ], ], ], ) s4 = """ struct v { int i; float; } v2;""" # just make sure this doesn't raise ParseError self.parse(s4) def test_struct_members_namespace(self): """Tests that structure/union member names reside in a separate namespace and can be named after existing types. """ s1 = """ typedef int Name; typedef Name NameArray[10]; struct { Name Name; Name NameArray[3]; } sye; void main(void) { sye.Name = 1; } """ s1_ast = self.parse(s1) self.assertEqual( expand_decl(s1_ast.ext[2]), [ "Decl", "sye", [ "TypeDecl", [ "Struct", None, [ [ "Decl", "Name", ["TypeDecl", ["IdentifierType", ["Name"]]], ], [ "Decl", "NameArray", [ "ArrayDecl", "3", [], ["TypeDecl", ["IdentifierType", ["Name"]]], ], ], ], ], ], ], ) self.assertEqual(s1_ast.ext[3].body.block_items[0].lvalue.field.name, "Name") def test_struct_bitfields(self): # a struct with two bitfields, one unnamed s1 = """ struct { int k:6; int :2; } joe; """ parsed_struct = self.parse(s1).ext[0] # We can see here the name of the decl for the unnamed bitfield is # None, but expand_decl doesn't show bitfield widths # ... self.assertEqual( expand_decl(parsed_struct), [ "Decl", "joe", [ "TypeDecl", [ "Struct", None, [ ["Decl", "k", ["TypeDecl", ["IdentifierType", ["int"]]]], ["Decl", None, ["TypeDecl", ["IdentifierType", ["int"]]]], ], ], ], ], ) # ... # so we test them manually self.assertEqual(parsed_struct.type.type.decls[0].bitsize.value, "6") self.assertEqual(parsed_struct.type.type.decls[1].bitsize.value, "2") def test_struct_empty(self): """ Tests that parsing an empty struct works. Empty structs do NOT follow C99 (See 6.2.5-20 of the C99 standard). This is nevertheless supported by some compilers (clang, gcc), especially when using FORTIFY code. Some compilers (visual) will fail to compile with an error. """ # an empty struct. This is NOT C99 compliant s1 = """ struct foo { }; """ parsed_struct = self.parse(s1).ext[0] self.assertEqual( expand_decl(parsed_struct), ["Decl", None, ["Struct", "foo", []]] ) s2 = """struct { } foo;""" parsed_struct = self.parse(s2).ext[0] self.assertEqual( expand_decl(parsed_struct), ["Decl", "foo", ["TypeDecl", ["Struct", None, []]]], ) s3 = """union { } foo;""" parsed_struct = self.parse(s3).ext[0] self.assertEqual( expand_decl(parsed_struct), ["Decl", "foo", ["TypeDecl", ["Union", None, []]]], ) def test_tags_namespace(self): """Tests that the tags of structs/unions/enums reside in a separate namespace and can be named after existing types. """ s1 = """ typedef int tagEntry; struct tagEntry { char* key; char* value; } Entry; """ s1_ast = self.parse(s1) self.assertEqual( expand_decl(s1_ast.ext[1]), [ "Decl", "Entry", [ "TypeDecl", [ "Struct", "tagEntry", [ [ "Decl", "key", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]], ], [ "Decl", "value", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]], ], ], ], ], ], ) s2 = """ struct tagEntry; typedef struct tagEntry tagEntry; struct tagEntry { char* key; char* value; } Entry; """ s2_ast = self.parse(s2) self.assertEqual( expand_decl(s2_ast.ext[2]), [ "Decl", "Entry", [ "TypeDecl", [ "Struct", "tagEntry", [ [ "Decl", "key", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]], ], [ "Decl", "value", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]], ], ], ], ], ], ) s3 = """ typedef int mytag; enum mytag {ABC, CDE}; enum mytag joe; """ s3_type = self.parse(s3).ext[1].type self.assertIsInstance(s3_type, Enum) self.assertEqual(s3_type.name, "mytag") def test_multi_decls(self): d1 = "int a, b;" self.assertEqual( self.get_decl(d1, 0), ["Decl", "a", ["TypeDecl", ["IdentifierType", ["int"]]]], ) self.assertEqual( self.get_decl(d1, 1), ["Decl", "b", ["TypeDecl", ["IdentifierType", ["int"]]]], ) d2 = "char* p, notp, ar[4];" self.assertEqual( self.get_decl(d2, 0), ["Decl", "p", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]]], ) self.assertEqual( self.get_decl(d2, 1), ["Decl", "notp", ["TypeDecl", ["IdentifierType", ["char"]]]], ) self.assertEqual( self.get_decl(d2, 2), [ "Decl", "ar", ["ArrayDecl", "4", [], ["TypeDecl", ["IdentifierType", ["char"]]]], ], ) def test_invalid_multiple_types_error(self): bad = ["int enum {ab, cd} fubr;", "enum kid char brbr;"] for b in bad: self.assertRaises(ParseError, self.parse, b) def test_invalid_typedef_storage_qual_error(self): """Tests that using typedef as a storage qualifier is correctly flagged as an error. """ bad = "typedef const int foo(int a) { return 0; }" self.assertRaises(ParseError, self.parse, bad) def test_duplicate_typedef(self): """Tests that redeclarations of existing types are parsed correctly. This is non-standard, but allowed by many compilers. """ d1 = """ typedef int numbertype; typedef int numbertype; """ self.assertEqual( self.get_decl(d1, 0), ["Typedef", "numbertype", ["TypeDecl", ["IdentifierType", ["int"]]]], ) self.assertEqual( self.get_decl(d1, 1), ["Typedef", "numbertype", ["TypeDecl", ["IdentifierType", ["int"]]]], ) d2 = """ typedef int (*funcptr)(int x); typedef int (*funcptr)(int x); """ self.assertEqual( self.get_decl(d2, 0), [ "Typedef", "funcptr", [ "PtrDecl", [ "FuncDecl", [["Decl", "x", ["TypeDecl", ["IdentifierType", ["int"]]]]], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ) self.assertEqual( self.get_decl(d2, 1), [ "Typedef", "funcptr", [ "PtrDecl", [ "FuncDecl", [["Decl", "x", ["TypeDecl", ["IdentifierType", ["int"]]]]], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ], ) d3 = """ typedef int numberarray[5]; typedef int numberarray[5]; """ self.assertEqual( self.get_decl(d3, 0), [ "Typedef", "numberarray", ["ArrayDecl", "5", [], ["TypeDecl", ["IdentifierType", ["int"]]]], ], ) self.assertEqual( self.get_decl(d3, 1), [ "Typedef", "numberarray", ["ArrayDecl", "5", [], ["TypeDecl", ["IdentifierType", ["int"]]]], ], ) def test_decl_inits(self): d1 = "int a = 16;" # ~ self.parse(d1).show() self.assertEqual( self.get_decl(d1), ["Decl", "a", ["TypeDecl", ["IdentifierType", ["int"]]]] ) self.assertEqual(self.get_decl_init(d1), ["Constant", "int", "16"]) d1_1 = "float f = 0xEF.56p1;" self.assertEqual(self.get_decl_init(d1_1), ["Constant", "double", "0xEF.56p1"]) d1_2 = "int bitmask = 0b1001010;" self.assertEqual(self.get_decl_init(d1_2), ["Constant", "int", "0b1001010"]) d2 = "long ar[] = {7, 8, 9};" self.assertEqual( self.get_decl(d2), [ "Decl", "ar", ["ArrayDecl", "", [], ["TypeDecl", ["IdentifierType", ["long"]]]], ], ) self.assertEqual( self.get_decl_init(d2), [ ["Constant", "int", "7"], ["Constant", "int", "8"], ["Constant", "int", "9"], ], ) d21 = "long ar[4] = {};" self.assertEqual(self.get_decl_init(d21), []) d3 = "char p = j;" self.assertEqual( self.get_decl(d3), ["Decl", "p", ["TypeDecl", ["IdentifierType", ["char"]]]] ) self.assertEqual(self.get_decl_init(d3), ["ID", "j"]) d4 = "char x = 'c', *p = {0, 1, 2, {4, 5}, 6};" self.assertEqual( self.get_decl(d4, 0), ["Decl", "x", ["TypeDecl", ["IdentifierType", ["char"]]]], ) self.assertEqual(self.get_decl_init(d4, 0), ["Constant", "char", "'c'"]) self.assertEqual( self.get_decl(d4, 1), ["Decl", "p", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]]], ) self.assertEqual( self.get_decl_init(d4, 1), [ ["Constant", "int", "0"], ["Constant", "int", "1"], ["Constant", "int", "2"], [["Constant", "int", "4"], ["Constant", "int", "5"]], ["Constant", "int", "6"], ], ) d5 = "float d = 1.0;" self.assertEqual(self.get_decl_init(d5), ["Constant", "double", "1.0"]) d51 = "float ld = 1.0l;" self.assertEqual(self.get_decl_init(d51), ["Constant", "long double", "1.0l"]) d52 = "float ld = 1.0L;" self.assertEqual(self.get_decl_init(d52), ["Constant", "long double", "1.0L"]) d53 = "float ld = 1.0f;" self.assertEqual(self.get_decl_init(d53), ["Constant", "float", "1.0f"]) d54 = "float ld = 1.0F;" self.assertEqual(self.get_decl_init(d54), ["Constant", "float", "1.0F"]) d55 = "float ld = 0xDE.38p0;" self.assertEqual(self.get_decl_init(d55), ["Constant", "double", "0xDE.38p0"]) d56 = "float ld = 0xDE.38p0f;" self.assertEqual(self.get_decl_init(d56), ["Constant", "float", "0xDE.38p0f"]) d57 = "float ld = 0xDE.38p0F;" self.assertEqual(self.get_decl_init(d57), ["Constant", "float", "0xDE.38p0F"]) d58 = "float ld = 0xDE.38p0l;" self.assertEqual( self.get_decl_init(d58), ["Constant", "long double", "0xDE.38p0l"] ) d59 = "float ld = 0xDE.38p0L;" self.assertEqual( self.get_decl_init(d59), ["Constant", "long double", "0xDE.38p0L"] ) d6 = "int i = 1;" self.assertEqual(self.get_decl_init(d6), ["Constant", "int", "1"]) d61 = "long int li = 1l;" self.assertEqual(self.get_decl_init(d61), ["Constant", "long int", "1l"]) d62 = "unsigned int ui = 1u;" self.assertEqual(self.get_decl_init(d62), ["Constant", "unsigned int", "1u"]) d63 = "unsigned long long int ulli = 1LLU;" self.assertEqual( self.get_decl_init(d63), ["Constant", "unsigned long long int", "1LLU"] ) def test_decl_named_inits(self): d1 = "int a = {.k = 16};" self.assertEqual( self.get_decl_init(d1), [([["ID", "k"]], ["Constant", "int", "16"])] ) d2 = "int a = { [0].a = {1}, [1].a[0] = 2 };" self.assertEqual( self.get_decl_init(d2), [ ([["Constant", "int", "0"], ["ID", "a"]], [["Constant", "int", "1"]]), ( [["Constant", "int", "1"], ["ID", "a"], ["Constant", "int", "0"]], ["Constant", "int", "2"], ), ], ) d3 = "int a = { .a = 1, .c = 3, 4, .b = 5};" self.assertEqual( self.get_decl_init(d3), [ ([["ID", "a"]], ["Constant", "int", "1"]), ([["ID", "c"]], ["Constant", "int", "3"]), ["Constant", "int", "4"], ([["ID", "b"]], ["Constant", "int", "5"]), ], ) def test_function_definitions(self): def parse_fdef(str): return self.parse(str).ext[0] def fdef_decl(fdef): return expand_decl(fdef.decl) f1 = parse_fdef(""" int factorial(int p) { return 3; } """) self.assertEqual( fdef_decl(f1), [ "Decl", "factorial", [ "FuncDecl", [["Decl", "p", ["TypeDecl", ["IdentifierType", ["int"]]]]], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) self.assertEqual(type(f1.body.block_items[0]), Return) f2 = parse_fdef(""" char* zzz(int p, char* c) { int a; char b; a = b + 2; return 3; } """) self.assertEqual( fdef_decl(f2), [ "Decl", "zzz", [ "FuncDecl", [ ["Decl", "p", ["TypeDecl", ["IdentifierType", ["int"]]]], [ "Decl", "c", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]], ], ], ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]], ], ], ) self.assertEqual( list(map(type, f2.body.block_items)), [Decl, Decl, Assignment, Return] ) f3 = parse_fdef(""" char* zzz(p, c) long p, *c; { int a; char b; a = b + 2; return 3; } """) self.assertEqual( fdef_decl(f3), [ "Decl", "zzz", [ "FuncDecl", [["ID", "p"], ["ID", "c"]], ["PtrDecl", ["TypeDecl", ["IdentifierType", ["char"]]]], ], ], ) self.assertEqual( list(map(type, f3.body.block_items)), [Decl, Decl, Assignment, Return] ) self.assertEqual( expand_decl(f3.param_decls[0]), ["Decl", "p", ["TypeDecl", ["IdentifierType", ["long"]]]], ) self.assertEqual( expand_decl(f3.param_decls[1]), ["Decl", "c", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["long"]]]]], ) # function return values and parameters may not have type information f4 = parse_fdef(""" que(p) { return 3; } """) self.assertEqual( fdef_decl(f4), [ "Decl", "que", ["FuncDecl", [["ID", "p"]], ["TypeDecl", ["IdentifierType", ["int"]]]], ], ) def test_static_assert(self): f1 = self.parse(""" _Static_assert(1, "123"); int factorial(int p) { _Static_assert(2, "456"); _Static_assert(3); } """) self.assertEqual(expand_decl(f1.ext[0]), ["StaticAssert", "1", '"123"']) self.assertEqual( expand_decl(f1.ext[1].body.block_items[0]), ["StaticAssert", "2", '"456"'] ) self.assertEqual( expand_decl(f1.ext[1].body.block_items[2]), ["StaticAssert", "3"] ) def test_unified_string_literals(self): # simple string, for reference d1 = self.get_decl_init('char* s = "hello";') self.assertEqual(d1, ["Constant", "string", '"hello"']) d2 = self.get_decl_init('char* s = "hello" " world";') self.assertEqual(d2, ["Constant", "string", '"hello world"']) # the test case from issue 6 d3 = self.parse(r""" int main() { fprintf(stderr, "Wrong Params?\n" "Usage:\n" "%s \n", argv[0] ); } """) self.assertEqual( d3.ext[0].body.block_items[0].args.exprs[1].value, r'"Wrong Params?\nUsage:\n%s \n"', ) d4 = self.get_decl_init('char* s = "" "foobar";') self.assertEqual(d4, ["Constant", "string", '"foobar"']) d5 = self.get_decl_init(r'char* s = "foo\"" "bar";') self.assertEqual(d5, ["Constant", "string", r'"foo\"bar"']) # This is not correct based on the the C spec, but testing it here to # see the behavior in action. Will have to fix this # for https://github.com/eliben/pycparser/issues/392 # # The spec says in section 6.4.5 that "escape sequences are converted # into single members of the execution character set just prior to # adjacent string literal concatenation". d6 = self.get_decl_init(r'char* s = "\1" "23";') self.assertEqual(d6, ["Constant", "string", r'"\123"']) def test_unified_wstring_literals(self): d1 = self.get_decl_init('char* s = L"hello" L"world";') self.assertEqual(d1, ["Constant", "string", 'L"helloworld"']) d2 = self.get_decl_init('char* s = L"hello " L"world" L" and I";') self.assertEqual(d2, ["Constant", "string", 'L"hello world and I"']) def test_inline_specifier(self): ps2 = self.parse("static inline void inlinefoo(void);") self.assertEqual(ps2.ext[0].funcspec, ["inline"]) def test_noreturn_specifier(self): ps2 = self.parse("static _Noreturn void noreturnfoo(void);") self.assertEqual(ps2.ext[0].funcspec, ["_Noreturn"]) # variable length array def test_vla(self): ps2 = self.parse(r""" int main() { int size; int var[size = 5]; int var2[*]; } """) self.assertIsInstance(ps2.ext[0].body.block_items[1].type.dim, Assignment) self.assertIsInstance(ps2.ext[0].body.block_items[2].type.dim, ID) def test_pragma(self): s1 = r""" #pragma bar void main() { #pragma foo for(;;) {} #pragma baz { int i = 0; } #pragma } struct s { #pragma baz } s; _Pragma("other \"string\"") """ s1_ast = self.parse(s1) self.assertIsInstance(s1_ast.ext[0], Pragma) self.assertEqual(s1_ast.ext[0].string, "bar") self.assertEqual(s1_ast.ext[0].coord.line, 2) self.assertIsInstance(s1_ast.ext[1].body.block_items[0], Pragma) self.assertEqual(s1_ast.ext[1].body.block_items[0].string, "foo") self.assertEqual(s1_ast.ext[1].body.block_items[0].coord.line, 4) self.assertIsInstance(s1_ast.ext[1].body.block_items[2], Pragma) self.assertEqual(s1_ast.ext[1].body.block_items[2].string, "baz") self.assertEqual(s1_ast.ext[1].body.block_items[2].coord.line, 6) self.assertIsInstance(s1_ast.ext[1].body.block_items[4], Pragma) self.assertEqual(s1_ast.ext[1].body.block_items[4].string, "") self.assertEqual(s1_ast.ext[1].body.block_items[4].coord.line, 10) self.assertIsInstance(s1_ast.ext[2].type.type.decls[0], Pragma) 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() { int sum = 0; for (int i; i < 3; i++) #pragma omp critical sum += 1; while(sum < 10) #pragma omp critical sum += 1; mylabel: #pragma foo sum += 10; if (sum > 10) #pragma bar #pragma baz sum = 10; switch (sum) case 10: #pragma foo sum = 20; } """ s1_ast = self.parse(s1) self.assertIsInstance(s1_ast.ext[0].body.block_items[1], For) self.assertIsInstance(s1_ast.ext[0].body.block_items[1].stmt, Compound) self.assertIsInstance( s1_ast.ext[0].body.block_items[1].stmt.block_items[0], Pragma ) self.assertIsInstance( s1_ast.ext[0].body.block_items[1].stmt.block_items[1], Assignment ) self.assertIsInstance(s1_ast.ext[0].body.block_items[2], While) self.assertIsInstance(s1_ast.ext[0].body.block_items[2].stmt, Compound) self.assertIsInstance( s1_ast.ext[0].body.block_items[2].stmt.block_items[0], Pragma ) self.assertIsInstance( s1_ast.ext[0].body.block_items[2].stmt.block_items[1], Assignment ) self.assertIsInstance(s1_ast.ext[0].body.block_items[3], Label) self.assertIsInstance(s1_ast.ext[0].body.block_items[3].stmt, Compound) self.assertIsInstance( s1_ast.ext[0].body.block_items[3].stmt.block_items[0], Pragma ) self.assertIsInstance( s1_ast.ext[0].body.block_items[3].stmt.block_items[1], Assignment ) self.assertIsInstance(s1_ast.ext[0].body.block_items[4], If) self.assertIsInstance(s1_ast.ext[0].body.block_items[4].iftrue, Compound) self.assertIsInstance( s1_ast.ext[0].body.block_items[4].iftrue.block_items[0], Pragma ) self.assertIsInstance( s1_ast.ext[0].body.block_items[4].iftrue.block_items[1], Pragma ) self.assertIsInstance( s1_ast.ext[0].body.block_items[4].iftrue.block_items[2], Assignment ) self.assertIsInstance(s1_ast.ext[0].body.block_items[5], Switch) self.assertIsInstance(s1_ast.ext[0].body.block_items[5].stmt.stmts[0], Compound) self.assertIsInstance( s1_ast.ext[0].body.block_items[5].stmt.stmts[0].block_items[0], Pragma ) self.assertIsInstance( s1_ast.ext[0].body.block_items[5].stmt.stmts[0].block_items[1], Assignment ) class TestCParser_whole_code(TestCParser_base): """Testing of parsing whole chunks of code. Since I don't want to rely on the structure of ASTs too much, most of these tests are implemented with visitors. """ # A simple helper visitor that lists the values of all the # Constant nodes it sees. # class ConstantVisitor(NodeVisitor): def __init__(self): self.values = [] def visit_Constant(self, node): self.values.append(node.value) # This visitor counts the amount of references to the ID # with the name provided to it in the constructor. # class IDNameCounter(NodeVisitor): def __init__(self, name): self.name = name self.nrefs = 0 def visit_ID(self, node): if node.name == self.name: self.nrefs += 1 # Counts the amount of nodes of a given class # class NodeKlassCounter(NodeVisitor): def __init__(self, node_klass): self.klass = node_klass self.n = 0 def generic_visit(self, node): if node.__class__ == self.klass: self.n += 1 NodeVisitor.generic_visit(self, node) def assert_all_Constants(self, code, constants): """Asserts that the list of all Constant values (by 'preorder' appearance) in the chunk of code is as given. """ if isinstance(code, str): parsed = self.parse(code) else: parsed = code cv = self.ConstantVisitor() cv.visit(parsed) self.assertEqual(cv.values, constants) def assert_num_ID_refs(self, code, name, num): """Asserts the number of references to the ID with the given name. """ if isinstance(code, str): parsed = self.parse(code) else: parsed = code iv = self.IDNameCounter(name) iv.visit(parsed) self.assertEqual(iv.nrefs, num) def assert_num_klass_nodes(self, code, klass, num): """Asserts the amount of klass nodes in the code.""" if isinstance(code, str): parsed = self.parse(code) else: parsed = code cv = self.NodeKlassCounter(klass) cv.visit(parsed) self.assertEqual(cv.n, num) def test_expressions(self): e1 = """int k = (r + 10.0) >> 6 + 8 << (3 & 0x14);""" self.assert_all_Constants(e1, ["10.0", "6", "8", "3", "0x14"]) e2 = r"""char n = '\n', *prefix = "st_";""" self.assert_all_Constants(e2, [r"'\n'", '"st_"']) s1 = r"""int main() { int i = 5, j = 6, k = 1; if ((i=j && k == 1) || k > j) printf("Hello, world\n"); return 0; }""" ps1 = self.parse(s1) self.assert_all_Constants(ps1, ["5", "6", "1", "1", '"Hello, world\\n"', "0"]) self.assert_num_ID_refs(ps1, "i", 1) self.assert_num_ID_refs(ps1, "j", 2) def test_statements(self): s1 = r""" void foo(){ if (sp == 1) if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') return -1; else if (strcmp(argv[optind], "--") == 0) { optind++; return -1; } } """ self.assert_all_Constants( s1, ["1", "0", r"'-'", "1", r"'\0'", "1", r'"--"', "0", "1"] ) ps1 = self.parse(s1) self.assert_num_ID_refs(ps1, "argv", 3) self.assert_num_ID_refs(ps1, "optind", 5) self.assert_num_klass_nodes(ps1, If, 3) self.assert_num_klass_nodes(ps1, Return, 2) self.assert_num_klass_nodes(ps1, FuncCall, 1) # strcmp self.assert_num_klass_nodes(ps1, BinaryOp, 7) # In the following code, Hash and Node were defined as # int to pacify the parser that sees they're used as # types # s2 = r""" typedef int Hash, Node; void HashDestroy(Hash* hash) { unsigned int i; if (hash == NULL) return; for (i = 0; i < hash->table_size; ++i) { Node* temp = hash->heads[i]; while (temp != NULL) { Node* temp2 = temp; free(temp->entry->key); free(temp->entry->value); free(temp->entry); temp = temp->next; free(temp2); } } free(hash->heads); hash->heads = NULL; free(hash); } """ ps2 = self.parse(s2) self.assert_num_klass_nodes(ps2, FuncCall, 6) self.assert_num_klass_nodes(ps2, FuncDef, 1) self.assert_num_klass_nodes(ps2, For, 1) self.assert_num_klass_nodes(ps2, While, 1) self.assert_num_klass_nodes(ps2, StructRef, 10) # declarations don't count self.assert_num_ID_refs(ps2, "hash", 6) self.assert_num_ID_refs(ps2, "i", 4) s3 = r""" void x(void) { int a, b; if (a < b) do { a = 0; } while (0); else if (a == b) { a = 1; } } """ ps3 = self.parse(s3) self.assert_num_klass_nodes(ps3, DoWhile, 1) self.assert_num_ID_refs(ps3, "a", 4) self.assert_all_Constants(ps3, ["0", "0", "1"]) def test_empty_statements(self): s1 = r""" void foo(void){ ; return;; ; } """ ps1 = self.parse(s1) self.assert_num_klass_nodes(ps1, EmptyStatement, 3) self.assert_num_klass_nodes(ps1, Return, 1) self.assert_coord(ps1.ext[0].body.block_items[0], 3) self.assert_coord(ps1.ext[0].body.block_items[1], 4) self.assert_coord(ps1.ext[0].body.block_items[2], 4) self.assert_coord(ps1.ext[0].body.block_items[3], 6) def test_switch_statement(self): def assert_case_node(node, const_value): self.assertIsInstance(node, Case) self.assertIsInstance(node.expr, Constant) self.assertEqual(node.expr.value, const_value) def assert_default_node(node): self.assertIsInstance(node, Default) s1 = r""" int foo(void) { switch (myvar) { case 10: k = 10; p = k + 1; return 10; case 20: case 30: return 20; default: break; } return 0; } """ ps1 = self.parse(s1) switch = ps1.ext[0].body.block_items[0] block = switch.stmt.block_items self.assertEqual(len(block), 4) assert_case_node(block[0], "10") self.assertEqual(len(block[0].stmts), 3) assert_case_node(block[1], "20") self.assertEqual(len(block[1].stmts), 0) assert_case_node(block[2], "30") self.assertEqual(len(block[2].stmts), 1) assert_default_node(block[3]) s2 = r""" int foo(void) { switch (myvar) { default: joe = moe; return 10; case 10: case 20: case 30: case 40: break; } return 0; } """ ps2 = self.parse(s2) switch = ps2.ext[0].body.block_items[0] block = switch.stmt.block_items self.assertEqual(len(block), 5) assert_default_node(block[0]) self.assertEqual(len(block[0].stmts), 2) assert_case_node(block[1], "10") self.assertEqual(len(block[1].stmts), 0) assert_case_node(block[2], "20") self.assertEqual(len(block[1].stmts), 0) assert_case_node(block[3], "30") self.assertEqual(len(block[1].stmts), 0) assert_case_node(block[4], "40") self.assertEqual(len(block[4].stmts), 1) s3 = r""" int foo(void) { switch (myvar) { } return 0; } """ ps3 = self.parse(s3) switch = ps3.ext[0].body.block_items[0] self.assertEqual(switch.stmt.block_items, []) def test_for_statement(self): s2 = r""" void x(void) { int i; for (i = 0; i < 5; ++i) { x = 50; } } """ ps2 = self.parse(s2) self.assert_num_klass_nodes(ps2, For, 1) # here there are 3 refs to 'i' since the declaration doesn't count as # a ref in the visitor # self.assert_num_ID_refs(ps2, "i", 3) s3 = r""" void x(void) { for (int i = 0; i < 5; ++i) { x = 50; } } """ ps3 = self.parse(s3) self.assert_num_klass_nodes(ps3, For, 1) # here there are 2 refs to 'i' since the declaration doesn't count as # a ref in the visitor # self.assert_num_ID_refs(ps3, "i", 2) s4 = r""" void x(void) { for (int i = 0;;) i; } """ ps4 = self.parse(s4) self.assert_num_ID_refs(ps4, "i", 1) def _open_c_file(self, name): """Find a c file by name, taking into account the current dir can be in a couple of typical places """ testdir = os.path.dirname(__file__) name = os.path.join(testdir, "c_files", name) assert os.path.exists(name) return io.open(name) def test_whole_file(self): # See how pycparser handles a whole, real C file. # with self._open_c_file("memmgr_with_h.c") as f: code = f.read() p = self.parse(code) self.assert_num_klass_nodes(p, FuncDef, 5) # each FuncDef also has a FuncDecl. 4 declarations # + 5 definitions, overall 9 self.assert_num_klass_nodes(p, FuncDecl, 9) self.assert_num_klass_nodes(p, Typedef, 4) self.assertEqual(p.ext[4].coord.line, 88) self.assertEqual(p.ext[4].coord.file, "./memmgr.h") self.assertEqual(p.ext[6].coord.line, 10) self.assertEqual(p.ext[6].coord.file, "memmgr.c") def test_whole_file_with_stdio(self): # Parse a whole file with stdio.h included by cpp # with self._open_c_file("cppd_with_stdio_h.c") as f: code = f.read() p = self.parse(code) self.assertIsInstance(p.ext[0], Typedef) self.assertEqual(p.ext[0].coord.line, 213) self.assertEqual(p.ext[0].coord.file, r"D:\eli\cpp_stuff\libc_include/stddef.h") self.assertIsInstance(p.ext[-1], FuncDef) self.assertEqual(p.ext[-1].coord.line, 15) self.assertEqual(p.ext[-1].coord.file, "example_c_file.c") self.assertIsInstance(p.ext[-8], Typedef) self.assertIsInstance(p.ext[-8].type, TypeDecl) self.assertEqual(p.ext[-8].name, "cookie_io_functions_t") class TestCParser_typenames(TestCParser_base): """Test issues related to the typedef-name problem.""" def test_innerscope_typedef(self): # should fail since TT is not a type in bar s1 = r""" void foo() { typedef char TT; TT x; } void bar() { TT y; } """ self.assertRaises(ParseError, self.parse, s1) # should succeed since TT is not a type in bar s2 = r""" void foo() { typedef char TT; TT x; } void bar() { unsigned TT; } """ self.assertIsInstance(self.parse(s2), FileAST) def test_ambiguous_parameters(self): # From ISO/IEC 9899:TC2, 6.7.5.3.11: # "If, in a parameter declaration, an identifier can be treated either # as a typedef name or as a parameter name, it shall be taken as a # typedef name." # foo takes an int named aa # bar takes a function taking a TT s1 = r""" typedef char TT; int foo(int (aa)); int bar(int (TT)); """ s1_ast = self.parse(s1) self.assertEqual( expand_decl(s1_ast.ext[1].type.args.params[0]), ["Decl", "aa", ["TypeDecl", ["IdentifierType", ["int"]]]], ) self.assertEqual( expand_decl(s1_ast.ext[2].type.args.params[0]), [ "Typename", [ "FuncDecl", [["Typename", ["TypeDecl", ["IdentifierType", ["TT"]]]]], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) # foo takes a function taking a char # bar takes a function taking a function taking a char s2 = r""" typedef char TT; int foo(int (aa (char))); int bar(int (TT (char))); """ s2_ast = self.parse(s2) self.assertEqual( expand_decl(s2_ast.ext[1].type.args.params[0]), [ "Decl", "aa", [ "FuncDecl", [["Typename", ["TypeDecl", ["IdentifierType", ["char"]]]]], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) self.assertEqual( expand_decl(s2_ast.ext[2].type.args.params[0]), [ "Typename", [ "FuncDecl", [ [ "Typename", [ "FuncDecl", [ [ "Typename", ["TypeDecl", ["IdentifierType", ["char"]]], ] ], ["TypeDecl", ["IdentifierType", ["TT"]]], ], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) # foo takes an int array named aa # bar takes a function taking a TT array s3 = r""" typedef char TT; int foo(int (aa[])); int bar(int (TT[])); """ s3_ast = self.parse(s3) self.assertEqual( expand_decl(s3_ast.ext[1].type.args.params[0]), [ "Decl", "aa", ["ArrayDecl", "", [], ["TypeDecl", ["IdentifierType", ["int"]]]], ], ) self.assertEqual( expand_decl(s3_ast.ext[2].type.args.params[0]), [ "Typename", [ "FuncDecl", [ [ "Typename", [ "ArrayDecl", "", [], ["TypeDecl", ["IdentifierType", ["TT"]]], ], ] ], ["TypeDecl", ["IdentifierType", ["int"]]], ], ], ) def test_innerscope_reuse_typedef_name(self): # identifiers can be reused in inner scopes; the original should be # restored at the end of the block s1 = r""" typedef char TT; void foo(void) { unsigned TT; TT = 10; } TT x = 5; """ s1_ast = self.parse(s1) self.assertEqual( expand_decl(s1_ast.ext[1].body.block_items[0]), ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["unsigned"]]]], ) self.assertEqual( expand_decl(s1_ast.ext[2]), ["Decl", "x", ["TypeDecl", ["IdentifierType", ["TT"]]]], ) # this should be recognized even with an initializer s2 = r""" typedef char TT; void foo(void) { unsigned TT = 10; } """ s2_ast = self.parse(s2) self.assertEqual( expand_decl(s2_ast.ext[1].body.block_items[0]), ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["unsigned"]]]], ) # before the second local variable, TT is a type; after, it's a # variable s3 = r""" typedef char TT; void foo(void) { TT tt = sizeof(TT); unsigned TT = 10; } """ s3_ast = self.parse(s3) self.assertEqual( expand_decl(s3_ast.ext[1].body.block_items[0]), ["Decl", "tt", ["TypeDecl", ["IdentifierType", ["TT"]]]], ) self.assertEqual( expand_decl(s3_ast.ext[1].body.block_items[1]), ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["unsigned"]]]], ) # a variable and its type can even share the same name s4 = r""" typedef char TT; void foo(void) { TT TT = sizeof(TT); unsigned uu = TT * 2; } """ s4_ast = self.parse(s4) self.assertEqual( expand_decl(s4_ast.ext[1].body.block_items[0]), ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["TT"]]]], ) self.assertEqual( expand_decl(s4_ast.ext[1].body.block_items[1]), ["Decl", "uu", ["TypeDecl", ["IdentifierType", ["unsigned"]]]], ) # ensure an error is raised if a type, redeclared as a variable, is # used as a type s5 = r""" typedef char TT; void foo(void) { unsigned TT = 10; TT erroneous = 20; } """ self.assertRaises(ParseError, self.parse, s5) # reusing a type name should work with multiple declarators s6 = r""" typedef char TT; void foo(void) { unsigned TT, uu; } """ s6_ast = self.parse(s6) items = s6_ast.ext[1].body.block_items self.assertEqual( expand_decl(items[0]), ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["unsigned"]]]], ) self.assertEqual( expand_decl(items[1]), ["Decl", "uu", ["TypeDecl", ["IdentifierType", ["unsigned"]]]], ) # reusing a type name should work after a pointer s7 = r""" typedef char TT; void foo(void) { unsigned * TT; } """ s7_ast = self.parse(s7) items = s7_ast.ext[1].body.block_items self.assertEqual( expand_decl(items[0]), ["Decl", "TT", ["PtrDecl", ["TypeDecl", ["IdentifierType", ["unsigned"]]]]], ) # redefine a name in the middle of a multi-declarator declaration s8 = r""" typedef char TT; void foo(void) { int tt = sizeof(TT), TT, uu = sizeof(TT); int uu = sizeof(tt); } """ s8_ast = self.parse(s8) items = s8_ast.ext[1].body.block_items self.assertEqual( expand_decl(items[0]), ["Decl", "tt", ["TypeDecl", ["IdentifierType", ["int"]]]], ) self.assertEqual( expand_decl(items[1]), ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["int"]]]], ) self.assertEqual( expand_decl(items[2]), ["Decl", "uu", ["TypeDecl", ["IdentifierType", ["int"]]]], ) # Don't test this until we have support for it # self.assertEqual(expand_init(items[0].init), # ['UnaryOp', 'sizeof', ['Typename', ['TypeDecl', ['IdentifierType', ['TT']]]]]) # self.assertEqual(expand_init(items[2].init), # ['UnaryOp', 'sizeof', ['ID', 'TT']]) def test_parameter_reuse_typedef_name(self): # identifiers can be reused as parameter names; parameter name scope # begins and ends with the function body; it's important that TT is # used immediately before the LBRACE or after the RBRACE, to test # a corner case s1 = r""" typedef char TT; void foo(unsigned TT, TT bar) { TT = 10; } TT x = 5; """ s1_ast = self.parse(s1) self.assertEqual( expand_decl(s1_ast.ext[1].decl), [ "Decl", "foo", [ "FuncDecl", [ ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["unsigned"]]]], ["Decl", "bar", ["TypeDecl", ["IdentifierType", ["TT"]]]], ], ["TypeDecl", ["IdentifierType", ["void"]]], ], ], ) # the scope of a parameter name in a function declaration ends at the # end of the declaration...so it is effectively never used; it's # important that TT is used immediately after the declaration, to # test a corner case s2 = r""" typedef char TT; void foo(unsigned TT, TT bar); TT x = 5; """ s2_ast = self.parse(s2) self.assertEqual( expand_decl(s2_ast.ext[1]), [ "Decl", "foo", [ "FuncDecl", [ ["Decl", "TT", ["TypeDecl", ["IdentifierType", ["unsigned"]]]], ["Decl", "bar", ["TypeDecl", ["IdentifierType", ["TT"]]]], ], ["TypeDecl", ["IdentifierType", ["void"]]], ], ], ) # ensure an error is raised if a type, redeclared as a parameter, is # used as a type s3 = r""" typedef char TT; void foo(unsigned TT, TT bar) { TT erroneous = 20; } """ self.assertRaises(ParseError, self.parse, s3) def test_nested_function_decls(self): # parameter names of nested function declarations must not escape into # the top-level function _definition's_ scope; the following must # succeed because TT is still a typedef inside foo's body s1 = r""" typedef char TT; void foo(unsigned bar(int TT)) { TT x = 10; } """ self.assertIsInstance(self.parse(s1), FileAST) def test_samescope_reuse_name(self): # a typedef name cannot be reused as an object name in the same scope s1 = r""" typedef char TT; char TT = 5; """ self.assertRaises(ParseError, self.parse, s1) # ...and vice-versa s2 = r""" char TT = 5; typedef char TT; """ self.assertRaises(ParseError, self.parse, s2) def test_label_empty_statement(self): # Labels with empty statements and no semicolon should be parsed correctly s1 = r""" int main() { int i = 0; label0: i++; label1: } """ s1_ast: FileAST = self.parse(s1) self.assertIsInstance(s1_ast.ext[0].body.block_items[1], Label) self.assertIsInstance(s1_ast.ext[0].body.block_items[1].stmt, UnaryOp) self.assertIsInstance(s1_ast.ext[0].body.block_items[2], Label) self.assertIsInstance(s1_ast.ext[0].body.block_items[2].stmt, EmptyStatement) def test_case_empty_statement(self): # Labels with empty statements and no semicolon should be parsed correctly s1 = r""" int main() { int i = 0; switch (i) { case 0: i = 1; case 1: } return i; } """ s2 = r""" int main() { int i = 0; switch (i) { case 0: i = 1; default: } return i; } """ s1_ast: FileAST = self.parse(s1) s2_ast: FileAST = self.parse(s2) self.assertIsInstance(s1_ast.ext[0].body.block_items[1], Switch) self.assertIsInstance(s1_ast.ext[0].body.block_items[1].stmt, Compound) self.assertIsInstance( s1_ast.ext[0].body.block_items[1].stmt.block_items[0], Case ) self.assertIsInstance( s1_ast.ext[0].body.block_items[1].stmt.block_items[0].stmts[0], Assignment ) self.assertIsInstance( s1_ast.ext[0].body.block_items[1].stmt.block_items[1], Case ) self.assertIsInstance( s1_ast.ext[0].body.block_items[1].stmt.block_items[1].stmts[0], EmptyStatement, ) self.assertIsInstance( s2_ast.ext[0].body.block_items[1].stmt.block_items[1].stmts[0], EmptyStatement, ) if __name__ == "__main__": # ~ suite = unittest.TestLoader().loadTestsFromNames( # ~ ['test_c_parser.TestCParser_fundamentals.test_typedef']) # ~ unittest.TextTestRunner(verbosity=2).run(suite) unittest.main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/tests/test_examples.py0000664000175000017500000000171415134157072017305 0ustar00elibenelibenimport os import sys import unittest sys.path.insert(0, ".") from tests.test_util import run_exe, cpp_supported # Runs all pycparser examples with no command-line arguments and makes sure they # run successfully (return code = 0), without actually verifying their output. class TestExamplesSucceed(unittest.TestCase): @unittest.skipUnless(cpp_supported(), "cpp only works on Unix") def test_all_examples(self): root = "./examples" for filename in os.listdir(root): if os.path.splitext(filename)[1] == ".py": with self.subTest(name=filename): path = os.path.join(root, filename) rc, stdout, stderr = run_exe(path) self.assertEqual( rc, 0, f'example "{filename}" failed with stdout =\n{stdout}\nstderr =\n{stderr}', ) if __name__ == "__main__": unittest.main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/tests/test_general.py0000664000175000017500000000537715134157072017115 0ustar00elibenelibenimport os import sys import unittest sys.path.insert(0, "..") from pycparser import parse_file, c_ast from tests.test_util import cpp_supported, cpp_path, cpp_args # Test successful parsing # class TestParsing(unittest.TestCase): def _find_file(self, name): """Find a c file by name, taking into account the current dir can be in a couple of typical places """ testdir = os.path.dirname(__file__) name = os.path.join(testdir, "c_files", name) assert os.path.exists(name) return name def test_without_cpp(self): ast = parse_file(self._find_file("example_c_file.c")) self.assertIsInstance(ast, c_ast.FileAST) @unittest.skipUnless(cpp_supported(), "cpp only works on Unix") def test_with_cpp(self): memmgr_path = self._find_file("memmgr.c") c_files_path = os.path.dirname(memmgr_path) ast = parse_file( memmgr_path, use_cpp=True, cpp_path=cpp_path(), cpp_args=cpp_args(f"-I{c_files_path}"), ) self.assertIsInstance(ast, c_ast.FileAST) fake_libc = os.path.join(c_files_path, "..", "..", "utils", "fake_libc_include") ast2 = parse_file( self._find_file("year.c"), use_cpp=True, cpp_path=cpp_path(), cpp_args=cpp_args(f"-I{fake_libc}"), ) self.assertIsInstance(ast2, c_ast.FileAST) @unittest.skipUnless(cpp_supported(), "cpp only works on Unix") def test_cpp_funkydir(self): # This test contains Windows specific path escapes if sys.platform != "win32": return c_files_path = os.path.join("tests", "c_files") ast = parse_file( self._find_file("simplemain.c"), use_cpp=True, cpp_path=cpp_path(), cpp_args=cpp_args(f"-I{c_files_path}"), ) self.assertIsInstance(ast, c_ast.FileAST) @unittest.skipUnless(cpp_supported(), "cpp only works on Unix") def test_no_real_content_after_cpp(self): ast = parse_file( self._find_file("empty.h"), use_cpp=True, cpp_path=cpp_path(), cpp_args=cpp_args(), ) self.assertIsInstance(ast, c_ast.FileAST) @unittest.skipUnless(cpp_supported(), "cpp only works on Unix") def test_c11_with_cpp(self): c_files_path = os.path.join("tests", "c_files") fake_libc = os.path.join(c_files_path, "..", "..", "utils", "fake_libc_include") ast = parse_file( self._find_file("c11.c"), use_cpp=True, cpp_path=cpp_path(), cpp_args=cpp_args(f"-I{fake_libc}"), ) self.assertIsInstance(ast, c_ast.FileAST) if __name__ == "__main__": unittest.main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1769004602.0 pycparser-3.0/tests/test_util.py0000664000175000017500000000276715134157072016455 0ustar00elibeneliben# ------------------------------------------------------------------------------ # pycparser: test_util.py # # Utility code for tests. # # Eli Bendersky [https://eli.thegreenplace.net/] # This file contributed by vit9696@users.noreply.github.com # License: BSD # ------------------------------------------------------------------------------ import os import platform import subprocess import sys def cpp_supported(): """Is cpp (the C preprocessor) supported as a native command?""" return platform.system() == "Linux" def cpp_path(): """Path to cpp command.""" if platform.system() == "Darwin": return "gcc" return "cpp" def cpp_args(args=[]): """Turn args into a suitable format for passing to cpp.""" if isinstance(args, str): args = [args] if platform.system() == "Darwin": return ["-E"] + args return args def _bytes2str(b): return b.decode("latin-1") def run_exe(exe_path, args=[], echo=False): """Runs the given executable as a subprocess, given the list of arguments. Captures its return code (rc) and stdout and returns a tuple: rc, stdout, stderr """ popen_cmd = [exe_path] + args if os.path.splitext(exe_path)[1] == ".py": popen_cmd.insert(0, sys.executable) if echo: print("[cmd]", " ".join(popen_cmd)) proc = subprocess.Popen(popen_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = proc.communicate() return proc.returncode, _bytes2str(stdout), _bytes2str(stderr) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4625738 pycparser-3.0/utils/0000775000175000017500000000000015134160755014053 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4679601 pycparser-3.0/utils/fake_libc_include/0000775000175000017500000000000015134160755017455 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1769005549.468089 pycparser-3.0/utils/fake_libc_include/X11/0000775000175000017500000000000015134160755020026 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/X11/Intrinsic.h0000664000175000017500000000016614716121044022135 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" #include "_X11_fake_defines.h" #include "_X11_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/X11/Xlib.h0000664000175000017500000000016614716121044021071 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" #include "_X11_fake_defines.h" #include "_X11_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/X11/_X11_fake_defines.h0000664000175000017500000000046714716121044023372 0ustar00elibeneliben#ifndef _X11_FAKE_DEFINES_H #define _X11_FAKE_DEFINES_H #define Atom CARD32 #define Bool int #define KeySym CARD32 #define Pixmap CARD32 #define Time CARD32 #define _XFUNCPROTOBEGIN #define _XFUNCPROTOEND #define _Xconst const #define _X_RESTRICT_KYWD #define Cardinal unsigned int #define Boolean int #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/X11/_X11_fake_typedefs.h0000664000175000017500000000212714716121044023573 0ustar00elibeneliben#ifndef _X11_FAKE_TYPEDEFS_H #define _X11_FAKE_TYPEDEFS_H typedef char* XPointer; typedef unsigned char KeyCode; typedef unsigned int CARD32; typedef unsigned long VisualID; typedef unsigned long XIMResetState; typedef unsigned long XID; typedef XID Window; typedef XID Colormap; typedef XID Cursor; typedef XID Drawable; typedef void* XtPointer; typedef XtPointer XtRequestId; typedef struct Display Display; typedef struct Screen Screen; typedef struct Status Status; typedef struct Visual Visual; typedef struct Widget *Widget; typedef struct XColor XColor; typedef struct XClassHint XClassHint; typedef struct XEvent XEvent; typedef struct XFontStruct XFontStruct; typedef struct XGCValues XGCValues; typedef struct XKeyEvent XKeyEvent; typedef struct XKeyPressedEvent XKeyPressedEvent; typedef struct XPoint XPoint; typedef struct XRectangle XRectangle; typedef struct XSelectionRequestEvent XSelectionRequestEvent; typedef struct XWindowChanges XWindowChanges; typedef struct _XGC _XCG; typedef struct _XGC *GC; typedef struct _XIC *XIC; typedef struct _XIM *XIM; typedef struct _XImage XImage; #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/_ansi.h0000664000175000017500000000006714716121044020713 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/_fake_defines.h0000664000175000017500000001344114716121044022364 0ustar00elibeneliben#ifndef _FAKE_DEFINES_H #define _FAKE_DEFINES_H #define NULL 0 #define BUFSIZ 1024 #define FOPEN_MAX 20 #define FILENAME_MAX 1024 #ifndef SEEK_SET #define SEEK_SET 0 /* set file offset to offset */ #endif #ifndef SEEK_CUR #define SEEK_CUR 1 /* set file offset to current plus offset */ #endif #ifndef SEEK_END #define SEEK_END 2 /* set file offset to EOF plus offset */ #endif #define __LITTLE_ENDIAN 1234 #define LITTLE_ENDIAN __LITTLE_ENDIAN #define __BIG_ENDIAN 4321 #define BIG_ENDIAN __BIG_ENDIAN #define __BYTE_ORDER __LITTLE_ENDIAN #define BYTE_ORDER __BYTE_ORDER #define EXIT_FAILURE 1 #define EXIT_SUCCESS 0 #define SCHAR_MIN -128 #define SCHAR_MAX 127 #define CHAR_MIN -128 #define CHAR_MAX 127 #define UCHAR_MAX 255 #define SHRT_MIN -32768 #define SHRT_MAX 32767 #define USHRT_MAX 65535 #define INT_MIN -2147483648 #define INT_MAX 2147483647 #define UINT_MAX 4294967295U #define LONG_MIN -9223372036854775808L #define LONG_MAX 9223372036854775807L #define ULONG_MAX 18446744073709551615UL #define RAND_MAX 32767 /* C99 inttypes.h defines */ #define PRId8 "d" #define PRIi8 "i" #define PRIo8 "o" #define PRIu8 "u" #define PRIx8 "x" #define PRIX8 "X" #define PRId16 "d" #define PRIi16 "i" #define PRIo16 "o" #define PRIu16 "u" #define PRIx16 "x" #define PRIX16 "X" #define PRId32 "d" #define PRIi32 "i" #define PRIo32 "o" #define PRIu32 "u" #define PRIx32 "x" #define PRIX32 "X" #define PRId64 "d" #define PRIi64 "i" #define PRIo64 "o" #define PRIu64 "u" #define PRIx64 "x" #define PRIX64 "X" #define PRIdLEAST8 "d" #define PRIiLEAST8 "i" #define PRIoLEAST8 "o" #define PRIuLEAST8 "u" #define PRIxLEAST8 "x" #define PRIXLEAST8 "X" #define PRIdLEAST16 "d" #define PRIiLEAST16 "i" #define PRIoLEAST16 "o" #define PRIuLEAST16 "u" #define PRIxLEAST16 "x" #define PRIXLEAST16 "X" #define PRIdLEAST32 "d" #define PRIiLEAST32 "i" #define PRIoLEAST32 "o" #define PRIuLEAST32 "u" #define PRIxLEAST32 "x" #define PRIXLEAST32 "X" #define PRIdLEAST64 "d" #define PRIiLEAST64 "i" #define PRIoLEAST64 "o" #define PRIuLEAST64 "u" #define PRIxLEAST64 "x" #define PRIXLEAST64 "X" #define PRIdFAST8 "d" #define PRIiFAST8 "i" #define PRIoFAST8 "o" #define PRIuFAST8 "u" #define PRIxFAST8 "x" #define PRIXFAST8 "X" #define PRIdFAST16 "d" #define PRIiFAST16 "i" #define PRIoFAST16 "o" #define PRIuFAST16 "u" #define PRIxFAST16 "x" #define PRIXFAST16 "X" #define PRIdFAST32 "d" #define PRIiFAST32 "i" #define PRIoFAST32 "o" #define PRIuFAST32 "u" #define PRIxFAST32 "x" #define PRIXFAST32 "X" #define PRIdFAST64 "d" #define PRIiFAST64 "i" #define PRIoFAST64 "o" #define PRIuFAST64 "u" #define PRIxFAST64 "x" #define PRIXFAST64 "X" #define PRIdPTR "d" #define PRIiPTR "i" #define PRIoPTR "o" #define PRIuPTR "u" #define PRIxPTR "x" #define PRIXPTR "X" #define PRIdMAX "d" #define PRIiMAX "i" #define PRIoMAX "o" #define PRIuMAX "u" #define PRIxMAX "x" #define PRIXMAX "X" #define SCNd8 "d" #define SCNi8 "i" #define SCNo8 "o" #define SCNu8 "u" #define SCNx8 "x" #define SCNd16 "d" #define SCNi16 "i" #define SCNo16 "o" #define SCNu16 "u" #define SCNx16 "x" #define SCNd32 "d" #define SCNi32 "i" #define SCNo32 "o" #define SCNu32 "u" #define SCNx32 "x" #define SCNd64 "d" #define SCNi64 "i" #define SCNo64 "o" #define SCNu64 "u" #define SCNx64 "x" #define SCNdLEAST8 "d" #define SCNiLEAST8 "i" #define SCNoLEAST8 "o" #define SCNuLEAST8 "u" #define SCNxLEAST8 "x" #define SCNdLEAST16 "d" #define SCNiLEAST16 "i" #define SCNoLEAST16 "o" #define SCNuLEAST16 "u" #define SCNxLEAST16 "x" #define SCNdLEAST32 "d" #define SCNiLEAST32 "i" #define SCNoLEAST32 "o" #define SCNuLEAST32 "u" #define SCNxLEAST32 "x" #define SCNdLEAST64 "d" #define SCNiLEAST64 "i" #define SCNoLEAST64 "o" #define SCNuLEAST64 "u" #define SCNxLEAST64 "x" #define SCNdFAST8 "d" #define SCNiFAST8 "i" #define SCNoFAST8 "o" #define SCNuFAST8 "u" #define SCNxFAST8 "x" #define SCNdFAST16 "d" #define SCNiFAST16 "i" #define SCNoFAST16 "o" #define SCNuFAST16 "u" #define SCNxFAST16 "x" #define SCNdFAST32 "d" #define SCNiFAST32 "i" #define SCNoFAST32 "o" #define SCNuFAST32 "u" #define SCNxFAST32 "x" #define SCNdFAST64 "d" #define SCNiFAST64 "i" #define SCNoFAST64 "o" #define SCNuFAST64 "u" #define SCNxFAST64 "x" #define SCNdPTR "d" #define SCNiPTR "i" #define SCNoPTR "o" #define SCNuPTR "u" #define SCNxPTR "x" #define SCNdMAX "d" #define SCNiMAX "i" #define SCNoMAX "o" #define SCNuMAX "u" #define SCNxMAX "x" /* C99 stdbool.h defines */ #define __bool_true_false_are_defined 1 #define false 0 #define true 1 /* va_arg macros and type*/ #define va_start(_ap, _type) __builtin_va_start((_ap)) #define va_arg(_ap, _type) __builtin_va_arg((_ap)) #define va_end(_list) /* Vectors */ #define __m128 int #define __m128_u int #define __m128d int #define __m128d_u int #define __m128i int #define __m128i_u int #define __m256 int #define __m256_u int #define __m256d int #define __m256d_u int #define __m256i int #define __m256i_u int #define __m512 int #define __m512_u int #define __m512d int #define __m512d_u int #define __m512i int #define __m512i_u int /* C11 stdnoreturn.h defines */ #define __noreturn_is_defined 1 #define noreturn _Noreturn /* C11 threads.h defines */ #define thread_local _Thread_local /* C11 assert.h defines */ #define static_assert _Static_assert /* C11 stdatomic.h defines */ #define ATOMIC_BOOL_LOCK_FREE 0 #define ATOMIC_CHAR_LOCK_FREE 0 #define ATOMIC_CHAR16_T_LOCK_FREE 0 #define ATOMIC_CHAR32_T_LOCK_FREE 0 #define ATOMIC_WCHAR_T_LOCK_FREE 0 #define ATOMIC_SHORT_LOCK_FREE 0 #define ATOMIC_INT_LOCK_FREE 0 #define ATOMIC_LONG_LOCK_FREE 0 #define ATOMIC_LLONG_LOCK_FREE 0 #define ATOMIC_POINTER_LOCK_FREE 0 #define ATOMIC_VAR_INIT(value) (value) #define ATOMIC_FLAG_INIT { 0 } #define kill_dependency(y) (y) /* C11 stdalign.h defines */ #define alignas _Alignas #define alignof _Alignof #define __alignas_is_defined 1 #define __alignof_is_defined 1 #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1755552424.0 pycparser-3.0/utils/fake_libc_include/_fake_typedefs.h0000664000175000017500000001532115050715250022571 0ustar00elibeneliben#ifndef _FAKE_TYPEDEFS_H #define _FAKE_TYPEDEFS_H typedef int size_t; typedef int __builtin_va_list; typedef int __gnuc_va_list; typedef int va_list; typedef int __int8_t; typedef int __uint8_t; typedef int __int16_t; typedef int __uint16_t; typedef int __int_least16_t; typedef int __uint_least16_t; typedef int __int32_t; typedef int __uint32_t; typedef int __int64_t; typedef int __uint64_t; typedef int __int_least32_t; typedef int __uint_least32_t; typedef int __s8; typedef int __u8; typedef int __s16; typedef int __u16; typedef int __s32; typedef int __u32; typedef int __s64; typedef int __u64; typedef int _LOCK_T; typedef int _LOCK_RECURSIVE_T; typedef int _off_t; typedef int __dev_t; typedef int __uid_t; typedef int __gid_t; typedef int _off64_t; typedef int _fpos_t; typedef int _ssize_t; typedef int wint_t; typedef int _mbstate_t; typedef int _flock_t; typedef int _iconv_t; typedef int __ULong; typedef int __FILE; typedef int ptrdiff_t; typedef int wchar_t; typedef int char16_t; typedef int char32_t; typedef int __off_t; typedef int __pid_t; typedef int __loff_t; typedef int u_char; typedef int u_short; typedef int u_int; typedef int u_long; typedef int ushort; typedef int uint; typedef int clock_t; typedef int time_t; typedef int daddr_t; typedef int caddr_t; typedef int ino_t; typedef int off_t; typedef int dev_t; typedef int uid_t; typedef int gid_t; typedef int pid_t; typedef int key_t; typedef int ssize_t; typedef int mode_t; typedef int nlink_t; typedef int fd_mask; typedef int _types_fd_set; typedef int clockid_t; typedef int timer_t; typedef int useconds_t; typedef int suseconds_t; typedef int FILE; typedef int fpos_t; typedef int cookie_read_function_t; typedef int cookie_write_function_t; typedef int cookie_seek_function_t; typedef int cookie_close_function_t; typedef int cookie_io_functions_t; typedef int div_t; typedef int ldiv_t; typedef int lldiv_t; typedef int sigset_t; typedef int __sigset_t; typedef int _sig_func_ptr; typedef int sig_atomic_t; typedef int __tzrule_type; typedef int __tzinfo_type; typedef int mbstate_t; typedef int sem_t; typedef int pthread_t; typedef int pthread_attr_t; typedef int pthread_mutex_t; typedef int pthread_mutexattr_t; typedef int pthread_cond_t; typedef int pthread_condattr_t; typedef int pthread_key_t; typedef int pthread_once_t; typedef int pthread_rwlock_t; typedef int pthread_rwlockattr_t; typedef int pthread_spinlock_t; typedef int pthread_barrier_t; typedef int pthread_barrierattr_t; typedef int jmp_buf; typedef int rlim_t; typedef int sa_family_t; typedef int sigjmp_buf; typedef int stack_t; typedef int siginfo_t; typedef int z_stream; /* C99 exact-width integer types */ typedef int int8_t; typedef int uint8_t; typedef int int16_t; typedef int uint16_t; typedef int int32_t; typedef int uint32_t; typedef int int64_t; typedef int uint64_t; /* C99 minimum-width integer types */ typedef int int_least8_t; typedef int uint_least8_t; typedef int int_least16_t; typedef int uint_least16_t; typedef int int_least32_t; typedef int uint_least32_t; typedef int int_least64_t; typedef int uint_least64_t; /* C99 fastest minimum-width integer types */ typedef int int_fast8_t; typedef int uint_fast8_t; typedef int int_fast16_t; typedef int uint_fast16_t; typedef int int_fast32_t; typedef int uint_fast32_t; typedef int int_fast64_t; typedef int uint_fast64_t; /* C99 integer types capable of holding object pointers */ typedef int intptr_t; typedef int uintptr_t; /* C99 greatest-width integer types */ typedef int intmax_t; typedef int uintmax_t; /* C99 stdbool.h bool type. _Bool is built-in in C99 */ typedef _Bool bool; /* GNU Extension for 64-bit targets */ #ifdef __SIZEOF_INT128__ typedef int __int128_t; typedef int __uint128_t; #endif /* __SIZEOF_INT128__ */ /* Mir typedefs */ typedef void* MirEGLNativeWindowType; typedef void* MirEGLNativeDisplayType; typedef struct MirConnection MirConnection; typedef struct MirSurface MirSurface; typedef struct MirSurfaceSpec MirSurfaceSpec; typedef struct MirScreencast MirScreencast; typedef struct MirPromptSession MirPromptSession; typedef struct MirBufferStream MirBufferStream; typedef struct MirPersistentId MirPersistentId; typedef struct MirBlob MirBlob; typedef struct MirDisplayConfig MirDisplayConfig; /* xcb typedefs */ typedef struct xcb_connection_t xcb_connection_t; typedef uint32_t xcb_window_t; typedef uint32_t xcb_visualid_t; /* dirent typedef */ typedef void* DIR; /* socket typedefs */ typedef __uint32_t __socklen_t; typedef __socklen_t socklen_t; typedef unsigned short __kernel_sa_family_t; /* C11 stdatomic.h types */ typedef _Atomic(_Bool) atomic_bool; typedef _Atomic(char) atomic_char; typedef _Atomic(signed char) atomic_schar; typedef _Atomic(unsigned char) atomic_uchar; typedef _Atomic(short) atomic_short; typedef _Atomic(unsigned short) atomic_ushort; typedef _Atomic(int) atomic_int; typedef _Atomic(unsigned int) atomic_uint; typedef _Atomic(long) atomic_long; typedef _Atomic(unsigned long) atomic_ulong; typedef _Atomic(long long) atomic_llong; typedef _Atomic(unsigned long long) atomic_ullong; typedef _Atomic(uint_least16_t) atomic_char16_t; typedef _Atomic(uint_least32_t) atomic_char32_t; typedef _Atomic(wchar_t) atomic_wchar_t; typedef _Atomic(int_least8_t) atomic_int_least8_t; typedef _Atomic(uint_least8_t) atomic_uint_least8_t; typedef _Atomic(int_least16_t) atomic_int_least16_t; typedef _Atomic(uint_least16_t) atomic_uint_least16_t; typedef _Atomic(int_least32_t) atomic_int_least32_t; typedef _Atomic(uint_least32_t) atomic_uint_least32_t; typedef _Atomic(int_least64_t) atomic_int_least64_t; typedef _Atomic(uint_least64_t) atomic_uint_least64_t; typedef _Atomic(int_fast8_t) atomic_int_fast8_t; typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t; typedef _Atomic(int_fast16_t) atomic_int_fast16_t; typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t; typedef _Atomic(int_fast32_t) atomic_int_fast32_t; typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t; typedef _Atomic(int_fast64_t) atomic_int_fast64_t; typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t; typedef _Atomic(intptr_t) atomic_intptr_t; typedef _Atomic(uintptr_t) atomic_uintptr_t; typedef _Atomic(size_t) atomic_size_t; typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t; typedef _Atomic(intmax_t) atomic_intmax_t; typedef _Atomic(uintmax_t) atomic_uintmax_t; typedef struct atomic_flag { atomic_bool _Value; } atomic_flag; typedef enum memory_order { memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel, memory_order_seq_cst } memory_order; #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/_syslist.h0000664000175000017500000000006714716121044021473 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/aio.h0000664000175000017500000000006714716121044020372 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/alloca.h0000664000175000017500000000006714716121044021055 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/ar.h0000664000175000017500000000006714716121044020224 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/argz.h0000664000175000017500000000006714716121044020565 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4681196 pycparser-3.0/utils/fake_libc_include/arpa/0000775000175000017500000000000015134160755020400 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/arpa/inet.h0000664000175000017500000000006714716121044021504 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4681535 pycparser-3.0/utils/fake_libc_include/asm-generic/0000775000175000017500000000000015134160755021647 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/asm-generic/int-ll64.h0000664000175000017500000000006714716121044023365 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/assert.h0000664000175000017500000000006714716121044021123 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/complex.h0000664000175000017500000000006714716121044021271 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/cpio.h0000664000175000017500000000006714716121044020554 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/ctype.h0000664000175000017500000000006714716121044020746 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/dirent.h0000664000175000017500000000006714716121044021107 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/dlfcn.h0000664000175000017500000000006714716121044020710 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/emmintrin.h0000664000175000017500000000006714716121044021624 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/endian.h0000664000175000017500000000006714716121044021060 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/envz.h0000664000175000017500000000006714716121044020604 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/errno.h0000664000175000017500000000006714716121044020747 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/fastmath.h0000664000175000017500000000006714716121044021431 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/fcntl.h0000664000175000017500000000006714716121044020730 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/features.h0000664000175000017500000000006714716121044021440 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/fenv.h0000664000175000017500000000006714716121044020560 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/float.h0000664000175000017500000000006714716121044020727 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/fmtmsg.h0000664000175000017500000000006714716121044021117 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/fnmatch.h0000664000175000017500000000006714716121044021242 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/ftw.h0000664000175000017500000000006714716121044020422 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/getopt.h0000664000175000017500000000006714716121044021124 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/glob.h0000664000175000017500000000006714716121044020545 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/grp.h0000664000175000017500000000006714716121044020412 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/iconv.h0000664000175000017500000000006714716121044020740 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/ieeefp.h0000664000175000017500000000006714716121044021057 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/immintrin.h0000664000175000017500000000006714716121044021630 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/inttypes.h0000664000175000017500000000006714716121044021501 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/iso646.h0000664000175000017500000000006714716121044020654 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/langinfo.h0000664000175000017500000000006714716121044021417 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/libgen.h0000664000175000017500000000006714716121044021062 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/libintl.h0000664000175000017500000000006714716121044021257 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/limits.h0000664000175000017500000000006714716121044021123 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1769005549.468215 pycparser-3.0/utils/fake_libc_include/linux/0000775000175000017500000000000015134160755020614 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/linux/socket.h0000664000175000017500000000006714716121044022251 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/linux/version.h0000664000175000017500000000006714716121044022446 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/locale.h0000664000175000017500000000006714716121044021061 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/malloc.h0000664000175000017500000000006714716121044021071 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/math.h0000664000175000017500000000006714716121044020553 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4682453 pycparser-3.0/utils/fake_libc_include/mir_toolkit/0000775000175000017500000000000015134160755022011 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/mir_toolkit/client_types.h0000664000175000017500000000006714716121044024660 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/monetary.h0000664000175000017500000000006714716121044021460 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/mqueue.h0000664000175000017500000000006714716121044021123 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/ndbm.h0000664000175000017500000000006714716121044020542 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4682767 pycparser-3.0/utils/fake_libc_include/net/0000775000175000017500000000000015134160755020243 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/net/if.h0000664000175000017500000000006714716121044021006 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/netdb.h0000664000175000017500000000006714716121044020716 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1769005549.468338 pycparser-3.0/utils/fake_libc_include/netinet/0000775000175000017500000000000015134160755021123 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/netinet/in.h0000664000175000017500000000006714716121044021676 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/netinet/tcp.h0000664000175000017500000000006714716121044022056 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/newlib.h0000664000175000017500000000006714716121044021102 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/nl_types.h0000664000175000017500000000006714716121044021457 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1769005549.468486 pycparser-3.0/utils/fake_libc_include/openssl/0000775000175000017500000000000015134160755021140 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/openssl/err.h0000664000175000017500000000006714716121044022075 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/openssl/evp.h0000664000175000017500000000006714716121044022077 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/openssl/hmac.h0000664000175000017500000000006714716121044022215 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/openssl/ssl.h0000664000175000017500000000006714716121044022106 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/openssl/x509v3.h0000664000175000017500000000006714716121044022263 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/paths.h0000664000175000017500000000006714716121044020741 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/poll.h0000664000175000017500000000006714716121044020570 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/process.h0000664000175000017500000000006714716121044021300 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/pthread.h0000664000175000017500000000006714716121044021251 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/pwd.h0000664000175000017500000000006714716121044020414 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/reent.h0000664000175000017500000000006714716121044020737 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/regdef.h0000664000175000017500000000006714716121044021056 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/regex.h0000664000175000017500000000006714716121044020734 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sched.h0000664000175000017500000000006714716121044020710 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/search.h0000664000175000017500000000006714716121044021067 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/semaphore.h0000664000175000017500000000006714716121044021605 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/setjmp.h0000664000175000017500000000006714716121044021124 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/signal.h0000664000175000017500000000006714716121044021077 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/smmintrin.h0000664000175000017500000000006714716121044021642 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/spawn.h0000664000175000017500000000006714716121044020752 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/stdalign.h0000664000175000017500000000006714716121044021427 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/stdarg.h0000664000175000017500000000006714716121044021106 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/stdatomic.h0000664000175000017500000000006714716121044021611 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/stdbool.h0000664000175000017500000000006714716121044021270 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/stddef.h0000664000175000017500000000006714716121044021073 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/stdint.h0000664000175000017500000000006714716121044021127 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/stdio.h0000664000175000017500000000006714716121044020744 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/stdlib.h0000664000175000017500000000006714716121044021103 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/stdnoreturn.h0000664000175000017500000000006714716121044022211 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/string.h0000664000175000017500000000006714716121044021130 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/strings.h0000664000175000017500000000006714716121044021313 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/stropts.h0000664000175000017500000000006714716121044021340 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1769005549.469108 pycparser-3.0/utils/fake_libc_include/sys/0000775000175000017500000000000015134160755020273 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/ioctl.h0000664000175000017500000000006714716121044021552 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/ipc.h0000664000175000017500000000006714716121044021213 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/mman.h0000664000175000017500000000006714716121044021370 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/msg.h0000664000175000017500000000006714716121044021226 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/poll.h0000664000175000017500000000006714716121044021406 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/resource.h0000664000175000017500000000006714716121044022267 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/select.h0000664000175000017500000000006714716121044021717 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/sem.h0000664000175000017500000000006714716121044021224 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/shm.h0000664000175000017500000000006714716121044021227 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/socket.h0000664000175000017500000000006714716121044021730 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/stat.h0000664000175000017500000000006714716121044021413 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/statvfs.h0000664000175000017500000000006714716121044022132 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/sysctl.h0000664000175000017500000000006714716121044021761 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/time.h0000664000175000017500000000006714716121044021376 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/times.h0000664000175000017500000000006714716121044021561 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/types.h0000664000175000017500000000006714716121044021604 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/uio.h0000664000175000017500000000006714716121044021234 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/un.h0000664000175000017500000000006714716121044021062 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/utsname.h0000664000175000017500000000006714716121044022114 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/sys/wait.h0000664000175000017500000000006714716121044021404 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/syslog.h0000664000175000017500000000006714716121044021142 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/tar.h0000664000175000017500000000006714716121044020410 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/termios.h0000664000175000017500000000006714716121044021304 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/tgmath.h0000664000175000017500000000006714716121044021106 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/threads.h0000664000175000017500000000006714716121044021254 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/time.h0000664000175000017500000000006714716121044020560 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/trace.h0000664000175000017500000000006714716121044020720 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/ulimit.h0000664000175000017500000000006714716121044021125 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/unctrl.h0000664000175000017500000000006714716121044021131 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/unistd.h0000664000175000017500000000006714716121044021130 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/utime.h0000664000175000017500000000006714716121044020745 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/utmp.h0000664000175000017500000000006714716121044020607 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/utmpx.h0000664000175000017500000000006714716121044020777 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/wchar.h0000664000175000017500000000006714716121044020726 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/wctype.h0000664000175000017500000000006714716121044021135 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/wordexp.h0000664000175000017500000000006714716121044021312 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1769005549.4691398 pycparser-3.0/utils/fake_libc_include/xcb/0000775000175000017500000000000015134160755020231 5ustar00elibeneliben././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/xcb/xcb.h0000664000175000017500000000006714716121044021152 0ustar00elibeneliben#include "_fake_defines.h" #include "_fake_typedefs.h" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1731764772.0 pycparser-3.0/utils/fake_libc_include/zlib.h0000664000175000017500000000100214716121044020550 0ustar00elibeneliben#ifndef ZLIB_H #define ZLIB_H #include "_fake_defines.h" #include "_fake_typedefs.h" typedef int uInt; typedef int uLong; #if !defined(__MACTYPES__) typedef int Byte; #endif typedef int Bytef; typedef int charf; typedef int intf; typedef int uIntf; typedef int uLongf; typedef int voidpc; typedef int voidpf; typedef int voidp; #if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) typedef int Z_U4; #endif typedef int z_crc_t; typedef int z_size_t; typedef int alloc_func; typedef int free_func; #endif