c-expr.y 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /* GCC-StarPU
  2. Copyright (C) 2011, 2012 Institut National de Recherche en Informatique et Automatique
  3. GCC-StarPU is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. GCC-StarPU is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with GCC-StarPU. If not, see <http://www.gnu.org/licenses/>. */
  13. /* Parser for simple C expressions in pragmas. */
  14. %define api.pure
  15. %parse-param { location_t loc }
  16. %parse-param { const char *pragma }
  17. %parse-param { tree *seq }
  18. %debug
  19. %{
  20. #include <starpu-gcc-config.h>
  21. #include <gcc-plugin.h>
  22. #include <plugin.h>
  23. #include <tree.h>
  24. #include <cpplib.h>
  25. #ifdef HAVE_C_FAMILY_C_COMMON_H
  26. # include <c-family/c-common.h>
  27. #elif HAVE_C_COMMON_H
  28. # include <c-common.h>
  29. #endif
  30. #ifdef HAVE_C_FAMILY_C_PRAGMA_H
  31. # include <c-family/c-pragma.h>
  32. #elif HAVE_C_PRAGMA_H
  33. # include <c-pragma.h>
  34. #endif
  35. #if !HAVE_DECL_BUILD_ARRAY_REF
  36. /* This declaration is missing in GCC 4.6.1. */
  37. extern tree build_array_ref (location_t loc, tree array, tree index);
  38. #endif
  39. #define YYSTYPE tree
  40. #define YYLTYPE location_t
  41. static void
  42. yyerror (location_t loc, const char *pragma, tree *seq,
  43. char const *message)
  44. {
  45. error_at (loc, "parse error in pragma %qs: %s", pragma, message);
  46. }
  47. /* Return SOMETHING if it's a VAR_DECL, an identifier bound to a VAR_DECL,
  48. or another object; raise an error otherwise. */
  49. static tree
  50. ensure_bound (location_t loc, tree something)
  51. {
  52. gcc_assert (something != NULL_TREE);
  53. if (DECL_P (something))
  54. return something;
  55. else if (TREE_CODE (something) == IDENTIFIER_NODE)
  56. {
  57. tree var = lookup_name (something);
  58. if (var == NULL_TREE)
  59. {
  60. error_at (loc, "unbound variable %qE", something);
  61. return error_mark_node;
  62. }
  63. else
  64. return var;
  65. }
  66. return something;
  67. }
  68. static tree
  69. build_component_ref (location_t loc, tree what, tree field)
  70. {
  71. sorry ("struct field access not implemented yet"); /* XXX */
  72. return error_mark_node;
  73. }
  74. /* Interpret the string beneath CST, and return a new string constant. */
  75. static tree
  76. interpret_string (const_tree cst)
  77. {
  78. gcc_assert (TREE_CODE (cst) == STRING_CST);
  79. cpp_string input, interpreted;
  80. input.text = (unsigned char *) TREE_STRING_POINTER (cst);
  81. input.len = TREE_STRING_LENGTH (cst);
  82. bool success;
  83. success = cpp_interpret_string (parse_in, &input, 1, &interpreted,
  84. CPP_STRING);
  85. gcc_assert (success);
  86. return build_string (interpreted.len, (char *) interpreted.text);
  87. }
  88. %}
  89. %code {
  90. /* Mapping of libcpp token names to Bison-generated token names. This is
  91. not ideal but Bison cannot be told to use the `enum cpp_ttype'
  92. values. */
  93. #define STARPU_CPP_TOKENS \
  94. TK (CPP_NAME) \
  95. TK (CPP_NUMBER) \
  96. TK (CPP_AND) \
  97. TK (CPP_OPEN_SQUARE) \
  98. TK (CPP_CLOSE_SQUARE) \
  99. TK (CPP_OPEN_PAREN) \
  100. TK (CPP_CLOSE_PAREN) \
  101. TK (CPP_PLUS) \
  102. TK (CPP_MINUS) \
  103. TK (CPP_MULT) \
  104. TK (CPP_DIV) \
  105. TK (CPP_DOT) \
  106. TK (CPP_DEREF) \
  107. TK (CPP_STRING)
  108. #ifndef __cplusplus
  109. static const int cpplib_bison_token_map[] =
  110. {
  111. # define TK(x) [x] = Y ## x,
  112. STARPU_CPP_TOKENS
  113. # undef TK
  114. };
  115. #else /* __cplusplus */
  116. /* No designated initializers in C++. */
  117. static int cpplib_bison_token_map[CPP_PADDING];
  118. #endif /* __cplusplus */
  119. static int
  120. yylex (YYSTYPE *lvalp)
  121. {
  122. int ret;
  123. enum cpp_ttype type;
  124. location_t loc;
  125. #ifdef __cplusplus
  126. if (cpplib_bison_token_map[CPP_NAME] != YCPP_NAME)
  127. {
  128. /* Initialize the table. */
  129. # define TK(x) cpplib_bison_token_map[x] = Y ## x;
  130. STARPU_CPP_TOKENS
  131. # undef TK
  132. }
  133. #endif
  134. /* First check whether EOL is reached, because the EOL token needs to be
  135. left to the C parser. */
  136. type = cpp_peek_token (parse_in, 0)->type;
  137. if (type == CPP_PRAGMA_EOL)
  138. ret = -1;
  139. else
  140. {
  141. /* Tell the lexer to not concatenate adjacent strings like cpp and
  142. `pragma_lex' normally do, because we want to be able to
  143. distinguish adjacent STRING_CST. */
  144. type = c_lex_with_flags (lvalp, &loc, NULL, C_LEX_STRING_NO_JOIN);
  145. if (type == CPP_STRING)
  146. /* XXX: When using `C_LEX_STRING_NO_JOIN', `c_lex_with_flags'
  147. doesn't call `cpp_interpret_string', leaving us with an
  148. uninterpreted string (with quotes, etc.) This hack works around
  149. that. */
  150. *lvalp = interpret_string (*lvalp);
  151. if (type < sizeof cpplib_bison_token_map / sizeof cpplib_bison_token_map[0])
  152. ret = cpplib_bison_token_map[type];
  153. else
  154. ret = -1;
  155. }
  156. return ret;
  157. }
  158. }
  159. %token YCPP_NAME "identifier"
  160. %token YCPP_NUMBER "integer"
  161. %token YCPP_AND "&"
  162. %token YCPP_OPEN_SQUARE "["
  163. %token YCPP_CLOSE_SQUARE "]"
  164. %token YCPP_OPEN_PAREN "("
  165. %token YCPP_CLOSE_PAREN ")"
  166. %token YCPP_PLUS "+"
  167. %token YCPP_MINUS "-"
  168. %token YCPP_MULT "*"
  169. %token YCPP_DIV "/"
  170. %token YCPP_DOT "."
  171. %token YCPP_DEREF "->"
  172. %token YCPP_STRING "string"
  173. %% /* Grammar rules. */
  174. /* Always return a TREE_LIST rather than a raw chain, because the elements
  175. of that list may be already chained for other purposes---e.g., PARM_DECLs
  176. of a function are chained together. */
  177. sequence: expression {
  178. gcc_assert (*seq == NULL_TREE);
  179. *seq = tree_cons (NULL_TREE, $1, NULL_TREE);
  180. $$ = *seq;
  181. }
  182. | expression sequence {
  183. gcc_assert ($2 == *seq);
  184. *seq = tree_cons (NULL_TREE, $1, $2);
  185. $$ = *seq;
  186. }
  187. ;
  188. expression: binary_expression
  189. ;
  190. /* XXX: `ensure_bound' below leads to errors raised even for non-significant
  191. arguments---e.g., junk after pragma. */
  192. identifier: YCPP_NAME { $$ = ensure_bound (loc, $1); }
  193. ;
  194. binary_expression: additive_expression
  195. ;
  196. multiplicative_expression: multiplicative_expression YCPP_MULT cast_expression {
  197. $$ = build_binary_op (UNKNOWN_LOCATION, MULT_EXPR, $1, $3, 0);
  198. }
  199. | multiplicative_expression YCPP_DIV cast_expression {
  200. $$ = build_binary_op (UNKNOWN_LOCATION, TRUNC_DIV_EXPR, $1, $3, 0);
  201. }
  202. | cast_expression
  203. ;
  204. additive_expression: multiplicative_expression
  205. | additive_expression YCPP_PLUS multiplicative_expression {
  206. $$ = build_binary_op (UNKNOWN_LOCATION, PLUS_EXPR, $1, $3, 0);
  207. }
  208. | additive_expression YCPP_MINUS multiplicative_expression {
  209. $$ = build_binary_op (UNKNOWN_LOCATION, MINUS_EXPR, $1, $3, 0);
  210. }
  211. ;
  212. cast_expression: unary_expression
  213. /* XXX: No support for '(' TYPE-NAME ')' UNARY-EXPRESSION. */
  214. ;
  215. unary_expression: postfix_expression
  216. | YCPP_AND cast_expression {
  217. $$ = build_addr (ensure_bound (loc, $2), current_function_decl);
  218. }
  219. ;
  220. postfix_expression:
  221. primary_expression
  222. | postfix_expression YCPP_OPEN_SQUARE expression YCPP_CLOSE_SQUARE {
  223. #if 1
  224. /* Build the array ref with proper error checking. */
  225. $$ = build_array_ref (loc, ensure_bound (loc, $1),
  226. ensure_bound (loc, $3));
  227. #else /* TIMTOWTDI */
  228. $$ = build_indirect_ref (loc,
  229. build_binary_op (loc, PLUS_EXPR, ensure_bound (loc, $1), ensure_bound (loc, $3), 0),
  230. RO_ARRAY_INDEXING);
  231. #endif
  232. }
  233. | postfix_expression YCPP_DOT identifier {
  234. $$ = build_component_ref (loc, ensure_bound (loc, $1), $2);
  235. }
  236. | postfix_expression YCPP_DEREF identifier {
  237. $$ = build_component_ref (loc,
  238. build_indirect_ref (loc, ensure_bound (loc, $1), RO_ARRAY_INDEXING),
  239. $2);
  240. }
  241. ;
  242. primary_expression: identifier
  243. | constant
  244. | string_literal
  245. | YCPP_OPEN_PAREN expression YCPP_CLOSE_PAREN { $$ = $2; }
  246. ;
  247. constant: YCPP_NUMBER { $$ = $1; }
  248. ;
  249. string_literal: YCPP_STRING { $$ = $1; }
  250. ;
  251. %%