lexer.h 22 KB
Newer Older
1
/* This file is part of KDevelop
Ralf Habacker's avatar
Ralf Habacker committed
2
    Copyright (C) 2002, 2003 Roberto Raggi <roberto@kdevelop.org>
3
4
5
6
7
8
9
10
11
12
13
14

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
15
16
    along with this library; see the file COPYING.LIB.  If not, see
    <http://www.gnu.org/licenses/>.
17
18
19
20
21
*/

#ifndef LEXER_H
#define LEXER_H

22
23
24
#undef QT_NO_CAST_TO_ASCII
#undef QT_NO_CAST_FROM_ASCII

25
#include "driver.h"
Ralf Habacker's avatar
Ralf Habacker committed
26
#include "debug_utils.h"
27

28
29
30
31
32
#include <qglobal.h>
#include <QString>
#include <qmap.h>
#include <qpair.h>
#include <hashedstring.h>
33

34
#define CHARTYPE QChar
35
#define DBG_LEXER DEBUG(QLatin1String("Lexer"))
36

37
38
39
40
41
42
43
44
45
enum Type {
    Token_eof = 0,
    Token_identifier = 1000,
    Token_number_literal,
    Token_char_literal,
    Token_string_literal,
    Token_whitespaces,
    Token_comment,
    Token_preproc,
46

47
48
49
50
51
52
53
54
55
56
57
58
59
    Token_assign = 2000,
    Token_ptrmem,
    Token_ellipsis,
    Token_scope,
    Token_shift,
    Token_eq,
    Token_leq,
    Token_geq,
    Token_incr,
    Token_decr,
    Token_arrow,

    Token_concat,
60

61
62
63
    Token_K_DCOP,
    Token_k_dcop,
    Token_k_dcop_signals,
64

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
    Token_Q_OBJECT,
    Token_signals,
    Token_slots,
    Token_emit,
    Token_foreach, // qt4 [erbsland]

    Token_and,
    Token_and_eq,
    Token_asm,
    Token_auto,
    Token_bitand,
    Token_bitor,
    Token_bool,
    Token_break,
    Token_case,
    Token_catch,
    Token_char,
    Token_class,
    Token_compl,
    Token_const,
85
    Token_const_expr,
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
    Token_const_cast,
    Token_continue,
    Token_default,
    Token_delete,
    Token_do,
    Token_double,
    Token_dynamic_cast,
    Token_else,
    Token_enum,
    Token_explicit,
    Token_export,
    Token_extern,
    Token_false,
    Token_float,
    Token_for,
    Token_friend,
    Token_goto,
    Token_if,
    Token_inline,
    Token_int,
    Token_long,
    Token_mutable,
    Token_namespace,
    Token_new,
    Token_not,
    Token_not_eq,
    Token_operator,
    Token_or,
    Token_or_eq,
115
    Token_override,
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
    Token_private,
    Token_protected,
    Token_public,
    Token_register,
    Token_reinterpret_cast,
    Token_return,
    Token_short,
    Token_signed,
    Token_sizeof,
    Token_static,
    Token_static_cast,
    Token_struct,
    Token_switch,
    Token_template,
    Token_this,
    Token_throw,
    Token_true,
    Token_try,
    Token_typedef,
    Token_typeid,
    Token_typename,
    Token_union,
    Token_unsigned,
    Token_using,
    Token_virtual,
    Token_void,
    Token_volatile,
    Token_wchar_t,
    Token_while,
    Token_xor,
    Token_xor_eq
};
148

149
150
151
152
enum SkipType {
    SkipWord,
    SkipWordAndArguments
};
153

154
155
struct LexerData;

156
class Token
157
{
158
    explicit Token(const QString &);
159
160
161
162
163
164
165
    Token(int type, int position, int length, const QString& text);
    Token(const Token& source);

    Token& operator = (const Token& source);
    bool operator == (const Token& token) const;
    operator int () const;

166
public:
167
    bool isNull() const;
168

169
170
    int type() const;
    void setType(int type);
171

172
173
174
175
    void getStartPosition(int* line, int* column) const;
    void setStartPosition(int line, int column);
    void getEndPosition(int* line, int* column) const;
    void setEndPosition(int line, int column);
176

177
178
179
180
181
182
183
    unsigned int length() const;
    void setLength(unsigned int length);

    int position() const;
    void setPosition(int position);

    QString text() const;
184
185

private:
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
    int m_type;
    int m_position;
    int m_length;
    int m_startLine;
    int m_startColumn;
    int m_endLine;
    int m_endColumn;
    const QString & m_text;

    friend class Lexer;
    friend class Parser;
}; // class Token

