Home | History | Annotate | Download | only in preprocessor
      1 //
      2 // Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 
      7 #include "Preprocessor.h"
      8 
      9 #include <cassert>
     10 #include <sstream>
     11 
     12 #include "DiagnosticsBase.h"
     13 #include "DirectiveParser.h"
     14 #include "Macro.h"
     15 #include "MacroExpander.h"
     16 #include "Token.h"
     17 #include "Tokenizer.h"
     18 
     19 namespace pp
     20 {
     21 
     22 struct PreprocessorImpl
     23 {
     24     Diagnostics* diagnostics;
     25     MacroSet macroSet;
     26     Tokenizer tokenizer;
     27     DirectiveParser directiveParser;
     28     MacroExpander macroExpander;
     29 
     30     PreprocessorImpl(Diagnostics* diag,
     31                      DirectiveHandler* directiveHandler) :
     32         diagnostics(diag),
     33         tokenizer(diag),
     34         directiveParser(&tokenizer, &macroSet, diag, directiveHandler),
     35         macroExpander(&directiveParser, &macroSet, diag)
     36     {
     37     }
     38 };
     39 
     40 Preprocessor::Preprocessor(Diagnostics* diagnostics,
     41                            DirectiveHandler* directiveHandler)
     42 {
     43     mImpl = new PreprocessorImpl(diagnostics, directiveHandler);
     44 }
     45 
     46 Preprocessor::~Preprocessor()
     47 {
     48     delete mImpl;
     49 }
     50 
     51 bool Preprocessor::init(size_t count,
     52                         const char* const string[],
     53                         const int length[])
     54 {
     55     static const int kGLSLVersion = 100;
     56 
     57     // Add standard pre-defined macros.
     58     predefineMacro("__LINE__", 0);
     59     predefineMacro("__FILE__", 0);
     60     predefineMacro("__VERSION__", kGLSLVersion);
     61     predefineMacro("GL_ES", 1);
     62 
     63     return mImpl->tokenizer.init(count, string, length);
     64 }
     65 
     66 void Preprocessor::predefineMacro(const char* name, int value)
     67 {
     68     std::ostringstream stream;
     69     stream << value;
     70 
     71     Token token;
     72     token.type = Token::CONST_INT;
     73     token.text = stream.str();
     74 
     75     Macro macro;
     76     macro.predefined = true;
     77     macro.type = Macro::kTypeObj;
     78     macro.name = name;
     79     macro.replacements.push_back(token);
     80 
     81     mImpl->macroSet[name] = macro;
     82 }
     83 
     84 void Preprocessor::lex(Token* token)
     85 {
     86     bool validToken = false;
     87     while (!validToken)
     88     {
     89         mImpl->macroExpander.lex(token);
     90         switch (token->type)
     91         {
     92           // We should not be returning internal preprocessing tokens.
     93           // Convert preprocessing tokens to compiler tokens or report
     94           // diagnostics.
     95           case Token::PP_HASH:
     96             assert(false);
     97             break;
     98           case Token::CONST_INT:
     99           {
    100             int val = 0;
    101             if (!token->iValue(&val))
    102             {
    103                 // Do not mark the token as invalid.
    104                 // Just emit the diagnostic and reset value to 0.
    105                 mImpl->diagnostics->report(Diagnostics::INTEGER_OVERFLOW,
    106                                            token->location, token->text);
    107                 token->text.assign("0");
    108             }
    109             validToken = true;
    110             break;
    111           }
    112           case Token::CONST_FLOAT:
    113           {
    114             float val = 0;
    115             if (!token->fValue(&val))
    116             {
    117                 // Do not mark the token as invalid.
    118                 // Just emit the diagnostic and reset value to 0.0.
    119                 mImpl->diagnostics->report(Diagnostics::FLOAT_OVERFLOW,
    120                                            token->location, token->text);
    121                 token->text.assign("0.0");
    122             }
    123             validToken = true;
    124             break;
    125           }
    126           case Token::PP_NUMBER:
    127             mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER,
    128                                        token->location, token->text);
    129             break;
    130           case Token::PP_OTHER:
    131             mImpl->diagnostics->report(Diagnostics::INVALID_CHARACTER,
    132                                        token->location, token->text);
    133             break;
    134           default:
    135             validToken = true;
    136             break;
    137         }
    138     }
    139 }
    140 
    141 }  // namespace pp
    142 
    143