Intel SPMD Program Compiler  1.11.0
lex.ll
Go to the documentation of this file.
1 /*
2  Copyright (c) 2010-2012, Intel Corporation
3  All rights reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are
7  met:
8 
9  * Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11 
12  * Redistributions in binary form must reproduce the above copyright
13  notice, this list of conditions and the following disclaimer in the
14  documentation and/or other materials provided with the distribution.
15 
16  * Neither the name of Intel Corporation nor the names of its
17  contributors may be used to endorse or promote products derived from
18  this software without specific prior written permission.
19 
20 
21  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 %{
35 
36 #include "ispc.h"
37 #include "sym.h"
38 #include "util.h"
39 #include "module.h"
40 #include "type.h"
41 #include "parse.hh"
42 #include <stdlib.h>
43 #include <stdint.h>
44 
45 static uint64_t lParseBinary(const char *ptr, SourcePos pos, char **endPtr);
46 static int lParseInteger(bool dotdotdot);
47 static void lCComment(SourcePos *);
48 static void lCppComment(SourcePos *);
49 static void lPragmaIgnoreWarning(SourcePos *);
50 static void lHandleCppHash(SourcePos *);
51 static void lStringConst(YYSTYPE *, SourcePos *);
52 static double lParseHexFloat(const char *ptr);
53 extern void RegisterDependency(const std::string &fileName);
54 
55 #define YY_USER_ACTION \
56  yylloc.first_line = yylloc.last_line; \
57  yylloc.first_column = yylloc.last_column; \
58  yylloc.last_column += yyleng;
59 
60 #ifdef ISPC_IS_WINDOWS
61 inline int isatty(int) { return 0; }
62 #else
63 #include <unistd.h>
64 #endif // ISPC_IS_WINDOWS
65 
66 static int allTokens[] = {
67  TOKEN_ASSERT, TOKEN_BOOL, TOKEN_BREAK, TOKEN_CASE,
68  TOKEN_CDO, TOKEN_CFOR, TOKEN_CIF, TOKEN_CWHILE,
69  TOKEN_CONST, TOKEN_CONTINUE, TOKEN_DEFAULT, TOKEN_DO,
70  TOKEN_DELETE, TOKEN_DOUBLE, TOKEN_ELSE, TOKEN_ENUM,
71  TOKEN_EXPORT, TOKEN_EXTERN, TOKEN_FALSE, TOKEN_FLOAT, TOKEN_FOR,
72  TOKEN_FOREACH, TOKEN_FOREACH_ACTIVE, TOKEN_FOREACH_TILED,
73  TOKEN_FOREACH_UNIQUE, TOKEN_GOTO, TOKEN_IF, TOKEN_IN, TOKEN_INLINE,
74  TOKEN_INT, TOKEN_INT8, TOKEN_INT16, TOKEN_INT, TOKEN_INT64, TOKEN_LAUNCH,
75  TOKEN_NEW, TOKEN_NULL, TOKEN_PRINT, TOKEN_RETURN, TOKEN_SOA, TOKEN_SIGNED,
76  TOKEN_SIZEOF, TOKEN_STATIC, TOKEN_STRUCT, TOKEN_SWITCH, TOKEN_SYNC,
77  TOKEN_TASK, TOKEN_TRUE, TOKEN_TYPEDEF, TOKEN_UNIFORM, TOKEN_UNMASKED,
78  TOKEN_UNSIGNED, TOKEN_VARYING, TOKEN_VOID, TOKEN_WHILE,
79  TOKEN_STRING_C_LITERAL, TOKEN_DOTDOTDOT,
80  TOKEN_FLOAT_CONSTANT, TOKEN_DOUBLE_CONSTANT,
81  TOKEN_INT8_CONSTANT, TOKEN_UINT8_CONSTANT,
82  TOKEN_INT16_CONSTANT, TOKEN_UINT16_CONSTANT,
83  TOKEN_INT32_CONSTANT, TOKEN_UINT32_CONSTANT,
84  TOKEN_INT64_CONSTANT, TOKEN_UINT64_CONSTANT,
85  TOKEN_INC_OP, TOKEN_DEC_OP, TOKEN_LEFT_OP, TOKEN_RIGHT_OP, TOKEN_LE_OP,
86  TOKEN_GE_OP, TOKEN_EQ_OP, TOKEN_NE_OP, TOKEN_AND_OP, TOKEN_OR_OP,
87  TOKEN_MUL_ASSIGN, TOKEN_DIV_ASSIGN, TOKEN_MOD_ASSIGN, TOKEN_ADD_ASSIGN,
88  TOKEN_SUB_ASSIGN, TOKEN_LEFT_ASSIGN, TOKEN_RIGHT_ASSIGN, TOKEN_AND_ASSIGN,
89  TOKEN_XOR_ASSIGN, TOKEN_OR_ASSIGN, TOKEN_PTR_OP,
90  ';', '{', '}', ',', ':', '=', '(', ')', '[', ']', '.', '&', '!', '~', '-',
91  '+', '*', '/', '%', '<', '>', '^', '|', '?',
92 };
93 
94 std::map<int, std::string> tokenToName;
95 std::map<std::string, std::string> tokenNameRemap;
96 
97 void ParserInit() {
98  tokenToName[TOKEN_ASSERT] = "assert";
99  tokenToName[TOKEN_BOOL] = "bool";
100  tokenToName[TOKEN_BREAK] = "break";
101  tokenToName[TOKEN_CASE] = "case";
102  tokenToName[TOKEN_CDO] = "cdo";
103  tokenToName[TOKEN_CFOR] = "cfor";
104  tokenToName[TOKEN_CIF] = "cif";
105  tokenToName[TOKEN_CWHILE] = "cwhile";
106  tokenToName[TOKEN_CONST] = "const";
107  tokenToName[TOKEN_CONTINUE] = "continue";
108  tokenToName[TOKEN_DEFAULT] = "default";
109  tokenToName[TOKEN_DO] = "do";
110  tokenToName[TOKEN_DELETE] = "delete";
111  tokenToName[TOKEN_DOUBLE] = "double";
112  tokenToName[TOKEN_ELSE] = "else";
113  tokenToName[TOKEN_ENUM] = "enum";
114  tokenToName[TOKEN_EXPORT] = "export";
115  tokenToName[TOKEN_EXTERN] = "extern";
116  tokenToName[TOKEN_FALSE] = "false";
117  tokenToName[TOKEN_FLOAT] = "float";
118  tokenToName[TOKEN_FOR] = "for";
119  tokenToName[TOKEN_FOREACH] = "foreach";
120  tokenToName[TOKEN_FOREACH_ACTIVE] = "foreach_active";
121  tokenToName[TOKEN_FOREACH_TILED] = "foreach_tiled";
122  tokenToName[TOKEN_FOREACH_UNIQUE] = "foreach_unique";
123  tokenToName[TOKEN_GOTO] = "goto";
124  tokenToName[TOKEN_IF] = "if";
125  tokenToName[TOKEN_IN] = "in";
126  tokenToName[TOKEN_INLINE] = "inline";
127  tokenToName[TOKEN_INT] = "int";
128  tokenToName[TOKEN_INT8] = "int8";
129  tokenToName[TOKEN_INT16] = "int16";
130  tokenToName[TOKEN_INT] = "int";
131  tokenToName[TOKEN_INT64] = "int64";
132  tokenToName[TOKEN_LAUNCH] = "launch";
133  tokenToName[TOKEN_NEW] = "new";
134  tokenToName[TOKEN_NULL] = "NULL";
135  tokenToName[TOKEN_PRINT] = "print";
136  tokenToName[TOKEN_RETURN] = "return";
137  tokenToName[TOKEN_SOA] = "soa";
138  tokenToName[TOKEN_SIGNED] = "signed";
139  tokenToName[TOKEN_SIZEOF] = "sizeof";
140  tokenToName[TOKEN_STATIC] = "static";
141  tokenToName[TOKEN_STRUCT] = "struct";
142  tokenToName[TOKEN_SWITCH] = "switch";
143  tokenToName[TOKEN_SYNC] = "sync";
144  tokenToName[TOKEN_TASK] = "task";
145  tokenToName[TOKEN_TRUE] = "true";
146  tokenToName[TOKEN_TYPEDEF] = "typedef";
147  tokenToName[TOKEN_UNIFORM] = "uniform";
148  tokenToName[TOKEN_UNMASKED] = "unmasked";
149  tokenToName[TOKEN_UNSIGNED] = "unsigned";
150  tokenToName[TOKEN_VARYING] = "varying";
151  tokenToName[TOKEN_VOID] = "void";
152  tokenToName[TOKEN_WHILE] = "while";
153  tokenToName[TOKEN_STRING_C_LITERAL] = "\"C\"";
154  tokenToName[TOKEN_DOTDOTDOT] = "...";
155  tokenToName[TOKEN_FLOAT_CONSTANT] = "TOKEN_FLOAT_CONSTANT";
156  tokenToName[TOKEN_DOUBLE_CONSTANT] = "TOKEN_DOUBLE_CONSTANT";
157  tokenToName[TOKEN_INT8_CONSTANT] = "TOKEN_INT8_CONSTANT";
158  tokenToName[TOKEN_UINT8_CONSTANT] = "TOKEN_UINT8_CONSTANT";
159  tokenToName[TOKEN_INT16_CONSTANT] = "TOKEN_INT16_CONSTANT";
160  tokenToName[TOKEN_UINT16_CONSTANT] = "TOKEN_UINT16_CONSTANT";
161  tokenToName[TOKEN_INT32_CONSTANT] = "TOKEN_INT32_CONSTANT";
162  tokenToName[TOKEN_UINT32_CONSTANT] = "TOKEN_UINT32_CONSTANT";
163  tokenToName[TOKEN_INT64_CONSTANT] = "TOKEN_INT64_CONSTANT";
164  tokenToName[TOKEN_UINT64_CONSTANT] = "TOKEN_UINT64_CONSTANT";
165  tokenToName[TOKEN_INC_OP] = "++";
166  tokenToName[TOKEN_DEC_OP] = "--";
167  tokenToName[TOKEN_LEFT_OP] = "<<";
168  tokenToName[TOKEN_RIGHT_OP] = ">>";
169  tokenToName[TOKEN_LE_OP] = "<=";
170  tokenToName[TOKEN_GE_OP] = ">=";
171  tokenToName[TOKEN_EQ_OP] = "==";
172  tokenToName[TOKEN_NE_OP] = "!=";
173  tokenToName[TOKEN_AND_OP] = "&&";
174  tokenToName[TOKEN_OR_OP] = "||";
175  tokenToName[TOKEN_MUL_ASSIGN] = "*=";
176  tokenToName[TOKEN_DIV_ASSIGN] = "/=";
177  tokenToName[TOKEN_MOD_ASSIGN] = "%=";
178  tokenToName[TOKEN_ADD_ASSIGN] = "+=";
179  tokenToName[TOKEN_SUB_ASSIGN] = "-=";
180  tokenToName[TOKEN_LEFT_ASSIGN] = "<<=";
181  tokenToName[TOKEN_RIGHT_ASSIGN] = ">>=";
182  tokenToName[TOKEN_AND_ASSIGN] = "&=";
183  tokenToName[TOKEN_XOR_ASSIGN] = "^=";
184  tokenToName[TOKEN_OR_ASSIGN] = "|=";
185  tokenToName[TOKEN_PTR_OP] = "->";
186  tokenToName[';'] = ";";
187  tokenToName['{'] = "{";
188  tokenToName['}'] = "}";
189  tokenToName[','] = ",";
190  tokenToName[':'] = ":";
191  tokenToName['='] = "=";
192  tokenToName['('] = "(";
193  tokenToName[')'] = ")";
194  tokenToName['['] = "[";
195  tokenToName[']'] = "]";
196  tokenToName['.'] = ".";
197  tokenToName['&'] = "&";
198  tokenToName['!'] = "!";
199  tokenToName['~'] = "~";
200  tokenToName['-'] = "-";
201  tokenToName['+'] = "+";
202  tokenToName['*'] = "*";
203  tokenToName['/'] = "/";
204  tokenToName['%'] = "%";
205  tokenToName['<'] = "<";
206  tokenToName['>'] = ">";
207  tokenToName['^'] = "^";
208  tokenToName['|'] = "|";
209  tokenToName['?'] = "?";
210  tokenToName[';'] = ";";
211 
212  tokenNameRemap["TOKEN_ASSERT"] = "\'assert\'";
213  tokenNameRemap["TOKEN_BOOL"] = "\'bool\'";
214  tokenNameRemap["TOKEN_BREAK"] = "\'break\'";
215  tokenNameRemap["TOKEN_CASE"] = "\'case\'";
216  tokenNameRemap["TOKEN_CDO"] = "\'cdo\'";
217  tokenNameRemap["TOKEN_CFOR"] = "\'cfor\'";
218  tokenNameRemap["TOKEN_CIF"] = "\'cif\'";
219  tokenNameRemap["TOKEN_CWHILE"] = "\'cwhile\'";
220  tokenNameRemap["TOKEN_CONST"] = "\'const\'";
221  tokenNameRemap["TOKEN_CONTINUE"] = "\'continue\'";
222  tokenNameRemap["TOKEN_DEFAULT"] = "\'default\'";
223  tokenNameRemap["TOKEN_DO"] = "\'do\'";
224  tokenNameRemap["TOKEN_DELETE"] = "\'delete\'";
225  tokenNameRemap["TOKEN_DOUBLE"] = "\'double\'";
226  tokenNameRemap["TOKEN_ELSE"] = "\'else\'";
227  tokenNameRemap["TOKEN_ENUM"] = "\'enum\'";
228  tokenNameRemap["TOKEN_EXPORT"] = "\'export\'";
229  tokenNameRemap["TOKEN_EXTERN"] = "\'extern\'";
230  tokenNameRemap["TOKEN_FALSE"] = "\'false\'";
231  tokenNameRemap["TOKEN_FLOAT"] = "\'float\'";
232  tokenNameRemap["TOKEN_FOR"] = "\'for\'";
233  tokenNameRemap["TOKEN_FOREACH"] = "\'foreach\'";
234  tokenNameRemap["TOKEN_FOREACH_ACTIVE"] = "\'foreach_active\'";
235  tokenNameRemap["TOKEN_FOREACH_TILED"] = "\'foreach_tiled\'";
236  tokenNameRemap["TOKEN_FOREACH_UNIQUE"] = "\'foreach_unique\'";
237  tokenNameRemap["TOKEN_GOTO"] = "\'goto\'";
238  tokenNameRemap["TOKEN_IDENTIFIER"] = "identifier";
239  tokenNameRemap["TOKEN_IF"] = "\'if\'";
240  tokenNameRemap["TOKEN_IN"] = "\'in\'";
241  tokenNameRemap["TOKEN_INLINE"] = "\'inline\'";
242  tokenNameRemap["TOKEN_INT"] = "\'int\'";
243  tokenNameRemap["TOKEN_INT8"] = "\'int8\'";
244  tokenNameRemap["TOKEN_INT16"] = "\'int16\'";
245  tokenNameRemap["TOKEN_INT"] = "\'int\'";
246  tokenNameRemap["TOKEN_INT64"] = "\'int64\'";
247  tokenNameRemap["TOKEN_LAUNCH"] = "\'launch\'";
248  tokenNameRemap["TOKEN_NEW"] = "\'new\'";
249  tokenNameRemap["TOKEN_NULL"] = "\'NULL\'";
250  tokenNameRemap["TOKEN_PRINT"] = "\'print\'";
251  tokenNameRemap["TOKEN_RETURN"] = "\'return\'";
252  tokenNameRemap["TOKEN_SOA"] = "\'soa\'";
253  tokenNameRemap["TOKEN_SIGNED"] = "\'signed\'";
254  tokenNameRemap["TOKEN_SIZEOF"] = "\'sizeof\'";
255  tokenNameRemap["TOKEN_STATIC"] = "\'static\'";
256  tokenNameRemap["TOKEN_STRUCT"] = "\'struct\'";
257  tokenNameRemap["TOKEN_SWITCH"] = "\'switch\'";
258  tokenNameRemap["TOKEN_SYNC"] = "\'sync\'";
259  tokenNameRemap["TOKEN_TASK"] = "\'task\'";
260  tokenNameRemap["TOKEN_TRUE"] = "\'true\'";
261  tokenNameRemap["TOKEN_TYPEDEF"] = "\'typedef\'";
262  tokenNameRemap["TOKEN_UNIFORM"] = "\'uniform\'";
263  tokenNameRemap["TOKEN_UNMASKED"] = "\'unmasked\'";
264  tokenNameRemap["TOKEN_UNSIGNED"] = "\'unsigned\'";
265  tokenNameRemap["TOKEN_VARYING"] = "\'varying\'";
266  tokenNameRemap["TOKEN_VOID"] = "\'void\'";
267  tokenNameRemap["TOKEN_WHILE"] = "\'while\'";
268  tokenNameRemap["TOKEN_STRING_C_LITERAL"] = "\"C\"";
269  tokenNameRemap["TOKEN_DOTDOTDOT"] = "\'...\'";
270  tokenNameRemap["TOKEN_FLOAT_CONSTANT"] = "float constant";
271  tokenNameRemap["TOKEN_DOUBLE_CONSTANT"] = "double constant";
272  tokenNameRemap["TOKEN_INT8_CONSTANT"] = "int8 constant";
273  tokenNameRemap["TOKEN_UINT8_CONSTANT"] = "unsigned int8 constant";
274  tokenNameRemap["TOKEN_INT16_CONSTANT"] = "int16 constant";
275  tokenNameRemap["TOKEN_UINT16_CONSTANT"] = "unsigned int16 constant";
276  tokenNameRemap["TOKEN_INT32_CONSTANT"] = "int32 constant";
277  tokenNameRemap["TOKEN_UINT32_CONSTANT"] = "unsigned int32 constant";
278  tokenNameRemap["TOKEN_INT64_CONSTANT"] = "int64 constant";
279  tokenNameRemap["TOKEN_UINT64_CONSTANT"] = "unsigned int64 constant";
280  tokenNameRemap["TOKEN_INC_OP"] = "\'++\'";
281  tokenNameRemap["TOKEN_DEC_OP"] = "\'--\'";
282  tokenNameRemap["TOKEN_LEFT_OP"] = "\'<<\'";
283  tokenNameRemap["TOKEN_RIGHT_OP"] = "\'>>\'";
284  tokenNameRemap["TOKEN_LE_OP"] = "\'<=\'";
285  tokenNameRemap["TOKEN_GE_OP"] = "\'>=\'";
286  tokenNameRemap["TOKEN_EQ_OP"] = "\'==\'";
287  tokenNameRemap["TOKEN_NE_OP"] = "\'!=\'";
288  tokenNameRemap["TOKEN_AND_OP"] = "\'&&\'";
289  tokenNameRemap["TOKEN_OR_OP"] = "\'||\'";
290  tokenNameRemap["TOKEN_MUL_ASSIGN"] = "\'*=\'";
291  tokenNameRemap["TOKEN_DIV_ASSIGN"] = "\'/=\'";
292  tokenNameRemap["TOKEN_MOD_ASSIGN"] = "\'%=\'";
293  tokenNameRemap["TOKEN_ADD_ASSIGN"] = "\'+=\'";
294  tokenNameRemap["TOKEN_SUB_ASSIGN"] = "\'-=\'";
295  tokenNameRemap["TOKEN_LEFT_ASSIGN"] = "\'<<=\'";
296  tokenNameRemap["TOKEN_RIGHT_ASSIGN"] = "\'>>=\'";
297  tokenNameRemap["TOKEN_AND_ASSIGN"] = "\'&=\'";
298  tokenNameRemap["TOKEN_XOR_ASSIGN"] = "\'^=\'";
299  tokenNameRemap["TOKEN_OR_ASSIGN"] = "\'|=\'";
300  tokenNameRemap["TOKEN_PTR_OP"] = "\'->\'";
301  tokenNameRemap["$end"] = "end of file";
302 }
303 
304 
305 inline int ispcRand() {
306 #ifdef ISPC_IS_WINDOWS
307  return rand();
308 #else
309  return lrand48();
310 #endif
311 }
312 
313 #define RT \
314  if (g->enableFuzzTest) { \
315  int r = ispcRand() % 40; \
316  if (r == 0) { \
317  Warning(yylloc, "Fuzz test dropping token"); \
318  } \
319  else if (r == 1) { \
320  Assert (tokenToName.size() > 0); \
321  int nt = sizeof(allTokens) / sizeof(allTokens[0]); \
322  int tn = ispcRand() % nt; \
323  yylval.stringVal = new std::string(yytext); /* just in case */\
324  Warning(yylloc, "Fuzz test replaced token with \"%s\"", tokenToName[allTokens[tn]].c_str()); \
325  return allTokens[tn]; \
326  } \
327  else if (r == 2) { \
328  Symbol *sym = m->symbolTable->RandomSymbol(); \
329  if (sym != NULL) { \
330  yylval.stringVal = new std::string(sym->name); \
331  Warning(yylloc, "Fuzz test replaced with identifier \"%s\".", sym->name.c_str()); \
332  return TOKEN_IDENTIFIER; \
333  } \
334  } \
335  /* TOKEN_TYPE_NAME */ \
336  } else /* swallow semicolon */
337 
338 %}
339 
340 %option nounput
341 %option noyywrap
342 %option nounistd
343 
344 WHITESPACE [ \t\r]+
345 INT_NUMBER (([0-9]+)|(0x[0-9a-fA-F]+)|(0b[01]+))[uUlL]*[kMG]?[uUlL]*
346 INT_NUMBER_DOTDOTDOT (([0-9]+)|(0x[0-9a-fA-F]+)|(0b[01]+))[uUlL]*[kMG]?[uUlL]*\.\.\.
347 FLOAT_NUMBER (([0-9]+|(([0-9]+\.[0-9]*[fF]?)|(\.[0-9]+)))([eE][-+]?[0-9]+)?[fF]?)
348 HEX_FLOAT_NUMBER (0x[01](\.[0-9a-fA-F]*)?p[-+]?[0-9]+[fF]?)
349 FORTRAN_DOUBLE_NUMBER (([0-9]+\.[0-9]*[dD])|([0-9]+\.[0-9]*[dD][-+]?[0-9]+)|([0-9]+[dD][-+]?[0-9]+)|(\.[0-9]*[dD][-+]?[0-9]+))
350 
351 
352 
353 IDENT [a-zA-Z_][a-zA-Z_0-9]*
354 ZO_SWIZZLE ([01]+[w-z]+)+|([01]+[rgba]+)+|([01]+[uv]+)+
355 
356 %%
357 "/*" { lCComment(&yylloc); }
358 "//" { lCppComment(&yylloc); }
359 "#pragma ignore warning" { lPragmaIgnoreWarning(&yylloc); }
360 
361 __assert { RT; return TOKEN_ASSERT; }
362 bool { RT; return TOKEN_BOOL; }
363 break { RT; return TOKEN_BREAK; }
364 case { RT; return TOKEN_CASE; }
365 cbreak { RT; Warning(yylloc, "\"cbreak\" is deprecated. Use \"break\"."); return TOKEN_BREAK; }
366 ccontinue { RT; Warning(yylloc, "\"ccontinue\" is deprecated. Use \"continue\"."); return TOKEN_CONTINUE; }
367 cdo { RT; return TOKEN_CDO; }
368 cfor { RT; return TOKEN_CFOR; }
369 cif { RT; return TOKEN_CIF; }
370 cwhile { RT; return TOKEN_CWHILE; }
371 const { RT; return TOKEN_CONST; }
372 continue { RT; return TOKEN_CONTINUE; }
373 creturn { RT; Warning(yylloc, "\"creturn\" is deprecated. Use \"return\"."); return TOKEN_RETURN; }
374 __declspec { RT; return TOKEN_DECLSPEC; }
375 default { RT; return TOKEN_DEFAULT; }
376 do { RT; return TOKEN_DO; }
377 delete { RT; return TOKEN_DELETE; }
378 delete\[\] { RT; return TOKEN_DELETE; }
379 double { RT; return TOKEN_DOUBLE; }
380 else { RT; return TOKEN_ELSE; }
381 enum { RT; return TOKEN_ENUM; }
382 export { RT; return TOKEN_EXPORT; }
383 extern { RT; return TOKEN_EXTERN; }
384 false { RT; return TOKEN_FALSE; }
385 float { RT; return TOKEN_FLOAT; }
386 for { RT; return TOKEN_FOR; }
387 foreach { RT; return TOKEN_FOREACH; }
388 foreach_active { RT; return TOKEN_FOREACH_ACTIVE; }
389 foreach_tiled { RT; return TOKEN_FOREACH_TILED; }
390 foreach_unique { RT; return TOKEN_FOREACH_UNIQUE; }
391 goto { RT; return TOKEN_GOTO; }
392 if { RT; return TOKEN_IF; }
393 in { RT; return TOKEN_IN; }
394 inline { RT; return TOKEN_INLINE; }
395 int { RT; return TOKEN_INT; }
396 int8 { RT; return TOKEN_INT8; }
397 int16 { RT; return TOKEN_INT16; }
398 int32 { RT; return TOKEN_INT; }
399 int64 { RT; return TOKEN_INT64; }
400 launch { RT; return TOKEN_LAUNCH; }
401 new { RT; return TOKEN_NEW; }
402 NULL { RT; return TOKEN_NULL; }
403 print { RT; return TOKEN_PRINT; }
404 return { RT; return TOKEN_RETURN; }
405 soa { RT; return TOKEN_SOA; }
406 signed { RT; return TOKEN_SIGNED; }
407 sizeof { RT; return TOKEN_SIZEOF; }
408 static { RT; return TOKEN_STATIC; }
409 struct { RT; return TOKEN_STRUCT; }
410 switch { RT; return TOKEN_SWITCH; }
411 sync { RT; return TOKEN_SYNC; }
412 task { RT; return TOKEN_TASK; }
413 true { RT; return TOKEN_TRUE; }
414 typedef { RT; return TOKEN_TYPEDEF; }
415 uniform { RT; return TOKEN_UNIFORM; }
416 unmasked { RT; return TOKEN_UNMASKED; }
417 unsigned { RT; return TOKEN_UNSIGNED; }
418 varying { RT; return TOKEN_VARYING; }
419 void { RT; return TOKEN_VOID; }
420 while { RT; return TOKEN_WHILE; }
421 \"C\" { RT; return TOKEN_STRING_C_LITERAL; }
422 \.\.\. { RT; return TOKEN_DOTDOTDOT; }
423 
424 "operator*" { return TOKEN_IDENTIFIER; }
425 "operator+" { return TOKEN_IDENTIFIER; }
426 "operator-" { return TOKEN_IDENTIFIER; }
427 "operator<<" { return TOKEN_IDENTIFIER; }
428 "operator>>" { return TOKEN_IDENTIFIER; }
429 "operator/" { return TOKEN_IDENTIFIER; }
430 "operator%" { return TOKEN_IDENTIFIER; }
431 
432 L?\"(\\.|[^\\"])*\" { lStringConst(&yylval, &yylloc); return TOKEN_STRING_LITERAL; }
433 
434 {IDENT} {
435  RT;
436  /* We have an identifier--is it a type name or an identifier?
437  The symbol table will straighten us out... */
438  yylval.stringVal = new std::string(yytext);
439  if (m->symbolTable->LookupType(yytext) != NULL)
440  return TOKEN_TYPE_NAME;
441  else
442  return TOKEN_IDENTIFIER;
443 }
444 
445 {INT_NUMBER} {
446  RT;
447  return lParseInteger(false);
448 }
449 
450 {INT_NUMBER_DOTDOTDOT} {
451  RT;
452  return lParseInteger(true);
453 }
454 
455 {FORTRAN_DOUBLE_NUMBER} {
456  RT;
457  {
458  int i = 0;
459  while (yytext[i] != 'd' && yytext[i] != 'D') i++;
460  yytext[i] = 'E';
461  }
462  yylval.doubleVal = atof(yytext);
463  return TOKEN_DOUBLE_CONSTANT;
464 }
465 
466 
467 {FLOAT_NUMBER} {
468  RT;
469  yylval.floatVal = (float)atof(yytext);
470  return TOKEN_FLOAT_CONSTANT;
471 }
472 
473 {HEX_FLOAT_NUMBER} {
474  RT;
475  yylval.floatVal = (float)lParseHexFloat(yytext);
476  return TOKEN_FLOAT_CONSTANT;
477 }
478 
479 
480 
481 "++" { RT; return TOKEN_INC_OP; }
482 "--" { RT; return TOKEN_DEC_OP; }
483 "<<" { RT; return TOKEN_LEFT_OP; }
484 ">>" { RT; return TOKEN_RIGHT_OP; }
485 "<=" { RT; return TOKEN_LE_OP; }
486 ">=" { RT; return TOKEN_GE_OP; }
487 "==" { RT; return TOKEN_EQ_OP; }
488 "!=" { RT; return TOKEN_NE_OP; }
489 "&&" { RT; return TOKEN_AND_OP; }
490 "||" { RT; return TOKEN_OR_OP; }
491 "*=" { RT; return TOKEN_MUL_ASSIGN; }
492 "/=" { RT; return TOKEN_DIV_ASSIGN; }
493 "%=" { RT; return TOKEN_MOD_ASSIGN; }
494 "+=" { RT; return TOKEN_ADD_ASSIGN; }
495 "-=" { RT; return TOKEN_SUB_ASSIGN; }
496 "<<=" { RT; return TOKEN_LEFT_ASSIGN; }
497 ">>=" { RT; return TOKEN_RIGHT_ASSIGN; }
498 "&=" { RT; return TOKEN_AND_ASSIGN; }
499 "^=" { RT; return TOKEN_XOR_ASSIGN; }
500 "|=" { RT; return TOKEN_OR_ASSIGN; }
501 "->" { RT; return TOKEN_PTR_OP; }
502 ";" { RT; return ';'; }
503 ("{"|"<%") { RT; return '{'; }
504 ("}"|"%>") { RT; return '}'; }
505 "," { RT; return ','; }
506 ":" { RT; return ':'; }
507 "=" { RT; return '='; }
508 "(" { RT; return '('; }
509 ")" { RT; return ')'; }
510 ("["|"<:") { RT; return '['; }
511 ("]"|":>") { RT; return ']'; }
512 "." { RT; return '.'; }
513 "&" { RT; return '&'; }
514 "!" { RT; return '!'; }
515 "~" { RT; return '~'; }
516 "-" { RT; return '-'; }
517 "+" { RT; return '+'; }
518 "*" { RT; return '*'; }
519 "/" { RT; return '/'; }
520 "%" { RT; return '%'; }
521 "<" { RT; return '<'; }
522 ">" { RT; return '>'; }
523 "^" { RT; return '^'; }
524 "|" { RT; return '|'; }
525 "?" { RT; return '?'; }
526 
527 {WHITESPACE} { }
528 
529 \n {
530  yylloc.last_line++;
531  yylloc.last_column = 1;
532 }
533 
534 #(line)?[ ][0-9]+[ ]\"(\\.|[^\\"])*\"[^\n]* {
535  lHandleCppHash(&yylloc);
536 }
537 
538 . {
539  Error(yylloc, "Illegal character: %c (0x%x)", yytext[0], int(yytext[0]));
540  YY_USER_ACTION
541 }
542 
543 %%
544 
545 /*short { return TOKEN_SHORT; }*/
546 /*long { return TOKEN_LONG; }*/
547 /*signed { return TOKEN_SIGNED; }*/
548 /*volatile { return TOKEN_VOLATILE; }*/
549 /*"long"[ \t\v\f\n]+"long" { return TOKEN_LONGLONG; }*/
550 /*union { return TOKEN_UNION; }*/
551 /*"..." { return TOKEN_ELLIPSIS; }*/
552 
553 /** Return the integer version of a binary constant from a string.
554  */
555 static uint64_t
556 lParseBinary(const char *ptr, SourcePos pos, char **endPtr) {
557  uint64_t val = 0;
558  bool warned = false;
559 
560  while (*ptr == '0' || *ptr == '1') {
561  if ((val & (((int64_t)1)<<63)) && warned == false) {
562  // We're about to shift out a set bit
563  Warning(pos, "Can't represent binary constant with a 64-bit integer type");
564  warned = true;
565  }
566 
567  val = (val << 1) | (*ptr == '0' ? 0 : 1);
568  ++ptr;
569  }
570  *endPtr = (char *)ptr;
571  return val;
572 }
573 
574 
575 static int
576 lParseInteger(bool dotdotdot) {
577  int ls = 0, us = 0;
578 
579  char *endPtr = NULL;
580  if (yytext[0] == '0' && yytext[1] == 'b')
581  yylval.intVal = lParseBinary(yytext+2, yylloc, &endPtr);
582  else {
583 #if defined(ISPC_IS_WINDOWS) && !defined(__MINGW32__)
584  yylval.intVal = _strtoui64(yytext, &endPtr, 0);
585 #else
586  // FIXME: should use strtouq and then issue an error if we can't
587  // fit into 64 bits...
588  yylval.intVal = strtoull(yytext, &endPtr, 0);
589 #endif
590  }
591 
592  bool kilo = false, mega = false, giga = false;
593  for (; *endPtr; endPtr++) {
594  if (*endPtr == 'k')
595  kilo = true;
596  else if (*endPtr == 'M')
597  mega = true;
598  else if (*endPtr == 'G')
599  giga = true;
600  else if (*endPtr == 'l' || *endPtr == 'L')
601  ls++;
602  else if (*endPtr == 'u' || *endPtr == 'U')
603  us++;
604  else
605  Assert(dotdotdot && *endPtr == '.');
606  }
607  if (kilo)
608  yylval.intVal *= 1024;
609  if (mega)
610  yylval.intVal *= 1024*1024;
611  if (giga)
612  yylval.intVal *= 1024*1024*1024;
613 
614  if (dotdotdot) {
615  if (ls >= 2)
616  return us ? TOKEN_UINT64DOTDOTDOT_CONSTANT : TOKEN_INT64DOTDOTDOT_CONSTANT;
617  else if (ls == 1)
618  return us ? TOKEN_UINT32DOTDOTDOT_CONSTANT : TOKEN_INT32DOTDOTDOT_CONSTANT;
619 
620  // See if we can fit this into a 32-bit integer...
621  if ((yylval.intVal & 0xffffffff) == yylval.intVal)
622  return us ? TOKEN_UINT32DOTDOTDOT_CONSTANT : TOKEN_INT32DOTDOTDOT_CONSTANT;
623  else
624  return us ? TOKEN_UINT64DOTDOTDOT_CONSTANT : TOKEN_INT64DOTDOTDOT_CONSTANT;
625  }
626  else {
627  if (ls >= 2)
628  return us ? TOKEN_UINT64_CONSTANT : TOKEN_INT64_CONSTANT;
629  else if (ls == 1)
630  return us ? TOKEN_UINT32_CONSTANT : TOKEN_INT32_CONSTANT;
631  else if (us) {
632  // u suffix only
633  if (yylval.intVal <= 0xffffffffL)
634  return TOKEN_UINT32_CONSTANT;
635  else
636  return TOKEN_UINT64_CONSTANT;
637  }
638  else {
639  // No u or l suffix
640  // If we're compiling to an 8-bit mask target and the constant
641  // fits into 8 bits, return an 8-bit int.
642  if (g->target->getDataTypeWidth() == 8) {
643  if (yylval.intVal <= 0x7fULL)
644  return TOKEN_INT8_CONSTANT;
645  else if (yylval.intVal <= 0xffULL)
646  return TOKEN_UINT8_CONSTANT;
647  }
648  // And similarly for 16-bit masks and constants
649  if (g->target->getDataTypeWidth() == 16) {
650  if (yylval.intVal <= 0x7fffULL)
651  return TOKEN_INT16_CONSTANT;
652  else if (yylval.intVal <= 0xffffULL)
653  return TOKEN_UINT16_CONSTANT;
654  }
655  // Otherwise, see if we can fit this into a 32-bit integer...
656  if (yylval.intVal <= 0x7fffffffULL)
657  return TOKEN_INT32_CONSTANT;
658  else if (yylval.intVal <= 0xffffffffULL)
659  return TOKEN_UINT32_CONSTANT;
660  else if (yylval.intVal <= 0x7fffffffffffffffULL)
661  return TOKEN_INT64_CONSTANT;
662  else
663  return TOKEN_UINT64_CONSTANT;
664  }
665  }
666 }
667 
668 
669 /** Handle a C-style comment in the source.
670  */
671 static void
672 lCComment(SourcePos *pos) {
673  char c, prev = 0;
674 
675  while ((c = yyinput()) != 0) {
676  ++pos->last_column;
677 
678  if (c == '\n') {
679  pos->last_line++;
680  pos->last_column = 1;
681  }
682  if (c == '/' && prev == '*')
683  return;
684  prev = c;
685  }
686  Error(*pos, "unterminated comment");
687 }
688 
689 /** Handle pragma directive to ignore warning.
690  */
691 static void
692 lPragmaIgnoreWarning(SourcePos *pos) {
693  char c;
694  std::string userReq;
695  bool perfWarningOnly = false;
696  do {
697  c = yyinput();
698  ++pos->last_column;
699  } while (c == ' ');
700  if (c == '\n') {
701  pos->last_column = 1;
702  pos->last_line++;
703  std::pair<int, std::string> key = std::pair<int, std::string>(pos->last_line, pos->name);
704  g->turnOffWarnings[key] = perfWarningOnly;
705  return;
706  }
707  else if (c == '(') {
708  do {
709  c = yyinput();
710  ++pos->last_column;
711  } while (c == ' ');
712  while (c != 0 && c != '\n' && c != ' ' && c != ')') {
713  userReq += c;
714  c = yyinput();
715  ++pos->last_column;
716  }
717  if ((c == ' ') || (c == ')')) {
718  while (c == ' ') {
719  c = yyinput();
720  ++pos->last_column;
721  }
722  if (c == ')') {
723  do {
724  c = yyinput();
725  ++pos->last_column;
726  } while (c == ' ');
727  if (c == '\n') {
728  pos->last_column = 1;
729  pos->last_line++;
730  if (userReq.compare("perf") == 0) {
731  perfWarningOnly = true;
732  std::pair<int, std::string> key = std::pair<int, std::string>(pos->last_line, pos->name);
733  g->turnOffWarnings[key] = perfWarningOnly;
734  return;
735  }
736  else if (userReq.compare("all") == 0) {
737  std::pair<int, std::string> key = std::pair<int, std::string>(pos->last_line, pos->name);
738  g->turnOffWarnings[key] = perfWarningOnly;
739  return;
740  }
741  }
742  }
743  }
744  else if (c == '\n') pos->last_line++;;
745  }
746  Error(*pos, "Undefined #pragma");
747 }
748 
749 /** Handle a C++-style comment--eat everything up until the end of the line.
750  */
751 static void
752 lCppComment(SourcePos *pos) {
753  char c;
754  do {
755  c = yyinput();
756  } while (c != 0 && c != '\n');
757  if (c == '\n') {
758  pos->last_line++;
759  pos->last_column = 1;
760  }
761 }
762 
763 /** Handle a line that starts with a # character; this should be something
764  left behind by the preprocessor indicating the source file/line
765  that our current position corresponds to.
766  */
767 static void lHandleCppHash(SourcePos *pos) {
768  char *ptr, *src;
769 
770  // Advance past the opening stuff on the line.
771  Assert(yytext[0] == '#');
772  if (yytext[1] == ' ')
773  // On Linux/OSX, the preprocessor gives us lines like
774  // # 1234 "foo.c"
775  ptr = yytext + 2;
776  else {
777  // On windows, cl.exe's preprocessor gives us lines of the form:
778  // #line 1234 "foo.c"
779  Assert(!strncmp(yytext+1, "line ", 5));
780  ptr = yytext + 6;
781  }
782 
783  // Now we can set the line number based on the integer in the string
784  // that ptr is pointing at.
785  pos->last_line = strtol(ptr, &src, 10) - 1;
786  pos->last_column = 1;
787  // Make sure that the character after the integer is a space and that
788  // then we have open quotes
789  Assert(src != ptr && src[0] == ' ' && src[1] == '"');
790  src += 2;
791 
792  // And the filename is everything up until the closing quotes
793  std::string filename;
794  while (*src != '"') {
795  Assert(*src && *src != '\n');
796  filename.push_back(*src);
797  ++src;
798  }
799  pos->name = strdup(filename.c_str());
800  RegisterDependency(filename);
801 }
802 
803 
804 /** Given a pointer to a position in a string, return the character that it
805  represents, accounting for the escape characters supported in string
806  constants. (i.e. given the literal string "\\", return the character
807  '/'). The return value is the new position in the string and the
808  decoded character is returned in *pChar.
809 */
810 static char *
811 lEscapeChar(char *str, char *pChar, SourcePos *pos)
812 {
813  if (*str != '\\') {
814  *pChar = *str;
815  }
816  else {
817  char *tail;
818  ++str;
819  switch (*str) {
820  case '\'': *pChar = '\''; break;
821  case '\"': *pChar = '\"'; break;
822  case '?': *pChar = '\?'; break;
823  case '\\': *pChar = '\\'; break;
824  case 'a': *pChar = '\a'; break;
825  case 'b': *pChar = '\b'; break;
826  case 'f': *pChar = '\f'; break;
827  case 'n': *pChar = '\n'; break;
828  case 'r': *pChar = '\r'; break;
829  case 't': *pChar = '\t'; break;
830  case 'v': *pChar = '\v'; break;
831  // octal constants \012
832  case '0': case '1': case '2': case '3': case '4':
833  case '5': case '6': case '7':
834  *pChar = (char)strtol(str, &tail, 8);
835  str = tail - 1;
836  break;
837  // hexidecimal constant \xff
838  case 'x':
839  *pChar = (char)strtol(str, &tail, 16);
840  str = tail - 1;
841  break;
842  default:
843  Error(*pos, "Bad character escape sequence: '%s'.", str);
844  break;
845  }
846  }
847  ++str;
848  return str;
849 }
850 
851 
852 /** Parse a string constant in the source file. For each character in the
853  string, handle any escaped characters with lEscapeChar() and keep eating
854  characters until we come to the closing quote.
855 */
856 static void
857 lStringConst(YYSTYPE *yylval, SourcePos *pos)
858 {
859  char *p;
860  std::string str;
861  p = strchr(yytext, '"') + 1;
862  while (*p != '\"') {
863  char cval = '\0';
864  p = lEscapeChar(p, &cval, pos);
865  str.push_back(cval);
866  }
867  yylval->stringVal = new std::string(str);
868 }
869 
870 
871 /** Compute the value 2^n, where the exponent is given as an integer.
872  There are more efficient ways to do this, for example by just slamming
873  the bits into the appropriate bits of the double, but let's just do the
874  obvious thing.
875 */
876 static double
877 ipow2(int exponent) {
878  if (exponent < 0)
879  return 1. / ipow2(-exponent);
880 
881  double ret = 1.;
882  while (exponent > 16) {
883  ret *= 65536.;
884  exponent -= 16;
885  }
886  while (exponent-- > 0)
887  ret *= 2.;
888  return ret;
889 }
890 
891 
892 /** Parse a hexadecimal-formatted floating-point number (C99 hex float
893  constant-style).
894 */
895 static double
896 lParseHexFloat(const char *ptr) {
897  Assert(ptr != NULL);
898 
899  Assert(ptr[0] == '0' && ptr[1] == 'x');
900  ptr += 2;
901 
902  // Start initializing the mantissa
903  Assert(*ptr == '0' || *ptr == '1');
904  double mantissa = (*ptr == '1') ? 1. : 0.;
905  ++ptr;
906 
907  if (*ptr == '.') {
908  // Is there a fraction part? If so, the i'th digit we encounter
909  // gives the 1/(16^i) component of the mantissa.
910  ++ptr;
911 
912  double scale = 1. / 16.;
913  // Keep going until we come to the 'p', which indicates that we've
914  // come to the exponent
915  while (*ptr != 'p') {
916  // Figure out the raw value from 0-15
917  int digit;
918  if (*ptr >= '0' && *ptr <= '9')
919  digit = *ptr - '0';
920  else if (*ptr >= 'a' && *ptr <= 'f')
921  digit = 10 + *ptr - 'a';
922  else {
923  Assert(*ptr >= 'A' && *ptr <= 'F');
924  digit = 10 + *ptr - 'A';
925  }
926 
927  // And add its contribution to the mantissa
928  mantissa += scale * digit;
929  scale /= 16.;
930  ++ptr;
931  }
932  }
933  else
934  // If there's not a '.', then we better be going straight to the
935  // exponent
936  Assert(*ptr == 'p');
937 
938  ++ptr; // skip the 'p'
939 
940  // interestingly enough, the exponent is provided base 10..
941  int exponent = (int)strtol(ptr, (char **)NULL, 10);
942 
943  // Does stdlib exp2() guarantee exact results for integer n where can
944  // be represented exactly as doubles? I would hope so but am not sure,
945  // so let's be sure.
946  return mantissa * ipow2(exponent);
947 }