class Lexer
{
public:
202
    explicit Lexer(Driver* driver);
203
204
    ~Lexer();

205
    bool recordComments() const;
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
    void setRecordComments(bool record);

    bool recordWhiteSpaces() const;
    void setRecordWhiteSpaces(bool record);

    bool reportWarnings() const;
    void setReportWarnings(bool enable);

    bool reportMessages() const;
    void setReportMessages(bool enable);

    bool skipWordsEnabled() const;
    void setSkipWordsEnabled(bool enabled);

    bool preprocessorEnabled() const;
    void setPreprocessorEnabled(bool enabled);

    void resetSkipWords();
Ralf Habacker's avatar
Ralf Habacker committed
224
    void addSkipWord(const QString& word, SkipType skipType=SkipWord, const QString& str = QString());
225
226
227
228
229
230
231
232
233

    QString source() const;
    void setSource(const QString& source);

    int index() const;
    void setIndex(int index);

    //returns the count of lines that wer skipped due to #ifdef's
    int skippedLines() const;
234

235
    void reset();
236
237
238
239
240
241
242
243
244
245

    const Token& tokenAt(int position) const;
    const Token& nextToken();
    const Token& lookAhead(int n) const;

    static int toInt(const Token& token);

    int tokenPosition(const Token& token) const;
    void getTokenPosition(const Token& token, int* line, int* col);

246
247
248
249
250
251
252
253
    int currentLine() const
    {
        return m_currentLine;
    }
    int currentColumn() const
    {
        return m_currentColumn;
    }
254

255
256
    inline const CHARTYPE* offset(int offset) const
    {
257
258
        Q_ASSERT(offset >= 0);
        Q_ASSERT(offset <= m_source.length());
259
260
261
        return m_source.unicode() + offset;
    }

262
263
    inline int getOffset(const QChar* p) const
    {
264
265
266
267
268
        const QChar* src = m_source.unicode();
        Q_ASSERT(p >= src);
        int result = int(p - src);
        Q_ASSERT(result <= m_source.length());
        return result;
269
    }
270

271
private:
272
273
274
275
276
277
278
    void setEndPtr(const QChar* c)
    {
        m_endPtr = c;
        if (m_ptr <  m_endPtr)
            m_currentChar = *m_ptr;
        else
            m_currentChar = 0;
279
280
281
282
    }
    const QChar currentChar() const;
    QChar peekChar(int n=1) const;
    int currentPosition() const;
283

284
    void insertCurrent(const QString& str);
285

286
287
288
289
290
291
292
293
294
295
296
297
    void tokenize();
    void nextToken(Token& token, bool stopOnNewline=false);
    void nextChar();
    void nextChar(int n);
    void skip(int l, int r);
    void readIdentifier();
    void readWhiteSpaces(bool skipNewLine=true, bool skipOnlyOnce=false);
    void readLineComment();
    void readMultiLineComment();
    void readCharLiteral();
    void readStringLiteral();
    void readNumberLiteral();
298

299
300
301
    int findOperator3() const;
    int findOperator2() const;
    bool eof() const;
302

303
304
305
306
    // preprocessor (based on an article of Al Stevens on Dr.Dobb's journal)
    int testIfLevel();
    int macroDefined();
    QString readArgument();
307

308
309
310
311
312
313
314
315
316
317
318
    int macroPrimary();
    int macroMultiplyDivide();
    int macroAddSubtract();
    int macroRelational();
    int macroEquality();
    int macroBoolAnd();
    int macroBoolXor();
    int macroBoolOr();
    int macroLogicalAnd();
    int macroLogicalOr();
    int macroExpression();
319

320
321
322
323
324
325
326
327
328
329
    void handleDirective(const QString& directive);
    void processDefine(Macro& macro);
    void processElse();
    void processElif();
    void processEndif();
    void processIf();
    void processIfdef();
    void processIfndef();
    void processInclude();
    void processUndef();
330

331
332
333
334
335
336
337
338
339
340
private:
    LexerData* d;
    Driver* m_driver;
    QVector<Token*> m_tokens;
    int m_size;
    int m_index;
    QString m_source;
    const QChar* m_ptr;
    const QChar* m_endPtr;
    QChar m_currentChar;
341
    bool m_recordComments;
342
343
    bool m_recordWhiteSpaces;
    bool m_startLine;
344
    QHash< HashedString, QPair<SkipType, QString> > m_words;
345

346

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
    int m_skippedLines;
    int m_currentLine;
    int m_currentColumn;
    bool m_skipWordsEnabled;

