Try to stay compatible with Bison 2.5 (for Ubuntu precise), support C++11 and C++17 static_assert, improve error reporting, handle several gcc keyword aliases, fix bug handling preprocessor expression in which the same manifest occurs more than once

This commit is contained in:
rdb 2015-10-11 16:52:33 +02:00
parent 1c9ff40236
commit ba45120eac
9 changed files with 3046 additions and 2938 deletions

File diff suppressed because it is too large Load Diff

View File

@ -131,25 +131,26 @@ extern int cppyydebug;
KW_SIGNED = 340, KW_SIGNED = 340,
KW_SIZEOF = 341, KW_SIZEOF = 341,
KW_STATIC = 342, KW_STATIC = 342,
KW_STATIC_CAST = 343, KW_STATIC_ASSERT = 343,
KW_STRUCT = 344, KW_STATIC_CAST = 344,
KW_TEMPLATE = 345, KW_STRUCT = 345,
KW_THROW = 346, KW_TEMPLATE = 346,
KW_TRUE = 347, KW_THROW = 347,
KW_TRY = 348, KW_TRUE = 348,
KW_TYPEDEF = 349, KW_TRY = 349,
KW_TYPENAME = 350, KW_TYPEDEF = 350,
KW_UNION = 351, KW_TYPENAME = 351,
KW_UNSIGNED = 352, KW_UNION = 352,
KW_USING = 353, KW_UNSIGNED = 353,
KW_VIRTUAL = 354, KW_USING = 354,
KW_VOID = 355, KW_VIRTUAL = 355,
KW_VOLATILE = 356, KW_VOID = 356,
KW_WCHAR_T = 357, KW_VOLATILE = 357,
KW_WHILE = 358, KW_WCHAR_T = 358,
START_CPP = 359, KW_WHILE = 359,
START_CONST_EXPR = 360, START_CPP = 360,
START_TYPE = 361 START_CONST_EXPR = 361,
START_TYPE = 362
}; };
#endif #endif
/* Tokens. */ /* Tokens. */
@ -238,25 +239,26 @@ extern int cppyydebug;
#define KW_SIGNED 340 #define KW_SIGNED 340
#define KW_SIZEOF 341 #define KW_SIZEOF 341
#define KW_STATIC 342 #define KW_STATIC 342
#define KW_STATIC_CAST 343 #define KW_STATIC_ASSERT 343
#define KW_STRUCT 344 #define KW_STATIC_CAST 344
#define KW_TEMPLATE 345 #define KW_STRUCT 345
#define KW_THROW 346 #define KW_TEMPLATE 346
#define KW_TRUE 347 #define KW_THROW 347
#define KW_TRY 348 #define KW_TRUE 348
#define KW_TYPEDEF 349 #define KW_TRY 349
#define KW_TYPENAME 350 #define KW_TYPEDEF 350
#define KW_UNION 351 #define KW_TYPENAME 351
#define KW_UNSIGNED 352 #define KW_UNION 352
#define KW_USING 353 #define KW_UNSIGNED 353
#define KW_VIRTUAL 354 #define KW_USING 354
#define KW_VOID 355 #define KW_VIRTUAL 355
#define KW_VOLATILE 356 #define KW_VOID 356
#define KW_WCHAR_T 357 #define KW_VOLATILE 357
#define KW_WHILE 358 #define KW_WCHAR_T 358
#define START_CPP 359 #define KW_WHILE 359
#define START_CONST_EXPR 360 #define START_CPP 360
#define START_TYPE 361 #define START_CONST_EXPR 361
#define START_TYPE 362

View File

