File: CxxPreProcessorScanner.cpp

package info (click to toggle)
codelite 17.0.0%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 136,244 kB
  • sloc: cpp: 491,547; ansic: 280,393; php: 10,259; sh: 8,930; lisp: 7,664; vhdl: 6,518; python: 6,020; lex: 4,920; yacc: 3,123; perl: 2,385; javascript: 1,715; cs: 1,193; xml: 1,110; makefile: 804; cobol: 741; sql: 709; ruby: 620; f90: 566; ada: 534; asm: 464; fortran: 350; objc: 289; tcl: 258; java: 157; erlang: 61; pascal: 51; ml: 49; awk: 44; haskell: 36
file content (383 lines) | stat: -rw-r--r-- 12,730 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
#include "CxxPreProcessorScanner.h"

#include "CxxPreProcessor.h"
#include "CxxPreProcessorExpression.h"
#include "CxxScannerTokens.h"
#include "file_logger.h"

#include <wx/sharedptr.h>

CxxPreProcessorScanner::CxxPreProcessorScanner(const wxFileName& filename, size_t options,
                                               std::unordered_set<wxString>& visitedFiles)
    : m_scanner(NULL)
    , m_filename(filename)
    , m_options(options)
    , m_visitedFiles(visitedFiles)
{
    m_scanner = ::LexerNew(m_filename, m_options);
    wxASSERT(m_scanner);
}

CxxPreProcessorScanner::~CxxPreProcessorScanner()
{
    if(m_scanner) {
        ::LexerDestroy(&m_scanner);
    }
}

void CxxPreProcessorScanner::GetRestOfPPLine(wxString& rest, bool collectNumberOnly)
{
    CxxLexerToken token;
    bool numberFound = false;
    while(m_scanner && ::LexerNext(m_scanner, token) && token.GetType() != T_PP_STATE_EXIT) {
        if(!numberFound && collectNumberOnly) {
            if(token.GetType() == T_PP_DEC_NUMBER || token.GetType() == T_PP_OCTAL_NUMBER ||
               token.GetType() == T_PP_HEX_NUMBER || token.GetType() == T_PP_FLOAT_NUMBER) {
                rest = token.GetWXString();
                numberFound = true;
            }
        } else if(!collectNumberOnly) {
            rest << " " << token.GetWXString();
        }
    }
    rest.Trim(false).Trim(true);
}

bool CxxPreProcessorScanner::ConsumeBlock()
{
    CxxLexerToken token;
    int depth = 1;
    while(m_scanner && ::LexerNext(m_scanner, token)) {
        switch(token.GetType()) {
        case T_PP_ENDIF:
            depth--;
            if(depth == 0) {
                return true;
            }
            break;
        case T_PP_IF:
        case T_PP_IFDEF:
        case T_PP_IFNDEF:
            depth++;
            break;
        default:
            break;
        }
    }
    // throw CxxLexerException("Invalid EOF");
    return false;
}

