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