:snake: Complete C99 parser in pure Python

Overview

pycparser v2.20


1   Introduction

1.1   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.

1.2   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.

1.3   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.

1.4   What grammar does pycparser follow?

pycparser very closely follows the C grammar provided in Annex A of the C99 standard (ISO/IEC 9899).

1.5   How is pycparser licensed?

BSD license.

1.6   Contact details

For reporting problems with pycparser or submitting feature requests, please open an issue, or submit a pull request.

2   Installing

2.1   Prerequisites

  • pycparser was tested on Python 2.7, 3.4-3.6, on both Linux and Windows. It should work on any later version (in both the 2.x and 3.x lines) as well.
  • pycparser has no external dependencies. The only non-stdlib library it uses is PLY, which is bundled in pycparser/ply. The current PLY version is 3.10, retrieved from http://www.dabeaz.com/ply/

Note that pycparser (and PLY) uses docstrings for grammar specifications. Python installations that strip docstrings (such as when using the Python -OO option) will fail to instantiate and use pycparser. You can try to work around this problem by making sure the PLY parsing tables are pre-generated in normal mode; this isn't an officially supported/tested mode of operation, though.

2.2   Installation process

Installing pycparser is very simple. Once you download and unzip the package, you just have to execute the standard python setup.py install. The setup script will then place the pycparser module into site-packages in your Python's installation library.

Alternatively, since pycparser is listed in the Python Package Index (PyPI), you can install it using your favorite Python packaging/distribution tool, for example with:

> pip install pycparser

2.3   Known problems

  • Some users who've installed a new version of pycparser over an existing version ran into a problem using the newly installed library. This has to do with parse tables staying around as .pyc files from the older version. If you see unexplained errors from pycparser after an upgrade, remove it (by deleting the pycparser directory in your Python's site-packages, or wherever you installed it) and install again.

3   Using

3.1   Interaction with the C preprocessor

In order to be compilable, C code must be preprocessed by the C preprocessor - cpp. 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.

3.2   What about the standard C library headers?

C code almost always #includes 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 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 setup.py (#224).

3.3   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.

3.4   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.

4   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.
  • Make sure you understand the optimized mode of pycparser - for that you must read the docstring in the constructor of the CParser class. For development you should create the parser without optimizations, so that it will regenerate the Yacc and Lex tables when you change the grammar.

5   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:
Installation script
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.
utils/internal/:
Internal utilities for my own use. You probably don't need them.

6   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.

