Change skippreproc -> processpre, add #pragma option processing.

Usage:

Options are case insensitive.
This commit is contained in:
Sei Lisa 2016-06-28 03:20:21 +02:00
parent a13b1cb77e
commit 0c3ad9b938
3 changed files with 89 additions and 16 deletions

View file

@ -312,6 +312,70 @@ class parser(object):
if self.pos >= self.length:
raise EInternal() # force GetToken to return EOF
def SetOpt(self, option, value):
# See parse() for meaning of options.
if option == 'extendedglobalexpr':
self.extendedglobalexpr = value
if option == 'extendedtypecast':
self.extendedtypecast = value
if option == 'extendedassignment':
self.extendedassignment = value
if option == 'explicitcast':
self.explicitcast = value
if option == 'allowkeyconcat':
self.allowkeyconcat = value
if option == 'allowmultistrings':
self.allowmultistrings = value
if option == 'processpre':
self.processpre = value
# TODO: Allow pure C-style string escapes. This is low-priority.
#if option == 'allowcescapes':
# self.allowcescapes = value
# Enable switch statements.
if option == 'enableswitch':
if not self.enableswitch and value:
self.keywords |= self.switch_keywords
elif self.enableswitch and not value:
self.keywords = self.base_keywords
if self.breakcont:
self.keywords |= self.brkcont_keywords
self.enableswitch = value
# Enable break/continue
if option == 'breakcont':
if not self.breakcont and value:
self.keywords |= self.brkcont_keywords
elif self.breakcont and not value:
self.keywords = self.base_keywords
if self.enableswitch:
self.keywords |= self.switch_keywords
self.breakcont = value
if option == 'errmissingdefault':
self.errmissingdefault = value
if option == 'lazylists':
self.lazylists = value
if option == 'duplabels':
self.duplabels = value
if option == 'shrinknames':
self.shrinknames = value
if option == 'funcoverride':
self.funcoverride = value
def ProcessDirective(self, directive):
"""Process a given preprocessor directive during parsing."""
@ -327,7 +391,7 @@ class parser(object):
r'^#\s*(?:'
r'(?:[Ll][Ii][Nn][Ee]\s+)?(\d+)(?:\s+("(?:[^"\\]|\\.)*"))?'
r'|'
r'([A-Za-z0-9_]+)\s+(.+?)'
r'([A-Za-z0-9_]+)\s+([A-Za-z0-9_]+)\s+([-+,A-Za-z0-9_]+)'
r')\s*$'
)
match = self.parse_directive_re.search(directive)
@ -351,9 +415,16 @@ class parser(object):
del linenum
else:
assert match.group(3) is not None
if match.group(3).lower() == 'pragma':
# TODO: process #pragma
warning('pragma not implemented')
if match.group(3).lower() == 'pragma' and match.group(4) == 'OPT':
opts = match.group(5).lower().split(',')
for opt in opts:
if opt != '':
if opt[0] == '-':
self.SetOpt(opt[1:], False)
elif opt[0] == '+':
self.SetOpt(opt[1:], True)
else:
self.SetOpt(opt, True)
def GetToken(self):
"""Lexer"""
@ -366,8 +437,8 @@ class parser(object):
c = self.script[self.pos]
self.pos += 1
# Process comments
if self.skippreproc and self.linestart and c == '#':
# Process preprocessor directives
if self.processpre and self.linestart and c == '#':
# Preprocessor directive.
# Most are not supposed to reach us but some do:
# - gcpp generates lines in the output like:
@ -392,6 +463,7 @@ class parser(object):
self.ceof()
continue
# Process comments
if c == '/':
if self.script[self.pos:self.pos+1] == '/':
self.pos += 1
@ -2398,8 +2470,8 @@ list lazy_list_set(list L, integer i, list v)
# Allow C style string composition of strings: "blah" "blah" = "blahblah"
self.allowmultistrings = 'allowmultistrings' in options
# Skip preprocessor directives (specifically #line).
self.skippreproc = 'skippreproc' in options
# Process preprocessor directives (especially #pragma and #line).
self.processpre = 'processpre' in options
# TODO: Allow pure C-style string escapes. This is low-priority.
#self.allowcescapes = 'allowcescapes' in options

15
main.py
View file

@ -196,8 +196,8 @@ Preprocessor modes:
pertinent to it. Implies --precmd=cpp
none No preprocessing (default)
Normally, running the preprocessor needs -O skippreproc to make the output
readable by the optimizer.
Normally, running the preprocessor needs the option 'processpre' active, to
make the output readable by the optimizer. This option is active by default.
'''.format(progname=sys.argv[0], version=VERSION))
return
@ -284,10 +284,11 @@ Optimizer options (+ means active by default, - means inactive by default):
warntabs + Suppress warning when a function can't be optimized
because it generates a string or list with a tab, or
when a string contains a tab.
skippreproc + Skip preprocessor directives in the source as if they
were comments. Not useful unless the script is itself
the output of a preprocessor like GNU cpp, which inserts
directives like: # 123 "filename".
processpre + Process some preprocessor directives in the source. This
enables usage of #pragma/#line preprocessor directives,
and is probably necessary if the script is itself the
output of a preprocessor. Note that this option does not
make the optimizer process macros.
explicitcast - Add explicit casts where they are implicit. This option
is useless with 'optimize' and 'optsigns', and is of
basically no use in general, other than to see where
@ -304,7 +305,7 @@ def main():
# Default options
options = set(('extendedglobalexpr','extendedtypecast','extendedassignment',
'allowkeyconcat','allowmultistrings','skippreproc','warntabs','optimize',
'allowkeyconcat','allowmultistrings','processpre','warntabs','optimize',
'optsigns','optfloats','constfold','dcr','errmissingdefault',
))

View file

@ -213,7 +213,7 @@ class Test02_Parser(UnitTestCase):
}}''',
['explicitcast','extendedtypecast','extendedassignment',
'extendedglobalexpr', 'allowmultistrings', 'allowkeyconcat',
'skippreproc', 'duplabels']
'processpre', 'duplabels']
))
print self.parser.scopeindex