1 /* 2 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 This file contains the Lex specification for GLSL ES preprocessor. 17 Based on Microsoft Visual Studio 2010 Preprocessor Grammar: 18 http://msdn.microsoft.com/en-us/library/2scxys89.aspx 19 20 IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh. 21 */ 22 23 %top{ 24 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 25 // 26 // Licensed under the Apache License, Version 2.0 (the "License"); 27 // you may not use this file except in compliance with the License. 28 // You may obtain a copy of the License at 29 // 30 // http://www.apache.org/licenses/LICENSE-2.0 31 // 32 // Unless required by applicable law or agreed to in writing, software 33 // distributed under the License is distributed on an "AS IS" BASIS, 34 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 // See the License for the specific language governing permissions and 36 // limitations under the License. 37 38 // This file is auto-generated by generate_parser.sh. DO NOT EDIT! 39 } 40 41 %{ 42 #include "Tokenizer.h" 43 44 #include "Diagnostics.h" 45 #include "Token.h" 46 47 #if defined(__GNUC__) 48 // Triggered by the auto-generated yy_fatal_error function. 49 #pragma GCC diagnostic ignored "-Wmissing-noreturn" 50 #endif 51 52 typedef std::string YYSTYPE; 53 typedef pp::SourceLocation YYLTYPE; 54 55 // Use the unused yycolumn variable to track file (string) number. 56 #define yyfileno yycolumn 57 58 #define YY_USER_INIT \ 59 do { \ 60 yyfileno = 0; \ 61 yylineno = 1; \ 62 yyextra->leadingSpace = false; \ 63 yyextra->lineStart = true; \ 64 } while(0); 65 66 #define YY_USER_ACTION \ 67 do \ 68 { \ 69 pp::Input* input = &yyextra->input; \ 70 pp::Input::Location* scanLoc = &yyextra->scanLoc; \ 71 while ((scanLoc->sIndex < input->count()) && \ 72 (scanLoc->cIndex >= input->length(scanLoc->sIndex))) \ 73 { \ 74 scanLoc->cIndex -= input->length(scanLoc->sIndex++); \ 75 ++yyfileno; yylineno = 1; \ 76 } \ 77 yylloc->file = yyfileno; \ 78 yylloc->line = yylineno; \ 79 scanLoc->cIndex += yyleng; \ 80 } while(0); 81 82 #define YY_INPUT(buf, result, maxSize) \ 83 result = yyextra->input.read(buf, maxSize); 84 85 %} 86 87 %option noyywrap nounput never-interactive 88 %option reentrant bison-bridge bison-locations 89 %option prefix="pp" 90 %option extra-type="pp::Tokenizer::Context*" 91 %x COMMENT 92 93 NEWLINE \n|\r|\r\n 94 IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]* 95 PUNCTUATOR [][<>(){}.+-/*%^|&~=!:;,?] 96 97 DECIMAL_CONSTANT [1-9][0-9]*[uU]? 98 OCTAL_CONSTANT 0[0-7]*[uU]? 99 HEXADECIMAL_CONSTANT 0[xX][0-9a-fA-F]+[uU]? 100 101 DIGIT [0-9] 102 EXPONENT_PART [eE][+-]?{DIGIT}+ 103 FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") 104 105 %% 106 107 /* Line comment */ 108 "//"[^\r\n]* 109 110 /* Block comment */ 111 /* Line breaks are just counted - not returned. */ 112 /* The comment is replaced by a single space. */ 113 "/*" { BEGIN(COMMENT); } 114 <COMMENT>[^*\r\n]+ 115 <COMMENT>"*" 116 <COMMENT>{NEWLINE} { ++yylineno; } 117 <COMMENT>"*/" { 118 yyextra->leadingSpace = true; 119 BEGIN(INITIAL); 120 } 121 122 # { 123 // # is only valid at start of line for preprocessor directives. 124 yylval->assign(1, yytext[0]); 125 return yyextra->lineStart ? pp::Token::PP_HASH : pp::Token::PP_OTHER; 126 } 127 128 {IDENTIFIER} { 129 yylval->assign(yytext, yyleng); 130 return pp::Token::IDENTIFIER; 131 } 132 133 ({DECIMAL_CONSTANT}[uU]?)|({OCTAL_CONSTANT}[uU]?)|({HEXADECIMAL_CONSTANT}[uU]?) { 134 yylval->assign(yytext, yyleng); 135 return pp::Token::CONST_INT; 136 } 137 138 ({DIGIT}+{EXPONENT_PART}[fF]?)|({FRACTIONAL_CONSTANT}{EXPONENT_PART}?[fF]?) { 139 yylval->assign(yytext, yyleng); 140 return pp::Token::CONST_FLOAT; 141 } 142 143 /* Anything that starts with a {DIGIT} or .{DIGIT} must be a number. */ 144 /* Rule to catch all invalid integers and floats. */ 145 ({DIGIT}+[_a-zA-Z0-9.]*)|("."{DIGIT}+[_a-zA-Z0-9.]*) { 146 yylval->assign(yytext, yyleng); 147 return pp::Token::PP_NUMBER; 148 } 149 150 "++" { 151 yylval->assign(yytext, yyleng); 152 return pp::Token::OP_INC; 153 } 154 "--" { 155 yylval->assign(yytext, yyleng); 156 return pp::Token::OP_DEC; 157 } 158 "<<" { 159 yylval->assign(yytext, yyleng); 160 return pp::Token::OP_LEFT; 161 } 162 ">>" { 163 yylval->assign(yytext, yyleng); 164 return pp::Token::OP_RIGHT; 165 } 166 "<=" { 167 yylval->assign(yytext, yyleng); 168 return pp::Token::OP_LE; 169 } 170 ">=" { 171 yylval->assign(yytext, yyleng); 172 return pp::Token::OP_GE; 173 } 174 "==" { 175 yylval->assign(yytext, yyleng); 176 return pp::Token::OP_EQ; 177 } 178 "!=" { 179 yylval->assign(yytext, yyleng); 180 return pp::Token::OP_NE; 181 } 182 "&&" { 183 yylval->assign(yytext, yyleng); 184 return pp::Token::OP_AND; 185 } 186 "^^" { 187 yylval->assign(yytext, yyleng); 188 return pp::Token::OP_XOR; 189 } 190 "||" { 191 yylval->assign(yytext, yyleng); 192 return pp::Token::OP_OR; 193 } 194 "+=" { 195 yylval->assign(yytext, yyleng); 196 return pp::Token::OP_ADD_ASSIGN; 197 } 198 "-=" { 199 yylval->assign(yytext, yyleng); 200 return pp::Token::OP_SUB_ASSIGN; 201 } 202 "*=" { 203 yylval->assign(yytext, yyleng); 204 return pp::Token::OP_MUL_ASSIGN; 205 } 206 "/=" { 207 yylval->assign(yytext, yyleng); 208 return pp::Token::OP_DIV_ASSIGN; 209 } 210 "%=" { 211 yylval->assign(yytext, yyleng); 212 return pp::Token::OP_MOD_ASSIGN; 213 } 214 "<<=" { 215 yylval->assign(yytext, yyleng); 216 return pp::Token::OP_LEFT_ASSIGN; 217 } 218 ">>=" { 219 yylval->assign(yytext, yyleng); 220 return pp::Token::OP_RIGHT_ASSIGN; 221 } 222 "&=" { 223 yylval->assign(yytext, yyleng); 224 return pp::Token::OP_AND_ASSIGN; 225 } 226 "^=" { 227 yylval->assign(yytext, yyleng); 228 return pp::Token::OP_XOR_ASSIGN; 229 } 230 "|=" { 231 yylval->assign(yytext, yyleng); 232 return pp::Token::OP_OR_ASSIGN; 233 } 234 235 {PUNCTUATOR} { 236 yylval->assign(1, yytext[0]); 237 return yytext[0]; 238 } 239 240 [ \t\v\f]+ { yyextra->leadingSpace = true; } 241 242 {NEWLINE} { 243 ++yylineno; 244 yylval->assign(1, '\n'); 245 return '\n'; 246 } 247 248 \\{NEWLINE} { ++yylineno; } 249 250 . { 251 yylval->assign(1, yytext[0]); 252 return pp::Token::PP_OTHER; 253 } 254 255 <*><<EOF>> { 256 // YY_USER_ACTION is not invoked for handling EOF. 257 // Set the location for EOF token manually. 258 pp::Input* input = &yyextra->input; 259 pp::Input::Location* scanLoc = &yyextra->scanLoc; 260 int sIndexMax = std::max(0, input->count() - 1); 261 if (scanLoc->sIndex != sIndexMax) 262 { 263 // We can only reach here if there are empty strings at the 264 // end of the input. 265 scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0; 266 yyfileno = sIndexMax; yylineno = 1; 267 } 268 yylloc->file = yyfileno; 269 yylloc->line = yylineno; 270 yylval->clear(); 271 272 if (YY_START == COMMENT) 273 { 274 yyextra->diagnostics->report(pp::Diagnostics::EOF_IN_COMMENT, 275 pp::SourceLocation(yyfileno, yylineno), 276 ""); 277 } 278 yyterminate(); 279 } 280 281 %% 282 283 namespace pp { 284 285 // TODO(alokp): Maximum token length should ideally be specified by 286 // the preprocessor client, i.e., the compiler. 287 const size_t Tokenizer::kMaxTokenLength = 256; 288 289 Tokenizer::Tokenizer(Diagnostics* diagnostics) : mHandle(0) 290 { 291 mContext.diagnostics = diagnostics; 292 } 293 294 Tokenizer::~Tokenizer() 295 { 296 destroyScanner(); 297 } 298 299 bool Tokenizer::init(int count, const char* const string[], const int length[]) 300 { 301 if (count < 0) return false; 302 if ((count > 0) && (string == 0)) return false; 303 304 mContext.input = Input(count, string, length); 305 return initScanner(); 306 } 307 308 void Tokenizer::setFileNumber(int file) 309 { 310 // We use column number as file number. 311 // See macro yyfileno. 312 yyset_column(file, mHandle); 313 } 314 315 void Tokenizer::setLineNumber(int line) 316 { 317 yyset_lineno(line, mHandle); 318 } 319 320 void Tokenizer::lex(Token* token) 321 { 322 token->type = yylex(&token->text, &token->location, mHandle); 323 if (token->text.size() > kMaxTokenLength) 324 { 325 mContext.diagnostics->report(Diagnostics::TOKEN_TOO_LONG, 326 token->location, token->text); 327 token->text.erase(kMaxTokenLength); 328 } 329 330 token->flags = 0; 331 332 token->setAtStartOfLine(mContext.lineStart); 333 mContext.lineStart = token->type == '\n'; 334 335 token->setHasLeadingSpace(mContext.leadingSpace); 336 mContext.leadingSpace = false; 337 } 338 339 bool Tokenizer::initScanner() 340 { 341 if ((mHandle == NULL) && yylex_init_extra(&mContext, &mHandle)) 342 return false; 343 344 yyrestart(0, mHandle); 345 return true; 346 } 347 348 void Tokenizer::destroyScanner() 349 { 350 if (mHandle == NULL) 351 return; 352 353 yylex_destroy(mHandle); 354 mHandle = NULL; 355 } 356 357 } // namespace pp 358 359