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

source code of qtquick3d/src/glslparser/glsllexer.cpp