    // preprocessor
    QVector<bool> m_skipping;
    QVector<bool> m_trueTest;
    int m_ifLevel;
    bool m_preprocessorEnabled;
    bool m_inPreproc;

    bool m_reportWarnings;
    bool m_reportMessages;

private:
    Lexer(const Lexer& source);
    void operator = (const Lexer& source);
365
366
};

367

368
inline Token::Token(const QString & text)
369
370
371
    : m_type(-1),
      m_position(0),
      m_length(0),
372
373
374
375
      m_startLine(0),
      m_startColumn(0),
      m_endLine(0),
      m_endColumn(0),
376
377
378
379
380
381
382
383
      m_text(text)
{
}

inline Token::Token(int type, int position, int length, const QString& text)
    : m_type(type),
      m_position(position),
      m_length(length),
384
385
386
387
      m_startLine(0),
      m_startColumn(0),
      m_endLine(0),
      m_endColumn(0),
388
389
      m_text(text)
{
390
    DBG_LEXER << type << position << length << text.mid(position, length);
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
}

inline Token::Token(const Token& source)
    : m_type(source.m_type),
      m_position(source.m_position),
      m_length(source.m_length),
      m_startLine(source.m_startLine),
      m_startColumn(source.m_startColumn),
      m_endLine(source.m_endLine),
      m_endColumn(source.m_endColumn),
      m_text(source.m_text)
{
}

inline Token& Token::operator = (const Token& source)
{
    m_type = source.m_type;
    m_position = source.m_position;
    m_length = source.m_length;
    m_startLine = source.m_startLine;
    m_startColumn = source.m_startColumn;
    m_endLine = source.m_endLine;
    m_endColumn = source.m_endColumn;
//    m_text = source.m_text;
415
    return (*this);
416
417
418
419
420
421
422
423
424
425
}

inline Token::operator int () const
{
    return m_type;
}

inline bool Token::operator == (const Token& token) const
{
    return m_type == token.m_type &&
426
427
428
429
430
431
           m_position == token.m_position &&
           m_length == token.m_length &&
           m_startLine == token.m_startLine &&
           m_startColumn == token.m_startColumn &&
           m_endLine == token.m_endLine &&
           m_endColumn == token.m_endColumn &&
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
           m_text == token.m_text;
}

inline bool Token::isNull() const
{
    return m_type == Token_eof || m_length == 0;
}

inline int Token::type() const
{
    return m_type;
}

inline void Token::setType(int type)
{
    m_type = type;
}

inline int Token::position() const
{
    return m_position;
}

inline QString Token::text() const
{
    return m_text.mid(m_position, m_length);
}

inline void Token::setStartPosition(int line, int column)
{
    m_startLine = line;
    m_startColumn = column;
464
}
465
466
467
468
469
470
471
472
473

inline void Token::setEndPosition(int line, int column)
{
    m_endLine = line;
    m_endColumn = column;
}

inline void Token::getStartPosition(int* line, int* column) const
{
474
475
    if (line) *line = m_startLine;
    if (column) *column = m_startColumn;
476
477
478
479
}

inline void Token::getEndPosition(int* line, int* column) const
{
480
481
    if (line) *line = m_endLine;
    if (column) *column = m_endColumn;
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
}

inline void Token::setPosition(int position)
{
    m_position = position;
}

inline unsigned int Token::length() const
{
    return m_length;
}

inline void Token::setLength(unsigned int length)
{
    m_length = length;
}

499
500
inline bool Lexer::recordComments() const
{
501
    return m_recordComments;
502
503
}

504
inline void Lexer::setRecordComments(bool record)
505
506
{
    m_recordComments = record;
507
508
}

509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
inline bool Lexer::recordWhiteSpaces() const
{
    return m_recordWhiteSpaces;
}

inline void Lexer::setRecordWhiteSpaces(bool record)
{
    m_recordWhiteSpaces = record;
}

inline QString Lexer::source() const
{
    return m_source;
}

inline int Lexer::index() const
{
    return m_index;
}

inline void Lexer::setIndex(int index)
{
    m_index = index;
}

