diff --git a/bin/pcc-cpp.exe b/bin/pcc-cpp.exe index 8a1de53..2d6bade 100644 Binary files a/bin/pcc-cpp.exe and b/bin/pcc-cpp.exe differ diff --git a/tools/pcc-cpp.c b/tools/pcc-cpp.c index 640e4e1..7d22ec3 100644 --- a/tools/pcc-cpp.c +++ b/tools/pcc-cpp.c @@ -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; } +