Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
recognizer.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3// Qt-Security score:insignificant reason:build-tool
4
5#include "recognizer.h"
6
7#include <QtCore/qdir.h>
8
9#include <cstdlib>
10#include <cstring>
11#include <cctype>
12
13using namespace Qt::StringLiterals;
14
15Recognizer::Recognizer (Grammar *grammar, bool no_lines):
16 tos(0),
17 stack_size(0),
18 state_stack(nullptr),
19 _M_line(1),
20 _M_action_line(0),
21 _M_grammar(grammar),
22 _M_no_lines(no_lines)
23{
24}
25
26Recognizer::~Recognizer()
27{
28 if (stack_size)
29 ::free(state_stack);
30}
31
32inline void Recognizer::reallocateStack()
33{
34 if (! stack_size)
35 stack_size = 128;
36 else
37 stack_size <<= 1;
38
39 sym_stack.resize (stack_size);
40
41 if (! state_stack)
42 state_stack = reinterpret_cast<int*> (::malloc(stack_size * sizeof(int)));
43 else
44 state_stack = reinterpret_cast<int*> (::realloc(state_stack, stack_size * sizeof(int)));
45}
46
47int Recognizer::nextToken()
48{
49 QString text;
50
51 Lagain:
52 while (ch.isSpace ())
53 inp ();
54
55 if (ch.isNull ())
56 return EOF_SYMBOL;
57
58 int token = ch.unicode ();
59
60 if (token == '"')
61 {
62 inp(); // skip "
63 text.clear ();
64 while (!ch.isNull () && ch != u'"')
65 {
66 if (ch == u'\\')
67 {
68 text += ch;
69 inp();
70 }
71 text += ch;
72 inp ();
73 }
74
75 if (ch == u'"')
76 inp ();
77 else
78 qerr() << _M_input_file << ":" << _M_line << ": Warning. Expected `\"'" << Qt::endl;
79
80 _M_current_value = text;
81 return (token = STRING_LITERAL);
82 }
83
84 else if (ch.isLetterOrNumber () || ch == u'_')
85 {
86 text.clear ();
87 do { text += ch; inp (); }
88 while (ch.isLetterOrNumber () || ch == u'_' || ch == u'.');
89 _M_current_value = text;
90 return (token = ID);
91 }
92
93 else if (token == '%')
94 {
95 text.clear ();
96
97 do { inp (); }
98 while (ch.isSpace ());
99
100 do { text += ch; inp (); }
101 while (ch.isLetterOrNumber () || ch == u'_' || ch == u'-');
102
103 if (text == "token_prefix"_L1)
104 return (token = TOKEN_PREFIX);
105 else if (text == "merged_output"_L1)
106 return (token = MERGED_OUTPUT);
107 else if (text == "token"_L1)
108 return (token = TOKEN);
109 else if (text == "start"_L1)
110 return (token = START);
111 else if (text == "parser"_L1)
112 return (token = PARSER);
113 else if (text == "decl"_L1)
114 return (token = DECL_FILE);
115 else if (text == "impl"_L1)
116 return (token = IMPL_FILE);
117 else if (text == "expect"_L1)
118 return (token = EXPECT);
119 else if (text == "expect-rr"_L1)
120 return (token = EXPECT_RR);
121 else if (text == "left"_L1)
122 return (token = LEFT);
123 else if (text == "right"_L1)
124 return (token = RIGHT);
125 else if (text == "nonassoc"_L1)
126 return (token = NONASSOC);
127 else if (text == "prec"_L1)
128 return (token = PREC);
129 else
130 {
131 qerr() << _M_input_file << ":" << _M_line << ": Unknown keyword `" << text << "'" << Qt::endl;
132 exit (EXIT_FAILURE);
133 return (token = ERROR);
134 }
135 }
136
137 inp ();
138
139 if (token == '-' && ch == u'-')
140 {
141 do { inp (); }
142 while (!ch.isNull () && ch != u'\n');
143 goto Lagain;
144 }
145
146 else if (token == ':' && ch == u':')
147 {
148 inp ();
149 if (ch != u'=')
150 return (token = ERROR);
151 inp ();
152 return (token = COLON);
153 }
154
155 else if (token == '/' && ch == u':')
156 {
157 _M_action_line = _M_line;
158
159 text.clear ();
160 if (! _M_no_lines)
161 text += "\n#line "_L1 + QString::number(_M_action_line) +
162 " \""_L1 + QDir::fromNativeSeparators(_M_input_file) + "\"\n"_L1;
163 inp (); // skip ':'
164
165 forever
166 {
167 while (! ch.isNull ())
168 {
169 token = ch.unicode ();
170 inp ();
171
172 if (token == ':' && ch == u'/')
173 break;
174
175 text += QLatin1Char (token);
176 }
177
178 if (ch != u'/')
179 return (token = ERROR);
180
181 inp ();
182
183 if (ch.isNull () || ch.isSpace ())
184 {
185 _M_current_value = text;
186 return (token = DECL);
187 }
188 else
189 text += ":/"_L1;
190 }
191 }
192
193 else if (token == '/' && ch == u'.')
194 {
195 _M_action_line = _M_line;
196
197 text.clear ();
198 if (! _M_no_lines)
199 text += "\n#line "_L1 + QString::number(_M_action_line) +
200 " \""_L1 + QDir::fromNativeSeparators(_M_input_file) + "\"\n"_L1;
201
202 inp (); // skip ':'
203
204 forever
205 {
206 while (! ch.isNull ())
207 {
208 token = ch.unicode ();
209 inp ();
210
211 if (token == '.' && ch == u'/')
212 break;
213
214 text += QLatin1Char (token);
215 }
216
217 if (ch != u'/')
218 return (token = ERROR);
219
220 inp ();
221
222 if (ch.isNull () || ch.isSpace ())
223 {
224 _M_current_value = text;
225 return (token = IMPL);
226 }
227 else
228 text += ""_L1;
229 }
230 }
231
232 switch (token) {
233 case ':':
234 return (token = COLON);
235
236 case ';':
237 return (token = SEMICOLON);
238
239 case '|':
240 return (token = OR);
241
242 default:
243 break;
244 }
245
246 return token;
247}
248
249bool Recognizer::parse (const QString &input_file)
250{
251 _M_input_file = input_file;
252
253 QFile file(_M_input_file);
254 if (! file.open(QFile::ReadOnly))
255 {
256 qerr() << "qlalr: no input file\n";
257 return false;
258 }
259
260 QString _M_contents = QTextStream(&file).readAll();
261 _M_firstChar = _M_contents.constBegin();
262 _M_lastChar = _M_contents.constEnd();
263 _M_currentChar = _M_firstChar;
264 _M_line = 1;
265
266 int yytoken = -1;
267 inp ();
268
269 reallocateStack();
270
271 _M_current_rule = _M_grammar->rules.end ();
272 _M_decls.clear ();
273 _M_impls.clear ();
274
275 tos = 0;
276 state_stack[++tos] = 0;
277
278 while (true)
279 {
280 if (yytoken == -1 && - TERMINAL_COUNT != action_index [state_stack [tos]])
281 yytoken = nextToken();
282
283 int act = t_action (state_stack [tos], yytoken);
284
285 if (act == ACCEPT_STATE)
286 return true;
287
288 else if (act > 0)
289 {
290 if (++tos == stack_size)
291 reallocateStack();
292
293 sym_stack [tos] = _M_current_value;
294 state_stack [tos] = act;
295 yytoken = -1;
296 }
297
298 else if (act < 0)
299 {
300 int r = - act - 1;
301
302 tos -= rhs [r];
303 act = state_stack [tos++];
304
305 switch (r) {
306
307case 3: {
308 Name name = _M_grammar->intern (sym(2));
309 _M_grammar->start = name;
310 _M_grammar->non_terminals.insert (name);
311} break;
312
313case 5: {
314 _M_grammar->table_name = sym(2);
315} break;
316
317case 6: {
318 _M_grammar->merged_output = sym(2);
319} break;
320
321case 7: {
322 _M_grammar->decl_file_name = sym(2);
323} break;
324
325case 8: {
326 _M_grammar->impl_file_name = sym(2);
327} break;
328
329case 9: {
330 _M_grammar->expected_shift_reduce = sym(2).toInt();
331} break;
332
333case 10: {
334 _M_grammar->expected_reduce_reduce = sym(2).toInt();
335} break;
336
337case 11: {
338 _M_grammar->token_prefix = sym(2);
339} break;
340case 17:case 18: {
341 Name name = _M_grammar->intern (sym(1));
342 _M_grammar->terminals.insert (name);
343 _M_grammar->spells.insert (name, sym(2));
344} break;
345
346case 19: {
347 _M_grammar->current_assoc = Grammar::Left;
348 ++_M_grammar->current_prec;
349} break;
350
351case 20: {
353 ++_M_grammar->current_prec;
354} break;
355
356case 21: {
358 ++_M_grammar->current_prec;
359} break;
360
361case 25: {
362 Name name = _M_grammar->intern (sym(1));
363 _M_grammar->terminals.insert (name);
364
365 Grammar::TokenInfo info;
366 info.prec = _M_grammar->current_prec;
367 info.assoc = _M_grammar->current_assoc;
368 _M_grammar->token_info.insert (name, info);
369} break;
370
371case 26: {
372 _M_decls += expand (sym(1));
373} break;
374
375case 27: {
376 _M_impls += expand (sym(1));
377} break;
378
379case 34: {
380 _M_current_rule = _M_grammar->rules.insert (_M_grammar->rules.end (), Rule ());
381 _M_current_rule->lhs = _M_grammar->intern (sym(1));
382 _M_grammar->declared_lhs.insert (_M_current_rule->lhs);
383
384 if (_M_grammar->terminals.find (_M_current_rule->lhs) != _M_grammar->terminals.end ())
385 {
386 qerr() << _M_input_file << ":" << _M_line << ": Invalid non terminal `" << *_M_current_rule->lhs << "'" << Qt::endl;
387 return false;
388 }
389
390 _M_grammar->non_terminals.insert (_M_current_rule->lhs);
391} break;
392
393case 38: {
394 Name lhs = _M_current_rule->lhs;
395 _M_current_rule = _M_grammar->rules.insert (_M_grammar->rules.end (), Rule ());
396 _M_current_rule->lhs = lhs;
397 _M_grammar->declared_lhs.insert (_M_current_rule->lhs);
398
399 if (_M_grammar->terminals.find (_M_current_rule->lhs) != _M_grammar->terminals.end ())
400 {
401 qerr() << _M_input_file << ":" << _M_line << ": Invalid non terminal `" << *_M_current_rule->lhs << "'" << Qt::endl;
402 return false;
403 }
404
405 _M_grammar->non_terminals.insert (_M_current_rule->lhs);
406} break;
407
408case 39: {
409 _M_current_rule->prec = _M_grammar->names.end ();
410
411 for (NameList::iterator it = _M_current_rule->rhs.begin (); it != _M_current_rule->rhs.end (); ++it)
412 {
413 if (! _M_grammar->isTerminal (*it))
414 continue;
415
416 _M_current_rule->prec = *it;
417 }
418} break;
419
420case 40: {
421 Name tok = _M_grammar->intern (sym(2));
422 if (! _M_grammar->isTerminal (tok))
423 {
424 qerr() << _M_input_file << ":" << _M_line << ": `" << *tok << " is not a terminal symbol" << Qt::endl;
425 _M_current_rule->prec = _M_grammar->names.end ();
426 }
427 else
428 _M_current_rule->prec = tok;
429} break;
430
431case 42: {
432 Name name = _M_grammar->intern (sym(2));
433
434 if (_M_grammar->terminals.find (name) == _M_grammar->terminals.end ())
435 _M_grammar->non_terminals.insert (name);
436
437 _M_current_rule->rhs.push_back (name);
438} break;
439
440case 43: {
441 sym(1) = QString();
442} break;
443
444 } // switch
445
446 state_stack [tos] = nt_action (act, lhs [r] - TERMINAL_COUNT);
447 }
448
449 else
450 {
451 break;
452 }
453 }
454
455 qerr() << _M_input_file << ":" << _M_line << ": Syntax error" << Qt::endl;
456 return false;
457}
@ Left
Definition lalr.h:253
@ Right
Definition lalr.h:254
@ NonAssoc
Definition lalr.h:252
Name intern(const char *id)
Definition lalr.h:220
Assoc current_assoc
Definition lalr.h:263
NameSet terminals
Definition lalr.h:239
NameSet declared_lhs
Definition lalr.h:247
debug_infot rules
Definition lalr.h:242
Name start
Definition lalr.h:238
int current_prec
Definition lalr.h:264
bool isTerminal(Name name) const
Definition lalr.h:222
NameSet non_terminals
Definition lalr.h:240
Definition lalr.h:49
std::list< QString >::iterator Name
Definition lalr.h:28