stage2: reference support (refs)

- Builtin refs: int& -> int* in signature, (*a) deref in body
- Class refs: Cls& -> Cls* in signature, p.field -> p->field in body
- Call-site & injection via FnRef table (swap(x,y) -> swap(&x,&y))
- Member call ref args also get & injected
- Virtual dispatch for pointer-ref params preserved
- parse_member_decl: ptr param recording + dot-to-arrow conversion
- parse_function: iref body rewrite + fnref call-site rewrite
这个提交包含在:
Paze AI
2026-08-16 19:49:36 +08:00
父节点 b112fa79e4
当前提交 ed918d046d
修改 2 个文件,包含 386 行新增26 行删除
二进制
查看文件
二进制文件未显示。
+386 -26
查看文件
@@ -37,6 +37,41 @@ static int g_line = 1;
static int g_ns_open = 0; /* namespace block depth (flattened) */
static int g_virt_pending = 0; /* next member decl is virtual */
/* ---------------- references ---------------- */
typedef struct FnRef {
char fn[64];
int arg[16];
int narg;
struct FnRef *next;
} FnRef;
static FnRef *g_fnrefs = NULL;
static FnRef *find_fnref(const char *fn)
{
FnRef *p;
for (p = g_fnrefs; p; p = p->next)
if (!strcmp(p->fn, fn)) return p;
return NULL;
}
static int fr_has_arg(const FnRef *fr, int ai)
{
int i;
for (i = 0; i < fr->narg; i++)
if (fr->arg[i] == ai) return 1;
return 0;
}
static void add_fnref(const char *fn, int ai)
{
FnRef *p = find_fnref(fn);
if (!p) {
p = (FnRef*)calloc(1, sizeof *p);
strncpy(p->fn, fn, sizeof p->fn - 1);
p->fn[sizeof p->fn - 1] = 0;
p->next = g_fnrefs;
g_fnrefs = p;
}
if (p->narg < 16) p->arg[p->narg++] = ai;
}
/* ---------------- templates ---------------- */
typedef struct TplFn {
@@ -523,12 +558,16 @@ static void proto_emit(const char *fmt, ...)
static void gather_decl(char *type, int typesz, char *name, int namesz);
static int tpl_call_check(char varcls[][128], char varname[][64], int nvars);
static void parse_member_decl(const char *cls, const char *ret_type,
const char *mname_in, int is_virtual)
static void parse_member_decl(const char *cls, const char *ret_type, const char *mname_in, int is_virt)
{
char name[256];
char mname[256];
int is_ctor, is_dtor;
char bptrcls[64][128], bptrname[64][64];
int bnptrs = 0;
char biref[64][64];
int bn_iref = 0;
int sig_pidx = 0;
ClassInfo *ci = find_class(cls);
if (mname_in && mname_in[0])
@@ -543,7 +582,7 @@ static void parse_member_decl(const char *cls, const char *ret_type,
if (is_dtor) ci->has_dtor = 1;
else add_member(ci, name);
/* record virtual methods (name + trimmed return type) */
if (is_virtual && !is_ctor && !is_dtor && ci->n_virt < 16) {
if (is_virt && !is_ctor && !is_dtor && ci->n_virt < 16) {
char rtb[64];
int rl;
snprintf(rtb, sizeof rtb, "%s", ret_type);
@@ -609,10 +648,29 @@ static void parse_member_decl(const char *cls, const char *ret_type,
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")")) depth--;
/* class type param -> struct Class */
if (g_tok.type == T_IDENT && find_class(g_tok.text)) {
char ptcls[128];
strncpy(ptcls, g_tok.text, sizeof ptcls - 1);
ptcls[sizeof ptcls - 1] = 0;
proto_emit(" struct %s", g_tok.text);
strncat(g_params, " struct ", sizeof g_params - strlen(g_params) - 1);
strncat(g_params, g_tok.text, sizeof g_params - strlen(g_params) - 1);
next_tok();
/* handle * or & suffix: convert to pointer param */
if (g_tok.type == T_PUNCT &&
(!strcmp(g_tok.text, "*") || !strcmp(g_tok.text, "&"))) {
int is_ref = !strcmp(g_tok.text, "&");
proto_emit(" *");
strncat(g_params, " *", sizeof g_params - strlen(g_params) - 1);
next_tok();
/* record ptr param for body dispatch */
if (g_tok.type == T_IDENT && bnptrs < 64) {
strncpy(bptrcls[bnptrs], ptcls, 127);
strncpy(bptrname[bnptrs], g_tok.text, 63);
bnptrs++;
}
if (is_ref)
add_fnref(mname, sig_pidx);
}
continue;
}
/* smart spacing for prototype params */
@@ -620,12 +678,19 @@ static void parse_member_decl(const char *cls, const char *ret_type,
const char *tt = g_tok.text;
int c = tt[0];
if (g_tok.type == T_PUNCT) {
if (!(c == ')' || c == ']' || c == ';' || c == ',' ||
c == '*' || c == '&' || c == '(' ))
proto_emit(" ");
proto_emit("%s", tt);
strncat(g_params, " ", sizeof g_params - strlen(g_params) - 1);
strncat(g_params, tt, sizeof g_params - strlen(g_params) - 1);
if (c == '&') {
/* reference param -> pointer param */
proto_emit("*");
strncat(g_params, " *", sizeof g_params - strlen(g_params) - 1);
add_fnref(mname, sig_pidx);
} else {
if (!(c == ')' || c == ']' || c == ';' || c == ',' ||
c == '*' || c == '&' || c == '(' ))
proto_emit(" ");
proto_emit("%s", tt);
strncat(g_params, " ", sizeof g_params - strlen(g_params) - 1);
strncat(g_params, tt, sizeof g_params - strlen(g_params) - 1);
}
} else {
proto_emit(" %s", tt);
strncat(g_params, " ", sizeof g_params - strlen(g_params) - 1);
@@ -675,6 +740,17 @@ static void parse_member_decl(const char *cls, const char *ret_type,
int prev_dot = 0;
while (bd > 0) {
if (g_tok.type == T_EOF) break;
/* builtin ref param: a -> (*a) */
if (g_tok.type == T_IDENT && bn_iref > 0) {
int i;
for (i = 0; i < bn_iref; i++)
if (!strcmp(g_tok.text, biref[i])) break;
if (i < bn_iref) {
proto_emit(" (*%s)", g_tok.text);
next_tok();
continue;
}
}
/* namespace-qualified name: ns::name -> name */
if (g_tok.type == T_IDENT && !find_class(g_tok.text)) {
Token nxt;
@@ -838,7 +914,85 @@ static void parse_member_decl(const char *cls, const char *ret_type,
next_tok();
continue;
}
/* ptr/var member dispatch: p->method / p.field */
if (g_tok.type == T_IDENT && bnptrs > 0) {
int pi;
for (pi = 0; pi < bnptrs; pi++) {
if (!strcmp(g_tok.text, bptrname[pi])) {
Token t1, t2;
read_tok(&t1);
if (t1.type == T_PUNCT && !strcmp(t1.text, "->")) {
read_tok(&t2);
if (t2.type == T_IDENT) {
Token t3;
read_tok(&t3);
if (t3.type == T_PUNCT && !strcmp(t3.text, "(")) {
char meth[128], mname[256];
ClassInfo *pci = find_class(bptrcls[pi]);
strncpy(meth, t2.text, sizeof meth - 1);
meth[sizeof meth - 1] = 0;
if (is_virtual(pci, meth)) {
proto_emit(" %s->__vtbl->%s(%s",
g_tok.text, meth, g_tok.text);
} else {
snprintf(mname, sizeof mname, "%s_%s",
bptrcls[pi], meth);
proto_emit(" %s(%s", mname, g_tok.text);
}
next_tok(); next_tok(); next_tok();
if (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")"))) {
proto_emit(", ");
int ad = 0;
while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")") && ad == 0)) {
if (g_tok.type == T_EOF) break;
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "(")) ad++;
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")")) ad--;
proto_emit(" %s", g_tok.text);
next_tok();
}
}
proto_emit(")");
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")")) next_tok();
prev_dot = 0;
continue;
}
unread_tok(&t3);
}
unread_tok(&t2);
} else if (t1.type == T_PUNCT && !strcmp(t1.text, ".")) {
unread_tok(&t1);
break;
}
unread_tok(&t1);
break;
}
}
}
/* fall-through: emit token as-is */
/* ptr ref: p.field -> p->field (fix dot to arrow for known ptr vars) */
if (g_tok.type == T_IDENT && bnptrs > 0) {
int pi2;
for (pi2 = 0; pi2 < bnptrs; pi2++) {
if (!strcmp(g_tok.text, bptrname[pi2])) {
Token nxt2;
read_tok(&nxt2);
if (nxt2.type == T_PUNCT && !strcmp(nxt2.text, ".")) {
Token nxt3;
read_tok(&nxt3);
if (nxt3.type == T_IDENT) {
proto_emit("%s->%s", g_tok.text, nxt3.text);
/* consumed '.', field by read_tok; skip 'p' via next_tok */
next_tok(); /* consume 'p' from g_tok */
prev_dot = 1;
continue;
}
unread_tok(&nxt3);
}
unread_tok(&nxt2);
break;
}
}
}
prev_dot = (g_tok.type == T_PUNCT &&
(!strcmp(g_tok.text, ".") || !strcmp(g_tok.text, "->")));
proto_emit(" %s", g_tok.text);
@@ -1126,6 +1280,18 @@ static void parse_member_definition(const char *ret_type)
if (g_tok.type == T_IDENT && find_class(g_tok.text)) {
emit(" struct %s", g_tok.text);
next_tok();
/* handle * or & suffix */
if (g_tok.type == T_PUNCT &&
(!strcmp(g_tok.text, "*") || !strcmp(g_tok.text, "&"))) {
emit(" *");
next_tok();
}
continue;
}
/* builtin ref param: type &name -> type *name */
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "&")) {
emit("*");
next_tok();
continue;
}
emit_tok();
@@ -1706,6 +1872,9 @@ static void parse_function(const char *ret_type, const char *name)
char ptrcls[64][128]; /* pointer variable name -> class name */
char ptrname[64][64];
int nptrs = 0;
char iref[64][64]; /* builtin-type reference params (deref in body) */
int n_iref = 0;
int sig_pidx = 0; /* param index while scanning signature */
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "::")) {
/* member function: class is 'name', method follows */
@@ -1742,14 +1911,21 @@ static void parse_function(const char *ret_type, const char *name)
/* signature: class types need 'struct'; class params are recorded */
while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{"))) {
if (g_tok.type == T_EOF) break;
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ",")) {
sig_pidx++;
emit_tok();
next_tok();
continue;
}
if (g_tok.type == T_IDENT && find_class(g_tok.text)) {
char clsname[128];
Token nxt;
strncpy(clsname, g_tok.text, sizeof clsname - 1);
clsname[sizeof clsname - 1] = 0;
read_tok(&nxt);
if (nxt.type == T_PUNCT && !strcmp(nxt.text, "*")) {
/* Cls* name -> struct Cls* name (pointer param) */
if (nxt.type == T_PUNCT &&
(!strcmp(nxt.text, "*") || !strcmp(nxt.text, "&"))) {
/* Cls* / Cls& name -> struct Cls* name (pointer param) */
emit(" struct %s*", clsname);
next_tok(); /* g_tok = param name */
if (g_tok.type == T_IDENT && nptrs < 64) {
@@ -1758,6 +1934,8 @@ static void parse_function(const char *ret_type, const char *name)
nptrs++;
emit(" %s", g_tok.text);
next_tok();
if (!strcmp(nxt.text, "&"))
add_fnref(name, sig_pidx);
}
continue;
}
@@ -1774,6 +1952,24 @@ static void parse_function(const char *ret_type, const char *name)
}
emit(" struct %s", clsname);
unread_tok(&nxt);
} else if (g_tok.type == T_IDENT && !find_class(g_tok.text)) {
/* builtin ref param: int &a -> int *a */
Token nxt;
read_tok(&nxt);
if (nxt.type == T_PUNCT && !strcmp(nxt.text, "&")) {
emit(" %s*", g_tok.text);
next_tok(); /* g_tok = param name */
if (g_tok.type == T_IDENT && n_iref < 64) {
strncpy(iref[n_iref], g_tok.text, 63);
iref[n_iref][63] = 0;
n_iref++;
}
add_fnref(name, sig_pidx);
emit(" %s", g_tok.text); /* emit param name */
next_tok();
continue;
}
unread_tok(&nxt);
}
emit_tok();
next_tok();
@@ -1797,6 +1993,64 @@ static void parse_function(const char *ret_type, const char *name)
/* template function call: max(a, b) -> max_i(a, b) */
if (tpl_call_check(varcls, varname, nvars))
continue;
/* builtin ref param: a -> (*a) */
if (g_tok.type == T_IDENT && n_iref > 0) {
int i;
for (i = 0; i < n_iref; i++)
if (!strcmp(g_tok.text, iref[i])) break;
if (i < n_iref) {
emit(" (*%s)", g_tok.text);
next_tok();
continue;
}
}
/* function call with reference args: swap(x, y) -> swap(&x, &y) */
if (g_tok.type == T_IDENT) {
FnRef *fr = find_fnref(g_tok.text);
if (fr) {
Token nxt;
read_tok(&nxt);
if (nxt.type == T_PUNCT && !strcmp(nxt.text, "(")) {
unread_tok(&nxt); /* push '(' back — next_tok calls will consume properly */
int ai = 0, adepth = 0;
for (int ki = 0; ki < n_iref; ki++) fprintf(stderr, " iref[%d]=%s", ki, iref[ki]);
fprintf(stderr, "\n");
for (int ki = 0; ki < fr->narg; ki++) fprintf(stderr, " DBG fnref arg[%d]=%d", ki, fr->arg[ki]);
fprintf(stderr, "\n");
emit(" %s(", g_tok.text);
next_tok(); /* consume name */
next_tok(); /* consume '(' */
if (!(g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")"))) {
for (;;) {
if (g_tok.type == T_EOF) break;
if (g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")") && adepth == 0)
break;
if (g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, "(")) adepth++;
if (g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")")) adepth--;
if (g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ",") && adepth == 0) {
ai++;
emit(",");
next_tok();
continue;
}
if (fr_has_arg(fr, ai)) emit("&");
emit_tok();
next_tok();
}
}
emit(")");
if (g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")")) next_tok();
continue;
}
unread_tok(&nxt);
}
}
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) { depth++; emit(" {"); next_tok(); continue; }
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}")) {
if (depth > 0) { depth--; emit("}"); next_tok(); continue; }
@@ -1810,6 +2064,27 @@ static void parse_function(const char *ret_type, const char *name)
clsname[sizeof clsname - 1] = 0;
emit(" struct %s", clsname);
next_tok();
/* reference declaration: Cls& r = p -> struct Cls* r = &p */
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "&")) {
emit(" *");
next_tok();
if (g_tok.type == T_IDENT && nptrs < 64) {
strncpy(ptrcls[nptrs], clsname, 127);
strncpy(ptrname[nptrs], g_tok.text, 63);
nptrs++;
emit(" %s", g_tok.text);
next_tok();
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "=")) {
emit(" = &");
next_tok();
if (g_tok.type == T_IDENT) {
emit(" %s", g_tok.text);
next_tok();
}
}
}
continue;
}
/* pointer declaration: Cls* p = ... */
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "*")) {
emit(" *");
@@ -2046,21 +2321,33 @@ static void parse_function(const char *ret_type, const char *name)
token to reach first arg or ')' */
next_tok(); /* -> first arg or ) */
/* now g_tok is first arg or ')' */
if (!(g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")"))) {
emit(", ");
int adepth = 0;
while (!(g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")") && adepth == 0)) {
if (g_tok.type == T_EOF) break;
if (g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, "(")) adepth++;
if (g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")")) adepth--;
emit_tok();
next_tok();
}
}
if (!(g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")"))) {
emit(", ");
int adepth = 0;
int carg = 0;
while (!(g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")") && adepth == 0)) {
if (g_tok.type == T_EOF) break;
if (g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, "(")) adepth++;
if (g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")")) adepth--;
if (g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ",") && adepth == 0) {
carg++;
emit(",");
next_tok();
continue;
}
if (carg < 16) {
FnRef *fr = find_fnref(mname);
if (fr && fr_has_arg(fr, carg)) emit("&");
}
emit_tok();
next_tok();
}
}
emit(")");
if (g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")")) next_tok();
@@ -2134,6 +2421,78 @@ static void parse_function(const char *ret_type, const char *name)
}
}
}
/* pointer member call / virtual dispatch: p->method(args) */
if (g_tok.type == T_IDENT && nptrs > 0) {
int pi;
for (pi = 0; pi < nptrs; pi++) {
if (!strcmp(g_tok.text, ptrname[pi])) {
Token t1;
read_tok(&t1);
if (t1.type == T_PUNCT && !strcmp(t1.text, "->")) {
/* method call via -> */
Token t2;
read_tok(&t2);
if (t2.type == T_IDENT) {
Token t3;
read_tok(&t3);
if (t3.type == T_PUNCT &&
!strcmp(t3.text, "(")) {
char meth[128], mname[256];
ClassInfo *pci = find_class(ptrcls[pi]);
strncpy(meth, t2.text, sizeof meth - 1);
meth[sizeof meth - 1] = 0;
if (is_virtual(pci, meth)) {
emit(" %s->__vtbl->%s(%s",
g_tok.text, meth, g_tok.text);
} else {
snprintf(mname, sizeof mname, "%s_%s",
ptrcls[pi], meth);
emit(" %s(%s", mname, g_tok.text);
}
next_tok();
next_tok();
next_tok();
if (!(g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")"))) {
emit(", ");
int adepth = 0;
while (!(g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")") &&
adepth == 0)) {
if (g_tok.type == T_EOF) break;
if (g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, "(")) adepth++;
if (g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")")) adepth--;
emit_tok();
next_tok();
}
}
emit(")");
if (g_tok.type == T_PUNCT &&
!strcmp(g_tok.text, ")")) next_tok();
goto next_body_tok;
}
unread_tok(&t3);
}
unread_tok(&t2);
} else if (t1.type == T_PUNCT && !strcmp(t1.text, ".")) {
/* data member via ref: p.field -> p->field */
Token t2;
read_tok(&t2);
if (t2.type == T_IDENT) {
emit(" %s->%s", g_tok.text, t2.text);
next_tok(); /* consume '.' */
next_tok(); /* consume field name */
goto next_body_tok;
}
unread_tok(&t2);
}
unread_tok(&t1);
break;
}
}
}
/* class name used as type -> add 'struct' */
if (g_tok.type == T_IDENT && find_class(g_tok.text)) {
emit(" struct %s", g_tok.text);
@@ -2519,3 +2878,4 @@ int main(int argc, char **argv)
if (g_out != stdout) fclose(g_out);
return 0;
}