4

What is a recommended way to import a bunch of constants defined in a c-style (not c++, just plain old c) .h file into python module so that it can be used in python's part of a project. In the project we use a mix of languages and in perl I can do this importing by using h2xs utility to generate .pm module.

Constants definition looks like

#define FOO 1
enum {
    BAR,
    BAZ
}; 

etc.

C-style comments are also presented an have to be properly handled.

2
  • Do you want to import the constants and make them into globals or somesuch in Python, or just store constants in a list? Commented Dec 21, 2009 at 19:23
  • @Skurmedel I'd prefer the first way Commented Dec 21, 2009 at 19:40

5 Answers 5

6

I recently used the pyparsing library to scan for enum constants. Here it is, along with a sample string and the resulting output. Notice it also handles comments and commented out sections. With a little modification it could stuff the constants in a dictionary.

from pyparsing import *

sample = '''
    stuff before

    enum hello {
        Zero,
        One,
        Two,
        Three,
        Five=5,
        Six,
        Ten=10
    }

    in the middle

    enum blah
    {
        alpha, // blah
        beta,  /* blah blah
        gamma = 10 , */
        zeta = 50
    }

    at the end
    '''

# syntax we don't want to see in the final parse tree
_lcurl = Suppress('{')
_rcurl = Suppress('}')
_equal = Suppress('=')
_comma = Suppress(',')
_enum = Suppress('enum')

identifier = Word(alphas,alphanums+'_')
integer = Word(nums)

enumValue = Group(identifier('name') + Optional(_equal + integer('value')))
enumList = Group(enumValue + ZeroOrMore(_comma + enumValue))
enum = _enum + identifier('enum') + _lcurl + enumList('list') + _rcurl

enum.ignore(cppStyleComment)

for item,start,stop in enum.scanString(sample):
    id = 0
    for entry in item.list:
        if entry.value != '':
            id = int(entry.value)
        print '%s_%s = %d' % (item.enum.upper(),entry.name.upper(),id)
        id += 1

OUTPUT:

HELLO_ZERO = 0
HELLO_ONE = 1
HELLO_TWO = 2
HELLO_THREE = 3
HELLO_FIVE = 5
HELLO_SIX = 6
HELLO_TEN = 10
BLAH_ALPHA = 0
BLAH_BETA = 1
BLAH_ZETA = 50
Sign up to request clarification or add additional context in comments.

Comments

1

I once had to do something similar, and in the end I did something strange but highly reliable. Dealing with all the possibilities for how values might be defined is tricky... for instance, you have to handle

#include "someotherfile.h"
enum NewEnum {
   A = -5,
   B = SOME_OTHER_ENUM, 
   C,
   D = 3
};

(which is really nasty and no one should ever do...)

In the end, part of my build process was a perl script that parsed the header file for all enums and defines, and then produced a .c file that included the header and was nothing more then a bunch of print statements, printing the actual value for each define. This file was compiled and executed, and the output of that was used to produce the next source file ( Java, in my case ).

This ensured that I got the right values, as I was using the C preprocessor and compiler to produce the answers.

Comments

0

I'd suggest the other way round, if possible: define all your constants in a Python dict or module and auto-generate the .h in Python. It will be much, much easier.

Comments

0

Create a script/program that is called from make and creates the necessary python file. If you only need #define and enum it shouldn't be too hard to write. Then remember NOT to check this python file into source control as you want the build process to force the regeneration of the file every time.

Comments

0

You can do this but it is a bit of a fiddle. Say you have a python file fruit.py

APPLE = 0x80,
BANANA = 0x81,
CHERRY = 0x82,
DAMSON = 0x83,

In C/C++, you can declare it as

const int
#include "fruit.py"
notused = 0;

In python

from fruit import *

but there is a catch. The items declared as number, are sets or lists. To access the value, you need the first element so the values are APPLE[0], BANANA[0] etc or *APPLE, *BANANA. If the last item ends with a ; then it doesn't need an index

To add comments, use #undef

#undef rem // $Id$
#undef rem // $URL$
#undef rem // Common header file between python and C++

In C++, it will just undefine a macro. The rule is that you can undefine something even though it hasn't been defined, which is perfect for this. In python, it will just be a comment. The full example

include file (fruit.py)

#undef rem // $Id$
#undef rem // $URL$
#undef rem // Common header file between python and C++
APPLE = 0x80,
BANANA = 0x81,
CHERRY = 0x82,
DAMSON = 0x83,

python

from fruit import *
print(APPLE[0])
print(*BANANA)

C++

#include <iostream>
const int
#include "fruit.py"
NOTUSED = 0;
int main()
{
    std::cout << APPLE << std::endl;
    std::cout << BANANA << std::endl;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.