adeded new features

This commit is contained in:
SkrinVex
2026-01-22 20:34:46 +05:00
parent 5223311837
commit 895c678ca6
6 changed files with 544 additions and 55 deletions
+197 -6
View File
@@ -9,6 +9,15 @@
#include <fstream>
#include <sstream>
#include <algorithm>
#include <thread>
#include <chrono>
#ifdef _WIN32
#include <conio.h>
#else
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#endif
struct Node;
@@ -74,6 +83,9 @@ struct ReturnValue {
Value value;
};
struct BreakException {};
struct ContinueException {};
static std::string formatNumber(double val) {
std::string s = std::to_string(val);
s.erase(s.find_last_not_of('0') + 1, std::string::npos);
@@ -116,14 +128,58 @@ struct FuncCallNode : Node {
Value eval(Context& ctx) override {
// Встроенные функции
if (name == "print" && args.size() == 1) {
std::cout << args[0]->eval(ctx).value << std::endl;
if (name == "print") {
if (args.empty()) {
std::cout << std::endl;
} else {
for (size_t i = 0; i < args.size(); i++) {
if (i > 0) std::cout << " ";
std::cout << args[i]->eval(ctx).value;
}
std::cout << std::endl;
}
return {"void", ""};
}
if (name == "input" && args.size() == 0) {
std::string input; std::getline(std::cin, input);
if (name == "input") {
if (args.size() == 1) {
// Вывести приглашение
std::cout << args[0]->eval(ctx).value;
}
std::string input;
std::getline(std::cin, input);
return {"string", input};
}
if (name == "getch" && args.size() == 0) {
#ifdef _WIN32
return {"string", std::string(1, _getch())};
#else
struct termios oldt, newt;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
char ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return {"string", std::string(1, ch)};
#endif
}
if (name == "kbhit" && args.size() == 0) {
#ifdef _WIN32
return {"bool", _kbhit() ? "true" : "false"};
#else
int ch = getchar();
if (ch != EOF) {
ungetc(ch, stdin);
return {"bool", "true"};
}
return {"bool", "false"};
#endif
}
if (name == "wait" && args.size() == 1) {
int milliseconds = std::stoi(args[0]->eval(ctx).value);
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
return {"void", ""};
}
if (name == "round" && args.size() == 1) {
double val = std::stod(args[0]->eval(ctx).value);
return {"int", std::to_string((int)std::round(val))};
@@ -258,6 +314,68 @@ struct FuncCallNode : Node {
return {"int", "0"};
}
}
if (name == "httpget" && args.size() == 1) {
Value urlVal = args[0]->eval(ctx);
std::string cmd = "curl -s \"" + urlVal.value + "\"";
FILE* pipe = popen(cmd.c_str(), "r");
if (!pipe) return {"string", ""};
std::string result;
char buffer[128];
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
result += buffer;
}
pclose(pipe);
return {"string", result};
}
if (name == "httppost" && args.size() >= 2) {
Value urlVal = args[0]->eval(ctx);
Value dataVal = args[1]->eval(ctx);
std::string contentType = args.size() > 2 ? args[2]->eval(ctx).value : "application/json";
std::string cmd = "curl -s -X POST -H \"Content-Type: " + contentType + "\" -d \"" + dataVal.value + "\" \"" + urlVal.value + "\"";
FILE* pipe = popen(cmd.c_str(), "r");
if (!pipe) return {"string", ""};
std::string result;
char buffer[128];
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
result += buffer;
}
pclose(pipe);
return {"string", result};
}
if (name == "httpput" && args.size() >= 2) {
Value urlVal = args[0]->eval(ctx);
Value dataVal = args[1]->eval(ctx);
std::string contentType = args.size() > 2 ? args[2]->eval(ctx).value : "application/json";
std::string cmd = "curl -s -X PUT -H \"Content-Type: " + contentType + "\" -d \"" + dataVal.value + "\" \"" + urlVal.value + "\"";
FILE* pipe = popen(cmd.c_str(), "r");
if (!pipe) return {"string", ""};
std::string result;
char buffer[128];
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
result += buffer;
}
pclose(pipe);
return {"string", result};
}
if (name == "httpdelete" && args.size() == 1) {
Value urlVal = args[0]->eval(ctx);
std::string cmd = "curl -s -X DELETE \"" + urlVal.value + "\"";
FILE* pipe = popen(cmd.c_str(), "r");
if (!pipe) return {"string", ""};
std::string result;
char buffer[128];
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
result += buffer;
}
pclose(pipe);
return {"string", result};
}
// Пользовательские функции
auto funcNodeBase = ctx.getFunc(name);
@@ -494,7 +612,13 @@ struct WhileNode : Node {
: condition(std::move(c)), body(std::move(b)) {}
Value eval(Context& ctx) override {
while (condition->eval(ctx).value == "true") {
body->eval(ctx);
try {
body->eval(ctx);
} catch (const BreakException&) {
break;
} catch (const ContinueException&) {
continue;
}
}
return {"void", ""};
}
@@ -507,13 +631,80 @@ struct ForNode : Node {
Value eval(Context& ctx) override {
if (init) init->eval(ctx);
while (condition->eval(ctx).value == "true") {
body->eval(ctx);
try {
body->eval(ctx);
} catch (const BreakException&) {
break;
} catch (const ContinueException&) {
// continue - выполняем step и продолжаем цикл
}
if (step) step->eval(ctx);
}
return {"void", ""};
}
};
struct BreakNode : Node {
Value eval(Context& ctx) override {
throw BreakException{};
}
};
struct ContinueNode : Node {
Value eval(Context& ctx) override {
throw ContinueException{};
}
};
struct WaitNode : Node {
std::unique_ptr<Node> timeExpr;
WaitNode(std::unique_ptr<Node> t) : timeExpr(std::move(t)) {}
Value eval(Context& ctx) override {
int milliseconds = std::stoi(timeExpr->eval(ctx).value);
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
return {"void", ""};
}
};
struct SwitchNode : Node {
std::unique_ptr<Node> expr;
std::vector<std::pair<std::unique_ptr<Node>, std::unique_ptr<Node>>> cases; // value, body
std::unique_ptr<Node> defaultCase;
SwitchNode(std::unique_ptr<Node> e) : expr(std::move(e)) {}
Value eval(Context& ctx) override {
Value switchValue = expr->eval(ctx);
bool executed = false;
bool fallthrough = false;
for (auto& caseItem : cases) {
if (!executed && !fallthrough) {
Value caseValue = caseItem.first->eval(ctx);
if (switchValue.value == caseValue.value) {
executed = true;
fallthrough = true;
}
}
if (fallthrough) {
try {
caseItem.second->eval(ctx);
} catch (const BreakException&) {
fallthrough = false;
break;
}
}
}
if (!executed && defaultCase) {
defaultCase->eval(ctx);
}
return {"void", ""};
}
};
struct InputNode : Node {
Value eval(Context& ctx) override {
std::string input; std::getline(std::cin, input);
+16 -4
View File
@@ -68,10 +68,10 @@ std::vector<Token> Lexer::tokenize() {
else if (id == "round") tokens.push_back({TokenType::ROUND, id, line});
else if (id == "random") tokens.push_back({TokenType::RANDOM, id, line});
else if (id == "fox") tokens.push_back({TokenType::FOX, id, line});
else if (id == "read_file") tokens.push_back({TokenType::READ_FILE, id, line});
else if (id == "json_get") tokens.push_back({TokenType::JSON_GET, id, line});
else if (id == "str_contains") tokens.push_back({TokenType::STR_CONTAINS, id, line});
else if (id == "str_to_int") tokens.push_back({TokenType::STR_TO_INT, id, line});
else if (id == "readfile") tokens.push_back({TokenType::READ_FILE, id, line});
else if (id == "jsonget") tokens.push_back({TokenType::JSON_GET, id, line});
else if (id == "strcontains") tokens.push_back({TokenType::STR_CONTAINS, id, line});
else if (id == "strtoint") tokens.push_back({TokenType::STR_TO_INT, id, line});
else if (id == "int") tokens.push_back({TokenType::INT_KW, id, line});
else if (id == "float") tokens.push_back({TokenType::FLOAT_KW, id, line});
else if (id == "string") tokens.push_back({TokenType::STRING_KW, id, line});
@@ -83,6 +83,12 @@ std::vector<Token> Lexer::tokenize() {
else if (id == "for") tokens.push_back({TokenType::FOR, id, line});
else if (id == "if") tokens.push_back({TokenType::IF, id, line});
else if (id == "else") tokens.push_back({TokenType::ELSE, id, line});
else if (id == "switch") tokens.push_back({TokenType::SWITCH, id, line});
else if (id == "case") tokens.push_back({TokenType::CASE, id, line});
else if (id == "default") tokens.push_back({TokenType::DEFAULT, id, line});
else if (id == "break") tokens.push_back({TokenType::BREAK, id, line});
else if (id == "continue") tokens.push_back({TokenType::CONTINUE, id, line});
else if (id == "wait") tokens.push_back({TokenType::WAIT, id, line});
else if (id == "array") tokens.push_back({TokenType::ARRAY, id, line});
else if (id == "set") tokens.push_back({TokenType::SET, id, line});
else if (id == "get") tokens.push_back({TokenType::GET, id, line});
@@ -91,6 +97,12 @@ std::vector<Token> Lexer::tokenize() {
else if (id == "using") tokens.push_back({TokenType::USING, id, line});
else if (id == "return") tokens.push_back({TokenType::RETURN, id, line});
else if (id == "global") tokens.push_back({TokenType::GLOBAL, id, line});
else if (id == "httpget") tokens.push_back({TokenType::HTTP_GET, id, line});
else if (id == "httppost") tokens.push_back({TokenType::HTTP_POST, id, line});
else if (id == "httpput") tokens.push_back({TokenType::HTTP_PUT, id, line});
else if (id == "httpdelete") tokens.push_back({TokenType::HTTP_DELETE, id, line});
else if (id == "getch") tokens.push_back({TokenType::GETCH, id, line});
else if (id == "kbhit") tokens.push_back({TokenType::KBHIT, id, line});
else tokens.push_back({TokenType::IDENTIFIER, id, line});
}
else {
+135 -2
View File
@@ -93,8 +93,13 @@ std::unique_ptr<Node> Parser::primary() {
}
if (tokens[pos].type == TokenType::INPUT) {
consume(TokenType::INPUT); consume(TokenType::LPAREN); consume(TokenType::RPAREN);
return std::make_unique<InputNode>();
consume(TokenType::INPUT); consume(TokenType::LPAREN);
std::vector<std::unique_ptr<Node>> args;
if (tokens[pos].type != TokenType::RPAREN) {
args.push_back(expression());
}
consume(TokenType::RPAREN);
return std::make_unique<FuncCallNode>("input", std::move(args));
}
if (tokens[pos].type == TokenType::READ_FILE) {
@@ -104,6 +109,70 @@ std::unique_ptr<Node> Parser::primary() {
return std::make_unique<ReadFileNode>(std::move(filename));
}
// HTTP функции в выражениях
if (tokens[pos].type == TokenType::HTTP_GET) {
consume(TokenType::HTTP_GET); consume(TokenType::LPAREN);
auto url = expression();
consume(TokenType::RPAREN);
std::vector<std::unique_ptr<Node>> args;
args.push_back(std::move(url));
return std::make_unique<FuncCallNode>("httpget", std::move(args));
}
if (tokens[pos].type == TokenType::HTTP_POST) {
consume(TokenType::HTTP_POST); consume(TokenType::LPAREN);
auto url = expression();
consume(TokenType::COMMA);
auto data = expression();
std::vector<std::unique_ptr<Node>> args;
args.push_back(std::move(url));
args.push_back(std::move(data));
if (tokens[pos].type == TokenType::COMMA) {
consume(TokenType::COMMA);
args.push_back(expression());
}
consume(TokenType::RPAREN);
return std::make_unique<FuncCallNode>("httppost", std::move(args));
}
if (tokens[pos].type == TokenType::HTTP_PUT) {
consume(TokenType::HTTP_PUT); consume(TokenType::LPAREN);
auto url = expression();
consume(TokenType::COMMA);
auto data = expression();
std::vector<std::unique_ptr<Node>> args;
args.push_back(std::move(url));
args.push_back(std::move(data));
if (tokens[pos].type == TokenType::COMMA) {
consume(TokenType::COMMA);
args.push_back(expression());
}
consume(TokenType::RPAREN);
return std::make_unique<FuncCallNode>("httpput", std::move(args));
}
if (tokens[pos].type == TokenType::HTTP_DELETE) {
consume(TokenType::HTTP_DELETE); consume(TokenType::LPAREN);
auto url = expression();
consume(TokenType::RPAREN);
std::vector<std::unique_ptr<Node>> args;
args.push_back(std::move(url));
return std::make_unique<FuncCallNode>("httpdelete", std::move(args));
}
// Функции ввода
if (tokens[pos].type == TokenType::GETCH) {
consume(TokenType::GETCH); consume(TokenType::LPAREN); consume(TokenType::RPAREN);
std::vector<std::unique_ptr<Node>> args;
return std::make_unique<FuncCallNode>("getch", std::move(args));
}
if (tokens[pos].type == TokenType::KBHIT) {
consume(TokenType::KBHIT); consume(TokenType::LPAREN); consume(TokenType::RPAREN);
std::vector<std::unique_ptr<Node>> args;
return std::make_unique<FuncCallNode>("kbhit", std::move(args));
}
if (tokens[pos].type == TokenType::LPAREN) {
consume(TokenType::LPAREN);
auto n = expression();
@@ -343,6 +412,70 @@ std::unique_ptr<Node> Parser::statement() {
return std::make_unique<IfNode>(std::move(cond), std::move(thenB), std::move(elseB));
}
if (tokens[pos].type == TokenType::BREAK) {
consume(TokenType::BREAK); consume(TokenType::SEMICOLON);
return std::make_unique<BreakNode>();
}
if (tokens[pos].type == TokenType::CONTINUE) {
consume(TokenType::CONTINUE); consume(TokenType::SEMICOLON);
return std::make_unique<ContinueNode>();
}
if (tokens[pos].type == TokenType::WAIT) {
consume(TokenType::WAIT); consume(TokenType::LPAREN);
auto timeExpr = expression();
consume(TokenType::RPAREN); consume(TokenType::SEMICOLON);
return std::make_unique<WaitNode>(std::move(timeExpr));
}
if (tokens[pos].type == TokenType::SWITCH) {
consume(TokenType::SWITCH); consume(TokenType::LPAREN);
auto expr = expression();
consume(TokenType::RPAREN); consume(TokenType::LBRACE);
auto switchNode = std::make_unique<SwitchNode>(std::move(expr));
while (tokens[pos].type == TokenType::CASE || tokens[pos].type == TokenType::DEFAULT) {
if (tokens[pos].type == TokenType::CASE) {
consume(TokenType::CASE);
auto caseValue = expression();
consume(TokenType::COLON);
std::vector<std::unique_ptr<Node>> caseStatements;
while (tokens[pos].type != TokenType::CASE &&
tokens[pos].type != TokenType::DEFAULT &&
tokens[pos].type != TokenType::RBRACE) {
caseStatements.push_back(statement());
}
auto caseBody = std::make_unique<BlockNode>();
for (auto& stmt : caseStatements) {
static_cast<BlockNode*>(caseBody.get())->stmts.push_back(std::move(stmt));
}
switchNode->cases.push_back(std::make_pair(std::move(caseValue), std::move(caseBody)));
} else if (tokens[pos].type == TokenType::DEFAULT) {
consume(TokenType::DEFAULT); consume(TokenType::COLON);
std::vector<std::unique_ptr<Node>> defaultStatements;
while (tokens[pos].type != TokenType::RBRACE) {
defaultStatements.push_back(statement());
}
auto defaultBody = std::make_unique<BlockNode>();
for (auto& stmt : defaultStatements) {
static_cast<BlockNode*>(defaultBody.get())->stmts.push_back(std::move(stmt));
}
switchNode->defaultCase = std::move(defaultBody);
}
}
consume(TokenType::RBRACE);
return std::move(switchNode);
}
if (tokens[pos].type == TokenType::PRINT) {
consume(TokenType::PRINT); consume(TokenType::LPAREN);
auto expr = expression();
+10 -1
View File
@@ -12,13 +12,22 @@ enum class TokenType {
PRINT, INPUT, ROUND, RANDOM, FOX, READ_FILE, JSON_GET, STR_CONTAINS, STR_TO_INT,
INT_KW, FLOAT_KW, STRING_KW, BOOL_KW, VOID_KW, // Типы данных
TRUE_KW, FALSE_KW, // Boolean литералы
WHILE, FOR, IF, ELSE,
WHILE, FOR, IF, ELSE, SWITCH, CASE, DEFAULT,
ARRAY, SET, GET, SIZE,
INCLUDE, USING, // Подключение файлов
// НОВЫЕ: возврат и глобальные
RETURN, GLOBAL,
// Управление потоком
BREAK, CONTINUE, WAIT,
// Сетевые функции
HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_DELETE,
// Ввод с клавиатуры
GETCH, KBHIT,
IDENTIFIER,
END, ERROR
};