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 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 &&
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户