编程实战:类C语法的编译型脚本解释器(六)表达式

初级代码游戏的专栏介绍与文章目录-CSDN博客

系列入口:

编程实战:类C语法的编译型脚本解释器(系列)-CSDN博客

        脚本的结构与C语言类似,由语句和表达式构成,后来增加了子函数,子函数当作独立的脚本。

        本文介绍表达式。从本文开始前面介绍过的东西和后面要介绍的东西会纠缠在一起,互相递归。

目录

 一、表达式概览

二、表达式类型

三、成员变量

四、计算结果类型

五、编译时检查

六、执行


 一、表达式概览

		//表达式,单目算符有两个操作数则为后缀(第一个不使用),函数参数个数不限
		//VARIABLE:pVariable 包含常量
		//PLUGIN:pPlugin(operands)
		//OPERATION:op operands
		struct Expression
		{
			enum types { NULLEXPRESSION, CONSTANT, DEFINE, VARIABLE, FUNCTION, PLUGIN, OPERATION };
			types type;
			Variable::types result_type;//编译用的结果类型,执行时实际上并不需要这个
			size_t source_start;//起始位置
			size_t source_end;//结束位置

			//变量
			string VariableName;
			Variable m_variable;//用于常量或运行时创建变量

			//函数
			CScript * pFunction;//函数索引

			//插件
			CPluginMap::HANDLE pPlugin;

			//插件或函数的参数
			vector<Expression > ParamList;

			//操作
			string op;
			vector<Expression > Operands;//操作数

			//函数和属性
			void* user_p;//用户自行使用的指针,编译时可设置,执行时不可修改(指向的内容由用户决定)

			Expression() :type(NULLEXPRESSION), result_type(Variable::NULLVARIABLE), source_start(0), source_end(0), pFunction(NULL), user_p(NULL) {}
			Expression* pLeftOperand() { return (Operands.size() >= 1 && Operands[0].type != NULLEXPRESSION ? &Operands[0] : NULL); }//左操作数
			Expression const* pLeftOperand()const { return (Operands.size() >= 1 && Operands[0].type != NULLEXPRESSION ? &Operands[0] : NULL); }//左操作数
			Expression* pRightOperand() { return (Operands.size() >= 2 && Operands[1].type != NULLEXPRESSION ? &Operands[1] : NULL); }//右操作数
			Expression const* pRightOperand()const { return (Operands.size() >= 2 && Operands[1].type != NULLEXPRESSION ? &Operands[1] : NULL); }//右操作数
			bool AddLeftOperand(Expression const& exp)
			{
				if (NULL != pLeftOperand())return false;
				if (Operands.size() < 1)Operands.resize(1);
				Operands[0] = exp;
				return true;
			}
			bool AddRightOperand(Expression const& exp)
			{
				if (NULL != pRightOperand())return false;
				if (Operands.size() < 2)Operands.resize(2);
				Operands[1] = exp;
				return true;
			}

			Variable::types GetResultType(string& source, T_VARIABLE_S& vars);
			//setpp记录已经做过的++ --
			bool CheckExpression(string& source, T_VARIABLE_S& vars, long level, set<string >& setpp);
			bool ExecExpression(CScript const& script, T_VARIABLE_S& vars, Variable& ret, void* pe)const;
			string ToString(string const& source, T_VARIABLE_S const& vars, long level = 0)const
			{
				STATIC_C const char typestr[][TOKEN_BUF_LEN] = { "NULLEXPRESSION","DEFINE","CONSTANT","VARIABLE","FUNCTION","PLUGIN","OPERATION" };//必须与types对应
				char buf[256];
				string ret;
				size_t i;
				string prefix;
				prefix.assign(level * 4, ' ');

				ret = prefix.c_str();
				sprintf(buf, "%03ld %03ld 表达式类型 %-12s 结果类型 %-12s: ", source_start, source_end - 1, typestr[type], Variable::TypeStr(result_type));
				ret += buf;
				ret += source.substr(source_start, source_end - source_start);
				ret += "\r\n";
				switch (type)
				{
				case DEFINE:
					ret += VariableName + " " + m_variable.ToString(level + 1);
					ret += "\r\n";
					break;
				case CONSTANT:
					ret += m_variable.ToString(level + 1);
					ret += "\r\n";
					break;
				case VARIABLE:
					if (NULL == vars.FindVariable(VariableName))
					{
						ret += VariableName;
					}
					else ret += vars.FindVariable(VariableName)->ToString(level + 1);
					ret += "\r\n";
					break;
				case FUNCTION:
					ret += prefix + "函数名: " + pFunction->script_name;
					if (ParamList.size() != 0)
					{
						ret += prefix + "参数:\r\n";
						for (i = 0; i < ParamList.size(); ++i)
						{
							ret += ParamList[i].ToString(source, vars, level + 1);
						}
					}
					else
					{
						ret += "\r\n";
					}
					break;
				case PLUGIN:
					ret += prefix + "插件名: " + CPluginMap::GetPlugin(pPlugin)->plugin_name;
					if (ParamList.size() != 0)
					{
						ret += prefix + "参数:\r\n";
						for (i = 0; i < ParamList.size(); ++i)
						{
							ret += ParamList[i].ToString(source, vars, level + 1);
						}
					}
					else
					{
						ret += "\r\n";
					}
					break;
				case OPERATION:
					if (NULL != pLeftOperand())
					{
						ret += pLeftOperand()->ToString(source, vars, level + 1);
					}
					ret += prefix + "    " + op;
					ret += "\r\n";
					if (NULL != pRightOperand())
					{
						ret += pRightOperand()->ToString(source, vars, level + 1);
					}
					break;
				default:
					break;
				}
				return ret;
			}
		};

        表达式就是用运算符穿起来的一组变量,总是可以拆解为“左操作数+运算符+右操作数”的形式(三元运算符没打算支持),比如“a+b+c”就可以拆解为:

  ----a+表达式

  --------b+c

        表达式总是有个值的,除非是函数调用,返回值为“void”。

