3 from __future__
import print_function
8 def debug(*args
, **kwargs
):
9 print(*args
, file=sys
.stderr
, **kwargs
)
12 parser
= argparse
.ArgumentParser(description
='Preprocess Basic code.')
13 parser
.add_argument('infile', type=str,
14 help='the Basic file to preprocess')
15 parser
.add_argument('--keep-rems', action
='store_true', default
=False,
16 help='The type of REMs to keep (0 (none) -> 4 (all)')
17 parser
.add_argument('--keep-blank-lines', action
='store_true', default
=False,
18 help='Keep blank lines from the original file')
19 parser
.add_argument('--keep-indent', action
='store_true', default
=False,
20 help='Keep line identing')
21 parser
.add_argument('--number-lines', action
='store_true', default
=False,
22 help='Number the lines')
23 parser
.add_argument('--keep-labels', action
='store_true', default
=False,
24 help='Keep string labels instead of replacing with line numbers')
26 return parser
.parse_args()
28 # pull in include files
29 def resolve_includes(orig_lines
, keep_rems
=0):
32 for line
in orig_lines
:
33 m
= re
.match(r
"^ *REM \$INCLUDE: '([^']*)' *$", line
)
34 if m
and m
.group(1) not in included
:
37 ilines
= [l
.rstrip() for l
in open(f
).readlines()]
38 if keep_rems
: lines
.append("REM vvv BEGIN '%s' vvv" % f
)
40 if keep_rems
: lines
.append("REM ^^^ END '%s' ^^^" % f
)
42 debug("Ignoring already included file: %s" % f
)
47 def drop_blank_lines(orig_lines
):
49 for line
in orig_lines
:
50 if re
.match(r
"^\w*$", line
): continue
55 def drop_rems(orig_lines
):
57 for line
in orig_lines
:
58 if re
.match(r
"^ *REM", line
):
60 m
= re
.match(r
"^(.*): *REM .*$", line
)
62 lines
.append(m
.group(1))
67 def remove_indent(orig_lines
):
69 for line
in orig_lines
:
70 m
= re
.match(r
"^ *([^ ].*)$", line
)
71 lines
.append(m
.group(1))
74 def number_lines(orig_lines
, keep_labels
=True):
79 for line
in orig_lines
:
81 m
= re
.match(r
"^ *([^ ]*): *$", line
)
83 labels
[m
.groups(1)] = lnum
85 lines
.append("%s %s" % (lnum
, line
))
89 text
= "\n".join(lines
)
90 # search for and replace GOTO/GOSUBs
91 for label
, lnum
in labels
.items():
92 text
= re
.sub(r
"(THEN) %s\b" % label
, r
"THEN %s" % lnum
, text
)
93 text
= re
.sub(r
"(ON [^:]* GOTO [^:]*) %s\b" % label
, r
"\1 %s" % lnum
, text
)
94 text
= re
.sub(r
"(ON [^:]* GOSUB [^:]*) %s\b" % label
, r
"\2 %s" % lnum
, text
)
95 text
= re
.sub(r
"(GOSUB) %s\b" % label
, r
"\1 %s" % lnum
, text
)
96 text
= re
.sub(r
"(GOTO) %s\b" % label
, r
"\1 %s" % lnum
, text
)
97 return text
.split("\n")
101 if __name__
== '__main__':
104 debug("Preprocessing basic file '"+args
.infile
+"'")
107 lines
= [l
.rstrip() for l
in open(args
.infile
).readlines()]
108 debug("Number of original lines: %s" % len(lines
))
110 # pull in include files
111 lines
= resolve_includes(lines
, keep_rems
=args
.keep_rems
)
112 debug("Number of lines after includes: %s" % len(lines
))
115 if not args
.keep_blank_lines
:
116 lines
= drop_blank_lines(lines
)
117 debug("Number of lines after dropping blank lines: %s" % len(lines
))
120 if not args
.keep_rems
:
121 lines
= drop_rems(lines
)
122 debug("Number of lines after dropping REMs: %s" % len(lines
))
124 # keep/remove the indenting
125 if not args
.keep_indent
:
126 lines
= remove_indent(lines
)
129 if args
.number_lines
:
130 lines
= number_lines(lines
, keep_labels
=args
.keep_labels
)
132 print("\n".join(lines
))