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