153d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton"""Rudimentary parser for C struct definitions."""
253d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton
353d527ad1828d484e336626ee59d7d5606b58499Jeremy Hyltonimport re
453d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton
553d527ad1828d484e336626ee59d7d5606b58499Jeremy HyltonPyObject_HEAD = "PyObject_HEAD"
653d527ad1828d484e336626ee59d7d5606b58499Jeremy HyltonPyObject_VAR_HEAD = "PyObject_VAR_HEAD"
753d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton
853d527ad1828d484e336626ee59d7d5606b58499Jeremy Hyltonrx_name = re.compile("} (\w+);")
953d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton
1053d527ad1828d484e336626ee59d7d5606b58499Jeremy Hyltonclass Struct:
1153d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    def __init__(self, name, head, members):
1253d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton        self.name = name
1353d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton        self.head = head
1453d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton        self.members = members
1553d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton
1653d527ad1828d484e336626ee59d7d5606b58499Jeremy Hyltondef parse(s):
1753d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    """Parse a C struct definition.
1853d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton
1953d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    The parser is very restricted in what it will accept.
2053d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    """
2153d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton
2253d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    lines = filter(None, s.split("\n")) # get non-empty lines
2353d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    assert lines[0].strip() == "typedef struct {"
2453d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    pyhead = lines[1].strip()
2553d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    assert (pyhead.startswith("PyObject") and
2653d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton            pyhead.endswith("HEAD"))
2753d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    members = []
2853d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    for line in lines[2:]:
2953d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton        line = line.strip()
3053d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton        if line.startswith("}"):
3153d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton            break
32182b5aca27d376b08a2904bed42b751496f932f3Tim Peters
3353d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton        assert line.endswith(";")
3453d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton        line = line[:-1]
3553d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton        words = line.split()
3653d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton        name = words[-1]
3753d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton        type = " ".join(words[:-1])
3853d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton        if name[0] == "*":
3953d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton            name = name[1:]
4053d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton            type += " *"
4153d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton        members.append((name, type))
4253d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    name = None
4353d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    mo = rx_name.search(line)
4453d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    assert mo is not None
4553d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    name = mo.group(1)
4653d527ad1828d484e336626ee59d7d5606b58499Jeremy Hylton    return Struct(name, pyhead, members)
47