前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >M语言编程_所有编程语言大全

M语言编程_所有编程语言大全

作者头像
全栈程序员站长
发布于 2022-09-20 07:05:24
发布于 2022-09-20 07:05:24
13.1K00
代码可运行
举报
运行总次数:0
代码可运行

一直对技术有很强的兴趣,终于,决定要写自己的语言(m语言)。那就先从最简单的开始:解释执行器。

一套完整的语言包含的肯定不止解释执行器了,还要有编译器IDE,也就还要有语法高亮、智能提示等,不过还没学会那些,先搞个最基本的解释执行器。

思路如下:

  1. 定义好希望的语法(基本语句有:顺序执行、if语句、for语句、while语句、系统自有函数定义、用户函数定义、函数调用)
  2. 找一款词法语法解析器工具,让字符串流变成语法书(AST)
  3. 编写解释执行器
    1. 元数据收集
    2. 变量作用域定义、查找
    3. 解释执行

先设想我们的m语言语法要怎么牛b啊,比如下面这段demo语法代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
go 计算标准体重(年龄) { 体重:年龄*3; 体重; } 体重:10; a:10; a:输出(体重); b:25; a:100+10+b; 输出(a); (a==135)-> { a:a+a+a; 输出(a); } else { 输出(b); }; a:1; while a<10 ->{ a:a+2; 输出(a); }; 输出("WHILE OK"); repeat i from 0 to 100 step 10->{ 输出(i); } init->{ 输出("FOR INIT"); } onerror->{ 输出("FOR ERROR"); } finally->{ 输出("FOR FINALLY"); }; 输出('FOR OK'); a:10; 输出(计算标准体重(a));

很显然,第一个语句块是用户函数的定义方式,以”go”字符串为函数定义的开始,接着是常规的函数名称、参数、函数方法块。

剩下的大致上就是顺序执行了,其中穿插着一些循环语句等,repeat循环自定义的比较厉害,好叼。。。感觉。。真的好叼。。。。

每个语句以封号后缀结束、赋值以冒号来标识。

接着来看看基于ANTLR的词法定义:

m.g4:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
grammar m; import basic,function,assignStmt,ifStmt,forStmt,whileStmt; nomalStmt :assignStmt |ifStmt |forStmt |whileStmt ; declarationStmt :functionDeclare ; stmt :nomalStmt LS |declarationStmt ; program : stmt+ ;  

由于词法语法定义较多,不贴代码了,可以下载代码看全部的(基于ideas/需要安装antlr4插件)

接下来是时候让我们load进demo代码解析成AST树啦:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
String code=Utils.readTxtFile("F:\\BaiduYunDownload\\mLanguage(4)\\m_code2.m");//这个是放demo代码的文件 code=code.substring(1);//去掉第一个特殊字符 CharStream is = CharStreams.fromString(code);                 //antlr对象,读入字符串 mLexer lexer = new mLexer(is);                         //mLexer是antlr自动生成的一个词法类 CommonTokenStream tokens = new CommonTokenStream(lexer);         //antlr对象 mParser parser = new mParser(tokens);                     //mParser是antlr自动生成的一个此法解析类 mParser.ProgramContext tree=parser.program();                //program是入口规则,根规则 program program= NodeParser.parseProgram(tree);               //自己写的NodeParser类,需要一堆自定义的节点类型配合解析整棵AST树 mRuntime runtime=new mRuntime(program); runtime.plainInterpreter();                           //解释器执行 System.out.println(""); 

AST节点的定义:

demo代码构建成AST树的效果图(antlr插件中能看):

转换成为AST树后,剩下的就是编写解释执行器,其实相当于前端编译器。

