新聞中心
前言
都說程序員的三大浪漫是:操作系統(tǒng)、編譯原理、圖形學(xué);最后的圖形學(xué)確實(shí)是特定的專業(yè)領(lǐng)域,我們幾乎接觸不到,所以對我來說換成網(wǎng)絡(luò)更合適一些,最后再加上一個(gè)數(shù)據(jù)庫。

網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、成都小程序開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了科爾沁免費(fèi)建站歡迎大家使用!
這四項(xiàng)技術(shù)如果都能掌握的話那豈不是在 IT 行業(yè)橫著走了,加上這幾年互聯(lián)網(wǎng)行業(yè)越來越不景氣,越底層的技術(shù)就越不可能被替代;所以為了給自己的 30+ 危機(jī)留點(diǎn)出路,從今年上半年開始我就逐漸開始從頭學(xué)習(xí)編譯原理。
功夫不負(fù)有心人,經(jīng)過近一個(gè)月的挑燈夜戰(zhàn),每晚都在老婆的催促下才休息,克服了中途好幾次想放棄的沖動,終于現(xiàn)在完成了 GScript 一個(gè)預(yù)覽版。
預(yù)覽版的意思是語法結(jié)構(gòu)與整體設(shè)計(jì)基本完成,后續(xù)更新也不太會改動這部分內(nèi)容、但還缺少一些易用功能。
特性
首先來看看保留環(huán)節(jié), GScript 是如何編寫 hello world 的。
hello_world.gs:
println("hello world");gscript hello_world.gs
hello world
廢話說完了接下來重點(diǎn)聊聊 GScript 所支持的特性了。
后文會重點(diǎn)說明每一個(gè)特性。
例子
除了剛才提到的 hello world,再來看一個(gè)也是示例代碼經(jīng)常演示的打印斐波那契數(shù)列。
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());
}輸出結(jié)果如下:
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())
}
都是通過閉包變量實(shí)現(xiàn)的,同時(shí)也展示了 GScript 對閉包、函數(shù)的使用,后文詳細(xì)介紹閉包的用法。
語法
GScript 的語法與常見的 Java/Go 類似,所以上手非常簡單。
基本類型
先來看看基本類型,目前支持 int/string/float/bool 四種基本類型以及 nil 特殊類型。
變量聲明語法和 Java 類似:
int a=10;
string b,c;
float e = 10.1;
bool f = false;
個(gè)人覺得將類型放在前面,代碼閱讀起來會更清晰一些,當(dāng)然這也是個(gè)人喜好。
數(shù)組
// 聲明并初始化
int[] a={1,2,3};
println(a);
// 聲明一個(gè)空數(shù)組并指定大小
int[] table = [4]{};
println();
// 向數(shù)組 append 數(shù)據(jù)
a = append(a,4);
println(a);
for(int i=0;iprintln(a[i]);
}
// 通過下標(biāo)獲取數(shù)組數(shù)據(jù)
int b=a[2];
println(b);
其實(shí)嚴(yán)格來講這并不算是數(shù)組,因?yàn)樗牡讓邮怯?nbsp;Go 切片實(shí)現(xiàn)的,所以可以動態(tài)擴(kuò)容。
以這段代碼為例:
int[] a=[2]{};
println("數(shù)組大小:"+len(a));
a = append(a,1);
println("數(shù)組大小:"+len(a));
println(a);
a[0]=100;
println(a);輸出:
數(shù)組大小:2
數(shù)組大小:3
[1]
[1001]
Class
類的支持非常重要,是實(shí)現(xiàn)面向?qū)ο蟮幕A(chǔ),目前還未完全實(shí)現(xiàn)面向?qū)ο?,只?shí)現(xiàn)了數(shù)據(jù)與函數(shù)的封裝。
class ListNode{
int value;
ListNode next;
ListNode(int v, ListNode n){
value =v;
next = n;
}
}
// 調(diào)用構(gòu)造函數(shù)時(shí)不需要使用 new 關(guān)鍵字。
ListNode l1 = ListNode(1, nil);
// 使用 . 調(diào)用對象屬性或函數(shù)。
println(l1.value);缺省情況下 class 具有無參構(gòu)造函數(shù):
class Person{
int age=10;
string name="abc";
int getAge(){
return 100+age;
}
}
// 無參構(gòu)造函數(shù)
Person xx= Person();
println(xx.age);
assertEqual(xx.age, 10);
println(xx.getAge());
assertEqual(xx.getAge(), 110);得益于 class 的實(shí)現(xiàn),結(jié)合剛才的數(shù)組也可以定義出自定義類型的數(shù)組:
// 大小為 16 的 Person 數(shù)組
Person[] personList = [16]{};
函數(shù)
函數(shù)其實(shí)分為兩類:
- 普通的全局函數(shù)。
- 類的函數(shù)。
本質(zhì)上沒有任何區(qū)別,只是所屬范圍不同而已。
// 判斷鏈表是否有環(huán)
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);
這里演示了鏈表是否有環(huán)的一個(gè)函數(shù),只要有其他語言的使用基礎(chǔ),相信閱讀起來沒有任何問題。
add(int a){}當(dāng)函數(shù)沒有返回值時(shí),可以聲明為 void 或直接忽略返回類型。
閉包
閉包我認(rèn)為是非常有意思的一個(gè)特性,可以實(shí)現(xiàn)很靈活的設(shè)計(jì),也是函數(shù)式編程的基礎(chǔ)。
所以在 GScript 中函數(shù)是作為一等公民存在;因此 GScript 也支持函數(shù)類型的變量。
函數(shù)變量聲明語法如下:func typeTypeOrVoid '(' typeList? ')'
// 外部變量,全局共享。
int varExternal =10;
func int(int) f1(){
// 閉包變量對每個(gè)閉包單獨(dú)可見
int varInner = 20;
int innerFun(int a){
println(a);
int c=100;
varExternal++;
varInner++;
return varInner;
}
// 返回函數(shù)
return innerFun;
}
// f2 作為一個(gè)函數(shù)類型,接收的是一個(gè)返回值和參數(shù)都是 int 的函數(shù)。
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 是一個(gè)返回值,入?yún)⒍紴?int 的函數(shù)類型;所以后續(xù)可以直接當(dāng)做函數(shù)調(diào)用 f2(i).
例子中將閉包分別賦值給 f2 和 f3 變量,這兩個(gè)變量中的閉包數(shù)據(jù)也是互相隔離、互不影響的,所有基于這個(gè)特性甚至還是實(shí)現(xiàn)面向?qū)ο蟆?/p>
標(biāo)準(zhǔn)庫
標(biāo)準(zhǔn)庫源碼:https://github.com/crossoverJie/gscript/tree/main/internal
目前實(shí)現(xiàn)的標(biāo)準(zhǔn)庫并不多,這完全是一個(gè)體力活;基于現(xiàn)有的語法和基礎(chǔ)數(shù)據(jù)類型,幾乎可以實(shí)現(xiàn)大部分的數(shù)據(jù)結(jié)構(gòu)了,所以感興趣的朋友也歡迎來貢獻(xiàn)標(biāo)準(zhǔn)庫代碼;比如 Stack、Set 之類的數(shù)據(jù)結(jié)構(gòu)。
MapString
以這個(gè) MapString 為例:鍵值對都為 string 的 HashMap。
int count =100;
MapString m1 = MapString();
for (int i=0;istring key = i+"";
string value = key;
m1.put(key,value);
}
println(m1.getSize());
assertEqual(m1.getSize(),count);
for (int i=0;istring key = i+"";
string value = m1.get(key);
println("key="+key+ ":"+ value);
assertEqual(key,value);
}
使用起來和 Java 的 HashMap 類似,當(dāng)然他的實(shí)現(xiàn)源碼也是參考的 jdk1.7 的 HashMap。
由于目前并有一個(gè)類似于 Java 的 object 或者是 go 中的 interface{}, 所以如果需要存放 int,那還得實(shí)現(xiàn)一個(gè) MapInt,不過這個(gè)通用類型很快會實(shí)現(xiàn)。
內(nèi)置函數(shù)
int[] a={1,2,3};
// len 返回?cái)?shù)組大小
println(len(a));
// 向數(shù)組追加數(shù)據(jù)
a = append(a,4);
println(a);
// output: [1,2,3,4]
// 斷言函數(shù),不相等時(shí)會拋出運(yùn)行時(shí)異常,并中斷程序。
assertEqual(len(a),4);
// 返回 hashcode
int hashcode = hash(key);也內(nèi)置了一些基本函數(shù),當(dāng)然也這不是由 GScript 源碼實(shí)現(xiàn)的,而是編譯器實(shí)現(xiàn)的,所以新增起來要稍微麻煩一些;后續(xù)會逐步完善,比如和 IO 相關(guān)的內(nèi)置函數(shù)。
總結(jié)
現(xiàn)階段的 GScript 還有許多功能沒有完善,比如 JSON、網(wǎng)絡(luò)庫、更完善的語法檢查、編譯報(bào)錯(cuò)信息等;現(xiàn)在拿來刷刷 LeetCode 還是沒有問題的。
從這 65 個(gè) todo 就能看出還有很長的路要走,我對它的終極目標(biāo)就是可以編寫一個(gè)網(wǎng)站那就算是一個(gè)成熟的語言了。
目前還有一個(gè)問題是沒有集成開發(fā)環(huán)境,現(xiàn)在的開發(fā)體驗(yàn)和白板上寫代碼相差無異,所以后續(xù)有時(shí)間的話嘗試寫一個(gè) VS Code 的插件,至少能有語法高亮與提示。
最后對 GScript 或者是編譯原理感興趣的小伙伴可以加我微信一起交流。
本文名稱:終于實(shí)現(xiàn)了一門屬于自己的編程語言
文章網(wǎng)址:http://m.fisionsoft.com.cn/article/cdicppe.html


咨詢
建站咨詢
