diff --git a/.gitignore b/.gitignore index 0d13d72..e977286 100644 --- a/.gitignore +++ b/.gitignore @@ -92,3 +92,5 @@ bin/* !bin/pcc-asm.exe !bin/pcc-get.exe !bin/pcc-impdef.exe +!bin/pcc-cpp.exe + diff --git a/bin/pcc-cpp.exe b/bin/pcc-cpp.exe new file mode 100644 index 0000000..fb032e9 Binary files /dev/null and b/bin/pcc-cpp.exe differ diff --git a/bin/pcc.exe b/bin/pcc.exe index aac99cf..716fe08 100644 Binary files a/bin/pcc.exe and b/bin/pcc.exe differ diff --git a/docs/cpp-plan.md b/docs/cpp-plan.md new file mode 100644 index 0000000..5d69c3b --- /dev/null +++ b/docs/cpp-plan.md @@ -0,0 +1,86 @@ +# PCC C++ 阶段 1 实现计划(修订版) + +## 架构决策:C++ 前端转换器(pcc-cpp) + +**不在核心解析器中实现 C++**(风险高、工程大),而是创建一个 +**独立的 C++ → C 转换器**,把 C++ 代码翻译成等效 C 代码, +再交给现有 pcc 编译。这是 cfront/Comeau 的成熟做法。 + +## 转换规则 + +### 1. class 声明 +```cpp +class Point { +public: + int x, y; + int sum(); +}; +``` +→ +```c +struct Point { int x, y; }; +int Point_sum(struct Point *this); +``` + +### 2. 成员函数定义 +```cpp +int Point::sum() { return x + y; } +``` +→ +```c +int Point_sum(struct Point *this) { return this->x + this->y; } +``` + +### 3. 成员调用 +```cpp +Point p; +p.sum(); // → Point_sum(&p) +``` +`p.x = 5` 直接用 struct 字段访问(无需转换) + +### 4. 构造函数 +```cpp +Point::Point(int a, int b) { x = a; y = b; } +``` +→ +```c +void Point_ctor(struct Point *this, int a, int b) { this->x = a; this->y = b; } +``` +局部对象声明时自动插入构造调用 + +### 5. 析构函数 +```cpp +Point::~Point() { } +``` +→ +```c +void Point_dtor(struct Point *this) { } +``` + +### 6. 简单继承 +```cpp +class Shape : public Point { }; +``` +→ +```c +struct Shape { struct Point __base; }; +``` + +## 实现形式 +- **pcc-cpp.c**:独立转换器,读取 .cpp,输出 .c +- pcc 检测 .cpp 文件时自动调用(内部集成) +- 用 pcc 自身编译(自举) + +## 测试用例 +```cpp +class Point { +public: + int x, y; + Point(int a, int b) { x = a; y = b; } + int sum() { return x + y; } +}; +int main() { + Point p(3, 4); + return p.sum() - 7; +} +``` diff --git a/libpcc.c b/libpcc.c index 9109d41..5525a5e 100644 --- a/libpcc.c +++ b/libpcc.c @@ -822,6 +822,7 @@ static int pcc_compile(PCCState *s1, int filetype, const char *str, int fd) } preprocess_start(s1, filetype); + s1->cpp_mode = !!(filetype & AFF_TYPE_CPP); /* C++ mode */ tccgen_init(s1); if (s1->output_type == PCC_OUTPUT_PREPROCESS) { @@ -1196,8 +1197,10 @@ static int guess_filetype(const char *filename) if (1) { /* use a file extension to detect a filetype */ const char *ext = pcc_fileextension(filename); + if (ext[0]) { ext++; + if (!strcmp(ext, "S")) filetype = AFF_TYPE_ASMPP; else if (!strcmp(ext, "s")) @@ -1206,6 +1209,11 @@ static int guess_filetype(const char *filename) || !PATHCMP(ext, "h") || !PATHCMP(ext, "i")) filetype = AFF_TYPE_C; + else if (!PATHCMP(ext, "cpp") + || !PATHCMP(ext, "cc") + || !PATHCMP(ext, "cxx") + || !PATHCMP(ext, "c++")) + filetype = AFF_TYPE_C | AFF_TYPE_CPP; else filetype |= AFF_TYPE_BIN; } else { @@ -1244,12 +1252,86 @@ ST_FUNC int pcc_add_file_internal(PCCState *s1, const char *filename, int flags) if (flags & AFF_TYPE_BIN) return pcc_add_binary(s1, flags, filename, fd); + /* C++ source: transpile to C via pcc-cpp, then compile the result */ + if (flags & AFF_TYPE_CPP) { + + char cmdbuf[2048]; + char tmpc[1024]; + char pcccpp[1024]; + const char *exedir; + /* find pcc-cpp next to pcc.exe (or in PATH) */ + pcccpp[0] = 0; +#ifdef _WIN32 + { + char selfpath[1024]; + char *slash; + GetModuleFileNameA(NULL, selfpath, sizeof selfpath); + slash = strrchr(selfpath, '\\'); + if (slash) { + *slash = 0; + snprintf(pcccpp, sizeof pcccpp, "%s\\pcc-cpp.exe", selfpath); + if (GetFileAttributesA(pcccpp) == INVALID_FILE_ATTRIBUTES) + strcpy(pcccpp, "pcc-cpp"); + } else + strcpy(pcccpp, "pcc-cpp"); + } +#else + strcpy(pcccpp, "pcc-cpp"); +#endif + snprintf(tmpc, sizeof tmpc, "%s.pcc.c", filename); +#ifdef _WIN32 + snprintf(cmdbuf, sizeof cmdbuf, "\"%s\" \"%s\" -o \"%s\"", + pcccpp, filename, tmpc); + /* use CreateProcess so quoted paths with spaces work */ + { + STARTUPINFOA si; + PROCESS_INFORMATION pi; + char *cmdline = (char*)pcc_malloc(strlen(cmdbuf) + 1); + if (!cmdline) { close(fd); return -1; } + strcpy(cmdline, cmdbuf); + memset(&si, 0, sizeof si); + si.cb = sizeof si; + if (!CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, + NULL, &si, &pi)) { + pcc_error_noabort("cannot run pcc-cpp (%lu)", (unsigned long)GetLastError()); + pcc_free(cmdline); + close(fd); + return -1; + } + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + pcc_free(cmdline); + } +#else + snprintf(cmdbuf, sizeof cmdbuf, "%s \"%s\" -o \"%s\"", + pcccpp, filename, tmpc); + if (system(cmdbuf) != 0) { + pcc_error_noabort("pcc-cpp failed on '%s'", filename); + close(fd); + return -1; + } +#endif + close(fd); + /* compile the generated C file */ + fd = _pcc_open(s1, tmpc); + if (fd < 0) { + pcc_error_noabort("cannot open generated file '%s'", tmpc); + return -1; + } + flags &= ~AFF_TYPE_CPP; + flags |= AFF_TYPE_C; + dynarray_add(&s1->target_deps, &s1->nb_target_deps, pcc_strdup(tmpc)); + return pcc_compile(s1, flags, tmpc, fd); + } + dynarray_add(&s1->target_deps, &s1->nb_target_deps, pcc_strdup(filename)); return pcc_compile(s1, flags, filename, fd); } LIBPCCAPI int pcc_add_file(PCCState *s, const char *filename) { + return pcc_add_file_internal(s, filename, s->filetype | AFF_PRINT_ERROR); } diff --git a/pcc.h b/pcc.h index 7fc9b13..1d6d5a7 100644 --- a/pcc.h +++ b/pcc.h @@ -790,6 +790,8 @@ struct PCCState { unsigned char gnu_ext; /* use PazeCC extensions */ unsigned char pcc_ext; + /* C++ mode (compile .cpp files with C++ extensions) */ + unsigned char cpp_mode; unsigned char dflag; /* -dX value */ unsigned char Pflag; /* -P switch (LINE_MACRO_OUTPUT_FORMAT) */ @@ -1285,6 +1287,7 @@ ST_FUNC int pcc_add_file_internal(PCCState *s1, const char *filename, int flags) #define AFF_TYPE_ASM 2 #define AFF_TYPE_ASMPP 4 #define AFF_TYPE_LIB 8 +#define AFF_TYPE_CPP 0x100 /* C++ source file */ #define AFF_TYPE_MASK (7 | AFF_TYPE_BIN) /* values from pcc_object_type(...) */ #define AFF_BINTYPE_REL 1 diff --git a/pccpp.c b/pccpp.c index f0ffefb..7f785e8 100644 --- a/pccpp.c +++ b/pccpp.c @@ -1702,7 +1702,8 @@ static int pragma_parse(PCCState *s1) #pragma pack(pop) // restore previous */ next(); skip('('); - if (tok == TOK_ASM_pop) { + if (tok == TOK_ASM_pop || (tok >= TOK_IDENT && + !strcmp(get_tok_str(tok, NULL), "pop"))) { next(); if (s1->pack_stack_ptr <= s1->pack_stack) { stk_error: @@ -1712,7 +1713,8 @@ static int pragma_parse(PCCState *s1) } else { int val = 0; if (tok != ')') { - if (tok == TOK_ASM_push) { + if (tok == TOK_ASM_push || (tok >= TOK_IDENT && + !strcmp(get_tok_str(tok, NULL), "push"))) { next(); if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1) goto stk_error; diff --git a/pcctok.h b/pcctok.h index 86b76c3..89bc265 100644 --- a/pcctok.h +++ b/pcctok.h @@ -369,6 +369,22 @@ DEF(TOK_longjmp, "longjmp") #endif +/* ------------ C++ keywords ------------ */ + DEF(TOK_CLASS, "class") + DEF(TOK_CPP_PUBLIC, "public") + DEF(TOK_CPP_PRIVATE, "private") + DEF(TOK_CPP_PROTECTED, "protected") + DEF(TOK_THIS, "this") + DEF(TOK_CPP_NEW, "new") + DEF(TOK_CPP_DELETE, "delete") + DEF(TOK_CPP_NAMESPACE, "namespace") + DEF(TOK_CPP_USING, "using") + DEF(TOK_CPP_VIRTUAL, "virtual") + DEF(TOK_CPP_INLINE, "inline") + DEF(TOK_CPP_FRIEND, "friend") + DEF(TOK_CPP_TEMPLATE, "template") + DEF(TOK_CPP_CONSTEXPR, "constexpr") + /*********************************************************************/ /* Tiny Assembler */ diff --git a/tools/pcc-cpp.c b/tools/pcc-cpp.c new file mode 100644 index 0000000..c9fd1b0 --- /dev/null +++ b/tools/pcc-cpp.c @@ -0,0 +1,1037 @@ +/* + * pcc-cpp.c - C++ to C transpiler for PCC (stage 1) + * + * Converts a C++ subset (class, member functions, ctors/dtors, + * simple inheritance) into equivalent C code, which is then + * compiled by pcc. + * + * License: MIT + */ + +#include +#include +#include +#include +#include + +/* ---------------- tokenizer ---------------- */ + +typedef enum { + T_EOF, T_IDENT, T_NUMBER, T_STRING, T_CHAR, + T_CLASS, T_STRUCT, T_PUBLIC, T_PRIVATE, T_PROTECTED, + T_THIS, T_NEW, T_DELETE, T_NAMESPACE, T_USING, T_VIRTUAL, + T_INLINE, T_FRIEND, T_TEMPLATE, T_CONSTEXPR, + T_PREPROC, T_PUNCT +} TokType; + +typedef struct { + TokType type; + char text[256]; + long ival; +} Token; + +static FILE *g_in, *g_out; +static Token g_tok; +static int g_line = 1; + +typedef struct ClassInfo { + char name[128]; + char base[128]; + int has_ctor; + int has_dtor; + char members[64][64]; /* member names (data + functions) */ + int n_members; + struct ClassInfo *next; +} ClassInfo; +static ClassInfo *g_classes = NULL; + +static ClassInfo *find_class(const char *name) +{ + ClassInfo *c; + for (c = g_classes; c; c = c->next) + if (strcmp(c->name, name) == 0) + return c; + return NULL; +} + +static void add_member(ClassInfo *ci, const char *m) +{ + int i; + if (!ci) return; + for (i = 0; i < ci->n_members; i++) + if (!strcmp(ci->members[i], m)) return; + if (ci->n_members < 64) + strncpy(ci->members[ci->n_members++], m, 63); + +} + +static int is_member(ClassInfo *ci, const char *m) +{ + int i; + if (!ci) return 0; + for (i = 0; i < ci->n_members; i++) + if (!strcmp(ci->members[i], m)) return 1; + /* search base class */ + if (ci->base[0]) { + ClassInfo *b = find_class(ci->base); + if (b) return is_member(b, m); + } + return 0; +} + +/* find access path for a member: base-class member -> this->__base */ +static void member_path(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, "this"); + return; + } + if (ci->base[0]) { + ClassInfo *b = find_class(ci->base); + if (b && is_member(b, m)) { + snprintf(out, outsz, "this->__base"); + return; + } + } + snprintf(out, outsz, "this"); +} + +static void add_class(const char *name) +{ + ClassInfo *c; + if (find_class(name)) return; + c = (ClassInfo*)calloc(1, sizeof *c); + strncpy(c->name, name, sizeof c->name - 1); + c->next = g_classes; + g_classes = c; +} + +/* ---------------- tokenizer ---------------- */ + +static Token g_peek; /* one-token lookahead buffer */ +static int g_have_peek = 0; +static Token g_pb[16]; /* pushback stack for peeking */ +static int g_pb_len = 0; + +static void next_tok_internal(Token *t); /* fwd decl */ + +/* read next token (from pushback, peek buffer, or input) */ +static void read_tok(Token *t) +{ + if (g_pb_len > 0) { + *t = g_pb[--g_pb_len]; + return; + } + if (g_have_peek) { + *t = g_peek; + g_have_peek = 0; + } else { + next_tok_internal(t); + } +} + +/* push a token back onto the stack (LIFO) */ +static void unread_tok(const Token *t) +{ + if (g_pb_len < 16) + g_pb[g_pb_len++] = *t; + else { + /* fallback: single peek */ + g_peek = *t; + g_have_peek = 1; + } +} + +static void next_tok(void) +{ + read_tok(&g_tok); +} + +static int getc2(void) +{ + int c = fgetc(g_in); + if (c == '\n') g_line++; + return c; +} + +static void ungetc2(int c) +{ + if (c == '\n') g_line--; + ungetc(c, g_in); +} + +static TokType kw_type(const char *s) +{ + if (!strcmp(s, "class")) return T_CLASS; + if (!strcmp(s, "struct")) return T_STRUCT; + if (!strcmp(s, "public")) return T_PUBLIC; + if (!strcmp(s, "private")) return T_PRIVATE; + if (!strcmp(s, "protected")) return T_PROTECTED; + if (!strcmp(s, "this")) return T_THIS; + if (!strcmp(s, "new")) return T_NEW; + if (!strcmp(s, "delete")) return T_DELETE; + if (!strcmp(s, "namespace")) return T_NAMESPACE; + if (!strcmp(s, "using")) return T_USING; + if (!strcmp(s, "virtual")) return T_VIRTUAL; + if (!strcmp(s, "inline")) return T_INLINE; + if (!strcmp(s, "friend")) return T_FRIEND; + if (!strcmp(s, "template")) return T_TEMPLATE; + if (!strcmp(s, "constexpr")) return T_CONSTEXPR; + return T_IDENT; +} + +/* read a raw token from the input stream */ +static void next_tok_internal(Token *t) +{ + int c; + for (;;) { + c = getc2(); + if (c == EOF) { t->type = T_EOF; t->text[0] = 0; return; } + if (isspace(c)) continue; + if (c == '/') { + int c2 = getc2(); + if (c2 == '/') { + while ((c = getc2()) != '\n' && c != EOF); + continue; + } else if (c2 == '*') { + int prev = 0; + while ((c = getc2()) != EOF) { + if (prev == '*' && c == '/') break; + prev = c; + } + continue; + } else { + ungetc2(c2); + t->type = T_PUNCT; + t->text[0] = '/'; t->text[1] = 0; + return; + } + } + break; + } + + /* preprocessor directive: copy the whole line verbatim */ + if (c == '#') { + int n = 0; + g_tok.type = T_PREPROC; + g_tok.text[n++] = '#'; + while (n < 250) { + c = getc2(); + if (c == '\n' || c == EOF) break; + g_tok.text[n++] = (char)c; + } + g_tok.text[n] = 0; + return; + } + + if (isalpha(c) || c == '_') { + int n = 0; + t->text[n++] = (char)c; + while (n < 255) { + c = getc2(); + if (isalnum(c) || c == '_') + t->text[n++] = (char)c; + else { ungetc2(c); break; } + } + t->text[n] = 0; + t->type = kw_type(t->text); + return; + } + + if (isdigit(c)) { + int n = 0; + t->text[n++] = (char)c; + while (n < 255) { + c = getc2(); + if (isalnum(c) || c == '.' || c == '_') + t->text[n++] = (char)c; + else { ungetc2(c); break; } + } + t->text[n] = 0; + t->ival = strtol(t->text, NULL, 0); + t->type = T_NUMBER; + return; + } + + if (c == '"') { + int n = 0; + t->type = T_STRING; + t->text[n++] = '"'; + while (n < 250) { + c = getc2(); + t->text[n++] = (char)c; + if (c == '\\') { + t->text[n++] = (char)getc2(); + } else if (c == '"') break; + else if (c == EOF || c == '\n') break; + } + t->text[n] = 0; + return; + } + + if (c == '\'') { + int n = 0; + t->type = T_CHAR; + t->text[n++] = '\''; + while (n < 250) { + c = getc2(); + t->text[n++] = (char)c; + if (c == '\\') { + t->text[n++] = (char)getc2(); + } else if (c == '\'') break; + else if (c == EOF || c == '\n') break; + } + t->text[n] = 0; + return; + } + + { + int c2 = getc2(); + char two[3] = { (char)c, (char)c2, 0 }; + static const char *multi[] = { "::", "->", "<<", ">>", "<=", ">=", "==", + "!=", "&&", "||", "++", "--", "+=", "-=", + "*=", "/=", "%=", "&=", "|=", "^=" }; + int i; + for (i = 0; i < (int)(sizeof multi / sizeof multi[0]); i++) + if (!strcmp(two, multi[i])) { + strcpy(t->text, two); + t->type = T_PUNCT; + return; + } + ungetc2(c2); + t->text[0] = (char)c; + t->text[1] = 0; + t->type = T_PUNCT; + } +} + +/* ---------------- output with smart spacing ---------------- */ + +static int g_out_is_word = 0; /* last emitted char was word char */ + +static void emit(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(g_out, fmt, ap); + va_end(ap); +} + +/* emit a token with proper spacing */ +static int g_need_space = 0; /* whether to add space before next word */ + +static void emit_tok(void) +{ + const char *t = g_tok.text; + int c; + if (g_tok.type == T_PREPROC) { + emit("\n%s\n", t); /* preprocessor line verbatim */ + g_need_space = 1; + return; + } + if (g_tok.type == T_PUNCT) { + c = t[0]; + if (c == ')' || c == ']' || c == ';' || c == ',' || c == '}' || + c == '.' || c == ':' || c == '(' ) + emit("%s", t); + else if (g_need_space) { + emit(" %s", t); + } else { + emit("%s", t); + } + /* after '.', '->', '::' no space before next word */ + g_need_space = !(c == '.' || t[1] == '>' || + (c == ':' && t[1] == ':')); + } else { + if (g_need_space) + emit(" %s", t); + else + emit("%s", t); + g_need_space = 1; + } +} + +/* pending member function prototypes (emitted after struct) */ +static char g_protos[8192]; +static int g_proto_len; +static char g_params[1024]; /* captured params for inline defs */ + +static void proto_emit(const char *fmt, ...) +{ + va_list ap; + int n; + va_start(ap, fmt); + n = vsnprintf(g_protos + g_proto_len, sizeof g_protos - g_proto_len, fmt, ap); + va_end(ap); + if (n > 0) g_proto_len += n; + if (g_proto_len >= (int)sizeof g_protos - 1) g_proto_len = sizeof g_protos - 1; +} + +/* ---------------- class parsing ---------------- */ + +static void gather_decl(char *type, int typesz, char *name, int namesz); + +static void parse_member_decl(const char *cls, const char *ret_type, const char *mname_in) +{ + char name[256]; + char mname[256]; + int is_ctor, is_dtor; + ClassInfo *ci = find_class(cls); + + if (mname_in && mname_in[0]) + strncpy(name, mname_in, sizeof name - 1); + else + strncpy(name, g_tok.text, sizeof name - 1); + name[sizeof name - 1] = 0; + is_ctor = !strcmp(name, cls); + is_dtor = (name[0] == '~' && !strcmp(name + 1, cls)); + if (ci) { + if (is_ctor) ci->has_ctor = 1; + if (is_dtor) ci->has_dtor = 1; + else add_member(ci, name); + } + /* only advance if g_tok is the name (not already consumed) */ + if (!mname_in || !mname_in[0]) + next_tok(); + + if (is_ctor) + snprintf(mname, sizeof mname, "%s_ctor", cls); + else if (is_dtor) + snprintf(mname, sizeof mname, "%s_dtor", cls); + else + snprintf(mname, sizeof mname, "%s_%s", cls, name); + + /* constructors/destructors return void */ + if (is_ctor || is_dtor) + ret_type = "void"; + + proto_emit(" %s %s(struct %s *this", ret_type, mname, cls); + g_params[0] = 0; + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "(")) { + next_tok(); + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")")) { + proto_emit(");\n"); + next_tok(); + } else { + proto_emit(", "); + int depth = 0; + while (!(g_tok.type == T_EOF)) { + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")") && depth == 0) + break; + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "(")) depth++; + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")")) depth--; + /* smart spacing for prototype params */ + { + const char *tt = g_tok.text; + int c = tt[0]; + if (g_tok.type == T_PUNCT) { + if (!(c == ')' || c == ']' || c == ';' || c == ',' || + c == '*' || c == '&' || c == '(' )) + proto_emit(" "); + proto_emit("%s", tt); + strncat(g_params, " ", sizeof g_params - strlen(g_params) - 1); + strncat(g_params, tt, sizeof g_params - strlen(g_params) - 1); + } else { + proto_emit(" %s", tt); + strncat(g_params, " ", sizeof g_params - strlen(g_params) - 1); + strncat(g_params, tt, sizeof g_params - strlen(g_params) - 1); + } + } + next_tok(); + } + proto_emit(");\n"); + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")")) next_tok(); + } + } + /* skip constructor initializer list: ": Base(args, ...)" */ + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ":")) { + int bd = 0; + while (!(g_tok.type == T_EOF)) { + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "(")) bd++; + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")")) bd--; + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{") && bd == 0) + break; + next_tok(); + } + } + /* after the prototype, either ';' (decl only) or '{' (inline body) */ + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) { + /* inline member function definition: emit the body as a + separate function after the class */ + ClassInfo *mci = find_class(cls); + proto_emit("%s %s(struct %s *this%s", ret_type, mname, cls, + g_params[0] ? ", " : ""); + proto_emit("%s) {\n", g_params); + next_tok(); /* consume '{' */ + { + int bd = 1; + while (bd > 0) { + if (g_tok.type == T_EOF) break; + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) { bd++; 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"); next_tok(); continue; } + /* bare member name -> this->member (or this->__base->member) */ + if (g_tok.type == T_IDENT && mci && is_member(mci, g_tok.text)) { + char path[64]; + member_path(mci, g_tok.text, path, sizeof path); + /* path is "this" -> this->x ; "this->__base" -> this->__base.x */ + if (!strcmp(path, "this")) + proto_emit(" this->%s", g_tok.text); + else + proto_emit(" %s.%s", path, g_tok.text); + next_tok(); + continue; + } + proto_emit(" %s", g_tok.text); + next_tok(); + } + } + proto_emit("}\n\n"); + /* skip trailing ; */ + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ";")) next_tok(); + } else { + while (!(g_tok.type == T_EOF)) { + if (g_tok.type == T_PUNCT && + (!strcmp(g_tok.text, ";") || !strcmp(g_tok.text, "}"))) break; + next_tok(); + } + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ";")) next_tok(); + } +} + +static void parse_class(void) +{ + char clsname[128]; + char base[128] = ""; + ClassInfo *ci; + + next_tok(); + if (g_tok.type != T_IDENT) { emit("/* anon class */\n"); return; } + strncpy(clsname, g_tok.text, sizeof clsname - 1); + clsname[sizeof clsname - 1] = 0; + next_tok(); + + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ":")) { + next_tok(); + if (g_tok.type == T_PUBLIC || g_tok.type == T_PRIVATE || + g_tok.type == T_PROTECTED || g_tok.type == T_VIRTUAL) + next_tok(); + if (g_tok.type == T_IDENT) { + strncpy(base, g_tok.text, sizeof base - 1); + base[sizeof base - 1] = 0; + next_tok(); + } + } + + add_class(clsname); + 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; } + + 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); + add_member(cci, tmp); + while (!(g_tok.type == T_PUNCT && + (!strcmp(g_tok.text, ";") || !strcmp(g_tok.text, "}")))) { + if (g_tok.type == T_EOF) break; + /* additional declarators: , y */ + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ",")) { + emit(", "); + next_tok(); + /* next word is another member name */ + if (g_tok.type == T_IDENT) { + add_member(cci, g_tok.text); + } + continue; + } + emit_tok(); + next_tok(); + } + emit(";\n"); + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ";")) next_tok(); + } else if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}")) { + /* nothing - end of class */ + } else { + /* unknown, copy through */ + if (tybuf[0]) emit("%s", tybuf); + while (!(g_tok.type == T_PUNCT && + (!strcmp(g_tok.text, ";") || !strcmp(g_tok.text, "}")))) { + if (g_tok.type == T_EOF) break; + emit_tok(); + next_tok(); + } + emit(";\n"); + 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(); + emit("};\n"); + /* emit member function prototypes after the struct */ + if (g_proto_len) { + emit("%s", g_protos); + g_proto_len = 0; + } + emit("\n"); +} + +/* member function definition: Ret Class::method(params) { body } */ +static void parse_member_definition(const char *ret_type) +{ + char cls[128], method[128], mname[256]; + int is_ctor = 0, is_dtor = 0; + ClassInfo *ci; + + strncpy(cls, g_tok.text, sizeof cls - 1); + cls[sizeof cls - 1] = 0; + next_tok(); + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "::")) next_tok(); + if (g_tok.type != T_IDENT) { emit("/* bad member def */\n"); return; } + strncpy(method, g_tok.text, sizeof method - 1); + method[sizeof method - 1] = 0; + if (!strcmp(method, cls)) is_ctor = 1; + if (method[0] == '~') is_dtor = 1; + next_tok(); + + if (is_ctor) + snprintf(mname, sizeof mname, "%s_ctor", cls); + else if (is_dtor) + snprintf(mname, sizeof mname, "%s_dtor", cls); + else + snprintf(mname, sizeof mname, "%s_%s", cls, method); + ci = find_class(cls); + if (ci) { if (is_ctor) ci->has_ctor = 1; if (is_dtor) ci->has_dtor = 1; } + + /* constructors/destructors return void */ + if (is_ctor || is_dtor) + ret_type = "void"; + + emit("%s %s(struct %s *this", ret_type, mname, cls); + + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "(")) { + next_tok(); + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")")) { + emit(")"); + next_tok(); + } else { + emit(", "); + int depth = 0; + while (!(g_tok.type == T_EOF)) { + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")") && depth == 0) break; + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "(")) depth++; + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")")) depth--; + emit_tok(); + next_tok(); + } + emit(")"); + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")")) next_tok(); + } + } + + /* skip constructor initializer list: ": Base(args, ...)" */ + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ":")) { + int bd = 0; + /* skip to '{' at depth 0 */ + while (!(g_tok.type == T_EOF)) { + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "(")) bd++; + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")")) bd--; + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{") && bd == 0) + break; + next_tok(); + } + } + + emit(" {\n"); + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{")) next_tok(); + { + int depth = 0; + ClassInfo *mci = find_class(cls); + while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}") && depth == 0)) { + if (g_tok.type == T_EOF) break; + 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; } + break; + } + if (g_tok.type == T_THIS) { + emit("this"); + next_tok(); + continue; + } + /* bare member name -> this->member (or this->__base->member) */ + if (g_tok.type == T_IDENT && mci && is_member(mci, g_tok.text)) { + char path[64]; + member_path(mci, g_tok.text, path, sizeof path); + if (!strcmp(path, "this")) + emit(" this->%s", g_tok.text); + else + emit(" %s.%s", path, g_tok.text); + next_tok(); + continue; + } + emit_tok(); + next_tok(); + } + } + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}")) next_tok(); + emit("}\n\n"); +} + +/* ---------------- top-level ---------------- */ + +static void parse_function(const char *ret_type, const char *name) +{ + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "::")) { + /* member function: class is 'name', method follows */ + g_tok.type = T_IDENT; + strncpy(g_tok.text, name, sizeof g_tok.text - 1); + g_tok.text[sizeof g_tok.text - 1] = 0; + parse_member_definition(ret_type); + return; + } + + emit("%s %s", ret_type, name); + while (!(g_tok.type == T_PUNCT && !strcmp(g_tok.text, "{"))) { + if (g_tok.type == T_EOF) break; + 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)) { + if (g_tok.type == T_EOF) break; + 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; } + break; + } + /* variable declaration: struct Cls var; -> record var:Cls */ + if (g_tok.type == T_IDENT && find_class(g_tok.text) && + (nvars < 64)) { + char clsname[128]; + strncpy(clsname, g_tok.text, sizeof clsname - 1); + clsname[sizeof clsname - 1] = 0; + emit(" struct %s", clsname); + next_tok(); + /* next token(s): var [= ...] */ + if (g_tok.type == T_IDENT && nvars < 64) { + char vname[64]; + strncpy(varcls[nvars], clsname, 127); + strncpy(varname[nvars], g_tok.text, 63); + strncpy(vname, g_tok.text, sizeof vname - 1); + vname[sizeof vname - 1] = 0; + nvars++; + emit(" %s", g_tok.text); + next_tok(); + /* if this class has a ctor, call it after declaration */ + { + ClassInfo *cci = find_class(clsname); + if (cci && cci->has_ctor) { + /* check for parenthesized ctor args: var(args) */ + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "(")) { + emit("; %s_ctor(&%s", clsname, vname); + next_tok(); + /* first arg or ')' */ + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ")")) { + emit(")"); + next_tok(); + } else { + 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(); + } + continue; + } else { + emit("; %s_ctor(&%s)", clsname, vname); + } + } + } + } + continue; + } + /* member call: var.method(args) -> Class_method(&var, args) */ + if (g_tok.type == T_IDENT) { + int vi; + for (vi = 0; vi < nvars; vi++) { + if (!strcmp(g_tok.text, varname[vi])) { + Token t1, t2, t3; + /* peek: . method ( */ + read_tok(&t1); + if (t1.type == T_PUNCT && !strcmp(t1.text, ".")) { + read_tok(&t2); + if (t2.type == T_IDENT) { + read_tok(&t3); + if (t3.type == T_PUNCT && !strcmp(t3.text, "(")) { + char meth[128]; + char mname[256]; + strncpy(meth, t2.text, sizeof meth - 1); + meth[sizeof meth - 1] = 0; + snprintf(mname, sizeof mname, "%s_%s", + varcls[vi], meth); + emit(" %s(&%s", mname, varname[vi]); + /* peek already consumed: var . method ( + g_tok is still the var name. Read one + token to reach first arg or ')' */ + next_tok(); /* -> first arg or ) */ + /* now g_tok is first arg or ')' */ + if (!(g_tok.type == T_PUNCT && + !strcmp(g_tok.text, ")"))) { + 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); + next_tok(); + continue; + } + emit_tok(); + next_tok(); + next_body_tok: + ; + } + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}")) next_tok(); + emit("}\n\n"); + } +} + +/* collect tokens until we hit a '(', ';', '{', '}', ',' or EOF. + The last identifier seen is the declared name; everything + before it is the type. Returns the name in 'name'. */ +static void gather_decl(char *type, int typesz, char *name, int namesz) +{ + type[0] = 0; + name[0] = 0; + + for (;;) { + if (g_tok.type == T_EOF) break; + if (g_tok.type == T_PUNCT) { + const char *t = g_tok.text; + if (!strcmp(t, "(") || !strcmp(t, ";") || !strcmp(t, "{") || + !strcmp(t, "}") || !strcmp(t, ",")) break; + /* punctuators like * & [] are part of the type/name */ + strncat(type, t, typesz - strlen(type) - 1); + strncat(type, " ", typesz - strlen(type) - 1); + next_tok(); + continue; + } + /* word token */ + { + char word[256]; + strncpy(word, g_tok.text, sizeof word - 1); + word[sizeof word - 1] = 0; + next_tok(); + if (g_tok.type == T_PUNCT && + (!strcmp(g_tok.text, "(") || !strcmp(g_tok.text, "::"))) { + /* this word is the name */ + strncpy(name, word, namesz - 1); + name[namesz - 1] = 0; + return; + } + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ",")) { + /* this word is the name of the first declarator */ + strncpy(name, word, namesz - 1); + name[namesz - 1] = 0; + return; + } + if (g_tok.type == T_PUNCT && + (!strcmp(g_tok.text, ";") || !strcmp(g_tok.text, "}") || + !strcmp(g_tok.text, "{"))) { + /* word is the name (declarator before ; } {) */ + strncpy(name, word, namesz - 1); + name[namesz - 1] = 0; + return; + } + /* it's part of the type */ + strncat(type, word, typesz - strlen(type) - 1); + strncat(type, " ", typesz - strlen(type) - 1); + } + } + /* no name found; caller handles */ +} + +static void parse_program(void) +{ + for (;;) { + char tybuf[512]; + if (g_tok.type == T_EOF) break; + + if (g_tok.type == T_CLASS) { parse_class(); continue; } + if (g_tok.type == T_PREPROC) { + emit("%s\n", g_tok.text); + next_tok(); + continue; + } + + if (g_tok.type == T_STRUCT) { + next_tok(); + emit("struct "); + while (!(g_tok.type == T_EOF)) { + emit_tok(); + next_tok(); + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}")) break; + } + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "}")) { + emit("}"); + next_tok(); + } + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ";")) { + emit(";"); + next_tok(); + } + emit("\n"); + 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_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) { + next_tok(); + while (!(g_tok.type == T_EOF)) { + if (g_tok.type == T_PUNCT && + (!strcmp(g_tok.text, ";") || !strcmp(g_tok.text, "}"))) break; + next_tok(); + } + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ";")) { + emit("/* skipped */\n"); + next_tok(); + } + continue; + } + + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ";")) { + emit(";\n"); + next_tok(); + continue; + } + + { + char tybuf[512], nmbuf[256]; + gather_decl(tybuf, sizeof tybuf, nmbuf, sizeof nmbuf); + if (nmbuf[0]) { + parse_function(tybuf[0] ? tybuf : "int", nmbuf); + } else if (g_tok.type == T_EOF) { + break; + } else if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, "(")) { + /* function without return type (C style) */ + emit("int "); + parse_function("int", "f"); + } else { + /* global variable: type + rest */ + if (tybuf[0]) emit("%s", tybuf); + while (!(g_tok.type == T_EOF)) { + if (g_tok.type == T_PUNCT && + (!strcmp(g_tok.text, ";") || !strcmp(g_tok.text, "}"))) break; + emit_tok(); + next_tok(); + } + if (g_tok.type == T_PUNCT && !strcmp(g_tok.text, ";")) { emit(";"); next_tok(); } + emit("\n"); + } + } + } +} + +int main(int argc, char **argv) +{ + const char *infile = NULL, *outfile = NULL; + int i; + + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] == 'o' && i + 1 < argc) + outfile = argv[++i]; + else if (argv[i][0] != '-') + infile = argv[i]; + } + if (!infile) { + fprintf(stderr, "usage: pcc-cpp input.cpp [-o output.c]\n"); + return 1; + } + g_in = fopen(infile, "r"); + if (!g_in) { fprintf(stderr, "cannot open %s\n", infile); return 1; } + g_out = outfile ? fopen(outfile, "w") : stdout; + if (!g_out) { fprintf(stderr, "cannot open %s\n", outfile); return 1; } + + next_tok(); + parse_program(); + + fclose(g_in); + if (g_out != stdout) fclose(g_out); + return 0; +} diff --git a/win32/include/direct.h b/win32/include/direct.h index 99ce69d..ae2ad77 100644 --- a/win32/include/direct.h +++ b/win32/include/direct.h @@ -9,7 +9,7 @@ #include <_mingw.h> #include -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifdef __cplusplus extern "C" { diff --git a/win32/include/dirent.h b/win32/include/dirent.h index cd31f59..006e066 100644 --- a/win32/include/dirent.h +++ b/win32/include/dirent.h @@ -12,7 +12,7 @@ #define _DIRENT_H_ -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #include diff --git a/win32/include/dos.h b/win32/include/dos.h index 294e8fe..913debc 100644 --- a/win32/include/dos.h +++ b/win32/include/dos.h @@ -9,7 +9,7 @@ #include <_mingw.h> #include -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifdef __cplusplus extern "C" { diff --git a/win32/include/excpt.h b/win32/include/excpt.h index 26cc943..26d933c 100644 --- a/win32/include/excpt.h +++ b/win32/include/excpt.h @@ -8,7 +8,7 @@ #include <_mingw.h> -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifdef __cplusplus extern "C" { diff --git a/win32/include/io.h b/win32/include/io.h index e2aeec3..7207418 100644 --- a/win32/include/io.h +++ b/win32/include/io.h @@ -10,7 +10,7 @@ #include <_mingw.h> #include -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifndef _POSIX_ diff --git a/win32/include/locale.h b/win32/include/locale.h index 686aa9b..9f1ddf2 100644 --- a/win32/include/locale.h +++ b/win32/include/locale.h @@ -8,7 +8,7 @@ #include <_mingw.h> -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifdef __cplusplus extern "C" { diff --git a/win32/include/malloc.h b/win32/include/malloc.h index 5e30c82..9316a4d 100644 --- a/win32/include/malloc.h +++ b/win32/include/malloc.h @@ -8,7 +8,7 @@ #include <_mingw.h> -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifndef _MM_MALLOC_H_INCLUDED #define _MM_MALLOC_H_INCLUDED diff --git a/win32/include/math.h b/win32/include/math.h index 9e9eec6..0b274a1 100644 --- a/win32/include/math.h +++ b/win32/include/math.h @@ -14,7 +14,7 @@ struct exception; -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #define _DOMAIN 1 #define _SING 2 diff --git a/win32/include/setjmp.h b/win32/include/setjmp.h index ab6a424..df274e4 100644 --- a/win32/include/setjmp.h +++ b/win32/include/setjmp.h @@ -8,7 +8,7 @@ #include <_mingw.h> -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifdef __cplusplus extern "C" { diff --git a/win32/include/stdio.h b/win32/include/stdio.h index da88793..f887cfb 100644 --- a/win32/include/stdio.h +++ b/win32/include/stdio.h @@ -8,7 +8,7 @@ #include <_mingw.h> -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifdef __cplusplus extern "C" { diff --git a/win32/include/stdlib.h b/win32/include/stdlib.h index b710ec1..96268f4 100644 --- a/win32/include/stdlib.h +++ b/win32/include/stdlib.h @@ -9,7 +9,7 @@ #include <_mingw.h> #include -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifdef __cplusplus extern "C" { diff --git a/win32/include/sys/stat.h b/win32/include/sys/stat.h index 4a95e65..772ef4a 100644 --- a/win32/include/sys/stat.h +++ b/win32/include/sys/stat.h @@ -13,7 +13,7 @@ #include <_mingw.h> #include -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifdef __cplusplus extern "C" { diff --git a/win32/include/sys/timeb.h b/win32/include/sys/timeb.h index 3483773..9fe2fd4 100644 --- a/win32/include/sys/timeb.h +++ b/win32/include/sys/timeb.h @@ -12,7 +12,7 @@ #error Only Win32 target is supported! #endif -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifdef __cplusplus extern "C" { diff --git a/win32/include/sys/utime.h b/win32/include/sys/utime.h index fec8304..d106c06 100644 --- a/win32/include/sys/utime.h +++ b/win32/include/sys/utime.h @@ -12,7 +12,7 @@ #include <_mingw.h> -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifdef __cplusplus extern "C" { diff --git a/win32/include/time.h b/win32/include/time.h index 6c72e26..8041f47 100644 --- a/win32/include/time.h +++ b/win32/include/time.h @@ -12,7 +12,7 @@ #error Only Win32 target is supported! #endif -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifdef __cplusplus extern "C" { diff --git a/win32/include/wchar.h b/win32/include/wchar.h index 389196f..53a27a2 100644 --- a/win32/include/wchar.h +++ b/win32/include/wchar.h @@ -8,7 +8,7 @@ #include <_mingw.h> -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifdef __cplusplus extern "C" { diff --git a/win32/include/wctype.h b/win32/include/wctype.h index a44cb38..74e7812 100644 --- a/win32/include/wctype.h +++ b/win32/include/wctype.h @@ -12,7 +12,7 @@ #include <_mingw.h> -#pragma pack(push,_CRT_PACKING) +#pragma pack(push,8) #ifdef __cplusplus extern "C" {