Comments
  • Don't fail if docstrings are disabled

    Don't fail if docstrings are disabled

    The attribute __doc__ will return None if running CPython in -OO mode as it discards docstrings.

    FYI, this broke builds for me because cryptography uses cffi which uses pycparser at install time, and always pulls the latest version regardless of any dependency pinning in requirements.txt. It would be nice to prioritize this getting in a release ASAP to fix this issue.

    opened by dsanders11 29
  • pycparser-2.14-py2.py3-none-any.whl causes AssertionError: sorry, but this version only supports 100 named groups

    pycparser-2.14-py2.py3-none-any.whl causes AssertionError: sorry, but this version only supports 100 named groups

    Looks like pycparser-2.14-py2.py3-none-any.whl is broken or something misconfigured, while pycparser-2.14.tar.gz is ok. After installing a Snowflake Connector for Python, a connector for Snowflake DB, this error happen:

    >pip install -U snowflake-connector-python
    >python -c "import snowflake.connector"
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/t/lib/python2.7/site-packages/snowflake/connector/__init__.py", line 21, in <module>
        from .connection import SnowflakeConnection
      File "/tmp/t/lib/python2.7/site-packages/snowflake/connector/connection.py", line 16, in <module>
        from .cursor import SnowflakeCursor
      File "/tmp/t/lib/python2.7/site-packages/snowflake/connector/cursor.py", line 30, in <module>
        from .file_transfer_agent import (SnowflakeFileTransferAgent)
      File "/tmp/t/lib/python2.7/site-packages/snowflake/connector/file_transfer_agent.py", line 29, in <module>
        from .s3_util import (SnowflakeS3FileEncryptionMaterial, SnowflakeS3Util,
      File "/tmp/t/lib/python2.7/site-packages/snowflake/connector/s3_util.py", line 25, in <module>
        from Crypto.Cipher import AES
      File "/tmp/t/lib/python2.7/site-packages/Crypto/Cipher/__init__.py", line 78, in <module>
        from Crypto.Cipher._mode_ecb import _create_ecb_cipher
      File "/tmp/t/lib/python2.7/site-packages/Crypto/Cipher/_mode_ecb.py", line 29, in <module>
        from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
      File "/tmp/t/lib/python2.7/site-packages/Crypto/Util/_raw_api.py", line 89, in <module>
        Array = ffi.new("char[1]").__class__.__bases__
      File "/tmp/t/lib/python2.7/site-packages/cffi/api.py", line 248, in new
        cdecl = self._typeof(cdecl)
      File "/tmp/t/lib/python2.7/site-packages/cffi/api.py", line 168, in _typeof
        result = self._typeof_locked(cdecl)
      File "/tmp/t/lib/python2.7/site-packages/cffi/api.py", line 153, in _typeof_locked
        type = self._parser.parse_type(cdecl)
      File "/tmp/t/lib/python2.7/site-packages/cffi/cparser.py", line 448, in parse_type
        return self.parse_type_and_quals(cdecl)[0]
      File "/tmp/t/lib/python2.7/site-packages/cffi/cparser.py", line 451, in parse_type_and_quals
        ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2]
      File "/tmp/t/lib/python2.7/site-packages/cffi/cparser.py", line 260, in _parse
        ast = _get_parser().parse(csource)
      File "/tmp/t/lib/python2.7/site-packages/cffi/cparser.py", line 40, in _get_parser
        _parser_cache = pycparser.CParser()
      File "/tmp/t/lib/python2.7/site-packages/pycparser/c_parser.py", line 87, in __init__
        outputdir=taboutputdir)
      File "/tmp/t/lib/python2.7/site-packages/pycparser/c_lexer.py", line 66, in build
        self.lexer = lex.lex(object=self, **kwargs)
      File "/tmp/t/lib/python2.7/site-packages/pycparser/ply/lex.py", line 911, in lex
        lexobj.readtab(lextab, ldict)
      File "/tmp/t/lib/python2.7/site-packages/pycparser/ply/lex.py", line 233, in readtab
        titem.append((re.compile(pat, lextab._lexreflags | re.VERBOSE), _names_to_funcs(func_name, fdict)))
      File "/tmp/t/lib/python2.7/re.py", line 194, in compile
        return _compile(pattern, flags)
      File "/tmp/t/lib/python2.7/re.py", line 249, in _compile
        p = sre_compile.compile(pattern, flags)
      File "/tmp/t/lib/python2.7/sre_compile.py", line 583, in compile
        "sorry, but this version only supports 100 named groups"
    AssertionError: sorry, but this version only supports 100 named groups
    

    But if I install it from source pycparser-2.14.tar.gz, it works

    >pip install -U ~/Downloads/pycparser-2.14.tar.gz
    Processing /Users/stakeda/Downloads/pycparser-2.14.tar.gz
    Building wheels for collected packages: pycparser
      Running setup.py bdist_wheel for pycparser ... done
      Stored in directory: /Users/stakeda/Library/Caches/pip/wheels/6e/f1/96/de2b8478c77d89fe540a5709a70e2cdc4e7331a3543cada3c1
    Successfully built pycparser
    Installing collected packages: pycparser
      Found existing installation: pycparser 2.13
        Uninstalling pycparser-2.13:
          Successfully uninstalled pycparser-2.13
    Successfully installed pycparser-2.14
    >python -c "import snowflake.connector"
    >
    

    Could you rebuild a new wheel or remove it? Thanks.

    opened by smtakeda 18
  • Fix parsing TYPEIDs in declarators

    Fix parsing TYPEIDs in declarators

    This fixes the parsing of TYPEIDs in declarators (and related expressions) once and for all, removing existing workarounds for specific cases of the problem. In particular, it solves the problem in the current parser where a TYPEID is used in a list of multiple declarators, for which there is no workaround.

    All tests are passing for me, and I added 2 more tests related to parsing declarators correctly.

    I've tried to organize the commits as logically and discretely as possible to make it clear what is happening in each step:

    1. Remove workaround productions
    2. Allow TYPEIDs in declarators
    3. Restrict declaration-specifiers and specifier-qualifier-list to contain at least one type-specifier, and only one if it is a typedef-name
    4. Force parameter-declarations to interpret a TYPEID as a typedef-name in cases of ambiguity

    It is likely there is some more leftover "workaround" code that can removed, but I decided it was best to do the PR as-is for now, as that may take some careful thought (and maybe more tests to ensure no change in behavior).

    opened by natezb 16
  • Implement `_Atomic` support

    Implement `_Atomic` support

    As mentioned in https://github.com/eliben/pycparser/pull/428 we need _Atomic keyword support for C11. This keyword is rather special, as it can be both a qualifier and a specifier. C standard provides two grammar definitions for this:

    (6.7.2) type-specifer:
      void
      char
      short
      int
      long
      float
      double
      signed
      unsigned
      _Bool
      _Complex
      atomic-type-specifer
      struct-or-union-specifer
      enum-specifer
      typedef-name
    
    (6.7.2.4) atomic-type-specifer:
      _Atomic ( type-name )
    
    (6.7.3) type-qualifer:
      const
      restrict
      volatile
      _Atomic
    

    Depending on whether the _Atomic keyword is a specifier or a qualifier it refers to an atomic type. The atomic type can contain another atomic type, i.e. define nested atomic types, and it can also refer to specific parts of the type. As mentioned in the original PR all the following examples are valid:

    _Atomic(int *) a;
    _Atomic(int) *b;
    _Atomic int *c;
    

    All these samples need to generate different code after being parsed through pycparser and converted back to C, so the implementation needs to treat _Atomic qualifier and specifier separately. My suggestion is to follow the grammar of the C standard and use a normal qualifier for _Atomic qualifier, and a dedicated class like with enum.

    opened by vit9696 14
  • Publish sdist and bdist wheel

    Publish sdist and bdist wheel

    The benefits of wheels are well documented. See: https://pythonwheels.com/ This package is pure Python and publishing it as both source and as a wheel is simple.

    Would you accept a contribution to add a Makefile to this repo that would allow you to build both source distribution (sdist) and built distribution (wheel)?

    opened by groodt 14
  • pycparser 2.18+ break pygit2

    pycparser 2.18+ break pygit2

    ____________________ ERROR collecting test/test_archive.py _____________________
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/cffi/api.py:174: in _typeof
        result = self._parsed_types[cdecl]
    E   KeyError: 'int (*git_transport_certificate_check_cb)(git_cert *cert, int valid, const char *host, void *payload)'
    During handling of the above exception, another exception occurred:
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/cffi/cparser.py:276: in _parse
        ast = _get_parser().parse(fullcsource)
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/pycparser/c_parser.py:152: in parse
        debug=debuglevel)
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/pycparser/ply/yacc.py:331: in parse
        return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc)
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/pycparser/ply/yacc.py:1199: in parseopt_notrack
        tok = call_errorfunc(self.errorfunc, errtoken, self)
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/pycparser/ply/yacc.py:193: in call_errorfunc
        r = errorfunc(token)
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/pycparser/c_parser.py:1848: in p_error
        column=self.clex.find_tok_column(p)))
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/pycparser/plyparser.py:67: in _parse_error
        raise ParseError("%s: %s" % (coord, msg))
    E   pycparser.plyparser.ParseError: <cdef source string>:2:7: before: git_transport_certificate_check_cb
    During handling of the above exception, another exception occurred:
    test/test_archive.py:36: in <module>
        from pygit2 import Index, Oid, Tree, Object
    pygit2/__init__.py:41: in <module>
        from .remote import Remote, RemoteCallbacks, get_credentials
    pygit2/remote.py:73: in <module>
        class RemoteCallbacks(object):
    pygit2/remote.py:315: in RemoteCallbacks
        @ffi.callback('int (*git_transport_certificate_check_cb)'
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/cffi/api.py:382: in callback
        cdecl = self._typeof(cdecl, consider_function_as_funcptr=True)
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/cffi/api.py:177: in _typeof
        result = self._typeof_locked(cdecl)
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/cffi/api.py:162: in _typeof_locked
        type = self._parser.parse_type(cdecl)
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/cffi/cparser.py:476: in parse_type
        return self.parse_type_and_quals(cdecl)[0]
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/cffi/cparser.py:479: in parse_type_and_quals
        ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2]
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/cffi/cparser.py:278: in _parse
        self.convert_pycparser_error(e, csource)
    ../../../virtualenv/python3.4.6/lib/python3.4/site-packages/cffi/cparser.py:307: in convert_pycparser_error
        raise CDefError(msg)
    E   cffi.error.CDefError: cannot parse "int (*git_transport_certificate_check_cb)(git_cert *cert, int valid, const char *host, void *payload)"
    E   <cdef source string>:2:7: before: git_transport_certificate_check_cb
    

    I'm pretty sure somebody did report a bug, but I can't find it..

    opened by ignatenkobrain 13
  • read_pickle method is vulnerable

    read_pickle method is vulnerable

    import pickle
    class joel_test(object):
        def __reduce__(self):
            return eval, ("os.system('calc.exe')",)
    test = joel_test()
    f=open('joel_test','wb')
    pickle.dump(test,f)
    f.close()
    joel=LRTable()
    joel.read_pickle('joel_test')
    

    Hi, there is a vulnerability in read_pickle method in yacc.py, please see PoC above. It can execute arbitrary python commands resulting in command execution.

    opened by Joel-MalwareBenchmark 12
  • Support for Weakref in __slots__

    Support for Weakref in __slots__

    Hello, I see you added support for the slots mechanism in the ast. Nice. However, this breaks cffi downstream, since they use weak references to Enum, etc objects (see their cparser.py file). In turn this breaks petlib which I maintain. I think the solution is to include the "weakref" in the "slots" list of fields, as per the advice at: https://docs.python.org/2/reference/datamodel.html#slots Many thanks, George

    bug 
    opened by gdanezis 11
  • Redeclared types

    Redeclared types

    While using pycparser to parse a large, existing codebase, I immediately came upon the typedef-name problem. The changes in this pull request resolve and test for the issues encountered; in particular:

    • Reusing typedef names as structure/union member names
    • Reusing typedef names as variables names in inner scopes
    • Reusing typedef names as parameter names in declarations and definitions
    • Duplicated typedef declarations (non-standard, but apparently common and syntactically similar to the above)

    There is a corner case regarding parameter name scoping that required access to yacc.py's lookahead token (see p_direct_declarator_5 in c_parser.py for details). There are three solutions as I see it:

    • Modify yacc.py to expose the lookahead token as an attribute of the parser (...but requiring future PLY updates to be merged, not copied)
    • Keep track of the most-recent token via a custom tokenfunc (...but trusting that the parser's lookaheadstack is empty)
    • Use the inspect module to grab the value of the parser's lookahead variable (...but direct inspection of Python frames and local dictionaries is pretty evil)

    For the purpose of this change I decided to use the inspect module, as it is the least error-prone (it can inspect lookaheadstack to ensure it's empty) and the least invasive to the codebase. I can instead make lookahead/lookaheadstack attributes, if you're willing to support the merging of PLY.

    opened by Syeberman 11
  • ParseError while using gcc_E_lib example to parse my C code

    ParseError while using gcc_E_lib example to parse my C code

    Trying to parse the following c file

    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    
    #define  MaxElements 16
    
    typedef float HeapElementType;
    
    typedef  struct {
         HeapElementType key;
    } HeapNode;
    
    typedef struct {
            int Size;
            HeapNode Element[MaxElements+1];
    } HeapType;
    
    typedef enum {
        FALSE, TRUE
    } boolean;
    
    void CreateMinHeap(HeapType *Heap);
    boolean FullHeap(HeapType Heap);
    void InsertMinHeap(HeapType *Heap, HeapNode Item);
    boolean EmptyHeap(HeapType Heap);
    void DeleteMinHeap(HeapType *Heap, HeapNode *Item);
    void PrintHeap(HeapType Heap);
    
    int main()
    {
        HeapType AHeap;
        HeapNode AnItem;
        int m;
        FILE *fp;
    
        printf("Give m: ");
        scanf("%d", &m);
    
        CreateMinHeap(&AHeap);
    
        fp=fopen("transactions.txt","r");
    
        while(!feof(fp))
        {
            fscanf(fp, "%f", &AnItem.key);
            InsertMinHeap(&AHeap, AnItem);
            if(AHeap.Size>m)
                DeleteMinHeap(&AHeap, &AnItem);
        }
    
        PrintHeap(AHeap);
    
        printf("Transactions\n");
        while(!EmptyHeap(AHeap))
        {
            DeleteMinHeap(&AHeap, &AnItem);
            printf("%.2f ", AnItem.key);
        }
    
        return 0;
    }
    
    void CreateMinHeap(HeapType *Heap)
    {
      (*Heap).Size=0;
    }
    
    boolean EmptyHeap(HeapType Heap)
    {
      return (Heap.Size==0);
    }
    
    boolean FullHeap(HeapType Heap)
    {
      return (Heap.Size==MaxElements);
    }
    
    
    void PrintHeap(HeapType Heap)
    {
        int i;
        printf("Data Structure size =%d\n", Heap.Size);
        for(i=1;i<=Heap.Size;i++)
            printf("%.2f ", Heap.Element[i].key);
        printf("\n");
    }
    
    

    and get this error

    _error raise ParseError("%s: %s" % (coord, msg)) pycparser.plyparser.ParseError: /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/include/stdarg.h:40:27: before: __gnuc_va_list

    opened by tassosblackg 10
  • offsetof() support is incomplete

    offsetof() support is incomplete

    pycparser 2.13 added support for offsetof, and it is listed in the CHANGES file as "offsetof() the way gcc implements it". However, there are two differences between gcc's implemenation and pycparser's.

    The important one: pycparser defines the syntax for offsetof() as

            primary_expression  : OFFSETOF LPAREN type_name COMMA identifier RPAREN
    

    but gcc defines it as

         primary:
                 "__builtin_offsetof" "(" typename "," offsetof_member_designator ")"
    
         offsetof_member_designator:
                   identifier
                 | offsetof_member_designator "." identifier
                 | offsetof_member_designator "[" expr "]"
    
    

    The less important one (also visible above) is that gcc supports spelling offsetof as __builtin_offsetof.

    opened by shai-xio 10
  • _Pragma is not supported

    _Pragma is not supported

    The use of _Pragma instead of #pragma is accepted in C99. [1] pycparser raises a ParseError on this minimal main.c:

    /* main.c */
    _Pragma ("GCC dependency \"parse.y\"")
    
    int main() {
            return 0;
    }
    

    Python3+pycparser prompt:

    from pycparser import parse_file, c_generator
    parse_file('./main.c', use_cpp=False)
    

    Output:

    >>> parse_file('./main.c', use_cpp=False)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/home/jordy/.local/lib/python3.8/site-packages/pycparser/__init__.py", line 90, in parse_file
        return parser.parse(text, filename)
      File "/home/jordy/.local/lib/python3.8/site-packages/pycparser/c_parser.py", line 147, in parse
        return self.cparser.parse(
      File "/home/jordy/.local/lib/python3.8/site-packages/pycparser/ply/yacc.py", line 331, in parse
        return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc)
      File "/home/jordy/.local/lib/python3.8/site-packages/pycparser/ply/yacc.py", line 1199, in parseopt_notrack
        tok = call_errorfunc(self.errorfunc, errtoken, self)
      File "/home/jordy/.local/lib/python3.8/site-packages/pycparser/ply/yacc.py", line 193, in call_errorfunc
        r = errorfunc(token)
      File "/home/jordy/.local/lib/python3.8/site-packages/pycparser/c_parser.py", line 1931, in p_error
        self._parse_error(
      File "/home/jordy/.local/lib/python3.8/site-packages/pycparser/plyparser.py", line 67, in _parse_error
        raise ParseError("%s: %s" % (coord, msg))
    pycparser.plyparser.ParseError: ./main.c:1:10: before: "GCC dependency \"parse.y\""
    

    [1] https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html

    opened by jordr 1
  • Labels at the end of compound statements

    Labels at the end of compound statements

    This sample would be incorrect in C++, iirc, but it is valid in modern C (sorry, I can't find the standard version when it was added first):

    int main(void) {
        switch(0) {
            case 0: {
                if (1) {
                    goto label;
                }
            label:
            }
        }
    }
    

    gcc works properly even w/ -std=c99 (clang fails, but looks like it's possible to fix w/ proper flags), pycparser fails with ParseError: before: }

    @eliben I'm not sure if you want to support this feature, but I'd really appreciate an advice. Will try to workaround during the preprocessing stage, label:; should help here, probably.

    opened by nxmaintainer 0
  • Can't parse like this “for (iLoop = 0; iLoop < g_stNotesParams.iNoteNums; (void)({iLoop++;b=iLoop;}))”

    Can't parse like this “for (iLoop = 0; iLoop < g_stNotesParams.iNoteNums; (void)({iLoop++;b=iLoop;}))”

    I wrote some code like this:

    void testPrintNotes()
    {
        int iLoop = 0;
        int b=0;
        for (iLoop = 0; iLoop < g_stNotesParams.iNoteNums; (void)({iLoop++;b=iLoop;}))
        {
            printf("%s\n", g_stNotesParams.acNotesNames[iLoop]);
        }
    }
    

    It can work well in Linux(actually in WSL):

    $ uname -a
    Linux DESKTOP-JHULLF6 4.4.0-19041-Microsoft #2311-Microsoft Tue Nov 08 17:09:00 PST 2022 x86_64 x86_64 x86_64 GNU/Linux
    

    But the pycparser cannot parse the code, and raise the error:

    Traceback (most recent call last):
      File "func_calls.py", line 75, in <module>
        ast = parse_file('./codes/notes.c', use_cpp=True, cpp_path='gcc', cpp_args=['-E','-I/home/xkey/WorkSpace/pycparser/utils/fake_libc_include/'])
      File "/home/xkey/.local/lib/python3.8/site-packages/pycparser/__init__.py", line 90, in parse_file
        return parser.parse(text, filename)
      File "/home/xkey/.local/lib/python3.8/site-packages/pycparser/c_parser.py", line 147, in parse
        return self.cparser.parse(
      File "/home/xkey/.local/lib/python3.8/site-packages/pycparser/ply/yacc.py", line 331, in parse
        return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc)
      File "/home/xkey/.local/lib/python3.8/site-packages/pycparser/ply/yacc.py", line 1199, in parseopt_notrack
        tok = call_errorfunc(self.errorfunc, errtoken, self)
      File "/home/xkey/.local/lib/python3.8/site-packages/pycparser/ply/yacc.py", line 193, in call_errorfunc
        r = errorfunc(token)
      File "/home/xkey/.local/lib/python3.8/site-packages/pycparser/c_parser.py", line 1931, in p_error
        self._parse_error(
      File "/home/xkey/.local/lib/python3.8/site-packages/pycparser/plyparser.py", line 67, in _parse_error
        raise ParseError("%s: %s" % (coord, msg))
    pycparser.plyparser.ParseError: ./codes/notes.c:35:63: before: {
    
    opened by xkey3960 0
  • Fix #478 (pragma-before-semicolon)

    Fix #478 (pragma-before-semicolon)

    This makes code written as

    a += 1
    #pragma foo
    ;
    

    to be parsed as

    a += 1
    ;
    #pragma foo
    

    Handling #pragma (and especially corner-cases) with minimal impact is tricky.
    This focuses only on the #pragma-before-; case, by generating the #pragma pseudo-statement after the real statement.

    p_pragmacomp_or_statement covers the most common use-cases.
    For p_statement's possible sub-rules:

    • p_labeled_statement: Already handles #pragma before ; through the pragmacomp_or_statement rule.
    • p_expression_statement: Added sub-rule.
    • p_compound_statement: Not relevant.
    • p_selection_statement: Already handles #pragma before ; through the pragmacomp_or_statement rule.
    • p_iteration_statement: Several sub-rules already handle #pragma through the pragmacomp_or_statement rule which is already fixed by #479. Tweaks added to p_continue, p_break, p_return.
    • p_jump_statement: Modified in a similar way as p_expression_statement
    • pppragma_directive: Not relevant
    • static_assert: Not relevant

    Notes:

    • I'm not sure if the modified rules should be written as an additional line, or with an _opt suffix.
      E.g. Would you recommend writing:

        def p_jump_statement_2(self, p):
            """ jump_statement  : BREAK SEMI 
                                | BREAK pppragma_directive_list SEMI
            """
      

      or rather change to something like:

        def p_jump_statement_2(self, p):
            """ jump_statement  : BREAK pppragma_directive_list_opt SEMI """
      

      Does one style have an impact on parsing (performance, readability...) ?

    • Similarly, for rules that rely on len(p), would you recommend writing rules as:

        def p_jump_statement_5(self, p):
            """ jump_statement  : RETURN expression pppragma_directive_list SEMI
                                | RETURN pppragma_directive_list SEMI
            """
            p[0] = [c_ast.Return(p[2] if len(p) == 5 else None, self._token_coord(p, 1))] + p[3 if len(p) == 5 else 2]
      

      or split the rule to not rely on len(p) as :

        def p_jump_statement_5(self, p):
            """ jump_statement  : RETURN expression pppragma_directive_list SEMI
            """
            p[0] = [c_ast.Return(p[2], self._token_coord(p, 1))] + p[3]
      
        def p_jump_statement_6(self, p):
            """ jump_statement  : RETURN pppragma_directive_list SEMI
            """
            p[0] = [c_ast.Return(None, self._token_coord(p, 1))] + p[2]
      
    opened by ldore 2
  • Grammar railroad diagram

    Grammar railroad diagram

    Using a script to extract the grammar rules from https://github.com/eliben/pycparser/blob/master/pycparser/c_parser.py and manually adding the tokens from https://github.com/eliben/pycparser/blob/master/pycparser/c_lexer.py we can have a navigable railroad diagram.

    Copy and paste the EBNF shown bellow on https://www.bottlecaps.de/rr/ui on the tab Edit Grammar then click the tab View Diagram:

    translation_unit_or_empty   ::= translation_unit
                                            | empty
    
     translation_unit    ::= external_declaration
    
     translation_unit    ::= translation_unit external_declaration
    
     external_declaration    ::= function_definition
    
     external_declaration    ::= declaration
    
     external_declaration    ::= pp_directive
                                        | pppragma_directive
    
     external_declaration    ::= SEMI
    
     external_declaration    ::= static_assert
    
     static_assert           ::= _STATIC_ASSERT LPAREN constant_expression COMMA unified_string_literal RPAREN
                                        | _STATIC_ASSERT LPAREN constant_expression RPAREN
    
     pp_directive  ::= PPHASH
    
     pppragma_directive      ::= PPPRAGMA
                                        | PPPRAGMA PPPRAGMASTR
    
     pppragma_directive_list ::= pppragma_directive
                                        | pppragma_directive_list pppragma_directive
    
     function_definition ::= id_declarator declaration_list_opt compound_statement
    
     function_definition ::= declaration_specifiers id_declarator declaration_list_opt compound_statement
    
     statement   ::= labeled_statement
                            | expression_statement
                            | compound_statement
                            | selection_statement
                            | iteration_statement
                            | jump_statement
                            | pppragma_directive
                            | static_assert
    
     pragmacomp_or_statement     ::= pppragma_directive_list statement
                                            | statement
    
     decl_body ::= declaration_specifiers init_declarator_list_opt
                          | declaration_specifiers_no_type id_init_declarator_list_opt
    
     declaration ::= decl_body SEMI
    
     declaration_list    ::= declaration
                                    | declaration_list declaration
    
     declaration_specifiers_no_type  ::= type_qualifier declaration_specifiers_no_type_opt
    
     declaration_specifiers_no_type  ::= storage_class_specifier declaration_specifiers_no_type_opt
    
     declaration_specifiers_no_type  ::= function_specifier declaration_specifiers_no_type_opt
    
     declaration_specifiers_no_type  ::= atomic_specifier declaration_specifiers_no_type_opt
    
     declaration_specifiers_no_type  ::= alignment_specifier declaration_specifiers_no_type_opt
    
     declaration_specifiers  ::= declaration_specifiers type_qualifier
    
     declaration_specifiers  ::= declaration_specifiers storage_class_specifier
    
     declaration_specifiers  ::= declaration_specifiers function_specifier
    
     declaration_specifiers  ::= declaration_specifiers type_specifier_no_typeid
    
     declaration_specifiers  ::= type_specifier
    
     declaration_specifiers  ::= declaration_specifiers_no_type type_specifier
    
     declaration_specifiers  ::= declaration_specifiers alignment_specifier
    
     storage_class_specifier ::= AUTO
                                        | REGISTER
                                        | STATIC
                                        | EXTERN
                                        | TYPEDEF
                                        | _THREAD_LOCAL
    
     function_specifier  ::= INLINE
                                    | _NORETURN
    
     type_specifier_no_typeid  ::= VOID
                                          | _BOOL
                                          | CHAR
                                          | SHORT
                                          | INT
                                          | LONG
                                          | FLOAT
                                          | DOUBLE
                                          | _COMPLEX
                                          | SIGNED
                                          | UNSIGNED
                                          | __INT128
    
     type_specifier  ::= typedef_name
                                | enum_specifier
                                | struct_or_union_specifier
                                | type_specifier_no_typeid
                                | atomic_specifier
    
     atomic_specifier  ::= _ATOMIC LPAREN type_name RPAREN
    
     type_qualifier  ::= CONST
                                | RESTRICT
                                | VOLATILE
                                | _ATOMIC
    
     init_declarator_list    ::= init_declarator
                                        | init_declarator_list COMMA init_declarator
    
     init_declarator ::= declarator
                                | declarator EQUALS initializer
    
     id_init_declarator_list    ::= id_init_declarator
                                           | id_init_declarator_list COMMA init_declarator
    
     id_init_declarator ::= id_declarator
                                   | id_declarator EQUALS initializer
    
     specifier_qualifier_list    ::= specifier_qualifier_list type_specifier_no_typeid
    
     specifier_qualifier_list    ::= specifier_qualifier_list type_qualifier
    
     specifier_qualifier_list  ::= type_specifier
    
     specifier_qualifier_list  ::= type_qualifier_list type_specifier
    
     specifier_qualifier_list  ::= alignment_specifier
    
     specifier_qualifier_list  ::= specifier_qualifier_list alignment_specifier
    
     struct_or_union_specifier   ::= struct_or_union ID
                                            | struct_or_union TYPEID
    
     struct_or_union_specifier ::= struct_or_union brace_open struct_declaration_list brace_close
                                          | struct_or_union brace_open brace_close
    
     struct_or_union_specifier   ::= struct_or_union ID brace_open struct_declaration_list brace_close
                                            | struct_or_union ID brace_open brace_close
                                            | struct_or_union TYPEID brace_open struct_declaration_list brace_close
                                            | struct_or_union TYPEID brace_open brace_close
    
     struct_or_union ::= STRUCT
                                | UNION
    
     struct_declaration_list     ::= struct_declaration
                                            | struct_declaration_list struct_declaration
    
     struct_declaration ::= specifier_qualifier_list struct_declarator_list_opt SEMI
    
     struct_declaration ::= SEMI
    
     struct_declaration ::= pppragma_directive
    
     struct_declarator_list  ::= struct_declarator
                                        | struct_declarator_list COMMA struct_declarator
    
     struct_declarator ::= declarator
    
     struct_declarator   ::= declarator COLON constant_expression
                                    | COLON constant_expression
    
     enum_specifier  ::= ENUM ID
                                | ENUM TYPEID
    
     enum_specifier  ::= ENUM brace_open enumerator_list brace_close
    
     enum_specifier  ::= ENUM ID brace_open enumerator_list brace_close
                                | ENUM TYPEID brace_open enumerator_list brace_close
    
     enumerator_list ::= enumerator
                                | enumerator_list COMMA
                                | enumerator_list COMMA enumerator
    
     alignment_specifier  ::= _ALIGNAS LPAREN type_name RPAREN
                                     | _ALIGNAS LPAREN constant_expression RPAREN
    
     enumerator  ::= ID
                            | ID EQUALS constant_expression
    
     declarator  ::= id_declarator
                            | typeid_declarator
    
     xxx_declarator  ::= direct_xxx_declarator
    
     xxx_declarator  ::= pointer direct_xxx_declarator
    
     direct_xxx_declarator   ::= yyy
    
     direct_xxx_declarator   ::= LPAREN xxx_declarator RPAREN
    
     direct_xxx_declarator   ::= direct_xxx_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET
    
     direct_xxx_declarator   ::= direct_xxx_declarator LBRACKET STATIC type_qualifier_list_opt assignment_expression RBRACKET
                                        | direct_xxx_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET
    
     direct_xxx_declarator   ::= direct_xxx_declarator LBRACKET type_qualifier_list_opt TIMES RBRACKET
    
     direct_xxx_declarator   ::= direct_xxx_declarator LPAREN parameter_type_list RPAREN
                                        | direct_xxx_declarator LPAREN identifier_list_opt RPAREN
    
     pointer ::= TIMES type_qualifier_list_opt
                        | TIMES type_qualifier_list_opt pointer
    
     type_qualifier_list ::= type_qualifier
                                    | type_qualifier_list type_qualifier
    
     parameter_type_list ::= parameter_list
                                    | parameter_list COMMA ELLIPSIS
    
     parameter_list  ::= parameter_declaration
                                | parameter_list COMMA parameter_declaration
    
     parameter_declaration   ::= declaration_specifiers id_declarator
                                        | declaration_specifiers typeid_noparen_declarator
    
     parameter_declaration   ::= declaration_specifiers abstract_declarator_opt
    
     identifier_list ::= identifier
                                | identifier_list COMMA identifier
    
     initializer ::= assignment_expression
    
     initializer ::= brace_open initializer_list_opt brace_close
                            | brace_open initializer_list COMMA brace_close
    
     initializer_list    ::= designation_opt initializer
                                    | initializer_list COMMA designation_opt initializer
    
     designation ::= designator_list EQUALS
    
     designator_list ::= designator
                                | designator_list designator
    
     designator  ::= LBRACKET constant_expression RBRACKET
                            | PERIOD identifier
    
     type_name   ::= specifier_qualifier_list abstract_declarator_opt
    
     abstract_declarator     ::= pointer
    
     abstract_declarator     ::= pointer direct_abstract_declarator
    
     abstract_declarator     ::= direct_abstract_declarator
    
     direct_abstract_declarator  ::= LPAREN abstract_declarator RPAREN
     direct_abstract_declarator  ::= direct_abstract_declarator LBRACKET assignment_expression_opt RBRACKET
    
     direct_abstract_declarator  ::= LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET
    
     direct_abstract_declarator  ::= direct_abstract_declarator LBRACKET TIMES RBRACKET
    
     direct_abstract_declarator  ::= LBRACKET TIMES RBRACKET
    
     direct_abstract_declarator  ::= direct_abstract_declarator LPAREN parameter_type_list_opt RPAREN
    
     direct_abstract_declarator  ::= LPAREN parameter_type_list_opt RPAREN
    
     block_item  ::= declaration
                            | statement
    
     block_item_list ::= block_item
                                | block_item_list block_item
    
     compound_statement ::= brace_open block_item_list_opt brace_close
     labeled_statement ::= ID COLON pragmacomp_or_statement
     labeled_statement ::= CASE constant_expression COLON pragmacomp_or_statement
     labeled_statement ::= DEFAULT COLON pragmacomp_or_statement
     selection_statement ::= IF LPAREN expression RPAREN pragmacomp_or_statement
     selection_statement ::= IF LPAREN expression RPAREN statement ELSE pragmacomp_or_statement
     selection_statement ::= SWITCH LPAREN expression RPAREN pragmacomp_or_statement
     iteration_statement ::= WHILE LPAREN expression RPAREN pragmacomp_or_statement
     iteration_statement ::= DO pragmacomp_or_statement WHILE LPAREN expression RPAREN SEMI
     iteration_statement ::= FOR LPAREN expression_opt SEMI expression_opt SEMI expression_opt RPAREN pragmacomp_or_statement
     iteration_statement ::= FOR LPAREN declaration expression_opt SEMI expression_opt RPAREN pragmacomp_or_statement
     jump_statement  ::= GOTO ID SEMI
     jump_statement  ::= BREAK SEMI
     jump_statement  ::= CONTINUE SEMI
     jump_statement  ::= RETURN expression SEMI
                                | RETURN SEMI
    
     expression_statement ::= expression_opt SEMI
     expression  ::= assignment_expression
                            | expression COMMA assignment_expression
    
     assignment_expression ::= LPAREN compound_statement RPAREN
     typedef_name ::= TYPEID
     assignment_expression   ::= conditional_expression
                                        | unary_expression assignment_operator assignment_expression
    
     assignment_operator ::= EQUALS
                                    | XOREQUAL
                                    | TIMESEQUAL
                                    | DIVEQUAL
                                    | MODEQUAL
                                    | PLUSEQUAL
                                    | MINUSEQUAL
                                    | LSHIFTEQUAL
                                    | RSHIFTEQUAL
                                    | ANDEQUAL
                                    | OREQUAL
    
     constant_expression ::= conditional_expression
     conditional_expression  ::= binary_expression
                                        | binary_expression CONDOP expression COLON conditional_expression
    
     binary_expression   ::= cast_expression
                                    | binary_expression TIMES binary_expression
                                    | binary_expression DIVIDE binary_expression
                                    | binary_expression MOD binary_expression
                                    | binary_expression PLUS binary_expression
                                    | binary_expression MINUS binary_expression
                                    | binary_expression RSHIFT binary_expression
                                    | binary_expression LSHIFT binary_expression
                                    | binary_expression LT binary_expression
                                    | binary_expression LE binary_expression
                                    | binary_expression GE binary_expression
                                    | binary_expression GT binary_expression
                                    | binary_expression EQ binary_expression
                                    | binary_expression NE binary_expression
                                    | binary_expression AND binary_expression
                                    | binary_expression OR binary_expression
                                    | binary_expression XOR binary_expression
                                    | binary_expression LAND binary_expression
                                    | binary_expression LOR binary_expression
    
     cast_expression ::= unary_expression
     cast_expression ::= LPAREN type_name RPAREN cast_expression
     unary_expression    ::= postfix_expression
     unary_expression    ::= PLUSPLUS unary_expression
                                    | MINUSMINUS unary_expression
                                    | unary_operator cast_expression
    
     unary_expression    ::= SIZEOF unary_expression
                                    | SIZEOF LPAREN type_name RPAREN
                                    | _ALIGNOF LPAREN type_name RPAREN
    
     unary_operator  ::= AND
                                | TIMES
                                | PLUS
                                | MINUS
                                | NOT
                                | LNOT
    
     postfix_expression  ::= primary_expression
     postfix_expression  ::= postfix_expression LBRACKET expression RBRACKET
     postfix_expression  ::= postfix_expression LPAREN argument_expression_list RPAREN
                                    | postfix_expression LPAREN RPAREN
    
     postfix_expression  ::= postfix_expression PERIOD ID
                                    | postfix_expression PERIOD TYPEID
                                    | postfix_expression ARROW ID
                                    | postfix_expression ARROW TYPEID
    
     postfix_expression  ::= postfix_expression PLUSPLUS
                                    | postfix_expression MINUSMINUS
    
     postfix_expression  ::= LPAREN type_name RPAREN brace_open initializer_list brace_close
                                    | LPAREN type_name RPAREN brace_open initializer_list COMMA brace_close
    
     primary_expression  ::= identifier
     primary_expression  ::= constant
     primary_expression  ::= unified_string_literal
                                    | unified_wstring_literal
    
     primary_expression  ::= LPAREN expression RPAREN
     primary_expression  ::= OFFSETOF LPAREN type_name COMMA offsetof_member_designator RPAREN
    
     offsetof_member_designator ::= identifier
                                             | offsetof_member_designator PERIOD identifier
                                             | offsetof_member_designator LBRACKET expression RBRACKET
    
     argument_expression_list    ::= assignment_expression
                                            | argument_expression_list COMMA assignment_expression
    
     identifier  ::= ID
     constant    ::= INT_CONST_DEC
                            | INT_CONST_OCT
                            | INT_CONST_HEX
                            | INT_CONST_BIN
                            | INT_CONST_CHAR
    
     constant    ::= FLOAT_CONST
                            | HEX_FLOAT_CONST
    
     constant    ::= CHAR_CONST
                            | WCHAR_CONST
                            | U8CHAR_CONST
                            | U16CHAR_CONST
                            | U32CHAR_CONST
    
     unified_string_literal  ::= STRING_LITERAL
                                        | unified_string_literal STRING_LITERAL
    
     unified_wstring_literal ::= WSTRING_LITERAL
                                        | U8STRING_LITERAL
                                        | U16STRING_LITERAL
                                        | U32STRING_LITERAL
                                        | unified_wstring_literal WSTRING_LITERAL
                                        | unified_wstring_literal U8STRING_LITERAL
                                        | unified_wstring_literal U16STRING_LITERAL
                                        | unified_wstring_literal U32STRING_LITERAL
    
     brace_open  ::=   LBRACE
    
     brace_close ::=   RBRACE
    
    
     //Tokens
    
    AUTO	::=	'auto'
    BREAK	::=	'break'
    CASE	::=	'case'
    CHAR	::=	'char'
    CONST	::=	'const'
    CONTINUE	::=	'continue'
    DEFAULT	::=	'default'
    DO	::=	'do'
    DOUBLE	::=	'double'
    ELSE	::=	'else'
    ENUM	::=	'enum'
    EXTERN	::=	'extern'
    FLOAT	::=	'float'
    FOR	::=	'for'
    GOTO	::=	'goto'
    IF	::=	'if'
    INLINE	::=	'inline'
    INT	::=	'int'
    LONG	::=	'long'
    REGISTER	::=	'register'
    OFFSETOF	::=	'offsetof'
    RESTRICT	::=	'restrict'
    RETURN	::=	'return'
    SHORT	::=	'short'
    SIGNED	::=	'signed'
    SIZEOF	::=	'sizeof'
    STATIC	::=	'static'
    STRUCT	::=	'struct'
    SWITCH	::=	'switch'
    TYPEDEF	::=	'typedef'
    UNION	::=	'union'
    UNSIGNED	::=	'unsigned'
    VOID	::=	'void'
    VOLATILE	::=	'volatile'
    WHILE	::=	'while'
    __INT128	::=	'__int128'
    
    _BOOL	::=	'_bool'
    _COMPLEX	::=	'_complex'
    _NORETURN	::=	'_noreturn'
    _THREAD_LOCAL	::=	'_thread_local'
    _STATIC_ASSERT	::=	'_static_assert'
    _ATOMIC	::=	'_atomic'
    _ALIGNOF	::=	'_alignof'
    _ALIGNAS	::=	'_alignas'
    
    //# Operators
    PLUS              ::= '+'
    MINUS             ::= '-'
    TIMES             ::= '*'
    DIVIDE            ::= '/'
    MOD               ::= '%'
    OR                ::= '|'
    AND               ::= '&'
    NOT               ::= '~'
    XOR               ::= '^'
    LSHIFT            ::= '<<'
    RSHIFT            ::= '>>'
    LOR               ::= '||'
    LAND              ::= '&&'
    LNOT              ::= '!'
    LT                ::= '<'
    GT                ::= '>'
    LE                ::= '<='
    GE                ::= '>='
    EQ                ::= '=='
    NE                ::= '!='
    
    //# Assignment operators
    EQUALS            ::= '='
    TIMESEQUAL        ::= '*='
    DIVEQUAL          ::= '/='
    MODEQUAL          ::= '%='
    PLUSEQUAL         ::= '+='
    MINUSEQUAL        ::= '-='
    LSHIFTEQUAL       ::= '<<='
    RSHIFTEQUAL       ::= '>>='
    ANDEQUAL          ::= '&='
    OREQUAL           ::= '|='
    XOREQUAL          ::= '^='
    
    //# Increment/decrement
    PLUSPLUS          ::= '++'
    MINUSMINUS        ::= '--'
    
    //# ->
    ARROW             ::= '->'
    
    //# ?
    CONDOP            ::= '\?'
    
    //# Delimiters
    LPAREN            ::= '('
    RPAREN            ::= ')'
    LBRACKET          ::= '['
    RBRACKET          ::= ']'
    COMMA             ::= ','
    PERIOD            ::= '.'
    SEMI              ::= ';'
    COLON             ::= ':'
    ELLIPSIS          ::= '...'
    
    opened by mingodad 0
  • #Pragmas in statements raise error

    #Pragmas in statements raise error

    Pycparser raises a parser error when trying to parse statements that contain #pragma.
    A typical example comes from Apple's iPhoneOS.sdk/usr/include/sys/event.h:371 (SDK 13).

    The relevant sys/event.h:371 source code is:

    struct knote;
    SLIST_HEAD(klist, knote);
    

    Once pre-processed, the SLIST_HEAD macro expands to:

    struct knote;
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wnullability-completeness"
     struct klist { struct knote *slh_first; }
    #pragma clang diagnostic pop
     ;
    

    Note the #pragma that comes before the end-of-statement ;.

    When parsing, pycparser raises the following error:

    pycparser.plyparser.ParseError: Platforms/iphoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/sys/event.h:371:2: before: pragma
    
    patches-welcome 
    opened by ldore-ks 0
Owner
Eli Bendersky
Eli Bendersky
A simple but complete exercise to learning Python

ResourceReservationProject This is a simple but complete exercise to learning Python. Task and flow chart We are going to do a new fork of the existin

null 2 Nov 14, 2022
A complete python calculator with 2 modes Float and Int numbers.

Python Calculator This program is made for learning purpose. Getting started This Program runs using python, install it via terminal or from thier ofi

Felix Sanchez 1 Jan 18, 2022
Analisador de strings feito em Python // String parser made in Python

Este é um analisador feito em Python, neste programa, estou estudando funções e a sua junção com "if's" e dados colocados pelo usuário. Neste código,

Dev Nasser 1 Nov 3, 2021
A repository containing useful resources needed to complete the SUSE Scholarship Challenge #UdacitySUSEScholars #poweredbySUSE

SUSE-udacity-cloud-native-scholarship A repository containing useful resources needed to complete the SUSE Scholarship Challenge #UdacitySUSEScholars

Nandini Proothi 11 Dec 2, 2021
Install Firefox from Mozilla.org easily, complete with .desktop file creation.

firefox-installer Install Firefox from Mozilla.org easily, complete with .desktop file creation. Dependencies Python 3 Python LXML Debian/Ubuntu: sudo

rany 7 Nov 4, 2022
Running a complete single-node all-in-one cluster instance of TIBCO ActiveMatrix™ BusinessWorks 6.8.0.

TIBCO ActiveMatrix™ BusinessWorks 6.8 Docker Image Image for running a complete single-node all-in-one cluster instance of TIBCO ActiveMatrix™ Busines

Federico Alpi 1 Dec 10, 2021
The semi-complete teardown of Cosmo's Cosmic Adventure.

The semi-complete teardown of Cosmo's Cosmic Adventure.

Scott Smitelli 10 Dec 2, 2022
Taxonomy addition for complete trees

TACT: Taxonomic Addition for Complete Trees TACT is a Python app for stochastic polytomy resolution. It uses birth-death-sampling estimators across an

Jonathan Chang 3 Jun 7, 2022
A Gura parser implementation for Python

Gura parser This repository contains the implementation of a Gura format parser in Python. Installation pip install gura-parser Usage import gura gur

JWare Solutions 19 Jan 25, 2022
Parser for RISC OS Font control characters in Python

RISC OS Font control parsing in Python This repository contains a class (FontControlParser) for parsing font control codes from a byte squence, in Pyt

Charles Ferguson 1 Nov 2, 2021
A python library for writing parser-based interactive fiction.

About IntFicPy A python library for writing parser-based interactive fiction. Currently in early development. IntFicPy Docs Parser-based interactive f

Rita Lester 31 Nov 23, 2022
Neogex is a human readable parser standard, being implemented in Python

Neogex (New Expressions) Parsing Standard Much like Regex, Neogex allows for string parsing and validation based on a set of requirements. Unlike Rege

Seamus Donnellan 1 Dec 17, 2021
Ergonomic option parser on top of dataclasses, inspired by structopt.

oppapī Ergonomic option parser on top of dataclasses, inspired by structopt. Usage from typing import Optional from oppapi import from_args, oppapi @

yukinarit 4 Jul 19, 2022
Parser for air tickets' price

Air-ticket-price-parser Parser for air tickets' price How to Install Firefox If geckodriver.exe is not compatible with your Firefox version, download

Situ Xuannn 1 Dec 13, 2021
A simple string parser based on CLR to check whether a string is acceptable or not for a given grammar.

A simple string parser based on CLR to check whether a string is acceptable or not for a given grammar.

Bharath M Kulkarni 1 Dec 15, 2021
A parser of Windows Defender's DetectionHistory forensic artifact, containing substantial info about quarantined files and executables.

A parser of Windows Defender's DetectionHistory forensic artifact, containing substantial info about quarantined files and executables.

Jordan Klepser 101 Oct 30, 2022
The parser of a timetable of tennis matches for Flashscore website

FlashscoreParser The parser of a timetable of tennis matches for Flashscore website. The program collects the schedule of tennis matches for two days

Valendovsky 1 Jul 15, 2022
An ultra fast cross-platform multiple screenshots module in pure Python using ctypes.

Python MSS from mss import mss # The simplest use, save a screen shot of the 1st monitor with mss() as sct: sct.shot() An ultra fast cross-platfo

Mickaël Schoentgen 799 Dec 30, 2022
Ikaros is a free financial library built in pure python that can be used to get information for single stocks, generate signals and build prortfolios

Ikaros is a free financial library built in pure python that can be used to get information for single stocks, generate signals and build prortfolios

Salma Saidane 64 Sep 28, 2022