二、表达式类型

			enum types { NULLEXPRESSION, CONSTANT, DEFINE, VARIABLE, FUNCTION, PLUGIN, OPERATION };

        这个枚举定义了表达式类型,包括:

  • 无类型 空的表达式,只是表达式结构的初始状态
  • 常量
  • 定义 定义变量
  • 变量
  • 函数 脚本里面定义的子函数
  • 插件 外部实现的自定义函数(包括内置函数)
  • 运算

        实际上这是一个递归的表达方式,一个运算最终会被拆解到变量、常量和函数,函数又会被拆解到插件和参数(每个参数是一个表达式)。

三、成员变量

        表达式具有如下几个通用成员变量:

类型名称用途
typestype类型
Variable::typesresult_type结果类型,仅在编译时使用
size_tsource_start在脚本中的起始位置
size_tsource_end在脚本中的结束位置

        其余参数视类型不同而分别使用。比如变量使用VariableName和m_variable,操作则使用op和Operands。函数和插件都要用到ParamList。

        user_p并没有实际使用。

四、计算结果类型

			Variable::types GetResultType(string& source, T_VARIABLE_S& vars)
			{
				Variable::types _resulttype = Variable::NULLVARIABLE;
				bool eva;
				switch (type)
				{
				case NULLEXPRESSION:
					_resulttype = Variable::NULLVARIABLE;
					break;
				case DEFINE:
					_resulttype = m_variable.type;
					break;
				case CONSTANT:
					_resulttype = m_variable.type;
					break;
				case VARIABLE:
					if (0 == VariableName.size())CException::Throw(__FILE__, __LINE__, source, source_start, "未声明的变量");
					if (NULL == vars.FindVariable(VariableName))
					{
						cout << VariableName << endl << vars.ToString() << endl;
						CException::Throw(__FILE__, __LINE__, source, source_start, "未声明的变量");
					}
					_resulttype = vars.FindVariable(VariableName)->type;
					break;
				case FUNCTION:
					if (NULL== pFunction)CException::Throw(__FILE__, __LINE__, source, source_start, "未声明的函数");
					_resulttype = pFunction->return_type;
					break;
				case PLUGIN:
					if (pPlugin.isNULL())CException::Throw(__FILE__, __LINE__, source, source_start, "未声明的插件");
					_resulttype = CPluginMap::GetPlugin(pPlugin)->plugin_return_type;
					break;
				case OPERATION:
					if (NULL == pLeftOperand() && NULL != pRightOperand())_resulttype = pRightOperand()->GetResultType(source, vars);
					else if (NULL != pLeftOperand() && NULL == pRightOperand())_resulttype = pLeftOperand()->GetResultType(source, vars);
					else if (NULL != pLeftOperand() && NULL != pRightOperand())
					{
						if ("=" == op || "+=" == op || "-=" == op || "*=" == op || "/=" == op || "%=" == op)eva = true;
						else eva = false;
						_resulttype = Variable::typeUpgrade(pLeftOperand()->GetResultType(source, vars), pRightOperand()->GetResultType(source, vars), eva);
						if (">" == op || "<" == op || ">=" == op || "<=" == op || "==" == op || "!=" == op || "||" == op || "&&" == op)
						{
							if (Variable::NULLVARIABLE != _resulttype)_resulttype = Variable::LONG;
						}
						if ("," == op)_resulttype = pRightOperand()->GetResultType(source, vars);
					}
					else CException::Throw(__FILE__, __LINE__, source, source_start, "左右操作数不能都没有");
					break;
				default:
					CException::Throw(__FILE__, __LINE__, source, source_start, "未知的表达式类型");
					break;
				}
				return _resulttype;
			}

        计算结果类型根据表达式类型不同而有不同的方法,左右操作数根据运算符得到结果类型。

