Files
dl_old/dl/script/dl_script.cpp
T
2026-04-28 00:53:04 +08:00

1358 lines
31 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "dl_script.h"
#include <cassert>
#include "io/dl_log.h"
#include "base/dl_string.h"
namespace dl
{
enum class ScriptLogType
{
E_print, // 调用打印
E_debug,
E_info,
E_err, // 用户错误
E_damage, // 引擎bug
E_compile,
};
void script_print(ScriptLogType type, std::string_view str)
{
switch (type)
{
case ScriptLogType::E_print:
log_info("script:{}", str);
break;
case ScriptLogType::E_debug:
log_msg("script:【调试】 {}", str);
break;
case ScriptLogType::E_info:
log_msg("script:【提示】 {}", str);
break;
case ScriptLogType::E_err:
log_warn("script:【错误】 {}", str);
break;
case ScriptLogType::E_damage:
log_err("script:【严重错误】 {}", str);
break;
case ScriptLogType::E_compile:
log_err("script:【编译错误】 {}", str);
break;
default:
assert(0);
break;
}
}
ScriptBlock ScriptSystem::Compile(std::string_view src_raw)
{
script_print(ScriptLogType::E_debug, fmt::format("{:=^32}", "开始编译脚本"));
script_print(ScriptLogType::E_debug, fmt::format("源:\n{}", src_raw));
ScriptBlock ret;
// 预处理
g_script->PreprocessLineNumber(ret, src_raw);
std::string src = g_script->Preprocess(src_raw);
std::vector<ScriptSegment>& vec_seg = ret._allSeg;
std::size_t beg = 0;
std::size_t end = 0;
std::vector<ScriptToken> vec_token;
// 括号层级
size_t level_brace = 0;
// 行号
size_t line_number = 0;
enum class State
{
FREE,// 空闲
NORMAL,// 单词匹配
STRING,// 字符串
SYMBOL,// 符号
};
State state = State::FREE;
// 构造当前
auto fn_string = [&]() {
return std::string_view{ src.begin() + beg, src.begin() + end };
};
// 构造word 返回值 0正常、1失败
auto fn_make_word = [&](ScriptToken::Type type) -> int {
std::string_view word = fn_string();
if (!word.empty())
{
if (type == ScriptToken::Type::OPERATOR)
{
// 操作符拆分、例如 ++-( 拆分为 ++、-、(
size_t beg = 0;
size_t end = word.size();
while (beg != end)
{
std::string_view word_sub{ word.data() + beg, word.data() + end };
if (g_script->IsOperator(word_sub))
{
script_print(ScriptLogType::E_debug,
fmt::format("操作符:[{}]", word_sub));
vec_token.push_back({ type, word_sub });
beg = end;
end = word.size();
}
else
{
if (word_sub.size() == 1)
{
script_print(ScriptLogType::E_compile,
fmt::format("无效操作符:{}中的{}", word, word_sub));
return 1;
}
--end;
}
}
}
else if(type == ScriptToken::Type::STRING)
{
script_print(ScriptLogType::E_debug, fmt::format("字符串:[\"{}\"]", word));
vec_token.push_back({ type, word });
}
else
{
script_print(ScriptLogType::E_debug, fmt::format("token :[{}]", word));
vec_token.push_back({ type, word });
}
}
return 0;
};
// 表达式完成
auto fn_expr = [&](ScriptSegment& seg) {
if (vec_token.empty())
{
script_print(ScriptLogType::E_debug, "空行");
return;
}
seg._allExpr.push_back({});
ScriptExpr& expr = seg._allExpr.back();
expr._lineNumber = line_number;
expr._strRaw = ret._vecSource[expr._lineNumber];
// 例:print a + b
// 1、函数视为变量
// 2、若变量后不是操作符,则添加 call 视为函数调用
// 3、检查是否合法中缀表达式
size_t i = 0;
std::vector<ScriptExprToken> vec_mid;
// token 转 表达式
for (ScriptToken& token : vec_token)
{
ScriptExprToken expr = MakeExprToken(ret, token);
vec_mid.push_back(expr);
}
vec_token.clear();
// 4、转为后缀表达式
// 初始化:创建一个空栈用于存放运算符,以及一个空列表或向量用于存放最终的后缀表达式。
std::vector<ScriptExprToken>& vec_out = expr._allToken;
vec_out = ConvertMid(vec_mid);
// 打印
script_print(ScriptLogType::E_debug, "后缀表达式为:");
std::string str;
for (ScriptExprToken& expr : vec_out)
{
if(expr._type == ScriptExprTokenType::ESET_literal
&& expr._value.GetType() == ScriptVarType::E_string)
str += String::AddQuotes(expr._name);
else
str += expr._name;
str += ' ';
}
if (!str.empty())
str.pop_back();
script_print(ScriptLogType::E_debug, str);
script_print(ScriptLogType::E_debug,
fmt::format("表达式完成,词数量 {}", vec_out.size()));
};
size_t seg_level = 0;
ScriptSegment seg;
auto fn_segment = [&]() {
seg._level = seg_level;
vec_seg.push_back(seg);
script_print(ScriptLogType::E_debug,
fmt::format("==========代码段完成,表达式数量 {}", seg._allExpr.size()));
seg._allExpr.clear();
};
while (true)
{
// end为当前字符
char ch = src[end];
#ifndef NDEBUG
std::string_view word_current = fn_string();
#endif
switch (state)
{
case State::FREE:
{// 空闲状态,跳过空白字符
if (ch == ' ' || ch == '\t')
{
++beg;
++end;
}
else if (ch == '\'' || ch == '\"')
{
state = State::STRING;
++beg;
++end;
}
else
{
state = State::NORMAL;
}
}
break;
case State::NORMAL:
{// 普通字符则继续,
if (ch == ' ' || ch == '\t' || ch == '\n')
{
fn_make_word(ScriptToken::Type::NORMAL);
if (ch == '\n' && level_brace == 0)
{
fn_expr(seg); // 解析表达式
++line_number;
}
++end;
beg = end;
}
else if (ch == '\'' || ch == '\"')
{
state = State::STRING;
++beg;
++end;
}
else if (ch == '{')
{
if (beg != end)
{
fn_make_word(ScriptToken::Type::NORMAL);
}
++end;
beg = end;
seg._type = ScriptSegmentType::E_expr;
fn_segment();
++seg_level;
state = State::FREE;
}
else if (ch == '}')
{
if (beg != end)
{
fn_make_word(ScriptToken::Type::NORMAL);
}
++end;
beg = end;
seg._type = ScriptSegmentType::E_expr;
fn_segment();
state = State::FREE;
if (seg_level == 0)
{
script_print(ScriptLogType::E_compile, fmt::format("{}", "花括号数量不匹配!"));
return {};
}
--seg_level;
}
else if (g_script->IsMaybeOperator(ch))
{
if (beg != end)
{
fn_make_word(ScriptToken::Type::NORMAL);
++beg;
}
++end;
state = State::SYMBOL;
}
else
++end;
}
break;
case State::STRING:
{
if (ch == '\'' || ch == '\"')
{
fn_make_word(ScriptToken::Type::STRING);
++end;
beg = end;
state = State::FREE;
}
else
++end;
}
break;
case State::SYMBOL:
{
if (g_script->IsMaybeOperator(ch))
{// 连续解析,后面再拆分
++end;
}
else
{
fn_make_word(ScriptToken::Type::OPERATOR);
beg = end;
state = State::FREE;
}
}
break;
default:
break;
}
if (end >= src.size())
{
fn_make_word(ScriptToken::Type::NORMAL);
if(!vec_token.empty())
fn_expr(seg);
seg._type = ScriptSegmentType::E_expr;
fn_segment();
break;
}
}
script_print(ScriptLogType::E_debug, fmt::format("{:=^32}", "词法分析完成"));
return ret;
}
std::vector<dl::ScriptExprToken> ScriptSystem::ConvertMid(const std::vector<ScriptExprToken>& vec_mid)
{
std::vector<ScriptExprToken> vec_out;
std::stack<ScriptExprToken> s;
// 遍历中缀表达式:从左到右遍历中缀表达式的每一个元素。
for (const ScriptExprToken& expr : vec_mid)
{
// 如果当前元素是操作数(如数字、变量等非运算符),直接将其添加到后缀表达式的列表中。
if (expr._type != ScriptExprTokenType::ESET_operator)
{
vec_out.push_back(expr);
}
else if(expr._name == "(")
s.push(expr);
else if (expr._name == ")")
{
// 右小括号,出栈一直出到遇到第一个左括号
while (true)
{
ScriptExprToken& expr_top = s.top();
if (expr_top._name != "(")
{
vec_out.push_back(expr_top);
s.pop();
}
else
{
s.pop();
break;
}
}
}
else if(s.empty())
s.push(expr);
else
{
int p_new = GetOperatorPriority(expr._name);
while (true)
{
ScriptExprToken& expr_top = s.top();
if (expr_top._name == "(")
{
s.push(expr);
break;
}
int p_top = GetOperatorPriority(expr_top._name);
if (p_top < p_new)
{// 如果栈里比较小,则后计算,所以自己入栈
s.push(expr);
break;
}
else
{// 否则栈顶送入到结果,先计算
vec_out.push_back(expr_top);
s.pop();
// 弹栈之后,若空了,
if (s.empty())
{
s.push(expr);
break;
}
}
}
}
}
// 处理剩余栈内运算符:
// 遍历结束后,如果栈中还有剩余的运算符,将它们全部弹出并追加到后缀表达式的末尾。
// 这是因为这些运算符没有遇到更低优先级的运算符,按照运算符的顺序应该在表达式的最后。
while (!s.empty())
{
vec_out.push_back(s.top());
s.pop();
}
/*注意事项:
需要定义一个函数来确定每个运算符的优先级。
空格和括号在实际处理时可能需要特殊考虑,尤其是处理括号时,遇到左括号直接入栈,遇到右括号则弹出栈顶运算符直到遇到左括号对应的符号。
对于一元运算符,如负号 - 作为负数标志或逻辑非 !,需要特别处理规则,确保正确识别其作用。*/
return vec_out;
}
std::string ScriptSystem::Preprocess(std::string_view src)
{
std::string ret;
int mode = 0; // 1.string 2.comment
for (size_t i = 0; i < src.size(); ++i)
{
const char& ch = src[i];
if (mode == 0)
{
if (ch == '\"')
{
mode = 1;
ret.push_back(ch);
}
else
{
if (ch == '/'
&& i + 1 < src.size()
&& src[i + 1] == '/')
mode = 2;
else
ret.push_back(ch);
}
}
else if (mode == 1)
{
if(ch == '\"')
mode = 0;
ret.push_back(ch);
}
else
{
if (ch == '\n')
{
mode = 0;
ret.push_back(ch);
}
}
}
return ret;
}
void ScriptSystem::PreprocessLineNumber(ScriptBlock& block, std::string_view src)
{
std::vector<std::string_view> vec = String::SplitView(src, "\n");
for (auto& iter : vec)
block._vecSource.push_back(std::string{ iter });
/*if (vec.empty())
return;
for (size_t i = 0; i < vec.size() - 1; ++i)
{
block._vecSource.push_back(vec[i] + "\n");
}
block._vecSource.push_back(std::string{ vec.back() });*/
}
bool ScriptSystem::IsOperator(std::string_view str)
{
return _allOperator.contains(str);
}
bool ScriptSystem::IsMaybeOperator(char ch)
{
return (ch == '!')
|| (ch >= 35 && ch <= 47)
|| (ch == ':')
|| (ch >= 60 && ch <= 64)
|| (ch >= 91 && ch <= 94)
|| (ch == '|')
|| (ch == '~');
}
int ScriptSystem::GetOperatorPriority(std::string_view str)
{
auto iter = _allOperator.find(str);
if (iter == _allOperator.end())
return -1;
return iter->second;
}
bool ScriptSystem::IsKeyword(std::string_view str)
{
return _allKeyword.contains(str);
}
bool ScriptSystem::IsVariable(std::string_view str)
{
/*变量名称只能使用字母、数字和下划线。
第一个字符必须是字母或下划线,因为C++不允许数字作为变量名的首字符。
区分大小写,即变量name和Name是不同的。
避免使用C++的关键字和保留字作为变量名。*/
assert(!str.empty());
if (!std::isalpha(str[0]) && str[0] != '_')
return false;
for (auto& iter : str)
{
if (iter != '_'
&& !std::isalpha(iter)
&& !std::isdigit(iter))
return false;
}
return true;
}
bool ScriptSystem::IsGlobalVariable(std::string_view str)
{
return str.size() > 2
&& str[0] == 'g'
&& str[1] == '_';
}
dl::ScriptExprTokenType ScriptSystem::GetTokenType(std::string_view str)
{
if (IsOperator(str))
return ScriptExprTokenType::ESET_operator;
else if (IsVariable(str))
return ScriptExprTokenType::ESET_variable;
else
return ScriptExprTokenType::ESET_literal;
}
dl::ScriptExprToken ScriptSystem::MakeExprToken(ScriptBlock& block, const ScriptToken& token)
{
ScriptExprToken ret;
if (token._type == ScriptToken::STRING)
ret._type = ScriptExprTokenType::ESET_literal;
else
ret._type = GetTokenType(token._str);
switch (ret._type)
{
case dl::ScriptExprTokenType::ESET_variable:
ret._name = token._str;
break;
case dl::ScriptExprTokenType::ESET_literal:
ret._name = token._str;
ret._value = MakeLiteral(block, token);
break;
case dl::ScriptExprTokenType::ESET_operator:
ret._name = token._str;
ret._value.FromOperator(String2Operator(token._str));
break;
default:
break;
}
return ret;
}
ScriptVar ScriptSystem::MakeLiteral(ScriptBlock& block, const ScriptToken& token)
{
ScriptVar ret;
if (token._type == ScriptToken::STRING)
ret = block._varSpaceIteral.AddString(token._str);
else
{
// 字面量类型有限 数字、字符串、表
StringType type = String::GetType(token._str);
switch (type)
{
case StringType::NORMAL:
script_print(ScriptLogType::E_compile, fmt::format("错误的字面量:{}", token._str));
break;
case StringType::INTGER:
ret.FromInt(std::stoi(token._str));
break;
case StringType::FLOAT:
ret.FromFloat(std::stof(token._str));
break;
default:
assert(0);
}
// 赋值后再设置
ret._set_space_index(SCRIPT_INDEX_VS_ITERAL);
}
return ret;
}
ScriptOperator ScriptSystem::String2Operator(std::string_view str)
{
if (str == "=")
return ScriptOperator::E_assign;
if (str == "+")
return ScriptOperator::E_add;
if (str == "-")
return ScriptOperator::E_sub;
if (str == "*")
return ScriptOperator::E_mul;
if (str == "/")
return ScriptOperator::E_div;
if (str == ",")
return ScriptOperator::E_comma;
if (str == "==")
return ScriptOperator::E_equal;
return ScriptOperator::E_error;
}
dl::ScriptVar ScriptSystem::OpArithmetic(ScriptVM& vm, ScriptOperator op, const ScriptVar& v0, const ScriptVar& v1)
{
ScriptVar ret;
if (v0.GetType() == ScriptVarType::E_int)
{
ScriptInt vv0 = v0.ToInt();
if (v1.GetType() == ScriptVarType::E_int)
{
ScriptInt vv1 = v1.ToInt();
ScriptInt vv_ret;
switch (op)
{
case dl::ScriptOperator::E_add:
vv_ret = vv0 + vv1;
break;
case dl::ScriptOperator::E_sub:
vv_ret = vv0 - vv1;
break;
case dl::ScriptOperator::E_mul:
vv_ret = vv0 * vv1;
break;
case dl::ScriptOperator::E_div:
vv_ret = vv0 / vv1;
break;
default:
assert(0);
break;
}
ret.FromInt(vv_ret);
}
}
else if (v0.GetType() == ScriptVarType::E_string)
{
ScriptString vv0 = vm.GetVariableString(v0);
if (v1.GetType() == ScriptVarType::E_string)
{
ScriptString vv1 = vm.GetVariableString(v1);
ScriptString vv_ret;
switch (op)
{
case dl::ScriptOperator::E_add:
vv_ret = vv0 + vv1;
break;
case dl::ScriptOperator::E_sub:
case dl::ScriptOperator::E_mul:
case dl::ScriptOperator::E_div:
break;
default:
assert(0);
break;
}
ret = vm._varSpaceTemp.AddString(vv_ret);
}
}
if (ret.GetType() == ScriptVarType::E_null)
{
script_print(ScriptLogType::E_err,
fmt::format("OP:算术运算失败:{} {} {}", v0.GetTypeString(), dl::to_string(op), v1.GetTypeString()));
}
return ret;
}
void ScriptSystem::OpAssign(ScriptVM& vm, ScriptVar& v0, const ScriptVar& v1)
{
if (v0.GetType() == ScriptVarType::E_null)
{
v0 = vm.AddVariable(v0.GetSpaceIndex(), v1.GetType());
}
if (v0.GetType() == ScriptVarType::E_int)
{
if (v1.GetType() == ScriptVarType::E_int)
{
ScriptInt vv1 = v1.ToInt();
v0.FromInt(vv1);
return;
}
else if (v1.GetType() == ScriptVarType::E_float)
{
ScriptFloat vv1 = v1.ToFloat();
v0.FromInt((ScriptInt)vv1);
return;
}
}
else if (v0.GetType() == ScriptVarType::E_float)
{
if (v1.GetType() == ScriptVarType::E_int)
{
ScriptInt vv1 = v1.ToInt();
v0.FromFloat((ScriptFloat)vv1);
return;
}
else if (v1.GetType() == ScriptVarType::E_float)
{
ScriptFloat vv1 = v1.ToFloat();
v0.FromFloat(vv1);
return;
}
}
else if (v0.GetType() == ScriptVarType::E_string)
{
if (v1.GetType() == ScriptVarType::E_string)
{
const ScriptString& vv1 = vm.GetVariableString(v1);
vm.SetVariableString(v0, vv1);
return;
}
}
else if (v0.GetType() == ScriptVarType::E_vector)
{
if (v1.GetType() == ScriptVarType::E_vector)
{
const ScriptVector& vv1 = vm.GetVariableVector(v1);
vm.SetVariableVector(v0, vv1);
return;
}
}
script_print(ScriptLogType::E_err,
fmt::format("OP:赋值失败:{} = {}", v0.GetTypeString(), v1.GetTypeString()));
}
int ex_script_print(ScriptVM& vm, ScriptParam param)
{
script_print(ScriptLogType::E_print, vm.Variable2String(param[0]));
return 0;
}
int ex_script_assert(ScriptVM& vm, ScriptParam param)
{
if (!vm.Variable2Bool(param[0]))
vm.Throw();
return 0;
}
ScriptSystem::ScriptSystem():
_varSpaceGlobal{0, 0}
{
_allKeyword["function"] = 0;
_allKeyword["param"] = 0;
_allKeyword["typeof"] = 0;
_allKeyword["is_null"] = 0;
_allKeyword["operator"] = 0;
_allKeyword["return"] = 0;
_allKeyword["new"] = 0;
_allKeyword["if"] = 0;
_allKeyword["elseif"] = 0;
_allKeyword["else"] = 0;
_allKeyword["while"] = 0;
_allKeyword["for"] = 0;
_allKeyword["goto"] = 0;
_allOperator["="] = 10;
_allOperator[","] = 11;
_allOperator["=="] = 15;
_allOperator["+"] = 20;
_allOperator["-"] = 20;
_allOperator["*"] = 21;
_allOperator["/"] = 21;
_allOperator["("] = 0;
_allOperator[")"] = 0;
RegisterFunction("print", ex_script_print);
RegisterFunction("assert", ex_script_assert);
}
void ScriptVM::Execute(const ScriptBlock& block)
{
script_print(ScriptLogType::E_info, fmt::format("开始执行代码块:\n{}", block.GetSource()));
// 记录代码块
_block = &block;
size_t cur = 0;
while (cur < block._allSeg.size())
{
const ScriptSegment& seg = block._allSeg[cur];
// 出栈变量空间,直到层级小于自己
while (true)
{
if(_allVarSpace.size() == 1)
break;
ScriptVarSpace* vs_top = _allVarSpace.back();
if(vs_top->GetLevel() <= seg._level)
break;
_delete_var_space(vs_top);
delete vs_top;
_allVarSpace.pop_back();
}
ScriptVarSpace* var_space = new ScriptVarSpace(
(ScriptIndexVS)_allVarSpace.size(), seg._level);
_allVarSpace.push_back(var_space);
size_t cur_expr = 0;
while (cur_expr < seg._allExpr.size())
{
const ScriptExpr& expr = seg._allExpr[cur_expr];
switch (seg._type)
{
case ScriptSegmentType::E_expr:
_exec_expr(expr);
break;
case ScriptSegmentType::E_if:
break;
case ScriptSegmentType::E_ifelse:
break;
case ScriptSegmentType::E_else:
break;
case ScriptSegmentType::E_while:
break;
case ScriptSegmentType::E_for:
break;
default:
script_print(ScriptLogType::E_damage,
fmt::format("未知表达式类型:{}行,{}", expr._lineNumber + 1, (int)seg._type));
return;
}
if (_bThrow)
{
script_print(ScriptLogType::E_err,
fmt::format("line{}: {}", expr._lineNumber + 1, expr._strRaw));
break;
}
++cur_expr;
_clear_expr();
}
++cur;
if (_bThrow)
{
break;
}
}
assert(_allVarSpace.size() > 1);
for (size_t i = 1; i < _allVarSpace.size(); ++i)
{
delete _allVarSpace[i];
}
_block = nullptr;
if(_bThrow)
script_print(ScriptLogType::E_info, fmt::format("执行代码块出错:\n{}", block.GetSource()));
else
script_print(ScriptLogType::E_info, fmt::format("执行代码块完成", ""));
}
ScriptVM::ScriptVM() :
_bThrow{ false },
_varSpaceGlobal{ 0 , 0 },
_varSpaceTemp{ SCRIPT_INDEX_VS_TEMP , 0 }
{
g_script->CopyVariableToVm(*this);
_allVarSpace.push_back(&_varSpaceGlobal);
_param.resize(16);
}
void ScriptVM::_exec_expr(const ScriptExpr& expr)
{
_expr = &expr;
_stackVar.clear();
const std::vector<ScriptExprToken>& vec_token = _expr->_allToken;
for (size_t i = 0; i < vec_token.size(); ++i)
{
const ScriptExprToken& token = vec_token[i];
if (token._type == ScriptExprTokenType::ESET_operator)
{
ScriptOperator op = token._value.ToOperator();
switch (op)
{
case ScriptOperator::E_assign:
_op_assign();
break;
case ScriptOperator::E_add:
case ScriptOperator::E_sub:
case ScriptOperator::E_mul:
case ScriptOperator::E_div:
_op_arithmetic(op);
break;
case ScriptOperator::E_comma:
_op_comma();
break;
case ScriptOperator::E_equal:
_op_equal();
break;
default:
script_print(ScriptLogType::E_damage, fmt::format("未知操作符:{}", token._name));
break;
}
}
else
{
_stackVar.push_back((ScriptIndex)i);
}
}
// 剩余栈处理
if (_stackVar.size() == 0)
int temp = 0;
if (_stackVar.size() == 1)
int temp = 1;
else if (_stackVar.size() == 2)
{
ScriptVar& var0 = _get_stack_var(0);
ScriptVar& var1 = _get_stack_var(1);
_stack_pop(2);
ScriptFunction func = GetVariableFunction(var0);
_param[0] = var1;
func(*this, _param);
}
else
{
script_print(ScriptLogType::E_damage,
fmt::format("剩余栈错误:{}", dl::to_string(_stackVar)));
}
int a = 3;
}
void ScriptVM::_clear_expr()
{
_stackVar.clear();
}
const ScriptExprToken& ScriptVM::_get_stack_expr_token(size_t i)
{
if(i >= _stackVar.size())
{
script_print(ScriptLogType::E_damage, "stack越界!");
return _return;
}
if (_stackVar[i] == SCRIPT_INDEX_RETURN)
return _return;
else
return _expr->_allToken[_stackVar[i]];
}
const ScriptExprToken& ScriptVM::_get_stack_expr_token_top(size_t i)
{
i = _stackVar.size() - i - 1;
return _get_stack_expr_token(i);
}
dl::ScriptVar& ScriptVM::_get_stack_var(size_t i)
{
return _get_variable(_get_stack_expr_token(i));
}
dl::ScriptVar& ScriptVM::_get_stack_var_top(size_t i)
{
i = _stackVar.size() - i - 1;
return _get_stack_var(i);
}
void ScriptVM::_stack_pop(size_t i)
{
i = _stackVar.size() - i;
if (i > _stackVar.size())
{
script_print(ScriptLogType::E_damage, "stack数量不足!");
return;
}
_stackVar.resize(i);
}
void ScriptVM::_op_arithmetic(ScriptOperator op)
{
ScriptVar& var0 = _get_stack_var_top(1);
ScriptVar& var1 = _get_stack_var_top(0);
_stack_pop(2);
_stackVar.push_back(SCRIPT_INDEX_RETURN);
_return._type = ScriptExprTokenType::ESET_variable;
_return._value = g_script->OpArithmetic(*this, op, var0, var1);
_return._name = {};
}
void ScriptVM::_op_assign()
{
const ScriptExprToken& t0 = _get_stack_expr_token_top(1);
ScriptVar& var0 = _get_stack_var_top(1);
ScriptVar& var1 = _get_stack_var_top(0);
_stack_pop(2);
g_script->OpAssign(*this, var0, var1);
_stackVar.push_back(SCRIPT_INDEX_RETURN);
_return._type = ScriptExprTokenType::ESET_variable;
_return._value = var0;
_return._name = t0._name;
}
void ScriptVM::_op_comma()
{
ScriptVar& var0 = _get_stack_var_top(1);
ScriptVar& var1 = _get_stack_var_top(0);
_stack_pop(2);
if (var0.GetType() == ScriptVarType::E_vector)
{// 0为容器则加到容器
ScriptVector& vec = GetVariableVector(var0);
vec.push_back(var1);
_return._value = var0;
}
else
{// 新建临时容器
ScriptVar var = _varSpaceTemp.AddVector();
ScriptVector& vec = GetVariableVector(var);
vec.push_back(var0);
vec.push_back(var1);
_return._value = var;
}
_stackVar.push_back(SCRIPT_INDEX_RETURN);
_return._type = ScriptExprTokenType::ESET_variable;
_return._name = {};
}
void ScriptVM::_op_equal()
{
ScriptVar& var0 = _get_stack_var_top(1);
ScriptVar& var1 = _get_stack_var_top(0);
_stack_pop(2);
bool equal = true;
do
{
if (var0.GetType() != var1.GetType())
{
equal = false;
break;
}
if (IsBaseType(var0.GetType()))
{
equal = var0.GetValue() == var1.GetValue();
break;
}
if (var0.GetType() == ScriptVarType::E_string)
{
equal = GetVariableString(var0) == GetVariableString(var1);
break;
}
// todo
equal = false;
} while (0);
_stackVar.push_back(SCRIPT_INDEX_RETURN);
_return._type = ScriptExprTokenType::ESET_variable;
_return._value.FromInt(equal ? 1 : 0);
_return._name = {};
}
ScriptVar& ScriptVM::_get_variable(const ScriptExprToken& t)
{
if (t._type == ScriptExprTokenType::ESET_literal)
{// 字面量
return (ScriptVar&)t._value;
}
// 空名变量视为返回值
if (t._name.empty())
{
return _return._value;
}
auto iter = _allVar.find(t._name);
if (iter == _allVar.end())
{
// 新建
ScriptVar& var = _allVar[t._name];
if (g_script->IsGlobalVariable(t._name))
var._set_space_index(0);
else
{
assert(_allVarSpace.size() > 1);
var._set_space_index((ScriptIndexVS)_allVarSpace.size() - 1);
}
return var;
}
return _allVar[t._name];
}
void ScriptVM::_delete_var_space(ScriptVarSpace* vs)
{
for (auto iter = _allVar.begin(); iter != _allVar.end();)
{
if (iter->second.GetSpaceIndex() == vs->GetIndex())
iter = _allVar.erase(iter);
else
++iter;
}
int x = 3;
}
dl::ScriptVarSpace* ScriptVM::GetVariableSpaceRef(ScriptIndexVS index)
{
if (index == SCRIPT_INDEX_VS_TEMP)
return &_varSpaceTemp;
if (index >= _allVarSpace.size())
{
script_print(ScriptLogType::E_damage, "变量空间下标错误!");
return {};
}
return _allVarSpace[index];
}
const dl::ScriptVarSpace* ScriptVM::GetVariableSpace(ScriptIndexVS index)
{
if (index == SCRIPT_INDEX_VS_ITERAL)
return &_block->_varSpaceIteral;
if (index == SCRIPT_INDEX_VS_TEMP)
return &_varSpaceTemp;
if (index >= _allVarSpace.size())
{
script_print(ScriptLogType::E_damage, "变量空间下标错误!");
return {};
}
return _allVarSpace[index];
}
dl::ScriptVar ScriptVM::AddVariable(ScriptIndexVS index, ScriptVarType type)
{
ScriptVar v;
// nil -> 构造实际的变量
if (type == ScriptVarType::E_string)
{
v = GetVariableSpaceRef(index)->AddString({});
}
else if (type == ScriptVarType::E_vector)
{
v = GetVariableSpaceRef(index)->AddVector();
}
else
{
// nil -> 基础类型默认值0
v.SetType(type);
v.SetValue(0);
}
return v;
}
dl::ScriptFunction ScriptVM::GetVariableFunction(ScriptVar var)
{
auto space = GetVariableSpace(var);
return space->GetFunction(var.GetIndex());
}
dl::ScriptString ScriptVM::GetVariableString(ScriptVar var)
{
auto space = GetVariableSpace(var);
return space->GetString(var.GetIndex());
}
dl::ScriptVector& ScriptVM::GetVariableVector(ScriptVar var)
{
auto space = GetVariableSpaceRef(var);
return space->GetVetorRef(var.GetIndex());
}
void ScriptVM::SetVariableString(ScriptVar var, ScriptString str)
{
auto space = GetVariableSpaceRef(var);
return space->SetString(var.GetIndex(), str);
}
void ScriptVM::SetVariableVector(ScriptVar var, const ScriptVector& vec)
{
auto space = GetVariableSpaceRef(var);
return space->SetVector(var.GetIndex(), vec);
}
std::string ScriptVM::Variable2String(const ScriptVar& var)
{
switch (var.GetType())
{
case ScriptVarType::E_null:
return "null";
case ScriptVarType::E_int:
return std::to_string(var.ToInt());
case ScriptVarType::E_float:
return std::to_string(var.ToFloat());
case ScriptVarType::E_string:
return GetVariableString(var);
case ScriptVarType::E_class:
case ScriptVarType::E_vector:
{
std::string ret;
const ScriptVector& vec = GetVariableVector(var);
ret += '[';
for (size_t i = 0; i < vec.size(); ++i)
{
if (vec[i] == var)
{// todo 深层循环引用
ret += "self";
}
else
{
ret += Variable2String(vec[i]);
}
if (i + 1 < vec.size())
ret += ", ";
}
ret += ']';
return ret;
}
case ScriptVarType::E_table:
case ScriptVarType::E_function:
case ScriptVarType::E_userdata:
case ScriptVarType::E_operator:
case ScriptVarType::E_max:
default:
break;
}
assert(0);
return "error_variable";
}
bool ScriptVM::Variable2Bool(const ScriptVar& var)
{
switch (var.GetType())
{
case ScriptVarType::E_null:
return false;
case ScriptVarType::E_int:
return var.ToInt();
case ScriptVarType::E_float:
return var.ToFloat();
case ScriptVarType::E_string:
return !GetVariableString(var).empty();
case ScriptVarType::E_class:
case ScriptVarType::E_vector:
case ScriptVarType::E_table:
case ScriptVarType::E_function:
case ScriptVarType::E_userdata:
case ScriptVarType::E_operator:
case ScriptVarType::E_max:
default:
break;
}
script_print(ScriptLogType::E_err,
fmt::format("变量类型不支持转换bool:{}", var.GetTypeString()));
return false;
}
std::string_view ScriptVar::GetTypeString() const
{
switch (_type)
{
case dl::ScriptVarType::E_null:
return "null";
case dl::ScriptVarType::E_int:
return "int";
case dl::ScriptVarType::E_float:
return "float";
case dl::ScriptVarType::E_string:
return "string";
case dl::ScriptVarType::E_class:
return "class";
case dl::ScriptVarType::E_vector:
return "vector";
case dl::ScriptVarType::E_table:
return "table";
case dl::ScriptVarType::E_function:
return "function";
case dl::ScriptVarType::E_userdata:
return "userdata";
case dl::ScriptVarType::E_operator:
return "operator";
case dl::ScriptVarType::E_max:
default:
script_print(ScriptLogType::E_damage,
fmt::format("错误的变量类型:{}", (int)_type));
return "error_var_type";
}
}
std::string_view to_string(ScriptOperator op)
{
switch (op)
{
case dl::ScriptOperator::E_assign:
return "=";
case dl::ScriptOperator::E_add:
return "+";
case dl::ScriptOperator::E_sub:
return "-";
case dl::ScriptOperator::E_mul:
return "*";
case dl::ScriptOperator::E_div:
return "/";
case dl::ScriptOperator::E_comma:
return ",";
case dl::ScriptOperator::E_equal:
return "==";
default:
return "error_op";
}
}
std::string_view to_string(ScriptToken::Type type)
{
switch (type)
{
case dl::ScriptToken::NORMAL:
return "普通";
case dl::ScriptToken::STRING:
return "字符串";
//case dl::ScriptToken::LBRACE:
// return "左括号";
//case dl::ScriptToken::RBRACE:
// return "右括号";
default:
break;
}
return "error_token";
}
std::string ScriptBlock::GetSource(bool line_number /*= true*/,
bool header /*= true*/, bool footer /*= true*/) const
{
std::string ret;
if (header)
ret += "--------------------------------\n";
for (size_t i = 0; i < _vecSource.size(); ++i)
{
if (line_number)
ret += fmt::format("{: >6}.|", i + 1);
ret += _vecSource[i];
ret += "\n";
}
if (footer)
ret += "--------------------------------";
else
ret.pop_back();
return ret;
}
}