eliben / pycparser

:snake: Complete C99 parser in pure Python
Other
3.24k stars 609 forks source link

A variable which declared as static within a function causes parser to fail with an error ":4700:18: before: locale" #549

Closed retif closed 3 months ago

retif commented 3 months ago

Static variable declaration

static locale_t locale = NULL;

from the function

static inline float spa_strtof(const char *str, char **endptr)
{
    static locale_t locale = NULL;
    locale_t prev;

    float v;

    if ((locale == NULL))
        locale = newlocale(LC_ALL_MASK, "C", NULL);
    prev = uselocale(locale);
    v = strtof(str, endptr);
    uselocale(prev);
    return v;
}

causes parser to fail.

At yacc.py:1070

t = actions[state].get(ltype) # where state = 28 and ltype = "ID" 

t is resolved to None value

Output with debuglevel=1

State  : 159
Stack  : translation_unit declaration_specifiers id_declarator declaration_list_opt . LexToken(LBRACE,'{',4698,151782)
Action : Shift and goto state 147

State  : 147
Stack  : translation_unit declaration_specifiers id_declarator declaration_list_opt LBRACE . LexToken(STATIC,'static',4700,151786)
Action : Reduce rule [brace_open -> LBRACE] with ['{'] and goto state 156
Result : <str @ 0xb455a8> ('{')

State  : 156
Stack  : translation_unit declaration_specifiers id_declarator declaration_list_opt brace_open . LexToken(STATIC,'static',4700,151786)
Action : Shift and goto state 29

State  : 29
Stack  : translation_unit declaration_specifiers id_declarator declaration_list_opt brace_open STATIC . LexToken(ID,'locale_t',4700,151793)
Action : Reduce rule [storage_class_specifier -> STATIC] with ['static'] and goto state 22
Result : <str @ 0x7efde71a7090> ('static')

State  : 22
Stack  : translation_unit declaration_specifiers id_declarator declaration_list_opt brace_open storage_class_specifier . LexToken(ID,'locale_t',4700,151793)
Action : Reduce rule [empty -> <empty>] with [] and goto state 122
Result : <NoneType @ 0xa3f8a0> (None)

State  : 122
Stack  : translation_unit declaration_specifiers id_declarator declaration_list_opt brace_open storage_class_specifier empty . LexToken(ID,'locale_t',4700,151793)
Action : Reduce rule [declaration_specifiers_no_type_opt -> empty] with [None] and goto state 125
Result : <NoneType @ 0xa3f8a0> (None)

State  : 125
Stack  : translation_unit declaration_specifiers id_declarator declaration_list_opt brace_open storage_class_specifier declaration_specifiers_no_type_opt . LexToken(ID,'locale_t',4700,151793)
Action : Reduce rule [declaration_specifiers_no_type -> storage_class_specifier declaration_specifiers_no_type_opt] with ['static',None] and goto state 84
Result : <dict @ 0x7efde6edffc0> ({'qual': [], 'storage': ['static'], 'typ ...)

State  : 84
Stack  : translation_unit declaration_specifiers id_declarator declaration_list_opt brace_open declaration_specifiers_no_type . LexToken(ID,'locale_t',4700,151793)
Action : Shift and goto state 28

State  : 28
Stack  : translation_unit declaration_specifiers id_declarator declaration_list_opt brace_open declaration_specifiers_no_type ID . LexToken(ID,'locale',4700,151802)
ERROR: Error  : translation_unit declaration_specifiers id_declarator declaration_list_opt brace_open declaration_specifiers_no_type ID . LexToken(ID,'locale',4700,151802)
retif commented 3 months ago

May be the issue there that locale_t is considered as LexToken(ID,'locale_t',4700,151793) instead LexToken(TYPEID,'locale_t',4700,151793)

I see that the type definition of "locale_t" is not present in the content provided to .parse() method

eliben commented 3 months ago

This is likely relevant: https://eli.thegreenplace.net/2015/on-parsing-c-type-declarations-and-fake-headers

Please double check that all types are defined

retif commented 3 months ago

https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/2997

As I see the issue which I faced with pipewire-py project(which with the help of pycparser generates bindings from c to py) is coming from standard locale_t type not being included. It seems should be implicitly included by the compiler(some of, some standard of), but in our case we dont use compiler at all. We just pack all includes and trying to parse them.

Not sure how that worked for original package developer.

And its clearly not an pycparser issue. Its preprocessing issue.

The only thing I could wish from pycparser is to give more informative error when user trying to parse undefined types or variables. If it falls, why not to fall a bit more gracefully 😊