RPA Toolkit
work on bitmap operations
[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                 rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_BL, DA, XX, XX, 3));
411                 rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_EMITTAIL, XX, XX, XX, 0));
412                 rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_EXT, XX, XX, XX, 0));
413
414                 if ((prec->usertype & RPA_LOOP_PATH)) {
415                         rpa_compiler_loop_begin(dbex->co, name, namesize);
416                 } else {
417 #if 0
418                         rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_MATCHBITMAP, DA, XX, XX, prec->userdata));
419                         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_BXLES, LR, XX, XX, 0));
420 #endif
421                         rpa_compiler_rule_begin(dbex->co, name, namesize, RPA_BITMAP_GETVAL(RPA_RECORD2BITMAP(prec)));
422                 }
423         }
424         r_array_add(dbex->inlinestack, &rec);
425         rpa_dbex_debug_recordtail(dbex, rec);
426         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
427                 return -1;
428         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
429         prec = rpa_dbex_record(dbex, rec);
430         R_ASSERT(prec);
431         rpa_dbex_debug_recordhead(dbex, rec);
432         r_array_removelast(dbex->inlinestack);
433         if (!r_array_empty(dbex->inlinestack)) {
434                 rpa_compiler_inlinerule_end(dbex->co);
435         } else {
436                 if ((prec->usertype & RPA_LOOP_PATH)) {
437                         rpa_compiler_loop_end(dbex->co);
438                 } else {
439                         rpa_compiler_rule_end(dbex->co);
440                 }
441         }
442         rpa_dbex_debug_recordtail(dbex, rec);
443         return 0;
444 }
445
446
447 static int rpa_dbex_rh_anonymousrule(rpadbex_t *dbex, long rec)
448 {
449         rarray_t *records = dbex->records;
450         rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
451
452         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
453         prec = rpa_dbex_record(dbex, rec);
454         R_ASSERT(prec);
455         rpa_dbex_debug_recordhead(dbex, rec);
456         rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_SHIFT, XX, XX, XX, 0));
457         rpa_compiler_exp_begin(dbex->co, RPA_MATCH_NONE);
458         rpa_dbex_debug_recordtail(dbex, rec);
459         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
460                 return -1;
461         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
462         prec = rpa_dbex_record(dbex, rec);
463         R_ASSERT(prec);
464         rpa_dbex_debug_recordhead(dbex, rec);
465         rpa_compiler_exp_end(dbex->co);
466         rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_EMITTAIL, XX, XX, XX, 0));
467         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_EXT, XX, XX, XX, 0));
468         rpa_dbex_debug_recordtail(dbex, rec);
469
470         return 0;
471 }
472
473
474 static int rpa_dbex_rh_char(rpadbex_t *dbex, long rec)
475 {
476         rparecord_t *prec;
477         rarray_t *records = dbex->records;
478         ruint32 wc = 0;
479
480         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
481         prec = rpa_dbex_record(dbex, rec);
482         R_ASSERT(prec);
483         rpa_dbex_debug_recordhead(dbex, rec);
484         rpa_dbex_debug_recordtail(dbex, rec);
485         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
486                 return -1;
487         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
488         prec = rpa_dbex_record(dbex, rec);
489         R_ASSERT(prec);
490         rpa_dbex_debug_recordhead(dbex, rec);
491         if (r_utf8_mbtowc(&wc, (const unsigned char*) prec->input, (const unsigned char*)prec->input + prec->inputsiz) < 0) {
492
493                 return -1;
494         }
495         rvm_codegen_addins(dbex->co->cg, rvm_asm(rpa_dbex_getmatchchr(prec->usertype & RPA_MATCH_MASK), DA, XX, XX, wc));
496         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
497         rpa_dbex_debug_recordtail(dbex, rec);
498         return 0;
499 }
500
501
502 static int rpa_dbex_rh_specialchar(rpadbex_t *dbex, long rec)
503 {
504         ruint32 wc = 0;
505         rarray_t *records = dbex->records;
506         rparecord_t *prec;
507
508         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
509         prec = rpa_dbex_record(dbex, rec);
510         R_ASSERT(prec);
511         rpa_dbex_debug_recordhead(dbex, rec);
512         rpa_dbex_debug_recordtail(dbex, rec);
513         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
514                 return -1;
515         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
516         prec = rpa_dbex_record(dbex, rec);
517         R_ASSERT(prec);
518         rpa_dbex_debug_recordhead(dbex, rec);
519         if (r_utf8_mbtowc(&wc, (const unsigned char*) prec->input, (const unsigned char*)prec->input + prec->inputsiz) < 0) {
520
521                 return -1;
522         }
523         rvm_codegen_addins(dbex->co->cg, rvm_asm(rpa_dbex_getmatchspecialchr(prec->usertype & RPA_MATCH_MASK), DA, XX, XX, wc));
524         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
525         rpa_dbex_debug_recordtail(dbex, rec);
526         return 0;
527 }
528
529
530 static int rpa_dbex_rh_cls(rpadbex_t *dbex, long rec)
531 {
532         rarray_t *records = dbex->records;
533         rparecord_t *prec;
534
535         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
536         prec = rpa_dbex_record(dbex, rec);
537         R_ASSERT(prec);
538         rpa_dbex_debug_recordhead(dbex, rec);
539         rpa_compiler_class_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
540         rpa_dbex_debug_recordtail(dbex, rec);
541         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
542                 return -1;
543         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
544         prec = rpa_dbex_record(dbex, rec);
545         R_ASSERT(prec);
546         rpa_dbex_debug_recordhead(dbex, rec);
547         rpa_compiler_class_end(dbex->co);
548         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
549         rpa_dbex_debug_recordtail(dbex, rec);
550         return 0;
551 }
552
553
554 static int rpa_dbex_rh_clschar(rpadbex_t *dbex, long rec)
555 {
556         ruint32 wc = 0;
557         rarray_t *records = dbex->records;
558         rparecord_t *prec;
559
560         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
561         prec = rpa_dbex_record(dbex, rec);
562         R_ASSERT(prec);
563         rpa_dbex_debug_recordhead(dbex, rec);
564         rpa_dbex_debug_recordtail(dbex, rec);
565         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
566                 return -1;
567         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
568         prec = rpa_dbex_record(dbex, rec);
569         R_ASSERT(prec);
570         rpa_dbex_debug_recordhead(dbex, rec);
571         if (r_utf8_mbtowc(&wc, (const unsigned char*) prec->input, (const unsigned char*)prec->input + prec->inputsiz) < 0) {
572
573                 return -1;
574         }
575         rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, wc));
576         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
577         rpa_dbex_debug_recordtail(dbex, rec);
578         return 0;
579 }
580
581
582 static int rpa_dbex_rh_minexp(rpadbex_t *dbex, long rec)
583 {
584         rarray_t *records = dbex->records;
585         rparecord_t *prec;
586
587         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
588         prec = rpa_dbex_record(dbex, rec);
589         R_ASSERT(prec);
590         rpa_dbex_debug_recordhead(dbex, rec);
591         rpa_compiler_exp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
592         rpa_dbex_debug_recordtail(dbex, rec);
593         if (rpa_dbex_playreversechildrecords(dbex, rec) < 0)
594                 return -1;
595         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
596         prec = rpa_dbex_record(dbex, rec);
597         R_ASSERT(prec);
598         rpa_dbex_debug_recordhead(dbex, rec);
599         rpa_compiler_exp_end(dbex->co);
600         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
601         rpa_dbex_debug_recordtail(dbex, rec);
602         return 0;
603 }
604
605
606 static int rpa_dbex_rh_exp(rpadbex_t *dbex, long rec)
607 {
608         rarray_t *records = dbex->records;
609         rparecord_t *prec;
610
611         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
612         prec = rpa_dbex_record(dbex, rec);
613         R_ASSERT(prec);
614         rpa_dbex_debug_recordhead(dbex, rec);
615         rpa_compiler_exp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
616         rpa_dbex_debug_recordtail(dbex, rec);
617         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
618                 return -1;
619         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
620         prec = rpa_dbex_record(dbex, rec);
621         R_ASSERT(prec);
622         rpa_dbex_debug_recordhead(dbex, rec);
623         rpa_compiler_exp_end(dbex->co);
624         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
625         rpa_dbex_debug_recordtail(dbex, rec);
626         return 0;
627 }
628
629
630 static int rpa_dbex_rh_orop(rpadbex_t *dbex, long rec)
631 {
632         rarray_t *records = dbex->records;
633         rparecord_t *prec;
634
635         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
636         prec = rpa_dbex_record(dbex, rec);
637         R_ASSERT(prec);
638         rpa_dbex_debug_recordhead(dbex, rec);
639         rpa_compiler_altexp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK, RPA_BITMAP_GETVAL(RPA_RECORD2BITMAP(prec)));
640         rpa_dbex_debug_recordtail(dbex, rec);
641         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
642                 return -1;
643         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
644         prec = rpa_dbex_record(dbex, rec);
645         R_ASSERT(prec);
646         rpa_dbex_debug_recordhead(dbex, rec);
647         rpa_compiler_altexp_end(dbex->co);
648         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
649         rpa_dbex_debug_recordtail(dbex, rec);
650         return 0;
651 }
652
653
654 static int rpa_dbex_rh_norop(rpadbex_t *dbex, long rec)
655 {
656         rarray_t *records = dbex->records;
657         rparecord_t *prec;
658
659         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
660         prec = rpa_dbex_record(dbex, rec);
661         R_ASSERT(prec);
662         rpa_dbex_debug_recordhead(dbex, rec);
663         rpa_compiler_altexp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK, 0);
664         rpa_dbex_debug_recordtail(dbex, rec);
665         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
666                 return -1;
667         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
668         prec = rpa_dbex_record(dbex, rec);
669         R_ASSERT(prec);
670         rpa_dbex_debug_recordhead(dbex, rec);
671         rpa_compiler_altexp_end(dbex->co);
672         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
673         rpa_dbex_debug_recordtail(dbex, rec);
674         return 0;
675 }
676
677
678 static int rpa_dbex_rh_notop(rpadbex_t *dbex, long rec)
679 {
680         rarray_t *records = dbex->records;
681         rparecord_t *prec;
682
683         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
684         prec = rpa_dbex_record(dbex, rec);
685         R_ASSERT(prec);
686         rpa_dbex_debug_recordhead(dbex, rec);
687         rpa_compiler_notexp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
688         rpa_dbex_debug_recordtail(dbex, rec);
689         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
690                 return -1;
691         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
692         prec = rpa_dbex_record(dbex, rec);
693         R_ASSERT(prec);
694         rpa_dbex_debug_recordhead(dbex, rec);
695         rpa_compiler_notexp_end(dbex->co);
696         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
697         rpa_dbex_debug_recordtail(dbex, rec);
698         return 0;
699 }
700
701
702 static int rpa_dbex_rh_range(rpadbex_t *dbex, long rec)
703 {
704         rarray_t *records = dbex->records;
705         rparecord_t *prec;
706
707         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
708         prec = rpa_dbex_record(dbex, rec);
709         R_ASSERT(prec);
710         rpa_dbex_debug_recordhead(dbex, rec);
711         dbex->co->currange.p1 = 0;
712         dbex->co->currange.p2 = 0;
713         rpa_dbex_debug_recordtail(dbex, rec);
714         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
715                 return -1;
716         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
717         prec = rpa_dbex_record(dbex, rec);
718         R_ASSERT(prec);
719         rpa_dbex_debug_recordhead(dbex, rec);
720         if (dbex->co->currange.p1 < dbex->co->currange.p2)
721                 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p1, dbex->co->currange.p2));
722         else
723                 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p2, dbex->co->currange.p1));
724         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
725         rpa_dbex_debug_recordtail(dbex, rec);
726         return 0;
727 }
728
729
730 static int rpa_dbex_rh_numrange(rpadbex_t *dbex, long rec)
731 {
732         rarray_t *records = dbex->records;
733         rparecord_t *prec;
734         rparecord_t *child;
735         /*
736          * Fix me: probably we don't need to access the children from here. There should be a way just to
737          * play them a regular records!
738          */
739
740         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
741         prec = rpa_dbex_record(dbex, rec);
742         R_ASSERT(prec);
743         rpa_dbex_debug_recordhead(dbex, rec);
744         child = rpa_dbex_record(dbex, rpa_recordtree_firstchild(dbex->records, rec, RPA_RECORD_END));
745         if (rpa_record2long(child, &dbex->co->currange.p1) < 0)
746                 return -1;
747         child = rpa_dbex_record(dbex, rpa_recordtree_lastchild(dbex->records, rec, RPA_RECORD_END));
748         if (rpa_record2long(child, &dbex->co->currange.p2) < 0)
749                 return -1;
750         rpa_dbex_debug_recordtail(dbex, rec);
751         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
752                 return -1;
753         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
754         prec = rpa_dbex_record(dbex, rec);
755         R_ASSERT(prec);
756         rpa_dbex_debug_recordhead(dbex, rec);
757         if (dbex->co->currange.p1 < dbex->co->currange.p2)
758                 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p1, dbex->co->currange.p2));
759         else
760                 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p2, dbex->co->currange.p1));
761         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
762         rpa_dbex_debug_recordtail(dbex, rec);
763         return 0;
764 }
765
766
767 static int rpa_dbex_rh_clsnum(rpadbex_t *dbex, long rec)
768 {
769         rarray_t *records = dbex->records;
770         rparecord_t *prec;
771         rparecord_t *child;
772         ruint32 wc;
773
774         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
775         prec = rpa_dbex_record(dbex, rec);
776         R_ASSERT(prec);
777         rpa_dbex_debug_recordhead(dbex, rec);
778         rpa_dbex_debug_recordtail(dbex, rec);
779         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
780                 return -1;
781         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
782         prec = rpa_dbex_record(dbex, rec);
783         R_ASSERT(prec);
784         rpa_dbex_debug_recordhead(dbex, rec);
785         child = rpa_dbex_record(dbex, rpa_recordtree_firstchild(dbex->records, rec, RPA_RECORD_END));
786         if (rpa_record2long(child, &wc) < 0)
787                 return -1;
788         rvm_codegen_addins(dbex->co->cg, rvm_asm(rpa_dbex_getmatchchr(prec->usertype & RPA_MATCH_MASK), DA, XX, XX, wc));
789         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
790         rpa_dbex_debug_recordtail(dbex, rec);
791         return 0;
792 }
793
794
795 static int rpa_dbex_rh_beginchar(rpadbex_t *dbex, long rec)
796 {
797         rarray_t *records = dbex->records;
798         rparecord_t *prec;
799         ruint32 wc = 0;
800
801         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
802         prec = rpa_dbex_record(dbex, rec);
803         R_ASSERT(prec);
804         rpa_dbex_debug_recordhead(dbex, rec);
805         rpa_dbex_debug_recordtail(dbex, rec);
806         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
807                 return -1;
808         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
809         prec = rpa_dbex_record(dbex, rec);
810         R_ASSERT(prec);
811         rpa_dbex_debug_recordhead(dbex, rec);
812         if (r_utf8_mbtowc(&wc, (const unsigned char*) prec->input, (const unsigned char*)prec->input + prec->inputsiz) < 0) {
813
814                 return -1;
815         }
816         dbex->co->currange.p1 = wc;
817         rpa_dbex_debug_recordtail(dbex, rec);
818         return 0;
819 }
820
821
822 static int rpa_dbex_rh_endchar(rpadbex_t *dbex, long rec)
823 {
824         rarray_t *records = dbex->records;
825         rparecord_t *prec;
826         ruint32 wc = 0;
827
828         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
829         prec = rpa_dbex_record(dbex, rec);
830         R_ASSERT(prec);
831         rpa_dbex_debug_recordhead(dbex, rec);
832         rpa_dbex_debug_recordtail(dbex, rec);
833         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
834                 return -1;
835         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
836         prec = rpa_dbex_record(dbex, rec);
837         R_ASSERT(prec);
838         rpa_dbex_debug_recordhead(dbex, rec);
839         if (r_utf8_mbtowc(&wc, (const unsigned char*) prec->input, (const unsigned char*)prec->input + prec->inputsiz) < 0) {
840
841                 return -1;
842         }
843         dbex->co->currange.p2 = wc;
844         rpa_dbex_debug_recordtail(dbex, rec);
845         return 0;
846 }
847
848
849 static int rpa_dbex_rh_branch(rpadbex_t *dbex, long rec)
850 {
851         rarray_t *records = dbex->records;
852         rparecord_t *prec;
853
854         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
855         prec = rpa_dbex_record(dbex, rec);
856         R_ASSERT(prec);
857         rpa_dbex_debug_recordhead(dbex, rec);
858         if (prec->usertype & RPA_NONLOOP_PATH) {
859                 rpa_compiler_nonloopybranch_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
860         } else {
861                 rpa_compiler_branch_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
862         }
863         rpa_dbex_debug_recordtail(dbex, rec);
864         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
865                 return -1;
866         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
867         prec = rpa_dbex_record(dbex, rec);
868         R_ASSERT(prec);
869         rpa_dbex_debug_recordhead(dbex, rec);
870         if (prec->usertype & RPA_NONLOOP_PATH) {
871                 rpa_compiler_nonloopybranch_end(dbex->co);
872         } else {
873                 rpa_compiler_branch_end(dbex->co);
874         }
875         rpa_dbex_debug_recordtail(dbex, rec);
876         return 0;
877 }
878
879
880 static void rpa_dbex_rh_loopref(rpadbex_t *dbex, rparecord_t *prec)
881 {
882         /*
883          * We ignore, it doesn't make sense for loops:
884          * RPA_MATCH_MULTIPLE
885          */
886         rpa_compiler_exp_begin(dbex->co, (prec->usertype & RPA_MATCH_OPTIONAL));
887         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_CMP, R_LOO, DA, XX, 0));
888         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_BGRE, DA, XX, XX, 3));
889         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
890         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
891         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_ADD, R_TOP, R_TOP, R_LOO, 0));
892         rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_MOVS, R0, R_LOO, XX, 0));
893         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
894         rpa_compiler_exp_end(dbex->co);
895 }
896
897
898 static int rpa_dbex_rh_aref(rpadbex_t *dbex, long rec)
899 {
900         const char *name = NULL;
901         rsize_t namesize;
902         rpa_ruleinfo_t *info;
903         rarray_t *records = dbex->records;
904         rparecord_t *prec;
905
906         rec = rpa_recordtree_get(records, rec, RPA_RECORD_START);
907         prec = rpa_dbex_record(dbex, rec);
908         R_ASSERT(prec);
909         rpa_dbex_debug_recordhead(dbex, rec);
910         if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
911
912                 return -1;
913         }
914
915         if ((prec->usertype & RPA_LOOP_PATH) && rpa_parseinfo_loopdetect(dbex, rec, rpa_dbex_firstinlined(dbex))) {
916                 info = (rpa_ruleinfo_t *) r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesize));
917                 if (!info) {
918                         RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_UNRESOLVEDSYMBOL);
919                         RPA_DBEX_SETERRINFO_NAME(dbex, name, namesize);
920                         return -1;
921                 }
922                 if (rpa_dbex_findinlined(dbex, info->startrec)) {
923                         rpa_dbex_rh_loopref(dbex, prec);
924                 } else {
925                         if (prec->usertype & RPA_MATCH_OPTIONAL) {
926                                 /*
927                                  * Most probably this is useless case - loop refs shouldn't have quantitative modifiers
928                                  * but in case they do we wrap the inlined production rule in quantitative expression.
929                                  * The inlined named rule can take the quantitative argument, but I just don't have
930                                  * a clean way to pass it from here - so, lets play the records inside an expression that
931                                  * has the right quantitative argument.
932                                  * We ignore, it doesn't make sense for loops:
933                                  * RPA_MATCH_MULTIPLE
934                                  */
935                                 rpa_compiler_exp_begin(dbex->co, RPA_MATCH_OPTIONAL);
936                                 rpa_dbex_playrecord(dbex, info->startrec);
937                                 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
938                                 rpa_compiler_exp_end(dbex->co);
939                         } else {
940                                 rpa_dbex_playrecord(dbex, info->startrec);
941                         }
942                 }
943         } else {
944                 rpa_compiler_reference(dbex->co, name, namesize, (prec->usertype & RPA_MATCH_MASK));
945         }
946         rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
947         rpa_dbex_debug_recordtail(dbex, rec);
948         if (rpa_dbex_playchildrecords(dbex, rec) < 0)
949                 return -1;
950         rec = rpa_recordtree_get(records, rec, RPA_RECORD_END);
951         prec = rpa_dbex_record(dbex, rec);
952         R_ASSERT(prec);
953         rpa_dbex_debug_recordhead(dbex, rec);
954         rpa_dbex_debug_recordtail(dbex, rec);
955         return 0;
956 }
957
958
959 rpadbex_t *rpa_dbex_create(void)
960 {
961         rpadbex_t *dbex = (rpadbex_t *) r_zmalloc(sizeof(*dbex));
962
963         dbex->co = rpa_compiler_create();
964         dbex->pa = rpa_parser_create();
965         dbex->text = r_array_create(sizeof(char *));
966         dbex->records = r_array_create(sizeof(rparecord_t));
967         dbex->temprecords = r_array_create(sizeof(rparecord_t));
968         dbex->rules = r_harray_create(sizeof(rpa_ruleinfo_t));
969         dbex->recstack = r_array_create(sizeof(unsigned long));
970         dbex->inlinestack = r_array_create(sizeof(unsigned long));
971         dbex->handlers = r_zmalloc(sizeof(rpa_dbex_recordhandler) * RPA_PRODUCTION_COUNT);
972         rpa_dbex_cfgset(dbex, RPA_DBEXCFG_OPTIMIZATIONS, 1);
973         rpa_dbex_cfgset(dbex, RPA_DBEXCFG_BITMAP, 1);
974
975         dbex->handlers[RPA_PRODUCTION_NONE] = rpa_dbex_rh_default;
976         dbex->handlers[RPA_PRODUCTION_NAMEDRULE] = rpa_dbex_rh_namedrule;
977         dbex->handlers[RPA_PRODUCTION_ANONYMOUSRULE] = rpa_dbex_rh_anonymousrule;
978         dbex->handlers[RPA_PRODUCTION_CLS] = rpa_dbex_rh_cls;
979         dbex->handlers[RPA_PRODUCTION_CHAR] = rpa_dbex_rh_char;
980         dbex->handlers[RPA_PRODUCTION_SPECIALCHAR] = rpa_dbex_rh_specialchar;
981         dbex->handlers[RPA_PRODUCTION_CLSCHAR] = rpa_dbex_rh_clschar;
982         dbex->handlers[RPA_PRODUCTION_AREF] = rpa_dbex_rh_aref;
983         dbex->handlers[RPA_PRODUCTION_CREF] = rpa_dbex_rh_aref;
984         dbex->handlers[RPA_PRODUCTION_BRACKETEXP] = rpa_dbex_rh_exp;
985         dbex->handlers[RPA_PRODUCTION_OROP] = rpa_dbex_rh_orop;
986         dbex->handlers[RPA_PRODUCTION_NOTOP] = rpa_dbex_rh_notop;
987         dbex->handlers[RPA_PRODUCTION_ALTBRANCH] = rpa_dbex_rh_branch;
988         dbex->handlers[RPA_PRODUCTION_NEGBRANCH] = rpa_dbex_rh_branch;
989         dbex->handlers[RPA_PRODUCTION_CHARRNG] = rpa_dbex_rh_range;
990         dbex->handlers[RPA_PRODUCTION_NUMRNG] = rpa_dbex_rh_numrange;
991         dbex->handlers[RPA_PRODUCTION_CLSNUM] = rpa_dbex_rh_clsnum;
992         dbex->handlers[RPA_PRODUCTION_BEGINCHAR] = rpa_dbex_rh_beginchar;
993         dbex->handlers[RPA_PRODUCTION_ENDCHAR] = rpa_dbex_rh_endchar;
994         dbex->handlers[RPA_PRODUCTION_NOROP] = rpa_dbex_rh_norop;
995         dbex->handlers[RPA_PRODUCTION_REQOP] = rpa_dbex_rh_exp;
996         dbex->handlers[RPA_PRODUCTION_MINOP] = rpa_dbex_rh_minexp;
997         dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMIT] = rpa_dbex_rh_emit;
998         dbex->handlers[RPA_PRODUCTION_DIRECTIVEABORT] = rpa_dbex_rh_abort;
999         dbex->handlers[RPA_PRODUCTION_DIRECTIVENOEMIT] = rpa_dbex_rh_noemit;
1000         dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMITALL] = rpa_dbex_rh_emitall;
1001         dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMITNONE] = rpa_dbex_rh_emitnone;
1002         dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMITID] = rpa_dbex_rh_uid;
1003
1004         return dbex;
1005 }
1006
1007
1008 void rpa_dbex_destroy(rpadbex_t *dbex)
1009 {
1010         int i;
1011         if (dbex) {
1012                 for (i = 0; i < r_array_length(dbex->text); i++)
1013                         r_free(r_array_index(dbex->text, i, char*));
1014                 rpa_compiler_destroy(dbex->co);
1015                 rpa_parser_destroy(dbex->pa);
1016                 r_harray_destroy(dbex->rules);
1017                 r_array_destroy(dbex->records);
1018                 r_array_destroy(dbex->temprecords);
1019                 r_array_destroy(dbex->recstack);
1020                 r_array_destroy(dbex->inlinestack);
1021                 r_array_destroy(dbex->text);
1022                 r_free(dbex->handlers);
1023                 r_free(dbex);
1024         }
1025 }
1026
1027
1028 static int rpa_parseinfo_loopdetect_do(rpadbex_t *dbex, long parent, long loopto, int inderction)
1029 {
1030         rsize_t namesiz;
1031         const char *name;
1032         long i;
1033         int ret = 0;
1034         rparecord_t *prec;
1035
1036         if (parent == loopto && inderction > 0)
1037                 return 1;
1038         for (i = 0; i < r_array_length(dbex->recstack); i++) {
1039                 if (parent == r_array_index(dbex->recstack, i, long))
1040                         return 0;
1041         }
1042         r_array_add(dbex->recstack, &parent);
1043
1044         if (!(prec = (rparecord_t *)r_array_slot(dbex->records, parent)))
1045                 return 0;
1046         if (prec->ruleuid == RPA_PRODUCTION_AREF || prec->ruleuid == RPA_PRODUCTION_CREF)
1047                 i = parent;
1048         else
1049                 i = rpa_recordtree_firstchild(dbex->records, parent, RPA_RECORD_START);
1050         for (; i >= 0; i = rpa_recordtree_next(dbex->records, i, RPA_RECORD_START)) {
1051                 prec = (rparecord_t *)r_array_slot(dbex->records, i);
1052                 if (prec->ruleuid == RPA_PRODUCTION_RULENAME)
1053                         continue;
1054                 if (prec->ruleuid == RPA_PRODUCTION_AREF || prec->ruleuid == RPA_PRODUCTION_CREF) {
1055                         rpa_ruleinfo_t *info;
1056                         if ((inderction > 0 || i != parent) && i == loopto) {
1057                                 /*
1058                                  * We found what we are looking for
1059                                  */
1060                                 ret = 1;
1061                                 break;
1062                         }
1063                         if (rpa_dbex_rulename(dbex, i, &name, &namesiz) < 0)
1064                                 R_ASSERT(0);
1065                         info = (rpa_ruleinfo_t *) r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesiz));
1066                         if (!info)
1067                                 continue;
1068                         if ((ret = rpa_parseinfo_loopdetect_do(dbex, info->startrec, loopto, inderction + 1)) > 0)
1069                                 break;
1070                 } else {
1071                         if ((ret = rpa_parseinfo_loopdetect_do(dbex, i, loopto, inderction + 1)) > 0)
1072                                 break;
1073                 }
1074
1075                 if ((prec->usertype & RPA_MATCH_OPTIONAL) == 0 && (prec->ruleuid == RPA_PRODUCTION_CREF || prec->ruleuid == RPA_PRODUCTION_AREF ||
1076                                 prec->ruleuid == RPA_PRODUCTION_CHAR || prec->ruleuid == RPA_PRODUCTION_CLS || prec->ruleuid == RPA_PRODUCTION_SPECIALCHAR))
1077                         break;
1078
1079         }
1080
1081         r_array_removelast(dbex->recstack);
1082         return ret;
1083 }
1084
1085
1086 static int rpa_parseinfo_loopdetect(rpadbex_t *dbex, long parent, long loopto)
1087 {
1088         if (parent != loopto) {
1089                 /*
1090                  * Make sure we are dealing with a loop first
1091                  */
1092                 if (!rpa_parseinfo_loopdetect_do(dbex, loopto, parent, 0))
1093                         return 0;
1094         }
1095
1096         return (rpa_parseinfo_loopdetect_do(dbex, parent, loopto, 0)) ? 1 : 0;
1097 }
1098
1099
1100 static void rpa_parseinfo_marklooppath(rpadbex_t *dbex, long parent)
1101 {
1102         long i;
1103
1104         if (rpa_parseinfo_loopdetect(dbex, parent, parent) > 0) {
1105                 rpa_record_setusertype(dbex->records, parent, RPA_LOOP_PATH, RVALSET_OR);
1106                 for (i = rpa_recordtree_firstchild(dbex->records, parent, RPA_RECORD_START); i >= 0; i = rpa_recordtree_next(dbex->records, i, RPA_RECORD_START)) {
1107                         rpa_parseinfo_marklooppath(dbex, i);
1108                 }
1109         }
1110 }
1111
1112
1113 static int rpa_parseinfo_rule_checkforloop(rpadbex_t *dbex, const char *name, rsize_t namesize, long loopto)
1114 {
1115         rpa_ruleinfo_t *info = info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesize));
1116
1117         if (!info)
1118                 return 0;
1119         return rpa_parseinfo_loopdetect(dbex, info->startrec, loopto);
1120 }
1121
1122
1123 static void rpa_dbex_buildloopinfo(rpadbex_t *dbex)
1124 {
1125         unsigned int i, p;
1126         rharray_t *rules = dbex->rules;
1127         rpa_ruleinfo_t *info;
1128
1129         for (i = 0; i < r_array_length(rules->members); i++) {
1130                 if ((info = (rpa_ruleinfo_t *)r_harray_get(rules, i)) != NULL)
1131                         rpa_parseinfo_marklooppath(dbex, info->startrec);
1132         }
1133
1134         /*
1135          * Mark the non-loop branches.
1136          */
1137         for (i = 0; i < r_array_length(dbex->records); i++) {
1138                 rparecord_t *prec = (rparecord_t *)r_array_slot(dbex->records, i);
1139                 if (prec->type == RPA_RECORD_START &&
1140                         (prec->ruleuid == RPA_PRODUCTION_ALTBRANCH) &&
1141                         (prec->usertype & RPA_LOOP_PATH) == 0) {
1142                         p = rpa_recordtree_parent(dbex->records, i, RPA_RECORD_START);
1143                         if (p >= 0) {
1144                                 prec = (rparecord_t *)r_array_slot(dbex->records, p);
1145                                 if (prec && (prec->usertype & RPA_LOOP_PATH))
1146                                         rpa_record_setusertype(dbex->records, i, RPA_NONLOOP_PATH, RVALSET_OR);
1147                         }
1148                 }
1149         }
1150 }
1151
1152
1153 static void rpa_dbex_buildruleinfo(rpadbex_t *dbex)
1154 {
1155         rparecord_t *rec;
1156         rpa_ruleinfo_t info;
1157         unsigned int nrecords;
1158         long i;
1159         const char *name = NULL;
1160         rsize_t namesize = 0;
1161
1162         if (dbex->rules) {
1163                 r_object_destroy((robject_t *)dbex->rules);
1164                 dbex->rules = NULL;
1165         }
1166         dbex->rules = r_harray_create(sizeof(rpa_ruleinfo_t));
1167
1168         for (i = 0, nrecords = r_array_length(dbex->records); i < nrecords; i++) {
1169                 if (!(rec = rpa_dbex_record(dbex, i)))
1170                         continue;
1171                 if ((rec->ruleuid == RPA_PRODUCTION_NAMEDRULE) && (rec->type & RPA_RECORD_START)) {
1172                         r_memset(&info, 0, sizeof(info));
1173                         info.type = RPA_RULEINFO_NAMEDRULE;
1174                         info.startrec = i;
1175                         info.sizerecs = rpa_recordtree_size(dbex->records, i);
1176                         if (info.sizerecs < 0)
1177                                 continue;
1178                         if (rpa_dbex_rulename(dbex, i, &name, &namesize) < 0) {
1179                                 continue;
1180                         }
1181                         r_harray_add(dbex->rules, name, namesize, &info);
1182                         i += info.sizerecs - 1;
1183                 } else if ((rec->ruleuid == RPA_PRODUCTION_ANONYMOUSRULE) && (rec->type & RPA_RECORD_START)) {
1184                         r_memset(&info, 0, sizeof(info));
1185                         info.type = RPA_RULEINFO_ANONYMOUSRULE;
1186                         info.startrec = i;
1187                         info.sizerecs = rpa_recordtree_size(dbex->records, i);
1188                         if (info.sizerecs < 0)
1189                                 continue;
1190                         if ((rec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, i, RPA_RECORD_END))))
1191                                 r_harray_add(dbex->rules, rec->input, rec->inputsiz, &info);
1192                         i += info.sizerecs - 1;
1193                 } else if ((rec->type & RPA_RECORD_START) && (rec->ruleuid >= RPA_PRODUCTION_DIRECTIVEEMIT) && (rec->ruleuid <= RPA_PRODUCTION_DIRECTIVEEMITID)) {
1194                         r_memset(&info, 0, sizeof(info));
1195                         info.type = RPA_RULEINFO_DIRECTIVE;
1196                         info.startrec = i;
1197                         info.sizerecs = rpa_recordtree_size(dbex->records, i);
1198                         if (info.sizerecs < 0)
1199                                 continue;
1200                         if ((rec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, i, RPA_RECORD_END))))
1201                                 r_harray_add(dbex->rules, rec->input, rec->inputsiz, &info);
1202                         i += info.sizerecs - 1;
1203                 }
1204
1205         }
1206 }
1207
1208
1209 static long rpa_dbex_copy_handler(rarray_t *records, long rec, rpointer userdata)
1210 {
1211         rpadbex_t *dbex = (rpadbex_t *)userdata;
1212         long index;
1213
1214         rparecord_t *prec = (rparecord_t *)r_array_slot(records, rec);
1215         if (prec->ruleuid == RPA_PRODUCTION_OCCURENCE && (prec->type & RPA_RECORD_START)) {
1216                 /*
1217                  * Ignore it
1218                  */
1219         } else if (prec->ruleuid == RPA_PRODUCTION_OCCURENCE && (prec->type & (RPA_RECORD_END))) {
1220                 ruint32 usertype = RPA_MATCH_NONE;
1221                 long lastrec = 0;
1222                 /*
1223                  * Don't copy it but set the usertype of the previous record accordingly.
1224                  */
1225                 switch (*prec->input) {
1226                 case '?':
1227                         usertype = RPA_MATCH_OPTIONAL;
1228                         break;
1229                 case '+':
1230                         usertype = RPA_MATCH_MULTIPLE;
1231                         break;
1232                 case '*':
1233                         usertype = RPA_MATCH_MULTIOPT;
1234                         break;
1235                 default:
1236                         usertype = RPA_MATCH_NONE;
1237                 };
1238                 lastrec = r_array_length(dbex->records) - 1;
1239                 if (lastrec >= 0)
1240                         rpa_record_setusertype(dbex->records, lastrec, usertype, RVALSET_OR);
1241         } else if (prec->ruleuid) {
1242                 index = r_array_add(dbex->records, prec);
1243                 /*
1244                  * Optimizations. Lets apply the optimizations while we copy the records.
1245                  * This is probably not the most clean way to apply optimizations. In the future
1246                  * we should probably think of optimization pass right before compiling.
1247                  */
1248                 if (dbex->optimizations) {
1249                         if (prec->ruleuid == RPA_PRODUCTION_OROP && (prec->type & RPA_RECORD_END)) {
1250                                 rpa_optimiztion_orop(dbex->records, rpa_recordtree_get(dbex->records, index, RPA_RECORD_START));
1251                         }
1252                 }
1253         }
1254
1255         return 0;
1256 }
1257
1258
1259 static void rpa_dbex_copyrecords(rpadbex_t *dbex)
1260 {
1261         int i;
1262         rarray_t *records = dbex->temprecords;
1263
1264         for (i = rpa_recordtree_get(records, 0, RPA_RECORD_START); i >= 0; i = rpa_recordtree_next(records, i, RPA_RECORD_START))
1265                 rpa_recordtree_walk(records, i, 0, rpa_dbex_copy_handler, dbex);
1266 }
1267
1268
1269 static rparecord_t *rpa_dbex_record(rpadbex_t *dbex, long rec)
1270 {
1271         rparecord_t *prec;
1272
1273         if (!dbex || !dbex->rules)
1274                 return NULL;
1275         if (rec < 0 || rec >= r_array_length(dbex->records))
1276                 return NULL;
1277         prec = (rparecord_t *)r_array_slot(dbex->records, rec);
1278         return prec;
1279
1280 }
1281
1282
1283 static rparecord_t *rpa_dbex_rulerecord(rpadbex_t *dbex, rparule_t rid)
1284 {
1285         rparecord_t *prec;
1286         rpa_ruleinfo_t *info;
1287         long rec;
1288
1289         if (!dbex || !dbex->rules)
1290                 return NULL;
1291         info = r_harray_get(dbex->rules, rid);
1292         if (!info)
1293                 return NULL;
1294         rec = info->startrec + info->sizerecs - 1;
1295         if (rec < 0 || rec >= r_array_length(dbex->records))
1296                 return NULL;
1297         prec = (rparecord_t *)r_array_slot(dbex->records, rec);
1298         return prec;
1299 }
1300
1301
1302 static int rpa_dbex_rulename(rpadbex_t *dbex, long rec, const char **name, rsize_t *namesize)
1303 {
1304         rparecord_t *pnamerec = rpa_dbex_record(dbex, rpa_recordtree_firstchild(dbex->records, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_START), RPA_RECORD_END));
1305         if (!pnamerec || !(pnamerec->ruleuid & RPA_PRODUCTION_RULENAME))
1306                 return -1;
1307         *name = pnamerec->input;
1308         *namesize = pnamerec->inputsiz;
1309         return 0;
1310 }
1311
1312
1313 int rpa_dbex_open(rpadbex_t *dbex)
1314 {
1315         if (!dbex)
1316                 return -1;
1317         if (dbex->rules) {
1318                 r_object_destroy((robject_t *)dbex->rules);
1319                 dbex->rules = NULL;
1320         }
1321         dbex->compiled = 0;
1322         return 0;
1323 }
1324
1325
1326 void rpa_dbex_close(rpadbex_t *dbex)
1327 {
1328         if (!dbex)
1329                 return;
1330         rpa_dbex_buildruleinfo(dbex);
1331         rpa_dbex_buildloopinfo(dbex);
1332         if (dbex->bitmap)
1333                 rpa_dbex_buildbitmapinfo(dbex);
1334 }
1335
1336
1337 long rpa_dbex_load(rpadbex_t *dbex, const char *rules, rsize_t size)
1338 {
1339         long ret;
1340         char *text;
1341
1342         if (!dbex)
1343                 return -1;
1344         if (dbex->rules) {
1345                 /*
1346                  * Dbex is not open
1347                  */
1348                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTOPEN);
1349                 return -1;
1350         }
1351
1352         text = r_strndup(rules, size);
1353         R_ASSERT(text);
1354         r_array_add(dbex->text, &text);
1355         r_array_setlength(dbex->temprecords, 0);
1356         if ((ret = rpa_parser_load(dbex->pa, text, size, dbex->temprecords)) < 0) {
1357
1358                 return -1;
1359         }
1360         if (ret != size) {
1361                 long line = 1;
1362                 char *ptext = text;
1363                 ptext += ret;
1364                 for (line = 1; ptext >= text; --ptext) {
1365                         if (*ptext == '\n')
1366                                 line += 1;
1367                 }
1368                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAXERROR);
1369                 RPA_DBEX_SETERRINFO_OFFSET(dbex, ret);
1370                 RPA_DBEX_SETERRINFO_LINE(dbex, line);
1371                 return -1;
1372         }
1373         rpa_dbex_copyrecords(dbex);
1374         return ret;
1375 }
1376
1377
1378 long rpa_dbex_load_s(rpadbex_t *dbex, const char *rules)
1379 {
1380         return rpa_dbex_load(dbex, rules, r_strlen(rules));
1381 }
1382
1383
1384 void rpa_dbex_dumpindented(rpadbex_t *dbex, long rec, int level, const char *rulelabel)
1385 {
1386         char buffer[1024];
1387         int i, size;
1388         rparecord_t *prec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END));
1389
1390         if (!prec)
1391                 return;
1392         r_memset(buffer, 0, sizeof(buffer));
1393         r_printf("[ 0x%016lx ] ", prec->userdata);
1394         for (i = 0; i < level + 1; i++)
1395                 r_printf("   ");
1396         r_printf("(");
1397         r_printf("%s, %c, %c", rulelabel, rpa_record_optchar(prec, 'x'), rpa_record_loopchar(prec, 'x'));
1398         r_printf(")");
1399         size = R_MIN(prec->inputsiz, sizeof(buffer) - 1);
1400         r_strncpy(buffer, prec->input, size);
1401
1402         if (size == (sizeof(buffer) - 1))
1403                 r_printf(" %s ...\n", buffer);
1404         else
1405                 r_printf(" %s\n", buffer);
1406         return;
1407 }
1408
1409
1410 static long rpa_dbex_firstinlined(rpadbex_t *dbex)
1411 {
1412         long ret = r_array_empty(dbex->inlinestack) ? -1 : r_array_index(dbex->inlinestack, 0, long);
1413         return ret;
1414 }
1415
1416
1417 static int rpa_dbex_findinlined(rpadbex_t *dbex, long startrec)
1418 {
1419         long i;
1420         for (i = 0; i < r_array_length(dbex->inlinestack); i++) {
1421                 if (r_array_index(dbex->inlinestack, i, long) == startrec)
1422                         return 1;
1423         }
1424         return 0;
1425 }
1426
1427
1428 static void rpa_dbex_dumptree_do(rpadbex_t *dbex, long rec, int level)
1429 {
1430         rparecord_t *prec = rpa_dbex_record(dbex, rec);
1431         if (prec && prec->ruleuid == RPA_PRODUCTION_RULENAME)
1432                 return;
1433         if (prec && (prec->ruleuid == RPA_PRODUCTION_AREF || prec->ruleuid == RPA_PRODUCTION_CREF)) {
1434                 const char *name = NULL;
1435                 rsize_t namesize = 0;
1436                 int loop = 0;
1437                 rpa_ruleinfo_t *info;
1438
1439                 if (rpa_dbex_rulename(dbex, rec, &name, &namesize) >= 0) {
1440                         loop = rpa_parseinfo_rule_checkforloop(dbex, name, namesize, rpa_dbex_firstinlined(dbex));
1441                         info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesize));
1442                         if (loop && info){
1443                                 if (!rpa_dbex_findinlined(dbex, info->startrec)) {
1444                                         /*
1445                                          * Temporary set the quantitative flags for the inlined rule to the parent
1446                                          * reference, so they are printed correctly. After the printing is done
1447                                          * restore the original flags.
1448                                          */
1449                                         rparecord_t *prulestart = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, info->startrec, RPA_RECORD_START));
1450                                         rparecord_t *pruleend = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, info->startrec, RPA_RECORD_END));
1451                                         unsigned long optional = (prulestart->usertype & RPA_MATCH_OPTIONAL);
1452                                         prulestart->usertype |= (prec->usertype & RPA_MATCH_OPTIONAL);
1453                                         pruleend->usertype |= (prec->usertype & RPA_MATCH_OPTIONAL);
1454                                         r_array_add(dbex->inlinestack, &info->startrec);
1455                                         rpa_dbex_dumptree_do(dbex, info->startrec, level);
1456                                         r_array_removelast(dbex->inlinestack);
1457                                         if (!optional) {
1458                                                 prulestart->usertype &= ~RPA_MATCH_OPTIONAL;
1459                                                 pruleend->usertype &= ~RPA_MATCH_OPTIONAL;
1460                                         }
1461                                 } else {
1462                                         rpa_dbex_dumpindented(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END), level, "loopref");
1463                                 }
1464                                 return;
1465                         }
1466                 }
1467         }
1468         rpa_dbex_dumpindented(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END), level, prec->rule);
1469         for (rec = rpa_recordtree_firstchild(dbex->records, rec, RPA_RECORD_START); rec >= 0; rec = rpa_recordtree_next(dbex->records, rec, RPA_RECORD_START)) {
1470                 rpa_dbex_dumptree_do(dbex, rec, level + 1);
1471         }
1472 }
1473
1474
1475 int rpa_dbex_dumptree(rpadbex_t *dbex, rparule_t rid)
1476 {
1477         rpa_ruleinfo_t *info;
1478
1479         if (!dbex)
1480                 return -1;
1481         if (rid < 0) {
1482                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_PARAM);
1483                 return -1;
1484         }
1485         if (!dbex->rules) {
1486                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1487                 return -1;
1488         }
1489         if (!(info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid))) {
1490                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1491                 return -1;
1492         }
1493         r_array_add(dbex->inlinestack, &info->startrec);
1494         rpa_dbex_dumptree_do(dbex, info->startrec, 0);
1495         r_array_removelast(dbex->inlinestack);
1496         return 0;
1497 }
1498
1499
1500 int rpa_dbex_dumpproductions(rpadbex_t *dbex)
1501 {
1502         int ret = 0;
1503         rparule_t rid;
1504         char buffer[512];
1505
1506         if (!dbex)
1507                 return -1;
1508         if (!dbex->rules) {
1509                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1510                 return -1;
1511         }
1512         for (rid = rpa_dbex_first(dbex); rid >= 0; rid = rpa_dbex_next(dbex, rid)) {
1513                 ret = rpa_dbex_strncpy(dbex, buffer, rid, sizeof(buffer));
1514                 if ( ret >= 0) {
1515                         if (ret == sizeof(buffer))
1516                                 r_printf("   %s ...\n", buffer);
1517                         else
1518                                 r_printf("   %s\n", buffer);
1519                 }
1520
1521         }
1522         return ret;
1523 }
1524
1525
1526 int rpa_dbex_dumprecords(rpadbex_t *dbex)
1527 {
1528         long i;
1529
1530         if (!dbex)
1531                 return -1;
1532         if (!dbex->rules) {
1533                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1534                 return -1;
1535         }
1536         for (i = 0; i < r_array_length(dbex->records); i++) {
1537                 rpa_record_dump(dbex->records, i);
1538         }
1539         return 0;
1540 }
1541
1542
1543 int rpa_dbex_dumpinfo(rpadbex_t *dbex)
1544 {
1545         long i;
1546         rpa_ruleinfo_t *info;
1547
1548         if (!dbex)
1549                 return -1;
1550         if (!dbex->rules) {
1551                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1552                 return -1;
1553         }
1554         for (i = 0; i < r_array_length(dbex->rules->names); i++) {
1555                 rstr_t *name = r_array_index(dbex->rules->names, i, rstr_t*);
1556                 info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, i);
1557                 switch (info->type) {
1558                 case RPA_RULEINFO_NAMEDRULE:
1559                         r_printf("N ");
1560                         break;
1561                 case RPA_RULEINFO_ANONYMOUSRULE:
1562                         r_printf("A ");
1563                         break;
1564                 case RPA_RULEINFO_DIRECTIVE:
1565                         r_printf("D ");
1566                         break;
1567                 default:
1568                         r_printf("  ");
1569                         break;
1570                 };
1571                 r_printf("(%7d, %4d, code: %7ld, %5ld) : %s\n", info->startrec, info->sizerecs, info->codeoff, info->codesiz, name->str);
1572         }
1573         return 0;
1574 }
1575
1576
1577 int rpa_dbex_dumpuids(rpadbex_t *dbex)
1578 {
1579         long i;
1580         long rec;
1581         rpa_ruleinfo_t *info;
1582         char *buffer = r_zmalloc(32 * sizeof(char));
1583
1584         if (!dbex)
1585                 return -1;
1586         if (!dbex->rules) {
1587                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1588                 return -1;
1589         }
1590         for (i = 0; i < r_array_length(dbex->rules->names); i++) {
1591                 info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, i);
1592                 if (info->type == RPA_RULEINFO_DIRECTIVE) {
1593                         rparecord_t *prec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, info->startrec, RPA_RECORD_END));
1594                         if (prec->ruleuid == RPA_PRODUCTION_DIRECTIVEEMITID && prec->inputsiz) {
1595                                 rec = rpa_recordtree_firstchild(dbex->records, info->startrec, RPA_RECORD_START);
1596                                 while (rec >= 0) {
1597                                         prec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END));
1598                                         if (prec->ruleuid == RPA_PRODUCTION_ALIASNAME) {
1599                                                 ruint32 dec;
1600                                                 if (rpa_record2long(rpa_dbex_record(dbex, rpa_recordtree_next(dbex->records, rec, RPA_RECORD_END)), &dec) < 0)
1601                                                         break;
1602                                                 buffer = r_realloc(buffer, prec->inputsiz + 1);
1603                                                 r_memset(buffer, 0, prec->inputsiz + 1);
1604                                                 r_memcpy(buffer, prec->input, prec->inputsiz);
1605                                                 r_printf("#define %s %d\n", buffer, dec);
1606                                                 break;
1607                                         }
1608                                         rec = rpa_recordtree_next(dbex->records, rec, RPA_RECORD_START);
1609                                 }
1610                         }
1611                 }
1612         }
1613         r_free(buffer);
1614         return 0;
1615 }
1616
1617
1618 int rpa_dbex_dumpcode(rpadbex_t* dbex, rparule_t rid)
1619 {
1620         rpa_ruleinfo_t *info;
1621         if (!dbex)
1622                 return -1;
1623         if (rid < 0) {
1624                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_PARAM);
1625                 return -1;
1626         }
1627         if (!dbex->rules) {
1628                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1629                 return -1;
1630         }
1631         info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid);
1632         if (!info)
1633                 return -1;
1634         rvm_asm_dump(rvm_codegen_getcode(dbex->co->cg, info->codeoff), info->codesiz);
1635         return 0;
1636 }
1637
1638
1639 rsize_t rpa_dbex_strlen(rpadbex_t *dbex, rparule_t rid)
1640 {
1641         rparecord_t *prec;
1642         rsize_t size;
1643
1644         if (!dbex)
1645                 return -1;
1646         if ((prec = rpa_dbex_rulerecord(dbex, rid)) == NULL) {
1647                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1648                 return -1;
1649         }
1650         size = prec->inputsiz;
1651         return size;
1652 }
1653
1654
1655 rsize_t rpa_dbex_strncpy(rpadbex_t *dbex, char *dst, rparule_t rid, rsize_t n)
1656 {
1657         rparecord_t *prec;
1658         rsize_t size;
1659
1660         if (!dbex)
1661                 return -1;
1662         if ((prec = rpa_dbex_rulerecord(dbex, rid)) == NULL) {
1663                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1664                 return -1;
1665         }
1666         size = prec->inputsiz;
1667         if (n <= size)
1668                 size = n - 1;
1669         r_memset(dst, 0, n);
1670         r_strncpy(dst, prec->input, size);
1671         return size + 1;
1672 }
1673
1674
1675 const char *rpa_dbex_name(rpadbex_t *dbex, rparule_t rid)
1676 {
1677         rstr_t *name;
1678
1679         if (!dbex)
1680                 return NULL;
1681         if (!dbex->rules) {
1682                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1683                 return NULL;
1684         }
1685         if (rid >= r_array_length(dbex->rules->members))
1686                 return NULL;
1687         name = r_array_index(dbex->rules->names, rid, rstr_t*);
1688         return name->str;
1689 }
1690
1691
1692 rparule_t rpa_dbex_first(rpadbex_t *dbex)
1693 {
1694         if (!dbex)
1695                 return -1;
1696         if (!dbex->rules) {
1697                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1698                 return -1;
1699         }
1700
1701         if (r_array_length(dbex->rules->members) <= 0) {
1702                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1703                 return -1;
1704         }
1705         return 0;
1706 }
1707
1708
1709 rparule_t rpa_dbex_last(rpadbex_t *dbex)
1710 {
1711         if (!dbex)
1712                 return -1;
1713         if (!dbex->rules) {
1714                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1715                 return -1;
1716         }
1717
1718         if (r_array_length(dbex->rules->members) <= 0) {
1719                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1720                 return -1;
1721         }
1722         return r_array_length(dbex->rules->members) - 1;
1723 }
1724
1725
1726 rparule_t rpa_dbex_lookup(rpadbex_t *dbex, const char *name, rsize_t namesize)
1727 {
1728         rparule_t ret;
1729
1730         if (!dbex) {
1731                 return -1;
1732         }
1733         if (!dbex->rules) {
1734                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1735                 return -1;
1736         }
1737
1738         ret = (rparule_t) r_harray_taillookup(dbex->rules, name, namesize);
1739         if (ret < 0) {
1740                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1741         }
1742         return ret;
1743 }
1744
1745
1746 rparule_t rpa_dbex_lookup_s(rpadbex_t *dbex, const char *name)
1747 {
1748         return rpa_dbex_lookup(dbex, name, r_strlen(name));
1749 }
1750
1751
1752 rparule_t rpa_dbex_next(rpadbex_t *dbex, rparule_t rid)
1753 {
1754         if (!dbex)
1755                 return -1;
1756         if (!dbex->rules) {
1757                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1758                 return -1;
1759         }
1760
1761         ++rid;
1762         if (rid < r_array_length(dbex->rules->members))
1763                 return rid;
1764         return -1;
1765 }
1766
1767
1768 rparule_t rpa_dbex_prev(rpadbex_t *dbex, rparule_t rid)
1769 {
1770         if (!dbex)
1771                 return -1;
1772         if (!dbex->rules) {
1773                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1774                 return -1;
1775         }
1776         --rid;
1777         if (rid >= 0)
1778                 return rid;
1779         return -1;
1780 }
1781
1782
1783 long rpa_dbex_lasterror(rpadbex_t *dbex)
1784 {
1785         if (!dbex)
1786                 return -1;
1787         return dbex->err.code;
1788 }
1789
1790
1791 long rpa_dbex_lasterrorinfo(rpadbex_t *dbex, rpa_errinfo_t *errinfo)
1792 {
1793         if (!dbex || !errinfo)
1794                 return -1;
1795         r_memcpy(errinfo, &dbex->err, sizeof(rpa_errinfo_t));
1796         return 0;
1797 }
1798
1799
1800 const char *rpa_dbex_version()
1801 {
1802         return "2.0";
1803 }
1804
1805
1806 static int rpa_dbex_compile_rule(rpadbex_t *dbex, rparule_t rid)
1807 {
1808         long codeoff;
1809         rpa_ruleinfo_t *info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid);
1810
1811         if (!info)
1812                 return -1;
1813         codeoff = rvm_codegen_getcodesize(dbex->co->cg);
1814         /*
1815          * Set the rid in the rulepref, so the compiler associates this rule
1816          * with the correct rid.
1817          */
1818         rpa_compiler_rulepref_set_ruleid_s(dbex->co, rpa_dbex_name(dbex, rid), rid);
1819         if (rpa_dbex_playrecord(dbex, info->startrec) < 0)
1820                 return -1;
1821         info->codeoff = codeoff;
1822         info->codesiz = rvm_codegen_getcodesize(dbex->co->cg) - codeoff;
1823         return 0;
1824 }
1825
1826
1827 int rpa_dbex_compile(rpadbex_t *dbex)
1828 {
1829         rparule_t rid;
1830         rvm_codelabel_t *labelerr;
1831
1832         if (!dbex)
1833                 return -1;
1834         if (!dbex->rules) {
1835                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1836                 return -1;
1837         }
1838         /*
1839          * By default all production rules emit
1840          */
1841         if (dbex->co)
1842                 rpa_compiler_destroy(dbex->co);
1843         dbex->co = rpa_compiler_create();
1844         rpa_dbex_setemit(dbex, TRUE);
1845
1846         for (rid = rpa_dbex_first(dbex); rid >= 0; rid = rpa_dbex_next(dbex, rid)) {
1847                 if (rpa_dbex_compile_rule(dbex, rid) < 0) {
1848                         RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_COMPILE);
1849                         return -1;
1850                 }
1851         }
1852
1853         if (rvm_codegen_relocate(dbex->co->cg, &labelerr) < 0) {
1854                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_UNRESOLVEDSYMBOL);
1855                 RPA_DBEX_SETERRINFO_NAME(dbex, labelerr->name->str, labelerr->name->size);
1856                 return -1;
1857         }
1858         dbex->compiled = 1;
1859         return 0;
1860 }
1861
1862
1863 rvm_asmins_t *rpa_dbex_executable(rpadbex_t *dbex)
1864 {
1865         if (!dbex)
1866                 return NULL;
1867         if (!dbex->rules) {
1868                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1869                 return NULL;
1870         }
1871         if (!dbex->compiled || rvm_codegen_getcodesize(dbex->co->cg) == 0) {
1872                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCOMPILED);
1873                 return NULL;
1874         }
1875         return rvm_codegen_getcode(dbex->co->cg, 0);
1876 }
1877
1878
1879 long rpa_dbex_executableoffset(rpadbex_t *dbex, rparule_t rid)
1880 {
1881         rpa_ruleinfo_t *info;
1882
1883         if (!dbex)
1884                 return -1;
1885         if (!dbex->rules) {
1886                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1887                 return -1;
1888         }
1889         if (!dbex->compiled) {
1890                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCOMPILED);
1891                 return -1;
1892         }
1893         info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid);
1894         if (!info) {
1895                 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1896                 return -1;
1897         }
1898         return info->codeoff;
1899 }
1900
1901
1902 long rpa_dbex_cfgset(rpadbex_t *dbex, unsigned long cfg, unsigned long val)
1903 {
1904         if (!dbex)
1905                 return -1;
1906         if (cfg == RPA_DBEXCFG_OPTIMIZATIONS) {
1907                 dbex->optimizations = val;
1908                 return 0;
1909         } else if(cfg == RPA_DBEXCFG_DEBUG) {
1910                 dbex->debug = val;
1911                 return 0;
1912         } else if(cfg == RPA_DBEXCFG_BITMAP) {
1913                 dbex->bitmap = val;
1914                 return 0;
1915         }
1916         return -1;
1917 }
1918
1919
1920 long rpa_dbex_cfgget(rpadbex_t *dbex, unsigned long cfg)
1921 {
1922         if (!dbex)
1923                 return -1;
1924         if (cfg == RPA_DBEXCFG_OPTIMIZATIONS) {
1925                 return dbex->optimizations;
1926         } else if(cfg == RPA_DBEXCFG_DEBUG) {
1927                 return dbex->debug;
1928         } else if(cfg == RPA_DBEXCFG_BITMAP) {
1929                 return dbex->bitmap;
1930         }
1931         return -1;
1932 }
1933