主要步骤是3步:

  1. 收集元数据
  2. 定义变量作用域
  3. 语句块的解释执行
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void execute(program program) { //1. 先扫描函数定义,收集元数据  collectMetaData(program); //2. 变量作用域  walkAST4Variables(program); //3. 解释执行代码  runCode(program); }

1. 收集元数据,其实就是对自定义函数的收集,统一放到一个Dictionary里,以便到时候引用到了执行语句块(和参数的传递)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void collectMetaData(program program) { for(com.mckay.language.m.core.nodes.m.stmt stmt:program.stmts) if(stmt.declarationStmt!=null) this.userDefinedFunctionSymbols.defineMethod(stmt.declarationStmt.functionDeclare.functionIdentifier.getIdentifier(), stmt.declarationStmt.functionDeclare); } public class UserDefinedFunctionSymbols { private Dictionary<String, functionDeclare> methods=new Hashtable<>(); public functionDeclare getMethod(String identifier) { return methods.get(identifier); } public void defineMethod(String identifier, functionDeclare ast) { methods.put(identifier, ast); } }

functionDeclare是具体的node,属于AST中众多节点类型中的一种,代表函数声明节点。

2. 定义变量作用域,由于存在函数(自定义函数、系统自带函数),因此需要有变量Scope的概念,存在局部变量覆盖全局变量现象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void walkAST4Variables(program program) { program.VariableSymbols=globalVariableSymbol; for(com.mckay.language.m.core.nodes.m.stmt stmt:program.stmts) { stmt.VariableSymbols=program.VariableSymbols; if(stmt.declarationStmt!=null) { stmt.declarationStmt.VariableSymbols=stmt.VariableSymbols; VarWalker.walk(stmt.declarationStmt); } if(stmt.nomalStmt!=null) { stmt.nomalStmt.VariableSymbols=stmt.VariableSymbols; VarWalker.walk(stmt.nomalStmt); } } } public class VariableSymbol { private Dictionary<String, Variable> variables=new Hashtable<>(); private VariableSymbol parentVariableSymbol; public void setParentVariableSymbol(VariableSymbol parentVariableSymbol) { this.parentVariableSymbol=parentVariableSymbol; } public void defineVariable(String name, Variable variable) { variables.put(name, variable); } public void setValue(String name, Object value) { Variable variable=getVariable(name); variable.Value=value; } public Object getValue(String name) { Variable variable=getVariable(name); return variable.Value; } private Variable getVariable(String name) { List<String> keys=Collections.list(variables.keys()); if(keys.contains(name)) return this.variables.get(name); if(this.parentVariableSymbol!=null) return this.parentVariableSymbol.getVariable(name); throw new RuntimeException("变量未定义"); } }  

当局部变量中没有找到本地变量定义时,会根据parent关联向上找变量,直到为null。

3. 语句块的解释执行,这个可以说是最容易理解的地方了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void runCode(program program) { StmtExecutor executor=new StmtExecutor(this); for(com.mckay.language.m.core.nodes.m.stmt stmt:program.stmts) if(stmt.nomalStmt!=null) executor.execute(stmt.nomalStmt); }

StmtExecutor.execute(nomalStmt)会调用一系列子语句,如下图就一图就懂:

如上图中,针对expression是调用calc的,一堆calc,expression中套expression。

system built-in函数的定义,是通过NativeMethodNode.setCode来标识的,比如当前实现的code为OUTPUT,功能如下:System.out.print/Console.Write()

第一个红框是native node中判断code是哪个system built-in函数的编码代号

第二个红框是对应built-in函数的java语句执行。

demo m代码对应的解释执行输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
10 135 405 3 5 7 9 11 WHILE OK FOR INIT 0 10 20 30 40 50 60 70 80 90 100 FOR FINALLY FOR OK 30 ok  

代码下载(基于java)

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/167994.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
PHP 使用 nikic/php-parser 处理 AST
nikic/PHP-Parser 可以解析 PHP 代码并生成 AST,还支持修改 AST 再还原成PHP源码,从而实现元编程,可用来做 AOP 和静态代码检查等。Swoft 框架中 AOP 也是基于 PHP-parser 开发的。
菜皮日记
2023/12/18
2730
Reactjs开发自制编程语言Monkey的编译器:语法解析
前面章节中,我们完成了词法解析器的开发。词法解析的目的是把程序代码中的各个字符串进行识别分类,把不同字符串归纳到相应的分类中,例如数字构成的字符串统一归类为INTEGER, 字符构成的字符串,如果不是关键字的话,那么他们统一被归纳为IDENTIFIER。 例如下面这条语句: let foo = 1234; 语句经过词法解析器解析后,就会转变为: LET IDENTIFIER ASSIGN_SIGN INTEGER SEMI 完成上面工作后,词法解析器的任务就完成了,接下来就轮到词法解析器出场。词法解析器的作
望月从良
2018/07/19
9200
MyCat - 源代码篇(15)
对于有默认节点的schema,且不是show, describe, select @@之类的语句,则路由到默认的节点上。 对于show, describe, select @@之类的语句,利用查询信息路由方法算出路由。
干货满满张哈希
2021/04/12
3860
MyCat - 源代码篇(15)
用 go 实现 lua 虚拟机
下面依次介绍上面的一些步骤,本文旨在一篇文章写清楚大概流程,具体的细节将会忽略,实际的实现也会尽可能的简化,本文主要参考 自己动手实现 lua,和 gopher-lua
王磊-字节跳动
2020/12/27
2.1K0
Cobar源码分析之AST
Cobar是阿里开源的数据库中间件,关于它的介绍这里不再赘述,可以参考之前的文章《Cobar SQL审计的设计与实现》
龟仙老人
2021/07/07
7220
Cobar源码分析之AST
Rc-lang开发周记12 部分Parser
由于是由换行来分句,我觉得一个头疼的点在于要想清楚哪里要换行,想清楚这个parser都是由什么组成,然后拼接在一起。但是写到这里的时候我才想到如果表达式有多行(这个也是非常常见的情况)就支持不了了…以后再做支持吧,这个或许可以对于表达式单独添加换行的支持。
AkemiHomura
2023/04/07
1950
Rc-lang开发周记12 部分Parser
深入浅出:Go语言编译原理与过程解析
Go语言是一种静态强类型、编译型开发语言,编译器扮演着核心角色,它不仅负责将Go源代码转换成机器代码,还涉及代码的优化、错误检查和性能分析等关键环节。
windealli
2024/03/28
1.3K0
深入浅出:Go语言编译原理与过程解析
ChatGPT|AI自制编程语言-语法解析1
而本篇主要集中语义解析和AST树生成部分,还未实现求值(下一篇《语法解析1》实现求值功能)。
用户1904552
2025/02/27
670
ChatGPT|AI自制编程语言-语法解析1
TiDB SQL Parser 的实现
其中,SQL Parser的功能是把SQL语句按照SQL语法规则进行解析,将文本转换成抽象语法树(AST),这部分功能需要些背景知识才能比较容易理解,我尝试做下相关知识的介绍,希望能对读懂这部分代码有点帮助。
mazhen
2023/11/24
6270
TiDB SQL Parser 的实现
TiDB 源码阅读系列文章(二十三)Prepare/Execute 请求处理
在之前的一篇文章《TiDB 源码阅读系列文章(三)SQL 的一生》中,我们介绍了 TiDB 在收到客户端请求包时,最常见的 Command --- COM_QUERY 的请求处理流程。本文我们将介绍另外一种大家经常使用的 Command --- Prepare/Execute 请求在 TiDB 中的处理过程。
PingCAP
2019/01/04
9780
CPython源码阅读笔记(1)
目前 CPython 的开发已经迁移到了 Github 上,可以直接去 Github clone 对应的分支。 我们将基于 Python 2.7.13 版本, Linux x86_64 环境进行接下来的工作。 下载好代码以后以
鱼塘小咸鱼
2018/11/06
4.6K0
自己动手写编译器:通过语法编译构建语法树并实现中间代码生成
上一节我们手动构造了语法树,然后调用各个节点实现中间代码生成。语法树的构建由语法解析完成,本节我们要完成语法解析逻辑,在语法解析过程中构造语法树,然后再像上一节那样实现中间代码生成。
望月从良
2022/04/27
9540
自己动手写编译器:通过语法编译构建语法树并实现中间代码生成
PyTorch 源码解读之即时编译篇
来源丨https://zhuanlan.zhihu.com/p/361101354
BBuf
2021/07/01
1.2K0
PyTorch 源码解读之即时编译篇
Rc-lang开发周记14 重构与AST Visitor
本周先是解决了上周遗留下来的一个非常头疼的问题,之后重构了Token和AST的定义以及考虑了一下Visitor。之后也编写了建立符号表的代码以及一半转换到vm指令的代码,但是总觉得哪里不太对劲就先停了下来,后续确认无误了再一起拿出来讲。还学习了一些rust的实现方式,关于IR方面有更多了解以后有意向再单独出一篇文章讲解自己的一些了解
AkemiHomura
2023/04/07
2940
Rc-lang开发周记14 重构与AST Visitor
打破国外垄断,开发中国人自己的编程语言(1):编写解析表达式的计算器
本文是《打破国外垄断,开发中国人自己的编程语言》系列文章的第1篇。本系列文章的主要目的是教大家学会如何从零开始设计一种编程语言(marvel语言),并使用marvel语言开发一些真实的项目,如移动App、Web应用等。marvel语言可以通过下面3种方式运行:
蒙娜丽宁
2020/07/30
2.4K1
打破国外垄断,开发中国人自己的编程语言(1):编写解析表达式的计算器
Python Ast介绍及应用
Abstract Syntax Trees即抽象语法树。Ast是python源码到字节码的一种中间产物,借助ast模块可以从语法树的角度分析源码结构。此外,我们不仅可以修改和执行语法树,还可以将Source生成的语法树unparse成python源码。因此ast给python源码检查、语法分析、修改代码以及代码调试等留下了足够的发挥空间。
py3study
2020/02/10
2.3K1
(1)PHP内核 - 玩转php的编译与执行
曾几何时php一不小心闯入了我生活,php语法竟然和C语言那么莫名的相似,这是最初php给我的感受,当接触的php时间越来越多的时候,php也没有那般生涩难懂,但是偶尔一些的新的php 设计思想,也会思考许久,不知是从什么时候开始了php另一个世界。我想应该是从那次的类型转换开始的,"1e12"字符串类型在转化为数字类型变量时,不同的php版本下转换结果截然不同,有的就变成了数字1,有的却可以正常的识别为科学计数法10^12,在这个地方就已经悄悄的埋下了一枚种子。
猿哥
2019/07/10
1.9K0
自己动手写编译器:符号表及其实现
大家如果对c, c++, java有所了解,那么就会知道作用域这个概念。所谓作用域就是变量在一个范围内起作用,一旦出了既定范围,那么它就会失效。c,c++,java用{表示作用域的起始,用}表示作用域的结束。内层作用域的变量会覆盖上一层作用域的变量。例如在上面代码中最外层定义了两个变量,分别是int类型的x,和char类型的y,在内层作用域又定义了一个bool类型的同名变量y,它会覆盖外面的char类型y,在内层作用域访问y时,我们访问的是类型为bool的y,但由于内层作用域没有定义x,因此访问x时,它对应外层作用域的x,因此我们的任务是识别作用域,同时解析出变量在不同作用域中对应的类型。
望月从良
2022/04/27
1K0
自己动手写编译器:符号表及其实现
golang源码分析(18)添加一个新语句到Golang编译器内部
在Go中添加while语句是简单的,因为只需要简单的将while翻译为for。所以我们选择了一个更具有挑战性的任务:添加until。until与while相似,只是将判定条件改为了否定,意为“直到……”。例如:
golangLeetcode
2022/08/02
3530
golang源码分析(18)添加一个新语句到Golang编译器内部
基于ANTLR4的大数据SQL编辑器解析引擎实践|得物技术
随着得物离线业务的快速增长,为了脱离全托管服务的一些限制和享受技术发展带来的成本优化,公司提出了大数据Galaxy开源演进项目,将离线业务从全托管且封闭的环境迁移到一个开源且自主可控的生态系统中,而离线开发治理套件是Galaxy自研体系中一个核心的项目,在数据开发IDE中最核心的就是SQL编辑器,我们需要一个SQL解析引擎在SQL编辑提供适配得物自研Spark引擎的语法定义,实时语法解析,语法补全,语法校验等能力,结合业内dataworks和dataphin的实践,我们最终选用ANTLR作为SQL解析引擎底座。
得物技术
2025/03/06
2270
基于ANTLR4的大数据SQL编辑器解析引擎实践|得物技术
相关推荐
PHP 使用 nikic/php-parser 处理 AST
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验