1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com> |
5 | ** Contact: https://www.qt.io/licensing/ |
6 | ** |
7 | ** This file is part of the tools applications of the Qt Toolkit. |
8 | ** |
9 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
10 | ** Commercial License Usage |
11 | ** Licensees holding valid commercial Qt licenses may use this file in |
12 | ** accordance with the commercial license agreement provided with the |
13 | ** Software or, alternatively, in accordance with the terms contained in |
14 | ** a written agreement between you and The Qt Company. For licensing terms |
15 | ** and conditions see https://www.qt.io/terms-conditions. For further |
16 | ** information use the contact form at https://www.qt.io/contact-us. |
17 | ** |
18 | ** GNU General Public License Usage |
19 | ** Alternatively, this file may be used under the terms of the GNU |
20 | ** General Public License version 3 as published by the Free Software |
21 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
22 | ** included in the packaging of this file. Please review the following |
23 | ** information to ensure the GNU General Public License requirements will |
24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
25 | ** |
26 | ** $QT_END_LICENSE$ |
27 | ** |
28 | ****************************************************************************/ |
29 | |
30 | #ifndef SYMBOLS_H |
31 | #define SYMBOLS_H |
32 | |
33 | #include "token.h" |
34 | #include <qstring.h> |
35 | #include <qhash.h> |
36 | #include <qvector.h> |
37 | #include <qstack.h> |
38 | #include <qdebug.h> |
39 | |
40 | QT_BEGIN_NAMESPACE |
41 | |
42 | //#define USE_LEXEM_STORE |
43 | |
44 | struct SubArray |
45 | { |
46 | inline SubArray():from(0),len(-1){} |
47 | inline SubArray(const QByteArray &a):array(a),from(0), len(a.size()){} |
48 | inline SubArray(const char *s):array(s),from(0) { len = array.size(); } |
49 | inline SubArray(const QByteArray &a, int from, int len):array(a), from(from), len(len){} |
50 | QByteArray array; |
51 | int from, len; |
52 | inline bool operator==(const SubArray &other) const { |
53 | if (len != other.len) |
54 | return false; |
55 | for (int i = 0; i < len; ++i) |
56 | if (array.at(i: from + i) != other.array.at(i: other.from + i)) |
57 | return false; |
58 | return true; |
59 | } |
60 | }; |
61 | |
62 | inline uint qHash(const SubArray &key) |
63 | { |
64 | return qHash(key: QLatin1String(key.array.constData() + key.from, key.len)); |
65 | } |
66 | |
67 | |
68 | struct Symbol |
69 | { |
70 | |
71 | #ifdef USE_LEXEM_STORE |
72 | typedef QHash<SubArray, QHashDummyValue> LexemStore; |
73 | static LexemStore lexemStore; |
74 | |
75 | inline Symbol() : lineNum(-1),token(NOTOKEN){} |
76 | inline Symbol(int lineNum, Token token): |
77 | lineNum(lineNum), token(token){} |
78 | inline Symbol(int lineNum, Token token, const QByteArray &lexem): |
79 | lineNum(lineNum), token(token),lex(lexem){} |
80 | inline Symbol(int lineNum, Token token, const QByteArray &lexem, int from, int len): |
81 | lineNum(lineNum), token(token){ |
82 | LexemStore::const_iterator it = lexemStore.constFind(SubArray(lexem, from, len)); |
83 | |
84 | if (it != lexemStore.constEnd()) { |
85 | lex = it.key().array; |
86 | } else { |
87 | lex = lexem.mid(from, len); |
88 | lexemStore.insert(lex, QHashDummyValue()); |
89 | } |
90 | } |
91 | int lineNum; |
92 | Token token; |
93 | inline QByteArray unquotedLexem() const { return lex.mid(1, lex.length()-2); } |
94 | inline QByteArray lexem() const { return lex; } |
95 | inline operator QByteArray() const { return lex; } |
96 | QByteArray lex; |
97 | |
98 | #else |
99 | |
100 | inline Symbol() : lineNum(-1),token(NOTOKEN), from(0),len(-1) {} |
101 | inline Symbol(int lineNum, Token token): |
102 | lineNum(lineNum), token(token), from(0), len(-1) {} |
103 | inline Symbol(int lineNum, Token token, const QByteArray &lexem): |
104 | lineNum(lineNum), token(token), lex(lexem), from(0) { len = lex.size(); } |
105 | inline Symbol(int lineNum, Token token, const QByteArray &lexem, int from, int len): |
106 | lineNum(lineNum), token(token),lex(lexem),from(from), len(len){} |
107 | int lineNum; |
108 | Token token; |
109 | inline QByteArray lexem() const { return lex.mid(index: from, len); } |
110 | inline QByteArray unquotedLexem() const { return lex.mid(index: from+1, len: len-2); } |
111 | inline operator SubArray() const { return SubArray(lex, from, len); } |
112 | bool operator==(const Symbol& o) const |
113 | { |
114 | return SubArray(lex, from, len) == SubArray(o.lex, o.from, o.len); |
115 | } |
116 | QByteArray lex; |
117 | int from, len; |
118 | |
119 | #endif |
120 | }; |
121 | Q_DECLARE_TYPEINFO(Symbol, Q_MOVABLE_TYPE); |
122 | |
123 | typedef QVector<Symbol> Symbols; |
124 | |
125 | struct SafeSymbols { |
126 | Symbols symbols; |
127 | QByteArray expandedMacro; |
128 | QSet<QByteArray> excludedSymbols; |
129 | int index; |
130 | }; |
131 | Q_DECLARE_TYPEINFO(SafeSymbols, Q_MOVABLE_TYPE); |
132 | |
133 | class SymbolStack : public QStack<SafeSymbols> |
134 | { |
135 | public: |
136 | inline bool hasNext() { |
137 | while (!isEmpty() && top().index >= top().symbols.size()) |
138 | pop(); |
139 | return !isEmpty(); |
140 | } |
141 | inline Token next() { |
142 | while (!isEmpty() && top().index >= top().symbols.size()) |
143 | pop(); |
144 | if (isEmpty()) |
145 | return NOTOKEN; |
146 | return top().symbols.at(i: top().index++).token; |
147 | } |
148 | bool test(Token); |
149 | inline const Symbol &symbol() const { return top().symbols.at(i: top().index-1); } |
150 | inline Token token() { return symbol().token; } |
151 | inline QByteArray lexem() const { return symbol().lexem(); } |
152 | inline QByteArray unquotedLexem() { return symbol().unquotedLexem(); } |
153 | |
154 | bool dontReplaceSymbol(const QByteArray &name); |
155 | QSet<QByteArray> excludeSymbols(); |
156 | }; |
157 | |
158 | inline bool SymbolStack::test(Token token) |
159 | { |
160 | int stackPos = size() - 1; |
161 | while (stackPos >= 0 && at(i: stackPos).index >= at(i: stackPos).symbols.size()) |
162 | --stackPos; |
163 | if (stackPos < 0) |
164 | return false; |
165 | if (at(i: stackPos).symbols.at(i: at(i: stackPos).index).token == token) { |
166 | next(); |
167 | return true; |
168 | } |
169 | return false; |
170 | } |
171 | |
172 | inline bool SymbolStack::dontReplaceSymbol(const QByteArray &name) |
173 | { |
174 | for (int i = 0; i < size(); ++i) { |
175 | if (name == at(i).expandedMacro || at(i).excludedSymbols.contains(value: name)) |
176 | return true; |
177 | } |
178 | return false; |
179 | } |
180 | |
181 | inline QSet<QByteArray> SymbolStack::excludeSymbols() |
182 | { |
183 | QSet<QByteArray> set; |
184 | for (int i = 0; i < size(); ++i) { |
185 | set << at(i).expandedMacro; |
186 | set += at(i).excludedSymbols; |
187 | } |
188 | return set; |
189 | } |
190 | |
191 | QT_END_NAMESPACE |
192 | |
193 | #endif // SYMBOLS_H |
194 | |