mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 19:08:55 -04:00
cppparser: support directives __LINE__, __FILE__, __has_include
This commit is contained in:
parent
fa851ae5ac
commit
40ea0ab786
@ -809,6 +809,8 @@ expand_manifests(const string &input_expr, bool expand_undefined,
|
||||
// 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);
|
||||
@ -817,6 +819,20 @@ expand_manifests(const string &input_expr, bool expand_undefined,
|
||||
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.
|
||||
@ -1486,31 +1502,22 @@ handle_undef_directive(const string &args, const YYLTYPE &loc) {
|
||||
*/
|
||||
void CPPPreprocessor::
|
||||
handle_ifdef_directive(const string &args, const YYLTYPE &loc) {
|
||||
Manifests::const_iterator mi = _manifests.find(args);
|
||||
if (mi != _manifests.end()) {
|
||||
// The macro is defined. We continue.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_manifest_defined(args)) {
|
||||
// The macro is undefined. Skip stuff.
|
||||
skip_false_if_block(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void CPPPreprocessor::
|
||||
handle_ifndef_directive(const string &args, const YYLTYPE &loc) {
|
||||
Manifests::const_iterator mi = _manifests.find(args);
|
||||
if (mi == _manifests.end()) {
|
||||
// The macro is undefined. We continue.
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_manifest_defined(args)) {
|
||||
// The macro is defined. Skip stuff.
|
||||
skip_false_if_block(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
@ -1593,6 +1600,8 @@ handle_include_directive(const string &args, const YYLTYPE &loc) {
|
||||
_angle_includes.insert(filename);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warning("Ignoring invalid #include directive", loc);
|
||||
}
|
||||
|
||||
filename.set_text();
|
||||
@ -1600,49 +1609,9 @@ handle_include_directive(const string &args, const YYLTYPE &loc) {
|
||||
|
||||
// Now look for the filename. If we didn't use angle quotes, look first in
|
||||
// the current directory.
|
||||
bool found_file = false;
|
||||
CPPFile::Source source = CPPFile::S_none;
|
||||
|
||||
if (okflag) {
|
||||
found_file = false;
|
||||
|
||||
// Search the current directory.
|
||||
if (!angle_quotes && !found_file && filename.exists()) {
|
||||
found_file = true;
|
||||
source = CPPFile::S_local;
|
||||
}
|
||||
|
||||
// Search the same directory as the includer.
|
||||
if (!angle_quotes && !found_file) {
|
||||
Filename match(get_file()._filename.get_dirname(), filename);
|
||||
if (match.exists()) {
|
||||
filename = match;
|
||||
found_file = true;
|
||||
source = CPPFile::S_alternate;
|
||||
}
|
||||
}
|
||||
|
||||
// Now search the angle-include-path
|
||||
if (angle_quotes && !found_file && filename.resolve_filename(_angle_include_path)) {
|
||||
found_file = true;
|
||||
source = CPPFile::S_system;
|
||||
}
|
||||
|
||||
// Now search the quote-include-path
|
||||
if (!angle_quotes && !found_file) {
|
||||
for (size_t dir=0; dir<_quote_include_path.get_num_directories(); dir++) {
|
||||
Filename match(_quote_include_path.get_directory(dir), filename);
|
||||
if (match.exists()) {
|
||||
filename = match;
|
||||
found_file = true;
|
||||
source = _quote_include_kind[dir];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_file) {
|
||||
warning("Cannot find " + filename.get_fullpath(), loc);
|
||||
} else {
|
||||
if (find_include(filename, angle_quotes, source)) {
|
||||
_last_c = '\0';
|
||||
|
||||
// If it was explicitly named on the command-line, mark it S_local.
|
||||
@ -1662,9 +1631,8 @@ handle_include_directive(const string &args, const YYLTYPE &loc) {
|
||||
if (!push_file(file)) {
|
||||
warning("Unable to read " + filename.get_fullpath(), loc);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warning("Ignoring invalid #include directive", loc);
|
||||
warning("Cannot find " + filename.get_fullpath(), loc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1779,6 +1747,69 @@ skip_false_if_block(bool consider_elifs) {
|
||||
_save_comments = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given manifest is defined.
|
||||
*/
|
||||
bool CPPPreprocessor::
|
||||
is_manifest_defined(const string &manifest_name) {
|
||||
Manifests::const_iterator mi = _manifests.find(manifest_name);
|
||||
if (mi != _manifests.end()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (manifest_name == "__has_include" ||
|
||||
manifest_name == "__FILE__" ||
|
||||
manifest_name == "__LINE__") {
|
||||
// Special built-in directives that are considered "defined".
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the given filename. Changes the first argument to the full path.
|
||||
*/
|
||||
bool CPPPreprocessor::
|
||||
find_include(Filename &filename, bool angle_quotes, CPPFile::Source &source) {
|
||||
// Now look for the filename. If we didn't use angle quotes, look first in
|
||||
// the current directory.
|
||||
if (!angle_quotes && filename.exists()) {
|
||||
source = CPPFile::S_local;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Search the same directory as the includer.
|
||||
if (!angle_quotes) {
|
||||
Filename match(get_file()._filename.get_dirname(), filename);
|
||||
if (match.exists()) {
|
||||
filename = match;
|
||||
source = CPPFile::S_alternate;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Now search the angle-include-path
|
||||
if (angle_quotes && filename.resolve_filename(_angle_include_path)) {
|
||||
source = CPPFile::S_system;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now search the quote-include-path
|
||||
if (!angle_quotes) {
|
||||
for (size_t dir = 0; dir < _quote_include_path.get_num_directories(); ++dir) {
|
||||
Filename match(_quote_include_path.get_directory(dir), filename);
|
||||
if (match.exists()) {
|
||||
filename = match;
|
||||
source = _quote_include_kind[dir];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ -1885,6 +1916,14 @@ get_identifier(int c) {
|
||||
if (mi != _manifests.end() && !should_ignore_manifest((*mi).second)) {
|
||||
return expand_manifest((*mi).second);
|
||||
}
|
||||
if (name == "__FILE__") {
|
||||
return get_literal(SIMPLE_STRING, loc, loc.file._filename_as_referenced);
|
||||
}
|
||||
if (name == "__LINE__") {
|
||||
YYSTYPE result;
|
||||
result.u.integer = loc.first_line;
|
||||
return CPPToken(INTEGER, loc, "", result);
|
||||
}
|
||||
|
||||
// Check for keywords.
|
||||
int kw = check_keyword(name);
|
||||
@ -2227,9 +2266,7 @@ expand_defined_function(string &expr, size_t q, size_t &p) {
|
||||
vector_string args;
|
||||
extract_manifest_args_inline("defined", 1, -1, args, expr, p);
|
||||
if (args.size() >= 1) {
|
||||
const string &manifest_name = args[0];
|
||||
Manifests::const_iterator mi = _manifests.find(manifest_name);
|
||||
if (mi != _manifests.end()) {
|
||||
if (is_manifest_defined(args[0])) {
|
||||
// The macro is defined; the result is "1".
|
||||
result = "1";
|
||||
} else {
|
||||
@ -2242,6 +2279,70 @@ expand_defined_function(string &expr, size_t q, size_t &p) {
|
||||
p = q + result.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands the __has_include(manifest) function to either 1 or 0, depending on
|
||||
* whether the include file exists.
|
||||
*/
|
||||
void CPPPreprocessor::
|
||||
expand_has_include_function(string &expr, size_t q, size_t &p, YYLTYPE loc) {
|
||||
bool found_file = false;
|
||||
|
||||
// Skip whitespace till paren.
|
||||
while (p < expr.size() && isspace(expr[p])) {
|
||||
p++;
|
||||
}
|
||||
size_t args_begin = p + 1;
|
||||
|
||||
vector_string args;
|
||||
extract_manifest_args_inline("__has_include", 1, -1, args, expr, p);
|
||||
|
||||
if (!args.empty() && args[0].size() >= 2) {
|
||||
Filename filename;
|
||||
bool angle_quotes = false;
|
||||
|
||||
string inc = args[0];
|
||||
|
||||
// Just to play things safe, since our manifest-expansion logic might not
|
||||
// filter out quotes and angle brackets properly, we'll only expand
|
||||
// manifests if we don't begin with a quote or bracket.
|
||||
if (!inc.empty() && (inc[0] != '"' && inc[0] != '<')) {
|
||||
inc = expand_manifests(inc, false, loc);
|
||||
}
|
||||
|
||||
if (inc[0] == '"' && inc[inc.size() - 1] == '"') {
|
||||
filename = inc.substr(1, inc.size() - 2);
|
||||
} else if (inc[0] == '<' && inc[inc.size() - 1] == '>') {
|
||||
filename = inc.substr(1, inc.size() - 2);
|
||||
if (!_noangles) {
|
||||
// If _noangles is true, we don't make a distinction between angle
|
||||
// brackets and quote marks--all #inc statements are treated the
|
||||
// same, as if they used quote marks.
|
||||
angle_quotes = true;
|
||||
}
|
||||
} else {
|
||||
loc.last_column += loc.first_column + p - 2;
|
||||
loc.first_column += args_begin;
|
||||
warning("invalid argument for __has_include() directive", loc);
|
||||
expr = expr.substr(0, q) + "0" + expr.substr(p);
|
||||
p = q + 1;
|
||||
return;
|
||||
}
|
||||
|
||||
filename.set_text();
|
||||
|
||||
CPPFile::Source source = CPPFile::S_none;
|
||||
found_file = find_include(filename, angle_quotes, source);
|
||||
} else {
|
||||
loc.last_column += loc.first_column + p - 2;
|
||||
loc.first_column += args_begin;
|
||||
warning("invalid argument for __has_include() directive", loc);
|
||||
}
|
||||
|
||||
string result = found_file ? "1" : "0";
|
||||
expr = expr.substr(0, q) + result + expr.substr(p);
|
||||
p = q + result.size();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -143,6 +143,8 @@ private:
|
||||
void handle_error_directive(const string &args, const YYLTYPE &loc);
|
||||
|
||||
void skip_false_if_block(bool consider_elifs);
|
||||
bool is_manifest_defined(const string &manifest_name);
|
||||
bool find_include(Filename &filename, bool angle_quotes, CPPFile::Source &source);
|
||||
|
||||
CPPToken get_quoted_char(int c);
|
||||
CPPToken get_quoted_string(int c);
|
||||
@ -153,6 +155,7 @@ private:
|
||||
void extract_manifest_args(const string &name, int num_args,
|
||||
int va_arg, vector_string &args);
|
||||
void expand_defined_function(string &expr, size_t q, size_t &p);
|
||||
void expand_has_include_function(string &expr, size_t q, size_t &p, YYLTYPE loc);
|
||||
void expand_manifest_inline(string &expr, size_t q, size_t &p,
|
||||
const CPPManifest *manifest);
|
||||
void extract_manifest_args_inline(const string &name, int num_args,
|
||||
|
Loading…
x
Reference in New Issue
Block a user