#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD");
#endif
#include <stdlib.h>
#include "lint1.h"
int initerr;
sym_t *initsym;
istk_t *initstk;
static void popi2 __P((void));
static void popinit __P((int));
static void pushinit __P((void));
static void testinit __P((void));
static void nextinit __P((int));
static int strginit __P((tnode_t *));
void
prepinit()
{
istk_t *istk;
if (initerr)
return;
while ((istk = initstk) != NULL) {
initstk = istk->i_nxt;
free(istk);
}
if (initsym->s_type->t_tspec == ARRAY && incompl(initsym->s_type))
initsym->s_type = duptyp(initsym->s_type);
istk = initstk = xcalloc(1, sizeof (istk_t));
istk->i_subt = initsym->s_type;
istk->i_cnt = 1;
}
static void
popi2()
{
istk_t *istk;
sym_t *m;
initstk = (istk = initstk)->i_nxt;
if (initstk == NULL)
lerror("popi2() 1");
free(istk);
istk = initstk;
istk->i_cnt--;
if (istk->i_cnt < 0)
lerror("popi2() 3");
if (istk->i_cnt > 0 && istk->i_type->t_tspec == STRUCT) {
do {
m = istk->i_mem = istk->i_mem->s_nxt;
if (m == NULL)
lerror("popi2() 2");
} while (m->s_field && m->s_name == unnamed);
istk->i_subt = m->s_type;
}
}
static void
popinit(brace)
int brace;
{
if (brace) {
do {
brace = initstk->i_brace;
popi2();
} while (!brace);
} else {
while (!initstk->i_brace &&
initstk->i_cnt == 0 && !initstk->i_nolimit) {
popi2();
}
}
}
static void
pushinit()
{
istk_t *istk;
int cnt;
sym_t *m;
istk = initstk;
if (istk->i_cnt == 0) {
if (istk->i_nxt->i_nxt != NULL)
lerror("pushinit() 1");
istk->i_cnt = 1;
if (istk->i_type->t_tspec != ARRAY)
lerror("pushinit() 2");
istk->i_type->t_dim++;
setcompl(istk->i_type, 0);
}
if (istk->i_cnt <= 0)
lerror("pushinit() 3");
if (istk->i_type != NULL && issclt(istk->i_type->t_tspec))
lerror("pushinit() 4");
initstk = xcalloc(1, sizeof (istk_t));
initstk->i_nxt = istk;
initstk->i_type = istk->i_subt;
if (initstk->i_type->t_tspec == FUNC)
lerror("pushinit() 5");
istk = initstk;
switch (istk->i_type->t_tspec) {
case ARRAY:
if (incompl(istk->i_type) && istk->i_nxt->i_nxt != NULL) {
error(175);
initerr = 1;
return;
}
istk->i_subt = istk->i_type->t_subt;
istk->i_nolimit = incompl(istk->i_type);
istk->i_cnt = istk->i_type->t_dim;
break;
case UNION:
if (tflag)
warning(238);
case STRUCT:
if (incompl(istk->i_type)) {
error(175);
initerr = 1;
return;
}
cnt = 0;
for (m = istk->i_type->t_str->memb; m != NULL; m = m->s_nxt) {
if (m->s_field && m->s_name == unnamed)
continue;
if (++cnt == 1) {
istk->i_mem = m;
istk->i_subt = m->s_type;
}
}
if (cnt == 0) {
error(179);
initerr = 1;
return;
}
istk->i_cnt = istk->i_type->t_tspec == STRUCT ? cnt : 1;
break;
default:
istk->i_cnt = 1;
break;
}
}
static void
testinit()
{
istk_t *istk;
istk = initstk;
if (istk->i_cnt == 0 && !istk->i_nolimit) {
switch (istk->i_type->t_tspec) {
case ARRAY:
error(173);
break;
case STRUCT:
case UNION:
error(172);
break;
default:
error(174);
break;
}
initerr = 1;
}
}
static void
nextinit(brace)
int brace;
{
if (!brace) {
if (initstk->i_type == NULL &&
!issclt(initstk->i_subt->t_tspec)) {
error(181);
}
if (!initerr)
testinit();
while (!initerr && (initstk->i_type == NULL ||
!issclt(initstk->i_type->t_tspec))) {
if (!initerr)
pushinit();
}
} else {
if (initstk->i_type != NULL &&
issclt(initstk->i_type->t_tspec)) {
error(176);
initerr = 1;
}
if (!initerr)
testinit();
if (!initerr)
pushinit();
if (!initerr)
initstk->i_brace = 1;
}
}
void
initlbr()
{
if (initerr)
return;
if ((initsym->s_scl == AUTO || initsym->s_scl == REG) &&
initstk->i_nxt == NULL) {
if (tflag && !issclt(initstk->i_subt->t_tspec))
warning(188);
}
popinit(0);
nextinit(1);
}
void
initrbr()
{
if (initerr)
return;
popinit(1);
}
void
mkinit(tn)
tnode_t *tn;
{
ptrdiff_t offs;
sym_t *sym;
tspec_t lt, rt;
tnode_t *ln;
struct mbl *tmem;
scl_t sc;
if (initerr || tn == NULL)
goto end;
sc = initsym->s_scl;
if ((sc == AUTO || sc == REG) &&
initsym->s_type->t_tspec != ARRAY && initstk->i_nxt == NULL) {
ln = getnnode(initsym, 0);
ln->tn_type = tduptyp(ln->tn_type);
ln->tn_type->t_const = 0;
tn = build(ASSIGN, ln, tn);
expr(tn, 0, 0);
goto end;
}
popinit(0);
if (strginit(tn))
goto end;
nextinit(0);
if (initerr || tn == NULL)
goto end;
initstk->i_cnt--;
ln = tgetblk(sizeof (tnode_t));
ln->tn_op = NAME;
ln->tn_type = tduptyp(initstk->i_type);
ln->tn_type->t_const = 0;
ln->tn_lvalue = 1;
ln->tn_sym = initsym;
tn = cconv(tn);
lt = ln->tn_type->t_tspec;
rt = tn->tn_type->t_tspec;
if (!issclt(lt))
lerror("mkinit() 1");
if (!typeok(INIT, 0, ln, tn))
goto end;
tmem = tsave();
expr(tn, 1, 0);
trestor(tmem);
if (isityp(lt) && ln->tn_type->t_isfield && !isityp(rt)) {
if (tflag)
warning(186);
}
if (lt != rt || (initstk->i_type->t_isfield && tn->tn_op == CON))
tn = convert(INIT, 0, initstk->i_type, tn);
if (tn != NULL && tn->tn_op != CON) {
sym = NULL;
offs = 0;
if (conaddr(tn, &sym, &offs) == -1) {
if (sc == AUTO || sc == REG) {
(void)gnuism(177);
} else {
error(177);
}
}
}
end:
tfreeblk();
}
static int
strginit(tn)
tnode_t *tn;
{
tspec_t t;
istk_t *istk;
int len;
strg_t *strg;
if (tn->tn_op != STRING)
return (0);
istk = initstk;
strg = tn->tn_strg;
if (istk->i_subt->t_tspec == ARRAY) {
t = istk->i_subt->t_subt->t_tspec;
if (!((strg->st_tspec == CHAR &&
(t == CHAR || t == UCHAR || t == SCHAR)) ||
(strg->st_tspec == WCHAR && t == WCHAR))) {
return (0);
}
pushinit();
istk = initstk;
} else if (istk->i_type != NULL && istk->i_type->t_tspec == ARRAY) {
t = istk->i_type->t_subt->t_tspec;
if (!((strg->st_tspec == CHAR &&
(t == CHAR || t == UCHAR || t == SCHAR)) ||
(strg->st_tspec == WCHAR && t == WCHAR))) {
return (0);
}
if (istk->i_cnt != istk->i_type->t_dim)
return (0);
} else {
return (0);
}
len = strg->st_len;
if (istk->i_nolimit) {
istk->i_nolimit = 0;
istk->i_type->t_dim = len + 1;
setcompl(istk->i_type, 0);
} else {
if (istk->i_type->t_dim < len) {
warning(187);
}
}
istk->i_cnt = 0;
return (1);
}