From b112fa79e4af870054bfc5f7de5e6fe5889e02f6 Mon Sep 17 00:00:00 2001 From: Paze AI Date: Sun, 16 Aug 2026 18:19:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20C++=20=E9=98=B6=E6=AE=B5=202=20-=20?= =?UTF-8?q?=E8=99=9A=E5=87=BD=E6=95=B0/=E5=A4=9A=E6=80=81=20(vtable)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - virtual 成员: 类结构加 __vtbl 指针字段 - 每类发射 vtable typedef (owner) + 实例, 含实现原型保证声明顺序 - 构造器设置 __vtbl = &Cls_vtbl_inst (含派生类 __base.__vtbl) - 覆盖检测: virtual_impl 沿继承链找实现 - 指针变量: Cls* p = &d -> (struct Cls*)&d 转换 - p->virt() -> p->__vtbl->virt(p) 虚分发; 非虚 -> Cls_meth(p, ...) - 函数签名: 类参数 Cls* / Cls 加 struct 前缀并注册为指针/值变量 - parse_class 重构: 先收集字段, 后发射 struct (vtbl 字段依赖解析结果) --- bin/pcc-cpp.exe | Bin 80384 -> 85504 bytes tools/pcc-cpp.c | 358 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 327 insertions(+), 31 deletions(-) diff --git a/bin/pcc-cpp.exe b/bin/pcc-cpp.exe index 1dc73a78a3551a3cbe79d4ef375acc28e38296c3..8a1de5323f58c437da5deb11801a3c3c67520553 100644 GIT binary patch delta 38977 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 O2UZ?knT& diff --git a/tools/pcc-cpp.c b/tools/pcc-cpp.c index e5125dc..640e4e1 100644 --- a/tools/pcc-cpp.c +++ b/tools/pcc-cpp.c @@ -35,6 +35,7 @@ static FILE *g_in, *g_out; static Token g_tok; 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 */ /* ---------------- templates ---------------- */ @@ -55,11 +56,14 @@ static TplInst *g_tplinsts = NULL; static int g_capture = 0; /* capture emit() into g_cap */ static char g_cap[4096]; static int g_cap_len; -static int g_emit_sect = 0; /* 0 = decl buffer, 1 = function buffer */ +static int g_emit_sect = 0; /* 0 = decl buffer, 1 = fn buffer, + 2 = class-fields buffer */ static char g_outbuf[8 * 1024 * 1024]; /* declarations (classes, globals) */ static int g_out_len; static char g_fn_buf[8 * 1024 * 1024]; /* top-level function bodies */ static int g_fn_len; +static char g_fields[16384]; /* class data-member fields (per class) */ +static int g_fields_len; static char g_tpl_defs[16384]; /* instantiated definitions (flushed at end) */ static int g_tpl_defs_len; @@ -70,6 +74,9 @@ typedef struct ClassInfo { int has_dtor; char members[64][64]; /* member names (data + functions) */ int n_members; + char virt[16][64]; /* virtual method names (own) */ + char virt_ret[16][64]; /* virtual method return types */ + int n_virt; struct ClassInfo *next; } ClassInfo; static ClassInfo *g_classes = NULL; @@ -167,6 +174,59 @@ static void add_class(const char *name) g_classes = c; } +/* is 'm' a virtual method of this class (own or inherited)? */ +static int is_virtual(ClassInfo *ci, const char *m) +{ + int i; + if (!ci) return 0; + for (i = 0; i < ci->n_virt; i++) + if (!strcmp(ci->virt[i], m)) return 1; + if (ci->base[0]) { + ClassInfo *b = find_class(ci->base); + if (b) return is_virtual(b, m); + } + return 0; +} + +/* does this class need a vtable pointer (own or inherited virtuals)? */ +static int class_has_vtbl(ClassInfo *ci) +{ + if (!ci) return 0; + if (ci->n_virt > 0) return 1; + if (ci->base[0]) { + ClassInfo *b = find_class(ci->base); + if (b) return class_has_vtbl(b); + } + return 0; +} + +/* topmost class whose vtable type is used (the one introducing virtuals) */ +static const char *vtbl_owner(ClassInfo *ci) +{ + if (!ci) return ""; + if (ci->base[0]) { + ClassInfo *b = find_class(ci->base); + if (b && class_has_vtbl(b)) return vtbl_owner(b); + } + return ci->name; +} + +/* which function implements virtual 'm' for class 'ci' */ +static void virtual_impl(ClassInfo *ci, const char *m, char *out, int outsz) +{ + int i; + for (i = 0; i < ci->n_members; i++) + if (!strcmp(ci->members[i], m)) { + snprintf(out, outsz, "%s_%s", ci->name, m); + return; + } + if (ci->base[0]) { + ClassInfo *b = find_class(ci->base); + if (b) { virtual_impl(b, m, out, outsz); return; } + } + snprintf(out, outsz, "%s_%s", ci->name, m); +} + /* ---------------- tokenizer ---------------- */ static Token g_peek; /* one-token lookahead buffer */ @@ -388,6 +448,12 @@ static void emit(const char *fmt, ...) n = vsnprintf(g_cap + g_cap_len, sizeof g_cap - g_cap_len, fmt, ap); if (n > 0) g_cap_len += n; if (g_cap_len >= (int)sizeof g_cap - 1) g_cap_len = sizeof g_cap - 1; + } else if (g_emit_sect == 2) { + if (g_fields_len < (int)sizeof g_fields - 1) { + n = vsnprintf(g_fields + g_fields_len, + sizeof g_fields - g_fields_len, fmt, ap); + if (n > 0) g_fields_len += n; + } } else if (g_emit_sect == 1) { if (g_fn_len < (int)sizeof g_fn_buf - 1) { n = vsnprintf(g_fn_buf + g_fn_len, @@ -457,7 +523,8 @@ 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) +static void parse_member_decl(const char *cls, const char *ret_type, + const char *mname_in, int is_virtual) { char name[256]; char mname[256]; @@ -475,6 +542,20 @@ static void parse_member_decl(const char *cls, const char *ret_type, const char if (is_ctor) ci->has_ctor = 1; 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) { + char rtb[64]; + int rl; + snprintf(rtb, sizeof rtb, "%s", ret_type); + rl = (int)strlen(rtb); + while (rl > 0 && (rtb[rl-1] == ' ' || rtb[rl-1] == '\t')) + rtb[--rl] = 0; + strncpy(ci->virt[ci->n_virt], name, 63); + ci->virt[ci->n_virt][63] = 0; + strncpy(ci->virt_ret[ci->n_virt], rtb[0] ? rtb : "int", 63); + ci->virt_ret[ci->n_virt][63] = 0; + ci->n_virt++; + } } /* only advance if g_tok is the name (not already consumed) */ if (!mname_in || !mname_in[0]) @@ -583,6 +664,12 @@ static void parse_member_decl(const char *cls, const char *ret_type, const char if (bci && bci->has_ctor) proto_emit(" %s_ctor(&this->__base);", mci->base); } + /* ctor: set the vtable pointer */ + if (is_ctor && class_has_vtbl(mci)) { + if (mci->base[0]) + proto_emit(" this->__base.__vtbl = &%s_vtbl_inst;", cls); + proto_emit(" this->__vtbl = &%s_vtbl_inst;", cls); + } { int bd = 1; int prev_dot = 0; @@ -771,6 +858,21 @@ static void parse_member_decl(const char *cls, const char *ret_type, const char } } +/* emit a prototype for a mangled member function "Cls_method" */ +static void emit_impl_proto(const char *mname, const char *ret) +{ + const char *us = strrchr(mname, '_'); + if (us) { + int n = (int)(us - mname); + if (n > 0 && n < 95) { + char cls[96]; + memcpy(cls, mname, n); + cls[n] = 0; + emit(" %s %s(struct %s *this);\n", ret, mname, cls); + } + } +} + static void parse_class(void) { char clsname[128]; @@ -799,34 +901,43 @@ static void parse_class(void) ci = find_class(clsname); if (base[0]) strncpy(ci->base, base, sizeof ci->base - 1); - emit("struct %s {\n", clsname); - if (base[0]) - emit(" struct %s __base;\n", base); - if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) next_tok(); - else { emit("};\n\n"); return; } + else { emit("struct %s;\n\n", clsname); return; } - while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}"))) { - if (g_tok.type == T_EOF) break; - if (g_tok.type == T_PUBLIC || g_tok.type == T_PRIVATE || - g_tok.type == T_PROTECTED) { - next_tok(); - if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ":")) next_tok(); - continue; - } - if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ";")) { next_tok(); continue; } - { - char tybuf[512] = ""; - char tmp[256]; - /* use gather_decl: type + name (stops at '(' or ';' or '}') */ - gather_decl(tybuf, sizeof tybuf, tmp, sizeof tmp); - if (tmp[0] && g_tok.type == T_PUNCT && !strcmp(g_tok.text, "(")) { - /* member function decl */ - parse_member_decl(clsname, tybuf[0] ? tybuf : "int", tmp); - } else if (tmp[0]) { - /* data member(s): type name [more] ; */ - ClassInfo *cci = find_class(clsname); - emit(" %s %s", tybuf, tmp); + /* phase 1: parse the class body; data members go to the fields + buffer (g_emit_sect=2), member functions go to g_protos. The + struct is emitted afterwards once virtuals are known. */ + { + int was_sect = g_emit_sect; + g_emit_sect = 2; + g_fields_len = 0; + while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}"))) { + if (g_tok.type == T_EOF) break; + if (g_tok.type == T_VIRTUAL) { + g_virt_pending = 1; + next_tok(); + continue; + } + if (g_tok.type == T_PUBLIC || g_tok.type == T_PRIVATE || + g_tok.type == T_PROTECTED) { + next_tok(); + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ":")) next_tok(); + continue; + } + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ";")) { next_tok(); continue; } + { + char tybuf[512] = ""; + char tmp[256]; + /* use gather_decl: type + name (stops at '(' or ';' or '}') */ + gather_decl(tybuf, sizeof tybuf, tmp, sizeof tmp); + if (tmp[0] && g_tok.type == T_PUNCT && !strcmp(g_tok.text, "(")) { + /* member function decl */ + parse_member_decl(clsname, tybuf[0] ? tybuf : "int", tmp, + g_virt_pending); + } else if (tmp[0]) { + /* data member(s): type name [more] ; */ + ClassInfo *cci = find_class(clsname); + emit(" %s %s", tybuf, tmp); add_member(cci, tmp); while (!(g_tok.type == T_PUNCT && (!strcmp(g_tok.text, ";") || !strcmp(g_tok.text, "}")))) { @@ -861,10 +972,48 @@ static void parse_class(void) if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ";")) next_tok(); } } + g_virt_pending = 0; + } + g_emit_sect = was_sect; } if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}")) next_tok(); if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ";")) next_tok(); + /* phase 2: emit the struct (vtbl field known once body is parsed) */ + emit("struct %s {\n", clsname); + if (base[0]) + emit(" struct %s __base;\n", base); + if (class_has_vtbl(ci)) + emit(" struct %s_vtbl *__vtbl;\n", vtbl_owner(ci)); + emit("%s", g_fields); emit("};\n"); + /* vtable: typedef once for the owner, instance per class */ + if (ci->n_virt > 0) { + int i; + emit("typedef struct %s_vtbl {\n", ci->name); + for (i = 0; i < ci->n_virt; i++) + emit(" %s (*%s)(struct %s *this);\n", + ci->virt_ret[i], ci->virt[i], ci->name); + emit("} %s_vtbl;\n", ci->name); + } + if (class_has_vtbl(ci)) { + int i; + const char *owner = vtbl_owner(ci); + ClassInfo *oci = find_class(owner); + /* prototypes for the implementations so the initializer is valid */ + for (i = 0; i < oci->n_virt; i++) { + char impl[64]; + virtual_impl(ci, oci->virt[i], impl, sizeof impl); + emit_impl_proto(impl, oci->virt_ret[i]); + } + emit("static %s_vtbl %s_vtbl_inst = {\n", owner, clsname); + for (i = 0; i < oci->n_virt; i++) { + char impl[64]; + virtual_impl(ci, oci->virt[i], impl, sizeof impl); + emit(" (%s(*)(struct %s*))%s,\n", + oci->virt_ret[i], owner, impl); + } + emit("};\n"); + } /* emit member function prototypes after the struct */ if (g_proto_len) { emit("%s", g_protos); @@ -1008,6 +1157,12 @@ static void parse_member_definition(const char *ret_type) if (bci && bci->has_ctor) emit(" %s_ctor(&this->__base);\n", ci->base); } + /* ctor: set the vtable pointer */ + if (is_ctor && class_has_vtbl(ci)) { + if (ci->base[0]) + emit(" this->__base.__vtbl = &%s_vtbl_inst;\n", cls); + emit(" this->__vtbl = &%s_vtbl_inst;\n", cls); + } { int depth = 0; ClassInfo *mci = find_class(cls); @@ -1545,6 +1700,13 @@ static int tpl_call_check(char varcls[][128], char varname[][64], int nvars) static void parse_function(const char *ret_type, const char *name) { + char varcls[64][128]; /* variable name -> class name */ + char varname[64][64]; + int nvars = 0; + char ptrcls[64][128]; /* pointer variable name -> class name */ + char ptrname[64][64]; + int nptrs = 0; + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "::")) { /* member function: class is 'name', method follows */ g_tok.type = T_IDENT; @@ -1561,17 +1723,63 @@ static void parse_function(const char *ret_type, const char *name) return; } + /* class return type needs 'struct' prefix */ + { + char rtbuf[160]; + int rl; + snprintf(rtbuf, sizeof rtbuf, "%s", ret_type); + rl = (int)strlen(rtbuf); + while (rl > 0 && (rtbuf[rl-1] == ' ' || rtbuf[rl-1] == '\t')) + rtbuf[--rl] = 0; + if (find_class(rtbuf)) { + static char rtbuf2[192]; + snprintf(rtbuf2, sizeof rtbuf2, "struct %s", rtbuf); + ret_type = rtbuf2; + } + } + emit("%s %s", ret_type, 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_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) */ + emit(" struct %s*", clsname); + next_tok(); /* g_tok = param name */ + 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(); + } + continue; + } + if (nxt.type == T_IDENT) { + /* Cls name -> struct Cls name (value param) */ + emit(" struct %s %s", clsname, nxt.text); + if (nvars < 64) { + strncpy(varcls[nvars], clsname, 127); + strncpy(varname[nvars], nxt.text, 63); + nvars++; + } + next_tok(); + continue; + } + emit(" struct %s", clsname); + unread_tok(&nxt); + } emit_tok(); next_tok(); } if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) { int depth = 0; - char varcls[64][128]; /* variable name -> class name */ - char varname[64][64]; - int nvars = 0; emit(" {"); next_tok(); while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}") && depth == 0)) { @@ -1602,6 +1810,35 @@ static void parse_function(const char *ret_type, const char *name) clsname[sizeof clsname - 1] = 0; emit(" struct %s", clsname); next_tok(); + /* pointer declaration: Cls* 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(); + /* init: = &var -> = (struct Cls *)&var */ + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "=")) { + Token amp, vv; + read_tok(&); + if (amp.type == T_PUNCT && !strcmp(amp.text, "&")) { + read_tok(&vv); + if (vv.type == T_IDENT) { + emit(" = (struct %s *)&%s", + clsname, vv.text); + next_tok(); + continue; + } + unread_tok(&vv); + } + unread_tok(&); + } + } + continue; + } /* next token(s): var [= ...] */ if (g_tok.type == T_IDENT && nvars < 64) { char vname[64]; @@ -1838,6 +2075,65 @@ 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, 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]; + char 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)) { + /* dispatch through the vtable */ + 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(); /* -> 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(); + } + } + emit(")"); + if (g_tok.type == T_PUNCT && + !strcmp(g_tok.text, ")")) next_tok(); + goto next_body_tok; + } + unread_tok(&t3); + } + 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);