OSDN Git Service

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