void CxxPreProcessorScanner::Parse(CxxPreProcessor* pp)
{
    CxxLexerToken token;
    bool searchingForBranch = false;
    CxxPreProcessorToken::Map_t& ppTable = pp->GetTokens();
    while(m_scanner && ::LexerNext(m_scanner, token)) {
        // Pre Processor state
        switch(token.GetType()) {
        case T_PP_INCLUDE_FILENAME: {
            // we found an include statement, recurse into it
            wxFileName include;
            if(pp->ExpandInclude(m_filename, token.GetWXString(), include) &&
               m_visitedFiles.count(include.GetFullPath()) == 0) {
                m_visitedFiles.insert(include.GetFullPath());
                CxxPreProcessorScanner scanner(include, pp->GetOptions(), m_visitedFiles);
                try {
                    if(!scanner.IsNull()) {
                        scanner.Parse(pp);
                    }
                } catch(CxxLexerException& e) {
                    // catch the exception
                    clDEBUG() << "Exception caught:" << e.message << endl;
                }
                // make sure we always delete the scanner
                LOG_IF_TRACE { clDEBUG1() << "<== Resuming parser on file:" << m_filename << clEndl; }
            }
            break;
        }
        case T_PP_IFDEF: {
            searchingForBranch = true;
            // read the identifier
            ReadUntilMatch(T_PP_IDENTIFIER, token);
            if(IsTokenExists(ppTable, token)) {
                searchingForBranch = false;
                // condition is true
                Parse(pp);
            } else {
                // skip until we find the next:
                // else, elif, endif (but do not consume these tokens)
                if(!ConsumeCurrentBranch())
                    return;
            }
            break;
        }
        case T_PP_IFNDEF: {
            searchingForBranch = true;
            // read the identifier
            ReadUntilMatch(T_PP_IDENTIFIER, token);
            if(!IsTokenExists(ppTable, token)) {
                searchingForBranch = false;
                // condition is true
                Parse(pp);
            } else {
                // skip until we find the next:
                // else, elif, endif (but do not consume these tokens)
                if(!ConsumeCurrentBranch())
                    return;
            }
            break;
        }
        case T_PP_IF:
            searchingForBranch = true;
        case T_PP_ELIF: {
            if(searchingForBranch) {
                // We expect a condition
                if(!CheckIf(ppTable)) {
                    // skip until we find the next:
                    // else, elif, endif (but do not consume these tokens)
                    if(!ConsumeCurrentBranch())
                        return;

                } else {
                    searchingForBranch = false;
                    // condition is true
                    Parse(pp);
                }
            } else {
                ConsumeBlock();
                return;
            }
            break;
        }
        case T_PP_ELSE: {
            if(searchingForBranch) {
                // if we reached an else, it means that we could not match
                // a if/elif/ifdef condition until now - enter it
                Parse(pp);
                searchingForBranch = false;
            } else {
                // we already found the branch for the current block
                // this means that the 'else' is a stop sign for us
                ConsumeBlock();
                return;
            }
            break;
        }
        case T_PP_ENDIF: {
            return;
        }
        case T_PP_DEFINE: {
            if(!::LexerNext(m_scanner, token) || token.GetType() != T_PP_IDENTIFIER) {
                // Recover
                wxString dummy;
                GetRestOfPPLine(dummy);
                break;
            }
            wxString macroName = token.GetWXString();

            wxString macroValue;
            // Optionally get the value
            GetRestOfPPLine(macroValue, m_options & kLexerOpt_CollectMacroValueNumbers);

            CxxPreProcessorToken pp;
            pp.name = macroName;
            pp.value = macroValue;
            // mark this token for deletion when the entire TU parsing is done
            pp.deleteOnExit = (m_options & kLexerOpt_DontCollectMacrosDefinedInThisFile);
            ppTable.insert(std::make_pair(pp.name, pp));
            break;
        }
        }
    }
}

bool CxxPreProcessorScanner::CheckIfDefined(const CxxPreProcessorToken::Map_t& table)
{
    CxxLexerToken token;
    if(m_scanner && ::LexerNext(m_scanner, token)) {
        if(token.GetType() == T_PP_STATE_EXIT) {
            return false;
        }
        switch(token.GetType()) {
        case T_PP_IDENTIFIER:
            return table.count(token.GetWXString());
        case '(':
            // ignore
            break;
        default:
            break;
        }
    }
    return false;
}

#define SET_CUR_EXPR_VALUE_RET_FALSE(v) \
    if(cur->IsValueSet())               \
        return false;                   \
    else                                \
        cur->SetValue((double)v);

struct ExpressionLocker {
    CxxPreProcessorExpression* m_expr;
    ExpressionLocker(CxxPreProcessorExpression* expr)
        : m_expr(expr)
    {
    }
    ~ExpressionLocker() { wxDELETE(m_expr); }
};

