1 /****************************************************************************
2 **
3 ** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
4 **
5 ** This file is part of the Edyuk project <http://edyuk.org>
6 **
7 ** This file may be used under the terms of the GNU General Public License
8 ** version 3 as published by the Free Software Foundation and appearing in the
9 ** file GPL.txt included in the packaging of this file.
10 **
11 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13 **
14 ****************************************************************************/
15
16 #ifndef _Q_NFA_H_
17 #define _Q_NFA_H_
18
19 /*!
20 \file qnfa.h
21 \brief Definition of the core QNFA syntax engine
22 */
23
24 #include <QChar>
25 #include <QList>
26 #include <QHash>
27 #include <QStack>
28 #include <QString>
29
30 #include "light_vector.h"
31
32 struct QNFA;
33
34 typedef light_vector<quint16> QNFASet;
35
36 class QNFABranch : public light_vector<QNFA*>
37 {
38 public:
39 ~QNFABranch();
40 };
41
42 enum NFAType
43 {
44 Char = 0,
45
46 Match = 1,
47
48 CxtBeg = 2,
49 CxtEnd = 4,
50 CxtEsc = 8,
51
52 ContextBegin = Match | CxtBeg,
53 ContextEnd = Match | CxtEnd,
54 EscapeSeq = Match | CxtEsc,
55
56 Escaped = 16,
57 Exclusive = 32,
58 StayOnLine = 64,
59
60 Reserved = 128
61 };
62
63 enum NFAAssertion
64 {
65 NoAssertion = 0,
66
67 One = 0, // default standard
68 ZeroOrOne = 1, // ?
69 ZeroOrMore = 2, // *
70 OneOrMore = 4, // +
71
72 WordStart = 8,
73 WordEnd = 16,
74
75 Word = 32,
76 NonWord = 64,
77
78 Digit = 128,
79 NonDigit = 256,
80
81 Space = 512,
82 NonSpace = 1024,
83
84 CaseSensitive = 2048
85 };
86
87 struct QCharTreeNode;
88
89 typedef QHash<quint16, QCharTreeNode> QCharTreeLevel;
90
91 struct QCharTreeNode
92 {
93 inline QCharTreeNode(quint16 v = 0) { value.unicode = v; }
QCharTreeNodeQCharTreeNode94 inline QCharTreeNode(const QCharTreeNode& o) { value = o.value; next = o.next; }
95
96 union
97 {
98 int action;
99 quint16 unicode;
100 } value;
101
102 QCharTreeLevel next;
103 };
104
105 Q_DECLARE_TYPEINFO(QCharTreeNode, Q_MOVABLE_TYPE);
106
107 typedef QCharTreeLevel QCharTree;
108
109 struct QNFA
110 {
111 QNFA();
112 ~QNFA();
113
114 QNFASet c;
115 QCharTree tree;
116
117 union
118 {
119 QNFA *next;
120 QNFABranch *branch;
121 } out;
122
123 quint8 type;
124 quint16 assertion;
125
126 int actionid;
127
128 static quint32 _count;
129 };
130
131 struct QNFAMatchContext
132 {
contextQNFAMatchContext133 inline QNFAMatchContext(QNFA *root = 0) : context(root) {}
134
135 inline QNFAMatchContext& operator = (QNFAMatchContext *c)
136 {
137 if ( c )
138 {
139 context = c->context;
140 parents = c->parents;
141 meaningless = c->meaningless;
142 } else {
143 reset();
144 }
145
146 return *this;
147 }
148
149 inline QNFAMatchContext& operator = (const QNFAMatchContext& c)
150 {
151 context = c.context;
152 parents = c.parents;
153 meaningless = c.meaningless;
154
155 return *this;
156 }
157
resetQNFAMatchContext158 inline void reset()
159 {
160 context = 0;
161
162 while ( parents.count() )
163 context = parents.pop();
164 }
165
166 QNFA *context;
167 QNFASet meaningless;
168 QStack<QNFA*> parents;
169 };
170
171 class QNFAMatchHandler
172 {
173 public:
~QNFAMatchHandler()174 virtual ~QNFAMatchHandler() {}
175
176 virtual void matched(int pos, int len, int action) = 0;
177 };
178
179 class QNFAMatchNotifier
180 {
181 private:
182 struct Command
183 {
CommandCommand184 inline Command(int p, int len, int act)
185 : pos(p), length(len), action(act) {}
186
187 int pos;
188 int length;
189 int action;
190 };
191
192 typedef QList<Command> CommandList;
193
194 public:
QNFAMatchNotifier(QNFAMatchHandler * h)195 inline QNFAMatchNotifier(QNFAMatchHandler *h)
196 : handler(h) {}
197
198 inline QNFAMatchNotifier& operator = (const QNFAMatchNotifier& n)
199 {
200 handler = n.handler;
201
202 return *this;
203 }
204
operator()205 inline void operator () (int pos, int len, int action)
206 {
207 if ( handler && (m_buffers.isEmpty() || m_pending.count()) )
208 handler->matched(pos, len, action);
209 else
210 m_buffers.top() << Command(pos, len, action);
211 }
212
bufferLevel()213 inline int bufferLevel() const
214 {
215 return m_buffers.count();
216 }
217
startBuffering()218 inline void startBuffering()
219 {
220 m_buffers.push(CommandList());
221 }
222
stopBuffering()223 inline void stopBuffering()
224 {
225 m_pending = m_buffers.pop();
226 }
227
flush()228 inline void flush()
229 {
230 foreach ( Command c, m_pending )
231 handler->matched(c.pos, c.length, c.action);
232
233 m_pending.clear();
234 }
235
clear()236 inline void clear()
237 {
238 m_pending.clear();
239 m_buffers.clear();
240 }
241
242 private:
243 QNFAMatchHandler *handler;
244
245 CommandList m_pending;
246 QStack<CommandList> m_buffers;
247 };
248
249 void match( QNFAMatchContext *lexer,
250 const QChar *d,
251 int length,
252 QNFAMatchNotifier notify);
253
match(QNFAMatchContext * lexer,const QString & s,QNFAMatchNotifier notify)254 inline void match( QNFAMatchContext *lexer,
255 const QString& s,
256 QNFAMatchNotifier notify)
257 { match(lexer, s.constData(), s.length(), notify); }
258
259 QNFA* lexer();
260
261 void squeeze(QNFA *nfa);
262 void squeeze(QCharTreeLevel& lvl);
263
264 QNFA* sharedContext(const QString& start,
265 QNFA *other,
266 bool cs);
267
268 QNFA* context( const QString& start,
269 const QString& stop,
270 const QString& escape,
271 int action,
272 QNFA **handler = 0,
273 bool cs = true);
274
addNFA(QNFA * context,QNFA * nfa)275 inline void addNFA(QNFA *context, QNFA *nfa)
276 { context->out.branch->append(nfa); }
277
278 bool plain(const QString& word, QString *dest);
279
280 void addWord( QCharTree& tree,
281 const QString& w,
282 int action,
283 bool cs);
284
285 void addWord( QNFA *lexer,
286 const QString& w,
287 int action,
288 bool cs);
289
290 void addSequence( QNFA *lexer,
291 const QString& w,
292 int action,
293 bool cs);
294
295 QNFA* sequence( const QChar *d,
296 int length,
297 QNFA **end,
298 bool cs);
299
sequence(const QString & s,QNFA ** end,bool cs)300 inline QNFA* sequence(
301 const QString& s,
302 QNFA **end,
303 bool cs)
304 { return sequence(s.constData(), s.length(), end, cs); }
305
306 #endif //!_Q_NFA_H_
307