add support for computed constants in header files
Created originally on Bitbucket by ernwa (Andrea Waite)
as it stands cffi chokes on declarations like
buf_t payload[ SZ_RX_BUF-4 ];
for two reasons; one, preprocessor support isn't used. So the #define giving SZ_RX_BUF isn't handled. If we run the header first through gcc -E to preprocess, there's a second more serious problem -- the preprocessor's output is, for example
buf_t payload[ 255 -4 ];
at this point, cffi chokes on the constant 255 - 4. This makes an entire class of C headers unusable without extensive and error-prone hand modification, and prevents one from feeding cffi the same code that one compiles. It's annoying
an example traceback is
Traceback (most recent call last):
File "test_cvorg_protocol_threaded.py", line 5, in <module>
ffi.cdef(file('cvorg_protocol_threaded.i.h','r').read())
File "/usr/local/lib/python2.7/site-packages/cffi/api.py", line 105, in cdef
self._cdef(csource, override=override, packed=packed)
File "/usr/local/lib/python2.7/site-packages/cffi/api.py", line 119, in _cdef
self._parser.parse(csource, override=override, **options)
File "/usr/local/lib/python2.7/site-packages/cffi/cparser.py", line 299, in parse
self._internal_parse(csource)
File "/usr/local/lib/python2.7/site-packages/cffi/cparser.py", line 335, in _internal_parse
decl.type, name=decl.name, partial_length_ok=True)
File "/usr/local/lib/python2.7/site-packages/cffi/cparser.py", line 566, in _get_type_and_quals
tp = self._get_struct_union_enum_type('union', type, name)
File "/usr/local/lib/python2.7/site-packages/cffi/cparser.py", line 727, in _get_struct_union_enum_type
partial_length_ok=True)
File "/usr/local/lib/python2.7/site-packages/cffi/cparser.py", line 581, in _get_type_and_quals
nested=True), 0
File "/usr/local/lib/python2.7/site-packages/cffi/cparser.py", line 727, in _get_struct_union_enum_type
partial_length_ok=True)
File "/usr/local/lib/python2.7/site-packages/cffi/cparser.py", line 511, in _get_type_and_quals
typenode.dim, partial_length_ok=partial_length_ok)
File "/usr/local/lib/python2.7/site-packages/cffi/cparser.py", line 796, in _parse_constant
"simple numeric constant" % exprnode.coord.line)
cffi.api.FFIError: :51: unsupported expression: expected a simple numeric constant
*** Err: buf_t payload[ 255 -4 ];
I have created a modification to cparser. _parse_constant, which detects a ast.BinaryOp and calls pycparser to convert it back to a string, then uses python eval() on it as a lazy but capable way of reducing all reasonable constant expressions to a number. Attached is the patch file.
The import part is just:
#!python
if isinstance(exprnode, pycparser.c_ast.BinaryOp):
node_text = c_generator.CGenerator().visit(exprnode) # get some C code back
try:
return eval(node_text, {'__builtins__':None}) # try parsing it the lazy way
except (NameError, SyntaxError):
pass
raise api.FFIError(":%d: unsupported expression" % exprnode.coord.line)
please do let me know if there's anything else I can do to help.