五、编译时检查

			//setpp记录已经做过的++ --
			bool CheckExpression(string& source, T_VARIABLE_S& vars, long level, set<string >& setpp)
			{
				size_t i;
				string msg;
				Variable var;
				vector<Variable > _paramvars;//函数调用的参数

				if (DEFINE == type)
				{
					if (!vars.AddVariable(VariableName, m_variable))CException::Throw(__FILE__, __LINE__, source, source_start, "添加变量失败");
					//cout <<"添加变量 "<< VariableName << endl << vars.ToString() << endl;
				}

				result_type = GetResultType(source, vars);
				switch (type)
				{
				case NULLEXPRESSION:
					break;
				case DEFINE:
					if (0 == VariableName.size())CException::Throw(__FILE__, __LINE__, source, source_start, "未声明的变量");
					if (Variable::NULLVARIABLE == m_variable.type)CZException::Throw(__FILE__, __LINE__, source, source_start, "变量类型不能为NULLVARIABLE");
					if (Operands.size() > 1)CException::Throw(__FILE__, __LINE__, source, source_start, "变量定义最多有一个操作数");
					break;
				case CONSTANT:
					if (0 != VariableName.size())CException::Throw(__FILE__, __LINE__, source, source_start, "常量不应该有名字");
					if (Variable::NULLVARIABLE == m_variable.type)CException::Throw(__FILE__, __LINE__, source, source_start, "常量类型不能为NULLVARIABLE");
					break;
				case VARIABLE:
					if (0 == VariableName.size())CException::Throw(__FILE__, __LINE__, source, source_start, "未声明的变量");
					break;
				case FUNCTION:
					if (NULL==pFunction)CException::Throw(__FILE__, __LINE__, source, source_start, "未声明的函数");
					if (!pFunction->IsCompiled())CException::Throw(__FILE__, __LINE__, source, source_start, "子函数未能成功编译");
					if (pFunction->m_EnvVariables.size() != ParamList.size())CException::Throw(__FILE__, __LINE__, source, source_start, "函数参数个数错误");
					for (i = 0; i < ParamList.size(); ++i)
					{
						ParamList[i].CheckExpression(source, vars, 0, setpp);
					}
					break;
				case PLUGIN:
					if (pPlugin.isNULL())CException::Throw(__FILE__, __LINE__, source, source_start, "未声明的插件");
					_paramvars.reserve(ParamList.size());
					for (i = 0; i < ParamList.size(); ++i)
					{
						ParamList[i].CheckExpression(source, vars, 0, setpp);
						if (Expression::VARIABLE == ParamList[i].type && vars.FindVariable(ParamList[i].VariableName)->isconst)
						{
							_paramvars.push_back(*vars.FindVariable(ParamList[i].VariableName));
						}
						else
						{
							var.type = ParamList[i].result_type;
							_paramvars.push_back(var);
						}
					}
					if (!CPluginMap::GetPlugin(pPlugin)->CheckPlugin(_paramvars, user_p, msg))CException::Throw(__FILE__, __LINE__, source, source_start, msg.c_str());
					break;
				case OPERATION:
					//先检查左右表达式
					if (NULL != pLeftOperand())
					{
						pLeftOperand()->CheckExpression(source, vars, level + 1, setpp);
					}
					if (NULL != pRightOperand())
					{
						pRightOperand()->CheckExpression(source, vars, level + 1, setpp);
					}
					//检查操作是否合理
					if (NULL == pRightOperand())
					{//后缀
						if ("++" == op || "--" == op)
						{
							if (result_type != Variable::LONG)CException::Throw(__FILE__, __LINE__, source, source_start, "后缀++ --操作只能用于整数");
							if (Expression::VARIABLE != pLeftOperand()->type || vars.FindVariable(pLeftOperand()->VariableName)->isconst)CException::Throw(__FILE__, __LINE__, source, source_start, "后缀++ --操作只能用于变量");
							if (0 != level)CException::Throw(__FILE__, __LINE__, source, source_start, "后缀++ --操作只能作为独立语句使用,如'i++;'或'for(...;...;i++)',不能用于赋值或组合运算");
						}
						else
						{
							CException::Throw(__FILE__, __LINE__, source, source_start, "不支持的后缀操作");
						}
					}
					else if (NULL == pLeftOperand())
					{//前缀
						if ("-" == op || "+" == op)
						{
							if (result_type != Variable::DOUBLE && result_type != Variable::LONG)CException::Throw(__FILE__, __LINE__, source, source_start, "前缀+-操作只能用于数值");
						}
						else if ("!" == op)
						{
							if (result_type != Variable::LONG)CException::Throw(__FILE__, __LINE__, source, source_start, "前缀!操作只能用于整数");
						}
						else if ("++" == op || "--" == op)
						{
							if (result_type != Variable::LONG)CException::Throw(__FILE__, __LINE__, source, source_start, "前缀++ --操作只能用于整数");
							if (Expression::VARIABLE != pRightOperand()->type || vars.FindVariable(pRightOperand()->VariableName)->isconst)CException::Throw(__FILE__, __LINE__, source, source_start, "前缀++ --操作只能用于变量");
							if (setpp.find(pRightOperand()->VariableName) != setpp.end())
								CException::Throw(__FILE__, __LINE__, source, source_start, "前缀++ --操作每个语句对每个变量仅限使用一次(不区分++ --)");
							setpp.insert(pRightOperand()->VariableName);
						}
						else
						{
							CException::Throw(__FILE__, __LINE__, source, source_start, "不支持的前缀操作");
						}
					}
					else
					{//二元
						if ("+" == op || ">" == op || "<" == op || ">=" == op || "<=" == op || "==" == op || "!=" == op || "," == op)
						{
						}
						else if ("-" == op || "*" == op || "/" == op)
						{
							if (Variable::STRING == result_type)CException::Throw(__FILE__, __LINE__, source, source_start, "不能对字符串做-*/");
						}
						else if ("-=" == op || "*=" == op || "/=" == op)
						{
							if (Variable::STRING == result_type)CException::Throw(__FILE__, __LINE__, source, source_start, "不能对字符串做-*/");
							if (pLeftOperand()->type != Expression::VARIABLE || vars.FindVariable(pLeftOperand()->VariableName)->isconst)CException::Throw(__FILE__, __LINE__, source, source_start, "不能对常量赋值");
						}
						else if ("&&" == op || "||" == op)
						{
							if (Variable::STRING == result_type)CException::Throw(__FILE__, __LINE__, source, source_start, "不能对字符串做&& ||");
						}
						else if ("%" == op)
						{
							if (Variable::LONG != result_type)CException::Throw(__FILE__, __LINE__, source, source_start, "只能对整数做%");
						}
						else if ("%=" == op)
						{
							if (Variable::LONG != result_type)CException::Throw(__FILE__, __LINE__, source, source_start, "只能对整数做%");
							if (pLeftOperand()->type != Expression::VARIABLE || vars.FindVariable(pLeftOperand()->VariableName)->isconst)CException::Throw(__FILE__, __LINE__, source, source_start, "不能对常量赋值");
						}
						else if ("=" == op || "+=" == op)
						{
							if (pLeftOperand()->type != Expression::VARIABLE || vars.FindVariable(pLeftOperand()->VariableName)->isconst)CException::Throw(__FILE__, __LINE__, source, source_start, "不能对常量赋值");
						}
						else
						{
							CException::Throw(__FILE__, __LINE__, source, source_start, (op + " 不支持的操作").c_str());
						}

						if ("," != op)
						{
							if (Variable::NULLVARIABLE == result_type)CException::Throw(__FILE__, __LINE__, source, source_start, "操作符两边类型不匹配,不允许数值和字符串的自动转换");
						}
					}
					break;
				}
				return true;
			}

        这个函数在编译后检查是否存在语法问题。如果检查成功,起码在语法上是没有问题的。

