544 lines
13 KiB
C++
544 lines
13 KiB
C++
/**
|
||
* @file dl_script.h
|
||
* @brief dl脚本语言
|
||
*
|
||
*
|
||
* @version 1.0
|
||
* @author lveyou
|
||
* @date 24-05-30
|
||
*
|
||
* @note 尽量不依赖dl的其他文件
|
||
*/
|
||
#pragma once
|
||
|
||
#include <vector>
|
||
#include <list>
|
||
#include <unordered_map>
|
||
#include <functional>
|
||
#include <string>
|
||
#include <cassert>
|
||
#include <stack>
|
||
#include <variant>
|
||
#include <array>
|
||
#include <cstdint>
|
||
|
||
namespace dl
|
||
{
|
||
using ScriptIndex = uint32_t;
|
||
using ScriptInt = int64_t;
|
||
using ScriptFloat = double;
|
||
using ScriptString = std::string;
|
||
using ScriptIndexVS = uint8_t; // 变量空间下标
|
||
|
||
struct ScriptVar;
|
||
class ScriptVM;
|
||
|
||
using ScriptVector = std::vector<ScriptVar>;
|
||
using ScriptTable = std::unordered_map<std::string, ScriptVar>;
|
||
using ScriptParam = ScriptVector;
|
||
using ScriptFunction = std::function<int(ScriptVM&, const ScriptParam&)>;
|
||
|
||
constexpr ScriptIndex SCRIPT_INDEX_RETURN = (ScriptIndex)-1; // 返回值
|
||
constexpr ScriptIndexVS SCRIPT_INDEX_VS_0 = 0; // 全局空间
|
||
constexpr ScriptIndexVS SCRIPT_INDEX_VS_ITERAL = (ScriptIndexVS)-3; // 字面量
|
||
constexpr ScriptIndexVS SCRIPT_INDEX_VS_TEMP = (ScriptIndexVS)-2; // 临时变量
|
||
constexpr ScriptIndexVS SCRIPT_INDEX_VS_ERROR = (ScriptIndexVS)-1; // 初始变量
|
||
|
||
//! 变量类型(用户层面)
|
||
enum class ScriptVarType : ScriptIndex
|
||
{
|
||
E_null, // 空
|
||
E_int, // 整数
|
||
E_float, // 浮点
|
||
E_string, // 字符串
|
||
E_class, // 类
|
||
E_vector, // 数组
|
||
E_table, // 表
|
||
E_function, // 函数
|
||
E_userdata, // 指针
|
||
E_operator, // 操作符
|
||
E_max
|
||
};
|
||
//! 是基础类型
|
||
inline bool IsBaseType(ScriptVarType type)
|
||
{
|
||
return type == ScriptVarType::E_null
|
||
|| type == ScriptVarType::E_int
|
||
|| type == ScriptVarType::E_float
|
||
|| type == ScriptVarType::E_userdata
|
||
|| type == ScriptVarType::E_operator;
|
||
}
|
||
|
||
//! 操作类型
|
||
enum class ScriptOperator : ScriptIndex
|
||
{
|
||
E_assign, // 赋值
|
||
E_add, //
|
||
E_sub,
|
||
E_mul,
|
||
E_div,
|
||
E_comma, // 逗号,视为 push_back
|
||
E_equal, // ==
|
||
E_error
|
||
};
|
||
std::string_view to_string(ScriptOperator op);
|
||
|
||
//! 变量(大小严格控制)
|
||
struct ScriptVar
|
||
{
|
||
friend class ScriptVarSpace;
|
||
friend bool operator==(const ScriptVar& a, const ScriptVar& b);
|
||
public:
|
||
ScriptVar()
|
||
{
|
||
_type = ScriptVarType::E_null;
|
||
_indexVarSpace = SCRIPT_INDEX_VS_ERROR;
|
||
_value = 0;
|
||
}
|
||
void FromInt(ScriptInt v)
|
||
{
|
||
assert(_indexVarSpace != SCRIPT_INDEX_VS_ITERAL);
|
||
_type = ScriptVarType::E_int;
|
||
*(ScriptInt*)&_value = *(ScriptInt*)&v;
|
||
}
|
||
void FromFloat(ScriptFloat v)
|
||
{
|
||
assert(_indexVarSpace != SCRIPT_INDEX_VS_ITERAL);
|
||
_type = ScriptVarType::E_float;
|
||
*(ScriptFloat*)&_value = *(ScriptFloat*)&v;
|
||
}
|
||
void FromOperator(ScriptOperator v)
|
||
{
|
||
assert(_indexVarSpace != SCRIPT_INDEX_VS_ITERAL);
|
||
_type = ScriptVarType::E_operator;
|
||
*(ScriptOperator*)&_value = *(ScriptOperator*)&v;
|
||
}
|
||
|
||
|
||
ScriptInt ToInt() const
|
||
{
|
||
assert(_type == ScriptVarType::E_int);
|
||
return (ScriptInt)_value;
|
||
}
|
||
ScriptFloat ToFloat() const
|
||
{
|
||
assert(_type == ScriptVarType::E_float);
|
||
return (ScriptFloat)_value;
|
||
}
|
||
ScriptOperator ToOperator() const
|
||
{
|
||
assert(_type == ScriptVarType::E_operator);
|
||
return (ScriptOperator)_value;
|
||
}
|
||
|
||
ScriptVarType GetType() const { return _type; }
|
||
std::string_view GetTypeString() const;
|
||
|
||
uint64_t GetValue() const
|
||
{
|
||
assert(IsBaseType(_type));
|
||
return _value;
|
||
}
|
||
uint64_t GetIndex() const
|
||
{
|
||
assert(!IsBaseType(_type));
|
||
return _value;
|
||
}
|
||
ScriptIndexVS GetSpaceIndex() const
|
||
{
|
||
return _indexVarSpace;
|
||
}
|
||
void SetValue(uint64_t v)
|
||
{
|
||
assert(IsBaseType(_type));
|
||
assert(_indexVarSpace != SCRIPT_INDEX_VS_ITERAL);
|
||
_value = v;
|
||
}
|
||
void SetType(ScriptVarType type)
|
||
{
|
||
assert(_type == ScriptVarType::E_null);
|
||
_type = type;
|
||
}
|
||
|
||
void _set_space_index(ScriptIndexVS index)
|
||
{
|
||
_indexVarSpace = index;
|
||
}
|
||
|
||
private:
|
||
ScriptVarType _type;
|
||
ScriptIndexVS _indexVarSpace; // 所在变量空间(基础类型需要释放,也需要标记)
|
||
uint64_t _value; // 基础类型直接存储(或变量下标)
|
||
};
|
||
|
||
|
||
inline bool operator==(const ScriptVar& a, const ScriptVar& b)
|
||
{
|
||
return a._type == b._type
|
||
&& a._indexVarSpace == b._indexVarSpace
|
||
&& a._value == b._value;
|
||
}
|
||
|
||
// 初步token(文本解析)
|
||
struct ScriptToken
|
||
{
|
||
enum Type
|
||
{
|
||
NORMAL,
|
||
STRING,
|
||
OPERATOR,// 操作符
|
||
};
|
||
ScriptToken() :
|
||
_type{ Type::NORMAL }
|
||
{}
|
||
ScriptToken(Type type, std::string_view str) :
|
||
_type{ type },
|
||
_str{ std::string{str} }
|
||
{}
|
||
|
||
Type _type;
|
||
std::string _str;
|
||
};
|
||
|
||
std::string_view to_string(ScriptToken::Type type);
|
||
|
||
//! 表达式token类型
|
||
enum class ScriptExprTokenType
|
||
{
|
||
ESET_variable, // 变量
|
||
ESET_literal, // 字面量
|
||
ESET_operator, //
|
||
};
|
||
|
||
//! 表达式token(指向真实变量)
|
||
struct ScriptExprToken
|
||
{
|
||
ScriptExprTokenType _type; // 类别
|
||
std::string _name; // 字符串内容(变量使用)
|
||
ScriptVar _value; // 值(表达式用、字面量)
|
||
|
||
std::string GetTypeString() const
|
||
{
|
||
return "expr_token";
|
||
}
|
||
};
|
||
|
||
//! 后缀表达式
|
||
struct ScriptExpr
|
||
{
|
||
std::vector<ScriptExprToken> _allToken;
|
||
size_t _lineNumber; // 行号(0开始)
|
||
std::string _strRaw;// 源代码,调试用
|
||
};
|
||
|
||
inline std::string to_string(const ScriptExpr& expr)
|
||
{
|
||
if (expr._allToken.empty())
|
||
return {};
|
||
std::string ret;
|
||
for (size_t i = 0; i < expr._allToken.size() - 1; ++i)
|
||
{
|
||
ret += expr._allToken[i]._name;
|
||
ret += ' ';
|
||
}
|
||
ret += expr._allToken[expr._allToken.size() - 1]._name;
|
||
return ret;
|
||
}
|
||
|
||
//! 变量空间
|
||
class ScriptVarSpace
|
||
{
|
||
public:
|
||
ScriptVarSpace(ScriptIndexVS index, size_t level) :
|
||
_index{ index },
|
||
_level{ level }
|
||
{}
|
||
ScriptIndexVS GetIndex() const { return _index; }
|
||
size_t GetLevel() const { return _level; }
|
||
|
||
ScriptVar AddString(std::string_view v)
|
||
{
|
||
ScriptVar ret;
|
||
ret._type = ScriptVarType::E_string;
|
||
ret._indexVarSpace = _index;
|
||
ret._value = _vecString.size();
|
||
_vecString.push_back(std::string{ v });
|
||
return ret;
|
||
}
|
||
ScriptVar AddFunction(ScriptFunction v)
|
||
{
|
||
ScriptVar ret;
|
||
ret._type = ScriptVarType::E_function;
|
||
ret._indexVarSpace = _index;
|
||
ret._value = _vecFunction.size();
|
||
_vecFunction.push_back(v);
|
||
return ret;
|
||
}
|
||
ScriptVar AddVector()
|
||
{
|
||
ScriptVar ret;
|
||
ret._type = ScriptVarType::E_vector;
|
||
ret._indexVarSpace = _index;
|
||
ret._value = _vecVector.size();
|
||
_vecVector.push_back({});
|
||
return ret;
|
||
}
|
||
void SetString(size_t i, const ScriptString& str)
|
||
{
|
||
_vecString[i] = str;
|
||
}
|
||
void SetVector(size_t i, const ScriptVector& vec)
|
||
{
|
||
_vecVector[i] = vec;
|
||
}
|
||
|
||
const ScriptString& GetString(size_t i) const
|
||
{
|
||
return _vecString[i];
|
||
}
|
||
const ScriptFunction& GetFunction(size_t i) const
|
||
{
|
||
return _vecFunction[i];
|
||
}
|
||
ScriptVector& GetVetorRef(size_t i)
|
||
{
|
||
return _vecVector[i];
|
||
}
|
||
private:
|
||
ScriptIndexVS _index; // 自己下标 0全局变量
|
||
size_t _level;
|
||
std::vector<ScriptString> _vecString;
|
||
std::vector<ScriptTable> _vecClass;
|
||
std::vector<ScriptVector> _vecVector;
|
||
std::vector<ScriptTable> _vecTable;
|
||
std::vector<ScriptFunction> _vecFunction;
|
||
std::vector<ScriptExpr> _vecExpr;
|
||
};
|
||
|
||
|
||
enum class ScriptSegmentType : ScriptIndex
|
||
{
|
||
E_expr,
|
||
E_if,
|
||
E_ifelse,
|
||
E_else,
|
||
E_while,
|
||
E_for,
|
||
E_vector,
|
||
E_table,
|
||
};
|
||
|
||
//! 代码段(包含单独作用域)
|
||
struct ScriptSegment
|
||
{
|
||
ScriptSegmentType _type;
|
||
size_t _level; // 层级(作用域)
|
||
std::vector<ScriptExpr> _allExpr;
|
||
};
|
||
//! 代码块
|
||
struct ScriptBlock
|
||
{
|
||
ScriptBlock() :
|
||
_varSpaceIteral{ SCRIPT_INDEX_VS_ITERAL, 0 }
|
||
{}
|
||
|
||
std::vector<ScriptSegment> _allSeg;
|
||
// 字面量是编译器固定的,不可修改,全局可见,所以单独处理
|
||
ScriptVarSpace _varSpaceIteral;
|
||
std::vector<std::string> _vecSource;// 不包含换行
|
||
|
||
std::string GetSource(bool line_number = true, bool header = true, bool footer = true) const;
|
||
};
|
||
|
||
|
||
//! 控制语句
|
||
struct ScriptControlIf
|
||
{
|
||
ScriptExpr _cond;
|
||
ScriptSegment _seg;
|
||
};
|
||
struct ScriptControlIfElse
|
||
{
|
||
ScriptExpr _cond;
|
||
ScriptSegment _seg;
|
||
};
|
||
struct ScriptControlElse
|
||
{
|
||
ScriptExpr _cond;
|
||
ScriptSegment _seg;
|
||
};
|
||
struct ScriptControlFor
|
||
{
|
||
std::array<ScriptExpr, 3> _cond;
|
||
ScriptSegment _seg;
|
||
};
|
||
struct ScriptControlWhile
|
||
{
|
||
ScriptExpr _cond;
|
||
ScriptSegment _seg;
|
||
};
|
||
|
||
//! 代码段运行时
|
||
struct ScriptSegmentRT
|
||
{
|
||
//std::
|
||
};
|
||
|
||
//! 虚拟机
|
||
class ScriptVM
|
||
{
|
||
friend class ScriptSystem;
|
||
public:
|
||
void Execute(const ScriptBlock& block);
|
||
|
||
// 变量转字符串
|
||
std::string Variable2String(const ScriptVar& var);
|
||
// 变量转bool
|
||
bool Variable2Bool(const ScriptVar& var);
|
||
|
||
// 中断执行(内部调用)
|
||
void Throw() { _bThrow = true; }
|
||
|
||
ScriptVM();
|
||
private:
|
||
// 当前执行代码块
|
||
const ScriptBlock* _block;
|
||
// 名字 -> 变量(变量)
|
||
std::unordered_map<std::string, ScriptVar> _allVar;
|
||
// 全局变量空间
|
||
ScriptVarSpace _varSpaceGlobal;
|
||
// 变量空间
|
||
std::vector<ScriptVarSpace*> _allVarSpace;
|
||
// 函数参数
|
||
ScriptParam _param;
|
||
|
||
//-------------------------------expr------------------------------
|
||
// 返回值(可变)
|
||
ScriptExprToken _return;
|
||
// 操作堆栈
|
||
std::vector<ScriptIndex> _stackVar;
|
||
// 当前表达式
|
||
const ScriptExpr* _expr;
|
||
// 临时变量空间
|
||
ScriptVarSpace _varSpaceTemp; //todo清理
|
||
// 出现异常
|
||
bool _bThrow;
|
||
|
||
void _exec_expr(const ScriptExpr& expr);
|
||
void _clear_expr();
|
||
|
||
// 从 操作堆栈 访问
|
||
const ScriptExprToken& _get_stack_expr_token(size_t i);
|
||
const ScriptExprToken& _get_stack_expr_token_top(size_t i);
|
||
ScriptVar& _get_stack_var(size_t i);
|
||
ScriptVar& _get_stack_var_top(size_t i);
|
||
|
||
void _stack_pop(size_t i);
|
||
|
||
void _op_arithmetic(ScriptOperator op);
|
||
void _op_assign();
|
||
void _op_comma();
|
||
void _op_equal();
|
||
|
||
// 获取(新建)变量,新建则在当前变量空间初始化
|
||
ScriptVar& _get_variable(const ScriptExprToken& var0);
|
||
// 移除变量空间后,从变量表中移除
|
||
void _delete_var_space(ScriptVarSpace* vs);
|
||
|
||
// 返回变量所在空间
|
||
ScriptVarSpace* GetVariableSpaceRef(ScriptIndexVS index);
|
||
const ScriptVarSpace* GetVariableSpace(ScriptIndexVS index);
|
||
ScriptVarSpace* GetVariableSpaceRef(ScriptVar var)
|
||
{
|
||
return GetVariableSpaceRef(var.GetSpaceIndex());
|
||
}
|
||
const ScriptVarSpace* GetVariableSpace(ScriptVar var)
|
||
{
|
||
return GetVariableSpace(var.GetSpaceIndex());
|
||
}
|
||
//------------------------------------变量创建(默认值)--------------
|
||
ScriptVar AddVariable(ScriptIndexVS index, ScriptVarType type);
|
||
//------------------------------------变量获取(必须已存在)--------------
|
||
ScriptFunction GetVariableFunction(ScriptVar var);
|
||
ScriptString GetVariableString(ScriptVar var);
|
||
ScriptVector& GetVariableVector(ScriptVar var);
|
||
//------------------------------------变量设置(必须已存在)--------------
|
||
void SetVariableString(ScriptVar var, ScriptString str);
|
||
void SetVariableVector(ScriptVar var, const ScriptVector& vec);
|
||
|
||
};
|
||
|
||
//! 管理器
|
||
class ScriptSystem
|
||
{
|
||
public:
|
||
ScriptBlock Compile(std::string_view src);
|
||
|
||
// 中缀 -> 后缀(逆波兰表达式)
|
||
std::vector<ScriptExprToken> ConvertMid(const std::vector<ScriptExprToken>& vec);
|
||
|
||
//! 预处理代码(行号不变)
|
||
std::string Preprocess(std::string_view src);
|
||
void PreprocessLineNumber(ScriptBlock& block, std::string_view src);
|
||
|
||
//! 是否操作符
|
||
bool IsOperator(std::string_view str);
|
||
//! 是否可能为操作符内容(变量名不可能出现)
|
||
bool IsMaybeOperator(char ch);
|
||
|
||
//! 返回操作符优先级,越大越优先
|
||
int GetOperatorPriority(std::string_view str);
|
||
|
||
//! 是否关键字
|
||
bool IsKeyword(std::string_view str);
|
||
//! 是否变量名
|
||
bool IsVariable(std::string_view str);
|
||
//! 是否全局变量名
|
||
bool IsGlobalVariable(std::string_view str);
|
||
|
||
//! 返回token类型
|
||
ScriptExprTokenType GetTokenType(std::string_view str);
|
||
|
||
//! 生成表达式token(字面量是编译器信息,需要生成到block)
|
||
ScriptExprToken MakeExprToken(ScriptBlock& block, const ScriptToken& token);
|
||
|
||
//! 生成字面量
|
||
ScriptVar MakeLiteral(ScriptBlock& block, const ScriptToken& token);
|
||
|
||
//! 注册函数
|
||
void RegisterFunction(std::string_view name, ScriptFunction func)
|
||
{
|
||
ScriptVar var = _varSpaceGlobal.AddFunction(func);
|
||
_allVar[std::string{ name }] = var;
|
||
}
|
||
void CopyVariableToVm(ScriptVM& vm)
|
||
{
|
||
vm._allVar = _allVar;
|
||
vm._varSpaceGlobal = _varSpaceGlobal;
|
||
}
|
||
|
||
bool CheckToken(ScriptExprTokenType type);
|
||
|
||
//! 字符串转操作符变量
|
||
ScriptOperator String2Operator(std::string_view str);
|
||
|
||
//------------------------------------基础运算(不考虑变量)-----------------------
|
||
ScriptVar OpArithmetic(ScriptVM& vm, ScriptOperator op, const ScriptVar& v0, const ScriptVar& v1);
|
||
void OpAssign(ScriptVM& vm, ScriptVar& v0, const ScriptVar& v1);
|
||
|
||
ScriptSystem();
|
||
private:
|
||
// 关键字
|
||
std::unordered_map<std::string_view, int> _allKeyword;
|
||
// 操作符、优先级(越大越优先)
|
||
std::unordered_map<std::string_view, int> _allOperator;
|
||
// 变量空间池
|
||
std::list<ScriptVarSpace*> _listVarSpaceFree;
|
||
// 内置变量(例print)
|
||
std::unordered_map<std::string, ScriptVar> _allVar;
|
||
// 内置变量空间(全局)
|
||
ScriptVarSpace _varSpaceGlobal;
|
||
};
|
||
|
||
extern ScriptSystem* g_script;
|
||
} |