Spaces:
Running
Running
text-generation-webui
/
installer_files
/conda
/lib
/python3.10
/site-packages
/pycparser
/ply
/cpp.py
# ----------------------------------------------------------------------------- | |
# cpp.py | |
# | |
# Author: David Beazley (http://www.dabeaz.com) | |
# Copyright (C) 2017 | |
# All rights reserved | |
# | |
# This module implements an ANSI-C style lexical preprocessor for PLY. | |
# ----------------------------------------------------------------------------- | |
import sys | |
# Some Python 3 compatibility shims | |
if sys.version_info.major < 3: | |
STRING_TYPES = (str, unicode) | |
else: | |
STRING_TYPES = str | |
xrange = range | |
# ----------------------------------------------------------------------------- | |
# Default preprocessor lexer definitions. These tokens are enough to get | |
# a basic preprocessor working. Other modules may import these if they want | |
# ----------------------------------------------------------------------------- | |
tokens = ( | |
'CPP_ID','CPP_INTEGER', 'CPP_FLOAT', 'CPP_STRING', 'CPP_CHAR', 'CPP_WS', 'CPP_COMMENT1', 'CPP_COMMENT2', 'CPP_POUND','CPP_DPOUND' | |
) | |
literals = "+-*/%|&~^<>=!?()[]{}.,;:\\\'\"" | |
# Whitespace | |
def t_CPP_WS(t): | |
r'\s+' | |
t.lexer.lineno += t.value.count("\n") | |
return t | |
t_CPP_POUND = r'\#' | |
t_CPP_DPOUND = r'\#\#' | |
# Identifier | |
t_CPP_ID = r'[A-Za-z_][\w_]*' | |
# Integer literal | |
def CPP_INTEGER(t): | |
r'(((((0x)|(0X))[0-9a-fA-F]+)|(\d+))([uU][lL]|[lL][uU]|[uU]|[lL])?)' | |
return t | |
t_CPP_INTEGER = CPP_INTEGER | |
# Floating literal | |
t_CPP_FLOAT = r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?' | |
# String literal | |
def t_CPP_STRING(t): | |
r'\"([^\\\n]|(\\(.|\n)))*?\"' | |
t.lexer.lineno += t.value.count("\n") | |
return t | |
# Character constant 'c' or L'c' | |
def t_CPP_CHAR(t): | |
r'(L)?\'([^\\\n]|(\\(.|\n)))*?\'' | |
t.lexer.lineno += t.value.count("\n") | |
return t | |
# Comment | |
def t_CPP_COMMENT1(t): | |
r'(/\*(.|\n)*?\*/)' | |
ncr = t.value.count("\n") | |
t.lexer.lineno += ncr | |
# replace with one space or a number of '\n' | |
t.type = 'CPP_WS'; t.value = '\n' * ncr if ncr else ' ' | |
return t | |
# Line comment | |
def t_CPP_COMMENT2(t): | |
r'(//.*?(\n|$))' | |
# replace with '/n' | |
t.type = 'CPP_WS'; t.value = '\n' | |
return t | |
def t_error(t): | |
t.type = t.value[0] | |
t.value = t.value[0] | |
t.lexer.skip(1) | |
return t | |
import re | |
import copy | |
import time | |
import os.path | |
# ----------------------------------------------------------------------------- | |
# trigraph() | |
# | |
# Given an input string, this function replaces all trigraph sequences. | |
# The following mapping is used: | |
# | |
# ??= # | |
# ??/ \ | |
# ??' ^ | |
# ??( [ | |
# ??) ] | |
# ??! | | |
# ??< { | |
# ??> } | |
# ??- ~ | |
# ----------------------------------------------------------------------------- | |
_trigraph_pat = re.compile(r'''\?\?[=/\'\(\)\!<>\-]''') | |
_trigraph_rep = { | |
'=':'#', | |
'/':'\\', | |
"'":'^', | |
'(':'[', | |
')':']', | |
'!':'|', | |
'<':'{', | |
'>':'}', | |
'-':'~' | |
} | |
def trigraph(input): | |
return _trigraph_pat.sub(lambda g: _trigraph_rep[g.group()[-1]],input) | |
# ------------------------------------------------------------------ | |
# Macro object | |
# | |
# This object holds information about preprocessor macros | |
# | |
# .name - Macro name (string) | |
# .value - Macro value (a list of tokens) | |
# .arglist - List of argument names | |
# .variadic - Boolean indicating whether or not variadic macro | |
# .vararg - Name of the variadic parameter | |
# | |
# When a macro is created, the macro replacement token sequence is | |
# pre-scanned and used to create patch lists that are later used | |
# during macro expansion | |
# ------------------------------------------------------------------ | |
class Macro(object): | |
def __init__(self,name,value,arglist=None,variadic=False): | |
self.name = name | |
self.value = value | |
self.arglist = arglist | |
self.variadic = variadic | |
if variadic: | |
self.vararg = arglist[-1] | |
self.source = None | |
# ------------------------------------------------------------------ | |
# Preprocessor object | |
# | |
# Object representing a preprocessor. Contains macro definitions, | |
# include directories, and other information | |
# ------------------------------------------------------------------ | |
class Preprocessor(object): | |
def __init__(self,lexer=None): | |
if lexer is None: | |
lexer = lex.lexer | |
self.lexer = lexer | |
self.macros = { } | |
self.path = [] | |
self.temp_path = [] | |
# Probe the lexer for selected tokens | |
self.lexprobe() | |
tm = time.localtime() | |
self.define("__DATE__ \"%s\"" % time.strftime("%b %d %Y",tm)) | |
self.define("__TIME__ \"%s\"" % time.strftime("%H:%M:%S",tm)) | |
self.parser = None | |
# ----------------------------------------------------------------------------- | |
# tokenize() | |
# | |
# Utility function. Given a string of text, tokenize into a list of tokens | |
# ----------------------------------------------------------------------------- | |
def tokenize(self,text): | |
tokens = [] | |
self.lexer.input(text) | |
while True: | |
tok = self.lexer.token() | |
if not tok: break | |
tokens.append(tok) | |
return tokens | |
# --------------------------------------------------------------------- | |
# error() | |
# | |
# Report a preprocessor error/warning of some kind | |
# ---------------------------------------------------------------------- | |
def error(self,file,line,msg): | |
print("%s:%d %s" % (file,line,msg)) | |
# ---------------------------------------------------------------------- | |
# lexprobe() | |
# | |
# This method probes the preprocessor lexer object to discover | |
# the token types of symbols that are important to the preprocessor. | |
# If this works right, the preprocessor will simply "work" | |
# with any suitable lexer regardless of how tokens have been named. | |
# ---------------------------------------------------------------------- | |
def lexprobe(self): | |
# Determine the token type for identifiers | |
self.lexer.input("identifier") | |
tok = self.lexer.token() | |
if not tok or tok.value != "identifier": | |
print("Couldn't determine identifier type") | |
else: | |
self.t_ID = tok.type | |
# Determine the token type for integers | |
self.lexer.input("12345") | |
tok = self.lexer.token() | |
if not tok or int(tok.value) != 12345: | |
print("Couldn't determine integer type") | |
else: | |
self.t_INTEGER = tok.type | |
self.t_INTEGER_TYPE = type(tok.value) | |
# Determine the token type for strings enclosed in double quotes | |
self.lexer.input("\"filename\"") | |
tok = self.lexer.token() | |
if not tok or tok.value != "\"filename\"": | |
print("Couldn't determine string type") | |
else: | |
self.t_STRING = tok.type | |
# Determine the token type for whitespace--if any | |
self.lexer.input(" ") | |
tok = self.lexer.token() | |
if not tok or tok.value != " ": | |
self.t_SPACE = None | |
else: | |
self.t_SPACE = tok.type | |
# Determine the token type for newlines | |
self.lexer.input("\n") | |
tok = self.lexer.token() | |
if not tok or tok.value != "\n": | |
self.t_NEWLINE = None | |
print("Couldn't determine token for newlines") | |
else: | |
self.t_NEWLINE = tok.type | |
self.t_WS = (self.t_SPACE, self.t_NEWLINE) | |
# Check for other characters used by the preprocessor | |
chars = [ '<','>','#','##','\\','(',')',',','.'] | |
for c in chars: | |
self.lexer.input(c) | |
tok = self.lexer.token() | |
if not tok or tok.value != c: | |
print("Unable to lex '%s' required for preprocessor" % c) | |
# ---------------------------------------------------------------------- | |
# add_path() | |
# | |
# Adds a search path to the preprocessor. | |
# ---------------------------------------------------------------------- | |
def add_path(self,path): | |
self.path.append(path) | |
# ---------------------------------------------------------------------- | |
# group_lines() | |
# | |
# Given an input string, this function splits it into lines. Trailing whitespace | |
# is removed. Any line ending with \ is grouped with the next line. This | |
# function forms the lowest level of the preprocessor---grouping into text into | |
# a line-by-line format. | |
# ---------------------------------------------------------------------- | |
def group_lines(self,input): | |
lex = self.lexer.clone() | |
lines = [x.rstrip() for x in input.splitlines()] | |
for i in xrange(len(lines)): | |
j = i+1 | |
while lines[i].endswith('\\') and (j < len(lines)): | |
lines[i] = lines[i][:-1]+lines[j] | |
lines[j] = "" | |
j += 1 | |
input = "\n".join(lines) | |
lex.input(input) | |
lex.lineno = 1 | |
current_line = [] | |
while True: | |
tok = lex.token() | |
if not tok: | |
break | |
current_line.append(tok) | |
if tok.type in self.t_WS and '\n' in tok.value: | |
yield current_line | |
current_line = [] | |
if current_line: | |
yield current_line | |
# ---------------------------------------------------------------------- | |
# tokenstrip() | |
# | |
# Remove leading/trailing whitespace tokens from a token list | |
# ---------------------------------------------------------------------- | |
def tokenstrip(self,tokens): | |
i = 0 | |
while i < len(tokens) and tokens[i].type in self.t_WS: | |
i += 1 | |
del tokens[:i] | |
i = len(tokens)-1 | |
while i >= 0 and tokens[i].type in self.t_WS: | |
i -= 1 | |
del tokens[i+1:] | |
return tokens | |
# ---------------------------------------------------------------------- | |
# collect_args() | |
# | |
# Collects comma separated arguments from a list of tokens. The arguments | |
# must be enclosed in parenthesis. Returns a tuple (tokencount,args,positions) | |
# where tokencount is the number of tokens consumed, args is a list of arguments, | |
# and positions is a list of integers containing the starting index of each | |
# argument. Each argument is represented by a list of tokens. | |
# | |
# When collecting arguments, leading and trailing whitespace is removed | |
# from each argument. | |
# | |
# This function properly handles nested parenthesis and commas---these do not | |
# define new arguments. | |
# ---------------------------------------------------------------------- | |
def collect_args(self,tokenlist): | |
args = [] | |
positions = [] | |
current_arg = [] | |
nesting = 1 | |
tokenlen = len(tokenlist) | |
# Search for the opening '('. | |
i = 0 | |
while (i < tokenlen) and (tokenlist[i].type in self.t_WS): | |
i += 1 | |
if (i < tokenlen) and (tokenlist[i].value == '('): | |
positions.append(i+1) | |
else: | |
self.error(self.source,tokenlist[0].lineno,"Missing '(' in macro arguments") | |
return 0, [], [] | |
i += 1 | |
while i < tokenlen: | |
t = tokenlist[i] | |
if t.value == '(': | |
current_arg.append(t) | |
nesting += 1 | |
elif t.value == ')': | |
nesting -= 1 | |
if nesting == 0: | |
if current_arg: | |
args.append(self.tokenstrip(current_arg)) | |
positions.append(i) | |
return i+1,args,positions | |
current_arg.append(t) | |
elif t.value == ',' and nesting == 1: | |
args.append(self.tokenstrip(current_arg)) | |
positions.append(i+1) | |
current_arg = [] | |
else: | |
current_arg.append(t) | |
i += 1 | |
# Missing end argument | |
self.error(self.source,tokenlist[-1].lineno,"Missing ')' in macro arguments") | |
return 0, [],[] | |
# ---------------------------------------------------------------------- | |
# macro_prescan() | |
# | |
# Examine the macro value (token sequence) and identify patch points | |
# This is used to speed up macro expansion later on---we'll know | |
# right away where to apply patches to the value to form the expansion | |
# ---------------------------------------------------------------------- | |
def macro_prescan(self,macro): | |
macro.patch = [] # Standard macro arguments | |
macro.str_patch = [] # String conversion expansion | |
macro.var_comma_patch = [] # Variadic macro comma patch | |
i = 0 | |
while i < len(macro.value): | |
if macro.value[i].type == self.t_ID and macro.value[i].value in macro.arglist: | |
argnum = macro.arglist.index(macro.value[i].value) | |
# Conversion of argument to a string | |
if i > 0 and macro.value[i-1].value == '#': | |
macro.value[i] = copy.copy(macro.value[i]) | |
macro.value[i].type = self.t_STRING | |
del macro.value[i-1] | |
macro.str_patch.append((argnum,i-1)) | |
continue | |
# Concatenation | |
elif (i > 0 and macro.value[i-1].value == '##'): | |
macro.patch.append(('c',argnum,i-1)) | |
del macro.value[i-1] | |
continue | |
elif ((i+1) < len(macro.value) and macro.value[i+1].value == '##'): | |
macro.patch.append(('c',argnum,i)) | |
i += 1 | |
continue | |
# Standard expansion | |
else: | |
macro.patch.append(('e',argnum,i)) | |
elif macro.value[i].value == '##': | |
if macro.variadic and (i > 0) and (macro.value[i-1].value == ',') and \ | |
((i+1) < len(macro.value)) and (macro.value[i+1].type == self.t_ID) and \ | |
(macro.value[i+1].value == macro.vararg): | |
macro.var_comma_patch.append(i-1) | |
i += 1 | |
macro.patch.sort(key=lambda x: x[2],reverse=True) | |
# ---------------------------------------------------------------------- | |
# macro_expand_args() | |
# | |
# Given a Macro and list of arguments (each a token list), this method | |
# returns an expanded version of a macro. The return value is a token sequence | |
# representing the replacement macro tokens | |
# ---------------------------------------------------------------------- | |
def macro_expand_args(self,macro,args): | |
# Make a copy of the macro token sequence | |
rep = [copy.copy(_x) for _x in macro.value] | |
# Make string expansion patches. These do not alter the length of the replacement sequence | |
str_expansion = {} | |
for argnum, i in macro.str_patch: | |
if argnum not in str_expansion: | |
str_expansion[argnum] = ('"%s"' % "".join([x.value for x in args[argnum]])).replace("\\","\\\\") | |
rep[i] = copy.copy(rep[i]) | |
rep[i].value = str_expansion[argnum] | |
# Make the variadic macro comma patch. If the variadic macro argument is empty, we get rid | |
comma_patch = False | |
if macro.variadic and not args[-1]: | |
for i in macro.var_comma_patch: | |
rep[i] = None | |
comma_patch = True | |
# Make all other patches. The order of these matters. It is assumed that the patch list | |
# has been sorted in reverse order of patch location since replacements will cause the | |
# size of the replacement sequence to expand from the patch point. | |
expanded = { } | |
for ptype, argnum, i in macro.patch: | |
# Concatenation. Argument is left unexpanded | |
if ptype == 'c': | |
rep[i:i+1] = args[argnum] | |
# Normal expansion. Argument is macro expanded first | |
elif ptype == 'e': | |
if argnum not in expanded: | |
expanded[argnum] = self.expand_macros(args[argnum]) | |
rep[i:i+1] = expanded[argnum] | |
# Get rid of removed comma if necessary | |
if comma_patch: | |
rep = [_i for _i in rep if _i] | |
return rep | |
# ---------------------------------------------------------------------- | |
# expand_macros() | |
# | |
# Given a list of tokens, this function performs macro expansion. | |
# The expanded argument is a dictionary that contains macros already | |
# expanded. This is used to prevent infinite recursion. | |
# ---------------------------------------------------------------------- | |
def expand_macros(self,tokens,expanded=None): | |
if expanded is None: | |
expanded = {} | |
i = 0 | |
while i < len(tokens): | |
t = tokens[i] | |
if t.type == self.t_ID: | |
if t.value in self.macros and t.value not in expanded: | |
# Yes, we found a macro match | |
expanded[t.value] = True | |
m = self.macros[t.value] | |
if not m.arglist: | |
# A simple macro | |
ex = self.expand_macros([copy.copy(_x) for _x in m.value],expanded) | |
for e in ex: | |
e.lineno = t.lineno | |
tokens[i:i+1] = ex | |
i += len(ex) | |
else: | |
# A macro with arguments | |
j = i + 1 | |
while j < len(tokens) and tokens[j].type in self.t_WS: | |
j += 1 | |
if tokens[j].value == '(': | |
tokcount,args,positions = self.collect_args(tokens[j:]) | |
if not m.variadic and len(args) != len(m.arglist): | |
self.error(self.source,t.lineno,"Macro %s requires %d arguments" % (t.value,len(m.arglist))) | |
i = j + tokcount | |
elif m.variadic and len(args) < len(m.arglist)-1: | |
if len(m.arglist) > 2: | |
self.error(self.source,t.lineno,"Macro %s must have at least %d arguments" % (t.value, len(m.arglist)-1)) | |
else: | |
self.error(self.source,t.lineno,"Macro %s must have at least %d argument" % (t.value, len(m.arglist)-1)) | |
i = j + tokcount | |
else: | |
if m.variadic: | |
if len(args) == len(m.arglist)-1: | |
args.append([]) | |
else: | |
args[len(m.arglist)-1] = tokens[j+positions[len(m.arglist)-1]:j+tokcount-1] | |
del args[len(m.arglist):] | |
# Get macro replacement text | |
rep = self.macro_expand_args(m,args) | |
rep = self.expand_macros(rep,expanded) | |
for r in rep: | |
r.lineno = t.lineno | |
tokens[i:j+tokcount] = rep | |
i += len(rep) | |
del expanded[t.value] | |
continue | |
elif t.value == '__LINE__': | |
t.type = self.t_INTEGER | |
t.value = self.t_INTEGER_TYPE(t.lineno) | |
i += 1 | |
return tokens | |
# ---------------------------------------------------------------------- | |
# evalexpr() | |
# | |
# Evaluate an expression token sequence for the purposes of evaluating | |
# integral expressions. | |
# ---------------------------------------------------------------------- | |
def evalexpr(self,tokens): | |
# tokens = tokenize(line) | |
# Search for defined macros | |
i = 0 | |
while i < len(tokens): | |
if tokens[i].type == self.t_ID and tokens[i].value == 'defined': | |
j = i + 1 | |
needparen = False | |
result = "0L" | |
while j < len(tokens): | |
if tokens[j].type in self.t_WS: | |
j += 1 | |
continue | |
elif tokens[j].type == self.t_ID: | |
if tokens[j].value in self.macros: | |
result = "1L" | |
else: | |
result = "0L" | |
if not needparen: break | |
elif tokens[j].value == '(': | |
needparen = True | |
elif tokens[j].value == ')': | |
break | |
else: | |
self.error(self.source,tokens[i].lineno,"Malformed defined()") | |
j += 1 | |
tokens[i].type = self.t_INTEGER | |
tokens[i].value = self.t_INTEGER_TYPE(result) | |
del tokens[i+1:j+1] | |
i += 1 | |
tokens = self.expand_macros(tokens) | |
for i,t in enumerate(tokens): | |
if t.type == self.t_ID: | |
tokens[i] = copy.copy(t) | |
tokens[i].type = self.t_INTEGER | |
tokens[i].value = self.t_INTEGER_TYPE("0L") | |
elif t.type == self.t_INTEGER: | |
tokens[i] = copy.copy(t) | |
# Strip off any trailing suffixes | |
tokens[i].value = str(tokens[i].value) | |
while tokens[i].value[-1] not in "0123456789abcdefABCDEF": | |
tokens[i].value = tokens[i].value[:-1] | |
expr = "".join([str(x.value) for x in tokens]) | |
expr = expr.replace("&&"," and ") | |
expr = expr.replace("||"," or ") | |
expr = expr.replace("!"," not ") | |
try: | |
result = eval(expr) | |
except Exception: | |
self.error(self.source,tokens[0].lineno,"Couldn't evaluate expression") | |
result = 0 | |
return result | |
# ---------------------------------------------------------------------- | |
# parsegen() | |
# | |
# Parse an input string/ | |
# ---------------------------------------------------------------------- | |
def parsegen(self,input,source=None): | |
# Replace trigraph sequences | |
t = trigraph(input) | |
lines = self.group_lines(t) | |
if not source: | |
source = "" | |
self.define("__FILE__ \"%s\"" % source) | |
self.source = source | |
chunk = [] | |
enable = True | |
iftrigger = False | |
ifstack = [] | |
for x in lines: | |
for i,tok in enumerate(x): | |
if tok.type not in self.t_WS: break | |
if tok.value == '#': | |
# Preprocessor directive | |
# insert necessary whitespace instead of eaten tokens | |
for tok in x: | |
if tok.type in self.t_WS and '\n' in tok.value: | |
chunk.append(tok) | |
dirtokens = self.tokenstrip(x[i+1:]) | |
if dirtokens: | |
name = dirtokens[0].value | |
args = self.tokenstrip(dirtokens[1:]) | |
else: | |
name = "" | |
args = [] | |
if name == 'define': | |
if enable: | |
for tok in self.expand_macros(chunk): | |
yield tok | |
chunk = [] | |
self.define(args) | |
elif name == 'include': | |
if enable: | |
for tok in self.expand_macros(chunk): | |
yield tok | |
chunk = [] | |
oldfile = self.macros['__FILE__'] | |
for tok in self.include(args): | |
yield tok | |
self.macros['__FILE__'] = oldfile | |
self.source = source | |
elif name == 'undef': | |
if enable: | |
for tok in self.expand_macros(chunk): | |
yield tok | |
chunk = [] | |
self.undef(args) | |
elif name == 'ifdef': | |
ifstack.append((enable,iftrigger)) | |
if enable: | |
if not args[0].value in self.macros: | |
enable = False | |
iftrigger = False | |
else: | |
iftrigger = True | |
elif name == 'ifndef': | |
ifstack.append((enable,iftrigger)) | |
if enable: | |
if args[0].value in self.macros: | |
enable = False | |
iftrigger = False | |
else: | |
iftrigger = True | |
elif name == 'if': | |
ifstack.append((enable,iftrigger)) | |
if enable: | |
result = self.evalexpr(args) | |
if not result: | |
enable = False | |
iftrigger = False | |
else: | |
iftrigger = True | |
elif name == 'elif': | |
if ifstack: | |
if ifstack[-1][0]: # We only pay attention if outer "if" allows this | |
if enable: # If already true, we flip enable False | |
enable = False | |
elif not iftrigger: # If False, but not triggered yet, we'll check expression | |
result = self.evalexpr(args) | |
if result: | |
enable = True | |
iftrigger = True | |
else: | |
self.error(self.source,dirtokens[0].lineno,"Misplaced #elif") | |
elif name == 'else': | |
if ifstack: | |
if ifstack[-1][0]: | |
if enable: | |
enable = False | |
elif not iftrigger: | |
enable = True | |
iftrigger = True | |
else: | |
self.error(self.source,dirtokens[0].lineno,"Misplaced #else") | |
elif name == 'endif': | |
if ifstack: | |
enable,iftrigger = ifstack.pop() | |
else: | |
self.error(self.source,dirtokens[0].lineno,"Misplaced #endif") | |
else: | |
# Unknown preprocessor directive | |
pass | |
else: | |
# Normal text | |
if enable: | |
chunk.extend(x) | |
for tok in self.expand_macros(chunk): | |
yield tok | |
chunk = [] | |
# ---------------------------------------------------------------------- | |
# include() | |
# | |
# Implementation of file-inclusion | |
# ---------------------------------------------------------------------- | |
def include(self,tokens): | |
# Try to extract the filename and then process an include file | |
if not tokens: | |
return | |
if tokens: | |
if tokens[0].value != '<' and tokens[0].type != self.t_STRING: | |
tokens = self.expand_macros(tokens) | |
if tokens[0].value == '<': | |
# Include <...> | |
i = 1 | |
while i < len(tokens): | |
if tokens[i].value == '>': | |
break | |
i += 1 | |
else: | |
print("Malformed #include <...>") | |
return | |
filename = "".join([x.value for x in tokens[1:i]]) | |
path = self.path + [""] + self.temp_path | |
elif tokens[0].type == self.t_STRING: | |
filename = tokens[0].value[1:-1] | |
path = self.temp_path + [""] + self.path | |
else: | |
print("Malformed #include statement") | |
return | |
for p in path: | |
iname = os.path.join(p,filename) | |
try: | |
data = open(iname,"r").read() | |
dname = os.path.dirname(iname) | |
if dname: | |
self.temp_path.insert(0,dname) | |
for tok in self.parsegen(data,filename): | |
yield tok | |
if dname: | |
del self.temp_path[0] | |
break | |
except IOError: | |
pass | |
else: | |
print("Couldn't find '%s'" % filename) | |
# ---------------------------------------------------------------------- | |
# define() | |
# | |
# Define a new macro | |
# ---------------------------------------------------------------------- | |
def define(self,tokens): | |
if isinstance(tokens,STRING_TYPES): | |
tokens = self.tokenize(tokens) | |
linetok = tokens | |
try: | |
name = linetok[0] | |
if len(linetok) > 1: | |
mtype = linetok[1] | |
else: | |
mtype = None | |
if not mtype: | |
m = Macro(name.value,[]) | |
self.macros[name.value] = m | |
elif mtype.type in self.t_WS: | |
# A normal macro | |
m = Macro(name.value,self.tokenstrip(linetok[2:])) | |
self.macros[name.value] = m | |
elif mtype.value == '(': | |
# A macro with arguments | |
tokcount, args, positions = self.collect_args(linetok[1:]) | |
variadic = False | |
for a in args: | |
if variadic: | |
print("No more arguments may follow a variadic argument") | |
break | |
astr = "".join([str(_i.value) for _i in a]) | |
if astr == "...": | |
variadic = True | |
a[0].type = self.t_ID | |
a[0].value = '__VA_ARGS__' | |
variadic = True | |
del a[1:] | |
continue | |
elif astr[-3:] == "..." and a[0].type == self.t_ID: | |
variadic = True | |
del a[1:] | |
# If, for some reason, "." is part of the identifier, strip off the name for the purposes | |
# of macro expansion | |
if a[0].value[-3:] == '...': | |
a[0].value = a[0].value[:-3] | |
continue | |
if len(a) > 1 or a[0].type != self.t_ID: | |
print("Invalid macro argument") | |
break | |
else: | |
mvalue = self.tokenstrip(linetok[1+tokcount:]) | |
i = 0 | |
while i < len(mvalue): | |
if i+1 < len(mvalue): | |
if mvalue[i].type in self.t_WS and mvalue[i+1].value == '##': | |
del mvalue[i] | |
continue | |
elif mvalue[i].value == '##' and mvalue[i+1].type in self.t_WS: | |
del mvalue[i+1] | |
i += 1 | |
m = Macro(name.value,mvalue,[x[0].value for x in args],variadic) | |
self.macro_prescan(m) | |
self.macros[name.value] = m | |
else: | |
print("Bad macro definition") | |
except LookupError: | |
print("Bad macro definition") | |
# ---------------------------------------------------------------------- | |
# undef() | |
# | |
# Undefine a macro | |
# ---------------------------------------------------------------------- | |
def undef(self,tokens): | |
id = tokens[0].value | |
try: | |
del self.macros[id] | |
except LookupError: | |
pass | |
# ---------------------------------------------------------------------- | |
# parse() | |
# | |
# Parse input text. | |
# ---------------------------------------------------------------------- | |
def parse(self,input,source=None,ignore={}): | |
self.ignore = ignore | |
self.parser = self.parsegen(input,source) | |
# ---------------------------------------------------------------------- | |
# token() | |
# | |
# Method to return individual tokens | |
# ---------------------------------------------------------------------- | |
def token(self): | |
try: | |
while True: | |
tok = next(self.parser) | |
if tok.type not in self.ignore: return tok | |
except StopIteration: | |
self.parser = None | |
return None | |
if __name__ == '__main__': | |
import ply.lex as lex | |
lexer = lex.lex() | |
# Run a preprocessor | |
import sys | |
f = open(sys.argv[1]) | |
input = f.read() | |
p = Preprocessor(lexer) | |
p.parse(input,sys.argv[1]) | |
while True: | |
tok = p.token() | |
if not tok: break | |
print(p.source, tok) | |