mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-28 07:48:37 -04:00
cppparser: Fix problems with recursive expansion in preprocessor
Other half of #1635
This commit is contained in:
parent
685b98021c
commit
80147990cc
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::string;
|
using std::string;
|
||||||
@ -796,80 +797,8 @@ expand_manifests(const string &input_expr, bool expand_undefined,
|
|||||||
// Get a copy of the expression string we can modify.
|
// Get a copy of the expression string we can modify.
|
||||||
string expr = input_expr;
|
string expr = input_expr;
|
||||||
|
|
||||||
// Repeatedly scan the expr for any manifest names or defined() function.
|
std::set<const CPPManifest *> expanded;
|
||||||
|
r_expand_manifests(expr, expand_undefined, loc, expanded);
|
||||||
bool manifest_found;
|
|
||||||
do {
|
|
||||||
manifest_found = false;
|
|
||||||
size_t p = 0;
|
|
||||||
while (p < expr.size()) {
|
|
||||||
if (isalpha(expr[p]) || expr[p] == '_') {
|
|
||||||
size_t q = p;
|
|
||||||
while (p < expr.size() && (isalnum(expr[p]) || expr[p] == '_')) {
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
string ident = expr.substr(q, p - q);
|
|
||||||
|
|
||||||
// Here's an identifier. Is it "defined"?
|
|
||||||
if (ident == "defined") {
|
|
||||||
expand_defined_function(expr, q, p);
|
|
||||||
} else if (expand_undefined && ident == "__has_include") {
|
|
||||||
expand_has_include_function(expr, q, p, loc);
|
|
||||||
} else {
|
|
||||||
// Is it a manifest?
|
|
||||||
Manifests::const_iterator mi = _manifests.find(ident);
|
|
||||||
if (mi != _manifests.end()) {
|
|
||||||
const CPPManifest *manifest = (*mi).second;
|
|
||||||
expand_manifest_inline(expr, q, p, manifest);
|
|
||||||
manifest_found = true;
|
|
||||||
|
|
||||||
} else if (ident == "__FILE__") {
|
|
||||||
// Special case: this is a dynamic definition.
|
|
||||||
string file = string("\"") + loc.file._filename_as_referenced.get_fullpath() + "\"";
|
|
||||||
expr = expr.substr(0, q) + file + expr.substr(p);
|
|
||||||
p = q + file.size();
|
|
||||||
manifest_found = true;
|
|
||||||
|
|
||||||
} else if (ident == "__LINE__") {
|
|
||||||
// So is this.
|
|
||||||
string line = format_string(loc.first_line);
|
|
||||||
expr = expr.substr(0, q) + line + expr.substr(p);
|
|
||||||
p = q + line.size();
|
|
||||||
manifest_found = true;
|
|
||||||
|
|
||||||
} else if (expand_undefined && ident != "true" && ident != "false") {
|
|
||||||
// It is not found. Expand it to 0, but only if we are currently
|
|
||||||
// parsing an #if expression.
|
|
||||||
expr = expr.substr(0, q) + "0" + expr.substr(p);
|
|
||||||
p = q + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (expr[p] == '\'' || expr[p] == '"') {
|
|
||||||
// Skip the next part until we find a closing quotation mark.
|
|
||||||
char quote = expr[p];
|
|
||||||
p++;
|
|
||||||
while (p < expr.size() && expr[p] != quote) {
|
|
||||||
if (expr[p] == '\\') {
|
|
||||||
// This might be an escaped quote. Skip an extra char.
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
if (p >= expr.size()) {
|
|
||||||
// Unclosed string.
|
|
||||||
warning("missing terminating " + string(1, quote) + " character", loc);
|
|
||||||
}
|
|
||||||
p++;
|
|
||||||
} else {
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we expanded any manifests at all that time, then go back through the
|
|
||||||
// string and look again--we might have a manifest that expands to another
|
|
||||||
// manifest.
|
|
||||||
} while (manifest_found);
|
|
||||||
|
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2187,6 +2116,96 @@ expand_manifest(const CPPManifest *manifest) {
|
|||||||
return internal_get_next_token();
|
return internal_get_next_token();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive implementation of expand_manifests().
|
||||||
|
*/
|
||||||
|
void CPPPreprocessor::
|
||||||
|
r_expand_manifests(string &expr, bool expand_undefined,
|
||||||
|
const YYLTYPE &loc, std::set<const CPPManifest *> &expanded) {
|
||||||
|
size_t p = 0;
|
||||||
|
while (p < expr.size()) {
|
||||||
|
if (isalpha(expr[p]) || expr[p] == '_') {
|
||||||
|
size_t q = p;
|
||||||
|
while (p < expr.size() && (isalnum(expr[p]) || expr[p] == '_')) {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
string ident = expr.substr(q, p - q);
|
||||||
|
|
||||||
|
// Here's an identifier. Is it "defined"?
|
||||||
|
if (ident == "defined") {
|
||||||
|
expand_defined_function(expr, q, p);
|
||||||
|
}
|
||||||
|
else if (expand_undefined && ident == "__has_include") {
|
||||||
|
expand_has_include_function(expr, q, p, loc);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Is it a manifest?
|
||||||
|
Manifests::const_iterator mi = _manifests.find(ident);
|
||||||
|
if (mi != _manifests.end()) {
|
||||||
|
const CPPManifest *manifest = (*mi).second;
|
||||||
|
if (expanded.count(manifest) == 0) {
|
||||||
|
vector_string args;
|
||||||
|
if (manifest->_has_parameters) {
|
||||||
|
extract_manifest_args_inline(manifest->_name, manifest->_num_parameters,
|
||||||
|
manifest->_variadic_param, args, expr, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
string result = manifest->expand(args);
|
||||||
|
|
||||||
|
// Recurse, but adding the manifest we just expanded to the list
|
||||||
|
// to be ignored for future expansion, to prevent recursion.
|
||||||
|
std::set<const CPPManifest *> ignore = expanded;
|
||||||
|
ignore.insert(manifest);
|
||||||
|
r_expand_manifests(result, expand_undefined, loc, ignore);
|
||||||
|
|
||||||
|
expr = expr.substr(0, q) + result + expr.substr(p);
|
||||||
|
p = q + result.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ident == "__FILE__") {
|
||||||
|
// Special case: this is a dynamic definition.
|
||||||
|
string file = string("\"") + loc.file._filename_as_referenced.get_fullpath() + "\"";
|
||||||
|
expr = expr.substr(0, q) + file + expr.substr(p);
|
||||||
|
p = q + file.size();
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (ident == "__LINE__") {
|
||||||
|
// So is this.
|
||||||
|
string line = format_string(loc.first_line);
|
||||||
|
expr = expr.substr(0, q) + line + expr.substr(p);
|
||||||
|
p = q + line.size();
|
||||||
|
}
|
||||||
|
else if (expand_undefined && ident != "true" && ident != "false") {
|
||||||
|
// It is not found. Expand it to 0, but only if we are currently
|
||||||
|
// parsing an #if expression.
|
||||||
|
expr = expr.substr(0, q) + "0" + expr.substr(p);
|
||||||
|
p = q + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (expr[p] == '\'' || expr[p] == '"') {
|
||||||
|
// Skip the next part until we find a closing quotation mark.
|
||||||
|
char quote = expr[p];
|
||||||
|
p++;
|
||||||
|
while (p < expr.size() && expr[p] != quote) {
|
||||||
|
if (expr[p] == '\\') {
|
||||||
|
// This might be an escaped quote. Skip an extra char.
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
if (p >= expr.size()) {
|
||||||
|
// Unclosed string.
|
||||||
|
warning("missing terminating " + string(1, quote) + " character", loc);
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -115,7 +115,7 @@ protected:
|
|||||||
bool push_string(const std::string &input, bool lock_position);
|
bool push_string(const std::string &input, bool lock_position);
|
||||||
|
|
||||||
std::string expand_manifests(const std::string &input_expr, bool expand_undefined,
|
std::string expand_manifests(const std::string &input_expr, bool expand_undefined,
|
||||||
const YYLTYPE &loc);
|
const YYLTYPE &loc);
|
||||||
CPPExpression *parse_expr(const std::string &expr, CPPScope *current_scope,
|
CPPExpression *parse_expr(const std::string &expr, CPPScope *current_scope,
|
||||||
CPPScope *global_scope, const YYLTYPE &loc);
|
CPPScope *global_scope, const YYLTYPE &loc);
|
||||||
|
|
||||||
@ -152,6 +152,8 @@ private:
|
|||||||
CPPToken get_literal(int token, YYLTYPE loc, const std::string &str,
|
CPPToken get_literal(int token, YYLTYPE loc, const std::string &str,
|
||||||
const YYSTYPE &result = YYSTYPE());
|
const YYSTYPE &result = YYSTYPE());
|
||||||
CPPToken expand_manifest(const CPPManifest *manifest);
|
CPPToken expand_manifest(const CPPManifest *manifest);
|
||||||
|
void r_expand_manifests(std::string &expr, bool expand_undefined,
|
||||||
|
const YYLTYPE &loc, std::set<const CPPManifest *> &expanded);
|
||||||
void extract_manifest_args(const std::string &name, int num_args,
|
void extract_manifest_args(const std::string &name, int num_args,
|
||||||
int va_arg, vector_string &args);
|
int va_arg, vector_string &args);
|
||||||
void expand_defined_function(std::string &expr, size_t q, size_t &p);
|
void expand_defined_function(std::string &expr, size_t q, size_t &p);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user