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