It is said that the three major romances of programmers are: operating system, compilation principle, graphics; the last graphics is indeed a specific professional field, which we can hardly touch, so it is more suitable for me to switch to the network, and finally plus a database.

If these four technologies can be mastered, wouldn’t it be in the IT industry, and the Internet industry has become more and more sluggish in recent years, and the lower-level technologies are less likely to be replaced; so in order to give their 30+ The crisis leaves some way out. Since the first half of this year, I have gradually started to learn the principles of compilation from scratch.

The hard work pays off. After nearly a month of night battles, I rested every night under the urging of my wife, overcame the urge to give up several times in the middle, and finally completed a preview version of GScript.

The preview version means that the syntax structure and overall design are basically completed, and subsequent updates will not change this part of the content, but there are still some easy-to-use features missing.

Let’s first look at the reserved part, how GScript is written hello world of.

hello_world.gs:

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

After talking nonsense, let’s focus on talking GScript supported features.

Each of these features is highlighted below.

In addition to the hello world just mentioned, let’s look at another example code that is often demonstrated打印斐波那契数列.

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());
}

The output is as follows:

0
1
1
2
3

The overall writing is similar to the official recommendation of 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())
}

are implemented through closure variables, and also show GScript For the use of closures and functions, the usage of closures will be described in detail later.

GScript syntax and common Java/Go Similar, so getting started is very simple.

basic type

Let’s take a look at the basic types first, currently supported int/string/float/bool The four basic types and nil special type.

variable declaration syntax and Java similar:

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

Personally, I think putting the type in the front will make the code read more clearly, of course, this is also a personal preference.

array

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

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

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

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

In fact, this is not strictly an array, because its bottom layer is used Go Slicing is implemented, so it can be dynamically expanded.

Take this code as an example:

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

output:

数组大小:2
数组大小:3
[<nil> <nil> 1]
[100 <nil> 1]

Class

Class support is very important and is the basis for implementing object-oriented. At present, object-oriented has not been fully implemented, only the encapsulation of data and functions has been implemented.

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

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

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

By default class With a no-argument constructor:

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);

benefit from class The implementation of , combined with the array just now, can also define an array of custom types:

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

function

There are actually two types of functions:

  • Ordinary global function.
  • class function.

There is no difference in essence, only the scope is different.

// 判断链表是否有环
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);

Here is a function that demonstrates whether the linked list has a ring. As long as there is a basis for the use of other languages, I believe there is no problem in reading it.

add(int a){}

When a function has no return value, it can be declared void or simply ignore the return type.

Closure

I think closures are a very interesting feature that enables very flexible designs and is the foundation of functional programming.

so in GScript The middle function exists as a first-class citizen; therefore GScript Variables of function type are also supported.

The function variable declaration syntax is as follows: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);
}

The final output is as follows:

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();

Take this code as an example: f2 is a function type with a return value and input parameters are int; so it can be directly used as a function call in the future f2(i).

In the example, the closure is assigned to the f2 and f3 variables respectively. The closure data in these two variables is also isolated from each other and does not affect each other. All based on this feature, even object-oriented is implemented.

Regarding the implementation of closures, a separate article will be updated later.

For more examples, please refer to: https://github.com/crossoverJie/gscript/tree/main/example

Standard library source code: https://github.com/crossoverJie/gscript/tree/main/internal

There are not many standard libraries implemented at present, which is completely manual work; based on the existing grammar and basic data types, almost most data structures can be implemented, so interested friends are also welcome to contribute standard library code; for example Stack,Set data structures such as .

MapString

take this MapString For example: the key-value pairs are both string of HashMap.

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

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

use and Java of HashMap Similar, of course, his implementation source code is also the reference jdk1.7 HashMap.

Since there is currently no Java-like object or in go interface{}so if you need to store an int, you have to implement a MapInt, but this generic type will be implemented soon.

built-in function

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);

There are also some basic functions built in, of course, this is not caused by GScript It is implemented by the source code, but by the compiler, so it is a little more troublesome to add it; it will be gradually improved in the future, such as built-in functions related to IO.

current stage GScript There are still many functions that are not perfect, such as JSON, network library, more complete grammar check, compilation error information, etc.; now use it to brush LeetCode Still no problem.

From these 65 todos, it can be seen that there is still a long way to go, and my ultimate goal for it is to be able to write a website even if it is a mature language.

Another problem is that there is no integrated development environment. The current development experience is no different from writing code on a whiteboard, so if you have time in the future, try to write a VS Code plug-in, at least with syntax highlighting and prompts.

last pair GScript Or friends who are interested in the compilation principle can add me to WeChat to communicate.

Project source code: https://github.com/crossoverJie/gscript

Download address: https://github.com/crossoverJie/gscript/releases/tag/v0.0.6

#Finally #realized #programming #language #crossoverJies #personal #page #News Fast Delivery

Leave a Comment

Your email address will not be published. Required fields are marked *