写一个中文编程语言:实现代码入口和注册寄存器

举报
码乐 发表于 2024/02/27 13:44:39 2024/02/27
【摘要】 5.2 实现 注册代码: 虚拟寄存器,把指令注册到寄存器上下文构造一个思想,如果时间太长就把注意力放在实践,它将改进理论思想,执行实践,如果时间太长则把注意力放在思想,它将改善理论思想。上下文是个啥东西,它帮助我们管理代码,它整理指令周围的信息,负责管理指令的执行范围,属于哪个环境,是否main入口。最重要的是,它管理着我们的最终指令组,一如以前 我们计划在这里解析的语句,组织为 二元组的...

6 实现 注册代码: 虚拟寄存器,把指令注册到寄存器上下文

构造一个思想,如果时间太长就把注意力放在实践,它将改进理论思想,
执行实践,如果时间太长则把注意力放在思想,它将改善理论思想。

上下文是个啥东西,它帮助我们管理代码,它整理指令周围的信息,负责管理指令的执行范围,属于哪个环境,是否main入口。

最重要的是,它管理着我们的最终指令组,一如以前 我们计划在这里解析的语句,组织为 二元组的 代码块。

[][2]string{{'IPUSH', '3'}, {'IPUSH', '4'}, {'IPUSH', '5'}, {'IMUL',''} {'IADD',''}   {'PRINTI'.''} }

因此,我们定义一个 TVMContext 上下文管理器,只要管理我们的二元代码块

	type TVMContext struct {  
		Code     [][2]string 
		Scope    string
	}

我们将代码范围默认指定为 global,并且提供把代码块注册到虚拟机VM的 机制。

	/*
	检测代码的顶级函数
	*/
	func GenerateTVMC(mode *tlink) *TVMContext {

		tcontext := MakeWVMContext("")
		for mode.size > 0 {

			_, statements := mode.MvTheOne()
			Datas := statements.GetNodeData()
			if Datas != nil { 
				Generate(Datas, tcontext) 
			}
		}

		tcontext.Code = append(tcontext.Code, [2]string{"HALT"})
		return tcontext
	}

识别代码语句,将其存储在TVMContext,Generate执行这个工作,但是我们并不知道下一个Node节点中Data的实际类型。
这里使用 any,以便 接受 其不同节点值的类型。

	/*
	@param:node 结构体实例, 比如 PrintStatement,
	*/
	func Generate(nodeData *Node, context *TVMContext) string {

		node = nodeData.Data

		switch nt := node.(type) {
		case *PrintStatement:

			val := node.(*PrintStatement)
			ty := Generate(val.Value, context)
			if ty == "int" {
				context.Code = append(context.Code, [2]string{"PRINTI"})
				return ""
			}
			return "" 
		case *Integer:

			val := node.(*Integer)
			context.Code = append(context.Code, [2]string{"IPUSH", val.Value})
			return "int"  
		case *BinOp:

			var rettype string
			var instr [2]string
			nod := node.(*BinOp)
			leftype := Generate(nod.Left, context)
			Generate(nod.Right, context)
			// fmt.Printf("right type:%#v \n", righttype)
			rettype = leftype
			if leftype == "int" { //整型计算
				if nod.Op == "+" || nod.Op == "PLUS" {
					instr = [2]string{"IADD", ""}
				} else if nod.Op == "-" || nod.Op == "MINUS" {
					instr = [2]string{"ISUB", ""}
				} else if nod.Op == "*" || nod.Op == "TIMES" {
					instr = [2]string{"IMUL", ""}
				} else if nod.Op == "/" || nod.Op == "DIVIDE" {
					instr = [2]string{"IDIV", ""}
				} else if nod.Op == "&&" || nod.Op == "LAND" {
					instr = [2]string{"AND", ""}
				} else if nod.Op == "||" || nod.Op == "LOR" {
					instr = [2]string{"OR", ""}
				}
			}
			context.Code = append(context.Code, instr)
			return rettype
		default:

			msg := fmt.Sprintf("Couldn't generate %#v with nt:%#v ", node, nt)
			panic(msg)
		}
		return ""
	}

依靠以上的实现,我们可以将代码语句转换为虚拟机可以匹配和执行的形式

[][2]string{{'IPUSH', '3'}, {'IPUSH', '4'}, {'IPUSH', '5'}, {'IMUL',''} {'IADD',''}   {'PRINTI'.''} }

