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