File: preprocessor.py

package info (click to toggle)
crazy-complete 0.3.6-2
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 2,404 kB
  • sloc: python: 7,949; sh: 4,636; makefile: 74
file content (68 lines) | stat: -rw-r--r-- 1,626 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
'''Contains code for preprocessing text.'''


def preprocess(string, defines):
    '''Simple preprocessor function with #ifdef, #else, and #endif support.'''

    defines = set(defines)
    output = []
    stack = []  # stack of booleans: is this block currently active?

    lines = string.splitlines(keepends=True)

    for line in lines:
        stripped_line = line.lstrip()

        if stripped_line.startswith("#ifdef"):
            define = stripped_line.split()[1]
            active = define in defines
            stack.append(active)

        elif stripped_line.startswith("#else"):
            if not stack:
                raise SyntaxError("#else without #ifdef")
            # flip only the current (top of stack)
            stack[-1] = not stack[-1]

        elif stripped_line.startswith("#endif"):
            if not stack:
                raise SyntaxError("#endif without #ifdef")
            stack.pop()

        else:
            # output only if all enclosing blocks are active
            if not stack or all(stack):
                output.append(line)

    if stack:
        raise SyntaxError("Unclosed #ifdef")

    return ''.join(output)


def strip_double_empty_lines(string):
    '''Collapse triple newlines into double newlines.'''

    return string.replace('\n\n\n', '\n\n')


def _test():
    string = """\
Lorem Ipsum
#ifdef DEBUG
    This is debug code.
    #ifdef FOO
    This is foo code.
    #else
    This is foo else code.
    #endif
#endif
Dolor Sit Amet\
"""
    defines = ["DEBUG"]
    result = preprocess(string, defines)
    print(result)


if __name__ == '__main__':
    _test()