blob: 294d658dd56b869d082af49a89297125293e85b8 (
plain)
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
#
# include_preprocessor.py
#
# Short pyparsing script to perform #include inclusions similar to the C preprocessor
#
# Copyright 2019, Paul McGuire
#
import pyparsing as pp
from pathlib import Path
# parser elements to be used to assemble into #include parser
SEMI = pp.Suppress(";")
INCLUDE = pp.Keyword("#include")
quoted_string = pp.quotedString.addParseAction(pp.removeQuotes)
file_ref = quoted_string | pp.Word(pp.printables, excludeChars=";")
# parser for parsing "#include xyz.dat;" directives
include_directive = INCLUDE + file_ref("include_file_name") + SEMI
# add parse action that will recursively pull in included files - when
# using transformString, the value returned from the parse action will replace
# the text matched by the attached expression
seen = set()
def read_include_contents(s, l, t):
include_file_ref = t.include_file_name
include_echo = "/* {} */".format(pp.line(l, s).strip())
# guard against recursive includes
if include_file_ref not in seen:
seen.add(include_file_ref)
included_file_contents = Path(include_file_ref).read_text()
return (
include_echo
+ "\n"
+ include_directive.transformString(included_file_contents)
)
else:
lead = " " * (pp.col(l, s) - 1)
return "/* recursive include! */\n{}{}".format(lead, include_echo)
# attach include processing method as parse action (parse-time callback)
# to include_directive expression
include_directive.addParseAction(read_include_contents)
if __name__ == "__main__":
# demo
# create test files:
# - a.txt includes b.txt
# - b.txt includes c.txt
# - c.txt includes b.txt (must catch infinite recursion)
Path("a.txt").write_text(
"""\
/* a.txt */
int i;
/* sometimes included files aren't in quotes */
#include b.txt;
"""
)
Path("b.txt").write_text(
"""\
i = 100;
#include 'c.txt';
"""
)
Path("c.txt").write_text(
"""\
i += 1;
/* watch out! this might be recursive if this file included by b.txt */
#include b.txt;
"""
)
# use include_directive.transformString to perform includes
# read contents of original file
initial_file = Path("a.txt").read_text()
# print original file
print(initial_file)
print("-----------------")
# expand includes in source file (and any included files) and print the result
expanded_source = include_directive.transformString(initial_file)
print(expanded_source)
# clean up
for fname in "a.txt b.txt c.txt".split():
Path(fname).unlink()
|