bajdcc / jMiniLang

用Kotlin实现的编译器和虚拟机,并在此基础上构建操作系统。
http://files.cnblogs.com/files/bajdcc/jMiniLang-manual.pdf
MIT License
65 stars 20 forks source link
compiler java lambda layui multi-process parser spring-boot thymeleaf virtual-machine vuejs

jMiniLang - GLR Compiler and Virtual Machine (Kotlin)

Build status

设计思路:https://zhuanlan.zhihu.com/p/28540783

视频演示:https://www.bilibili.com/video/av13294962/

语法参考(LR状态转移表)

一言以蔽之,本项目涉及的思想包括:

一言以蔽之,本项目涉及的玩法包括:


jMiniLang is a simplified compiler/vm framework. Developed by bajdcc. PS. LR Analysis refers to VFS developed by vczh.

本项目是一个LR编译器、虚拟机一体化工程,并且对虚拟机进行了拓展,参考了操作系统设计的思想。

Features(特性)

  1. 词法分析阶段。Lexer which generates NFA and DFA.
  2. 语法分析、词法分析、制导翻译。Parser which implements LALR(1) Grammar with optional semantic action.
  3. 语义分析。Customized semantic analysis.
  4. 可打印语法树。Printable syntax tree.
  5. 基于栈的自定义指令集。Stack-based instruction design.
  6. Kotlin本地方法导入。Native method.
  7. 代码页导入/导出。Import and export of code page.
  8. 代码页序列化。Serializable code page.
  9. 匿名函数及闭包。Lambda functions and Closure.
  10. 语法/词法错误提示。Display grammar and semantic errors.
  11. 管道机制。Pipe.
  12. 多进程机制。Multiple process.
  13. 同步/异步执行代码。Load file with Sync/Async.
  14. 虚拟机。Virtual machine.
  15. 支持彩色界面。Support Colorful GUI.
  16. 函数式编程。Functional programming.
  17. LISP.
  18. 网络流。Socket stream.
  19. 虚拟文件系统。Save/Load file or VFS.
  20. 基于原型的类设计。Class prototype.
  21. Bash Interface.
  22. 数组/词典初始化。Array/Map initialize list.
  23. 异常机制。Try/Catch/Throw.
  24. 行为树。Behavior Tree, including PC network simulator.
  25. 用户级进程。RING 3 Process, including User Service, fork.
  26. 网页服务器。Web Server, including Online Compiler and Runner.
  27. C语言解析。CParser class on ModuleUser.

What it generates(产生)

Virtual Machine OS

An OS running on jMiniLang compiler and interpreter.

Now has commands:(现在主窗口支持的cmd命令)

