mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 05:42:29 +00:00
python-3.6.zip added from Github
README.cosmo contains the necessary links.
This commit is contained in:
parent
75fc601ff5
commit
0c4c56ff39
4219 changed files with 1968626 additions and 0 deletions
191
third_party/python/Tools/clinic/cpp.py
vendored
Normal file
191
third_party/python/Tools/clinic/cpp.py
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
import re
|
||||
import sys
|
||||
|
||||
def negate(condition):
|
||||
"""
|
||||
Returns a CPP conditional that is the opposite of the conditional passed in.
|
||||
"""
|
||||
if condition.startswith('!'):
|
||||
return condition[1:]
|
||||
return "!" + condition
|
||||
|
||||
class Monitor:
|
||||
"""
|
||||
A simple C preprocessor that scans C source and computes, line by line,
|
||||
what the current C preprocessor #if state is.
|
||||
|
||||
Doesn't handle everything--for example, if you have /* inside a C string,
|
||||
without a matching */ (also inside a C string), or with a */ inside a C
|
||||
string but on another line and with preprocessor macros in between...
|
||||
the parser will get lost.
|
||||
|
||||
Anyway this implementation seems to work well enough for the CPython sources.
|
||||
"""
|
||||
|
||||
is_a_simple_defined = re.compile(r'^defined\s*\(\s*[A-Za-z0-9_]+\s*\)$').match
|
||||
|
||||
def __init__(self, filename=None, *, verbose=False):
|
||||
self.stack = []
|
||||
self.in_comment = False
|
||||
self.continuation = None
|
||||
self.line_number = 0
|
||||
self.filename = filename
|
||||
self.verbose = verbose
|
||||
|
||||
def __repr__(self):
|
||||
return ''.join((
|
||||
'<Monitor ',
|
||||
str(id(self)),
|
||||
" line=", str(self.line_number),
|
||||
" condition=", repr(self.condition()),
|
||||
">"))
|
||||
|
||||
def status(self):
|
||||
return str(self.line_number).rjust(4) + ": " + self.condition()
|
||||
|
||||
def condition(self):
|
||||
"""
|
||||
Returns the current preprocessor state, as a single #if condition.
|
||||
"""
|
||||
return " && ".join(condition for token, condition in self.stack)
|
||||
|
||||
def fail(self, *a):
|
||||
if self.filename:
|
||||
filename = " " + self.filename
|
||||
else:
|
||||
filename = ''
|
||||
print("Error at" + filename, "line", self.line_number, ":")
|
||||
print(" ", ' '.join(str(x) for x in a))
|
||||
sys.exit(-1)
|
||||
|
||||
def close(self):
|
||||
if self.stack:
|
||||
self.fail("Ended file while still in a preprocessor conditional block!")
|
||||
|
||||
def write(self, s):
|
||||
for line in s.split("\n"):
|
||||
self.writeline(line)
|
||||
|
||||
def writeline(self, line):
|
||||
self.line_number += 1
|
||||
line = line.strip()
|
||||
|
||||
def pop_stack():
|
||||
if not self.stack:
|
||||
self.fail("#" + token + " without matching #if / #ifdef / #ifndef!")
|
||||
return self.stack.pop()
|
||||
|
||||
if self.continuation:
|
||||
line = self.continuation + line
|
||||
self.continuation = None
|
||||
|
||||
if not line:
|
||||
return
|
||||
|
||||
if line.endswith('\\'):
|
||||
self.continuation = line[:-1].rstrip() + " "
|
||||
return
|
||||
|
||||
# we have to ignore preprocessor commands inside comments
|
||||
#
|
||||
# we also have to handle this:
|
||||
# /* start
|
||||
# ...
|
||||
# */ /* <-- tricky!
|
||||
# ...
|
||||
# */
|
||||
# and this:
|
||||
# /* start
|
||||
# ...
|
||||
# */ /* also tricky! */
|
||||
if self.in_comment:
|
||||
if '*/' in line:
|
||||
# snip out the comment and continue
|
||||
#
|
||||
# GCC allows
|
||||
# /* comment
|
||||
# */ #include <stdio.h>
|
||||
# maybe other compilers too?
|
||||
_, _, line = line.partition('*/')
|
||||
self.in_comment = False
|
||||
|
||||
while True:
|
||||
if '/*' in line:
|
||||
if self.in_comment:
|
||||
self.fail("Nested block comment!")
|
||||
|
||||
before, _, remainder = line.partition('/*')
|
||||
comment, comment_ends, after = remainder.partition('*/')
|
||||
if comment_ends:
|
||||
# snip out the comment
|
||||
line = before.rstrip() + ' ' + after.lstrip()
|
||||
continue
|
||||
# comment continues to eol
|
||||
self.in_comment = True
|
||||
line = before.rstrip()
|
||||
break
|
||||
|
||||
# we actually have some // comments
|
||||
# (but block comments take precedence)
|
||||
before, line_comment, comment = line.partition('//')
|
||||
if line_comment:
|
||||
line = before.rstrip()
|
||||
|
||||
if not line.startswith('#'):
|
||||
return
|
||||
|
||||
line = line[1:].lstrip()
|
||||
assert line
|
||||
|
||||
fields = line.split()
|
||||
token = fields[0].lower()
|
||||
condition = ' '.join(fields[1:]).strip()
|
||||
|
||||
if_tokens = {'if', 'ifdef', 'ifndef'}
|
||||
all_tokens = if_tokens | {'elif', 'else', 'endif'}
|
||||
|
||||
if token not in all_tokens:
|
||||
return
|
||||
|
||||
# cheat a little here, to reuse the implementation of if
|
||||
if token == 'elif':
|
||||
pop_stack()
|
||||
token = 'if'
|
||||
|
||||
if token in if_tokens:
|
||||
if not condition:
|
||||
self.fail("Invalid format for #" + token + " line: no argument!")
|
||||
if token == 'if':
|
||||
if not self.is_a_simple_defined(condition):
|
||||
condition = "(" + condition + ")"
|
||||
else:
|
||||
fields = condition.split()
|
||||
if len(fields) != 1:
|
||||
self.fail("Invalid format for #" + token + " line: should be exactly one argument!")
|
||||
symbol = fields[0]
|
||||
condition = 'defined(' + symbol + ')'
|
||||
if token == 'ifndef':
|
||||
condition = '!' + condition
|
||||
|
||||
self.stack.append(("if", condition))
|
||||
if self.verbose:
|
||||
print(self.status())
|
||||
return
|
||||
|
||||
previous_token, previous_condition = pop_stack()
|
||||
|
||||
if token == 'else':
|
||||
self.stack.append(('else', negate(previous_condition)))
|
||||
elif token == 'endif':
|
||||
pass
|
||||
if self.verbose:
|
||||
print(self.status())
|
||||
|
||||
if __name__ == '__main__':
|
||||
for filename in sys.argv[1:]:
|
||||
with open(filename, "rt") as f:
|
||||
cpp = Monitor(filename, verbose=True)
|
||||
print()
|
||||
print(filename)
|
||||
for line_number, line in enumerate(f.read().split('\n'), 1):
|
||||
cpp.writeline(line)
|
Loading…
Add table
Add a link
Reference in a new issue