feat: C++ 阶段 2 - 命名空间支持

- namespace NAME { } 块扁平化: 跳过关键字, 内容按顶层解析
- 表达式/函数体中 ns::name -> name (非类名 + :: 跳过)
- 外部成员定义 ns::Class::method -> Class_method (跳命名空间限定)
- 支持嵌套命名空间 outer::inner::Class::method
- using namespace ns; / using ns::name; 跳过
- 修复: gather_decl 已消费首个 :: 的流位置不对称问题
这个提交包含在:
Paze AI
2026-08-16 18:06:01 +08:00
父节点 d4b6fdc1f3
当前提交 7d6ca9130c
修改 2 个文件,包含 82 行新增4 行删除
二进制
查看文件
二进制文件未显示。
+82 -4
查看文件
@@ -34,6 +34,7 @@ typedef struct {
static FILE *g_in, *g_out; 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) */
typedef struct ClassInfo { typedef struct ClassInfo {
char name[128]; char name[128];
@@ -544,6 +545,16 @@ static void parse_member_decl(const char *cls, const char *ret_type, const char
int prev_dot = 0; int prev_dot = 0;
while (bd > 0) { while (bd > 0) {
if (g_tok.type == T_EOF) break; if (g_tok.type == T_EOF) break;
/* namespace-qualified name: ns::name -> name */
if (g_tok.type == T_IDENT && !find_class(g_tok.text)) {
Token nxt;
read_tok(&nxt);
if (nxt.type == T_PUNCT && !strcmp(nxt.text, "::")) {
next_tok(); /* consume '::' */
continue;
}
unread_tok(&nxt);
}
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) { bd++; proto_emit(" {"); prev_dot = 0; next_tok(); continue; } if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) { bd++; proto_emit(" {"); prev_dot = 0; next_tok(); continue; }
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}")) { bd--; if (bd > 0) proto_emit("}"); next_tok(); continue; } if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}")) { bd--; if (bd > 0) proto_emit("}"); next_tok(); continue; }
if (g_tok.type == T_THIS) { proto_emit("this"); prev_dot = 0; next_tok(); continue; } if (g_tok.type == T_THIS) { proto_emit("this"); prev_dot = 0; next_tok(); continue; }
@@ -823,6 +834,26 @@ static void parse_member_definition(const char *ret_type)
int is_ctor = 0, is_dtor = 0; int is_ctor = 0, is_dtor = 0;
ClassInfo *ci; ClassInfo *ci;
/* skip namespace qualifiers: math::Point::draw -> Point::draw.
gather_decl already consumed the first '::', so the stream is at
the second segment; if the first segment is not a class it is a
namespace prefix that must be dropped. */
if (g_tok.type == T_IDENT && !find_class(g_tok.text)) {
/* skip the first namespace segment (its '::' already consumed) */
next_tok(); /* g_tok = second segment */
/* skip remaining 'ns ::' pairs */
while (g_tok.type == T_IDENT && !find_class(g_tok.text)) {
Token nxt;
read_tok(&nxt);
if (nxt.type == T_PUNCT && !strcmp(nxt.text, "::")) {
next_tok(); /* g_tok = segment after '::' */
continue;
}
unread_tok(&nxt);
break;
}
}
strncpy(cls, g_tok.text, sizeof cls - 1); strncpy(cls, g_tok.text, sizeof cls - 1);
cls[sizeof cls - 1] = 0; cls[sizeof cls - 1] = 0;
next_tok(); next_tok();
@@ -937,6 +968,16 @@ static void parse_member_definition(const char *ret_type)
int prev_dot = 0; int prev_dot = 0;
while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}") && depth == 0)) { while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}") && depth == 0)) {
if (g_tok.type == T_EOF) break; if (g_tok.type == T_EOF) break;
/* namespace-qualified name: ns::name -> name */
if (g_tok.type == T_IDENT && !find_class(g_tok.text)) {
Token nxt;
read_tok(&nxt);
if (nxt.type == T_PUNCT && !strcmp(nxt.text, "::")) {
next_tok(); /* consume '::' */
continue;
}
unread_tok(&nxt);
}
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) { depth++; emit(" {"); prev_dot = 0; next_tok(); continue; } if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) { depth++; emit(" {"); prev_dot = 0; next_tok(); continue; }
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}")) { if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}")) {
if (depth > 0) { depth--; emit("}"); next_tok(); continue; } if (depth > 0) { depth--; emit("}"); next_tok(); continue; }
@@ -1207,6 +1248,16 @@ static void parse_free_operator(const char *ret_type, const char *name)
while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}") && while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}") &&
bdepth == 0)) { bdepth == 0)) {
if (g_tok.type == T_EOF) break; if (g_tok.type == T_EOF) break;
/* namespace-qualified name: ns::name -> name */
if (g_tok.type == T_IDENT && !find_class(g_tok.text)) {
Token nxt;
read_tok(&nxt);
if (nxt.type == T_PUNCT && !strcmp(nxt.text, "::")) {
next_tok(); /* consume '::' */
continue;
}
unread_tok(&nxt);
}
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) { if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) {
bdepth++; bdepth++;
emit(" {"); emit(" {");
@@ -1344,6 +1395,16 @@ static void parse_function(const char *ret_type, const char *name)
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)) {
if (g_tok.type == T_EOF) break; if (g_tok.type == T_EOF) break;
/* namespace-qualified name: ns::name -> name */
if (g_tok.type == T_IDENT && !find_class(g_tok.text)) {
Token nxt;
read_tok(&nxt);
if (nxt.type == T_PUNCT && !strcmp(nxt.text, "::")) {
next_tok(); /* consume '::' */
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, "{")) { depth++; emit(" {"); next_tok(); continue; }
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}")) { if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}")) {
if (depth > 0) { depth--; emit("}"); next_tok(); continue; } if (depth > 0) { depth--; emit("}"); next_tok(); continue; }
@@ -1732,10 +1793,27 @@ static void parse_program(void)
continue; continue;
} }
if (g_tok.type == T_USING || g_tok.type == T_NAMESPACE || if (g_tok.type == T_NAMESPACE) {
g_tok.type == T_TEMPLATE || g_tok.type == T_INLINE || /* namespace NAME { ... } -> flattened: parse the body at
g_tok.type == T_CONSTEXPR || g_tok.type == T_FRIEND || top level; '}' (tracked by g_ns_open) closes it */
g_tok.type == T_VIRTUAL) { next_tok();
if (g_tok.type == T_IDENT) next_tok();
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) {
next_tok();
g_ns_open++;
}
continue;
}
/* '}' closes a namespace block */
if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}")) {
if (g_ns_open > 0) g_ns_open--;
next_tok();
continue;
}
if (g_tok.type == T_USING || g_tok.type == T_TEMPLATE ||
g_tok.type == T_INLINE || g_tok.type == T_CONSTEXPR ||
g_tok.type == T_FRIEND || g_tok.type == T_VIRTUAL) {
next_tok(); next_tok();
while (!(g_tok.type == T_EOF)) { while (!(g_tok.type == T_EOF)) {
if (g_tok.type == T_PUNCT && if (g_tok.type == T_PUNCT &&