[Golang]使用Golang从零开始设计实现一个自定义脚本指令语言

本文介绍了三种自制简易脚本解释器的方法:使用JSON、手写解析器及GoYACC。旨在实现通过文本文件控制Golang函数的调用,支持基本的并发与延时操作。

前言

    使用“语言”这么一个敏感的描述余自知不妥,但这像极了余当初对于这个需求的理解和印象,君莫见怪。其实,本文描述内容的最终形态其实是用GOYACC实现了一个简单的解释器:

解释器(英语:Interpreter),又译为直译器,是一种电脑程序,能够把高级编程语言一行一行直接转译运
行。解释器不会一次把整个程序转译出来,只像一位“中间人”,每次运行程序时都要先转成另一种语言再作运行,
因此解释器的程序运行速度比较缓慢。它每转译一行程序叙述就立刻运行,然后再转译下一行,再运行,如此不停
地进行下去.--------------《百度百科》

   为啥还要造轮子?现在不是有一大堆的脚本可以用吗?Lua毁天灭地,Python宇宙无敌不香吗?主要是因为好玩,其次是不需要我们的脚本是一门“编程语言”,诸如变量声明函数定义等等功能统统不需要,我就想安安静静的执行一串动作。

目标

    本问内容的目标:实现一个程序,使得其能够通过一个文本文件输入来随意调用指定的几个函数,例如,我们拥有如下Golang函数:

func ZMoveTo(target float32) {
	fmt.Println("ZMoveTo:", target)
	time.Sleep(time.Second)
	fmt.Println("Z done.")
}

func XMoveTo(target float32) {
	fmt.Println("XMoveTo:", target)
	time.Sleep(time.Second*3)
	fmt.Println("X done.")
}

func YMoveTo(target float32) {
	fmt.Println("YMoveTo:", target)
	time.Sleep(time.Second)
	fmt.Println("Y done.")
}

func Sleep(t int) {
	fmt.Println("sleeping...")
	time.Sleep(time.Duration(t)*time.Millisecond)
	fmt.Println("sleep done.")
}

我们想要随意地控制XYZ的移动,并添加适当的延时,如果可以,我们甚至能够允许多个方向同时移动:

1.先Z方向运动到0;
2.之后X和Y方向同时分别运动到50和100;
3.延时500ms;
4.Z方向运动到45.

在Golang中,我们这样写:

ZMoveT(0);

wg := sync.WaitGroup{}
wg.Add(2)
go func() {
    defer wg.Done()
    XMoveTo(50)
}
go func() {
    defer wg.Done()
    YMoveTo(100)
}
wg.Wait()

time.Sleep(time.Duration(500)*time.Millisecond)

ZMoveT(45);

    然后我们在某个地方嵌入这段代码,然后编译,最后得到二进制程序,执行后能够固定地运行我们的流程。这种方式做的事有如下特性:

1、仅Golang熟悉者能够自如地编写;
2、流程写死,需要改动流程必须要重新编写代码,不具备灵活性;
3、需要编译,需要重启程序,消耗时间。

    那么,如果有一种简单的脚本来安排这些流程就好了!我们的目标不也挺简单的不是吗?不需要声明,不需要返回,只有纯粹的函数执行。其实有很多种思路来实现,举个绕远路的例子:把上述函数封装成http api,然后javascript调用。js和html做的UI配合,实现动作的灵活编排不是什么难事。先不说复杂度,实现这一想法需要javascript和html,我没掌握,连熟悉都谈不上。然后需要浏览器,没有UI的命令行界面玩不起。

    所以下面介绍下我的几个实现。

一、用JSON实现

    既然前面提到了javascript,那么我立马就想到了json。json是格式非常简单的文本类型,只有键值对,对json的解析也十分便利,语法要求还省去了我们的脚本校验过程。这是我的实现方法:

   

指令json样子如下:
{
    "cmds":[
        {
            "cmd1":"ZMove",
            "pos1": 0
        },
        {
            "cmd1":"XMove",
            "cmd2":"YMove",
            "pos1": 50,
            "pos2": 100,
        },
            
        ...省略
    ]
}

实现原理:
    JSON端:利用json的有序array达到编排动作顺序的目的;然后利用object的键值对传递动作名和其参数。
    解析端:golang的struct可以直接解析json成员到自己的各个field上,极其便利地获取了动作名和相关
参数; 建立字符串类型的动作指令名与对应执行函数的映射:map, 其key为string,value为interface{},即对应函数本身。
  

    说得不知道请不清楚,所以直接上带注释而且必能够直接运行的例子:

//输入指令
[
  {
    "Cmd": [
      "XMoveTo"
    ],
    "Param": {
      "XMoveTo": 20
    }
  },
  {
    "Cmd": [
      "XMoveTo"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值