Tasks:(使用方法如:@system halt

UI:(使用方法如:@ui on clock

Toggle UI:

Implemented IPC, usage:(微服务)

Utility:

Tests:(测试命令,直接在主窗口cmd输入,Ctrl-C中止)

Implemented MSG, usage:(远程控制)

PC command:

LINQ:

TASK PROC:

USER HANDLE:(用户级进程支持的句柄种类)

Dependencies:(使用的开源库,下面为部分)

Manual

Simplified Chinese Version

Example

Web Server

  1. Spring Boot API, port 8080
  2. Java NIO, port 8088
  3. Render Markdown using FlexMark

Front-end: LayUI(前端)

1. Spring Boot API

Front-end: LayUI + Vue.js

API: Json + RestController

Back-end: jMiniLang API Handler (RING 3 Process)

Run on Server

Online Compiler Example V: GUI User Window

Screenshot GUI-1

window.txt

import "user.base";
var w = g_window("test window");
var width = 800;
var height = 600;
var border = 10;
w."msg"(0, width, height); // CREATE
w."svg"('M', border, border);
w."svg"('L', width - border, border);
w."svg"('L', width - border, height - border);
w."svg"('L', border, height - border);
w."svg"('L', border, border);
w."svg"('M', border * 2, border * 2);
w."svg"('S', width - border * 4, height - border * 4);
w."str"(1, g_string_rep("Hello world! ", 20));
w."svg"('m', 0, 200);
w."str"(1, g_string_rep("Hello world! ", 20));
w."svg"('m', 0, 200);
w."str"(0, g_string_rep("Hello world! ", 20));
g_sleep_s(1);
w."msg"(2, 0, 0); // WAIT FOR CLOSE

Online Compiler Example IV: Mutex

import "user.base";

var channel = g_pipe("TEST-MUTEX");
var goods = g_share("TEST-MUTEX#GOOD", g_from([]));
var index = g_share("TEST-MUTEX#INDEX", 0);
g_create_dir("/example-mutex");

var new_id = func ~() -> index."set!"(lambda(a) -> a++);
var enqueue = func ~(id) -> goods."get!"(lambda(a) -> a."push"(id));
var dequeue = func ~() -> goods."get!"(lambda(a) -> a."pop"());

var consumer_id = func ~(id) -> "/example-mutex/consumer-" + id;
var producer_id = func ~(id) -> "/example-mutex/producer-" + id;

var consumer = func ~(id) {
    var obj;
    var now = g_get_timestamp();
    channel."writeln"("消费者 #" + id + " 已启动");
    foreach (var i : g_range(1, 5)) {
        while (g_is_null(obj := dequeue())) {}
        channel."writeln"("消费者 #" + id + " 收到:" + obj);
    }
    channel."writeln"("消费者 #" + id + " 已退出");
    var span = g_get_timestamp() - now;
    g_write_file(consumer_id(id), "消费者 #" + id + " 用时 " + span + "ms", true, true);
};

var producer = func ~(id) {
    var obj;
    var now = g_get_timestamp();
    channel."writeln"("生产者 #" + id + " 已启动");
    foreach (var i : g_range(1, 5)) {
        enqueue(obj := new_id());
        channel."writeln"("生产者 #" + id + " 发送:" + obj);
    }
    channel."writeln"("生产者 #" + id + " 已退出");
    var span = g_get_timestamp() - now;
    g_write_file(producer_id(id), "生产者 #" + id + " 用时 " + span + "ms", true, true);
};

var child = false;

foreach (var i : g_range(1, 5)) {
    if (g_fork() == -1) {
        consumer(i);
        child := true;
        break;
    }
    if (g_fork() == -1) {
        producer(i);
        child := true;
        break;
    }
}

if (child) { return; }

if (g_fork() == -1) {
    var i = 0;
    while (i < 10) {
        foreach (var id : g_range(1, 5)) {
            if (g_query_file(consumer_id(id)) == 1) {
                i++;
                channel."writeln"(g_read_file(consumer_id(id)));
                g_delete_file(consumer_id(id));
            }
            if (g_query_file(producer_id(id)) == 1) {
                i++;
                channel."writeln"(g_read_file(producer_id(id)));
                g_delete_file(producer_id(id));
            }
        }
    }
    channel."write"(g_noop_true);
    g_delete_file("/example-mutex");
    return;
}

channel."pipe"(g_system_output());

Output:

运行成功!PID:24
消费者 #1 已启动
生产者 #1 已启动
消费者 #2 已启动
生产者 #2 已启动
消费者 #3 已启动
生产者 #3 已启动
消费者 #4 已启动
生产者 #4 已启动
消费者 #5 已启动
生产者 #5 已启动
生产者 #1 发送:1
消费者 #2 收到:1
生产者 #2 发送:2
消费者 #3 收到:2
生产者 #3 发送:3
...
消费者 #3 已退出
生产者 #4 发送:19
消费者 #4 收到:19
消费者 #4 已退出
生产者 #5 发送:20
消费者 #5 收到:20
消费者 #5 已退出
生产者 #1 发送:21
生产者 #1 已退出
消费者 #1 收到:21
消费者 #1 已退出
生产者 #2 发送:22
生产者 #2 已退出
生产者 #3 发送:23
生产者 #3 已退出
生产者 #4 发送:24
生产者 #4 已退出
生产者 #5 发送:25
生产者 #5 已退出
消费者 #2 收到:22
消费者 #2 收到:23
消费者 #2 收到:24
消费者 #2 收到:25
消费者 #2 已退出
生产者 #1 用时 106ms
消费者 #2 用时 131ms
生产者 #2 用时 107ms
消费者 #3 用时 91ms
生产者 #3 用时 104ms
消费者 #4 用时 88ms
生产者 #4 用时 101ms
消费者 #5 用时 89ms
生产者 #5 用时 100ms
消费者 #1 用时 108ms

正常退出

Online Compiler Example III: Fork

Fork support yield

import "user.base";

var channel = g_pipe("TEST-FORK");

var pid = g_null;
if ((pid := g_fork()) != -1) { // 父进程读取管道
    g_puts("父进程 PID:" + g_pid());
    g_puts("父进程 FORK 返回:" + pid);
    g_puts(channel, "读取管道:");
    channel."pipe"(g_system_output());
} else { // 子进程写入管道
    channel."writeln"("子进程 FORK 返回:" + pid);
    var range = yield ~() { // 枚举器
        for (var i = 0; i < 3; i++) {
            yield g_fork(); // 枚举返回值
        }
    };
    foreach (var i : range()) {
        var txt = "这是一条测试消息! PID:" + g_pid() + " 编号:" + i;
        channel."writeln"(txt);//写管道
        g_sleep_s(1);
    }
    channel."write"(g_noop_true);//发送管道关闭信号
}

Output:

运行成功!PID:24
父进程 PID:24
父进程 FORK 返回:25
class= system::pipe 字符串(system::pipe)
读取管道:
子进程 FORK 返回:-1
这是一条测试消息! PID:25 编号:26
这是一条测试消息! PID:26 编号:-1
这是一条测试消息! PID:32 编号:-1
这是一条测试消息! PID:33 编号:-1
这是一条测试消息! PID:25 编号:32
这是一条测试消息! PID:26 编号:33
这是一条测试消息! PID:32 编号:38
这是一条测试消息! PID:33 编号:39
这是一条测试消息! PID:38 编号:-1
这是一条测试消息! PID:39 编号:-1
这是一条测试消息! PID:40 编号:-1
这是一条测试消息! PID:41 编号:-1
这是一条测试消息! PID:25 编号:40
这是一条测试消息! PID:26 编号:41

正常退出

Online Compiler Example II: Pipe

Reader

import "user.base";

var channel = g_pipe("TEST");
g_puts(channel, "读取管道:");
channel."pipe"(g_system_output());//将管道重定向至输出流

Writer

import "user.base";

var channel = g_pipe("TEST");
g_puts(channel, "写入管道:");
for (var i = 0; i < 10; i++) {
    var txt = "这是一条测试消息! 编号:" + i;
    channel."write"(txt + g_endl);//写管道
    g_puts(txt);
    g_sleep_s(1);
}
g_puts();
channel."write"(g_noop_true);//发送管道关闭信号

Screenshot 108


Screenshot 107

Screenshot 106

Screenshot 107

Online Compiler Example I: Hanoi

hanoi.txt

import "user.base";
var move = func ~(i, x, y) ->
    g_puts(g_to_string(i) + ": " + g_to_string(x) + " -> " + g_to_string(y));
var h = call (func ~(f) ->
    call (func [
    "实现Y Combinator",
    "Y = f -> (x -> f x x) (x -> f x x)",
    "相关网页——https://www.cnblogs.com/bajdcc/p/5757410.html"
    ] ~(h) -> h(h))(
        lambda(x) -> lambda(i, a, b, c) ->
            call (f(x(x)))(i, a, b, c)))
(lambda(f) -> lambda(i, a, b, c) {
    if (i == 1) {
        move(i, a, c);
    } else {
        f(i - 1, a, c, b);
        move(i, a, c);
        f(i - 1, b, a, c);
    }
});
h(3, 'A', 'B', 'C');

Online Documentation

Screenshot 105

Screenshot 102

Screenshot 103

Back-end

api.txt


2. Java NIO

URTest.txt

Screenshot 101

User mode Screenshot 100

LINQ Example

URTest.txt

Bash Example

URTest.txt

Tail optimization (尾递归优化)

var g_tail_opt = func ["尾递归优化"] ~(fun, args) {
    var x = lambda(a) { throw a; };
    var fact = fun(x);
    for (;;) {
        try {
            return g_call_apply(fact, args);
        } catch (e) {
            args := e;
        }
    }
};

// Usage
g_printn("Factorial(10) = " + g_tail_opt(
    lambda(f) -> lambda(n, total) -> n <= 1 ? total : f([n - 1, total * n]),
    [10, 1]));
g_printn("Fibonacci(10) = " + g_tail_opt(
    lambda(f) -> lambda(n, a, total) -> n <= 1 ? total : f([n - 1, total, a + total]),
    [10, 0, 1]));

0. Class (Omitted 省略)

URTest.txt

1. Lambda: Y Combinator of Hanoi (见上面的例子)

Hidden, see Online Compiler Example I: Hanoi above.

2. Lambda: Trampoline (Omitted 省略)

3. List: LinkedList (Omitted 省略)

4. Multi-Process: Pipe (Omitted 省略)

5. Multi-Process: Consumer-Producer Model (生产者-消费者模型)

See online compiler example above. 见上面的例子。

6. Multi-Process: PC and Router (多进程,Omitted 省略)

7. Functional programming (函数式编程)

ModuleFunction.txt

以上省略的内容可见此README的历史版本。

Screenshot

Screenshot 1 - Code Screenshot 1

Screenshot 2 - Results Screenshot 2

Screenshot 3 - Y-Combinator Screenshot 3

Screenshot 4 - OS Virtual Machine with GUI Screenshot 4

Screenshot 5 - Remote window Screenshot 5

Screenshot 6 - Functional programming Screenshot 6

Screenshot 7 - 哲学家就餐

专栏:https://zhuanlan.zhihu.com/p/29008180

Screenshot 7

Screenshot 8 - LISP

专栏:https://zhuanlan.zhihu.com/p/29243574

Screenshot 8

Screenshot 9 - 网络流

专栏:https://zhuanlan.zhihu.com/p/32692408

Screenshot 9