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 已消费首个 :: 的流位置不对称问题
这个提交包含在:
二进制
二进制文件未显示。
+82
-4
@@ -34,6 +34,7 @@ typedef struct {
|
||||
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) */
|
||||
|
||||
typedef struct ClassInfo {
|
||||
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;
|
||||
while (bd > 0) {
|
||||
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--; if (bd > 0) proto_emit("}"); 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;
|
||||
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);
|
||||
cls[sizeof cls - 1] = 0;
|
||||
next_tok();
|
||||
@@ -937,6 +968,16 @@ static void parse_member_definition(const char *ret_type)
|
||||
int prev_dot = 0;
|
||||
while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}") && depth == 0)) {
|
||||
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, "}")) {
|
||||
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, "}") &&
|
||||
bdepth == 0)) {
|
||||
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, "{")) {
|
||||
bdepth++;
|
||||
emit(" {");
|
||||
@@ -1344,6 +1395,16 @@ static void parse_function(const char *ret_type, const char *name)
|
||||
next_tok();
|
||||
while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}") && depth == 0)) {
|
||||
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, "}")) {
|
||||
if (depth > 0) { depth--; emit("}"); next_tok(); continue; }
|
||||
@@ -1732,10 +1793,27 @@ static void parse_program(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (g_tok.type == T_USING || g_tok.type == T_NAMESPACE ||
|
||||
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) {
|
||||
if (g_tok.type == T_NAMESPACE) {
|
||||
/* namespace NAME { ... } -> flattened: parse the body at
|
||||
top level; '}' (tracked by g_ns_open) closes it */
|
||||
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();
|
||||
while (!(g_tok.type == T_EOF)) {
|
||||
if (g_tok.type == T_PUNCT &&
|
||||
|
||||
在新工单中引用
屏蔽一个用户