RPA Toolkit
2c55986dcc7084cc2de824d5b8a3b246a1194afe
[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 = 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)
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
443         rvm_codegen_addins(co->cg, rvm_asm(RPA_CHECKCACHE, DA, R_TOP, XX, exp.start));
444         rvm_codegen_addins(co->cg, rvm_asm(RVM_BXNEQ, LR, XX, XX, 0));
445         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_REC, XX, XX, 0));
446         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
447         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
448         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_EMITRECORD)) {
449                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_EMITSTART, DA, R_TOP, XX, 0));
450         }
451
452         r_array_add(co->expressions, &exp);
453         return 0;
454 }
455
456
457 int rpa_compiler_rule_begin_s(rpa_compiler_t *co, const char *name)
458 {
459         return rpa_compiler_rule_begin(co, name, r_strlen(name));
460 }
461
462
463 int rpa_compiler_rule_end(rpa_compiler_t *co)
464 {
465         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
466
467         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
468         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_OTP, XX, XX, 0));
469         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R1, XX, XX, 0));
470         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R_OTP, 0));
471
472         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_EMITRECORD)) {
473                 rvm_codegen_addins(co->cg, rvm_asm(RVM_BEQ, DA, XX, XX, 4));
474                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_EMITEND, DA, R_OTP, R0, 0));
475         } else {
476                 rvm_codegen_addins(co->cg, rvm_asm(RVM_BEQ, DA, XX, XX, 3));
477         }
478         rvm_codegen_addins(co->cg, rvm_asml(RPA_SETCACHE, DA, R1, R_REC, exp.start));
479         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
480         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_REC, R1, XX, 0));
481         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
482         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_ABORTONFAIL)) {
483                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_ABORT, DA, R_OTP, R0, 0));
484         }
485         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
486         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
487         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
488         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
489         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_REC, XX, XX, 0));
490         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_OTP, R_TOP, XX, 0));
491         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
492         rvm_codegen_addins(co->cg, rvm_asml(RPA_SETCACHE, DA, R_REC, R_REC, exp.start));
493         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_ABORTONFAIL)) {
494                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_ABORT, DA, R_OTP, R0, 0));
495         }
496         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
497         return 0;
498 }
499
500
501 int rpa_compiler_inlinerule_begin(rpa_compiler_t *co, const char *name, unsigned int namesize, unsigned int flags)
502 {
503         rpa_ruledef_t exp;
504         long ruleuid = 0;
505         long ruleid = 0;
506         unsigned long ruleflags = 0;
507
508         r_memset(&exp, 0, sizeof(exp));
509         exp.rulepref = rpa_compiler_rulepref_lookup(co, name, namesize);
510         if (exp.rulepref) {
511                 ruleflags = exp.rulepref->flags;
512                 ruleuid = exp.rulepref->ruleuid;
513                 ruleid = exp.rulepref->ruleid;
514         }
515
516         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
517         exp.start = rvm_codegen_getcodesize(co->cg);
518         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__inlined", exp.start);
519         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
520         exp.dataidx = rpa_compiler_addblob(co, ruleid, ruleuid, ruleflags, name, namesize);
521
522         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_REC, XX, XX, 0));
523         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
524         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
525         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_EMITRECORD)) {
526                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_EMITSTART, DA, R_TOP, XX, 0));
527         }
528         r_array_add(co->expressions, &exp);
529         return 0;
530 }
531
532
533 int rpa_compiler_inlinerule_begin_s(rpa_compiler_t *co, const char *name, unsigned int flags)
534 {
535         return rpa_compiler_inlinerule_begin(co, name, r_strlen(name), flags);
536 }
537
538
539 int rpa_compiler_inlinerule_end(rpa_compiler_t *co)
540 {
541         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
542
543         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
544         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_OTP, XX, XX, 0));
545         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R1, XX, XX, 0));
546         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R_OTP, 0));
547         if (exp.rulepref && (exp.rulepref->flags & RPA_RFLAG_EMITRECORD)) {
548                 rvm_codegen_addins(co->cg, rvm_asm(RVM_BEQ, DA, XX, XX, 3));
549                 rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BLOB, exp.dataidx, rvm_asm(RPA_EMITEND, DA, R_OTP, R0, 0));
550         } else {
551                 rvm_codegen_addins(co->cg, rvm_asm(RVM_BEQ, DA, XX, XX, 2));
552         }
553         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
554         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_REC, R1, XX, 0));
555         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
556         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
557         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
558         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
559         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
560         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_REC, XX, XX, 0));
561         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
562         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
563         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
564         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
565
566         return 0;
567 }
568
569
570 int rpa_compiler_exp_begin(rpa_compiler_t *co, unsigned int flags)
571 {
572         rpa_ruledef_t exp;
573
574         exp.flags = flags;
575         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
576         exp.start = rvm_codegen_getcodesize(co->cg);
577         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__begin", exp.start);
578         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
579         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_REC, XX, XX, 0));
580         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
581         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
582         r_array_add(co->expressions, &exp);
583         return 0;
584 }
585
586
587 int rpa_compiler_exp_end(rpa_compiler_t *co)
588 {
589         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
590
591         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
592         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R1, XX, XX, 0));
593         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R0, XX, XX, 0));
594         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
595         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
596         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
597         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
598         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
599         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_REC, XX, XX, 0));
600         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
601         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
602         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
603         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
604         return 0;
605 }
606
607
608 int rpa_compiler_altexp_begin(rpa_compiler_t *co, unsigned int flags)
609 {
610         rpa_ruledef_t exp;
611
612         exp.flags = flags;
613         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
614         exp.start = rvm_codegen_getcodesize(co->cg);
615         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__begin", exp.start);
616         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
617         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
618         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
619
620         r_array_add(co->expressions, &exp);
621         return 0;
622 }
623
624
625 int rpa_compiler_altexp_end(rpa_compiler_t *co)
626 {
627         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
628
629         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
630         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
631         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
632         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
633         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
634         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
635         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R1, XX, XX, 0));
636
637         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
638         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
639
640         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
641         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
642         return 0;
643 }
644
645
646 int rpa_compiler_branch_begin(rpa_compiler_t *co, unsigned int flags)
647 {
648         rpa_ruledef_t exp;
649
650         exp.flags = flags;
651         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
652         exp.start = rvm_codegen_getcodesize(co->cg);
653         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__begin", exp.start);
654         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
655         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_REC, XX, XX, 0));
656         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
657         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
658
659         r_array_add(co->expressions, &exp);
660         return 0;
661 }
662
663
664 int rpa_compiler_branch_end(rpa_compiler_t *co)
665 {
666         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
667
668         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
669         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R1, XX, XX, 0));
670         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R0, XX, XX, 0));
671         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
672         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
673         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
674         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
675         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
676         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_REC, XX, XX, 0));
677         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
678         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
679         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
680         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
681         rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
682
683         return 0;
684 }
685
686
687 int rpa_compiler_nonloopybranch_begin(rpa_compiler_t *co, unsigned int flags)
688 {
689         rpa_ruledef_t exp;
690
691         exp.flags = flags;
692         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
693         exp.start = rvm_codegen_getcodesize(co->cg);
694         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__begin", exp.start);
695         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
696         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_REC, XX, XX, 0));
697         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
698         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
699         rvm_codegen_addins(co->cg, rvm_asm(RVM_CMP, R_LOO, DA, XX, 0));
700         rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, exp.endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
701         r_array_add(co->expressions, &exp);
702         return 0;
703
704 }
705
706
707 int rpa_compiler_nonloopybranch_end(rpa_compiler_t *co)
708 {
709         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
710
711         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
712         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R1, XX, XX, 0));
713         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R0, XX, XX, 0));
714         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
715         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOV, R_LOO, R0, XX, 0));
716         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
717         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
718         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
719         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
720         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_REC, XX, XX, 0));
721         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
722         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
723         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
724         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
725         rvm_codegen_index_addrelocins(co->cg, RVM_RELOC_BRANCH, RPA_COMPILER_CURRENTEXP(co)->endidx, rvm_asm(RVM_BGRE, DA, XX, XX, 0));
726
727         return 0;
728 }
729
730
731 int rpa_compiler_class_begin(rpa_compiler_t *co, unsigned int flags)
732 {
733         rpa_ruledef_t exp;
734
735         exp.flags = flags;
736         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
737         exp.start = rvm_codegen_getcodesize(co->cg);
738         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__begin", exp.start);
739         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
740         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
741         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
742
743         r_array_add(co->expressions, &exp);
744         return 0;
745 }
746
747
748 int rpa_compiler_class_end(rpa_compiler_t *co)
749 {
750         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
751
752         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
753         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
754         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
755         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
756         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
757         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
758         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R1, XX, XX, 0));
759         rvm_codegen_addins(co->cg, rvm_asm(RVM_SUBS, R0, R_TOP, R1, 0));
760         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
761
762         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
763         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
764         return 0;
765 }
766
767
768 int rpa_compiler_notexp_begin(rpa_compiler_t *co, unsigned int flags)
769 {
770         rpa_ruledef_t exp;
771
772         exp.flags = flags;
773         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
774         exp.start = rvm_codegen_getcodesize(co->cg);
775         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__begin", exp.start);
776         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
777         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_REC, XX, XX, 0));
778         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
779         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
780
781         r_array_add(co->expressions, &exp);
782         return 0;
783 }
784
785
786 int rpa_compiler_notexp_end(rpa_compiler_t *co)
787 {
788         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
789
790         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
791         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
792         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_REC, XX, XX, 0));
793         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
794         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
795         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
796         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
797         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
798         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R0, XX, XX, 0));
799         rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHSPCHR_NAN, DA, XX, XX, '.'));
800         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
801
802         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
803         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
804         return 0;
805 }
806
807
808 int rpa_compiler_negexp_begin(rpa_compiler_t *co, unsigned int flags)
809 {
810         rpa_ruledef_t exp;
811
812         exp.flags = flags;
813         exp.branch = rvm_codegen_addins(co->cg, rvm_asm(RVM_B, DA, XX, XX, 0));
814         exp.start = rvm_codegen_getcodesize(co->cg);
815         exp.startidx = rpa_codegen_add_numlabel_s(co->cg, "__begin", exp.start);
816         exp.endidx = rpa_codegen_invalid_add_numlabel_s(co->cg, "__end", exp.start);
817         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_REC, XX, XX, 0));
818         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, R_TOP, XX, XX, 0));
819         rvm_codegen_addins(co->cg, rvm_asm(RVM_PUSH, LR, XX, XX, 0));
820
821         r_array_add(co->expressions, &exp);
822         return 0;
823
824 }
825
826
827 int rpa_compiler_negexp_end(rpa_compiler_t *co)
828 {
829         rpa_ruledef_t exp = r_array_pop(co->expressions, rpa_ruledef_t);
830
831         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
832         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
833         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_REC, XX, XX, 0));
834         rvm_codegen_addins(co->cg, rvm_asm(RVM_MOVS, R0, DA, XX, -1));
835         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
836         rvm_codegen_redefinelabel_default(co->cg, exp.endidx);
837         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, LR, XX, XX, 0));
838         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R_TOP, XX, XX, 0));
839         rvm_codegen_addins(co->cg, rvm_asm(RVM_POP, R0, XX, XX, 0));
840         rvm_codegen_addins(co->cg, rvm_asm(RPA_MATCHSPCHR_NAN, DA, XX, XX, '.'));
841         rvm_codegen_addins(co->cg, rvm_asm(RVM_BX, LR, XX, XX, 0));
842         rvm_codegen_replaceins(co->cg, exp.branch, rvm_asm(RVM_B, DA, XX, XX, rvm_codegen_getcodesize(co->cg) - exp.branch));
843         rpa_compiler_index_reference(co, exp.startidx, (exp.flags & RPA_MATCH_MASK));
844         return 0;
845 }