/*ident "@(#)ctrans:src/dcl2.c 1.4" */ /************************************************************************** C++ source for cfront, the C++ compiler front-end written in the computer science research center of Bell Labs Copyright (c) 1984 AT&T, Inc. All Rights Reserved THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T, INC. dcl2.c: *************************************************************************/ #include "cfront.h" #include "size.h" Pname conv_dominates(Pname on1, Pname on2) /* compare for duplicates and dominance: on1 and on2 are two conversion operator functions return the the one that dominates the other (according to the class hierarchy) otherwise 0 (0 thus indicats ambiguous conversion) */ { Ptype r1 = on1->tp->base==FCT ? Pfct(on1->tp)->returns : Pfct(Pgen(on1->tp)->fct_list->f->tp)->returns; Ptype r2 = on2->tp->base==FCT ? Pfct(on2->tp)->returns : Pfct(Pgen(on2->tp)->fct_list->f->tp)->returns; //error('d',"conv_dominates(%n,%n)",on1,on2); if (r1==r2 || r1->check(r2,0)==0) return on1; Pptr p1 = r1->is_ptr_or_ref(); Pptr p2 = r2->is_ptr_or_ref(); if (p1 && p2) { Pname cn1 = p1->typ->is_cl_obj(); Pname cn2 = p2->typ->is_cl_obj(); if (cn1 && cn2) { // is_cl_obj() returns b_name // Pclass c1 = Pclass(Pbase(cn1->tp)->b_name->tp); // Pclass c2 = Pclass(Pbase(cn2->tp)->b_name->tp); Pclass c1 = Pclass(cn1->tp); Pclass c2 = Pclass(cn2->tp); if (c1 && c2) { //if (c1==c2 || c1->has_base(c2)) if (c1->has_base(c2)) return on1; else if (c2->has_base(c1)) return on2; } } } return 0; } Pstmt curr_loop; Pstmt curr_switch; Pblock curr_block; void stmt::reached() { register Pstmt ss = s_list; if (ss == 0) return; switch (ss->base) { case LABEL: case CASE: case DEFAULT: break; default: error('w',&ss->where,"S after%k not reached",base); for (; ss; ss=ss->s_list) { // delete unreacheable code switch (ss->base) { case LABEL: case CASE: case DEFAULT: // reachable s_list = ss; return; case DCL: // the dcl may be used later // keep to avoid cascading errors case IF: case DO: case WHILE: case SWITCH: case FOR: case BLOCK: // may hide a label s_list = ss; return; } } s_list = 0; } } Pexpr check_cond(Pexpr e, TOK b, Ptable tbl) { //error('d',"check_cond(%k %k) tbl %d",e->base,b,tbl); Pname cn; if (e == dummy) error("empty condition for %k",b); int const_obj = 0; const_obj = e->tp->tconst(); Pexpr ee = e; while (ee && (ee->base==DOT || ee->base==REF)) { Pexpr m = ee->mem; if ( ee->base==REF && m->tp && m->tp->is_ptr()) break; ee = ee->e1; } if (ee) { Ptype ttt = ee->tp; switch (e->base) { case REF: Pptr p = ttt?ttt->is_ptr():0; if (p && p->typ->tconst()) const_obj = 1; break; case DOT: if (ttt && ttt->tconst()) const_obj = 1; } } if (cn = e->tp->is_cl_obj()) { Pclass cl = Pclass(cn->tp); int i = 0; Pname found = 0; for (Pname on = cl->conv; on; on=on->n_list) { Pfct f = on->tp->base == FCT ? Pfct(on->tp) : Pfct(Pgen(on->tp)->fct_list->f->tp); Ptype t = f->returns; while (t->base == TYPE) t = Pbase(t)->b_name->tp; switch (t->base) { case PTR: if (b == UMINUS) break; case FLOAT: case DOUBLE: case LDOUBLE: if (b == DEREF || b == SWITCH) break; case CHAR: case SHORT: case INT: case LONG: case EOBJ: // if (found==0 || found->tp->check(on->tp,0)) { //error('d',"found %n on %n",found,on); { Pname xx = found; if (found == 0) { i = 1; found = on; } else if ((found = really_dominate(found,on,const_obj)) == 0) { i = 2; found = on; error("two conversions for%nO in%kE: %n and %n",cn,b,xx,on); return e; } } } } //error('d',"i %d",i); switch (i) { case 0: error("%nO in%kE",cn,b); return e; /* case 1: { Pname xx = new name(found->string); Pref r = new ref(DOT,e,xx); Pexpr rr = r->typ(tbl); Pexpr c = new expr(G_CALL,rr,0); if (e->lval(0)) { // Pref r = new ref(DOT,e,found); // r->tp = found->tp; // Pexpr c = new expr(G_CALL,r,0); // c->fct_name = found; return c->typ(tbl); } else { // (temp=init,temp.coerce()) Pname tmp = make_tmp('U',e->tp,tbl); Pexpr ass = init_tmp(tmp,e,tbl); // Pref r = new ref(DOT,tmp,found); // Pexpr rr = r->typ(tbl); // Pexpr c = new expr(G_CALL,rr,0); // c->fct_name = found; ass = new expr(CM,ass,c); return ass->typ(tbl); } } */ case 1: { Pname xx = new name(found->string); Pexpr c; if (e->lval(0)) { Pref r = new ref(DOT,e,xx); Pexpr rr = r->typ(tbl); c = new expr(G_CALL,rr,0); } else { // (temp=init,temp.coerce()) Pname tmp = make_tmp('U',e->tp,tbl); Pexpr ass = init_tmp(tmp,e,tbl); Pref r = new ref(DOT,tmp,xx); Pexpr rr = r->typ(tbl); c = new expr(G_CALL,rr,0); c = new expr(CM,ass,c); } return c->typ(tbl); } // default: // error("%d possible conversions for%nO in%kE",i,cn,b); // return e; } } if (e->tp->memptr()) { e = new mdot("i",e); e->i1 = 9; e = new expr(NE,e,zero); } else if (e->tp->num_ptr(b) == FCT) error("%k(F)",b); return e; } void stmt::dcl() /* typecheck statement "this" in scope "curr_block->tbl" */ { Pstmt ss; Pname n; Pname nn; Pstmt ostmt = Cstmt; DB( if(Ddebug>=1) error('d',&where,"'%k'->stmt::dcl()",base); ); for (ss=this; ss; ss=ss->s_list) { Pstmt old_loop, old_switch; Cstmt = ss; enum_promote = 0; Ptable tbl = curr_block->memtbl; //error('d',"stmt::dcl %k",ss->base); switch (ss->base) { case BREAK: inline_restr |= 16; if (curr_loop==0 && curr_switch==0) error("break not in loop or switch"); ss->reached(); break; case CONTINUE: inline_restr |= 32; if (curr_loop == 0) error("continue not in loop"); ss->reached(); break; case DEFAULT: if (curr_switch == 0) { error("default not in switch"); break; } if (curr_switch->has_default) error("two defaults in switch"); curr_switch->has_default = ss; ss->s->s_list = ss->s_list; ss->s_list = 0; ss->s->dcl(); break; case SM: { if (ss->e ==0) break; TOK b = ss->e->base; switch (b) { case DUMMY: ss->e = 0; break; // check for unused results // don't check operators that are likely // to be overloaded to represent "actions": // ! ~ < <= > >= << >> case EQ: case NE: case PLUS: case MINUS: case REF: case DOT: case MUL: case DIV: case ADDROF: case AND: case OR: case ER: case DEREF: case ANDAND: case OROR: case NAME: case VALUE: if (ss->e->tp) break; // avoid looking at generated code ss->e = ss->e->typ(tbl); if (ss->e->base == CALL) break; if (ss->e->tp->base != VOID) { if ( ss->e->base == DEREF ) error('w',"result of %sE not used",ss->e->e2?"[]":"*"); else error('w',"result of%kE not used",b); if (ss->e->not_simple()==0) ss->e = dummy; } break; default: ss->e = ss->e->typ(tbl); } break; } case RETURN: { Pname fn = cc->nof; Pfct f = Pfct(fn->tp); Ptype rt = f->returns; Pexpr v = ss->e; //error('d',"rt %t",rt); while (rt->base == TYPE) rt = Pbase(rt)->b_name->tp; if (v != dummy) { if (rt->base == RPTR || rt->base == PTR) { const_ptr = Pbase(Pptr(rt)->typ)->tconst(); } if (rt->base == RPTR) { ref_initializer++; v = v->typ(tbl); ref_initializer--; } else v = v->typ(tbl); const_ptr = 0; if (fn->n_oper==CTOR || fn->n_oper==DTOR || (rt->base==VOID && v->tp!=void_type)) { error("unexpected return value"); // refuse to return the value: ss->e = dummy; } else { switch (rt->base) { // case TYPE: laready done above case RPTR: switch (v->base) { case NAME: if (Pname(v)->n_scope==FCT || Pname(v)->n_scope==ARG) error('w',"R to localV returned"); break; case ICON: case CCON: case FCON: case STRING: if (Pptr(rt)->typ->tconst()==0) error('w',"R to literal returned"); } v = ref_init(Pptr(rt),v,tbl); if (v->base==G_CM && v->e2->base==G_ADDROF && v->e2->e2->base==NAME) error('w',"R to temporary returned (return value is not lvalue or of wrongT)"); case ANY: break; case COBJ: if (v->base == DEREF) { Pexpr v1 = v->e1; if (v1->base==CAST) { Pexpr v2 = v1->e1; if (v2->base == G_CM) { // *(T)(e1,e2) => (e1,*(T)e2) Pexpr v3 = v2->e2; v2->e2 = v; v2->tp = v->tp; v = v2; v1->e1 = v3; } } } if (f->f_result) { if (v->base==G_CM && rt->check(v->tp,0/*ASSIGN*/)==0) v = replace_temp(v,f->f_result); else { v = class_init(f->f_result->contents(),rt,v,tbl); Pname rcn = rt->is_cl_obj(); if (Pclass(rcn->tp)->has_itor()==0) { // can happen for virtuals and for user defined conversions v->tp = rt; v = new expr(ASSIGN,f->f_result->contents(),v); v->tp = rt; } } } else v = class_init(0,rt,v,tbl); break; case PTR: { Pexpr x = v; v = ptr_init(Pptr(rt),v,tbl); if (v->base == ADDROF && v->e2->base == NAME && Pname(v->e2)->n_stclass == AUTO) error('w',"P to local variable%n returned",Pname(v->e2)); // if (v==x ||v->e2==x) goto def; if (Pchecked == 0) goto def; goto ret_save; // break; } case INT: case CHAR: case LONG: case SHORT: if (Pbase(rt)->b_unsigned && v->base==UMINUS && v->e2->base==ICON) error('w',"negative returned fromF returning unsigned"); default: def: { Pexpr x = try_to_coerce(rt,v,"return value",tbl); if (x) v = x; else if (rt->check(v->tp,ASSIGN)) error("bad return valueT for%n:%t (%tX)",fn,v->tp,rt); } } ret_save: ss->ret_tp = rt; ss->e = v; } } else { if (rt->base != VOID) error("return valueX"); } ss->reached(); break; } case DO: // in DO the stmt is before the test inline_restr |= 8; old_loop = curr_loop; curr_loop = ss; { Pstmt st = ss->s; while(st && st->base == FOR) st = st->for_init; if (st && st->base == DCL) if (st==ss->s) error("D as onlyS in do-loop"); } ss->s->dcl(); ss->e = ss->e->typ(tbl); ss->e = check_cond(ss->e,DO,tbl); curr_loop = old_loop; break; case WHILE: inline_restr |= 8; old_loop = curr_loop; curr_loop = ss; ss->e = ss->e->typ(tbl); ss->e = check_cond(ss->e,WHILE,tbl); { Pstmt st = ss->s; while(st && st->base == FOR) st = st->for_init; if (st && st->base == DCL) if(st==ss->s) error("D as onlyS in while-loop"); } ss->s->dcl(); curr_loop = old_loop; break; case SWITCH: { int ne = 0; inline_restr |= 4; old_switch = curr_switch; curr_switch = ss; ss->e = ss->e->typ(tbl); ss->e = check_cond(ss->e,SWITCH,tbl); { Pstmt st = ss->s; while(st && st->base == FOR) st = st->for_init; if (st && st->base == DCL) if(st==ss->s) error("D as onlyS in switchS"); } { Ptype tt = ss->e->tp; sii: switch (tt->base) { case TYPE: tt = Pbase(tt)->b_name->tp; goto sii; case EOBJ: ne = Penum(Pbase(tt)->b_name->tp)->no_of_enumerators; case ZTYPE: case ANY: case CHAR: case SHORT: case INT: case LONG: case FIELD: break; default: error("%t switchE",ss->e->tp); } } ss->s->dcl(); if (ne) { /* see if the number of cases is "close to" but not equal to the number of enumerators */ int i = 0; Pstmt cs; for (cs=ss->case_list; cs; cs=cs->case_list) i++; if (i && i!=ne) { if (ne < i) { ee: error('w',"switch (%t)W %d cases (%d enumerators)",ss->e->tp,i,ne); } else { switch (ne-i) { case 1: if (3<ne) goto ee; case 2: if (7<ne) goto ee; case 3: if (23<ne) goto ee; case 4: if (60<ne) goto ee; case 5: if (99<ne) goto ee; } } } } curr_switch = old_switch; break; } case CASE: if (curr_switch == 0) { error("case not in switch"); break; } ss->e = ss->e->typ(tbl); ss->e->tp->num_ptr(CASE); { Ptype tt = ss->e->tp; iii: switch (tt->base) { case TYPE: tt = Pbase(tt)->b_name->tp; goto iii; case ZTYPE: case ANY: case CHAR: case SHORT: case INT: case LONG: case EOBJ: Neval = 0; long i = ss->e->eval(); if (Neval == 0) { Pstmt cs; if (largest_int<i) error("long case value"); for (cs=curr_switch->case_list; cs; cs=cs->case_list) { if (cs->case_value == i) error("case %d used twice in switch",i); } ss->case_value = int(i); ss->case_list = curr_switch->case_list; curr_switch->case_list = ss; } else error("bad case label: %s",Neval); break; default: error("%t caseE",ss->e->tp); } } // if (1) { // Neval = 0; // long i = ss->e->eval(); // if (Neval == 0) { // Pstmt cs; // if (largest_int<i) error("long case value"); // for (cs=curr_switch->case_list; cs; cs=cs->case_list) { // if (cs->case_value == i) error("case %d used twice in switch",i); // } // ss->case_value = int(i); // ss->case_list = curr_switch->case_list; // curr_switch->case_list = ss; // } // else // error("bad case label: %s",Neval); // } if (ss->s->s_list) error('i',"case%k",ss->s->s_list->base); ss->s->s_list = ss->s_list; ss->s_list = 0; ss->s->dcl(); break; case GOTO: inline_restr |= 2; ss->reached(); case LABEL: /* Insert label in function mem table; labels have function scope. */ n = ss->d; nn = cc->ftbl->insert(n,LABEL); /* Set a ptr to the mem table corresponding to the scope in which the label actually occurred. This allows the processing of goto's in the presence of ctors and dtors */ if (ss->base == LABEL) { nn->n_realscope = curr_block->memtbl; inline_restr |= 1; } if (Nold) { if (ss->base == LABEL) { if (nn->n_initializer) error("twoDs of label%n",n); nn->n_initializer = (Pexpr)1; } if (n != nn) ss->d = nn; } else { if (ss->base == LABEL) nn->n_initializer = (Pexpr)1; nn->where = ss->where; } if (ss->base == GOTO) nn->use(); else { if (ss->s->s_list) error('i',"label%k",ss->s->s_list->base); ss->s->s_list = ss->s_list; ss->s_list = 0; nn->assign(); } if (ss->s) ss->s->dcl(); break; case IF: { Pexpr ee = ss->e->typ(tbl); if (ee->base == ASSIGN) { Neval = 0; (void)ee->e2->eval(); if (Neval == 0) error('w',"constant assignment in condition"); } ss->e = ee = check_cond(ee,IF,tbl); if (ss->s->base == DCL) error("D as onlyS after `if'"); // pointer to member returns with a tp set to 0 if ( ee->tp ) switch (ee->tp->base) { case INT: case EOBJ: case ZTYPE: { long i; Neval = 0; i = ee->eval(); if (Neval == 0) { Pstmt sl = ss->s_list; if (i) { DEL(ss->else_stmt); ss->s->dcl(); *ss = *ss->s; } else { DEL(ss->s); if (ss->else_stmt) { ss->else_stmt->dcl(); *ss = *ss->else_stmt; } else { ss->base = SM; ss->e = dummy; ss->s = 0; } } ss->s_list = sl; continue; } } } ss->s->dcl(); if (ss->else_stmt) { if (ss->else_stmt->base == DCL) error("D as onlyS after `else'"); ss->else_stmt->dcl(); } break; } case FOR: inline_restr |= 8; old_loop = curr_loop; curr_loop = ss; if (ss->for_init) { Pstmt fi = ss->for_init; switch (fi->base) { case SM: if (fi->e == dummy) { ss->for_init = 0; break; } fi->dcl(); break; default: // for (stmt; e1; e2) stmt1 stmt2 // => {stmt; for(; e1; e2) stmt1 stmt2} // if stmt != declaration // if stmt == declaration, temporarily // rewrite to avoid symbol table // problems in some contexts. // Then put decl back to avoid // extraneous {}. // Note: to maintain pointers, ss // must not change { Pstmt tmp = new stmt (SM,curloc,0); *tmp = *ss; // tmp = original for tmp->for_init = 0; fi->s_list = tmp; *ss = *fi; curr_loop = old_loop; ss->dcl(); tmp = ss->s_list; if ( ss->base == DCL && tmp->base == FOR // sanity check && tmp->for_init == 0 // sanity check ) { // put DCL back in for init *fi = *ss; *ss = *tmp; ss->for_init = fi; fi->s_list = 0; } else { // non-decl stmt in for init // put stmts in block in case // they follow a condition... // allocate tmp to be sure // fields are initialized *fi = *ss; tmp = new block(ss->where,0,fi); tmp->own_tbl = 0; tmp->memtbl = curr_block->memtbl; tmp->permanent = ss->permanent; *ss = *tmp; tmp->permanent = 0; delete tmp; } // don't repeat stmt::dcl() for // remaining stmts goto done; } } } if (ss->e == dummy) ss->e = 0; else { ss->e = ss->e->typ(tbl); ss->e = check_cond(ss->e,FOR,tbl); } { Pstmt st = ss->s; while(st && st->base == FOR) st = st->for_init; if (st && st->base == DCL) if(st==ss->s) error("D as onlyS in for-loop"); } ss->s->dcl(); ss->e2 = (ss->e2 == dummy) ? 0 : ss->e2->typ(tbl); curr_loop = old_loop; break; case DCL: /* declaration after statement */ { /* collect all the contiguous DCL nodes from the head of the s_list. find the next statement */ int non_trivial = 0; int count = 0; Pname tail = ss->d; for (Pname nn=tail; nn; nn=nn->n_list) { // find tail; // detect non-trivial declarations count++; if (nn->n_list) tail = nn->n_list; Pname n = tbl->look(nn->string,0); if (n && n->n_table==tbl) non_trivial = 2; if (non_trivial == 2) continue; if ((nn->n_sto==STATIC && nn->tp->base!=FCT) || nn->tp->is_ref() || (nn->tp->tconst() && fct_const==0)) { non_trivial = 2; continue; } Pexpr in = nn->n_initializer; if (in) switch (in->base) { case ILIST: case STRING: non_trivial = 2; continue; } non_trivial = 1; Pname cln = nn->tp->is_cl_obj(); if (cln == 0) cln = cl_obj_vec; if (cln == 0) continue; if (Pclass(cln->tp)->has_ctor()) { non_trivial = 2; continue; } if (Pclass(cln->tp)->has_dtor()) non_trivial = 2; } while( ss->s_list && ss->s_list->base==DCL ) { Pstmt sx = ss->s_list; tail = tail->n_list = sx->d; // add to tail for (nn=sx->d; nn; nn=nn->n_list) { // find tail; // detect non-trivial declarations count++; if (nn->n_list) tail = nn->n_list; Pname n = tbl->look(nn->string,0); if (n && n->n_table==tbl) non_trivial = 2; if (non_trivial == 2) continue; if ((nn->n_sto==STATIC && nn->tp->base!=FCT) || nn->tp->is_ref() || (nn->tp->tconst() && fct_const==0)) { non_trivial = 2; continue; } Pexpr in = nn->n_initializer; if (in) switch (in->base) { case ILIST: case STRING: non_trivial = 2; continue; } non_trivial = 1; Pname cln = nn->tp->is_cl_obj(); if (cln == 0) cln = cl_obj_vec; if (cln == 0) continue; if (Pclass(cln->tp)->has_ctor()) { non_trivial = 2; continue; } if (Pclass(cln->tp)->has_dtor()) non_trivial = 2; } ss->s_list = sx->s_list; /* delete sx; */ } Pstmt next_st = ss->s_list; //error('d',"dcl stmt : d %n non_trivial %d curr own_tbl %d inline_restr 0%o",ss->d,non_trivial,curr_block->own_tbl,inline_restr); if (non_trivial==2 // must || (non_trivial==1 // might && ( curr_block->own_tbl==0 // why not? || inline_restr&3 /* label seen */) ) ) { if (curr_switch && non_trivial==2) { Pstmt cs = curr_switch->case_list; Pstmt ds = curr_switch->has_default; Pstmt bl; if (cs == 0) bl = ds; else if (ds == 0) bl = cs; else if (cs->where.line<ds->where.line) bl = ds; else bl = cs; if ((bl==0 || bl->s->base!=BLOCK) && curr_switch->s->memtbl==tbl) error('s',"non trivialD in switchS (try enclosing it in a block)"); } /* Create a new block, put all the declarations at the head, and the remainder of the slist as the statement list of the block. */ //ss->base = BLOCK; //DCL /* check that there are no redefinitions since the last "real" (user-written, non-generated) block */ { Pname lastnn = 0; for( nn=ss->d; nn; nn=nn->n_list ) { Pname n; //n=curr_block->memtbl->look(nn->string,0); //error('d',"checking %n lex_level: %d n: %n n->lex_level: %d",nn,nn->lex_level,n,n?n->lex_level:0); //error('d'," own_tbl: %d curr_block: %d n->n_table: %d",curr_block->own_tbl,curr_block,n->n_table); //error('d'," real_block: %d n's real_block: %d",curr_block->memtbl->real_block,n->n_table->real_block); //if( curr_block->own_tbl if ( (n=curr_block->memtbl->look(nn->string,0)) && n->n_table->real_block==curr_block->memtbl->real_block && n->tp->base!=FCT && n->tp->base!=OVERLOAD && nn->lex_level == n->lex_level ) { error("twoDs of%n",n); if (lastnn==0) ss->d=nn->n_list; else lastnn->n_list=nn->n_list; } else lastnn = nn; } // for nn } /* attach the remainder of the s_list as the statement part of the block. */ ss->s = next_st; ss->s_list = 0; /* create the table in advance, in order to set the real_block ptr to that of the enclosing table */ ss->memtbl = new table(count+4,tbl,0); ss->memtbl->real_block = curr_block->memtbl->real_block; Pblock(ss)->dcl(ss->memtbl); } else { /* to reduce the number of symbol tables, do not make a new block, instead insert names in enclosing block, and make the initializers into expression statements. */ Pstmt sss = ss; { Pname lastnn = 0; for( nn=ss->d; nn; nn=nn->n_list ) { Pname n; //error('d',"nn %n",nn); //if( curr_block->own_tbl if ( (n=curr_block->memtbl->look(nn->string,0)) && n->n_table->real_block==curr_block->memtbl->real_block && n->tp->base!=FCT && n->tp->base!=OVERLOAD && nn->lex_level == n->lex_level ) { error("twoDs of%n",n); n = 0; if (lastnn==0) ss->d=nn->n_list; else lastnn->n_list=nn->n_list; } else { n = nn->dcl(tbl,FCT); lastnn=nn; } if (n == 0) { if (ss) { ss->base = SM; ss->e = 0; } continue; } //error('d',"hoisted %n to outer blk",n); Pexpr in = n->n_initializer; n->n_initializer = 0; if (ss) { sss->base = SM; ss = 0; } else sss = sss->s_list = new estmt(SM,sss->where,0,0); if (in) { switch (in->base) { case G_CALL: /* constructor? */ { Pname fn = in->fct_name; if (fn && fn->n_oper==CTOR) break; } default: in = new expr(ASSIGN,n,in); in->tp = n->tp; } // sss->e = in->typ(tbl); sss->e = in; } else sss->e = dummy; } // for nn } ss = sss; ss->s_list = next_st; } break; } case BLOCK: Pblock(ss)->dcl(tbl); break; case ASM: /* save string */ { char* s = (char*)ss->e; int ll = strlen(s); char* s2 = new char[ll+1]; strcpy(s2,s); ss->e = Pexpr(s2); break; } default: error('i',"badS(%p %d)",ss,ss->base); } } done: Cstmt = ostmt; } void block::dcl(Ptable tbl) /* Note: for a block without declarations memtbl denotes the table for the enclosing scope. A function body has its memtbl created by fct::dcl(). */ { int bit_old = bit_offset; int byte_old = byte_offset; int max_old = max_align; Pblock block_old = curr_block; if (base != BLOCK && base != DCL) error('i',"block::dcl(%d)",base); curr_block = this; //error('d',"%d->block::dcl(%d) base %k",this,tbl,base); //error('d'," memtbl %d own_tbl %d d %n s %k",memtbl,own_tbl,d,s?s->base:0); if (d) { own_tbl = 1; base = BLOCK; if (memtbl == 0) { int nmem = d->no_of_names()+4; memtbl = new table(nmem,tbl,0); memtbl->real_block = this; /* this is a "real" block from the source text, and not one created by DCL's inside a block. */ } else if (memtbl != tbl) error('i',"block::dcl(?)"); Pname nx; for (Pname n=d; n; n=nx) { nx = n->n_list; n->dcl(memtbl,FCT); switch (n->tp->base) { case CLASS: case ANON: case ENUM: break; default: delete n; } } } else if ( base == BLOCK ) { own_tbl = 1; if (memtbl == 0) { int nmem = 4; memtbl = new table(nmem,tbl,0); memtbl->real_block = this; /* this is a "real" block from the source text, and not one created by DCL's inside a block. */ } else if (memtbl != tbl) error('i',"block::dcl(?)"); } else { base = BLOCK; memtbl = tbl; } Pname odcl = Cdcl; if (s) s->dcl(); if (own_tbl) { Pname m; int i; for (m=memtbl->get_mem(i=1); m; m=memtbl->get_mem(++i)) { Ptype t = m->tp; if (in_class_dcl) m->lex_level -= 1; if (t == 0) { if (m->n_assigned_to == 0) error("label %sU",m->string); if (m->n_used == 0) error('w',"label %s not used", m->string); continue; } ll: switch (t->base) { case TYPE: t = Pbase(t)->b_name->tp; goto ll; case CLASS: case ANON: case ENUM: case FCT: //case VEC: continue; } if (m->n_addr_taken == 0) { if (m->n_used) { if (m->n_assigned_to) { } else if ( t->base != VEC ) { switch (m->n_scope) { case FCT: Cdcl = m; if (m->string[0] != '_' && m->string[1] != '_' ) error('w',&m->where,"%n used but not set",m); } } } else { if (m->n_assigned_to) { } else if (m->string[0]!='_' || m->string[1]!='_') { switch (m->n_scope) { case ARG: case FCT: Cdcl = m; error('w',&m->where,"%n not used",m); } } } } } } Cdcl = odcl; d = 0; if (bit_offset) byte_offset += SZ_WORD; bit_offset = bit_old; byte_offset = byte_old; curr_block = block_old; } void name::field_align() /* adjust alignment */ { Pbase fld = (Pbase)tp; int nbits = fld->b_bits; int a = (F_SENSITIVE) ? fld->b_fieldtype->align() : SZ_WORD; if (max_align < a) max_align = a; if (nbits == 0) { // force word alignment int b; if (bit_offset) nbits = BI_IN_WORD - bit_offset; else if (b = byte_offset%SZ_WORD) nbits = b * BI_IN_BYTE; // else // nbits = BI_IN_WORD; if (max_align < SZ_WORD) max_align = SZ_WORD; } else if (bit_offset == 0) { // take care of part of word int b = byte_offset%SZ_WORD; if (b) { byte_offset -= b; bit_offset = b*BI_IN_BYTE; } } //error('d',"byteoff %d bitoff %d bits %d",byte_offset,bit_offset,nbits); int x = (bit_offset += nbits); if (BI_IN_WORD < x) { fld->b_offset = 0; byte_offset += SZ_WORD; bit_offset = nbits; } else { fld->b_offset = bit_offset; if (BI_IN_WORD == x) { bit_offset = 0; byte_offset += SZ_WORD; } else bit_offset = x; } n_offset = byte_offset; }