Fix some edge cases for preprocessor, support auto keyword, MSVC compile fix

This commit is contained in:
rdb 2015-10-17 02:54:07 +02:00
parent 94b48d568f
commit 155ae811aa
11 changed files with 1860 additions and 1803 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1723,6 +1723,10 @@ type:
str << *$3; str << *$3;
yyerror("could not determine type of " + str.str(), @3); yyerror("could not determine type of " + str.str(), @3);
} }
}
| KW_AUTO
{
$$ = new CPPSimpleType(CPPSimpleType::T_auto);
} }
; ;
@ -1813,6 +1817,10 @@ type_decl:
str << *$3; str << *$3;
yyerror("could not determine type of " + str.str(), @3); yyerror("could not determine type of " + str.str(), @3);
} }
}
| KW_AUTO
{
$$ = new CPPSimpleType(CPPSimpleType::T_auto);
} }
; ;
@ -2114,7 +2122,7 @@ namespace_declaration:
} }
CPPNamespace *nspace = new CPPNamespace($3, scope, @2.file); CPPNamespace *nspace = new CPPNamespace($3, scope, @2.file);
nspace->_inline = true; nspace->_is_inline = true;
current_scope->add_declaration(nspace, global_scope, current_lexer, @2); current_scope->add_declaration(nspace, global_scope, current_lexer, @2);
current_scope->define_namespace(nspace); current_scope->define_namespace(nspace);
push_scope(scope); push_scope(scope);

View File

