#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(__RCSID)
__RCSID("$NetBSD: emit1.c,v 1.97 2026/01/11 18:11:38 rillig Exp $");
#endif
#include <stdlib.h>
#include "lint1.h"
static void outtt(sym_t *, sym_t *);
static void outfstrg(const char *);
void
outtype(const type_t *tp)
{
static const char tt[NTSPEC] = "???BCCCSSIILLQQJJDDD?XXXV?TTTPAF";
static const char ss[NTSPEC] = "??? su u u u u us l?s l ?sue ";
int na;
tspec_t ts;
while (tp != NULL) {
if ((ts = tp->t_tspec) == INT && tp->t_is_enum)
ts = ENUM;
lint_assert(tt[ts] != '?' && ss[ts] != '?');
if (tp->t_const)
outchar('c');
if (tp->t_volatile)
outchar('v');
if (ss[ts] != ' ')
outchar(ss[ts]);
outchar(tt[ts]);
if (ts == ARRAY) {
outint(tp->u.dimension);
} else if (ts == ENUM) {
outtt(tp->u.enumer->en_tag,
tp->u.enumer->en_first_typedef);
} else if (is_struct_or_union(ts)) {
outtt(tp->u.sou->sou_tag,
tp->u.sou->sou_first_typedef);
} else if (ts == FUNC && tp->t_proto) {
na = 0;
for (const sym_t *param = tp->u.params;
param != NULL; param = param->s_next)
na++;
if (tp->t_vararg)
na++;
outint(na);
for (const sym_t *param = tp->u.params;
param != NULL; param = param->s_next)
outtype(param->s_type);
if (tp->t_vararg)
outchar('E');
}
tp = tp->t_subt;
}
}
static void
outtt(sym_t *tag, sym_t *tdef)
{
if (tag->s_name != unnamed) {
outint(1);
outname(tag->s_name);
} else if (tdef != NULL) {
outint(2);
outname(tdef->s_name);
} else {
outint(3);
outint(tag->s_def_pos.p_line);
outchar('.');
outint(get_filename_id(tag->s_def_pos.p_file));
outchar('.');
outint(tag->s_def_pos.p_uniq);
}
}
void
outsym(const sym_t *sym, scl_t sc, def_t def)
{
if (sc != EXTERN && !(sc == STATIC && sym->s_type->t_tspec == FUNC))
return;
if (ch_isdigit(sym->s_name[0]))
return;
outint(csrc_pos.p_line);
outchar('d');
outint(get_filename_id(sym->s_def_pos.p_file));
outchar('.');
outint(sym->s_def_pos.p_line);
if (def == DEF)
outchar('d');
else if (def == TDEF)
outchar('t');
else {
lint_assert(def == DECL);
outchar('e');
}
if (llibflg && def != DECL) {
outchar('u');
}
if (sc == STATIC)
outchar('s');
outname(sym->s_name);
if (sym->s_rename != NULL) {
outchar('r');
outname(sym->s_rename);
}
outtype(sym->s_type);
outchar('\n');
}
void
outfdef(const sym_t *fsym, const pos_t *posp, bool rval, bool osdef,
const sym_t *args)
{
int narg;
if (posp->p_file == csrc_pos.p_file) {
outint(posp->p_line);
} else {
outint(csrc_pos.p_line);
}
outchar('d');
outint(get_filename_id(posp->p_file));
outchar('.');
outint(posp->p_line);
if (printflike_argnum != -1) {
nvararg = printflike_argnum;
} else if (scanflike_argnum != -1) {
nvararg = scanflike_argnum;
}
if (nvararg != -1) {
outchar('v');
outint(nvararg);
}
if (scanflike_argnum != -1) {
outchar('S');
outint(scanflike_argnum);
}
if (printflike_argnum != -1) {
outchar('P');
outint(printflike_argnum);
}
nvararg = printflike_argnum = scanflike_argnum = -1;
outchar('d');
if (rval)
outchar('r');
if (llibflg)
outchar('u');
if (osdef)
outchar('o');
if (fsym->s_inline)
outchar('i');
if (fsym->s_scl == STATIC)
outchar('s');
outname(fsym->s_name);
if (fsym->s_rename != NULL) {
outchar('r');
outname(fsym->s_rename);
}
if (osdef) {
narg = 0;
for (const sym_t *arg = args; arg != NULL; arg = arg->s_next)
narg++;
outchar('f');
outint(narg);
for (const sym_t *arg = args; arg != NULL; arg = arg->s_next)
outtype(arg->s_type);
outtype(fsym->s_type->t_subt);
} else {
outtype(fsym->s_type);
}
outchar('\n');
}
void
outcall(const tnode_t *tn, bool retval_used, bool retval_discarded)
{
outint(csrc_pos.p_line);
outchar('c');
outint(get_filename_id(curr_pos.p_file));
outchar('.');
outint(curr_pos.p_line);
const function_call *call = tn->u.call;
for (size_t i = 0, n = call->args_len; i < n; i++) {
const tnode_t *arg = call->args[i];
if (arg->tn_op == CON) {
tspec_t t = arg->tn_type->t_tspec;
if (is_integer(t)) {
int64_t si = arg->u.value.u.integer;
if (si == 0)
outchar('z');
else if (!msb(si, t))
outchar('p');
else
outchar('n');
outint((int)i + 1);
}
} else if (arg->tn_op == ADDR &&
arg->u.ops.left->tn_op == STRING &&
arg->u.ops.left->u.str_literals->data != NULL) {
buffer buf;
buf_init(&buf);
quoted_iterator it = { .end = 0 };
while (quoted_next(arg->u.ops.left->u.str_literals, &it))
buf_add_char(&buf, (char)it.value);
outchar('s');
outint((int)i + 1);
outfstrg(buf.data);
free(buf.data);
}
}
outchar((char)(retval_discarded ? 'd' : retval_used ? 'u' : 'i'));
outname(call->func->u.ops.left->u.sym->s_name);
outchar('f');
outint((int)call->args_len);
for (size_t i = 0, n = call->args_len; i < n; i++)
outtype(call->args[i]->tn_type);
outtype(tn->tn_type);
outchar('\n');
}
static void
outqchar(char c)
{
if (ch_isprint(c) && c != '\\' && c != '"' && c != '\'') {
outchar(c);
return;
}
outchar('\\');
switch (c) {
case '\\':
outchar('\\');
break;
case '"':
outchar('"');
break;
case '\'':
outchar('\'');
break;
case '\b':
outchar('b');
break;
case '\t':
outchar('t');
break;
case '\n':
outchar('n');
break;
case '\f':
outchar('f');
break;
case '\r':
outchar('r');
break;
case '\v':
outchar('v');
break;
case '\a':
outchar('a');
break;
default:
outchar((char)((((unsigned char)c >> 6) & 07) + '0'));
outchar((char)((((unsigned char)c >> 3) & 07) + '0'));
outchar((char)((c & 07) + '0'));
break;
}
}
static void
outfstrg(const char *cp)
{
outchar('"');
char c = *cp++;
while (c != '\0') {
if (c != '%') {
c = *cp++;
continue;
}
outchar('%');
c = *cp++;
while (c == '-' || c == '+' || c == ' ' ||
c == '#' || c == '0' || c == '*') {
outchar(c);
c = *cp++;
}
while (ch_isdigit(c)) {
outchar(c);
c = *cp++;
}
if (c == '.') {
outchar(c);
c = *cp++;
if (c == '*') {
outchar(c);
c = *cp++;
} else {
while (ch_isdigit(c)) {
outchar(c);
c = *cp++;
}
}
}
if (c == 'h' || c == 'l' || c == 'L' || c == 'q') {
outchar(c);
c = *cp++;
}
if (c != '\0') {
outqchar(c);
char oc = c;
c = *cp++;
if (oc == '[') {
if (c == '^')
c = *cp++;
if (c == ']')
c = *cp++;
bool first = true;
while (c != '\0' && c != ']') {
if (c == '-') {
if (!first && *cp != ']')
outchar(c);
}
first = false;
c = *cp++;
}
if (c == ']') {
outchar(c);
c = *cp++;
}
}
}
}
outchar('"');
}
void
outusg(const sym_t *sym)
{
if (ch_isdigit(sym->s_name[0]))
return;
outint(csrc_pos.p_line);
outchar('u');
outint(get_filename_id(curr_pos.p_file));
outchar('.');
outint(curr_pos.p_line);
outchar('x');
outname(sym->s_name);
outchar('\n');
}