bool CxxPreProcessorScanner::CheckIf(const CxxPreProcessorToken::Map_t& table)
{
    // we currently support
    // #if IDENTIFIER
    // #if NUMBER
    // #if (cond) && (cond) || !(cond)
    // anything else, returns false
    CxxLexerToken token;
    CxxPreProcessorExpression* cur = new CxxPreProcessorExpression(false);
    ExpressionLocker locker(cur);
    CxxPreProcessorExpression* head = cur;
    while(m_scanner && ::LexerNext(m_scanner, token)) {
        if(token.GetType() == T_PP_STATE_EXIT) {
            bool res = head->IsTrue();
            return res;
        }
        switch(token.GetType()) {
        case '(':
        case ')':
            // ignore parenthesis
            break;

        case '!':
            cur->SetNot();
            break;

        case T_PP_DEC_NUMBER: {
            SET_CUR_EXPR_VALUE_RET_FALSE(atol(token.GetText()));
            break;
        }
        case T_PP_OCTAL_NUMBER: {
            SET_CUR_EXPR_VALUE_RET_FALSE(atol(token.GetText()));
            break;
        }
        case T_PP_HEX_NUMBER: {
            SET_CUR_EXPR_VALUE_RET_FALSE(atol(token.GetText()));
            break;
        }
        case T_PP_FLOAT_NUMBER: {
            SET_CUR_EXPR_VALUE_RET_FALSE(atof(token.GetText()));
            break;
        }
        case T_PP_IDENTIFIER: {
            wxString identifier = token.GetWXString();
            CxxPreProcessorToken::Map_t::const_iterator iter = table.find(identifier);
            if(iter == table.end()) {
                SET_CUR_EXPR_VALUE_RET_FALSE(0);
            } else {
                if(cur->IsDefined()) {
                    // no need to test further, it exists (the current expression
                    // if a 'defined' statement)
                    SET_CUR_EXPR_VALUE_RET_FALSE(1);
                } else {
                    wxString macroValue = iter->second.value;
                    if(macroValue.IsEmpty()) {
                        SET_CUR_EXPR_VALUE_RET_FALSE(0);
                    } else {
                        long v(0);
                        bool res = macroValue.ToCLong(&v);
                        if(!res) {
                            SET_CUR_EXPR_VALUE_RET_FALSE(0);

                        } else {
                            SET_CUR_EXPR_VALUE_RET_FALSE(v);
                        }
                    }
                }
            }
            break;
        }
        case T_PP_DEFINED:
            cur->SetDefined(true);
            break;
        case T_PP_AND:
            // And operand
            cur = cur->SetNext(CxxPreProcessorExpression::kAND, new CxxPreProcessorExpression(false));
            break;
        case T_PP_OR:
            // OR operand
            cur = cur->SetNext(CxxPreProcessorExpression::kOR, new CxxPreProcessorExpression(false));
            break;
        case T_PP_GT:
            cur = cur->SetNext(CxxPreProcessorExpression::kGreaterThan, new CxxPreProcessorExpression(0));
            break;
        case T_PP_GTEQ:
            cur = cur->SetNext(CxxPreProcessorExpression::kGreaterThanEqual, new CxxPreProcessorExpression(0));
            break;
        case T_PP_LT:
            cur = cur->SetNext(CxxPreProcessorExpression::kLowerThan, new CxxPreProcessorExpression(0));
            break;
        case T_PP_LTEQ:
            cur = cur->SetNext(CxxPreProcessorExpression::kLowerThanEqual, new CxxPreProcessorExpression(0));
            break;
        default:
            break;
        }
    }
    return false;
}

/**
 * @brief fast-forward until we hit one of the tokens in the stopTokens
 * Note that this function does not consume the 'stopToken'
 */
bool CxxPreProcessorScanner::ConsumeCurrentBranch()
{
    CxxLexerToken token;
    int depth = 1;
    // T_PP_ELIF
    // T_PP_ELSE
    // T_PP_ENDIF
    while(m_scanner && ::LexerNext(m_scanner, token)) {
        switch(token.GetType()) {
        case T_PP_IF:
        case T_PP_IFDEF:
        case T_PP_IFNDEF:
            depth++;
            break;
        case T_PP_ENDIF:
            if(depth == 1) {
                return true;
            }
            depth--;
            break;
        case T_PP_ELIF:
        case T_PP_ELSE:
            if(depth == 1) {
                ::LexerUnget(m_scanner);
                return true;
            }
            break;
        default:
            break;
        }
    }
    return false;
}

void CxxPreProcessorScanner::ReadUntilMatch(int type, CxxLexerToken& token)
{
    while(m_scanner && ::LexerNext(m_scanner, token)) {
        if(token.GetType() == type) {
            return;
        } else if(token.GetType() == T_PP_STATE_EXIT) {
            throw CxxLexerException(wxString() << "Could not find a match for type: " << type);
        }
    }
    throw CxxLexerException(wxString() << "<<EOF>> Could not find a match for type: " << type);
}

bool CxxPreProcessorScanner::IsTokenExists(const CxxPreProcessorToken::Map_t& table, const CxxLexerToken& token)
{
    return table.count(token.GetWXString());
}