@ -189,7 +189,7 @@ get_local_name(CPPScope *scope) const {
// Strip off template scopes, since they don't add anything // Strip off template scopes, since they don't add anything
// particularly meaningful to the local name. // particularly meaningful to the local name.
while (my_scope->as_template_scope() != NULL) { while (my_scope != NULL && my_scope->as_template_scope() != NULL) {
my_scope = my_scope->get_parent_scope(); my_scope = my_scope->get_parent_scope();
} }

View File

@ -28,7 +28,7 @@ CPPNamespace(CPPIdentifier *ident, CPPScope *scope, const CPPFile &file) :
CPPDeclaration(file), CPPDeclaration(file),
_ident(ident), _ident(ident),
_scope(scope), _scope(scope),
_inline(false) _is_inline(false)
{ {
} }
@ -88,7 +88,7 @@ get_scope() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void CPPNamespace:: void CPPNamespace::
output(ostream &out, int indent_level, CPPScope *scope, bool complete) const { output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
if (_inline) { if (_is_inline) {
out << "inline "; out << "inline ";
} }
if (!complete && _ident != NULL) { if (!complete && _ident != NULL) {

View File

@ -42,7 +42,9 @@ public:
virtual CPPNamespace *as_namespace(); virtual CPPNamespace *as_namespace();
bool _inline; // We can't call this _inline since that would clash with an MSVC
// built-in keyword declaration.
bool _is_inline;
private: private:
CPPIdentifier *_ident; CPPIdentifier *_ident;

View File

@ -72,7 +72,8 @@ parse_file(const Filename &filename) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
CPPExpression *CPPParser:: CPPExpression *CPPParser::
parse_expr(const string &expr) { parse_expr(const string &expr) {
return CPPPreprocessor::parse_expr(expr, this, this); YYLTYPE loc = {};
return CPPPreprocessor::parse_expr(expr, this, this, loc);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -774,6 +774,7 @@ push_file(const CPPFile &file) {
indent(cerr, _files.size() * 2) indent(cerr, _files.size() * 2)
<< "Reading " << file << "\n"; << "Reading " << file << "\n";
} }
assert(_last_c == 0);
_files.push_back(InputFile()); _files.push_back(InputFile());
InputFile &infile = _files.back(); InputFile &infile = _files.back();
@ -841,7 +842,8 @@ push_string(const string &input, bool lock_position) {
// string and return the new string. // string and return the new string.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
string CPPPreprocessor:: string CPPPreprocessor::
expand_manifests(const string &input_expr, bool expand_undefined) { expand_manifests(const string &input_expr, bool expand_undefined,
const YYLTYPE &loc) {
// 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;
@ -872,11 +874,28 @@ expand_manifests(const string &input_expr, bool expand_undefined) {
manifest_found = true; manifest_found = true;
} else if (expand_undefined && ident != "true" && ident != "false") { } else if (expand_undefined && ident != "true" && ident != "false") {
// It is not found. Expand it to 0. // 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); expr = expr.substr(0, q) + "0" + expr.substr(p);
p = q + 1; 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 { } else {
p++; p++;
} }
@ -903,8 +922,8 @@ expand_manifests(const string &input_expr, bool expand_undefined) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
CPPExpression *CPPPreprocessor:: CPPExpression *CPPPreprocessor::
parse_expr(const string &input_expr, CPPScope *current_scope, parse_expr(const string &input_expr, CPPScope *current_scope,
CPPScope *global_scope) { CPPScope *global_scope, const YYLTYPE &loc) {
string expr = expand_manifests(input_expr, false); string expr = expand_manifests(input_expr, false, loc);
CPPExpressionParser ep(current_scope, global_scope); CPPExpressionParser ep(current_scope, global_scope);
ep._verbose = 0; ep._verbose = 0;
@ -1475,7 +1494,7 @@ handle_define_directive(const string &args, const YYLTYPE &loc) {
if (!manifest->_has_parameters) { if (!manifest->_has_parameters) {
string expr_string = manifest->expand(); string expr_string = manifest->expand();
if (!expr_string.empty()) { if (!expr_string.empty()) {
manifest->_expr = parse_expr(expr_string, global_scope, global_scope); manifest->_expr = parse_expr(expr_string, global_scope, global_scope, loc);
} }
} }
@ -1554,7 +1573,7 @@ void CPPPreprocessor::
handle_if_directive(const string &args, const YYLTYPE &loc) { handle_if_directive(const string &args, const YYLTYPE &loc) {
// When expanding manifests, we should replace unknown macros // When expanding manifests, we should replace unknown macros
// with 0. // with 0.
string expr = expand_manifests(args, true); string expr = expand_manifests(args, true, loc);
int expression_result = 0; int expression_result = 0;
CPPExpressionParser ep(current_scope, global_scope); CPPExpressionParser ep(current_scope, global_scope);
@ -1602,7 +1621,7 @@ handle_include_directive(const string &args, const YYLTYPE &loc) {
// might not filter out quotes and angle brackets properly, we'll // might not filter out quotes and angle brackets properly, we'll
// only expand manifests if we don't begin with a quote or bracket. // only expand manifests if we don't begin with a quote or bracket.
if (!expr.empty() && (expr[0] != '"' && expr[0] != '<')) { if (!expr.empty() && (expr[0] != '"' && expr[0] != '<')) {
expr = expand_manifests(expr, false); expr = expand_manifests(expr, false, loc);
} }
if (!expr.empty()) { if (!expr.empty()) {
@ -2727,14 +2746,11 @@ get() {
indent(cerr, _files.size() * 2) indent(cerr, _files.size() * 2)
<< "End of input stream, restoring to previous input\n"; << "End of input stream, restoring to previous input\n";
#endif #endif
int last_c = _files.back()._prev_last_c;
_files.pop_back(); _files.pop_back();
if (last_c != '\0') { // Synthesize a newline, just in case the file doesn't already
c = last_c; // end with one.
} else if (!_files.empty()) { c = '\n';
c = _files.back().get();
}
} }
if (c == '\n') { if (c == '\n') {

View File

@ -111,9 +111,10 @@ protected:
bool push_file(const CPPFile &file); bool push_file(const CPPFile &file);
bool push_string(const string &input, bool lock_position); bool push_string(const string &input, bool lock_position);
string expand_manifests(const string &input_expr, bool expand_undefined); string expand_manifests(const string &input_expr, bool expand_undefined,
const YYLTYPE &loc);
CPPExpression *parse_expr(const string &expr, CPPScope *current_scope, CPPExpression *parse_expr(const string &expr, CPPScope *current_scope,
CPPScope *global_scope); CPPScope *global_scope, const YYLTYPE &loc);
private: private:
CPPToken internal_get_next_token(); CPPToken internal_get_next_token();

View File

@ -297,7 +297,7 @@ define_namespace(CPPNamespace *ns) {
_namespaces[name] = ns; _namespaces[name] = ns;
if (ns->_inline) { if (ns->_is_inline) {
// Add an implicit using declaration for an inline namespace. // Add an implicit using declaration for an inline namespace.
_using.insert(ns->get_scope()); _using.insert(ns->get_scope());
} }

View File

@ -158,6 +158,10 @@ output(ostream &out, int, CPPScope *, bool) const {
out << "parameter"; out << "parameter";
break; break;
case T_auto:
out << "auto";
break;
default: default:
out << "***invalid type***"; out << "***invalid type***";
} }

View File

@ -55,6 +55,13 @@ public:
// but it initially looks like a function prototype. // but it initially looks like a function prototype.
// //
T_parameter, T_parameter,
// T_auto is also a special type that corresponds to the "auto"
// keyword used in a variable assignment. The type of it is
// automatically determined at a later stage based on the type
// of the expression that is assigned to it.
//
T_auto,
}; };
enum Flags { enum Flags {