forked from xxq250/Nasal-Interpreter
Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
980350d70a | ||
|
|
0ccd3c9bd0 | ||
|
|
3e7ba4d774 | ||
|
|
a176022840 | ||
|
|
24a1e39ad3 | ||
|
|
a09c6ae2f9 | ||
|
|
2a85e92d4a | ||
|
|
92646840e4 | ||
|
|
c55ce758ed | ||
|
|
aa301aefc3 | ||
|
|
d6d90ab7c8 | ||
|
|
bf780514e6 | ||
|
|
eaa54035ff | ||
|
|
baa4f5a258 | ||
|
|
df24db5b58 | ||
|
|
4def93b4ad | ||
|
|
0a407437a4 | ||
|
|
05ab4640da | ||
|
|
b92eb4b089 | ||
|
|
5778d1e38d | ||
|
|
479e5a2c52 | ||
|
|
2f455c52c1 | ||
|
|
78c1f9b7a9 | ||
|
|
c68b4c5947 | ||
|
|
40344455e6 | ||
|
|
630c99c39a | ||
|
|
46716620e3 | ||
|
|
70a43c2f03 | ||
|
|
1923fc74e4 | ||
|
|
f0ae63bce5 | ||
|
|
30650bb64f | ||
|
|
d87aef82b7 | ||
|
|
e79d1eb8a4 | ||
|
|
189d49fa4a | ||
|
|
6a543f2aa7 | ||
|
|
c27c5b70ee | ||
|
|
0a246d2fc7 | ||
|
|
0956a08bec | ||
|
|
5a80258d20 | ||
|
|
85bb502191 | ||
|
|
ead49a657e | ||
|
|
df5be35af8 | ||
|
|
19d5952210 | ||
|
|
afd87da5e7 | ||
|
|
9861ecd03e | ||
|
|
aa191a9feb | ||
|
|
b8ef3cf6b6 | ||
|
|
0a8655eb4d | ||
|
|
52b49edbcf | ||
|
|
6a35c58df4 | ||
|
|
cd08b2d1bb | ||
|
|
f8e2918561 | ||
|
|
e4ea34db51 | ||
|
|
4bfce37f40 | ||
|
|
fd0d836c03 | ||
|
|
183446d32a | ||
|
|
540aeb73f4 | ||
|
|
4f0acc4d63 | ||
|
|
56280db2c7 | ||
|
|
885b57cd52 | ||
|
|
bbee31ea55 | ||
|
|
1bfa7d2638 | ||
|
|
d4a9412947 | ||
|
|
1b240b293e | ||
|
|
e41f728589 | ||
|
|
577546763f | ||
|
|
58ea303202 | ||
|
|
818685c48d | ||
|
|
5d13261516 | ||
|
|
56289b5d22 | ||
|
|
1733ac0573 |
34
.github/workflows/c-cpp.yml
vendored
Normal file
34
.github/workflows/c-cpp.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: C/C++ CI
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 16 * * *"
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: make
|
||||
run: make
|
||||
- name: Release file
|
||||
# You may pin to the exact commit or the version.
|
||||
# uses: djnicholson/release-action@e9a535b3eced09c460e07a84118fb74ae9b53236
|
||||
uses: marvinpinto/action-automatic-releases@v1.2.1
|
||||
with:
|
||||
# GitHub auth token
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Name of Release to add file to
|
||||
title: macOS Nightly build
|
||||
# Name of the tag for the release (will be associated with current branch)
|
||||
automatic_release_tag: next
|
||||
# File to release
|
||||
files: nasal
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -30,3 +30,7 @@
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
nasal
|
||||
.vscode
|
||||
dump
|
||||
395
lib.nas
395
lib.nas
@@ -1,149 +1,318 @@
|
||||
var import=func(filename)
|
||||
{
|
||||
# lib.nas
|
||||
|
||||
# import is used to link another file, this lib function will do nothing.
|
||||
# because nasal_import will recognize this and link files before generating bytecode.
|
||||
var import=func(filename){
|
||||
return __builtin_import(filename);
|
||||
}
|
||||
var print=func(elems...)
|
||||
{
|
||||
|
||||
# print is used to print all things in nasal, try and see how it works.
|
||||
# this function uses std::cout/printf to output logs.
|
||||
var print=func(elems...){
|
||||
return __builtin_print(elems);
|
||||
};
|
||||
var println=func(elems...)
|
||||
{
|
||||
}
|
||||
|
||||
# append is used to add values into a vector.
|
||||
var append=func(vec,elems...){
|
||||
return __builtin_append(vec,elems);
|
||||
}
|
||||
|
||||
# setsize is used to change the size of vector.
|
||||
# if the size is larger than before,
|
||||
# this function will fill vm_nil into uninitialized space.
|
||||
var setsize=func(vec,size){
|
||||
return __builtin_setsize(vec,size);
|
||||
}
|
||||
|
||||
# system has the same use in C.
|
||||
var system=func(str){
|
||||
return __builtin_system(str);
|
||||
}
|
||||
|
||||
# input uses std::cin and returns what we input.
|
||||
var input=func(){
|
||||
return __builtin_input();
|
||||
}
|
||||
|
||||
# split a string by delimiter for example:
|
||||
# split("ll","hello world") -> ["he","o world"]
|
||||
# this function will return a vector.
|
||||
var split=func(deli,str){
|
||||
return __builtin_split(deli,str);
|
||||
}
|
||||
|
||||
# rand has the same function as the rand in C
|
||||
# if seed is nil, it will return the random number.
|
||||
# if seed is not nil, it will be initialized by this seed.
|
||||
var rand=func(seed=nil){
|
||||
return __builtin_rand(seed);
|
||||
}
|
||||
|
||||
# id will return the pointer of an gc-object.
|
||||
# if this object is not managed by gc, it will return 0.
|
||||
var id=func(object){
|
||||
return __builtin_id(object);
|
||||
}
|
||||
|
||||
# int will get the integer of input number.
|
||||
# but carefully use it, because int has range between -2147483648~2147483647
|
||||
var int=func(val){
|
||||
return __builtin_int(val);
|
||||
}
|
||||
|
||||
# num will change all the other types into number.
|
||||
# mostly used to change a numerable string.
|
||||
var num=func(val){
|
||||
return __builtin_num(val);
|
||||
}
|
||||
|
||||
# pop used to pop the last element in a vector.
|
||||
# this function will return the value that poped if vector has element(s).
|
||||
# if the vector is empty, it will return nil.
|
||||
var pop=func(vec){
|
||||
return __builtin_pop(vec);
|
||||
}
|
||||
|
||||
# str is used to change number into string.
|
||||
var str=func(num){
|
||||
return __builtin_str(num);
|
||||
}
|
||||
|
||||
# size can get the size of a string/vector/hashmap.
|
||||
# in fact it can also get the size of number, and the result is the number itself.
|
||||
# so don't do useless things, though it really works.
|
||||
var size=func(object){
|
||||
return __builtin_size(object);
|
||||
}
|
||||
|
||||
# contains is used to check if a key exists in a hashmap/dict.
|
||||
var contains=func(hash,key){
|
||||
return __builtin_contains(hash,key);
|
||||
}
|
||||
|
||||
# delete is used to delete a pair in a hashmap/dict by key.
|
||||
var delete=func(hash,key){
|
||||
return __builtin_delete(hash,key);
|
||||
}
|
||||
|
||||
# keys is used to get all keys in a hashmap/dict.
|
||||
# this function will return a vector.
|
||||
var keys=func(hash){
|
||||
return __builtin_keys(hash);
|
||||
}
|
||||
|
||||
# time has the same function in C.
|
||||
var time=func(begin){
|
||||
return __builtin_time(begin);
|
||||
}
|
||||
|
||||
# die is a special native function.
|
||||
# use it at where you want the program to crash immediately.
|
||||
var die=func(str){
|
||||
return __builtin_die(str);
|
||||
}
|
||||
|
||||
# typeof is used to get the type of an object.
|
||||
# this function returns a string.
|
||||
var typeof=func(object){
|
||||
return __builtin_type(object);
|
||||
}
|
||||
|
||||
# substr will get the sub-string.
|
||||
# it gets the string, the begin index and sub-string's length as arguments.
|
||||
var substr=func(str,begin,len){
|
||||
return __builtin_substr(str,begin,len);
|
||||
}
|
||||
|
||||
# streq is used to compare if two strings are the same.
|
||||
var streq=func(a,b){
|
||||
return __builtin_streq(a,b);
|
||||
}
|
||||
|
||||
# left is used to get the sub-string like substr.
|
||||
# but the begin index is 0.
|
||||
var left=func(str,len){
|
||||
return __builtin_left(str,len);
|
||||
}
|
||||
|
||||
# right i used to get the sub-string like substr.
|
||||
# but the begin index is strlen-len.
|
||||
var right=func(str,len){
|
||||
return __builtin_right(str,len);
|
||||
}
|
||||
|
||||
# cmp is used to compare two strings.
|
||||
# normal string will not be correctly compared by operators < > <= >=
|
||||
# because these operators will turn strings into numbers then compare.
|
||||
var cmp=func(a,b){
|
||||
return __builtin_cmp(a,b);
|
||||
}
|
||||
|
||||
# chr is used to get the character by ascii-number.
|
||||
# for example chr(65) -> 'A'
|
||||
var chr=func(code){
|
||||
return __builtin_chr(code);
|
||||
}
|
||||
|
||||
# println has the same function as print.
|
||||
# but it will output a '\n' after using print.
|
||||
var println=func(elems...){
|
||||
__builtin_print(elems);
|
||||
elems=['\n'];
|
||||
return __builtin_print(elems);
|
||||
}
|
||||
var append=func(vec,elems...)
|
||||
{
|
||||
return __builtin_append(vec,elems);
|
||||
}
|
||||
var setsize=func(vec,size)
|
||||
{
|
||||
return __builtin_setsize(vec,size);
|
||||
}
|
||||
var system=func(str)
|
||||
{
|
||||
return __builtin_system(str);
|
||||
}
|
||||
var input=func()
|
||||
{
|
||||
return __builtin_input();
|
||||
}
|
||||
var sleep=func(duration)
|
||||
{
|
||||
return __builtin_sleep(duration);
|
||||
}
|
||||
var split=func(deli,str)
|
||||
{
|
||||
return __builtin_split(deli,str);
|
||||
}
|
||||
var rand=func(seed=nil)
|
||||
{
|
||||
return __builtin_rand(seed);
|
||||
}
|
||||
var id=func(object)
|
||||
{
|
||||
return __builtin_id(object);
|
||||
}
|
||||
var int=func(val)
|
||||
{
|
||||
return __builtin_int(val);
|
||||
}
|
||||
var num=func(val)
|
||||
{
|
||||
return __builtin_num(val);
|
||||
}
|
||||
var pop=func(vec)
|
||||
{
|
||||
return __builtin_pop(vec);
|
||||
}
|
||||
var str=func(num)
|
||||
{
|
||||
return __builtin_str(num);
|
||||
}
|
||||
var size=func(object)
|
||||
{
|
||||
return __builtin_size(object);
|
||||
}
|
||||
var contains=func(hash,key)
|
||||
{
|
||||
return __builtin_contains(hash,key);
|
||||
}
|
||||
var delete=func(hash,key)
|
||||
{
|
||||
return __builtin_delete(hash,key);
|
||||
}
|
||||
var keys=func(hash)
|
||||
{
|
||||
return __builtin_keys(hash);
|
||||
}
|
||||
var time=func(begin_time)
|
||||
{
|
||||
return __builtin_time(begin_time);
|
||||
}
|
||||
var die=func(str)
|
||||
{
|
||||
return __builtin_die(str);
|
||||
}
|
||||
var typeof=func(object)
|
||||
{
|
||||
return __builtin_type(object);
|
||||
}
|
||||
var substr=func(str,begin,len)
|
||||
{
|
||||
return __builtin_substr(str,begin,len);
|
||||
}
|
||||
var streq=func(a,b)
|
||||
{
|
||||
return __builtin_streq(a,b);
|
||||
}
|
||||
var left=func(str,len)
|
||||
{
|
||||
return __builtin_left(str,len);
|
||||
}
|
||||
var right=func(str,len)
|
||||
{
|
||||
return __builtin_right(str,len);
|
||||
}
|
||||
var cmp=func(a,b)
|
||||
{
|
||||
return __builtin_cmp(a,b);
|
||||
}
|
||||
var chr=func(code)
|
||||
{
|
||||
return __builtin_chr(code);
|
||||
}
|
||||
|
||||
var io=
|
||||
{
|
||||
fin: func(filename){return __builtin_fin(filename);},
|
||||
fout:func(filename,str){return __builtin_fout(filename,str);}
|
||||
SEEK_SET:0,
|
||||
SEEK_CUR:1,
|
||||
SEEK_END:2,
|
||||
# get content of a file by filename. returns a string.
|
||||
fin: func(filename){return __builtin_fin(filename);},
|
||||
# input a string as the content of a file.
|
||||
fout: func(filename,str){return __builtin_fout(filename,str);},
|
||||
# same as C fopen. open file and get the FILE*.
|
||||
open: func(filename,mode="r"){return __builtin_open(filename,mode);},
|
||||
# same as C fclose. close file by FILE*.
|
||||
close: func(filehandle){return __builtin_close(filehandle);},
|
||||
# same as C fread. read file by FILE*.
|
||||
read: func(filehandle,buf,len){return __builtin_read(filehandle,buf,len);},
|
||||
# same as C fwrite. write file by FILE*.
|
||||
write: func(filehandle,str){return __builtin_write(filehandle,str);},
|
||||
# same as C fseek. seek place by FILE*.
|
||||
seek: func(filehandle,pos,whence){return __builtin_seek(filehandle,pos,whence);},
|
||||
# same as C ftell.
|
||||
tell: func(filehandle){return __builtin_tell(filehandle);},
|
||||
# read file by lines. use FILE*.
|
||||
# get nil if EOF
|
||||
readln:func(filehandle){return __builtin_readln(filehandle);},
|
||||
# same as C stat.
|
||||
stat: func(filename){return __builtin_stat(filename);},
|
||||
# same as C feof. check if FILE* gets the end of file(EOF).
|
||||
eof: func(filehandle){return __builtin_eof(filehandle);}
|
||||
};
|
||||
|
||||
# get file status. using data from io.stat
|
||||
var fstat=func(filename){
|
||||
var s=io.stat(filename);
|
||||
return {
|
||||
st_dev: s[0],
|
||||
st_ino: s[1],
|
||||
st_mode: s[2],
|
||||
st_nlink:s[3],
|
||||
st_uid: s[4],
|
||||
st_gid: s[5],
|
||||
st_rdev: s[6],
|
||||
st_size: s[7],
|
||||
st_atime:s[8],
|
||||
st_mtime:s[9],
|
||||
st_ctime:s[10]
|
||||
};
|
||||
}
|
||||
|
||||
# functions that do bitwise calculation.
|
||||
# carefully use it, all the calculations are based on integer.
|
||||
var bits=
|
||||
{
|
||||
# xor
|
||||
bitxor: func(a,b){return __builtin_xor(a,b); },
|
||||
# and
|
||||
bitand: func(a,b){return __builtin_and(a,b); },
|
||||
# or
|
||||
bitor: func(a,b){return __builtin_or(a,b); },
|
||||
# nand
|
||||
bitnand: func(a,b){return __builtin_nand(a,b);},
|
||||
bitnot: func(a) {return __builtin_not(a); }
|
||||
# not
|
||||
bitnot: func(a) {return __builtin_not(a); },
|
||||
# get bit data from a special string. for example:
|
||||
# bits.fld(s,0,3);
|
||||
# if s stores 10100010(162)
|
||||
# will get 101(5).
|
||||
fld: func(str,startbit,len){return __builtin_fld;},
|
||||
# get sign-extended data from a special string. for example:
|
||||
# bits.sfld(s,0,3);
|
||||
# if s stores 10100010(162)
|
||||
# will get 101(5) then this will be signed extended to
|
||||
# 11111101(-3).
|
||||
sfld: func(str,startbit,len){return __builtin_sfld;},
|
||||
# set value into a special string to store it. little-endian, for example:
|
||||
# bits.setfld(s,0,8,69);
|
||||
# set 01000101(69) to string will get this:
|
||||
# 10100010(162)
|
||||
# so s[0]=162.
|
||||
setfld: func(str,startbit,len,val){return __builtin_setfld;},
|
||||
# get a special string filled by '\0' to use in setfld.
|
||||
buf: func(len){return __builtin_buf;}
|
||||
};
|
||||
|
||||
# mostly used math functions and special constants, you know.
|
||||
var math=
|
||||
{
|
||||
e: 2.7182818284590452354,
|
||||
pi: 3.14159265358979323846264338327950288,
|
||||
inf: 1/0,
|
||||
nan: 0/0,
|
||||
sin: func(x) {return __builtin_sin(x); },
|
||||
cos: func(x) {return __builtin_cos(x); },
|
||||
tan: func(x) {return __builtin_tan(x); },
|
||||
exp: func(x) {return __builtin_exp(x); },
|
||||
exp: func(x) {return __builtin_exp(x); },
|
||||
lg: func(x) {return __builtin_lg(x); },
|
||||
ln: func(x) {return __builtin_ln(x); },
|
||||
sqrt: func(x) {return __builtin_sqrt(x); },
|
||||
atan2: func(x,y){return __builtin_atan2(x,y);},
|
||||
inf: 1/0,
|
||||
nan: 0/0,
|
||||
isnan: func(x) {return __builtin_isnan(x); }
|
||||
};
|
||||
|
||||
var unix=
|
||||
{
|
||||
pipe: func(){die("not supported yet");},
|
||||
fork: func(){die("not supported yet");},
|
||||
dup2: func(fd0,fd1){die("not supported yet");},
|
||||
exec: func(filename,argv,envp){die("not supported yet");},
|
||||
waitpid: func(pid,nohang=0){die("not supported yet");},
|
||||
isdir: func(path){return bits.bitand(io.stat(path)[2],0x4000);}, # S_IFDIR 0x4000
|
||||
isfile: func(path){return bits.bitand(io.stat(path)[2],0x8000);}, # S_IFREG 0x8000
|
||||
opendir: func(path){return __builtin_opendir;},
|
||||
readdir: func(handle){return __builtin_readdir;},
|
||||
closedir: func(handle){return __builtin_closedir;},
|
||||
time: func(){return time(0);},
|
||||
sleep: func(secs){return __builtin_sleep(secs);},
|
||||
chdir: func(path){return __builtin_chdir(path);},
|
||||
environ: func(){die("not supported yet");},
|
||||
getcwd: func(){return __builtin_getcwd();},
|
||||
getenv: func(envvar){return __builtin_getenv(envvar);}
|
||||
};
|
||||
|
||||
# dylib is the core hashmap for developers to load their own library.
|
||||
var dylib=
|
||||
{
|
||||
# open dynamic lib.
|
||||
dlopen: func(libname){return __builtin_dlopen;},
|
||||
# load symbol from an open dynamic lib.
|
||||
dlsym: func(lib,sym){return __builtin_dlsym; },
|
||||
# close dynamic lib, this operation will make all the symbols loaded from it invalid.
|
||||
dlclose: func(lib){return __builtin_dlclose; },
|
||||
# call the loaded symbol.
|
||||
dlcall: func(funcptr,args...){return __builtin_dlcall}
|
||||
};
|
||||
|
||||
# os is used to use or get some os-related info/functions.
|
||||
# windows/macOS/linux are supported.
|
||||
var os=
|
||||
{
|
||||
# get a string that tell which os it runs on.
|
||||
platform: func(){return __builtin_platform;}
|
||||
};
|
||||
|
||||
# runtime gives us some functions that we could manage it manually.
|
||||
var runtime=
|
||||
{
|
||||
# do garbage collection manually.
|
||||
# carefully use it because using it frequently may make program running slower.
|
||||
gc: func(){return __builtin_gc;}
|
||||
};
|
||||
|
||||
# important global constants
|
||||
var D2R=math.pi/180;
|
||||
var FPS2KT=0.5925;
|
||||
var FT2M=0.3048;
|
||||
|
||||
304
main.cpp
304
main.cpp
@@ -1,144 +1,162 @@
|
||||
#include "nasal.h"
|
||||
|
||||
void help_cmd()
|
||||
{
|
||||
std::cout
|
||||
#ifdef _WIN32
|
||||
<<"use command \'chcp 65001\' if want to use unicode.\n"
|
||||
#endif
|
||||
<<"nasal [option]\n"
|
||||
<<"option:\n"
|
||||
<<" -h, --help | get help.\n"
|
||||
<<" -v, --version | get version of nasal interpreter.\n\n"
|
||||
<<"nasal [file]\n"
|
||||
<<"file:\n"
|
||||
<<" input file name to execute script file.\n\n"
|
||||
<<"nasal [option] [file]\n"
|
||||
<<"option:\n"
|
||||
<<" -l, --lex | view token info.\n"
|
||||
<<" -a, --ast | view abstract syntax tree.\n"
|
||||
<<" -c, --code | view bytecode.\n"
|
||||
<<" -e, --exec | execute script file.\n"
|
||||
<<" -t, --time | execute and get the running time.\n"
|
||||
<<" -o, --opcnt | count operands while running.\n"
|
||||
<<"file:\n"
|
||||
<<" input file name to execute script file.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
void logo()
|
||||
{
|
||||
std::cout
|
||||
<<" __ _ \n"
|
||||
<<" /\\ \\ \\__ _ ___ __ _| | \n"
|
||||
<<" / \\/ / _` / __|/ _` | | \n"
|
||||
<<" / /\\ / (_| \\__ \\ (_| | | \n"
|
||||
<<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
|
||||
<<"nasal interpreter ver 7.0\n"
|
||||
<<"thanks to : https://github.com/andyross/nasal\n"
|
||||
<<"code repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
|
||||
<<"code repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
|
||||
<<"lang info : http://wiki.flightgear.org/Nasal_scripting_language\n"
|
||||
<<"input \"nasal -h\" to get help .\n";
|
||||
return;
|
||||
}
|
||||
|
||||
void die(const char* stage,const std::string& filename)
|
||||
{
|
||||
std::cout<<"["<<stage<<"] in <"<<filename<<">: error(s) occurred,stop.\n";
|
||||
std::exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
void execute(const std::string& file,const std::string& command)
|
||||
{
|
||||
nasal_lexer lexer;
|
||||
nasal_parse parse;
|
||||
nasal_import import;
|
||||
nasal_codegen codegen;
|
||||
nasal_vm vm;
|
||||
lexer.openfile(file);
|
||||
lexer.scanner();
|
||||
if(lexer.get_error())
|
||||
die("lexer",file);
|
||||
if(command=="--lex" || command=="-l")
|
||||
{
|
||||
lexer.print_token();
|
||||
return;
|
||||
}
|
||||
parse.main_process(lexer.get_token_list());
|
||||
if(parse.get_error())
|
||||
die("parse",file);
|
||||
if(command=="--ast" || command=="-a")
|
||||
{
|
||||
parse.get_root().print_ast(0);
|
||||
return;
|
||||
}
|
||||
// first used file is itself
|
||||
import.link(parse.get_root(),file);
|
||||
if(import.get_error())
|
||||
die("import",file);
|
||||
codegen.main_progress(import.get_root(),import.get_file());
|
||||
if(codegen.get_error())
|
||||
die("code",file);
|
||||
if(command=="--code" || command=="-c")
|
||||
{
|
||||
codegen.print_byte_code();
|
||||
return;
|
||||
}
|
||||
vm.init(
|
||||
codegen.get_str_table(),
|
||||
codegen.get_num_table(),
|
||||
import.get_file()
|
||||
);
|
||||
if(command=="--exec" || command=="-e" || command=="--opcnt" || command=="-o")
|
||||
vm.run(codegen.get_exec_code(),command=="--opcnt" || command=="-o");
|
||||
else if(command=="--time" || command=="-t")
|
||||
{
|
||||
clock_t begin=clock();
|
||||
vm.run(codegen.get_exec_code(),false);
|
||||
std::cout<<"process exited after "<<((double)(clock()-begin))/CLOCKS_PER_SEC<<"s.\n";
|
||||
}
|
||||
vm.clear();
|
||||
return;
|
||||
}
|
||||
int main(int argc,const char* argv[])
|
||||
{
|
||||
std::string command,file;
|
||||
if(argc==2 && (!strcmp(argv[1],"-v") || !strcmp(argv[1],"--version")))
|
||||
logo();
|
||||
else if(argc==2 && (!strcmp(argv[1],"-h") || !strcmp(argv[1],"--help")))
|
||||
help_cmd();
|
||||
else if(argc==2 && argv[1][0]!='-')
|
||||
{
|
||||
file=argv[1];
|
||||
command="-e";
|
||||
execute(file,command);
|
||||
}
|
||||
else if(argc==3 &&
|
||||
(!strcmp(argv[1],"--lex") ||
|
||||
!strcmp(argv[1],"-l") ||
|
||||
!strcmp(argv[1],"--ast") ||
|
||||
!strcmp(argv[1],"-a") ||
|
||||
!strcmp(argv[1],"--code") ||
|
||||
!strcmp(argv[1],"-c") ||
|
||||
!strcmp(argv[1],"--exec") ||
|
||||
!strcmp(argv[1],"-e") ||
|
||||
!strcmp(argv[1],"--opcnt")||
|
||||
!strcmp(argv[1],"-o") ||
|
||||
!strcmp(argv[1],"--time") ||
|
||||
!strcmp(argv[1],"-t")))
|
||||
{
|
||||
file=argv[2];
|
||||
command=argv[1];
|
||||
execute(file,command);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout
|
||||
<<"invalid argument(s).\n"
|
||||
<<"use nasal -h to get help.\n";
|
||||
exit(1);
|
||||
}
|
||||
return 0;
|
||||
#include "nasal.h"
|
||||
|
||||
const uint32_t VM_LEXINFO =1;
|
||||
const uint32_t VM_ASTINFO =2;
|
||||
const uint32_t VM_CODEINFO =4;
|
||||
const uint32_t VM_EXECTIME =8;
|
||||
const uint32_t VM_OPCALLNUM=16;
|
||||
const uint32_t VM_EXEC =32;
|
||||
const uint32_t VM_DBGINFO =64;
|
||||
const uint32_t VM_DEBUG =128;
|
||||
const uint32_t VM_OPTIMIZE =256;
|
||||
|
||||
void help()
|
||||
{
|
||||
std::cout
|
||||
#ifdef _WIN32
|
||||
<<"use command \'chcp 65001\' if want to use unicode.\n"
|
||||
#endif
|
||||
<<"nasal <option>\n"
|
||||
<<"option:\n"
|
||||
<<" -h, --help | get help.\n"
|
||||
<<" -v, --version | get version of nasal interpreter.\n\n"
|
||||
<<"nasal <file>\n"
|
||||
<<"file:\n"
|
||||
<<" input file name to execute script file.\n\n"
|
||||
<<"nasal [options...] <file>\n"
|
||||
<<"option:\n"
|
||||
<<" -l, --lex | view token info.\n"
|
||||
<<" -a, --ast | view abstract syntax tree.\n"
|
||||
<<" -c, --code | view bytecode.\n"
|
||||
<<" -e, --exec | execute.\n"
|
||||
<<" -t, --time | execute and get the running time.\n"
|
||||
<<" -o, --opcnt | execute and count used operands.\n"
|
||||
<<" -d, --detail | execute and get detail crash info.\n"
|
||||
<<" | get garbage collector info if didn't crash.\n"
|
||||
<<" -op, --optimize| use optimizer(beta).\n"
|
||||
<<" | if want to use -op and run, please use -op -e/-t/-o/-d.\n"
|
||||
<<" -dbg, --debug | debug mode (this will ignore -t -o -d).\n"
|
||||
<<"file:\n"
|
||||
<<" input file name to execute script file.\n";
|
||||
}
|
||||
|
||||
void logo()
|
||||
{
|
||||
std::cout
|
||||
<<" __ _ \n"
|
||||
<<" /\\ \\ \\__ _ ___ __ _| | \n"
|
||||
<<" / \\/ / _` / __|/ _` | | \n"
|
||||
<<" / /\\ / (_| \\__ \\ (_| | | \n"
|
||||
<<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
|
||||
<<"nasal interpreter ver 8.0\n"
|
||||
<<"thanks to : https://github.com/andyross/nasal\n"
|
||||
<<"code repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
|
||||
<<"code repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
|
||||
<<"lang info : http://wiki.flightgear.org/Nasal_scripting_language\n"
|
||||
<<"input <nasal -h> to get help .\n";
|
||||
}
|
||||
|
||||
void err()
|
||||
{
|
||||
std::cout
|
||||
<<"invalid argument(s).\n"
|
||||
<<"use <nasal -h> to get help.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
void execute(const std::string& file,const uint32_t cmd)
|
||||
{
|
||||
// front end use the same error module
|
||||
nasal_err nerr;
|
||||
nasal_lexer lexer(nerr);
|
||||
nasal_parse parse(nerr);
|
||||
nasal_import linker(nerr);
|
||||
nasal_codegen gen(nerr);
|
||||
// back end
|
||||
nasal_vm vm;
|
||||
|
||||
// lexer scans file to get tokens
|
||||
lexer.scan(file);
|
||||
if(cmd&VM_LEXINFO)
|
||||
lexer.print();
|
||||
|
||||
// parser gets lexer's token list to compile
|
||||
parse.compile(lexer);
|
||||
// linker gets parser's ast and load import files to this ast
|
||||
linker.link(parse,file);
|
||||
if(cmd&VM_ASTINFO)
|
||||
parse.print();
|
||||
|
||||
// optimizer does simple optimization on ast
|
||||
if(cmd&VM_OPTIMIZE)
|
||||
optimize(parse.ast());
|
||||
|
||||
// code generator gets parser's ast and linker's import file list to generate code
|
||||
gen.compile(parse,linker);
|
||||
if(cmd&VM_CODEINFO)
|
||||
gen.print();
|
||||
|
||||
// run bytecode
|
||||
if(cmd&VM_DEBUG)
|
||||
{
|
||||
nasal_dbg debugger;
|
||||
debugger.run(gen,linker);
|
||||
}
|
||||
else if(cmd&VM_EXECTIME)
|
||||
{
|
||||
clock_t t=clock();
|
||||
vm.run(gen,linker,cmd&VM_OPCALLNUM,cmd&VM_DBGINFO);
|
||||
std::cout<<"process exited after "<<((double)(clock()-t))/CLOCKS_PER_SEC<<"s.\n";
|
||||
}
|
||||
else if(cmd&VM_EXEC)
|
||||
vm.run(gen,linker,cmd&VM_OPCALLNUM,cmd&VM_DBGINFO);
|
||||
}
|
||||
|
||||
int main(int argc,const char* argv[])
|
||||
{
|
||||
if(argc<=1)
|
||||
{
|
||||
logo();
|
||||
return 0;
|
||||
}
|
||||
if(argc==2)
|
||||
{
|
||||
std::string s(argv[1]);
|
||||
if(s=="-v" || s=="--version")
|
||||
logo();
|
||||
else if(s=="-h" || s=="--help")
|
||||
help();
|
||||
else if(s[0]!='-')
|
||||
execute(s,VM_EXEC);
|
||||
else
|
||||
err();
|
||||
return 0;
|
||||
}
|
||||
uint32_t cmd=0;
|
||||
for(int i=1;i<argc-1;++i)
|
||||
{
|
||||
std::string s(argv[i]);
|
||||
if(s=="--lex" || s=="-l")
|
||||
cmd|=VM_LEXINFO;
|
||||
else if(s=="--ast" || s=="-a")
|
||||
cmd|=VM_ASTINFO;
|
||||
else if(s=="--code" || s=="-c")
|
||||
cmd|=VM_CODEINFO;
|
||||
else if(s=="--exec" || s=="-e")
|
||||
cmd|=VM_EXEC;
|
||||
else if(s=="--opcnt" || s=="-o")
|
||||
cmd|=VM_OPCALLNUM|VM_EXEC;
|
||||
else if(s=="--time" || s=="-t")
|
||||
cmd|=VM_EXECTIME;
|
||||
else if(s=="--detail" || s=="-d")
|
||||
cmd|=VM_DBGINFO|VM_EXEC;
|
||||
else if(s=="--optimize" || s=="-op")
|
||||
cmd|=VM_OPTIMIZE;
|
||||
else if(s=="--debug" || s=="-dbg")
|
||||
cmd|=VM_DEBUG;
|
||||
else
|
||||
err();
|
||||
}
|
||||
execute(argv[argc-1],cmd);
|
||||
return 0;
|
||||
}
|
||||
34
makefile
Normal file
34
makefile
Normal file
@@ -0,0 +1,34 @@
|
||||
.PHONY=test
|
||||
nasal:main.cpp nasal_ast.h nasal_err.h nasal_builtin.h nasal_opt.h nasal_codegen.h nasal_gc.h nasal_import.h nasal_lexer.h nasal_parse.h nasal_vm.h nasal_dbg.h nasal.h
|
||||
clang++ -std=c++11 -O3 main.cpp -o nasal -fno-exceptions -ldl -Wshadow -Wall
|
||||
test:nasal
|
||||
./nasal -op -e test/ascii-art.nas
|
||||
./nasal -op -c test/bf.nas
|
||||
./nasal -op -c test/bfconvertor.nas
|
||||
./nasal -op -e -d test/bfs.nas
|
||||
./nasal -op -t test/bigloop.nas
|
||||
./nasal -op -e test/bp.nas
|
||||
./nasal -op -e -d test/calc.nas
|
||||
./nasal -op -e test/choice.nas
|
||||
./nasal -op -e test/class.nas
|
||||
./nasal -op -c test/exception.nas
|
||||
./nasal -op -t -d test/fib.nas
|
||||
./nasal -op -e test/filesystem.nas
|
||||
./nasal -op -e -d test/hexdump.nas
|
||||
./nasal -op -e test/json.nas
|
||||
./nasal -op -e test/leetcode1319.nas
|
||||
./nasal -op -e -d test/lexer.nas
|
||||
./nasal -op -e -d test/life.nas
|
||||
./nasal -op -t test/loop.nas
|
||||
./nasal -op -t -d test/mandel.nas
|
||||
./nasal -op -t -d test/mandelbrot.nas
|
||||
./nasal -op -c test/module_test.nas
|
||||
./nasal -op -e test/nasal_test.nas
|
||||
./nasal -op -t -d test/pi.nas
|
||||
./nasal -op -t -d test/prime.nas
|
||||
./nasal -op -t -d test/quick_sort.nas
|
||||
./nasal -op -e test/scalar.nas
|
||||
./nasal -op -e test/trait.nas
|
||||
./nasal -op -t -d test/turingmachine.nas
|
||||
./nasal -op -t -d test/ycombinator.nas
|
||||
|
||||
30
module/fib.cpp
Normal file
30
module/fib.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <iostream>
|
||||
#include "../nasal.h"
|
||||
|
||||
double fibonaci(double x){
|
||||
if(x<=2)
|
||||
return x;
|
||||
return fibonaci(x-1)+fibonaci(x-2);
|
||||
}
|
||||
extern "C" nasal_ref fib(std::vector<nasal_ref>& args,nasal_gc& gc){
|
||||
std::cout<<"[mod] this is the first test module of nasal\n";
|
||||
nasal_ref num=args[0];
|
||||
if(num.type!=vm_num)
|
||||
return builtin_err("extern_fib","\"num\" must be number");
|
||||
return {vm_num,fibonaci(num.to_number())};
|
||||
}
|
||||
extern "C" nasal_ref quick_fib(std::vector<nasal_ref>& args,nasal_gc& gc){
|
||||
std::cout<<"[mod] this is the first test module of nasal\n";
|
||||
nasal_ref num=args[0];
|
||||
if(num.type!=vm_num)
|
||||
return builtin_err("extern_quick_fib","\"num\" must be number");
|
||||
if(num.num()<2)
|
||||
return num;
|
||||
double a=1,b=1,res=0;
|
||||
for(double i=1;i<num.num();i+=1){
|
||||
res=a+b;
|
||||
a=b;
|
||||
b=res;
|
||||
}
|
||||
return {vm_num,res};
|
||||
}
|
||||
9
module/makefile
Normal file
9
module/makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
.PHONY=clean
|
||||
libfib.so: fib.cpp
|
||||
clang++ -c -O3 fib.cpp -fPIC -o fib.o
|
||||
clang++ -shared -o libfib.so fib.o
|
||||
libfib.dll: fib.cpp
|
||||
g++ -c -O3 fib.cpp -fPIC -o fib.o
|
||||
g++ -shared -o libfib.dll fib.o
|
||||
clean:
|
||||
rm *.o *.so *.dll *.dylib
|
||||
45
nasal.h
45
nasal.h
@@ -1,8 +1,6 @@
|
||||
#ifndef __NASAL_H__
|
||||
#define __NASAL_H__
|
||||
|
||||
#pragma GCC optimize(2)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
@@ -21,10 +19,16 @@
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
/*
|
||||
check if a string can be converted to a number
|
||||
if this string cannot be converted to a number,it will return nan
|
||||
*/
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
inline double hex_to_double(const char* str)
|
||||
{
|
||||
double ret=0;
|
||||
@@ -105,33 +109,34 @@ double str2num(const char* str)
|
||||
return is_negative?-ret_num:ret_num;
|
||||
}
|
||||
|
||||
/*
|
||||
show raw string
|
||||
*/
|
||||
void raw_string(const std::string& str)
|
||||
std::string rawstr(const std::string& str)
|
||||
{
|
||||
std::string ret("");
|
||||
for(auto i:str)
|
||||
switch(i)
|
||||
{
|
||||
case '\a': std::cout<<"\\a";break;
|
||||
case '\b': std::cout<<"\\b";break;
|
||||
case '\f': std::cout<<"\\f";break;
|
||||
case '\n': std::cout<<"\\n";break;
|
||||
case '\r': std::cout<<"\\r";break;
|
||||
case '\t': std::cout<<"\\t";break;
|
||||
case '\v': std::cout<<"\\v";break;
|
||||
case '\0': std::cout<<"\\0";break;
|
||||
default: std::cout<<i; break;
|
||||
case '\a': ret+="\\a";break;
|
||||
case '\b': ret+="\\b";break;
|
||||
case '\f': ret+="\\f";break;
|
||||
case '\n': ret+="\\n";break;
|
||||
case '\r': ret+="\\r";break;
|
||||
case '\t': ret+="\\t";break;
|
||||
case '\v': ret+="\\v";break;
|
||||
case '\0': ret+="\\0";break;
|
||||
default: ret+=i; break;
|
||||
}
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
#include "nasal_err.h"
|
||||
#include "nasal_lexer.h"
|
||||
#include "nasal_ast.h"
|
||||
#include "nasal_parse.h"
|
||||
#include "nasal_import.h"
|
||||
#include "nasal_opt.h"
|
||||
#include "nasal_gc.h"
|
||||
#include "nasal_builtin.h"
|
||||
#include "nasal_codegen.h"
|
||||
#include "nasal_vm.h"
|
||||
#include "nasal_dbg.h"
|
||||
|
||||
#endif
|
||||
|
||||
298
nasal_ast.h
298
nasal_ast.h
@@ -3,152 +3,246 @@
|
||||
|
||||
enum ast_node
|
||||
{
|
||||
ast_null=0,
|
||||
ast_root,ast_block,
|
||||
ast_file, // ast_file is only used to store which file the subtree is on,codegen will generate nothing
|
||||
ast_nil,ast_num,ast_str,ast_id,ast_func,ast_hash,ast_vec,
|
||||
ast_hashmember,ast_call,ast_callh,ast_callv,ast_callf,ast_subvec,
|
||||
ast_args,ast_default_arg,ast_dynamic_id,
|
||||
ast_and,ast_or,
|
||||
ast_equal,ast_addeq,ast_subeq,ast_multeq,ast_diveq,ast_lnkeq,
|
||||
ast_cmpeq,ast_neq,
|
||||
ast_less,ast_leq,
|
||||
ast_grt,ast_geq,
|
||||
ast_add,ast_sub,ast_mult,ast_div,ast_link,
|
||||
ast_neg,ast_not,
|
||||
ast_trino,
|
||||
ast_for,ast_forindex,ast_foreach,ast_while,ast_new_iter,
|
||||
ast_conditional,ast_if,ast_elsif,ast_else,
|
||||
ast_multi_id,ast_multi_scalar,
|
||||
ast_def,ast_multi_assign,
|
||||
ast_continue,ast_break,ast_ret
|
||||
ast_null=0, // null node
|
||||
ast_root, // mark the root node of ast
|
||||
ast_block, // expression block
|
||||
ast_file, // used to store which file the sub-tree is on, only used in main block
|
||||
ast_nil, // nil keyword
|
||||
ast_num, // number, basic value type
|
||||
ast_str, // string, basic value type
|
||||
ast_id, // identifier
|
||||
ast_func, // func keyword
|
||||
ast_hash, // hash, basic value type
|
||||
ast_vec, // vector, basic value type
|
||||
ast_pair, // pair of key and value in hashmap
|
||||
ast_call, // mark a sub-tree of calling an identifier
|
||||
ast_callh, // id.name
|
||||
ast_callv, // id[index]
|
||||
ast_callf, // id()
|
||||
ast_subvec, // id[index:index]
|
||||
ast_args, // mark a sub-tree of function parameters
|
||||
ast_default, // default parameter
|
||||
ast_dynamic, // dynamic parameter
|
||||
ast_and, // and keyword
|
||||
ast_or, // or keyword
|
||||
ast_equal, // =
|
||||
ast_addeq, // +=
|
||||
ast_subeq, // -=
|
||||
ast_multeq, // *=
|
||||
ast_diveq, // /=
|
||||
ast_lnkeq, // ~=
|
||||
ast_cmpeq, // ==
|
||||
ast_neq, // !=
|
||||
ast_less, // <
|
||||
ast_leq, // <=
|
||||
ast_grt, // >
|
||||
ast_geq, // >=
|
||||
ast_add, // +
|
||||
ast_sub, // -
|
||||
ast_mult, // *
|
||||
ast_div, // /
|
||||
ast_link, // ~
|
||||
ast_neg, // -
|
||||
ast_not, // ~
|
||||
ast_trino, // ?:
|
||||
ast_for, // for keyword
|
||||
ast_forindex, // forindex keyword
|
||||
ast_foreach, // foreach keyword
|
||||
ast_while, // while
|
||||
ast_iter, // iterator, used in forindex/foreach
|
||||
ast_conditional, // mark a sub-tree of conditional expression
|
||||
ast_if, // if keyword
|
||||
ast_elsif, // elsif keyword
|
||||
ast_else, // else keyword
|
||||
ast_multi_id, // multi identifiers sub-tree
|
||||
ast_multi_scalar,// multi value sub-tree
|
||||
ast_def, // definition
|
||||
ast_multi_assign,// multi assignment sub-tree
|
||||
ast_continue, // continue keyword, only used in loop
|
||||
ast_break, // break keyword, only used in loop
|
||||
ast_ret // return keyword, only used in function block
|
||||
};
|
||||
|
||||
const char* ast_name[]=
|
||||
{
|
||||
"null",
|
||||
"root","block",
|
||||
"root",
|
||||
"block",
|
||||
"file",
|
||||
"nil","num","str","id","func","hash","vec",
|
||||
"hashmember","call","callh","callv","callf","subvec",
|
||||
"args","deflt_arg","dyn_id",
|
||||
"and","or",
|
||||
"=","+=","-=","*=","/=","~=",
|
||||
"==","!=",
|
||||
"<","<=",
|
||||
">",">=",
|
||||
"+","-","*","/","~",
|
||||
"unary-","unary!",
|
||||
"nil",
|
||||
"num",
|
||||
"str",
|
||||
"id",
|
||||
"func",
|
||||
"hash",
|
||||
"vec",
|
||||
"hashmember",
|
||||
"call",
|
||||
"callh",
|
||||
"callv",
|
||||
"callf",
|
||||
"subvec",
|
||||
"args",
|
||||
"default",
|
||||
"dynamic",
|
||||
"and",
|
||||
"or",
|
||||
"=",
|
||||
"+=",
|
||||
"-=",
|
||||
"*=",
|
||||
"/=",
|
||||
"~=",
|
||||
"==",
|
||||
"!=",
|
||||
"<",
|
||||
"<=",
|
||||
">",
|
||||
">=",
|
||||
"+",
|
||||
"-",
|
||||
"*",
|
||||
"/",
|
||||
"~",
|
||||
"unary-",
|
||||
"unary!",
|
||||
"trino",
|
||||
"for","forindex","foreach","while","iter",
|
||||
"conditional","if","elsif","else",
|
||||
"multi_id","multi_scalar",
|
||||
"def","multi_assign",
|
||||
"continue","break","return"
|
||||
"for",
|
||||
"forindex",
|
||||
"foreach",
|
||||
"while",
|
||||
"iter",
|
||||
"conditional",
|
||||
"if",
|
||||
"elsif",
|
||||
"else",
|
||||
"multi_id",
|
||||
"multi_scalar",
|
||||
"def",
|
||||
"multi_assign",
|
||||
"continue",
|
||||
"break",
|
||||
"return",
|
||||
nullptr
|
||||
};
|
||||
|
||||
class nasal_ast
|
||||
{
|
||||
private:
|
||||
int line;
|
||||
int type;
|
||||
double num;
|
||||
std::string str;
|
||||
std::vector<nasal_ast> children;
|
||||
uint32_t _line;
|
||||
uint32_t _type;
|
||||
double _num;
|
||||
std::string _str;
|
||||
std::vector<nasal_ast> _child;
|
||||
public:
|
||||
nasal_ast(){line=0;type=ast_null;}
|
||||
nasal_ast(const int l,const int t){line=l;type=t;}
|
||||
nasal_ast(const uint32_t l=0,const uint32_t t=ast_null):_line(l),_type(t){}
|
||||
nasal_ast(const nasal_ast&);
|
||||
nasal_ast(nasal_ast&&);
|
||||
void print(int,bool);
|
||||
void clear();
|
||||
|
||||
nasal_ast& operator=(const nasal_ast&);
|
||||
nasal_ast& operator=(nasal_ast&&);
|
||||
void print_ast(const int);
|
||||
void clear();
|
||||
void add_child(nasal_ast&& ast){children.push_back(std::move(ast));}
|
||||
void add_child(const nasal_ast& ast){children.push_back(ast);}
|
||||
void set_line(const int l){line=l;}
|
||||
void set_type(const int t){type=t;}
|
||||
void set_str(const std::string& s){str=s;}
|
||||
void set_num(const double n){num=n;}
|
||||
int get_line(){return line;}
|
||||
int get_type(){return type;}
|
||||
double get_num() {return num;}
|
||||
std::string& get_str(){return str;}
|
||||
std::vector<nasal_ast>& get_children(){return children;}
|
||||
nasal_ast& operator[](const int index){return _child[index];}
|
||||
const nasal_ast& operator[](const int index) const {return _child[index];}
|
||||
size_t size() const {return _child.size();}
|
||||
|
||||
void add(nasal_ast&& ast){_child.push_back(std::move(ast));}
|
||||
void add(const nasal_ast& ast){_child.push_back(ast);}
|
||||
void set_line(const uint32_t l){_line=l;}
|
||||
void set_type(const uint32_t t){_type=t;}
|
||||
void set_str(const std::string& s){_str=s;}
|
||||
void set_num(const double n){_num=n;}
|
||||
|
||||
int get_line() const {return line;}
|
||||
int get_type() const {return type;}
|
||||
double get_num() const {return num;}
|
||||
const std::string& get_str() const {return str;}
|
||||
const std::vector<nasal_ast>& get_children() const {return children;}
|
||||
inline uint32_t line() const {return _line;}
|
||||
inline uint32_t type() const {return _type;}
|
||||
inline double num() const {return _num;}
|
||||
inline const std::string& str() const {return _str;}
|
||||
inline const std::vector<nasal_ast>& child() const {return _child;}
|
||||
inline std::vector<nasal_ast>& child(){return _child;}
|
||||
};
|
||||
|
||||
nasal_ast::nasal_ast(const nasal_ast& tmp)
|
||||
{
|
||||
line=tmp.line;
|
||||
type=tmp.type;
|
||||
num =tmp.num;
|
||||
str =tmp.str;
|
||||
children=tmp.children;
|
||||
return;
|
||||
_line=tmp._line;
|
||||
_type=tmp._type;
|
||||
_num =tmp._num;
|
||||
_str =tmp._str;
|
||||
_child=tmp._child;
|
||||
}
|
||||
|
||||
nasal_ast::nasal_ast(nasal_ast&& tmp)
|
||||
{
|
||||
line=tmp.line;
|
||||
type=tmp.type;
|
||||
num =tmp.num;
|
||||
str.swap(tmp.str);
|
||||
children.swap(tmp.children);
|
||||
return;
|
||||
_line=tmp._line;
|
||||
_type=tmp._type;
|
||||
_num =tmp._num;
|
||||
_str.swap(tmp._str);
|
||||
_child.swap(tmp._child);
|
||||
}
|
||||
|
||||
nasal_ast& nasal_ast::operator=(const nasal_ast& tmp)
|
||||
{
|
||||
line=tmp.line;
|
||||
type=tmp.type;
|
||||
num=tmp.num;
|
||||
str=tmp.str;
|
||||
children=tmp.children;
|
||||
_line=tmp._line;
|
||||
_type=tmp._type;
|
||||
_num=tmp._num;
|
||||
_str=tmp._str;
|
||||
_child=tmp._child;
|
||||
return *this;
|
||||
}
|
||||
|
||||
nasal_ast& nasal_ast::operator=(nasal_ast&& tmp)
|
||||
{
|
||||
line=tmp.line;
|
||||
type=tmp.type;
|
||||
num=tmp.num;
|
||||
str.swap(tmp.str);
|
||||
children.swap(tmp.children);
|
||||
_line=tmp._line;
|
||||
_type=tmp._type;
|
||||
_num=tmp._num;
|
||||
_str.swap(tmp._str);
|
||||
_child.swap(tmp._child);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void nasal_ast::clear()
|
||||
{
|
||||
line=0;
|
||||
num=0;
|
||||
str="";
|
||||
type=ast_null;
|
||||
children.clear();
|
||||
return;
|
||||
_line=0;
|
||||
_num=0;
|
||||
_str="";
|
||||
_type=ast_null;
|
||||
_child.clear();
|
||||
}
|
||||
|
||||
void nasal_ast::print_ast(const int depth)
|
||||
void nasal_ast::print(int depth,bool last=false)
|
||||
{
|
||||
for(int i=0;i<depth;++i)
|
||||
std::cout<<"| ";
|
||||
std::cout<<ast_name[type];
|
||||
if(type==ast_str || type==ast_id || type==ast_default_arg || type==ast_dynamic_id || type==ast_callh)
|
||||
{
|
||||
std::cout<<":";
|
||||
raw_string(str);
|
||||
}
|
||||
else if(type==ast_num || type==ast_file)
|
||||
std::cout<<":"<<num;
|
||||
static std::vector<std::string> intentation={};
|
||||
for(auto& i:intentation)
|
||||
std::cout<<i;
|
||||
std::cout<<ast_name[_type];
|
||||
if(
|
||||
_type==ast_str ||
|
||||
_type==ast_id ||
|
||||
_type==ast_default ||
|
||||
_type==ast_dynamic ||
|
||||
_type==ast_callh)
|
||||
std::cout<<":"<<rawstr(_str);
|
||||
else if(_type==ast_num || _type==ast_file)
|
||||
std::cout<<":"<<_num;
|
||||
std::cout<<'\n';
|
||||
for(auto& i:children)
|
||||
i.print_ast(depth+1);
|
||||
return;
|
||||
if(last && depth)
|
||||
intentation.back()=" ";
|
||||
else if(!last && depth)
|
||||
#ifdef _WIN32
|
||||
intentation.back()="| ";
|
||||
#else
|
||||
intentation.back()="│ ";
|
||||
#endif
|
||||
for(uint32_t i=0;i<_child.size();++i)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
intentation.push_back(i==_child.size()-1?"`-":"|-");
|
||||
#else
|
||||
intentation.push_back(i==_child.size()-1?"└─":"├─");
|
||||
#endif
|
||||
_child[i].print(depth+1,i==_child.size()-1);
|
||||
intentation.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
1466
nasal_builtin.h
1466
nasal_builtin.h
File diff suppressed because it is too large
Load Diff
1094
nasal_codegen.h
1094
nasal_codegen.h
File diff suppressed because it is too large
Load Diff
306
nasal_dbg.h
Normal file
306
nasal_dbg.h
Normal file
@@ -0,0 +1,306 @@
|
||||
#ifndef __NASAL_DBG_H__
|
||||
#define __NASAL_DBG_H__
|
||||
|
||||
#include "nasal_vm.h"
|
||||
|
||||
class nasal_dbg:public nasal_vm
|
||||
{
|
||||
private:
|
||||
bool next_step;
|
||||
uint16_t bk_fidx;
|
||||
uint32_t bk_line;
|
||||
file_line src;
|
||||
|
||||
std::vector<std::string> parse(const std::string&);
|
||||
uint16_t get_fileindex(const std::string&);
|
||||
void err();
|
||||
void help();
|
||||
void stepinfo();
|
||||
void interact();
|
||||
public:
|
||||
nasal_dbg():
|
||||
next_step(false),
|
||||
bk_fidx(0),bk_line(0){}
|
||||
void run(
|
||||
const nasal_codegen&,
|
||||
const nasal_import&
|
||||
);
|
||||
};
|
||||
|
||||
std::vector<std::string> nasal_dbg::parse(const std::string& cmd)
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
std::string tmp="";
|
||||
for(uint32_t i=0;i<cmd.length();++i)
|
||||
{
|
||||
if(cmd[i]==' ' && tmp.length())
|
||||
{
|
||||
res.push_back(tmp);
|
||||
tmp="";
|
||||
continue;
|
||||
}
|
||||
tmp+=cmd[i];
|
||||
}
|
||||
if(tmp.length())
|
||||
res.push_back(tmp);
|
||||
return res;
|
||||
}
|
||||
|
||||
uint16_t nasal_dbg::get_fileindex(const std::string& filename)
|
||||
{
|
||||
for(uint16_t i=0;i<files_size;++i)
|
||||
if(filename==files[i])
|
||||
return i;
|
||||
return 65535;
|
||||
}
|
||||
|
||||
void nasal_dbg::err()
|
||||
{
|
||||
std::cerr
|
||||
<<"incorrect command\n"
|
||||
<<"input \'h\' to get help\n";
|
||||
}
|
||||
|
||||
void nasal_dbg::help()
|
||||
{
|
||||
std::cout
|
||||
<<"<option>\n"
|
||||
<<"\th, help | get help\n"
|
||||
<<"\tbt, backtrace | get function call trace\n"
|
||||
<<"\tc, continue | run program until break point or exit\n"
|
||||
<<"\tg, global | see global values\n"
|
||||
<<"\tl, local | see local values\n"
|
||||
<<"\tu, upval | see upvalue\n"
|
||||
<<"\ta, all | show global,local and upvalue\n"
|
||||
<<"\tn, next | execute next bytecode\n"
|
||||
<<"\tq, exit | exit debugger\n"
|
||||
<<"<option> <filename> <line>\n"
|
||||
<<"\tbk, break | set break point\n";
|
||||
}
|
||||
|
||||
void nasal_dbg::stepinfo()
|
||||
{
|
||||
uint32_t begin,end;
|
||||
uint32_t line=bytecode[pc].line==0?0:bytecode[pc].line-1;
|
||||
src.load(files[bytecode[pc].fidx]);
|
||||
printf("\nsource code:\n");
|
||||
begin=(line>>3)==0?0:((line>>3)<<3);
|
||||
end=(1+(line>>3))<<3;
|
||||
for(uint32_t i=begin;i<end && i<src.size();++i)
|
||||
printf("%s\t%s\n",i==line?"-->":" ",src[i].c_str());
|
||||
printf("next bytecode:\n");
|
||||
begin=(pc>>3)==0?0:((pc>>3)<<3);
|
||||
end=(1+(pc>>3))<<3;
|
||||
for(uint32_t i=begin;i<end && bytecode[i].op!=op_exit;++i)
|
||||
bytecodeinfo(i==pc?"-->\t":" \t",i);
|
||||
stackinfo(5);
|
||||
}
|
||||
|
||||
void nasal_dbg::interact()
|
||||
{
|
||||
// special operand
|
||||
if(bytecode[pc].op==op_intg)
|
||||
{
|
||||
std::cout
|
||||
<<"[debug] nasal debug mode\n"
|
||||
<<"input \'h\' to get help\n";
|
||||
}
|
||||
else if(bytecode[pc].op==op_nop || bytecode[pc].op==op_exit)
|
||||
return;
|
||||
|
||||
if(
|
||||
(bytecode[pc].fidx!=bk_fidx || bytecode[pc].line!=bk_line) && // break point
|
||||
!next_step // next step
|
||||
)return;
|
||||
|
||||
next_step=false;
|
||||
std::string cmd;
|
||||
stepinfo();
|
||||
while(1)
|
||||
{
|
||||
printf(">> ");
|
||||
std::getline(std::cin,cmd);
|
||||
auto res=parse(cmd);
|
||||
if(res.size()==1)
|
||||
{
|
||||
if(res[0]=="h" || res[0]=="help")
|
||||
help();
|
||||
else if(res[0]=="bt" || res[0]=="backtrace")
|
||||
traceback();
|
||||
else if(res[0]=="c" || res[0]=="continue")
|
||||
return;
|
||||
else if(res[0]=="g" || res[0]=="global")
|
||||
global_state();
|
||||
else if(res[0]=="l" || res[0]=="local")
|
||||
local_state();
|
||||
else if(res[0]=="u" || res[0]=="upval")
|
||||
upval_state();
|
||||
else if(res[0]=="a" || res[0]=="all")
|
||||
{
|
||||
global_state();
|
||||
local_state();
|
||||
upval_state();
|
||||
}
|
||||
else if(res[0]=="n" || res[0]=="next")
|
||||
{
|
||||
next_step=true;
|
||||
return;
|
||||
}
|
||||
else if(res[0]=="q" || res[0]=="exit")
|
||||
std::exit(0);
|
||||
else
|
||||
err();
|
||||
}
|
||||
else if(res.size()==3)
|
||||
{
|
||||
if(res[0]=="bk" || res[0]=="break")
|
||||
{
|
||||
bk_fidx=get_fileindex(res[1]);
|
||||
if(bk_fidx==65535)
|
||||
{
|
||||
printf("cannot find file named \"%s\"\n",res[1].c_str());
|
||||
bk_fidx=0;
|
||||
}
|
||||
int tmp=atoi(res[2].c_str());
|
||||
if(tmp<=0)
|
||||
printf("incorrect line number \"%s\"\n",res[2].c_str());
|
||||
else
|
||||
bk_line=tmp;
|
||||
}
|
||||
else
|
||||
err();
|
||||
}
|
||||
else
|
||||
err();
|
||||
}
|
||||
}
|
||||
|
||||
void nasal_dbg::run(
|
||||
const nasal_codegen& gen,
|
||||
const nasal_import& linker)
|
||||
{
|
||||
detail_info=true;
|
||||
init(gen.get_strs(),gen.get_nums(),linker.get_file());
|
||||
const void* opr_table[]=
|
||||
{
|
||||
&&nop, &&intg, &&intl, &&loadg,
|
||||
&&loadl, &&loadu, &&pnum, &&pnil,
|
||||
&&pstr, &&newv, &&newh, &&newf,
|
||||
&&happ, &¶, &&defpara,&&dynpara,
|
||||
&&unot, &&usub, &&add, &&sub,
|
||||
&&mul, &&div, &&lnk, &&addc,
|
||||
&&subc, &&mulc, &&divc, &&lnkc,
|
||||
&&addeq, &&subeq, &&muleq, &&diveq,
|
||||
&&lnkeq, &&addeqc, &&subeqc, &&muleqc,
|
||||
&&diveqc, &&lnkeqc, &&meq, &&eq,
|
||||
&&neq, &&less, &&leq, &&grt,
|
||||
&&geq, &&lessc, &&leqc, &&grtc,
|
||||
&&geqc, &&pop, &&jmp, &&jt,
|
||||
&&jf, &&counter, &&findex, &&feach,
|
||||
&&callg, &&calll, &&upval, &&callv,
|
||||
&&callvi, &&callh, &&callfv, &&callfh,
|
||||
&&callb, &&slcbegin, &&slcend, &&slc,
|
||||
&&slc2, &&mcallg, &&mcalll, &&mupval,
|
||||
&&mcallv, &&mcallh, &&ret, &&vmexit
|
||||
};
|
||||
bytecode=gen.get_code().data();
|
||||
std::vector<const void*> code;
|
||||
for(auto& i:gen.get_code())
|
||||
{
|
||||
code.push_back(opr_table[i.op]);
|
||||
imm.push_back(i.num);
|
||||
}
|
||||
|
||||
// set canary and program counter
|
||||
auto canary=gc.stack+STACK_MAX_DEPTH-1;
|
||||
pc=0;
|
||||
// goto the first operand
|
||||
goto *code[pc];
|
||||
|
||||
vmexit:
|
||||
if(gc.top>=canary)
|
||||
die("stack overflow");
|
||||
gc.clear();
|
||||
imm.clear();
|
||||
printf("[debug] debugger exited\n");
|
||||
return;
|
||||
#define dbg(op) {interact();op();if(gc.top<canary)goto *code[++pc];goto vmexit;}
|
||||
|
||||
nop: dbg(opr_nop );
|
||||
intg: dbg(opr_intg );
|
||||
intl: dbg(opr_intl );
|
||||
loadg: dbg(opr_loadg );
|
||||
loadl: dbg(opr_loadl );
|
||||
loadu: dbg(opr_loadu );
|
||||
pnum: dbg(opr_pnum );
|
||||
pnil: dbg(opr_pnil );
|
||||
pstr: dbg(opr_pstr );
|
||||
newv: dbg(opr_newv );
|
||||
newh: dbg(opr_newh );
|
||||
newf: dbg(opr_newf );
|
||||
happ: dbg(opr_happ );
|
||||
para: dbg(opr_para );
|
||||
defpara: dbg(opr_defpara );
|
||||
dynpara: dbg(opr_dynpara );
|
||||
unot: dbg(opr_unot );
|
||||
usub: dbg(opr_usub );
|
||||
add: dbg(opr_add );
|
||||
sub: dbg(opr_sub );
|
||||
mul: dbg(opr_mul );
|
||||
div: dbg(opr_div );
|
||||
lnk: dbg(opr_lnk );
|
||||
addc: dbg(opr_addc );
|
||||
subc: dbg(opr_subc );
|
||||
mulc: dbg(opr_mulc );
|
||||
divc: dbg(opr_divc );
|
||||
lnkc: dbg(opr_lnkc );
|
||||
addeq: dbg(opr_addeq );
|
||||
subeq: dbg(opr_subeq );
|
||||
muleq: dbg(opr_muleq );
|
||||
diveq: dbg(opr_diveq );
|
||||
lnkeq: dbg(opr_lnkeq );
|
||||
addeqc: dbg(opr_addeqc );
|
||||
subeqc: dbg(opr_subeqc );
|
||||
muleqc: dbg(opr_muleqc );
|
||||
diveqc: dbg(opr_diveqc );
|
||||
lnkeqc: dbg(opr_lnkeqc );
|
||||
meq: dbg(opr_meq );
|
||||
eq: dbg(opr_eq );
|
||||
neq: dbg(opr_neq );
|
||||
less: dbg(opr_less );
|
||||
leq: dbg(opr_leq );
|
||||
grt: dbg(opr_grt );
|
||||
geq: dbg(opr_geq );
|
||||
lessc: dbg(opr_lessc );
|
||||
leqc: dbg(opr_leqc );
|
||||
grtc: dbg(opr_grtc );
|
||||
geqc: dbg(opr_geqc );
|
||||
pop: dbg(opr_pop );
|
||||
jmp: dbg(opr_jmp );
|
||||
jt: dbg(opr_jt );
|
||||
jf: dbg(opr_jf );
|
||||
counter: dbg(opr_counter );
|
||||
findex: dbg(opr_findex );
|
||||
feach: dbg(opr_feach );
|
||||
callg: dbg(opr_callg );
|
||||
calll: dbg(opr_calll );
|
||||
upval: dbg(opr_upval );
|
||||
callv: dbg(opr_callv );
|
||||
callvi: dbg(opr_callvi );
|
||||
callh: dbg(opr_callh );
|
||||
callfv: dbg(opr_callfv );
|
||||
callfh: dbg(opr_callfh );
|
||||
callb: dbg(opr_callb );
|
||||
slcbegin:dbg(opr_slcbegin);
|
||||
slcend: dbg(opr_slcend );
|
||||
slc: dbg(opr_slc );
|
||||
slc2: dbg(opr_slc2 );
|
||||
mcallg: dbg(opr_mcallg );
|
||||
mcalll: dbg(opr_mcalll );
|
||||
mupval: dbg(opr_mupval );
|
||||
mcallv: dbg(opr_mcallv );
|
||||
mcallh: dbg(opr_mcallh );
|
||||
ret: dbg(opr_ret );
|
||||
}
|
||||
|
||||
#endif
|
||||
77
nasal_err.h
Normal file
77
nasal_err.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifndef __NASAL_ERR_H__
|
||||
#define __NASAL_ERR_H__
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
class file_line
|
||||
{
|
||||
protected:
|
||||
std::string file;
|
||||
std::vector<std::string> res;
|
||||
public:
|
||||
void load(const std::string& f)
|
||||
{
|
||||
if(file==f) // don't need to load a loaded file
|
||||
return;
|
||||
file=f;
|
||||
res.clear();
|
||||
std::ifstream fin(f,std::ios::binary);
|
||||
if(fin.fail())
|
||||
{
|
||||
std::cerr<<"[src] cannot open file <"<<f<<">\n";
|
||||
std::exit(1);
|
||||
}
|
||||
std::string line;
|
||||
while(!fin.eof())
|
||||
{
|
||||
std::getline(fin,line);
|
||||
res.push_back(line);
|
||||
}
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
std::vector<std::string> tmp;
|
||||
res.swap(tmp);
|
||||
}
|
||||
const std::string& operator[](const uint32_t line){return res[line];}
|
||||
const std::string& name(){return file;}
|
||||
size_t size(){return res.size();}
|
||||
};
|
||||
|
||||
class nasal_err:public file_line
|
||||
{
|
||||
private:
|
||||
uint32_t error;
|
||||
public:
|
||||
void err(const char* stage,const std::string& info)
|
||||
{
|
||||
++error;
|
||||
std::cerr<<"["<<stage<<"] "<<info<<'\n';
|
||||
}
|
||||
void err(const char* stage,uint32_t line,uint32_t column,const std::string& info)
|
||||
{
|
||||
++error;
|
||||
if(!line)
|
||||
{
|
||||
std::cerr<<"["<<stage<<"] "<<file<<": "<<info<<'\n';
|
||||
return;
|
||||
}
|
||||
std::cerr<<"["<<stage<<"] "<<file<<":"<<line<<":"<<column<<" "<<info<<"\n"<<res[line-1]<<'\n';
|
||||
for(int i=0;i<(int)column-1;++i)
|
||||
std::cerr<<char(" \t"[res[line-1][i]=='\t']);
|
||||
std::cerr<<"^\n";
|
||||
}
|
||||
void err(const char* stage,uint32_t line,const std::string& info)
|
||||
{
|
||||
++error;
|
||||
if(!line)
|
||||
std::cerr<<"["<<stage<<"] "<<file<<": "<<info<<'\n';
|
||||
else
|
||||
std::cerr<<"["<<stage<<"] "<<file<<":"<<line<<" "<<info<<"\n"<<res[line-1]<<'\n';
|
||||
}
|
||||
void chkerr(){if(error)std::exit(1);}
|
||||
};
|
||||
|
||||
#endif
|
||||
456
nasal_gc.h
456
nasal_gc.h
@@ -3,8 +3,13 @@
|
||||
|
||||
enum nasal_type
|
||||
{
|
||||
vm_nil=0,
|
||||
/* none-gc object */
|
||||
vm_none=0,
|
||||
vm_cnt,
|
||||
vm_ret,
|
||||
vm_nil,
|
||||
vm_num,
|
||||
/* gc object */
|
||||
vm_str,
|
||||
vm_func,
|
||||
vm_vec,
|
||||
@@ -14,172 +19,196 @@ enum nasal_type
|
||||
};
|
||||
|
||||
// change parameters here to make your own efficient gc
|
||||
// better set bigger number on vm_num and vm_vec
|
||||
const int increment[vm_type_size]=
|
||||
// better set bigger number on vm_vec
|
||||
const uint32_t increment[vm_type_size]=
|
||||
{
|
||||
0, // vm_nil,in fact it is not in use
|
||||
65536,// vm_num
|
||||
2048, // vm_str
|
||||
512, // vm_func
|
||||
8192, // vm_vec
|
||||
512, // vm_hash
|
||||
0 // vm_obj
|
||||
/* none-gc object */
|
||||
0, // vm_none, error type
|
||||
0, // vm_count, used in foreach/forindex
|
||||
0, // vm_ret, used to store call-return address
|
||||
0, // vm_nil
|
||||
0, // vm_num
|
||||
/* gc object */
|
||||
256, // vm_str
|
||||
512, // vm_func
|
||||
512, // vm_vec
|
||||
128, // vm_hash
|
||||
16 // vm_obj
|
||||
};
|
||||
|
||||
// declaration of nasal_val
|
||||
struct nasal_val;
|
||||
// define nasal_ref => nasal_val*
|
||||
typedef nasal_val* nasal_ref;
|
||||
struct nasal_vec; // vector
|
||||
struct nasal_hash;// hashmap(dict)
|
||||
struct nasal_func;// function(lambda)
|
||||
struct nasal_obj; // special objects
|
||||
struct nasal_val; // nasal_val includes gc-managed types
|
||||
|
||||
#ifdef __NASAL_REF__
|
||||
struct nasal_ref
|
||||
{
|
||||
uint8_t type;
|
||||
union
|
||||
{
|
||||
double num;
|
||||
uint32_t ret;
|
||||
int64_t cnt;
|
||||
double num;
|
||||
nasal_val* gcobj;
|
||||
}value;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct nasal_vec// 24 bytes
|
||||
nasal_ref(const uint8_t t=vm_none):type(t){}
|
||||
nasal_ref(const uint8_t t,const uint32_t n):type(t){value.ret=n;}
|
||||
nasal_ref(const uint8_t t,const int64_t n):type(t){value.cnt=n;}
|
||||
nasal_ref(const uint8_t t,const double n):type(t){value.num=n;}
|
||||
nasal_ref(const uint8_t t,nasal_val* n):type(t){value.gcobj=n;}
|
||||
nasal_ref(const nasal_ref& nr):type(nr.type),value(nr.value){}
|
||||
nasal_ref& operator=(const nasal_ref& nr)
|
||||
{
|
||||
type=nr.type;
|
||||
value=nr.value;
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const nasal_ref& nr){return type==nr.type && value.gcobj==nr.value.gcobj;}
|
||||
bool operator!=(const nasal_ref& nr){return type!=nr.type || value.gcobj!=nr.value.gcobj;}
|
||||
// number and string can be translated to each other
|
||||
double to_number();
|
||||
std::string to_string();
|
||||
void print();
|
||||
inline uint32_t ret ();
|
||||
inline int64_t& cnt ();
|
||||
inline double& num ();
|
||||
inline std::string* str ();
|
||||
inline nasal_vec* vec ();
|
||||
inline nasal_hash* hash();
|
||||
inline nasal_func* func();
|
||||
inline nasal_obj* obj ();
|
||||
};
|
||||
|
||||
struct nasal_vec
|
||||
{
|
||||
std::vector<nasal_ref> elems;
|
||||
|
||||
void print();
|
||||
nasal_ref get_val(int);
|
||||
nasal_ref* get_mem(int);
|
||||
nasal_ref get_val(const int);
|
||||
nasal_ref* get_mem(const int);
|
||||
};
|
||||
|
||||
struct nasal_hash// 56 bytes
|
||||
struct nasal_hash
|
||||
{
|
||||
std::unordered_map<std::string,nasal_ref> elems;
|
||||
|
||||
void print();
|
||||
nasal_ref get_val(std::string&);
|
||||
nasal_ref* get_mem(std::string&);
|
||||
nasal_ref get_val(const std::string&);
|
||||
nasal_ref* get_mem(const std::string&);
|
||||
};
|
||||
|
||||
struct nasal_func// 120 bytes
|
||||
struct nasal_func
|
||||
{
|
||||
int32_t dynpara; // dynamic parameter name index in hash
|
||||
uint32_t offset; // arguments will be loaded into local scope from this offset
|
||||
uint32_t entry; // pc will set to entry-1 to call this function
|
||||
std::vector<nasal_ref> default_para;// default value(nasal_ref)
|
||||
std::unordered_map<std::string,int> key_table;// parameter name hash
|
||||
nasal_ref closure; // closure will be loaded to gc.local.back() as the local scope
|
||||
int32_t dynpara; // dynamic parameter name index in hash.
|
||||
uint32_t entry; // pc will set to entry-1 to call this function
|
||||
uint32_t psize; // used to load default parameters to a new function
|
||||
uint32_t lsize; // used to expand memory space for local values on stack
|
||||
std::vector<nasal_ref> local; // local scope with default value(nasal_ref)
|
||||
std::vector<nasal_ref> upvalue; // closure
|
||||
std::unordered_map<std::string,size_t> keys; // parameter name table, size_t begins from 1
|
||||
|
||||
nasal_func();
|
||||
nasal_func():dynpara(-1){}
|
||||
void clear();
|
||||
};
|
||||
|
||||
struct nasal_val// 16 bytes
|
||||
struct nasal_obj
|
||||
{
|
||||
uint32_t type;
|
||||
void* ptr;
|
||||
nasal_obj():ptr(nullptr){}
|
||||
void clear(){ptr=nullptr;}
|
||||
};
|
||||
|
||||
const uint8_t GC_UNCOLLECTED=0;
|
||||
const uint8_t GC_COLLECTED =1;
|
||||
const uint8_t GC_FOUND =2;
|
||||
struct nasal_val
|
||||
{
|
||||
#define GC_UNCOLLECTED 0
|
||||
#define GC_COLLECTED 1
|
||||
#define GC_FOUND 2
|
||||
uint8_t mark;
|
||||
uint8_t type;
|
||||
uint8_t unmut; // used to mark if a string is unmutable
|
||||
union
|
||||
{
|
||||
double num;
|
||||
std::string* str;
|
||||
nasal_vec* vec;
|
||||
nasal_hash* hash;
|
||||
nasal_func* func;
|
||||
void* obj;
|
||||
nasal_obj* obj;
|
||||
}ptr;
|
||||
|
||||
nasal_val(int);
|
||||
nasal_val(uint8_t);
|
||||
~nasal_val();
|
||||
double to_number();
|
||||
std::string to_string();
|
||||
};
|
||||
|
||||
/*functions of nasal_vec*/
|
||||
nasal_ref nasal_vec::get_val(int index)
|
||||
nasal_ref nasal_vec::get_val(const int index)
|
||||
{
|
||||
int vec_size=elems.size();
|
||||
if(index<-vec_size || index>=vec_size)
|
||||
return nullptr;
|
||||
return elems[index>=0?index:index+vec_size];
|
||||
int size=elems.size();
|
||||
if(index<-size || index>=size)
|
||||
return {vm_none};
|
||||
return elems[index>=0?index:index+size];
|
||||
}
|
||||
nasal_ref* nasal_vec::get_mem(int index)
|
||||
nasal_ref* nasal_vec::get_mem(const int index)
|
||||
{
|
||||
int vec_size=elems.size();
|
||||
if(index<-vec_size || index>=vec_size)
|
||||
int size=elems.size();
|
||||
if(index<-size || index>=size)
|
||||
return nullptr;
|
||||
return &elems[index>=0?index:index+vec_size];
|
||||
return &elems[index>=0?index:index+size];
|
||||
}
|
||||
void nasal_vec::print()
|
||||
{
|
||||
static int depth=0;
|
||||
if(++depth>32)
|
||||
if(!elems.size() || depth>8)
|
||||
{
|
||||
std::cout<<"[..]";
|
||||
--depth;
|
||||
std::cout<<(elems.size()?"[..]":"[]");
|
||||
return;
|
||||
}
|
||||
if(!elems.size())
|
||||
{
|
||||
std::cout<<"[]";
|
||||
return;
|
||||
}
|
||||
ssize_t iter=0;
|
||||
++depth;
|
||||
size_t iter=0;
|
||||
std::cout<<'[';
|
||||
for(auto i:elems)
|
||||
for(auto& i:elems)
|
||||
{
|
||||
switch(i->type)
|
||||
{
|
||||
case vm_nil: std::cout<<"nil"; break;
|
||||
case vm_num: std::cout<<i->ptr.num; break;
|
||||
case vm_str: std::cout<<*i->ptr.str; break;
|
||||
case vm_vec: i->ptr.vec->print(); break;
|
||||
case vm_hash: i->ptr.hash->print(); break;
|
||||
case vm_func: std::cout<<"func(..){..}"; break;
|
||||
}
|
||||
i.print();
|
||||
std::cout<<",]"[(++iter)==elems.size()];
|
||||
}
|
||||
--depth;
|
||||
return;
|
||||
}
|
||||
|
||||
/*functions of nasal_hash*/
|
||||
nasal_ref nasal_hash::get_val(std::string& key)
|
||||
nasal_ref nasal_hash::get_val(const std::string& key)
|
||||
{
|
||||
if(elems.count(key))
|
||||
return elems[key];
|
||||
else if(elems.count("parents"))
|
||||
{
|
||||
nasal_ref ret_addr=nullptr;
|
||||
nasal_ref val_addr=elems["parents"];
|
||||
if(val_addr->type==vm_vec)
|
||||
for(auto i:val_addr->ptr.vec->elems)
|
||||
nasal_ref ret(vm_none);
|
||||
nasal_ref val=elems["parents"];
|
||||
if(val.type==vm_vec)
|
||||
for(auto& i:val.vec()->elems)
|
||||
{
|
||||
if(i->type==vm_hash)
|
||||
ret_addr=i->ptr.hash->get_val(key);
|
||||
if(ret_addr)
|
||||
return ret_addr;
|
||||
if(i.type==vm_hash)
|
||||
ret=i.hash()->get_val(key);
|
||||
if(ret.type!=vm_none)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return {vm_none};
|
||||
}
|
||||
nasal_ref* nasal_hash::get_mem(std::string& key)
|
||||
nasal_ref* nasal_hash::get_mem(const std::string& key)
|
||||
{
|
||||
if(elems.count(key))
|
||||
return &elems[key];
|
||||
else if(elems.count("parents"))
|
||||
{
|
||||
nasal_ref* mem_addr=nullptr;
|
||||
nasal_ref val_addr=elems["parents"];
|
||||
if(val_addr->type==vm_vec)
|
||||
for(auto i:val_addr->ptr.vec->elems)
|
||||
nasal_ref* addr=nullptr;
|
||||
nasal_ref val=elems["parents"];
|
||||
if(val.type==vm_vec)
|
||||
for(auto& i:val.vec()->elems)
|
||||
{
|
||||
if(i->type==vm_hash)
|
||||
mem_addr=i->ptr.hash->get_mem(key);
|
||||
if(mem_addr)
|
||||
return mem_addr;
|
||||
if(i.type==vm_hash)
|
||||
addr=i.hash()->get_mem(key);
|
||||
if(addr)
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -187,66 +216,44 @@ nasal_ref* nasal_hash::get_mem(std::string& key)
|
||||
void nasal_hash::print()
|
||||
{
|
||||
static int depth=0;
|
||||
if(++depth>32)
|
||||
if(!elems.size() || depth>8)
|
||||
{
|
||||
std::cout<<"{..}";
|
||||
--depth;
|
||||
return;
|
||||
}
|
||||
if(!elems.size())
|
||||
{
|
||||
std::cout<<"{}";
|
||||
std::cout<<(elems.size()?"{..}":"{}");
|
||||
return;
|
||||
}
|
||||
++depth;
|
||||
size_t iter=0;
|
||||
std::cout<<'{';
|
||||
for(auto& i:elems)
|
||||
{
|
||||
std::cout<<i.first<<':';
|
||||
nasal_ref tmp=i.second;
|
||||
switch(tmp->type)
|
||||
{
|
||||
case vm_nil: std::cout<<"nil"; break;
|
||||
case vm_num: std::cout<<tmp->ptr.num; break;
|
||||
case vm_str: std::cout<<*tmp->ptr.str; break;
|
||||
case vm_vec: tmp->ptr.vec->print(); break;
|
||||
case vm_hash: tmp->ptr.hash->print(); break;
|
||||
case vm_func: std::cout<<"func(..){..}"; break;
|
||||
}
|
||||
i.second.print();
|
||||
std::cout<<",}"[(++iter)==elems.size()];
|
||||
}
|
||||
--depth;
|
||||
return;
|
||||
}
|
||||
|
||||
/*functions of nasal_func*/
|
||||
nasal_func::nasal_func()
|
||||
{
|
||||
dynpara=-1;
|
||||
return;
|
||||
}
|
||||
void nasal_func::clear()
|
||||
{
|
||||
dynpara=-1;
|
||||
default_para.clear();
|
||||
key_table.clear();
|
||||
return;
|
||||
local.clear();
|
||||
upvalue.clear();
|
||||
keys.clear();
|
||||
}
|
||||
|
||||
/*functions of nasal_val*/
|
||||
nasal_val::nasal_val(int val_type)
|
||||
nasal_val::nasal_val(uint8_t val_type)
|
||||
{
|
||||
mark=GC_COLLECTED;
|
||||
type=val_type;
|
||||
switch(type)
|
||||
unmut=0;
|
||||
switch(val_type)
|
||||
{
|
||||
case vm_num: ptr.num=0; break;
|
||||
case vm_str: ptr.str=new std::string; break;
|
||||
case vm_vec: ptr.vec=new nasal_vec; break;
|
||||
case vm_hash: ptr.hash=new nasal_hash; break;
|
||||
case vm_func: ptr.func=new nasal_func; break;
|
||||
case vm_obj: ptr.obj=new nasal_obj; break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
nasal_val::~nasal_val()
|
||||
{
|
||||
@@ -256,79 +263,100 @@ nasal_val::~nasal_val()
|
||||
case vm_vec: delete ptr.vec; break;
|
||||
case vm_hash: delete ptr.hash; break;
|
||||
case vm_func: delete ptr.func; break;
|
||||
case vm_obj: delete ptr.obj; break;
|
||||
}
|
||||
type=vm_nil;
|
||||
return;
|
||||
}
|
||||
double nasal_val::to_number()
|
||||
double nasal_ref::to_number()
|
||||
{
|
||||
return type!=vm_str?value.num:str2num(str()->c_str());
|
||||
}
|
||||
std::string nasal_ref::to_string()
|
||||
{
|
||||
if(type==vm_str)
|
||||
return str2num(ptr.str->c_str());
|
||||
return ptr.num;
|
||||
}
|
||||
std::string nasal_val::to_string()
|
||||
{
|
||||
if(type==vm_str)
|
||||
return *ptr.str;
|
||||
return *str();
|
||||
else if(type==vm_num)
|
||||
return std::to_string(ptr.num);
|
||||
return std::to_string(num());
|
||||
return "";
|
||||
}
|
||||
void nasal_ref::print()
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case vm_none: std::cout<<"undefined"; break;
|
||||
case vm_nil: std::cout<<"nil"; break;
|
||||
case vm_num: std::cout<<value.num; break;
|
||||
case vm_str: std::cout<<*(this->str());break;
|
||||
case vm_vec: this->vec()->print(); break;
|
||||
case vm_hash: this->hash()->print(); break;
|
||||
case vm_func: std::cout<<"func(..){..}";break;
|
||||
case vm_obj: std::cout<<"<object>"; break;
|
||||
}
|
||||
}
|
||||
inline uint32_t nasal_ref::ret (){return value.ret; }
|
||||
inline int64_t& nasal_ref::cnt (){return value.cnt; }
|
||||
inline double& nasal_ref::num (){return value.num; }
|
||||
inline std::string* nasal_ref::str (){return value.gcobj->ptr.str; }
|
||||
inline nasal_vec* nasal_ref::vec (){return value.gcobj->ptr.vec; }
|
||||
inline nasal_hash* nasal_ref::hash(){return value.gcobj->ptr.hash;}
|
||||
inline nasal_func* nasal_ref::func(){return value.gcobj->ptr.func;}
|
||||
inline nasal_obj* nasal_ref::obj (){return value.gcobj->ptr.obj; }
|
||||
|
||||
const uint32_t STACK_MAX_DEPTH=4095;
|
||||
const nasal_ref zero={vm_num,(double)0};
|
||||
const nasal_ref one ={vm_num,(double)1};
|
||||
const nasal_ref nil ={vm_nil,nullptr};
|
||||
struct nasal_gc
|
||||
{
|
||||
#define STACK_MAX_DEPTH (4095)
|
||||
nasal_ref zero_addr; // reserved address of nasal_val,type vm_num, 0
|
||||
nasal_ref one_addr; // reserved address of nasal_val,type vm_num, 1
|
||||
nasal_ref nil_addr; // reserved address of nasal_val,type vm_nil
|
||||
nasal_ref val_stack[STACK_MAX_DEPTH+1];// 1 reserved to avoid stack overflow, stack grows 1 each time
|
||||
nasal_ref* stack_top; // stack top
|
||||
std::vector<nasal_ref> num_addrs; // reserved address for const vm_num
|
||||
std::vector<nasal_ref> str_addrs; // reserved address for const vm_str
|
||||
std::vector<nasal_ref> memory; // gc memory
|
||||
std::queue <nasal_ref> free_list[vm_type_size]; // gc free list
|
||||
std::vector<nasal_ref> local;
|
||||
void mark();
|
||||
void sweep();
|
||||
void gc_init(const std::vector<double>&,const std::vector<std::string>&);
|
||||
void gc_clear();
|
||||
nasal_ref gc_alloc(int);
|
||||
nasal_ref builtin_alloc(int);
|
||||
nasal_ref stack[STACK_MAX_DEPTH+1];// 1 reserved to avoid stack overflow
|
||||
nasal_ref* top; // stack top
|
||||
std::vector<nasal_ref> strs; // reserved address for const vm_str
|
||||
std::vector<nasal_val*> memory; // gc memory
|
||||
std::queue<nasal_val*> free_list[vm_type_size]; // gc free list
|
||||
std::vector<nasal_ref> local;
|
||||
uint64_t size[vm_type_size];
|
||||
uint64_t count[vm_type_size];
|
||||
void mark();
|
||||
void sweep();
|
||||
void init(const std::vector<std::string>&);
|
||||
void clear();
|
||||
void info();
|
||||
nasal_ref alloc(const uint8_t);
|
||||
nasal_ref builtin_alloc(const uint8_t);
|
||||
};
|
||||
|
||||
/* gc functions */
|
||||
void nasal_gc::mark()
|
||||
{
|
||||
std::queue<nasal_ref> bfs;
|
||||
for(auto i:local)
|
||||
for(auto& i:local)
|
||||
bfs.push(i);
|
||||
for(nasal_ref* i=val_stack;i<=stack_top;++i)
|
||||
for(nasal_ref* i=stack;i<=top;++i)
|
||||
bfs.push(*i);
|
||||
while(!bfs.empty())
|
||||
{
|
||||
nasal_ref tmp=bfs.front();
|
||||
bfs.pop();
|
||||
if(tmp->mark) continue;
|
||||
tmp->mark=GC_FOUND;
|
||||
switch(tmp->type)
|
||||
if(tmp.type<=vm_num || tmp.value.gcobj->mark) continue;
|
||||
tmp.value.gcobj->mark=GC_FOUND;
|
||||
switch(tmp.type)
|
||||
{
|
||||
case vm_vec:
|
||||
for(auto i:tmp->ptr.vec->elems)
|
||||
for(auto& i:tmp.vec()->elems)
|
||||
bfs.push(i);
|
||||
break;
|
||||
case vm_hash:
|
||||
for(auto& i:tmp->ptr.hash->elems)
|
||||
for(auto& i:tmp.hash()->elems)
|
||||
bfs.push(i.second);
|
||||
break;
|
||||
case vm_func:
|
||||
bfs.push(tmp->ptr.func->closure);
|
||||
for(auto i:tmp->ptr.func->default_para)
|
||||
if(i)
|
||||
bfs.push(i);
|
||||
for(auto& i:tmp.func()->local)
|
||||
bfs.push(i);
|
||||
for(auto& i:tmp.func()->upvalue)
|
||||
bfs.push(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
void nasal_gc::sweep()
|
||||
{
|
||||
@@ -342,6 +370,7 @@ void nasal_gc::sweep()
|
||||
case vm_vec: i->ptr.vec->elems.clear(); break;
|
||||
case vm_hash:i->ptr.hash->elems.clear();break;
|
||||
case vm_func:i->ptr.func->clear(); break;
|
||||
case vm_obj: i->ptr.obj->clear(); break;
|
||||
}
|
||||
free_list[i->type].push(i);
|
||||
i->mark=GC_COLLECTED;
|
||||
@@ -349,99 +378,96 @@ void nasal_gc::sweep()
|
||||
else if(i->mark==GC_FOUND)
|
||||
i->mark=GC_UNCOLLECTED;
|
||||
}
|
||||
return;
|
||||
}
|
||||
void nasal_gc::gc_init(const std::vector<double>& nums,const std::vector<std::string>& strs)
|
||||
void nasal_gc::init(const std::vector<std::string>& s)
|
||||
{
|
||||
for(int i=vm_num;i<vm_type_size;++i)
|
||||
for(int j=0;j<increment[i];++j)
|
||||
for(uint8_t i=0;i<vm_type_size;++i)
|
||||
size[i]=count[i]=0;
|
||||
for(uint8_t i=vm_str;i<vm_type_size;++i)
|
||||
for(uint32_t j=0;j<increment[i];++j)
|
||||
{
|
||||
nasal_ref tmp=new nasal_val(i);
|
||||
nasal_val* tmp=new nasal_val(i);
|
||||
memory.push_back(tmp);
|
||||
free_list[i].push(tmp);
|
||||
}
|
||||
|
||||
stack_top=val_stack; // set stack_top to val_stack
|
||||
|
||||
zero_addr=new nasal_val(vm_num); // init constant 0
|
||||
zero_addr->ptr.num=0;
|
||||
|
||||
one_addr=new nasal_val(vm_num); // init constant 1
|
||||
one_addr->ptr.num=1;
|
||||
|
||||
nil_addr=new nasal_val(vm_nil); // init nil
|
||||
|
||||
// init constant numbers
|
||||
num_addrs.resize(nums.size());
|
||||
for(int i=0;i<nums.size();++i)
|
||||
{
|
||||
num_addrs[i]=new nasal_val(vm_num);
|
||||
num_addrs[i]->ptr.num=nums[i];
|
||||
}
|
||||
top=stack;
|
||||
// init constant strings
|
||||
str_addrs.resize(strs.size());
|
||||
for(int i=0;i<strs.size();++i)
|
||||
strs.resize(s.size());
|
||||
for(uint32_t i=0;i<strs.size();++i)
|
||||
{
|
||||
str_addrs[i]=new nasal_val(vm_str);
|
||||
*str_addrs[i]->ptr.str=strs[i];
|
||||
strs[i]={vm_str,new nasal_val(vm_str)};
|
||||
strs[i].value.gcobj->unmut=1;
|
||||
*strs[i].str()=s[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
void nasal_gc::gc_clear()
|
||||
void nasal_gc::clear()
|
||||
{
|
||||
for(auto i:memory)
|
||||
delete i;
|
||||
memory.clear();
|
||||
for(int i=0;i<vm_type_size;++i)
|
||||
for(uint8_t i=0;i<vm_type_size;++i)
|
||||
while(!free_list[i].empty())
|
||||
free_list[i].pop();
|
||||
local.clear();
|
||||
|
||||
delete nil_addr;
|
||||
delete one_addr;
|
||||
delete zero_addr;
|
||||
for(auto i:num_addrs)
|
||||
delete i;
|
||||
num_addrs.clear();
|
||||
for(auto i:str_addrs)
|
||||
delete i;
|
||||
str_addrs.clear();
|
||||
return;
|
||||
for(auto& i:strs)
|
||||
delete i.value.gcobj;
|
||||
strs.clear();
|
||||
}
|
||||
nasal_ref nasal_gc::gc_alloc(int type)
|
||||
void nasal_gc::info()
|
||||
{
|
||||
const char* name[]={
|
||||
"null","cnt ","ret ",
|
||||
"nil ","num ","str ",
|
||||
"func","vec ","hash","obj "
|
||||
};
|
||||
std::cout<<"\ngarbage collector info:\n";
|
||||
for(uint8_t i=vm_str;i<vm_type_size;++i)
|
||||
std::cout<<name[i]<<" | "<<count[i]<<"\n";
|
||||
std::cout<<"\nmemory allocator info(max size):\n";
|
||||
for(uint8_t i=vm_str;i<vm_type_size;++i)
|
||||
std::cout<<name[i]<<" | "<<(size[i]+1)*increment[i]<<"(+"<<size[i]<<")\n";
|
||||
}
|
||||
nasal_ref nasal_gc::alloc(uint8_t type)
|
||||
{
|
||||
if(free_list[type].empty())
|
||||
{
|
||||
++count[type];
|
||||
mark();
|
||||
sweep();
|
||||
}
|
||||
if(free_list[type].empty())
|
||||
for(int i=0;i<increment[type];++i)
|
||||
{
|
||||
++size[type];
|
||||
for(uint32_t i=0;i<increment[type];++i)
|
||||
{
|
||||
nasal_ref tmp=new nasal_val(type);
|
||||
nasal_val* tmp=new nasal_val(type);
|
||||
memory.push_back(tmp);
|
||||
free_list[type].push(tmp);
|
||||
}
|
||||
nasal_ref ret=free_list[type].front();
|
||||
ret->mark=GC_UNCOLLECTED;
|
||||
}
|
||||
nasal_ref ret={type,free_list[type].front()};
|
||||
ret.value.gcobj->mark=GC_UNCOLLECTED;
|
||||
free_list[type].pop();
|
||||
return ret;
|
||||
}
|
||||
nasal_ref nasal_gc::builtin_alloc(int type)
|
||||
nasal_ref nasal_gc::builtin_alloc(uint8_t type)
|
||||
{
|
||||
// when running a builtin function,alloc will run more than one time
|
||||
// this may cause mark-sweep in gc_alloc
|
||||
// this may cause mark-sweep in gc::alloc
|
||||
// and the value got before will be collected,this is a fatal error
|
||||
// so use builtin_alloc in builtin functions if this function uses alloc more then one time
|
||||
if(free_list[type].empty())
|
||||
for(int i=0;i<increment[type];++i)
|
||||
{
|
||||
++size[type];
|
||||
for(uint32_t i=0;i<increment[type];++i)
|
||||
{
|
||||
nasal_ref tmp=new nasal_val(type);
|
||||
nasal_val* tmp=new nasal_val(type);
|
||||
memory.push_back(tmp);
|
||||
free_list[type].push(tmp);
|
||||
}
|
||||
nasal_ref ret=free_list[type].front();
|
||||
ret->mark=GC_UNCOLLECTED;
|
||||
}
|
||||
nasal_ref ret={type,free_list[type].front()};
|
||||
ret.value.gcobj->mark=GC_UNCOLLECTED;
|
||||
free_list[type].pop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
231
nasal_import.h
231
nasal_import.h
@@ -1,134 +1,99 @@
|
||||
#ifndef __NASAL_IMPORT_H__
|
||||
#define __NASAL_IMPORT_H__
|
||||
|
||||
class nasal_import
|
||||
{
|
||||
private:
|
||||
int error;
|
||||
nasal_lexer import_lex;
|
||||
nasal_parse import_par;
|
||||
nasal_ast import_ast;
|
||||
std::vector<std::string> filename_table;
|
||||
void die(const std::string&,const char*);
|
||||
bool check_import(const nasal_ast&);
|
||||
bool check_exist(const std::string&);
|
||||
void linker(nasal_ast&,nasal_ast&&);
|
||||
nasal_ast file_import(nasal_ast&);
|
||||
nasal_ast load(nasal_ast&,uint16_t);
|
||||
public:
|
||||
const int get_error(){return error;}
|
||||
void link(nasal_ast&,const std::string&);
|
||||
const nasal_ast&
|
||||
get_root(){return import_ast;}
|
||||
const std::vector<std::string>&
|
||||
get_file(){return filename_table;}
|
||||
};
|
||||
|
||||
void nasal_import::die(const std::string& filename,const char* error_stage)
|
||||
{
|
||||
++error;
|
||||
std::cout<<"[import] in <\""<<filename<<"\">: error(s) occurred in "<<error_stage<<".\n";
|
||||
return;
|
||||
}
|
||||
|
||||
bool nasal_import::check_import(const nasal_ast& node)
|
||||
{
|
||||
/*
|
||||
only this kind of node can be recognized as 'import':
|
||||
call
|
||||
id:import
|
||||
call_func
|
||||
string:'filename'
|
||||
*/
|
||||
if(node.get_type()!=ast_call)
|
||||
return false;
|
||||
const std::vector<nasal_ast>& ref_vec=node.get_children();
|
||||
if(ref_vec.size()!=2)
|
||||
return false;
|
||||
if(ref_vec[0].get_str()!="import")
|
||||
return false;
|
||||
if(ref_vec[1].get_type()!=ast_callf)
|
||||
return false;
|
||||
if(ref_vec[1].get_children().size()!=1 || ref_vec[1].get_children()[0].get_type()!=ast_str)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nasal_import::check_exist(const std::string& file)
|
||||
{
|
||||
// avoid importing the same file
|
||||
for(auto& fname:filename_table)
|
||||
if(file==fname)
|
||||
return true;
|
||||
filename_table.push_back(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
void nasal_import::linker(nasal_ast& root,nasal_ast&& add_root)
|
||||
{
|
||||
// add children of add_root to the back of root
|
||||
for(auto& i:add_root.get_children())
|
||||
root.add_child(std::move(i));
|
||||
return;
|
||||
}
|
||||
|
||||
nasal_ast nasal_import::file_import(nasal_ast& node)
|
||||
{
|
||||
// initializing
|
||||
nasal_ast tmp(0,ast_root);
|
||||
|
||||
// get filename and set node to ast_null
|
||||
std::string filename=node.get_children()[1].get_children()[0].get_str();
|
||||
node.clear();
|
||||
|
||||
// avoid infinite loading loop
|
||||
if(check_exist(filename))
|
||||
return tmp;
|
||||
|
||||
// start importing...
|
||||
import_lex.openfile(filename);
|
||||
import_lex.scanner();
|
||||
if(import_lex.get_error())
|
||||
{
|
||||
die(filename,"lexer");
|
||||
return tmp;
|
||||
}
|
||||
import_par.main_process(import_lex.get_token_list());
|
||||
if(import_par.get_error())
|
||||
{
|
||||
die(filename,"parser");
|
||||
return tmp;
|
||||
}
|
||||
tmp=std::move(import_par.get_root());
|
||||
// check if tmp has 'import'
|
||||
return load(tmp,filename_table.size()-1);
|
||||
}
|
||||
|
||||
nasal_ast nasal_import::load(nasal_ast& root,uint16_t fileindex)
|
||||
{
|
||||
nasal_ast new_root(0,ast_root);
|
||||
for(auto& i:root.get_children())
|
||||
if(check_import(i))
|
||||
linker(new_root,file_import(i));
|
||||
// add root to the back of new_root
|
||||
nasal_ast file_head(0,ast_file);
|
||||
file_head.set_num(fileindex);
|
||||
new_root.add_child(std::move(file_head));
|
||||
linker(new_root,std::move(root));
|
||||
return new_root;
|
||||
}
|
||||
|
||||
void nasal_import::link(nasal_ast& root,const std::string& self)
|
||||
{
|
||||
// initializing
|
||||
error=0;
|
||||
filename_table.clear();
|
||||
filename_table.push_back(self);
|
||||
import_ast.clear();
|
||||
// scan root and import files,then generate a new ast and return to import_ast
|
||||
// the main file's index is 0
|
||||
import_ast=load(root,0);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef __NASAL_IMPORT_H__
|
||||
#define __NASAL_IMPORT_H__
|
||||
|
||||
class nasal_import
|
||||
{
|
||||
private:
|
||||
nasal_err& nerr;
|
||||
std::vector<std::string> files;
|
||||
bool check_import(const nasal_ast&);
|
||||
bool check_exist(const std::string&);
|
||||
void linker(nasal_ast&,nasal_ast&&);
|
||||
nasal_ast file_import(nasal_ast&);
|
||||
nasal_ast load(nasal_ast&,uint16_t);
|
||||
public:
|
||||
nasal_import(nasal_err& e):nerr(e){}
|
||||
void link(nasal_parse&,const std::string&);
|
||||
const std::vector<std::string>& get_file() const {return files;}
|
||||
};
|
||||
|
||||
bool nasal_import::check_import(const nasal_ast& node)
|
||||
{
|
||||
/*
|
||||
only this kind of node can be recognized as 'import':
|
||||
call
|
||||
|_id:import
|
||||
|_call_func
|
||||
|_string:'filename'
|
||||
*/
|
||||
return (
|
||||
node.type()==ast_call &&
|
||||
node.size()==2 &&
|
||||
node[0].str()=="import" &&
|
||||
node[1].type()==ast_callf &&
|
||||
node[1].size()==1 &&
|
||||
node[1][0].type()==ast_str
|
||||
);
|
||||
}
|
||||
|
||||
bool nasal_import::check_exist(const std::string& file)
|
||||
{
|
||||
// avoid importing the same file
|
||||
for(auto& fname:files)
|
||||
if(file==fname)
|
||||
return true;
|
||||
files.push_back(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
void nasal_import::linker(nasal_ast& root,nasal_ast&& add_root)
|
||||
{
|
||||
// add children of add_root to the back of root
|
||||
for(auto& i:add_root.child())
|
||||
root.add(std::move(i));
|
||||
}
|
||||
|
||||
nasal_ast nasal_import::file_import(nasal_ast& node)
|
||||
{
|
||||
nasal_lexer lex(nerr);
|
||||
nasal_parse par(nerr);
|
||||
// get filename and set node to ast_null
|
||||
std::string filename=node[1][0].str();
|
||||
node.clear();
|
||||
|
||||
// avoid infinite loading loop
|
||||
if(check_exist(filename))
|
||||
return {0,ast_root};
|
||||
|
||||
// start importing...
|
||||
lex.scan(filename);
|
||||
par.compile(lex);
|
||||
nasal_ast tmp=std::move(par.ast());
|
||||
// check if tmp has 'import'
|
||||
return load(tmp,files.size()-1);
|
||||
}
|
||||
|
||||
nasal_ast nasal_import::load(nasal_ast& root,uint16_t fileindex)
|
||||
{
|
||||
nasal_ast new_root(0,ast_root);
|
||||
for(auto& i:root.child())
|
||||
if(check_import(i))
|
||||
linker(new_root,file_import(i));
|
||||
// add root to the back of new_root
|
||||
nasal_ast file_head(0,ast_file);
|
||||
file_head.set_num(fileindex);
|
||||
new_root.add(std::move(file_head));
|
||||
linker(new_root,std::move(root));
|
||||
return new_root;
|
||||
}
|
||||
|
||||
void nasal_import::link(nasal_parse& parse,const std::string& self)
|
||||
{
|
||||
// initializing
|
||||
files={self};
|
||||
// scan root and import files,then generate a new ast and return to import_ast
|
||||
// the main file's index is 0
|
||||
parse.ast()=load(parse.ast(),0);
|
||||
}
|
||||
|
||||
#endif
|
||||
714
nasal_lexer.h
714
nasal_lexer.h
@@ -1,362 +1,354 @@
|
||||
#ifndef __NASAL_LEXER_H__
|
||||
#define __NASAL_LEXER_H__
|
||||
|
||||
#define IS_IDENTIFIER(c) ((c=='_')||('a'<=c && c<='z')||('A'<=c&&c<='Z'))
|
||||
#define IS_HEX_NUMBER(c) (('0'<=c&&c<='9')||('a'<=c&&c<='f')||('A'<=c && c<='F'))
|
||||
#define IS_OCT_NUMEBR(c) ('0'<=c&&c<='7')
|
||||
#define IS_DIGIT(c) ('0'<=c&&c<='9')
|
||||
#define IS_STRING(c) (c=='\''||c=='\"'||c=='`')
|
||||
// single operators have only one character
|
||||
#define IS_SINGLE_OPERATOR(c) (c=='('||c==')'||c=='['||c==']'||c=='{'||c=='}'||c==','||c==';'||c=='|'||c==':'||\
|
||||
c=='?'||c=='`'||c=='&'||c=='@'||c=='%'||c=='$'||c=='^'||c=='\\')
|
||||
// calculation operators may have two chars, for example: += -= *= /= ~= != == >= <=
|
||||
#define IS_CALC_OPERATOR(c) (c=='='||c=='+'||c=='-'||c=='*'||c=='!'||c=='/'||c=='<'||c=='>'||c=='~')
|
||||
#define IS_NOTE(c) (c=='#')
|
||||
|
||||
enum token_type
|
||||
{
|
||||
tok_null=0,
|
||||
tok_num,tok_str,tok_id,
|
||||
tok_for,tok_forindex,tok_foreach,tok_while,
|
||||
tok_var,tok_func,tok_break,tok_continue,
|
||||
tok_ret,tok_if,tok_elsif,tok_else,tok_nil,
|
||||
tok_lcurve,tok_rcurve,
|
||||
tok_lbracket,tok_rbracket,
|
||||
tok_lbrace,tok_rbrace,
|
||||
tok_semi,tok_and,tok_or,tok_comma,tok_dot,tok_ellipsis,tok_quesmark,
|
||||
tok_colon,tok_add,tok_sub,tok_mult,tok_div,tok_link,tok_not,
|
||||
tok_eq,
|
||||
tok_addeq,tok_subeq,tok_multeq,tok_diveq,tok_lnkeq,
|
||||
tok_cmpeq,tok_neq,tok_less,tok_leq,tok_grt,tok_geq,
|
||||
tok_eof
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
const char* str;
|
||||
const int tok_type;
|
||||
}token_table[]=
|
||||
{
|
||||
{"for" ,tok_for },
|
||||
{"forindex",tok_forindex },
|
||||
{"foreach" ,tok_foreach },
|
||||
{"while" ,tok_while },
|
||||
{"var" ,tok_var },
|
||||
{"func" ,tok_func },
|
||||
{"break" ,tok_break },
|
||||
{"continue",tok_continue },
|
||||
{"return" ,tok_ret },
|
||||
{"if" ,tok_if },
|
||||
{"elsif" ,tok_elsif },
|
||||
{"else" ,tok_else },
|
||||
{"nil" ,tok_nil },
|
||||
{"(" ,tok_lcurve },
|
||||
{")" ,tok_rcurve },
|
||||
{"[" ,tok_lbracket },
|
||||
{"]" ,tok_rbracket },
|
||||
{"{" ,tok_lbrace },
|
||||
{"}" ,tok_rbrace },
|
||||
{";" ,tok_semi },
|
||||
{"and" ,tok_and },
|
||||
{"or" ,tok_or },
|
||||
{"," ,tok_comma },
|
||||
{"." ,tok_dot },
|
||||
{"..." ,tok_ellipsis },
|
||||
{"?" ,tok_quesmark },
|
||||
{":" ,tok_colon },
|
||||
{"+" ,tok_add },
|
||||
{"-" ,tok_sub },
|
||||
{"*" ,tok_mult },
|
||||
{"/" ,tok_div },
|
||||
{"~" ,tok_link },
|
||||
{"!" ,tok_not },
|
||||
{"=" ,tok_eq },
|
||||
{"+=" ,tok_addeq },
|
||||
{"-=" ,tok_subeq },
|
||||
{"*=" ,tok_multeq },
|
||||
{"/=" ,tok_diveq },
|
||||
{"~=" ,tok_lnkeq },
|
||||
{"==" ,tok_cmpeq },
|
||||
{"!=" ,tok_neq },
|
||||
{"<" ,tok_less },
|
||||
{"<=" ,tok_leq },
|
||||
{">" ,tok_grt },
|
||||
{">=" ,tok_geq },
|
||||
{nullptr ,-1 }
|
||||
};
|
||||
|
||||
struct token
|
||||
{
|
||||
int line;
|
||||
int type;
|
||||
std::string str;
|
||||
token(int l=0,int t=tok_null,std::string s=""){line=l;type=t;str=s;}
|
||||
};
|
||||
|
||||
class nasal_lexer
|
||||
{
|
||||
private:
|
||||
int error;
|
||||
int res_size;
|
||||
int line;
|
||||
int ptr;
|
||||
std::string line_code;
|
||||
std::string res;
|
||||
std::vector<token> token_list;
|
||||
int get_tok_type(const std::string&);
|
||||
void die(const char*);
|
||||
std::string id_gen();
|
||||
std::string num_gen();
|
||||
std::string str_gen();
|
||||
public:
|
||||
void openfile(const std::string&);
|
||||
void scanner();
|
||||
void print_token();
|
||||
int get_error(){return error;}
|
||||
std::vector<token>& get_token_list(){return token_list;}
|
||||
};
|
||||
|
||||
void nasal_lexer::openfile(const std::string& filename)
|
||||
{
|
||||
error=0;
|
||||
res.clear();
|
||||
std::ifstream fin(filename,std::ios::binary);
|
||||
if(fin.fail())
|
||||
{
|
||||
++error;
|
||||
std::cout<<"[lexer] cannot open file <"<<filename<<">.\n";
|
||||
return;
|
||||
}
|
||||
while(!fin.eof())
|
||||
{
|
||||
char c=fin.get();
|
||||
if(fin.eof())
|
||||
break;
|
||||
res+=c;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int nasal_lexer::get_tok_type(const std::string& tk_str)
|
||||
{
|
||||
for(int i=0;token_table[i].str;++i)
|
||||
if(tk_str==token_table[i].str)
|
||||
return token_table[i].tok_type;
|
||||
return tok_null;
|
||||
}
|
||||
|
||||
void nasal_lexer::die(const char* error_info)
|
||||
{
|
||||
++error;
|
||||
std::cout<<"[lexer] line "<<line<<" column "<<line_code.length()<<": \n"<<line_code<<"\n";
|
||||
for(auto i:line_code)
|
||||
std::cout<<(i=='\t'?'\t':' ');
|
||||
std::cout<<"^"<<error_info<<'\n';
|
||||
return;
|
||||
}
|
||||
|
||||
std::string nasal_lexer::id_gen()
|
||||
{
|
||||
std::string token_str="";
|
||||
while(ptr<res_size && (IS_IDENTIFIER(res[ptr])||IS_DIGIT(res[ptr])))
|
||||
token_str+=res[ptr++];
|
||||
line_code+=token_str;
|
||||
return token_str;
|
||||
// after running this process, ptr will point to the next token's beginning character
|
||||
}
|
||||
|
||||
std::string nasal_lexer::num_gen()
|
||||
{
|
||||
// generate hex number
|
||||
if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='x')
|
||||
{
|
||||
std::string token_str="0x";
|
||||
ptr+=2;
|
||||
while(ptr<res_size && IS_HEX_NUMBER(res[ptr]))
|
||||
token_str+=res[ptr++];
|
||||
line_code+=token_str;
|
||||
if(token_str.length()<3)// "0x"
|
||||
die("incorrect number.");
|
||||
return token_str;
|
||||
}
|
||||
// generate oct number
|
||||
else if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='o')
|
||||
{
|
||||
std::string token_str="0o";
|
||||
ptr+=2;
|
||||
while(ptr<res_size && IS_OCT_NUMEBR(res[ptr]))
|
||||
token_str+=res[ptr++];
|
||||
line_code+=token_str;
|
||||
if(token_str.length()<3)// "0o"
|
||||
die("incorrect number.");
|
||||
return token_str;
|
||||
}
|
||||
// generate dec number
|
||||
// dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
|
||||
std::string token_str="";
|
||||
while(ptr<res_size && IS_DIGIT(res[ptr]))
|
||||
token_str+=res[ptr++];
|
||||
if(ptr<res_size && res[ptr]=='.')
|
||||
{
|
||||
token_str+=res[ptr++];
|
||||
while(ptr<res_size && IS_DIGIT(res[ptr]))
|
||||
token_str+=res[ptr++];
|
||||
// "xxxx." is not a correct number
|
||||
if(token_str.back()=='.')
|
||||
{
|
||||
line_code+=token_str;
|
||||
die("incorrect number.");
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
if(ptr<res_size && (res[ptr]=='e' || res[ptr]=='E'))
|
||||
{
|
||||
token_str+=res[ptr++];
|
||||
if(ptr<res_size && (res[ptr]=='-' || res[ptr]=='+'))
|
||||
token_str+=res[ptr++];
|
||||
while(ptr<res_size && IS_DIGIT(res[ptr]))
|
||||
token_str+=res[ptr++];
|
||||
// "xxxe(-|+)" is not a correct number
|
||||
if(token_str.back()=='e' || token_str.back()=='E' || token_str.back()=='-' || token_str.back()=='+')
|
||||
{
|
||||
line_code+=token_str;
|
||||
die("incorrect number.");
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
line_code+=token_str;
|
||||
return token_str;
|
||||
}
|
||||
|
||||
std::string nasal_lexer::str_gen()
|
||||
{
|
||||
std::string token_str="";
|
||||
char str_begin=res[ptr];
|
||||
line_code+=str_begin;
|
||||
while(++ptr<res_size && res[ptr]!=str_begin)
|
||||
{
|
||||
line_code+=res[ptr];
|
||||
if(res[ptr]=='\n')
|
||||
{
|
||||
line_code="";
|
||||
++line;
|
||||
}
|
||||
if(res[ptr]=='\\' && ptr+1<res_size)
|
||||
{
|
||||
line_code+=res[++ptr];
|
||||
switch(res[ptr])
|
||||
{
|
||||
case 'a': token_str.push_back('\a');break;
|
||||
case 'b': token_str.push_back('\b');break;
|
||||
case 'f': token_str.push_back('\f');break;
|
||||
case 'n': token_str.push_back('\n');break;
|
||||
case 'r': token_str.push_back('\r');break;
|
||||
case 't': token_str.push_back('\t');break;
|
||||
case 'v': token_str.push_back('\v');break;
|
||||
case '?': token_str.push_back('\?');break;
|
||||
case '0': token_str.push_back('\0');break;
|
||||
case '\\':token_str.push_back('\\');break;
|
||||
case '\'':token_str.push_back('\'');break;
|
||||
case '\"':token_str.push_back('\"');break;
|
||||
default: token_str.push_back(res[ptr]);break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
token_str+=res[ptr];
|
||||
}
|
||||
// check if this string ends with a " or '
|
||||
if(ptr++>=res_size)
|
||||
die("get EOF when generating string.");
|
||||
if(str_begin=='`' && token_str.length()!=1)
|
||||
die("\'`\' is used for string that includes one character.");
|
||||
return token_str;
|
||||
}
|
||||
|
||||
void nasal_lexer::scanner()
|
||||
{
|
||||
token_list.clear();
|
||||
line=1;
|
||||
ptr=0;
|
||||
line_code="";
|
||||
res_size=res.size();
|
||||
|
||||
std::string token_str;
|
||||
while(ptr<res_size)
|
||||
{
|
||||
while(ptr<res_size && (res[ptr]==' ' || res[ptr]=='\n' || res[ptr]=='\t' || res[ptr]=='\r' || res[ptr]<0))
|
||||
{
|
||||
// these characters will be ignored, and '\n' will cause ++line
|
||||
line_code+=res[ptr];
|
||||
if(res[ptr++]=='\n')
|
||||
{
|
||||
++line;
|
||||
line_code="";
|
||||
}
|
||||
}
|
||||
if(ptr>=res_size) break;
|
||||
if(IS_IDENTIFIER(res[ptr]))
|
||||
{
|
||||
token_str=id_gen();
|
||||
token_list.push_back({line,get_tok_type(token_str),token_str});
|
||||
if(!token_list.back().type)
|
||||
token_list.back().type=tok_id;
|
||||
}
|
||||
else if(IS_DIGIT(res[ptr]))
|
||||
token_list.push_back({line,tok_num,num_gen()});
|
||||
else if(IS_STRING(res[ptr]))
|
||||
token_list.push_back({line,tok_str,str_gen()});
|
||||
else if(IS_SINGLE_OPERATOR(res[ptr]))
|
||||
{
|
||||
token_str=res[ptr];
|
||||
line_code+=res[ptr];
|
||||
int type=get_tok_type(token_str);
|
||||
if(!type)
|
||||
die("incorrect operator.");
|
||||
token_list.push_back({line,type,token_str});
|
||||
++ptr;
|
||||
}
|
||||
else if(res[ptr]=='.')
|
||||
{
|
||||
if(ptr+2<res_size && res[ptr+1]=='.' && res[ptr+2]=='.')
|
||||
{
|
||||
token_str="...";
|
||||
ptr+=3;
|
||||
}
|
||||
else
|
||||
{
|
||||
token_str=".";
|
||||
++ptr;
|
||||
}
|
||||
line_code+=token_str;
|
||||
token_list.push_back({line,get_tok_type(token_str),token_str});
|
||||
}
|
||||
else if(IS_CALC_OPERATOR(res[ptr]))
|
||||
{
|
||||
// get calculation operator
|
||||
token_str=res[ptr++];
|
||||
if(ptr<res_size && res[ptr]=='=')
|
||||
token_str+=res[ptr++];
|
||||
line_code+=token_str;
|
||||
token_list.push_back({line,get_tok_type(token_str),token_str});
|
||||
}
|
||||
else if(IS_NOTE(res[ptr]))// avoid note, after this process ptr will point to a '\n', so next loop line counter+1
|
||||
while(++ptr<res_size && res[ptr]!='\n');
|
||||
else
|
||||
{
|
||||
line_code+=res[ptr++];
|
||||
die("unknown character.");
|
||||
}
|
||||
}
|
||||
token_list.push_back({line,tok_eof,""});
|
||||
res.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
void nasal_lexer::print_token()
|
||||
{
|
||||
for(auto& tok:token_list)
|
||||
std::cout<<"("<<tok.line<<" | "<<tok.str<<")\n";
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef __NASAL_LEXER_H__
|
||||
#define __NASAL_LEXER_H__
|
||||
|
||||
#define ID(c) ((c=='_')||('a'<=c && c<='z')||('A'<=c&&c<='Z'))
|
||||
#define HEX(c) (('0'<=c&&c<='9')||('a'<=c&&c<='f')||('A'<=c && c<='F'))
|
||||
#define OCT(c) ('0'<=c&&c<='7')
|
||||
#define DIGIT(c) ('0'<=c&&c<='9')
|
||||
#define STR(c) (c=='\''||c=='\"'||c=='`')
|
||||
// single operators have only one character
|
||||
#define SINGLE_OPERATOR(c) (c=='('||c==')'||c=='['||c==']'||c=='{'||c=='}'||c==','||c==';'||c=='|'||c==':'||\
|
||||
c=='?'||c=='`'||c=='&'||c=='@'||c=='%'||c=='$'||c=='^'||c=='\\')
|
||||
// calculation operators may have two chars, for example: += -= *= /= ~= != == >= <=
|
||||
#define CALC_OPERATOR(c) (c=='='||c=='+'||c=='-'||c=='*'||c=='!'||c=='/'||c=='<'||c=='>'||c=='~')
|
||||
#define NOTE(c) (c=='#')
|
||||
|
||||
enum token_type
|
||||
{
|
||||
tok_null=0,// null token default token type
|
||||
tok_num, // number basic token type
|
||||
tok_str, // string basic token type
|
||||
tok_id, // identifier basic token type
|
||||
tok_for,tok_forindex,tok_foreach,tok_while,
|
||||
tok_var,tok_func,tok_break,tok_continue,
|
||||
tok_ret,tok_if,tok_elsif,tok_else,tok_nil,
|
||||
tok_lcurve,tok_rcurve,
|
||||
tok_lbracket,tok_rbracket,
|
||||
tok_lbrace,tok_rbrace,
|
||||
tok_semi,tok_and,tok_or,tok_comma,tok_dot,tok_ellipsis,tok_quesmark,
|
||||
tok_colon,tok_add,tok_sub,tok_mult,tok_div,tok_link,tok_not,
|
||||
tok_eq,
|
||||
tok_addeq,tok_subeq,tok_multeq,tok_diveq,tok_lnkeq,
|
||||
tok_cmpeq,tok_neq,tok_less,tok_leq,tok_grt,tok_geq,
|
||||
tok_eof // end of token list
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
const char* str;
|
||||
const uint32_t tok_type;
|
||||
}token_table[]=
|
||||
{
|
||||
{"for" ,tok_for },
|
||||
{"forindex",tok_forindex },
|
||||
{"foreach" ,tok_foreach },
|
||||
{"while" ,tok_while },
|
||||
{"var" ,tok_var },
|
||||
{"func" ,tok_func },
|
||||
{"break" ,tok_break },
|
||||
{"continue",tok_continue },
|
||||
{"return" ,tok_ret },
|
||||
{"if" ,tok_if },
|
||||
{"elsif" ,tok_elsif },
|
||||
{"else" ,tok_else },
|
||||
{"nil" ,tok_nil },
|
||||
{"(" ,tok_lcurve },
|
||||
{")" ,tok_rcurve },
|
||||
{"[" ,tok_lbracket },
|
||||
{"]" ,tok_rbracket },
|
||||
{"{" ,tok_lbrace },
|
||||
{"}" ,tok_rbrace },
|
||||
{";" ,tok_semi },
|
||||
{"and" ,tok_and },
|
||||
{"or" ,tok_or },
|
||||
{"," ,tok_comma },
|
||||
{"." ,tok_dot },
|
||||
{"..." ,tok_ellipsis },
|
||||
{"?" ,tok_quesmark },
|
||||
{":" ,tok_colon },
|
||||
{"+" ,tok_add },
|
||||
{"-" ,tok_sub },
|
||||
{"*" ,tok_mult },
|
||||
{"/" ,tok_div },
|
||||
{"~" ,tok_link },
|
||||
{"!" ,tok_not },
|
||||
{"=" ,tok_eq },
|
||||
{"+=" ,tok_addeq },
|
||||
{"-=" ,tok_subeq },
|
||||
{"*=" ,tok_multeq },
|
||||
{"/=" ,tok_diveq },
|
||||
{"~=" ,tok_lnkeq },
|
||||
{"==" ,tok_cmpeq },
|
||||
{"!=" ,tok_neq },
|
||||
{"<" ,tok_less },
|
||||
{"<=" ,tok_leq },
|
||||
{">" ,tok_grt },
|
||||
{">=" ,tok_geq },
|
||||
{nullptr ,0 }
|
||||
};
|
||||
|
||||
struct token
|
||||
{
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
uint32_t type;
|
||||
std::string str;
|
||||
token(uint32_t l=0,uint32_t c=0,uint32_t t=tok_null,std::string s="")
|
||||
{
|
||||
line=l;
|
||||
column=c;
|
||||
type=t;
|
||||
str=s;
|
||||
}
|
||||
};
|
||||
|
||||
class nasal_lexer
|
||||
{
|
||||
private:
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
uint32_t ptr;
|
||||
nasal_err& nerr;
|
||||
std::string res;
|
||||
std::vector<token> tokens;
|
||||
|
||||
uint32_t get_type(const std::string&);
|
||||
void die(std::string info){nerr.err("lexer",line,column,info);};
|
||||
void open(const std::string&);
|
||||
std::string id_gen();
|
||||
std::string num_gen();
|
||||
std::string str_gen();
|
||||
public:
|
||||
nasal_lexer(nasal_err& e):nerr(e){}
|
||||
void scan(const std::string&);
|
||||
void print();
|
||||
const std::vector<token>& get_tokens() const {return tokens;}
|
||||
};
|
||||
|
||||
void nasal_lexer::open(const std::string& file)
|
||||
{
|
||||
std::ifstream fin(file,std::ios::binary);
|
||||
if(fin.fail())
|
||||
nerr.err("lexer","cannot open file <"+file+">.");
|
||||
else
|
||||
nerr.load(file);
|
||||
std::stringstream ss;
|
||||
ss<<fin.rdbuf();
|
||||
res=ss.str();
|
||||
}
|
||||
|
||||
uint32_t nasal_lexer::get_type(const std::string& tk_str)
|
||||
{
|
||||
for(int i=0;token_table[i].str;++i)
|
||||
if(tk_str==token_table[i].str)
|
||||
return token_table[i].tok_type;
|
||||
return tok_null;
|
||||
}
|
||||
|
||||
std::string nasal_lexer::id_gen()
|
||||
{
|
||||
std::string str="";
|
||||
while(ptr<res.size() && (ID(res[ptr])||DIGIT(res[ptr])))
|
||||
str+=res[ptr++];
|
||||
column+=str.length();
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string nasal_lexer::num_gen()
|
||||
{
|
||||
// generate hex number
|
||||
if(ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='x')
|
||||
{
|
||||
std::string str="0x";
|
||||
ptr+=2;
|
||||
while(ptr<res.size() && HEX(res[ptr]))
|
||||
str+=res[ptr++];
|
||||
column+=str.length();
|
||||
if(str.length()<3)// "0x"
|
||||
die("invalid number:"+str);
|
||||
return str;
|
||||
}
|
||||
// generate oct number
|
||||
else if(ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='o')
|
||||
{
|
||||
std::string str="0o";
|
||||
ptr+=2;
|
||||
while(ptr<res.size() && OCT(res[ptr]))
|
||||
str+=res[ptr++];
|
||||
column+=str.length();
|
||||
if(str.length()<3)// "0o"
|
||||
die("invalid number:"+str);
|
||||
return str;
|
||||
}
|
||||
// generate dec number
|
||||
// dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
|
||||
std::string str="";
|
||||
while(ptr<res.size() && DIGIT(res[ptr]))
|
||||
str+=res[ptr++];
|
||||
if(ptr<res.size() && res[ptr]=='.')
|
||||
{
|
||||
str+=res[ptr++];
|
||||
while(ptr<res.size() && DIGIT(res[ptr]))
|
||||
str+=res[ptr++];
|
||||
// "xxxx." is not a correct number
|
||||
if(str.back()=='.')
|
||||
{
|
||||
column+=str.length();
|
||||
die("invalid number:"+str);
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
if(ptr<res.size() && (res[ptr]=='e' || res[ptr]=='E'))
|
||||
{
|
||||
str+=res[ptr++];
|
||||
if(ptr<res.size() && (res[ptr]=='-' || res[ptr]=='+'))
|
||||
str+=res[ptr++];
|
||||
while(ptr<res.size() && DIGIT(res[ptr]))
|
||||
str+=res[ptr++];
|
||||
// "xxxe(-|+)" is not a correct number
|
||||
if(str.back()=='e' || str.back()=='E' || str.back()=='-' || str.back()=='+')
|
||||
{
|
||||
column+=str.length();
|
||||
die("invalid number:"+str);
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
column+=str.length();
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string nasal_lexer::str_gen()
|
||||
{
|
||||
std::string str="";
|
||||
char begin=res[ptr];
|
||||
++column;
|
||||
while(++ptr<res.size() && res[ptr]!=begin)
|
||||
{
|
||||
++column;
|
||||
if(res[ptr]=='\n')
|
||||
{
|
||||
column=0;
|
||||
++line;
|
||||
}
|
||||
if(res[ptr]=='\\' && ptr+1<res.size())
|
||||
{
|
||||
++column;
|
||||
++ptr;
|
||||
switch(res[ptr])
|
||||
{
|
||||
case '0': str+='\0'; break;
|
||||
case 'a': str+='\a'; break;
|
||||
case 'b': str+='\b'; break;
|
||||
case 't': str+='\t'; break;
|
||||
case 'n': str+='\n'; break;
|
||||
case 'v': str+='\v'; break;
|
||||
case 'f': str+='\f'; break;
|
||||
case 'r': str+='\r'; break;
|
||||
case '?': str+='\?'; break;
|
||||
case '\\':str+='\\'; break;
|
||||
case '\'':str+='\''; break;
|
||||
case '\"':str+='\"'; break;
|
||||
default: str+=res[ptr];break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
str+=res[ptr];
|
||||
}
|
||||
// check if this string ends with a " or '
|
||||
if(ptr++>=res.size())
|
||||
{
|
||||
die("get EOF when generating string.");
|
||||
return str;
|
||||
}
|
||||
++column;
|
||||
if(begin=='`' && str.length()!=1)
|
||||
die("\'`\' is used for string that includes one character.");
|
||||
return str;
|
||||
}
|
||||
|
||||
void nasal_lexer::scan(const std::string& file)
|
||||
{
|
||||
line=1;
|
||||
column=0;
|
||||
ptr=0;
|
||||
open(file);
|
||||
|
||||
std::string str;
|
||||
while(ptr<res.size())
|
||||
{
|
||||
while(ptr<res.size() && (res[ptr]==' ' || res[ptr]=='\n' || res[ptr]=='\t' || res[ptr]=='\r' || res[ptr]<0))
|
||||
{
|
||||
// these characters will be ignored, and '\n' will cause ++line
|
||||
++column;
|
||||
if(res[ptr++]=='\n')
|
||||
{
|
||||
++line;
|
||||
column=0;
|
||||
}
|
||||
}
|
||||
if(ptr>=res.size()) break;
|
||||
if(ID(res[ptr]))
|
||||
{
|
||||
str=id_gen();
|
||||
uint32_t type=get_type(str);
|
||||
tokens.push_back({line,column,type?type:tok_id,str});
|
||||
}
|
||||
else if(DIGIT(res[ptr]))
|
||||
{
|
||||
str=num_gen(); // make sure column is correct
|
||||
tokens.push_back({line,column,tok_num,str});
|
||||
}
|
||||
else if(STR(res[ptr]))
|
||||
{
|
||||
str=str_gen(); // make sure column is correct
|
||||
tokens.push_back({line,column,tok_str,str});
|
||||
}
|
||||
else if(SINGLE_OPERATOR(res[ptr]))
|
||||
{
|
||||
str=res[ptr];
|
||||
++column;
|
||||
uint32_t type=get_type(str);
|
||||
if(!type)
|
||||
die("invalid operator:"+str);
|
||||
tokens.push_back({line,column,type,str});
|
||||
++ptr;
|
||||
}
|
||||
else if(res[ptr]=='.')
|
||||
{
|
||||
str=".";
|
||||
if(ptr+2<res.size() && res[ptr+1]=='.' && res[ptr+2]=='.')
|
||||
str+="..";
|
||||
ptr+=str.length();
|
||||
column+=str.length();
|
||||
tokens.push_back({line,column,get_type(str),str});
|
||||
}
|
||||
else if(CALC_OPERATOR(res[ptr]))
|
||||
{
|
||||
// get calculation operator
|
||||
str=res[ptr++];
|
||||
if(ptr<res.size() && res[ptr]=='=')
|
||||
str+=res[ptr++];
|
||||
column+=str.length();
|
||||
tokens.push_back({line,column,get_type(str),str});
|
||||
}
|
||||
else if(NOTE(res[ptr]))// avoid note, after this process ptr will point to a '\n', so next loop line counter+1
|
||||
while(++ptr<res.size() && res[ptr]!='\n');
|
||||
else
|
||||
{
|
||||
++column;
|
||||
++ptr;
|
||||
die("unknown character.");
|
||||
}
|
||||
}
|
||||
tokens.push_back({line,column,tok_eof,"eof"});
|
||||
res="";
|
||||
nerr.chkerr();
|
||||
}
|
||||
|
||||
void nasal_lexer::print()
|
||||
{
|
||||
for(auto& tok:tokens)
|
||||
std::cout<<"("<<tok.line<<" | "<<rawstr(tok.str)<<")\n";
|
||||
}
|
||||
|
||||
#endif
|
||||
62
nasal_opt.h
Normal file
62
nasal_opt.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef __NASAL_OPT_H__
|
||||
#define __NASAL_OPT_H__
|
||||
|
||||
void const_str(nasal_ast& root)
|
||||
{
|
||||
auto& vec=root.child();
|
||||
root.set_str(vec[0].str()+vec[1].str());
|
||||
root.child().clear();
|
||||
root.set_type(ast_str);
|
||||
}
|
||||
|
||||
void const_num(nasal_ast& root)
|
||||
{
|
||||
auto& vec=root.child();
|
||||
double res;
|
||||
switch(root.type())
|
||||
{
|
||||
case ast_add: res=vec[0].num()+vec[1].num(); break;
|
||||
case ast_sub: res=vec[0].num()-vec[1].num(); break;
|
||||
case ast_mult:res=vec[0].num()*vec[1].num(); break;
|
||||
case ast_div: res=vec[0].num()/vec[1].num(); break;
|
||||
case ast_less:res=vec[0].num()<vec[1].num(); break;
|
||||
case ast_leq: res=vec[0].num()<=vec[1].num();break;
|
||||
case ast_grt: res=vec[0].num()>vec[1].num(); break;
|
||||
case ast_geq: res=vec[0].num()>=vec[1].num();break;
|
||||
}
|
||||
// inf and nan will cause number hashmap error in codegen
|
||||
if(std::isinf(res) || std::isnan(res))
|
||||
return;
|
||||
root.set_num(res);
|
||||
root.child().clear();
|
||||
root.set_type(ast_num);
|
||||
}
|
||||
|
||||
void calc_const(nasal_ast& root)
|
||||
{
|
||||
auto& vec=root.child();
|
||||
for(auto& i:vec)
|
||||
calc_const(i);
|
||||
if(vec.size()!=2)
|
||||
return;
|
||||
if(root.type()!=ast_add &&
|
||||
root.type()!=ast_sub &&
|
||||
root.type()!=ast_mult &&
|
||||
root.type()!=ast_div &&
|
||||
root.type()!=ast_link &&
|
||||
root.type()!=ast_less &&
|
||||
root.type()!=ast_leq &&
|
||||
root.type()!=ast_grt &&
|
||||
root.type()!=ast_geq)
|
||||
return;
|
||||
if(root.type()==ast_link && vec[0].type()==ast_str && vec[1].type()==ast_str)
|
||||
const_str(root);
|
||||
else if(root.type()!=ast_link && vec[0].type()==ast_num && vec[1].type()==ast_num)
|
||||
const_num(root);
|
||||
}
|
||||
void optimize(nasal_ast& root)
|
||||
{
|
||||
for(auto& i:root.child())
|
||||
calc_const(i);
|
||||
}
|
||||
#endif
|
||||
2026
nasal_parse.h
2026
nasal_parse.h
File diff suppressed because it is too large
Load Diff
1181
nasal_vm.h
1181
nasal_vm.h
File diff suppressed because it is too large
Load Diff
BIN
pic/benchmark.png
Normal file
BIN
pic/benchmark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
395
stl/lib.nas
395
stl/lib.nas
@@ -1,149 +1,318 @@
|
||||
var import=func(filename)
|
||||
{
|
||||
# lib.nas
|
||||
|
||||
# import is used to link another file, this lib function will do nothing.
|
||||
# because nasal_import will recognize this and link files before generating bytecode.
|
||||
var import=func(filename){
|
||||
return __builtin_import(filename);
|
||||
}
|
||||
var print=func(elems...)
|
||||
{
|
||||
|
||||
# print is used to print all things in nasal, try and see how it works.
|
||||
# this function uses std::cout/printf to output logs.
|
||||
var print=func(elems...){
|
||||
return __builtin_print(elems);
|
||||
};
|
||||
var println=func(elems...)
|
||||
{
|
||||
}
|
||||
|
||||
# append is used to add values into a vector.
|
||||
var append=func(vec,elems...){
|
||||
return __builtin_append(vec,elems);
|
||||
}
|
||||
|
||||
# setsize is used to change the size of vector.
|
||||
# if the size is larger than before,
|
||||
# this function will fill vm_nil into uninitialized space.
|
||||
var setsize=func(vec,size){
|
||||
return __builtin_setsize(vec,size);
|
||||
}
|
||||
|
||||
# system has the same use in C.
|
||||
var system=func(str){
|
||||
return __builtin_system(str);
|
||||
}
|
||||
|
||||
# input uses std::cin and returns what we input.
|
||||
var input=func(){
|
||||
return __builtin_input();
|
||||
}
|
||||
|
||||
# split a string by delimiter for example:
|
||||
# split("ll","hello world") -> ["he","o world"]
|
||||
# this function will return a vector.
|
||||
var split=func(deli,str){
|
||||
return __builtin_split(deli,str);
|
||||
}
|
||||
|
||||
# rand has the same function as the rand in C
|
||||
# if seed is nil, it will return the random number.
|
||||
# if seed is not nil, it will be initialized by this seed.
|
||||
var rand=func(seed=nil){
|
||||
return __builtin_rand(seed);
|
||||
}
|
||||
|
||||
# id will return the pointer of an gc-object.
|
||||
# if this object is not managed by gc, it will return 0.
|
||||
var id=func(object){
|
||||
return __builtin_id(object);
|
||||
}
|
||||
|
||||
# int will get the integer of input number.
|
||||
# but carefully use it, because int has range between -2147483648~2147483647
|
||||
var int=func(val){
|
||||
return __builtin_int(val);
|
||||
}
|
||||
|
||||
# num will change all the other types into number.
|
||||
# mostly used to change a numerable string.
|
||||
var num=func(val){
|
||||
return __builtin_num(val);
|
||||
}
|
||||
|
||||
# pop used to pop the last element in a vector.
|
||||
# this function will return the value that poped if vector has element(s).
|
||||
# if the vector is empty, it will return nil.
|
||||
var pop=func(vec){
|
||||
return __builtin_pop(vec);
|
||||
}
|
||||
|
||||
# str is used to change number into string.
|
||||
var str=func(num){
|
||||
return __builtin_str(num);
|
||||
}
|
||||
|
||||
# size can get the size of a string/vector/hashmap.
|
||||
# in fact it can also get the size of number, and the result is the number itself.
|
||||
# so don't do useless things, though it really works.
|
||||
var size=func(object){
|
||||
return __builtin_size(object);
|
||||
}
|
||||
|
||||
# contains is used to check if a key exists in a hashmap/dict.
|
||||
var contains=func(hash,key){
|
||||
return __builtin_contains(hash,key);
|
||||
}
|
||||
|
||||
# delete is used to delete a pair in a hashmap/dict by key.
|
||||
var delete=func(hash,key){
|
||||
return __builtin_delete(hash,key);
|
||||
}
|
||||
|
||||
# keys is used to get all keys in a hashmap/dict.
|
||||
# this function will return a vector.
|
||||
var keys=func(hash){
|
||||
return __builtin_keys(hash);
|
||||
}
|
||||
|
||||
# time has the same function in C.
|
||||
var time=func(begin){
|
||||
return __builtin_time(begin);
|
||||
}
|
||||
|
||||
# die is a special native function.
|
||||
# use it at where you want the program to crash immediately.
|
||||
var die=func(str){
|
||||
return __builtin_die(str);
|
||||
}
|
||||
|
||||
# typeof is used to get the type of an object.
|
||||
# this function returns a string.
|
||||
var typeof=func(object){
|
||||
return __builtin_type(object);
|
||||
}
|
||||
|
||||
# substr will get the sub-string.
|
||||
# it gets the string, the begin index and sub-string's length as arguments.
|
||||
var substr=func(str,begin,len){
|
||||
return __builtin_substr(str,begin,len);
|
||||
}
|
||||
|
||||
# streq is used to compare if two strings are the same.
|
||||
var streq=func(a,b){
|
||||
return __builtin_streq(a,b);
|
||||
}
|
||||
|
||||
# left is used to get the sub-string like substr.
|
||||
# but the begin index is 0.
|
||||
var left=func(str,len){
|
||||
return __builtin_left(str,len);
|
||||
}
|
||||
|
||||
# right i used to get the sub-string like substr.
|
||||
# but the begin index is strlen-len.
|
||||
var right=func(str,len){
|
||||
return __builtin_right(str,len);
|
||||
}
|
||||
|
||||
# cmp is used to compare two strings.
|
||||
# normal string will not be correctly compared by operators < > <= >=
|
||||
# because these operators will turn strings into numbers then compare.
|
||||
var cmp=func(a,b){
|
||||
return __builtin_cmp(a,b);
|
||||
}
|
||||
|
||||
# chr is used to get the character by ascii-number.
|
||||
# for example chr(65) -> 'A'
|
||||
var chr=func(code){
|
||||
return __builtin_chr(code);
|
||||
}
|
||||
|
||||
# println has the same function as print.
|
||||
# but it will output a '\n' after using print.
|
||||
var println=func(elems...){
|
||||
__builtin_print(elems);
|
||||
elems=['\n'];
|
||||
return __builtin_print(elems);
|
||||
}
|
||||
var append=func(vec,elems...)
|
||||
{
|
||||
return __builtin_append(vec,elems);
|
||||
}
|
||||
var setsize=func(vec,size)
|
||||
{
|
||||
return __builtin_setsize(vec,size);
|
||||
}
|
||||
var system=func(str)
|
||||
{
|
||||
return __builtin_system(str);
|
||||
}
|
||||
var input=func()
|
||||
{
|
||||
return __builtin_input();
|
||||
}
|
||||
var sleep=func(duration)
|
||||
{
|
||||
return __builtin_sleep(duration);
|
||||
}
|
||||
var split=func(deli,str)
|
||||
{
|
||||
return __builtin_split(deli,str);
|
||||
}
|
||||
var rand=func(seed=nil)
|
||||
{
|
||||
return __builtin_rand(seed);
|
||||
}
|
||||
var id=func(object)
|
||||
{
|
||||
return __builtin_id(object);
|
||||
}
|
||||
var int=func(val)
|
||||
{
|
||||
return __builtin_int(val);
|
||||
}
|
||||
var num=func(val)
|
||||
{
|
||||
return __builtin_num(val);
|
||||
}
|
||||
var pop=func(vec)
|
||||
{
|
||||
return __builtin_pop(vec);
|
||||
}
|
||||
var str=func(num)
|
||||
{
|
||||
return __builtin_str(num);
|
||||
}
|
||||
var size=func(object)
|
||||
{
|
||||
return __builtin_size(object);
|
||||
}
|
||||
var contains=func(hash,key)
|
||||
{
|
||||
return __builtin_contains(hash,key);
|
||||
}
|
||||
var delete=func(hash,key)
|
||||
{
|
||||
return __builtin_delete(hash,key);
|
||||
}
|
||||
var keys=func(hash)
|
||||
{
|
||||
return __builtin_keys(hash);
|
||||
}
|
||||
var time=func(begin_time)
|
||||
{
|
||||
return __builtin_time(begin_time);
|
||||
}
|
||||
var die=func(str)
|
||||
{
|
||||
return __builtin_die(str);
|
||||
}
|
||||
var typeof=func(object)
|
||||
{
|
||||
return __builtin_type(object);
|
||||
}
|
||||
var substr=func(str,begin,len)
|
||||
{
|
||||
return __builtin_substr(str,begin,len);
|
||||
}
|
||||
var streq=func(a,b)
|
||||
{
|
||||
return __builtin_streq(a,b);
|
||||
}
|
||||
var left=func(str,len)
|
||||
{
|
||||
return __builtin_left(str,len);
|
||||
}
|
||||
var right=func(str,len)
|
||||
{
|
||||
return __builtin_right(str,len);
|
||||
}
|
||||
var cmp=func(a,b)
|
||||
{
|
||||
return __builtin_cmp(a,b);
|
||||
}
|
||||
var chr=func(code)
|
||||
{
|
||||
return __builtin_chr(code);
|
||||
}
|
||||
|
||||
var io=
|
||||
{
|
||||
fin: func(filename){return __builtin_fin(filename);},
|
||||
fout:func(filename,str){return __builtin_fout(filename,str);}
|
||||
SEEK_SET:0,
|
||||
SEEK_CUR:1,
|
||||
SEEK_END:2,
|
||||
# get content of a file by filename. returns a string.
|
||||
fin: func(filename){return __builtin_fin(filename);},
|
||||
# input a string as the content of a file.
|
||||
fout: func(filename,str){return __builtin_fout(filename,str);},
|
||||
# same as C fopen. open file and get the FILE*.
|
||||
open: func(filename,mode="r"){return __builtin_open(filename,mode);},
|
||||
# same as C fclose. close file by FILE*.
|
||||
close: func(filehandle){return __builtin_close(filehandle);},
|
||||
# same as C fread. read file by FILE*.
|
||||
read: func(filehandle,buf,len){return __builtin_read(filehandle,buf,len);},
|
||||
# same as C fwrite. write file by FILE*.
|
||||
write: func(filehandle,str){return __builtin_write(filehandle,str);},
|
||||
# same as C fseek. seek place by FILE*.
|
||||
seek: func(filehandle,pos,whence){return __builtin_seek(filehandle,pos,whence);},
|
||||
# same as C ftell.
|
||||
tell: func(filehandle){return __builtin_tell(filehandle);},
|
||||
# read file by lines. use FILE*.
|
||||
# get nil if EOF
|
||||
readln:func(filehandle){return __builtin_readln(filehandle);},
|
||||
# same as C stat.
|
||||
stat: func(filename){return __builtin_stat(filename);},
|
||||
# same as C feof. check if FILE* gets the end of file(EOF).
|
||||
eof: func(filehandle){return __builtin_eof(filehandle);}
|
||||
};
|
||||
|
||||
# get file status. using data from io.stat
|
||||
var fstat=func(filename){
|
||||
var s=io.stat(filename);
|
||||
return {
|
||||
st_dev: s[0],
|
||||
st_ino: s[1],
|
||||
st_mode: s[2],
|
||||
st_nlink:s[3],
|
||||
st_uid: s[4],
|
||||
st_gid: s[5],
|
||||
st_rdev: s[6],
|
||||
st_size: s[7],
|
||||
st_atime:s[8],
|
||||
st_mtime:s[9],
|
||||
st_ctime:s[10]
|
||||
};
|
||||
}
|
||||
|
||||
# functions that do bitwise calculation.
|
||||
# carefully use it, all the calculations are based on integer.
|
||||
var bits=
|
||||
{
|
||||
# xor
|
||||
bitxor: func(a,b){return __builtin_xor(a,b); },
|
||||
# and
|
||||
bitand: func(a,b){return __builtin_and(a,b); },
|
||||
# or
|
||||
bitor: func(a,b){return __builtin_or(a,b); },
|
||||
# nand
|
||||
bitnand: func(a,b){return __builtin_nand(a,b);},
|
||||
bitnot: func(a) {return __builtin_not(a); }
|
||||
# not
|
||||
bitnot: func(a) {return __builtin_not(a); },
|
||||
# get bit data from a special string. for example:
|
||||
# bits.fld(s,0,3);
|
||||
# if s stores 10100010(162)
|
||||
# will get 101(5).
|
||||
fld: func(str,startbit,len){return __builtin_fld;},
|
||||
# get sign-extended data from a special string. for example:
|
||||
# bits.sfld(s,0,3);
|
||||
# if s stores 10100010(162)
|
||||
# will get 101(5) then this will be signed extended to
|
||||
# 11111101(-3).
|
||||
sfld: func(str,startbit,len){return __builtin_sfld;},
|
||||
# set value into a special string to store it. little-endian, for example:
|
||||
# bits.setfld(s,0,8,69);
|
||||
# set 01000101(69) to string will get this:
|
||||
# 10100010(162)
|
||||
# so s[0]=162.
|
||||
setfld: func(str,startbit,len,val){return __builtin_setfld;},
|
||||
# get a special string filled by '\0' to use in setfld.
|
||||
buf: func(len){return __builtin_buf;}
|
||||
};
|
||||
|
||||
# mostly used math functions and special constants, you know.
|
||||
var math=
|
||||
{
|
||||
e: 2.7182818284590452354,
|
||||
pi: 3.14159265358979323846264338327950288,
|
||||
inf: 1/0,
|
||||
nan: 0/0,
|
||||
sin: func(x) {return __builtin_sin(x); },
|
||||
cos: func(x) {return __builtin_cos(x); },
|
||||
tan: func(x) {return __builtin_tan(x); },
|
||||
exp: func(x) {return __builtin_exp(x); },
|
||||
exp: func(x) {return __builtin_exp(x); },
|
||||
lg: func(x) {return __builtin_lg(x); },
|
||||
ln: func(x) {return __builtin_ln(x); },
|
||||
sqrt: func(x) {return __builtin_sqrt(x); },
|
||||
atan2: func(x,y){return __builtin_atan2(x,y);},
|
||||
inf: 1/0,
|
||||
nan: 0/0,
|
||||
isnan: func(x) {return __builtin_isnan(x); }
|
||||
};
|
||||
|
||||
var unix=
|
||||
{
|
||||
pipe: func(){die("not supported yet");},
|
||||
fork: func(){die("not supported yet");},
|
||||
dup2: func(fd0,fd1){die("not supported yet");},
|
||||
exec: func(filename,argv,envp){die("not supported yet");},
|
||||
waitpid: func(pid,nohang=0){die("not supported yet");},
|
||||
isdir: func(path){return bits.bitand(io.stat(path)[2],0x4000);}, # S_IFDIR 0x4000
|
||||
isfile: func(path){return bits.bitand(io.stat(path)[2],0x8000);}, # S_IFREG 0x8000
|
||||
opendir: func(path){return __builtin_opendir;},
|
||||
readdir: func(handle){return __builtin_readdir;},
|
||||
closedir: func(handle){return __builtin_closedir;},
|
||||
time: func(){return time(0);},
|
||||
sleep: func(secs){return __builtin_sleep(secs);},
|
||||
chdir: func(path){return __builtin_chdir(path);},
|
||||
environ: func(){die("not supported yet");},
|
||||
getcwd: func(){return __builtin_getcwd();},
|
||||
getenv: func(envvar){return __builtin_getenv(envvar);}
|
||||
};
|
||||
|
||||
# dylib is the core hashmap for developers to load their own library.
|
||||
var dylib=
|
||||
{
|
||||
# open dynamic lib.
|
||||
dlopen: func(libname){return __builtin_dlopen;},
|
||||
# load symbol from an open dynamic lib.
|
||||
dlsym: func(lib,sym){return __builtin_dlsym; },
|
||||
# close dynamic lib, this operation will make all the symbols loaded from it invalid.
|
||||
dlclose: func(lib){return __builtin_dlclose; },
|
||||
# call the loaded symbol.
|
||||
dlcall: func(funcptr,args...){return __builtin_dlcall}
|
||||
};
|
||||
|
||||
# os is used to use or get some os-related info/functions.
|
||||
# windows/macOS/linux are supported.
|
||||
var os=
|
||||
{
|
||||
# get a string that tell which os it runs on.
|
||||
platform: func(){return __builtin_platform;}
|
||||
};
|
||||
|
||||
# runtime gives us some functions that we could manage it manually.
|
||||
var runtime=
|
||||
{
|
||||
# do garbage collection manually.
|
||||
# carefully use it because using it frequently may make program running slower.
|
||||
gc: func(){return __builtin_gc;}
|
||||
};
|
||||
|
||||
# important global constants
|
||||
var D2R=math.pi/180;
|
||||
var FPS2KT=0.5925;
|
||||
var FT2M=0.3048;
|
||||
|
||||
33
stl/list.nas
33
stl/list.nas
@@ -3,65 +3,50 @@
|
||||
var list=func()
|
||||
{
|
||||
var (begin,end)=(nil,nil);
|
||||
return
|
||||
{
|
||||
push_back:func(elem)
|
||||
{
|
||||
return{
|
||||
push_back:func(elem){
|
||||
var tmp={elem:elem,prev:nil,next:nil};
|
||||
if(end!=nil)
|
||||
{
|
||||
if(end!=nil){
|
||||
end.next=tmp;
|
||||
tmp.prev=end;
|
||||
end=tmp;
|
||||
}
|
||||
else
|
||||
begin=end=tmp;
|
||||
return;
|
||||
},
|
||||
push_front:func(elem)
|
||||
{
|
||||
push_front:func(elem){
|
||||
var tmp={elem:elem,prev:nil,next:nil};
|
||||
if(begin!=nil)
|
||||
{
|
||||
if(begin!=nil){
|
||||
begin.prev=tmp;
|
||||
tmp.next=begin;
|
||||
begin=tmp;
|
||||
}
|
||||
else
|
||||
begin=end=tmp;
|
||||
return;
|
||||
},
|
||||
pop_back:func()
|
||||
{
|
||||
pop_back:func(){
|
||||
if(end!=nil)
|
||||
end=end.prev;
|
||||
if(end==nil)
|
||||
begin=nil;
|
||||
else
|
||||
end.next=nil;
|
||||
return;
|
||||
},
|
||||
pop_front:func()
|
||||
{
|
||||
pop_front:func(){
|
||||
if(begin!=nil)
|
||||
begin=begin.next;
|
||||
if(begin==nil)
|
||||
end=nil;
|
||||
else
|
||||
begin.prev=nil;
|
||||
return;
|
||||
},
|
||||
front:func()
|
||||
{
|
||||
front:func(){
|
||||
if(begin!=nil)
|
||||
return begin.elem;
|
||||
return nil;
|
||||
},
|
||||
back:func()
|
||||
{
|
||||
back:func(){
|
||||
if(end!=nil)
|
||||
return end.elem;
|
||||
return nil;
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -3,43 +3,33 @@
|
||||
var queue=func()
|
||||
{
|
||||
var (begin,end)=(nil,nil);
|
||||
return
|
||||
{
|
||||
push:func(elem)
|
||||
{
|
||||
var new_node=
|
||||
{
|
||||
return{
|
||||
push:func(elem){
|
||||
var new_node={
|
||||
elem:elem,
|
||||
next:nil
|
||||
};
|
||||
if(begin==nil)
|
||||
begin=end=new_node;
|
||||
else
|
||||
{
|
||||
else{
|
||||
end.next=new_node;
|
||||
end=new_node;
|
||||
}
|
||||
return;
|
||||
},
|
||||
pop:func()
|
||||
{
|
||||
pop:func(){
|
||||
if(begin!=nil)
|
||||
begin=begin.next;
|
||||
if(begin==nil)
|
||||
end=nil;
|
||||
},
|
||||
front:func()
|
||||
{
|
||||
front:func(){
|
||||
if(begin!=nil)
|
||||
return begin.elem;
|
||||
return nil;
|
||||
},
|
||||
clear:func()
|
||||
{
|
||||
clear:func(){
|
||||
begin=end=nil;
|
||||
},
|
||||
empty:func()
|
||||
{
|
||||
empty:func(){
|
||||
return begin==nil;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@ var ResultTrait={
|
||||
},
|
||||
unwrap:func(){
|
||||
if(me.flag)
|
||||
die("error: "~me.err);
|
||||
die(me.err);
|
||||
return me.ok;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,33 +3,22 @@
|
||||
var stack=func()
|
||||
{
|
||||
var next=nil;
|
||||
return
|
||||
{
|
||||
push:func(elem)
|
||||
{
|
||||
return{
|
||||
push:func(elem){
|
||||
next={elem:elem,next:next};
|
||||
return;
|
||||
},
|
||||
pop:func()
|
||||
{
|
||||
var tmp=next;
|
||||
if(tmp!=nil)
|
||||
next=tmp.next;
|
||||
return;
|
||||
pop:func(){
|
||||
if(next!=nil)
|
||||
next=next.next;
|
||||
},
|
||||
top:func()
|
||||
{
|
||||
var tmp=next;
|
||||
if(tmp!=nil)
|
||||
return tmp.elem;
|
||||
return nil;
|
||||
top:func(){
|
||||
if(next!=nil)
|
||||
return next.elem;
|
||||
},
|
||||
clear:func()
|
||||
{
|
||||
clear:func(){
|
||||
next=nil;
|
||||
},
|
||||
empty:func()
|
||||
{
|
||||
empty:func(){
|
||||
return next==nil;
|
||||
}
|
||||
};
|
||||
|
||||
74
test/bf.nas
74
test/bf.nas
@@ -149,94 +149,78 @@ var mandelbrot=
|
||||
|
||||
var paper=[];
|
||||
var (ptr,pc)=(0,0);
|
||||
var (code,inum,stack)=(nil,nil,nil);
|
||||
var (code,inum,stack)=([],[],[]);
|
||||
var (add,mov,jt,jf,in,out)=(0,1,2,3,4,5);
|
||||
var func_table=[
|
||||
func paper[ptr]+=inum[pc],
|
||||
func ptr+=inum[pc],
|
||||
func if(paper[ptr])pc=inum[pc],
|
||||
func if(!paper[ptr])pc=inum[pc],
|
||||
func paper[ptr]=input()[0],
|
||||
func print(chr(paper[ptr]))
|
||||
];
|
||||
|
||||
var bf=func(program)
|
||||
{
|
||||
var bf=func(program){
|
||||
setsize(paper,131072);
|
||||
(ptr,code,inum,stack)=(0,[],[],[]);
|
||||
var len=size(program);
|
||||
|
||||
for(var i=0;i<len;i+=1)
|
||||
{
|
||||
for(var i=0;i<len;i+=1){
|
||||
var c=chr(program[i]);
|
||||
if(c=='+' or c=='-')
|
||||
{
|
||||
append(code,func_table[add]);
|
||||
if(c=='+' or c=='-'){
|
||||
append(code,add);
|
||||
append(inum,0);
|
||||
for(;i<len;i+=1)
|
||||
{
|
||||
for(;i<len;i+=1){
|
||||
if(chr(program[i])=='+')
|
||||
inum[-1]+=1;
|
||||
elsif(chr(program[i])=='-')
|
||||
inum[-1]-=1;
|
||||
elsif(chr(program[i])!='\n')
|
||||
{
|
||||
elsif(chr(program[i])!='\n'){
|
||||
i-=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif(c=='<' or c=='>')
|
||||
{
|
||||
append(code,func_table[mov]);
|
||||
elsif(c=='<' or c=='>'){
|
||||
append(code,mov);
|
||||
append(inum,0);
|
||||
for(;i<len;i+=1)
|
||||
{
|
||||
for(;i<len;i+=1){
|
||||
if(chr(program[i])=='>')
|
||||
inum[-1]+=1;
|
||||
elsif(chr(program[i])=='<')
|
||||
inum[-1]-=1;
|
||||
elsif(chr(program[i])!='\n')
|
||||
{
|
||||
elsif(chr(program[i])!='\n'){
|
||||
i-=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif(c==',')
|
||||
{
|
||||
append(code,func_table[in]);
|
||||
elsif(c==','){
|
||||
append(code,in);
|
||||
append(inum,0);
|
||||
}
|
||||
elsif(c=='.')
|
||||
{
|
||||
append(code,func_table[out]);
|
||||
elsif(c=='.'){
|
||||
append(code,out);
|
||||
append(inum,0);
|
||||
}
|
||||
elsif(c=='[')
|
||||
{
|
||||
append(code,func_table[jf]);
|
||||
elsif(c=='['){
|
||||
append(code,jf);
|
||||
append(inum,0);
|
||||
append(stack,size(code)-1);
|
||||
}
|
||||
elsif(c==']')
|
||||
{
|
||||
elsif(c==']'){
|
||||
if(!size(stack))
|
||||
die("lack [");
|
||||
var label=pop(stack);
|
||||
append(code,func_table[jt]);
|
||||
append(code,jt);
|
||||
append(inum,label-1);
|
||||
inum[label]=size(code)-2;
|
||||
}
|
||||
}
|
||||
if(size(stack))
|
||||
{
|
||||
if(size(stack)){
|
||||
die("lack ]");
|
||||
return;
|
||||
}
|
||||
len=size(code);
|
||||
for(pc=0;pc<len;pc+=1)
|
||||
code[pc]();
|
||||
for(pc=0;pc<len;pc+=1){
|
||||
var c=code[pc];
|
||||
if(c==add) paper[ptr]+=inum[pc];
|
||||
elsif(c==mov)ptr+=inum[pc];
|
||||
elsif(c==jt){if(paper[ptr])pc=inum[pc];}
|
||||
elsif(c==jf){if(!paper[ptr])pc=inum[pc];}
|
||||
elsif(c==in) paper[ptr]=input()[0];
|
||||
else print(chr(paper[ptr]));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
20
test/bfs.nas
20
test/bfs.nas
@@ -8,20 +8,25 @@ var map=[];
|
||||
for(var i=0;i<10;i+=1)
|
||||
{
|
||||
append(map,[]);
|
||||
for(var j=0;j<10;j+=1)
|
||||
for(var j=0;j<20;j+=1)
|
||||
append(map[i],(rand()>0.7));
|
||||
}
|
||||
|
||||
var prt=func()
|
||||
{
|
||||
var s="";
|
||||
if(os.platform()=="windows")
|
||||
system("cls");
|
||||
else
|
||||
system("clear");
|
||||
var s="+--------------------+\n";
|
||||
for(var i=0;i<10;i+=1)
|
||||
{
|
||||
for(var j=0;j<10;j+=1)
|
||||
s~="|";
|
||||
for(var j=0;j<20;j+=1)
|
||||
s~=pixel[map[i][j]];
|
||||
s~='\n';
|
||||
s~='|\n';
|
||||
}
|
||||
s~='----------\n';
|
||||
s~='+--------------------+\n';
|
||||
print(s);
|
||||
}
|
||||
|
||||
@@ -31,6 +36,7 @@ var bfs=func(begin,end)
|
||||
var que=queue();
|
||||
que.push(begin);
|
||||
map[begin[0]][begin[1]]=2;
|
||||
map[end[0]][end[1]]=0;
|
||||
while(!que.empty())
|
||||
{
|
||||
var vertex=que.front();
|
||||
@@ -45,7 +51,7 @@ var bfs=func(begin,end)
|
||||
prt();
|
||||
return;
|
||||
}
|
||||
if(0<=x and x<10 and 0<=y and y<10 and map[x][y]==0)
|
||||
if(0<=x and x<10 and 0<=y and y<20 and map[x][y]==0)
|
||||
{
|
||||
que.push([x,y]);
|
||||
map[x][y]=2;
|
||||
@@ -57,4 +63,4 @@ var bfs=func(begin,end)
|
||||
return;
|
||||
}
|
||||
|
||||
bfs([0,0],[9,9]);
|
||||
bfs([0,0],[9,19]);
|
||||
112
test/calc.nas
112
test/calc.nas
@@ -1,32 +1,96 @@
|
||||
import("lib.nas");
|
||||
var filename=["main.cpp","nasal_ast.h","nasal_builtin.h","nasal_codegen.h","nasal_gc.h","nasal_import.h","nasal_lexer.h","nasal_parse.h","nasal_vm.h","nasal.h"];
|
||||
var space=[" "," ","",""," "," "," "," "," "," "];
|
||||
var enter_cnt=func(s)
|
||||
{
|
||||
var (cnt,len,enter)=(0,size(s),'\n'[0]);
|
||||
var source=[
|
||||
"main.cpp ",
|
||||
"nasal_err.h ",
|
||||
"nasal_ast.h ",
|
||||
"nasal_builtin.h ",
|
||||
"nasal_codegen.h ",
|
||||
"nasal_opt.h ",
|
||||
"nasal_gc.h ",
|
||||
"nasal_import.h ",
|
||||
"nasal_lexer.h ",
|
||||
"nasal_parse.h ",
|
||||
"nasal_vm.h ",
|
||||
"nasal_dbg.h ",
|
||||
"nasal.h "
|
||||
];
|
||||
|
||||
var lib=[
|
||||
"stl/lib.nas ",
|
||||
"stl/list.nas ",
|
||||
"stl/queue.nas ",
|
||||
"stl/result.nas ",
|
||||
"stl/sort.nas ",
|
||||
"stl/stack.nas "
|
||||
];
|
||||
|
||||
var testfile=[
|
||||
"test/ascii-art.nas ",
|
||||
"test/auto_crash.nas ",
|
||||
"test/bf.nas ",
|
||||
"test/bfconvertor.nas ",
|
||||
"test/bfs.nas ",
|
||||
"test/bigloop.nas ",
|
||||
"test/bp.nas ",
|
||||
"test/calc.nas ",
|
||||
"test/choice.nas ",
|
||||
"test/class.nas ",
|
||||
"test/exception.nas ",
|
||||
"test/fib.nas ",
|
||||
"test/filesystem.nas ",
|
||||
"test/hexdump.nas ",
|
||||
"test/json.nas ",
|
||||
"test/leetcode1319.nas ",
|
||||
"test/lexer.nas ",
|
||||
"test/life.nas ",
|
||||
"test/loop.nas ",
|
||||
"test/mandel.nas ",
|
||||
"test/mandelbrot.nas ",
|
||||
"test/module_test.nas ",
|
||||
"test/nasal_test.nas ",
|
||||
"test/pi.nas ",
|
||||
"test/prime.nas ",
|
||||
"test/props.nas ",
|
||||
"test/quick_sort.nas ",
|
||||
"test/scalar.nas ",
|
||||
"test/trait.nas ",
|
||||
"test/turingmachine.nas",
|
||||
"test/ycombinator.nas "
|
||||
];
|
||||
|
||||
var module=[
|
||||
"module/fib.cpp "
|
||||
];
|
||||
|
||||
var getname=func(s){
|
||||
var (len,ch)=(size(s),' '[0]);
|
||||
for(var i=0;i<len and s[i]!=ch;i+=1);
|
||||
return substr(s,0,i);
|
||||
}
|
||||
|
||||
var count=func(s,c){
|
||||
var (cnt,len,ch)=(0,size(s),c[0]);
|
||||
for(var i=0;i<len;i+=1)
|
||||
cnt+=(s[i]==enter);
|
||||
cnt+=(s[i]==ch);
|
||||
return cnt;
|
||||
}
|
||||
var semic_cnt=func(s)
|
||||
{
|
||||
var (cnt,len,semi)=(0,size(s),';'[0]);
|
||||
for(var i=0;i<len;i+=1)
|
||||
cnt+=(s[i]==semi);
|
||||
return cnt;
|
||||
}
|
||||
func(){
|
||||
var (bytes,line,semi)=(0,0,0);
|
||||
forindex(var i;filename)
|
||||
{
|
||||
var s=io.fin(filename[i]);
|
||||
|
||||
var calc=func(codetype,files){
|
||||
println(codetype);
|
||||
var (bytes,line,semi,line_cnt,semi_cnt)=(0,0,0,0,0);
|
||||
forindex(var i;files){
|
||||
var s=io.fin(getname(files[i]));
|
||||
(line_cnt,semi_cnt)=(count(s,'\n'),count(s,';'));
|
||||
println(files[i],'| ',line_cnt,' \tline | ',semi_cnt,' \tsemi');
|
||||
bytes+=size(s);
|
||||
var line_cnt=enter_cnt(s);
|
||||
var semi_cnt=semic_cnt(s);
|
||||
println(filename[i],space[i],'| ',line_cnt,' \tline | ',semi_cnt,' \tsemi');
|
||||
line+=line_cnt;
|
||||
semi+=semi_cnt;
|
||||
}
|
||||
println('total: | ',line,' \tline | ',semi,' \tsemi');
|
||||
println('bytes: | ',bytes,' bytes| ',int(bytes/1024),' \tkb');
|
||||
}();
|
||||
println('total: | ',line,' \tline | ',semi,' \tsemi');
|
||||
println('bytes: | ',bytes,'\tbytes| ',int(bytes/1024),' \tkb');
|
||||
}
|
||||
|
||||
calc("source code:",source);
|
||||
calc("lib:",lib);
|
||||
calc("test file:",testfile);
|
||||
calc("module:",module);
|
||||
@@ -1,8 +1,6 @@
|
||||
import("lib.nas");
|
||||
|
||||
var student=func(name,age)
|
||||
{
|
||||
var (n,a)=(name,age);
|
||||
var student=func(n,a){
|
||||
return {
|
||||
print_info:func println(n,' ',a),
|
||||
set_age: func(age) a=age,
|
||||
@@ -63,6 +61,4 @@ a(); # 2048 1024 -1
|
||||
b(); # 2048 1024 1 1
|
||||
|
||||
m.h()(2147483647);
|
||||
m.a();
|
||||
# flightgear-nasal-console: 2147483647 1024
|
||||
# nasal-interpreter 2048 1024
|
||||
m.a();# 2147483647 1024
|
||||
@@ -13,7 +13,7 @@ var ResultTrait={
|
||||
},
|
||||
unwrap:func(){
|
||||
if(me.flag)
|
||||
die("error: "~me.err);
|
||||
die(me.err);
|
||||
return me.ok;
|
||||
}
|
||||
};
|
||||
@@ -32,7 +32,7 @@ var a=func(){
|
||||
}
|
||||
|
||||
var b=func(){
|
||||
return Result().Err("unknown");
|
||||
return Result().Err("exception test");
|
||||
}
|
||||
|
||||
println(a().unwrap());
|
||||
|
||||
36
test/filesystem.nas
Normal file
36
test/filesystem.nas
Normal file
@@ -0,0 +1,36 @@
|
||||
import("lib.nas");
|
||||
|
||||
var fd=io.open("test/filesystem.nas");
|
||||
while((var line=io.readln(fd))!=nil)
|
||||
println(line);
|
||||
io.close(fd);
|
||||
println(io.stat("test/filesystem.nas"));
|
||||
|
||||
var dd=unix.opendir("test");
|
||||
while(var name=unix.readdir(dd))
|
||||
println(name);
|
||||
unix.closedir(dd);
|
||||
|
||||
var files=func(dir){
|
||||
var dd=unix.opendir(dir);
|
||||
var res=[];
|
||||
while(var n=unix.readdir(dd))
|
||||
append(res,n);
|
||||
unix.closedir(dd);
|
||||
return res;
|
||||
}
|
||||
var prt=func(s,path){
|
||||
foreach(var i;files(path)){
|
||||
print(s,i);
|
||||
if(unix.isdir(path~'/'~i)){
|
||||
print(' <dir>\n');
|
||||
if(i!='.' and i!='..')
|
||||
prt(s~' |',path~'/'~i);
|
||||
}
|
||||
elsif(unix.isfile(path~'/'~i))
|
||||
print(" <file>\n");
|
||||
else
|
||||
print(' <unknown>\n');
|
||||
}
|
||||
}
|
||||
prt('',".");
|
||||
@@ -16,8 +16,7 @@ foreach(var i;hex_num)
|
||||
append(hex,i~j);
|
||||
|
||||
# read file
|
||||
var s=func()
|
||||
{
|
||||
var s=func(){
|
||||
var filename=[
|
||||
"nasal.h",
|
||||
"main.cpp",
|
||||
@@ -43,49 +42,45 @@ var cnt=0;
|
||||
var hex_index=[0,0,0,0];
|
||||
|
||||
# print binary in text format
|
||||
var textprint=func(index)
|
||||
{
|
||||
print(' |');
|
||||
var textprint=func(index){
|
||||
var info='';
|
||||
for(var i=index-cnt;i<index;i+=1)
|
||||
print((0<=s[i] and s[i]<32)?'.':chr(s[i]));
|
||||
info~=(0<=s[i] and s[i]<32)?'.':chr(s[i]);
|
||||
for(var i=cnt;i<16;i+=1)
|
||||
print('.');
|
||||
print('|\n');
|
||||
info~='.';
|
||||
return ' |'~info~'|\n';
|
||||
}
|
||||
|
||||
# print index
|
||||
var indexprint=func(index)
|
||||
{
|
||||
forindex(var i;hex_index)
|
||||
{
|
||||
var indexprint=func(index){
|
||||
forindex(var i;hex_index){
|
||||
hex_index[i]=index-int(index/256)*256;
|
||||
index=int(index/256);
|
||||
}
|
||||
var info='';
|
||||
for(var i=3;i>=0;i-=1)
|
||||
print(hex[hex_index[i]]);
|
||||
print(' ');
|
||||
return;
|
||||
info~=hex[hex_index[i]];
|
||||
return info~' ';
|
||||
}
|
||||
|
||||
# main
|
||||
func()
|
||||
{
|
||||
indexprint(0);
|
||||
for(var i=0;i<size(s);i+=1)
|
||||
{
|
||||
func(){
|
||||
var info=indexprint(0);
|
||||
for(var i=0;i<size(s);i+=1){
|
||||
if(cnt==16){
|
||||
textprint(i);
|
||||
info~=textprint(i);
|
||||
print(info);
|
||||
cnt=0;
|
||||
indexprint(i);
|
||||
}elsif(cnt==8){
|
||||
print(' ');
|
||||
}
|
||||
info=indexprint(i);
|
||||
}elsif(cnt==8)
|
||||
info~=' ';
|
||||
cnt+=1;
|
||||
print(hex[s[i]],' ');
|
||||
info~=hex[s[i]]~' ';
|
||||
}
|
||||
for(var l=cnt;l<16;l+=1)
|
||||
print(' ');
|
||||
info~=' ';
|
||||
if(cnt<=8)
|
||||
print(' ');
|
||||
textprint(i);
|
||||
info~=' ';
|
||||
info~=textprint(i);
|
||||
print(info);
|
||||
}();
|
||||
@@ -161,7 +161,7 @@ var lexer=func(file)
|
||||
ptr+=1;
|
||||
return;
|
||||
},
|
||||
main:func()
|
||||
compile:func()
|
||||
{
|
||||
while(ptr<len)
|
||||
{
|
||||
@@ -185,9 +185,8 @@ var lexer=func(file)
|
||||
};
|
||||
}
|
||||
|
||||
var nasal_lexer=lexer("test/lexer.nas");
|
||||
nasal_lexer.main();
|
||||
var info="";
|
||||
foreach(var tok;nasal_lexer.get_token())
|
||||
info~=tok~' ';
|
||||
println(info);
|
||||
var lex=lexer("test/props.nas");
|
||||
lex.compile();
|
||||
foreach(var tok;lex.get_token())
|
||||
print(tok,' ');
|
||||
print('\n');
|
||||
@@ -30,7 +30,10 @@ var prt=func()
|
||||
s~=elem~' ';
|
||||
s~='\n';
|
||||
}
|
||||
system("cls");
|
||||
if(os.platform()=="windows")
|
||||
system("cls");
|
||||
else
|
||||
system("clear");
|
||||
print(s);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,25 +7,32 @@ for(;;)
|
||||
}
|
||||
for(var i=1;;)break;
|
||||
for(var i=1;;i+=1)break;
|
||||
for(var i=1;i<10;i+=1)print(i);
|
||||
for(var i=1;i<10;i+=1)print(i,'\n');
|
||||
|
||||
while(1)break;
|
||||
var j=0;
|
||||
while(j<10)
|
||||
{
|
||||
print(j);
|
||||
print(j,'\n');
|
||||
j+=1;
|
||||
}
|
||||
|
||||
forindex(var j;[0,1,2,3])print(j);
|
||||
forindex(var j;[0,1,2,3])print(j,'\n');
|
||||
forindex(var j;[0,1,2,3])
|
||||
{
|
||||
var a=j;
|
||||
print(a*a);
|
||||
print(a*a,'\n');
|
||||
}
|
||||
foreach(var j;[0,1,2,3])print([0,1,2,3][j]);
|
||||
foreach(var j;[0,1,2,3])print([0,1,2,3][j],'\n');
|
||||
foreach(var j;[0,1,2,3])
|
||||
{
|
||||
var a=[0,1,2,3][j];
|
||||
print(a*a-1);
|
||||
print(a*a-1,'\n');
|
||||
}
|
||||
|
||||
var f=func(){
|
||||
var x=0;
|
||||
return func(){x+=1;};
|
||||
}();
|
||||
for(var i=0;i<4e6;i+=1)
|
||||
f();
|
||||
4893
test/mandel.nas
Normal file
4893
test/mandel.nas
Normal file
File diff suppressed because it is too large
Load Diff
17
test/module_test.nas
Normal file
17
test/module_test.nas
Normal file
@@ -0,0 +1,17 @@
|
||||
import("lib.nas");
|
||||
|
||||
var libfib=func(){
|
||||
var dl=dylib.dlopen("./module/libfib."~(os.platform()=="windows"?"dll":"so"));
|
||||
var fib=dylib.dlsym(dl,"fib");
|
||||
var qfib=dylib.dlsym(dl,"quick_fib");
|
||||
var call=dylib.dlcall;
|
||||
return
|
||||
{
|
||||
fib: func(x){return call(fib,x)},
|
||||
qfib:func(x){return call(qfib,x)}
|
||||
};
|
||||
}();
|
||||
|
||||
println(libfib);
|
||||
println(libfib.fib(29));
|
||||
println(libfib.qfib(29));
|
||||
@@ -3,7 +3,7 @@ import("lib.nas");
|
||||
var (t,res)=(1,0);
|
||||
for(var m=1;m<4e6;m+=2)
|
||||
{
|
||||
res+=t*1/m;
|
||||
res+=t/m;
|
||||
t=-t;
|
||||
}
|
||||
println(res*4);
|
||||
@@ -19,7 +19,7 @@ var sort=func(vec,left,right)
|
||||
}
|
||||
var vec=[];
|
||||
rand(time(0));
|
||||
for(var i=0;i<200;i+=1)
|
||||
append(vec,int(rand()*1000));
|
||||
for(var i=0;i<1e4;i+=1)
|
||||
append(vec,int(rand()*1e5));
|
||||
sort(vec,0,size(vec)-1);
|
||||
println(vec);
|
||||
51
test/turingmachine.nas
Normal file
51
test/turingmachine.nas
Normal file
@@ -0,0 +1,51 @@
|
||||
import("lib.nas");
|
||||
|
||||
var table=[
|
||||
['q0','0','1','R','q1'],
|
||||
['q1','1','1','R','q1'],
|
||||
['q1','0','0','S','q2'],
|
||||
['q2','0','1','R','q3'],
|
||||
['q3',nil,nil,'S','q3']
|
||||
];
|
||||
var prt=func(state,pointer,paper,act=nil){
|
||||
print(state,':',pointer,':',act!=nil?act:'','\n\t');
|
||||
var s='';
|
||||
foreach(var i;paper)
|
||||
s~=i;
|
||||
s~='\n\t';
|
||||
for(var i=0;i<pointer;i+=1)
|
||||
for(var j=0;j<size(paper[i]);j+=1)
|
||||
s~=' ';
|
||||
print(s,'^\n');
|
||||
}
|
||||
var run=func(table,node,start,stop){
|
||||
var paper=['0','1','1','1','0','1','0','a'];
|
||||
var pointer=0;
|
||||
foreach(var action;table){
|
||||
if(!contains(node,action[0]))
|
||||
node[action[0]]=nil;
|
||||
if(!contains(node,action[4]))
|
||||
node[action[4]]=nil;
|
||||
}
|
||||
print("nodes: ",keys(node),'\n');
|
||||
if(!contains(node,start))
|
||||
die(start~" is not a valid node");
|
||||
if(!contains(node,stop))
|
||||
die(stop~" is not a valid node");
|
||||
var state=start;
|
||||
prt(state,pointer,paper);
|
||||
while(state!=stop){
|
||||
foreach(var action;table)
|
||||
if(action[0]==state and (action[1]==paper[pointer] or action[1]==' ')){
|
||||
paper[pointer]=action[2]==nil?paper[pointer]:action[2];
|
||||
if(action[3]=='L') pointer-=1;
|
||||
elsif(action[3]=='R') pointer+=1;
|
||||
elsif(action[3]!='S') die("invalid action <"~action[3]~'>');
|
||||
state=action[4];
|
||||
break;
|
||||
}
|
||||
prt(state,pointer,paper,action);
|
||||
}
|
||||
}
|
||||
|
||||
run(table,{},'q0','q3');
|
||||
@@ -8,10 +8,11 @@ var fib=func(f){
|
||||
func(f){
|
||||
return func(x){
|
||||
if(x<2) return x;
|
||||
return f(f)(x-1)+f(f)(x-2);
|
||||
var tmp=f(f);
|
||||
return tmp(x-1)+tmp(x-2);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
for(var i=1;i<31;i+=1)
|
||||
println(fib(i));
|
||||
println(fib(i));
|
||||
|
||||
Reference in New Issue
Block a user