diff options
author | Russ Cox <rsc@golang.org> | 2009-05-30 21:18:15 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2009-05-30 21:18:15 -0700 |
commit | c72bed1269c67e9c6fd0bc85909402cb7402743f (patch) | |
tree | 9f9a09155507a5eeda36de1b3fb259348fd4fb7c /src | |
parent | ab76fe57aa2eac85c355c0ad20dacae11b366c80 (diff) | |
download | golang-c72bed1269c67e9c6fd0bc85909402cb7402743f.tar.gz |
bug157
R=ken
OCL=29651
CL=29653
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/gc/go.y | 131 | ||||
-rw-r--r-- | src/cmd/gc/swt.c | 104 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 121 |
3 files changed, 190 insertions, 166 deletions
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 374b671b6..cc9caf926 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -47,11 +47,11 @@ %type <node> common_dcl Acommon_dcl Bcommon_dcl %type <node> oarg_type_list arg_type_list_r arg_chunk arg_chunk_list_r arg_type_list %type <node> Aelse_stmt Belse_stmt -%type <node> complex_stmt compound_stmt ostmt_list -%type <node> stmt_list_r Astmt_list_r Bstmt_list_r +%type <node> complex_stmt compound_stmt switch_body ocaseblock_list ostmt_list +%type <node> caseblock_list_r stmt_list_r Astmt_list_r Bstmt_list_r %type <node> Astmt Bstmt %type <node> for_stmt for_body for_header -%type <node> if_stmt if_body if_header select_stmt condition +%type <node> if_stmt if_header select_stmt switch_stmt condition case caseblock %type <node> simple_stmt osimple_stmt range_stmt semi_stmt %type <node> expr uexpr pexpr expr_list oexpr oexpr_list expr_list_r %type <node> exprsym3_list_r exprsym3 pseudocall @@ -511,34 +511,23 @@ simple_stmt: } complex_stmt: - LFOR for_stmt + for_stmt +| switch_stmt +| select_stmt +| if_stmt { popdcl(); - $$ = $2; - } -| LSWITCH if_stmt - { - popdcl(); - $$ = $2; - $$->op = OSWITCH; - } -| LIF if_stmt - { - popdcl(); - $$ = $2; - } -| LIF if_stmt LELSE Aelse_stmt - { - popdcl(); - $$ = $2; - $$->nelse = $4; + $$ = $1; } -| LSELECT select_stmt +| if_stmt LELSE Aelse_stmt { popdcl(); - $$ = $2; + $$ = $1; + $$->nelse = $3; } -| LCASE expr_list ':' + +case: + LCASE expr_list ':' { // will be converted to OCASE // right will point to next case @@ -620,11 +609,11 @@ semi_stmt: { $$ = nod(ORETURN, $2, N); } -| LIF if_stmt LELSE Belse_stmt +| if_stmt LELSE Belse_stmt { popdcl(); - $$ = $2; - $$->nelse = $4; + $$ = $1; + $$->nelse = $3; } compound_stmt: @@ -639,6 +628,33 @@ compound_stmt: popdcl(); } +switch_body: + '{' + { + markdcl(); + } + ocaseblock_list '}' + { + $$ = $3; + if($$ == N) + $$ = nod(OEMPTY, N, N); + popdcl(); + } + +caseblock: + case ostmt_list + { + $$ = $1; + $$->nbody = $2; + } + +caseblock_list_r: + caseblock +| caseblock_list_r caseblock + { + $$ = nod(OLIST, $1, $2); + } + range_stmt: exprsym3_list_r '=' LRANGE expr { @@ -684,11 +700,14 @@ for_body: } for_stmt: + LFOR { markdcl(); - } for_body + } + for_body { - $$ = $2; + $$ = $3; + popdcl(); } /* @@ -722,38 +741,51 @@ if_header: $$->ntest = $3; } -if_body: +if_stmt: + LIF + { + markdcl(); + } + if_header compound_stmt + { + $$ = $3; + $$->nbody = $4; + // no popdcl; maybe there's an LELSE + } + +switch_stmt: + LSWITCH + { + markdcl(); + } if_header { Node *n; - n = $1->ntest; + n = $3->ntest; if(n != N && n->op == OTYPESW) n = n->left; else n = N; typeswvar = nod(OLIST, typeswvar, n); - } compound_stmt - { - $$ = $1; - $$->nbody = $3; - typeswvar = typeswvar->left; } - -if_stmt: - { - markdcl(); - } if_body + switch_body { - $$ = $2; + $$ = $3; + $$->op = OSWITCH; + $$->nbody = $5; + typeswvar = typeswvar->left; + popdcl(); } select_stmt: + LSELECT { markdcl(); } - compound_stmt + switch_body { - $$ = nod(OSELECT, $2, N); + $$ = nod(OSELECT, $3, N); + popdcl(); } /* @@ -1849,6 +1881,15 @@ ostmt_list: $$ = rev($1); } +ocaseblock_list: + { + $$ = N; + } +| caseblock_list_r + { + $$ = rev($1); + } + oxdcl_list: { $$ = N; diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c index 318427636..486e181b1 100644 --- a/src/cmd/gc/swt.c +++ b/src/cmd/gc/swt.c @@ -348,8 +348,8 @@ newlabel() void casebody(Node *sw) { - Iter save; - Node *os, *oc, *n, *c; + Iter save, save1; + Node *os, *oc, *n, *n1, *c; Node *cas, *stat, *def; Node *go, *br; int32 lno; @@ -368,70 +368,56 @@ casebody(Node *sw) oc = N; // last case br = nod(OBREAK, N, N); -loop: - if(n == N) { - if(oc == N && os != N) - yyerror("first switch statement must be a case"); - - stat = list(stat, br); - cas = list(cas, def); - - sw->nbody = nod(OLIST, rev(cas), rev(stat)); -//dump("case", sw->nbody->left); -//dump("stat", sw->nbody->right); - lineno = lno; - return; - } - - lno = setlineno(n); - - if(n->op != OXCASE) { - stat = list(stat, n); - os = n; - goto next; - } - - n->op = OCASE; - if(oc == N && os != N) - yyerror("first switch statement must be a case"); + for(; n != N; n = listnext(&save)) { + lno = setlineno(n); + if(n->op != OXCASE) + fatal("casebody %O", n->op); + n->op = OCASE; + + go = nod(OGOTO, newlabel(), N); + c = n->left; + if(c == N) { + if(def != N) + yyerror("more than one default case"); + // reuse original default case + n->right = go; + def = n; + } - // botch - shouldnt fall thru declaration - if(os != N && os->op == OXFALL) - os->op = OFALL; - else - stat = list(stat, br); + // expand multi-valued cases + for(; c!=N; c=c->right) { + if(c->op != OLIST) { + // reuse original case + n->left = c; + n->right = go; + cas = list(cas, n); + break; + } + cas = list(cas, nod(OCASE, c->left, go)); + } - go = nod(OGOTO, newlabel(), N); + stat = list(stat, nod(OLABEL, go->left, N)); - c = n->left; - if(c == N) { - if(def != N) - yyerror("more than one default case"); + os = N; + for(n1 = listfirst(&save1, &n->nbody); n1 != N; n1 = listnext(&save1)) { + os = n1; + stat = list(stat, n1); + } - // reuse original default case - n->right = go; - def = n; + // botch - shouldnt fall thru declaration + if(os != N && os->op == OXFALL) + os->op = OFALL; + else + stat = list(stat, br); } - // expand multi-valued cases - for(; c!=N; c=c->right) { - if(c->op != OLIST) { - // reuse original case - n->left = c; - n->right = go; - cas = list(cas, n); - break; - } - cas = list(cas, nod(OCASE, c->left, go)); - } - stat = list(stat, nod(OLABEL, go->left, N)); - oc = n; - os = N; - goto next; + stat = list(stat, br); + cas = list(cas, def); -next: - n = listnext(&save); - goto loop; + sw->nbody = nod(OLIST, rev(cas), rev(stat)); +//dump("case", sw->nbody->left); +//dump("stat", sw->nbody->right); + lineno = lno; } Case* diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index f18227951..1cfac55af 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -1539,8 +1539,8 @@ bad: void walkselect(Node *sel) { - Iter iter; - Node *n, *l, *oc, *on, *r; + Iter iter, iter1; + Node *n, *n1, *l, *oc, *on, *r; Node *var, *bod, *nbod, *res, *def; int count, op; int32 lno; @@ -1552,8 +1552,10 @@ walkselect(Node *sel) tempname(var, ptrto(types[TUINT8])); n = listfirst(&iter, &sel->left); - if(n == N || n->op != OXCASE) - yyerror("first select statement must be a case"); + if(n == N || n->op == OEMPTY) { + yyerror("empty select"); + return; + } count = 0; // number of cases res = N; // entire select body @@ -1563,72 +1565,67 @@ walkselect(Node *sel) for(; n!=N; n=listnext(&iter)) { setlineno(n); + if(n->op != OXCASE) + fatal("walkselect %O", n->op); - switch(n->op) { + count++; + if(n->left == N) { + op = ORECV; // actual value not used + if(def != N) + yyerror("repeated default; first at %L", def->lineno); + def = n; + } else + op = n->left->op; + + nbod = N; + switch(op) { default: - bod = list(bod, n); - break; + yyerror("select cases must be send, recv or default"); + continue; - case OXCASE: - if(n->left == N) { - op = ORECV; // actual value not used - if(def != N) - yyerror("only one default select allowed"); - def = n; - } else - op = n->left->op; - nbod = N; - switch(op) { - default: + case OAS: + // convert new syntax (a=recv(chan)) to (recv(a,chan)) + l = n->left; + if(l->right == N || l->right->op != ORECV) { yyerror("select cases must be send, recv or default"); break; - - case OAS: - // convert new syntax (a=recv(chan)) to (recv(a,chan)) - l = n->left; - if(l->right == N || l->right->op != ORECV) { - yyerror("select cases must be send, recv or default"); - break; - } - r = l->right; // rcv - r->right = r->left; - r->left = l->left; - n->left = r; - - // convert case x := foo: body - // to case tmp := foo: x := tmp; body. - // if x escapes and must be allocated - // on the heap, this delays the allocation - // until after the select has chosen this branch. - if(n->ninit != N && n->ninit->op == ODCL) { - on = nod(OXXX, N, N); - tempname(on, l->left->type); - on->sym = lookup("!tmpselect!"); - r->left = on; - nbod = nod(OAS, l->left, on); - nbod->ninit = n->ninit; - n->ninit = N; - } - - // fall through - case OSEND: - case ORECV: - if(oc != N) { - bod = list(bod, nod(OBREAK, N, N)); - oc->nbody = rev(bod); - } - oc = selcase(n, var); - res = list(res, oc); - break; } - bod = nbod; - count++; + r = l->right; // rcv + r->right = r->left; + r->left = l->left; + n->left = r; + + // convert case x := foo: body + // to case tmp := foo: x := tmp; body. + // if x escapes and must be allocated + // on the heap, this delays the allocation + // until after the select has chosen this branch. + if(n->ninit != N && n->ninit->op == ODCL) { + on = nod(OXXX, N, N); + tempname(on, l->left->type); + on->sym = lookup("!tmpselect!"); + r->left = on; + nbod = nod(OAS, l->left, on); + nbod->ninit = n->ninit; + n->ninit = N; + } + break; + + case OSEND: + case ORECV: break; } - } - if(oc != N) { - bod = list(bod, nod(OBREAK, N, N)); - oc->nbody = rev(bod); + + for(n1 = listfirst(&iter1, &n->nbody); n1 != N; n1 = listnext(&iter1)) + nbod = list(nbod, n1); + nbod = list(nbod, nod(OBREAK, N, N)); + n->nbody = N; + + oc = selcase(n, var); + if(oc != N) { + oc->nbody = rev(nbod); + res = list(res, oc); + } } setlineno(sel); |