Merge branch 'master' into verilog-ams
[sverilog.git] / t-dll-proc.cc
blob5d843e9d492962e956dc8e89ab9955b5d07627a3
1 /*
2 * Copyright (c) 2000 Stephen Williams (steve@icarus.com)
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
8 * any later version.will need a Picture Elements Binary Software
9 * License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20 #ifdef HAVE_CVS_IDENT
21 #ident "$Id: $"
22 #endif
24 # include "config.h"
26 # include <iostream>
28 # include <cstring>
29 # include "target.h"
30 # include "ivl_target.h"
31 # include "compiler.h"
32 # include "t-dll.h"
33 #ifdef HAVE_MALLOC_H
34 # include <malloc.h>
35 #endif
36 # include <stdlib.h>
38 bool dll_target::process(const NetProcTop*net)
40 ivl_process_t obj = (struct ivl_process_s*)
41 calloc(1, sizeof(struct ivl_process_s));
43 switch (net->type()) {
44 case NetProcTop::KINITIAL:
45 obj->type_ = IVL_PR_INITIAL;
46 break;
47 case NetProcTop::KALWAYS:
48 obj->type_ = IVL_PR_ALWAYS;
49 break;
50 default:
51 assert(0);
54 /* Save the scope of the process. */
55 obj->scope_ = lookup_scope_(net->scope());
57 obj->nattr = net->attr_cnt();
58 obj->attr = fill_in_attributes(net);
60 /* This little bit causes the process to be completely
61 generated so that it can be passed to the DLL. The
62 stmt_cur_ member us used to hold a pointer to the current
63 statement in progress, and the emit_proc() method fills in
64 that object.
66 We know a few things about the current statement: we are
67 not in the middle of one, and when we are done, we have our
68 statement back. The asserts check these conditions. */
70 assert(stmt_cur_ == 0);
71 stmt_cur_ = (struct ivl_statement_s*)calloc(1, sizeof*stmt_cur_);
72 assert(stmt_cur_);
73 net->statement()->emit_proc(this);
75 assert(stmt_cur_);
76 obj->stmt_ = stmt_cur_;
77 stmt_cur_ = 0;
79 /* Save the process in the design. */
80 obj->next_ = des_.threads_;
81 des_.threads_ = obj;
83 return true;
86 void dll_target::task_def(const NetScope*net)
88 ivl_scope_t scope = lookup_scope_(net);
89 const NetTaskDef*def = net->task_def();
91 assert(stmt_cur_ == 0);
92 stmt_cur_ = (struct ivl_statement_s*)calloc(1, sizeof*stmt_cur_);
93 assert(stmt_cur_);
94 def->proc()->emit_proc(this);
96 assert(stmt_cur_);
97 scope->def = stmt_cur_;
98 stmt_cur_ = 0;
102 bool dll_target::func_def(const NetScope*net)
104 ivl_scope_t scope = lookup_scope_(net);
105 const NetFuncDef*def = net->func_def();
107 assert(stmt_cur_ == 0);
108 stmt_cur_ = (struct ivl_statement_s*)calloc(1, sizeof*stmt_cur_);
109 assert(stmt_cur_);
110 def->proc()->emit_proc(this);
112 assert(stmt_cur_);
113 scope->def = stmt_cur_;
114 stmt_cur_ = 0;
116 scope->ports = def->port_count() + 1;
117 if (scope->ports > 0) {
118 scope->port = new ivl_signal_t[scope->ports];
119 for (unsigned idx = 1 ; idx < scope->ports ; idx += 1)
120 scope->port[idx] = find_signal(des_, def->port(idx-1));
123 /* FIXME: the ivl_target API expects port-0 to be the output
124 port. This assumes that the return value is a signal, which
125 is *not* correct. Someday, I'm going to have to change
126 this, but that will break code generators that use this
127 result. */
128 if (const NetNet*ret_sig = def->return_sig()) {
129 scope->port[0] = find_signal(des_, ret_sig);
130 return true;
133 cerr << "?:0" << ": internal error: "
134 << "Function " << net->basename() << " has a return type"
135 << " that I do not understand." << endl;
137 return false;
141 * This private function makes the assignment lvals for the various
142 * kinds of assignment statements.
144 void dll_target::make_assign_lvals_(const NetAssignBase*net)
146 assert(stmt_cur_);
148 unsigned cnt = net->l_val_count();
150 stmt_cur_->u_.assign_.lvals_ = cnt;
151 stmt_cur_->u_.assign_.lval_ = new struct ivl_lval_s[cnt];
152 stmt_cur_->u_.assign_.delay = 0;
154 for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
155 struct ivl_lval_s*cur = stmt_cur_->u_.assign_.lval_ + idx;
156 const NetAssign_*asn = net->l_val(idx);
157 const NetExpr*loff = asn->get_base();
159 if (loff == 0) {
160 cur->loff = 0;
161 } else {
162 loff->expr_scan(this);
163 cur->loff = expr_;
164 expr_ = 0;
167 cur->width_ = asn->lwidth();
169 if (asn->sig()) {
170 cur->type_ = IVL_LVAL_REG;
171 cur->n.sig = find_signal(des_, asn->sig());
173 cur->idx = 0;
174 // If there is a word select expression, it is
175 // really an array index. Note that the word index
176 // expression is already converted to canonical
177 // form by elaboration.
178 if (asn->word()) {
179 assert(expr_ == 0);
180 asn->word()->expr_scan(this);
181 cur->type_ = IVL_LVAL_ARR;
182 cur->idx = expr_;
183 expr_ = 0;
185 } else {
186 assert(0);
193 void dll_target::proc_assign(const NetAssign*net)
195 assert(stmt_cur_);
196 assert(stmt_cur_->type_ == IVL_ST_NONE);
198 stmt_cur_->type_ = IVL_ST_ASSIGN;
199 FILE_NAME(stmt_cur_, net);
201 stmt_cur_->u_.assign_.delay = 0;
203 /* Make the lval fields. */
204 make_assign_lvals_(net);
206 assert(expr_ == 0);
207 net->rval()->expr_scan(this);
208 stmt_cur_->u_.assign_.rval_ = expr_;
209 expr_ = 0;
211 const NetExpr*del = net->get_delay();
212 if (del) {
213 del->expr_scan(this);
214 stmt_cur_->u_.assign_.delay = expr_;
215 expr_ = 0;
220 void dll_target::proc_assign_nb(const NetAssignNB*net)
222 const NetExpr* delay_exp = net->get_delay();
223 assert(stmt_cur_);
224 assert(stmt_cur_->type_ == IVL_ST_NONE);
226 stmt_cur_->type_ = IVL_ST_ASSIGN_NB;
227 FILE_NAME(stmt_cur_, net);
229 stmt_cur_->u_.assign_.delay = 0;
231 /* Make the lval fields. */
232 make_assign_lvals_(net);
234 /* Make the rval field. */
235 assert(expr_ == 0);
236 net->rval()->expr_scan(this);
237 stmt_cur_->u_.assign_.rval_ = expr_;
238 expr_ = 0;
240 if (const NetEConst*delay_num = dynamic_cast<const NetEConst*>(delay_exp)) {
241 verinum val = delay_num->value();
242 ivl_expr_t de = new struct ivl_expr_s;
243 de->type_ = IVL_EX_ULONG;
244 de->width_ = 8 * sizeof(unsigned long);
245 de->signed_ = 0;
246 de->u_.ulong_.value = val.as_ulong();
247 stmt_cur_->u_.assign_.delay = de;
249 } else if (delay_exp != 0) {
250 delay_exp->expr_scan(this);
251 stmt_cur_->u_.assign_.delay = expr_;
252 expr_ = 0;
256 bool dll_target::proc_block(const NetBlock*net)
258 assert(stmt_cur_);
259 assert(stmt_cur_->type_ == IVL_ST_NONE);
260 FILE_NAME(stmt_cur_, net);
262 /* First, count the statements in the block. */
263 unsigned count = 0;
264 for (const NetProc*cur = net->proc_first()
265 ; cur ; cur = net->proc_next(cur))
266 count += 1;
268 /* If the block has no statements, then turn it into a no-op */
269 if (count == 0) {
270 stmt_cur_->type_ = IVL_ST_NOOP;
271 return true;
274 /* If there is exactly one statement, there is no need for the
275 block wrapper, generate the contained statement instead. */
276 if ((count == 1) && (net->subscope() == 0)) {
277 return net->proc_first()->emit_proc(this);
281 /* Handle the general case. The block has some statements in
282 it, so fill in the block fields of the existing statement,
283 and generate the contents for the statement array. */
285 stmt_cur_->type_ = (net->type() == NetBlock::SEQU)
286 ? IVL_ST_BLOCK
287 : IVL_ST_FORK;
288 stmt_cur_->u_.block_.nstmt_ = count;
289 stmt_cur_->u_.block_.stmt_ = (struct ivl_statement_s*)
290 calloc(count, sizeof(struct ivl_statement_s));
292 if (net->subscope())
293 stmt_cur_->u_.block_.scope = lookup_scope_(net->subscope());
294 else
295 stmt_cur_->u_.block_.scope = 0;
297 struct ivl_statement_s*save_cur_ = stmt_cur_;
298 unsigned idx = 0;
299 bool flag = true;
301 for (const NetProc*cur = net->proc_first()
302 ; cur ; cur = net->proc_next(cur), idx += 1) {
303 assert(idx < count);
304 stmt_cur_ = save_cur_->u_.block_.stmt_ + idx;
305 bool rc = cur->emit_proc(this);
306 flag = flag && rc;
308 assert(idx == count);
310 stmt_cur_ = save_cur_;
312 return flag;
316 * A case statement is in turn an array of statements with gate
317 * expressions. This builds arrays of the right size and builds the
318 * ivl_expr_t and ivl_statement_s arrays for the substatements.
320 void dll_target::proc_case(const NetCase*net)
322 assert(stmt_cur_);
323 assert(stmt_cur_->type_ == IVL_ST_NONE);
324 FILE_NAME(stmt_cur_, net);
326 switch (net->type()) {
327 case NetCase::EQ:
328 stmt_cur_->type_ = IVL_ST_CASE;
329 break;
330 case NetCase::EQX:
331 stmt_cur_->type_ = IVL_ST_CASEX;
332 break;
333 case NetCase::EQZ:
334 stmt_cur_->type_ = IVL_ST_CASEZ;
335 break;
337 assert(stmt_cur_->type_ != IVL_ST_NONE);
339 assert(expr_ == 0);
340 assert(net->expr());
341 net->expr()->expr_scan(this);
342 stmt_cur_->u_.case_.cond = expr_;
343 expr_ = 0;
345 /* If the condition expression is a real valued expression,
346 then change the case statement to a CASER statement. */
347 if (stmt_cur_->u_.case_.cond->value_ == IVL_VT_REAL)
348 stmt_cur_->type_ = IVL_ST_CASER;
350 unsigned ncase = net->nitems();
351 stmt_cur_->u_.case_.ncase = ncase;
353 stmt_cur_->u_.case_.case_ex = new ivl_expr_t[ncase];
354 stmt_cur_->u_.case_.case_st = new struct ivl_statement_s[ncase];
356 ivl_statement_t save_cur = stmt_cur_;
358 for (unsigned idx = 0 ; idx < ncase ; idx += 1) {
359 const NetExpr*ex = net->expr(idx);
360 if (ex) {
361 ex->expr_scan(this);
362 save_cur->u_.case_.case_ex[idx] = expr_;
363 expr_ = 0;
364 } else {
365 save_cur->u_.case_.case_ex[idx] = 0;
368 stmt_cur_ = save_cur->u_.case_.case_st + idx;
369 stmt_cur_->type_ = IVL_ST_NONE;
370 if (net->stat(idx) == 0) {
371 stmt_cur_->type_ = IVL_ST_NOOP;
372 } else {
373 net->stat(idx)->emit_proc(this);
377 stmt_cur_ = save_cur;
380 bool dll_target::proc_cassign(const NetCAssign*net)
383 assert(stmt_cur_);
384 assert(stmt_cur_->type_ == IVL_ST_NONE);
385 FILE_NAME(stmt_cur_, net);
387 stmt_cur_->type_ = IVL_ST_CASSIGN;
389 /* Make the l-value fields. */
390 make_assign_lvals_(net);
392 assert(expr_ == 0);
393 net->rval()->expr_scan(this);
394 stmt_cur_->u_.assign_.rval_ = expr_;
395 expr_ = 0;
397 return true;
400 bool dll_target::proc_condit(const NetCondit*net)
402 assert(stmt_cur_);
403 assert(stmt_cur_->type_ == IVL_ST_NONE);
404 FILE_NAME(stmt_cur_, net);
406 stmt_cur_->type_ = IVL_ST_CONDIT;
407 stmt_cur_->u_.condit_.stmt_ = (struct ivl_statement_s*)
408 calloc(2, sizeof(struct ivl_statement_s));
410 assert(expr_ == 0);
411 net->expr()->expr_scan(this);
412 stmt_cur_->u_.condit_.cond_ = expr_;
413 expr_ = 0;
415 ivl_statement_t save_cur_ = stmt_cur_;
417 stmt_cur_ = save_cur_->u_.condit_.stmt_+0;
418 bool flag = net->emit_recurse_if(this);
420 stmt_cur_ = save_cur_->u_.condit_.stmt_+1;
421 flag = flag && net->emit_recurse_else(this);
423 stmt_cur_ = save_cur_;
424 return flag;
427 bool dll_target::proc_deassign(const NetDeassign*net)
429 assert(stmt_cur_);
430 assert(stmt_cur_->type_ == IVL_ST_NONE);
431 FILE_NAME(stmt_cur_, net);
433 stmt_cur_->type_ = IVL_ST_DEASSIGN;
435 /* Make the l-value fields. */
436 make_assign_lvals_(net);
438 return true;
441 bool dll_target::proc_delay(const NetPDelay*net)
443 assert(stmt_cur_);
444 assert(stmt_cur_->type_ == IVL_ST_NONE);
445 FILE_NAME(stmt_cur_, net);
447 ivl_statement_t tmp = (struct ivl_statement_s*)
448 calloc(1, sizeof(struct ivl_statement_s));
450 if (const NetExpr*expr = net->expr()) {
452 stmt_cur_->type_ = IVL_ST_DELAYX;
453 assert(expr_ == 0);
454 expr->expr_scan(this);
455 stmt_cur_->u_.delayx_.expr = expr_;
456 expr_ = 0;
458 stmt_cur_->u_.delayx_.stmt_ = tmp;
460 } else {
461 stmt_cur_->type_ = IVL_ST_DELAY;
462 stmt_cur_->u_.delay_.stmt_ = tmp;
463 stmt_cur_->u_.delay_.delay_ = net->delay();
466 ivl_statement_t save_cur_ = stmt_cur_;
467 stmt_cur_ = tmp;
468 bool flag = net->emit_proc_recurse(this);
470 /* If the recurse doesn't turn this new item into something,
471 then either it failed or there is no statement
472 there. Either way, draw a no-op into the statement. */
473 if (stmt_cur_->type_ == IVL_ST_NONE) {
474 stmt_cur_->type_ = IVL_ST_NOOP;
477 stmt_cur_ = save_cur_;
479 return flag;
482 bool dll_target::proc_disable(const NetDisable*net)
484 assert(stmt_cur_);
485 assert(stmt_cur_->type_ == IVL_ST_NONE);
486 FILE_NAME(stmt_cur_, net);
488 stmt_cur_->type_ = IVL_ST_DISABLE;
489 stmt_cur_->u_.disable_.scope = lookup_scope_(net->target());
490 return true;
493 bool dll_target::proc_force(const NetForce*net)
496 assert(stmt_cur_);
497 assert(stmt_cur_->type_ == IVL_ST_NONE);
499 stmt_cur_->type_ = IVL_ST_FORCE;
501 /* Make the l-value fields. */
502 make_assign_lvals_(net);
504 assert(expr_ == 0);
505 net->rval()->expr_scan(this);
506 stmt_cur_->u_.assign_.rval_ = expr_;
507 expr_ = 0;
509 return true;
512 void dll_target::proc_forever(const NetForever*net)
514 assert(stmt_cur_);
515 assert(stmt_cur_->type_ == IVL_ST_NONE);
516 FILE_NAME(stmt_cur_, net);
518 stmt_cur_->type_ = IVL_ST_FOREVER;
520 ivl_statement_t tmp = (struct ivl_statement_s*)
521 calloc(1, sizeof(struct ivl_statement_s));
523 ivl_statement_t save_cur_ = stmt_cur_;
524 stmt_cur_ = tmp;
526 net->emit_recurse(this);
528 save_cur_->u_.forever_.stmt_ = stmt_cur_;
529 stmt_cur_ = save_cur_;
532 bool dll_target::proc_release(const NetRelease*net)
534 assert(stmt_cur_);
535 assert(stmt_cur_->type_ == IVL_ST_NONE);
536 FILE_NAME(stmt_cur_, net);
538 stmt_cur_->type_ = IVL_ST_RELEASE;
540 /* Make the l-value fields. */
541 make_assign_lvals_(net);
543 return true;
546 void dll_target::proc_repeat(const NetRepeat*net)
548 assert(stmt_cur_);
549 assert(stmt_cur_->type_ == IVL_ST_NONE);
550 FILE_NAME(stmt_cur_, net);
552 stmt_cur_->type_ = IVL_ST_REPEAT;
554 assert(expr_ == 0);
555 net->expr()->expr_scan(this);
556 stmt_cur_->u_.while_.cond_ = expr_;
557 expr_ = 0;
559 ivl_statement_t tmp = (struct ivl_statement_s*)
560 calloc(1, sizeof(struct ivl_statement_s));
562 ivl_statement_t save_cur_ = stmt_cur_;
563 stmt_cur_ = tmp;
565 net->emit_recurse(this);
567 save_cur_->u_.while_.stmt_ = stmt_cur_;
568 stmt_cur_ = save_cur_;
571 void dll_target::proc_stask(const NetSTask*net)
573 unsigned nparms = net->nparms();
574 assert(stmt_cur_);
575 assert(stmt_cur_->type_ == IVL_ST_NONE);
576 FILE_NAME(stmt_cur_, net);
578 stmt_cur_->type_ = IVL_ST_STASK;
579 /* System task names are lex_strings strings. */
580 stmt_cur_->u_.stask_.name_ = net->name();
581 stmt_cur_->u_.stask_.nparm_= nparms;
582 stmt_cur_->u_.stask_.parms_= (ivl_expr_t*)
583 calloc(nparms, sizeof(ivl_expr_t));
585 for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
586 if (net->parm(idx))
587 net->parm(idx)->expr_scan(this);
588 stmt_cur_->u_.stask_.parms_[idx] = expr_;
589 expr_ = 0;
594 bool dll_target::proc_trigger(const NetEvTrig*net)
596 assert(stmt_cur_);
597 assert(stmt_cur_->type_ == IVL_ST_NONE);
598 FILE_NAME(stmt_cur_, net);
600 stmt_cur_->type_ = IVL_ST_TRIGGER;
601 stmt_cur_->u_.wait_.nevent = 1;
603 /* Locate the event by name. Save the ivl_event_t in the
604 statement so that the generator can find it easily. */
605 const NetEvent*ev = net->event();
606 ivl_scope_t ev_scope = lookup_scope_(ev->scope());
608 for (unsigned idx = 0 ; idx < ev_scope->nevent_ ; idx += 1) {
609 const char*ename = ivl_event_basename(ev_scope->event_[idx]);
610 if (strcmp(ev->name(), ename) == 0) {
611 stmt_cur_->u_.wait_.event = ev_scope->event_[idx];
612 break;
617 return true;
620 void dll_target::proc_utask(const NetUTask*net)
622 assert(stmt_cur_);
623 assert(stmt_cur_->type_ == IVL_ST_NONE);
624 FILE_NAME(stmt_cur_, net);
626 stmt_cur_->type_ = IVL_ST_UTASK;
627 stmt_cur_->u_.utask_.def = lookup_scope_(net->task());
630 bool dll_target::proc_wait(const NetEvWait*net)
632 assert(stmt_cur_);
633 assert(stmt_cur_->type_ == IVL_ST_NONE);
634 FILE_NAME(stmt_cur_, net);
636 stmt_cur_->type_ = IVL_ST_WAIT;
637 stmt_cur_->u_.wait_.stmt_ = (struct ivl_statement_s*)
638 calloc(1, sizeof(struct ivl_statement_s));
640 stmt_cur_->u_.wait_.nevent = net->nevents();
641 if (net->nevents() > 1) {
642 stmt_cur_->u_.wait_.events = (ivl_event_t*)
643 calloc(net->nevents(), sizeof(ivl_event_t*));
646 for (unsigned edx = 0 ; edx < net->nevents() ; edx += 1) {
648 /* Locate the event by name. Save the ivl_event_t in the
649 statement so that the generator can find it easily. */
650 const NetEvent*ev = net->event(edx);
651 ivl_scope_t ev_scope = lookup_scope_(ev->scope());
652 ivl_event_t ev_tmp=0;
654 assert(ev_scope);
655 assert(ev_scope->nevent_ > 0);
656 for (unsigned idx = 0 ; idx < ev_scope->nevent_ ; idx += 1) {
657 const char*ename = ivl_event_basename(ev_scope->event_[idx]);
658 if (strcmp(ev->name(), ename) == 0) {
659 ev_tmp = ev_scope->event_[idx];
660 break;
663 // XXX should we assert(ev_tmp)?
665 if (net->nevents() == 1)
666 stmt_cur_->u_.wait_.event = ev_tmp;
667 else
668 stmt_cur_->u_.wait_.events[edx] = ev_tmp;
670 /* If this is an event with a probe, then connect up the
671 pins. This wasn't done during the ::event method because
672 the signals weren't scanned yet. */
674 if (ev->nprobe() >= 1) {
675 unsigned iany = 0;
676 unsigned ineg = ev_tmp->nany;
677 unsigned ipos = ineg + ev_tmp->nneg;
679 for (unsigned idx = 0 ; idx < ev->nprobe() ; idx += 1) {
680 const NetEvProbe*pr = ev->probe(idx);
681 unsigned base = 0;
683 switch (pr->edge()) {
684 case NetEvProbe::ANYEDGE:
685 base = iany;
686 iany += pr->pin_count();
687 break;
688 case NetEvProbe::NEGEDGE:
689 base = ineg;
690 ineg += pr->pin_count();
691 break;
692 case NetEvProbe::POSEDGE:
693 base = ipos;
694 ipos += pr->pin_count();
695 break;
698 for (unsigned bit = 0
699 ; bit < pr->pin_count()
700 ; bit += 1) {
701 ivl_nexus_t nex = (ivl_nexus_t)
702 pr->pin(bit).nexus()->t_cookie();
703 assert(nex);
704 ev_tmp->pins[base+bit] = nex;
710 /* The ivl_statement_t for the wait statement is not complete
711 until we calculate the sub-statement. */
713 ivl_statement_t save_cur_ = stmt_cur_;
714 stmt_cur_ = stmt_cur_->u_.wait_.stmt_;
715 bool flag = net->emit_recurse(this);
716 if (flag && (stmt_cur_->type_ == IVL_ST_NONE))
717 stmt_cur_->type_ = IVL_ST_NOOP;
719 stmt_cur_ = save_cur_;
721 return flag;
724 void dll_target::proc_while(const NetWhile*net)
726 assert(stmt_cur_);
727 assert(stmt_cur_->type_ == IVL_ST_NONE);
728 FILE_NAME(stmt_cur_, net);
730 stmt_cur_->type_ = IVL_ST_WHILE;
731 stmt_cur_->u_.while_.stmt_ = (struct ivl_statement_s*)
732 calloc(1, sizeof(struct ivl_statement_s));
734 assert(expr_ == 0);
735 net->expr()->expr_scan(this);
736 stmt_cur_->u_.while_.cond_ = expr_;
737 expr_ = 0;
739 /* Now generate the statement of the while loop. We know it is
740 a single statement, and we know that the
741 emit_proc_recurse() will call emit_proc() for it. */
743 ivl_statement_t save_cur_ = stmt_cur_;
744 stmt_cur_ = save_cur_->u_.while_.stmt_;
745 net->emit_proc_recurse(this);
746 stmt_cur_ = save_cur_;