/* GCC-StarPU
Copyright (C) 2011, 2012 Institut National de Recherche en Informatique et Automatique
GCC-StarPU is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
GCC-StarPU is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC-StarPU. If not, see . */
/* Parser for simple C expressions in pragmas. */
%define api.pure
%parse-param { location_t loc }
%parse-param { const char *pragma }
%parse-param { tree *seq }
%debug
%{
#include
#include
#include
#include
#include
#ifdef HAVE_C_FAMILY_C_COMMON_H
# include
#elif HAVE_C_COMMON_H
# include
#endif
#ifdef HAVE_C_FAMILY_C_PRAGMA_H
# include
#elif HAVE_C_PRAGMA_H
# include
#endif
#include
#if !HAVE_DECL_BUILD_ARRAY_REF
/* This declaration is missing in GCC 4.6.1. */
extern tree build_array_ref (location_t loc, tree array, tree index);
#endif
#define YYSTYPE tree
#define YYLTYPE location_t
static void
yyerror (location_t loc, const char *pragma, tree *seq,
char const *message)
{
error_at (loc, "parse error in pragma %qs: %s", pragma, message);
}
/* Return SOMETHING if it's a VAR_DECL, an identifier bound to a VAR_DECL,
or another object; raise an error otherwise. */
static tree
ensure_bound (location_t loc, tree something)
{
gcc_assert (something != NULL_TREE);
if (DECL_P (something))
return something;
else if (TREE_CODE (something) == IDENTIFIER_NODE)
{
tree var = lookup_name (something);
if (var == NULL_TREE)
{
error_at (loc, "unbound variable %qE", something);
return error_mark_node;
}
else
return var;
}
return something;
}
static tree
build_component_ref (location_t loc, tree what, tree field)
{
sorry ("struct field access not implemented yet"); /* XXX */
return error_mark_node;
}
/* Interpret the string beneath CST, and return a new string constant. */
static tree
interpret_string (const_tree cst)
{
gcc_assert (TREE_CODE (cst) == STRING_CST);
cpp_string input, interpreted;
input.text = (unsigned char *) TREE_STRING_POINTER (cst);
input.len = TREE_STRING_LENGTH (cst);
bool success;
success = cpp_interpret_string (parse_in, &input, 1, &interpreted,
CPP_STRING);
gcc_assert (success);
return build_string (interpreted.len, (char *) interpreted.text);
}
%}
%code {
/* Mapping of libcpp token names to Bison-generated token names. This is
not ideal but Bison cannot be told to use the `enum cpp_ttype'
values. */
#define STARPU_CPP_TOKENS \
TK (CPP_NAME) \
TK (CPP_NUMBER) \
TK (CPP_AND) \
TK (CPP_OPEN_SQUARE) \
TK (CPP_CLOSE_SQUARE) \
TK (CPP_OPEN_PAREN) \
TK (CPP_CLOSE_PAREN) \
TK (CPP_PLUS) \
TK (CPP_MINUS) \
TK (CPP_MULT) \
TK (CPP_DIV) \
TK (CPP_DOT) \
TK (CPP_DEREF) \
TK (CPP_STRING)
#ifndef __cplusplus
static const int cpplib_bison_token_map[] =
{
# define TK(x) [x] = Y ## x,
STARPU_CPP_TOKENS
# undef TK
};
#else /* __cplusplus */
/* No designated initializers in C++. */
static int cpplib_bison_token_map[CPP_PADDING];
#endif /* __cplusplus */
static int
yylex (YYSTYPE *lvalp)
{
int ret;
enum cpp_ttype type;
location_t loc;
#ifdef __cplusplus
if (cpplib_bison_token_map[CPP_NAME] != YCPP_NAME)
{
/* Initialize the table. */
# define TK(x) cpplib_bison_token_map[x] = Y ## x;
STARPU_CPP_TOKENS
# undef TK
}
#endif
/* First check whether EOL is reached, because the EOL token needs to be
left to the C parser. */
type = cpp_peek_token (parse_in, 0)->type;
if (type == CPP_PRAGMA_EOL)
ret = -1;
else
{
/* Tell the lexer to not concatenate adjacent strings like cpp and
`pragma_lex' normally do, because we want to be able to
distinguish adjacent STRING_CST. */
type = c_lex_with_flags (lvalp, &loc, NULL, C_LEX_STRING_NO_JOIN);
if (type == CPP_STRING)
/* XXX: When using `C_LEX_STRING_NO_JOIN', `c_lex_with_flags'
doesn't call `cpp_interpret_string', leaving us with an
uninterpreted string (with quotes, etc.) This hack works around
that. */
*lvalp = interpret_string (*lvalp);
if (type < sizeof cpplib_bison_token_map / sizeof cpplib_bison_token_map[0])
ret = cpplib_bison_token_map[type];
else
ret = -1;
}
return ret;
}
}
%token YCPP_NAME "identifier"
%token YCPP_NUMBER "integer"
%token YCPP_AND "&"
%token YCPP_OPEN_SQUARE "["
%token YCPP_CLOSE_SQUARE "]"
%token YCPP_OPEN_PAREN "("
%token YCPP_CLOSE_PAREN ")"
%token YCPP_PLUS "+"
%token YCPP_MINUS "-"
%token YCPP_MULT "*"
%token YCPP_DIV "/"
%token YCPP_DOT "."
%token YCPP_DEREF "->"
%token YCPP_STRING "string"
%% /* Grammar rules. */
/* Always return a TREE_LIST rather than a raw chain, because the elements
of that list may be already chained for other purposes---e.g., PARM_DECLs
of a function are chained together. */
sequence: expression {
gcc_assert (*seq == NULL_TREE);
*seq = tree_cons (NULL_TREE, $1, NULL_TREE);
$$ = *seq;
}
| expression sequence {
gcc_assert ($2 == *seq);
*seq = tree_cons (NULL_TREE, $1, $2);
$$ = *seq;
}
;
expression: binary_expression
;
/* XXX: `ensure_bound' below leads to errors raised even for non-significant
arguments---e.g., junk after pragma. */
identifier: YCPP_NAME { $$ = ensure_bound (loc, $1); }
;
binary_expression: additive_expression
;
multiplicative_expression: multiplicative_expression YCPP_MULT cast_expression {
$$ = build_binary_op (UNKNOWN_LOCATION, MULT_EXPR, $1, $3, 0);
}
| multiplicative_expression YCPP_DIV cast_expression {
$$ = build_binary_op (UNKNOWN_LOCATION, TRUNC_DIV_EXPR, $1, $3, 0);
}
| cast_expression
;
additive_expression: multiplicative_expression
| additive_expression YCPP_PLUS multiplicative_expression {
$$ = build_binary_op (UNKNOWN_LOCATION, PLUS_EXPR, $1, $3, 0);
}
| additive_expression YCPP_MINUS multiplicative_expression {
$$ = build_binary_op (UNKNOWN_LOCATION, MINUS_EXPR, $1, $3, 0);
}
;
cast_expression: unary_expression
/* XXX: No support for '(' TYPE-NAME ')' UNARY-EXPRESSION. */
;
unary_expression: postfix_expression
| YCPP_AND cast_expression {
$$ = build_addr (ensure_bound (loc, $2), current_function_decl);
}
;
postfix_expression:
primary_expression
| postfix_expression YCPP_OPEN_SQUARE expression YCPP_CLOSE_SQUARE {
#if 1
/* Build the array ref with proper error checking. */
$$ = build_array_ref (loc, ensure_bound (loc, $1),
ensure_bound (loc, $3));
#else /* TIMTOWTDI */
$$ = build_indirect_ref (loc,
build_binary_op (loc, PLUS_EXPR, ensure_bound (loc, $1), ensure_bound (loc, $3), 0),
RO_ARRAY_INDEXING);
#endif
}
| postfix_expression YCPP_DOT identifier {
$$ = build_component_ref (loc, ensure_bound (loc, $1), $2);
}
| postfix_expression YCPP_DEREF identifier {
$$ = build_component_ref (loc,
build_indirect_ref (loc, ensure_bound (loc, $1), RO_ARRAY_INDEXING),
$2);
}
;
primary_expression: identifier
| constant
| string_literal
| YCPP_OPEN_PAREN expression YCPP_CLOSE_PAREN { $$ = $2; }
;
constant: YCPP_NUMBER { $$ = $1; }
;
string_literal: YCPP_STRING { $$ = $1; }
;
%%