inline const Token& Lexer::nextToken()
{
536
    if (m_index < m_size)
537
538
539
540
541
542
543
544
545
546
547
548
        return *m_tokens[ m_index++ ];

    return *m_tokens[ m_index ];
}

inline const Token& Lexer::tokenAt(int n) const
{
    return *m_tokens[ qMin(n, m_size-1) ];
}

inline const Token& Lexer::lookAhead(int n) const
{
Ralf Habacker's avatar
Ralf Habacker committed
549
    Token &t = *m_tokens[ qMin(m_index + n, m_size-1) ];
550
    DBG_LEXER << t;
Ralf Habacker's avatar
Ralf Habacker committed
551
    return t;
552
553
554
555
556
557
558
559
560
}

inline int Lexer::tokenPosition(const Token& token) const
{
    return token.position();
}

inline void Lexer::nextChar()
{
561
562
563
564
    if (m_ptr >= m_endPtr) {
        m_currentChar = QChar();
        return;
    }
565
    if (*m_ptr == QLatin1Char('\n')) {
566
567
568
569
        ++m_currentLine;
        m_currentColumn = 0;
        m_startLine = true;
    } else {
570
        ++m_currentColumn;
571
572
573
    }
    ++m_ptr;

574
    if (m_ptr <  m_endPtr)
575
576
577
578
579
580
581
        m_currentChar = *m_ptr;
    else
        m_currentChar = QChar();
}

inline void Lexer::nextChar(int n)
{
582
583
584
585
586
    if (m_ptr + n >= m_endPtr) {
        m_ptr = m_endPtr;
        m_currentChar = QChar();
        return;
    }
587
588
    m_currentColumn += n;
    m_ptr += n;
589
590

    if (m_ptr <  m_endPtr)
591
592
593
594
595
596
597
        m_currentChar = *m_ptr;
    else
        m_currentChar = QChar();
}

inline void Lexer::readIdentifier()
{
598
    while (currentChar().isLetterOrNumber() || currentChar() == QLatin1Char('_'))
599
600
601
602
603
        nextChar();
}

inline void Lexer::readWhiteSpaces(bool skipNewLine, bool skipOnlyOnce)
{
604
    while (!currentChar().isNull()) {
605
606
        QChar ch = currentChar();

607
        if (ch == QLatin1Char('\n') && !skipNewLine) {
608
            break;
609
        } else if (ch.isSpace()) {
610
            nextChar();
611
        } else if (m_inPreproc && currentChar() == QLatin1Char('\\')) {
612
613
614
615
616
            nextChar();
            readWhiteSpaces(true, true);
        } else {
            break;
        }
617
        if (skipOnlyOnce && ch == QLatin1Char('\n')) {
618
            skipNewLine = false;
619
620
621
622
623
        }
    }
}

//little hack for better performance
624
625
626
inline bool isTodo(const QString& txt, int position)
{
    if (txt.length() < position + 4) return false;
627
628
629
630
    return (txt[ position ] == QLatin1Char('t') || txt[ position ] == QLatin1Char('T'))
           && (txt[ position+1 ] == QLatin1Char('o') || txt[ position+1 ] == QLatin1Char('O'))
           && (txt[ position+2 ] == QLatin1Char('d') || txt[ position+2 ] == QLatin1Char('D'))
           && (txt[ position+3 ] == QLatin1Char('o') || txt[ position+3 ] == QLatin1Char('O'));
631
632
}

633
634
635
inline bool isFixme(const QString& txt, int position)
{
    if (txt.length() < position + 5) return false;
636
637
638
639
640
    return (txt[ position ] == QLatin1Char('f') || txt[ position ] == QLatin1Char('F'))
           && (txt[ position+1 ] == QLatin1Char('i') || txt[ position+1 ] == QLatin1Char('I'))
           && (txt[ position+2 ] == QLatin1Char('x') || txt[ position+2 ] == QLatin1Char('X'))
           && (txt[ position+3 ] == QLatin1Char('m') || txt[ position+3 ] == QLatin1Char('M'))
           && (txt[ position+4 ] == QLatin1Char('e') || txt[ position+4 ] == QLatin1Char('E'));
641
642
643
644
}

inline void Lexer::readLineComment()
{
645
    while (!currentChar().isNull() && currentChar() != QLatin1Char('\n')) {
646
647
648
649
650
651
652
        if (m_reportMessages && isTodo(m_source, currentPosition())) {
            nextChar(4);
            QString msg;
            int line = m_currentLine;
            int col = m_currentColumn;

            while (!currentChar().isNull()) {
653
                if (currentChar() == QLatin1Char('*') && peekChar() == QLatin1Char('/'))
654
                    break;
655
                else if (currentChar() == QLatin1Char('\n'))
656
657
658
659
660
661
662
                    break;

                msg += currentChar();
                nextChar();
            }
            m_driver->addProblem(m_driver->currentFileName(), Problem(msg, line, col, Problem::Level_Todo));
        } else if (m_reportMessages && isFixme(m_source, currentPosition())) {
663
664
665
666
667
            nextChar(5);
            QString msg;
            int line = m_currentLine;
            int col = m_currentColumn;

668
            while (!currentChar().isNull()) {
669
                if (currentChar() == QLatin1Char('*') && peekChar() == QLatin1Char('/'))
670
                    break;
671
                else if (currentChar() == QLatin1Char('\n'))
672
                    break;
673

674
675
                msg += currentChar();
                nextChar();
676
677
678
679
680
681
682
683
684
            }
            m_driver->addProblem(m_driver->currentFileName(), Problem(msg, line, col, Problem::Level_Fixme));
        } else
            nextChar();
    }
}

inline void Lexer::readMultiLineComment()
{
685
    while (!currentChar().isNull()) {
686
        if (currentChar() == QLatin1Char('*') && peekChar() == QLatin1Char('/')) {
687
688
            nextChar(2);
            return;
689
690
691
692
693
694
695
        } else if (m_reportMessages && isTodo(m_source, currentPosition())) {
            nextChar(4);
            QString msg;
            int line = m_currentLine;
            int col = m_currentColumn;

            while (!currentChar().isNull()) {
696
                if (currentChar() == QLatin1Char('*') && peekChar() == QLatin1Char('/'))
697
                    break;
698
                else if (currentChar() == QLatin1Char('\n'))
699
700
701
702
703
704
                    break;
                msg += currentChar();
                nextChar();
            }
            m_driver->addProblem(m_driver->currentFileName(), Problem(msg, line, col, Problem::Level_Todo));
        } else if (m_reportMessages && isFixme(m_source, currentPosition())) {
705
706
707
708
709
            nextChar(5);
            QString msg;
            int line = m_currentLine;
            int col = m_currentColumn;

710
            while (!currentChar().isNull()) {
711
                if (currentChar() == QLatin1Char('*') && peekChar() == QLatin1Char('/'))
712
                    break;
713
                else if (currentChar() == QLatin1Char('\n'))
714
                    break;
715

716
717
                msg += currentChar();
                nextChar();
718
719
720
721
722
723
724
725
726
            }
            m_driver->addProblem(m_driver->currentFileName(), Problem(msg, line, col, Problem::Level_Fixme));
        } else
            nextChar();
    }
}

inline void Lexer::readCharLiteral()
{
727
    if (currentChar() == QLatin1Char('\''))
728
        nextChar(); // skip '
729
    else if (currentChar() == QLatin1Char('L') && peekChar() == QLatin1Char('\''))
730
        nextChar(2); // slip L'
731
732
733
    else
        return;

734
    while (!currentChar().isNull()) {
735
736
        int len = getOffset(m_endPtr) - currentPosition();

737
        if (len>=2 && (currentChar() == QLatin1Char('\\') && peekChar() == QLatin1Char('\''))) {
738
            nextChar(2);
739
        } else if (len>=2 && (currentChar() == QLatin1Char('\\') && peekChar() == QLatin1Char('\\'))) {
740
            nextChar(2);
741
        } else if (currentChar() == QLatin1Char('\'')) {
742
743
744
            nextChar();
            break;
        } else {
745
746
            nextChar();
        }
747
748
749
750
751
    }
}

inline void Lexer::readStringLiteral()
{
752
    if (currentChar() != QLatin1Char('"'))
753
754
755
756
        return;

    nextChar(); // skip "

757
    while (!currentChar().isNull()) {
758
759
        int len = getOffset(m_endPtr) - currentPosition();

760
        if (len>=2 && currentChar() == QLatin1Char('\\') && peekChar() == QLatin1Char('"')) {
761
            nextChar(2);
762
        } else if (len>=2 && currentChar() == QLatin1Char('\\') && peekChar() == QLatin1Char('\\')) {
763
            nextChar(2);
764
        } else if (currentChar() == QLatin1Char('"')) {
765
766
767
            nextChar();
            break;
        } else {
768
769
            nextChar();
        }
770
771
772
773
774
    }
}

inline void Lexer::readNumberLiteral()
{
775
    while (currentChar().isLetterOrNumber() || currentChar() == QLatin1Char('.'))
776
777
778
779
780
781
782
        nextChar();
}

inline int Lexer::findOperator3() const
{
    int n = getOffset(m_endPtr) - currentPosition();

783
    if (n >= 3) {
784
785
786
        char ch  = currentChar().toLatin1();
        char ch1 = peekChar().toLatin1();
        char ch2 = peekChar(2).toLatin1();
787

788
789
790
791
        if (ch == '<' && ch1 == '<' && ch2 == '=') return Token_assign;
        else if (ch == '>' && ch1 == '>' && ch2 == '=') return Token_assign;
        else if (ch == '-' && ch1 == '>' && ch2 == '*') return Token_ptrmem;
        else if (ch == '.' && ch1 == '.' && ch2 == '.') return Token_ellipsis;
792
793
794
795
796
797
798
799
800
    }

    return -1;
}

inline int Lexer::findOperator2() const
{
    int n = getOffset(m_endPtr) - currentPosition();

801
    if (n>=2) {
802
        char ch = currentChar().toLatin1(), ch1 = peekChar().toLatin1();
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825

        if (ch == ':' && ch1 == ':') return Token_scope;
        else if (ch == '.' && ch1 == '*') return Token_ptrmem;
        else if (ch == '+' && ch1 == '=') return Token_assign;
        else if (ch == '-' && ch1 == '=') return Token_assign;
        else if (ch == '*' && ch1 == '=') return Token_assign;
        else if (ch == '/' && ch1 == '=') return Token_assign;
        else if (ch == '%' && ch1 == '=') return Token_assign;
        else if (ch == '^' && ch1 == '=') return Token_assign;
        else if (ch == '&' && ch1 == '=') return Token_assign;
        else if (ch == '|' && ch1 == '=') return Token_assign;
        else if (ch == '<' && ch1 == '<') return Token_shift;
        //else if(ch == '>' && ch1 == '>') return Token_shift;
        else if (ch == '=' && ch1 == '=') return Token_eq;
        else if (ch == '!' && ch1 == '=') return Token_eq;
        else if (ch == '<' && ch1 == '=') return Token_leq;
        else if (ch == '>' && ch1 == '=') return Token_geq;
        else if (ch == '&' && ch1 == '&') return Token_and;
        else if (ch == '|' && ch1 == '|') return Token_or;
        else if (ch == '+' && ch1 == '+') return Token_incr;
        else if (ch == '-' && ch1 == '-') return Token_decr;
        else if (ch == '-' && ch1 == '>') return Token_arrow;
        else if (ch == '#' && ch1 == '#') return Token_concat;
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
    }

    return -1;
}

inline bool Lexer::skipWordsEnabled() const
{
    return m_skipWordsEnabled;
}

inline void Lexer::setSkipWordsEnabled(bool enabled)
{
    m_skipWordsEnabled = enabled;
}

inline bool Lexer::preprocessorEnabled() const
{
    return m_preprocessorEnabled;
}

inline void Lexer::setPreprocessorEnabled(bool enabled)
{
    m_preprocessorEnabled = enabled;
}

inline int Lexer::currentPosition() const
{
    return getOffset(m_ptr);
}

inline const QChar Lexer::currentChar() const
{
    return m_currentChar;
}

inline QChar Lexer::peekChar(int n) const
{
    const QChar* p = m_ptr + n;
864
865

    if (p <  m_endPtr)
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
        return *p;
    else
        return QChar();
}

inline bool Lexer::eof() const
{
    return m_ptr >= m_endPtr;
}

inline bool Lexer::reportWarnings() const
{
    return m_reportWarnings;
}

inline void Lexer::setReportWarnings(bool enable)
{
    m_reportWarnings = enable;
}

inline bool Lexer::reportMessages() const
{
    return m_reportMessages;
}

inline void Lexer::setReportMessages(bool enable)
{
    m_reportMessages = enable;
}

896
897
inline void Lexer::insertCurrent(const QString& str)
{
898
899
900
901
902
    int posi = currentPosition();
    m_source.insert(posi, str);

    m_ptr = offset(posi);
    m_endPtr = offset(m_source.length());
903
904
    if (m_ptr < m_endPtr)
        m_currentChar = *m_ptr;
905
    else
906
        m_currentChar = QChar();
907
908
}

909
#endif