RPA Toolkit
696898d04af1d9ecf3184c164fd09c54038b0528
[rpatk.git] / rpa / rpadbex.c
1 /*
2  *  Regular Pattern Analyzer (RPA)
3  *  Copyright (c) 2009-2010 Martin Stoilov
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  *  Martin Stoilov <martin@rpasearch.com>
19  */
20
21 /**
22  *@file rpadbex.c
23  */
24
25
26 #include "rlib/rmem.h"
27 #include "rlib/rutf.h"
28 #include "rpa/rpabitmap.h"
29 #include "rpa/rpadbexpriv.h"
30 #include "rpa/rpadbex.h"
31 #include "rpa/rpastatpriv.h"
32
33
34 #define RPA_DBEX_SETERRINFO_CODE(__d__, __e__) do { (__d__)->err.code = __e__; (__d__)->err.mask |= RPA_ERRINFO_CODE; } while (0)
35 #define RPA_DBEX_SETERRINFO_OFFSET(__d__, __o__) do { (__d__)->err.offset = __o__; (__d__)->err.mask |= RPA_ERRINFO_OFFSET; } while (0)
36 #define RPA_DBEX_SETERRINFO_LINE(__d__, __l__) do { (__d__)->err.line = __l__; (__d__)->err.mask |= RPA_ERRINFO_LINE; } while (0)
37 #define RPA_DBEX_SETERRINFO_NAME(__d__, __n__, __s__) do { \
38         (__d__)->err.mask |= RPA_ERRINFO_NAME; \
39         r_memset((__d__)->err.name, 0, sizeof((__d__)->err.name)); \
40         r_strncpy((__d__)->err.name, __n__, R_MIN(__s__, (sizeof((__d__)->err.name) - 1)));  } while (0)
41
42
43
44 static rparecord_t *rpa_dbex_rulerecord(rpadbex_t *dbex, rparule_t rid);
45 static rparecord_t *rpa_dbex_record(rpadbex_t *dbex, long rec);
46 static int rpa_dbex_rulename(rpadbex_t *dbex, long rec, const char **name, rsize_t *namesize);
47 static int rpa_parseinfo_loopdetect(rpadbex_t *dbex, long parent, long loopto);
48 static long rpa_dbex_firstinlined(rpadbex_t *dbex);
49 static int rpa_dbex_findinlined(rpadbex_t *dbex, long startrec);
50 static int rpa_dbex_playchildrecords(rpadbex_t *dbex, long rec);
51 static int rpa_dbex_playreversechildrecords(rpadbex_t *dbex, long rec);
52 static int rpa_dbex_playrecord(rpadbex_t *dbex, long rec);
53 static int rpa_dbex_rh_default(rpadbex_t *dbex, long rec);
54
55
56 void rpa_dbex_debug_recordhead(rpadbex_t *dbex, long rec)
57 {
58         if (dbex->debug) {
59                 rarray_t *records = dbex->records;
60                 rparecord_t *prec = (rparecord_t *) r_array_slot(records, rec);
61                 dbex->headoff = rvm_codegen_getcodesize(dbex->co->cg);
62                 if (prec->type & RPA_RECORD_START) {
63                         rpa_record_dump(records, rec);
64                 }
65         }
66
67 }
68
69
70 void rpa_dbex_debug_recordtail(rpadbex_t *dbex, long rec)
71 {
72         if (dbex->debug) {
73                 rarray_t *records = dbex->records;
74                 rparecord_t *prec = (rparecord_t *) r_array_slot(records, rec);
75                 rvm_asm_dump(rvm_codegen_getcode(dbex->co->cg, dbex->headoff), rvm_codegen_getcodesize(dbex->co->cg) - dbex->headoff);
76                 if (prec->type & RPA_RECORD_END) {
77                         rpa_record_dump(records, rec);
78                 }
79         }
80 }
81
82
83 static int rpa_dbex_rh_default(rpadbex_t *dbex, long rec)
84 {
85         rarray_t *records = dbex->records;
86         rparecord_t *prec;
87
88         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
89         prec = rpa_dbex_record(dbex, rec);
90         R_ASSERT(prec);
91         rpa_dbex_debug_recordhead(dbex, rec);
92         rpa_dbex_debug_recordtail(dbex, rec);
93         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
94                 return -1;
95         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
96         prec = rpa_dbex_record(dbex, rec);
97         R_ASSERT(prec);
98         rpa_dbex_debug_recordhead(dbex, rec);
99         rpa_dbex_debug_recordtail(dbex, rec);
100         return 0;
101 }
102
103
104
105 static int rpa_dbex_playrecord(rpadbex_t *dbex, long rec)
106 {
107         rarray_t *records = dbex->records;
108         rparecord_t *prec = (rparecord_t *)r_array_slot(records, rec);
109
110         if (prec->ruleuid >= 0 && prec->ruleuid < RPA_PRODUCTION_COUNT && dbex->handlers[prec->ruleuid]) {
111                 return dbex->handlers[prec->ruleuid](dbex, rec);
112         }
113         return rpa_dbex_rh_default(dbex, rec);
114 }
115
116
117 static int rpa_dbex_playchildrecords(rpadbex_t *dbex, long rec)
118 {
119         long child;
120         rarray_t *records = dbex->records;
121
122         for (child = rpa_recordtree_firstchild(records, rec, RPA_RECORD_START); child >= 0; child = rpa_recordtree_next(records, child, RPA_RECORD_START)) {
123                 if (rpa_dbex_playrecord(dbex, child) < 0)
124                         return -1;
125         }
126         return 0;
127 }
128
129
130 static int rpa_dbex_playreversechildrecords(rpadbex_t *dbex, long rec)
131 {
132         long child;
133         rarray_t *records = dbex->records;
134
135         for (child = rpa_recordtree_lastchild(records, rec, RPA_RECORD_START); child >= 0; child = rpa_recordtree_prev(records, child, RPA_RECORD_START)) {
136                 if (rpa_dbex_playrecord(dbex, child) < 0)
137                         return -1;
138         }
139
140         return 0;
141 }
142
143
144 static long rpa_dbex_getmatchchr(unsigned long matchtype)
145 {
146         switch (matchtype & RPA_MATCH_MASK) {
147         default:
148         case RPA_MATCH_NONE:
149                 return RPA_MATCHCHR_NAN;
150                 break;
151         case RPA_MATCH_MULTIPLE:
152                 return RPA_MATCHCHR_MUL;
153                 break;
154         case RPA_MATCH_OPTIONAL:
155                 return RPA_MATCHCHR_OPT;
156                 break;
157         case RPA_MATCH_MULTIOPT:
158                 return RPA_MATCHCHR_MOP;
159                 break;
160         };
161         return RPA_MATCHCHR_NAN;
162 }
163
164
165 static long rpa_dbex_getmatchspecialchr(unsigned long matchtype)
166 {
167         switch (matchtype & RPA_MATCH_MASK) {
168         default:
169         case RPA_MATCH_NONE:
170                 return RPA_MATCHSPCHR_NAN;
171                 break;
172         case RPA_MATCH_MULTIPLE:
173                 return RPA_MATCHSPCHR_MUL;
174                 break;
175         case RPA_MATCH_OPTIONAL:
176                 return RPA_MATCHSPCHR_OPT;
177                 break;
178         case RPA_MATCH_MULTIOPT:
179                 return RPA_MATCHSPCHR_MOP;
180                 break;
181         };
182         return RPA_MATCHSPCHR_NAN;
183 }
184
185
186 int rpa_record2long(rparecord_t *prec, ruint32 *num)
187 {
188         char *endptr = NULL;
189         char buffer[64];
190
191         if (!prec || !num || prec->inputsiz == 0 || prec->inputsiz >= sizeof(buffer))
192                 return -1;
193         r_memset(buffer, 0, sizeof(buffer));
194         r_memcpy(buffer, prec->input, prec->inputsiz);
195         if (prec->ruleuid == RPA_PRODUCTION_HEX) {
196                 *num = (ruint32)r_strtoul(prec->input, &endptr, 16);
197         } else if (prec->ruleuid == RPA_PRODUCTION_DEC) {
198                 *num = (ruint32)r_strtoul(prec->input, &endptr, 10);
199         } else {
200                 return -1;
201         }
202         return 0;
203 }
204
205
206 static int rpa_dbex_rh_uid(rpadbex_t *dbex, long rec)
207 {
208         const char *name = NULL;
209         rsize_t namesize;
210         ruint32 uid = 0;
211         rparecord_t *pnumrec;
212         rarray_t *records = dbex->records;
213         rparecord_t *prec;
214
215         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
216         prec = rpa_dbex_record(dbex, rec);
217         R_ASSERT(prec);
218         rpa_dbex_debug_recordhead(dbex, rec);
219         if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
220                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAXERROR);
221                 return -1;
222         }
223         pnumrec = rpa_dbex_record(dbex, rpa_recordtree_lastchild(dbex->records, rec, RPA_RECORD_END));
224         if (!pnumrec) {
225                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAXERROR);
226                 return -1;
227         }
228         if (rpa_record2long(pnumrec, &uid) < 0) {
229                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAXERROR);
230                 return -1;
231         }
232         rpa_compiler_rulepref_set_ruleuid(dbex->co, name, namesize, uid);
233         rpa_compiler_rulepref_set_flag(dbex->co, name, namesize, RPA_RFLAG_EMITRECORD);
234         rpa_dbex_debug_recordtail(dbex, rec);
235         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
236                 return -1;
237         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
238         prec = rpa_dbex_record(dbex, rec);
239         R_ASSERT(prec);
240         rpa_dbex_debug_recordhead(dbex, rec);
241         rpa_dbex_debug_recordtail(dbex, rec);
242         return 0;
243 }
244
245
246 static int rpa_dbex_rh_abort(rpadbex_t *dbex, long rec)
247 {
248         const char *name = NULL;
249         rsize_t namesize;
250         rarray_t *records = dbex->records;
251         rparecord_t *prec;
252
253         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
254         prec = rpa_dbex_record(dbex, rec);
255         R_ASSERT(prec);
256         rpa_dbex_debug_recordhead(dbex, rec);
257         if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
258                 return -1;
259         }
260         rpa_compiler_rulepref_set_flag(dbex->co, name, namesize, RPA_RFLAG_ABORTONFAIL);
261         rpa_dbex_debug_recordtail(dbex, rec);
262         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
263                 return -1;
264         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
265         prec = rpa_dbex_record(dbex, rec);
266         R_ASSERT(prec);
267         rpa_dbex_debug_recordhead(dbex, rec);
268         rpa_dbex_debug_recordtail(dbex, rec);
269         return 0;
270 }
271
272
273 static int rpa_dbex_rh_emit(rpadbex_t *dbex, long rec)
274 {
275         const char *name = NULL;
276         rsize_t namesize;
277         rarray_t *records = dbex->records;
278         rparecord_t *prec;
279
280         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
281         prec = rpa_dbex_record(dbex, rec);
282         R_ASSERT(prec);
283         rpa_dbex_debug_recordhead(dbex, rec);
284         if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
285                 return -1;
286         }
287         rpa_compiler_rulepref_set_flag(dbex->co, name, namesize, RPA_RFLAG_EMITRECORD);
288         rpa_dbex_debug_recordtail(dbex, rec);
289         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
290                 return -1;
291         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
292         prec = rpa_dbex_record(dbex, rec);
293         R_ASSERT(prec);
294         rpa_dbex_debug_recordhead(dbex, rec);
295         rpa_dbex_debug_recordtail(dbex, rec);
296         return 0;
297 }
298
299
300 static int rpa_dbex_rh_noemit(rpadbex_t *dbex, long rec)
301 {
302         const char *name = NULL;
303         rsize_t namesize;
304         rarray_t *records = dbex->records;
305         rparecord_t *prec;
306
307         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
308         prec = rpa_dbex_record(dbex, rec);
309         R_ASSERT(prec);
310         rpa_dbex_debug_recordhead(dbex, rec);
311         if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
312                 return -1;
313         }
314         rpa_compiler_rulepref_clear_flag(dbex->co, name, namesize, RPA_RFLAG_EMITRECORD);
315         rpa_dbex_debug_recordtail(dbex, rec);
316         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
317                 return -1;
318         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
319         prec = rpa_dbex_record(dbex, rec);
320         R_ASSERT(prec);
321         rpa_dbex_debug_recordhead(dbex, rec);
322         rpa_dbex_debug_recordtail(dbex, rec);
323         return 0;
324 }
325
326
327 static int rpa_dbex_setemit(rpadbex_t *dbex, rboolean emit)
328 {
329         long i;
330         rpa_ruleinfo_t *info;
331
332         for (i = 0; i < r_array_length(dbex->rules->names); i++) {
333                 rstr_t *name = r_array_index(dbex->rules->names, i, rstr_t*);
334                 info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, i);
335                 if (info->type == RPA_RULEINFO_NAMEDRULE) {
336                         if (emit) {
337                                 rpa_compiler_rulepref_set_flag(dbex->co, name->str, name->size, RPA_RFLAG_EMITRECORD);
338                         } else {
339                                 rpa_compiler_rulepref_clear_flag(dbex->co, name->str, name->size, RPA_RFLAG_EMITRECORD);
340                         }
341                 }
342         }
343         return 0;
344 }
345
346
347 static int rpa_dbex_rh_emitall(rpadbex_t *dbex, long rec)
348 {
349         rarray_t *records = dbex->records;
350         rparecord_t *prec;
351
352         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
353         prec = rpa_dbex_record(dbex, rec);
354         R_ASSERT(prec);
355         rpa_dbex_debug_recordhead(dbex, rec);
356         rpa_dbex_setemit(dbex, TRUE);
357         rpa_dbex_debug_recordtail(dbex, rec);
358         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
359                 return -1;
360         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
361         prec = rpa_dbex_record(dbex, rec);
362         R_ASSERT(prec);
363         rpa_dbex_debug_recordhead(dbex, rec);
364         rpa_dbex_debug_recordtail(dbex, rec);
365         return 0;
366 }
367
368
369 static int rpa_dbex_rh_emitnone(rpadbex_t *dbex, long rec)
370 {
371         rarray_t *records = dbex->records;
372         rparecord_t *prec;
373
374         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
375         prec = rpa_dbex_record(dbex, rec);
376         R_ASSERT(prec);
377         rpa_dbex_debug_recordhead(dbex, rec);
378         rpa_dbex_setemit(dbex, FALSE);
379         rpa_dbex_debug_recordtail(dbex, rec);
380         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
381                 return -1;
382         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
383         prec = rpa_dbex_record(dbex, rec);
384         R_ASSERT(prec);
385         rpa_dbex_debug_recordhead(dbex, rec);
386         rpa_dbex_debug_recordtail(dbex, rec);
387         return 0;
388 }
389
390
391 static int rpa_dbex_rh_namedrule(rpadbex_t *dbex, long rec)
392 {
393         const char *name = NULL;
394         rsize_t namesize;
395         rarray_t *records = dbex->records;
396         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
397
398         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
399         prec = rpa_dbex_record(dbex, rec);
400         R_ASSERT(prec);
401         rpa_dbex_debug_recordhead(dbex, rec);
402         if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
403
404                 return -1;
405         }
406         if (!r_array_empty(dbex->inlinestack)) {
407                 rpa_compiler_inlinerule_begin(dbex->co, name, namesize, 0);
408         } else {
409                 rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_SHIFT, XX, XX, XX, 0));
410                 if (RPA_BITMAP_GETVAL(RPA_RECORD2BITMAP(prec))) {
411                         rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_EXITONBITMAP, DA, XX, XX, RPA_BITMAP_GETVAL(RPA_RECORD2BITMAP(prec))));
412                 }
413                 rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_BL, DA, XX, XX, 3));
414                 rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_EMITTAIL, XX, XX, XX, 0));
415                 rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_EXT, XX, XX, XX, 0));
416
417                 if ((prec->usertype & RPA_LOOP_PATH)) {
418                         rpa_compiler_loop_begin(dbex->co, name, namesize);
419                 } else {
420                         rpa_compiler_rule_begin(dbex->co, name, namesize, RPA_BITMAP_GETVAL(RPA_RECORD2BITMAP(prec)));
421                 }
422         }
423         r_array_add(dbex->inlinestack, &rec);
424         rpa_dbex_debug_recordtail(dbex, rec);
425         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
426                 return -1;
427         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
428         prec = rpa_dbex_record(dbex, rec);
429         R_ASSERT(prec);
430         rpa_dbex_debug_recordhead(dbex, rec);
431         r_array_removelast(dbex->inlinestack);
432         if (!r_array_empty(dbex->inlinestack)) {
433                 rpa_compiler_inlinerule_end(dbex->co);
434         } else {
435                 if ((prec->usertype & RPA_LOOP_PATH)) {
436                         rpa_compiler_loop_end(dbex->co);
437                 } else {
438                         rpa_compiler_rule_end(dbex->co);
439                 }
440         }
441         rpa_dbex_debug_recordtail(dbex, rec);
442         return 0;
443 }
444
445
446 static int rpa_dbex_rh_anonymousrule(rpadbex_t *dbex, long rec)
447 {
448         rarray_t *records = dbex->records;
449         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
450
451         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
452         prec = rpa_dbex_record(dbex, rec);
453         R_ASSERT(prec);
454         rpa_dbex_debug_recordhead(dbex, rec);
455         rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_SHIFT, XX, XX, XX, 0));
456         if (RPA_BITMAP_GETVAL(RPA_RECORD2BITMAP(prec))) {
457                 rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_EXITONBITMAP, DA, XX, XX, RPA_BITMAP_GETVAL(RPA_RECORD2BITMAP(prec))));
458         }
459         rpa_compiler_exp_begin(dbex->co, RPA_MATCH_NONE, RPA_BITMAP_GETVAL(RPA_RECORD2BITMAP(prec)));
460         rpa_dbex_debug_recordtail(dbex, rec);
461         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
462                 return -1;
463         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
464         prec = rpa_dbex_record(dbex, rec);
465         R_ASSERT(prec);
466         rpa_dbex_debug_recordhead(dbex, rec);
467         rpa_compiler_exp_end(dbex->co);
468         rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_EMITTAIL, XX, XX, XX, 0));
469         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_EXT, XX, XX, XX, 0));
470         rpa_dbex_debug_recordtail(dbex, rec);
471
472         return 0;
473 }
474
475
476 static int rpa_dbex_rh_char(rpadbex_t *dbex, long rec)
477 {
478         rparecord_t *prec;
479         rarray_t *records = dbex->records;
480         ruint32 wc = 0;
481
482         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
483         prec = rpa_dbex_record(dbex, rec);
484         R_ASSERT(prec);
485         rpa_dbex_debug_recordhead(dbex, rec);
486         rpa_dbex_debug_recordtail(dbex, rec);
487         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
488                 return -1;
489         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
490         prec = rpa_dbex_record(dbex, rec);
491         R_ASSERT(prec);
492         rpa_dbex_debug_recordhead(dbex, rec);
493         if (r_utf8_mbtowc(&wc, (const unsigned char*) prec->input, (const unsigned char*)prec->input + prec->inputsiz) < 0) {
494
495                 return -1;
496         }
497         rvm_codegen_addins(dbex->co->cg, rvm_asm(rpa_dbex_getmatchchr(prec->usertype & RPA_MATCH_MASK), DA, XX, XX, wc));
498         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
499         rpa_dbex_debug_recordtail(dbex, rec);
500         return 0;
501 }
502
503
504 static int rpa_dbex_rh_specialchar(rpadbex_t *dbex, long rec)
505 {
506         ruint32 wc = 0;
507         rarray_t *records = dbex->records;
508         rparecord_t *prec;
509
510         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
511         prec = rpa_dbex_record(dbex, rec);
512         R_ASSERT(prec);
513         rpa_dbex_debug_recordhead(dbex, rec);
514         rpa_dbex_debug_recordtail(dbex, rec);
515         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
516                 return -1;
517         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
518         prec = rpa_dbex_record(dbex, rec);
519         R_ASSERT(prec);
520         rpa_dbex_debug_recordhead(dbex, rec);
521         if (r_utf8_mbtowc(&wc, (const unsigned char*) prec->input, (const unsigned char*)prec->input + prec->inputsiz) < 0) {
522
523                 return -1;
524         }
525         rvm_codegen_addins(dbex->co->cg, rvm_asm(rpa_dbex_getmatchspecialchr(prec->usertype & RPA_MATCH_MASK), DA, XX, XX, wc));
526         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
527         rpa_dbex_debug_recordtail(dbex, rec);
528         return 0;
529 }
530
531
532 static int rpa_dbex_rh_cls(rpadbex_t *dbex, long rec)
533 {
534         rarray_t *records = dbex->records;
535         rparecord_t *prec;
536
537         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
538         prec = rpa_dbex_record(dbex, rec);
539         R_ASSERT(prec);
540         rpa_dbex_debug_recordhead(dbex, rec);
541         rpa_compiler_class_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
542         rpa_dbex_debug_recordtail(dbex, rec);
543         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
544                 return -1;
545         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
546         prec = rpa_dbex_record(dbex, rec);
547         R_ASSERT(prec);
548         rpa_dbex_debug_recordhead(dbex, rec);
549         rpa_compiler_class_end(dbex->co);
550         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
551         rpa_dbex_debug_recordtail(dbex, rec);
552         return 0;
553 }
554
555
556 static int rpa_dbex_rh_clschar(rpadbex_t *dbex, long rec)
557 {
558         ruint32 wc = 0;
559         rarray_t *records = dbex->records;
560         rparecord_t *prec;
561
562         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
563         prec = rpa_dbex_record(dbex, rec);
564         R_ASSERT(prec);
565         rpa_dbex_debug_recordhead(dbex, rec);
566         rpa_dbex_debug_recordtail(dbex, rec);
567         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
568                 return -1;
569         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
570         prec = rpa_dbex_record(dbex, rec);
571         R_ASSERT(prec);
572         rpa_dbex_debug_recordhead(dbex, rec);
573         if (r_utf8_mbtowc(&wc, (const unsigned char*) prec->input, (const unsigned char*)prec->input + prec->inputsiz) < 0) {
574
575                 return -1;
576         }
577         rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, wc));
578         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
579         rpa_dbex_debug_recordtail(dbex, rec);
580         return 0;
581 }
582
583
584 static int rpa_dbex_rh_minexp(rpadbex_t *dbex, long rec)
585 {
586         rarray_t *records = dbex->records;
587         rparecord_t *prec;
588
589         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
590         prec = rpa_dbex_record(dbex, rec);
591         R_ASSERT(prec);
592         rpa_dbex_debug_recordhead(dbex, rec);
593         rpa_compiler_exp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK, RPA_BITMAP_GETVAL(RPA_RECORD2BITMAP(prec)));
594         rpa_dbex_debug_recordtail(dbex, rec);
595         if (rpa_dbex_playreversechildrecords(dbex, rec) < 0)
596                 return -1;
597         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
598         prec = rpa_dbex_record(dbex, rec);
599         R_ASSERT(prec);
600         rpa_dbex_debug_recordhead(dbex, rec);
601         rpa_compiler_exp_end(dbex->co);
602         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
603         rpa_dbex_debug_recordtail(dbex, rec);
604         return 0;
605 }
606
607
608 static int rpa_dbex_rh_exp(rpadbex_t *dbex, long rec)
609 {
610         rarray_t *records = dbex->records;
611         rparecord_t *prec;
612
613         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
614         prec = rpa_dbex_record(dbex, rec);
615         R_ASSERT(prec);
616         rpa_dbex_debug_recordhead(dbex, rec);
617         rpa_compiler_exp_begin(dbex->co, (prec->usertype & RPA_MATCH_MASK), 0);
618         rpa_dbex_debug_recordtail(dbex, rec);
619         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
620                 return -1;
621         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
622         prec = rpa_dbex_record(dbex, rec);
623         R_ASSERT(prec);
624         rpa_dbex_debug_recordhead(dbex, rec);
625         rpa_compiler_exp_end(dbex->co);
626         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
627         rpa_dbex_debug_recordtail(dbex, rec);
628         return 0;
629 }
630
631
632 static int rpa_dbex_rh_orop(rpadbex_t *dbex, long rec)
633 {
634         rarray_t *records = dbex->records;
635         rparecord_t *prec;
636
637         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
638         prec = rpa_dbex_record(dbex, rec);
639         R_ASSERT(prec);
640         rpa_dbex_debug_recordhead(dbex, rec);
641         rpa_compiler_altexp_begin(dbex->co, (prec->usertype & RPA_MATCH_MASK), RPA_BITMAP_GETVAL(RPA_RECORD2BITMAP(prec)));
642         rpa_dbex_debug_recordtail(dbex, rec);
643         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
644                 return -1;
645         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
646         prec = rpa_dbex_record(dbex, rec);
647         R_ASSERT(prec);
648         rpa_dbex_debug_recordhead(dbex, rec);
649         rpa_compiler_altexp_end(dbex->co);
650         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
651         rpa_dbex_debug_recordtail(dbex, rec);
652         return 0;
653 }
654
655
656 static int rpa_dbex_rh_norop(rpadbex_t *dbex, long rec)
657 {
658         rarray_t *records = dbex->records;
659         rparecord_t *prec;
660
661         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
662         prec = rpa_dbex_record(dbex, rec);
663         R_ASSERT(prec);
664         rpa_dbex_debug_recordhead(dbex, rec);
665         rpa_compiler_altexp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK, 0);
666         rpa_dbex_debug_recordtail(dbex, rec);
667         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
668                 return -1;
669         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
670         prec = rpa_dbex_record(dbex, rec);
671         R_ASSERT(prec);
672         rpa_dbex_debug_recordhead(dbex, rec);
673         rpa_compiler_altexp_end(dbex->co);
674         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
675         rpa_dbex_debug_recordtail(dbex, rec);
676         return 0;
677 }
678
679
680 static int rpa_dbex_rh_notop(rpadbex_t *dbex, long rec)
681 {
682         rarray_t *records = dbex->records;
683         rparecord_t *prec;
684
685         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
686         prec = rpa_dbex_record(dbex, rec);
687         R_ASSERT(prec);
688         rpa_dbex_debug_recordhead(dbex, rec);
689         rpa_compiler_notexp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
690         rpa_dbex_debug_recordtail(dbex, rec);
691         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
692                 return -1;
693         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
694         prec = rpa_dbex_record(dbex, rec);
695         R_ASSERT(prec);
696         rpa_dbex_debug_recordhead(dbex, rec);
697         rpa_compiler_notexp_end(dbex->co);
698         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
699         rpa_dbex_debug_recordtail(dbex, rec);
700         return 0;
701 }
702
703
704 static int rpa_dbex_rh_range(rpadbex_t *dbex, long rec)
705 {
706         rarray_t *records = dbex->records;
707         rparecord_t *prec;
708
709         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
710         prec = rpa_dbex_record(dbex, rec);
711         R_ASSERT(prec);
712         rpa_dbex_debug_recordhead(dbex, rec);
713         dbex->co->currange.p1 = 0;
714         dbex->co->currange.p2 = 0;
715         rpa_dbex_debug_recordtail(dbex, rec);
716         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
717                 return -1;
718         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
719         prec = rpa_dbex_record(dbex, rec);
720         R_ASSERT(prec);
721         rpa_dbex_debug_recordhead(dbex, rec);
722         if (dbex->co->currange.p1 < dbex->co->currange.p2)
723                 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p1, dbex->co->currange.p2));
724         else
725                 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p2, dbex->co->currange.p1));
726         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
727         rpa_dbex_debug_recordtail(dbex, rec);
728         return 0;
729 }
730
731
732 static int rpa_dbex_rh_numrange(rpadbex_t *dbex, long rec)
733 {
734         rarray_t *records = dbex->records;
735         rparecord_t *prec;
736         rparecord_t *child;
737         /*
738          * Fix me: probably we don't need to access the children from here. There should be a way just to
739          * play them a regular records!
740          */
741
742         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
743         prec = rpa_dbex_record(dbex, rec);
744         R_ASSERT(prec);
745         rpa_dbex_debug_recordhead(dbex, rec);
746         child = rpa_dbex_record(dbex, rpa_recordtree_firstchild(dbex->records, rec, RPA_RECORD_END));
747         if (rpa_record2long(child, &dbex->co->currange.p1) < 0)
748                 return -1;
749         child = rpa_dbex_record(dbex, rpa_recordtree_lastchild(dbex->records, rec, RPA_RECORD_END));
750         if (rpa_record2long(child, &dbex->co->currange.p2) < 0)
751                 return -1;
752         rpa_dbex_debug_recordtail(dbex, rec);
753         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
754                 return -1;
755         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
756         prec = rpa_dbex_record(dbex, rec);
757         R_ASSERT(prec);
758         rpa_dbex_debug_recordhead(dbex, rec);
759         if (dbex->co->currange.p1 < dbex->co->currange.p2)
760                 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p1, dbex->co->currange.p2));
761         else
762                 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p2, dbex->co->currange.p1));
763         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
764         rpa_dbex_debug_recordtail(dbex, rec);
765         return 0;
766 }
767
768
769 static int rpa_dbex_rh_clsnum(rpadbex_t *dbex, long rec)
770 {
771         rarray_t *records = dbex->records;
772         rparecord_t *prec;
773         rparecord_t *child;
774         ruint32 wc;
775
776         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
777         prec = rpa_dbex_record(dbex, rec);
778         R_ASSERT(prec);
779         rpa_dbex_debug_recordhead(dbex, rec);
780         rpa_dbex_debug_recordtail(dbex, rec);
781         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
782                 return -1;
783         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
784         prec = rpa_dbex_record(dbex, rec);
785         R_ASSERT(prec);
786         rpa_dbex_debug_recordhead(dbex, rec);
787         child = rpa_dbex_record(dbex, rpa_recordtree_firstchild(dbex->records, rec, RPA_RECORD_END));
788         if (rpa_record2long(child, &wc) < 0)
789                 return -1;
790         rvm_codegen_addins(dbex->co->cg, rvm_asm(rpa_dbex_getmatchchr(prec->usertype & RPA_MATCH_MASK), DA, XX, XX, wc));
791         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
792         rpa_dbex_debug_recordtail(dbex, rec);
793         return 0;
794 }
795
796
797 static int rpa_dbex_rh_beginchar(rpadbex_t *dbex, long rec)
798 {
799         rarray_t *records = dbex->records;
800         rparecord_t *prec;
801         ruint32 wc = 0;
802
803         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
804         prec = rpa_dbex_record(dbex, rec);
805         R_ASSERT(prec);
806         rpa_dbex_debug_recordhead(dbex, rec);
807         rpa_dbex_debug_recordtail(dbex, rec);
808         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
809                 return -1;
810         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
811         prec = rpa_dbex_record(dbex, rec);
812         R_ASSERT(prec);
813         rpa_dbex_debug_recordhead(dbex, rec);
814         if (r_utf8_mbtowc(&wc, (const unsigned char*) prec->input, (const unsigned char*)prec->input + prec->inputsiz) < 0) {
815
816                 return -1;
817         }
818         dbex->co->currange.p1 = wc;
819         rpa_dbex_debug_recordtail(dbex, rec);
820         return 0;
821 }
822
823
824 static int rpa_dbex_rh_endchar(rpadbex_t *dbex, long rec)
825 {
826         rarray_t *records = dbex->records;
827         rparecord_t *prec;
828         ruint32 wc = 0;
829
830         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
831         prec = rpa_dbex_record(dbex, rec);
832         R_ASSERT(prec);
833         rpa_dbex_debug_recordhead(dbex, rec);
834         rpa_dbex_debug_recordtail(dbex, rec);
835         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
836                 return -1;
837         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
838         prec = rpa_dbex_record(dbex, rec);
839         R_ASSERT(prec);
840         rpa_dbex_debug_recordhead(dbex, rec);
841         if (r_utf8_mbtowc(&wc, (const unsigned char*) prec->input, (const unsigned char*)prec->input + prec->inputsiz) < 0) {
842
843                 return -1;
844         }
845         dbex->co->currange.p2 = wc;
846         rpa_dbex_debug_recordtail(dbex, rec);
847         return 0;
848 }
849
850
851 static int rpa_dbex_rh_branch(rpadbex_t *dbex, long rec)
852 {
853         rarray_t *records = dbex->records;
854         rparecord_t *prec;
855
856         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
857         prec = rpa_dbex_record(dbex, rec);
858         R_ASSERT(prec);
859         rpa_dbex_debug_recordhead(dbex, rec);
860         if (prec->usertype & RPA_NONLOOP_PATH) {
861                 rpa_compiler_nonloopybranch_begin(dbex->co, (prec->usertype & RPA_MATCH_MASK));
862         } else {
863                 rpa_compiler_branch_begin(dbex->co, (prec->usertype & RPA_MATCH_MASK), RPA_BITMAP_GETVAL(RPA_RECORD2BITMAP(prec)));
864         }
865         rpa_dbex_debug_recordtail(dbex, rec);
866         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
867                 return -1;
868         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
869         prec = rpa_dbex_record(dbex, rec);
870         R_ASSERT(prec);
871         rpa_dbex_debug_recordhead(dbex, rec);
872         if (prec->usertype & RPA_NONLOOP_PATH) {
873                 rpa_compiler_nonloopybranch_end(dbex->co);
874         } else {
875                 rpa_compiler_branch_end(dbex->co);
876         }
877         rpa_dbex_debug_recordtail(dbex, rec);
878         return 0;
879 }
880
881
882 static void rpa_dbex_rh_loopref(rpadbex_t *dbex, rparecord_t *prec)
883 {
884         /*
885          * We ignore, it doesn't make sense for loops:
886          * RPA_MATCH_MULTIPLE
887          */
888         rpa_compiler_exp_begin(dbex->co, (prec->usertype & RPA_MATCH_OPTIONAL), 0);
889         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_CMP, R_LOO, DA, XX, 0));
890         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_BGRE, DA, XX, XX, 3));
891         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
892         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
893         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_ADD, R_TOP, R_TOP, R_LOO, 0));
894         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_MOVS, R0, R_LOO, XX, 0));
895         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
896         rpa_compiler_exp_end(dbex->co);
897 }
898
899
900 static int rpa_dbex_rh_aref(rpadbex_t *dbex, long rec)
901 {
902         const char *name = NULL;
903         rsize_t namesize;
904         rpa_ruleinfo_t *info;
905         rarray_t *records = dbex->records;
906         rparecord_t *prec;
907
908         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
909         prec = rpa_dbex_record(dbex, rec);
910         R_ASSERT(prec);
911         rpa_dbex_debug_recordhead(dbex, rec);
912         if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
913
914                 return -1;
915         }
916
917         if ((prec->usertype & RPA_LOOP_PATH) && rpa_parseinfo_loopdetect(dbex, rec, rpa_dbex_firstinlined(dbex))) {
918                 info = (rpa_ruleinfo_t *) r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesize));
919                 if (!info) {
920                         RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_UNRESOLVEDSYMBOL);
921                         RPA_DBEX_SETERRINFO_NAME(dbex, name, namesize);
922                         return -1;
923                 }
924                 if (rpa_dbex_findinlined(dbex, info->startrec)) {
925                         rpa_dbex_rh_loopref(dbex, prec);
926                 } else {
927                         if (prec->usertype & RPA_MATCH_OPTIONAL) {
928                                 /*
929                                  * Most probably this is useless case - loop refs shouldn't have quantitative modifiers
930                                  * but in case they do we wrap the inlined production rule in quantitative expression.
931                                  * The inlined named rule can take the quantitative argument, but I just don't have
932                                  * a clean way to pass it from here - so, lets play the records inside an expression that
933                                  * has the right quantitative argument.
934                                  * We ignore, it doesn't make sense for loops:
935                                  * RPA_MATCH_MULTIPLE
936                                  */
937                                 rpa_compiler_exp_begin(dbex->co, RPA_MATCH_OPTIONAL, 0);
938                                 rpa_dbex_playrecord(dbex, info->startrec);
939                                 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
940                                 rpa_compiler_exp_end(dbex->co);
941                         } else {
942                                 rpa_dbex_playrecord(dbex, info->startrec);
943                         }
944                 }
945         } else {
946                 rpa_compiler_reference(dbex->co, name, namesize, (prec->usertype & RPA_MATCH_MASK));
947         }
948         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
949         rpa_dbex_debug_recordtail(dbex, rec);
950         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
951                 return -1;
952         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
953         prec = rpa_dbex_record(dbex, rec);
954         R_ASSERT(prec);
955         rpa_dbex_debug_recordhead(dbex, rec);
956         rpa_dbex_debug_recordtail(dbex, rec);
957         return 0;
958 }
959
960
961 rpadbex_t *rpa_dbex_create(void)
962 {
963         rpadbex_t *dbex = (rpadbex_t *) r_zmalloc(sizeof(*dbex));
964
965         dbex->co = rpa_compiler_create();
966         dbex->pa = rpa_parser_create();
967         dbex->text = r_array_create(sizeof(char *));
968         dbex->records = r_array_create(sizeof(rparecord_t));
969         dbex->temprecords = r_array_create(sizeof(rparecord_t));
970         dbex->rules = r_harray_create(sizeof(rpa_ruleinfo_t));
971         dbex->recstack = r_array_create(sizeof(unsigned long));
972         dbex->inlinestack = r_array_create(sizeof(unsigned long));
973         dbex->handlers = r_zmalloc(sizeof(rpa_dbex_recordhandler) * RPA_PRODUCTION_COUNT);
974         rpa_dbex_cfgset(dbex, RPA_DBEXCFG_OPTIMIZATIONS, 1);
975         rpa_dbex_cfgset(dbex, RPA_DBEXCFG_BITMAP, 1);
976
977         dbex->handlers[RPA_PRODUCTION_NONE] = rpa_dbex_rh_default;
978         dbex->handlers[RPA_PRODUCTION_NAMEDRULE] = rpa_dbex_rh_namedrule;
979         dbex->handlers[RPA_PRODUCTION_ANONYMOUSRULE] = rpa_dbex_rh_anonymousrule;
980         dbex->handlers[RPA_PRODUCTION_CLS] = rpa_dbex_rh_cls;
981         dbex->handlers[RPA_PRODUCTION_CHAR] = rpa_dbex_rh_char;
982         dbex->handlers[RPA_PRODUCTION_SPECIALCHAR] = rpa_dbex_rh_specialchar;
983         dbex->handlers[RPA_PRODUCTION_CLSCHAR] = rpa_dbex_rh_clschar;
984         dbex->handlers[RPA_PRODUCTION_AREF] = rpa_dbex_rh_aref;
985         dbex->handlers[RPA_PRODUCTION_CREF] = rpa_dbex_rh_aref;
986         dbex->handlers[RPA_PRODUCTION_BRACKETEXP] = rpa_dbex_rh_exp;
987         dbex->handlers[RPA_PRODUCTION_OROP] = rpa_dbex_rh_orop;
988         dbex->handlers[RPA_PRODUCTION_NOTOP] = rpa_dbex_rh_notop;
989         dbex->handlers[RPA_PRODUCTION_ALTBRANCH] = rpa_dbex_rh_branch;
990         dbex->handlers[RPA_PRODUCTION_NEGBRANCH] = rpa_dbex_rh_branch;
991         dbex->handlers[RPA_PRODUCTION_CHARRNG] = rpa_dbex_rh_range;
992         dbex->handlers[RPA_PRODUCTION_NUMRNG] = rpa_dbex_rh_numrange;
993         dbex->handlers[RPA_PRODUCTION_CLSNUM] = rpa_dbex_rh_clsnum;
994         dbex->handlers[RPA_PRODUCTION_BEGINCHAR] = rpa_dbex_rh_beginchar;
995         dbex->handlers[RPA_PRODUCTION_ENDCHAR] = rpa_dbex_rh_endchar;
996         dbex->handlers[RPA_PRODUCTION_NOROP] = rpa_dbex_rh_norop;
997         dbex->handlers[RPA_PRODUCTION_REQOP] = rpa_dbex_rh_exp;
998         dbex->handlers[RPA_PRODUCTION_MINOP] = rpa_dbex_rh_minexp;
999         dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMIT] = rpa_dbex_rh_emit;
1000         dbex->handlers[RPA_PRODUCTION_DIRECTIVEABORT] = rpa_dbex_rh_abort;
1001         dbex->handlers[RPA_PRODUCTION_DIRECTIVENOEMIT] = rpa_dbex_rh_noemit;
1002         dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMITALL] = rpa_dbex_rh_emitall;
1003         dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMITNONE] = rpa_dbex_rh_emitnone;
1004         dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMITID] = rpa_dbex_rh_uid;
1005
1006         return dbex;
1007 }
1008
1009
1010 void rpa_dbex_destroy(rpadbex_t *dbex)
1011 {
1012         int i;
1013         if (dbex) {
1014                 for (i = 0; i < r_array_length(dbex->text); i++)
1015                         r_free(r_array_index(dbex->text, i, char*));
1016                 rpa_compiler_destroy(dbex->co);
1017                 rpa_parser_destroy(dbex->pa);
1018                 r_harray_destroy(dbex->rules);
1019                 r_array_destroy(dbex->records);
1020                 r_array_destroy(dbex->temprecords);
1021                 r_array_destroy(dbex->recstack);
1022                 r_array_destroy(dbex->inlinestack);
1023                 r_array_destroy(dbex->text);
1024                 r_free(dbex->handlers);
1025                 r_free(dbex);
1026         }
1027 }
1028
1029
1030 static int rpa_parseinfo_loopdetect_do(rpadbex_t *dbex, long parent, long loopto, int inderction)
1031 {
1032         rsize_t namesiz;
1033         const char *name;
1034         long i;
1035         int ret = 0;
1036         rparecord_t *prec;
1037
1038         if (parent == loopto && inderction > 0)
1039                 return 1;
1040         for (i = 0; i < r_array_length(dbex->recstack); i++) {
1041                 if (parent == r_array_index(dbex->recstack, i, long))
1042                         return 0;
1043         }
1044         r_array_add(dbex->recstack, &parent);
1045
1046         if (!(prec = (rparecord_t *)r_array_slot(dbex->records, parent)))
1047                 return 0;
1048         if (prec->ruleuid == RPA_PRODUCTION_AREF || prec->ruleuid == RPA_PRODUCTION_CREF)
1049                 i = parent;
1050         else
1051                 i = rpa_recordtree_firstchild(dbex->records, parent, RPA_RECORD_START);
1052         for (; i >= 0; i = rpa_recordtree_next(dbex->records, i, RPA_RECORD_START)) {
1053                 prec = (rparecord_t *)r_array_slot(dbex->records, i);
1054                 if (prec->ruleuid == RPA_PRODUCTION_RULENAME)
1055                         continue;
1056                 if (prec->ruleuid == RPA_PRODUCTION_AREF || prec->ruleuid == RPA_PRODUCTION_CREF) {
1057                         rpa_ruleinfo_t *info;
1058                         if ((inderction > 0 || i != parent) && i == loopto) {
1059                                 /*
1060                                  * We found what we are looking for
1061                                  */
1062                                 ret = 1;
1063                                 break;
1064                         }
1065                         if (rpa_dbex_rulename(dbex, i, &name, &namesiz) < 0)
1066                                 R_ASSERT(0);
1067                         info = (rpa_ruleinfo_t *) r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesiz));
1068                         if (!info)
1069                                 continue;
1070                         if ((ret = rpa_parseinfo_loopdetect_do(dbex, info->startrec, loopto, inderction + 1)) > 0)
1071                                 break;
1072                 } else {
1073                         if ((ret = rpa_parseinfo_loopdetect_do(dbex, i, loopto, inderction + 1)) > 0)
1074                                 break;
1075                 }
1076
1077                 if ((prec->usertype & RPA_MATCH_OPTIONAL) == 0 && (prec->ruleuid == RPA_PRODUCTION_CREF || prec->ruleuid == RPA_PRODUCTION_AREF ||
1078                                 prec->ruleuid == RPA_PRODUCTION_CHAR || prec->ruleuid == RPA_PRODUCTION_CLS || prec->ruleuid == RPA_PRODUCTION_SPECIALCHAR))
1079                         break;
1080
1081         }
1082
1083         r_array_removelast(dbex->recstack);
1084         return ret;
1085 }
1086
1087
1088 static int rpa_parseinfo_loopdetect(rpadbex_t *dbex, long parent, long loopto)
1089 {
1090         if (parent != loopto) {
1091                 /*
1092                  * Make sure we are dealing with a loop first
1093                  */
1094                 if (!rpa_parseinfo_loopdetect_do(dbex, loopto, parent, 0))
1095                         return 0;
1096         }
1097
1098         return (rpa_parseinfo_loopdetect_do(dbex, parent, loopto, 0)) ? 1 : 0;
1099 }
1100
1101
1102 static void rpa_parseinfo_marklooppath(rpadbex_t *dbex, long parent)
1103 {
1104         long i;
1105
1106         if (rpa_parseinfo_loopdetect(dbex, parent, parent) > 0) {
1107                 rpa_record_setusertype(dbex->records, parent, RPA_LOOP_PATH, RVALSET_OR);
1108                 for (i = rpa_recordtree_firstchild(dbex->records, parent, RPA_RECORD_START); i >= 0; i = rpa_recordtree_next(dbex->records, i, RPA_RECORD_START)) {
1109                         rpa_parseinfo_marklooppath(dbex, i);
1110                 }
1111         }
1112 }
1113
1114
1115 static int rpa_parseinfo_rule_checkforloop(rpadbex_t *dbex, const char *name, rsize_t namesize, long loopto)
1116 {
1117         rpa_ruleinfo_t *info = info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesize));
1118
1119         if (!info)
1120                 return 0;
1121         return rpa_parseinfo_loopdetect(dbex, info->startrec, loopto);
1122 }
1123
1124
1125 static void rpa_dbex_buildloopinfo(rpadbex_t *dbex)
1126 {
1127         unsigned int i, p;
1128         rharray_t *rules = dbex->rules;
1129         rpa_ruleinfo_t *info;
1130
1131         for (i = 0; i < r_array_length(rules->members); i++) {
1132                 if ((info = (rpa_ruleinfo_t *)r_harray_get(rules, i)) != NULL)
1133                         rpa_parseinfo_marklooppath(dbex, info->startrec);
1134         }
1135
1136         /*
1137          * Mark the non-loop branches.
1138          */
1139         for (i = 0; i < r_array_length(dbex->records); i++) {
1140                 rparecord_t *prec = (rparecord_t *)r_array_slot(dbex->records, i);
1141                 if (prec->type == RPA_RECORD_START &&
1142                         (prec->ruleuid == RPA_PRODUCTION_ALTBRANCH) &&
1143                         (prec->usertype & RPA_LOOP_PATH) == 0) {
1144                         p = rpa_recordtree_parent(dbex->records, i, RPA_RECORD_START);
1145                         if (p >= 0) {
1146                                 prec = (rparecord_t *)r_array_slot(dbex->records, p);
1147                                 if (prec && (prec->usertype & RPA_LOOP_PATH))
1148                                         rpa_record_setusertype(dbex->records, i, RPA_NONLOOP_PATH, RVALSET_OR);
1149                         }
1150                 }
1151         }
1152 }
1153
1154
1155 static void rpa_dbex_buildruleinfo(rpadbex_t *dbex)
1156 {
1157         rparecord_t *rec;
1158         rpa_ruleinfo_t info;
1159         unsigned int nrecords;
1160         long i;
1161         const char *name = NULL;
1162         rsize_t namesize = 0;
1163
1164         if (dbex->rules) {
1165                 r_object_destroy((robject_t *)dbex->rules);
1166                 dbex->rules = NULL;
1167         }
1168         dbex->rules = r_harray_create(sizeof(rpa_ruleinfo_t));
1169
1170         for (i = 0, nrecords = r_array_length(dbex->records); i < nrecords; i++) {
1171                 if (!(rec = rpa_dbex_record(dbex, i)))
1172                         continue;
1173                 if ((rec->ruleuid == RPA_PRODUCTION_NAMEDRULE) && (rec->type & RPA_RECORD_START)) {
1174                         r_memset(&info, 0, sizeof(info));
1175                         info.type = RPA_RULEINFO_NAMEDRULE;
1176                         info.startrec = i;
1177                         info.sizerecs = rpa_recordtree_size(dbex->records, i);
1178                         if (info.sizerecs < 0)
1179                                 continue;
1180                         if (rpa_dbex_rulename(dbex, i, &name, &namesize) < 0) {
1181                                 continue;
1182                         }
1183                         r_harray_add(dbex->rules, name, namesize, &info);
1184                         i += info.sizerecs - 1;
1185                 } else if ((rec->ruleuid == RPA_PRODUCTION_ANONYMOUSRULE) && (rec->type & RPA_RECORD_START)) {
1186                         r_memset(&info, 0, sizeof(info));
1187                         info.type = RPA_RULEINFO_ANONYMOUSRULE;
1188                         info.startrec = i;
1189                         info.sizerecs = rpa_recordtree_size(dbex->records, i);
1190                         if (info.sizerecs < 0)
1191                                 continue;
1192                         if ((rec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, i, RPA_RECORD_END))))
1193                                 r_harray_add(dbex->rules, rec->input, rec->inputsiz, &info);
1194                         i += info.sizerecs - 1;
1195                 } else if ((rec->type & RPA_RECORD_START) && (rec->ruleuid >= RPA_PRODUCTION_DIRECTIVEEMIT) && (rec->ruleuid <= RPA_PRODUCTION_DIRECTIVEEMITID)) {
1196                         r_memset(&info, 0, sizeof(info));
1197                         info.type = RPA_RULEINFO_DIRECTIVE;
1198                         info.startrec = i;
1199                         info.sizerecs = rpa_recordtree_size(dbex->records, i);
1200                         if (info.sizerecs < 0)
1201                                 continue;
1202                         if ((rec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, i, RPA_RECORD_END))))
1203                                 r_harray_add(dbex->rules, rec->input, rec->inputsiz, &info);
1204                         i += info.sizerecs - 1;
1205                 }
1206
1207         }
1208 }
1209
1210
1211 static long rpa_dbex_copy_handler(rarray_t *records, long rec, rpointer userdata)
1212 {
1213         rpadbex_t *dbex = (rpadbex_t *)userdata;
1214         long index;
1215
1216         rparecord_t *prec = (rparecord_t *)r_array_slot(records, rec);
1217         if (prec->ruleuid == RPA_PRODUCTION_OCCURENCE && (prec->type & RPA_RECORD_START)) {
1218                 /*
1219                  * Ignore it
1220                  */
1221         } else if (prec->ruleuid == RPA_PRODUCTION_OCCURENCE && (prec->type & (RPA_RECORD_END))) {
1222                 ruint32 usertype = RPA_MATCH_NONE;
1223                 long lastrec = 0;
1224                 /*
1225                  * Don't copy it but set the usertype of the previous record accordingly.
1226                  */
1227                 switch (*prec->input) {
1228                 case '?':
1229                         usertype = RPA_MATCH_OPTIONAL;
1230                         break;
1231                 case '+':
1232                         usertype = RPA_MATCH_MULTIPLE;
1233                         break;
1234                 case '*':
1235                         usertype = RPA_MATCH_MULTIOPT;
1236                         break;
1237                 default:
1238                         usertype = RPA_MATCH_NONE;
1239                 };
1240                 lastrec = r_array_length(dbex->records) - 1;
1241                 if (lastrec >= 0)
1242                         rpa_record_setusertype(dbex->records, lastrec, usertype, RVALSET_OR);
1243         } else if (prec->ruleuid) {
1244                 index = r_array_add(dbex->records, prec);
1245                 /*
1246                  * Optimizations. Lets apply the optimizations while we copy the records.
1247                  * This is probably not the most clean way to apply optimizations. In the future
1248                  * we should probably think of optimization pass right before compiling.
1249                  */
1250                 if (dbex->optimizations) {
1251                         if (prec->ruleuid == RPA_PRODUCTION_OROP && (prec->type & RPA_RECORD_END)) {
1252                                 rpa_optimiztion_orop(dbex->records, rpa_recordtree_get(dbex->records, index, RPA_RECORD_START));
1253                         }
1254                 }
1255         }
1256
1257         return 0;
1258 }
1259
1260
1261 static void rpa_dbex_copyrecords(rpadbex_t *dbex)
1262 {
1263         int i;
1264         rarray_t *records = dbex->temprecords;
1265
1266         for (i = rpa_recordtree_get(records, 0, RPA_RECORD_START); i >= 0; i = rpa_recordtree_next(records, i, RPA_RECORD_START))
1267                 rpa_recordtree_walk(records, i, 0, rpa_dbex_copy_handler, dbex);
1268 }
1269
1270
1271 static rparecord_t *rpa_dbex_record(rpadbex_t *dbex, long rec)
1272 {
1273         rparecord_t *prec;
1274
1275         if (!dbex || !dbex->rules)
1276                 return NULL;
1277         if (rec < 0 || rec >= r_array_length(dbex->records))
1278                 return NULL;
1279         prec = (rparecord_t *)r_array_slot(dbex->records, rec);
1280         return prec;
1281
1282 }
1283
1284
1285 static rparecord_t *rpa_dbex_rulerecord(rpadbex_t *dbex, rparule_t rid)
1286 {
1287         rparecord_t *prec;
1288         rpa_ruleinfo_t *info;
1289         long rec;
1290
1291         if (!dbex || !dbex->rules)
1292                 return NULL;
1293         info = r_harray_get(dbex->rules, rid);
1294         if (!info)
1295                 return NULL;
1296         rec = info->startrec + info->sizerecs - 1;
1297         if (rec < 0 || rec >= r_array_length(dbex->records))
1298                 return NULL;
1299         prec = (rparecord_t *)r_array_slot(dbex->records, rec);
1300         return prec;
1301 }
1302
1303
1304 static int rpa_dbex_rulename(rpadbex_t *dbex, long rec, const char **name, rsize_t *namesize)
1305 {
1306         rparecord_t *pnamerec = rpa_dbex_record(dbex, rpa_recordtree_firstchild(dbex->records, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_START), RPA_RECORD_END));
1307         if (!pnamerec || !(pnamerec->ruleuid & RPA_PRODUCTION_RULENAME))
1308                 return -1;
1309         *name = pnamerec->input;
1310         *namesize = pnamerec->inputsiz;
1311         return 0;
1312 }
1313
1314
1315 int rpa_dbex_open(rpadbex_t *dbex)
1316 {
1317         if (!dbex)
1318                 return -1;
1319         if (dbex->rules) {
1320                 r_object_destroy((robject_t *)dbex->rules);
1321                 dbex->rules = NULL;
1322         }
1323         dbex->compiled = 0;
1324         return 0;
1325 }
1326
1327
1328 void rpa_dbex_close(rpadbex_t *dbex)
1329 {
1330         if (!dbex)
1331                 return;
1332         rpa_dbex_buildruleinfo(dbex);
1333         rpa_dbex_buildloopinfo(dbex);
1334         if (dbex->bitmap)
1335                 rpa_dbex_buildbitmapinfo(dbex);
1336 }
1337
1338
1339 long rpa_dbex_load(rpadbex_t *dbex, const char *rules, rsize_t size)
1340 {
1341         long ret;
1342         char *text;
1343
1344         if (!dbex)
1345                 return -1;
1346         if (dbex->rules) {
1347                 /*
1348                  * Dbex is not open
1349                  */
1350                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTOPEN);
1351                 return -1;
1352         }
1353
1354         text = r_strndup(rules, size);
1355         R_ASSERT(text);
1356         r_array_add(dbex->text, &text);
1357         r_array_setlength(dbex->temprecords, 0);
1358         if ((ret = rpa_parser_load(dbex->pa, text, size, dbex->temprecords)) < 0) {
1359
1360                 return -1;
1361         }
1362         if (ret != size) {
1363                 long line = 1;
1364                 char *ptext = text;
1365                 ptext += ret;
1366                 for (line = 1; ptext >= text; --ptext) {
1367                         if (*ptext == '\n')
1368                                 line += 1;
1369                 }
1370                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAXERROR);
1371                 RPA_DBEX_SETERRINFO_OFFSET(dbex, ret);
1372                 RPA_DBEX_SETERRINFO_LINE(dbex, line);
1373                 return -1;
1374         }
1375         rpa_dbex_copyrecords(dbex);
1376         return ret;
1377 }
1378
1379
1380 long rpa_dbex_load_s(rpadbex_t *dbex, const char *rules)
1381 {
1382         return rpa_dbex_load(dbex, rules, r_strlen(rules));
1383 }
1384
1385
1386 void rpa_dbex_dumpindented(rpadbex_t *dbex, long rec, int level, const char *rulelabel)
1387 {
1388         char buffer[1024];
1389         int i, size;
1390         rparecord_t *prec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END));
1391
1392         if (!prec)
1393                 return;
1394         r_memset(buffer, 0, sizeof(buffer));
1395         r_printf("[ 0x%016lx ] ", prec->userdata);
1396         for (i = 0; i < level + 1; i++)
1397                 r_printf("   ");
1398         r_printf("(");
1399         r_printf("%s, %c, %c", rulelabel, rpa_record_optchar(prec, 'x'), rpa_record_loopchar(prec, 'x'));
1400         r_printf(")");
1401         size = R_MIN(prec->inputsiz, sizeof(buffer) - 1);
1402         r_strncpy(buffer, prec->input, size);
1403
1404         if (size == (sizeof(buffer) - 1))
1405                 r_printf(" %s ...\n", buffer);
1406         else
1407                 r_printf(" %s\n", buffer);
1408         return;
1409 }
1410
1411
1412 static long rpa_dbex_firstinlined(rpadbex_t *dbex)
1413 {
1414         long ret = r_array_empty(dbex->inlinestack) ? -1 : r_array_index(dbex->inlinestack, 0, long);
1415         return ret;
1416 }
1417
1418
1419 static int rpa_dbex_findinlined(rpadbex_t *dbex, long startrec)
1420 {
1421         long i;
1422         for (i = 0; i < r_array_length(dbex->inlinestack); i++) {
1423                 if (r_array_index(dbex->inlinestack, i, long) == startrec)
1424                         return 1;
1425         }
1426         return 0;
1427 }
1428
1429
1430 static void rpa_dbex_dumptree_do(rpadbex_t *dbex, long rec, int level)
1431 {
1432         rparecord_t *prec = rpa_dbex_record(dbex, rec);
1433         if (prec && prec->ruleuid == RPA_PRODUCTION_RULENAME)
1434                 return;
1435         if (prec && (prec->ruleuid == RPA_PRODUCTION_AREF || prec->ruleuid == RPA_PRODUCTION_CREF)) {
1436                 const char *name = NULL;
1437                 rsize_t namesize = 0;
1438                 int loop = 0;
1439                 rpa_ruleinfo_t *info;
1440
1441                 if (rpa_dbex_rulename(dbex, rec, &name, &namesize) >= 0) {
1442                         loop = rpa_parseinfo_rule_checkforloop(dbex, name, namesize, rpa_dbex_firstinlined(dbex));
1443                         info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesize));
1444                         if (loop && info){
1445                                 if (!rpa_dbex_findinlined(dbex, info->startrec)) {
1446                                         /*
1447                                          * Temporary set the quantitative flags for the inlined rule to the parent
1448                                          * reference, so they are printed correctly. After the printing is done
1449                                          * restore the original flags.
1450                                          */
1451                                         rparecord_t *prulestart = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, info->startrec, RPA_RECORD_START));
1452                                         rparecord_t *pruleend = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, info->startrec, RPA_RECORD_END));
1453                                         unsigned long optional = (prulestart->usertype & RPA_MATCH_OPTIONAL);
1454                                         prulestart->usertype |= (prec->usertype & RPA_MATCH_OPTIONAL);
1455                                         pruleend->usertype |= (prec->usertype & RPA_MATCH_OPTIONAL);
1456                                         r_array_add(dbex->inlinestack, &info->startrec);
1457                                         rpa_dbex_dumptree_do(dbex, info->startrec, level);
1458                                         r_array_removelast(dbex->inlinestack);
1459                                         if (!optional) {
1460                                                 prulestart->usertype &= ~RPA_MATCH_OPTIONAL;
1461                                                 pruleend->usertype &= ~RPA_MATCH_OPTIONAL;
1462                                         }
1463                                 } else {
1464                                         rpa_dbex_dumpindented(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END), level, "loopref");
1465                                 }
1466                                 return;
1467                         }
1468                 }
1469         }
1470         rpa_dbex_dumpindented(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END), level, prec->rule);
1471         for (rec = rpa_recordtree_firstchild(dbex->records, rec, RPA_RECORD_START); rec >= 0; rec = rpa_recordtree_next(dbex->records, rec, RPA_RECORD_START)) {
1472                 rpa_dbex_dumptree_do(dbex, rec, level + 1);
1473         }
1474 }
1475
1476
1477 int rpa_dbex_dumptree(rpadbex_t *dbex, rparule_t rid)
1478 {
1479         rpa_ruleinfo_t *info;
1480
1481         if (!dbex)
1482                 return -1;
1483         if (rid < 0) {
1484                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_PARAM);
1485                 return -1;
1486         }
1487         if (!dbex->rules) {
1488                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1489                 return -1;
1490         }
1491         if (!(info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid))) {
1492                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1493                 return -1;
1494         }
1495         r_array_add(dbex->inlinestack, &info->startrec);
1496         rpa_dbex_dumptree_do(dbex, info->startrec, 0);
1497         r_array_removelast(dbex->inlinestack);
1498         return 0;
1499 }
1500
1501
1502 int rpa_dbex_dumpproductions(rpadbex_t *dbex)
1503 {
1504         int ret = 0;
1505         rparule_t rid;
1506         char buffer[512];
1507
1508         if (!dbex)
1509                 return -1;
1510         if (!dbex->rules) {
1511                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1512                 return -1;
1513         }
1514         for (rid = rpa_dbex_first(dbex); rid >= 0; rid = rpa_dbex_next(dbex, rid)) {
1515                 ret = rpa_dbex_strncpy(dbex, buffer, rid, sizeof(buffer));
1516                 if ( ret >= 0) {
1517                         if (ret == sizeof(buffer))
1518                                 r_printf("   %s ...\n", buffer);
1519                         else
1520                                 r_printf("   %s\n", buffer);
1521                 }
1522
1523         }
1524         return ret;
1525 }
1526
1527
1528 int rpa_dbex_dumprecords(rpadbex_t *dbex)
1529 {
1530         long i;
1531
1532         if (!dbex)
1533                 return -1;
1534         if (!dbex->rules) {
1535                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1536                 return -1;
1537         }
1538         for (i = 0; i < r_array_length(dbex->records); i++) {
1539                 rpa_record_dump(dbex->records, i);
1540         }
1541         return 0;
1542 }
1543
1544
1545 int rpa_dbex_dumpinfo(rpadbex_t *dbex)
1546 {
1547         long i;
1548         rpa_ruleinfo_t *info;
1549
1550         if (!dbex)
1551                 return -1;
1552         if (!dbex->rules) {
1553                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1554                 return -1;
1555         }
1556         for (i = 0; i < r_array_length(dbex->rules->names); i++) {
1557                 rstr_t *name = r_array_index(dbex->rules->names, i, rstr_t*);
1558                 info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, i);
1559                 switch (info->type) {
1560                 case RPA_RULEINFO_NAMEDRULE:
1561                         r_printf("N ");
1562                         break;
1563                 case RPA_RULEINFO_ANONYMOUSRULE:
1564                         r_printf("A ");
1565                         break;
1566                 case RPA_RULEINFO_DIRECTIVE:
1567                         r_printf("D ");
1568                         break;
1569                 default:
1570                         r_printf("  ");
1571                         break;
1572                 };
1573                 r_printf("(%7d, %4d, code: %7ld, %5ld) : %s\n", info->startrec, info->sizerecs, info->codeoff, info->codesiz, name->str);
1574         }
1575         return 0;
1576 }
1577
1578
1579 int rpa_dbex_dumpuids(rpadbex_t *dbex)
1580 {
1581         long i;
1582         long rec;
1583         rpa_ruleinfo_t *info;
1584         char *buffer = r_zmalloc(32 * sizeof(char));
1585
1586         if (!dbex)
1587                 return -1;
1588         if (!dbex->rules) {
1589                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1590                 return -1;
1591         }
1592         for (i = 0; i < r_array_length(dbex->rules->names); i++) {
1593                 info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, i);
1594                 if (info->type == RPA_RULEINFO_DIRECTIVE) {
1595                         rparecord_t *prec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, info->startrec, RPA_RECORD_END));
1596                         if (prec->ruleuid == RPA_PRODUCTION_DIRECTIVEEMITID && prec->inputsiz) {
1597                                 rec = rpa_recordtree_firstchild(dbex->records, info->startrec, RPA_RECORD_START);
1598                                 while (rec >= 0) {
1599                                         prec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END));
1600                                         if (prec->ruleuid == RPA_PRODUCTION_ALIASNAME) {
1601                                                 ruint32 dec;
1602                                                 if (rpa_record2long(rpa_dbex_record(dbex, rpa_recordtree_next(dbex->records, rec, RPA_RECORD_END)), &dec) < 0)
1603                                                         break;
1604                                                 buffer = r_realloc(buffer, prec->inputsiz + 1);
1605                                                 r_memset(buffer, 0, prec->inputsiz + 1);
1606                                                 r_memcpy(buffer, prec->input, prec->inputsiz);
1607                                                 r_printf("#define %s %d\n", buffer, dec);
1608                                                 break;
1609                                         }
1610                                         rec = rpa_recordtree_next(dbex->records, rec, RPA_RECORD_START);
1611                                 }
1612                         }
1613                 }
1614         }
1615         r_free(buffer);
1616         return 0;
1617 }
1618
1619
1620 int rpa_dbex_dumpcode(rpadbex_t* dbex, rparule_t rid)
1621 {
1622         rpa_ruleinfo_t *info;
1623         if (!dbex)
1624                 return -1;
1625         if (rid < 0) {
1626                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_PARAM);
1627                 return -1;
1628         }
1629         if (!dbex->rules) {
1630                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1631                 return -1;
1632         }
1633         info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid);
1634         if (!info)
1635                 return -1;
1636         rvm_asm_dump(rvm_codegen_getcode(dbex->co->cg, info->codeoff), info->codesiz);
1637         return 0;
1638 }
1639
1640
1641 rsize_t rpa_dbex_strlen(rpadbex_t *dbex, rparule_t rid)
1642 {
1643         rparecord_t *prec;
1644         rsize_t size;
1645
1646         if (!dbex)
1647                 return -1;
1648         if ((prec = rpa_dbex_rulerecord(dbex, rid)) == NULL) {
1649                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1650                 return -1;
1651         }
1652         size = prec->inputsiz;
1653         return size;
1654 }
1655
1656
1657 rsize_t rpa_dbex_strncpy(rpadbex_t *dbex, char *dst, rparule_t rid, rsize_t n)
1658 {
1659         rparecord_t *prec;
1660         rsize_t size;
1661
1662         if (!dbex)
1663                 return -1;
1664         if ((prec = rpa_dbex_rulerecord(dbex, rid)) == NULL) {
1665                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1666                 return -1;
1667         }
1668         size = prec->inputsiz;
1669         if (n <= size)
1670                 size = n - 1;
1671         r_memset(dst, 0, n);
1672         r_strncpy(dst, prec->input, size);
1673         return size + 1;
1674 }
1675
1676
1677 const char *rpa_dbex_name(rpadbex_t *dbex, rparule_t rid)
1678 {
1679         rstr_t *name;
1680
1681         if (!dbex)
1682                 return NULL;
1683         if (!dbex->rules) {
1684                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1685                 return NULL;
1686         }
1687         if (rid >= r_array_length(dbex->rules->members))
1688                 return NULL;
1689         name = r_array_index(dbex->rules->names, rid, rstr_t*);
1690         return name->str;
1691 }
1692
1693
1694 rparule_t rpa_dbex_first(rpadbex_t *dbex)
1695 {
1696         if (!dbex)
1697                 return -1;
1698         if (!dbex->rules) {
1699                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1700                 return -1;
1701         }
1702
1703         if (r_array_length(dbex->rules->members) <= 0) {
1704                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1705                 return -1;
1706         }
1707         return 0;
1708 }
1709
1710
1711 rparule_t rpa_dbex_last(rpadbex_t *dbex)
1712 {
1713         if (!dbex)
1714                 return -1;
1715         if (!dbex->rules) {
1716                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1717                 return -1;
1718         }
1719
1720         if (r_array_length(dbex->rules->members) <= 0) {
1721                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1722                 return -1;
1723         }
1724         return r_array_length(dbex->rules->members) - 1;
1725 }
1726
1727
1728 rparule_t rpa_dbex_lookup(rpadbex_t *dbex, const char *name, rsize_t namesize)
1729 {
1730         rparule_t ret;
1731
1732         if (!dbex) {
1733                 return -1;
1734         }
1735         if (!dbex->rules) {
1736                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1737                 return -1;
1738         }
1739
1740         ret = (rparule_t) r_harray_taillookup(dbex->rules, name, namesize);
1741         if (ret < 0) {
1742                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1743         }
1744         return ret;
1745 }
1746
1747
1748 rparule_t rpa_dbex_lookup_s(rpadbex_t *dbex, const char *name)
1749 {
1750         return rpa_dbex_lookup(dbex, name, r_strlen(name));
1751 }
1752
1753
1754 rparule_t rpa_dbex_next(rpadbex_t *dbex, rparule_t rid)
1755 {
1756         if (!dbex)
1757                 return -1;
1758         if (!dbex->rules) {
1759                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1760                 return -1;
1761         }
1762
1763         ++rid;
1764         if (rid < r_array_length(dbex->rules->members))
1765                 return rid;
1766         return -1;
1767 }
1768
1769
1770 rparule_t rpa_dbex_prev(rpadbex_t *dbex, rparule_t rid)
1771 {
1772         if (!dbex)
1773                 return -1;
1774         if (!dbex->rules) {
1775                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1776                 return -1;
1777         }
1778         --rid;
1779         if (rid >= 0)
1780                 return rid;
1781         return -1;
1782 }
1783
1784
1785 long rpa_dbex_lasterror(rpadbex_t *dbex)
1786 {
1787         if (!dbex)
1788                 return -1;
1789         return dbex->err.code;
1790 }
1791
1792
1793 long rpa_dbex_lasterrorinfo(rpadbex_t *dbex, rpa_errinfo_t *errinfo)
1794 {
1795         if (!dbex || !errinfo)
1796                 return -1;
1797         r_memcpy(errinfo, &dbex->err, sizeof(rpa_errinfo_t));
1798         return 0;
1799 }
1800
1801
1802 const char *rpa_dbex_version()
1803 {
1804         return "2.0";
1805 }
1806
1807
1808 static int rpa_dbex_compile_rule(rpadbex_t *dbex, rparule_t rid)
1809 {
1810         long codeoff;
1811         rpa_ruleinfo_t *info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid);
1812
1813         if (!info)
1814                 return -1;
1815         codeoff = rvm_codegen_getcodesize(dbex->co->cg);
1816         /*
1817          * Set the rid in the rulepref, so the compiler associates this rule
1818          * with the correct rid.
1819          */
1820         rpa_compiler_rulepref_set_ruleid_s(dbex->co, rpa_dbex_name(dbex, rid), rid);
1821         if (rpa_dbex_playrecord(dbex, info->startrec) < 0)
1822                 return -1;
1823         info->codeoff = codeoff;
1824         info->codesiz = rvm_codegen_getcodesize(dbex->co->cg) - codeoff;
1825         return 0;
1826 }
1827
1828
1829 int rpa_dbex_compile(rpadbex_t *dbex)
1830 {
1831         rparule_t rid;
1832         rvm_codelabel_t *labelerr;
1833
1834         if (!dbex)
1835                 return -1;
1836         if (!dbex->rules) {
1837                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1838                 return -1;
1839         }
1840         /*
1841          * By default all production rules emit
1842          */
1843         if (dbex->co)
1844                 rpa_compiler_destroy(dbex->co);
1845         dbex->co = rpa_compiler_create();
1846         rpa_dbex_setemit(dbex, TRUE);
1847
1848         for (rid = rpa_dbex_first(dbex); rid >= 0; rid = rpa_dbex_next(dbex, rid)) {
1849                 if (rpa_dbex_compile_rule(dbex, rid) < 0) {
1850                         RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_COMPILE);
1851                         return -1;
1852                 }
1853         }
1854
1855         if (rvm_codegen_relocate(dbex->co->cg, &labelerr) < 0) {
1856                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_UNRESOLVEDSYMBOL);
1857                 RPA_DBEX_SETERRINFO_NAME(dbex, labelerr->name->str, labelerr->name->size);
1858                 return -1;
1859         }
1860         dbex->compiled = 1;
1861         return 0;
1862 }
1863
1864
1865 rvm_asmins_t *rpa_dbex_executable(rpadbex_t *dbex)
1866 {
1867         if (!dbex)
1868                 return NULL;
1869         if (!dbex->rules) {
1870                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1871                 return NULL;
1872         }
1873         if (!dbex->compiled || rvm_codegen_getcodesize(dbex->co->cg) == 0) {
1874                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCOMPILED);
1875                 return NULL;
1876         }
1877         return rvm_codegen_getcode(dbex->co->cg, 0);
1878 }
1879
1880
1881 long rpa_dbex_executableoffset(rpadbex_t *dbex, rparule_t rid)
1882 {
1883         rpa_ruleinfo_t *info;
1884
1885         if (!dbex)
1886                 return -1;
1887         if (!dbex->rules) {
1888                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1889                 return -1;
1890         }
1891         if (!dbex->compiled) {
1892                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCOMPILED);
1893                 return -1;
1894         }
1895         info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid);
1896         if (!info) {
1897                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1898                 return -1;
1899         }
1900         return info->codeoff;
1901 }
1902
1903
1904 long rpa_dbex_cfgset(rpadbex_t *dbex, unsigned long cfg, unsigned long val)
1905 {
1906         if (!dbex)
1907                 return -1;
1908         if (cfg == RPA_DBEXCFG_OPTIMIZATIONS) {
1909                 dbex->optimizations = val;
1910                 return 0;
1911         } else if(cfg == RPA_DBEXCFG_DEBUG) {
1912                 dbex->debug = val;
1913                 return 0;
1914         } else if(cfg == RPA_DBEXCFG_BITMAP) {
1915                 dbex->bitmap = val;
1916                 return 0;
1917         }
1918         return -1;
1919 }
1920
1921
1922 long rpa_dbex_cfgget(rpadbex_t *dbex, unsigned long cfg)
1923 {
1924         if (!dbex)
1925                 return -1;
1926         if (cfg == RPA_DBEXCFG_OPTIMIZATIONS) {
1927                 return dbex->optimizations;
1928         } else if(cfg == RPA_DBEXCFG_DEBUG) {
1929                 return dbex->debug;
1930         } else if(cfg == RPA_DBEXCFG_BITMAP) {
1931                 return dbex->bitmap;
1932         }
1933         return -1;
1934 }
1935