六、执行

			bool ExecExpression(CZBScript const& script, T_VARIABLE_S& vars, Variable& ret, void* pe)const
			{
				size_t i;
				string msg;
				vector<Variable > _paramvars;//插件调用的参数
				Variable ret_left;
				Variable ret_right;
				ret.type = result_type;
				switch (type)
				{
				case NULLEXPRESSION:
					ret.type = Variable::NULLVARIABLE;
					break;
				case DEFINE:
					ret.type = Variable::NULLVARIABLE;
					vars.AddVariable(VariableName, m_variable);
					if (NULL != pLeftOperand())
					{
						pLeftOperand()->ExecExpression(script, vars, ret_left, pe);
						if (ret_left.isNull())script.Throw(__FILE__, __LINE__, "左操作数计算出错");
						ret = *(vars.FindVariable(VariableName)) = ret_left;
					}
					break;
				case CONSTANT:
					ret = m_variable;
					break;
				case VARIABLE:
					ret = *vars.FindVariable(VariableName);
					break;
				case FUNCTION:
					{
						T_VARIABLE_BLOCK tmpparams;
						tmpparams = pFunction->m_EnvVariables;
						if(tmpparams.size()!= ParamList.size())script.Throw(__FILE__, __LINE__, "函数参数个数错误");
						for (i = 0; i < ParamList.size(); ++i)
						{
							ParamList[i].ExecExpression(script, vars, ret, pe);
							tmpparams[i].second = ret;
						}
						
						T_VARIABLE_S tmpvars;
						tmpvars.FromParentVars(vars, pFunction->count_global_variable, &tmpparams);
						
						ret.type = result_type;
						if (!pFunction->ExeSentences(tmpvars, ret, pe))script.Throw(__FILE__, __LINE__, "函数执行出错");
					}
					break;
				case PLUGIN:
					_paramvars.reserve(ParamList.size());
					for (i = 0; i < ParamList.size(); ++i)
					{
						ParamList[i].ExecExpression(script, vars, ret, pe);
						_paramvars.push_back(ret);
					}
					ret.type = result_type;
					if (!CPluginMap::GetPlugin(pPlugin)->ExecFunction(_paramvars, user_p, ret, msg, pe))script.Throw(__FILE__, __LINE__, "插件执行出错");
					break;
				case OPERATION:
					//计算
					if (NULL == pRightOperand())
					{
						if ("++" == op)
						{
							ret = *vars.FindVariable(pLeftOperand()->VariableName);
							++vars.FindVariable(pLeftOperand()->VariableName)->lValue;
						}
						else if ("--" == op)
						{
							ret = *vars.FindVariable(pLeftOperand()->VariableName);
							--vars.FindVariable(pLeftOperand()->VariableName)->lValue;
						}
						else
						{
							script.Throw(__FILE__, __LINE__, "不支持的前缀操作");
						}
					}
					else if (NULL == pLeftOperand())
					{//前缀
						pRightOperand()->ExecExpression(script, vars, ret_right, pe);
						if (ret_right.isNull())script.Throw(__FILE__, __LINE__, "右操作数计算出错");
						if ("-" == op)
						{
							ret = -ret_right;
						}
						else if ("+" == op)
						{
							ret = ret_right;
						}
						else if ("++" == op)
						{
							++vars.FindVariable(pRightOperand()->VariableName)->lValue;
							ret = *vars.FindVariable(pRightOperand()->VariableName);
						}
						else if ("--" == op)
						{
							--vars.FindVariable(pRightOperand()->VariableName)->lValue;
							ret = *vars.FindVariable(pRightOperand()->VariableName);
						}
						else if ("!" == op)
						{
							ret = ret_right;
							ret.lValue = (0 == ret.lValue ? 1 : 0);
						}
						else
						{
							script.Throw(__FILE__, __LINE__, "不支持的前缀操作");
						}
					}
					else
					{//二元
						if ("||" == op)
						{//若前面为真则不计算后面
							pLeftOperand()->ExecExpression(script, vars, ret_left, pe);
							if (ret_left.isNull())script.Throw(__FILE__, __LINE__, "左操作数计算出错");
							if (ret_left.GetBool())ret = ret_left;
							else
							{
								pRightOperand()->ExecExpression(script, vars, ret_right, pe);
								if (ret_right.isNull())script.Throw(__FILE__, __LINE__, "右操作数计算出错");
								ret = ret_right;
							}
						}
						else
						{
							{
								//先计算左右表达式
								pLeftOperand()->ExecExpression(script, vars, ret_left, pe);
								if (ret_left.isNull())script.Throw(__FILE__, __LINE__, "左操作数计算出错");
								pRightOperand()->ExecExpression(script, vars, ret_right, pe);
								if (ret_right.isNull())script.Throw(__FILE__, __LINE__, "右操作数计算出错");
								else if ("+" == op)ret = ret_left + ret_right;
								else if ("-" == op)ret = ret_left - ret_right;
								else if ("*" == op)ret = ret_left * ret_right;
								else if ("/" == op)ret = ret_left / ret_right;
								else if ("%" == op)ret = ret_left % ret_right;
								else if (">" == op)ret = ret_left > ret_right;
								else if ("<" == op)ret = ret_left < ret_right;
								else if (">=" == op)ret = ret_left >= ret_right;
								else if ("<=" == op)ret = ret_left <= ret_right;
								else if ("==" == op)ret = ret_left == ret_right;
								else if ("!=" == op)ret = ret_left != ret_right;
								else if ("&&" == op)ret = ret_left && ret_right;
								else if ("=" == op)ret = *(vars.FindVariable(pLeftOperand()->VariableName)) = ret_right;
								else if ("+=" == op)ret = *(vars.FindVariable(pLeftOperand()->VariableName)) = ret_left + ret_right;
								else if ("-=" == op)ret = *(vars.FindVariable(pLeftOperand()->VariableName)) = ret_left - ret_right;
								else if ("*=" == op)ret = *(vars.FindVariable(pLeftOperand()->VariableName)) = ret_left * ret_right;
								else if ("/=" == op)ret = *(vars.FindVariable(pLeftOperand()->VariableName)) = ret_left / ret_right;
								else if ("%=" == op)ret = *(vars.FindVariable(pLeftOperand()->VariableName)) = ret_left % ret_right;
								else if ("," == op)
								{
									ret = ret_right;
								}
								else
								{
									script.Throw(__FILE__, __LINE__, "不支持的操作");
								}
							}
						}
						if (Variable::NULLVARIABLE == ret.type)script.Throw(__FILE__, __LINE__, "操作符两边类型不匹配");
					}
					break;
				}
				return true;
			}

        执行时仍然可能出错。

(这里是结束,但不是整个系列的结束)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

初级代码游戏

知识究竟是有价还是无价

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值