Rewrite handling of stringify and token-paste operators to work better. Add support for variadic macros.

This commit is contained in:
rdb 2014-09-19 15:14:11 +00:00
parent 4be5346a1a
commit 30d8cc29b3
4 changed files with 367 additions and 193 deletions

View File

@ -24,8 +24,8 @@
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
CPPManifest::ExpansionNode:: CPPManifest::ExpansionNode::
ExpansionNode(int parm_number) : ExpansionNode(int parm_number, bool stringify, bool paste) :
_parm_number(parm_number) _parm_number(parm_number), _stringify(stringify), _paste(paste)
{ {
} }
@ -35,8 +35,8 @@ ExpansionNode(int parm_number) :
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
CPPManifest::ExpansionNode:: CPPManifest::ExpansionNode::
ExpansionNode(const string &str) : ExpansionNode(const string &str, bool paste) :
_parm_number(-1), _str(str) _parm_number(-1), _stringify(false), _paste(paste), _str(str)
{ {
} }
@ -46,7 +46,11 @@ ExpansionNode(const string &str) :
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
CPPManifest:: CPPManifest::
CPPManifest(const string &args, const CPPFile &file) : _file(file) { CPPManifest(const string &args, const CPPFile &file) :
_file(file),
_variadic_param(-1),
_expr((CPPExpression *)NULL)
{
assert(!args.empty()); assert(!args.empty());
assert(!isspace(args[0])); assert(!isspace(args[0]));
@ -69,6 +73,7 @@ CPPManifest(const string &args, const CPPFile &file) : _file(file) {
_has_parameters = true; _has_parameters = true;
parse_parameters(args, p, parameter_names); parse_parameters(args, p, parameter_names);
_num_parameters = parameter_names.size(); _num_parameters = parameter_names.size();
p++; p++;
} else { } else {
_has_parameters = false; _has_parameters = false;
@ -83,7 +88,6 @@ CPPManifest(const string &args, const CPPFile &file) : _file(file) {
save_expansion(args.substr(p), parameter_names); save_expansion(args.substr(p), parameter_names);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: CPPManifest::Destructor // Function: CPPManifest::Destructor
// Access: Public // Access: Public
@ -96,7 +100,58 @@ CPPManifest::
} }
} }
////////////////////////////////////////////////////////////////////
// Function: CPPManifest::stringify
// Access: Public, Static
// Description: This implements the stringification operator, #.
////////////////////////////////////////////////////////////////////
string CPPManifest::
stringify(const string &source) {
string result("\"");
enum {
S_escaped = 0x01,
S_single_quoted = 0x02,
S_double_quoted = 0x04,
S_quoted = 0x06,
};
int state = 0;
string::const_iterator it;
for (it = source.begin(); it != source.end(); ++it) {
char c = *it;
if ((state & S_escaped) == 0) {
switch (c) {
case '\\':
if (state & S_quoted) {
state |= S_escaped;
result += '\\';
}
break;
case '\'':
state ^= S_single_quoted;
break;
case '"':
state ^= S_double_quoted;
result += '\\';
break;
}
} else {
if (c == '\\' || c == '"') {
result += '\\';
}
state &= ~S_escaped;
}
result += c;
}
result += '"';
return result;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: CPPManifest::expand // Function: CPPManifest::expand
@ -111,14 +166,45 @@ expand(const vector_string &args) const {
for (ei = _expansion.begin(); ei != _expansion.end(); ++ei) { for (ei = _expansion.begin(); ei != _expansion.end(); ++ei) {
if ((*ei)._parm_number >= 0) { if ((*ei)._parm_number >= 0) {
int i = (*ei)._parm_number; int i = (*ei)._parm_number;
string subst;
if (i < (int)args.size()) { if (i < (int)args.size()) {
result += " " + args[i] + " "; subst = args[i];
} else {
result += " "; if (i == _variadic_param) {
for (++i; i < (int)args.size(); ++i) {
subst += ", " + args[i];
}
}
if ((*ei)._stringify) {
subst = stringify(subst);
}
} else if (i == _variadic_param && (*ei)._paste) {
// Special case GCC behavior: if __VA_ARGS__ is pasted
// to a comma and no arguments are passed, the comma
// is removed. MSVC does this automatically. Not sure
// if we should allow MSVC behavior as well.
if (*result.rbegin() == ',') {
result.resize(result.size() - 1);
}
}
if (!subst.empty()) {
if (result.empty() || (*ei)._paste) {
result += subst;
} else {
result += ' ';
result += subst;
}
} }
} }
if (!(*ei)._str.empty()) { if (!(*ei)._str.empty()) {
result += (*ei)._str; if (result.empty() || (*ei)._paste) {
result += (*ei)._str;
} else {
result += ' ';
result += (*ei)._str;
}
} }
} }
@ -151,20 +237,40 @@ output(ostream &out) const {
if (_has_parameters) { if (_has_parameters) {
out << "("; out << "(";
if (_num_parameters > 0) { if (_num_parameters > 0) {
out << "$1"; if (_variadic_param == 0) {
out << "...";
} else {
out << "$1";
}
for (int i = 1; i < _num_parameters; ++i) { for (int i = 1; i < _num_parameters; ++i) {
out << ", $" << i + 1; if (_variadic_param == i) {
out << ", ...";
} else {
out << ", $" << i + 1;
}
} }
} }
out << ")"; out << ")";
} }
out << " ";
Expansion::const_iterator ei; Expansion::const_iterator ei;
for (ei = _expansion.begin(); ei != _expansion.end(); ++ei) { for (ei = _expansion.begin(); ei != _expansion.end(); ++ei) {
if ((*ei)._paste) {
out << " ## ";
} else {
out << " ";
}
if ((*ei)._parm_number >= 0) { if ((*ei)._parm_number >= 0) {
out << " $" << (*ei)._parm_number + 1 << " "; if (stringify) {
out << "#";
}
if ((*ei)._parm_number == _variadic_param) {
out << "__VA_ARGS__";
} else {
out << "$" << (*ei)._parm_number + 1;
}
} }
if (!(*ei)._str.empty()) { if (!(*ei)._str.empty()) {
out << (*ei)._str; out << (*ei)._str;
@ -172,8 +278,6 @@ output(ostream &out) const {
} }
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: CPPManifest::parse_parameters // Function: CPPManifest::parse_parameters
// Access: Private // Access: Private
@ -197,7 +301,16 @@ parse_parameters(const string &args, size_t &p,
args[p] != ')' && args[p] != ',') { args[p] != ')' && args[p] != ',') {
p++; p++;
} }
parameter_names.push_back(args.substr(q, p - q));
// Check if it's a variadic parameter by checking if it ends
// with "...". This picks up both C99-style variadic macros
// and GCC-style variadic macros.
if (p - q >= 3 && args.compare(p - 3, 3, "...") == 0) {
_variadic_param = parameter_names.size();
parameter_names.push_back(args.substr(q, p - q - 3));
} else {
parameter_names.push_back(args.substr(q, p - q));
}
// Skip whitespace after the parameter name. // Skip whitespace after the parameter name.
while (p < args.size() && isspace(args[p])) { while (p < args.size() && isspace(args[p])) {
@ -221,16 +334,12 @@ parse_parameters(const string &args, size_t &p,
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void CPPManifest:: void CPPManifest::
save_expansion(const string &exp, const vector_string &parameter_names) { save_expansion(const string &exp, const vector_string &parameter_names) {
if (parameter_names.empty()) {
// No parameters; this is an easy case.
_expansion.push_back(ExpansionNode(exp));
return;
}
// Walk through the expansion string. For each substring that is an // Walk through the expansion string. For each substring that is an
// identifier, check it against parameter_names. // identifier, check it against parameter_names.
size_t p = 0; size_t p = 0;
size_t last = 0; size_t last = 0;
bool stringify = false;
bool paste = false;
while (p < exp.size()) { while (p < exp.size()) {
if (isalpha(exp[p]) || exp[p] == '_') { if (isalpha(exp[p]) || exp[p] == '_') {
// Here's the start of an identifier. Find the end of it. // Here's the start of an identifier. Find the end of it.
@ -244,26 +353,67 @@ save_expansion(const string &exp, const vector_string &parameter_names) {
// Is this identifier one of our parameters? // Is this identifier one of our parameters?
int pnum = -1; int pnum = -1;
for (int i = 0; pnum == -1 && i < (int)parameter_names.size(); ++i) { bool va_args = false;
if (parameter_names[i] == ident) {
pnum = i; if (ident == "__VA_ARGS__") {
va_args = true;
// C99-style variadics, ie. #define macro(...) __VA_ARGS__
pnum = _variadic_param;
} else {
for (int i = 0; pnum == -1 && i < (int)parameter_names.size(); ++i) {
const string &pname = parameter_names[i];
if (pname == ident) {
pnum = i;
}
} }
} }
if (pnum != -1) { if (pnum != -1) {
// Yep! // Yep!
if (last != q) { if (last != q) {
_expansion.push_back(ExpansionNode(exp.substr(last, q - last))); _expansion.push_back(ExpansionNode(exp.substr(last, q - last), paste));
paste = false;
} }
_expansion.push_back(pnum); _expansion.push_back(ExpansionNode(pnum, stringify, paste));
stringify = false;
paste = false;
last = p; last = p;
} }
} else if (exp[p] == '#') {
// This may be a stringification operator.
if (last != p) {
_expansion.push_back(ExpansionNode(exp.substr(last, p - last), paste));
paste = false;
}
++p;
if (p < exp.size() && exp[p] == '#') {
// Woah, this is a token-pasting operator.
paste = true;
++p;
} else {
// Mark that the next argument should be stringified.
stringify = true;
}
last = p;
} else if (isspace(exp[p])) {
if (last != p) {
_expansion.push_back(ExpansionNode(exp.substr(last, p - last), paste));
paste = false;
}
++p;
last = p;
} else { } else {
p++; ++p;
} }
} }
if (last != p) { if (last != p) {
_expansion.push_back(exp.substr(last, p - last)); _expansion.push_back(ExpansionNode(exp.substr(last, p - last), paste));
} }
} }

View File

@ -33,6 +33,8 @@ class CPPManifest {
public: public:
CPPManifest(const string &args, const CPPFile &file = CPPFile()); CPPManifest(const string &args, const CPPFile &file = CPPFile());
~CPPManifest(); ~CPPManifest();
static string stringify(const string &source);
string expand(const vector_string &args = vector_string()) const; string expand(const vector_string &args = vector_string()) const;
CPPType *determine_type() const; CPPType *determine_type() const;
@ -42,6 +44,7 @@ public:
string _name; string _name;
bool _has_parameters; bool _has_parameters;
int _num_parameters; int _num_parameters;
int _variadic_param;
CPPFile _file; CPPFile _file;
CPPExpression *_expr; CPPExpression *_expr;
@ -59,9 +62,11 @@ private:
class ExpansionNode { class ExpansionNode {
public: public:
ExpansionNode(int parm_number); ExpansionNode(int parm_number, bool stringify, bool paste);
ExpansionNode(const string &str); ExpansionNode(const string &str, bool paste = false);
int _parm_number; int _parm_number;
bool _stringify;
bool _paste;
string _str; string _str;
}; };
typedef vector<ExpansionNode> Expansion; typedef vector<ExpansionNode> Expansion;

View File

@ -315,23 +315,6 @@ get_next_token0() {
int first_col = token._lloc.first_column; int first_col = token._lloc.first_column;
CPPFile first_file = token._lloc.file; CPPFile first_file = token._lloc.file;
if (token._token == '#') {
// Stringify.
token = internal_get_next_token();
if (token._token == SIMPLE_IDENTIFIER ||
token._token == INTEGER ||
token._token == REAL ||
token._token == STRING) {
token._token = STRING;
} else {
// Stringify nothing.
_saved_tokens.push_back(token);
token._token = STRING;
token._lval.str = "";
}
}
if (_resolve_identifiers && if (_resolve_identifiers &&
(token._token == SIMPLE_IDENTIFIER || token._token == SCOPE)) { (token._token == SIMPLE_IDENTIFIER || token._token == SCOPE)) {
// We will be returning a scoped identifier, or a scoping. Keep // We will be returning a scoped identifier, or a scoping. Keep
@ -366,59 +349,41 @@ get_next_token0() {
} }
} }
while (token._token == SCOPE || token._token == TOKENPASTE) { while (token._token == SCOPE) {
if (token._token == TOKENPASTE) { name += "::";
// The token-pasting operator creates one continuous token = internal_get_next_token();
// identifier across whitespace. string token_prefix;
token = internal_get_next_token();
if (token._token == SIMPLE_IDENTIFIER ||
token._token == INTEGER ||
token._token == REAL) {
name += token._lval.str;
ident->_names.back().append_name(token._lval.str);
token = internal_get_next_token();
} else {
// Token-paste with nothing.
}
} else { // token._token == SCOPE
name += "::";
token = internal_get_next_token();
string token_prefix;
if (token._token == '~') {
// A scoping operator followed by a tilde can only be the
// start of a scoped destructor name. Make the tilde be part
// of the name.
name += "~";
token_prefix = "~";
token = internal_get_next_token();
}
if (token._token != SIMPLE_IDENTIFIER) {
// The last useful token was a SCOPE, thus this is a scoping
// token.
if (token._token == KW_OPERATOR) {
// Unless the last token we came across was the "operator"
// keyword. We make a special case for this, because it's
// occasionally scoped in normal use.
token._lval = result;
return token;
}
_saved_tokens.push_back(token);
return CPPToken(SCOPING, first_line, first_col, first_file,
name, result);
}
name += token._lval.str;
ident->_names.push_back(token_prefix + token._lval.str);
if (token._token == '~') {
// A scoping operator followed by a tilde can only be the
// start of a scoped destructor name. Make the tilde be part
// of the name.
name += "~";
token_prefix = "~";
token = internal_get_next_token(); token = internal_get_next_token();
} }
if (token._token != SIMPLE_IDENTIFIER) {
// The last useful token was a SCOPE, thus this is a scoping
// token.
if (token._token == KW_OPERATOR) {
// Unless the last token we came across was the "operator"
// keyword. We make a special case for this, because it's
// occasionally scoped in normal use.
token._lval = result;
return token;
}
_saved_tokens.push_back(token);
return CPPToken(SCOPING, first_line, first_col, first_file,
name, result);
}
name += token._lval.str;
ident->_names.push_back(token_prefix + token._lval.str);
token = internal_get_next_token();
if (token._token == '<') { if (token._token == '<') {
// If the next token is an angle bracket and the current // If the next token is an angle bracket and the current
// indentifier wants template instantiation, assume the angle // indentifier wants template instantiation, assume the angle
@ -887,11 +852,6 @@ internal_get_next_token() {
case '%': case '%':
if (next_c == '=') return CPPToken(MODEQUAL, first_line, first_col, first_file); if (next_c == '=') return CPPToken(MODEQUAL, first_line, first_col, first_file);
break; break;
// These are actually preprocessor operators, but it's useful to
// treat them as tokens.
case '#':
if (next_c == '#') return CPPToken(TOKENPASTE, first_line, first_col, first_file);
} }
// It wasn't any of the two- or three-character tokens, so put back // It wasn't any of the two- or three-character tokens, so put back
@ -945,11 +905,13 @@ skip_whitespace(int c) {
c = skip_comment(c); c = skip_comment(c);
if (c == '\\') { if (c == '\\') {
// A backslash character is an unusual thing to encounter in the // This does not usually occur in the middle of unquoted C++
// middle of unquoted C++ code. But it seems to be legal, and // code, except before a newline character.
// it seems to mean the same thing it does within quotes: to
// escape the following character. We simply ignore it.
c = get(); c = get();
if (c != '\n') {
unget(c);
return '\\';
}
} }
if (!isspace(c)) { if (!isspace(c)) {
@ -1633,7 +1595,8 @@ expand_manifest(const CPPManifest *manifest) {
if (manifest->_has_parameters) { if (manifest->_has_parameters) {
// Hmm, we're expecting arguments. // Hmm, we're expecting arguments.
extract_manifest_args(manifest->_name, manifest->_num_parameters, args); extract_manifest_args(manifest->_name, manifest->_num_parameters,
manifest->_variadic_param, args);
} }
string expanded = " " + manifest->expand(args) + " "; string expanded = " " + manifest->expand(args) + " ";
@ -1659,7 +1622,7 @@ expand_manifest(const CPPManifest *manifest) {
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void CPPPreprocessor:: void CPPPreprocessor::
extract_manifest_args(const string &name, int num_args, extract_manifest_args(const string &name, int num_args, int va_arg,
vector_string &args) { vector_string &args) {
CPPFile first_file = get_file(); CPPFile first_file = get_file();
int first_line = get_line_number(); int first_line = get_line_number();
@ -1683,12 +1646,14 @@ extract_manifest_args(const string &name, int num_args,
} else { } else {
// Skip paren. // Skip paren.
c = get(); c = skip_whitespace(get());
int paren_level = 1;
string arg; string arg;
while (c != EOF && c != ')') { while (c != EOF) {
if (c == ',') { if (c == ',' && paren_level == 1) {
args.push_back(arg); args.push_back(arg);
arg = ""; arg = "";
c = get();
} else if (c == '"' || c == '\'') { } else if (c == '"' || c == '\'') {
// Quoted string or character. // Quoted string or character.
@ -1706,35 +1671,55 @@ extract_manifest_args(const string &name, int num_args,
} }
} }
arg += c; arg += c;
c = get();
} else if (c == '(') { } else if (c == '(') {
// Nested parens. arg += '(';
int paren_level = 1; ++paren_level;
while (c != EOF && paren_level > 0) { c = get();
arg += c;
c = get(); } else if (c == ')') {
if (c == '(') { --paren_level;
paren_level++; if (paren_level == 0) {
} else if (c == ')') { break;
paren_level--;
}
} }
if (c != EOF) { arg += ')';
arg += c; c = get();
} else if (isspace(c)) {
// Skip extra whitespace.
c = skip_whitespace(c);
if (!arg.empty()) {
arg += ' ';
}
} else if (c == '\\') {
// It could be a slash before a newline.
// If so, that's whitespace as well.
c = get();
if (c != '\n') {
arg += '\\';
} else if (!arg.empty()) {
arg += ' ';
c = skip_whitespace(get());
} }
} else { } else {
arg += c; arg += c;
c = get();
} }
c = get();
} }
if (num_args != 0 || !arg.empty()) { if (num_args != 0 || !arg.empty()) {
args.push_back(arg); args.push_back(arg);
} }
} }
if ((int)args.size() != num_args) { if ((int)args.size() < num_args) {
warning("Wrong number of arguments for manifest " + name, warning("Not enough arguments for manifest " + name,
first_line, first_col, first_file);
} else if (va_arg < 0 && (int)args.size() > num_args) {
warning("Too many arguments for manifest " + name,
first_line, first_col, first_file); first_line, first_col, first_file);
} }
} }
@ -1742,14 +1727,15 @@ extract_manifest_args(const string &name, int num_args,
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: CPPPreprocessor::expand_defined_function // Function: CPPPreprocessor::expand_defined_function
// Access: Private // Access: Private
// Description: // Description: Expands the defined(manifest) function to either
// 1 or 0, depending on whether the manifest exists.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void CPPPreprocessor:: void CPPPreprocessor::
expand_defined_function(string &expr, size_t q, size_t &p) { expand_defined_function(string &expr, size_t q, size_t &p) {
string result; string result;
vector_string args; vector_string args;
extract_manifest_args_inline("defined", 1, args, expr, p); extract_manifest_args_inline("defined", 1, -1, args, expr, p);
if (args.size() >= 1) { if (args.size() >= 1) {
const string &manifest_name = args[0]; const string &manifest_name = args[0];
Manifests::const_iterator mi = _manifests.find(manifest_name); Manifests::const_iterator mi = _manifests.find(manifest_name);
@ -1777,7 +1763,7 @@ expand_manifest_inline(string &expr, size_t q, size_t &p,
vector_string args; vector_string args;
if (manifest->_has_parameters) { if (manifest->_has_parameters) {
extract_manifest_args_inline(manifest->_name, manifest->_num_parameters, extract_manifest_args_inline(manifest->_name, manifest->_num_parameters,
args, expr, p); manifest->_variadic_param, args, expr, p);
} }
string result = manifest->expand(args); string result = manifest->expand(args);
@ -1792,7 +1778,7 @@ expand_manifest_inline(string &expr, size_t q, size_t &p,
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void CPPPreprocessor:: void CPPPreprocessor::
extract_manifest_args_inline(const string &name, int num_args, extract_manifest_args_inline(const string &name, int num_args,
vector_string &args, int va_arg, vector_string &args,
const string &expr, size_t &p) { const string &expr, size_t &p) {
// Skip whitespace till paren. // Skip whitespace till paren.
while (p < expr.size() && isspace(expr[p])) { while (p < expr.size() && isspace(expr[p])) {
@ -1819,7 +1805,7 @@ extract_manifest_args_inline(const string &name, int num_args,
} }
} }
p++; p++;
} else { } else {
// Skip paren. // Skip paren.
p++; p++;
@ -1850,8 +1836,11 @@ extract_manifest_args_inline(const string &name, int num_args,
} }
} }
if ((int)args.size() != num_args) { if ((int)args.size() < num_args) {
warning("Wrong number of arguments for manifest " + name); warning("Not enough arguments for manifest " + name);
} else if (va_arg < 0 && (int)args.size() > num_args) {
warning("Too many arguments for manifest " + name);
} }
} }
@ -2035,6 +2024,90 @@ check_keyword(const string &name) {
return 0; return 0;
} }
////////////////////////////////////////////////////////////////////
// Function: CPPPreprocessor::scan_escape_sequence
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
int CPPPreprocessor::
scan_escape_sequence(int c) {
if (c != '\\') {
return c;
}
c = get();
switch (c) {
case 'a':
return '\a';
case 'b':
return '\b';
case 'f':
return '\f';
case 'n':
return '\n';
case 'r':
return '\r';
case 't':
return '\t';
case 'v':
return '\v';
case 'e':
// \e is non-standard, buT GCC supports it.
return '\x1B';
case 'x':
// hex character.
c = get();
if (isxdigit(c)) {
int val = hex_val(c);
c = get();
if (isxdigit(c)) {
val = (val << 4) | hex_val(c);
} else {
unget(c);
}
return val;
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
// Octal character.
{
int val = (c - '0');
c = get();
if (c >= '0' && c <= '7') {
val = (val << 3) | (c - '0');
c = get();
if (c >= '0' && c <= '7') {
val = (val << 3) | (c - '0');
} else {
unget(c);
}
} else {
unget(c);
}
return val;
}
}
// Simply output the following character.
return c;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: CPPPreprocessor::scan_quoted // Function: CPPPreprocessor::scan_quoted
// Access: Private // Access: Private
@ -2049,62 +2122,7 @@ scan_quoted(int c) {
while (c != EOF && c != '\n' && c != quote_mark) { while (c != EOF && c != '\n' && c != quote_mark) {
if (c == '\\') { if (c == '\\') {
// Backslash means a special character follows. // Backslash means a special character follows.
c = get(); c = scan_escape_sequence(c);
switch (c) {
case 'n':
c = '\n';
break;
case 't':
c = '\t';
break;
case 'r':
c = '\r';
break;
case 'x':
// hex character.
c = get();
if (isxdigit(c)) {
int val = hex_val(c);
c = get();
if (isxdigit(c)) {
val = (val << 4) | hex_val(c);
} else {
unget(c);
}
c = val;
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
// Octal character.
{
int val = (c - '0');
c = get();
if (c >= '0' && c <= '7') {
val = (val << 3) | (c - '0');
c = get();
if (c >= '0' && c <= '7') {
val = (val << 3) | (c - '0');
} else {
unget(c);
}
} else {
unget(c);
}
c = val;
}
break;
}
} }
str += c; str += c;

View File

@ -142,16 +142,17 @@ private:
CPPToken get_identifier(int c); CPPToken get_identifier(int c);
CPPToken expand_manifest(const CPPManifest *manifest); CPPToken expand_manifest(const CPPManifest *manifest);
void extract_manifest_args(const string &name, int num_args, void extract_manifest_args(const string &name, int num_args,
vector_string &args); int va_arg, vector_string &args);
void expand_defined_function(string &expr, size_t q, size_t &p); void expand_defined_function(string &expr, size_t q, size_t &p);
void expand_manifest_inline(string &expr, size_t q, size_t &p, void expand_manifest_inline(string &expr, size_t q, size_t &p,
const CPPManifest *manifest); const CPPManifest *manifest);
void extract_manifest_args_inline(const string &name, int num_args, void extract_manifest_args_inline(const string &name, int num_args,
vector_string &args, int va_arg, vector_string &args,
const string &expr, size_t &p); const string &expr, size_t &p);
CPPToken get_number(int c, int c2 = 0); CPPToken get_number(int c, int c2 = 0);
static int check_keyword(const string &name); static int check_keyword(const string &name);
int scan_escape_sequence(int c);
string scan_quoted(int c); string scan_quoted(int c);
bool should_ignore_manifest(const CPPManifest *manifest) const; bool should_ignore_manifest(const CPPManifest *manifest) const;