1/* 2 Copyright (c) 2010-2021, 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 <stdlib.h> 42#include <stdint.h> 43 44using namespace ispc; 45#include "parse.hh" 46 47static uint64_t lParseBinary(const char *ptr, SourcePos pos, char **endPtr); 48static int lParseInteger(bool dotdotdot); 49static void lCComment(SourcePos *); 50static void lCppComment(SourcePos *); 51static void lNextValidChar(SourcePos *, char const*&); 52static void lPragmaIgnoreWarning(SourcePos *, std::string); 53static void lPragmaUnroll(YYSTYPE *, SourcePos *, std::string, bool); 54static bool lConsumePragma(YYSTYPE *, SourcePos *); 55static void lHandleCppHash(SourcePos *); 56static void lStringConst(YYSTYPE *, SourcePos *); 57static double lParseHexFloat(const char *ptr); 58extern void RegisterDependency(const std::string &fileName); 59 60#define YY_USER_ACTION \ 61 yylloc.first_line = yylloc.last_line; \ 62 yylloc.first_column = yylloc.last_column; \ 63 yylloc.last_column += yyleng; 64 65#ifdef ISPC_HOST_IS_WINDOWS 66inline int isatty(int) { return 0; } 67#else 68#include <unistd.h> 69#endif // ISPC_HOST_IS_WINDOWS 70 71static int allTokens[] = { 72 TOKEN_ASSERT, TOKEN_BOOL, TOKEN_BREAK, TOKEN_CASE, 73 TOKEN_CDO, TOKEN_CFOR, TOKEN_CIF, TOKEN_CWHILE, 74 TOKEN_CONST, TOKEN_CONTINUE, TOKEN_DEFAULT, TOKEN_DO, 75 TOKEN_DELETE, TOKEN_DOUBLE, TOKEN_ELSE, TOKEN_ENUM, 76 TOKEN_EXPORT, TOKEN_EXTERN, TOKEN_FALSE, TOKEN_FLOAT, TOKEN_FOR, 77 TOKEN_FOREACH, TOKEN_FOREACH_ACTIVE, TOKEN_FOREACH_TILED, 78 TOKEN_FOREACH_UNIQUE, TOKEN_GOTO, TOKEN_IF, TOKEN_IN, TOKEN_INLINE, 79 TOKEN_INT, TOKEN_INT8, TOKEN_INT16, TOKEN_INT, TOKEN_INT64, TOKEN_LAUNCH, 80 TOKEN_UINT, TOKEN_UINT8, TOKEN_UINT16, TOKEN_UINT64, 81 TOKEN_NEW, TOKEN_NULL, TOKEN_PRINT, TOKEN_RETURN, TOKEN_SOA, TOKEN_SIGNED, 82 TOKEN_SIZEOF, TOKEN_ALLOCA, TOKEN_STATIC, TOKEN_STRUCT, TOKEN_SWITCH, TOKEN_SYNC, 83 TOKEN_TASK, TOKEN_TRUE, TOKEN_TYPEDEF, TOKEN_UNIFORM, TOKEN_UNMASKED, 84 TOKEN_UNSIGNED, TOKEN_VARYING, TOKEN_VOID, TOKEN_WHILE, 85 TOKEN_STRING_C_LITERAL, TOKEN_DOTDOTDOT, 86 TOKEN_FLOAT_CONSTANT, TOKEN_DOUBLE_CONSTANT, 87 TOKEN_INT8_CONSTANT, TOKEN_UINT8_CONSTANT, 88 TOKEN_INT16_CONSTANT, TOKEN_UINT16_CONSTANT, 89 TOKEN_INT32_CONSTANT, TOKEN_UINT32_CONSTANT, 90 TOKEN_INT64_CONSTANT, TOKEN_UINT64_CONSTANT, 91 TOKEN_INC_OP, TOKEN_DEC_OP, TOKEN_LEFT_OP, TOKEN_RIGHT_OP, TOKEN_LE_OP, 92 TOKEN_GE_OP, TOKEN_EQ_OP, TOKEN_NE_OP, TOKEN_AND_OP, TOKEN_OR_OP, 93 TOKEN_MUL_ASSIGN, TOKEN_DIV_ASSIGN, TOKEN_MOD_ASSIGN, TOKEN_ADD_ASSIGN, 94 TOKEN_SUB_ASSIGN, TOKEN_LEFT_ASSIGN, TOKEN_RIGHT_ASSIGN, TOKEN_AND_ASSIGN, 95 TOKEN_XOR_ASSIGN, TOKEN_OR_ASSIGN, TOKEN_PTR_OP, TOKEN_NOINLINE, TOKEN_VECTORCALL, 96 ';', '{', '}', ',', ':', '=', '(', ')', '[', ']', '.', '&', '!', '~', '-', 97 '+', '*', '/', '%', '<', '>', '^', '|', '?', 98}; 99 100std::map<int, std::string> tokenToName; 101std::map<std::string, std::string> tokenNameRemap; 102 103void ParserInit() { 104 tokenToName[TOKEN_ASSERT] = "assert"; 105 tokenToName[TOKEN_BOOL] = "bool"; 106 tokenToName[TOKEN_BREAK] = "break"; 107 tokenToName[TOKEN_CASE] = "case"; 108 tokenToName[TOKEN_CDO] = "cdo"; 109 tokenToName[TOKEN_CFOR] = "cfor"; 110 tokenToName[TOKEN_CIF] = "cif"; 111 tokenToName[TOKEN_CWHILE] = "cwhile"; 112 tokenToName[TOKEN_CONST] = "const"; 113 tokenToName[TOKEN_CONTINUE] = "continue"; 114 tokenToName[TOKEN_DEFAULT] = "default"; 115 tokenToName[TOKEN_DO] = "do"; 116 tokenToName[TOKEN_DELETE] = "delete"; 117 tokenToName[TOKEN_DOUBLE] = "double"; 118 tokenToName[TOKEN_ELSE] = "else"; 119 tokenToName[TOKEN_ENUM] = "enum"; 120 tokenToName[TOKEN_EXPORT] = "export"; 121 tokenToName[TOKEN_EXTERN] = "extern"; 122 tokenToName[TOKEN_FALSE] = "false"; 123 tokenToName[TOKEN_FLOAT] = "float"; 124 tokenToName[TOKEN_FOR] = "for"; 125 tokenToName[TOKEN_FOREACH] = "foreach"; 126 tokenToName[TOKEN_FOREACH_ACTIVE] = "foreach_active"; 127 tokenToName[TOKEN_FOREACH_TILED] = "foreach_tiled"; 128 tokenToName[TOKEN_FOREACH_UNIQUE] = "foreach_unique"; 129 tokenToName[TOKEN_GOTO] = "goto"; 130 tokenToName[TOKEN_IF] = "if"; 131 tokenToName[TOKEN_IN] = "in"; 132 tokenToName[TOKEN_INLINE] = "inline"; 133 tokenToName[TOKEN_NOINLINE] = "noinline"; 134 tokenToName[TOKEN_VECTORCALL] = "__vectorcall"; 135 tokenToName[TOKEN_INT] = "int"; 136 tokenToName[TOKEN_UINT] = "uint"; 137 tokenToName[TOKEN_INT8] = "int8"; 138 tokenToName[TOKEN_UINT8] = "uint8"; 139 tokenToName[TOKEN_INT16] = "int16"; 140 tokenToName[TOKEN_UINT16] = "uint16"; 141 tokenToName[TOKEN_INT] = "int"; 142 tokenToName[TOKEN_INT64] = "int64"; 143 tokenToName[TOKEN_UINT64] = "uint64"; 144 tokenToName[TOKEN_LAUNCH] = "launch"; 145 tokenToName[TOKEN_NEW] = "new"; 146 tokenToName[TOKEN_NULL] = "NULL"; 147 tokenToName[TOKEN_PRINT] = "print"; 148 tokenToName[TOKEN_RETURN] = "return"; 149 tokenToName[TOKEN_SOA] = "soa"; 150 tokenToName[TOKEN_SIGNED] = "signed"; 151 tokenToName[TOKEN_SIZEOF] = "sizeof"; 152 tokenToName[TOKEN_ALLOCA] = "alloca"; 153 tokenToName[TOKEN_STATIC] = "static"; 154 tokenToName[TOKEN_STRUCT] = "struct"; 155 tokenToName[TOKEN_SWITCH] = "switch"; 156 tokenToName[TOKEN_SYNC] = "sync"; 157 tokenToName[TOKEN_TASK] = "task"; 158 tokenToName[TOKEN_TRUE] = "true"; 159 tokenToName[TOKEN_TYPEDEF] = "typedef"; 160 tokenToName[TOKEN_UNIFORM] = "uniform"; 161 tokenToName[TOKEN_UNMASKED] = "unmasked"; 162 tokenToName[TOKEN_UNSIGNED] = "unsigned"; 163 tokenToName[TOKEN_VARYING] = "varying"; 164 tokenToName[TOKEN_VOID] = "void"; 165 tokenToName[TOKEN_WHILE] = "while"; 166 tokenToName[TOKEN_STRING_C_LITERAL] = "\"C\""; 167 tokenToName[TOKEN_DOTDOTDOT] = "..."; 168 tokenToName[TOKEN_FLOAT_CONSTANT] = "TOKEN_FLOAT_CONSTANT"; 169 tokenToName[TOKEN_DOUBLE_CONSTANT] = "TOKEN_DOUBLE_CONSTANT"; 170 tokenToName[TOKEN_INT8_CONSTANT] = "TOKEN_INT8_CONSTANT"; 171 tokenToName[TOKEN_UINT8_CONSTANT] = "TOKEN_UINT8_CONSTANT"; 172 tokenToName[TOKEN_INT16_CONSTANT] = "TOKEN_INT16_CONSTANT"; 173 tokenToName[TOKEN_UINT16_CONSTANT] = "TOKEN_UINT16_CONSTANT"; 174 tokenToName[TOKEN_INT32_CONSTANT] = "TOKEN_INT32_CONSTANT"; 175 tokenToName[TOKEN_UINT32_CONSTANT] = "TOKEN_UINT32_CONSTANT"; 176 tokenToName[TOKEN_INT64_CONSTANT] = "TOKEN_INT64_CONSTANT"; 177 tokenToName[TOKEN_UINT64_CONSTANT] = "TOKEN_UINT64_CONSTANT"; 178 tokenToName[TOKEN_INC_OP] = "++"; 179 tokenToName[TOKEN_DEC_OP] = "--"; 180 tokenToName[TOKEN_LEFT_OP] = "<<"; 181 tokenToName[TOKEN_RIGHT_OP] = ">>"; 182 tokenToName[TOKEN_LE_OP] = "<="; 183 tokenToName[TOKEN_GE_OP] = ">="; 184 tokenToName[TOKEN_EQ_OP] = "=="; 185 tokenToName[TOKEN_NE_OP] = "!="; 186 tokenToName[TOKEN_AND_OP] = "&&"; 187 tokenToName[TOKEN_OR_OP] = "||"; 188 tokenToName[TOKEN_MUL_ASSIGN] = "*="; 189 tokenToName[TOKEN_DIV_ASSIGN] = "/="; 190 tokenToName[TOKEN_MOD_ASSIGN] = "%="; 191 tokenToName[TOKEN_ADD_ASSIGN] = "+="; 192 tokenToName[TOKEN_SUB_ASSIGN] = "-="; 193 tokenToName[TOKEN_LEFT_ASSIGN] = "<<="; 194 tokenToName[TOKEN_RIGHT_ASSIGN] = ">>="; 195 tokenToName[TOKEN_AND_ASSIGN] = "&="; 196 tokenToName[TOKEN_XOR_ASSIGN] = "^="; 197 tokenToName[TOKEN_OR_ASSIGN] = "|="; 198 tokenToName[TOKEN_PTR_OP] = "->"; 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 tokenToName['~'] = "~"; 213 tokenToName['-'] = "-"; 214 tokenToName['+'] = "+"; 215 tokenToName['*'] = "*"; 216 tokenToName['/'] = "/"; 217 tokenToName['%'] = "%"; 218 tokenToName['<'] = "<"; 219 tokenToName['>'] = ">"; 220 tokenToName['^'] = "^"; 221 tokenToName['|'] = "|"; 222 tokenToName['?'] = "?"; 223 tokenToName[';'] = ";"; 224 225 tokenNameRemap["TOKEN_ASSERT"] = "\'assert\'"; 226 tokenNameRemap["TOKEN_BOOL"] = "\'bool\'"; 227 tokenNameRemap["TOKEN_BREAK"] = "\'break\'"; 228 tokenNameRemap["TOKEN_CASE"] = "\'case\'"; 229 tokenNameRemap["TOKEN_CDO"] = "\'cdo\'"; 230 tokenNameRemap["TOKEN_CFOR"] = "\'cfor\'"; 231 tokenNameRemap["TOKEN_CIF"] = "\'cif\'"; 232 tokenNameRemap["TOKEN_CWHILE"] = "\'cwhile\'"; 233 tokenNameRemap["TOKEN_CONST"] = "\'const\'"; 234 tokenNameRemap["TOKEN_CONTINUE"] = "\'continue\'"; 235 tokenNameRemap["TOKEN_DEFAULT"] = "\'default\'"; 236 tokenNameRemap["TOKEN_DO"] = "\'do\'"; 237 tokenNameRemap["TOKEN_DELETE"] = "\'delete\'"; 238 tokenNameRemap["TOKEN_DOUBLE"] = "\'double\'"; 239 tokenNameRemap["TOKEN_ELSE"] = "\'else\'"; 240 tokenNameRemap["TOKEN_ENUM"] = "\'enum\'"; 241 tokenNameRemap["TOKEN_EXPORT"] = "\'export\'"; 242 tokenNameRemap["TOKEN_EXTERN"] = "\'extern\'"; 243 tokenNameRemap["TOKEN_FALSE"] = "\'false\'"; 244 tokenNameRemap["TOKEN_FLOAT"] = "\'float\'"; 245 tokenNameRemap["TOKEN_FOR"] = "\'for\'"; 246 tokenNameRemap["TOKEN_FOREACH"] = "\'foreach\'"; 247 tokenNameRemap["TOKEN_FOREACH_ACTIVE"] = "\'foreach_active\'"; 248 tokenNameRemap["TOKEN_FOREACH_TILED"] = "\'foreach_tiled\'"; 249 tokenNameRemap["TOKEN_FOREACH_UNIQUE"] = "\'foreach_unique\'"; 250 tokenNameRemap["TOKEN_GOTO"] = "\'goto\'"; 251 tokenNameRemap["TOKEN_IDENTIFIER"] = "identifier"; 252 tokenNameRemap["TOKEN_IF"] = "\'if\'"; 253 tokenNameRemap["TOKEN_IN"] = "\'in\'"; 254 tokenNameRemap["TOKEN_INLINE"] = "\'inline\'"; 255 tokenNameRemap["TOKEN_NOINLINE"] = "\'noinline\'"; 256 tokenNameRemap["TOKEN_VECTORCALL"] = "\'__vectorcall\'"; 257 tokenNameRemap["TOKEN_INT"] = "\'int\'"; 258 tokenNameRemap["TOKEN_UINT"] = "\'uint\'"; 259 tokenNameRemap["TOKEN_INT8"] = "\'int8\'"; 260 tokenNameRemap["TOKEN_UINT8"] = "\'uint8\'"; 261 tokenNameRemap["TOKEN_INT16"] = "\'int16\'"; 262 tokenNameRemap["TOKEN_UINT16"] = "\'uint16\'"; 263 tokenNameRemap["TOKEN_INT"] = "\'int\'"; 264 tokenNameRemap["TOKEN_INT64"] = "\'int64\'"; 265 tokenNameRemap["TOKEN_UINT64"] = "\'uint64\'"; 266 tokenNameRemap["TOKEN_LAUNCH"] = "\'launch\'"; 267 tokenNameRemap["TOKEN_NEW"] = "\'new\'"; 268 tokenNameRemap["TOKEN_NULL"] = "\'NULL\'"; 269 tokenNameRemap["TOKEN_PRINT"] = "\'print\'"; 270 tokenNameRemap["TOKEN_RETURN"] = "\'return\'"; 271 tokenNameRemap["TOKEN_SOA"] = "\'soa\'"; 272 tokenNameRemap["TOKEN_SIGNED"] = "\'signed\'"; 273 tokenNameRemap["TOKEN_SIZEOF"] = "\'sizeof\'"; 274 tokenNameRemap["TOKEN_ALLOCA"] = "\'TOKEN_ALLOCA\'"; 275 tokenNameRemap["TOKEN_STATIC"] = "\'static\'"; 276 tokenNameRemap["TOKEN_STRUCT"] = "\'struct\'"; 277 tokenNameRemap["TOKEN_SWITCH"] = "\'switch\'"; 278 tokenNameRemap["TOKEN_SYNC"] = "\'sync\'"; 279 tokenNameRemap["TOKEN_TASK"] = "\'task\'"; 280 tokenNameRemap["TOKEN_TRUE"] = "\'true\'"; 281 tokenNameRemap["TOKEN_TYPEDEF"] = "\'typedef\'"; 282 tokenNameRemap["TOKEN_UNIFORM"] = "\'uniform\'"; 283 tokenNameRemap["TOKEN_UNMASKED"] = "\'unmasked\'"; 284 tokenNameRemap["TOKEN_UNSIGNED"] = "\'unsigned\'"; 285 tokenNameRemap["TOKEN_VARYING"] = "\'varying\'"; 286 tokenNameRemap["TOKEN_VOID"] = "\'void\'"; 287 tokenNameRemap["TOKEN_WHILE"] = "\'while\'"; 288 tokenNameRemap["TOKEN_STRING_C_LITERAL"] = "\"C\""; 289 tokenNameRemap["TOKEN_DOTDOTDOT"] = "\'...\'"; 290 tokenNameRemap["TOKEN_FLOAT_CONSTANT"] = "float constant"; 291 tokenNameRemap["TOKEN_DOUBLE_CONSTANT"] = "double constant"; 292 tokenNameRemap["TOKEN_INT8_CONSTANT"] = "int8 constant"; 293 tokenNameRemap["TOKEN_UINT8_CONSTANT"] = "unsigned int8 constant"; 294 tokenNameRemap["TOKEN_INT16_CONSTANT"] = "int16 constant"; 295 tokenNameRemap["TOKEN_UINT16_CONSTANT"] = "unsigned int16 constant"; 296 tokenNameRemap["TOKEN_INT32_CONSTANT"] = "int32 constant"; 297 tokenNameRemap["TOKEN_UINT32_CONSTANT"] = "unsigned int32 constant"; 298 tokenNameRemap["TOKEN_INT64_CONSTANT"] = "int64 constant"; 299 tokenNameRemap["TOKEN_UINT64_CONSTANT"] = "unsigned int64 constant"; 300 tokenNameRemap["TOKEN_INC_OP"] = "\'++\'"; 301 tokenNameRemap["TOKEN_DEC_OP"] = "\'--\'"; 302 tokenNameRemap["TOKEN_LEFT_OP"] = "\'<<\'"; 303 tokenNameRemap["TOKEN_RIGHT_OP"] = "\'>>\'"; 304 tokenNameRemap["TOKEN_LE_OP"] = "\'<=\'"; 305 tokenNameRemap["TOKEN_GE_OP"] = "\'>=\'"; 306 tokenNameRemap["TOKEN_EQ_OP"] = "\'==\'"; 307 tokenNameRemap["TOKEN_NE_OP"] = "\'!=\'"; 308 tokenNameRemap["TOKEN_AND_OP"] = "\'&&\'"; 309 tokenNameRemap["TOKEN_OR_OP"] = "\'||\'"; 310 tokenNameRemap["TOKEN_MUL_ASSIGN"] = "\'*=\'"; 311 tokenNameRemap["TOKEN_DIV_ASSIGN"] = "\'/=\'"; 312 tokenNameRemap["TOKEN_MOD_ASSIGN"] = "\'%=\'"; 313 tokenNameRemap["TOKEN_ADD_ASSIGN"] = "\'+=\'"; 314 tokenNameRemap["TOKEN_SUB_ASSIGN"] = "\'-=\'"; 315 tokenNameRemap["TOKEN_LEFT_ASSIGN"] = "\'<<=\'"; 316 tokenNameRemap["TOKEN_RIGHT_ASSIGN"] = "\'>>=\'"; 317 tokenNameRemap["TOKEN_AND_ASSIGN"] = "\'&=\'"; 318 tokenNameRemap["TOKEN_XOR_ASSIGN"] = "\'^=\'"; 319 tokenNameRemap["TOKEN_OR_ASSIGN"] = "\'|=\'"; 320 tokenNameRemap["TOKEN_PTR_OP"] = "\'->\'"; 321 tokenNameRemap["$end"] = "end of file"; 322} 323 324 325inline int ispcRand() { 326#ifdef ISPC_HOST_IS_WINDOWS 327 return rand(); 328#else 329 return lrand48(); 330#endif 331} 332 333#define RT \ 334 if (g->enableFuzzTest) { \ 335 int r = ispcRand() % 40; \ 336 if (r == 0) { \ 337 Warning(yylloc, "Fuzz test dropping token"); \ 338 } \ 339 else if (r == 1) { \ 340 Assert (tokenToName.size() > 0); \ 341 int nt = sizeof(allTokens) / sizeof(allTokens[0]); \ 342 int tn = ispcRand() % nt; \ 343 yylval.stringVal = new std::string(yytext); /* just in case */\ 344 Warning(yylloc, "Fuzz test replaced token with \"%s\"", tokenToName[allTokens[tn]].c_str()); \ 345 return allTokens[tn]; \ 346 } \ 347 else if (r == 2) { \ 348 Symbol *sym = m->symbolTable->RandomSymbol(); \ 349 if (sym != NULL) { \ 350 yylval.stringVal = new std::string(sym->name); \ 351 Warning(yylloc, "Fuzz test replaced with identifier \"%s\".", sym->name.c_str()); \ 352 return TOKEN_IDENTIFIER; \ 353 } \ 354 } \ 355 /* TOKEN_TYPE_NAME */ \ 356 } else /* swallow semicolon */ 357 358%} 359 360%option nounput 361%option noyywrap 362%option nounistd 363 364WHITESPACE [ \t\r]+ 365INT_NUMBER (([0-9]+)|(0x[0-9a-fA-F]+)|(0b[01]+))[uUlL]*[kMG]?[uUlL]* 366INT_NUMBER_DOTDOTDOT (([0-9]+)|(0x[0-9a-fA-F]+)|(0b[01]+))[uUlL]*[kMG]?[uUlL]*\.\.\. 367FLOAT_NUMBER (([0-9]+|(([0-9]+\.[0-9]*[fF]?)|(\.[0-9]+)))([eE][-+]?[0-9]+)?[fF]?) 368HEX_FLOAT_NUMBER (0x[01](\.[0-9a-fA-F]*)?p[-+]?[0-9]+[fF]?) 369FORTRAN_DOUBLE_NUMBER (([0-9]+\.[0-9]*[dD])|([0-9]+\.[0-9]*[dD][-+]?[0-9]+)|([0-9]+[dD][-+]?[0-9]+)|(\.[0-9]*[dD][-+]?[0-9]+)) 370 371 372 373IDENT [a-zA-Z_][a-zA-Z_0-9]* 374INTRINSIC_CALL [@][l][l][v][m][.][.a-zA-Z_0-9]* 375ZO_SWIZZLE ([01]+[w-z]+)+|([01]+[rgba]+)+|([01]+[uv]+)+ 376 377%% 378"/*" { lCComment(&yylloc); } 379"//" { lCppComment(&yylloc); } 380"#pragma" { 381 if (lConsumePragma(&yylval, &yylloc)) { 382 return TOKEN_PRAGMA; 383 } 384} 385 386 387__assert { RT; return TOKEN_ASSERT; } 388bool { RT; return TOKEN_BOOL; } 389break { RT; return TOKEN_BREAK; } 390case { RT; return TOKEN_CASE; } 391cbreak { RT; Warning(yylloc, "\"cbreak\" is deprecated. Use \"break\"."); return TOKEN_BREAK; } 392ccontinue { RT; Warning(yylloc, "\"ccontinue\" is deprecated. Use \"continue\"."); return TOKEN_CONTINUE; } 393cdo { RT; return TOKEN_CDO; } 394cfor { RT; return TOKEN_CFOR; } 395cif { RT; return TOKEN_CIF; } 396cwhile { RT; return TOKEN_CWHILE; } 397const { RT; return TOKEN_CONST; } 398continue { RT; return TOKEN_CONTINUE; } 399creturn { RT; Warning(yylloc, "\"creturn\" is deprecated. Use \"return\"."); return TOKEN_RETURN; } 400__declspec { RT; return TOKEN_DECLSPEC; } 401default { RT; return TOKEN_DEFAULT; } 402do { RT; return TOKEN_DO; } 403delete { RT; return TOKEN_DELETE; } 404delete\[\] { RT; return TOKEN_DELETE; } 405double { RT; return TOKEN_DOUBLE; } 406else { RT; return TOKEN_ELSE; } 407enum { RT; return TOKEN_ENUM; } 408export { RT; return TOKEN_EXPORT; } 409extern { RT; return TOKEN_EXTERN; } 410false { RT; return TOKEN_FALSE; } 411float { RT; return TOKEN_FLOAT; } 412for { RT; return TOKEN_FOR; } 413foreach { RT; return TOKEN_FOREACH; } 414foreach_active { RT; return TOKEN_FOREACH_ACTIVE; } 415foreach_tiled { RT; return TOKEN_FOREACH_TILED; } 416foreach_unique { RT; return TOKEN_FOREACH_UNIQUE; } 417goto { RT; return TOKEN_GOTO; } 418if { RT; return TOKEN_IF; } 419in { RT; return TOKEN_IN; } 420inline { RT; return TOKEN_INLINE; } 421noinline { RT; return TOKEN_NOINLINE; } 422__vectorcall { RT; return TOKEN_VECTORCALL; } 423int { RT; return TOKEN_INT; } 424uint { RT; return TOKEN_UINT; } 425int8 { RT; return TOKEN_INT8; } 426uint8 { RT; return TOKEN_UINT8; } 427int16 { RT; return TOKEN_INT16; } 428uint16 { RT; return TOKEN_UINT16; } 429int32 { RT; return TOKEN_INT; } 430uint32 { RT; return TOKEN_UINT; } 431int64 { RT; return TOKEN_INT64; } 432uint64 { RT; return TOKEN_UINT64; } 433launch { RT; return TOKEN_LAUNCH; } 434new { RT; return TOKEN_NEW; } 435NULL { RT; return TOKEN_NULL; } 436print { RT; return TOKEN_PRINT; } 437return { RT; return TOKEN_RETURN; } 438soa { RT; return TOKEN_SOA; } 439signed { RT; return TOKEN_SIGNED; } 440sizeof { RT; return TOKEN_SIZEOF; } 441alloca { RT; return TOKEN_ALLOCA; } 442static { RT; return TOKEN_STATIC; } 443struct { RT; return TOKEN_STRUCT; } 444switch { RT; return TOKEN_SWITCH; } 445sync { RT; return TOKEN_SYNC; } 446task { RT; return TOKEN_TASK; } 447true { RT; return TOKEN_TRUE; } 448typedef { RT; return TOKEN_TYPEDEF; } 449uniform { RT; return TOKEN_UNIFORM; } 450unmasked { RT; return TOKEN_UNMASKED; } 451unsigned { RT; return TOKEN_UNSIGNED; } 452varying { RT; return TOKEN_VARYING; } 453void { RT; return TOKEN_VOID; } 454while { RT; return TOKEN_WHILE; } 455\"C\" { RT; return TOKEN_STRING_C_LITERAL; } 456\.\.\. { RT; return TOKEN_DOTDOTDOT; } 457 458"operator*" { return TOKEN_IDENTIFIER; } 459"operator+" { return TOKEN_IDENTIFIER; } 460"operator-" { return TOKEN_IDENTIFIER; } 461"operator<<" { return TOKEN_IDENTIFIER; } 462"operator>>" { return TOKEN_IDENTIFIER; } 463"operator/" { return TOKEN_IDENTIFIER; } 464"operator%" { return TOKEN_IDENTIFIER; } 465 466L?\"(\\.|[^\\"])*\" { lStringConst(&yylval, &yylloc); return TOKEN_STRING_LITERAL; } 467 468{IDENT} { 469 RT; 470 /* We have an identifier--is it a type name or an identifier? 471 The symbol table will straighten us out... */ 472 yylval.stringVal = new std::string(yytext); 473 if (m->symbolTable->LookupType(yytext) != NULL) 474 return TOKEN_TYPE_NAME; 475 else 476 return TOKEN_IDENTIFIER; 477} 478 479{INTRINSIC_CALL} { 480 RT; 481 /* We have a potential llvm intrinsic call.*/ 482 yylval.stringVal = new std::string(yytext); 483 return TOKEN_INTRINSIC_CALL; 484} 485 486{INT_NUMBER} { 487 RT; 488 return lParseInteger(false); 489} 490 491{INT_NUMBER_DOTDOTDOT} { 492 RT; 493 return lParseInteger(true); 494} 495 496{FORTRAN_DOUBLE_NUMBER} { 497 RT; 498 { 499 int i = 0; 500 while (yytext[i] != 'd' && yytext[i] != 'D') i++; 501 yytext[i] = 'E'; 502 } 503 yylval.doubleVal = atof(yytext); 504 return TOKEN_DOUBLE_CONSTANT; 505} 506 507 508{FLOAT_NUMBER} { 509 RT; 510 yylval.floatVal = (float)atof(yytext); 511 return TOKEN_FLOAT_CONSTANT; 512} 513 514{HEX_FLOAT_NUMBER} { 515 RT; 516 yylval.floatVal = (float)lParseHexFloat(yytext); 517 return TOKEN_FLOAT_CONSTANT; 518} 519 520 521 522"++" { RT; return TOKEN_INC_OP; } 523"--" { RT; return TOKEN_DEC_OP; } 524"<<" { RT; return TOKEN_LEFT_OP; } 525">>" { RT; return TOKEN_RIGHT_OP; } 526"<=" { RT; return TOKEN_LE_OP; } 527">=" { RT; return TOKEN_GE_OP; } 528"==" { RT; return TOKEN_EQ_OP; } 529"!=" { RT; return TOKEN_NE_OP; } 530"&&" { RT; return TOKEN_AND_OP; } 531"||" { RT; return TOKEN_OR_OP; } 532"*=" { RT; return TOKEN_MUL_ASSIGN; } 533"/=" { RT; return TOKEN_DIV_ASSIGN; } 534"%=" { RT; return TOKEN_MOD_ASSIGN; } 535"+=" { RT; return TOKEN_ADD_ASSIGN; } 536"-=" { RT; return TOKEN_SUB_ASSIGN; } 537"<<=" { RT; return TOKEN_LEFT_ASSIGN; } 538">>=" { RT; return TOKEN_RIGHT_ASSIGN; } 539"&=" { RT; return TOKEN_AND_ASSIGN; } 540"^=" { RT; return TOKEN_XOR_ASSIGN; } 541"|=" { RT; return TOKEN_OR_ASSIGN; } 542"->" { RT; return TOKEN_PTR_OP; } 543";" { RT; return ';'; } 544("{"|"<%") { RT; return '{'; } 545("}"|"%>") { RT; return '}'; } 546"," { RT; return ','; } 547":" { RT; return ':'; } 548"=" { RT; return '='; } 549"(" { RT; return '('; } 550")" { RT; return ')'; } 551("["|"<:") { RT; return '['; } 552("]"|":>") { RT; return ']'; } 553"." { RT; return '.'; } 554"&" { RT; return '&'; } 555"!" { RT; return '!'; } 556"~" { RT; return '~'; } 557"-" { RT; return '-'; } 558"+" { RT; return '+'; } 559"*" { RT; return '*'; } 560"/" { RT; return '/'; } 561"%" { RT; return '%'; } 562"<" { RT; return '<'; } 563">" { RT; return '>'; } 564"^" { RT; return '^'; } 565"|" { RT; return '|'; } 566"?" { RT; return '?'; } 567 568{WHITESPACE} { } 569 570\n { 571 yylloc.last_line++; 572 yylloc.last_column = 1; 573} 574 575#(line)?[ ][0-9]+[ ]\"(\\.|[^\\"])*\"[^\n]* { 576 lHandleCppHash(&yylloc); 577} 578 579. { 580 Error(yylloc, "Illegal character: %c (0x%x)", yytext[0], int(yytext[0])); 581 YY_USER_ACTION 582} 583 584%% 585 586/*short { return TOKEN_SHORT; }*/ 587/*long { return TOKEN_LONG; }*/ 588/*signed { return TOKEN_SIGNED; }*/ 589/*volatile { return TOKEN_VOLATILE; }*/ 590/*"long"[ \t\v\f\n]+"long" { return TOKEN_LONGLONG; }*/ 591/*union { return TOKEN_UNION; }*/ 592/*"..." { return TOKEN_ELLIPSIS; }*/ 593 594/** Return the integer version of a binary constant from a string. 595 */ 596static uint64_t 597lParseBinary(const char *ptr, SourcePos pos, char **endPtr) { 598 uint64_t val = 0; 599 bool warned = false; 600 601 while (*ptr == '0' || *ptr == '1') { 602 if ((val & (((int64_t)1)<<63)) && warned == false) { 603 // We're about to shift out a set bit 604 Warning(pos, "Can't represent binary constant with a 64-bit integer type"); 605 warned = true; 606 } 607 608 val = (val << 1) | (*ptr == '0' ? 0 : 1); 609 ++ptr; 610 } 611 *endPtr = (char *)ptr; 612 return val; 613} 614 615 616static int 617lParseInteger(bool dotdotdot) { 618 int ls = 0, us = 0; 619 620 char *endPtr = NULL; 621 if (yytext[0] == '0' && yytext[1] == 'b') 622 yylval.intVal = lParseBinary(yytext+2, yylloc, &endPtr); 623 else { 624#if defined(ISPC_HOST_IS_WINDOWS) && !defined(__MINGW32__) 625 yylval.intVal = _strtoui64(yytext, &endPtr, 0); 626#else 627 // FIXME: should use strtouq and then issue an error if we can't 628 // fit into 64 bits... 629 yylval.intVal = strtoull(yytext, &endPtr, 0); 630#endif 631 } 632 633 bool kilo = false, mega = false, giga = false; 634 for (; *endPtr; endPtr++) { 635 if (*endPtr == 'k') 636 kilo = true; 637 else if (*endPtr == 'M') 638 mega = true; 639 else if (*endPtr == 'G') 640 giga = true; 641 else if (*endPtr == 'l' || *endPtr == 'L') 642 ls++; 643 else if (*endPtr == 'u' || *endPtr == 'U') 644 us++; 645 else 646 Assert(dotdotdot && *endPtr == '.'); 647 } 648 if (kilo) 649 yylval.intVal *= 1024; 650 if (mega) 651 yylval.intVal *= 1024*1024; 652 if (giga) 653 yylval.intVal *= 1024*1024*1024; 654 655 if (dotdotdot) { 656 if (ls >= 2) 657 return us ? TOKEN_UINT64DOTDOTDOT_CONSTANT : TOKEN_INT64DOTDOTDOT_CONSTANT; 658 else if (ls == 1) 659 return us ? TOKEN_UINT32DOTDOTDOT_CONSTANT : TOKEN_INT32DOTDOTDOT_CONSTANT; 660 661 // See if we can fit this into a 32-bit integer... 662 if ((yylval.intVal & 0xffffffff) == yylval.intVal) 663 return us ? TOKEN_UINT32DOTDOTDOT_CONSTANT : TOKEN_INT32DOTDOTDOT_CONSTANT; 664 else 665 return us ? TOKEN_UINT64DOTDOTDOT_CONSTANT : TOKEN_INT64DOTDOTDOT_CONSTANT; 666 } 667 else { 668 if (ls >= 2) 669 return us ? TOKEN_UINT64_CONSTANT : TOKEN_INT64_CONSTANT; 670 else if (ls == 1) 671 return us ? TOKEN_UINT32_CONSTANT : TOKEN_INT32_CONSTANT; 672 else if (us) { 673 // u suffix only 674 if (yylval.intVal <= 0xffffffffL) 675 return TOKEN_UINT32_CONSTANT; 676 else 677 return TOKEN_UINT64_CONSTANT; 678 } 679 else { 680 // No u or l suffix 681 // If we're compiling to an 8-bit mask target and the constant 682 // fits into 8 bits, return an 8-bit int. 683 if (g->target->getDataTypeWidth() == 8) { 684 if (yylval.intVal <= 0x7fULL) 685 return TOKEN_INT8_CONSTANT; 686 else if (yylval.intVal <= 0xffULL) 687 return TOKEN_UINT8_CONSTANT; 688 } 689 // And similarly for 16-bit masks and constants 690 if (g->target->getDataTypeWidth() == 16) { 691 if (yylval.intVal <= 0x7fffULL) 692 return TOKEN_INT16_CONSTANT; 693 else if (yylval.intVal <= 0xffffULL) 694 return TOKEN_UINT16_CONSTANT; 695 } 696 // Otherwise, see if we can fit this into a 32-bit integer... 697 if (yylval.intVal <= 0x7fffffffULL) 698 return TOKEN_INT32_CONSTANT; 699 else if (yylval.intVal <= 0xffffffffULL) 700 return TOKEN_UINT32_CONSTANT; 701 else if (yylval.intVal <= 0x7fffffffffffffffULL) 702 return TOKEN_INT64_CONSTANT; 703 else 704 return TOKEN_UINT64_CONSTANT; 705 } 706 } 707} 708 709 710/** Handle a C-style comment in the source. 711 */ 712static void 713lCComment(SourcePos *pos) { 714 char c, prev = 0; 715 716 while ((c = yyinput()) != 0) { 717 ++pos->last_column; 718 719 if (c == '\n') { 720 pos->last_line++; 721 pos->last_column = 1; 722 } 723 if (c == '/' && prev == '*') 724 return; 725 prev = c; 726 } 727 Error(*pos, "unterminated comment"); 728} 729 730static void lNextValidChar(SourcePos *pos, char const*&currChar) { 731 while ((*currChar == ' ') || (*currChar == '\t') || (*currChar == '\r')) { 732 ++pos->last_column; 733 currChar++; 734 } 735} 736 737/** Handle pragma directive to unroll loops. 738*/ 739static void lPragmaUnroll(YYSTYPE *yylval, SourcePos *pos, std::string fromUserReq, bool isNounroll) { 740 741 const char *currChar = fromUserReq.data(); 742 yylval->pragmaAttributes = new PragmaAttributes(); 743 yylval->pragmaAttributes->aType = PragmaAttributes::AttributeType::pragmaloop; 744 int count = -1; 745 746 lNextValidChar(pos, currChar); 747 748 if (isNounroll) { 749 if (*currChar == '\n') { 750 yylval->pragmaAttributes->unrollType = Globals::pragmaUnrollType::nounroll; 751 pos->last_column = 1; 752 pos->last_line++; 753 return; 754 } 755 pos->last_column = 1; 756 pos->last_line++; 757 Warning(*pos, "extra tokens at end of '#pragma nounroll'."); 758 return; 759 760 } 761 762 if (*currChar == '\n') { 763 yylval->pragmaAttributes->unrollType = Globals::pragmaUnrollType::unroll; 764 pos->last_column = 1; 765 pos->last_line++; 766 return; 767 } 768 769 bool popPar = false; 770 if (*currChar == '(') { 771 popPar = true; 772 currChar++; 773 ++pos->last_column; 774 } 775 776 char *endPtr = NULL; 777#if defined(ISPC_HOST_IS_WINDOWS) && !defined(__MINGW32__) 778 count = _strtoui64(currChar, &endPtr, 0); 779#else 780 // FIXME: should use strtouq and then issue an error if we can't 781 // fit into 64 bits... 782 count = strtoull(currChar, &endPtr, 0); 783#endif 784 785 if((count == 0) && (endPtr != currChar)){ 786 Error(*pos, "'#pragma unroll()' invalid value '0'; must be positive."); 787 } 788 789 lNextValidChar(pos, const_cast<const char*&>(endPtr)); 790 791 if (popPar == true) { 792 if (*endPtr == ')') { 793 ++pos->last_column; 794 endPtr++; 795 lNextValidChar(pos, const_cast<const char*&>(endPtr)); 796 } 797 else { 798 Error(*pos, "Incomplete '#pragma unroll()' : expected ')'."); 799 } 800 } 801 802 yylval->pragmaAttributes->unrollType = Globals::pragmaUnrollType::count; 803 yylval->pragmaAttributes->count = count; 804 pos->last_line++; 805 pos->last_column = 1; 806} 807 808/** Handle pragma directive to ignore warning. 809*/ 810static void 811lPragmaIgnoreWarning(SourcePos *pos, std::string fromUserReq) { 812 std::string userReq; 813 const char *currChar = fromUserReq.data(); 814 bool perfWarningOnly = false; 815 lNextValidChar(pos, currChar); 816 817 if (*currChar == '\n') { 818 pos->last_column = 1; 819 pos->last_line++; 820 std::pair<int, std::string> key = std::pair<int, std::string>(pos->last_line, pos->name); 821 g->turnOffWarnings[key] = perfWarningOnly; 822 return; 823 } 824 else if (*currChar == '(') { 825 currChar++; 826 lNextValidChar(pos, currChar); 827 while (*currChar != 0 && *currChar != '\n' && *currChar != ' ' && *currChar != ')') { 828 userReq += *currChar; 829 currChar++; 830 ++pos->last_column; 831 } 832 if ((*currChar == ' ') || (*currChar == ')')) { 833 lNextValidChar(pos, currChar); 834 if (*currChar == ')') { 835 currChar++; 836 ++pos->last_column; 837 lNextValidChar(pos, currChar); 838 if (*currChar == '\n') { 839 pos->last_column = 1; 840 pos->last_line++; 841 if (userReq.compare("perf") == 0) { 842 perfWarningOnly = true; 843 std::pair<int, std::string> key = std::pair<int, std::string>(pos->last_line, pos->name); 844 g->turnOffWarnings[key] = perfWarningOnly; 845 } 846 else if (userReq.compare("all") == 0) { 847 std::pair<int, std::string> key = std::pair<int, std::string>(pos->last_line, pos->name); 848 g->turnOffWarnings[key] = perfWarningOnly; 849 } 850 else { 851 Error(*pos, "Incorrect argument for '#pragma ignore warning()'."); 852 } 853 return; 854 } 855 } 856 } 857 else if (*currChar == '\n') { 858 Error(*pos, "Incomplete '#pragma ignore warning()' : expected ')'."); 859 pos->last_column = 1; 860 pos->last_line++; 861 return; 862 } 863 } 864 Error(*pos, "Undefined #pragma."); 865} 866 867/** Consume line starting with '#pragma' and decide on next action based on 868 * directive. 869 */ 870static bool lConsumePragma(YYSTYPE *yylval, SourcePos *pos) { 871 char c; 872 std::string userReq; 873 do { 874 c = yyinput(); 875 ++pos->last_column; 876 } while ((c == ' ') || (c == '\t') || (c == '\r')); 877 if (c == '\n') { 878 // Ignore pragma since - directive provided. 879 pos->last_column = 1; 880 pos->last_line++; 881 return false; 882 } 883 884 while (c != '\n') { 885 userReq += c; 886 c = yyinput(); 887 } 888 userReq += c; 889 std::string loopUnroll("unroll"), loopNounroll("nounroll"), ignoreWarning("ignore warning"); 890 if (loopUnroll == userReq.substr(0, loopUnroll.size())) { 891 pos->last_column += loopUnroll.size(); 892 lPragmaUnroll(yylval, pos, userReq.erase(0, loopUnroll.size()), false); 893 return true; 894 } 895 else if (loopNounroll == userReq.substr(0, loopNounroll.size())) { 896 pos->last_column += loopNounroll.size(); 897 lPragmaUnroll(yylval, pos, userReq.erase(0, loopNounroll.size()), true); 898 return true; 899 } 900 else if (ignoreWarning == userReq.substr(0, ignoreWarning.size())) { 901 pos->last_column += ignoreWarning.size(); 902 lPragmaIgnoreWarning(pos, userReq.erase(0, ignoreWarning.size())); 903 return false; 904 } 905 906 // Ignore pragma : invalid directive provided. 907 Warning(*pos, "unknown pragma ignored."); 908 return false; 909} 910 911/** Handle a C++-style comment--eat everything up until the end of the line. 912 */ 913static void 914lCppComment(SourcePos *pos) { 915 char c; 916 do { 917 c = yyinput(); 918 } while (c != 0 && c != '\n'); 919 if (c == '\n') { 920 pos->last_line++; 921 pos->last_column = 1; 922 } 923} 924 925/** Handle a line that starts with a # character; this should be something 926 left behind by the preprocessor indicating the source file/line 927 that our current position corresponds to. 928 */ 929static void lHandleCppHash(SourcePos *pos) { 930 char *ptr, *src; 931 932 // Advance past the opening stuff on the line. 933 Assert(yytext[0] == '#'); 934 if (yytext[1] == ' ') 935 // On Linux/OSX, the preprocessor gives us lines like 936 // # 1234 "foo.c" 937 ptr = yytext + 2; 938 else { 939 // On windows, cl.exe's preprocessor gives us lines of the form: 940 // #line 1234 "foo.c" 941 Assert(!strncmp(yytext+1, "line ", 5)); 942 ptr = yytext + 6; 943 } 944 945 // Now we can set the line number based on the integer in the string 946 // that ptr is pointing at. 947 pos->last_line = strtol(ptr, &src, 10) - 1; 948 pos->last_column = 1; 949 // Make sure that the character after the integer is a space and that 950 // then we have open quotes 951 Assert(src != ptr && src[0] == ' ' && src[1] == '"'); 952 src += 2; 953 954 // And the filename is everything up until the closing quotes 955 std::string filename; 956 while (*src != '"') { 957 Assert(*src && *src != '\n'); 958 filename.push_back(*src); 959 ++src; 960 } 961 pos->name = strdup(filename.c_str()); 962 RegisterDependency(filename); 963} 964 965 966/** Given a pointer to a position in a string, return the character that it 967 represents, accounting for the escape characters supported in string 968 constants. (i.e. given the literal string "\\", return the character 969 '/'). The return value is the new position in the string and the 970 decoded character is returned in *pChar. 971*/ 972static char * 973lEscapeChar(char *str, char *pChar, SourcePos *pos) 974{ 975 if (*str != '\\') { 976 *pChar = *str; 977 } 978 else { 979 char *tail; 980 ++str; 981 switch (*str) { 982 case '\'': *pChar = '\''; break; 983 case '\"': *pChar = '\"'; break; 984 case '?': *pChar = '\?'; break; 985 case '\\': *pChar = '\\'; break; 986 case 'a': *pChar = '\a'; break; 987 case 'b': *pChar = '\b'; break; 988 case 'f': *pChar = '\f'; break; 989 case 'n': *pChar = '\n'; break; 990 case 'r': *pChar = '\r'; break; 991 case 't': *pChar = '\t'; break; 992 case 'v': *pChar = '\v'; break; 993 // octal constants \012 994 case '0': case '1': case '2': case '3': case '4': 995 case '5': case '6': case '7': 996 *pChar = (char)strtol(str, &tail, 8); 997 str = tail - 1; 998 break; 999 // hexidecimal constant \xff 1000 case 'x': 1001 *pChar = (char)strtol(str, &tail, 16); 1002 str = tail - 1; 1003 break; 1004 default: 1005 Error(*pos, "Bad character escape sequence: '%s'.", str); 1006 break; 1007 } 1008 } 1009 ++str; 1010 return str; 1011} 1012 1013 1014/** Parse a string constant in the source file. For each character in the 1015 string, handle any escaped characters with lEscapeChar() and keep eating 1016 characters until we come to the closing quote. 1017*/ 1018static void 1019lStringConst(YYSTYPE *yylval, SourcePos *pos) 1020{ 1021 char *p; 1022 std::string str; 1023 p = strchr(yytext, '"') + 1; 1024 if (p == NULL) 1025 return; 1026 1027 while (*p != '\"') { 1028 char cval = '\0'; 1029 p = lEscapeChar(p, &cval, pos); 1030 str.push_back(cval); 1031 } 1032 yylval->stringVal = new std::string(str); 1033} 1034 1035 1036/** Compute the value 2^n, where the exponent is given as an integer. 1037 There are more efficient ways to do this, for example by just slamming 1038 the bits into the appropriate bits of the double, but let's just do the 1039 obvious thing. 1040*/ 1041static double 1042ipow2(int exponent) { 1043 if (exponent < 0) 1044 return 1. / ipow2(-exponent); 1045 1046 double ret = 1.; 1047 while (exponent > 16) { 1048 ret *= 65536.; 1049 exponent -= 16; 1050 } 1051 while (exponent-- > 0) 1052 ret *= 2.; 1053 return ret; 1054} 1055 1056 1057/** Parse a hexadecimal-formatted floating-point number (C99 hex float 1058 constant-style). 1059*/ 1060static double 1061lParseHexFloat(const char *ptr) { 1062 Assert(ptr != NULL); 1063 1064 Assert(ptr[0] == '0' && ptr[1] == 'x'); 1065 ptr += 2; 1066 1067 // Start initializing the mantissa 1068 Assert(*ptr == '0' || *ptr == '1'); 1069 double mantissa = (*ptr == '1') ? 1. : 0.; 1070 ++ptr; 1071 1072 if (*ptr == '.') { 1073 // Is there a fraction part? If so, the i'th digit we encounter 1074 // gives the 1/(16^i) component of the mantissa. 1075 ++ptr; 1076 1077 double scale = 1. / 16.; 1078 // Keep going until we come to the 'p', which indicates that we've 1079 // come to the exponent 1080 while (*ptr != 'p') { 1081 // Figure out the raw value from 0-15 1082 int digit; 1083 if (*ptr >= '0' && *ptr <= '9') 1084 digit = *ptr - '0'; 1085 else if (*ptr >= 'a' && *ptr <= 'f') 1086 digit = 10 + *ptr - 'a'; 1087 else { 1088 Assert(*ptr >= 'A' && *ptr <= 'F'); 1089 digit = 10 + *ptr - 'A'; 1090 } 1091 1092 // And add its contribution to the mantissa 1093 mantissa += scale * digit; 1094 scale /= 16.; 1095 ++ptr; 1096 } 1097 } 1098 else 1099 // If there's not a '.', then we better be going straight to the 1100 // exponent 1101 Assert(*ptr == 'p'); 1102 1103 ++ptr; // skip the 'p' 1104 1105 // interestingly enough, the exponent is provided base 10.. 1106 char* endptr = NULL; 1107 int exponent = (int)strtol(ptr, &endptr, 10); 1108 Assert(ptr != endptr); 1109 1110 // Does stdlib exp2() guarantee exact results for integer n where can 1111 // be represented exactly as doubles? I would hope so but am not sure, 1112 // so let's be sure. 1113 return mantissa * ipow2(exponent); 1114} 1115