网易首页 > 网易号 > 正文 申请入驻

终于实现了一门属于自己的编程语言

0
分享至

前言

都说程序员的三大浪漫是:操作系统、编译原理、图形学;最后的图形学确实是特定的专业领域,我们几乎接触不到,所以对我来说换成网络更合适一些,最后再加上一个数据库。

这四项技术如果都能掌握的话那岂不是在 IT 行业横着走了,加上这几年互联网行业越来越不景气,越底层的技术就越不可能被替代;所以为了给自己的 30+ 危机留点出路,从今年上半年开始我就逐渐开始从头学习编译原理。

功夫不负有心人,经过近一个月的挑灯夜战,每晚都在老婆的催促下才休息,克服了中途好几次想放弃的冲动,终于现在完成了 GScript 一个预览版。

预览版的意思是语法结构与整体设计基本完成,后续更新也不太会改动这部分内容、但还缺少一些易用功能。
特性

首先来看看保留环节, GScript 是如何编写hello world的。

hello_world.gs:

println("hello world");
❯ gscript hello_world.gs
hello world

废话说完了接下来重点聊聊GScript所支持的特性了。

例子

除了刚才提到的 hello world,再来看一个也是示例代码经常演示的打印斐波那契数列

void fib(){
int a = 0;
int b = 1;
int fibonacci(){
int c = a;
a = b;
b = a+c;
return c;
return fibonacci;
func int() f = fib();
for (int i = 0; i < 5; i++){
println(f());

输出结果如下:

0
1
1
2
3

整体写法与 Go 官方推荐的类似:https://go.dev/play/p/NeGuDahW2yP

// fib returns a function that returns
// successive Fibonacci numbers.
func fib() func() int {
a, b := 0, 1
return func() int {
a, b = b, a+b
return a

func main() {
f := fib()
// Function calls are evaluated left-to-right.
fmt.Println(f(), f(), f(), f(), f())

都是通过闭包变量实现的,同时也展示了GScript对闭包、函数的使用,后文详细介绍闭包的用法。

语法

GScript的语法与常见的Java/Go类似,所以上手非常简单。

基本类型

先来看看基本类型,目前支持int/string/float/bool四种基本类型以及nil特殊类型。

变量声明语法和Java类似:

int a=10;
string b,c;
float e = 10.1;
bool f = false;

个人觉得将类型放在前面,代码阅读起来会更清晰一些,当然这也是个人喜好。

数组// 声明并初始化
int[] a={1,2,3};
println(a);

// 声明一个空数组并指定大小
int[] table = [4]{};

println();
// 向数组 append 数据
a = append(a,4);
println(a);
for(int i=0;i println(a[i]);
}

// 通过下标获取数组数据
int b=a[2];
println(b);

其实严格来讲这并不算是数组,因为它的底层是用Go切片实现的,所以可以动态扩容。

以这段代码为例:

int[] a=[2]{};
println("数组大小:"+len(a));
a = append(a,1);
println("数组大小:"+len(a));
println(a);
a[0]=100;
println(a);

输出:

数组大小:2
数组大小:3
[100 1]
Class

类的支持非常重要,是实现面向对象的基础,目前还未完全实现面向对象,只实现了数据与函数的封装。

class ListNode{
int value;
ListNode next;
ListNode(int v, ListNode n){
value =v;
next = n;

// 调用构造函数时不需要使用 new 关键字。
ListNode l1 = ListNode(1, nil);

// 使用 . 调用对象属性或函数。
println(l1.value);

缺省情况下class具有无参构造函数:

class Person{
int age=10;
string name="abc";
int getAge(){
return 100+age;

// 无参构造函数
Person xx= Person();
println(xx.age);
assertEqual(xx.age, 10);
println(xx.getAge());
assertEqual(xx.getAge(), 110);

得益于class的实现,结合刚才的数组也可以定义出自定义类型的数组:

// 大小为 16 的 Person 数组
Person[] personList = [16]{};
函数

函数其实分为两类:

  • 普通的全局函数。

  • 类的函数。

本质上没有任何区别,只是所属范围不同而已。

// 判断链表是否有环
bool hasCycle(ListNode head){
if (head == nil){
return false;
if (head.next == nil){
return false;

ListNode fast = head.next;
ListNode slow = head;
bool ret = false;
for (fast.next != nil){
if (fast.next == nil){
return false;
}
if (fast.next.next == nil){
return false;
}
if (slow.next == nil){
return false;
}
if (fast == slow){
ret = true;
return true;
}

fast = fast.next.next;
slow = slow.next;
}
return ret;
}

ListNode l1 = ListNode(1, nil);
bool b1 =hasCycle(l1);
println(b1);
assertEqual(b1, false);

ListNode l4 = ListNode(4, nil);
ListNode l3 = ListNode(3, l4);
ListNode l2 = ListNode(2, l3);
bool b2 = hasCycle(l2);
println(b2);
assertEqual(b2, false);

l4.next = l2;
bool b3 = hasCycle(l2);
println(b3);
assertEqual(b3, true);

这里演示了链表是否有环的一个函数,只要有其他语言的使用基础,相信阅读起来没有任何问题。

add(int a){}

当函数没有返回值时,可以声明为 void 或直接忽略返回类型。
闭包

闭包我认为是非常有意思的一个特性,可以实现很灵活的设计,也是函数式编程的基础。

所以在GScript中函数是作为一等公民存在;因此GScript也支持函数类型的变量。

函数变量声明语法如下:func typeTypeOrVoid '(' typeList? ')'

// 外部变量,全局共享。
int varExternal =10;
func int(int) f1(){
// 闭包变量对每个闭包单独可见
int varInner = 20;
int innerFun(int a){
println(a);
int c=100;
varExternal++;
varInner++;
return varInner;
// 返回函数
return innerFun;

// f2 作为一个函数类型,接收的是一个返回值和参数都是 int 的函数。
func int(int) f2 = f1();
for(int i=0;i<2;i++){
println("varInner=" + f2(i) + ", varExternal=" + varExternal);
}
println("=======");
func int(int) f3 = f1();
for(int i=0;i<2;i++){
println("varInner=" + f3(i) + ", varExternal=" + varExternal);
}

最终输出如下:

0
varInner=21, varExternal=11
1
varInner=22, varExternal=12
0
varInner=21, varExternal=13
1
varInner=22, varExternal=14
func int(int) f2 = f1();

以这段代码为例:f2 是一个返回值,入参都为 int 的函数类型;所以后续可以直接当做函数调用f2(i).

例子中将闭包分别赋值给 f2 和 f3 变量,这两个变量中的闭包数据也是互相隔离、互不影响的,所有基于这个特性甚至还是实现面向对象。

关于闭包的实现,后续会单独更新一篇。

更多样例请参考:https://github.com/crossoverJie/gscript/tree/main/example

标准库

标准库源码:https://github.com/crossoverJie/gscript/tree/main/internal

目前实现的标准库并不多,这完全是一个体力活;基于现有的语法和基础数据类型,几乎可以实现大部分的数据结构了,所以感兴趣的朋友也欢迎来贡献标准库代码;比如StackSet之类的数据结构。

MapString

以这个MapString为例:键值对都为stringHashMap

int count =100;
MapString m1 = MapString();
for (int i=0;i string key = i+"";
string value = key;
m1.put(key,value);
println(m1.getSize());
assertEqual(m1.getSize(),count);

for (int i=0;i string key = i+"";
string value = m1.get(key);
println("key="+key+ ":"+ value);
assertEqual(key,value);
}

使用起来和JavaHashMap类似,当然他的实现源码也是参考的 jdk1.7 的HashMap

由于目前并有一个类似于 Java 的 object 或者是 go 中的 interface{}, 所以如果需要存放 int,那还得实现一个 MapInt,不过这个通用类型很快会实现。
内置函数int[] a={1,2,3};
// len 返回数组大小
println(len(a));

// 向数组追加数据
a = append(a,4);
println(a);
// output: [1,2,3,4]

// 断言函数,不相等时会抛出运行时异常,并中断程序。
assertEqual(len(a),4);

// 返回 hashcode
int hashcode = hash(key);

也内置了一些基本函数,当然也这不是由GScript源码实现的,而是编译器实现的,所以新增起来要稍微麻烦一些;后续会逐步完善,比如和 IO 相关的内置函数。

总结

现阶段的GScript还有许多功能没有完善,比如 JSON、网络库、更完善的语法检查、编译报错信息等;现在拿来刷刷LeetCode还是没有问题的。

从这 65 个 todo 就能看出还有很长的路要走,我对它的终极目标就是可以编写一个网站那就算是一个成熟的语言了。

目前还有一个问题是没有集成开发环境,现在的开发体验和白板上写代码相差无异,所以后续有时间的话尝试写一个 VS Code 的插件,至少能有语法高亮与提示。

最后对GScript或者是编译原理感兴趣的小伙伴可以加我微信一起交流。

项目源码:https://github.com/crossoverJie/gscript

下载地址:https://github.com/crossoverJie/gscript/releases/tag/v0.0.6

开源是不是一种有利的经营手段?

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
缪昌文,重返江苏履新

缪昌文,重返江苏履新

鲁中晨报
2024-06-19 22:56:03
阿森西奥宣布与妻子离婚,两人去年7月刚完成婚礼

阿森西奥宣布与妻子离婚,两人去年7月刚完成婚礼

文明娱乐探索
2024-06-12 09:29:39
下下签!巴黎奥运中国女排被抽到死亡之组,2大劲敌围剿中国女排

下下签!巴黎奥运中国女排被抽到死亡之组,2大劲敌围剿中国女排

体坛知识分子
2024-06-19 19:26:50
上海市民叫苦:有些地方确实很坑!被吐槽的“长实线”到底该不该设,如何设?记者多方调查→

上海市民叫苦:有些地方确实很坑!被吐槽的“长实线”到底该不该设,如何设?记者多方调查→

上观新闻
2024-06-19 11:06:58
能否出战?姆巴佩回归训练场,鼻子缠了绷带但未戴护具

能否出战?姆巴佩回归训练场,鼻子缠了绷带但未戴护具

直播吧
2024-06-20 00:52:53
就在刚刚,中方正式下达“逐客令”,要求这国4天内必须离华!

就在刚刚,中方正式下达“逐客令”,要求这国4天内必须离华!

小乐讲故事
2023-05-17 09:52:08
黎巴嫩意外泄露的电子脉冲武器技术,让以色列高层深感困惑不已

黎巴嫩意外泄露的电子脉冲武器技术,让以色列高层深感困惑不已

橘色数码
2024-06-19 09:51:30
欧洲杯F组积分榜:土耳其居首葡萄牙暂列第2,格鲁吉亚垫底

欧洲杯F组积分榜:土耳其居首葡萄牙暂列第2,格鲁吉亚垫底

直播吧
2024-06-19 05:06:21
A股:2个消息来临,6月中下旬,A股或将重演22年历史?

A股:2个消息来临,6月中下旬,A股或将重演22年历史?

财经大拿
2024-06-20 00:55:02
失去中国国籍代价有多高?身价千亿依然是待宰的羔羊

失去中国国籍代价有多高?身价千亿依然是待宰的羔羊

枫冷慕诗
2024-06-18 19:09:58
一对情侣与领导吃烧烤,领导把男方灌醉,与女方去厕所偷偷接吻

一对情侣与领导吃烧烤,领导把男方灌醉,与女方去厕所偷偷接吻

一个岛岛
2024-06-18 22:52:05
61岁马旦曰落马!原任职单位多人被查

61岁马旦曰落马!原任职单位多人被查

上观新闻
2024-06-19 16:40:13
央行释放最新信号:个人活期存款、余额宝等或被纳入M1统计

央行释放最新信号:个人活期存款、余额宝等或被纳入M1统计

界面新闻
2024-06-19 11:40:00
千万别去意大利!一天被偷3次,到处衣不蔽体,炸药能过安检

千万别去意大利!一天被偷3次,到处衣不蔽体,炸药能过安检

青栀伊人
2024-06-17 22:04:27
死亡之组!中国女排巴黎奥运分组:与美国、塞尔维亚、法国同组

死亡之组!中国女排巴黎奥运分组:与美国、塞尔维亚、法国同组

直播吧
2024-06-19 19:20:08
抗日神剧八路军的伙食,不是海鲜就是法国菜,主打的就是一个上流

抗日神剧八路军的伙食,不是海鲜就是法国菜,主打的就是一个上流

附允历史观
2024-06-19 16:45:10
湖南一男子坐车时意外发现,6年前弟弟杀人案的死者依然活着

湖南一男子坐车时意外发现,6年前弟弟杀人案的死者依然活着

一个人讲故事
2024-04-23 20:17:39
三大消息:中方抓住“大鱼”;俄军不用打了?拜登向日本求救!

三大消息:中方抓住“大鱼”;俄军不用打了?拜登向日本求救!

日风的故事屋
2024-06-18 17:33:23
伤停15天姆巴佩报销!法国队变阵!40场9球混子首发,本泽马笑了

伤停15天姆巴佩报销!法国队变阵!40场9球混子首发,本泽马笑了

阿泰希特
2024-06-19 10:56:16
复旦法学院毕业典礼前多名教师曾寄语!有人勉励“和谐处世”

复旦法学院毕业典礼前多名教师曾寄语!有人勉励“和谐处世”

南方都市报
2024-06-19 23:32:04
2024-06-20 04:24:49
开源中国
开源中国
每天为开发者推送最新技术资讯
6335文章数 34226关注度
往期回顾 全部

科技要闻

618观察:谁为高强度的低价竞争买单?

头条要闻

丁进勇辞去越共中央政治局委员和河内市委书记职务

头条要闻

丁进勇辞去越共中央政治局委员和河内市委书记职务

体育要闻

欧洲杯最大的混子,非他莫属

娱乐要闻

黄一鸣“杀疯了” 直播间卖大葱养孩子

财经要闻

深化科创板改革 证监会发布八条措施

汽车要闻

双肾格栅变化大/内饰焕新 新一代宝马X3官图发布

态度原创

亲子
时尚
教育
公开课
军事航空

亲子要闻

宝宝看到对面小朋友们在打篮球也跟着模仿动作有模有样。

几个小物件,打造宅家时的「inner peace」

教育要闻

你好高校 | 对话北京航空航天大学

公开课

近视只是视力差?小心并发症

军事要闻

以色列涉嫌在加沙使用重型炸弹 或多次违反战争法

无障碍浏览 进入关怀版