5 #include "rpacompiler.h"
7 #include "rpastatpriv.h"
9 #include "rpaoptimization.h"
13 typedef rint (*rpa_dbex_recordhandler)(rpadbex_t *dbex, rlong rec);
15 #define RPA_RULEINFO_NONE 0
16 #define RPA_RULEINFO_NAMEDRULE 1
17 #define RPA_RULEINFO_ANONYMOUSRULE 2
18 #define RPA_RULEINFO_DIRECTIVE 3
20 #define RPA_DBEX_SETERRINFO_CODE(__d__, __e__) do { (__d__)->err.code = __e__; (__d__)->err.mask |= RPA_ERRINFO_CODE; } while (0)
21 #define RPA_DBEX_SETERRINFO_OFFSET(__d__, __o__) do { (__d__)->err.offset = __o__; (__d__)->err.mask |= RPA_ERRINFO_OFFSET; } while (0)
22 #define RPA_DBEX_SETERRINFO_RULEID(__d__, __r__) do { (__d__)->err.ruleid = __r__; (__d__)->err.mask |= RPA_ERRINFO_RULEID; } while (0)
23 #define RPA_DBEX_SETERRINFO_NAME(__d__, __n__, __s__) do { \
24 (__d__)->err.mask |= RPA_ERRINFO_NAME; \
25 r_memset((__d__)->err.name, 0, sizeof((__d__)->err.name)); \
26 r_strncpy((__d__)->err.name, __n__, R_MIN(__s__, (sizeof((__d__)->err.name) - 1))); } while (0)
29 typedef struct rpa_ruleinfo_s {
44 rarray_t *inlinestack;
45 rpa_dbex_recordhandler *handlers;
47 rulong optimizations:1;
50 static rparecord_t *rpa_dbex_rulerecord(rpadbex_t *dbex, rparule_t rid);
51 static rparecord_t *rpa_dbex_record(rpadbex_t *dbex, rlong rec);
52 static rint rpa_dbex_rulename(rpadbex_t *dbex, rlong rec, const rchar **name, rsize_t *namesize);
53 static rint rpa_parseinfo_loopdetect(rpadbex_t *dbex, rlong parent, rlong loopto);
54 static rlong rpa_dbex_play_recordhandler(rpadbex_t *dbex, rlong rec);
55 static rlong rpa_dbex_play_recordhandlers(rpadbex_t *dbex, rlong rec, rlong nrecs);
56 static rlong rpa_dbex_firstinlined(rpadbex_t *dbex);
57 static rint rpa_dbex_findinlined(rpadbex_t *dbex, rlong startrec);
60 static rlong rpa_dbex_getmatchchr(rulong matchtype)
62 switch (matchtype & RPA_MATCH_MASK) {
65 return RPA_MATCHCHR_NAN;
67 case RPA_MATCH_MULTIPLE:
68 return RPA_MATCHCHR_MUL;
70 case RPA_MATCH_OPTIONAL:
71 return RPA_MATCHCHR_OPT;
73 case RPA_MATCH_MULTIOPT:
74 return RPA_MATCHCHR_MOP;
77 return RPA_MATCHCHR_NAN;
81 static rlong rpa_dbex_getmatchspecialchr(rulong matchtype)
83 switch (matchtype & RPA_MATCH_MASK) {
86 return RPA_MATCHSPCHR_NAN;
88 case RPA_MATCH_MULTIPLE:
89 return RPA_MATCHSPCHR_MUL;
91 case RPA_MATCH_OPTIONAL:
92 return RPA_MATCHSPCHR_OPT;
94 case RPA_MATCH_MULTIOPT:
95 return RPA_MATCHSPCHR_MOP;
98 return RPA_MATCHSPCHR_NAN;
102 static rint rpa_record2long(rparecord_t *prec, ruint32 *num)
104 rchar *endptr = NULL;
107 if (!prec || !num || prec->inputsiz == 0 || prec->inputsiz >= sizeof(buffer))
109 r_memset(buffer, 0, sizeof(buffer));
110 r_memcpy(buffer, prec->input, prec->inputsiz);
111 if (prec->ruleuid == RPA_PRODUCTION_HEX) {
112 *num = (ruint32)r_strtoul(prec->input, &endptr, 16);
113 } else if (prec->ruleuid == RPA_PRODUCTION_DEC) {
114 *num = (ruint32)r_strtoul(prec->input, &endptr, 10);
122 static rint rpa_dbex_rh_uid(rpadbex_t *dbex, rlong rec)
124 const rchar *name = NULL;
127 rparecord_t *pnumrec;
128 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
130 if (prec->type & RPA_RECORD_START) {
131 if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
132 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAX_ERROR);
135 pnumrec = rpa_dbex_record(dbex, rpa_recordtree_lastchild(dbex->records, rec, RPA_RECORD_END));
137 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAX_ERROR);
140 if (rpa_record2long(pnumrec, &uid) < 0) {
141 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAX_ERROR);
144 rpa_compiler_rulepref_set_ruleuid(dbex->co, name, namesize, uid);
145 rpa_compiler_rulepref_set_flag(dbex->co, name, namesize, RPA_RFLAG_EMITRECORD);
146 } else if (prec->type & RPA_RECORD_END) {
153 static rint rpa_dbex_rh_emit(rpadbex_t *dbex, rlong rec)
155 const rchar *name = NULL;
157 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
159 if (prec->type & RPA_RECORD_START) {
160 if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
163 rpa_compiler_rulepref_set_flag(dbex->co, name, namesize, RPA_RFLAG_EMITRECORD);
164 } else if (prec->type & RPA_RECORD_END) {
171 static rint rpa_dbex_rh_noemit(rpadbex_t *dbex, rlong rec)
173 const rchar *name = NULL;
175 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
177 if (prec->type & RPA_RECORD_START) {
178 if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
181 rpa_compiler_rulepref_clear_flag(dbex->co, name, namesize, RPA_RFLAG_EMITRECORD);
182 } else if (prec->type & RPA_RECORD_END) {
189 static rint rpa_dbex_setemit(rpadbex_t *dbex, rboolean emit)
192 rpa_ruleinfo_t *info;
194 for (i = 0; i < r_array_length(dbex->rules->names); i++) {
195 rstr_t *name = r_array_index(dbex->rules->names, i, rstr_t*);
196 info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, i);
197 if (info->type == RPA_RULEINFO_NAMEDRULE) {
199 rpa_compiler_rulepref_set_flag(dbex->co, name->str, name->size, RPA_RFLAG_EMITRECORD);
201 rpa_compiler_rulepref_clear_flag(dbex->co, name->str, name->size, RPA_RFLAG_EMITRECORD);
209 static rint rpa_dbex_rh_emitall(rpadbex_t *dbex, rlong rec)
211 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
213 if (prec->type & RPA_RECORD_START) {
214 rpa_dbex_setemit(dbex, TRUE);
215 } else if (prec->type & RPA_RECORD_END) {
222 static rint rpa_dbex_rh_emitnone(rpadbex_t *dbex, rlong rec)
224 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
226 if (prec->type & RPA_RECORD_START) {
227 rpa_dbex_setemit(dbex, FALSE);
228 } else if (prec->type & RPA_RECORD_END) {
235 static rint rpa_dbex_rh_namedrule(rpadbex_t *dbex, rlong rec)
237 const rchar *name = NULL;
239 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
241 if (prec->type & RPA_RECORD_START) {
242 if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
246 if (!r_array_empty(dbex->inlinestack)) {
247 rpa_compiler_inlinerule_begin(dbex->co, name, namesize, 0);
249 rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_SHIFT, XX, XX, XX, 0));
250 rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_BL, DA, XX, XX, 3));
251 rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_EMITTAIL, XX, XX, XX, 0));
252 rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_EXT, XX, XX, XX, 0));
254 if ((prec->usertype & RPA_LOOP_PATH)) {
255 rpa_compiler_loop_begin(dbex->co, name, namesize);
257 rpa_compiler_rule_begin(dbex->co, name, namesize);
260 r_array_add(dbex->inlinestack, &rec);
261 } else if (prec->type & RPA_RECORD_END) {
262 r_array_removelast(dbex->inlinestack);
264 if (!r_array_empty(dbex->inlinestack)) {
265 rpa_compiler_inlinerule_end(dbex->co);
267 if ((prec->usertype & RPA_LOOP_PATH)) {
268 rpa_compiler_loop_end(dbex->co);
270 rpa_compiler_rule_end(dbex->co);
278 static rint rpa_dbex_rh_anonymousrule(rpadbex_t *dbex, rlong rec)
280 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
282 if (prec->type & RPA_RECORD_START) {
283 rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_SHIFT, XX, XX, XX, 0));
284 rpa_compiler_exp_begin(dbex->co, RPA_MATCH_NONE);
286 } else if (prec->type & RPA_RECORD_END) {
287 rpa_compiler_exp_end(dbex->co);
288 rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_EMITTAIL, XX, XX, XX, 0));
289 rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_EXT, XX, XX, XX, 0));
296 static rint rpa_dbex_rh_char(rpadbex_t *dbex, rlong rec)
298 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
300 if (prec->type & RPA_RECORD_END) {
302 if (r_utf8_mbtowc(&wc, (const ruchar*) prec->input, (const ruchar*)prec->input + prec->inputsiz) < 0) {
306 rvm_codegen_addins(dbex->co->cg, rvm_asm(rpa_dbex_getmatchchr(prec->usertype & RPA_MATCH_MASK), DA, XX, XX, wc));
307 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
314 static rint rpa_dbex_rh_specialchar(rpadbex_t *dbex, rlong rec)
316 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
318 if (prec->type & RPA_RECORD_END) {
320 if (r_utf8_mbtowc(&wc, (const ruchar*) prec->input, (const ruchar*)prec->input + prec->inputsiz) < 0) {
324 rvm_codegen_addins(dbex->co->cg, rvm_asm(rpa_dbex_getmatchspecialchr(prec->usertype & RPA_MATCH_MASK), DA, XX, XX, wc));
325 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
332 static rint rpa_dbex_rh_cls(rpadbex_t *dbex, rlong rec)
334 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
336 if (prec->type & RPA_RECORD_START) {
337 rpa_compiler_class_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
339 } else if (prec->type & RPA_RECORD_END) {
340 rpa_compiler_class_end(dbex->co);
341 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
348 static rint rpa_dbex_rh_clschar(rpadbex_t *dbex, rlong rec)
350 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
352 if (prec->type & RPA_RECORD_END) {
354 if (r_utf8_mbtowc(&wc, (const ruchar*) prec->input, (const ruchar*)prec->input + prec->inputsiz) < 0) {
358 rvm_codegen_addins(dbex->co->cg, rvm_asm(RPA_MATCHCHR_NAN, DA, XX, XX, wc));
359 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
366 static rint rpa_dbex_rh_exp(rpadbex_t *dbex, rlong rec)
368 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
370 if (prec->type & RPA_RECORD_START) {
371 rpa_compiler_exp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
373 } else if (prec->type & RPA_RECORD_END) {
374 rpa_compiler_exp_end(dbex->co);
375 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
382 static rint rpa_dbex_rh_orop(rpadbex_t *dbex, rlong rec)
384 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
386 if (prec->type & RPA_RECORD_START) {
387 rpa_compiler_altexp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
389 } else if (prec->type & RPA_RECORD_END) {
390 rpa_compiler_altexp_end(dbex->co);
391 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
398 static rint rpa_dbex_rh_norop(rpadbex_t *dbex, rlong rec)
400 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
402 if (prec->type & RPA_RECORD_START) {
403 rpa_compiler_altexp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
405 } else if (prec->type & RPA_RECORD_END) {
406 rpa_compiler_altexp_end(dbex->co);
407 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
414 static rint rpa_dbex_rh_notop(rpadbex_t *dbex, rlong rec)
416 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
418 if (prec->type & RPA_RECORD_START) {
419 rpa_compiler_notexp_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
421 } else if (prec->type & RPA_RECORD_END) {
422 rpa_compiler_notexp_end(dbex->co);
423 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
430 static rint rpa_dbex_rh_range(rpadbex_t *dbex, rlong rec)
432 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
434 if (prec->type & RPA_RECORD_START) {
435 dbex->co->currange.p1 = 0;
436 dbex->co->currange.p2 = 0;
437 } else if (prec->type & RPA_RECORD_END) {
438 if (dbex->co->currange.p1 < dbex->co->currange.p2)
439 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p1, dbex->co->currange.p2));
441 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p2, dbex->co->currange.p1));
442 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
449 static rint rpa_dbex_rh_numrange(rpadbex_t *dbex, rlong rec)
451 rparecord_t *prec = (rparecord_t *) rpa_dbex_record(dbex, rec);
456 if (prec->type & RPA_RECORD_START) {
458 child = rpa_dbex_record(dbex, rpa_recordtree_firstchild(dbex->records, rec, RPA_RECORD_END));
459 if (rpa_record2long(child, &dbex->co->currange.p1) < 0)
461 child = rpa_dbex_record(dbex, rpa_recordtree_lastchild(dbex->records, rec, RPA_RECORD_END));
462 if (rpa_record2long(child, &dbex->co->currange.p2) < 0)
464 } else if (prec->type & RPA_RECORD_END) {
465 if (dbex->co->currange.p1 < dbex->co->currange.p2)
466 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p1, dbex->co->currange.p2));
468 rvm_codegen_addins(dbex->co->cg, rvm_asm2(RPA_MATCHRNG_NAN, DA, XX, XX, dbex->co->currange.p2, dbex->co->currange.p1));
469 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
476 static rint rpa_dbex_rh_clsnum(rpadbex_t *dbex, rlong rec)
478 rparecord_t *prec = (rparecord_t *) rpa_dbex_record(dbex, rec);
482 if (prec->type & RPA_RECORD_START) {
484 } else if (prec->type & RPA_RECORD_END) {
487 child = rpa_dbex_record(dbex, rpa_recordtree_firstchild(dbex->records, rec, RPA_RECORD_END));
488 if (rpa_record2long(child, &wc) < 0)
490 rvm_codegen_addins(dbex->co->cg, rvm_asm(rpa_dbex_getmatchchr(prec->usertype & RPA_MATCH_MASK), DA, XX, XX, wc));
491 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
498 static rint rpa_dbex_rh_beginchar(rpadbex_t *dbex, rlong rec)
500 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
502 if (prec->type & RPA_RECORD_START) {
504 } else if (prec->type & RPA_RECORD_END) {
506 if (r_utf8_mbtowc(&wc, (const ruchar*) prec->input, (const ruchar*)prec->input + prec->inputsiz) < 0) {
510 dbex->co->currange.p1 = wc;
517 static rint rpa_dbex_rh_endchar(rpadbex_t *dbex, rlong rec)
519 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
521 if (prec->type & RPA_RECORD_START) {
523 } else if (prec->type & RPA_RECORD_END) {
525 if (r_utf8_mbtowc(&wc, (const ruchar*) prec->input, (const ruchar*)prec->input + prec->inputsiz) < 0) {
529 dbex->co->currange.p2 = wc;
536 static rint rpa_dbex_rh_branch(rpadbex_t *dbex, rlong rec)
538 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
540 if (prec->type & RPA_RECORD_START) {
541 if (prec->usertype & RPA_NONLOOP_PATH) {
542 rpa_compiler_nonloopybranch_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
544 rpa_compiler_branch_begin(dbex->co, prec->usertype & RPA_MATCH_MASK);
546 } else if (prec->type & RPA_RECORD_END) {
548 if (prec->usertype & RPA_NONLOOP_PATH) {
549 rpa_compiler_nonloopybranch_end(dbex->co);
551 rpa_compiler_branch_end(dbex->co);
560 static void rpa_dbex_rh_loopref(rpadbex_t *dbex, rparecord_t *prec)
563 * We ignore, it doesn't make sense for loops:
566 rpa_compiler_exp_begin(dbex->co, (prec->usertype & RPA_MATCH_OPTIONAL));
567 rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_CMP, R_LOO, DA, XX, 0));
568 rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_BGRE, DA, XX, XX, 3));
569 rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
570 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
571 rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_ADD, R_TOP, R_TOP, R_LOO, 0));
572 rvm_codegen_addins(dbex->co->cg, rvm_asm(RVM_MOVS, R0, R_LOO, XX, 0));
573 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
574 rpa_compiler_exp_end(dbex->co);
575 // rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
580 static rint rpa_dbex_rh_aref(rpadbex_t *dbex, rlong rec)
582 const rchar *name = NULL;
584 rpa_ruleinfo_t *info;
585 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
587 if (prec->type & RPA_RECORD_START) {
588 if (rpa_dbex_rulename(dbex, rec, &name, &namesize) < 0) {
593 if ((prec->usertype & RPA_LOOP_PATH) && rpa_parseinfo_loopdetect(dbex, rec, rpa_dbex_firstinlined(dbex))) {
594 info = (rpa_ruleinfo_t *) r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesize));
596 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_UNRESOLVED_SYMBOL);
597 RPA_DBEX_SETERRINFO_NAME(dbex, name, namesize);
600 if (rpa_dbex_findinlined(dbex, info->startrec)) {
601 rpa_dbex_rh_loopref(dbex, prec);
603 if (prec->usertype & RPA_MATCH_OPTIONAL) {
605 * Most probably this is useless case - loop refs shouldn't have quantitative modifiers
606 * but in case they do we wrap the inlined production rule in quantitative expression.
607 * The inlined named rule can take the quantitative argument, but I just don't have
608 * a clean way to pass it from here - so, lets play the records inside an expression that
609 * has the right quantitative argument.
610 * We ignore, it doesn't make sense for loops:
613 rpa_compiler_exp_begin(dbex->co, RPA_MATCH_OPTIONAL);
614 rpa_dbex_play_recordhandlers(dbex, info->startrec, info->sizerecs);
615 rvm_codegen_index_addrelocins(dbex->co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(dbex->co)->endidx, rvm_asm(RVM_BLES, DA, XX, XX, 0));
616 rpa_compiler_exp_end(dbex->co);
618 rpa_dbex_play_recordhandlers(dbex, info->startrec, info->sizerecs);
622 rpa_compiler_reference(dbex->co, name, namesize, (prec->usertype & RPA_MATCH_MASK));
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));
626 } else if (prec->type & RPA_RECORD_END) {
633 rpadbex_t *rpa_dbex_create(void)
635 rpadbex_t *dbex = (rpadbex_t *) r_zmalloc(sizeof(*dbex));
637 dbex->co = rpa_compiler_create();
638 dbex->pa = rpa_parser_create();
639 dbex->records = r_array_create(sizeof(rparecord_t));
640 dbex->rules = r_harray_create(sizeof(rpa_ruleinfo_t));
641 dbex->recstack = r_array_create(sizeof(rulong));
642 dbex->inlinestack = r_array_create(sizeof(rulong));
643 dbex->handlers = r_zmalloc(sizeof(rpa_dbex_recordhandler) * RPA_PRODUCTION_COUNT);
644 rpa_dbex_cfgset(dbex, RPA_DBEXCFG_OPTIMIZATIONS, 1);
646 dbex->handlers[RPA_PRODUCTION_NAMEDRULE] = rpa_dbex_rh_namedrule;
647 dbex->handlers[RPA_PRODUCTION_ANONYMOUSRULE] = rpa_dbex_rh_anonymousrule;
648 dbex->handlers[RPA_PRODUCTION_CLS] = rpa_dbex_rh_cls;
649 dbex->handlers[RPA_PRODUCTION_CHAR] = rpa_dbex_rh_char;
650 dbex->handlers[RPA_PRODUCTION_SPECIALCHAR] = rpa_dbex_rh_specialchar;
651 dbex->handlers[RPA_PRODUCTION_CLSCHAR] = rpa_dbex_rh_clschar;
652 dbex->handlers[RPA_PRODUCTION_AREF] = rpa_dbex_rh_aref;
653 dbex->handlers[RPA_PRODUCTION_CREF] = rpa_dbex_rh_aref;
654 dbex->handlers[RPA_PRODUCTION_BRACKETEXP] = rpa_dbex_rh_exp;
655 dbex->handlers[RPA_PRODUCTION_OROP] = rpa_dbex_rh_orop;
656 dbex->handlers[RPA_PRODUCTION_NOTOP] = rpa_dbex_rh_notop;
657 dbex->handlers[RPA_PRODUCTION_ALTBRANCH] = rpa_dbex_rh_branch;
658 dbex->handlers[RPA_PRODUCTION_NEGBRANCH] = rpa_dbex_rh_branch;
659 dbex->handlers[RPA_PRODUCTION_CHARRNG] = rpa_dbex_rh_range;
660 dbex->handlers[RPA_PRODUCTION_NUMRNG] = rpa_dbex_rh_numrange;
661 dbex->handlers[RPA_PRODUCTION_CLSNUM] = rpa_dbex_rh_clsnum;
662 dbex->handlers[RPA_PRODUCTION_BEGINCHAR] = rpa_dbex_rh_beginchar;
663 dbex->handlers[RPA_PRODUCTION_ENDCHAR] = rpa_dbex_rh_endchar;
664 dbex->handlers[RPA_PRODUCTION_NOROP] = rpa_dbex_rh_norop;
665 dbex->handlers[RPA_PRODUCTION_REQOP] = rpa_dbex_rh_exp;
666 dbex->handlers[RPA_PRODUCTION_MINOP] = rpa_dbex_rh_exp;
667 dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMIT] = rpa_dbex_rh_emit;
668 dbex->handlers[RPA_PRODUCTION_DIRECTIVENOEMIT] = rpa_dbex_rh_noemit;
669 dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMITALL] = rpa_dbex_rh_emitall;
670 dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMITNONE] = rpa_dbex_rh_emitnone;
671 dbex->handlers[RPA_PRODUCTION_DIRECTIVEEMITID] = rpa_dbex_rh_uid;
677 void rpa_dbex_destroy(rpadbex_t *dbex)
680 rpa_compiler_destroy(dbex->co);
681 rpa_parser_destroy(dbex->pa);
682 r_harray_destroy(dbex->rules);
683 r_array_destroy(dbex->records);
684 r_array_destroy(dbex->recstack);
685 r_array_destroy(dbex->inlinestack);
686 r_free(dbex->handlers);
692 static rint rpa_parseinfo_loopdetect_do(rpadbex_t *dbex, rlong parent, rlong loopto, rint inderction)
700 if (parent == loopto && inderction > 0)
702 for (i = 0; i < r_array_length(dbex->recstack); i++) {
703 if (parent == r_array_index(dbex->recstack, i, rlong))
706 r_array_add(dbex->recstack, &parent);
708 if (!(prec = (rparecord_t *)r_array_slot(dbex->records, parent)))
710 if (prec->ruleuid == RPA_PRODUCTION_AREF || prec->ruleuid == RPA_PRODUCTION_CREF)
713 i = rpa_recordtree_firstchild(dbex->records, parent, RPA_RECORD_START);
714 for (; i >= 0; i = rpa_recordtree_next(dbex->records, i, RPA_RECORD_START)) {
715 prec = (rparecord_t *)r_array_slot(dbex->records, i);
716 if (prec->ruleuid == RPA_PRODUCTION_RULENAME)
718 if (prec->ruleuid == RPA_PRODUCTION_AREF || prec->ruleuid == RPA_PRODUCTION_CREF) {
719 rpa_ruleinfo_t *info;
720 if ((inderction > 0 || i != parent) && i == loopto) {
722 * We found what we are looking for
727 if (rpa_dbex_rulename(dbex, i, &name, &namesiz) < 0)
729 info = (rpa_ruleinfo_t *) r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesiz));
732 if ((ret = rpa_parseinfo_loopdetect_do(dbex, info->startrec, loopto, inderction + 1)) > 0)
735 if ((ret = rpa_parseinfo_loopdetect_do(dbex, i, loopto, inderction + 1)) > 0)
739 if ((prec->usertype & RPA_MATCH_OPTIONAL) == 0 && (prec->ruleuid == RPA_PRODUCTION_CREF || prec->ruleuid == RPA_PRODUCTION_AREF ||
740 prec->ruleuid == RPA_PRODUCTION_CHAR || prec->ruleuid == RPA_PRODUCTION_CLS || prec->ruleuid == RPA_PRODUCTION_SPECIALCHAR))
745 r_array_removelast(dbex->recstack);
750 static rint rpa_parseinfo_loopdetect(rpadbex_t *dbex, rlong parent, rlong loopto)
752 if (parent != loopto) {
754 * Make sure we are dealing with a loop first
756 if (!rpa_parseinfo_loopdetect_do(dbex, loopto, parent, 0))
760 return (rpa_parseinfo_loopdetect_do(dbex, parent, loopto, 0)) ? 1 : 0;
764 static void rpa_parseinfo_marklooppath(rpadbex_t *dbex, rlong parent)
768 if (rpa_parseinfo_loopdetect(dbex, parent, parent) > 0) {
769 rpa_record_setusertype(dbex->records, parent, RPA_LOOP_PATH, RVALSET_OR);
770 for (i = rpa_recordtree_firstchild(dbex->records, parent, RPA_RECORD_START); i >= 0; i = rpa_recordtree_next(dbex->records, i, RPA_RECORD_START)) {
771 rpa_parseinfo_marklooppath(dbex, i);
777 static rint rpa_parseinfo_rule_checkforloop(rpadbex_t *dbex, const char *name, rsize_t namesize, rlong loopto)
779 rpa_ruleinfo_t *info = info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesize));
783 return rpa_parseinfo_loopdetect(dbex, info->startrec, loopto);
787 static void rpa_dbex_buildloopinfo(rpadbex_t *dbex)
790 rharray_t *rules = dbex->rules;
791 rpa_ruleinfo_t *info;
793 for (i = 0; i < r_array_length(rules->members); i++) {
794 if ((info = (rpa_ruleinfo_t *)r_harray_get(rules, i)) != NULL)
795 rpa_parseinfo_marklooppath(dbex, info->startrec);
799 * Mark the non-loop branches.
801 for (i = 0; i < r_array_length(dbex->records); i++) {
802 rparecord_t *prec = (rparecord_t *)r_array_slot(dbex->records, i);
803 if (prec->type == RPA_RECORD_START &&
804 (prec->ruleuid == RPA_PRODUCTION_ALTBRANCH) &&
805 (prec->usertype & RPA_LOOP_PATH) == 0) {
806 p = rpa_recordtree_parent(dbex->records, i, RPA_RECORD_START);
808 prec = (rparecord_t *)r_array_slot(dbex->records, p);
809 if (prec && (prec->usertype & RPA_LOOP_PATH))
810 rpa_record_setusertype(dbex->records, i, RPA_NONLOOP_PATH, RVALSET_OR);
817 static void rpa_dbex_buildruleinfo(rpadbex_t *dbex)
823 const rchar *name = NULL;
824 rsize_t namesize = 0;
827 r_object_destroy((robject_t *)dbex->rules);
830 dbex->rules = r_harray_create(sizeof(rpa_ruleinfo_t));
832 for (i = 0, nrecords = r_array_length(dbex->records); i < nrecords; i++) {
833 if (!(rec = rpa_dbex_record(dbex, i)))
835 if ((rec->ruleuid == RPA_PRODUCTION_NAMEDRULE) && (rec->type & RPA_RECORD_START)) {
836 r_memset(&info, 0, sizeof(info));
837 info.type = RPA_RULEINFO_NAMEDRULE;
839 info.sizerecs = rpa_recordtree_size(dbex->records, i);
840 if (info.sizerecs < 0)
842 if (rpa_dbex_rulename(dbex, i, &name, &namesize) < 0) {
845 r_harray_add(dbex->rules, name, namesize, &info);
846 i += info.sizerecs - 1;
847 } else if ((rec->ruleuid == RPA_PRODUCTION_ANONYMOUSRULE) && (rec->type & RPA_RECORD_START)) {
848 r_memset(&info, 0, sizeof(info));
849 info.type = RPA_RULEINFO_ANONYMOUSRULE;
851 info.sizerecs = rpa_recordtree_size(dbex->records, i);
852 if (info.sizerecs < 0)
854 if ((rec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, i, RPA_RECORD_END))))
855 r_harray_add(dbex->rules, rec->input, rec->inputsiz, &info);
856 i += info.sizerecs - 1;
857 } else if ((rec->type & RPA_RECORD_START) && (rec->ruleuid >= RPA_PRODUCTION_DIRECTIVEEMIT) && (rec->ruleuid <= RPA_PRODUCTION_DIRECTIVEEMITID)) {
858 r_memset(&info, 0, sizeof(info));
859 info.type = RPA_RULEINFO_DIRECTIVE;
861 info.sizerecs = rpa_recordtree_size(dbex->records, i);
862 if (info.sizerecs < 0)
864 if ((rec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, i, RPA_RECORD_END))))
865 r_harray_add(dbex->rules, rec->input, rec->inputsiz, &info);
866 i += info.sizerecs - 1;
873 static rlong rpa_dbex_copy_handler(rarray_t *records, rlong rec, rpointer userdata)
875 rpadbex_t *dbex = (rpadbex_t *)userdata;
878 rparecord_t *prec = (rparecord_t *)r_array_slot(records, rec);
879 if (prec->ruleuid == RPA_PRODUCTION_OCCURENCE && (prec->type & RPA_RECORD_START)) {
883 } else if (prec->ruleuid == RPA_PRODUCTION_OCCURENCE && (prec->type & (RPA_RECORD_MATCH | RPA_RECORD_END))) {
884 ruint32 usertype = RPA_MATCH_NONE;
887 * Don't copy it but set the usertype of the previous record accordingly.
889 switch (*prec->input) {
891 usertype = RPA_MATCH_OPTIONAL;
894 usertype = RPA_MATCH_MULTIPLE;
897 usertype = RPA_MATCH_MULTIOPT;
900 usertype = RPA_MATCH_NONE;
902 lastrec = r_array_length(dbex->records) - 1;
904 rpa_record_setusertype(dbex->records, lastrec, usertype, RVALSET_OR);
905 } else if (prec->ruleuid != RPA_RECORD_INVALID_UID) {
906 index = r_array_add(dbex->records, prec);
908 * Optimizations. Lets apply the optimizations while we copy the records.
909 * This is probably not the most clean way to apply optimizations, in the future
910 * we should probably think of optimization pass right before compiling.
912 if (dbex->optimizations) {
913 if (prec->ruleuid == RPA_PRODUCTION_OROP && (prec->type & RPA_RECORD_END)) {
914 rpa_optimiztion_orop(dbex->records, rpa_recordtree_get(dbex->records, index, RPA_RECORD_START));
923 static void rpa_dbex_copyrecords(rpadbex_t *dbex, rarray_t *records)
926 for (i = rpa_recordtree_get(records, 0, RPA_RECORD_START); i >= 0; i = rpa_recordtree_next(records, i, RPA_RECORD_START))
927 rpa_recordtree_walk(records, i, 0, rpa_dbex_copy_handler, dbex);
931 static rparecord_t *rpa_dbex_record(rpadbex_t *dbex, rlong rec)
935 if (!dbex || !dbex->rules)
937 if (rec < 0 || rec >= r_array_length(dbex->records))
939 prec = (rparecord_t *)r_array_slot(dbex->records, rec);
945 static rparecord_t *rpa_dbex_rulerecord(rpadbex_t *dbex, rparule_t rid)
948 rpa_ruleinfo_t *info;
951 if (!dbex || !dbex->rules)
953 info = r_harray_get(dbex->rules, rid);
956 rec = info->startrec + info->sizerecs - 1;
957 if (rec < 0 || rec >= r_array_length(dbex->records))
959 prec = (rparecord_t *)r_array_slot(dbex->records, rec);
964 static rint rpa_dbex_rulename(rpadbex_t *dbex, rlong rec, const rchar **name, rsize_t *namesize)
966 rparecord_t *pnamerec = rpa_dbex_record(dbex, rpa_recordtree_firstchild(dbex->records, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_START), RPA_RECORD_END));
967 if (!pnamerec || !(pnamerec->ruleuid & RPA_PRODUCTION_RULENAME))
969 *name = pnamerec->input;
970 *namesize = pnamerec->inputsiz;
975 rint rpa_dbex_open(rpadbex_t *dbex)
980 r_object_destroy((robject_t *)dbex->rules);
987 void rpa_dbex_close(rpadbex_t *dbex)
991 rpa_dbex_buildruleinfo(dbex);
992 rpa_dbex_buildloopinfo(dbex);
996 rlong rpa_dbex_load(rpadbex_t *dbex, const rchar *rules, rsize_t size)
1006 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTOPEN);
1009 if ((ret = rpa_parser_load(dbex->pa, rules, size)) < 0) {
1014 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_SYNTAX_ERROR);
1015 RPA_DBEX_SETERRINFO_OFFSET(dbex, ret);
1018 rpa_dbex_copyrecords(dbex, dbex->pa->stat->records);
1023 rlong rpa_dbex_load_s(rpadbex_t *dbex, const rchar *rules)
1025 return rpa_dbex_load(dbex, rules, r_strlen(rules));
1029 void rpa_dbex_dumpindented(rpadbex_t *dbex, rlong rec, rint level, const rchar *rulelabel)
1033 rparecord_t *prec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END));
1037 r_memset(buffer, 0, sizeof(buffer));
1038 for (i = 0; i < level + 1; i++)
1041 r_printf("%s, %c, %c", rulelabel, rpa_record_optchar(prec, 'x'), rpa_record_loopchar(prec, 'x'));
1043 size = R_MIN(prec->inputsiz, sizeof(buffer) - 1);
1044 r_strncpy(buffer, prec->input, size);
1046 if (size == (sizeof(buffer) - 1))
1047 r_printf(" %s ...\n", buffer);
1049 r_printf(" %s\n", buffer);
1054 static rlong rpa_dbex_firstinlined(rpadbex_t *dbex)
1056 rlong ret = r_array_empty(dbex->inlinestack) ? -1 : r_array_index(dbex->inlinestack, 0, rlong);
1061 static rint rpa_dbex_findinlined(rpadbex_t *dbex, rlong startrec)
1064 for (i = 0; i < r_array_length(dbex->inlinestack); i++) {
1065 if (r_array_index(dbex->inlinestack, i, rlong) == startrec)
1072 static void rpa_dbex_dumptree_do(rpadbex_t *dbex, rlong rec, rint level)
1074 rparecord_t *prec = rpa_dbex_record(dbex, rec);
1075 if (prec && prec->ruleuid == RPA_PRODUCTION_RULENAME)
1077 if (prec && (prec->ruleuid == RPA_PRODUCTION_AREF || prec->ruleuid == RPA_PRODUCTION_CREF)) {
1078 const rchar *name = NULL;
1079 rsize_t namesize = 0;
1081 rpa_ruleinfo_t *info;
1083 if (rpa_dbex_rulename(dbex, rec, &name, &namesize) >= 0) {
1084 loop = rpa_parseinfo_rule_checkforloop(dbex, name, namesize, rpa_dbex_firstinlined(dbex));
1085 info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rpa_dbex_lookup(dbex, name, namesize));
1087 if (!rpa_dbex_findinlined(dbex, info->startrec)) {
1089 * Temporary set the quantitative flags for the inlined rule to the parent
1090 * reference, so they are printed correctly. After the printing is done
1091 * restore the original flags.
1093 rparecord_t *prulestart = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, info->startrec, RPA_RECORD_START));
1094 rparecord_t *pruleend = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, info->startrec, RPA_RECORD_END));
1095 rulong optional = (prulestart->usertype & RPA_MATCH_OPTIONAL);
1096 prulestart->usertype |= (prec->usertype & RPA_MATCH_OPTIONAL);
1097 pruleend->usertype |= (prec->usertype & RPA_MATCH_OPTIONAL);
1098 r_array_add(dbex->inlinestack, &info->startrec);
1099 rpa_dbex_dumptree_do(dbex, info->startrec, level);
1100 r_array_removelast(dbex->inlinestack);
1102 prulestart->usertype &= ~RPA_MATCH_OPTIONAL;
1103 pruleend->usertype &= ~RPA_MATCH_OPTIONAL;
1106 rpa_dbex_dumpindented(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END), level, "loopref");
1112 rpa_dbex_dumpindented(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END), level, prec->rule);
1113 for (rec = rpa_recordtree_firstchild(dbex->records, rec, RPA_RECORD_START); rec >= 0; rec = rpa_recordtree_next(dbex->records, rec, RPA_RECORD_START)) {
1114 rpa_dbex_dumptree_do(dbex, rec, level + 1);
1119 rint rpa_dbex_dumptree(rpadbex_t *dbex, rparule_t rid)
1121 rpa_ruleinfo_t *info;
1126 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_PARAM);
1130 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1133 if (!(info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid))) {
1134 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1137 r_array_add(dbex->inlinestack, &info->startrec);
1138 rpa_dbex_dumptree_do(dbex, info->startrec, 0);
1139 r_array_removelast(dbex->inlinestack);
1144 rint rpa_dbex_dumpproductions(rpadbex_t *dbex)
1153 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1156 for (rid = rpa_dbex_first(dbex); rid >= 0; rid = rpa_dbex_next(dbex, rid)) {
1157 ret = rpa_dbex_strncpy(dbex, buffer, rid, sizeof(buffer));
1159 if (ret == sizeof(buffer))
1160 r_printf(" %s ...\n", buffer);
1162 r_printf(" %s\n", buffer);
1170 rint rpa_dbex_dumprecords(rpadbex_t *dbex)
1177 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1180 for (i = 0; i < r_array_length(dbex->records); i++) {
1181 rpa_record_dump(dbex->records, i);
1187 rint rpa_dbex_dumpinfo(rpadbex_t *dbex)
1190 rpa_ruleinfo_t *info;
1195 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1198 for (i = 0; i < r_array_length(dbex->rules->names); i++) {
1199 rstr_t *name = r_array_index(dbex->rules->names, i, rstr_t*);
1200 info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, i);
1201 switch (info->type) {
1202 case RPA_RULEINFO_NAMEDRULE:
1205 case RPA_RULEINFO_ANONYMOUSRULE:
1208 case RPA_RULEINFO_DIRECTIVE:
1215 r_printf("(%7d, %4d, code: %7ld, %5ld) : %s\n", info->startrec, info->sizerecs, info->codeoff, info->codesiz, name->str);
1221 rint rpa_dbex_dumpuids(rpadbex_t *dbex)
1225 rpa_ruleinfo_t *info;
1226 rchar *buffer = r_zmalloc(32 * sizeof(rchar));
1231 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1234 for (i = 0; i < r_array_length(dbex->rules->names); i++) {
1235 info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, i);
1236 if (info->type == RPA_RULEINFO_DIRECTIVE) {
1237 rparecord_t *prec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, info->startrec, RPA_RECORD_END));
1238 if (prec->ruleuid == RPA_PRODUCTION_DIRECTIVEEMITID && prec->inputsiz) {
1239 rec = rpa_recordtree_firstchild(dbex->records, info->startrec, RPA_RECORD_START);
1241 prec = rpa_dbex_record(dbex, rpa_recordtree_get(dbex->records, rec, RPA_RECORD_END));
1242 if (prec->ruleuid == RPA_PRODUCTION_ALIASNAME) {
1244 if (rpa_record2long(rpa_dbex_record(dbex, rpa_recordtree_next(dbex->records, rec, RPA_RECORD_END)), &dec) < 0)
1246 buffer = r_realloc(buffer, prec->inputsiz + 1);
1247 r_memset(buffer, 0, prec->inputsiz + 1);
1248 r_memcpy(buffer, prec->input, prec->inputsiz);
1249 r_printf("#define %s %d\n", buffer, dec);
1252 rec = rpa_recordtree_next(dbex->records, rec, RPA_RECORD_START);
1262 rint rpa_dbex_dumpcode(rpadbex_t* dbex, rparule_t rid)
1264 rpa_ruleinfo_t *info;
1268 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_PARAM);
1272 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1275 info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid);
1278 rvm_asm_dump(rvm_codegen_getcode(dbex->co->cg, info->codeoff), info->codesiz);
1283 rsize_t rpa_dbex_strlen(rpadbex_t *dbex, rparule_t rid)
1290 if ((prec = rpa_dbex_rulerecord(dbex, rid)) == NULL) {
1291 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1294 size = prec->inputsiz;
1299 rsize_t rpa_dbex_strncpy(rpadbex_t *dbex, rchar *dst, rparule_t rid, rsize_t n)
1306 if ((prec = rpa_dbex_rulerecord(dbex, rid)) == NULL) {
1307 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1310 size = prec->inputsiz;
1313 r_memset(dst, 0, n);
1314 r_strncpy(dst, prec->input, size);
1319 rparule_t rpa_dbex_first(rpadbex_t *dbex)
1321 if (!dbex || !dbex->rules)
1324 if (r_array_length(dbex->rules->members) > 0)
1330 rparule_t rpa_dbex_last(rpadbex_t *dbex)
1332 if (!dbex || !dbex->rules)
1335 if (r_array_length(dbex->rules->members) > 0)
1336 return r_array_length(dbex->rules->members) - 1;
1341 rparule_t rpa_dbex_lookup(rpadbex_t *dbex, const rchar *name, rsize_t namesize)
1347 return r_harray_taillookup(dbex->rules, name, namesize);
1351 rparule_t rpa_dbex_lookup_s(rpadbex_t *dbex, const rchar *name)
1353 return rpa_dbex_lookup(dbex, name, r_strlen(name));
1357 rparule_t rpa_dbex_next(rpadbex_t *dbex, rparule_t rid)
1359 if (!dbex || !dbex->rules)
1362 if (rid < r_array_length(dbex->rules->members))
1368 rparule_t rpa_dbex_prev(rpadbex_t *dbex, rparule_t rid)
1370 if (!dbex || !dbex->rules)
1379 rlong rpa_dbex_lasterror(rpadbex_t *dbex)
1383 return dbex->err.code;
1387 rlong rpa_dbex_lasterrorinfo(rpadbex_t *dbex, rpa_errinfo_t *errinfo)
1389 if (!dbex || !errinfo)
1391 r_memcpy(errinfo, &dbex->err, sizeof(rpa_errinfo_t));
1396 const rchar *rpa_dbex_version()
1402 static rlong rpa_dbex_play_recordhandler(rpadbex_t *dbex, rlong rec)
1404 rparecord_t *prec = (rparecord_t *) r_array_slot(dbex->records, rec);
1405 rpa_dbex_recordhandler handler = dbex->handlers[prec->ruleuid];
1407 if (handler(dbex, rec) < 0)
1414 static rlong rpa_dbex_play_recordhandlers(rpadbex_t *dbex, rlong rec, rlong nrecs)
1419 for (i = rec; i < rec + nrecs; i++) {
1420 prec = (rparecord_t *) r_array_slot(dbex->records, i);
1422 if (prec->ruleuid == RPA_PRODUCTION_MINOP && (prec->type & RPA_RECORD_START)) {
1423 rlong lastchild = rpa_recordtree_lastchild(dbex->records, i, RPA_RECORD_START);
1424 rlong firstchild = rpa_recordtree_firstchild(dbex->records, i, RPA_RECORD_START);
1425 if (firstchild < 0 || lastchild < 0 || firstchild == lastchild)
1427 if ((res = rpa_dbex_play_recordhandler(dbex, i)) < 0)
1429 if ((res = rpa_dbex_play_recordhandlers(dbex, lastchild, rpa_recordtree_size(dbex->records, lastchild))) < 0)
1431 if ((res = rpa_dbex_play_recordhandlers(dbex, firstchild, lastchild - firstchild)) < 0)
1433 if ((res = rpa_dbex_play_recordhandler(dbex, rpa_recordtree_get(dbex->records, i, RPA_RECORD_END))) < 0)
1435 i += rpa_recordtree_size(dbex->records, i) - 1;
1439 if (rpa_dbex_play_recordhandler(dbex, i) < 0)
1447 static rint rpa_dbex_compile_rule(rpadbex_t *dbex, rparule_t rid)
1450 rpa_ruleinfo_t *info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid);
1454 codeoff = rvm_codegen_getcodesize(dbex->co->cg);
1455 if (rpa_dbex_play_recordhandlers(dbex, info->startrec, info->sizerecs) < 0)
1457 info->codeoff = codeoff;
1458 info->codesiz = rvm_codegen_getcodesize(dbex->co->cg) - codeoff;
1464 rint rpa_dbex_compile(rpadbex_t *dbex)
1467 rvm_codelabel_t *labelerr;
1472 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1476 * By default all production rules emit
1479 rpa_compiler_destroy(dbex->co);
1480 dbex->co = rpa_compiler_create();
1481 rpa_dbex_setemit(dbex, TRUE);
1483 for (rid = rpa_dbex_first(dbex); rid >= 0; rid = rpa_dbex_next(dbex, rid)) {
1484 if (rpa_dbex_compile_rule(dbex, rid) < 0) {
1489 if (rvm_codegen_relocate(dbex->co->cg, &labelerr) < 0) {
1490 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_UNRESOLVED_SYMBOL);
1491 RPA_DBEX_SETERRINFO_NAME(dbex, labelerr->name->str, labelerr->name->size);
1499 rvm_asmins_t *rpa_dbex_executable(rpadbex_t *dbex)
1504 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1507 return rvm_codegen_getcode(dbex->co->cg, 0);
1511 rlong rpa_dbex_executableoffset(rpadbex_t *dbex, rparule_t rid)
1513 rpa_ruleinfo_t *info;
1518 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTCLOSED);
1521 info = (rpa_ruleinfo_t *)r_harray_get(dbex->rules, rid);
1523 RPA_DBEX_SETERRINFO_CODE(dbex, RPA_E_NOTFOUND);
1526 return info->codeoff;
1530 rlong rpa_dbex_cfgset(rpadbex_t *dbex, rulong cfg, rulong val)
1534 if (cfg == RPA_DBEXCFG_OPTIMIZATIONS) {
1535 dbex->optimizations = val;
1542 rlong rpa_dbex_cfgget(rpadbex_t *dbex, rulong cfg)
1546 if (cfg == RPA_DBEXCFG_OPTIMIZATIONS) {
1547 return dbex->optimizations;