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
19namespace pp
20{
21
22struct 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
40Preprocessor::Preprocessor(Diagnostics *diagnostics,
41                           DirectiveHandler *directiveHandler)
42{
43    mImpl = new PreprocessorImpl(diagnostics, directiveHandler);
44}
45
46Preprocessor::~Preprocessor()
47{
48    delete mImpl;
49}
50
51bool 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
66void 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
84void 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::PP_NUMBER:
99            mImpl->diagnostics->report(Diagnostics::PP_INVALID_NUMBER,
100                                       token->location, token->text);
101            break;
102          case Token::PP_OTHER:
103            mImpl->diagnostics->report(Diagnostics::PP_INVALID_CHARACTER,
104                                       token->location, token->text);
105            break;
106          default:
107            validToken = true;
108            break;
109        }
110    }
111}
112
113void Preprocessor::setMaxTokenSize(size_t maxTokenSize)
114{
115    mImpl->tokenizer.setMaxTokenSize(maxTokenSize);
116}
117
118}  // namespace pp
119