mirror of
https://github.com/golang/go
synced 2024-11-18 21:24:44 -07:00
fixed labels/break/continue/goto
R=r OCL=14675 CL=14675
This commit is contained in:
parent
354be785c6
commit
33ee52727f
200
src/cmd/6g/gen.c
200
src/cmd/6g/gen.c
@ -36,6 +36,10 @@ if(newproc == N) {
|
|||||||
|
|
||||||
if(fn->nbody == N)
|
if(fn->nbody == N)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// set up domain for labels
|
||||||
|
labellist = L;
|
||||||
|
|
||||||
lno = setlineno(fn);
|
lno = setlineno(fn);
|
||||||
|
|
||||||
curfn = fn;
|
curfn = fn;
|
||||||
@ -60,8 +64,9 @@ if(newproc == N) {
|
|||||||
// inarggen();
|
// inarggen();
|
||||||
|
|
||||||
ginit();
|
ginit();
|
||||||
gen(curfn->nbody);
|
gen(curfn->nbody, L);
|
||||||
gclean();
|
gclean();
|
||||||
|
checklabels();
|
||||||
|
|
||||||
// if(curfn->type->outtuple != 0)
|
// if(curfn->type->outtuple != 0)
|
||||||
// gins(AGOK, N, N);
|
// gins(AGOK, N, N);
|
||||||
@ -118,12 +123,14 @@ allocparams(void)
|
|||||||
* compile statements
|
* compile statements
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
gen(Node *n)
|
gen(Node *n, Label *labloop)
|
||||||
{
|
{
|
||||||
int32 lno;
|
int32 lno;
|
||||||
Prog *scontin, *sbreak;
|
Prog *scontin, *sbreak;
|
||||||
Prog *p1, *p2, *p3;
|
Prog *p1, *p2, *p3;
|
||||||
Sym *s;
|
Sym *s;
|
||||||
|
Node *l;
|
||||||
|
Label *lab;
|
||||||
|
|
||||||
lno = setlineno(n);
|
lno = setlineno(n);
|
||||||
|
|
||||||
@ -138,8 +145,24 @@ loop:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OLIST:
|
case OLIST:
|
||||||
gen(n->left);
|
l = n->left;
|
||||||
|
gen(l, L);
|
||||||
|
if(l != N && l->op == OLABEL) {
|
||||||
|
// call the next statement with a label
|
||||||
|
l = n->right;
|
||||||
|
if(l != N) {
|
||||||
|
if(l->op != OLIST) {
|
||||||
|
gen(l, labellist);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gen(l->left, labellist);
|
||||||
|
n = l->right;
|
||||||
|
labloop = L;
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
n = n->right;
|
n = n->right;
|
||||||
|
labloop = L;
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case OPANIC:
|
case OPANIC:
|
||||||
@ -154,59 +177,55 @@ loop:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OLABEL:
|
case OLABEL:
|
||||||
// before declaration, s->label points at
|
lab = mal(sizeof(*lab));
|
||||||
// a link list of PXGOTO instructions.
|
lab->link = labellist;
|
||||||
// after declaration, s->label points
|
labellist = lab;
|
||||||
// at a AJMP to .+1
|
lab->sym = n->left->sym;
|
||||||
|
|
||||||
s = n->left->sym;
|
lab->op = OLABEL;
|
||||||
p1 = (Prog*)s->label;
|
lab->label = pc;
|
||||||
|
|
||||||
if(p1 != P) {
|
|
||||||
if(p1->as == AJMP) {
|
|
||||||
yyerror("label redeclared: %S", s);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while(p1 != P) {
|
|
||||||
if(p1->as != AJMPX)
|
|
||||||
fatal("bad label pointer: %S", s);
|
|
||||||
p1->as = AJMP;
|
|
||||||
p2 = p1->to.branch;
|
|
||||||
patch(p1, pc);
|
|
||||||
p1 = p2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s->label = pc;
|
|
||||||
p1 = gbranch(AJMP, T);
|
|
||||||
patch(p1, pc);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OGOTO:
|
case OGOTO:
|
||||||
s = n->left->sym;
|
lab = mal(sizeof(*lab));
|
||||||
p1 = (Prog*)s->label;
|
lab->link = labellist;
|
||||||
if(p1 != P && p1->as == AJMP) {
|
labellist = lab;
|
||||||
// already declared
|
lab->sym = n->left->sym;
|
||||||
p2 = gbranch(AJMP, T);
|
|
||||||
patch(p2, p1->to.branch);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// link thru to.branch
|
lab->op = OGOTO;
|
||||||
p2 = gbranch(AJMPX, T);
|
lab->label = pc;
|
||||||
p2->to.branch = p1;
|
gbranch(AJMP, T);
|
||||||
s->label = p2;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OBREAK:
|
case OBREAK:
|
||||||
|
if(n->left != N) {
|
||||||
|
lab = findlab(n->left->sym);
|
||||||
|
if(lab == L || lab->breakpc == P) {
|
||||||
|
yyerror("break label is not defined: %S", n->left->sym);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
patch(gbranch(AJMP, T), lab->breakpc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if(breakpc == P) {
|
if(breakpc == P) {
|
||||||
yyerror("gen: break is not in a loop");
|
yyerror("break is not in a loop");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
patch(gbranch(AJMP, T), breakpc);
|
patch(gbranch(AJMP, T), breakpc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OCONTINUE:
|
case OCONTINUE:
|
||||||
|
if(n->left != N) {
|
||||||
|
lab = findlab(n->left->sym);
|
||||||
|
if(lab == L || lab->continpc == P) {
|
||||||
|
yyerror("continue label is not defined: %S", n->left->sym);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
patch(gbranch(AJMP, T), lab->continpc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if(continpc == P) {
|
if(continpc == P) {
|
||||||
yyerror("gen: continue is not in a loop");
|
yyerror("gen: continue is not in a loop");
|
||||||
break;
|
break;
|
||||||
@ -215,16 +234,21 @@ loop:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OFOR:
|
case OFOR:
|
||||||
gen(n->ninit); // init
|
gen(n->ninit, L); // init
|
||||||
p1 = gbranch(AJMP, T); // goto test
|
p1 = gbranch(AJMP, T); // goto test
|
||||||
sbreak = breakpc;
|
sbreak = breakpc;
|
||||||
breakpc = gbranch(AJMP, T); // break: goto done
|
breakpc = gbranch(AJMP, T); // break: goto done
|
||||||
scontin = continpc;
|
scontin = continpc;
|
||||||
continpc = pc;
|
continpc = pc;
|
||||||
gen(n->nincr); // contin: incr
|
gen(n->nincr, L); // contin: incr
|
||||||
patch(p1, pc); // test:
|
patch(p1, pc); // test:
|
||||||
bgen(n->ntest, 0, breakpc); // if(!test) goto break
|
bgen(n->ntest, 0, breakpc); // if(!test) goto break
|
||||||
gen(n->nbody); // body
|
if(labloop != L) {
|
||||||
|
labloop->op = OFOR;
|
||||||
|
labloop->continpc = continpc;
|
||||||
|
labloop->breakpc = breakpc;
|
||||||
|
}
|
||||||
|
gen(n->nbody, L); // body
|
||||||
patch(gbranch(AJMP, T), continpc); // goto contin
|
patch(gbranch(AJMP, T), continpc); // goto contin
|
||||||
patch(breakpc, pc); // done:
|
patch(breakpc, pc); // done:
|
||||||
continpc = scontin;
|
continpc = scontin;
|
||||||
@ -232,36 +256,44 @@ loop:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OIF:
|
case OIF:
|
||||||
gen(n->ninit); // init
|
gen(n->ninit, L); // init
|
||||||
p1 = gbranch(AJMP, T); // goto test
|
p1 = gbranch(AJMP, T); // goto test
|
||||||
p2 = gbranch(AJMP, T); // p2: goto else
|
p2 = gbranch(AJMP, T); // p2: goto else
|
||||||
patch(p1, pc); // test:
|
patch(p1, pc); // test:
|
||||||
bgen(n->ntest, 0, p2); // if(!test) goto p2
|
bgen(n->ntest, 0, p2); // if(!test) goto p2
|
||||||
gen(n->nbody); // then
|
gen(n->nbody, L); // then
|
||||||
p3 = gbranch(AJMP, T); // goto done
|
p3 = gbranch(AJMP, T); // goto done
|
||||||
patch(p2, pc); // else:
|
patch(p2, pc); // else:
|
||||||
gen(n->nelse); // else
|
gen(n->nelse, L); // else
|
||||||
patch(p3, pc); // done:
|
patch(p3, pc); // done:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OSWITCH:
|
case OSWITCH:
|
||||||
gen(n->ninit); // init
|
gen(n->ninit, L); // init
|
||||||
p1 = gbranch(AJMP, T); // goto test
|
p1 = gbranch(AJMP, T); // goto test
|
||||||
sbreak = breakpc;
|
sbreak = breakpc;
|
||||||
breakpc = gbranch(AJMP, T); // break: goto done
|
breakpc = gbranch(AJMP, T); // break: goto done
|
||||||
patch(p1, pc); // test:
|
patch(p1, pc); // test:
|
||||||
|
if(labloop != L) {
|
||||||
|
labloop->op = OFOR;
|
||||||
|
labloop->breakpc = breakpc;
|
||||||
|
}
|
||||||
swgen(n); // switch(test) body
|
swgen(n); // switch(test) body
|
||||||
patch(breakpc, pc); // done:
|
patch(breakpc, pc); // done:
|
||||||
breakpc = sbreak;
|
breakpc = sbreak;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OSELECT:
|
case OSELECT:
|
||||||
gen(n->ninit);
|
gen(n->ninit, L);
|
||||||
sbreak = breakpc;
|
sbreak = breakpc;
|
||||||
p1 = gbranch(AJMP, T); // goto test
|
p1 = gbranch(AJMP, T); // goto test
|
||||||
breakpc = gbranch(AJMP, T); // break: goto done
|
breakpc = gbranch(AJMP, T); // break: goto done
|
||||||
patch(p1, pc); // test:
|
patch(p1, pc); // test:
|
||||||
gen(n->nbody); // select() body
|
if(labloop != L) {
|
||||||
|
labloop->op = OFOR;
|
||||||
|
labloop->breakpc = breakpc;
|
||||||
|
}
|
||||||
|
gen(n->nbody, L); // select() body
|
||||||
patch(breakpc, pc); // done:
|
patch(breakpc, pc); // done:
|
||||||
breakpc = sbreak;
|
breakpc = sbreak;
|
||||||
break;
|
break;
|
||||||
@ -448,7 +480,7 @@ swgen(Node *n)
|
|||||||
if(c1->op != OCASE) {
|
if(c1->op != OCASE) {
|
||||||
if(s0 == C && dflt == P)
|
if(s0 == C && dflt == P)
|
||||||
yyerror("unreachable statements in a switch");
|
yyerror("unreachable statements in a switch");
|
||||||
gen(c1);
|
gen(c1, L);
|
||||||
|
|
||||||
any = 1;
|
any = 1;
|
||||||
if(c1->op == OFALL)
|
if(c1->op == OFALL)
|
||||||
@ -606,7 +638,7 @@ cgen_callinter(Node *n, Node *res, int proc)
|
|||||||
i = &tmpi;
|
i = &tmpi;
|
||||||
}
|
}
|
||||||
|
|
||||||
gen(n->right); // args
|
gen(n->right, L); // args
|
||||||
|
|
||||||
regalloc(&nodr, types[tptr], res);
|
regalloc(&nodr, types[tptr], res);
|
||||||
regalloc(&nodo, types[tptr], &nodr);
|
regalloc(&nodo, types[tptr], &nodr);
|
||||||
@ -673,7 +705,7 @@ cgen_call(Node *n, int proc)
|
|||||||
agen(n->left, &afun);
|
agen(n->left, &afun);
|
||||||
}
|
}
|
||||||
|
|
||||||
gen(n->right); // assign the args
|
gen(n->right, L); // assign the args
|
||||||
t = n->left->type;
|
t = n->left->type;
|
||||||
if(isptr[t->etype])
|
if(isptr[t->etype])
|
||||||
t = t->type;
|
t = t->type;
|
||||||
@ -784,7 +816,7 @@ cgen_aret(Node *n, Node *res)
|
|||||||
void
|
void
|
||||||
cgen_ret(Node *n)
|
cgen_ret(Node *n)
|
||||||
{
|
{
|
||||||
gen(n->left); // copy out args
|
gen(n->left, L); // copy out args
|
||||||
gins(ARET, N, N);
|
gins(ARET, N, N);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1143,3 +1175,63 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res)
|
|||||||
ret:
|
ret:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
checklabels(void)
|
||||||
|
{
|
||||||
|
Label *l, *m;
|
||||||
|
Sym *s;
|
||||||
|
|
||||||
|
// // print the label list
|
||||||
|
// for(l=labellist; l!=L; l=l->link) {
|
||||||
|
// print("lab %O %S\n", l->op, l->sym);
|
||||||
|
// }
|
||||||
|
|
||||||
|
for(l=labellist; l!=L; l=l->link) {
|
||||||
|
switch(l->op) {
|
||||||
|
case OFOR:
|
||||||
|
case OLABEL:
|
||||||
|
// these are definitions -
|
||||||
|
s = l->sym;
|
||||||
|
for(m=labellist; m!=L; m=m->link) {
|
||||||
|
if(m->sym != s)
|
||||||
|
continue;
|
||||||
|
switch(m->op) {
|
||||||
|
case OFOR:
|
||||||
|
case OLABEL:
|
||||||
|
// these are definitions -
|
||||||
|
// look for redefinitions
|
||||||
|
if(l != m)
|
||||||
|
yyerror("label %S redefined", s);
|
||||||
|
break;
|
||||||
|
case OGOTO:
|
||||||
|
// these are references -
|
||||||
|
// patch to definition
|
||||||
|
patch(m->label, l->label);
|
||||||
|
m->sym = S; // mark done
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// diagnostic for all undefined references
|
||||||
|
for(l=labellist; l!=L; l=l->link)
|
||||||
|
if(l->op == OGOTO && l->sym != S)
|
||||||
|
yyerror("label %S not defined", l->sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
Label*
|
||||||
|
findlab(Sym *s)
|
||||||
|
{
|
||||||
|
Label *l;
|
||||||
|
|
||||||
|
for(l=labellist; l!=L; l=l->link) {
|
||||||
|
if(l->sym != s)
|
||||||
|
continue;
|
||||||
|
if(l->op != OFOR)
|
||||||
|
continue;
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
return L;
|
||||||
|
}
|
||||||
|
@ -78,6 +78,18 @@ struct Pool
|
|||||||
Pool* link;
|
Pool* link;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct Label Label;
|
||||||
|
struct Label
|
||||||
|
{
|
||||||
|
uchar op; // OFOR/OGOTO/OLABEL
|
||||||
|
Sym* sym;
|
||||||
|
Prog* label; // pointer to code
|
||||||
|
Prog* breakpc; // pointer to code
|
||||||
|
Prog* continpc; // pointer to code
|
||||||
|
Label* link;
|
||||||
|
};
|
||||||
|
#define L ((Label*)0)
|
||||||
|
|
||||||
EXTERN Prog* continpc;
|
EXTERN Prog* continpc;
|
||||||
EXTERN Prog* breakpc;
|
EXTERN Prog* breakpc;
|
||||||
EXTERN Prog* pc;
|
EXTERN Prog* pc;
|
||||||
@ -99,13 +111,15 @@ EXTERN String emptystring;
|
|||||||
extern char* anames[];
|
extern char* anames[];
|
||||||
EXTERN Hist* hist;
|
EXTERN Hist* hist;
|
||||||
EXTERN Prog zprog;
|
EXTERN Prog zprog;
|
||||||
|
EXTERN Label* labellist;
|
||||||
|
EXTERN Label* findlab(Sym*);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* gen.c
|
* gen.c
|
||||||
*/
|
*/
|
||||||
void compile(Node*);
|
void compile(Node*);
|
||||||
void proglist(void);
|
void proglist(void);
|
||||||
void gen(Node*);
|
void gen(Node*, Label*);
|
||||||
void swgen(Node*);
|
void swgen(Node*);
|
||||||
void selgen(Node*);
|
void selgen(Node*);
|
||||||
Node* lookdot(Node*, Node*, int);
|
Node* lookdot(Node*, Node*, int);
|
||||||
@ -125,6 +139,7 @@ void genpanic(void);
|
|||||||
int needconvert(Type*, Type*);
|
int needconvert(Type*, Type*);
|
||||||
void genconv(Type*, Type*);
|
void genconv(Type*, Type*);
|
||||||
void allocparams(void);
|
void allocparams(void);
|
||||||
|
void checklabels();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cgen
|
* cgen
|
||||||
|
@ -205,7 +205,6 @@ struct Sym
|
|||||||
Type* otype; // TYPE node if a type
|
Type* otype; // TYPE node if a type
|
||||||
Node* oconst; // OLITERAL node if a const
|
Node* oconst; // OLITERAL node if a const
|
||||||
Type* forwtype; // TPTR iff forward declared
|
Type* forwtype; // TPTR iff forward declared
|
||||||
void* label; // pointer to Prog* of label
|
|
||||||
vlong offset; // stack location if automatic
|
vlong offset; // stack location if automatic
|
||||||
int32 lexical;
|
int32 lexical;
|
||||||
int32 vargen; // unique variable number
|
int32 vargen; // unique variable number
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
%type <node> range_header range_body range_stmt select_stmt
|
%type <node> range_header range_body range_stmt select_stmt
|
||||||
%type <node> simple_stmt osimple_stmt semi_stmt
|
%type <node> simple_stmt osimple_stmt semi_stmt
|
||||||
%type <node> expr uexpr pexpr expr_list oexpr oexpr_list expr_list_r
|
%type <node> expr uexpr pexpr expr_list oexpr oexpr_list expr_list_r
|
||||||
%type <node> name name_name new_name new_name_list_r conexpr
|
%type <node> name name_name onew_name new_name new_name_list_r conexpr
|
||||||
%type <node> vardcl_list_r vardcl Avardcl Bvardcl
|
%type <node> vardcl_list_r vardcl Avardcl Bvardcl
|
||||||
%type <node> interfacedcl_list_r interfacedcl
|
%type <node> interfacedcl_list_r interfacedcl
|
||||||
%type <node> structdcl_list_r structdcl
|
%type <node> structdcl_list_r structdcl
|
||||||
@ -326,6 +326,14 @@ noninc_stmt:
|
|||||||
{
|
{
|
||||||
$$ = nod(OAS, colas($1, $3), $3);
|
$$ = nod(OAS, colas($1, $3), $3);
|
||||||
}
|
}
|
||||||
|
| LPRINT '(' oexpr_list ')'
|
||||||
|
{
|
||||||
|
$$ = nod(OPRINT, $3, N);
|
||||||
|
}
|
||||||
|
| LPANIC '(' oexpr_list ')'
|
||||||
|
{
|
||||||
|
$$ = nod(OPANIC, $3, N);
|
||||||
|
}
|
||||||
|
|
||||||
inc_stmt:
|
inc_stmt:
|
||||||
expr LINC
|
expr LINC
|
||||||
@ -398,11 +406,11 @@ semi_stmt:
|
|||||||
// will be converted to OFALL
|
// will be converted to OFALL
|
||||||
$$ = nod(OXFALL, N, N);
|
$$ = nod(OXFALL, N, N);
|
||||||
}
|
}
|
||||||
| LBREAK oexpr
|
| LBREAK onew_name
|
||||||
{
|
{
|
||||||
$$ = nod(OBREAK, $2, N);
|
$$ = nod(OBREAK, $2, N);
|
||||||
}
|
}
|
||||||
| LCONTINUE oexpr
|
| LCONTINUE onew_name
|
||||||
{
|
{
|
||||||
$$ = nod(OCONTINUE, $2, N);
|
$$ = nod(OCONTINUE, $2, N);
|
||||||
}
|
}
|
||||||
@ -411,14 +419,6 @@ semi_stmt:
|
|||||||
$$ = nod(OCALL, $2, $4);
|
$$ = nod(OCALL, $2, $4);
|
||||||
$$ = nod(OPROC, $$, N);
|
$$ = nod(OPROC, $$, N);
|
||||||
}
|
}
|
||||||
| LPRINT '(' oexpr_list ')'
|
|
||||||
{
|
|
||||||
$$ = nod(OPRINT, $3, N);
|
|
||||||
}
|
|
||||||
| LPANIC '(' oexpr_list ')'
|
|
||||||
{
|
|
||||||
$$ = nod(OPANIC, $3, N);
|
|
||||||
}
|
|
||||||
| LGOTO new_name
|
| LGOTO new_name
|
||||||
{
|
{
|
||||||
$$ = nod(OGOTO, $2, N);
|
$$ = nod(OGOTO, $2, N);
|
||||||
@ -832,6 +832,12 @@ new_type:
|
|||||||
$$ = newtype($1);
|
$$ = newtype($1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onew_name:
|
||||||
|
{
|
||||||
|
$$ = N;
|
||||||
|
}
|
||||||
|
| new_name
|
||||||
|
|
||||||
sym:
|
sym:
|
||||||
LATYPE
|
LATYPE
|
||||||
| LNAME
|
| LNAME
|
||||||
|
Loading…
Reference in New Issue
Block a user