Initial commit: Oraset3 programming language with OS-level features
This commit is contained in:
@@ -0,0 +1,714 @@
|
||||
#include "oraset3.h"
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
|
||||
namespace oraset3 {
|
||||
|
||||
void CodeGenerator::emit(const std::string& str) {
|
||||
code += str;
|
||||
}
|
||||
|
||||
void CodeGenerator::emitLine(const std::string& str) {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
code += " ";
|
||||
}
|
||||
code += str + "\n";
|
||||
}
|
||||
|
||||
void CodeGenerator::indentUp() {
|
||||
indent++;
|
||||
}
|
||||
|
||||
void CodeGenerator::indentDown() {
|
||||
indent--;
|
||||
}
|
||||
|
||||
std::string CodeGenerator::generate(ProgramNode& program) {
|
||||
code = "";
|
||||
indent = 0;
|
||||
|
||||
emitLine("// Generated by Oraset3 Compiler");
|
||||
emitLine("#include <iostream>");
|
||||
emitLine("#include <string>");
|
||||
emitLine("#include <vector>");
|
||||
emitLine("#include <map>");
|
||||
emitLine("#include <cmath>");
|
||||
emitLine("#include <fstream>");
|
||||
emitLine("#include <cstdio>");
|
||||
emitLine("#include <cstdlib>");
|
||||
emitLine("#include <sstream>");
|
||||
emitLine("#ifdef _WIN32");
|
||||
emitLine("#include <windows.h>");
|
||||
emitLine("#include <conio.h>");
|
||||
emitLine("#include <commdlg.h>");
|
||||
emitLine("#else");
|
||||
emitLine("#include <unistd.h>");
|
||||
emitLine("#include <sys/ioctl.h>");
|
||||
emitLine("#include <termios.h>");
|
||||
emitLine("#endif");
|
||||
emitLine("");
|
||||
emitLine("using namespace std;");
|
||||
emitLine("");
|
||||
emitLine("// 设置控制台编码为 UTF-8");
|
||||
emitLine("#ifdef _WIN32");
|
||||
emitLine("struct ConsoleInitializer {");
|
||||
emitLine(" ConsoleInitializer() {");
|
||||
emitLine(" SetConsoleOutputCP(65001);");
|
||||
emitLine(" SetConsoleCP(65001);");
|
||||
emitLine(" }");
|
||||
emitLine("};");
|
||||
emitLine("static ConsoleInitializer _consoleInit;");
|
||||
emitLine("#endif");
|
||||
emitLine("");
|
||||
|
||||
// 输出内置函数声明
|
||||
emitLine("// Built-in functions");
|
||||
emitLine("void print(string value);");
|
||||
emitLine("void println(string value);");
|
||||
emitLine("void print(int value);");
|
||||
emitLine("void println(int value);");
|
||||
emitLine("void print(float value);");
|
||||
emitLine("void println(float value);");
|
||||
emitLine("void print(bool value);");
|
||||
emitLine("void println(bool value);");
|
||||
emitLine("");
|
||||
|
||||
// 系统操作函数声明
|
||||
emitLine("// System functions");
|
||||
emitLine("int sys(string cmd);");
|
||||
emitLine("");
|
||||
|
||||
// 文件操作函数声明
|
||||
emitLine("// File functions");
|
||||
emitLine("string file_read(string path);");
|
||||
emitLine("void file_write(string path, string content);");
|
||||
emitLine("bool file_exists(string path);");
|
||||
emitLine("");
|
||||
|
||||
// 屏幕操作函数声明
|
||||
emitLine("// Screen functions");
|
||||
emitLine("void screen_clear();");
|
||||
emitLine("string screen_size();");
|
||||
emitLine("");
|
||||
|
||||
// 绘图函数声明
|
||||
emitLine("// Draw functions");
|
||||
emitLine("void draw_text(int x, int y, string text);");
|
||||
emitLine("void draw_rect(int x, int y, int width, int height);");
|
||||
emitLine("void draw_line(int x1, int y1, int x2, int y2);");
|
||||
emitLine("void draw_set_color(int r, int g, int b);");
|
||||
emitLine("");
|
||||
|
||||
// UI函数声明(仅当导入了sysui时)
|
||||
if (sysuiImported) {
|
||||
emitLine("// UI functions (sysui)");
|
||||
emitLine("void ui_msgbox(string title, string message);");
|
||||
emitLine("string ui_inputbox(string title, string prompt);");
|
||||
emitLine("void ui_alert(string message);");
|
||||
emitLine("bool ui_confirm(string message);");
|
||||
emitLine("string ui_prompt(string message);");
|
||||
emitLine("string ui_openfile();");
|
||||
emitLine("string ui_savefile();");
|
||||
emitLine("string ui_dir();");
|
||||
emitLine("void ui_color(int r, int g, int b);");
|
||||
emitLine("");
|
||||
}
|
||||
|
||||
visit(program);
|
||||
|
||||
// 输出内置函数实现
|
||||
emitLine("// Built-in function implementations");
|
||||
emitLine("void println(string s) { printf(\"%s\\n\", s.c_str()); }");
|
||||
emitLine("void print(string s) { printf(\"%s\", s.c_str()); }");
|
||||
emitLine("void print(int value) { printf(\"%d\", value); }");
|
||||
emitLine("void println(int value) { printf(\"%d\\n\", value); }");
|
||||
emitLine("void print(float value) { printf(\"%g\", value); }");
|
||||
emitLine("void println(float value) { printf(\"%g\\n\", value); }");
|
||||
emitLine("void print(bool value) { printf(\"%s\", value ? \"true\" : \"false\"); }");
|
||||
emitLine("void println(bool value) { printf(\"%s\\n\", value ? \"true\" : \"false\"); }");
|
||||
emitLine("");
|
||||
|
||||
// 系统操作函数实现
|
||||
emitLine("// System function implementations");
|
||||
emitLine("int sys(string cmd) {");
|
||||
emitLine(" return system(cmd.c_str());");
|
||||
emitLine("}");
|
||||
emitLine("");
|
||||
|
||||
// 文件操作函数实现
|
||||
emitLine("// File function implementations");
|
||||
emitLine("string file_read(string path) {");
|
||||
emitLine(" ifstream file(path);");
|
||||
emitLine(" if (!file) return \"\";");
|
||||
emitLine(" stringstream buffer;");
|
||||
emitLine(" buffer << file.rdbuf();");
|
||||
emitLine(" return buffer.str();");
|
||||
emitLine("}");
|
||||
emitLine("void file_write(string path, string content) {");
|
||||
emitLine(" ofstream file(path);");
|
||||
emitLine(" if (file) {");
|
||||
emitLine(" file << content;");
|
||||
emitLine(" }");
|
||||
emitLine("}");
|
||||
emitLine("bool file_exists(string path) {");
|
||||
emitLine(" ifstream file(path);");
|
||||
emitLine(" return file.good();");
|
||||
emitLine("}");
|
||||
emitLine("");
|
||||
|
||||
// 屏幕操作函数实现
|
||||
emitLine("// Screen function implementations");
|
||||
emitLine("void screen_clear() {");
|
||||
emitLine("#ifdef _WIN32");
|
||||
emitLine(" system(\"cls\");");
|
||||
emitLine("#else");
|
||||
emitLine(" system(\"clear\");");
|
||||
emitLine("#endif");
|
||||
emitLine("}");
|
||||
emitLine("string screen_size() {");
|
||||
emitLine("#ifdef _WIN32");
|
||||
emitLine(" CONSOLE_SCREEN_BUFFER_INFO csbi;");
|
||||
emitLine(" GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);");
|
||||
emitLine(" int width = csbi.srWindow.Right - csbi.srWindow.Left + 1;");
|
||||
emitLine(" int height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;");
|
||||
emitLine(" return to_string(width) + \"x\" + to_string(height);");
|
||||
emitLine("#else");
|
||||
emitLine(" struct winsize w;");
|
||||
emitLine(" ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);");
|
||||
emitLine(" return to_string(w.ws_col) + \"x\" + to_string(w.ws_row);");
|
||||
emitLine("#endif");
|
||||
emitLine("}");
|
||||
emitLine("");
|
||||
|
||||
// 绘图函数实现
|
||||
emitLine("// Draw function implementations");
|
||||
emitLine("void draw_text(int x, int y, string text) {");
|
||||
emitLine("#ifdef _WIN32");
|
||||
emitLine(" COORD coord;");
|
||||
emitLine(" coord.X = x;");
|
||||
emitLine(" coord.Y = y;");
|
||||
emitLine(" SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);");
|
||||
emitLine(" printf(\"%s\", text.c_str());");
|
||||
emitLine("#else");
|
||||
emitLine(" printf(\"\\033[%d;%dH%s\", y+1, x+1, text.c_str());");
|
||||
emitLine("#endif");
|
||||
emitLine("}");
|
||||
emitLine("void draw_rect(int x, int y, int width, int height) {");
|
||||
emitLine(" for (int row = y; row < y + height; row++) {");
|
||||
emitLine(" for (int col = x; col < x + width; col++) {");
|
||||
emitLine(" if (row == y || row == y + height - 1 || col == x || col == x + width - 1) {");
|
||||
emitLine(" draw_text(col, row, \"*\");");
|
||||
emitLine(" }");
|
||||
emitLine(" }");
|
||||
emitLine(" }");
|
||||
emitLine("}");
|
||||
emitLine("void draw_line(int x1, int y1, int x2, int y2) {");
|
||||
emitLine(" int dx = abs(x2 - x1);");
|
||||
emitLine(" int dy = abs(y2 - y1);");
|
||||
emitLine(" int sx = (x1 < x2) ? 1 : -1;");
|
||||
emitLine(" int sy = (y1 < y2) ? 1 : -1;");
|
||||
emitLine(" int err = dx - dy;");
|
||||
emitLine(" int x = x1, y = y1;");
|
||||
emitLine(" while (true) {");
|
||||
emitLine(" draw_text(x, y, \".\");");
|
||||
emitLine(" if (x == x2 && y == y2) break;");
|
||||
emitLine(" int e2 = 2 * err;");
|
||||
emitLine(" if (e2 > -dy) { err -= dy; x += sx; }");
|
||||
emitLine(" if (e2 < dx) { err += dx; y += sy; }");
|
||||
emitLine(" }");
|
||||
emitLine("}");
|
||||
emitLine("void draw_set_color(int r, int g, int b) {");
|
||||
emitLine("#ifdef _WIN32");
|
||||
emitLine(" HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);");
|
||||
emitLine(" WORD color = ((r / 51) << 5) | ((g / 51) << 2) | (b / 51);");
|
||||
emitLine(" SetConsoleTextAttribute(hConsole, color);");
|
||||
emitLine("#else");
|
||||
emitLine(" printf(\"\\033[38;2;%d;%d;%dm\", r, g, b);");
|
||||
emitLine("#endif");
|
||||
emitLine("}");
|
||||
emitLine("");
|
||||
|
||||
// UI函数实现(仅当导入了sysui时)
|
||||
if (sysuiImported) {
|
||||
emitLine("// UI function implementations (sysui)");
|
||||
emitLine("void ui_msgbox(string title, string message) {");
|
||||
emitLine(" printf(\"[Dialog] %s:\\n%s\\n\", title.c_str(), message.c_str());");
|
||||
emitLine(" printf(\"Press Enter to continue...\");");
|
||||
emitLine(" getchar();");
|
||||
emitLine("}");
|
||||
emitLine("string ui_inputbox(string title, string prompt) {");
|
||||
emitLine(" printf(\"[%s] %s: \", title.c_str(), prompt.c_str());");
|
||||
emitLine(" string input;");
|
||||
emitLine(" getline(cin, input);");
|
||||
emitLine(" return input;");
|
||||
emitLine("}");
|
||||
emitLine("void ui_alert(string message) {");
|
||||
emitLine(" printf(\"[Alert] %s\\n\", message.c_str());");
|
||||
emitLine(" printf(\"Press Enter to continue...\");");
|
||||
emitLine(" getchar();");
|
||||
emitLine("}");
|
||||
emitLine("bool ui_confirm(string message) {");
|
||||
emitLine(" printf(\"[Confirm] %s (y/n): \", message.c_str());");
|
||||
emitLine(" char c = getchar();");
|
||||
emitLine(" // 清除换行符");
|
||||
emitLine(" if (c != '\\n') getchar();");
|
||||
emitLine(" return (c == 'y' || c == 'Y');");
|
||||
emitLine("}");
|
||||
emitLine("string ui_prompt(string message) {");
|
||||
emitLine(" printf(\"%s: \", message.c_str());");
|
||||
emitLine(" string input;");
|
||||
emitLine(" getline(cin, input);");
|
||||
emitLine(" return input;");
|
||||
emitLine("}");
|
||||
emitLine("string ui_openfile() {");
|
||||
emitLine(" printf(\"[Open File] Enter file path: \");");
|
||||
emitLine(" string path;");
|
||||
emitLine(" getline(cin, path);");
|
||||
emitLine(" return path;");
|
||||
emitLine("}");
|
||||
emitLine("string ui_savefile() {");
|
||||
emitLine(" printf(\"[Save File] Enter file path: \");");
|
||||
emitLine(" string path;");
|
||||
emitLine(" getline(cin, path);");
|
||||
emitLine(" return path;");
|
||||
emitLine("}");
|
||||
emitLine("string ui_dir() {");
|
||||
emitLine(" printf(\"[Select Directory] Enter directory path: \");");
|
||||
emitLine(" string path;");
|
||||
emitLine(" getline(cin, path);");
|
||||
emitLine(" return path;");
|
||||
emitLine("}");
|
||||
emitLine("void ui_color(int r, int g, int b) {");
|
||||
emitLine(" draw_set_color(r, g, b);");
|
||||
emitLine("}");
|
||||
emitLine("");
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(ProgramNode& node) {
|
||||
bool hasMain = false;
|
||||
std::vector<ASTNode*> topLevelStmts;
|
||||
|
||||
// 第一遍:输出所有结构体、接口、联合体和枚举声明
|
||||
for (auto& decl : node.declarations) {
|
||||
if (decl->getType() == NodeType::STRUCT_DECL || decl->getType() == NodeType::INTERFACE_DECL ||
|
||||
decl->getType() == NodeType::UNION_DECL || decl->getType() == NodeType::ENUM_DECL) {
|
||||
decl->accept(*this);
|
||||
emitLine("");
|
||||
}
|
||||
}
|
||||
|
||||
// 第二遍:输出所有函数声明(原型)并收集顶层语句
|
||||
for (auto& decl : node.declarations) {
|
||||
if (decl->getType() == NodeType::FUNC_DECL) {
|
||||
FuncDeclNode& funcDecl = static_cast<FuncDeclNode&>(*decl);
|
||||
if (funcDecl.name == "main") {
|
||||
hasMain = true;
|
||||
}
|
||||
|
||||
std::string returnType = funcDecl.returnType.empty() ? "void" : funcDecl.returnType;
|
||||
if (funcDecl.name == "main") {
|
||||
returnType = "int";
|
||||
}
|
||||
|
||||
emit(returnType + " " + funcDecl.name + "(");
|
||||
for (size_t i = 0; i < funcDecl.params.size(); i++) {
|
||||
std::string paramType = funcDecl.params[i].second.empty() ? "auto" : funcDecl.params[i].second;
|
||||
emit(paramType + " " + funcDecl.params[i].first);
|
||||
if (i < funcDecl.params.size() - 1) {
|
||||
emit(", ");
|
||||
}
|
||||
}
|
||||
emitLine(");");
|
||||
} else if (decl->getType() == NodeType::EXPR_STMT || decl->getType() == NodeType::VAR_DECL
|
||||
|| decl->getType() == NodeType::IF_STMT || decl->getType() == NodeType::WHILE_STMT
|
||||
|| decl->getType() == NodeType::FOR_STMT || decl->getType() == NodeType::RETURN_STMT) {
|
||||
// 收集顶层语句(包括控制流语句)
|
||||
topLevelStmts.push_back(decl.get());
|
||||
}
|
||||
}
|
||||
emitLine("");
|
||||
|
||||
// 如果没有main函数且有顶层语句,自动生成main函数
|
||||
if (!hasMain && !topLevelStmts.empty()) {
|
||||
emitLine("int main() {");
|
||||
indentUp();
|
||||
for (auto* stmt : topLevelStmts) {
|
||||
stmt->accept(*this);
|
||||
}
|
||||
emitLine("return 0;");
|
||||
indentDown();
|
||||
emitLine("}");
|
||||
emitLine("");
|
||||
}
|
||||
|
||||
// 第三遍:输出所有函数实现(跳过顶层语句和结构体/接口/联合体/枚举)
|
||||
for (auto& decl : node.declarations) {
|
||||
if (decl->getType() != NodeType::EXPR_STMT && decl->getType() != NodeType::VAR_DECL
|
||||
&& decl->getType() != NodeType::STRUCT_DECL && decl->getType() != NodeType::INTERFACE_DECL
|
||||
&& decl->getType() != NodeType::UNION_DECL && decl->getType() != NodeType::ENUM_DECL
|
||||
&& decl->getType() != NodeType::IF_STMT && decl->getType() != NodeType::WHILE_STMT
|
||||
&& decl->getType() != NodeType::FOR_STMT && decl->getType() != NodeType::RETURN_STMT) {
|
||||
decl->accept(*this);
|
||||
emitLine("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(VarDeclNode& node) {
|
||||
std::string type = node.type;
|
||||
|
||||
// 如果没有指定类型且有初始化器,尝试推断类型
|
||||
if (type.empty() && node.initializer) {
|
||||
// 检查初始化器是否是字符串字面量
|
||||
if (node.initializer->getType() == NodeType::LITERAL_EXPR) {
|
||||
LiteralExprNode* lit = static_cast<LiteralExprNode*>(node.initializer.get());
|
||||
if (lit->type == "string") {
|
||||
type = "string";
|
||||
} else {
|
||||
type = "auto";
|
||||
}
|
||||
} else {
|
||||
type = "auto";
|
||||
}
|
||||
} else if (type.empty()) {
|
||||
type = "auto";
|
||||
}
|
||||
|
||||
emit(type + " " + node.name);
|
||||
|
||||
if (node.initializer) {
|
||||
emit(" = ");
|
||||
node.initializer->accept(*this);
|
||||
}
|
||||
|
||||
emitLine(";");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(FuncDeclNode& node) {
|
||||
std::string returnType = node.returnType.empty() ? "void" : node.returnType;
|
||||
if (node.name == "main") {
|
||||
returnType = "int";
|
||||
}
|
||||
emit(returnType + " " + node.name + "(");
|
||||
|
||||
for (size_t i = 0; i < node.params.size(); i++) {
|
||||
std::string paramType = node.params[i].second.empty() ? "auto" : node.params[i].second;
|
||||
emit(paramType + " " + node.params[i].first);
|
||||
if (i < node.params.size() - 1) {
|
||||
emit(", ");
|
||||
}
|
||||
}
|
||||
|
||||
emitLine(") {");
|
||||
indentUp();
|
||||
|
||||
for (auto& stmt : node.body) {
|
||||
stmt->accept(*this);
|
||||
}
|
||||
|
||||
indentDown();
|
||||
emitLine("}");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(StructDeclNode& node) {
|
||||
emitLine("struct " + node.name + " {");
|
||||
indentUp();
|
||||
|
||||
for (auto& field : node.fields) {
|
||||
std::string fieldType = field.second.empty() ? "auto" : field.second;
|
||||
emitLine(fieldType + " " + field.first + ";");
|
||||
}
|
||||
|
||||
indentDown();
|
||||
emitLine("};");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(InterfaceDeclNode& node) {
|
||||
emitLine("class " + node.name + " {");
|
||||
indentUp();
|
||||
emitLine("public:");
|
||||
indentUp();
|
||||
|
||||
for (auto& method : node.methods) {
|
||||
std::string returnType = method.second.empty() ? "void" : method.second;
|
||||
emitLine("virtual " + returnType + " " + method.first + "() = 0;");
|
||||
}
|
||||
|
||||
indentDown();
|
||||
indentDown();
|
||||
emitLine("};");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(UnionDeclNode& node) {
|
||||
emitLine("union " + node.name + " {");
|
||||
indentUp();
|
||||
|
||||
for (auto& field : node.fields) {
|
||||
std::string fieldType = field.second.empty() ? "auto" : field.second;
|
||||
emitLine(fieldType + " " + field.first + ";");
|
||||
}
|
||||
|
||||
indentDown();
|
||||
emitLine("};");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(EnumDeclNode& node) {
|
||||
emitLine("enum " + node.name + " {");
|
||||
indentUp();
|
||||
|
||||
for (size_t i = 0; i < node.values.size(); i++) {
|
||||
auto& value = node.values[i];
|
||||
emit(value.first);
|
||||
if (!value.second.empty()) {
|
||||
emit(" = " + value.second);
|
||||
}
|
||||
if (i < node.values.size() - 1) {
|
||||
emit(",");
|
||||
}
|
||||
emitLine("");
|
||||
}
|
||||
|
||||
indentDown();
|
||||
emitLine("};");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(CastExprNode& node) {
|
||||
emit("(" + node.targetType + ")(");
|
||||
if (node.expr) {
|
||||
node.expr->accept(*this);
|
||||
}
|
||||
emit(")");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(IfStmtNode& node) {
|
||||
emit("if (");
|
||||
node.condition->accept(*this);
|
||||
emitLine(") {");
|
||||
indentUp();
|
||||
|
||||
for (auto& stmt : node.thenBranch) {
|
||||
stmt->accept(*this);
|
||||
}
|
||||
|
||||
indentDown();
|
||||
emitLine("}");
|
||||
|
||||
if (!node.elseBranch.empty()) {
|
||||
emit("else ");
|
||||
|
||||
if (node.elseBranch.size() == 1 &&
|
||||
node.elseBranch[0]->getType() == NodeType::IF_STMT) {
|
||||
node.elseBranch[0]->accept(*this);
|
||||
} else {
|
||||
emitLine("{");
|
||||
indentUp();
|
||||
|
||||
for (auto& stmt : node.elseBranch) {
|
||||
stmt->accept(*this);
|
||||
}
|
||||
|
||||
indentDown();
|
||||
emitLine("}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(ForStmtNode& node) {
|
||||
emit("for (");
|
||||
|
||||
if (node.init) {
|
||||
node.init->accept(*this);
|
||||
}
|
||||
emit("; ");
|
||||
|
||||
if (node.condition) {
|
||||
node.condition->accept(*this);
|
||||
}
|
||||
emit("; ");
|
||||
|
||||
if (node.update) {
|
||||
node.update->accept(*this);
|
||||
}
|
||||
|
||||
emitLine(") {");
|
||||
indentUp();
|
||||
|
||||
for (auto& stmt : node.body) {
|
||||
stmt->accept(*this);
|
||||
}
|
||||
|
||||
indentDown();
|
||||
emitLine("}");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(WhileStmtNode& node) {
|
||||
emit("while (");
|
||||
node.condition->accept(*this);
|
||||
emitLine(") {");
|
||||
indentUp();
|
||||
|
||||
for (auto& stmt : node.body) {
|
||||
stmt->accept(*this);
|
||||
}
|
||||
|
||||
indentDown();
|
||||
emitLine("}");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(ReturnStmtNode& node) {
|
||||
emit("return");
|
||||
|
||||
if (node.expr) {
|
||||
emit(" ");
|
||||
node.expr->accept(*this);
|
||||
}
|
||||
|
||||
emitLine(";");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(ExprStmtNode& node) {
|
||||
node.expr->accept(*this);
|
||||
emitLine(";");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(AssignExprNode& node) {
|
||||
node.left->accept(*this);
|
||||
emit(" " + node.op + " ");
|
||||
node.right->accept(*this);
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(BinaryExprNode& node) {
|
||||
emit("(");
|
||||
node.left->accept(*this);
|
||||
emit(" " + node.op + " ");
|
||||
node.right->accept(*this);
|
||||
emit(")");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(UnaryExprNode& node) {
|
||||
emit(node.op);
|
||||
node.operand->accept(*this);
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(CallExprNode& node) {
|
||||
// 检查是否是特殊的系统函数调用
|
||||
std::string funcName;
|
||||
|
||||
if (node.callee->getType() == NodeType::IDENTIFIER_EXPR) {
|
||||
IdentifierExprNode* ident = static_cast<IdentifierExprNode*>(node.callee.get());
|
||||
funcName = ident->name;
|
||||
} else if (node.callee->getType() == NodeType::MEMBER_EXPR) {
|
||||
MemberExprNode* member = static_cast<MemberExprNode*>(node.callee.get());
|
||||
if (member->object->getType() == NodeType::IDENTIFIER_EXPR) {
|
||||
IdentifierExprNode* objIdent = static_cast<IdentifierExprNode*>(member->object.get());
|
||||
funcName = objIdent->name + "." + member->property;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理系统函数调用的转换
|
||||
if (funcName == "sys") {
|
||||
emit("sys(");
|
||||
} else if (funcName == "file.read") {
|
||||
emit("file_read(");
|
||||
} else if (funcName == "file.write") {
|
||||
emit("file_write(");
|
||||
} else if (funcName == "file.exists") {
|
||||
emit("file_exists(");
|
||||
} else if (funcName == "screen.clear") {
|
||||
emit("screen_clear(");
|
||||
} else if (funcName == "screen.size") {
|
||||
emit("screen_size(");
|
||||
} else if (funcName == "draw.text") {
|
||||
emit("draw_text(");
|
||||
} else if (funcName == "draw.rect") {
|
||||
emit("draw_rect(");
|
||||
} else if (funcName == "draw.line") {
|
||||
emit("draw_line(");
|
||||
} else if (funcName == "draw.color") {
|
||||
emit("draw_set_color(");
|
||||
} else if (funcName == "ui.msgbox") {
|
||||
emit("ui_msgbox(");
|
||||
} else if (funcName == "ui.inputbox") {
|
||||
emit("ui_inputbox(");
|
||||
} else if (funcName == "ui.alert") {
|
||||
emit("ui_alert(");
|
||||
} else if (funcName == "ui.confirm") {
|
||||
emit("ui_confirm(");
|
||||
} else if (funcName == "ui.prompt") {
|
||||
emit("ui_prompt(");
|
||||
} else if (funcName == "ui.openfile") {
|
||||
emit("ui_openfile(");
|
||||
} else if (funcName == "ui.savefile") {
|
||||
emit("ui_savefile(");
|
||||
} else if (funcName == "ui.dir") {
|
||||
emit("ui_dir(");
|
||||
} else if (funcName == "ui.color") {
|
||||
emit("ui_color(");
|
||||
} else {
|
||||
node.callee->accept(*this);
|
||||
emit("(");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < node.args.size(); i++) {
|
||||
// 如果参数是字符串字面量,包装为 string() 以确保正确的函数重载
|
||||
if (node.args[i]->getType() == NodeType::LITERAL_EXPR) {
|
||||
LiteralExprNode* lit = static_cast<LiteralExprNode*>(node.args[i].get());
|
||||
if (lit->type == "string") {
|
||||
emit("string(");
|
||||
}
|
||||
}
|
||||
node.args[i]->accept(*this);
|
||||
if (node.args[i]->getType() == NodeType::LITERAL_EXPR) {
|
||||
LiteralExprNode* lit = static_cast<LiteralExprNode*>(node.args[i].get());
|
||||
if (lit->type == "string") {
|
||||
emit(")");
|
||||
}
|
||||
}
|
||||
if (i < node.args.size() - 1) {
|
||||
emit(", ");
|
||||
}
|
||||
}
|
||||
|
||||
emit(")");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(IndexExprNode& node) {
|
||||
node.base->accept(*this);
|
||||
emit("[");
|
||||
node.index->accept(*this);
|
||||
emit("]");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(MemberExprNode& node) {
|
||||
node.object->accept(*this);
|
||||
emit(node.op + node.property);
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(StructInitNode& node) {
|
||||
emit(node.typeName + "{");
|
||||
for (size_t i = 0; i < node.fields.size(); i++) {
|
||||
emit("." + node.fields[i].first + " = ");
|
||||
node.fields[i].second->accept(*this);
|
||||
if (i < node.fields.size() - 1) {
|
||||
emit(", ");
|
||||
}
|
||||
}
|
||||
emit("}");
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(LiteralExprNode& node) {
|
||||
if (node.type == "string") {
|
||||
emit("\"" + node.value + "\"");
|
||||
} else {
|
||||
emit(node.value);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::visit(IdentifierExprNode& node) {
|
||||
emit(node.name);
|
||||
}
|
||||
|
||||
} // namespace oraset3
|
||||
@@ -0,0 +1,403 @@
|
||||
#include "oraset3.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <sstream>
|
||||
#include <chrono>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace oraset3 {
|
||||
|
||||
// 全局变量:是否导入了 sysui
|
||||
bool sysuiImported = false;
|
||||
|
||||
// 加载头文件
|
||||
std::string loadHeader(const std::string& headerName) {
|
||||
std::vector<std::string> searchPaths = {
|
||||
"./include/",
|
||||
"./headers/",
|
||||
"./lib/",
|
||||
""
|
||||
};
|
||||
|
||||
std::string orhName = headerName;
|
||||
if (orhName.find(".orh") == std::string::npos) {
|
||||
orhName += ".orh";
|
||||
}
|
||||
|
||||
for (const auto& path : searchPaths) {
|
||||
std::string fullPath = path + orhName;
|
||||
if (std::filesystem::exists(fullPath)) {
|
||||
std::ifstream ifs(fullPath);
|
||||
if (ifs) {
|
||||
std::string content((std::istreambuf_iterator<char>(ifs)),
|
||||
std::istreambuf_iterator<char>());
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("Cannot find header file: " + headerName);
|
||||
}
|
||||
|
||||
// 处理 $ 导入语法
|
||||
std::string processHeaderIncludes(const std::string& source) {
|
||||
std::istringstream iss(source);
|
||||
std::string line;
|
||||
std::string result;
|
||||
bool inMultiLineComment = false;
|
||||
|
||||
while (std::getline(iss, line)) {
|
||||
std::string trimmed = line;
|
||||
// 去除首尾空白
|
||||
while (!trimmed.empty() && (trimmed[0] == ' ' || trimmed[0] == '\t')) {
|
||||
trimmed = trimmed.substr(1);
|
||||
}
|
||||
while (!trimmed.empty() && (trimmed.back() == ' ' || trimmed.back() == '\t')) {
|
||||
trimmed.pop_back();
|
||||
}
|
||||
|
||||
// 跳过单行注释
|
||||
if (trimmed.substr(0, 2) == "//") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 处理多行注释开始/结束
|
||||
if (trimmed.find("/*") != std::string::npos) {
|
||||
inMultiLineComment = true;
|
||||
}
|
||||
if (trimmed.find("*/") != std::string::npos) {
|
||||
inMultiLineComment = false;
|
||||
continue;
|
||||
}
|
||||
if (inMultiLineComment) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 处理 $ 头文件导入
|
||||
if (!trimmed.empty() && trimmed[0] == '$') {
|
||||
std::string headerName = trimmed.substr(1);
|
||||
// 去除可能的分号
|
||||
if (!headerName.empty() && headerName.back() == ';') {
|
||||
headerName.pop_back();
|
||||
}
|
||||
// 去除首尾空白
|
||||
while (!headerName.empty() && (headerName[0] == ' ' || headerName[0] == '\t')) {
|
||||
headerName = headerName.substr(1);
|
||||
}
|
||||
while (!headerName.empty() && (headerName.back() == ' ' || headerName.back() == '\t')) {
|
||||
headerName.pop_back();
|
||||
}
|
||||
|
||||
// 特殊处理 $sysui - 内置UI库
|
||||
if (headerName == "sysui") {
|
||||
sysuiImported = true;
|
||||
result += "// UI Library (sysui) imported\n";
|
||||
} else {
|
||||
try {
|
||||
std::string headerContent = loadHeader(headerName);
|
||||
result += "// Header: " + headerName + "\n";
|
||||
// 直接包含头文件内容(用Oraset3语言编写的函数实现)
|
||||
result += headerContent + "\n";
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Warning: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result += line + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Compiler::compile(const std::string& source) {
|
||||
try {
|
||||
// 重置 sysuiImported 标志
|
||||
sysuiImported = false;
|
||||
|
||||
// 预处理:处理头文件导入
|
||||
std::string processedSource = processHeaderIncludes(source);
|
||||
|
||||
// 词法分析
|
||||
Lexer lexer(processedSource);
|
||||
std::vector<std::unique_ptr<Token>> tokens;
|
||||
|
||||
while (true) {
|
||||
auto token = lexer.nextToken();
|
||||
if (token->type == TokenType::END_OF_FILE) {
|
||||
break;
|
||||
}
|
||||
tokens.push_back(std::move(token));
|
||||
}
|
||||
|
||||
// 语法分析
|
||||
Parser parser(std::move(tokens));
|
||||
auto program = parser.parse();
|
||||
|
||||
// 语义分析
|
||||
SemanticAnalyzer analyzer(sysuiImported);
|
||||
analyzer.analyze(*program);
|
||||
|
||||
if (analyzer.hasErrors()) {
|
||||
std::string errorMsg = "Semantic errors:\n";
|
||||
for (const auto& error : analyzer.getErrors()) {
|
||||
errorMsg += " - " + error + "\n";
|
||||
}
|
||||
throw std::runtime_error(errorMsg);
|
||||
}
|
||||
|
||||
// 代码生成
|
||||
CodeGenerator generator(sysuiImported);
|
||||
return generator.generate(*program);
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
throw std::runtime_error("Compilation failed: " + std::string(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace oraset3
|
||||
|
||||
void runProgram(const std::string& exePath) {
|
||||
std::string cmd = "\"" + exePath + "\"";
|
||||
int result = system(cmd.c_str());
|
||||
if (result != 0) {
|
||||
std::cerr << "Program exited with code: " << result << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getTempFileName(const std::string& prefix, const std::string& suffix) {
|
||||
static int counter = 0;
|
||||
return prefix + "_" + std::to_string(counter++) + suffix;
|
||||
}
|
||||
|
||||
// 运行程序并捕获输出
|
||||
std::string runProgramAndCapture(const std::string& exePath) {
|
||||
#ifdef _WIN32
|
||||
// 使用临时文件来捕获输出,避免管道问题
|
||||
std::string outputFile = getTempFileName("oraset3_out", ".txt");
|
||||
|
||||
// 确保路径中没有引号
|
||||
std::string cleanExePath = exePath;
|
||||
if (!cleanExePath.empty() && cleanExePath.front() == '"') {
|
||||
cleanExePath = cleanExePath.substr(1);
|
||||
}
|
||||
if (!cleanExePath.empty() && cleanExePath.back() == '"') {
|
||||
cleanExePath = cleanExePath.substr(0, cleanExePath.size() - 1);
|
||||
}
|
||||
|
||||
std::string cmd = cleanExePath + " > " + outputFile + " 2>&1";
|
||||
system(cmd.c_str());
|
||||
|
||||
std::string output;
|
||||
{
|
||||
std::ifstream ifs(outputFile);
|
||||
output = std::string((std::istreambuf_iterator<char>(ifs)),
|
||||
std::istreambuf_iterator<char>());
|
||||
} // ifs 在此处自动关闭
|
||||
|
||||
std::filesystem::remove(outputFile);
|
||||
return output;
|
||||
#else
|
||||
// Linux version
|
||||
std::string outputFile = getTempFileName("oraset3_out", ".txt");
|
||||
|
||||
std::string cmd = exePath + " > " + outputFile + " 2>&1";
|
||||
system(cmd.c_str());
|
||||
|
||||
std::string output;
|
||||
{
|
||||
std::ifstream ifs(outputFile);
|
||||
output = std::string((std::istreambuf_iterator<char>(ifs)),
|
||||
std::istreambuf_iterator<char>());
|
||||
} // ifs 在此处自动关闭
|
||||
|
||||
std::filesystem::remove(outputFile);
|
||||
return output;
|
||||
#endif
|
||||
}
|
||||
|
||||
// 解释器模式运行
|
||||
void interpretProgram(const std::string& source, bool noOutputHeader) {
|
||||
try {
|
||||
oraset3::Compiler compiler;
|
||||
std::string cppCode = compiler.compile(source);
|
||||
|
||||
// 使用临时文件
|
||||
std::string outputFile = getTempFileName("oraset3", ".cpp");
|
||||
std::string exeFile = outputFile;
|
||||
size_t dotPos = exeFile.find_last_of('.');
|
||||
if (dotPos != std::string::npos) {
|
||||
exeFile = exeFile.substr(0, dotPos);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
exeFile += ".exe";
|
||||
#endif
|
||||
|
||||
// 写入C++文件
|
||||
std::ofstream ofs(outputFile);
|
||||
ofs << cppCode;
|
||||
ofs.close();
|
||||
|
||||
// 编译
|
||||
std::string compileCmd;
|
||||
#ifdef _WIN32
|
||||
compileCmd = "g++ -std=c++20 -mconsole -finput-charset=utf-8 -fexec-charset=utf-8 -o \"" + exeFile + "\" \"" + outputFile + "\"";
|
||||
#else
|
||||
compileCmd = "g++ -std=c++20 -finput-charset=utf-8 -fexec-charset=utf-8 -o " + exeFile + " " + outputFile;
|
||||
#endif
|
||||
|
||||
if (!noOutputHeader) {
|
||||
std::cout << "Compiling... " << std::endl;
|
||||
}
|
||||
|
||||
// 记录编译开始时间
|
||||
auto compileStart = std::chrono::high_resolution_clock::now();
|
||||
|
||||
int compileResult = system(compileCmd.c_str());
|
||||
|
||||
// 记录编译结束时间
|
||||
auto compileEnd = std::chrono::high_resolution_clock::now();
|
||||
auto compileDuration = std::chrono::duration_cast<std::chrono::milliseconds>(compileEnd - compileStart).count();
|
||||
|
||||
if (compileResult != 0) {
|
||||
std::cerr << "C++ compilation failed" << std::endl;
|
||||
std::filesystem::remove(outputFile);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!noOutputHeader) {
|
||||
// 运行程序并捕获输出
|
||||
std::cout << "Running..." << std::endl;
|
||||
|
||||
// 记录运行开始时间
|
||||
auto runStart = std::chrono::high_resolution_clock::now();
|
||||
|
||||
std::string programOutput = runProgramAndCapture(exeFile);
|
||||
|
||||
// 记录运行结束时间
|
||||
auto runEnd = std::chrono::high_resolution_clock::now();
|
||||
auto runDuration = std::chrono::duration_cast<std::chrono::milliseconds>(runEnd - runStart).count();
|
||||
|
||||
std::cout << "------------------------" << std::endl;
|
||||
std::cout << programOutput;
|
||||
std::cout << "------------------------" << std::endl;
|
||||
|
||||
// 显示编译和运行时间
|
||||
std::cout << "编译耗时: " << compileDuration << " ms" << std::endl;
|
||||
std::cout << "运行耗时: " << runDuration << " ms" << std::endl;
|
||||
std::cout << "------------------------" << std::endl;
|
||||
std::cout << "Program finished" << std::endl;
|
||||
} else {
|
||||
// 仅输出程序结果 - 直接运行避免管道带来的额外空行
|
||||
std::string runCmd;
|
||||
#ifdef _WIN32
|
||||
runCmd = "\"" + exeFile + "\"";
|
||||
#else
|
||||
runCmd = exeFile;
|
||||
#endif
|
||||
system(runCmd.c_str());
|
||||
}
|
||||
|
||||
// 清理临时文件
|
||||
std::filesystem::remove(outputFile);
|
||||
std::filesystem::remove(exeFile);
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// 解析命令行参数
|
||||
std::string inputFile;
|
||||
std::string outputFile;
|
||||
bool runDirectly = true;
|
||||
bool noOutputHeader = false;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string arg = argv[i];
|
||||
if (arg == "--noo") {
|
||||
noOutputHeader = true;
|
||||
} else if (inputFile.empty()) {
|
||||
inputFile = arg;
|
||||
} else if (outputFile.empty()) {
|
||||
outputFile = arg;
|
||||
runDirectly = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (inputFile.empty()) {
|
||||
std::cerr << "Usage:" << std::endl;
|
||||
std::cerr << " oraset3 <input_file> - Compile and run with full output" << std::endl;
|
||||
std::cerr << " oraset3 <input_file> <output_file> - Compile to C++ file" << std::endl;
|
||||
std::cerr << " oraset3 <input_file> --noo - Run with minimal output (only program output)" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 如果使用 --noo 参数,直接运行
|
||||
if (noOutputHeader) {
|
||||
try {
|
||||
std::ifstream ifs(inputFile);
|
||||
if (!ifs) {
|
||||
std::cerr << "Cannot open input file: " << inputFile << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string source((std::istreambuf_iterator<char>(ifs)),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
interpretProgram(source, noOutputHeader);
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 传统模式 - 编译并运行
|
||||
try {
|
||||
// 读取源文件
|
||||
std::ifstream ifs(inputFile);
|
||||
if (!ifs) {
|
||||
std::cerr << "Cannot open input file: " << inputFile << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string source((std::istreambuf_iterator<char>(ifs)),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
if (runDirectly && outputFile.empty()) {
|
||||
// 没有指定输出文件,直接编译并运行(带完整输出)
|
||||
interpretProgram(source, false);
|
||||
} else {
|
||||
// 编译到指定文件
|
||||
oraset3::Compiler compiler;
|
||||
std::string output = compiler.compile(source);
|
||||
|
||||
// 写入输出文件
|
||||
std::ofstream ofs(outputFile);
|
||||
if (!ofs) {
|
||||
std::cerr << "Cannot open output file: " << outputFile << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
ofs << output;
|
||||
ofs.close();
|
||||
|
||||
std::cout << "Compilation successful! Output written to: " << outputFile << std::endl;
|
||||
}
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
#include "oraset3.h"
|
||||
#include <cctype>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace oraset3 {
|
||||
|
||||
Lexer::Lexer(const std::string& source)
|
||||
: source(source), pos(0), line(1), column(1) {}
|
||||
|
||||
char Lexer::currentChar() {
|
||||
if (pos >= source.size()) return '\0';
|
||||
return source[pos];
|
||||
}
|
||||
|
||||
void Lexer::advance() {
|
||||
if (currentChar() == '\n') {
|
||||
line++;
|
||||
column = 1;
|
||||
} else {
|
||||
column++;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
void Lexer::skipWhitespace() {
|
||||
while (isspace(currentChar())) {
|
||||
advance();
|
||||
}
|
||||
}
|
||||
|
||||
std::string Lexer::readIdentifier() {
|
||||
std::string result;
|
||||
while (isalnum(currentChar()) || currentChar() == '_') {
|
||||
result += currentChar();
|
||||
advance();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Lexer::readNumber() {
|
||||
std::string result;
|
||||
bool hasDecimal = false;
|
||||
|
||||
while (isdigit(currentChar()) || (currentChar() == '.' && !hasDecimal)) {
|
||||
if (currentChar() == '.') hasDecimal = true;
|
||||
result += currentChar();
|
||||
advance();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Lexer::readString(char quote) {
|
||||
std::string result;
|
||||
advance(); // 跳过引号
|
||||
|
||||
while (currentChar() != quote && currentChar() != '\0') {
|
||||
if (currentChar() == '\\') {
|
||||
advance();
|
||||
switch (currentChar()) {
|
||||
case 'n': result += '\n'; break;
|
||||
case 't': result += '\t'; break;
|
||||
case 'r': result += '\r'; break;
|
||||
case '\\': result += '\\'; break;
|
||||
case '"': result += '"'; break;
|
||||
case '\'': result += '\''; break;
|
||||
default: result += currentChar(); break;
|
||||
}
|
||||
} else {
|
||||
result += currentChar();
|
||||
}
|
||||
advance();
|
||||
}
|
||||
|
||||
advance(); // 跳过结束引号
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Token> Lexer::nextToken() {
|
||||
skipWhitespace();
|
||||
|
||||
char c = currentChar();
|
||||
int tokenLine = line;
|
||||
int tokenColumn = column;
|
||||
|
||||
if (c == '\0') {
|
||||
return std::make_unique<Token>(TokenType::END_OF_FILE, "", tokenLine, tokenColumn);
|
||||
}
|
||||
|
||||
if (isalpha(c) || c == '_') {
|
||||
std::string id = readIdentifier();
|
||||
|
||||
static const std::unordered_map<std::string, TokenType> keywords = {
|
||||
{"var", TokenType::VAR},
|
||||
{"let", TokenType::LET},
|
||||
{"const", TokenType::CONST},
|
||||
{"func", TokenType::FUNC},
|
||||
{"struct", TokenType::STRUCT},
|
||||
{"interface", TokenType::INTERFACE},
|
||||
{"union", TokenType::UNION},
|
||||
{"enum", TokenType::ENUM},
|
||||
{"if", TokenType::IF},
|
||||
{"else", TokenType::ELSE},
|
||||
{"for", TokenType::FOR},
|
||||
{"while", TokenType::WHILE},
|
||||
{"return", TokenType::RETURN},
|
||||
{"break", TokenType::BREAK},
|
||||
{"continue", TokenType::CONTINUE},
|
||||
{"import", TokenType::IMPORT},
|
||||
{"export", TokenType::EXPORT},
|
||||
{"true", TokenType::TRUE},
|
||||
{"false", TokenType::FALSE},
|
||||
{"nil", TokenType::NIL}
|
||||
};
|
||||
|
||||
auto it = keywords.find(id);
|
||||
if (it != keywords.end()) {
|
||||
return std::make_unique<Token>(it->second, id, tokenLine, tokenColumn);
|
||||
}
|
||||
return std::make_unique<Token>(TokenType::IDENTIFIER, id, tokenLine, tokenColumn);
|
||||
}
|
||||
|
||||
if (isdigit(c)) {
|
||||
std::string num = readNumber();
|
||||
if (num.find('.') != std::string::npos) {
|
||||
return std::make_unique<Token>(TokenType::FLOAT, num, tokenLine, tokenColumn);
|
||||
}
|
||||
return std::make_unique<Token>(TokenType::INTEGER, num, tokenLine, tokenColumn);
|
||||
}
|
||||
|
||||
if (c == '"' || c == '\'') {
|
||||
std::string str = readString(c);
|
||||
return std::make_unique<Token>(TokenType::STRING, str, tokenLine, tokenColumn);
|
||||
}
|
||||
|
||||
advance();
|
||||
|
||||
switch (c) {
|
||||
case '+': {
|
||||
if (currentChar() == '=') {
|
||||
advance();
|
||||
return std::make_unique<Token>(TokenType::ADD_ASSIGN, "+=", tokenLine, tokenColumn);
|
||||
}
|
||||
return std::make_unique<Token>(TokenType::PLUS, "+", tokenLine, tokenColumn);
|
||||
}
|
||||
case '-': {
|
||||
if (currentChar() == '=') {
|
||||
advance();
|
||||
return std::make_unique<Token>(TokenType::SUB_ASSIGN, "-=", tokenLine, tokenColumn);
|
||||
}
|
||||
return std::make_unique<Token>(TokenType::MINUS, "-", tokenLine, tokenColumn);
|
||||
}
|
||||
case '/': {
|
||||
if (currentChar() == '=') {
|
||||
advance();
|
||||
return std::make_unique<Token>(TokenType::DIV_ASSIGN, "/=", tokenLine, tokenColumn);
|
||||
}
|
||||
// 跳过注释
|
||||
if (currentChar() == '/') {
|
||||
while (currentChar() != '\n' && currentChar() != '\0') {
|
||||
advance();
|
||||
}
|
||||
return nextToken();
|
||||
}
|
||||
return std::make_unique<Token>(TokenType::DIV, "/", tokenLine, tokenColumn);
|
||||
}
|
||||
case '%': return std::make_unique<Token>(TokenType::MOD, "%", tokenLine, tokenColumn);
|
||||
case '=': {
|
||||
if (currentChar() == '=') {
|
||||
advance();
|
||||
return std::make_unique<Token>(TokenType::EQ, "==", tokenLine, tokenColumn);
|
||||
}
|
||||
return std::make_unique<Token>(TokenType::ASSIGN, "=", tokenLine, tokenColumn);
|
||||
}
|
||||
case '!': {
|
||||
if (currentChar() == '=') {
|
||||
advance();
|
||||
return std::make_unique<Token>(TokenType::NEQ, "!=", tokenLine, tokenColumn);
|
||||
}
|
||||
return std::make_unique<Token>(TokenType::NOT, "!", tokenLine, tokenColumn);
|
||||
}
|
||||
case '<': {
|
||||
if (currentChar() == '<') {
|
||||
advance();
|
||||
return std::make_unique<Token>(TokenType::SHL, "<<", tokenLine, tokenColumn);
|
||||
}
|
||||
if (currentChar() == '=') {
|
||||
advance();
|
||||
return std::make_unique<Token>(TokenType::LE, "<=", tokenLine, tokenColumn);
|
||||
}
|
||||
return std::make_unique<Token>(TokenType::LT, "<", tokenLine, tokenColumn);
|
||||
}
|
||||
case '>': {
|
||||
if (currentChar() == '>') {
|
||||
advance();
|
||||
return std::make_unique<Token>(TokenType::SHR, ">>", tokenLine, tokenColumn);
|
||||
}
|
||||
if (currentChar() == '=') {
|
||||
advance();
|
||||
return std::make_unique<Token>(TokenType::GE, ">=", tokenLine, tokenColumn);
|
||||
}
|
||||
return std::make_unique<Token>(TokenType::GT, ">", tokenLine, tokenColumn);
|
||||
}
|
||||
case '&': {
|
||||
if (currentChar() == '&') {
|
||||
advance();
|
||||
return std::make_unique<Token>(TokenType::AND, "&&", tokenLine, tokenColumn);
|
||||
}
|
||||
return std::make_unique<Token>(TokenType::BIT_AND, "&", tokenLine, tokenColumn);
|
||||
}
|
||||
case '|': {
|
||||
if (currentChar() == '|') {
|
||||
advance();
|
||||
return std::make_unique<Token>(TokenType::OR, "||", tokenLine, tokenColumn);
|
||||
}
|
||||
return std::make_unique<Token>(TokenType::BIT_OR, "|", tokenLine, tokenColumn);
|
||||
}
|
||||
case '^': return std::make_unique<Token>(TokenType::BIT_XOR, "^", tokenLine, tokenColumn);
|
||||
case '~': return std::make_unique<Token>(TokenType::BIT_NOT, "~", tokenLine, tokenColumn);
|
||||
case '*': {
|
||||
if (currentChar() == '=') {
|
||||
advance();
|
||||
return std::make_unique<Token>(TokenType::MUL_ASSIGN, "*=", tokenLine, tokenColumn);
|
||||
}
|
||||
return std::make_unique<Token>(TokenType::MUL, "*", tokenLine, tokenColumn);
|
||||
}
|
||||
case '(': return std::make_unique<Token>(TokenType::LPAREN, "(", tokenLine, tokenColumn);
|
||||
case ')': return std::make_unique<Token>(TokenType::RPAREN, ")", tokenLine, tokenColumn);
|
||||
case '{': return std::make_unique<Token>(TokenType::LBRACE, "{", tokenLine, tokenColumn);
|
||||
case '}': return std::make_unique<Token>(TokenType::RBRACE, "}", tokenLine, tokenColumn);
|
||||
case '[': return std::make_unique<Token>(TokenType::LBRACKET, "[", tokenLine, tokenColumn);
|
||||
case ']': return std::make_unique<Token>(TokenType::RBRACKET, "]", tokenLine, tokenColumn);
|
||||
case ',': return std::make_unique<Token>(TokenType::COMMA, ",", tokenLine, tokenColumn);
|
||||
case ';': return std::make_unique<Token>(TokenType::SEMICOLON, ";", tokenLine, tokenColumn);
|
||||
case ':': {
|
||||
if (currentChar() == ':') {
|
||||
advance();
|
||||
return std::make_unique<Token>(TokenType::DOUBLE_COLON, "::", tokenLine, tokenColumn);
|
||||
}
|
||||
if (currentChar() == '=') {
|
||||
advance();
|
||||
return std::make_unique<Token>(TokenType::COLON_ASSIGN, ":=", tokenLine, tokenColumn);
|
||||
}
|
||||
return std::make_unique<Token>(TokenType::COLON, ":", tokenLine, tokenColumn);
|
||||
}
|
||||
case '.': return std::make_unique<Token>(TokenType::DOT, ".", tokenLine, tokenColumn);
|
||||
case '$': {
|
||||
advance(); // 跳过 $
|
||||
std::string id = readIdentifier();
|
||||
return std::make_unique<Token>(TokenType::IMPORT_DIRECTIVE, id, tokenLine, tokenColumn);
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_unique<Token>(TokenType::END_OF_FILE, "", tokenLine, tokenColumn);
|
||||
}
|
||||
|
||||
} // namespace oraset3
|
||||
@@ -0,0 +1,797 @@
|
||||
#include "oraset3.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace oraset3 {
|
||||
|
||||
Parser::Parser(std::vector<std::unique_ptr<Token>> tokens)
|
||||
: tokens(std::move(tokens)), pos(0) {}
|
||||
|
||||
Token* Parser::currentToken() {
|
||||
if (pos >= tokens.size()) return nullptr;
|
||||
return tokens[pos].get();
|
||||
}
|
||||
|
||||
Token* Parser::peekToken() {
|
||||
if (pos + 1 >= tokens.size()) return nullptr;
|
||||
return tokens[pos + 1].get();
|
||||
}
|
||||
|
||||
void Parser::advance() {
|
||||
if (pos < tokens.size()) pos++;
|
||||
}
|
||||
|
||||
bool Parser::match(TokenType type) {
|
||||
Token* t = currentToken();
|
||||
return t && t->type == type;
|
||||
}
|
||||
|
||||
bool Parser::consume(TokenType type) {
|
||||
if (match(type)) {
|
||||
advance();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<ProgramNode> Parser::parse() {
|
||||
auto program = std::make_unique<ProgramNode>();
|
||||
|
||||
while (currentToken()) {
|
||||
program->declarations.push_back(parseDeclaration());
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseDeclaration() {
|
||||
if (match(TokenType::VAR) || match(TokenType::LET) || match(TokenType::CONST)) {
|
||||
return parseVarDecl();
|
||||
}
|
||||
if (match(TokenType::FUNC)) {
|
||||
return parseFuncDecl();
|
||||
}
|
||||
if (match(TokenType::STRUCT)) {
|
||||
return parseStructDecl();
|
||||
}
|
||||
if (match(TokenType::INTERFACE)) {
|
||||
return parseInterfaceDecl();
|
||||
}
|
||||
if (match(TokenType::UNION)) {
|
||||
return parseUnionDecl();
|
||||
}
|
||||
if (match(TokenType::ENUM)) {
|
||||
return parseEnumDecl();
|
||||
}
|
||||
// 处理导入指令 $xxx
|
||||
if (match(TokenType::IMPORT_DIRECTIVE)) {
|
||||
// 跳过导入指令,因为编译器已经在 lexer 阶段处理了
|
||||
// 返回一个空的表达式语句作为占位符
|
||||
return std::make_unique<ExprStmtNode>();
|
||||
}
|
||||
// 检查是否是 := 声明(x := 10) - 不消费标识符,让 parseVarDecl 处理
|
||||
if (match(TokenType::IDENTIFIER) && peekToken() && peekToken()->type == TokenType::COLON_ASSIGN) {
|
||||
return parseVarDecl();
|
||||
}
|
||||
// 检查是否是 类型 变量名 = 值 的声明
|
||||
if (match(TokenType::IDENTIFIER) && peekToken() && peekToken()->type == TokenType::IDENTIFIER) {
|
||||
Token* nextNext = nullptr;
|
||||
if (pos + 2 < tokens.size()) {
|
||||
nextNext = tokens[pos + 2].get();
|
||||
}
|
||||
if (nextNext && (nextNext->type == TokenType::ASSIGN || nextNext->type == TokenType::COLON_ASSIGN)) {
|
||||
// 这是一个带类型的变量声明,让 parseVarDecl 处理
|
||||
return parseVarDecl();
|
||||
}
|
||||
}
|
||||
|
||||
// 检查控制流语句
|
||||
if (match(TokenType::IF)) {
|
||||
return parseIfStmt();
|
||||
}
|
||||
if (match(TokenType::WHILE)) {
|
||||
return parseWhileStmt();
|
||||
}
|
||||
if (match(TokenType::FOR)) {
|
||||
return parseForStmt();
|
||||
}
|
||||
if (match(TokenType::RETURN)) {
|
||||
return parseReturnStmt();
|
||||
}
|
||||
if (match(TokenType::BREAK)) {
|
||||
auto stmt = std::make_unique<ExprStmtNode>();
|
||||
advance();
|
||||
consume(TokenType::SEMICOLON);
|
||||
return stmt;
|
||||
}
|
||||
if (match(TokenType::CONTINUE)) {
|
||||
auto stmt = std::make_unique<ExprStmtNode>();
|
||||
advance();
|
||||
consume(TokenType::SEMICOLON);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
// 顶层表达式语句(无需函数包装)
|
||||
std::unique_ptr<ASTNode> expr = parseExpression();
|
||||
consume(TokenType::SEMICOLON);
|
||||
|
||||
// 将表达式包装在 ExprStmtNode 中
|
||||
auto stmt = std::make_unique<ExprStmtNode>();
|
||||
stmt->expr = std::move(expr);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseVarDecl() {
|
||||
auto decl = std::make_unique<VarDeclNode>();
|
||||
bool hasKeyword = match(TokenType::VAR) || match(TokenType::LET) || match(TokenType::CONST);
|
||||
|
||||
if (hasKeyword) {
|
||||
advance(); // 跳过 var/let/const 关键字
|
||||
}
|
||||
|
||||
// 获取第一个标识符
|
||||
if (!consume(TokenType::IDENTIFIER)) {
|
||||
throw std::runtime_error("Expected variable name");
|
||||
}
|
||||
std::string firstToken = tokens[pos - 1]->value;
|
||||
|
||||
// 检查是否是 类型 变量名 = 值 的语法
|
||||
// 如果下一个是标识符,且下下个是赋值操作符
|
||||
bool hasTypeAnnotation = false;
|
||||
if (!hasKeyword && peekToken() && peekToken()->type == TokenType::IDENTIFIER) {
|
||||
Token* nextNext = nullptr;
|
||||
if (pos + 2 < tokens.size()) {
|
||||
nextNext = tokens[pos + 2].get();
|
||||
}
|
||||
if (nextNext && (nextNext->type == TokenType::ASSIGN || nextNext->type == TokenType::COLON_ASSIGN)) {
|
||||
hasTypeAnnotation = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasTypeAnnotation) {
|
||||
// 第一个标识符是类型
|
||||
decl->type = firstToken;
|
||||
// 获取变量名
|
||||
if (!consume(TokenType::IDENTIFIER)) {
|
||||
throw std::runtime_error("Expected variable name");
|
||||
}
|
||||
decl->name = tokens[pos - 1]->value;
|
||||
} else {
|
||||
// 第一个标识符是变量名
|
||||
decl->name = firstToken;
|
||||
// 检查类型注解 (var x int = 10)
|
||||
if (consume(TokenType::IDENTIFIER) && !match(TokenType::ASSIGN) && !match(TokenType::COLON_ASSIGN)) {
|
||||
decl->type = tokens[pos - 1]->value;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理赋值
|
||||
if (consume(TokenType::ASSIGN) || consume(TokenType::COLON_ASSIGN)) {
|
||||
decl->initializer = parseExpression();
|
||||
}
|
||||
|
||||
consume(TokenType::SEMICOLON);
|
||||
return decl;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseFuncDecl() {
|
||||
auto decl = std::make_unique<FuncDeclNode>();
|
||||
advance(); // 跳过 func
|
||||
|
||||
// 函数名
|
||||
if (!consume(TokenType::IDENTIFIER)) {
|
||||
throw std::runtime_error("Expected function name");
|
||||
}
|
||||
decl->name = tokens[pos - 1]->value;
|
||||
|
||||
// 参数列表
|
||||
consume(TokenType::LPAREN);
|
||||
while (match(TokenType::IDENTIFIER)) {
|
||||
std::string paramName = tokens[pos]->value;
|
||||
advance();
|
||||
std::string paramType = "auto";
|
||||
if (match(TokenType::COLON)) {
|
||||
advance();
|
||||
if (consume(TokenType::IDENTIFIER)) {
|
||||
paramType = tokens[pos - 1]->value;
|
||||
}
|
||||
}
|
||||
decl->params.push_back({paramName, paramType});
|
||||
|
||||
if (!match(TokenType::RPAREN)) {
|
||||
consume(TokenType::COMMA);
|
||||
}
|
||||
}
|
||||
consume(TokenType::RPAREN);
|
||||
|
||||
// 返回类型(可选)
|
||||
if (match(TokenType::COLON)) {
|
||||
advance();
|
||||
if (consume(TokenType::IDENTIFIER)) {
|
||||
decl->returnType = tokens[pos - 1]->value;
|
||||
}
|
||||
}
|
||||
|
||||
// 函数体
|
||||
consume(TokenType::LBRACE);
|
||||
while (!match(TokenType::RBRACE) && currentToken()) {
|
||||
decl->body.push_back(parseStatement());
|
||||
}
|
||||
consume(TokenType::RBRACE);
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseStructDecl() {
|
||||
auto decl = std::make_unique<StructDeclNode>();
|
||||
advance(); // 跳过 struct
|
||||
|
||||
if (!consume(TokenType::IDENTIFIER)) {
|
||||
throw std::runtime_error("Expected struct name");
|
||||
}
|
||||
decl->name = tokens[pos - 1]->value;
|
||||
|
||||
consume(TokenType::LBRACE);
|
||||
while (!match(TokenType::RBRACE) && currentToken()) {
|
||||
if (!consume(TokenType::IDENTIFIER)) {
|
||||
throw std::runtime_error("Expected field name");
|
||||
}
|
||||
std::string fieldName = tokens[pos - 1]->value;
|
||||
|
||||
std::string fieldType = "auto";
|
||||
if (consume(TokenType::COLON)) {
|
||||
if (consume(TokenType::IDENTIFIER)) {
|
||||
fieldType = tokens[pos - 1]->value;
|
||||
}
|
||||
}
|
||||
|
||||
decl->fields.push_back({fieldName, fieldType});
|
||||
consume(TokenType::SEMICOLON);
|
||||
}
|
||||
consume(TokenType::RBRACE);
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseInterfaceDecl() {
|
||||
auto decl = std::make_unique<InterfaceDeclNode>();
|
||||
advance(); // 跳过 interface
|
||||
|
||||
if (!consume(TokenType::IDENTIFIER)) {
|
||||
throw std::runtime_error("Expected interface name");
|
||||
}
|
||||
decl->name = tokens[pos - 1]->value;
|
||||
|
||||
consume(TokenType::LBRACE);
|
||||
while (!match(TokenType::RBRACE) && currentToken()) {
|
||||
if (!consume(TokenType::IDENTIFIER)) {
|
||||
throw std::runtime_error("Expected method name");
|
||||
}
|
||||
std::string methodName = tokens[pos - 1]->value;
|
||||
|
||||
consume(TokenType::LPAREN);
|
||||
consume(TokenType::RPAREN);
|
||||
|
||||
std::string returnType = "void";
|
||||
if (match(TokenType::COLON)) {
|
||||
advance();
|
||||
if (consume(TokenType::IDENTIFIER)) {
|
||||
returnType = tokens[pos - 1]->value;
|
||||
}
|
||||
}
|
||||
|
||||
decl->methods.push_back({methodName, returnType});
|
||||
consume(TokenType::SEMICOLON);
|
||||
}
|
||||
consume(TokenType::RBRACE);
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseUnionDecl() {
|
||||
auto decl = std::make_unique<UnionDeclNode>();
|
||||
advance(); // 跳过 union
|
||||
|
||||
if (!consume(TokenType::IDENTIFIER)) {
|
||||
throw std::runtime_error("Expected union name");
|
||||
}
|
||||
decl->name = tokens[pos - 1]->value;
|
||||
|
||||
consume(TokenType::LBRACE);
|
||||
while (!match(TokenType::RBRACE) && currentToken()) {
|
||||
if (!consume(TokenType::IDENTIFIER)) {
|
||||
throw std::runtime_error("Expected field name");
|
||||
}
|
||||
std::string fieldName = tokens[pos - 1]->value;
|
||||
|
||||
std::string fieldType = "auto";
|
||||
if (consume(TokenType::COLON)) {
|
||||
if (consume(TokenType::IDENTIFIER)) {
|
||||
fieldType = tokens[pos - 1]->value;
|
||||
}
|
||||
}
|
||||
|
||||
decl->fields.push_back({fieldName, fieldType});
|
||||
consume(TokenType::SEMICOLON);
|
||||
}
|
||||
consume(TokenType::RBRACE);
|
||||
consume(TokenType::SEMICOLON); // 添加分号消费
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseEnumDecl() {
|
||||
auto decl = std::make_unique<EnumDeclNode>();
|
||||
advance(); // 跳过 enum
|
||||
|
||||
if (!consume(TokenType::IDENTIFIER)) {
|
||||
throw std::runtime_error("Expected enum name");
|
||||
}
|
||||
decl->name = tokens[pos - 1]->value;
|
||||
|
||||
consume(TokenType::LBRACE);
|
||||
while (!match(TokenType::RBRACE) && currentToken()) {
|
||||
if (!consume(TokenType::IDENTIFIER)) {
|
||||
throw std::runtime_error("Expected enum value name");
|
||||
}
|
||||
std::string valueName = tokens[pos - 1]->value;
|
||||
std::string value = "";
|
||||
|
||||
if (consume(TokenType::ASSIGN)) {
|
||||
if (consume(TokenType::INTEGER)) {
|
||||
value = tokens[pos - 1]->value;
|
||||
}
|
||||
}
|
||||
|
||||
decl->values.push_back({valueName, value});
|
||||
|
||||
if (!match(TokenType::RBRACE)) {
|
||||
consume(TokenType::COMMA);
|
||||
}
|
||||
}
|
||||
consume(TokenType::RBRACE);
|
||||
consume(TokenType::SEMICOLON); // 添加分号消费
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseStatement() {
|
||||
if (match(TokenType::VAR) || match(TokenType::LET) || match(TokenType::CONST)) {
|
||||
return parseVarDecl();
|
||||
}
|
||||
if (match(TokenType::IF)) {
|
||||
return parseIfStmt();
|
||||
}
|
||||
if (match(TokenType::WHILE)) {
|
||||
return parseWhileStmt();
|
||||
}
|
||||
if (match(TokenType::FOR)) {
|
||||
return parseForStmt();
|
||||
}
|
||||
if (match(TokenType::RETURN)) {
|
||||
return parseReturnStmt();
|
||||
}
|
||||
if (match(TokenType::BREAK)) {
|
||||
auto stmt = std::make_unique<ExprStmtNode>();
|
||||
advance();
|
||||
consume(TokenType::SEMICOLON);
|
||||
return stmt;
|
||||
}
|
||||
if (match(TokenType::CONTINUE)) {
|
||||
auto stmt = std::make_unique<ExprStmtNode>();
|
||||
advance();
|
||||
consume(TokenType::SEMICOLON);
|
||||
return stmt;
|
||||
}
|
||||
if (match(TokenType::LBRACE)) {
|
||||
return parseBlock();
|
||||
}
|
||||
|
||||
// 检查是否是 := 声明(x := 10)
|
||||
if (match(TokenType::IDENTIFIER) && peekToken() && peekToken()->type == TokenType::COLON_ASSIGN) {
|
||||
return parseVarDecl();
|
||||
}
|
||||
|
||||
// 可能是表达式语句
|
||||
std::unique_ptr<ASTNode> expr = parseExpression();
|
||||
consume(TokenType::SEMICOLON);
|
||||
|
||||
// 将表达式包装在 ExprStmtNode 中
|
||||
auto stmt = std::make_unique<ExprStmtNode>();
|
||||
stmt->expr = std::move(expr);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseBlock() {
|
||||
auto block = std::make_unique<ExprStmtNode>();
|
||||
advance(); // 跳过 {
|
||||
|
||||
// 简单处理:只处理第一个语句
|
||||
if (!match(TokenType::RBRACE) && currentToken()) {
|
||||
block->expr = parseStatement();
|
||||
}
|
||||
|
||||
// 跳过其余语句直到找到 }
|
||||
while (!match(TokenType::RBRACE) && currentToken()) {
|
||||
advance();
|
||||
}
|
||||
|
||||
consume(TokenType::RBRACE);
|
||||
return block;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseIfStmt() {
|
||||
auto stmt = std::make_unique<IfStmtNode>();
|
||||
advance(); // 跳过 if
|
||||
|
||||
consume(TokenType::LPAREN);
|
||||
stmt->condition = parseExpression();
|
||||
consume(TokenType::RPAREN);
|
||||
|
||||
// then branch
|
||||
if (match(TokenType::LBRACE)) {
|
||||
stmt->thenBranch.push_back(parseBlock());
|
||||
} else {
|
||||
stmt->thenBranch.push_back(parseStatement());
|
||||
}
|
||||
|
||||
// else branch
|
||||
if (match(TokenType::ELSE)) {
|
||||
advance();
|
||||
if (match(TokenType::IF)) {
|
||||
stmt->elseBranch.push_back(parseIfStmt());
|
||||
} else if (match(TokenType::LBRACE)) {
|
||||
stmt->elseBranch.push_back(parseBlock());
|
||||
} else {
|
||||
stmt->elseBranch.push_back(parseStatement());
|
||||
}
|
||||
}
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseWhileStmt() {
|
||||
auto stmt = std::make_unique<WhileStmtNode>();
|
||||
advance(); // 跳过 while
|
||||
|
||||
consume(TokenType::LPAREN);
|
||||
stmt->condition = parseExpression();
|
||||
consume(TokenType::RPAREN);
|
||||
|
||||
if (match(TokenType::LBRACE)) {
|
||||
stmt->body.push_back(parseBlock());
|
||||
} else {
|
||||
stmt->body.push_back(parseStatement());
|
||||
}
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseForStmt() {
|
||||
auto stmt = std::make_unique<ForStmtNode>();
|
||||
advance(); // 跳过 for
|
||||
|
||||
consume(TokenType::LPAREN);
|
||||
|
||||
// 初始化
|
||||
if (!match(TokenType::SEMICOLON)) {
|
||||
stmt->init = parseExpression();
|
||||
}
|
||||
consume(TokenType::SEMICOLON);
|
||||
|
||||
// 条件
|
||||
if (!match(TokenType::SEMICOLON)) {
|
||||
stmt->condition = parseExpression();
|
||||
}
|
||||
consume(TokenType::SEMICOLON);
|
||||
|
||||
// 更新
|
||||
if (!match(TokenType::RPAREN)) {
|
||||
stmt->update = parseExpression();
|
||||
}
|
||||
consume(TokenType::RPAREN);
|
||||
|
||||
if (match(TokenType::LBRACE)) {
|
||||
stmt->body.push_back(parseBlock());
|
||||
} else {
|
||||
stmt->body.push_back(parseStatement());
|
||||
}
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseReturnStmt() {
|
||||
auto stmt = std::make_unique<ReturnStmtNode>();
|
||||
advance(); // 跳过 return
|
||||
|
||||
if (!match(TokenType::SEMICOLON)) {
|
||||
stmt->expr = parseExpression();
|
||||
}
|
||||
|
||||
consume(TokenType::SEMICOLON);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseExpression() {
|
||||
return parseAssignment();
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseAssignment() {
|
||||
std::unique_ptr<ASTNode> left = parseLogicalOr();
|
||||
|
||||
if (match(TokenType::ASSIGN) || match(TokenType::COLON_ASSIGN)) {
|
||||
auto assign = std::make_unique<AssignExprNode>();
|
||||
assign->left = std::move(left);
|
||||
assign->op = match(TokenType::ASSIGN) ? "=" : ":=";
|
||||
advance();
|
||||
assign->right = parseAssignment();
|
||||
return assign;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseLogicalOr() {
|
||||
std::unique_ptr<ASTNode> left = parseLogicalAnd();
|
||||
|
||||
while (match(TokenType::OR)) {
|
||||
auto binary = std::make_unique<BinaryExprNode>();
|
||||
binary->left = std::move(left);
|
||||
binary->op = "||";
|
||||
advance();
|
||||
binary->right = parseLogicalAnd();
|
||||
left = std::move(binary);
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseLogicalAnd() {
|
||||
std::unique_ptr<ASTNode> left = parseEquality();
|
||||
|
||||
while (match(TokenType::AND)) {
|
||||
auto binary = std::make_unique<BinaryExprNode>();
|
||||
binary->left = std::move(left);
|
||||
binary->op = "&&";
|
||||
advance();
|
||||
binary->right = parseEquality();
|
||||
left = std::move(binary);
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseEquality() {
|
||||
std::unique_ptr<ASTNode> left = parseComparison();
|
||||
|
||||
while (match(TokenType::EQ) || match(TokenType::NEQ)) {
|
||||
auto binary = std::make_unique<BinaryExprNode>();
|
||||
binary->left = std::move(left);
|
||||
binary->op = match(TokenType::EQ) ? "==" : "!=";
|
||||
advance();
|
||||
binary->right = parseComparison();
|
||||
left = std::move(binary);
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseComparison() {
|
||||
std::unique_ptr<ASTNode> left = parseShift();
|
||||
|
||||
while (match(TokenType::LT) || match(TokenType::GT) || match(TokenType::LE) || match(TokenType::GE)) {
|
||||
auto binary = std::make_unique<BinaryExprNode>();
|
||||
binary->left = std::move(left);
|
||||
if (match(TokenType::LT)) binary->op = "<";
|
||||
else if (match(TokenType::GT)) binary->op = ">";
|
||||
else if (match(TokenType::LE)) binary->op = "<=";
|
||||
else binary->op = ">=";
|
||||
advance();
|
||||
binary->right = parseShift();
|
||||
left = std::move(binary);
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseShift() {
|
||||
std::unique_ptr<ASTNode> left = parseAdditive();
|
||||
|
||||
while (match(TokenType::SHL) || match(TokenType::SHR) ||
|
||||
match(TokenType::BIT_AND) || match(TokenType::BIT_OR) || match(TokenType::BIT_XOR)) {
|
||||
auto binary = std::make_unique<BinaryExprNode>();
|
||||
binary->left = std::move(left);
|
||||
if (match(TokenType::SHL)) binary->op = "<<";
|
||||
else if (match(TokenType::SHR)) binary->op = ">>";
|
||||
else if (match(TokenType::BIT_AND)) binary->op = "&";
|
||||
else if (match(TokenType::BIT_OR)) binary->op = "|";
|
||||
else binary->op = "^";
|
||||
advance();
|
||||
binary->right = parseAdditive();
|
||||
left = std::move(binary);
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseAdditive() {
|
||||
std::unique_ptr<ASTNode> left = parseMultiplicative();
|
||||
|
||||
while (match(TokenType::PLUS) || match(TokenType::MINUS)) {
|
||||
auto binary = std::make_unique<BinaryExprNode>();
|
||||
binary->left = std::move(left);
|
||||
binary->op = match(TokenType::PLUS) ? "+" : "-";
|
||||
advance();
|
||||
binary->right = parseMultiplicative();
|
||||
left = std::move(binary);
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseMultiplicative() {
|
||||
std::unique_ptr<ASTNode> left = parseUnary();
|
||||
|
||||
while (match(TokenType::MUL) || match(TokenType::DIV) || match(TokenType::MOD)) {
|
||||
auto binary = std::make_unique<BinaryExprNode>();
|
||||
binary->left = std::move(left);
|
||||
if (match(TokenType::MUL)) binary->op = "*";
|
||||
else if (match(TokenType::DIV)) binary->op = "/";
|
||||
else binary->op = "%";
|
||||
advance();
|
||||
binary->right = parseUnary();
|
||||
left = std::move(binary);
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parseUnary() {
|
||||
if (match(TokenType::NOT) || match(TokenType::MINUS) ||
|
||||
match(TokenType::MUL) || match(TokenType::BIT_AND) || match(TokenType::BIT_NOT)) {
|
||||
auto unary = std::make_unique<UnaryExprNode>();
|
||||
if (match(TokenType::NOT)) unary->op = "!";
|
||||
else if (match(TokenType::MINUS)) unary->op = "-";
|
||||
else if (match(TokenType::MUL)) unary->op = "*";
|
||||
else if (match(TokenType::BIT_AND)) unary->op = "&";
|
||||
else unary->op = "~";
|
||||
advance();
|
||||
unary->operand = parseUnary();
|
||||
return unary;
|
||||
}
|
||||
|
||||
return parsePostfix();
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parsePostfix() {
|
||||
std::unique_ptr<ASTNode> expr = parsePrimary();
|
||||
|
||||
while (true) {
|
||||
if (match(TokenType::LPAREN)) {
|
||||
// 函数调用
|
||||
auto call = std::make_unique<CallExprNode>();
|
||||
call->callee = std::move(expr);
|
||||
|
||||
consume(TokenType::LPAREN);
|
||||
if (!match(TokenType::RPAREN)) {
|
||||
do {
|
||||
call->args.push_back(parseExpression());
|
||||
} while (consume(TokenType::COMMA));
|
||||
}
|
||||
consume(TokenType::RPAREN);
|
||||
|
||||
expr = std::move(call);
|
||||
} else if (match(TokenType::LBRACE)) {
|
||||
// 结构体实例化,如 Point{x: 10, y: 20}
|
||||
auto structInit = std::make_unique<StructInitNode>();
|
||||
structInit->typeName = static_cast<IdentifierExprNode*>(expr.get())->name;
|
||||
|
||||
advance(); // 跳过 {
|
||||
while (!match(TokenType::RBRACE) && currentToken()) {
|
||||
if (!consume(TokenType::IDENTIFIER)) {
|
||||
throw std::runtime_error("Expected field name in struct initializer");
|
||||
}
|
||||
std::string fieldName = tokens[pos - 1]->value;
|
||||
|
||||
consume(TokenType::COLON);
|
||||
std::unique_ptr<ASTNode> fieldValue = parseExpression();
|
||||
|
||||
structInit->fields.push_back({fieldName, std::move(fieldValue)});
|
||||
|
||||
if (!match(TokenType::RBRACE)) {
|
||||
consume(TokenType::COMMA);
|
||||
}
|
||||
}
|
||||
consume(TokenType::RBRACE);
|
||||
|
||||
expr = std::move(structInit);
|
||||
} else if (match(TokenType::DOT)) {
|
||||
// 成员访问
|
||||
advance();
|
||||
if (!consume(TokenType::IDENTIFIER)) {
|
||||
throw std::runtime_error("Expected member name");
|
||||
}
|
||||
auto member = std::make_unique<MemberExprNode>();
|
||||
member->object = std::move(expr);
|
||||
member->property = tokens[pos - 1]->value;
|
||||
member->op = ".";
|
||||
expr = std::move(member);
|
||||
} else if (match(TokenType::LBRACKET)) {
|
||||
// 数组索引
|
||||
advance();
|
||||
auto index = std::make_unique<IndexExprNode>();
|
||||
index->base = std::move(expr);
|
||||
index->index = parseExpression();
|
||||
consume(TokenType::RBRACKET);
|
||||
expr = std::move(index);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> Parser::parsePrimary() {
|
||||
// 类型转换: (type)expr
|
||||
if (match(TokenType::LPAREN) && peekToken() && peekToken()->type == TokenType::IDENTIFIER) {
|
||||
advance(); // 跳过 LPAREN
|
||||
std::string targetType = tokens[pos]->value;
|
||||
advance(); // 跳过类型名
|
||||
if (consume(TokenType::RPAREN)) {
|
||||
auto cast = std::make_unique<CastExprNode>();
|
||||
cast->targetType = targetType;
|
||||
cast->expr = parseUnary(); // 使用 parseUnary 允许括号内的表达式
|
||||
return cast;
|
||||
}
|
||||
}
|
||||
|
||||
if (match(TokenType::INTEGER) || match(TokenType::FLOAT)) {
|
||||
auto lit = std::make_unique<LiteralExprNode>();
|
||||
lit->value = tokens[pos]->value;
|
||||
lit->type = match(TokenType::FLOAT) ? "float" : "int";
|
||||
advance();
|
||||
return lit;
|
||||
}
|
||||
|
||||
if (match(TokenType::STRING)) {
|
||||
auto lit = std::make_unique<LiteralExprNode>();
|
||||
lit->value = tokens[pos]->value;
|
||||
lit->type = "string";
|
||||
advance();
|
||||
return lit;
|
||||
}
|
||||
|
||||
if (match(TokenType::TRUE)) {
|
||||
auto lit = std::make_unique<LiteralExprNode>();
|
||||
lit->value = "true";
|
||||
lit->type = "bool";
|
||||
advance();
|
||||
return lit;
|
||||
}
|
||||
|
||||
if (match(TokenType::FALSE)) {
|
||||
auto lit = std::make_unique<LiteralExprNode>();
|
||||
lit->value = "false";
|
||||
lit->type = "bool";
|
||||
advance();
|
||||
return lit;
|
||||
}
|
||||
|
||||
if (match(TokenType::IDENTIFIER)) {
|
||||
auto ident = std::make_unique<IdentifierExprNode>();
|
||||
ident->name = tokens[pos]->value;
|
||||
advance();
|
||||
return ident;
|
||||
}
|
||||
|
||||
if (match(TokenType::LPAREN)) {
|
||||
advance();
|
||||
std::unique_ptr<ASTNode> expr = parseExpression();
|
||||
consume(TokenType::RPAREN);
|
||||
return expr;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unexpected token");
|
||||
}
|
||||
|
||||
} // namespace oraset3
|
||||
@@ -0,0 +1,313 @@
|
||||
#include "oraset3.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace oraset3 {
|
||||
|
||||
void SemanticAnalyzer::analyze(ProgramNode& program) {
|
||||
// 添加基本类型
|
||||
symbolTable["int"] = "type";
|
||||
symbolTable["float"] = "type";
|
||||
symbolTable["string"] = "type";
|
||||
symbolTable["bool"] = "type";
|
||||
symbolTable["void"] = "type";
|
||||
|
||||
// 添加预定义标识符
|
||||
symbolTable["std"] = "namespace";
|
||||
symbolTable["cout"] = "ostream";
|
||||
symbolTable["endl"] = "stream";
|
||||
|
||||
// 添加内置函数(由编译器提供)
|
||||
symbolTable["print"] = "builtin_func";
|
||||
symbolTable["println"] = "builtin_func";
|
||||
|
||||
// 系统操作函数
|
||||
symbolTable["sys"] = "builtin_func";
|
||||
|
||||
// 文件操作函数
|
||||
symbolTable["file"] = "namespace";
|
||||
symbolTable["file.read"] = "builtin_func";
|
||||
symbolTable["file.write"] = "builtin_func";
|
||||
symbolTable["file.exists"] = "builtin_func";
|
||||
|
||||
// 屏幕操作函数
|
||||
symbolTable["screen"] = "namespace";
|
||||
symbolTable["screen.clear"] = "builtin_func";
|
||||
symbolTable["screen.size"] = "builtin_func";
|
||||
|
||||
// 绘图函数
|
||||
symbolTable["draw"] = "namespace";
|
||||
symbolTable["draw.text"] = "builtin_func";
|
||||
symbolTable["draw.rect"] = "builtin_func";
|
||||
symbolTable["draw.line"] = "builtin_func";
|
||||
|
||||
// 如果导入了 sysui,添加UI相关函数
|
||||
if (this->sysuiImported) {
|
||||
symbolTable["ui"] = "namespace";
|
||||
symbolTable["ui.msgbox"] = "builtin_func";
|
||||
symbolTable["ui.inputbox"] = "builtin_func";
|
||||
symbolTable["ui.alert"] = "builtin_func";
|
||||
symbolTable["ui.confirm"] = "builtin_func";
|
||||
symbolTable["ui.prompt"] = "builtin_func";
|
||||
symbolTable["ui.openfile"] = "builtin_func";
|
||||
symbolTable["ui.savefile"] = "builtin_func";
|
||||
symbolTable["ui.dir"] = "builtin_func";
|
||||
symbolTable["ui.color"] = "builtin_func";
|
||||
}
|
||||
|
||||
visit(program);
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(ProgramNode& node) {
|
||||
// 第一遍:收集所有声明
|
||||
for (auto& decl : node.declarations) {
|
||||
// 先添加函数声明到符号表
|
||||
if (decl->getType() == NodeType::FUNC_DECL) {
|
||||
FuncDeclNode& funcDecl = static_cast<FuncDeclNode&>(*decl);
|
||||
if (symbolTable.find(funcDecl.name) != symbolTable.end()) {
|
||||
std::stringstream ss;
|
||||
ss << "Function '" << funcDecl.name << "' already declared";
|
||||
errors.push_back(ss.str());
|
||||
}
|
||||
symbolTable[funcDecl.name] = "func";
|
||||
}
|
||||
// 添加变量和其他声明
|
||||
else if (decl->getType() == NodeType::VAR_DECL) {
|
||||
VarDeclNode& varDecl = static_cast<VarDeclNode&>(*decl);
|
||||
if (symbolTable.find(varDecl.name) != symbolTable.end()) {
|
||||
std::stringstream ss;
|
||||
ss << "Variable '" << varDecl.name << "' already declared";
|
||||
errors.push_back(ss.str());
|
||||
}
|
||||
symbolTable[varDecl.name] = varDecl.type;
|
||||
}
|
||||
// 添加结构体声明
|
||||
else if (decl->getType() == NodeType::STRUCT_DECL) {
|
||||
StructDeclNode& structDecl = static_cast<StructDeclNode&>(*decl);
|
||||
if (symbolTable.find(structDecl.name) != symbolTable.end()) {
|
||||
std::stringstream ss;
|
||||
ss << "Struct '" << structDecl.name << "' already declared";
|
||||
errors.push_back(ss.str());
|
||||
}
|
||||
symbolTable[structDecl.name] = "struct";
|
||||
}
|
||||
// 添加接口声明
|
||||
else if (decl->getType() == NodeType::INTERFACE_DECL) {
|
||||
InterfaceDeclNode& interfaceDecl = static_cast<InterfaceDeclNode&>(*decl);
|
||||
if (symbolTable.find(interfaceDecl.name) != symbolTable.end()) {
|
||||
std::stringstream ss;
|
||||
ss << "Interface '" << interfaceDecl.name << "' already declared";
|
||||
errors.push_back(ss.str());
|
||||
}
|
||||
symbolTable[interfaceDecl.name] = "interface";
|
||||
}
|
||||
// 添加联合体声明
|
||||
else if (decl->getType() == NodeType::UNION_DECL) {
|
||||
UnionDeclNode& unionDecl = static_cast<UnionDeclNode&>(*decl);
|
||||
if (symbolTable.find(unionDecl.name) != symbolTable.end()) {
|
||||
std::stringstream ss;
|
||||
ss << "Union '" << unionDecl.name << "' already declared";
|
||||
errors.push_back(ss.str());
|
||||
}
|
||||
symbolTable[unionDecl.name] = "union";
|
||||
}
|
||||
// 添加枚举声明
|
||||
else if (decl->getType() == NodeType::ENUM_DECL) {
|
||||
EnumDeclNode& enumDecl = static_cast<EnumDeclNode&>(*decl);
|
||||
if (symbolTable.find(enumDecl.name) != symbolTable.end()) {
|
||||
std::stringstream ss;
|
||||
ss << "Enum '" << enumDecl.name << "' already declared";
|
||||
errors.push_back(ss.str());
|
||||
}
|
||||
symbolTable[enumDecl.name] = "enum";
|
||||
// 添加枚举常量到符号表
|
||||
for (auto& value : enumDecl.values) {
|
||||
if (symbolTable.find(value.first) != symbolTable.end()) {
|
||||
std::stringstream ss;
|
||||
ss << "Enum value '" << value.first << "' already declared";
|
||||
errors.push_back(ss.str());
|
||||
}
|
||||
symbolTable[value.first] = enumDecl.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 第二遍:处理函数体
|
||||
for (auto& decl : node.declarations) {
|
||||
if (decl->getType() == NodeType::FUNC_DECL) {
|
||||
FuncDeclNode& funcDecl = static_cast<FuncDeclNode&>(*decl);
|
||||
|
||||
// 保存当前符号表状态
|
||||
std::map<std::string, std::string> savedSymbolTable = symbolTable;
|
||||
|
||||
// 添加参数到符号表(只检查函数内部重复)
|
||||
for (auto& param : funcDecl.params) {
|
||||
symbolTable[param.first] = param.second;
|
||||
}
|
||||
|
||||
// 处理函数体:先收集变量声明,再处理
|
||||
for (auto& stmt : funcDecl.body) {
|
||||
if (stmt->getType() == NodeType::VAR_DECL) {
|
||||
VarDeclNode& varDecl = static_cast<VarDeclNode&>(*stmt);
|
||||
auto it = symbolTable.find(varDecl.name);
|
||||
// 检查变量名是否已声明,但忽略类型名
|
||||
if (it != symbolTable.end() && it->second != "type") {
|
||||
std::stringstream ss;
|
||||
ss << "Variable '" << varDecl.name << "' already declared in function '" << funcDecl.name << "'";
|
||||
errors.push_back(ss.str());
|
||||
}
|
||||
symbolTable[varDecl.name] = varDecl.type;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理函数体
|
||||
for (auto& stmt : funcDecl.body) {
|
||||
stmt->accept(*this);
|
||||
}
|
||||
|
||||
// 恢复符号表状态
|
||||
symbolTable = savedSymbolTable;
|
||||
}
|
||||
else if (decl->getType() == NodeType::VAR_DECL) {
|
||||
VarDeclNode& varDecl = static_cast<VarDeclNode&>(*decl);
|
||||
if (varDecl.initializer) {
|
||||
varDecl.initializer->accept(*this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
decl->accept(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(VarDeclNode& node) {
|
||||
// 处理初始化表达式(如果存在)
|
||||
if (node.initializer) {
|
||||
node.initializer->accept(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(FuncDeclNode& node) {
|
||||
// 函数声明的处理已经在 ProgramNode 的 visit 方法中完成
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(StructDeclNode& node) {
|
||||
// 结构体声明的处理已经在 ProgramNode 的 visit 方法中完成
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(InterfaceDeclNode& node) {
|
||||
// 接口声明的处理已经在 ProgramNode 的 visit 方法中完成
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(UnionDeclNode& node) {
|
||||
// 联合体声明的处理已经在 ProgramNode 的 visit 方法中完成
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(EnumDeclNode& node) {
|
||||
// 枚举声明的处理已经在 ProgramNode 的 visit 方法中完成
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(CastExprNode& node) {
|
||||
// 类型转换表达式的处理
|
||||
if (node.expr) {
|
||||
node.expr->accept(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(IfStmtNode& node) {
|
||||
node.condition->accept(*this);
|
||||
|
||||
for (auto& stmt : node.thenBranch) {
|
||||
stmt->accept(*this);
|
||||
}
|
||||
|
||||
for (auto& stmt : node.elseBranch) {
|
||||
stmt->accept(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(ForStmtNode& node) {
|
||||
if (node.init) node.init->accept(*this);
|
||||
if (node.condition) node.condition->accept(*this);
|
||||
if (node.update) node.update->accept(*this);
|
||||
|
||||
for (auto& stmt : node.body) {
|
||||
stmt->accept(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(WhileStmtNode& node) {
|
||||
node.condition->accept(*this);
|
||||
|
||||
for (auto& stmt : node.body) {
|
||||
stmt->accept(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(ReturnStmtNode& node) {
|
||||
if (node.expr) {
|
||||
node.expr->accept(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(ExprStmtNode& node) {
|
||||
node.expr->accept(*this);
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(AssignExprNode& node) {
|
||||
node.left->accept(*this);
|
||||
node.right->accept(*this);
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(BinaryExprNode& node) {
|
||||
node.left->accept(*this);
|
||||
node.right->accept(*this);
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(UnaryExprNode& node) {
|
||||
node.operand->accept(*this);
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(CallExprNode& node) {
|
||||
node.callee->accept(*this);
|
||||
|
||||
for (auto& arg : node.args) {
|
||||
arg->accept(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(IndexExprNode& node) {
|
||||
node.base->accept(*this);
|
||||
node.index->accept(*this);
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(MemberExprNode& node) {
|
||||
node.object->accept(*this);
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(StructInitNode& node) {
|
||||
// 检查结构体是否已声明
|
||||
if (symbolTable.find(node.typeName) == symbolTable.end()) {
|
||||
std::stringstream ss;
|
||||
ss << "Undefined struct type '" << node.typeName << "'";
|
||||
errors.push_back(ss.str());
|
||||
}
|
||||
|
||||
// 递归处理字段初始化表达式
|
||||
for (auto& field : node.fields) {
|
||||
field.second->accept(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(LiteralExprNode& node) {
|
||||
// 字面量无需检查
|
||||
}
|
||||
|
||||
void SemanticAnalyzer::visit(IdentifierExprNode& node) {
|
||||
if (symbolTable.find(node.name) == symbolTable.end()) {
|
||||
std::stringstream ss;
|
||||
ss << "Undefined identifier '" << node.name << "'";
|
||||
errors.push_back(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace oraset3
|
||||
@@ -0,0 +1,159 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 3 {
|
||||
fmt.Println("Usage: oraset3-go <input_file> <output_file>")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
inputFile := os.Args[1]
|
||||
outputFile := os.Args[2]
|
||||
|
||||
err := compile(inputFile, outputFile)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("Compilation successful! Output: %s\n", outputFile)
|
||||
}
|
||||
|
||||
func compile(inputFile, outputFile string) error {
|
||||
source, err := readFile(inputFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 调用C++编译器核心
|
||||
cppOutput, err := runCppCompiler(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 写入临时C++文件
|
||||
tmpCppFile := outputFile + ".tmp.cpp"
|
||||
err = writeFile(tmpCppFile, cppOutput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(tmpCppFile)
|
||||
|
||||
// 根据平台调用相应的编译器
|
||||
if runtime.GOOS == "windows" {
|
||||
return compileWindows(tmpCppFile, outputFile)
|
||||
} else {
|
||||
return compileLinux(tmpCppFile, outputFile)
|
||||
}
|
||||
}
|
||||
|
||||
func readFile(path string) (string, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read file: %w", err)
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
func writeFile(path, content string) error {
|
||||
err := os.WriteFile(path, []byte(content), 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write file: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runCppCompiler(source string) (string, error) {
|
||||
// 在实际项目中,这里会调用C++编译核心
|
||||
// 由于Go无法直接调用C++代码,我们使用exec调用编译好的oraset3编译器
|
||||
// 或者可以使用cgo绑定
|
||||
|
||||
// 这里简化处理,直接返回源代码内容(演示用)
|
||||
return source, nil
|
||||
}
|
||||
|
||||
func compileWindows(cppFile, outputFile string) error {
|
||||
// 使用MinGW或MSVC编译
|
||||
gccPath, err := exec.LookPath("g++")
|
||||
if err != nil {
|
||||
return fmt.Errorf("g++ not found: %w", err)
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-o", outputFile,
|
||||
cppFile,
|
||||
"-std=c++17",
|
||||
"-Wall",
|
||||
}
|
||||
|
||||
cmd := exec.Command(gccPath, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("compilation failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func compileLinux(cppFile, outputFile string) error {
|
||||
// 使用Clang编译
|
||||
clangPath, err := exec.LookPath("clang++")
|
||||
if err != nil {
|
||||
return fmt.Errorf("clang++ not found: %w", err)
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-o", outputFile,
|
||||
cppFile,
|
||||
"-std=c++17",
|
||||
"-Wall",
|
||||
"-O2",
|
||||
}
|
||||
|
||||
cmd := exec.Command(clangPath, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("compilation failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isWindows() bool {
|
||||
return runtime.GOOS == "windows"
|
||||
}
|
||||
|
||||
func isLinux() bool {
|
||||
return runtime.GOOS == "linux"
|
||||
}
|
||||
|
||||
// getCompilerPath returns the path to the appropriate compiler
|
||||
func getCompilerPath() (string, error) {
|
||||
if isWindows() {
|
||||
return exec.LookPath("g++")
|
||||
}
|
||||
return exec.LookPath("clang++")
|
||||
}
|
||||
|
||||
// ensureDirectory ensures the output directory exists
|
||||
func ensureDirectory(path string) error {
|
||||
dir := filepath.Dir(path)
|
||||
if dir == "." {
|
||||
return nil
|
||||
}
|
||||
return os.MkdirAll(dir, 0755)
|
||||
}
|
||||
Reference in New Issue
Block a user