feat: C++ 阶段 2 - 虚函数/多态 (vtable)
- 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 字段依赖解析结果)
这个提交包含在:
二进制
二进制文件未显示。
+327
-31
@@ -35,6 +35,7 @@ static FILE *g_in, *g_out;
|
|||||||
static Token g_tok;
|
static Token g_tok;
|
||||||
static int g_line = 1;
|
static int g_line = 1;
|
||||||
static int g_ns_open = 0; /* namespace block depth (flattened) */
|
static int g_ns_open = 0; /* namespace block depth (flattened) */
|
||||||
|
static int g_virt_pending = 0; /* next member decl is virtual */
|
||||||
|
|
||||||
/* ---------------- templates ---------------- */
|
/* ---------------- templates ---------------- */
|
||||||
|
|
||||||
@@ -55,11 +56,14 @@ static TplInst *g_tplinsts = NULL;
|
|||||||
static int g_capture = 0; /* capture emit() into g_cap */
|
static int g_capture = 0; /* capture emit() into g_cap */
|
||||||
static char g_cap[4096];
|
static char g_cap[4096];
|
||||||
static int g_cap_len;
|
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 char g_outbuf[8 * 1024 * 1024]; /* declarations (classes, globals) */
|
||||||
static int g_out_len;
|
static int g_out_len;
|
||||||
static char g_fn_buf[8 * 1024 * 1024]; /* top-level function bodies */
|
static char g_fn_buf[8 * 1024 * 1024]; /* top-level function bodies */
|
||||||
static int g_fn_len;
|
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 char g_tpl_defs[16384]; /* instantiated definitions (flushed at end) */
|
||||||
static int g_tpl_defs_len;
|
static int g_tpl_defs_len;
|
||||||
|
|
||||||
@@ -70,6 +74,9 @@ typedef struct ClassInfo {
|
|||||||
int has_dtor;
|
int has_dtor;
|
||||||
char members[64][64]; /* member names (data + functions) */
|
char members[64][64]; /* member names (data + functions) */
|
||||||
int n_members;
|
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;
|
struct ClassInfo *next;
|
||||||
} ClassInfo;
|
} ClassInfo;
|
||||||
static ClassInfo *g_classes = NULL;
|
static ClassInfo *g_classes = NULL;
|
||||||
@@ -167,6 +174,59 @@ static void add_class(const char *name)
|
|||||||
g_classes = c;
|
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 ---------------- */
|
/* ---------------- tokenizer ---------------- */
|
||||||
|
|
||||||
static Token g_peek; /* one-token lookahead buffer */
|
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);
|
n = vsnprintf(g_cap + g_cap_len, sizeof g_cap - g_cap_len, fmt, ap);
|
||||||
if (n > 0) g_cap_len += n;
|
if (n > 0) g_cap_len += n;
|
||||||
if (g_cap_len >= (int)sizeof g_cap - 1) g_cap_len = sizeof g_cap - 1;
|
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) {
|
} else if (g_emit_sect == 1) {
|
||||||
if (g_fn_len < (int)sizeof g_fn_buf - 1) {
|
if (g_fn_len < (int)sizeof g_fn_buf - 1) {
|
||||||
n = vsnprintf(g_fn_buf + g_fn_len,
|
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 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 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 name[256];
|
||||||
char mname[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_ctor) ci->has_ctor = 1;
|
||||||
if (is_dtor) ci->has_dtor = 1;
|
if (is_dtor) ci->has_dtor = 1;
|
||||||
else add_member(ci, name);
|
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) */
|
/* only advance if g_tok is the name (not already consumed) */
|
||||||
if (!mname_in || !mname_in[0])
|
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)
|
if (bci && bci->has_ctor)
|
||||||
proto_emit(" %s_ctor(&this->__base);", mci->base);
|
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 bd = 1;
|
||||||
int prev_dot = 0;
|
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)
|
static void parse_class(void)
|
||||||
{
|
{
|
||||||
char clsname[128];
|
char clsname[128];
|
||||||
@@ -799,34 +901,43 @@ static void parse_class(void)
|
|||||||
ci = find_class(clsname);
|
ci = find_class(clsname);
|
||||||
if (base[0]) strncpy(ci->base, base, sizeof ci->base - 1);
|
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();
|
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, "}"))) {
|
/* phase 1: parse the class body; data members go to the fields
|
||||||
if (g_tok.type == T_EOF) break;
|
buffer (g_emit_sect=2), member functions go to g_protos. The
|
||||||
if (g_tok.type == T_PUBLIC || g_tok.type == T_PRIVATE ||
|
struct is emitted afterwards once virtuals are known. */
|
||||||
g_tok.type == T_PROTECTED) {
|
{
|
||||||
next_tok();
|
int was_sect = g_emit_sect;
|
||||||
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ":")) next_tok();
|
g_emit_sect = 2;
|
||||||
continue;
|
g_fields_len = 0;
|
||||||
}
|
while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}"))) {
|
||||||
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ";")) { next_tok(); continue; }
|
if (g_tok.type == T_EOF) break;
|
||||||
{
|
if (g_tok.type == T_VIRTUAL) {
|
||||||
char tybuf[512] = "";
|
g_virt_pending = 1;
|
||||||
char tmp[256];
|
next_tok();
|
||||||
/* use gather_decl: type + name (stops at '(' or ';' or '}') */
|
continue;
|
||||||
gather_decl(tybuf, sizeof tybuf, tmp, sizeof tmp);
|
}
|
||||||
if (tmp[0] && g_tok.type == T_PUNCT && !strcmp(g_tok.text, "(")) {
|
if (g_tok.type == T_PUBLIC || g_tok.type == T_PRIVATE ||
|
||||||
/* member function decl */
|
g_tok.type == T_PROTECTED) {
|
||||||
parse_member_decl(clsname, tybuf[0] ? tybuf : "int", tmp);
|
next_tok();
|
||||||
} else if (tmp[0]) {
|
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ":")) next_tok();
|
||||||
/* data member(s): type name [more] ; */
|
continue;
|
||||||
ClassInfo *cci = find_class(clsname);
|
}
|
||||||
emit(" %s %s", tybuf, tmp);
|
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);
|
add_member(cci, tmp);
|
||||||
while (!(g_tok.type == T_PUNCT &&
|
while (!(g_tok.type == T_PUNCT &&
|
||||||
(!strcmp(g_tok.text, ";") || !strcmp(g_tok.text, "}")))) {
|
(!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();
|
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();
|
||||||
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");
|
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 */
|
/* emit member function prototypes after the struct */
|
||||||
if (g_proto_len) {
|
if (g_proto_len) {
|
||||||
emit("%s", g_protos);
|
emit("%s", g_protos);
|
||||||
@@ -1008,6 +1157,12 @@ static void parse_member_definition(const char *ret_type)
|
|||||||
if (bci && bci->has_ctor)
|
if (bci && bci->has_ctor)
|
||||||
emit(" %s_ctor(&this->__base);\n", ci->base);
|
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;
|
int depth = 0;
|
||||||
ClassInfo *mci = find_class(cls);
|
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)
|
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, "::")) {
|
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "::")) {
|
||||||
/* member function: class is 'name', method follows */
|
/* member function: class is 'name', method follows */
|
||||||
g_tok.type = T_IDENT;
|
g_tok.type = T_IDENT;
|
||||||
@@ -1561,17 +1723,63 @@ static void parse_function(const char *ret_type, const char *name)
|
|||||||
return;
|
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);
|
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, "{"))) {
|
while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{"))) {
|
||||||
if (g_tok.type == T_EOF) break;
|
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();
|
emit_tok();
|
||||||
next_tok();
|
next_tok();
|
||||||
}
|
}
|
||||||
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) {
|
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) {
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
char varcls[64][128]; /* variable name -> class name */
|
|
||||||
char varname[64][64];
|
|
||||||
int nvars = 0;
|
|
||||||
emit(" {");
|
emit(" {");
|
||||||
next_tok();
|
next_tok();
|
||||||
while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}") && depth == 0)) {
|
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;
|
clsname[sizeof clsname - 1] = 0;
|
||||||
emit(" struct %s", clsname);
|
emit(" struct %s", clsname);
|
||||||
next_tok();
|
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 [= ...] */
|
/* next token(s): var [= ...] */
|
||||||
if (g_tok.type == T_IDENT && nvars < 64) {
|
if (g_tok.type == T_IDENT && nvars < 64) {
|
||||||
char vname[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' */
|
/* class name used as type -> add 'struct' */
|
||||||
if (g_tok.type == T_IDENT && find_class(g_tok.text)) {
|
if (g_tok.type == T_IDENT && find_class(g_tok.text)) {
|
||||||
emit(" struct %s", g_tok.text);
|
emit(" struct %s", g_tok.text);
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户