《玄》语言简介
《玄》 是一门用中文书写、编译为 C++ 的编程语言。它保留 C++ 的全部能力(指针、类、容器、模板、STL),但关键字、标点和控制流都可以用中文。
一段完整程序
玄
bash
头文件《标准IO》
使用命名空间标准;
整数 求和(整数 x,整数 y)《
返回 x 加 y;
》
主程序:
整数 a = 10;
整数 b = 0;
对于(整数 i = 0; i 比 a 小; i 递增)《
b = 求和(b,i);
》
输出:"总和=":b:换行;
返回 0;
。
编译后就是等价的 C++。
设计特点
| 常规写法 | 玄写法 |
|---|---|
int a = 5; |
整数 a = 5; |
if (a > b) {...} |
如果(a 大于 b)《...》 |
for (int i = 0; i < n; i++) |
对于(整数 i=0;i 比 n 小;i 递增) |
std::cout << "hi" << std::endl; |
输出:"hi":换行; |
class Student { public: ... }; |
类 学生《 公开: ... 》 |
独有语法(C++ 没有的):
玄
bash
重复 3 次《 输出:"hi":换行; 》
对于 i 从 1 到 5《 ... 》
遍历 x 在 v 中《 ... 》
若 分数 大于 90 则 输出:"优":换行;
否则 输出:"及格":换行;
整数 骰子 = 卦 1 到 6; // 随机数
环《 ... 跳出; ... 》 // 无限循环
转译原理
text
.玄 源文件
↓ translate_xuan()
output.cpp(标准 C++)
↓ g++ -std=c++17
output.exe
《玄》IDE 把这个流程包成图形界面:编辑 → 编译 → 运行 → 输出,全程不离开一个窗口。
定位
-
入门 C++ 的人 :中文关键字降低了"看见
<<->::就头疼"的门槛 -
教学场景:写算法、讲数据结构,用中文词表意更直观
-
试验性语言:想验证"中文能不能编程",它是一个完整可用的答案
已知边界
-
只能生成 C++,不能独立后端
-
依赖外部
g++ -
约 15 个核心语法(
重复/遍历/卦/环/智能指针等)硬编码,无法通过data/patterns.txt扩展 -
宏、模板元编程、协程等 C++ 高级特性无中文封装,需直写 C++ 原语法
想动手可以看三个文件:
-
xuan_ide.cpp------ IDE 主体 -
data/patterns.txt------ 关键字映射表(能改的都在这里) -
data/help.txt------ 语言手册
cpp
// ============================================================
// 《玄》IDE v3.8.2 --- 数据外置版
// v3.8.2 修复:
// R2 次 后跟全角标点
// R3 map_simple_type 用循环(无递归)
// R5 write_file(cppPath) 检查
// R1+R7 key 走 Unescape + patterns.txt 5 处 \s
// R6 types.txt 缺失弹窗
// S1 UTF-16 BOM 检测
// S2 static lambda 初始化(线程安全)
// S3 GetHelpAnsi 首次失败不重试
// 放弃:R4(嵌套智能指针,文档说明即可)
// 链接库:-lgdi32 -luser32 -lcomctl32 -static-libstdc++ -static-libgcc
// ============================================================
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <process.h>
#include <atomic>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cctype>
using namespace std;
#define IDM_FILE_NEW 1001
#define IDM_FILE_OPEN 1002
#define IDM_FILE_SAVE 1003
#define IDM_FILE_SAVEAS 1004
#define IDM_FILE_EXIT 1005
#define IDM_EDIT_CUT 1011
#define IDM_EDIT_COPY 1012
#define IDM_EDIT_PASTE 1013
#define IDM_RUN_COMPILE 1021
#define IDM_RUN_RUN 1022
#define IDM_RUN_STOP 1023
#define IDM_HELP_MANUAL 1031
#define IDM_HELP_ABOUT 1032
#define IDB_SAVE 201
#define IDB_COMPILE 202
#define IDB_RUN 203
#define IDB_STOP 204
#define IDB_CLEAR 205
#define WM_UPDATE_OUTPUT (WM_USER + 100)
#define WM_COMPILE_FINISHED (WM_USER + 101)
HWND g_hMainWnd=NULL, g_hEdit=NULL, g_hOutput=NULL, g_hStatusBar=NULL;
HWND g_hBtnSave=NULL, g_hBtnCompile=NULL, g_hBtnRun=NULL, g_hBtnStop=NULL, g_hBtnClear=NULL;
HWND g_hHelpWnd=NULL, g_hHelpEdit=NULL;
HFONT g_hFont=NULL, g_hOutFont=NULL, g_hHelpFont=NULL;
HINSTANCE g_hInst=NULL;
static std::atomic<HANDLE> g_hGppProcess{NULL};
static std::atomic<HANDLE> g_hOutputProcess{NULL};
static std::atomic<bool> g_stopRequested{false};
static string g_currentFilePath = "";
static string g_currentFileName;
static string g_tempDir = ".";
static string g_exeDir = ".";
static bool g_isRunning=false, g_isCompiling=false;
static string g_patterns_content;
static string g_types_content;
static bool g_patterns_loaded = false;
static bool g_types_loaded = false;
// ============================================================
// 编码工具
// ============================================================
static bool cpp_is_utf8() { return (sizeof("中") == 4); }
static string to_ansi(const char* s) {
if (!s || !*s) return string();
if (!cpp_is_utf8()) return string(s);
int wlen = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s, -1, NULL, 0);
if (wlen <= 0) return string(s);
vector<wchar_t> wbuf(wlen);
MultiByteToWideChar(CP_UTF8, 0, s, -1, &wbuf[0], wlen);
int alen = WideCharToMultiByte(CP_ACP, 0, &wbuf[0], -1, NULL, 0, NULL, NULL);
if (alen <= 0) return string(s);
vector<char> abuf(alen);
WideCharToMultiByte(CP_ACP, 0, &wbuf[0], -1, &abuf[0], alen, NULL, NULL);
return string(&abuf[0], alen - 1);
}
static string to_ansi_n(const char* s, size_t len) {
if (!s || len == 0) return string();
if (!cpp_is_utf8()) return string(s, len);
int wlen = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s, (int)len, NULL, 0);
if (wlen <= 0) return string(s, len);
vector<wchar_t> wbuf(wlen);
MultiByteToWideChar(CP_UTF8, 0, s, (int)len, &wbuf[0], wlen);
int alen = WideCharToMultiByte(CP_ACP, 0, &wbuf[0], wlen, NULL, 0, NULL, NULL);
if (alen <= 0) return string(s, len);
vector<char> abuf(alen);
WideCharToMultiByte(CP_ACP, 0, &wbuf[0], wlen, &abuf[0], alen, NULL, NULL);
return string(&abuf[0], alen);
}
#define XA(s) (to_ansi(s).c_str())
static bool looks_like_utf8(const string& s) {
if (s.size() >= 3 &&
(unsigned char)s[0] == 0xEF &&
(unsigned char)s[1] == 0xBB &&
(unsigned char)s[2] == 0xBF) return true;
size_t total_hi = 0, valid_utf8 = 0;
size_t k = 0;
while (k < s.size()) {
unsigned char c = (unsigned char)s[k];
if (c < 0x80) { k++; continue; }
total_hi++;
size_t need = 0;
if ((c & 0xE0) == 0xC0) need = 1;
else if ((c & 0xF0) == 0xE0) need = 2;
else if ((c & 0xF8) == 0xF0) need = 3;
bool ok = (need > 0) && (k + need < s.size());
if (ok) {
for (size_t i = 1; i <= need; ++i)
if (((unsigned char)s[k+i] & 0xC0) != 0x80) { ok = false; break; }
}
if (ok) { valid_utf8++; k += 1 + need; }
else k++;
}
if (total_hi == 0) return false;
return valid_utf8 * 2 > total_hi;
}
static string utf8_to_ansi(const string& s) {
size_t start = 0;
if (s.size() >= 3 &&
(unsigned char)s[0] == 0xEF &&
(unsigned char)s[1] == 0xBB &&
(unsigned char)s[2] == 0xBF) start = 3;
if (start >= s.size()) return string();
int wlen = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
s.c_str() + start, (int)(s.size() - start), NULL, 0);
if (wlen <= 0) return s;
vector<wchar_t> wbuf(wlen);
MultiByteToWideChar(CP_UTF8, 0, s.c_str() + start,
(int)(s.size() - start), &wbuf[0], wlen);
int alen = WideCharToMultiByte(CP_ACP, 0, &wbuf[0], wlen, NULL, 0, NULL, NULL);
if (alen <= 0) return s;
vector<char> abuf(alen);
WideCharToMultiByte(CP_ACP, 0, &wbuf[0], wlen, &abuf[0], alen, NULL, NULL);
return string(&abuf[0], alen);
}
// S1:UTF-16 转 ANSI(不支持 surrogate pairs,对中文 txt 够用)
static string utf16_to_ansi(const string& s, bool be) {
if (s.size() < 2) return s;
vector<wchar_t> wbuf;
for (size_t i = 2; i + 1 < s.size(); i += 2) {
unsigned char lo = (unsigned char)s[i];
unsigned char hi = (unsigned char)s[i+1];
wchar_t wc = be ? ((hi << 8) | lo) : ((lo << 8) | hi);
wbuf.push_back(wc);
}
if (wbuf.empty()) return string();
int alen = WideCharToMultiByte(CP_ACP, 0, &wbuf[0], (int)wbuf.size(),
NULL, 0, NULL, NULL);
if (alen <= 0) return s;
vector<char> abuf(alen);
WideCharToMultiByte(CP_ACP, 0, &wbuf[0], (int)wbuf.size(),
&abuf[0], alen, NULL, NULL);
return string(&abuf[0], alen);
}
// ============================================================
// 文件工具
// ============================================================
static bool FileExists(const string& path) {
ifstream f(path.c_str(), ios::binary);
return f.is_open();
}
static string read_file(const string& path) {
ifstream f(path.c_str(), ios::binary);
if (!f) return "";
stringstream ss; ss << f.rdbuf();
return ss.str();
}
static bool write_file(const string& path, const string& content) {
ofstream f(path.c_str(), ios::binary);
if (!f) return false;
f << content;
f.close();
return f.good();
}
static string GetExeDir() {
vector<char> buf(32768);
DWORD n = GetModuleFileNameA(NULL, &buf[0], (DWORD)buf.size());
if (n == 0 || n >= buf.size()) return ".";
string s(&buf[0], n);
size_t p = s.find_last_of("/\\");
return (p == string::npos) ? string(".") : s.substr(0, p);
}
static string Unescape(const string& v) {
string r;
for (size_t i = 0; i < v.size(); ++i) {
if (v[i] == '\\' && i + 1 < v.size()) {
char c = v[i+1];
if (c == 'n') { r += '\n'; i++; continue; }
if (c == 't') { r += '\t'; i++; continue; }
if (c == 's') { r += ' '; i++; continue; }
if (c == '\\') { r += '\\'; i++; continue; }
}
r += v[i];
}
return r;
}
// S1:加载文件,支持 UTF-8 BOM / UTF-16 LE / UTF-16 BE / 原生 ANSI
static bool LoadTextFile(const string& name, string& out) {
string path1 = g_exeDir + "\\data\\" + name;
string path2 = g_exeDir + "\\" + name;
string path;
if (FileExists(path1)) path = path1;
else if (FileExists(path2)) path = path2;
else return false;
out = read_file(path);
if (out.size() >= 2 &&
(unsigned char)out[0] == 0xFF &&
(unsigned char)out[1] == 0xFE) {
out = utf16_to_ansi(out, false);
return true;
}
if (out.size() >= 2 &&
(unsigned char)out[0] == 0xFE &&
(unsigned char)out[1] == 0xFF) {
out = utf16_to_ansi(out, true);
return true;
}
if (looks_like_utf8(out)) out = utf8_to_ansi(out);
if (out.size() >= 3 &&
(unsigned char)out[0] == 0xEF &&
(unsigned char)out[1] == 0xBB &&
(unsigned char)out[2] == 0xBF)
out = out.substr(3);
return true;
}
// R1:key 也走 Unescape
static void ParseKV(const string& content,
vector<pair<string,string> >& out) {
size_t p = 0;
while (p < content.size()) {
size_t e = content.find('\n', p);
if (e == string::npos) e = content.size();
string line = content.substr(p, e - p);
if (e >= content.size()) p = content.size();
else p = e + 1;
if (!line.empty() && line[line.size()-1] == '\r') line.erase(line.size()-1);
if (line.empty() || line[0] == '#') continue;
size_t tab = line.find('\t');
if (tab == string::npos) continue; // v3.8.2:不做空格容错(有风险)
if (tab + 1 > line.size()) continue;
out.push_back(make_pair(Unescape(line.substr(0, tab)),
Unescape(line.substr(tab + 1))));
}
}
// ============================================================
// 辅助
// ============================================================
static bool is_ascii_ident(unsigned char c) {
return (c>='a'&&c<='z') || (c>='A'&&c<='Z') || (c>='0'&&c<='9') || c=='_';
}
static size_t advance_one_char(const string& s, size_t pos) {
if (pos >= s.size()) return 1;
unsigned char c = (unsigned char)s[pos];
if (c < 0x80) return 1;
if ((c & 0xF8) == 0xF0 && pos + 3 < s.size() &&
((unsigned char)s[pos+1] & 0xC0) == 0x80 &&
((unsigned char)s[pos+2] & 0xC0) == 0x80 &&
((unsigned char)s[pos+3] & 0xC0) == 0x80) return 4;
if ((c & 0xF0) == 0xE0 && pos + 2 < s.size() &&
((unsigned char)s[pos+1] & 0xC0) == 0x80 &&
((unsigned char)s[pos+2] & 0xC0) == 0x80) return 3;
if ((c & 0xE0) == 0xC0 && pos + 1 < s.size() &&
((unsigned char)s[pos+1] & 0xC0) == 0x80) return 2;
return 2;
}
static bool ends_with_cjk_hanzi(const string& s) {
if (s.size() < 2) return false;
size_t p = s.size();
while (p > 0) { p--; if (((unsigned char)s[p] & 0xC0) != 0x80) break; }
unsigned char last = (unsigned char)s[p];
if (last >= 0x80) return true;
if (p > 0 && last >= 0x40 && last <= 0x7E) {
unsigned char lead = (unsigned char)s[p-1];
if (lead >= 0x81 && lead <= 0xFE) return true;
}
return false;
}
static bool is_fullwidth_punct_at(const string& s, size_t pos) {
if (pos >= s.size()) return false;
unsigned char c = (unsigned char)s[pos];
if (c < 0x80) return false;
if (c >= 0xA1 && c <= 0xA3) return true;
if (c == 0xEF) return true;
if (c == 0xE3 && pos + 1 < s.size() &&
(unsigned char)s[pos+1] == 0x80) return true;
return false;
}
// ============================================================
// 标点表
// ============================================================
static const vector<pair<string,string> >& get_punct_pairs() {
static vector<pair<string,string> > list;
static bool ready = false;
if (!ready) {
struct { const char* f; const char* t; } raw[] = {
{"(","("},{")",")"},{"「","["},{"」","]"},
{"【","{"},{"】","}"},{"《","{"},{"》","}"},
{",",","},{"、",","},{";",";"},{":"," << "}
};
for (size_t i = 0; i < sizeof(raw)/sizeof(raw[0]); ++i)
list.push_back(make_pair(to_ansi(raw[i].f), string(raw[i].t)));
ready = true;
}
return list;
}
static const vector<string>& get_punct_list() {
static vector<string> list;
static bool ready = false;
if (!ready) {
const char* raw[] = {";",":",",","。","、","!","?",
"(",")","【","】","「","」","《","》"," "};
for (size_t i = 0; i < sizeof(raw)/sizeof(raw[0]); ++i)
list.push_back(to_ansi(raw[i]));
ready = true;
}
return list;
}
static bool is_punct_pattern(const string& from) {
const vector<string>& L = get_punct_list();
for (size_t k = 0; k < L.size(); ++k) if (from == L[k]) return true;
return false;
}
static bool ends_with_any_punct(const string& s) {
const vector<string>& L = get_punct_list();
for (size_t k = 0; k < L.size(); ++k) {
size_t n = L[k].size();
if (s.size() >= n && s.compare(s.size()-n, n, L[k]) == 0) return true;
}
return false;
}
static bool is_cjk_terminator_at(const string& s, size_t pos) {
const vector<string>& L = get_punct_list();
for (size_t k = 0; k < L.size(); ++k) {
size_t n = L[k].size();
if (pos + n <= s.size() && s.compare(pos, n, L[k]) == 0)
return true;
}
return false;
}
static string translate_punct_only(const string& s) {
const vector<pair<string,string> >& subs = get_punct_pairs();
string r = s;
for (size_t k = 0; k < subs.size(); ++k) {
const string& from = subs[k].first;
const string& to = subs[k].second;
if (from.empty()) continue;
size_t flen = from.size(), tlen = to.size(), pos = 0;
while ((pos = r.find(from, pos)) != string::npos) {
r.replace(pos, flen, to);
pos += tlen;
}
}
return r;
}
static string translate_msg_args(const string& s) {
static vector<pair<string,string> > subs;
static bool ready = false;
if (!ready) {
subs.push_back(make_pair(to_ansi("("), "("));
subs.push_back(make_pair(to_ansi(")"), ")"));
subs.push_back(make_pair(to_ansi(","), ","));
subs.push_back(make_pair(to_ansi(";"), ";"));
subs.push_back(make_pair(to_ansi(":"), ":"));
ready = true;
}
string r;
size_t i = 0;
while (i < s.size()) {
if (s[i] == '"') {
r += s[i++];
while (i < s.size()) {
if (s[i] == '\\' && i + 1 < s.size()) { r += s[i++]; r += s[i++]; continue; }
if (s[i] == '"') { r += s[i++]; break; }
r += s[i++];
}
continue;
}
bool ok = false;
for (size_t k = 0; k < subs.size(); ++k) {
if (i + subs[k].first.size() <= s.size() &&
s.compare(i, subs[k].first.size(), subs[k].first) == 0) {
r += subs[k].second;
i += subs[k].first.size();
ok = true;
break;
}
}
if (!ok) r += s[i++];
}
return r;
}
static const char* GetFilterAnsi() {
static const char RAW[] = "玄源文件\0*.玄\0所有文件\0*.*\0";
static const string ANSI = to_ansi_n(RAW, sizeof(RAW) - 1);
return ANSI.c_str();
}
static const char* GetDefExtAnsi() {
static const string s = to_ansi("玄");
return s.c_str();
}
// ============================================================
// S2:线程安全的表初始化
// ============================================================
static const vector<pair<string,string> >& get_type_tbl() {
static const vector<pair<string,string> > v = []() {
vector<pair<string,string> > p;
if (g_types_loaded) ParseKV(g_types_content, p);
return p;
}();
return v;
}
static const vector<pair<string,string> >& get_patterns() {
static const vector<pair<string,string> > v = []() {
vector<pair<string,string> > p;
if (g_patterns_loaded) {
ParseKV(g_patterns_content, p);
sort(p.begin(), p.end(),
[](const pair<string,string>& a, const pair<string,string>& b) {
return a.first.size() > b.first.size();
});
}
return p;
}();
return v;
}
// R3:map_simple_type 用循环,无递归
static string map_simple_type(const string& t) {
static string FWSP, PTR_KW;
static bool ready = false;
if (!ready) {
FWSP = to_ansi(" ");
PTR_KW = to_ansi("指针");
ready = true;
}
string tt = t;
size_t fl = FWSP.size();
while (tt.size() >= fl && tt.compare(0, fl, FWSP) == 0) tt = tt.substr(fl);
while (tt.size() >= fl && tt.compare(tt.size()-fl, fl, FWSP) == 0)
tt = tt.substr(0, tt.size()-fl);
size_t s = 0, e = tt.size();
while (s < e && isspace((unsigned char)tt[s])) s++;
while (e > s && isspace((unsigned char)tt[e-1])) e--;
tt = tt.substr(s, e - s);
// 循环剥离 "指针" 后缀,最多 8 层
int ptr_count = 0;
const int MAX_PTR = 8;
while (ptr_count < MAX_PTR) {
if (tt.size() > PTR_KW.size() &&
tt.compare(tt.size()-PTR_KW.size(), PTR_KW.size(), PTR_KW) == 0) {
ptr_count++;
tt = tt.substr(0, tt.size() - PTR_KW.size());
// 剥后再剥一次空白
size_t s2 = 0, e2 = tt.size();
while (s2 < e2 && isspace((unsigned char)tt[s2])) s2++;
while (e2 > s2 && isspace((unsigned char)tt[e2-1])) e2--;
tt = tt.substr(s2, e2 - s2);
} else break;
}
const vector<pair<string,string> >& tbl = get_type_tbl();
string base;
bool found = false;
for (size_t k = 0; k < tbl.size(); ++k) {
if (tt == tbl[k].first) { base = tbl[k].second; found = true; break; }
}
if (!found) base = tt;
for (int i = 0; i < ptr_count; ++i) base += "*";
return base;
}
// ============================================================
// S3:帮助文本,首次失败不重试
// ============================================================
static const string& GetHelpAnsi() {
static string s;
static bool tried = false;
if (!tried) {
tried = true;
string content;
if (LoadTextFile("help.txt", content)) s = content;
else s = to_ansi("《玄》语言用法大全\n\n(help.txt 未找到,请确认 data 目录)\n");
}
return s;
}
// ============================================================
// translate_xuan
// ============================================================
string translate_xuan(const string& src) {
const vector<pair<string,string> >& patterns = get_patterns();
static string BI, XIAO, DA, ZUO, YOU, KUO_L, KUO_R, FENHAO, FW_COMMA;
static bool kw_ready = false;
if (!kw_ready) {
BI = to_ansi("比"); XIAO = to_ansi("小"); DA = to_ansi("大");
ZUO = to_ansi("("); YOU = to_ansi(")");
KUO_L = to_ansi("《"); KUO_R = to_ansi("》");
FENHAO = to_ansi(";");
FW_COMMA = to_ansi(",");
kw_ready = true;
}
const size_t BI_LEN = BI.size(), XIAO_LEN = XIAO.size(), DA_LEN = DA.size();
const size_t ZUO_LEN = ZUO.size(), YOU_LEN = YOU.size();
const size_t KUO_L_LEN = KUO_L.size(), KUO_R_LEN = KUO_R.size();
const size_t FENHAO_LEN = FENHAO.size(), FW_COMMA_LEN = FW_COMMA.size();
static string REPEAT_KW, TIMES_KW, FOR_KW, CONG_KW, DAO_KW, DEC_KW, GUA_KW, HUAN_KW;
static string BIANLI_KW, ZAI_KW, ZHONG_KW;
static bool new_kw_ready = false;
if (!new_kw_ready) {
REPEAT_KW = to_ansi("重复");
TIMES_KW = to_ansi("次");
FOR_KW = to_ansi("对于");
CONG_KW = to_ansi("从");
DAO_KW = to_ansi("到");
DEC_KW = to_ansi("递减");
GUA_KW = to_ansi("卦");
HUAN_KW = to_ansi("环");
BIANLI_KW = to_ansi("遍历");
ZAI_KW = to_ansi("在");
ZHONG_KW = to_ansi("中");
new_kw_ready = true;
}
const size_t REPEAT_LEN = REPEAT_KW.size(), TIMES_LEN = TIMES_KW.size();
const size_t FOR_KW_LEN = FOR_KW.size(), CONG_LEN = CONG_KW.size();
const size_t DAO_LEN = DAO_KW.size(), DEC_LEN = DEC_KW.size();
const size_t GUA_LEN = GUA_KW.size(), HUAN_LEN = HUAN_KW.size();
const size_t BIANLI_LEN = BIANLI_KW.size(), ZAI_LEN = ZAI_KW.size();
const size_t ZHONG_LEN = ZHONG_KW.size();
static string ZE_SPACE_KW, ZE_KW;
static bool ze_ready = false;
if (!ze_ready) {
ZE_SPACE_KW = to_ansi("则 ");
ZE_KW = to_ansi("则");
ze_ready = true;
}
static vector<pair<string,string> > SP_TBL;
static bool sp_ready = false;
if (!sp_ready) {
SP_TBL.push_back(make_pair(to_ansi("独占指针《"), "std::unique_ptr<"));
SP_TBL.push_back(make_pair(to_ansi("共享指针《"), "std::shared_ptr<"));
SP_TBL.push_back(make_pair(to_ansi("弱引用《"), "std::weak_ptr<"));
SP_TBL.push_back(make_pair(to_ansi("新建独占《"), "std::make_unique<"));
SP_TBL.push_back(make_pair(to_ansi("新建共享《"), "std::make_shared<"));
sort(SP_TBL.begin(), SP_TBL.end(),
[](const pair<string,string>& a, const pair<string,string>& b) {
return a.first.size() > b.first.size();
});
sp_ready = true;
}
static vector<pair<string,string> > CAST_TBL;
static bool cast_ready = false;
if (!cast_ready) {
CAST_TBL.push_back(make_pair(to_ansi("重解释转"), "reinterpret_cast"));
CAST_TBL.push_back(make_pair(to_ansi("静态转"), "static_cast"));
CAST_TBL.push_back(make_pair(to_ansi("动态转"), "dynamic_cast"));
CAST_TBL.push_back(make_pair(to_ansi("常量转"), "const_cast"));
sort(CAST_TBL.begin(), CAST_TBL.end(),
[](const pair<string,string>& a, const pair<string,string>& b) {
return a.first.size() > b.first.size();
});
cast_ready = true;
}
static string DANK_KW, XIAOXI_KW, DYX_KW;
static bool misc_ready = false;
if (!misc_ready) {
DANK_KW = to_ansi("弹窗(");
XIAOXI_KW = to_ansi("消息框(");
DYX_KW = to_ansi("读一行");
misc_ready = true;
}
vector<int> repeat_stack;
int next_rep_id = 0;
string out;
size_t i = 0;
const size_t N = src.size();
while (i < N) {
if (src[i] == '"') {
out += src[i++];
while (i < N) {
if (src[i] == '\\' && i+1 < N) { out += src[i++]; out += src[i++]; continue; }
if (src[i] == '"') break;
out += src[i++];
}
if (i < N) out += src[i++];
continue;
}
if (src[i] == '\\' && i + 1 < N) {
size_t clen = advance_one_char(src, i + 1);
size_t end = i + 1 + clen;
while (end < N) {
if (is_cjk_terminator_at(src, end)) break;
unsigned char c = (unsigned char)src[end];
if (c < 0x80) {
if (is_ascii_ident(c)) { end++; continue; }
break;
}
end += advance_one_char(src, end);
}
out += src.substr(i + 1, end - i - 1);
i = end;
continue;
}
if (src[i] == '/' && i+1 < N && src[i+1] == '/') {
while (i < N && src[i] != '\n') out += src[i++];
continue;
}
if (src[i] == '/' && i+1 < N && src[i+1] == '*') {
out += src[i++]; out += src[i++];
while (i < N && !(src[i-1] == '*' && src[i] == '/')) out += src[i++];
if (i < N) out += src[i++];
continue;
}
bool matched = false;
// 读一行
if (!matched && !DYX_KW.empty() && i + DYX_KW.size() <= N &&
src.compare(i, DYX_KW.size(), DYX_KW) == 0) {
if (i == 0 || !is_ascii_ident((unsigned char)src[i-1])) {
size_t j = i + DYX_KW.size();
while (j < N && isspace((unsigned char)src[j])) j++;
size_t es = j;
bool in_str = false, esc = false;
while (j < N) {
unsigned char c = (unsigned char)src[j];
if (esc) { esc = false; j++; continue; }
if (in_str) {
if (c == '\\') { esc = true; j++; continue; }
if (c == '"') { in_str = false; j++; continue; }
j++; continue;
}
if (c == '"') { in_str = true; j++; continue; }
if (c == ';') break;
if (j + FENHAO_LEN <= N && src.compare(j, FENHAO_LEN, FENHAO) == 0) break;
j += advance_one_char(src, j);
}
if (j > es) {
string expr = src.substr(es, j - es);
while (!expr.empty() && isspace((unsigned char)expr.back())) expr.pop_back();
out += "getline(cin, " + expr + ");";
if (j < N && src[j] == ';') j++;
else if (j + FENHAO_LEN <= N &&
src.compare(j, FENHAO_LEN, FENHAO) == 0) j += FENHAO_LEN;
i = j;
matched = true;
}
}
}
// 弹窗/消息框
if (!matched) {
const string* kw = NULL;
if (i + DANK_KW.size() <= N &&
src.compare(i, DANK_KW.size(), DANK_KW) == 0 &&
(i == 0 || !is_ascii_ident((unsigned char)src[i-1])))
kw = &DANK_KW;
else if (i + XIAOXI_KW.size() <= N &&
src.compare(i, XIAOXI_KW.size(), XIAOXI_KW) == 0 &&
(i == 0 || !is_ascii_ident((unsigned char)src[i-1])))
kw = &XIAOXI_KW;
if (kw) {
size_t j = i + kw->size();
size_t ps = j;
int depth = 0;
bool in_str = false, esc = false;
size_t close_pos = 0, close_len = 0;
while (j < N) {
unsigned char c = (unsigned char)src[j];
if (esc) { esc = false; j++; continue; }
if (in_str) {
if (c == '\\') { esc = true; j++; continue; }
if (c == '"') { in_str = false; j++; continue; }
j++; continue;
}
if (c == '"') { in_str = true; j++; continue; }
if (c == '(') { depth++; j++; continue; }
if (c == ')') {
if (depth == 0) { close_pos = j; close_len = 1; break; }
depth--; j++; continue;
}
if (j + ZUO_LEN <= N && src.compare(j, ZUO_LEN, ZUO) == 0) {
depth++; j += ZUO_LEN; continue;
}
if (j + YOU_LEN <= N && src.compare(j, YOU_LEN, YOU) == 0) {
if (depth == 0) { close_pos = j; close_len = YOU_LEN; break; }
depth--; j += YOU_LEN; continue;
}
j += advance_one_char(src, j);
}
if (close_pos > 0) {
string args = src.substr(ps, close_pos - ps);
int commas = 0;
bool ins = false, es = false;
for (size_t p = 0; p < args.size(); ) {
unsigned char a = (unsigned char)args[p];
if (es) { es = false; p++; continue; }
if (ins) {
if (a == '\\') { es = true; p++; continue; }
if (a == '"') { ins = false; p++; continue; }
p++; continue;
}
if (a == '"') { ins = true; p++; continue; }
if (a == ',') { commas++; p++; continue; }
if (p + FW_COMMA_LEN <= args.size() &&
args.compare(p, FW_COMMA_LEN, FW_COMMA) == 0) {
commas++; p += FW_COMMA_LEN; continue;
}
p += advance_one_char(args, p);
}
string args2 = translate_msg_args(args);
out += "MessageBoxA(NULL, ";
out += args2;
if (commas == 1) out += ", MB_OK";
out += ")";
i = close_pos + close_len;
matched = true;
}
}
}
// 智能指针
if (!matched) {
for (size_t k = 0; k < SP_TBL.size(); ++k) {
const string& from = SP_TBL[k].first;
const string& to = SP_TBL[k].second;
if (i + from.size() > N) continue;
if (src.compare(i, from.size(), from) != 0) continue;
if (i > 0 && is_ascii_ident((unsigned char)src[i-1])) continue;
size_t j = i + from.size();
size_t ts = j;
while (j < N && !(j + KUO_R_LEN <= N && src.compare(j, KUO_R_LEN, KUO_R) == 0))
j += advance_one_char(src, j);
if (j >= N) continue;
string T = src.substr(ts, j - ts);
string Tc = map_simple_type(T);
out += to + Tc + ">";
i = j + KUO_R_LEN;
matched = true;
break;
}
}
// cast
if (!matched) {
for (size_t k = 0; k < CAST_TBL.size(); ++k) {
const string& kw = CAST_TBL[k].first;
const string& cpp = CAST_TBL[k].second;
if (i + kw.size() > N) continue;
if (src.compare(i, kw.size(), kw) != 0) continue;
if (i > 0 && is_ascii_ident((unsigned char)src[i-1])) continue;
size_t j = i + kw.size();
while (j < N && isspace((unsigned char)src[j])) j++;
if (!(j + ZUO_LEN <= N && src.compare(j, ZUO_LEN, ZUO) == 0)) continue;
j += ZUO_LEN;
size_t ts = j;
while (j < N && !(j + YOU_LEN <= N && src.compare(j, YOU_LEN, YOU) == 0))
j += advance_one_char(src, j);
if (j >= N) continue;
string T = src.substr(ts, j - ts);
string Tc = map_simple_type(T);
out += cpp + "<" + Tc + ">";
i = j + YOU_LEN;
matched = true;
break;
}
}
// 重复 N 次
if (!matched && REPEAT_LEN > 0 && i + REPEAT_LEN <= N &&
src.compare(i, REPEAT_LEN, REPEAT_KW) == 0) {
if (i == 0 || !is_ascii_ident((unsigned char)src[i-1])) {
size_t probe = i + REPEAT_LEN;
while (probe < N && isspace((unsigned char)src[probe])) probe++;
bool valid_next = false;
if (probe < N) {
unsigned char nc = (unsigned char)src[probe];
if (nc < 0x80) {
if ((nc >= '0' && nc <= '9') ||
(nc >= 'a' && nc <= 'z') ||
(nc >= 'A' && nc <= 'Z') ||
nc == '_' || nc == '(' ||
nc == '+' || nc == '-' ||
nc == '!' || nc == '~') valid_next = true;
} else {
if (probe + ZUO_LEN <= N &&
src.compare(probe, ZUO_LEN, ZUO) == 0)
valid_next = true;
}
}
if (valid_next) {
int id = next_rep_id++;
repeat_stack.push_back(id);
out += "for (int _i_rep_" + to_string(id) + " = 0; _i_rep_"
+ to_string(id) + " < (";
i += REPEAT_LEN;
matched = true;
}
}
}
// 次(R2:加 is_cjk_terminator_at)
if (!matched && !repeat_stack.empty() && TIMES_LEN > 0 &&
i + TIMES_LEN <= N && src.compare(i, TIMES_LEN, TIMES_KW) == 0) {
if (i == 0 || !is_ascii_ident((unsigned char)src[i-1])) {
size_t aft = i + TIMES_LEN;
unsigned char nx = (aft < N) ? (unsigned char)src[aft] : (unsigned char)0;
if (nx == 0 || isspace(nx) ||
is_cjk_terminator_at(src, aft) ||
(aft + KUO_L_LEN <= N &&
src.compare(aft, KUO_L_LEN, KUO_L) == 0)) {
int id = repeat_stack.back();
repeat_stack.pop_back();
out += "); _i_rep_" + to_string(id) + "++) ";
i = aft;
matched = true;
}
}
}
// 遍历
if (!matched && BIANLI_LEN > 0 && i + BIANLI_LEN <= N &&
src.compare(i, BIANLI_LEN, BIANLI_KW) == 0) {
if (i == 0 || !is_ascii_ident((unsigned char)src[i-1])) {
size_t j = i + BIANLI_LEN;
while (j < N && isspace((unsigned char)src[j])) j++;
size_t vs = j;
while (j < N && !isspace((unsigned char)src[j]) &&
!(j + ZAI_LEN <= N && src.compare(j, ZAI_LEN, ZAI_KW) == 0))
j += advance_one_char(src, j);
size_t ve = j;
while (j < N && isspace((unsigned char)src[j])) j++;
if (ve > vs && j + ZAI_LEN <= N &&
src.compare(j, ZAI_LEN, ZAI_KW) == 0) {
string var = src.substr(vs, ve - vs);
j += ZAI_LEN;
while (j < N && isspace((unsigned char)src[j])) j++;
size_t cs = j;
while (j < N && !isspace((unsigned char)src[j]) &&
!(j + ZHONG_LEN <= N && src.compare(j, ZHONG_LEN, ZHONG_KW) == 0))
j += advance_one_char(src, j);
size_t ce = j;
while (j < N && isspace((unsigned char)src[j])) j++;
if (ce > cs && j + ZHONG_LEN <= N &&
src.compare(j, ZHONG_LEN, ZHONG_KW) == 0) {
j += ZHONG_LEN;
while (j < N && isspace((unsigned char)src[j])) j++;
if (j + KUO_L_LEN <= N &&
src.compare(j, KUO_L_LEN, KUO_L) == 0) {
string cont = src.substr(cs, ce - cs);
out += "for (auto " + var + " : " + cont + ") {";
i = j + KUO_L_LEN;
matched = true;
}
}
}
}
}
// 对于 X 从 A 到 B [递减]
if (!matched && FOR_KW_LEN > 0 && i + FOR_KW_LEN <= N &&
src.compare(i, FOR_KW_LEN, FOR_KW) == 0) {
if (i == 0 || !is_ascii_ident((unsigned char)src[i-1])) {
size_t j = i + FOR_KW_LEN;
while (j < N && isspace((unsigned char)src[j])) j++;
size_t vs = j;
while (j < N && !isspace((unsigned char)src[j]) &&
!(j + CONG_LEN <= N &&
src.compare(j, CONG_LEN, CONG_KW) == 0))
j += advance_one_char(src, j);
size_t ve = j;
while (j < N && isspace((unsigned char)src[j])) j++;
if (ve > vs && j + CONG_LEN <= N &&
src.compare(j, CONG_LEN, CONG_KW) == 0) {
string var = src.substr(vs, ve - vs);
j += CONG_LEN;
while (j < N && isspace((unsigned char)src[j])) j++;
size_t as = j;
while (j < N && !isspace((unsigned char)src[j]) &&
!(j + DAO_LEN <= N &&
src.compare(j, DAO_LEN, DAO_KW) == 0))
j += advance_one_char(src, j);
size_t ae = j;
while (j < N && isspace((unsigned char)src[j])) j++;
if (ae > as && j + DAO_LEN <= N &&
src.compare(j, DAO_LEN, DAO_KW) == 0) {
string A = src.substr(as, ae - as);
j += DAO_LEN;
while (j < N && isspace((unsigned char)src[j])) j++;
size_t bs = j;
while (j < N && !isspace((unsigned char)src[j]) &&
!(j + DEC_LEN <= N &&
src.compare(j, DEC_LEN, DEC_KW) == 0) &&
!(j + KUO_L_LEN <= N &&
src.compare(j, KUO_L_LEN, KUO_L) == 0)) {
if (is_cjk_terminator_at(src, j)) break;
j += advance_one_char(src, j);
}
size_t be = j;
if (be > bs) {
string B = src.substr(bs, be - bs);
while (j < N && isspace((unsigned char)src[j])) j++;
bool desc = false;
if (j + DEC_LEN <= N &&
src.compare(j, DEC_LEN, DEC_KW) == 0) {
desc = true; j += DEC_LEN;
}
out += "for (int " + var + " = " + A + "; " + var;
out += desc ? " >= " : " <= ";
out += B + "; " + var;
out += desc ? "--" : "++";
out += ") ";
i = j;
matched = true;
}
}
}
}
}
// 环
if (!matched && HUAN_LEN > 0 && i + HUAN_LEN <= N &&
src.compare(i, HUAN_LEN, HUAN_KW) == 0) {
if (i == 0 || !is_ascii_ident((unsigned char)src[i-1])) {
size_t j = i + HUAN_LEN;
while (j < N && isspace((unsigned char)src[j])) j++;
if (j + KUO_L_LEN <= N &&
src.compare(j, KUO_L_LEN, KUO_L) == 0) {
out += "while (true) {";
i = j + KUO_L_LEN;
matched = true;
}
}
}
// 卦
if (!matched && GUA_LEN > 0 && i + GUA_LEN <= N &&
src.compare(i, GUA_LEN, GUA_KW) == 0) {
if (i == 0 || !is_ascii_ident((unsigned char)src[i-1])) {
size_t j = i + GUA_LEN;
while (j < N && isspace((unsigned char)src[j])) j++;
size_t as = j;
while (j < N && !isspace((unsigned char)src[j]) &&
src[j] != ';' && src[j] != ')' &&
src[j] != ',' && src[j] != '(' &&
src[j] != '{' && src[j] != '}') {
if (j + DAO_LEN <= N &&
src.compare(j, DAO_LEN, DAO_KW) == 0) break;
if (is_cjk_terminator_at(src, j)) break;
j += advance_one_char(src, j);
}
size_t ae = j;
if (ae > as) {
while (j < N && isspace((unsigned char)src[j])) j++;
if (j + DAO_LEN <= N &&
src.compare(j, DAO_LEN, DAO_KW) == 0) {
j += DAO_LEN;
while (j < N && isspace((unsigned char)src[j])) j++;
size_t bs = j;
while (j < N && !isspace((unsigned char)src[j]) &&
src[j] != ';' && src[j] != ')' &&
src[j] != ',' && src[j] != '(' &&
src[j] != '{' && src[j] != '}') {
if (is_cjk_terminator_at(src, j)) break;
j += advance_one_char(src, j);
}
size_t be = j;
if (be > bs) {
string A = src.substr(as, ae - as);
string B = src.substr(bs, be - bs);
out += "((rand() % ((" + B + ") - (" + A
+ ") + 1)) + (" + A + "))";
i = j;
matched = true;
}
} else {
string N_ = src.substr(as, ae - as);
out += "(rand() % (" + N_ + "))";
i = ae;
matched = true;
}
}
}
}
// 比
if (!matched && BI_LEN > 0 && i + BI_LEN <= N && src.compare(i, BI_LEN, BI) == 0) {
bool boundary_ok = (i == 0) || !is_ascii_ident((unsigned char)src[i-1]);
if (!boundary_ok) {
size_t probe = i + BI_LEN;
if (probe < N) {
unsigned char p = (unsigned char)src[probe];
bool sp = isspace(p) != 0;
bool xa = (probe + XIAO_LEN <= N && src.compare(probe, XIAO_LEN, XIAO) == 0);
bool da = (probe + DA_LEN <= N && src.compare(probe, DA_LEN, DA) == 0);
boundary_ok = !sp && !xa && !da;
}
}
if (boundary_ok) {
size_t v1_end = i;
while (v1_end > 0 && isspace((unsigned char)src[v1_end-1])) v1_end--;
size_t v1_start = v1_end;
while (v1_start > 0 &&
!isspace((unsigned char)src[v1_start-1]) &&
src[v1_start-1] != '(' &&
!(v1_start >= ZUO_LEN && src.compare(v1_start - ZUO_LEN, ZUO_LEN, ZUO) == 0))
v1_start--;
size_t j = i + BI_LEN;
while (j < N && isspace((unsigned char)src[j])) j++;
size_t v2_start = j, v2_end = j;
int depth = 0;
const size_t MAX_SCAN = 4096;
while (v2_end < N && (v2_end - v2_start) < MAX_SCAN) {
unsigned char c = (unsigned char)src[v2_end];
if (c == '(') { depth++; v2_end++; continue; }
if (c == ')') { if (depth == 0) break; depth--; v2_end++; continue; }
if (v2_end + ZUO_LEN <= N && src.compare(v2_end, ZUO_LEN, ZUO) == 0) { depth++; v2_end += ZUO_LEN; continue; }
if (v2_end + YOU_LEN <= N && src.compare(v2_end, YOU_LEN, YOU) == 0) { if (depth == 0) break; depth--; v2_end += YOU_LEN; continue; }
if (depth == 0) {
if (isspace(c) || c == ';' || c == '{' || c == '}') break;
if (v2_end + KUO_L_LEN <= N && src.compare(v2_end, KUO_L_LEN, KUO_L) == 0) break;
if (v2_end + KUO_R_LEN <= N && src.compare(v2_end, KUO_R_LEN, KUO_R) == 0) break;
if (v2_end + XIAO_LEN <= N && src.compare(v2_end, XIAO_LEN, XIAO) == 0) break;
if (v2_end + DA_LEN <= N && src.compare(v2_end, DA_LEN, DA) == 0) break;
}
v2_end += advance_one_char(src, v2_end);
}
size_t after = v2_end;
while (after < N && isspace((unsigned char)src[after])) after++;
bool is_xiao = (after + XIAO_LEN <= N && src.compare(after, XIAO_LEN, XIAO) == 0);
bool is_da = (after + DA_LEN <= N && src.compare(after, DA_LEN, DA) == 0);
if (v1_end > v1_start && v2_end > v2_start && (is_xiao || is_da)) {
char op = is_xiao ? '<' : '>';
string var2 = src.substr(v2_start, v2_end - v2_start);
var2 = translate_punct_only(var2);
while (!out.empty() && isspace((unsigned char)out.back())) out.pop_back();
out += " "; out += op; out += " "; out += var2;
i = after + (is_xiao ? XIAO_LEN : DA_LEN);
matched = true;
}
}
}
// 常规 pattern
if (!matched) {
for (size_t k = 0; k < patterns.size(); ++k) {
const string& from = patterns[k].first;
const string& to = patterns[k].second;
if (from.empty() || i + from.size() > N) continue;
if (src.compare(i, from.size(), from) != 0) continue;
if ((from == ZE_SPACE_KW || from == ZE_KW) &&
i > 0 && (unsigned char)src[i-1] >= 0x80)
continue;
if (!is_punct_pattern(from) &&
i > 0 && is_ascii_ident((unsigned char)src[i-1])) continue;
if (ends_with_cjk_hanzi(from) && !ends_with_any_punct(from)) {
size_t end = i + from.size();
if (end < N) {
unsigned char next = (unsigned char)src[end];
if (is_ascii_ident(next)) continue;
if (next >= 0x80 && !is_fullwidth_punct_at(src, end)) continue;
}
}
out += to;
i += from.size();
matched = true;
break;
}
}
if (!matched) out += src[i++];
}
return out;
}
// ============================================================
// 后台任务
// ============================================================
struct CompileJob { string src; bool runAfter; };
static void FinishByStop() {
g_stopRequested.store(false);
if (g_hMainWnd) PostMessage(g_hMainWnd, WM_COMPILE_FINISHED, 0, 0);
}
static bool RunAndCapture(const string& cmdline,
std::atomic<HANDLE>* pSlot,
string& output) {
SECURITY_ATTRIBUTES sa = {};
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
HANDLE hRead = NULL, hWrite = NULL;
if (!CreatePipe(&hRead, &hWrite, &sa, 0)) return false;
SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0);
HANDLE hNul = CreateFileA("NUL", GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (hNul == INVALID_HANDLE_VALUE) hNul = NULL;
STARTUPINFOA si = { sizeof(si) };
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.hStdOutput = hWrite;
si.hStdError = hWrite;
si.hStdInput = hNul;
PROCESS_INFORMATION pi = {};
vector<char> cmdbuf(cmdline.begin(), cmdline.end());
cmdbuf.push_back('\0');
BOOL ok = CreateProcessA(NULL, &cmdbuf[0], NULL, NULL, TRUE,
CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
CloseHandle(hWrite);
if (hNul) CloseHandle(hNul);
if (!ok) { CloseHandle(hRead); return false; }
if (pSlot) pSlot->store(pi.hProcess);
CloseHandle(pi.hThread);
char buf[1024];
DWORD rd = 0;
while (ReadFile(hRead, buf, sizeof(buf) - 1, &rd, NULL) && rd > 0)
output.append(buf, rd);
CloseHandle(hRead);
WaitForSingleObject(pi.hProcess, INFINITE);
DWORD ec = 1;
GetExitCodeProcess(pi.hProcess, &ec);
if (pSlot) pSlot->store(NULL);
CloseHandle(pi.hProcess);
return (ec == 0);
}
void CompileAndRunTask(const string& src, bool runAfter) {
if (g_stopRequested.load()) { FinishByStop(); return; }
string cppPath = g_tempDir + "\\output.cpp";
string exePath = g_tempDir + "\\output.exe";
string cpp = translate_xuan(src);
{
static const string GUA_NEEDLE = to_ansi("卦");
if (cpp.find(GUA_NEEDLE) != string::npos ||
src.find(GUA_NEEDLE) != string::npos) {
string inject =
"// 玄 v3.8.2:检测到 卦,自动注入随机种子\n"
"#include <cstdlib>\n"
"#include <ctime>\n"
"namespace { struct _xuan_srand_init {"
" _xuan_srand_init(){ srand((unsigned)time(0)); }"
" } _xuan_srand_instance; }\n";
cpp = inject + cpp;
}
}
// R5:检查写文件
if (!write_file(cppPath, cpp)) {
string* pMsg = new string(
to_ansi("❌ 无法写入 output.cpp(磁盘满 / 权限不足)\n路径:")
+ cppPath + "\n");
if (g_hMainWnd) PostMessage(g_hMainWnd, WM_UPDATE_OUTPUT, 0, (LPARAM)pMsg);
else delete pMsg;
if (g_hMainWnd) PostMessage(g_hMainWnd, WM_COMPILE_FINISHED, 0, 0);
return;
}
string buildLog;
string gppCmd = "g++ \"" + cppPath + "\" -o \"" + exePath + "\" "
"-std=c++17 -pthread "
"-finput-charset=GBK -fexec-charset=GBK "
"-lgdi32 -luser32 -lcomctl32";
bool compileOK = RunAndCapture(gppCmd, &g_hGppProcess, buildLog);
if (g_stopRequested.load()) { FinishByStop(); return; }
if (!compileOK) {
string* pMsg = new string(
to_ansi("❌ 编译失败:\n") + buildLog
+ to_ansi("\n提示:转译后的 C++ 源码在 ") + cppPath + "\n");
if (g_hMainWnd) PostMessage(g_hMainWnd, WM_UPDATE_OUTPUT, 0, (LPARAM)pMsg);
else delete pMsg;
if (g_hMainWnd) PostMessage(g_hMainWnd, WM_COMPILE_FINISHED, 0, 0);
return;
}
string* pMsg = new string(to_ansi("✅ 编译成功!\n") + buildLog);
if (g_hMainWnd) PostMessage(g_hMainWnd, WM_UPDATE_OUTPUT, 0, (LPARAM)pMsg);
else delete pMsg;
if (runAfter) {
if (g_stopRequested.load()) { FinishByStop(); return; }
string outputLog;
string runCmd = "\"" + exePath + "\"";
RunAndCapture(runCmd, &g_hOutputProcess, outputLog);
if (g_stopRequested.load()) { FinishByStop(); return; }
if (looks_like_utf8(outputLog)) outputLog = utf8_to_ansi(outputLog);
string* pRun = new string(to_ansi("\n▶ 程序输出:\n--------------------\n")
+ outputLog
+ to_ansi("\n--------------------\n"));
if (g_hMainWnd) PostMessage(g_hMainWnd, WM_UPDATE_OUTPUT, 1, (LPARAM)pRun);
else delete pRun;
}
if (g_hMainWnd) PostMessage(g_hMainWnd, WM_COMPILE_FINISHED, 0, 0);
}
unsigned __stdcall CompileThreadProc(void* lpParam) {
CompileJob* pJob = (CompileJob*)lpParam;
if (!pJob) return 0;
CompileAndRunTask(pJob->src, pJob->runAfter);
delete pJob;
return 0;
}
void KillOutputExe() {
HANDLE hGpp = g_hGppProcess.load();
if (hGpp) TerminateProcess(hGpp, 1);
HANDLE hOut = g_hOutputProcess.load();
if (hOut) TerminateProcess(hOut, 1);
}
// ============================================================
// 帮助窗口
// ============================================================
LRESULT CALLBACK HelpWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE: {
g_hHelpEdit = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT",
GetHelpAnsi().c_str(),
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_READONLY |
ES_AUTOVSCROLL | WS_VSCROLL | ES_AUTOHSCROLL | WS_HSCROLL,
10, 10, 100, 100, hWnd, NULL, g_hInst, NULL);
g_hHelpFont = CreateFont(16, 0, 0, 0, FW_NORMAL, 0, 0, 0,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, XA("新宋体"));
SendMessage(g_hHelpEdit, WM_SETFONT, (WPARAM)g_hHelpFont, TRUE);
return 0;
}
case WM_SIZE: {
if (g_hHelpEdit)
SetWindowPos(g_hHelpEdit, NULL, 10, 10,
LOWORD(lParam) - 20, HIWORD(lParam) - 20, SWP_NOZORDER);
return 0;
}
case WM_CLOSE: DestroyWindow(hWnd); return 0;
case WM_DESTROY:
if (g_hHelpFont) { DeleteObject(g_hHelpFont); g_hHelpFont = NULL; }
g_hHelpWnd = NULL; g_hHelpEdit = NULL;
return 0;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
}
void ShowHelp() {
if (g_hHelpWnd && IsWindow(g_hHelpWnd)) {
SetForegroundWindow(g_hHelpWnd);
return;
}
WNDCLASSA wcCheck = {};
if (!GetClassInfoA(g_hInst, "XuanHelpWnd", &wcCheck)) {
WNDCLASSA wc = {};
wc.lpfnWndProc = HelpWndProc;
wc.hInstance = g_hInst;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = "XuanHelpWnd";
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_INFORMATION);
RegisterClassA(&wc);
}
g_hHelpWnd = CreateWindowExA(0, "XuanHelpWnd", XA("《玄》语言用法大全"),
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 700,
g_hMainWnd, NULL, g_hInst, NULL);
if (!g_hHelpWnd) return;
ShowWindow(g_hHelpWnd, SW_SHOW);
UpdateWindow(g_hHelpWnd);
EnableWindow(g_hMainWnd, FALSE);
MSG msg;
while (g_hHelpWnd && IsWindow(g_hHelpWnd) && GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
EnableWindow(g_hMainWnd, TRUE);
SetForegroundWindow(g_hMainWnd);
}
// ============================================================
// 文件操作
// ============================================================
void SetStatusText(const string& text) {
SendMessageA(g_hStatusBar, SB_SETTEXTA, 0, (LPARAM)text.c_str());
}
static bool IsDirty() {
if (!g_hEdit) return false;
return SendMessage(g_hEdit, EM_GETMODIFY, 0, 0) != 0;
}
static void ClearDirty() {
if (g_hEdit) SendMessage(g_hEdit, EM_SETMODIFY, FALSE, 0);
}
bool SaveFile(const string& content, bool saveAs=false) {
if (saveAs || g_currentFilePath.empty()) {
OPENFILENAMEA ofn = {};
char fileName[MAX_PATH] = "";
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = g_hMainWnd;
ofn.lpstrFilter = GetFilterAnsi();
ofn.lpstrFile = fileName;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrDefExt = GetDefExtAnsi();
ofn.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
if (!GetSaveFileNameA(&ofn)) return false;
g_currentFilePath = fileName;
}
if (!write_file(g_currentFilePath, content)) {
MessageBoxA(g_hMainWnd, "保存失败:无法写入文件。", "错误",
MB_OK | MB_ICONERROR);
return false;
}
ClearDirty();
size_t pos = g_currentFilePath.find_last_of("/\\");
g_currentFileName = (pos == string::npos) ? g_currentFilePath : g_currentFilePath.substr(pos+1);
SetStatusText(g_currentFileName);
return true;
}
bool OpenFile() {
OPENFILENAMEA ofn = {};
char fileName[MAX_PATH] = "";
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = g_hMainWnd;
ofn.lpstrFilter = GetFilterAnsi();
ofn.lpstrFile = fileName;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
if (!GetOpenFileNameA(&ofn)) return false;
g_currentFilePath = fileName;
string content = read_file(g_currentFilePath);
if (looks_like_utf8(content)) content = utf8_to_ansi(content);
SetWindowTextA(g_hEdit, content.c_str());
ClearDirty();
size_t pos = g_currentFilePath.find_last_of("/\\");
g_currentFileName = (pos == string::npos) ? g_currentFilePath : g_currentFilePath.substr(pos+1);
SetStatusText(g_currentFileName);
return true;
}
string GetEditContent() {
int len = GetWindowTextLength(g_hEdit) + 1;
if (len <= 1) return "";
char* buf = new char[len];
GetWindowTextA(g_hEdit, buf, len);
string s = buf;
delete[] buf;
return s;
}
static bool ConfirmDiscardOrSave(HWND hWnd, const char* prompt) {
if (!IsDirty()) return true;
int r = MessageBoxA(hWnd, XA(prompt), XA("确认"),
MB_YESNOCANCEL | MB_ICONQUESTION);
if (r == IDCANCEL) return false;
if (r == IDNO) return true;
if (!SaveFile(GetEditContent(), false)) return false;
return true;
}
// ============================================================
// 主窗口过程
// ============================================================
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE: {
HMENU hMenuBar = CreateMenu();
HMENU hFileMenu = CreatePopupMenu();
HMENU hEditMenu = CreatePopupMenu();
HMENU hRunMenu = CreatePopupMenu();
HMENU hHelpMenu = CreatePopupMenu();
AppendMenuA(hFileMenu, MF_STRING, IDM_FILE_NEW, XA("新建(&N)"));
AppendMenuA(hFileMenu, MF_STRING, IDM_FILE_OPEN, XA("打开(&O)..."));
AppendMenuA(hFileMenu, MF_STRING, IDM_FILE_SAVE, XA("保存(&S)"));
AppendMenuA(hFileMenu, MF_STRING, IDM_FILE_SAVEAS, XA("另存为(&A)..."));
AppendMenuA(hFileMenu, MF_SEPARATOR, 0, NULL);
AppendMenuA(hFileMenu, MF_STRING, IDM_FILE_EXIT, XA("退出(&X)"));
AppendMenuA(hEditMenu, MF_STRING, IDM_EDIT_CUT, XA("剪切(&T)"));
AppendMenuA(hEditMenu, MF_STRING, IDM_EDIT_COPY, XA("复制(&C)"));
AppendMenuA(hEditMenu, MF_STRING, IDM_EDIT_PASTE, XA("粘贴(&P)"));
AppendMenuA(hRunMenu, MF_STRING, IDM_RUN_COMPILE, XA("编译(&B)"));
AppendMenuA(hRunMenu, MF_STRING, IDM_RUN_RUN, XA("运行(&R)"));
AppendMenuA(hRunMenu, MF_STRING, IDM_RUN_STOP, XA("停止(&S)"));
AppendMenuA(hHelpMenu, MF_STRING, IDM_HELP_MANUAL, XA("用法大全(&H)"));
AppendMenuA(hHelpMenu, MF_STRING, IDM_HELP_ABOUT, XA("关于(&A)"));
AppendMenuA(hMenuBar, MF_POPUP, (UINT_PTR)hFileMenu, XA("文件(&F)"));
AppendMenuA(hMenuBar, MF_POPUP, (UINT_PTR)hEditMenu, XA("编辑(&E)"));
AppendMenuA(hMenuBar, MF_POPUP, (UINT_PTR)hRunMenu, XA("运行(&R)"));
AppendMenuA(hMenuBar, MF_POPUP, (UINT_PTR)hHelpMenu, XA("帮助(&H)"));
SetMenu(hWnd, hMenuBar);
g_hEdit = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "",
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL |
ES_AUTOHSCROLL | WS_HSCROLL,
0, 0, 0, 0, hWnd, (HMENU)101, g_hInst, NULL);
SendMessage(g_hEdit, WM_SETFONT, (WPARAM)g_hFont, TRUE);
g_hOutput = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "",
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL |
ES_AUTOHSCROLL | WS_HSCROLL | ES_READONLY,
0, 0, 0, 0, hWnd, (HMENU)102, g_hInst, NULL);
SendMessage(g_hOutput, WM_SETFONT, (WPARAM)g_hOutFont, TRUE);
g_hBtnSave = CreateWindowA("BUTTON", XA("保存"), WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, 5,5,70,28, hWnd,(HMENU)IDB_SAVE,g_hInst,NULL);
g_hBtnCompile = CreateWindowA("BUTTON", XA("编译"), WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, 80,5,70,28, hWnd,(HMENU)IDB_COMPILE,g_hInst,NULL);
g_hBtnRun = CreateWindowA("BUTTON", XA("运行"), WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, 155,5,70,28, hWnd,(HMENU)IDB_RUN,g_hInst,NULL);
g_hBtnStop = CreateWindowA("BUTTON", XA("停止"), WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, 230,5,70,28, hWnd,(HMENU)IDB_STOP,g_hInst,NULL);
EnableWindow(g_hBtnStop, FALSE);
g_hBtnClear = CreateWindowA("BUTTON", XA("清空"), WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, 305,5,70,28, hWnd,(HMENU)IDB_CLEAR,g_hInst,NULL);
g_hStatusBar = CreateWindowA(STATUSCLASSNAMEA, XA("未命名.玄"),
WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, (HMENU)301, g_hInst, NULL);
const char* demo =
"头文件《标准IO》\n"
"使用命名空间标准;\n"
"\n"
"主程序:\n"
" 重复 3 次《\n"
" 输出:\"hi\":换行;\n"
" 》\n"
"\n"
" 整数列表 v = 【10, 20, 30】;\n"
" 遍历 x 在 v 中《\n"
" 输出:\"x=\":x:换行;\n"
" 》\n"
"\n"
" 返回 0;\n"
"。\n";
SetWindowTextA(g_hEdit, to_ansi(demo).c_str());
ClearDirty();
return 0;
}
case WM_SIZE: {
RECT rc; GetClientRect(hWnd, &rc);
int w = rc.right - rc.left, h = rc.bottom - rc.top;
int toolbarH = 40, outH = 140, statusH = 25;
int editH = h - toolbarH - outH - statusH - 15;
if (editH < 50) editH = 50;
SetWindowPos(g_hEdit, NULL, 5, toolbarH+5, w-10, editH, SWP_NOZORDER);
SetWindowPos(g_hOutput, NULL, 5, toolbarH+10+editH, w-10, outH-5, SWP_NOZORDER);
SendMessage(g_hStatusBar, WM_SIZE, 0, 0);
return 0;
}
case WM_COMMAND: {
int id = LOWORD(wParam);
if (id == IDM_FILE_NEW) {
if (!ConfirmDiscardOrSave(hWnd, "当前代码已修改,是否保存?")) break;
SetWindowTextA(g_hEdit, "");
g_currentFilePath = "";
g_currentFileName = to_ansi("未命名.玄");
SetStatusText(g_currentFileName);
ClearDirty();
}
else if (id == IDM_FILE_OPEN) {
if (!ConfirmDiscardOrSave(hWnd, "当前代码已修改,是否保存?")) break;
OpenFile();
}
else if (id == IDM_FILE_SAVE) SaveFile(GetEditContent(), false);
else if (id == IDM_FILE_SAVEAS) SaveFile(GetEditContent(), true);
else if (id == IDM_FILE_EXIT) PostMessage(hWnd, WM_CLOSE, 0, 0);
else if (id == IDM_EDIT_CUT) SendMessage(g_hEdit, WM_CUT, 0, 0);
else if (id == IDM_EDIT_COPY) SendMessage(g_hEdit, WM_COPY, 0, 0);
else if (id == IDM_EDIT_PASTE) SendMessage(g_hEdit, WM_PASTE, 0, 0);
else if (id == IDM_RUN_COMPILE || id == IDB_COMPILE) {
if (g_isCompiling || g_isRunning) break;
string src = GetEditContent();
if (!g_currentFilePath.empty()) write_file(g_currentFilePath, src);
SetWindowTextA(g_hOutput, XA("正在编译...\n"));
EnableWindow(g_hBtnCompile, FALSE);
EnableWindow(g_hBtnRun, FALSE);
g_isCompiling = true;
g_stopRequested.store(false);
CompileJob* pJob = new CompileJob();
pJob->src = src; pJob->runAfter = false;
uintptr_t th = _beginthreadex(NULL, 0, CompileThreadProc, pJob, 0, NULL);
if (th) CloseHandle((HANDLE)(intptr_t)th);
else {
delete pJob;
g_isCompiling = false;
EnableWindow(g_hBtnCompile, TRUE);
EnableWindow(g_hBtnRun, TRUE);
SetWindowTextA(g_hOutput, XA("线程创建失败\n"));
}
}
else if (id == IDM_RUN_RUN || id == IDB_RUN) {
if (g_isCompiling || g_isRunning) break;
string src = GetEditContent();
if (!g_currentFilePath.empty()) write_file(g_currentFilePath, src);
SetWindowTextA(g_hOutput, XA("正在编译并运行...\n"));
EnableWindow(g_hBtnCompile, FALSE);
EnableWindow(g_hBtnRun, FALSE);
EnableWindow(g_hBtnStop, TRUE);
g_isRunning = true;
g_stopRequested.store(false);
CompileJob* pJob = new CompileJob();
pJob->src = src; pJob->runAfter = true;
uintptr_t th = _beginthreadex(NULL, 0, CompileThreadProc, pJob, 0, NULL);
if (th) CloseHandle((HANDLE)(intptr_t)th);
else {
delete pJob;
g_isRunning = false;
EnableWindow(g_hBtnCompile, TRUE);
EnableWindow(g_hBtnRun, TRUE);
EnableWindow(g_hBtnStop, FALSE);
SetWindowTextA(g_hOutput, XA("线程创建失败\n"));
}
}
else if (id == IDM_RUN_STOP || id == IDB_STOP) {
g_stopRequested.store(true);
KillOutputExe();
EnableWindow(g_hBtnStop, FALSE);
EnableWindow(g_hBtnCompile, FALSE);
EnableWindow(g_hBtnRun, FALSE);
SetWindowTextA(g_hOutput, XA("正在停止...\n"));
}
else if (id == IDB_SAVE) SaveFile(GetEditContent(), false);
else if (id == IDB_CLEAR) SetWindowTextA(g_hOutput, "");
else if (id == IDM_HELP_MANUAL) ShowHelp();
else if (id == IDM_HELP_ABOUT) {
MessageBoxA(hWnd,
XA("《玄》IDE v3.8.2\n\n数据外置版"),
XA("关于"), MB_OK|MB_ICONINFORMATION);
}
return 0;
}
case WM_UPDATE_OUTPUT: {
string* pMsg = (string*)lParam;
if (pMsg) {
if (wParam == 0) SetWindowTextA(g_hOutput, pMsg->c_str());
else {
int len = GetWindowTextLengthA(g_hOutput);
char* cur = new char[len+1];
GetWindowTextA(g_hOutput, cur, len+1);
string nt = string(cur) + *pMsg;
delete[] cur;
SetWindowTextA(g_hOutput, nt.c_str());
}
delete pMsg;
}
return 0;
}
case WM_COMPILE_FINISHED: {
g_isCompiling = false;
g_isRunning = false;
g_stopRequested.store(false);
EnableWindow(g_hBtnCompile, TRUE);
EnableWindow(g_hBtnRun, TRUE);
EnableWindow(g_hBtnStop, FALSE);
return 0;
}
case WM_CLOSE:
if (!ConfirmDiscardOrSave(hWnd, "退出前是否保存修改?")) return 0;
DestroyWindow(hWnd);
return 0;
case WM_DESTROY: {
g_hMainWnd = NULL;
KillOutputExe();
if (g_tempDir != ".") {
string cppPath = g_tempDir + "\\output.cpp";
string exePath = g_tempDir + "\\output.exe";
DeleteFileA(cppPath.c_str());
DeleteFileA(exePath.c_str());
RemoveDirectoryA(g_tempDir.c_str());
}
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
// ============================================================
// 入口
// ============================================================
static void InitTempDir() {
char tempPath[MAX_PATH];
DWORD len = GetTempPathA(MAX_PATH, tempPath);
if (len > 0 && len < MAX_PATH) {
char pidStr[32];
snprintf(pidStr, sizeof(pidStr), "xuan_ide_%lu",
(unsigned long)GetCurrentProcessId());
string dir = string(tempPath) + pidStr;
CreateDirectoryA(dir.c_str(), NULL);
DWORD attr = GetFileAttributesA(dir.c_str());
if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
g_tempDir = dir;
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
(void)hPrevInstance; (void)lpCmdLine;
{
typedef BOOL (WINAPI *PFN_DPIAWARE)();
HMODULE hU = GetModuleHandleA("user32.dll");
if (hU) {
PFN_DPIAWARE pFn = (PFN_DPIAWARE)GetProcAddress(hU, "SetProcessDPIAware");
if (pFn) pFn();
}
}
g_hInst = hInstance;
g_currentFileName = to_ansi("未命名.玄");
g_exeDir = GetExeDir();
if (!LoadTextFile("patterns.txt", g_patterns_content)) {
MessageBoxA(NULL,
"缺少 data\\patterns.txt。\n"
"请将 data 目录与 exe 放同一目录。",
"《玄》IDE 启动失败", MB_OK | MB_ICONERROR);
return 1;
}
g_patterns_loaded = true;
if (LoadTextFile("types.txt", g_types_content)) {
g_types_loaded = true;
} else {
// R6:types.txt 缺失弹窗警告
MessageBoxA(NULL,
"data\\types.txt 缺失。\n\n"
"智能指针《T》和类型转换(T)将不会翻译 T 里的中文类型名,\n"
"生成的 C++ 可能无法编译。\n\n"
"请将 types.txt 放回 data 目录。",
"警告", MB_OK | MB_ICONWARNING);
}
InitTempDir();
INITCOMMONCONTROLSEX icex = {sizeof(icex), ICC_WIN95_CLASSES};
InitCommonControlsEx(&icex);
g_hFont = CreateFontA(18,0,0,0,FW_NORMAL,0,0,0, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH|FF_DONTCARE, XA("宋体"));
g_hOutFont = CreateFontA(16,0,0,0,FW_NORMAL,0,0,0, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH|FF_DONTCARE, XA("宋体"));
WNDCLASSA wc = {};
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszClassName = "XuanIDE";
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassA(&wc)) return 1;
g_hMainWnd = CreateWindowExA(0, "XuanIDE", XA("《玄》IDE v3.8.2"),
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1000, 720,
NULL, NULL, hInstance, NULL);
if (!g_hMainWnd) return 1;
ShowWindow(g_hMainWnd, nCmdShow);
UpdateWindow(g_hMainWnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (g_hFont) DeleteObject(g_hFont);
if (g_hOutFont) DeleteObject(g_hOutFont);
return 0;
}
data/patterns.txt
cpp
# ============================================================
# 《玄》pattern 表 v3.8.2
# 格式:玄关键字<TAB>C++ 代码
# 转义:\n 换行 \t tab \s 空格 \\ 反斜杠
# 空行和 # 开头的行会被忽略
# ============================================================
# ---- 头文件 ----
头文件《标准IO》 #include <iostream>\n#include <string>\n#include <vector>\n#include <memory>\n#include <cstdlib>\n#include <ctime>\n
头文件《字符串》 #include <string>\n
头文件《向量》 #include <vector>\n
头文件《内存》 #include <memory>\n
头文件《算法》 #include <algorithm>\n
头文件《数学》 #include <cmath>\n
头文件《数值》 #include <numeric>\n
头文件《随机数》 #include <random>\n
头文件《随机》 #include <random>\n
头文件《映射》 #include <map>\n
头文件《字典》 #include <map>\n
头文件《无序映射》 #include <unordered_map>\n
头文件《无序集合》 #include <unordered_set>\n
头文件《优先队列》 #include <queue>\n
头文件《多重集合》 #include <set>\n
头文件《多重映射》 #include <map>\n
头文件《集合》 #include <set>\n
头文件《队列》 #include <queue>\n
头文件《栈》 #include <stack>\n
头文件《链表》 #include <list>\n
头文件《数组》 #include <array>\n
头文件《双端队列》 #include <deque>\n
头文件《元组》 #include <tuple>\n
头文件《对组》 #include <utility>\n
头文件《工具》 #include <utility>\n
头文件《函数》 #include <functional>\n
头文件《时间》 #include <chrono>\n
头文件《线程》 #include <thread>\n
头文件《互斥锁》 #include <mutex>\n
头文件《互斥》 #include <mutex>\n
头文件《原子》 #include <atomic>\n
头文件《条件变量》 #include <condition_variable>\n
头文件《文件流》 #include <fstream>\n
头文件《文件》 #include <fstream>\n
头文件《字符串流》 #include <sstream>\n
头文件《流格式》 #include <iomanip>\n
头文件《异常》 #include <stdexcept>\n
头文件《迭代器》 #include <iterator>\n
头文件《位集》 #include <bitset>\n
头文件《复数》 #include <complex>\n
头文件《Windows》 #include <windows.h>\n#include <cstdlib>\n
# ---- 命名空间 ----
使用命名空间标准; using namespace std;
使用命名空间标准 using namespace std
使用命名空间 using namespace\s
命名空间 namespace\s
# ---- 主程序 ----
主程序: int main() {
# ---- 输入输出 ----
输出: std::cout <<\s
输出 std::cout <<\s
输入: std::cin >>\s
输入 std::cin >>\s
换行 std::endl
# ---- 容器 ----
整数双端队列 std::deque<int>
整数映射 std::map<int,int>
文本映射 std::map<std::string,std::string>
整数集合 std::set<int>
文本集合 std::set<std::string>
整数队列 std::queue<int>
文本队列 std::queue<std::string>
整数栈 std::stack<int>
文本栈 std::stack<std::string>
整数对 std::pair<int,int>
文本对 std::pair<std::string,std::string>
整数列表 std::vector<int>
文本列表 std::vector<std::string>
浮点列表 std::vector<float>
无序映射 std::unordered_map<int,int>
无序集合 std::unordered_set<int>
优先队列 std::priority_queue<int>
多重集合 std::multiset<int>
多重映射 std::multimap<int,int>
# ---- 长短整数 ----
无符号长整数 unsigned long long
无符号短整数 unsigned short
无符号整数 unsigned int
超长整数指针 long long*
长整数指针 long long*
短整数指针 short*
超长整数列表 std::vector<long long>
长整数列表 std::vector<long long>
短整数列表 std::vector<short>
超长整数 long long
长整数 long long
短整数 short
长双精度 long double
# ---- 引用(指针) ----
引用超长整数指针 long long*&
引用长整数指针 long long*&
引用短整数指针 short*&
引用整数指针 int*&
引用文本指针 std::string*&
引用浮点指针 float*&
引用双精度指针 double*&
引用字符指针 char*&
引用布尔指针 bool*&
# ---- 引用(普通) ----
引用无符号长整数 unsigned long long&
引用无符号短整数 unsigned short&
引用无符号整数 unsigned int&
引用超长整数 long long&
引用长整数 long long&
引用短整数 short&
引用整数 int&
引用文本 std::string&
引用字符串 std::string&
引用浮点 float&
引用双精度 double&
引用长双精度 long double&
引用布尔 bool&
引用字符 char&
# ---- 指针类型 ----
整数指针 int*
文本指针 std::string*
浮点指针 float*
双精度指针 double*
字符指针 char*
布尔指针 bool*
# ---- 基本类型 ----
整数 int
浮点 float
双精度 double
字符 char
布尔 bool
文本 std::string
字符串 std::string
无 void
定义 int
常量表达式 constexpr\s
自动 auto\s
# ---- 指针操作 ----
取地址 &
取址 &
取内容 *
解引用 *
空指针 nullptr
新建数组 new\s
新建 new\s
释放数组 delete[]\s
释放 delete\s
常量 const\s
静态 static\s
友元 friend\s
# ---- 复合赋值 ----
增加 +=\s
减少 -=\s
乘以 *=\s
除以 /=\s
取模 %=\s
# ---- 比较 ----
不大于 <=
不小于 >=
小于 <
大于 >
等于 ==
不等于 !=
与 &&
且 &&
或者 ||
或 ||
非 !
# ---- 位运算 ----
位异或 ^
位与 &
位或 |
位非 ~
左移 <<
右移 >>
# ---- 算术 ----
递增 ++
递减 --
加 +
减 -
乘 *
除 /
模 %
# ---- 标点 ----
《 {
》 }
【 {
】 }
「 [
」 ]
( (
) )
; ;
: <<\s
。 }
, ,
、 ,
! !
? ?
\s
# ---- 控制流 ----
否则如果 else if\s
否则 else\s
如果 if\s
对于 for\s
只要 while\s
当 while\s
反复 do\s
跳出 break
继续 continue
返回 return\s
# ---- 异常 ----
尝试 try\s
捕获( catch (
抛出 throw\s
# ---- 类 ----
类 class\s
结构 struct\s
枚举 enum\s
继承 : public\s
公开 public:
公有 public:
私有 private:
保护 protected:
虚函数 virtual\s
# ---- 布尔 ----
真 true
假 false
# ---- 玄独有 ----
否则若\s else if (
若\s if (
则\s )\s
则 )
承 : public\s
此\s的\s this->
\s的\s .\s
# ---- Windows API ----
延时( Sleep(
系统( system(
退出程序( exit(
取时间() time(NULL)
进程号() GetCurrentProcessId()
data/types.txt
cpp
# 类型映射 ------ 智能指针《T》和 cast(T)用
# 格式:玄类型<TAB>C++ 类型
无符号长整数 unsigned long long
无符号短整数 unsigned short
无符号整数 unsigned int
超长整数 long long
长整数 long long
短整数 short
长双精度 long double
整数 int
浮点 float
双精度 double
字符 char
布尔 bool
文本 std::string
字符串 std::string
无 void
data/help.txt
在 v3.8.1 的 help.txt 基础上加 3 段说明:
text
bash
================================================================
《玄》语言用法大全 v3.8.2
================================================================
【1 文件结构】
头文件《标准IO》
使用命名空间标准;
主程序:
代码...
。
说明:
- 「主程序:」后接代码
- 结尾的「。」表示 main 结束
- 也可以用《》包裹主程序体
- 关键字后建议跟空格或全角标点
【2 头文件】(40 个)
标准IO iostream + string + vector + memory + cstdlib + ctime
字符串 string
向量 vector
内存 memory
算法 algorithm
数学 cmath
数值 numeric
随机数 / 随机 random
映射 / 字典 map
无序映射 unordered_map
无序集合 unordered_set
优先队列 queue
多重集合 set
多重映射 map
集合 set
队列 queue
栈 stack
链表 list
数组 array
双端队列 deque
元组 tuple
对组 / 工具 utility
函数 functional
时间 chrono
线程 thread
互斥 / 互斥锁 mutex
原子 atomic
条件变量 condition_variable
文件 / 文件流 fstream
字符串流 sstream
流格式 iomanip
异常 stdexcept
迭代器 iterator
位集 bitset
复数 complex
Windows windows.h + cstdlib
【3 命名空间】
使用命名空间标准; -> using namespace std;
使用命名空间 我的库; -> using namespace 我的库;
命名空间 我的库《 ... 》 -> namespace 我的库 { ... }
【4 基本类型】
整数 int
短整数 short
长整数 long long
超长整数 long long
无符号整数 unsigned int
无符号短整数 unsigned short
无符号长整数 unsigned long long
浮点 float
双精度 double
长双精度 long double
字符 char
布尔 bool
文本 / 字符串 std::string
无 void
真 / 假 true / false
定义 int(兼容旧写法)
自动 auto
常量表达式 constexpr
【5 容器类型别名】
整数映射 std::map<int,int>
文本映射 std::map<std::string,std::string>
整数集合 std::set<int>
文本集合 std::set<std::string>
无序映射 std::unordered_map<int,int>
无序集合 std::unordered_set<int>
优先队列 std::priority_queue<int>
多重集合 std::multiset<int>
多重映射 std::multimap<int,int>
整数队列 std::queue<int>
文本队列 std::queue<std::string>
整数栈 std::stack<int>
文本栈 std::stack<std::string>
整数双端队列 std::deque<int>
整数对 std::pair<int,int>
文本对 std::pair<std::string,std::string>
整数列表 std::vector<int>
文本列表 std::vector<std::string>
浮点列表 std::vector<float>
短整数列表 std::vector<short>
长整数列表 std::vector<long long>
超长整数列表 std::vector<long long>
【6 引用与指针】
引用整数 r = a; -> int& r = a;
引用整数指针 p = ...; -> int*& p = ...;
引用文本 r = s; -> std::string& r = s;
整数指针 p = 取地址 a; -> int* p = & a;
取内容 p / 解引用 p -> * p
空指针 -> nullptr
新建 整数(100) -> new int(100)
新建数组 整数「10」 -> new int[10]
释放 p / 释放数组 p -> delete / delete[]
【7 智能指针】
独占指针《整数》 p = 新建独占《整数》(5);
-> std::unique_ptr<int> p = std::make_unique<int>(5);
共享指针《整数》 -> std::shared_ptr<int>
弱引用《整数》 -> std::weak_ptr<int>
新建独占《T》(值) -> std::make_unique<T>(值)
新建共享《T》(值) -> std::make_shared<T>(值)
《T》里可写 types.txt 里的类型名,也可以写 整数指针 / 整数列表 等复合类型。
《T》里不支持嵌套 《》,如需嵌套请直接写 C++。
【8 类型转换】
静态转(整数)(x) -> static_cast<int>(x)
动态转(基类)(p) -> dynamic_cast<基类>(p)
常量转(整数)(x) -> const_cast<int>(x)
重解释转(整数)(x) -> reinterpret_cast<int>(x)
大小(T) / 字节数(T) -> sizeof(T)
【9 输入输出】
输出:"你好":换行; -> std::cout << "你好" << std::endl;
输入:a; -> std::cin >> a;
读一行 s; -> getline(cin, s);
说明:全角冒号(:)翻译为 <<
【10 运算符】
算术: 加 + 减 - 乘 * 除 / 模 %
递增 ++ 递减 --
复合: a 增加 1 / 减少 1 / 乘以 2 / 除以 2 / 取模 3
-> a += 1; / -= / *= / /= / %=
比较: 小于 < 大于 > 不大于 <= 不小于 >=
等于 == 不等于 !=
比...小 < 比...大 >(允许跨行、紧凑写法 i比a小)
逻辑: 与 / 且 && 或 / 或者 || 非 !
位: 位与 & 位或 | 位异或 ^
位非 ~(一元,写 位非 a)
左移 << 右移 >>
【11 控制流】
如果(条件)《...》 否则如果《...》 否则《...》
对于(整数 i=0;i 小于 10;i 递增)《...》
只要(条件)《...》 / 当(条件)《...》
反复《...》当(条件); -> do { ... }while(条件);
跳出 break / 继续 continue / 返回 return
【12 玄独有语法】
● 重复 N 次《...》
重复 3 次《 输出:"你好":换行; 》
-> for (int _i_rep_0 = 0; _i_rep_0 < (3); _i_rep_0++) { ... }
● 对于 X 从 A 到 B《...》 / 对于 X 从 A 到 B 递减《...》
对于 i 从 1 到 5《 输出:i:换行; 》
-> for (int i = 1; i <= 5; i++) { ... }
对于 i 从 3 到 1 递减《 ... 》
-> for (int i = 3; i >= 1; i--) { ... }
● 若 C 则 S;否则若 C 则 S;否则 S;
若 分数 大于 90 则 输出:"优":换行;
否则若 分数 大于 60 则 输出:"及格":换行;
否则 输出:"不及格":换行;
注意:若/则/否则若 前后必须有空格
● 遍历 x 在 v 中《...》
-> for (auto x : v) { ... }
● 环《...》 -> while (true) { ... }
● 卦 N / 卦 A 到 B -> 随机数,自动注入 srand
卦 6 范围 0..5
卦 1 到 6 范围 1..6
● 承 -> : public(继承)
类 大学生 承 学生《 ... 》
● 此 的 x / 对象 的 x
此 的 值 -> this->值
对象 的 成员 -> 对象. 成员
【13 异常处理】
尝试《 ... 》
捕获(整数 e)《 ... 》 -> catch (int e) { ... }
抛出 e; -> throw e;
注意:C++ 的 catch 参数必须带类型,不能只写捕获(e)。
写 捕获(整数 e)或 捕获(...)。
【14 类与结构】
类 学生《
公开:
文本 姓名;
整数 年龄;
学生(文本 n,整数 a)《 姓名=n; 年龄=a; 》
无 介绍()《 输出:"我是":姓名:换行; 》
》
继承:类 大学生 承 学生《 ... 》
友元 类 X; -> friend class X;
虚函数 无 f(); -> virtual void f();
【15 Windows API】
头文件《Windows》 -> #include <windows.h> + <cstdlib>
弹窗("内容", "标题"); -> MessageBoxA(NULL, "内容", "标题", MB_OK);
消息框 同 弹窗
延时(1000); -> Sleep(1000);
系统("dir"); -> system("dir");
退出程序(0); -> exit(0);
取时间() -> time(NULL)(需 头文件《标准IO》)
进程号() -> GetCurrentProcessId()
弹窗参数规则:
逗号数 == 1(2 个参数)-> 自动补 MB_OK
逗号数 >= 2 -> 不补
单参数会导致 MessageBoxA 编译失败
【16 数据文件说明】
data/patterns.txt ------ 主 pattern 表
格式:关键字<TAB>值
转义:\n 换行 \t tab \s 空格 \\ 反斜杠
key 和 value 都支持转义
尾空格必须写 \s(防止编辑器 trim)
data/types.txt ------ 类型映射表(智能指针《T》、cast(T)用)
格式同上
data/help.txt ------ 本文件
⚠ 约 15 个核心语法硬编码在主程序中,改 patterns.txt 不影响:
重复 / 遍历 / 卦 / 环 / 比 / 智能指针 / cast /
读一行 / 弹窗 / 承 / 此 的 / 对于X从A到B
⚠ 智能指针《T》里不支持嵌套 《》。如需
unique_ptr<unique_ptr<int>> 请直接写 C++ 原生语法。
【17 文件编码】
data/*.txt 支持四种编码,程序自动识别:
UTF-8 / UTF-16 LE / UTF-16 BE / ANSI(GBK)
建议用 UTF-8
.玄 源文件建议用 ANSI/GBK 保存。
用其他编辑器另存为 UTF-8 时,本 IDE 打开会自动转码。
【18 常见错误】
1. 忘记写 头文件《标准IO》
2. 忘记写 使用命名空间标准;
3. 字符串用中文引号 ------ 必须用英文引号 ""
4. 缺少主程序结尾的句号 。
5. 索引用 【】 是错的 ------ 索引用 「」,初始化用 【】
6. 关键字与中文变量名粘连 ------ 中间加空格
7. 以下关键字不能作变量名:
增加 / 减少 / 乘以 / 除以 / 取模 / 遍历
重复 / 卦 / 环 / 比 / 承
8. 位非 是一元运算符,写 位非 a,不写 a 位非 b
9. 转义 \标识符 保护整个标识符(遇标点停)
10. 若 / 则 / 否则若 / 此 的 / 的 前后要空格
《玄》IDE v3.8.2
================================================================