Skip to content

Commit

Permalink
Merge pull request #31 from ValKmjolnir/develop
Browse files Browse the repository at this point in the history
📝 update docs and makefile
  • Loading branch information
ValKmjolnir authored Oct 7, 2023
2 parents d661a6b + 63b97fc commit d108e40
Show file tree
Hide file tree
Showing 14 changed files with 184 additions and 111 deletions.
80 changes: 50 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
* [__Difference__](#difference-between-andys-and-this-interpreter)
* [__Trace Back Info__](#trace-back-info)
* [__Debugger__](#debugger)
* [__REPL__](#repl)

__Contact us if having great ideas to share!__

Expand Down Expand Up @@ -613,19 +614,24 @@ that is really inconvenient.

Luckily, we have developed some useful native-functions to help you add modules that created by you.

After 2021/12/3, there are some new functions added to `lib.nas`:
Functions used to load dynamic libraries are added to `std/dylib.nas`:

```javascript
var dylib={
dlopen: func(libname){
...
},
dlclose: func(lib){return __dlclose; },
dlcall: func(ptr,args...){return __dlcallv},
limitcall: func(arg_size=0){
...
}
};
var dlopen = func(libname) {
...
}

var dlclose = func(lib) {
...
}

var dlcall = func(ptr, args...) {
...
}

var limitcall = func(arg_size = 0) {
...
}
```

As you could see, these functions are used to load dynamic libraries into the nasal runtime and execute.
Expand All @@ -636,21 +642,26 @@ First, write a cpp file that you want to generate the dynamic lib, take the `fib
```C++
// add header file nasal.h to get api
#include "nasal.h"
double fibonaci(double x){
if(x<=2)
double fibonaci(double x) {
if (x<=2) {
return x;
}
return fibonaci(x-1)+fibonaci(x-2);
}
// module functions' parameter list example
var fib(var* args,usize size,gc* ngc){
var fib(var* args, usize size, gc* ngc) {
if (!size) {
return nas_err("fib", "lack arguments");
}
// the arguments are generated into a vm_vec: args
// get values from the vector that must be used here
var num=args[0];
var num = args[0];
// if you want your function safer, try this
// nas_err will print the error info on screen
// and return vm_null for runtime to interrupt
if(num.type!=vm_num)
return nas_err("extern_fib","\"num\" must be number");
if(num.type!=vm_num) {
return nas_err("extern_fib", "\"num\" must be number");
}
// ok, you must know that vm_num now is not managed by gc
// if want to return a gc object, use ngc->alloc(type)
// usage of gc is the same as adding a native function
Expand All @@ -659,17 +670,17 @@ var fib(var* args,usize size,gc* ngc){

// then put function name and address into this table
// make sure the end of the table is {nullptr,nullptr}
mod_func func_tbl[]={
{"fib",fib},
{nullptr,nullptr}
module_func_info func_tbl[] = {
{"fib", fib},
{nullptr, nullptr}
};

// must write this function, this will help nasal to
// get the function pointer by name
// the reason why using this way to get function pointer
// is because `var` has constructors, which is not compatiable in C
// so "extern "C" var fib" may get compilation warnings
extern "C" mod_func get(){
extern "C" module_func_info* get() {
return func_tbl;
}
```
Expand All @@ -693,10 +704,11 @@ Windows(`.dll`):
Then we write a test nasal file to run this fib function, using `os.platform()` we could write a cross-platform program:
```javascript
var dlhandle=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib=dlhandle.fib;
for(var i=1;i<30;i+=1)
println(dylib.dlcall(fib,i));
import.std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
for(var i = 1; i<30; i+=1)
println(dylib.dlcall(fib, i));
dylib.dlclose(dlhandle.lib);
```

Expand All @@ -709,11 +721,12 @@ dylib.dlclose(dlhandle.lib);
`dylib.limitcall` is used to get `dlcall` function that has limited parameter size, this function will prove the performance of your code because it does not use `vm_vec` to store the arguments, instead it uses local scope to store them, so this could avoid frequently garbage collecting. And the code above could also be written like this:

```javascript
var dlhandle=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib=dlhandle.fib;
var invoke=dylib.limitcall(1); # this means the called function has only one parameter
for(var i=1;i<30;i+=1)
println(invoke(fib,i));
import.std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
for(var i = 1; i<30; i+=1)
println(invoke(fib, i));
dylib.dlclose(dlhandle.lib);
```

Expand Down Expand Up @@ -998,3 +1011,10 @@ vm stack (0x7fffd0259138 <sp+65>, limit 10, total 7)
```

</details>

## REPL

We added experimental repl interpreter in v11.0.
Use this command to use the repl interpreter:

> nasal -r
81 changes: 50 additions & 31 deletions doc/README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
* [__特殊之处__](#与andy解释器的不同之处)
* [__堆栈追踪信息__](#堆栈追踪信息)
* [__调试器__](#调试器)
* [__交互解释器__](#交互解释器)

__如果有好的意见或建议,欢迎联系我们!__

Expand Down Expand Up @@ -591,19 +592,24 @@ import("./dirname/dirname/filename.nas");
如果只有上文中那种方式来添加你自定义的函数到nasal中,这肯定是非常麻烦的。
因此,我们实现了一组实用的内置函数来帮助你添加你自己创建的模块。

在2021/12/3更新后,我们给`lib.nas`添加了下面的这一批函数:
用于加载动态库的函数在`std/dylib.nas`:

```javascript
var dylib={
dlopen: func(libname){
...
},
dlclose: func(lib){return __dlclose; },
dlcall: func(ptr,args...){return __dlcallv},
limitcall: func(arg_size=0){
...
}
};
var dlopen = func(libname) {
...
}

var dlclose = func(lib) {
...
}

var dlcall = func(ptr, args...) {
...
}

var limitcall = func(arg_size = 0) {
...
}
```

这些函数是用来加载动态库的,这样nasal解释器可以根据用户需求灵活加载动态库来执行。让我们看看这些函数该如何使用。
Expand All @@ -613,36 +619,41 @@ var dylib={
```C++
// 这个头文件得加上,因为我们需要拿到nasal的api
#include "nasal.h"
double fibonaci(double x){
if(x<=2)
double fibonaci(double x) {
if (x<=2) {
return x;
}
return fibonaci(x-1)+fibonaci(x-2);
}

// 模块函数的参数列表一律以这个为准
var fib(var* args,usize size,gc* ngc){
var fib(var* args, usize size, gc* ngc) {
if (!size) {
return nas_err("fib", "lack arguments");
}
// 传参会给予一个var指针,指向一个vm_vec的data()
var num=args[0];
var num = args[0];
// 如果你想让这个函数有更强的稳定性,那么一定要进行合法性检查
// nas_err会输出错误信息并返回错误类型让虚拟机终止执行
if(num.type!=vm_num)
return nas_err("extern_fib","\"num\" must be number");
if(num.type!=vm_num) {
return nas_err("extern_fib", "\"num\" must be number");
}
// vm_num作为普通的数字类型,不是内存管理的对象,所以无需申请
// 如果需要返回内存管理的对象,请使用ngc->alloc(type)
return var::num(fibonaci(num.tonum()));
}

// 然后将函数名字和函数地址放到一个表里,一定要记住表尾是{nullptr,nullptr}
mod_func func_tbl[]={
{"fib",fib},
{nullptr,nullptr}
module_func_info func_tbl[] = {
{"fib", fib},
{nullptr, nullptr}
};

// 必须实现这个函数, 这样nasal可以通过字符串名字获得函数指针
// 之所以用这种方式来获取函数指针, 是因为`var`是有构造函数的
// 有构造函数的类型作为返回值, 和C是不兼容的, 这导致
// 类似 "extern "C" var fib" 的写法会得到编译错误
extern "C" mod_func get(){
extern "C" module_func_info* get() {
return func_tbl;
}
```
Expand All @@ -667,10 +678,11 @@ Windows(`.dll`):
下面例子中`os.platform()`是用来检测当前运行的系统环境的,这样可以实现跨平台:
```javascript
var dlhandle=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib=dlhandle.fib;
for(var i=1;i<30;i+=1)
println(dylib.dlcall(fib,i));
import.std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
for(var i = 1; i<30; i+=1)
println(dylib.dlcall(fib, i));
dylib.dlclose(dlhandle.lib);
```

Expand All @@ -683,15 +695,16 @@ dylib.dlclose(dlhandle.lib);
`dylib.limitcall`用于获取使用固定长度传参的 `dlcall` 函数,这种函数可以提高你的程序运行效率,因为它不需要用 `vm_vec` 来存储传入参数,而是使用局部作用域来直接存储,从而避免了频繁调用可能导致的频繁垃圾收集。所以上面展示的代码同样可以这样写:

```javascript
var dlhandle=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib=dlhandle.fib;
var invoke=dylib.limitcall(1); # this means the called function has only one parameter
for(var i=1;i<30;i+=1)
println(invoke(fib,i));
import.std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
for(var i = 1; i<30; i+=1)
println(invoke(fib, i));
dylib.dlclose(dlhandle.lib);
```

如果接下来你看到了这个运行结果,恭喜你!
如果得到如下运行结果,恭喜你!

```bash
./nasal a.nas
Expand Down Expand Up @@ -963,3 +976,9 @@ vm stack (0x7fffd0259138 <sp+65>, limit 10, total 7)
```

</details>

## 交互解释器

v11.0 版本新增了交互式解释器 (REPL),使用如下命令开启:

> nasal -r
13 changes: 6 additions & 7 deletions makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
STD=c++17
OS := $(shell uname)
STD = c++17
OS = $(shell uname)
ifeq ($(OS), Darwin)
CXXFLAGS=-std=$(STD) -c -O3 -fno-exceptions -fPIC -mmacosx-version-min=10.15
CXXFLAGS = -std=$(STD) -c -O3 -fno-exceptions -fPIC -mmacosx-version-min=10.15
else
CXXFLAGS=-std=$(STD) -c -O3 -fno-exceptions -fPIC
CXXFLAGS = -std=$(STD) -c -O3 -fno-exceptions -fPIC
endif
CPPFLAGS=-I .

CPPFLAGS = -I .

NASAL_HEADER=\
src/ast_dumper.h\
Expand Down Expand Up @@ -82,7 +81,7 @@ build/main.o: $(NASAL_HEADER) src/main.cpp | build
build/nasal_misc.o: src/nasal.h src/nasal_misc.cpp | build
$(CXX) $(CXXFLAGS) src/nasal_misc.cpp -o build/nasal_misc.o

build/repl.o: src/nasal.h src/repl.h src/repl.cpp | build
build/repl.o: $(NASAL_HEADER) src/repl.h src/repl.cpp | build
$(CXX) $(CXXFLAGS) src/repl.cpp -o build/repl.o

build/nasal_err.o: src/nasal.h src/repl.h src/nasal_err.h src/nasal_err.cpp | build
Expand Down
2 changes: 1 addition & 1 deletion module/fib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ double fibonaci(double x) {

var fib(var* args, usize size, gc* ngc) {
if (!size) {
return nas_err("fib","lack arguments");
return nas_err("fib", "lack arguments");
}
var num = args[0];
return var::num(fibonaci(num.tonum()));
Expand Down
7 changes: 4 additions & 3 deletions module/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ dynamic_libs_dll = libfib.dll libkey.dll libnasock.dll libmat.dll
used_header = ../src/nasal.h ../src/nasal_gc.h
used_object = ../build/nasal_misc.o ../build/nasal_gc.o

STD=c++17
STD = c++17
OS = $(shell uname)
ifeq ($(OS), Darwin)
CXXFLAGS-std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15
CXXFLAGS = -std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15
else
CXXFLAGS=-std=$(STD) -c -O3 -fPIC
CXXFLAGS = -std=$(STD) -c -O3 -fPIC
endif

all: $(dynamic_libs_so)
Expand Down
4 changes: 3 additions & 1 deletion src/nasal.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <cmath>
#include <vector>

// abbreviation of some useful basic type
using i32 = std::int32_t;
using i64 = std::int64_t;
using u8 = std::uint8_t;
Expand All @@ -35,7 +36,8 @@ bool is_powerpc();
bool is_superh();



// virtual machine stack depth
// both global depth and value stack depth
const u32 STACK_DEPTH = 4096;

f64 hex2f(const char*);
Expand Down
2 changes: 1 addition & 1 deletion src/nasal_ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ class call_expr:public expr {
void set_first(expr* node) {first = node;}
void add_call(call* node) {calls.push_back(node);}
expr* get_first() {return first;}
std::vector<call*>& get_calls() {return calls;}
auto& get_calls() {return calls;}
void accept(ast_visitor*) override;
};

Expand Down
Loading

0 comments on commit d108e40

Please sign in to comment.