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