没有太多神奇的地方,对吗? 确实如此,这里重在理解其工作方式。
有趣的是如果拥有大量 tvm. 这样每个最终将拥有大量函数,将指向 VM的代码置入 context中管理,并在不同ENV中选择执行有大量工作。

这有一个讨巧的方法,但是也节省了一些时间。
相反,我们创建了一个全局调度器解析 对象 TVM,并显式地使用,以检索虚拟机的全部函数并进行匹配和执行。

6.1 调度和执行指令:调度虚拟机_VirtualMachine 把指令集执行后结果返回到 VM 的堆栈

现在我们已经有了一组指令,还有了一些硬件执行措施,现在最需要的是调度和执行,比如这里的执行者组织,简单易懂 就叫CallFunc。

同时由于这里的虚拟机是全局唯一的,因此,我们只需要顺序调度在上一节产生的指令,然后在虚拟机TVM执行即可。
这里没有堆栈跟踪,但是在发送错误时,可以查找到哪一行的报错。

我们认为这样的东西通常对刚开始更好。
当表达式不是按照用户直觉的顺序计算时——在不同的实现中有可能以不同的顺序! 可能会很痛苦。

现在我们已经解析完成表达式,只需要按顺序执行即可。 那就很简单了对吗

 	/*
	@param T 待调用结构体
	@return 返回它的函数 
 	*/
	func Methods[T any](tt T) []string {
		var t T
		val := reflect.ValueOf(&t)
		typ := val.Type() 
		var NamesMethod []string
		for i := 0; i < val.NumMethod(); i++ {
			NamesMethod = append(NamesMethod, typ.Method(i).Name)
		} 
		return NamesMethod
	}

	/*
	@param tys 虚拟机实例
	@param fcName 函数名称 
	@param refVals 
	@return 返回虚拟机实例, 调用任意结构体的某个函数,用于查看函数执行结果.
	*/
	func CallFuncs(tys TVM, fcName string, refVals []reflect.Value) TVM {
		ms := Methods(tys)
		for _, m := range ms {
			if m == fcName { 
				reflect.ValueOf(&tys).MethodByName(m).Call(refVals)
				break
			}
		}
		return tys
	}

把它嵌入到虚拟机上下文管理器中即可。
这是一个简单的实现,但它已经足够我们完成当前的任务。

7 组织计算的入口: 中文表达式计算器_Evaluating Expressions 基于堆的TVM 虚拟机

我们将把之前的分词器,解析器,虚拟机整合为一个入口,为了醒目,我们使用: 提醒使用者计算结果在哪里。

	var filePath string
	if len(os.Args) < 2 {
		filePath = "./testxen.bl"
	} else {
		filePath = os.Args[1]
	}
 
	modelLinked := comp.ParseFile(filePath)
 	code :=  GenerateTVM(modelLinked)
	tvm :=  MakeTVM()
 	fmt.Printf("\n:\n\n")
	tvm.Run(code)

这就是完整的中文编程语言。

我们完成了挑战,在三个章节里完成一个可用的中文编程语言,也许可称之为计算器更多人容易接受。

我们使用了一种基于解释器的方法,去实现了中文编程语言,必须承认,这才刚刚开始,还有更多值得尝试的内容。

8 写在最后: 前景:穷途末路了吗

在现在的人工智能时代,有些人类学家,语言学家认为,其计算机用以处理现有的字符流,字节流,
有序依次或并行地处理输入,在工程上取得了优秀的成绩,
回顾发展历史,其根本逻辑的变化很小,也许深度学习的方式算得一些变化。 
但是这并不能表示人们已经完全掌握了 人类的进化机制,学习机制,人们如何面对未知和学习未知的机制。

———— web summary 大会记

更新更快的量子计算机,在将来我们也许可以处理更多更复杂的 宇宙尺度的数据,其承载的物理介质有些变化。

究其演化本质,是否仍然在重复人们自己, 是否值得重复,是个值得思考的问题。
关于更多尝试和优化Optimizatio

	在未来我们可做的事情:
	字节码 更通用地接近硬件
	内存管理
	
 	控制流,惰性计算
 	需要面向对象吗?
 	哈希表,闭包
 	按需扫描,跳跃 goto
 	类型系统
		类型检查, 类型互感
 	超类,方法和实例化,泛型,全局,局部变量,可变参数和类型。
 	跨通用平台
 	纯函数式的
 	LSP编译器向导
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。