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

View File

@ -57,7 +57,7 @@ int yyparse();
static void
yyerror(const string &msg) {
current_lexer->error(msg);
current_lexer->error(msg, current_lexer->_last_token_loc);
}
static void
@ -199,9 +199,11 @@ pop_struct() {
/* This is a bison-specific declaration to enable recursive calls to
yyparse(). It changes the calling sequence to yylex(), passing
pointers to the current yylval and yylloc. It also adds a pointer
to the current lloc to yyerror, which gives us better diagnostics. */
%define api.pure full
pointers to the current yylval and yylloc. Bison 2.7 introduces a
different syntax that will also pass the current yylloc to yyerror,
but we have to support Bison versions as old as 2.5 for now. */
/*%define api.pure full*/
%pure-parser
%locations
%token <u.real> REAL
@ -288,6 +290,7 @@ pop_struct() {
%token KW_SIGNED
%token KW_SIZEOF
%token KW_STATIC
%token KW_STATIC_ASSERT
%token KW_STATIC_CAST
%token KW_STRUCT
%token KW_TEMPLATE
@ -518,10 +521,29 @@ declaration:
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
}
}
| KW_MAKE_SEQ '(' name ',' name ',' name ')' ';'
| KW_MAKE_SEQ '(' name ',' name ',' name ')' ';'
{
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);
}
| 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();
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);
CPPInstanceIdentifier *ii = $4;
@ -871,6 +896,9 @@ function_prototype:
{
pop_scope();
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);
CPPInstanceIdentifier *ii = $5;
@ -1213,6 +1241,9 @@ template_formal_parameter_type:
| TYPENAME_IDENTIFIER
{
$$ = $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);
}
;
@ -1608,6 +1639,9 @@ type:
| TYPENAME_IDENTIFIER
{
$$ = $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);
}
| KW_TYPENAME name
@ -1668,6 +1702,9 @@ type_decl:
| TYPENAME_IDENTIFIER
{
$$ = $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);
}
| KW_TYPENAME name
@ -1746,6 +1783,9 @@ predefined_type:
| TYPENAME_IDENTIFIER
{
$$ = $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);
}
| KW_TYPENAME name
@ -2419,6 +2459,9 @@ const_expr:
{
// A constructor call.
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);
$$ = new CPPExpression(CPPExpression::construct_op(type, $3));
}
@ -2888,6 +2931,9 @@ typedefname:
TYPENAME_IDENTIFIER
{
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);
$$ = type;
}

View File

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

View File

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

View File

@ -407,6 +407,7 @@ get_next_token0() {
return token;
}
_saved_tokens.push_back(token);
_last_token_loc = loc;
return CPPToken(SCOPING, loc, name, result);
}
@ -444,10 +445,12 @@ get_next_token0() {
token_type = TYPENAME_IDENTIFIER;
}
_last_token_loc = loc;
return CPPToken(token_type, loc, name, result);
}
// This is the normal case: just pass through whatever token we got.
_last_token_loc = loc;
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()
// 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;
do {
manifest_found = false;
@ -867,10 +866,9 @@ expand_manifests(const string &input_expr, bool expand_undefined) {
Manifests::const_iterator mi = _manifests.find(ident);
if (mi != _manifests.end()) {
const CPPManifest *manifest = (*mi).second;
if (already_expanded.insert(manifest).second) {
expand_manifest_inline(expr, q, p, (*mi).second);
manifest_found = true;
}
expand_manifest_inline(expr, q, p, (*mi).second);
manifest_found = true;
} else if (expand_undefined && ident != "true" && ident != "false") {
// It is not found. Expand it to 0.
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()) {
warning("Ignoring empty #define directive", loc);
} else {
CPPManifest *manifest = new CPPManifest(args, loc.file);
CPPManifest *manifest = new CPPManifest(args, loc);
manifest->_vis = preprocessor_vis;
if (!manifest->_has_parameters) {
string expr_string = manifest->expand();
@ -1479,18 +1477,17 @@ handle_define_directive(const string &args, const YYLTYPE &loc) {
}
}
// ok one memory leak here..
Manifests::iterator mi = _manifests.find(manifest->_name);
if(mi != _manifests.end())
{
// i do not see a goodway to compare the old and new hmmmm
//cerr << "Warning Overwriting Constant " << manifest->_name << "\n";
delete mi->second;
pair<Manifests::iterator, bool> result =
_manifests.insert(Manifests::value_type(manifest->_name, manifest));
if (!result.second) {
// There was already a macro with this name. Delete the old.
CPPManifest *other = result.first->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) {
CPPExpression::Result result = expr->evaluate();
if (result._type == CPPExpression::RT_error) {
warning("Ignoring invalid expression " + args, loc);
ostringstream strm;
strm << *expr;
warning("Ignoring invalid expression " + strm.str(), loc);
} else {
expression_result = result.as_integer();
}
@ -2302,6 +2301,8 @@ check_keyword(const string &name) {
if (name == "char32_t") return KW_CHAR32_T;
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 == "delete") return KW_DELETE;
if (name == "double") return KW_DOUBLE;
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 == "if") return KW_IF;
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 == "long") return KW_LONG;
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 == "sizeof") return KW_SIZEOF;
if (name == "static") return KW_STATIC;
if (name == "static_assert") return KW_STATIC_ASSERT;
if (name == "static_cast") return KW_STATIC_CAST;
if (name == "struct") return KW_STRUCT;
if (name == "template") return KW_TEMPLATE;

View File

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

View File

@ -1344,14 +1344,14 @@ scan_manifest(CPPManifest *manifest) {
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
// manifests defined in a .h file.
return;
}
if (manifest->_file._source != CPPFile::S_local ||
in_ignorefile(manifest->_file._filename_as_referenced)) {
if (manifest->_loc.file._source != CPPFile::S_local ||
in_ignorefile(manifest->_loc.file._filename_as_referenced)) {
// The manifest is defined in some other package or in an
// ignorable file.
return;

View File

@ -1354,13 +1354,13 @@ def CompileIgate(woutd,wsrc,opts):
cmd += ' -srcdir %s -I%s' % (srcdir, srcdir)
cmd += ' -DCPPPARSER -D__STDC__=1 -D__cplusplus=201103L'
if (COMPILER=="MSVC"):
cmd += ' -D__inline -D_X86_ -DWIN32_VC -DWIN32 -D_WIN32'
cmd += ' -D_X86_ -DWIN32_VC -DWIN32 -D_WIN32'
if GetTargetArch() == 'x64':
cmd += ' -DWIN64_VC -DWIN64 -D_WIN64'
# 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'
if (COMPILER=="GCC"):
cmd += ' -D__inline -D__const=const -D__attribute__\(x\)='
cmd += ' -D__attribute__\(x\)='
if GetTargetArch() in ("x86_64", "amd64"):
cmd += ' -D_LP64'
else: