OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / shared / cplusplus / Lexer.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32 // Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
33 //
34 // Permission is hereby granted, free of charge, to any person obtaining a copy
35 // of this software and associated documentation files (the "Software"), to deal
36 // in the Software without restriction, including without limitation the rights
37 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38 // copies of the Software, and to permit persons to whom the Software is
39 // furnished to do so, subject to the following conditions:
40 //
41 // The above copyright notice and this permission notice shall be included in
42 // all copies or substantial portions of the Software.
43 //
44 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
47 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
50 // THE SOFTWARE.
51
52 #include "Lexer.h"
53 #include "Control.h"
54 #include "TranslationUnit.h"
55 #include "Literals.h"
56 #include <cctype>
57 #include <cassert>
58
59 using namespace CPlusPlus;
60
61 Lexer::Lexer(TranslationUnit *unit)
62     : _translationUnit(unit),
63       _state(State_Default),
64       _flags(0),
65       _currentLine(1)
66 {
67     f._scanKeywords = true;
68     setSource(_translationUnit->firstSourceChar(),
69               _translationUnit->lastSourceChar());
70 }
71
72 Lexer::Lexer(const char *firstChar, const char *lastChar)
73     : _translationUnit(0),
74       _state(State_Default),
75       _flags(0),
76       _currentLine(1)
77 {
78     f._scanKeywords = true;
79     setSource(firstChar, lastChar);
80 }
81
82 Lexer::~Lexer()
83 { }
84
85 TranslationUnit *Lexer::translationUnit() const
86 { return _translationUnit; }
87
88 Control *Lexer::control() const
89 {
90     if (_translationUnit)
91         return _translationUnit->control();
92
93     return 0;
94 }
95
96 void Lexer::setSource(const char *firstChar, const char *lastChar)
97 {
98     _firstChar = firstChar;
99     _lastChar = lastChar;
100     _currentChar = _firstChar - 1;
101     _tokenStart = _currentChar;
102     _yychar = '\n';
103 }
104
105 void Lexer::setStartWithNewline(bool enabled)
106 {
107     if (enabled)
108         _yychar = '\n';
109     else
110         _yychar = ' ';
111 }
112
113 int Lexer::state() const
114 { return _state; }
115
116 void Lexer::setState(int state)
117 { _state = state; }
118
119 bool Lexer::qtMocRunEnabled() const
120 { return f._qtMocRunEnabled; }
121
122 void Lexer::setQtMocRunEnabled(bool onoff)
123 { f._qtMocRunEnabled = onoff; }
124
125 bool Lexer::cxx0xEnabled() const
126 { return f._cxx0xEnabled; }
127
128 void Lexer::setCxxOxEnabled(bool onoff)
129 { f._cxx0xEnabled = onoff; }
130
131 bool Lexer::objCEnabled() const
132 { return f._objCEnabled; }
133
134 void Lexer::setObjCEnabled(bool onoff)
135 { f._objCEnabled = onoff; }
136
137 bool Lexer::isIncremental() const
138 { return f._isIncremental; }
139
140 void Lexer::setIncremental(bool isIncremental)
141 { f._isIncremental = isIncremental; }
142
143 bool Lexer::scanCommentTokens() const
144 { return f._scanCommentTokens; }
145
146 void Lexer::setScanCommentTokens(bool onoff)
147 { f._scanCommentTokens = onoff; }
148
149 bool Lexer::scanKeywords() const
150 { return f._scanKeywords; }
151
152 void Lexer::setScanKeywords(bool onoff)
153 { f._scanKeywords = onoff; }
154
155 void Lexer::setScanAngleStringLiteralTokens(bool onoff)
156 { f._scanAngleStringLiteralTokens = onoff; }
157
158 void Lexer::pushLineStartOffset()
159 {
160     ++_currentLine;
161
162     if (_translationUnit)
163         _translationUnit->pushLineOffset(_currentChar - _firstChar);
164 }
165
166 unsigned Lexer::tokenOffset() const
167 { return _tokenStart - _firstChar; }
168
169 unsigned Lexer::tokenLength() const
170 { return _currentChar - _tokenStart; }
171
172 const char *Lexer::tokenBegin() const
173 { return _tokenStart; }
174
175 const char *Lexer::tokenEnd() const
176 { return _currentChar; }
177
178 unsigned Lexer::currentLine() const
179 { return _currentLine; }
180
181 void Lexer::scan(Token *tok)
182 {
183     tok->reset();
184     scan_helper(tok);
185     tok->f.length = _currentChar - _tokenStart;
186 }
187
188 void Lexer::scan_helper(Token *tok)
189 {
190   _Lagain:
191     while (_yychar && std::isspace(_yychar)) {
192         if (_yychar == '\n') {
193             tok->f.joined = false;
194             tok->f.newline = true;
195         } else {
196             tok->f.whitespace = true;
197         }
198         yyinp();
199     }
200
201     if (! _translationUnit)
202         tok->lineno = _currentLine;
203
204     _tokenStart = _currentChar;
205     tok->offset = _currentChar - _firstChar;
206
207     if (_state == State_MultiLineComment || _state == State_MultiLineDoxyComment) {
208         const int originalState = _state;
209
210         if (! _yychar) {
211             tok->f.kind = T_EOF_SYMBOL;
212             return;
213         }
214
215         while (_yychar) {
216             if (_yychar != '*')
217                 yyinp();
218             else {
219                 yyinp();
220                 if (_yychar == '/') {
221                     yyinp();
222                     _state = State_Default;
223                     break;
224                 }
225             }
226         }
227
228         if (! f._scanCommentTokens)
229             goto _Lagain;
230
231         else if (originalState == State_MultiLineComment)
232             tok->f.kind = T_COMMENT;
233         else
234             tok->f.kind = T_DOXY_COMMENT;
235         return; // done
236     }
237
238     if (! _yychar) {
239         tok->f.kind = T_EOF_SYMBOL;
240         return;
241     }
242
243     unsigned char ch = _yychar;
244     yyinp();
245
246     switch (ch) {
247     case '\\':
248         while (_yychar != '\n' && std::isspace(_yychar))
249             yyinp();
250         // ### assert(! _yychar || _yychar == '\n');
251         if (_yychar == '\n') {
252             tok->f.joined = true;
253             tok->f.newline = false;
254             yyinp();
255         }
256         goto _Lagain;
257
258     case '"': case '\'': {
259         const char quote = ch;
260
261         tok->f.kind = quote == '"'
262             ? T_STRING_LITERAL
263             : T_CHAR_LITERAL;
264
265         const char *yytext = _currentChar;
266
267         while (_yychar && _yychar != quote) {
268             if (_yychar == '\n')
269                 break;
270             else if (_yychar != '\\')
271                 yyinp();
272             else {
273                 yyinp(); // skip `\\'
274
275                 if (_yychar)
276                     yyinp();
277             }
278         }
279         // assert(_yychar == quote);
280
281         int yylen = _currentChar - yytext;
282
283         if (_yychar == quote)
284             yyinp();
285
286         if (control())
287             tok->string = control()->stringLiteral(yytext, yylen);
288     } break;
289
290     case '{':
291         tok->f.kind = T_LBRACE;
292         break;
293
294     case '}':
295         tok->f.kind = T_RBRACE;
296         break;
297
298     case '[':
299         tok->f.kind = T_LBRACKET;
300         break;
301
302     case ']':
303         tok->f.kind = T_RBRACKET;
304         break;
305
306     case '#':
307         if (_yychar == '#') {
308             tok->f.kind = T_POUND_POUND;
309             yyinp();
310         } else {
311             tok->f.kind = T_POUND;
312         }
313         break;
314
315     case '(':
316         tok->f.kind = T_LPAREN;
317         break;
318
319     case ')':
320         tok->f.kind = T_RPAREN;
321         break;
322
323     case ';':
324         tok->f.kind = T_SEMICOLON;
325         break;
326
327     case ':':
328         if (_yychar == ':') {
329             yyinp();
330             tok->f.kind = T_COLON_COLON;
331         } else {
332             tok->f.kind = T_COLON;
333         }
334         break;
335
336     case '.':
337         if (_yychar == '*') {
338             yyinp();
339             tok->f.kind = T_DOT_STAR;
340         } else if (_yychar == '.') {
341             yyinp();
342             // ### assert(_yychar);
343             if (_yychar == '.') {
344                 yyinp();
345                 tok->f.kind = T_DOT_DOT_DOT;
346             } else {
347                 tok->f.kind = T_ERROR;
348             }
349         } else if (std::isdigit(_yychar)) {
350             const char *yytext = _currentChar - 2;
351             do {
352                 if (_yychar == 'e' || _yychar == 'E') {
353                     yyinp();
354                     if (_yychar == '-' || _yychar == '+') {
355                         yyinp();
356                         // ### assert(std::isdigit(_yychar));
357                     }
358                 } else if (std::isalnum(_yychar) || _yychar == '.') {
359                     yyinp();
360                 } else {
361                     break;
362                 }
363             } while (_yychar);
364             int yylen = _currentChar - yytext;
365             tok->f.kind = T_NUMERIC_LITERAL;
366             if (control())
367                 tok->number = control()->numericLiteral(yytext, yylen);
368         } else {
369             tok->f.kind = T_DOT;
370         }
371         break;
372
373     case '?':
374         tok->f.kind = T_QUESTION;
375         break;
376
377     case '+':
378         if (_yychar == '+') {
379             yyinp();
380             tok->f.kind = T_PLUS_PLUS;
381         } else if (_yychar == '=') {
382             yyinp();
383             tok->f.kind = T_PLUS_EQUAL;
384         } else {
385             tok->f.kind = T_PLUS;
386         }
387         break;
388
389     case '-':
390         if (_yychar == '-') {
391             yyinp();
392             tok->f.kind = T_MINUS_MINUS;
393         } else if (_yychar == '=') {
394             yyinp();
395             tok->f.kind = T_MINUS_EQUAL;
396         } else if (_yychar == '>') {
397             yyinp();
398             if (_yychar == '*') {
399                 yyinp();
400                 tok->f.kind = T_ARROW_STAR;
401             } else {
402                 tok->f.kind = T_ARROW;
403             }
404         } else {
405             tok->f.kind = T_MINUS;
406         }
407         break;
408
409     case '*':
410         if (_yychar == '=') {
411             yyinp();
412             tok->f.kind = T_STAR_EQUAL;
413         } else {
414             tok->f.kind = T_STAR;
415         }
416         break;
417
418     case '/':
419         if (_yychar == '/') {
420             yyinp();
421
422             bool doxy = false;
423
424             if (_yychar == '/' || _yychar == '!') {
425                 yyinp();
426
427                 if (_yychar == '<')
428                     yyinp();
429
430                 if (_yychar != '\n' && std::isspace(_yychar))
431                     doxy = true;
432             }
433
434             while (_yychar && _yychar != '\n')
435                 yyinp();
436
437             if (! f._scanCommentTokens)
438                 goto _Lagain;
439
440             tok->f.kind = doxy ? T_CPP_DOXY_COMMENT : T_CPP_COMMENT;
441
442         } else if (_yychar == '*') {
443             yyinp();
444
445             bool doxy = false;
446
447             if (_yychar == '*' || _yychar == '!') {
448                 const char ch = _yychar;
449
450                 yyinp();
451
452                 if (ch == '*' && _yychar == '/')
453                     goto _Ldone;
454
455                 if (_yychar == '<')
456                     yyinp();
457
458                 if (! _yychar || std::isspace(_yychar))
459                     doxy = true;
460             }
461
462             while (_yychar) {
463                 if (_yychar != '*') {
464                     yyinp();
465                 } else {
466                     yyinp();
467                     if (_yychar == '/')
468                         break;
469                 }
470             }
471
472         _Ldone:
473             if (_yychar)
474                 yyinp();
475             else
476                 _state = doxy ? State_MultiLineDoxyComment : State_MultiLineComment;
477
478             if (! f._scanCommentTokens)
479                 goto _Lagain;
480
481             tok->f.kind = doxy ? T_DOXY_COMMENT : T_COMMENT;
482
483         } else if (_yychar == '=') {
484             yyinp();
485             tok->f.kind = T_SLASH_EQUAL;
486         } else {
487             tok->f.kind = T_SLASH;
488         }
489         break;
490
491     case '%':
492         if (_yychar == '=') {
493             yyinp();
494             tok->f.kind = T_PERCENT_EQUAL;
495         } else {
496             tok->f.kind = T_PERCENT;
497         }
498         break;
499
500     case '^':
501         if (_yychar == '=') {
502             yyinp();
503             tok->f.kind = T_CARET_EQUAL;
504         } else {
505             tok->f.kind = T_CARET;
506         }
507         break;
508
509     case '&':
510         if (_yychar == '&') {
511             yyinp();
512             tok->f.kind = T_AMPER_AMPER;
513         } else if (_yychar == '=') {
514             yyinp();
515             tok->f.kind = T_AMPER_EQUAL;
516         } else {
517             tok->f.kind = T_AMPER;
518         }
519         break;
520
521     case '|':
522         if (_yychar == '|') {
523             yyinp();
524             tok->f.kind = T_PIPE_PIPE;
525         } else if (_yychar == '=') {
526             yyinp();
527             tok->f.kind = T_PIPE_EQUAL;
528         } else {
529             tok->f.kind = T_PIPE;
530         }
531         break;
532
533     case '~':
534         if (_yychar == '=') {
535             yyinp();
536             tok->f.kind = T_TILDE_EQUAL;
537         } else {
538             tok->f.kind = T_TILDE;
539         }
540         break;
541
542     case '!':
543         if (_yychar == '=') {
544             yyinp();
545             tok->f.kind = T_EXCLAIM_EQUAL;
546         } else {
547             tok->f.kind = T_EXCLAIM;
548         }
549         break;
550
551     case '=':
552         if (_yychar == '=') {
553             yyinp();
554             tok->f.kind = T_EQUAL_EQUAL;
555         } else {
556             tok->f.kind = T_EQUAL;
557         }
558         break;
559
560     case '<':
561         if (f._scanAngleStringLiteralTokens) {
562             const char *yytext = _currentChar;
563             while (_yychar && _yychar != '>')
564                 yyinp();
565             int yylen = _currentChar - yytext;
566             // ### assert(_yychar == '>');
567             if (_yychar == '>')
568                 yyinp();
569             if (control())
570                 tok->string = control()->stringLiteral(yytext, yylen);
571             tok->f.kind = T_ANGLE_STRING_LITERAL;
572         } else if (_yychar == '<') {
573             yyinp();
574             if (_yychar == '=') {
575                 yyinp();
576                 tok->f.kind = T_LESS_LESS_EQUAL;
577             } else
578                 tok->f.kind = T_LESS_LESS;
579         } else if (_yychar == '=') {
580             yyinp();
581             tok->f.kind = T_LESS_EQUAL;
582         } else {
583             tok->f.kind = T_LESS;
584         }
585         break;
586
587     case '>':
588         if (_yychar == '>') {
589             yyinp();
590             if (_yychar == '=') {
591                 yyinp();
592                 tok->f.kind = T_GREATER_GREATER_EQUAL;
593             } else
594                 tok->f.kind = T_LESS_LESS;
595             tok->f.kind = T_GREATER_GREATER;
596         } else if (_yychar == '=') {
597             yyinp();
598             tok->f.kind = T_GREATER_EQUAL;
599         } else {
600             tok->f.kind = T_GREATER;
601         }
602         break;
603
604     case ',':
605         tok->f.kind = T_COMMA;
606         break;
607
608     default: {
609         if (f._objCEnabled) {
610             if (ch == '@' && _yychar >= 'a' && _yychar <= 'z') {
611                 const char *yytext = _currentChar;
612
613                 do {
614                     yyinp();
615                     if (! (isalnum(_yychar) || _yychar == '_' || _yychar == '$'))
616                         break;
617                 } while (_yychar);
618
619                 const int yylen = _currentChar - yytext;
620                 tok->f.kind = classifyObjCAtKeyword(yytext, yylen);
621                 break;
622             } else if (ch == '@' && _yychar == '"') {
623                 // objc @string literals
624                 ch = _yychar;
625                 yyinp();
626                 tok->f.kind = T_AT_STRING_LITERAL;
627
628                 const char *yytext = _currentChar;
629
630                 while (_yychar && _yychar != '"') {
631                     if (_yychar != '\\')
632                         yyinp();
633                     else {
634                         yyinp(); // skip `\\'
635
636                         if (_yychar)
637                             yyinp();
638                     }
639                 }
640                 // assert(_yychar == '"');
641
642                 int yylen = _currentChar - yytext;
643
644                 if (_yychar == '"')
645                     yyinp();
646
647                 if (control())
648                     tok->string = control()->stringLiteral(yytext, yylen);
649
650                 break;
651             }
652         }
653
654         if (ch == 'L' && (_yychar == '"' || _yychar == '\'')) {
655             // wide char/string literals
656             ch = _yychar;
657             yyinp();
658
659             const char quote = ch;
660
661             tok->f.kind = quote == '"'
662                 ? T_WIDE_STRING_LITERAL
663                 : T_WIDE_CHAR_LITERAL;
664
665             const char *yytext = _currentChar;
666
667             while (_yychar && _yychar != quote) {
668                 if (_yychar != '\\')
669                     yyinp();
670                 else {
671                     yyinp(); // skip `\\'
672
673                     if (_yychar)
674                         yyinp();
675                 }
676             }
677             // assert(_yychar == quote);
678
679             int yylen = _currentChar - yytext;
680
681             if (_yychar == quote)
682                 yyinp();
683
684             if (control())
685                 tok->string = control()->stringLiteral(yytext, yylen);
686         } else if (std::isalpha(ch) || ch == '_' || ch == '$') {
687             const char *yytext = _currentChar - 1;
688             while (std::isalnum(_yychar) || _yychar == '_' || _yychar == '$')
689                 yyinp();
690             int yylen = _currentChar - yytext;
691             if (f._scanKeywords)
692                 tok->f.kind = classify(yytext, yylen, f._qtMocRunEnabled, f._cxx0xEnabled);
693             else
694                 tok->f.kind = T_IDENTIFIER;
695
696             if (tok->f.kind == T_IDENTIFIER) {
697                 tok->f.kind = classifyOperator(yytext, yylen);
698
699                 if (control())
700                     tok->identifier = control()->identifier(yytext, yylen);
701             }
702             break;
703         } else if (std::isdigit(ch)) {
704             const char *yytext = _currentChar - 1;
705             while (_yychar) {
706                 if (_yychar == 'e' || _yychar == 'E') {
707                     yyinp();
708                     if (_yychar == '-' || _yychar == '+') {
709                         yyinp();
710                         // ### assert(std::isdigit(_yychar));
711                     }
712                 } else if (std::isalnum(_yychar) || _yychar == '.') {
713                     yyinp();
714                 } else {
715                     break;
716                 }
717             }
718             int yylen = _currentChar - yytext;
719             tok->f.kind = T_NUMERIC_LITERAL;
720             if (control())
721                 tok->number = control()->numericLiteral(yytext, yylen);
722             break;
723         } else {
724             tok->f.kind = T_ERROR;
725             break;
726         }
727     } // default
728
729     } // switch
730 }
731
732