1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "glsllexer.h"
27 #include "glslparser.h"
28 #include "glslengine.h"
29 #include <qbytearray.h>
30 #include <cctype>
31 #include <iostream>
32 #include <cstdio>
33 
34 using namespace GLSL;
35 
Lexer(Engine * engine,const char * source,unsigned size)36 Lexer::Lexer(Engine *engine, const char *source, unsigned size)
37     : _engine(engine),
38       _source(source),
39       _it(source),
40       _size(size),
41       _yychar('\n'),
42       _lineno(0),
43       _state(0),
44       _variant(Variant_Mask & ~Variant_Reserved), // everything except reserved
45       _scanKeywords(true),
46       _scanComments(false)
47 {
48 }
49 
~Lexer()50 Lexer::~Lexer()
51 {
52 }
53 
yyinp()54 void Lexer::yyinp()
55 {
56     _yychar = (unsigned char) *_it++;
57     if (_yychar == '\n')
58         ++_lineno;
59 }
60 
yylex(Token * tk)61 int Lexer::yylex(Token *tk)
62 {
63     const char *pos = nullptr;
64     int line = 0;
65     _yyval.ptr = nullptr;
66     const int kind = yylex_helper(&pos, &line);
67     tk->kind = kind;
68     tk->position = pos - _source;
69     tk->length = _it - pos - 1;
70     tk->line = line;
71     tk->ptr = _yyval.ptr;
72     return kind;
73 }
74 
75 enum {
76     State_normal,
77     State_comment
78 };
79 
yylex_helper(const char ** position,int * line)80 int Lexer::yylex_helper(const char **position, int *line)
81 {
82     again:
83         while (std::isspace(_yychar))
84       yyinp();
85 
86     *position = _it - 1;
87     *line = _lineno;
88 
89     if (_yychar == 0)
90         return Parser::EOF_SYMBOL;
91 
92     if (_state == State_comment) {
93         while (_yychar) {
94             if (_yychar == '*') {
95                 yyinp();
96                 if (_yychar == '/') {
97                     yyinp();
98                     _state = State_normal;
99                     break;
100                 }
101             } else {
102                 yyinp();
103             }
104         }
105         return Parser::T_COMMENT;
106     }
107 
108     const int ch = _yychar;
109     yyinp();
110 
111     switch (ch) {
112     case '#':
113         for (; _yychar; yyinp()) {
114             if (_yychar == '\n')
115                 break;
116         }
117         goto again;
118 
119         // one of `!', `!='
120     case '!':
121         if (_yychar == '=') {
122             yyinp();
123             return Parser::T_NE_OP;
124         }
125         return Parser::T_BANG;
126 
127         // one of
128         //  %
129         //  %=
130     case '%':
131         if (_yychar == '=') {
132             yyinp();
133             return Parser::T_MOD_ASSIGN;
134         }
135         return Parser::T_PERCENT;
136 
137         // one of
138         // &
139         // &&
140         // &=
141     case '&':
142         if (_yychar == '=') {
143             yyinp();
144             return Parser::T_AND_ASSIGN;
145         } else if (_yychar == '&') {
146             yyinp();
147             return Parser::T_AND_OP;
148         }
149         return Parser::T_AMPERSAND;
150 
151         // (
152     case '(':
153         return Parser::T_LEFT_PAREN;
154 
155         // )
156     case ')':
157         return Parser::T_RIGHT_PAREN;
158 
159         // one of
160         // *
161         // *=
162     case '*':
163         if (_yychar == '=') {
164             yyinp();
165             return Parser::T_MUL_ASSIGN;
166         }
167         return Parser::T_STAR;
168 
169         // one of
170         // ++
171         // +=
172         // +
173     case '+':
174         if (_yychar == '=') {
175             yyinp();
176             return Parser::T_ADD_ASSIGN;
177         } else if (_yychar == '+') {
178             yyinp();
179             return Parser::T_INC_OP;
180         }
181         return Parser::T_PLUS;
182 
183         // ,
184     case ',':
185         return Parser::T_COMMA;
186 
187         // one of
188         // -
189         // --
190         // -=
191     case '-':
192         if (_yychar == '=') {
193             yyinp();
194             return Parser::T_SUB_ASSIGN;
195         } else if (_yychar == '-') {
196             yyinp();
197             return Parser::T_DEC_OP;
198         }
199         return Parser::T_DASH;
200 
201         // one of
202         // .
203         // float constant
204     case '.':
205         if (std::isdigit(_yychar)) {
206             const char *word = _it - 2;
207             while (std::isalnum(_yychar)) {
208                 yyinp();
209             }
210             if (_engine)
211                 _yyval.string = _engine->number(word, _it - word - 1);
212             return Parser::T_NUMBER;
213         }
214         return Parser::T_DOT;
215 
216         // one of
217         // /
218         // /=
219         // comment
220     case '/':
221         if (_yychar == '/') {
222             for (; _yychar; yyinp()) {
223                 if (_yychar == '\n')
224                     break;
225             }
226             if (_scanComments)
227                 return Parser::T_COMMENT;
228             goto again;
229         } else if (_yychar == '*') {
230             yyinp();
231             while (_yychar) {
232                 if (_yychar == '*') {
233                     yyinp();
234                     if (_yychar == '/') {
235                         yyinp();
236                         if (_scanComments)
237                             return Parser::T_COMMENT;
238                         goto again;
239                     }
240                 } else {
241                     yyinp();
242                 }
243             }
244             if (_scanComments) {
245                 _state = State_comment;
246                 return Parser::T_COMMENT;
247             }
248             goto again;
249         } else if (_yychar == '=') {
250             yyinp();
251             return Parser::T_DIV_ASSIGN;
252         }
253         return Parser::T_SLASH;
254 
255         // :
256     case ':':
257         return Parser::T_COLON;
258 
259         // ;
260     case ';':
261         return Parser::T_SEMICOLON;
262 
263         // one of
264         // <
265         // <=
266         // <<
267         // <<=
268     case '<':
269         if (_yychar == '=') {
270             yyinp();
271             return Parser::T_LE_OP;
272         } else if (_yychar == '<') {
273             yyinp();
274             if (_yychar == '=') {
275                 yyinp();
276                 return Parser::T_LEFT_ASSIGN;
277             }
278             return Parser::T_LEFT_OP;
279         }
280         return Parser::T_LEFT_ANGLE;
281 
282         // one of
283         // =
284         // ==
285     case '=':
286         if (_yychar == '=') {
287             yyinp();
288             return Parser::T_EQ_OP;
289         }
290         return Parser::T_EQUAL;
291 
292         // one of
293         // >
294         // >=
295         // >>=
296         // >>
297     case '>':
298         if (_yychar == '=') {
299             yyinp();
300             return Parser::T_GE_OP;
301         } else if (_yychar == '>') {
302             yyinp();
303             if (_yychar == '=') {
304                 yyinp();
305                 return Parser::T_RIGHT_ASSIGN;
306             }
307             return Parser::T_RIGHT_OP;
308         }
309         return Parser::T_RIGHT_ANGLE;
310 
311         // ?
312     case '?':
313         return Parser::T_QUESTION;
314 
315         // [
316     case '[':
317         return Parser::T_LEFT_BRACKET;
318 
319         // ]
320     case ']':
321         return Parser::T_RIGHT_BRACKET;
322 
323         // one of
324         // ^
325         // ^=
326     case '^':
327         if (_yychar == '=') {
328             yyinp();
329             return Parser::T_XOR_ASSIGN;
330         } else if (_yychar == '^') {
331             yyinp();
332             return Parser::T_XOR_OP;
333         }
334         return Parser::T_CARET;
335 
336         // {
337     case '{':
338         return Parser::T_LEFT_BRACE;
339 
340         // one of
341         // |
342         // |=
343         // ||
344     case '|':
345         if (_yychar == '=') {
346             yyinp();
347             return Parser::T_OR_ASSIGN;
348         } else if (_yychar == '|') {
349             yyinp();
350             return Parser::T_OR_OP;
351         }
352         return Parser::T_VERTICAL_BAR;
353 
354         // }
355     case '}':
356         return Parser::T_RIGHT_BRACE;
357 
358         // ~
359     case '~':
360         return Parser::T_TILDE;
361 
362     default:
363         if (std::isalpha(ch) || ch == '_') {
364             const char *word = _it - 2;
365             while (std::isalnum(_yychar) || _yychar == '_') {
366                 yyinp();
367             }
368             if (_scanKeywords) {
369                 const int k = findKeyword(word, _it - word - 1);
370 
371                 if (k != Parser::T_IDENTIFIER)
372                     return k;
373             }
374             if (_engine)
375                 _yyval.string = _engine->identifier(word, _it - word - 1);
376             return Parser::T_IDENTIFIER;
377         } else if (std::isdigit(ch)) {
378             const char *word = _it - 2;
379             while (std::isalnum(_yychar) || _yychar == '.') {
380                 yyinp();
381             }
382             if (_engine)
383                 _yyval.string = _engine->number(word, _it - word - 1);
384             return Parser::T_NUMBER;
385         }
386 
387     } // switch
388 
389     return Parser::T_ERROR;
390 }
391 
findKeyword(const char * word,int length) const392 int Lexer::findKeyword(const char *word, int length) const
393 {
394     int t = classify(word, length);
395     if (!(t & Variant_Mask))
396         return t;
397     if ((_variant & t & Variant_Mask) == 0) {
398         // Return a "reserved word" token if this keyword is not permitted
399         // in the current language variant so that the syntax highlighter
400         // can warn the user about the word.
401         if (!_scanKeywords)
402             return Parser::T_GLRESERVED;
403     }
404     return t & ~Variant_Mask;
405 }
406 
warning(int line,const QString & message)407 void Lexer::warning(int line, const QString &message)
408 {
409     _engine->warning(line, message);
410 }
411 
error(int line,const QString & message)412 void Lexer::error(int line, const QString &message)
413 {
414     _engine->error(line, message);
415 }
416