一直是用c++写代码,这个c++的使用上一直要我切换输入法,我现在便借助大模型来实现这个愿望。代码可能有错,请大家多多指教。
先运行,在用:
📝 使用示例
-
打开
XuanIDE.exe -
写代码(默认已提供示例)
-
点击 💾 保存 ,输入文件名(如
test.玄) -
点击 🛠 编译,下方显示"✅ 编译成功!"
-
点击 ▶ 运行,程序输出会显示在下方
-
若程序死循环,点击 ■ 停止 强制结束
cpp
// ============================================================
// 《玄》IDE v2.0 --- 完整版:保存/编译/运行/报错
// 编译: g++ XuanIDE.cpp -o XuanIDE.exe -lgdi32 -lcomctl32 -std=c++17 -static
// ============================================================
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <regex>
#include <algorithm>
#include <thread>
#include <cstdio>
#include <cstdlib>
#include <cctype>
using namespace std;
// ---------- 全局变量 ----------
HWND g_hMainWnd, g_hEdit, g_hOutput, g_hStatusBar;
HWND g_hBtnSave, g_hBtnCompile, g_hBtnRun, g_hBtnStop, g_hBtnClear;
HFONT g_hFont, g_hOutputFont;
HINSTANCE g_hInst;
string g_currentFilePath = "";
string g_currentFileName = "未命名.玄";
bool g_isRunning = false;
bool g_isCompiling = false;
// ---------- 工具函数 ----------
string read_file(const string& path) {
ifstream f(path, ios::binary);
if (!f) return "";
stringstream ss; ss << f.rdbuf();
return ss.str();
}
void write_file(const string& path, const string& content) {
ofstream f(path);
f << content;
}
bool file_exists(const string& path) {
ifstream f(path);
return f.good();
}
// ---------- 核心转译(增强"比"处理,支持"或者"中的英文符号) ----------
string translate_xuan(const string& src) {
// 预处理:将"或者"后面的括号内容直接移除(因为可能是英文符号,我们统一不处理)
// 但我们更保守:保留原样,因为后续映射会处理 < > 符号(兼容模式)
// 但为了规范化,我们把"(或者a<i)"这样的内容直接替换为""(空)
// 这样用户就可以写"i 比 a 小"即可,括号内的额外说明会被忽略。
string processed = src;
// 移除 "(或者...)" 和 "(或者...)" 中的内容,保留括号占位
regex or_pattern(R"([((]?或者\s*[\S\s]*?[))])");
processed = regex_replace(processed, or_pattern, "");
vector<pair<string, string>> patterns = {
{"头文件《标准IO》", "#include <iostream>\nusing namespace std;\n"},
{"主程序:", "int main() {"},
{"输出:", "std::cout << "},
{"输入:", "std::cin >> "},
{"换行", "std::endl"},
{"小于", "<"}, {"大于", ">"}, {"等于", "=="}, {"不等于", "!="},
{"与", "&&"}, {"或", "||"}, {"非", "!"},
{"递增", "++"}, {"递减", "--"},
{"加", "+"}, {"减", "-"}, {"乘", "*"}, {"除", "/"}, {"模", "%"},
{"《", "{"}, {"》", "}"}, {"「", "{"}, {"」", "}"},
{"(", "("}, {")", ")"}, {";", ";"}, {":", " << "}, {"。", "}"},
{"定义", "int"}, {"对于", "for"}, {"如果", "if"}, {"否则", "else"}, {"返回", "return"},
{"输出", "std::cout << "}
};
sort(patterns.begin(), patterns.end(),
[](const auto& a, const auto& b) { return a.first.size() > b.first.size(); });
// 自定义替换函数(跳过字符串和注释)
string out;
size_t i = 0;
while (i < processed.size()) {
// 跳过字符串
if (processed[i] == '"') {
out += processed[i++];
while (i < processed.size() && (processed[i] != '"' || (i > 0 && processed[i-1] == '\\'))) out += processed[i++];
if (i < processed.size()) out += processed[i++];
continue;
}
// 跳过单行注释
if (processed[i] == '/' && i+1 < processed.size() && processed[i+1] == '/') {
while (i < processed.size() && processed[i] != '\n') out += processed[i++];
continue;
}
// 跳过多行注释
if (processed[i] == '/' && i+1 < processed.size() && processed[i+1] == '*') {
out += processed[i++]; out += processed[i++];
while (!(processed[i-1] == '*' && processed[i] == '/') && i < processed.size()) out += processed[i++];
if (i < processed.size()) out += processed[i++];
continue;
}
bool matched = false;
// 处理"比"结构(i 比 a 小)
if (processed.compare(i, 1, "比") == 0) {
size_t start = i;
while (start > 0 && !isspace(processed[start-1]) && processed[start-1] != '(' && processed[start-1] != '(') start--;
size_t var1_end = i;
size_t j = i + 1;
while (j < processed.size() && isspace(processed[j])) j++;
if (j < processed.size() && (processed[j] == '小' || processed[j] == '大')) {
char op = (processed[j] == '小') ? '<' : '>';
size_t after_op = j + 1;
while (after_op < processed.size() && isspace(processed[after_op])) after_op++;
size_t var2_start = after_op;
while (var2_start < processed.size() && isspace(processed[var2_start])) var2_start++;
size_t var2_end = var2_start;
while (var2_end < processed.size() && !isspace(processed[var2_end]) && processed[var2_end] != ';' && processed[var2_end] != ')' && processed[var2_end] != ')' && processed[var2_end] != '《' && processed[var2_end] != '{') var2_end++;
if (var2_start < processed.size() && var2_end > var2_start) {
string var1 = processed.substr(start, var1_end - start);
string var2 = processed.substr(var2_start, var2_end - var2_start);
out += var1 + " " + op + " " + var2;
i = var2_end;
matched = true;
}
}
}
if (!matched) {
for (const auto& [from, to] : patterns) {
if (processed.compare(i, from.size(), from) == 0) {
out += to;
i += from.size();
matched = true;
break;
}
}
}
if (!matched) out += processed[i++];
}
return out;
}
// ---------- 编译并(可选)运行 ----------
void CompileAndRun(const string& src, bool runAfter) {
if (g_isRunning || g_isCompiling) return;
g_isCompiling = true;
SetWindowText(g_hBtnCompile, "⏳ 编译中...");
EnableWindow(g_hBtnCompile, FALSE);
SetWindowText(g_hBtnRun, "⏳ 编译中...");
EnableWindow(g_hBtnRun, FALSE);
SetWindowText(g_hOutput, "📝 正在转译...\n");
// 转译
string cpp = translate_xuan(src);
write_file("output.cpp", cpp);
// 调用编译器
string buildLog;
char buffer[1024];
#ifdef _WIN32
string cmd = "g++ output.cpp -o output.exe -std=c++17 2>&1";
#else
string cmd = "g++ output.cpp -o output -std=c++17 2>&1";
#endif
FILE* pipe = _popen(cmd.c_str(), "r");
if (pipe) {
while (fgets(buffer, sizeof(buffer), pipe)) buildLog += buffer;
_pclose(pipe);
}
// 显示编译结果
if (buildLog.find("error") != string::npos || buildLog.find("Error") != string::npos) {
SetWindowText(g_hOutput, ("❌ 编译失败:\n" + buildLog).c_str());
g_isCompiling = false;
SetWindowText(g_hBtnCompile, "🛠 编译");
EnableWindow(g_hBtnCompile, TRUE);
SetWindowText(g_hBtnRun, "▶ 运行");
EnableWindow(g_hBtnRun, TRUE);
return;
}
SetWindowText(g_hOutput, ("✅ 编译成功!\n" + buildLog).c_str());
if (runAfter) {
SetWindowText(g_hOutput, (string(GetWindowText(g_hOutput)) + "\n▶ 程序输出:\n--------------------\n").c_str());
string outputLog;
#ifdef _WIN32
FILE* runPipe = _popen("output.exe", "r");
#else
FILE* runPipe = _popen("./output", "r");
#endif
if (runPipe) {
while (fgets(buffer, sizeof(buffer), runPipe)) outputLog += buffer;
_pclose(runPipe);
}
SetWindowText(g_hOutput, (string(GetWindowText(g_hOutput)) + outputLog + "\n--------------------\n").c_str());
}
g_isCompiling = false;
SetWindowText(g_hBtnCompile, "🛠 编译");
EnableWindow(g_hBtnCompile, TRUE);
SetWindowText(g_hBtnRun, "▶ 运行");
EnableWindow(g_hBtnRun, TRUE);
}
// ---------- 文件操作 ----------
bool SaveFile(const string& content) {
if (g_currentFilePath.empty()) {
OPENFILENAMEA ofn = {};
char fileName[MAX_PATH] = "";
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = g_hMainWnd;
ofn.lpstrFilter = "玄源文件\0*.玄\0所有文件\0*.*\0";
ofn.lpstrFile = fileName;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrDefExt = "玄";
ofn.Flags = OFN_OVERWRITEPROMPT;
if (!GetSaveFileNameA(&ofn)) return false;
g_currentFilePath = fileName;
}
write_file(g_currentFilePath, content);
g_currentFileName = g_currentFilePath.substr(g_currentFilePath.find_last_of("/\\") + 1);
SetWindowText(g_hStatusBar, g_currentFileName.c_str());
return true;
}
bool OpenFile() {
OPENFILENAMEA ofn = {};
char fileName[MAX_PATH] = "";
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = g_hMainWnd;
ofn.lpstrFilter = "玄源文件\0*.玄\0所有文件\0*.*\0";
ofn.lpstrFile = fileName;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_FILEMUSTEXIST;
if (!GetOpenFileNameA(&ofn)) return false;
g_currentFilePath = fileName;
string content = read_file(g_currentFilePath);
SetWindowText(g_hEdit, content.c_str());
g_currentFileName = g_currentFilePath.substr(g_currentFilePath.find_last_of("/\\") + 1);
SetWindowText(g_hStatusBar, g_currentFileName.c_str());
return true;
}
// ---------- 窗口过程 ----------
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE: {
// 创建编辑区
g_hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "",
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL,
0, 0, 0, 0, hWnd, (HMENU)101, g_hInst, NULL);
SendMessage(g_hEdit, WM_SETFONT, (WPARAM)g_hFont, TRUE);
// 输出区
g_hOutput = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "",
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL | ES_READONLY,
0, 0, 0, 0, hWnd, (HMENU)102, g_hInst, NULL);
SendMessage(g_hOutput, WM_SETFONT, (WPARAM)g_hOutputFont, TRUE);
// 工具栏按钮
g_hBtnSave = CreateWindow("BUTTON", "💾 保存", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
5, 5, 70, 28, hWnd, (HMENU)201, g_hInst, NULL);
g_hBtnCompile = CreateWindow("BUTTON", "🛠 编译", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
80, 5, 70, 28, hWnd, (HMENU)202, g_hInst, NULL);
g_hBtnRun = CreateWindow("BUTTON", "▶ 运行", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
155, 5, 70, 28, hWnd, (HMENU)203, g_hInst, NULL);
g_hBtnStop = CreateWindow("BUTTON", "■ 停止", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
230, 5, 70, 28, hWnd, (HMENU)204, g_hInst, NULL);
EnableWindow(g_hBtnStop, FALSE);
g_hBtnClear = CreateWindow("BUTTON", "🗑 清空", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
305, 5, 70, 28, hWnd, (HMENU)205, g_hInst, NULL);
// 状态栏
g_hStatusBar = CreateWindow(STATUSCLASSNAME, "未命名.玄", WS_CHILD | WS_VISIBLE,
0, 0, 0, 0, hWnd, (HMENU)301, g_hInst, NULL);
// 默认示例
string demo =
"头文件《标准IO》\n"
"\n"
"主程序:\n"
" 定义 a = 10;\n"
" 定义 总数 = 0;\n"
"\n"
" 对于(定义 i = 0;i 比 a 小;i 递增)《\n"
" 如果(i 大于 2)《\n"
" 总数 = 总数 加 1;\n"
" 输出:\"当前i是:\":i:换行;\n"
" 》\n"
" 》\n"
"\n"
" 输出:\"循环结束,总数是:\":总数:换行;\n"
" 返回 0;\n"
"。// 结束\n";
SetWindowText(g_hEdit, demo.c_str());
break;
}
case WM_SIZE: {
RECT rc; GetClientRect(hWnd, &rc);
int w = rc.right - rc.left, h = rc.bottom - rc.top;
int toolbarH = 40, outH = 120, statusH = 25;
SetWindowPos(g_hEdit, NULL, 5, toolbarH+5, w-10, h-toolbarH-outH-statusH-15, SWP_NOZORDER);
SetWindowPos(g_hOutput, NULL, 5, h-outH-statusH-5, w-10, outH-5, SWP_NOZORDER);
SendMessage(g_hStatusBar, WM_SIZE, 0, 0);
break;
}
case WM_COMMAND: {
int id = LOWORD(wParam);
if (id == 201) { // 保存
int len = GetWindowTextLength(g_hEdit) + 1;
char* buf = new char[len];
GetWindowText(g_hEdit, buf, len);
string content = buf;
delete[] buf;
if (SaveFile(content)) {
SetWindowText(g_hOutput, "✅ 已保存: " + g_currentFilePath + "\n");
}
}
else if (id == 202) { // 编译
if (g_isCompiling || g_isRunning) break;
int len = GetWindowTextLength(g_hEdit) + 1;
char* buf = new char[len];
GetWindowText(g_hEdit, buf, len);
string src = buf;
delete[] buf;
// 先保存
if (!g_currentFilePath.empty()) {
write_file(g_currentFilePath, src);
}
SetWindowText(g_hOutput, "");
thread t([src]() { CompileAndRun(src, false); });
t.detach();
}
else if (id == 203) { // 运行
if (g_isCompiling || g_isRunning) break;
int len = GetWindowTextLength(g_hEdit) + 1;
char* buf = new char[len];
GetWindowText(g_hEdit, buf, len);
string src = buf;
delete[] buf;
if (!g_currentFilePath.empty()) {
write_file(g_currentFilePath, src);
}
SetWindowText(g_hOutput, "");
thread t([src]() { CompileAndRun(src, true); });
t.detach();
EnableWindow(g_hBtnStop, TRUE);
g_isRunning = true;
}
else if (id == 204) { // 停止
system("taskkill /F /IM output.exe >nul 2>nul");
g_isRunning = false;
EnableWindow(g_hBtnStop, FALSE);
SetWindowText(g_hOutput, "⏹ 已终止运行\n");
}
else if (id == 205) { // 清空
SetWindowText(g_hOutput, "");
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
// ---------- 入口 ----------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
g_hInst = hInstance;
INITCOMMONCONTROLSEX icex = {sizeof(icex), ICC_WIN95_CLASSES};
InitCommonControlsEx(&icex);
WNDCLASS 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);
RegisterClass(&wc);
g_hMainWnd = CreateWindowEx(0, "XuanIDE", "《玄》IDE v2.0",
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, 950, 700,
NULL, NULL, hInstance, NULL);
if (!g_hMainWnd) return 1;
g_hFont = CreateFont(20, 0, 0, 0, FW_NORMAL, 0, 0, 0,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Consolas");
g_hOutputFont = CreateFont(16, 0, 0, 0, FW_NORMAL, 0, 0, 0,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Consolas");
ShowWindow(g_hMainWnd, nCmdShow);
UpdateWindow(g_hMainWnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}