RPA Toolkit
a2469d8bcae1267182c577334aeb754aaa1352f7
[rpatk.git] / rpa / rpacompiler.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 #include "rlib/rmem.h"
22 #include "rpa/rpacompiler.h"
23 #include "rlib/rstring.h"
24
25
26 static long rpa_codegen_add_numlabel_s(rvm_codegen_t *cg, const char *alphaname, long numname)
27 {
28 #if 0
29         /*
30          * The alphaname and numname, might be used for
31          * debugging at some point, but not used for now
32          */
33         char label[128];
34
35         r_memset(label, 0, sizeof(label));
36         r_snprintf(label, sizeof(label) - 1, "L%07ld__%s:", numname, alphaname);
37         return rvm_codegen_addlabel_default_s(cg, label);
38 #else
39         return rvm_codegen_addlabel_default_s(cg, NULL);
40 #endif
41 }
42
43
44 static long rpa_codegen_invalid_add_numlabel_s(rvm_codegen_t *cg, const char *alphaname, long numname)
45 {
46 #if 0
47         /*
48          * The alphaname and numname, might be used for
49          * debugging at some point, but not used for now
50          */
51         char label[128];
52
53         r_memset(label, 0, sizeof(label));
54         r_snprintf(label, sizeof(label) - 1, "L%07ld__%s:", numname, alphaname);
55         return rvm_codegen_invalid_addlabel_s(cg, label);
56 #else
57         return rvm_codegen_invalid_addlabel_s(cg, NULL);
58 #endif
59 }
60
61
62 void rpa_compiler_index_reference_nan(rpa_compiler_t *co, unsigned long index)
63 {
64         rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, index, rvm_asm(RVM_BL, DA, XX, XX, 0));
65 }
66
67
68 void rpa_compiler_reference_nan(rpa_compiler_t *co, const char *name, rsize_t namesize)
69 {
70         rpa_compiler_index_reference_nan(co, rvm_codemap_lookupadd(co->cg->codemap, name, namesize));
71 }
72
73
74 void rpa_compiler_reference_nan_s(rpa_compiler_t *co, const char *name)
75 {
76         rpa_compiler_reference_nan(co, name, r_strlen(name));
77 }
78
79
80 void rpa_compiler_index_reference_opt(rpa_compiler_t *co, unsigned long index)
81 {
82         rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, index, rvm_asm(RVM_BL, DA, XX, XX, 0));
83         rvm_codegen_addins(co->cg, rvm_asml(RVM_MOVS, R0, R0, XX, 0));
84         rvm_codegen_addins(co->cg, rvm_asm(RVM_BGRE, DA, XX, XX, 2));
85         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, 0));
86 }
87
88
89 void rpa_compiler_reference_opt(rpa_compiler_t *co, const char *name, rsize_t namesize)
90 {
91         rpa_compiler_index_reference_opt(co, rvm_codemap_lookupadd(co->cg->codemap, name, namesize));
92 }
93
94
95 void rpa_compiler_reference_opt_s(rpa_compiler_t *co, const char *name)
96 {
97         rpa_compiler_reference_opt(co, name, r_strlen(name));
98 }
99
100
101 void rpa_compiler_index_reference_mul(rpa_compiler_t *co, unsigned long index)
102 {
103         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
104         rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, index, rvm_asm(RVM_BL, DA, XX, XX, 0));
105         rvm_codegen_addins(co->cg, rvm_asml(RVM_MOVS, R0, R0, XX, 0));
106         rvm_codegen_addins(co->cg, rvm_asm(RVM_BGRE, DA, XX, XX, -2));
107         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R0, XX, XX, 0));
108         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R0, 0));
109         rvm_codegen_addins(co->cg, rvm_asm(RVM_BGRE, DA, XX, XX, 2));
110         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
111 }
112
113
114 void rpa_compiler_reference_mul(rpa_compiler_t *co, const char *name, rsize_t namesize)
115 {
116         rpa_compiler_index_reference_mul(co, rvm_codemap_lookupadd(co->cg->codemap, name, namesize));
117
118 }
119
120
121 void rpa_compiler_reference_mul_s(rpa_compiler_t *co, const char *name)
122 {
123         rpa_compiler_reference_mul(co, name, r_strlen(name));
124 }
125
126
127 void rpa_compiler_index_reference_mop(rpa_compiler_t *co, unsigned long index)
128 {
129         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
130         rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, index, rvm_asm(RVM_BL, DA, XX, XX, 0));
131         rvm_codegen_addins(co->cg, rvm_asml(RVM_MOVS, R0, R0, XX, 0));
132         rvm_codegen_addins(co->cg, rvm_asm(RVM_BGRE, DA, XX, XX, -2));
133         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R0, XX, XX, 0));
134         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R0, 0));
135         rvm_codegen_addins(co->cg, rvm_asm(RVM_BGRE, DA, XX, XX, 2));
136         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, 0));
137 }
138
139
140 void rpa_compiler_reference_mop(rpa_compiler_t *co, const char *name, rsize_t namesize)
141 {
142         rpa_compiler_index_reference_mop(co, rvm_codemap_lookupadd(co->cg->codemap, name, namesize));
143 }
144
145
146 void rpa_compiler_reference_mop_s(rpa_compiler_t *co, const char *name)
147 {
148         rpa_compiler_reference_mop(co, name, r_strlen(name));
149 }
150
151
152 void rpa_compiler_index_reference(rpa_compiler_t *co, unsigned long index, unsigned int qflag)
153 {
154         if (qflag == RPA_MATCH_OPTIONAL) {
155                 rpa_compiler_index_reference_opt(co, index);
156         } else if (qflag == RPA_MATCH_MULTIPLE) {
157                 rpa_compiler_index_reference_mul(co, index);
158         } else if (qflag == RPA_MATCH_MULTIOPT) {
159                 rpa_compiler_index_reference_mop(co, index);
160         } else {
161                 rpa_compiler_index_reference_nan(co, index);
162         }
163 }
164
165
166 void rpa_compiler_reference(rpa_compiler_t *co, const char *name, rsize_t namesize, unsigned int qflag)
167 {
168         rpa_compiler_index_reference(co, rvm_codemap_lookupadd(co->cg->codemap, name, namesize), qflag);
169 }
170
171
172 void rpa_compiler_reference_s(rpa_compiler_t *co, const char *name, unsigned int qflag)
173 {
174         rpa_compiler_reference(co, name, r_strlen(name), qflag);
175 }
176
177
178 rpa_compiler_t *rpa_compiler_create()
179 {
180         rpa_compiler_t *co;
181
182         co = (rpa_compiler_t *)r_malloc(sizeof(*co));
183         r_memset(co, 0, sizeof(*co));
184         co->cg = rvm_codegen_create();
185         co->scope = rvm_scope_create();
186         co->expressions = r_array_create(sizeof(rpa_ruledef_t));
187         co->ruleprefs = r_harray_create(sizeof(rpa_rulepref_t));
188         return co;
189 }
190
191
192 void rpa_compiler_destroy(rpa_compiler_t *co)
193 {
194         if (co) {
195                 rvm_codegen_destroy(co->cg);
196                 rvm_scope_destroy(co->scope);
197                 r_object_destroy((robject_t*)co->ruleprefs);
198                 r_object_destroy((robject_t*)co->expressions);
199                 r_free(co);
200         }
201 }
202
203
204 rpa_rulepref_t *rpa_compiler_rulepref_lookup(rpa_compiler_t *co, const char *name, unsigned int namesize)
205 {
206         long index = r_harray_lookup(co->ruleprefs, name, namesize);
207         if (index < 0)
208                 return NULL;
209         return (rpa_rulepref_t *)r_harray_slot(co->ruleprefs, index);
210 }
211
212
213 rpa_rulepref_t *rpa_compiler_rulepref_lookup_s(rpa_compiler_t *co, const char *name)
214 {
215         return rpa_compiler_rulepref_lookup(co, name, r_strlen(name));
216 }
217
218
219 rpa_rulepref_t *rpa_compiler_rulepref(rpa_compiler_t *co, const char *name, unsigned int namesize)
220 {
221         long index = r_harray_lookup(co->ruleprefs, name, namesize);
222         if (index < 0)
223                 index = r_harray_add(co->ruleprefs, name, namesize, NULL);
224         return (rpa_rulepref_t *)r_harray_slot(co->ruleprefs, index);
225 }
226
227
228 rpa_rulepref_t *rpa_compiler_rulepref_s(rpa_compiler_t *co, const char *name)
229 {
230         return rpa_compiler_rulepref(co, name, r_strlen(name));
231 }
232
233
234 void rpa_compiler_rulepref_set_ruleid(rpa_compiler_t *co, const char *name, unsigned int namesize, long ruleid)
235 {
236         rpa_rulepref_t *rulepref = rpa_compiler_rulepref(co, name, namesize);
237
238         R_ASSERT(rulepref);
239         rulepref->ruleid = ruleid;
240 }
241
242
243 void rpa_compiler_rulepref_set_ruleid_s(rpa_compiler_t *co, const char *name, long ruleid)
244 {
245         rpa_compiler_rulepref_set_ruleid(co, name, r_strlen(name), ruleid);
246 }
247
248
249 void rpa_compiler_rulepref_set_ruleuid(rpa_compiler_t *co, const char *name, unsigned int namesize, long ruleuid)
250 {
251         rpa_rulepref_t *rulepref = rpa_compiler_rulepref(co, name, namesize);
252
253         R_ASSERT(rulepref);
254         rulepref->ruleuid = ruleuid;
255 }
256
257
258 void rpa_compiler_rulepref_set_ruleuid_s(rpa_compiler_t *co, const char *name, long ruleuid)
259 {
260         rpa_compiler_rulepref_set_ruleuid(co, name, r_strlen(name), ruleuid);
261 }
262
263
264 void rpa_compiler_rulepref_set_flag(rpa_compiler_t *co, const char *name, unsigned int namesize, unsigned long flag)
265 {
266         rpa_rulepref_t *rulepref = rpa_compiler_rulepref(co, name, namesize);
267
268         R_ASSERT(rulepref);
269         rulepref->flags |= flag;
270 }
271
272
273 void rpa_compiler_rulepref_set_flag_s(rpa_compiler_t *co, const char *name, unsigned long flag)
274 {
275         rpa_compiler_rulepref_set_flag(co, name, r_strlen(name), flag);
276 }
277
278
279 void rpa_compiler_rulepref_clear_flag(rpa_compiler_t *co, const char *name, unsigned int namesize, unsigned long flag)
280 {
281         rpa_rulepref_t *rulepref = rpa_compiler_rulepref(co, name, namesize);
282
283         R_ASSERT(rulepref);
284         rulepref->flags &= ~flag;
285 }
286
287
288 void rpa_compiler_rulepref_clear_flag_s(rpa_compiler_t *co, const char *name, unsigned long flag)
289 {
290         rpa_compiler_rulepref_clear_flag(co, name, r_strlen(name), flag);
291 }
292
293
294 void rpa_compiler_rulepref_set(rpa_compiler_t *co, const char *name, unsigned int namesize, long ruleid, long ruleuid, unsigned long flags)
295 {
296         rpa_rulepref_t *rulepref = rpa_compiler_rulepref(co, name, namesize);
297
298         R_ASSERT(rulepref);
299         rulepref->ruleid = ruleid;
300         rulepref->ruleuid = ruleuid;
301         rulepref->flags = flags;
302 }
303
304
305 void rpa_compiler_rulepref_set_s(rpa_compiler_t *co, const char *name, long ruleid, long ruleuid, unsigned long flags)
306 {
307         rpa_compiler_rulepref_set(co, name, r_strlen(name), ruleid, ruleuid, flags);
308 }
309
310
311 #define RPA_RULEBLOB_SIZE (RPA_RULENAME_MAXSIZE + sizeof(rpa_ruledata_t) + 2*sizeof(unsigned long))
312
313 long rpa_compiler_addblob(rpa_compiler_t *co, long ruleid, long ruleuid, unsigned long flags, const char *name, unsigned long namesize)
314 {
315         char blob[RPA_RULEBLOB_SIZE];
316         char *ptr;
317         rpa_ruledata_t *pblob = (rpa_ruledata_t *)blob;
318
319         if (namesize >= RPA_RULENAME_MAXSIZE)
320                 return -1;
321         r_memset(pblob, 0, RPA_RULEBLOB_SIZE);
322         ptr = blob + sizeof(rpa_ruledata_t);
323         pblob->name = ptr - blob;
324         pblob->ruleid = ruleid;
325         pblob->ruleuid = ruleuid;
326         pblob->flags = flags;
327         pblob->namesize = namesize;
328         r_strncpy(ptr, name, namesize);
329         ptr += namesize;
330         pblob->size = (long)(ptr - blob + 1);
331         return rvm_codegen_adddata_s(co->cg, NULL, pblob, pblob->size);
332 }
333
334
335 long rpa_compiler_addblob_s(rpa_compiler_t *co, long ruleid, long ruleuid, unsigned long flags, const char *name)
336 {
337         return 0;
338 }
339
340
341 int rpa_compiler_loop_begin(rpa_compiler_t *co, const char *name, unsigned int namesize)
342 {
343         rpa_ruledef_t exp;
344         long ruleuid = 0;
345         long ruleid = 0;
346         unsigned long flags = 0;
347
348         r_memset(&exp, 0, sizeof(exp));
349         exp.rulepref = rpa_compiler_rulepref_lookup(co, name, namesize);
350         if (exp.rulepref) {
351                 flags = exp.rulepref->flags;
352                 ruleuid = exp.rulepref->ruleuid;
353                 ruleid = exp.rulepref->ruleid;
354         }
355         exp.start = rvm_codegen_getcodesize(co->cg);
356         exp.startidx = rvm_codegen_addlabel_default(co->cg, name, namesize);
357         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
358         exp.successidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__success", exp.start);
359         exp.failidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__fail", exp.start);
360         exp.againidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__again", exp.start);
361         exp.dataidx = rpa_compiler_addblob(co, ruleid, ruleuid, flags, name, namesize);
362
363         rvm_codegen_addins(co->cg, rvm_asm(RVM_CLR, R3, XX, XX, 0));
364         rvm_codegen_addins(co->cg, rvm_asm(RVM_CLR, R0, XX, XX, 0));
365         exp.loopidx = rpa_codegen_add_numlabel_s(co->cg, "__loop", exp.start);
366         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSHM, DA, XX, XX, BIT(R_REC)|BIT(R_LOO)|BIT(R_TOP)|BIT(LR)));
367         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R0, XX, XX, 0));
368         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_LOO, R3, XX, 0));
369         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_EMITRECORD)) {
370                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_EMITSTART, DA, R_TOP, XX, 0));
371         }
372         r_array_add(co->expressions, &exp);
373         return 0;
374 }
375
376
377 int rpa_compiler_loop_begin_s(rpa_compiler_t *co, const char *name)
378 {
379         return rpa_compiler_loop_begin(co, name, r_strlen(name));
380 }
381
382
383 int rpa_compiler_loop_end(rpa_compiler_t *co)
384 {
385         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
386
387         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R3, R_LOO, XX, 0));         // Save LOO to R3 before restoring the old one
388         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R0, XX, XX, 0));            // Pop the accumulated ret, although ignored here
389         rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R1)|BIT(R_LOO)|BIT(R_OTP)|BIT(LR)));
390         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R_OTP, 0));
391         rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, exp.failidx, rvm_asm(RVM_BEQ, DA, XX, XX, 0));  // ------------- R_TOP is the same
392         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_EMITRECORD)) {                                            //       |
393                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_EMITEND, DA, R_OTP, R0, 0)); //      |
394         }
395         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R3, R0, XX, 0));                                                //          |
396         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_TOP, R_OTP, XX, 0));                                          //          |
397         rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, exp.loopidx, rvm_asm(RVM_B, DA, XX, XX, 0));        //          |
398         rvm_codegen_redefinelabel_default(co->cg, exp.failidx);                                                     //          |
399         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_REC, R1, XX, 0));          //        <-------------------------------------
400         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
401         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
402
403         /*
404          *  END FAILED:
405          */
406         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
407         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R3, R_LOO, XX, 0));         // Save LOO to R3 before restoring the old one
408         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R0, XX, XX, 0));            // Pop the accumulated ret, use it to save the status for return
409         rvm_codegen_addins(co->cg, rvm_asm(RVM_POPM, DA, XX, XX, BIT(R_REC)|BIT(R_LOO)|BIT(R_TOP)|BIT(LR)));
410         rvm_codegen_addins(co->cg, rvm_asm(RVM_CMP, R0, DA, XX, 0));
411         rvm_codegen_addins(co->cg, rvm_asm(RVM_BGRE, DA, XX, XX, 3));
412         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
413         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_ABORTONFAIL)) {
414                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_ABORT, DA, R_OTP, R0, 0));
415         } else {
416                 rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
417         }
418         rvm_codegen_addins(co->cg, rvm_asm(RVM_ADD, R_TOP, R_TOP, R3, 0));
419         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
420         return 0;
421 }
422
423
424 int rpa_compiler_rule_begin(rpa_compiler_t *co, const char *name, unsigned int namesize, rpabitmap_t bitmap)
425 {
426         rpa_ruledef_t exp;
427         long ruleuid = 0;
428         long ruleid = 0;
429         unsigned long flags = 0;
430
431         r_memset(&exp, 0, sizeof(exp));
432         exp.rulepref = rpa_compiler_rulepref_lookup(co, name, namesize);
433         if (exp.rulepref) {
434                 flags = exp.rulepref->flags;
435                 ruleuid = exp.rulepref->ruleuid;
436                 ruleid = exp.rulepref->ruleid;
437         }
438         exp.start = rvm_codegen_getcodesize(co->cg);
439         exp.startidx = rvm_codegen_addlabel_default(co->cg, name, namesize);
440         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
441         exp.dataidx = rpa_compiler_addblob(co, ruleid, ruleuid, flags, name, namesize);
442         exp.bitmap = bitmap;
443         if (exp.bitmap) {
444                 rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHBITMAP, DA, XX, XX, exp.bitmap));
445                 rvm_codegen_addins(co->cg, rvm_asm(RVM_BXLES, LR, XX, XX, 0));
446         }
447         rvm_codegen_addins(co->cg, rvm_asm(RPA_CHECKCACHE, DA, R_TOP, XX, exp.start));
448         rvm_codegen_addins(co->cg, rvm_asm(RVM_BXNEQ, LR, XX, XX, 0));
449         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_REC, XX, XX, 0));
450         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
451         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
452         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_EMITRECORD)) {
453                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_EMITSTART, DA, R_TOP, XX, 0));
454         }
455
456         r_array_add(co->expressions, &exp);
457         return 0;
458 }
459
460
461 int rpa_compiler_rule_begin_s(rpa_compiler_t *co, const char *name, rpabitmap_t bitmap)
462 {
463         return rpa_compiler_rule_begin(co, name, r_strlen(name), bitmap);
464 }
465
466
467 int rpa_compiler_rule_end(rpa_compiler_t *co)
468 {
469         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
470
471         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
472         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_OTP, XX, XX, 0));
473         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R1, XX, XX, 0));
474         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R_OTP, 0));
475
476         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_EMITRECORD)) {
477                 rvm_codegen_addins(co->cg, rvm_asm(RVM_BEQ, DA, XX, XX, 4));
478                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_EMITEND, DA, R_OTP, R0, 0));
479         } else {
480                 rvm_codegen_addins(co->cg, rvm_asm(RVM_BEQ, DA, XX, XX, 3));
481         }
482         rvm_codegen_addins(co->cg, rvm_asml(RPA_SETCACHE, DA, R1, R_REC, exp.start));
483         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
484         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_REC, R1, XX, 0));
485         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
486         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_ABORTONFAIL)) {
487                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_ABORT, DA, R_OTP, R0, 0));
488         }
489         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
490         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
491         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
492         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
493         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_REC, XX, XX, 0));
494         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_OTP, R_TOP, XX, 0));
495         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
496         rvm_codegen_addins(co->cg, rvm_asml(RPA_SETCACHE, DA, R_REC, R_REC, exp.start));
497         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_ABORTONFAIL)) {
498                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_ABORT, DA, R_OTP, R0, 0));
499         }
500         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
501         return 0;
502 }
503
504
505 int rpa_compiler_inlinerule_begin(rpa_compiler_t *co, const char *name, unsigned int namesize, unsigned int flags)
506 {
507         rpa_ruledef_t exp;
508         long ruleuid = 0;
509         long ruleid = 0;
510         unsigned long ruleflags = 0;
511
512         r_memset(&exp, 0, sizeof(exp));
513         exp.rulepref = rpa_compiler_rulepref_lookup(co, name, namesize);
514         if (exp.rulepref) {
515                 ruleflags = exp.rulepref->flags;
516                 ruleuid = exp.rulepref->ruleuid;
517                 ruleid = exp.rulepref->ruleid;
518         }
519
520         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
521         exp.start = rvm_codegen_getcodesize(co->cg);
522         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__inlined", exp.start);
523         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
524         exp.dataidx = rpa_compiler_addblob(co, ruleid, ruleuid, ruleflags, name, namesize);
525
526         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_REC, XX, XX, 0));
527         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
528         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
529         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_EMITRECORD)) {
530                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_EMITSTART, DA, R_TOP, XX, 0));
531         }
532         r_array_add(co->expressions, &exp);
533         return 0;
534 }
535
536
537 int rpa_compiler_inlinerule_begin_s(rpa_compiler_t *co, const char *name, unsigned int flags)
538 {
539         return rpa_compiler_inlinerule_begin(co, name, r_strlen(name), flags);
540 }
541
542
543 int rpa_compiler_inlinerule_end(rpa_compiler_t *co)
544 {
545         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
546
547         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
548         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_OTP, XX, XX, 0));
549         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R1, XX, XX, 0));
550         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R_OTP, 0));
551         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_EMITRECORD)) {
552                 rvm_codegen_addins(co->cg, rvm_asm(RVM_BEQ, DA, XX, XX, 3));
553                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_EMITEND, DA, R_OTP, R0, 0));
554         } else {
555                 rvm_codegen_addins(co->cg, rvm_asm(RVM_BEQ, DA, XX, XX, 2));
556         }
557         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
558         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_REC, R1, XX, 0));
559         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
560         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
561         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
562         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
563         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
564         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_REC, XX, XX, 0));
565         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
566         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
567         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
568         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
569
570         return 0;
571 }
572
573
574 int rpa_compiler_exp_begin(rpa_compiler_t *co, unsigned int flags, rpabitmap_t bitmap)
575 {
576         rpa_ruledef_t exp;
577
578         exp.flags = flags;
579         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
580         exp.start = rvm_codegen_getcodesize(co->cg);
581         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__begin", exp.start);
582         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
583         exp.bitmap = bitmap;
584         if (exp.bitmap) {
585                 rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHBITMAP, DA, XX, XX, exp.bitmap));
586                 rvm_codegen_addins(co->cg, rvm_asm(RVM_BXLES, LR, XX, XX, 0));
587         }
588         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_REC, XX, XX, 0));
589         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
590         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
591         r_array_add(co->expressions, &exp);
592         return 0;
593 }
594
595
596 int rpa_compiler_exp_end(rpa_compiler_t *co)
597 {
598         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
599
600         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
601         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R1, XX, XX, 0));
602         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R0, XX, XX, 0));
603         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
604         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
605         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
606         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
607         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
608         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_REC, XX, XX, 0));
609         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
610         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
611         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
612         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
613         return 0;
614 }
615
616
617 int rpa_compiler_altexp_begin(rpa_compiler_t *co, unsigned int flags, rpabitmap_t bitmap)
618 {
619
620         rpa_ruledef_t exp;
621
622         exp.flags = flags;
623         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
624         exp.start = rvm_codegen_getcodesize(co->cg);
625         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__begin", exp.start);
626         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
627         exp.bitmap = bitmap;
628         if (exp.bitmap) {
629                 rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHBITMAP, DA, XX, XX, exp.bitmap));
630                 rvm_codegen_addins(co->cg, rvm_asm(RVM_BXLES, LR, XX, XX, 0));
631         }
632         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
633         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
634
635         r_array_add(co->expressions, &exp);
636         return 0;
637 }
638
639
640 int rpa_compiler_altexp_end(rpa_compiler_t *co)
641 {
642         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
643
644         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
645         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
646         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
647         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
648         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
649         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
650         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R1, XX, XX, 0));
651         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
652         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
653
654         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
655         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
656 //      rvm_codegen_addins(co->cg, rvm_asm(RPA_VERIFYBITMAP, DA, XX, XX, exp.bitmap));
657         return 0;
658 }
659
660
661 int rpa_compiler_branch_begin(rpa_compiler_t *co, unsigned int flags, rpabitmap_t bitmap)
662 {
663         rpa_ruledef_t exp;
664
665         exp.flags = flags;
666         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
667         exp.start = rvm_codegen_getcodesize(co->cg);
668         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__begin", exp.start);
669         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
670         exp.bitmap = bitmap;
671         if (exp.bitmap) {
672                 rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHBITMAP, DA, XX, XX, exp.bitmap));
673                 rvm_codegen_addins(co->cg, rvm_asm(RVM_BXLES, LR, XX, XX, 0));
674         }
675         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_REC, XX, XX, 0));
676         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
677         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
678
679         r_array_add(co->expressions, &exp);
680         return 0;
681 }
682
683
684 int rpa_compiler_branch_end(rpa_compiler_t *co)
685 {
686         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
687
688         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
689         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R1, XX, XX, 0));
690         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R0, XX, XX, 0));
691         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
692         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
693         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
694         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
695         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
696         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_REC, XX, XX, 0));
697         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
698         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
699         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
700         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
701         rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
702
703         return 0;
704 }
705
706
707 int rpa_compiler_nonloopybranch_begin(rpa_compiler_t *co, unsigned int flags)
708 {
709         rpa_ruledef_t exp;
710
711         exp.flags = flags;
712         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
713         exp.start = rvm_codegen_getcodesize(co->cg);
714         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__begin", exp.start);
715         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
716         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_REC, XX, XX, 0));
717         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
718         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
719         rvm_codegen_addins(co->cg, rvm_asm(RVM_CMP, R_LOO, DA, XX, 0));
720         rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, exp.endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
721         r_array_add(co->expressions, &exp);
722         return 0;
723
724 }
725
726
727 int rpa_compiler_nonloopybranch_end(rpa_compiler_t *co)
728 {
729         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
730
731         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
732         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R1, XX, XX, 0));
733         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R0, XX, XX, 0));
734         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
735         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_LOO, R0, XX, 0));
736         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
737         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
738         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
739         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
740         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_REC, XX, XX, 0));
741         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
742         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
743         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
744         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
745         rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
746
747         return 0;
748 }
749
750
751 int rpa_compiler_class_begin(rpa_compiler_t *co, unsigned int flags)
752 {
753         rpa_ruledef_t exp;
754
755         exp.flags = flags;
756         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
757         exp.start = rvm_codegen_getcodesize(co->cg);
758         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__begin", exp.start);
759         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
760         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
761         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
762
763         r_array_add(co->expressions, &exp);
764         return 0;
765 }
766
767
768 int rpa_compiler_class_end(rpa_compiler_t *co)
769 {
770         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
771
772         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
773         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
774         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
775         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
776         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
777         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
778         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R1, XX, XX, 0));
779         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
780         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
781
782         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
783         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
784         return 0;
785 }
786
787
788 int rpa_compiler_notexp_begin(rpa_compiler_t *co, unsigned int flags)
789 {
790         rpa_ruledef_t exp;
791
792         exp.flags = flags;
793         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
794         exp.start = rvm_codegen_getcodesize(co->cg);
795         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__begin", exp.start);
796         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
797         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_REC, XX, XX, 0));
798         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
799         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
800
801         r_array_add(co->expressions, &exp);
802         return 0;
803 }
804
805
806 int rpa_compiler_notexp_end(rpa_compiler_t *co)
807 {
808         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
809
810         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
811         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
812         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_REC, XX, XX, 0));
813         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
814         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
815         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
816         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
817         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
818         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R0, XX, XX, 0));
819         rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHSPCHR_NAN, DA, XX, XX, '.'));
820         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
821
822         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
823         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
824         return 0;
825 }
826
827
828 int rpa_compiler_negexp_begin(rpa_compiler_t *co, unsigned int flags)
829 {
830         rpa_ruledef_t exp;
831
832         exp.flags = flags;
833         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
834         exp.start = rvm_codegen_getcodesize(co->cg);
835         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__begin", exp.start);
836         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
837         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_REC, XX, XX, 0));
838         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
839         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
840
841         r_array_add(co->expressions, &exp);
842         return 0;
843
844 }
845
846
847 int rpa_compiler_negexp_end(rpa_compiler_t *co)
848 {
849         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
850
851         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
852         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
853         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_REC, XX, XX, 0));
854         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
855         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
856         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
857         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
858         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
859         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R0, XX, XX, 0));
860         rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHSPCHR_NAN, DA, XX, XX, '.'));
861         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
862         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
863         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
864         return 0;
865 }