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