Home | History | Annotate | Download | only in preprocessor
      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 #if defined(_MSC_VER)
     43 #pragma warning(disable: 4005)
     44 #endif
     45 
     46 #include "Tokenizer.h"
     47 
     48 #include "DiagnosticsBase.h"
     49 #include "Token.h"
     50 
     51 #if defined(__GNUC__)
     52 // Triggered by the auto-generated yy_fatal_error function.
     53 #pragma GCC diagnostic ignored "-Wmissing-noreturn"
     54 #elif defined(_MSC_VER)
     55 #pragma warning(disable: 4244)
     56 #endif
     57 
     58 // Workaround for flex using the register keyword, deprecated in C++11.
     59 #ifdef __cplusplus
     60 #if __cplusplus > 199711L
     61 #define register
     62 #endif
     63 #endif
     64 
     65 typedef std::string YYSTYPE;
     66 typedef pp::SourceLocation YYLTYPE;
     67 
     68 // Use the unused yycolumn variable to track file (string) number.
     69 #define yyfileno yycolumn
     70 
     71 #define YY_USER_INIT                   \
     72     do {                               \
     73         yyfileno = 0;                  \
     74         yylineno = 1;                  \
     75         yyextra->leadingSpace = false; \
     76         yyextra->lineStart = true;     \
     77     } while(0);
     78 
     79 #define YY_USER_ACTION                                              \
     80     do                                                              \
     81     {                                                               \
     82         pp::Input* input = &yyextra->input;                         \
     83         pp::Input::Location* scanLoc = &yyextra->scanLoc;           \
     84         while ((scanLoc->sIndex < input->count()) &&                \
     85                (scanLoc->cIndex >= input->length(scanLoc->sIndex))) \
     86         {                                                           \
     87             scanLoc->cIndex -= input->length(scanLoc->sIndex++);    \
     88             ++yyfileno; yylineno = 1;                               \
     89         }                                                           \
     90         yylloc->file = yyfileno;                                    \
     91         yylloc->line = yylineno;                                    \
     92         scanLoc->cIndex += yyleng;                                  \
     93     } while(0);
     94 
     95 #define YY_INPUT(buf, result, maxSize) \
     96     result = yyextra->input.read(buf, maxSize, &yylineno);
     97 
     98 %}
     99 
    100 %option noyywrap nounput never-interactive
    101 %option reentrant bison-bridge bison-locations
    102 %option prefix="pp"
    103 %option extra-type="pp::Tokenizer::Context*"
    104 %x COMMENT
    105 
    106 NEWLINE     \n|\r|\r\n
    107 IDENTIFIER  [_a-zA-Z][_a-zA-Z0-9]*
    108 PUNCTUATOR  [][<>(){}.+-/*%^|&~=!:;,?]
    109 
    110 DECIMAL_CONSTANT      [1-9][0-9]*[uU]?
    111 OCTAL_CONSTANT        0[0-7]*[uU]?
    112 HEXADECIMAL_CONSTANT  0[xX][0-9a-fA-F]+[uU]?
    113 
    114 DIGIT                [0-9]
    115 EXPONENT_PART        [eE][+-]?{DIGIT}+
    116 FRACTIONAL_CONSTANT  ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".")
    117 
    118 %%
    119 
    120     /* Line comment */
    121 "//"[^\r\n]*
    122 
    123     /* Block comment */
    124     /* Line breaks are just counted - not returned. */
    125     /* The comment is replaced by a single space. */
    126 "/*" { BEGIN(COMMENT); }
    127 <COMMENT>[^*\r\n]+
    128 <COMMENT>"*"
    129 <COMMENT>{NEWLINE} {
    130     if (yylineno == INT_MAX)
    131     {
    132         *yylval = "Integer overflow on line number";
    133         return pp::Token::GOT_ERROR;
    134     }
    135     ++yylineno;
    136 }
    137 <COMMENT>"*/" {
    138     yyextra->leadingSpace = true;
    139     BEGIN(INITIAL);
    140 }
    141 
    142 # {
    143     // # is only valid at start of line for preprocessor directives.
    144     yylval->assign(1, yytext[0]);
    145     return yyextra->lineStart ? pp::Token::PP_HASH : pp::Token::PP_OTHER;
    146 }
    147 
    148 {IDENTIFIER} {
    149     yylval->assign(yytext, yyleng);
    150     return pp::Token::IDENTIFIER;
    151 }
    152 
    153 ({DECIMAL_CONSTANT}[uU]?)|({OCTAL_CONSTANT}[uU]?)|({HEXADECIMAL_CONSTANT}[uU]?) {
    154     yylval->assign(yytext, yyleng);
    155     return pp::Token::CONST_INT;
    156 }
    157 
    158 ({DIGIT}+{EXPONENT_PART}[fF]?)|({FRACTIONAL_CONSTANT}{EXPONENT_PART}?[fF]?) {
    159     yylval->assign(yytext, yyleng);
    160     return pp::Token::CONST_FLOAT;
    161 }
    162 
    163     /* Anything that starts with a {DIGIT} or .{DIGIT} must be a number. */
    164     /* Rule to catch all invalid integers and floats. */
    165 ({DIGIT}+[_a-zA-Z0-9.]*)|("."{DIGIT}+[_a-zA-Z0-9.]*) {
    166     yylval->assign(yytext, yyleng);
    167     return pp::Token::PP_NUMBER;
    168 }
    169 
    170 "++" {
    171     yylval->assign(yytext, yyleng);
    172     return pp::Token::OP_INC;
    173 }
    174 "--" {
    175     yylval->assign(yytext, yyleng);
    176     return pp::Token::OP_DEC;
    177 }
    178 "<<" {
    179     yylval->assign(yytext, yyleng);
    180     return pp::Token::OP_LEFT;
    181 }
    182 ">>" {
    183     yylval->assign(yytext, yyleng);
    184     return pp::Token::OP_RIGHT;
    185 }
    186 "<=" {
    187     yylval->assign(yytext, yyleng);
    188     return pp::Token::OP_LE;
    189 }
    190 ">=" {
    191     yylval->assign(yytext, yyleng);
    192     return pp::Token::OP_GE;
    193 }
    194 "==" {
    195     yylval->assign(yytext, yyleng);
    196     return pp::Token::OP_EQ;
    197 }
    198 "!=" {
    199     yylval->assign(yytext, yyleng);
    200     return pp::Token::OP_NE;
    201 }
    202 "&&" {
    203     yylval->assign(yytext, yyleng);
    204     return pp::Token::OP_AND;
    205 }
    206 "^^" {
    207     yylval->assign(yytext, yyleng);
    208     return pp::Token::OP_XOR;
    209 }
    210 "||" {
    211     yylval->assign(yytext, yyleng);
    212     return pp::Token::OP_OR;
    213 }
    214 "+=" {
    215     yylval->assign(yytext, yyleng);
    216     return pp::Token::OP_ADD_ASSIGN;
    217 }
    218 "-=" {
    219     yylval->assign(yytext, yyleng);
    220     return pp::Token::OP_SUB_ASSIGN;
    221 }
    222 "*=" {
    223     yylval->assign(yytext, yyleng);
    224     return pp::Token::OP_MUL_ASSIGN;
    225 }
    226 "/=" {
    227     yylval->assign(yytext, yyleng);
    228     return pp::Token::OP_DIV_ASSIGN;
    229 }
    230 "%=" {
    231     yylval->assign(yytext, yyleng);
    232     return pp::Token::OP_MOD_ASSIGN;
    233 }
    234 "<<=" {
    235     yylval->assign(yytext, yyleng);
    236     return pp::Token::OP_LEFT_ASSIGN;
    237 }
    238 ">>=" {
    239     yylval->assign(yytext, yyleng);
    240     return pp::Token::OP_RIGHT_ASSIGN;
    241 }
    242 "&=" {
    243     yylval->assign(yytext, yyleng);
    244     return pp::Token::OP_AND_ASSIGN;
    245 }
    246 "^=" {
    247     yylval->assign(yytext, yyleng);
    248     return pp::Token::OP_XOR_ASSIGN;
    249 }
    250 "|=" {
    251     yylval->assign(yytext, yyleng);
    252     return pp::Token::OP_OR_ASSIGN;
    253 }
    254 
    255 {PUNCTUATOR} {
    256     yylval->assign(1, yytext[0]);
    257     return yytext[0];
    258 }
    259 
    260 [ \t\v\f]+   { yyextra->leadingSpace = true; }
    261 
    262 {NEWLINE} {
    263     if (yylineno == INT_MAX)
    264     {
    265         *yylval = "Integer overflow on line number";
    266         return pp::Token::GOT_ERROR;
    267     }
    268     ++yylineno;
    269     yylval->assign(1, '\n');
    270     return '\n';
    271 }
    272 
    273 . {
    274     yylval->assign(1, yytext[0]);
    275     return pp::Token::PP_OTHER;
    276 }
    277 
    278 <*><<EOF>> {
    279     // YY_USER_ACTION is not invoked for handling EOF.
    280     // Set the location for EOF token manually.
    281     pp::Input* input = &yyextra->input;
    282     pp::Input::Location* scanLoc = &yyextra->scanLoc;
    283     yy_size_t sIndexMax = input->count() ? input->count() - 1 : 0;
    284     if (scanLoc->sIndex != sIndexMax)
    285     {
    286         // We can only reach here if there are empty strings at the
    287         // end of the input.
    288         scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0;
    289         // FIXME: this is not 64-bit clean.
    290         yyfileno = static_cast<int>(sIndexMax); yylineno = 1;
    291     }
    292     yylloc->file = yyfileno;
    293     yylloc->line = yylineno;
    294     yylval->clear();
    295 
    296     // Line number overflows fake EOFs to exit early, check for this case.
    297     if (yylineno == INT_MAX) {
    298         yyextra->diagnostics->report(pp::Diagnostics::PP_TOKENIZER_ERROR,
    299                 pp::SourceLocation(yyfileno, yylineno),
    300                 "Integer overflow on line number");
    301     }
    302     else if (YY_START == COMMENT)
    303     {
    304         yyextra->diagnostics->report(pp::Diagnostics::PP_EOF_IN_COMMENT,
    305                                      pp::SourceLocation(yyfileno, yylineno),
    306                                      "EOF while in a comment");
    307     }
    308     yyterminate();
    309 }
    310 
    311 %%
    312 
    313 namespace pp {
    314 
    315 Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(nullptr), mMaxTokenSize(1024)
    316 {
    317     mContext.diagnostics = diagnostics;
    318 }
    319 
    320 Tokenizer::~Tokenizer()
    321 {
    322     destroyScanner();
    323 }
    324 
    325 bool Tokenizer::init(size_t count, const char * const string[], const int length[])
    326 {
    327     if ((count > 0) && (string == 0))
    328         return false;
    329 
    330     mContext.input = Input(count, string, length);
    331     return initScanner();
    332 }
    333 
    334 void Tokenizer::setFileNumber(int file)
    335 {
    336     // We use column number as file number.
    337     // See macro yyfileno.
    338     yyset_column(file, mHandle);
    339 }
    340 
    341 void Tokenizer::setLineNumber(int line)
    342 {
    343     yyset_lineno(line, mHandle);
    344 }
    345 
    346 void Tokenizer::setMaxTokenSize(size_t maxTokenSize)
    347 {
    348     mMaxTokenSize = maxTokenSize;
    349 }
    350 
    351 void Tokenizer::lex(Token *token)
    352 {
    353     int tokenType = yylex(&token->text, &token->location, mHandle);
    354 
    355     if (tokenType == Token::GOT_ERROR)
    356     {
    357         mContext.diagnostics->report(Diagnostics::PP_TOKENIZER_ERROR, token->location, token->text);
    358         token->type = Token::LAST;
    359     }
    360     else
    361     {
    362         token->type = tokenType;
    363     }
    364 
    365     if (token->text.size() > mMaxTokenSize)
    366     {
    367         mContext.diagnostics->report(Diagnostics::PP_TOKEN_TOO_LONG,
    368                                      token->location, token->text);
    369         token->text.erase(mMaxTokenSize);
    370     }
    371 
    372     token->flags = 0;
    373 
    374     token->setAtStartOfLine(mContext.lineStart);
    375     mContext.lineStart = token->type == '\n';
    376 
    377     token->setHasLeadingSpace(mContext.leadingSpace);
    378     mContext.leadingSpace = false;
    379 }
    380 
    381 bool Tokenizer::initScanner()
    382 {
    383     if ((mHandle == nullptr) && yylex_init_extra(&mContext, &mHandle))
    384         return false;
    385 
    386     yyrestart(0, mHandle);
    387     return true;
    388 }
    389 
    390 void Tokenizer::destroyScanner()
    391 {
    392     if (mHandle == nullptr)
    393         return;
    394 
    395     yylex_destroy(mHandle);
    396     mHandle = nullptr;
    397 }
    398 
    399 }  // namespace pp
    400 
    401