@ -57,7 +57,7 @@ int yyparse();
static void static void
yyerror(const string &msg) { yyerror(const string &msg) {
current_lexer->error(msg); current_lexer->error(msg, current_lexer->_last_token_loc);
} }
static void static void
@ -199,9 +199,11 @@ pop_struct() {
/* This is a bison-specific declaration to enable recursive calls to /* This is a bison-specific declaration to enable recursive calls to
yyparse(). It changes the calling sequence to yylex(), passing yyparse(). It changes the calling sequence to yylex(), passing
pointers to the current yylval and yylloc. It also adds a pointer pointers to the current yylval and yylloc. Bison 2.7 introduces a
to the current lloc to yyerror, which gives us better diagnostics. */ different syntax that will also pass the current yylloc to yyerror,
%define api.pure full but we have to support Bison versions as old as 2.5 for now. */
/*%define api.pure full*/
%pure-parser
%locations %locations
%token <u.real> REAL %token <u.real> REAL
@ -288,6 +290,7 @@ pop_struct() {
%token KW_SIGNED %token KW_SIGNED
%token KW_SIZEOF %token KW_SIZEOF
%token KW_STATIC %token KW_STATIC
%token KW_STATIC_ASSERT
%token KW_STATIC_CAST %token KW_STATIC_CAST
%token KW_STRUCT %token KW_STRUCT
%token KW_TEMPLATE %token KW_TEMPLATE
@ -522,6 +525,25 @@ declaration:
{ {
CPPMakeSeq *make_seq = new CPPMakeSeq($3->get_simple_name(), $5->get_simple_name(), $7->get_simple_name(), @1.file); CPPMakeSeq *make_seq = new CPPMakeSeq($3->get_simple_name(), $5->get_simple_name(), $7->get_simple_name(), @1.file);
current_scope->add_declaration(make_seq, global_scope, current_lexer, @1); current_scope->add_declaration(make_seq, global_scope, current_lexer, @1);
}
| KW_STATIC_ASSERT '(' const_expr ',' string ')'
{
CPPExpression::Result result = $3->evaluate();
if (result._type == CPPExpression::RT_error) {
yywarning("static_assert requires a constant expression", @3);
} else if (!result.as_boolean()) {
yywarning("static_assert failed: " + $5, @3);
}
}
| KW_STATIC_ASSERT '(' const_expr ')'
{
// This alternative version of static_assert was introduced in C++17.
CPPExpression::Result result = $3->evaluate();
if (result._type == CPPExpression::RT_error) {
yywarning("static_assert requires a constant expression", @3);
} else if (!result.as_boolean()) {
yywarning("static_assert failed", @3);
}
} }
; ;
@ -856,6 +878,9 @@ function_prototype:
{ {
pop_scope(); pop_scope();
CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer);
if (type == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert(type != NULL); assert(type != NULL);
CPPInstanceIdentifier *ii = $4; CPPInstanceIdentifier *ii = $4;
@ -871,6 +896,9 @@ function_prototype:
{ {
pop_scope(); pop_scope();
CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer);
if (type == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert(type != NULL); assert(type != NULL);
CPPInstanceIdentifier *ii = $5; CPPInstanceIdentifier *ii = $5;
@ -1213,6 +1241,9 @@ template_formal_parameter_type:
| TYPENAME_IDENTIFIER | TYPENAME_IDENTIFIER
{ {
$$ = $1->find_type(current_scope, global_scope, false, current_lexer); $$ = $1->find_type(current_scope, global_scope, false, current_lexer);
if ($$ == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert($$ != NULL); assert($$ != NULL);
} }
; ;
@ -1608,6 +1639,9 @@ type:
| TYPENAME_IDENTIFIER | TYPENAME_IDENTIFIER
{ {
$$ = $1->find_type(current_scope, global_scope, false, current_lexer); $$ = $1->find_type(current_scope, global_scope, false, current_lexer);
if ($$ == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert($$ != NULL); assert($$ != NULL);
} }
| KW_TYPENAME name | KW_TYPENAME name
@ -1668,6 +1702,9 @@ type_decl:
| TYPENAME_IDENTIFIER | TYPENAME_IDENTIFIER
{ {
$$ = $1->find_type(current_scope, global_scope, false, current_lexer); $$ = $1->find_type(current_scope, global_scope, false, current_lexer);
if ($$ == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert($$ != NULL); assert($$ != NULL);
} }
| KW_TYPENAME name | KW_TYPENAME name
@ -1746,6 +1783,9 @@ predefined_type:
| TYPENAME_IDENTIFIER | TYPENAME_IDENTIFIER
{ {
$$ = $1->find_type(current_scope, global_scope, false, current_lexer); $$ = $1->find_type(current_scope, global_scope, false, current_lexer);
if ($$ == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert($$ != NULL); assert($$ != NULL);
} }
| KW_TYPENAME name | KW_TYPENAME name
@ -2419,6 +2459,9 @@ const_expr:
{ {
// A constructor call. // A constructor call.
CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer);
if (type == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert(type != NULL); assert(type != NULL);
$$ = new CPPExpression(CPPExpression::construct_op(type, $3)); $$ = new CPPExpression(CPPExpression::construct_op(type, $3));
} }
@ -2888,6 +2931,9 @@ typedefname:
TYPENAME_IDENTIFIER TYPENAME_IDENTIFIER
{ {
CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer);
if (type == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert(type != NULL); assert(type != NULL);
$$ = type; $$ = type;
} }

View File

@ -46,9 +46,9 @@ ExpansionNode(const string &str, bool paste) :
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
CPPManifest:: CPPManifest::
CPPManifest(const string &args, const CPPFile &file) : CPPManifest(const string &args, const cppyyltype &loc) :
_variadic_param(-1), _variadic_param(-1),
_file(file), _loc(loc),
_expr((CPPExpression *)NULL) _expr((CPPExpression *)NULL)
{ {
assert(!args.empty()); assert(!args.empty());

View File

@ -19,6 +19,7 @@
#include "cppFile.h" #include "cppFile.h"
#include "cppVisibility.h" #include "cppVisibility.h"
#include "cppBisonDefs.h"
#include "vector_string.h" #include "vector_string.h"
@ -31,7 +32,7 @@ class CPPType;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class CPPManifest { class CPPManifest {
public: public:
CPPManifest(const string &args, const CPPFile &file = CPPFile()); CPPManifest(const string &args, const cppyyltype &loc = {0});
~CPPManifest(); ~CPPManifest();
static string stringify(const string &source); static string stringify(const string &source);
@ -45,7 +46,7 @@ public:
bool _has_parameters; bool _has_parameters;
int _num_parameters; int _num_parameters;
int _variadic_param; int _variadic_param;
CPPFile _file; cppyyltype _loc;
CPPExpression *_expr; CPPExpression *_expr;
// Manifests don't have a visibility in the normal sense. Normally // Manifests don't have a visibility in the normal sense. Normally

View File

@ -407,6 +407,7 @@ get_next_token0() {
return token; return token;
} }
_saved_tokens.push_back(token); _saved_tokens.push_back(token);
_last_token_loc = loc;
return CPPToken(SCOPING, loc, name, result); return CPPToken(SCOPING, loc, name, result);
} }
@ -444,10 +445,12 @@ get_next_token0() {
token_type = TYPENAME_IDENTIFIER; token_type = TYPENAME_IDENTIFIER;
} }
_last_token_loc = loc;
return CPPToken(token_type, loc, name, result); return CPPToken(token_type, loc, name, result);
} }
// This is the normal case: just pass through whatever token we got. // This is the normal case: just pass through whatever token we got.
_last_token_loc = loc;
return token; return token;
} }
@ -843,10 +846,6 @@ expand_manifests(const string &input_expr, bool expand_undefined) {
// Repeatedly scan the expr for any manifest names or defined() // Repeatedly scan the expr for any manifest names or defined()
// function. // function.
// We'll need to save the set of manifests we've already expanded,
// to guard against recursive references.
set<const CPPManifest *> already_expanded;
bool manifest_found; bool manifest_found;
do { do {
manifest_found = false; manifest_found = false;
@ -867,10 +866,9 @@ expand_manifests(const string &input_expr, bool expand_undefined) {
Manifests::const_iterator mi = _manifests.find(ident); Manifests::const_iterator mi = _manifests.find(ident);
if (mi != _manifests.end()) { if (mi != _manifests.end()) {
const CPPManifest *manifest = (*mi).second; const CPPManifest *manifest = (*mi).second;
if (already_expanded.insert(manifest).second) {
expand_manifest_inline(expr, q, p, (*mi).second); expand_manifest_inline(expr, q, p, (*mi).second);
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.
expr = expr.substr(0, q) + "0" + expr.substr(p); expr = expr.substr(0, q) + "0" + expr.substr(p);
@ -1470,7 +1468,7 @@ handle_define_directive(const string &args, const YYLTYPE &loc) {
if (args.empty()) { if (args.empty()) {
warning("Ignoring empty #define directive", loc); warning("Ignoring empty #define directive", loc);
} else { } else {
CPPManifest *manifest = new CPPManifest(args, loc.file); CPPManifest *manifest = new CPPManifest(args, loc);
manifest->_vis = preprocessor_vis; manifest->_vis = preprocessor_vis;
if (!manifest->_has_parameters) { if (!manifest->_has_parameters) {
string expr_string = manifest->expand(); string expr_string = manifest->expand();
@ -1479,18 +1477,17 @@ handle_define_directive(const string &args, const YYLTYPE &loc) {
} }
} }
// ok one memory leak here.. pair<Manifests::iterator, bool> result =
Manifests::iterator mi = _manifests.find(manifest->_name); _manifests.insert(Manifests::value_type(manifest->_name, manifest));
if(mi != _manifests.end())
{ if (!result.second) {
// i do not see a goodway to compare the old and new hmmmm // There was already a macro with this name. Delete the old.
//cerr << "Warning Overwriting Constant " << manifest->_name << "\n"; CPPManifest *other = result.first->second;
delete mi->second; warning("redefinition of macro '" + manifest->_name + "'", loc);
warning("previous definition is here", other->_loc);
delete other;
result.first->second = manifest;
} }
_manifests[manifest->_name] = manifest;
} }
} }
@ -1560,7 +1557,9 @@ handle_if_directive(const string &args, const YYLTYPE &loc) {
if (expr != (CPPExpression *)NULL) { if (expr != (CPPExpression *)NULL) {
CPPExpression::Result result = expr->evaluate(); CPPExpression::Result result = expr->evaluate();
if (result._type == CPPExpression::RT_error) { if (result._type == CPPExpression::RT_error) {
warning("Ignoring invalid expression " + args, loc); ostringstream strm;
strm << *expr;
warning("Ignoring invalid expression " + strm.str(), loc);
} else { } else {
expression_result = result.as_integer(); expression_result = result.as_integer();
} }
@ -2302,6 +2301,8 @@ check_keyword(const string &name) {
if (name == "char32_t") return KW_CHAR32_T; if (name == "char32_t") return KW_CHAR32_T;
if (name == "class") return KW_CLASS; if (name == "class") return KW_CLASS;
if (name == "const") return KW_CONST; if (name == "const") return KW_CONST;
if (name == "__const") return KW_CONST;
if (name == "__const__") return KW_CONST;
if (name == "delete") return KW_DELETE; if (name == "delete") return KW_DELETE;
if (name == "double") return KW_DOUBLE; if (name == "double") return KW_DOUBLE;
if (name == "dynamic_cast") return KW_DYNAMIC_CAST; if (name == "dynamic_cast") return KW_DYNAMIC_CAST;
@ -2319,6 +2320,8 @@ check_keyword(const string &name) {
if (name == "goto") return KW_GOTO; if (name == "goto") return KW_GOTO;
if (name == "if") return KW_IF; if (name == "if") return KW_IF;
if (name == "inline") return KW_INLINE; if (name == "inline") return KW_INLINE;
if (name == "__inline") return KW_INLINE;
if (name == "__inline__") return KW_INLINE;
if (name == "int") return KW_INT; if (name == "int") return KW_INT;
if (name == "long") return KW_LONG; if (name == "long") return KW_LONG;
if (name == "__make_property") return KW_MAKE_PROPERTY; if (name == "__make_property") return KW_MAKE_PROPERTY;
@ -2337,6 +2340,7 @@ check_keyword(const string &name) {
if (name == "signed") return KW_SIGNED; if (name == "signed") return KW_SIGNED;
if (name == "sizeof") return KW_SIZEOF; if (name == "sizeof") return KW_SIZEOF;
if (name == "static") return KW_STATIC; if (name == "static") return KW_STATIC;
if (name == "static_assert") return KW_STATIC_ASSERT;
if (name == "static_cast") return KW_STATIC_CAST; if (name == "static_cast") return KW_STATIC_CAST;
if (name == "struct") return KW_STRUCT; if (name == "struct") return KW_STRUCT;
if (name == "template") return KW_TEMPLATE; if (name == "template") return KW_TEMPLATE;

View File

@ -101,6 +101,9 @@ public:
// incremented), or set it higher to get more debugging information. // incremented), or set it higher to get more debugging information.
int _verbose; int _verbose;
// The location of the last token.
cppyyltype _last_token_loc;
protected: protected:
bool init_cpp(const CPPFile &file); bool init_cpp(const CPPFile &file);
bool init_const_expr(const string &expr); bool init_const_expr(const string &expr);

View File

@ -1344,14 +1344,14 @@ scan_manifest(CPPManifest *manifest) {
return; return;
} }
if (manifest->_file.is_c_file()) { if (manifest->_loc.file.is_c_file()) {
// This #define appears in a .C file. We can only export // This #define appears in a .C file. We can only export
// manifests defined in a .h file. // manifests defined in a .h file.
return; return;
} }
if (manifest->_file._source != CPPFile::S_local || if (manifest->_loc.file._source != CPPFile::S_local ||
in_ignorefile(manifest->_file._filename_as_referenced)) { in_ignorefile(manifest->_loc.file._filename_as_referenced)) {
// The manifest is defined in some other package or in an // The manifest is defined in some other package or in an
// ignorable file. // ignorable file.
return; return;

View File

@ -1354,13 +1354,13 @@ def CompileIgate(woutd,wsrc,opts):
cmd += ' -srcdir %s -I%s' % (srcdir, srcdir) cmd += ' -srcdir %s -I%s' % (srcdir, srcdir)
cmd += ' -DCPPPARSER -D__STDC__=1 -D__cplusplus=201103L' cmd += ' -DCPPPARSER -D__STDC__=1 -D__cplusplus=201103L'
if (COMPILER=="MSVC"): if (COMPILER=="MSVC"):
cmd += ' -D__inline -D_X86_ -DWIN32_VC -DWIN32 -D_WIN32' cmd += ' -D_X86_ -DWIN32_VC -DWIN32 -D_WIN32'
if GetTargetArch() == 'x64': if GetTargetArch() == 'x64':
cmd += ' -DWIN64_VC -DWIN64 -D_WIN64' cmd += ' -DWIN64_VC -DWIN64 -D_WIN64'
# NOTE: this 1600 value is the version number for VC2010. # NOTE: this 1600 value is the version number for VC2010.
cmd += ' -D_MSC_VER=1600 -D"__declspec(param)=" -D__cdecl -D_near -D_far -D__near -D__far -D__stdcall' cmd += ' -D_MSC_VER=1600 -D"__declspec(param)=" -D__cdecl -D_near -D_far -D__near -D__far -D__stdcall'
if (COMPILER=="GCC"): if (COMPILER=="GCC"):
cmd += ' -D__inline -D__const=const -D__attribute__\(x\)=' cmd += ' -D__attribute__\(x\)='
if GetTargetArch() in ("x86_64", "amd64"): if GetTargetArch() in ("x86_64", "amd64"):
cmd += ' -D_LP64' cmd += ' -D_LP64'
else: else: