34 Commits
v5.0 ... v6.5

Author SHA1 Message Date
ValKmjolnir
3c9a10d710 avoid unnecessary deep copy by using rvalue ref
and test file update.
bug fixed in test/lexer.nas
2021-06-24 22:10:08 +08:00
ValKmjolnir
fd57e9a47c performance optimization of vm/lex/parse/test 2021-06-24 00:26:26 +08:00
ValKmjolnir
ab99d2d1ed change mcall to call->mcall&allow differen lvalue in assignment 2021-06-21 16:46:47 +08:00
Valk Richard Li
ae0dae5956 update 2021-06-21 01:02:09 +08:00
Valk Richard Li
00c6e3b4fd nothing changed 2021-06-20 01:27:01 +08:00
Valk Richard Li
cdf7b92a8e add statistical information 2021-06-19 00:32:10 +08:00
Valk Richard Li
0e979a6e7b bug fixed & delete operand vapp 2021-06-15 00:49:32 +08:00
Valk Richard Li
dd144305da update test file 2021-06-14 00:27:00 +08:00
Valk Richard Li
4f3ddf803a add tips 2021-06-13 01:01:32 +08:00
Valk Richard Li
de305d26ad fixed an error in README 2021-06-12 01:23:06 +08:00
Valk Richard Li
9f30f45774 Update README.md 2021-06-11 15:28:25 +08:00
Valk Richard Li
1ae47807eb Add command line parameters & chr supports extended ASCII 2021-06-11 15:16:06 +08:00
Valk Richard Li
3deea632f8 front end optimization&stack overflow prompt
change parameter type to avoid unnecessary copies of string.
change stack depth from 65536<<4 to 16+(65536<<2).
now you could know stack overflow when it happens
2021-06-07 23:53:43 +08:00
Valk Richard Li
9f2c31149a bug fixed
fixed SIGSEGV when failed to load file in nasal_lexer::openfile
2021-06-06 19:17:02 +08:00
Valk Richard Li
b25a1bc3f4 more efficient str2num 2021-06-05 20:42:58 +08:00
Valk Richard Li
fd7677f94f update README.md(some history of this project)
AND a question of admins' brains of gitee
2021-06-05 17:15:07 +08:00
Valk Richard Li
2e31a70406 Update README.md 2021-06-03 21:59:15 +08:00
Valk Richard Li
8e29a3ec5b bug fixed & more efficient callfv
I changed callfv's way of calling a function with arguments in vm_vec.
now callfv fetches arguments from val_stack directly,so it runs test/fib.nas from 2.4s to 1.9s.

delete operand callf,add operands callfv & callfh.

also,i check val_stack's top to make sure there is not a stack overflow.
2021-06-03 21:49:31 +08:00
Valk Richard Li
a68bf85f04 bug fixed
a gc bug which causes  fatal error.
add member value collect to make sure that nasal_val is not collected repeatedly.
use builtin_alloc in builtin function to avoid incorrect collection of value in use(gc_alloc).
change free_list to free_list[vm_type_size] to avoid too many calls of new/delete(but seems useless?)
but the most important thing is fixing this bug.
2021-05-31 19:10:59 +08:00
Valk Richard Li
aae9395d66 bug fixed
add operand op_offset to make sure arguments are loaded at correct places,before this commit,arguments are not loaded from a correct offset,which will cause SIGSEGV when calling a function that has complex closure
2021-05-17 21:15:57 +08:00
Valk Richard Li
a463af53b7 add license & other changes
parser recognizes syntax errors more accurately.
change some for loop to standard c++11 for(auto iter:obj)
add MIT license
change info in README.md
2021-05-04 17:39:24 +08:00
Valk Richard Li
6adb991c04 parser reports syntax error accurately
still need improvement
2021-05-04 01:13:53 +08:00
Valk Richard Li
c5f4736984 change scope from unordered_map to vector 2021-04-19 19:12:41 +08:00
Valk Richard Li
1a233fbe15 update 2021-04-12 13:21:13 +08:00
Valk Richard Li
a7d6518bff add test file & update README 2021-04-04 23:35:13 +08:00
Valk Richard Li
0700ce14f7 change function of vapp & README update 2021-04-03 23:47:14 +08:00
Valk Richard Li
c88620920b add stl & more efficient scope 2021-04-02 22:19:29 +08:00
Valk Richard Li
125fc8a9fe bug fixed & test file changes
compare operators now run more efficiently.
2021-03-31 20:59:13 +08:00
Valk Richard Li
b06e1bb5dd add static symbol check & test file update 2021-03-30 15:55:38 +08:00
Valk Richard Li
c7316e9780 change id name & add test file 2021-03-30 00:12:48 +08:00
Valk Richard Li
be1bcdfe2c bug fixed 2021-03-28 17:39:24 +08:00
Valk Richard Li
144e6f45da gc changed to mark-sweep 2021-03-27 01:08:05 +08:00
Valk Richard Li
569d5c6c6a update 2021-03-11 23:18:04 +08:00
Valk Richard Li
7087c67d79 add constant table in vm 2021-03-08 19:45:33 +08:00
51 changed files with 4423 additions and 15306 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 ValKmjolnir
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

488
README.md
View File

@@ -1,54 +1,105 @@
# Nasal Script Language
## Introduction
[Nasal](http://wiki.flightgear.org/Nasal_scripting_language) is a script language that used in [FlightGear](https://www.flightgear.org/).
The interpreter is totally rewritten by ValKmjolnir using C++(standard c++11) without reusing the code in Andy Ross's nasal interpreter(<https://github.com/andyross/nasal>). But we really appreciate that Andy created this amazing programming language and his interpreter project.
The interpreter is still in development(now it works well --2021/2/15). We really need your support!
Also,i am a member of [FGPRC](https://www.fgprc.org/), welcome to join us!
# Why Writing Nasal Interpreter
(2021/5/4) Now this project uses MIT license.Edit it if you want, use this project to learn or create more interesting things(But don't forget me XD).
Nasal is a script language first used in Flightgear.
## Why Writing Nasal Interpreter
Nasal is a script language first used in Flightgear, created by Andy Ross(<https://github.com/andyross>).
But in last summer holiday, members in FGPRC told me that it is hard to debug with nasal-console in Flightgear, especially when checking syntax errors.
So i tried to write a new interpreter to help them checking syntax error and even, runtime error.
I wrote the lexer, parser and runtime(bytecode virtual machine/ast-runtime virtual machine) to help checking errors.
I wrote the lexer, parser and runtimebytecode virtual machine(there was an ast-interpreter,but i deleted it after version4.0) to help checking errors.
They found it easier for them to check errors before copying nasal-codes in nasal-console in Flightgear to test.
They found it much easier to check syntax and runtime errors before copying nasal-codes in nasal-console in Flightgear to test.
# How to Compile
Also, you could use this language to write some interesting programs and run them without the lib of Flightgear.
> g++ -std=c++11 main.cpp -o main.exe
You could add your own built-in functions to change this interpreter to a useful tool in your own projects(such as a script in your own game).
# Parser
## How to Compile
Better choose the latest update of the interpreter.
MUST USE -O2/-O3 if want to optimize the interpreter! pragma gcc optimize(2) seems useless when using g++
> g++ -std=c++11 -O2 main.cpp -o nasal.exe
Or use this in linux/macOS/Unix
> g++ -std=c++11 -O2 main.cpp -o nasal
## How to Use?
Input this command to use interactive interpreter mode:
> ./nasal
Input this command to run scripts directly:
> ./nasal filename
Use these commands to get version of interpreter:
> ./nasal -v | -version
Use these commands to get help:
> ./nasal -h | -help
If your system is Windows and you want to output unicode,please use this command before running nasal interpreter:
> chcp 65001
The interpreter's interactive mode will do this automatically,so you don't need to run this command if you use the interactive interpreter.
## Parser
LL(k) parser.
```javascript
(var a,b,c)=[{b:nil},[1,2],func{return 0;}];
(a.b,b[0],c)=(1,2,3);
```
have the same first set,so LL(1) is useless for this language.
These two expressions have the same first set,so LL(1) is useless for this language.
Maybe in the future i can refactor it to LL(1) with special checks.
# Abstract Syntax Tree
### version 1.0(last update 2019/10/14)
## Version 1.2
First fully functional version of nasal_parser.
Before version 1.0,i tried many times to create a correct parser.
Finally i learned LL(1) and LL(k) and wrote a parser for math formulas in version 0.16(last update 2019/9/14).
In version 0.17(2019/9/15) 0.18(2019/9/18) 0.19(2019/10/1)i was playing the parser happily and after that i wrote version 1.0.
This project began at 2019/8/31.
## Abstract Syntax Tree
### Version 1.2(last update 2019/10/31)
The ast has been completed in this version.
## Version 2.0
### Version 2.0(last update 2020/8/31)
A completed ast-interpreter with unfinished lib functions.
## Version 3.0
### Version 3.0(last update 2020/10/23)
The ast is refactored and is now easier to read and maintain.
@@ -58,15 +109,15 @@ Now you can add your own functions as builtin-functions in this interpreter!
I decide to save the ast interpreter after releasing v4.0. Because it took me a long time to think and write...
## Version 5.0
### Version 5.0(last update 2021/3/7)
I change my mind.AST interpreter leaves me too much things to do.
If i continue saving this interpreter,it will be harder for me to make the bytecode vm become more efficient.
# Byte Code Interpreter
## Byte Code Interpreter
## Version 4.0
### Version 4.0(last update 2020/12/17)
I have just finished the first version of byte-code-interpreter.
@@ -86,20 +137,20 @@ for(var i=0;i<4000000;i+=1);
.number 1
.symbol i
0x00000000: pzero 0x00000000
0x00000001: load 0x00000000 (i)
0x00000002: call 0x00000000 (i)
0x00000001: loadg 0x00000000 (i)
0x00000002: callg 0x00000000 (i)
0x00000003: pnum 0x00000001 (4e+006)
0x00000004: less 0x00000000
0x00000005: jf 0x0000000b
0x00000006: pone 0x00000000
0x00000007: mcall 0x00000000 (i)
0x00000007: mcallg 0x00000000 (i)
0x00000008: addeq 0x00000000
0x00000009: pop 0x00000000
0x0000000a: jmp 0x00000002
0x0000000b: nop 0x00000000
```
## Version 5.0
### Version 5.0(last update 2021/3/7)
I decide to optimize bytecode vm in this version.
@@ -107,11 +158,231 @@ Because it takes more than 1.5s to count i from 0 to 4000000-1.This is not effic
2021/1/23 update: Now it can count from 0 to 4000000-1 in 1.5s.
# How to Use Nasal to Program
### Version 6.0(last update 2021/6/1)
## basic value type
Use loadg loadl callg calll mcallg mcalll to avoid branches.
nasal has 6 value types.Number,string,vector,hash,function,nil.
Delete type vm_scop.
Use const vm_num to avoid frequently new & delete.
Change garbage collector from reference-counting to mark-sweep.
Vapp and newf operand use .num to reduce the size of exec_code.
2021/4/3 update: Now it can count from 0 to 4000000-1 in 0.8s.
2021/4/19 update: Now it can count from 0 to 4e6-1 in 0.4s.
In this update i changed global and local scope from unordered_map to vector.
So the bytecode generator changed a lot.
```javascript
for(var i=0;i<4000000;i+=1);
```
```asm
.number 4e+006
0x00000000: intg 0x00000001
0x00000001: pzero 0x00000000
0x00000002: loadg 0x00000000
0x00000003: callg 0x00000000
0x00000004: pnum 0x00000000 (4e+006)
0x00000005: less 0x00000000
0x00000006: jf 0x0000000c
0x00000007: pone 0x00000000
0x00000008: mcallg 0x00000000
0x00000009: addeq 0x00000000
0x0000000a: pop 0x00000000
0x0000000b: jmp 0x00000003
0x0000000c: nop 0x00000000
```
### Version 6.5(latest)
2021/5/31 update: Now gc can collect garbage correctly without re-collecting,which will cause fatal error.
Add builtin_alloc to avoid mark-sweep when running a built-in function,which will mark useful items as useless garbage to collect.
Better use setsize and assignment to get a big array,append is very slow in this situation.
2021/6/3 update: Fixed a bug that gc still re-collects garbage,this time i use three mark states to make sure garbage is ready to be collected.
Change callf to callfv and callfh.And callfv fetches arguments from val_stack directly instead of using vm_vec,a not very efficient way.
Better use callfv instead of callfh,callfh will fetch a vm_hash from stack and parse it,making this process slow.
```javascript
var f=func(x,y){return x+y;}
f(1024,2048);
```
```asm
.number 1024
.number 2048
.symbol x
.symbol y
0x00000000: intg 0x00000001
0x00000001: newf 0x00000007
0x00000002: intl 0x00000003
0x00000003: offset 0x00000001
0x00000004: para 0x00000000 (x)
0x00000005: para 0x00000001 (y)
0x00000006: jmp 0x0000000b
0x00000007: calll 0x00000001
0x00000008: calll 0x00000002
0x00000009: add 0x00000000
0x0000000a: ret 0x00000000
0x0000000b: loadg 0x00000000
0x0000000c: callg 0x00000000
0x0000000d: pnum 0x00000000 (1024)
0x0000000e: pnum 0x00000001 (2048)
0x0000000f: callfv 0x00000002
0x00000010: pop 0x00000000
0x00000011: nop 0x00000000
```
2021/6/21 update: Now gc will not collect nullptr.And the function of assignment is complete,now these kinds of assignment is allowed:
```javascript
var f=func()
{
var _=[{_:0},{_:1}];
return func(x)
{
return _[x];
}
}
var m=f();
m(0)._=m(1)._=10;
[0,1,2][1:2][0]=0;
```
In the old version,parser will check this left-value and tells that these kinds of left-value are not allowed(bad lvalue).
But now it can work.And you could see its use by reading the code above.To make sure this assignment works correctly,codegen will generate byte code by nasal_codegen::call_gen() instead of nasal_codegen::mcall_gen(),and the last child of the ast will be generated by nasal_codegen::mcall_gen().So the bytecode is totally different now:
```asm
.number 10
.number 2
.symbol _
.symbol x
0x00000000: intg 0x00000002
0x00000001: newf 0x00000005
0x00000002: intl 0x00000002
0x00000003: offset 0x00000001
0x00000004: jmp 0x00000017
0x00000005: newh 0x00000000
0x00000006: pzero 0x00000000
0x00000007: happ 0x00000000 (_)
0x00000008: newh 0x00000000
0x00000009: pone 0x00000000
0x0000000a: happ 0x00000000 (_)
0x0000000b: newv 0x00000002
0x0000000c: loadl 0x00000001
0x0000000d: newf 0x00000012
0x0000000e: intl 0x00000003
0x0000000f: offset 0x00000002
0x00000010: para 0x00000001 (x)
0x00000011: jmp 0x00000016
0x00000012: calll 0x00000001
0x00000013: calll 0x00000002
0x00000014: callv 0x00000000
0x00000015: ret 0x00000000
0x00000016: ret 0x00000000
0x00000017: loadg 0x00000000
0x00000018: callg 0x00000000
0x00000019: callfv 0x00000000
0x0000001a: loadg 0x00000001
0x0000001b: pnum 0x00000000 (10.000000)
0x0000001c: callg 0x00000001
0x0000001d: pone 0x00000000
0x0000001e: callfv 0x00000001
0x0000001f: mcallh 0x00000000 (_)
0x00000020: meq 0x00000000
0x00000021: callg 0x00000001
0x00000022: pzero 0x00000000
0x00000023: callfv 0x00000001
0x00000024: mcallh 0x00000000 (_)
0x00000025: meq 0x00000000
0x00000026: pop 0x00000000
0x00000027: pzero 0x00000000
0x00000028: pzero 0x00000000
0x00000029: pone 0x00000000
0x0000002a: pnum 0x00000001 (2.000000)
0x0000002b: newv 0x00000003
0x0000002c: slcbeg 0x00000000
0x0000002d: pone 0x00000000
0x0000002e: pnum 0x00000001 (2.000000)
0x0000002f: slc2 0x00000000
0x00000030: slcend 0x00000000
0x00000031: pzero 0x00000000
0x00000032: mcallv 0x00000000
0x00000033: meq 0x00000000
0x00000034: pop 0x00000000
0x00000035: nop 0x00000000
```
As you could see from the bytecode above,mcall/mcallv/mcallh operands' using frequency will reduce,call/callv/callh/callfv/callfh at the opposite.
And because of the new structure of mcall, addr_stack, a stack used to store the memory address, is deleted from nasal_vm, and now nasal_vm use nasal_val** mem_addr to store the memory address. This will not cause fatal errors because the memory address is used __immediately__ after getting it.
## Test data
### version 6.5(i5-8250U windows10 2021/6/19)
running time and gc time:
|file|call gc|total time|gc time|
|:----|:----|:----|:----|
|pi.nas|12000049|0.593s|0.222s|
|fib.nas|10573747|2.838s|0.187s|
|bp.nas|4419829|1.99s|0.18s|
|bigloop.nas|4000000|0.419s|0.039s|
|mandelbrot.nas|1044630|0.433s|0.041s|
|life.nas|817112|8.557s|0.199s|
|ascii-art.nas|45612|0.48s|0.027s|
|calc.nas|8089|0.068s|0.006s|
|quick_sort.nas|2768|0.107s|0s|
|bfs.nas|2471|1.763s|0.003s|
operands calling frequency:
|file|1st|2nd|3rd|4th|5th|
|:----|:----|:----|:----|:----|:----|
|pi.nas|callg|pop|mcallg|pnum|pone|
|fib.nas|calll|pnum|callg|less|jf|
|bp.nas|calll|callg|pop|callv|addeq|
|bigloop.nas|pnum|less|jf|callg|pone|
|mandelbrot.nas|callg|mult|loadg|pnum|pop|
|life.nas|calll|callv|pnum|jf|callg|
|ascii-art.nas|calll|pop|mcalll|callg|callb|
|calc.nas|calll|pop|pstr|mcalll|jmp|
|quick_sort.nas|calll|pop|jt|jf|less|
|bfs.nas|calll|pop|callv|mcalll|jf|
operands calling total times:
|file|1st|2nd|3rd|4th|5th|
|:----|:----|:----|:----|:----|:----|
|pi.nas|6000004|6000003|6000000|4000005|4000002|
|fib.nas|17622792|10573704|7049218|7049155|7049155|
|bp.nas|7081480|4227268|2764676|2617112|2065441|
|bigloop.nas|4000001|4000001|4000001|4000001|4000000|
|mandelbrot.nas|1519632|563856|290641|286795|284844|
|life.nas|2114371|974244|536413|534794|489743|
|ascii-art.nas|37906|22736|22402|18315|18292|
|calc.nas|191|124|109|99|87|
|quick_sort.nas|16226|5561|4144|3524|2833|
|bfs.nas|24707|16297|14606|14269|8672|
## How to Use Nasal to Program
### basic value type
Nasal has 6 value types.Number,string,vector,hash,function,nil.
Number has 3 formats.Dec,hex and oct;
@@ -162,37 +433,30 @@ var f=func
{
return 1024;
}
var f=func(x,y,z,default_parameter1=1,default_parameter2=2)
var f=func(x,y,z,default_para1=1,default_para2=2)
{
return x+y+z+default_parameter1+default_parameter2;
return x+y+z+default_para1+default_para2;
}
var f=func(x,y,z,dynamic_parameter...)
var f=func(x,y,z,dynamic_para...)
{
var sum=0;
foreach(var i;dynamic_parameter)
foreach(var i;dynamic_para)
sum+=i;
return sum+x+y+z;
}
```
## operators
### operators
```javascript
1+2;
1-2;
1*2;
1/2;
1+2-1*2/1;
'str1'~'str2';
(1+2)*(3+4)
1+1 and 0;
1+2*3 or 0;
1<0;
1>0;
1<=0;
1>=0;
1==0;
1!=0;
1<0 or 1>0;
1<=0 and 1>=0;
1==0 or 1!=0;
-1;
!0;
@@ -205,7 +469,7 @@ a/=1;
a~='string';
```
## definition
### definition
```javascript
var a=1;
@@ -215,14 +479,14 @@ var (a,b,c)=(0,1,2);
(var a,b,c)=(0,1,2);
```
## multi-assignment
### multi-assignment
```javascript
(a,b[0],c.d)=[0,1,2];
(a,b[1],c.e)=(0,1,2);
```
## conditional expression
### conditional expression
```javascript
if(1)
@@ -243,7 +507,7 @@ else
}
```
## loop
### loop
```javascript
while(condition)
@@ -259,7 +523,7 @@ foreach(var i;elem)
print(i);
```
## subvec
### subvec
Use index to search one element in the string will get the ascii number of this character.If you want to get the character,use built-in function chr().
@@ -268,15 +532,27 @@ a[-1,1,0:2,0:,:3,:,nil:8,3:nil,nil:nil];
"hello world"[0];
```
## special function call
### special function call
This is of great use but is not very efficient.
This is of great use but is not very efficient(because hashmap use string as the key to compare).
```javascript
a(x:0,y:1,z:2);
```
## closure
### lambda
Also functions have this kind of use:
```javascript
func(x,y){return x+y}(0,1);
func(x){return 1/(1+math.exp(-x));}(0.5);
```
### closure
Use closure to OOP.
```javascript
var f=func()
{
@@ -284,9 +560,24 @@ var f=func()
return func(){return a;};
}
print(f()());
var student=func(name,age)
{
var val={
name:name,
age:age
};
return {
print_info:func(){println(val.name,' ',val.age);},
set_age: func(age){val.age=age;},
get_age: func(){return val.age;},
set_name: func(name){val.name=name;},
get_name: func(){return val.name;}
};
}
```
## built-in functions
### built-in functions
Must import lib.nas or has these functions' definitions inside your code.
@@ -299,37 +590,35 @@ If you want to add your own built-in functions,define the function in nasal_buil
Definition:
```C++
nasal_val* builtin_chr(nasal_val*,nasal_gc&);
nasal_val* builtin_chr(std::vector<nasal_val*>&,nasal_gc&);
```
Then complete this function using C++:
```C++
nasal_val* builtin_print(nasal_val* local_scope_addr,nasal_gc& gc)
nasal_val* builtin_print(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
{
// get arguments by using in_builtin_find
nasal_val* vector_value_addr=in_builtin_find("elements");
// get arguments by using builtin_find
// find value with index begin from 1
// because local_scope[0] is reserved for value 'me'
nasal_val* vector_value=local_scope[1];
// main process
// also check type here,if get a type error,use builtin_error_occurred and return nullptr
nasal_vec& ref_vec=vector_value_addr->get_vector();
int size=ref_vec.size();
for(int i=0;i<size;++i)
{
nasal_val* tmp=ref_vec[i];
switch(tmp->get_type())
// also check number of arguments and type here
// if get a type error,use builtin_err and return nullptr
for(auto i:vec_addr->ptr.vec->elems)
switch(i->type)
{
case vm_nil: std::cout<<"nil"; break;
case vm_num: std::cout<<tmp->get_number(); break;
case vm_str: std::cout<<tmp->get_string(); break;
case vm_vec: tmp->get_vector().print(); break;
case vm_hash: tmp->get_hash().print(); break;
case vm_func: std::cout<<"func(...){...}"; break;
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;
}
}
// if a nasal value is not in use,use gc::del_reference to delete it
// if get a new reference of a nasal value,use gc::add_reference
// generate return value,use gc::gc_alloc(type) to make a new value
return gc.gc_alloc(vm_nil);
// or use reserved reference gc.nil_addr/gc.one_addr/gc.zero_addr
return gc.nil_addr;
}
```
@@ -338,25 +627,64 @@ After that, write the built-in function's name(in nasal) and the function's poin
```C++
struct FUNC_TABLE
{
std::string func_name;
nasal_val* (*func_pointer)(nasal_val* x,nasal_gc& gc);
} builtin_func_table[]=
const char* name;
nasal_val* (*func)(std::vector<nasal_val*>&,nasal_gc&);
} builtin_func[]=
{
{"nasal_call_builtin_std_cout",builtin_print},
{"",NULL}
{"__builtin_print",builtin_print},
{nullptr, nullptr }
};
```
At last,warp the 'nasal_call_builtin_std_cout' in a nasal file:
At last,warp the '__builtin_print' in a nasal file:
```javascript
var print=func(elements...)
var print=func(elems...)
{
nasal_call_builtin_std_cout(elements);
return nil;
return __builtin_print(elems);
};
```
In fact the arguments that '__builtin_print' uses is not necessary,So writting it like this is also right:
```javascript
var print=func(elems...)
{
return __builtin_print;
};
```
In version 5.0,if you don't warp built-in function in a normal nasal function,this built-in function may cause a fault when searching arguments,which will cause SIGSEGV segmentation error(maybe).
Use import("") to get the nasal file including your biult-in functions,then you could use it.
Use import("") to get the nasal file including your built-in functions,then you could use it.
version 6.5 update:
Use nasal_gc::builtin_alloc in builtin function if this function uses alloc more then one time.
When running a builtin function,alloc will run more than one time,this may cause mark-sweep in gc_alloc.
The value got before will be collected,but stil in use in this builtin function,this is a fatal error.
So use builtin_alloc in builtin functions like this:
```C++
nasal_val* builtin_keys(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
{
nasal_val* hash_addr=local_scope[1];
if(hash_addr->type!=vm_hash)
{
builtin_err("keys","\"hash\" must be hash");
return nullptr;
}
nasal_val* ret_addr=gc.builtin_alloc(vm_vec);
std::vector<nasal_val*>& ref_vec=ret_addr->ptr.vec->elems;
for(auto iter:hash_addr->ptr.hash->elems)
{
nasal_val* str_addr=gc.builtin_alloc(vm_str);
*str_addr->ptr.str=iter.first;
ref_vec.push_back(str_addr);
}
return ret_addr;
}
```

133
lib.nas
View File

@@ -1,157 +1,144 @@
var import=func(filename)
{
nasal_call_import(filename);
return nil;
return __builtin_import(filename);
}
var print=func(elements...)
var print=func(elems...)
{
nasal_call_builtin_std_cout(elements);
return nil;
return __builtin_print(elems);
};
var println=func(elements...)
var println=func(elems...)
{
nasal_call_builtin_std_cout(elements);
print('\n');
return nil;
__builtin_print(elems);
elems=['\n'];
return __builtin_print(elems);
}
var append=func(vector,elements...)
var append=func(vec,elems...)
{
nasal_call_builtin_push_back(vector,elements);
return nil;
return __builtin_append(vec,elems);
}
var setsize=func(vector,size)
var setsize=func(vec,size)
{
nasal_call_builtin_set_size(vector,size);
return nil;
return __builtin_setsize(vec,size);
}
var system=func(str)
{
nasal_call_builtin_system(str);
return;
return __builtin_system(str);
}
var input=func()
{
return nasal_call_builtin_input();
return __builtin_input();
}
var sleep=func(duration)
{
nasal_call_builtin_sleep(duration);
return;
return __builtin_sleep(duration);
}
var split=func(delimeter,string)
var split=func(deli,str)
{
return nasal_call_builtin_split(delimeter,string);
return __builtin_split(deli,str);
}
var rand=func(seed=nil)
{
return nasal_call_builtin_rand(seed);
return __builtin_rand(seed);
}
var id=func(thing)
var id=func(object)
{
return nasal_call_builtin_get_id(thing);
return __builtin_id(object);
}
var int=func(value)
var int=func(val)
{
return nasal_call_builtin_trans_int(value);
return __builtin_int(val);
}
var num=func(value)
var num=func(val)
{
return nasal_call_builtin_trans_num(value);
return __builtin_num(val);
}
var pop=func(vector)
var pop=func(vec)
{
return nasal_call_builtin_pop_back(vector);
return __builtin_pop(vec);
}
var str=func(number)
var str=func(num)
{
return nasal_call_builtin_trans_str(number);
return __builtin_str(num);
}
var size=func(object)
{
return nasal_call_builtin_size(object);
return __builtin_size(object);
}
var contains=func(hash,key)
{
return nasal_call_builtin_contains(hash,key);
return __builtin_contains(hash,key);
}
var delete=func(hash,key)
{
nasal_call_builtin_delete(hash,key);
return;
return __builtin_delete(hash,key);
}
var keys=func(hash)
{
return nasal_call_builtin_get_keys(hash);
return __builtin_keys(hash);
}
var time=func(begin_time)
{
return nasal_call_builtin_time(begin_time);
return __builtin_time(begin_time);
}
var die=func(str)
{
nasal_call_builtin_die(str);
return nil;
return __builtin_die(str);
}
var typeof=func(object)
{
return nasal_call_builtin_type(object);
return __builtin_type(object);
}
var substr=func(str,begin,length)
var substr=func(str,begin,len)
{
return nasal_call_builtin_substr(str,begin,length);
return __builtin_substr(str,begin,len);
}
var streq=func(a,b)
{
return nasal_call_builtin_streq(a,b);
return __builtin_streq(a,b);
}
var left=func(string,length)
var left=func(str,len)
{
return nasal_call_builtin_left(string,length);
return __builtin_left(str,len);
}
var right=func(string,length)
var right=func(str,len)
{
return nasal_call_builtin_right(string,length);
return __builtin_right(str,len);
}
var cmp=func(a,b)
{
return nasal_call_builtin_cmp(a,b);
return __builtin_cmp(a,b);
}
var chr=func(code) #//Unlike in FG, this chr does not support Extended ASCII
var chr=func(code)
{
return nasal_call_builtin_chr(code);
return __builtin_chr(code);
}
var io=
{
fin:func(filename)
{
return nasal_call_builtin_finput(filename);
},
fout:func(filename,str)
{
nasal_call_builtin_foutput(filename,str);
return;
}
fin: func(filename){return __builtin_fin(filename);},
fout:func(filename,str){return __builtin_fout(filename,str);}
};
var bits=
{
bitxor: func(a,b){return nasal_call_builtin_xor(a,b); },
bitand: func(a,b){return nasal_call_builtin_and(a,b); },
bitor: func(a,b){return nasal_call_builtin_or(a,b); },
bitnand: func(a,b){return nasal_call_builtin_nand(a,b);},
bitnot: func(a) {return nasal_call_builtin_not(a); }
bitxor: func(a,b){return __builtin_xor(a,b); },
bitand: func(a,b){return __builtin_and(a,b); },
bitor: func(a,b){return __builtin_or(a,b); },
bitnand: func(a,b){return __builtin_nand(a,b);},
bitnot: func(a) {return __builtin_not(a); }
};
var math=
{
e: 2.7182818284590452354,
pi: 3.14159265358979323846264338327950288,
sin: func(x) {return nasal_call_builtin_sin(x); },
cos: func(x) {return nasal_call_builtin_cos(x); },
tan: func(x) {return nasal_call_builtin_tan(x); },
exp: func(x) {return nasal_call_builtin_exp(x); },
ln: func(x) {return nasal_call_builtin_cpp_math_ln(x); },
sqrt: func(x) {return nasal_call_builtin_cpp_math_sqrt(x);},
atan2: func(x,y){return nasal_call_builtin_cpp_atan2(x,y); }
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); },
ln: func(x) {return __builtin_ln(x); },
sqrt: func(x) {return __builtin_sqrt(x); },
atan2: func(x,y){return __builtin_atan2(x,y);}
};
var D2R=math.pi/180;

247
main.cpp
View File

@@ -1,27 +1,42 @@
#include "nasal.h"
nasal_lexer lexer;
nasal_parse parse;
nasal_import import;
std::string inputfile="null";
nasal_codegen code_generator;
nasal_vm vm;
void help()
void help_interact()
{
std::cout
<<">> [\"file\"] input a file name.\n"
<<">> [help ] show help.\n"
<<">> [clear ] clear the screen.\n"
<<">> [lex ] use lexer to turn code into tokens.\n"
<<">> [ast ] do parsing and check the abstract syntax tree.\n"
<<">> [code ] show byte code.\n"
<<">> [exec ] execute program on bytecode vm.\n"
<<">> [logo ] print logo of nasal .\n"
<<">> [exit ] quit nasal interpreter.\n";
<<">> [ ] input a file name to execute. \n"
<<">> [help ] show help. \n"
<<">> [clear] clear the screen. \n"
<<">> [lex ] view tokens. \n"
<<">> [ast ] view abstract syntax tree. \n"
<<">> [code ] view byte code. \n"
<<">> [exec ] execute program on bytecode vm.\n"
<<">> [logo ] print logo of nasal . \n"
<<">> [exit ] quit nasal interpreter. \n";
return;
}
void help_cmd()
{
std::cout
#ifdef _WIN32
<<"use command \'chcp 65001\' if want to use unicode.\n"
#endif
<<"nasal | use interactive interpreter.\n"
<<"nasal -h -help | get help.\n"
<<"nasal -v -version | get version of nasal interpreter.\n"
<<"nasal filename | execute script file.\n";
return;
}
void info()
{
std::cout
<<">> Nasal interpreter ver 6.5.\n"
<<">> Thanks to https://github.com/andyross/nasal\n"
<<">> Code: https://github.com/ValKmjolnir/Nasal-Interpreter\n"
<<">> Code: https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
<<">> Info: http://wiki.flightgear.org/Nasal_scripting_language\n"
<<">> Input \"help\" to get help .\n";
return;
}
void logo()
{
std::cout
@@ -32,163 +47,127 @@ void logo()
<<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n";
return;
}
void die(std::string stage,std::string filename)
void die(const char* stage,std::string& filename)
{
std::cout<<">> ["<<stage<<"] in <\""<<filename<<"\">: error(s) occurred,stop.\n";
return;
}
void clear()
void execute(std::string& file,std::string& command)
{
// this will clear the data in lexer/parser/import modules
// to reduce memory footprint
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);
return;
}
if(command=="lex")
{
lexer.print_token();
return;
}
parse.set_toklist(lexer.get_token_list());
lexer.get_token_list().clear();
parse.main_process();
if(parse.get_error())
{
die("parse",file);
return;
}
if(command=="ast")
{
parse.get_root().print_ast(0);
return;
}
import.link(parse.get_root());
parse.get_root().clear();
import.get_root().clear();
return;
}
void lex_func()
{
lexer.openfile(inputfile);
lexer.scanner();
if(lexer.get_error())
{
die("lexer",inputfile);
return;
}
lexer.print_token();
clear();
return;
}
void ast_print()
{
lexer.openfile(inputfile);
lexer.scanner();
if(lexer.get_error())
{
die("lexer",inputfile);
return;
}
parse.set_toklist(lexer.get_token_list());
parse.main_process();
if(parse.get_error())
{
die("parse",inputfile);
return;
}
parse.get_root().print_ast(0);
clear();
return;
}
void show_bytecode()
{
lexer.openfile(inputfile);
lexer.scanner();
if(lexer.get_error())
{
die("lexer",inputfile);
return;
}
parse.set_toklist(lexer.get_token_list());
parse.main_process();
if(parse.get_error())
{
die("parse",inputfile);
return;
}
import.link(parse.get_root());
if(import.get_error())
{
die("import",inputfile);
die("import",file);
return;
}
code_generator.main_progress(import.get_root());
clear();
code_generator.print_byte_code();
return;
}
void execute()
{
lexer.openfile(inputfile);
lexer.scanner();
if(lexer.get_error())
codegen.main_progress(import.get_root());
if(codegen.get_error())
{
die("lexer",inputfile);
die("codegen",file);
return;
}
parse.set_toklist(lexer.get_token_list());
parse.main_process();
if(parse.get_error())
if(command=="code")
{
die("parse",inputfile);
codegen.print_byte_code();
return;
}
import.link(parse.get_root());
if(import.get_error())
{
die("import",inputfile);
return;
}
code_generator.main_progress(import.get_root());
clear();
vm.run(
code_generator.get_string_table(),
code_generator.get_number_table(),
code_generator.get_exec_code()
vm.init(
codegen.get_str_table(),
codegen.get_num_table(),
codegen.get_exec_code()
);
vm.run();
vm.clear();
return;
}
int main()
void interact()
{
std::string command;
#ifdef _WIN32
// use chcp 65001 to use unicode io
system("chcp 65001");
system("cls");
#endif
std::string command,file="null";
logo();
std::cout<<">> Nasal interpreter ver 5.0 .\n";
std::cout<<">> Code: https://github.com/ValKmjolnir/Nasal-Interpreter\n";
std::cout<<">> Info: http://wiki.flightgear.org/Nasal_scripting_language\n";
std::cout<<">> Input \"help\" to get help .\n";
info();
while(1)
{
std::cout<<">> ";
std::cin>>command;
if(command=="help")
help();
help_interact();
else if(command=="clear")
{
#ifdef _WIN32
system("cls");
#endif
#ifdef _linux_
system("clear");
#endif
#ifdef TARGET_OS_MAC
system("clear");
#else
int rs=system("clear");
#endif
}
else if(command=="lex")
lex_func();
else if(command=="ast")
ast_print();
else if(command=="code")
show_bytecode();
else if(command=="exec")
execute();
else if(command=="logo")
logo();
else if(command=="exit")
break;
return;
else if(command=="lex" || command=="ast" || command=="code" || command=="exec")
execute(file,command);
else
inputfile=command;
file=command;
}
}
int main(int argc,const char* argv[])
{
std::string command,file="null";
if(argc==1)
interact();
else if(argc==2 && (!strcmp(argv[1],"-v") || !strcmp(argv[1],"-version")))
{
logo();
std::cout<<"Nasal interpreter ver 6.5\n";
}
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="exec";
execute(file,command);
return 0;
}
else
{
std::cout
<<"invalid command.\n"
<<"use nasal -h to get help.\n";
}
return 0;
}

View File

@@ -68,6 +68,7 @@ scalar::=
|hash {call_scalar}
|number
|string
|nil
|'(' calculation ')' {call_scalar}
;
call_scalar::=

115
nasal.h
View File

@@ -3,6 +3,7 @@
#pragma GCC optimize(2)
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
@@ -25,107 +26,95 @@
check if a string can be converted to a number
if this string cannot be converted to a number,it will return nan
*/
inline double hex_to_double(std::string str)
inline double hex_to_double(const char* str)
{
double ret=0;
for(int i=2;str[i];++i)
for(;*str;++str)
{
ret*=16;
if('0'<=str[i] && str[i]<='9')
ret+=(str[i]-'0');
else if('a'<=str[i] && str[i]<='f')
ret+=(str[i]-'a'+10);
else if('A'<=str[i] && str[i]<='F')
ret+=(str[i]-'A'+10);
if('0'<=*str && *str<='9')
ret+=(*str-'0');
else if('a'<=*str && *str<='f')
ret+=(*str-'a'+10);
else if('A'<=*str && *str<='F')
ret+=(*str-'A'+10);
else
return std::nan("");
return nan("");
}
return ret;
}
inline double oct_to_double(std::string str)
inline double oct_to_double(const char* str)
{
double ret=0;
for(int i=2;str[i];++i)
for(;*str;++str)
{
ret*=8;
if('0'<=str[i] && str[i]<='8')
ret+=(str[i]-'0');
if('0'<=*str && *str<='8')
ret+=(*str-'0');
else
return std::nan("");
return nan("");
}
return ret;
}
inline double dec_to_double(std::string str,int len)
inline double dec_to_double(const char* str)
{
double ret=0;
int i=0;
while('0'<=str[i] && str[i]<='9' && i<len)
ret=ret*10+(str[i++]-'0');
if(i==len) return ret;
if(str[i]!='.' && str[i]!='e' && str[i]!='E')
return std::nan("");
if(str[i]=='.')
double ret=0,negative=1,num_pow=0;
while('0'<=*str && *str<='9')
ret=ret*10+(*str++-'0');
if(!*str) return ret;
if(*str=='.')
{
++i;
if(i==len) return std::nan("");
double num_pow=0.1;
while('0'<=str[i] && str[i]<='9' && i<len)
if(!*++str) return nan("");
num_pow=0.1;
while('0'<=*str && *str<='9')
{
ret+=num_pow*(str[i++]-'0');
ret+=num_pow*(*str++-'0');
num_pow*=0.1;
}
if(!*str) return ret;
}
if(i==len) return ret;
if(str[i]!='e' && str[i]!='E')
return std::nan("");
++i;
if(i==len) return std::nan("");
double negative=(str[i]=='-'? -1:1);
if(str[i]=='-' || str[i]=='+')
++i;
if(i==len) return std::nan("");
double num_pow=0;
for(;i<len;++i)
if(*str!='e' && *str!='E')
return nan("");
if(!*++str) return nan("");
if(*str=='-' || *str=='+')
negative=(*str++=='-'? -1:1);
if(!*str) return nan("");
num_pow=0;
for(;*str;++str)
{
if('0'<=str[i] && str[i]<='9')
num_pow=num_pow*10+(str[i]-'0');
if('0'<=*str && *str<='9')
num_pow=num_pow*10+(*str-'0');
else
return std::nan("");
return nan("");
}
return ret*std::pow(10,negative*num_pow);
}
double trans_string_to_number(std::string str)
double str2num(const char* str)
{
double is_negative=1;
int len=str.length();
bool is_negative=false;
double ret_num=0;
if(!len) return std::nan("");
if(str[0]=='-' || str[0]=='+')
{
if(len==1) return std::nan("");
is_negative=(str[0]=='-'?-1:1);
str=str.substr(1,len--);
}
if(len>1 && str[0]=='0' && str[1]=='x')
ret_num=hex_to_double(str);
else if(len>1 && str[0]=='0' && str[1]=='o')
ret_num=oct_to_double(str);
if(*str=='-' || *str=='+')
is_negative=(*str++=='-');
if(!*str)
return nan("");
if(str[0]=='0' && str[1]=='x')
ret_num=hex_to_double(str+2);
else if(str[0]=='0' && str[1]=='o')
ret_num=oct_to_double(str+2);
else
ret_num=dec_to_double(str,len);
return is_negative*ret_num;
ret_num=dec_to_double(str);
return is_negative?-ret_num:ret_num;
}
/*
trans_number_to_string:
convert number to string
*/
std::string trans_number_to_string(double number)
std::string num2str(double number)
{
std::string res;
std::stringstream ss;
std::ostringstream ss;
ss<<number;
ss>>res;
return res;
return ss.str();
}
#include "nasal_lexer.h"
#include "nasal_ast.h"

View File

@@ -3,7 +3,8 @@
enum ast_node
{
ast_null=0,ast_root,ast_block,
ast_null=0,
ast_root,ast_block,
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,
@@ -18,214 +19,123 @@ enum ast_node
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_definition,ast_multi_assign,
ast_continue,ast_break,ast_return
ast_def,ast_multi_assign,
ast_continue,ast_break,ast_ret
};
std::string ast_name(int type)
const char* ast_name[]=
{
switch(type)
{
case ast_null: return "null";
case ast_root: return "root";
case ast_block: return "block";
case ast_nil: return "nil";
case ast_num: return "number";
case ast_str: return "string";
case ast_id: return "id";
case ast_func: return "function";
case ast_hash: return "hash";
case ast_vec: return "vector";
case ast_hashmember: return "hashmember";
case ast_call: return "call";
case ast_callh: return "callh";
case ast_callv: return "callv";
case ast_callf: return "callf";
case ast_subvec: return "subvec";
case ast_args: return "args";
case ast_default_arg: return "deflt_arg";
case ast_dynamic_id: return "dyn_id";
case ast_and: return "and";
case ast_or: return "or";
case ast_equal: return "=";
case ast_addeq: return "+=";
case ast_subeq: return "-=";
case ast_multeq: return "*=";
case ast_diveq: return "/=";
case ast_lnkeq: return "~=";
case ast_cmpeq: return "==";
case ast_neq: return "!=";
case ast_less: return "<";
case ast_leq: return "<=";
case ast_grt: return ">";
case ast_geq: return ">=";
case ast_add: return "+";
case ast_sub: return "-";
case ast_mult: return "*";
case ast_div: return "/";
case ast_link: return "~";
case ast_neg: return "unary-";
case ast_not: return "unary!";
case ast_trino: return "trino";
case ast_for: return "for";
case ast_forindex: return "forindex";
case ast_foreach: return "foreach";
case ast_while: return "while";
case ast_new_iter: return "iter";
case ast_conditional: return "conditional";
case ast_if: return "if";
case ast_elsif: return "elsif";
case ast_else: return "else";
case ast_multi_id: return "multi_id";
case ast_multi_scalar: return "multi_scalar";
case ast_definition: return "def";
case ast_multi_assign: return "multi_assign";
case ast_continue: return "continue";
case ast_break: return "break";
case ast_return: return "return";
}
return "null";
}
"null",
"root","block",
"nil","num","str","id","func","hash","vec",
"hashmember","call","callh","callv","callf","subvec",
"args","deflt_arg","dyn_id",
"and","or",
"=","+=","-=","*=","/=","~=",
"==","!=",
"<","<=",
">",">=",
"+","-","*","/","~",
"unary-","unary!",
"trino",
"for","forindex","foreach","while","iter",
"conditional","if","elsif","else",
"multi_id","multi_scalar",
"def","multi_assign",
"continue","break","return"
};
class nasal_ast
{
private:
int line;
int type;
int line;
int type;
double num;
std::string str;
double num;
std::vector<nasal_ast> children;
public:
nasal_ast(int,int);
nasal_ast(){line=0;type=ast_null;}
nasal_ast(int l,int t){line=l;type=t;}
nasal_ast(const nasal_ast&);
~nasal_ast();
nasal_ast(nasal_ast&&);
nasal_ast& operator=(const nasal_ast&);
void clear();
void set_line(int);
void set_type(int);
void set_str(std::string&);
void set_num(double);
void add_child(nasal_ast);
int get_line();
int get_type();
std::string get_str();
double get_num();
std::vector<nasal_ast>& get_children();
void print_ast(int);
nasal_ast& operator=(nasal_ast&&);
void print_ast(int);
void clear();
void add_child(nasal_ast&& ast){children.push_back(std::move(ast));}
void set_line(int l){line=l;}
void set_type(int t){type=t;}
void set_str(std::string& s){str=s;}
void set_num(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::nasal_ast(int init_line=0,int init_type=ast_null)
{
this->line=init_line;
this->type=init_type;
return;
}
nasal_ast::nasal_ast(const nasal_ast& tmp)
{
this->line=tmp.line;
this->type=tmp.type;
this->str=tmp.str;
this->num=tmp.num;
this->children=tmp.children;
line=tmp.line;
type=tmp.type;
str =tmp.str;
num =tmp.num;
children=tmp.children;
return;
}
nasal_ast::~nasal_ast()
nasal_ast::nasal_ast(nasal_ast&& tmp)
{
this->children.clear();
line=tmp.line;
type=tmp.type;
str.swap(tmp.str);
num =tmp.num;
children.swap(tmp.children);
return;
}
nasal_ast& nasal_ast::operator=(const nasal_ast& tmp)
{
this->line=tmp.line;
this->type=tmp.type;
this->str=tmp.str;
this->num=tmp.num;
this->children=tmp.children;
line=tmp.line;
type=tmp.type;
str=tmp.str;
num=tmp.num;
children=tmp.children;
return *this;
}
nasal_ast& nasal_ast::operator=(nasal_ast&& tmp)
{
line=tmp.line;
type=tmp.type;
str.swap(tmp.str);
num=tmp.num;
children.swap(tmp.children);
return *this;
}
void nasal_ast::clear()
{
this->line=0;
this->str="";
this->num=0;
this->type=ast_null;
this->children.clear();
line=0;
str="";
num=0;
type=ast_null;
children.clear();
return;
}
void nasal_ast::set_line(int l)
{
this->line=l;
return;
}
void nasal_ast::set_type(int t)
{
this->type=t;
return;
}
void nasal_ast::set_str(std::string& s)
{
this->str=s;
return;
}
void nasal_ast::set_num(double n)
{
this->num=n;
return;
}
void nasal_ast::add_child(nasal_ast ast)
{
children.push_back(ast);
return;
}
int nasal_ast::get_line()
{
return this->line;
}
int nasal_ast::get_type()
{
return this->type;
}
std::string nasal_ast::get_str()
{
return this->str;
}
double nasal_ast::get_num()
{
return this->num;
}
std::vector<nasal_ast>& nasal_ast::get_children()
{
return this->children;
}
void nasal_ast::print_ast(int depth)
{
std::string indentation="";
for(int i=0;i<depth;++i) indentation+="| ";
indentation+=ast_name(this->type);
std::cout<<indentation;
if(this->type==ast_str || this->type==ast_id || this->type==ast_dynamic_id || this->type==ast_callh)
std::cout<<":"<<this->str;
else if(this->type==ast_num)
std::cout<<":"<<this->num;
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<<":"<<str;
else if(type==ast_num)
std::cout<<":"<<num;
std::cout<<'\n';
int child_size=this->children.size();
for(int i=0;i<child_size;++i)
this->children[i].print_ast(depth+1);
for(auto& i:children)
i.print_ast(depth+1);
return;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,363 +1,173 @@
#ifndef __NASAL_GC_H__
#define __NASAL_GC_H__
enum runtime_scalar_type
enum nasal_type
{
vm_nil=0,
vm_num,
vm_str,
vm_scop,
vm_func,
vm_vec,
vm_hash
vm_hash,
vm_type_size
};
class nasal_gc;
class nasal_vec;
class nasal_hash;
class nasal_func;
class nasal_scop;
class nasal_val;
class nasal_vec
// 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]=
{
0, // vm_nil,in fact it is not in use
65536,// vm_num
256, // vm_str
16, // vm_func
2048, // vm_vec
8 // vm_hash
};
struct nasal_val;//declaration of nasal_val
struct nasal_vec// 24 bytes
{
private:
nasal_gc& gc;
std::vector<nasal_val*> elems;
public:
nasal_vec(nasal_gc&);
~nasal_vec();
int size();
void add_elem(nasal_val*);
void print();
nasal_val* del_elem();
nasal_val* operator[](const int);
nasal_val* get_value_address(int);
nasal_val** get_mem_address(int);
void print();
nasal_val* get_val(int);
nasal_val** get_mem(int);
};
class nasal_hash
struct nasal_hash// 56 bytes
{
private:
nasal_gc& gc;
std::unordered_map<std::string,nasal_val*> elems;
public:
nasal_hash(nasal_gc&);
~nasal_hash();
int size();
bool check_contain(std::string);
void add_elem(std::string,nasal_val*);
void del_elem(std::string);
void print();
nasal_val* get_special_para(std::string);
nasal_val* get_value_address(std::string);
nasal_val** get_mem_address(std::string);
nasal_val* get_keys();
void print();
nasal_val* get_val(std::string&);
nasal_val** get_mem(std::string&);
};
class nasal_func
struct nasal_func// 120 bytes
{
private:
nasal_gc& gc;
int entry;
nasal_val* closure_addr;
std::vector<int> para;
int dynpara;
std::vector<nasal_val*> default_para_addr;
public:
nasal_func(nasal_gc&);
~nasal_func();
int get_entry();
int get_dynamic_para();
void set_entry(int);
void add_para(int,nasal_val*,bool);
void set_closure_addr(nasal_val*);
void set_new_closure();
nasal_val* get_closure_addr();
std::vector<int>& get_para();
std::vector<nasal_val*>& get_default();
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_val*> default_para;// default value(nasal_val*)
std::unordered_map<std::string,int> key_table;// parameter name hash
std::vector<nasal_val*> closure;// closure will be loaded to gc.local.back() as the local scope
nasal_func();
void clear();
};
class nasal_scop
struct nasal_val// 16 bytes
{
private:
nasal_gc& gc;
std::unordered_map<int,nasal_val*> elems;
public:
nasal_scop(nasal_gc&);
~nasal_scop();
void set_closure(nasal_scop&);
void add_new_value(int,nasal_val*);
nasal_val* get_value_address(int);
nasal_val** get_mem_address(int);
};
class nasal_val
{
protected:
int type;
#define GC_UNCOLLECTED 0
#define GC_COLLECTED 1
#define GC_FOUND 2
uint8_t mark;
uint16_t type;
union
{
double num;
double num;
std::string* str;
nasal_vec* vec;
nasal_hash* hash;
nasal_func* func;
nasal_scop* cls;
}ptr;
public:
int ref_cnt;
nasal_val();
nasal_val(int,nasal_gc&);
~nasal_val();
void clear();
void set_type(int,nasal_gc&);
void set_number(double);
void set_string(std::string);
int get_type();
double to_number();
double get_number();
std::string to_string();
std::string get_string();
nasal_vec& get_vector();
nasal_hash& get_hash();
nasal_func& get_func();
nasal_scop& get_closure();
};
class nasal_gc
{
private:
std::queue<nasal_val*> free_space;
std::vector<nasal_val*> memory;
public:
~nasal_gc();
void clear();
nasal_val* gc_alloc(int);
void add_reference(nasal_val*);
void del_reference(nasal_val*);
nasal_val(int);
~nasal_val();
double to_number();
std::string to_string();
};
/*functions of nasal_vec*/
nasal_vec::nasal_vec(nasal_gc& ngc):gc(ngc)
{
return;
}
nasal_vec::~nasal_vec()
{
int size=elems.size();
for(int i=0;i<size;++i)
gc.del_reference(elems[i]);
return;
}
void nasal_vec::add_elem(nasal_val* value_address)
{
elems.push_back(value_address);
return;
}
nasal_val* nasal_vec::del_elem()
{
// pop back
if(!elems.size())
return NULL;
nasal_val* ret=elems.back();
elems.pop_back();
return ret;
}
int nasal_vec::size()
{
return elems.size();
}
nasal_val* nasal_vec::operator[](const int index)
{
return elems[index];
}
nasal_val* nasal_vec::get_value_address(int index)
nasal_val* nasal_vec::get_val(int index)
{
int vec_size=elems.size();
if(index<-vec_size || index>=vec_size)
{
std::cout<<">> [gc] nasal_vec::get_value_address: index out of range: "<<index<<"\n";
return NULL;
}
int idx[2]={index+vec_size,index};
return elems[idx[index>=0]];
return nullptr;
return elems[index>=0?index:index+vec_size];
}
nasal_val** nasal_vec::get_mem_address(int index)
nasal_val** nasal_vec::get_mem(int index)
{
int vec_size=elems.size();
if(index<-vec_size || index>=vec_size)
{
std::cout<<">> [gc] nasal_vec::get_mem_address: index out of range: "<<index<<"\n";
return NULL;
}
int idx[2]={index+vec_size,index};
return &elems[idx[index>=0]];
return nullptr;
return &elems[index>=0?index:index+vec_size];
}
void nasal_vec::print()
{
int size=elems.size();
std::cout<<"[";
if(!size)
std::cout<<"]";
for(int i=0;i<size;++i)
std::cout<<'[';
for(auto i:elems)
{
nasal_val* tmp=elems[i];
switch(tmp->get_type())
switch(i->type)
{
case vm_nil: std::cout<<"nil"; break;
case vm_num: std::cout<<tmp->get_number(); break;
case vm_str: std::cout<<tmp->get_string(); break;
case vm_vec: tmp->get_vector().print(); break;
case vm_hash: tmp->get_hash().print(); break;
case vm_func: std::cout<<"func(...){...}"; break;
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;
}
std::cout<<",]"[i==size-1];
std::cout<<',';
}
std::cout<<']';
return;
}
/*functions of nasal_hash*/
nasal_hash::nasal_hash(nasal_gc& ngc):gc(ngc)
nasal_val* nasal_hash::get_val(std::string& key)
{
return;
}
nasal_hash::~nasal_hash()
{
for(auto iter=elems.begin();iter!=elems.end();++iter)
gc.del_reference(iter->second);
return;
}
void nasal_hash::add_elem(std::string key,nasal_val* value_address)
{
if(!elems.count(key))
elems[key]=value_address;
return;
}
void nasal_hash::del_elem(std::string key)
{
if(!elems.count(key))
{
gc.del_reference(elems[key]);
elems.erase(key);
}
return;
}
int nasal_hash::size()
{
return elems.size();
}
nasal_val* nasal_hash::get_special_para(std::string key)
{
if(elems.count(key))
return elems[key];
return NULL;
}
nasal_val* nasal_hash::get_value_address(std::string key)
{
nasal_val* ret_value_addr=NULL;
nasal_val* ret_addr=nullptr;
if(elems.count(key))
return elems[key];
else if(elems.count("parents"))
{
nasal_val* val_addr=elems["parents"];
if(val_addr->get_type()==vm_vec)
{
nasal_vec& vec_ref=val_addr->get_vector();
int size=vec_ref.size();
for(int i=0;i<size;++i)
if(val_addr->type==vm_vec)
for(auto i:val_addr->ptr.vec->elems)
{
nasal_val* tmp_val_addr=vec_ref.get_value_address(i);
if(tmp_val_addr->get_type()==vm_hash)
ret_value_addr=tmp_val_addr->get_hash().get_value_address(key);
if(ret_value_addr)
break;
if(i->type==vm_hash)
ret_addr=i->ptr.hash->get_val(key);
if(ret_addr)
return ret_addr;
}
}
}
return ret_value_addr;
return nullptr;
}
nasal_val** nasal_hash::get_mem_address(std::string key)
nasal_val** nasal_hash::get_mem(std::string& key)
{
nasal_val** mem_addr=NULL;
nasal_val** mem_addr=nullptr;
if(elems.count(key))
return &elems[key];
else if(elems.count("parents"))
{
nasal_val* val_addr=elems["parents"];
if(val_addr->get_type()==vm_vec)
{
nasal_vec& vec_ref=val_addr->get_vector();
int size=vec_ref.size();
for(int i=0;i<size;++i)
if(val_addr->type==vm_vec)
for(auto i:val_addr->ptr.vec->elems)
{
nasal_val* tmp_val_addr=vec_ref.get_value_address(i);
if(tmp_val_addr->get_type()==vm_hash)
mem_addr=tmp_val_addr->get_hash().get_mem_address(key);
if(i->type==vm_hash)
mem_addr=i->ptr.hash->get_mem(key);
if(mem_addr)
break;
return mem_addr;
}
}
}
return mem_addr;
}
bool nasal_hash::check_contain(std::string key)
{
if(elems.count(key))
return true;
if(elems.count("parents"))
{
bool result=false;
nasal_val* val_addr=elems["parents"];
if(val_addr->get_type()==vm_vec)
{
nasal_vec& vec_ref=val_addr->get_vector();
int size=vec_ref.size();
for(int i=0;i<size;++i)
{
nasal_val* tmp_val_addr=vec_ref.get_value_address(i);
if(tmp_val_addr->get_type()==vm_hash)
result=tmp_val_addr->get_hash().check_contain(key);
if(result)
break;
}
}
return result;
}
return false;
}
nasal_val* nasal_hash::get_keys()
{
nasal_val* ret_addr=gc.gc_alloc(vm_vec);
nasal_vec& ref_vec=ret_addr->get_vector();
for(auto iter=elems.begin();iter!=elems.end();++iter)
{
nasal_val* str_addr=gc.gc_alloc(vm_str);
str_addr->set_string(iter->first);
ref_vec.add_elem(str_addr);
}
return ret_addr;
return nullptr;
}
void nasal_hash::print()
{
std::cout<<'{';
if(!elems.size())
for(auto& i:elems)
{
std::cout<<'}';
return;
}
for(auto i=elems.begin();i!=elems.end();++i)
{
std::cout<<i->first<<':';
nasal_val* tmp=i->second;
switch(tmp->get_type())
std::cout<<i.first<<':';
nasal_val* tmp=i.second;
switch(tmp->type)
{
case vm_nil: std::cout<<"nil"; break;
case vm_num: std::cout<<tmp->get_number(); break;
case vm_str: std::cout<<tmp->get_string(); break;
case vm_vec: tmp->get_vector().print(); break;
case vm_hash: tmp->get_hash().print(); break;
case vm_func: std::cout<<"func(...){...}"; break;
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;
}
std::cout<<',';
}
@@ -366,211 +176,51 @@ void nasal_hash::print()
}
/*functions of nasal_func*/
nasal_func::nasal_func(nasal_gc& ngc):gc(ngc)
nasal_func::nasal_func()
{
closure_addr=NULL;
dynpara=-1;
return;
}
nasal_func::~nasal_func()
void nasal_func::clear()
{
if(closure_addr)
gc.del_reference(closure_addr);
for(int i=0;i<default_para_addr.size();++i)
if(default_para_addr[i])
gc.del_reference(default_para_addr[i]);
return;
}
void nasal_func::set_entry(int etr)
{
entry=etr;
return;
}
int nasal_func::get_entry()
{
return entry;
}
void nasal_func::add_para(int name_index,nasal_val* val_addr=NULL,bool is_dynamic=false)
{
if(is_dynamic)
{
dynpara=name_index;
return;
}
para.push_back(name_index);
default_para_addr.push_back(val_addr);
return;
}
std::vector<int>& nasal_func::get_para()
{
return para;
}
int nasal_func::get_dynamic_para()
{
return dynpara;
}
std::vector<nasal_val*>& nasal_func::get_default()
{
return default_para_addr;
}
void nasal_func::set_closure_addr(nasal_val* value_address)
{
nasal_val* new_closure=gc.gc_alloc(vm_scop);
new_closure->get_closure().set_closure(value_address->get_closure());
closure_addr=new_closure;
return;
}
void nasal_func::set_new_closure()
{
closure_addr=gc.gc_alloc(vm_scop);
return;
}
nasal_val* nasal_func::get_closure_addr()
{
return closure_addr;
}
/*functions of nasal_scop*/
nasal_scop::nasal_scop(nasal_gc& ngc):gc(ngc)
{
return;
}
nasal_scop::~nasal_scop()
{
for(auto i=elems.begin();i!=elems.end();++i)
gc.del_reference(i->second);
return;
}
void nasal_scop::add_new_value(int key,nasal_val* value_address)
{
if(elems.count(key))
{
// if this value already exists,delete the old value and update a new value
gc.del_reference(elems[key]);
}
elems[key]=value_address;
return;
}
nasal_val* nasal_scop::get_value_address(int key)
{
if(elems.count(key))
return elems[key];
return NULL;
}
nasal_val** nasal_scop::get_mem_address(int key)
{
if(elems.count(key))
return &(elems[key]);
return NULL;
}
void nasal_scop::set_closure(nasal_scop& tmp)
{
elems=tmp.elems;
for(auto i=elems.begin();i!=elems.end();++i)
gc.add_reference(i->second);
dynpara=-1;
default_para.clear();
key_table.clear();
closure.clear();
return;
}
/*functions of nasal_val*/
nasal_val::nasal_val()
nasal_val::nasal_val(int val_type)
{
ref_cnt=1;
type=vm_nil;
return;
}
nasal_val::nasal_val(int nasal_val_type,nasal_gc& nvm)
{
ref_cnt=1;
type=nasal_val_type;
switch(nasal_val_type)
mark=GC_COLLECTED;
type=val_type;
switch(type)
{
case vm_nil: break;
case vm_num: ptr.num=0; break;
case vm_str: ptr.str=new std::string; break;
case vm_vec: ptr.vec=new nasal_vec(nvm); break;
case vm_hash: ptr.hash=new nasal_hash(nvm); break;
case vm_func: ptr.func=new nasal_func(nvm); break;
case vm_scop: ptr.cls=new nasal_scop(nvm); break;
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;
}
return;
}
nasal_val::~nasal_val()
{
// must set type and scalar_ptr to default first
// this operation will avoid SIGTRAP caused by circular reference
// circular reference will cause using destructor repeatedly
int tmp_type=type;
type=vm_nil;
switch(tmp_type)
switch(type)
{
case vm_nil: break;
case vm_num: break;
case vm_str: delete ptr.str; break;
case vm_vec: delete ptr.vec; break;
case vm_hash: delete ptr.hash; break;
case vm_func: delete ptr.func; break;
case vm_scop: delete ptr.cls; break;
}
return;
}
void nasal_val::clear()
{
// must set type and scalar_ptr to default first
// this operation will avoid SIGTRAP caused by circular reference
// circular reference will cause using destructor repeatedly
int tmp_type=type;
type=vm_nil;
switch(tmp_type)
{
case vm_nil: break;
case vm_num: break;
case vm_str: delete ptr.str; break;
case vm_vec: delete ptr.vec; break;
case vm_hash: delete ptr.hash; break;
case vm_func: delete ptr.func; break;
case vm_scop: delete ptr.cls; break;
}
return;
}
void nasal_val::set_type(int nasal_val_type,nasal_gc& nvm)
{
type=nasal_val_type;
switch(nasal_val_type)
{
case vm_nil: break;
case vm_num: ptr.num=0; break;
case vm_str: ptr.str=new std::string; break;
case vm_vec: ptr.vec=new nasal_vec(nvm); break;
case vm_hash: ptr.hash=new nasal_hash(nvm); break;
case vm_func: ptr.func=new nasal_func(nvm); break;
case vm_scop: ptr.cls=new nasal_scop(nvm); break;
}
return;
}
void nasal_val::set_number(double num)
{
ptr.num=num;
return;
}
void nasal_val::set_string(std::string str)
{
*ptr.str=str;
return;
}
int nasal_val::get_type()
{
return type;
}
double nasal_val::to_number()
{
if(type==vm_num)
return ptr.num;
else if(type==vm_str)
return trans_string_to_number(*ptr.str);
return 0;
}
double nasal_val::get_number()
{
if(type==vm_str)
return str2num(ptr.str->c_str());
return ptr.num;
}
std::string nasal_val::to_string()
@@ -578,82 +228,185 @@ std::string nasal_val::to_string()
if(type==vm_str)
return *ptr.str;
else if(type==vm_num)
return trans_number_to_string(ptr.num);
return num2str(ptr.num);
return "";
}
std::string nasal_val::get_string()
{
return *ptr.str;
}
nasal_vec& nasal_val::get_vector()
{
return *ptr.vec;
}
nasal_hash& nasal_val::get_hash()
{
return *ptr.hash;
}
nasal_func& nasal_val::get_func()
{
return *ptr.func;
}
nasal_scop& nasal_val::get_closure()
{
return *ptr.cls;
}
/*functions of nasal_gc*/
nasal_gc::~nasal_gc()
struct nasal_gc
{
int gc_mem_size=memory.size();
for(int i=0;i<gc_mem_size;++i)
memory[i]->clear();
for(int i=0;i<gc_mem_size;++i)
delete memory[i];
while(!free_space.empty())
free_space.pop();
return;
}
void nasal_gc::clear()
#define STACK_MAX_DEPTH (65536)
nasal_val* zero_addr; // reserved address of nasal_val,type vm_num, 0
nasal_val* one_addr; // reserved address of nasal_val,type vm_num, 1
nasal_val* nil_addr; // reserved address of nasal_val,type vm_nil
nasal_val* val_stack[STACK_MAX_DEPTH+16];// 16 reserved to avoid stack overflow
nasal_val** stack_top; // stack top
std::vector<nasal_val*> num_addrs; // reserved address for const vm_num
std::vector<nasal_val*> str_addrs; // reserved address for const vm_str
std::vector<nasal_val*> slice_stack; // slice stack for vec[val,val,val:val]
std::vector<nasal_val*> memory; // gc memory
std::queue <nasal_val*> free_list[vm_type_size]; // gc free list
std::vector<nasal_val*> global;
std::list<std::vector<nasal_val*>> local;
void mark();
void sweep();
void gc_init(std::vector<double>&,std::vector<std::string>&);
void gc_clear();
nasal_val* gc_alloc(int);
nasal_val* builtin_alloc(int);
};
/* gc functions */
void nasal_gc::mark()
{
int gc_mem_size=memory.size();
for(int i=0;i<gc_mem_size;++i)
memory[i]->clear();
for(int i=0;i<gc_mem_size;++i)
delete memory[i];
while(!free_space.empty())
free_space.pop();
memory.clear();
return;
}
nasal_val* nasal_gc::gc_alloc(int val_type)
{
if(free_space.empty())
std::queue<nasal_val*> bfs;
for(auto i:global)
bfs.push(i);
for(auto& i:local)
for(auto j:i)
bfs.push(j);
for(auto i:slice_stack)
bfs.push(i);
for(nasal_val** i=val_stack;i<=stack_top;++i)
bfs.push(*i);
while(!bfs.empty())
{
nasal_val* new_unit=new nasal_val(val_type,*this);
memory.push_back(new_unit);
return new_unit;
nasal_val* tmp=bfs.front();
bfs.pop();
if(tmp->mark) continue;
tmp->mark=GC_FOUND;
if(tmp->type==vm_vec)
for(auto i:tmp->ptr.vec->elems)
bfs.push(i);
else if(tmp->type==vm_hash)
for(auto& i:tmp->ptr.hash->elems)
bfs.push(i.second);
else if(tmp->type==vm_func)
{
for(auto i:tmp->ptr.func->closure)
bfs.push(i);
for(auto i:tmp->ptr.func->default_para)
if(i)
bfs.push(i);
}
}
nasal_val* ret=free_space.front();
free_space.pop();
ret->ref_cnt=1;
ret->set_type(val_type,*this);
return;
}
void nasal_gc::sweep()
{
for(auto i:memory)
{
if(i->mark==GC_UNCOLLECTED)
{
switch(i->type)
{
case vm_str: i->ptr.str->clear(); break;
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;
}
free_list[i->type].push(i);
i->mark=GC_COLLECTED;
}
else if(i->mark==GC_FOUND)
i->mark=GC_UNCOLLECTED;
}
return;
}
void nasal_gc::gc_init(std::vector<double>& nums,std::vector<std::string>& strs)
{
for(int i=vm_num;i<vm_type_size;++i)
for(int j=0;j<increment[i];++j)
{
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
*val_stack=nil_addr; // the first space will not store any values,but gc checks
// 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];
}
// init constant strings
str_addrs.resize(strs.size());
for(int i=0;i<strs.size();++i)
{
str_addrs[i]=new nasal_val(vm_str);
*str_addrs[i]->ptr.str=strs[i];
}
return;
}
void nasal_gc::gc_clear()
{
for(auto i:memory)
delete i;
memory.clear();
for(int i=0;i<vm_type_size;++i)
while(!free_list[i].empty())
free_list[i].pop();
global.clear();
local.clear();
slice_stack.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;
}
nasal_val* nasal_gc::gc_alloc(int type)
{
if(free_list[type].empty())
{
mark();
sweep();
}
if(free_list[type].empty())
for(int i=0;i<increment[type];++i)
{
nasal_val* tmp=new nasal_val(type);
memory.push_back(tmp);
free_list[type].push(tmp);
}
nasal_val* ret=free_list[type].front();
ret->mark=GC_UNCOLLECTED;
free_list[type].pop();
return ret;
}
void nasal_gc::add_reference(nasal_val* value_address)
nasal_val* nasal_gc::builtin_alloc(int type)
{
++value_address->ref_cnt;
return;
// when running a builtin function,alloc will run more than one time
// 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)
{
nasal_val* tmp=new nasal_val(type);
memory.push_back(tmp);
free_list[type].push(tmp);
}
nasal_val* ret=free_list[type].front();
ret->mark=GC_UNCOLLECTED;
free_list[type].pop();
return ret;
}
void nasal_gc::del_reference(nasal_val* value_address)
{
--value_address->ref_cnt;
if(!value_address->ref_cnt)
{
value_address->clear();
free_space.push(value_address);
}
return;
}
#endif

View File

@@ -4,35 +4,34 @@
class nasal_import
{
private:
nasal_lexer import_lex;
nasal_parse import_par;
nasal_ast import_ast;
std::vector<std::string> filename_table;
int error;
void die(std::string,std::string);
nasal_lexer import_lex;
nasal_parse import_par;
nasal_ast import_ast;
std::vector<std::string> filename_table;
void die(std::string&,const char*);
bool check_import(nasal_ast&);
bool check_exist(std::string);
void linker(nasal_ast&,nasal_ast&);
bool check_exist(std::string&);
void linker(nasal_ast&,nasal_ast&&);
nasal_ast file_import(nasal_ast&);
nasal_ast load(nasal_ast&);
public:
int get_error();
int get_error(){return error;}
void link(nasal_ast&);
nasal_ast& get_root();
nasal_ast& get_root(){return import_ast;}
};
void nasal_import::die(std::string filename,std::string error_stage)
void nasal_import::die(std::string& filename,const char* error_stage)
{
++error;
std::cout<<">> [import] in <\""<<filename<<"\">: error(s) occurred in "<<error_stage<<"."<<std::endl;
std::cout<<">> [import] in <\""<<filename<<"\">: error(s) occurred in "<<error_stage<<".\n";
return;
}
bool nasal_import::check_import(nasal_ast& node)
{
/*
only this kind of node can be recognized as 'import':
only this kind of node can be recognized as 'import':
call
id:import
call_func
@@ -52,24 +51,21 @@ bool nasal_import::check_import(nasal_ast& node)
return true;
}
bool nasal_import::check_exist(std::string filename)
bool nasal_import::check_exist(std::string& file)
{
// avoid importing the same file
int size=filename_table.size();
for(int i=0;i<size;++i)
if(filename==filename_table[i])
for(auto& fname:filename_table)
if(file==fname)
return true;
filename_table.push_back(filename);
filename_table.push_back(file);
return false;
}
void nasal_import::linker(nasal_ast& root,nasal_ast& add_root)
void nasal_import::linker(nasal_ast& root,nasal_ast&& add_root)
{
// add children of add_root to the back of root
std::vector<nasal_ast>& ref_vec=add_root.get_children();
int size=ref_vec.size();
for(int i=0;i<size;++i)
root.add_child(ref_vec[i]);
for(auto& i:add_root.get_children())
root.add_child(std::move(i));
return;
}
@@ -91,18 +87,19 @@ nasal_ast nasal_import::file_import(nasal_ast& node)
import_lex.scanner();
if(import_lex.get_error())
{
this->die(filename,"lexer");
die(filename,"lexer");
return tmp;
}
import_par.set_toklist(import_lex.get_token_list());
import_lex.get_token_list().clear();
import_par.main_process();
if(import_par.get_error())
{
this->die(filename,"parser");
die(filename,"parser");
return tmp;
}
tmp=import_par.get_root();
tmp=std::move(import_par.get_root());
import_par.get_root().clear();
// check if tmp has 'import'
return load(tmp);
}
@@ -110,21 +107,11 @@ nasal_ast nasal_import::file_import(nasal_ast& node)
nasal_ast nasal_import::load(nasal_ast& root)
{
nasal_ast new_root(0,ast_root);
std::vector<nasal_ast>& ref_vec=root.get_children();
int size=ref_vec.size();
for(int i=0;i<size;++i)
{
if(check_import(ref_vec[i]))
{
nasal_ast tmp=file_import(ref_vec[i]);
// add tmp to the back of new_root
linker(new_root,tmp);
}
}
for(auto& i:root.get_children())
if(check_import(i))
linker(new_root,file_import(i));
// add root to the back of new_root
linker(new_root,root);
// oops,i think it is not efficient if the root is too ... large?
linker(new_root,std::move(root));
return new_root;
}
@@ -139,14 +126,4 @@ void nasal_import::link(nasal_ast& root)
return;
}
nasal_ast& nasal_import::get_root()
{
return import_ast;
}
int nasal_import::get_error()
{
return error;
}
#endif

View File

@@ -82,7 +82,7 @@ struct
{"<=" ,tok_leq },
{">" ,tok_grt },
{">=" ,tok_geq },
{NULL ,-1 }
{nullptr ,-1 }
};
struct token
@@ -103,20 +103,20 @@ private:
std::string line_code;
std::vector<char> res;
std::vector<token> token_list;
int get_token_type(std::string);
void die(std::string,std::string,int,int);
std::string identifier_gen();
std::string number_gen();
std::string string_gen();
int get_tok_type(std::string&);
void die(const char*);
std::string id_gen();
std::string num_gen();
std::string str_gen();
public:
void openfile(std::string);
void openfile(std::string&);
void scanner();
void print_token();
int get_error();
std::vector<token>& get_token_list();
int get_error(){return error;}
std::vector<token>& get_token_list(){return token_list;}
};
void nasal_lexer::openfile(std::string filename)
void nasal_lexer::openfile(std::string& filename)
{
error=0;
res.clear();
@@ -125,7 +125,7 @@ void nasal_lexer::openfile(std::string filename)
{
++error;
std::cout<<">> [lexer] cannot open file \""<<filename<<"\".\n";
fin.close();
fin.close();
return;
}
while(!fin.eof())
@@ -136,11 +136,10 @@ void nasal_lexer::openfile(std::string filename)
res.push_back(c);
}
fin.close();
res_size=res.size();
return;
}
int nasal_lexer::get_token_type(std::string tk_str)
int nasal_lexer::get_tok_type(std::string& tk_str)
{
for(int i=0;token_table[i].str;++i)
if(tk_str==token_table[i].str)
@@ -148,17 +147,17 @@ int nasal_lexer::get_token_type(std::string tk_str)
return tok_null;
}
void nasal_lexer::die(std::string code,std::string error_info,int line=-1,int column=-1)
void nasal_lexer::die(const char* error_info)
{
++error;
std::cout<<">> [lexer] line "<<line<<" column "<<column<<": \n"<<code<<"\n";
for(int i=0;i<column-1;++i)
std::cout<<(code[i]=='\t'?'\t':' ');
std::cout<<"^ "<<error_info<<'\n';
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::identifier_gen()
std::string nasal_lexer::id_gen()
{
std::string token_str="";
while(ptr<res_size && (IS_IDENTIFIER(res[ptr])||IS_DIGIT(res[ptr])))
@@ -168,89 +167,62 @@ std::string nasal_lexer::identifier_gen()
// after running this process, ptr will point to the next token's beginning character
}
std::string nasal_lexer::number_gen()
std::string nasal_lexer::num_gen()
{
bool scientific_notation=false;// numbers like 1e8 are scientific_notation
std::string token_str="";
// generate hex number
if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='x')
{
token_str="0x";
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=="0x")
{
die(line_code,"incorrect number.",line,line_code.length());
return "0";
}
die("incorrect number.");
return token_str;
}
// generate oct number
else if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='o')
{
token_str="0o";
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=="0o")
{
die(line_code,"incorrect number.",line,line_code.length());
return "0";
}
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++];
// "xxxx." is not a correct number
if(ptr>=res_size)
{
line_code+=token_str;
die(line_code,"incorrect number.",line,line_code.length());
return "0";
}
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(line_code,"incorrect number.",line,line_code.length());
die("incorrect number.");
return "0";
}
}
if(ptr<res_size && (res[ptr]=='e' || res[ptr]=='E'))
{
token_str+=res[ptr++];
// "xxxe" is not a correct number
if(ptr>=res_size)
{
line_code+=token_str;
die(line_code,"incorrect number.",line,line_code.length());
return "0";
}
if(ptr<res_size && (res[ptr]=='-' || res[ptr]=='+'))
token_str+=res[ptr++];
if(ptr>=res_size)
{
line_code+=token_str;
die(line_code,"incorrect number.",line,line_code.length());
return "0";
}
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(line_code,"incorrect number.",line,line_code.length());
die("incorrect number.");
return "0";
}
}
@@ -258,7 +230,7 @@ std::string nasal_lexer::number_gen()
return token_str;
}
std::string nasal_lexer::string_gen()
std::string nasal_lexer::str_gen()
{
std::string token_str="";
char str_begin=res[ptr];
@@ -276,15 +248,15 @@ std::string nasal_lexer::string_gen()
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 '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;
@@ -296,7 +268,9 @@ std::string nasal_lexer::string_gen()
}
// check if this string ends with a " or '
if(ptr++>=res_size)
die(line_code,"get EOF when generating string.",line,line_code.length());
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;
}
@@ -306,6 +280,7 @@ void nasal_lexer::scanner()
line=1;
ptr=0;
line_code="";
res_size=res.size();
std::string token_str;
while(ptr<res_size)
@@ -323,33 +298,30 @@ void nasal_lexer::scanner()
if(ptr>=res_size) break;
if(IS_IDENTIFIER(res[ptr]))
{
token_str=identifier_gen();
token new_token(line,get_token_type(token_str),token_str);
token_str=id_gen();
token new_token(line,get_tok_type(token_str),token_str);
if(!new_token.type)
new_token.type=tok_id;
token_list.push_back(new_token);
}
else if(IS_DIGIT(res[ptr]))
{
token_str=number_gen();
token new_token(line,tok_num,token_str);
token_list.push_back(new_token);
token_str=num_gen();
token_list.push_back({line,tok_num,token_str});
}
else if(IS_STRING(res[ptr]))
{
token_str=string_gen();
token new_token(line,tok_str,token_str);
token_list.push_back(new_token);
token_str=str_gen();
token_list.push_back({line,tok_str,token_str});
}
else if(IS_SINGLE_OPERATOR(res[ptr]))
{
token_str="";
token_str+=res[ptr];
token_str=res[ptr];
line_code+=res[ptr];
token new_token(line,get_token_type(token_str),token_str);
if(!new_token.type)
die(line_code,"incorrect operator.",line,line_code.length());
token_list.push_back(new_token);
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]=='.')
@@ -365,8 +337,7 @@ void nasal_lexer::scanner()
++ptr;
}
line_code+=token_str;
token new_token(line,get_token_type(token_str),token_str);
token_list.push_back(new_token);
token_list.push_back({line,get_tok_type(token_str),token_str});
}
else if(IS_CALC_OPERATOR(res[ptr]))
{
@@ -375,37 +346,26 @@ void nasal_lexer::scanner()
if(ptr<res_size && res[ptr]=='=')
token_str+=res[ptr++];
line_code+=token_str;
token new_token(line,get_token_type(token_str),token_str);
token_list.push_back(new_token);
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(line_code,"unknown character.",line,line_code.length());
die("unknown character.");
}
}
token tk(line,tok_eof,"");
token_list.push_back(tk);
token_list.push_back({line,tok_eof,""});
res.clear();
return;
}
void nasal_lexer::print_token()
{
int size=token_list.size();
for(int i=0;i<size;++i)
std::cout<<"("<<token_list[i].line<<" | "<<token_list[i].str<<")\n";
for(auto tok:token_list)
std::cout<<"("<<tok.line<<" | "<<tok.str<<")\n";
return;
}
int nasal_lexer::get_error()
{
return error;
}
std::vector<token>& nasal_lexer::get_token_list()
{
return token_list;
}
#endif

View File

@@ -45,11 +45,12 @@ private:
int error;
nasal_ast root;
std::vector<token> tok_list;
std::vector<token> error_token;
int in_function; // count when generating function block,used to check return-expression
int in_loop; // count when generating loop block,used to check break/continue-expression
void reset();
void die(int,std::string);
void match(int);
void die(int,std::string&&);
void match(int type,const char* err_info="");
bool check_comma(int*);
bool check_multi_def();
bool check_multi_scalar();
bool check_function_end(nasal_ast&);
@@ -63,7 +64,7 @@ private:
nasal_ast id_gen();
nasal_ast vec_gen();
nasal_ast hash_gen();
nasal_ast hmem_gen(); // hash member
nasal_ast hmem_gen();
nasal_ast func_gen();
nasal_ast args_gen();
nasal_ast expr();
@@ -77,9 +78,9 @@ private:
nasal_ast unary();
nasal_ast scalar();
nasal_ast call_scalar();
nasal_ast call_hash();
nasal_ast call_vec();
nasal_ast call_func();
nasal_ast callh();
nasal_ast callv();
nasal_ast callf();
nasal_ast subvec();
nasal_ast definition();
nasal_ast var_incurve_def();
@@ -95,108 +96,93 @@ private:
nasal_ast conditional();
nasal_ast continue_expr();
nasal_ast break_expr();
nasal_ast return_expr();
nasal_ast ret_expr();
public:
int get_error();
void set_toklist(std::vector<token>&);
int get_error(){return error;}
void set_toklist(std::vector<token>& toks){tok_list=toks;}
void main_process();
nasal_ast& get_root();
nasal_ast& get_root(){return root;}
};
int nasal_parse::get_error()
{
return error;
}
void nasal_parse::set_toklist(std::vector<token>& toks)
{
tok_list=toks;
return;
}
void nasal_parse::main_process()
{
reset();
ptr=in_function=in_loop=error=0;
root.clear();
error_token.clear();
root.set_line(1);
root.set_type(ast_root);
while(tok_list[ptr].type!=tok_eof)
{
int err_tok_size=error_token.size();
root.add_child(expr());
if(tok_list[ptr].type==tok_semi)
match(tok_semi);
else if(need_semi_check(root.get_children().back()))
{
// the last expression can be recognized without semi
if(tok_list[ptr].type!=tok_eof)
die(error_line,"expected \";\"");
}
// if detect error token, avoid checking semicolon
else if(error_token.size()>err_tok_size)
continue;
// the last expression can be recognized without semi
else if(need_semi_check(root.get_children().back()) && tok_list[ptr].type!=tok_eof)
die(error_line,"expected \";\"");
}
if(!error_token.size())
return;
++error;
std::cout<<">> [parse] line";
int err_line=0;
for(auto& tok:error_token)
if(err_line!=tok.line)
{
std::cout<<' '<<tok.line;
err_line=tok.line;
}
std::cout
<<" have fatal syntax errors."
<<"check \'(\',\'[\',\'{\',\')\',\']\',\'}\' match or not.\n";
return;
}
nasal_ast& nasal_parse::get_root()
{
return root;
}
void nasal_parse::reset()
{
ptr=in_function=in_loop=error=0;
root.clear();
return;
}
void nasal_parse::die(int line,std::string info)
void nasal_parse::die(int line,std::string&& info)
{
++error;
std::cout<<">> [parse] line "<<line<<": "<<info<<".\n";
if(tok_list[ptr].type==tok_eof)
return;
++ptr;
while(tok_list[ptr].type!=tok_eof)// panic
{
if(tok_list[ptr].type==tok_semi ||
tok_list[ptr].type==tok_rcurve ||
tok_list[ptr].type==tok_rbracket ||
tok_list[ptr].type==tok_rbrace ||
tok_list[ptr].type==tok_eof)
break;
++ptr;
}
return;
}
void nasal_parse::match(int type)
void nasal_parse::match(int type,const char* err_info)
{
if(tok_list[ptr].type!=type)
{
std::string s="";
for(int i=0;token_table[i].str;++i)
if(token_table[i].tok_type==type)
{
s=token_table[i].str;
break;
}
if(type==tok_num)
die(error_line,"expect a number");
else if(type==tok_str)
die(error_line,"expect a string");
else if(type==tok_id)
die(error_line,"expect an identifier");
else
die(error_line,"expect \'"+s+"\'");
if(err_info[0])
{
die(error_line,err_info);
return;
}
switch(type)
{
case tok_num:die(error_line,"expected number"); break;
case tok_str:die(error_line,"expected string"); break;
case tok_id: die(error_line,"expected identifier");break;
default: die(error_line,"expected \'"+std::string(token_table[type-tok_for].str)+"\'"); break;
}
return;
}
if(tok_list[ptr].type==tok_eof)
return;
++ptr;
return;
}
bool nasal_parse::check_comma(int* panic_set)
{
for(int i=0;panic_set[i];++i)
if(tok_list[ptr].type==panic_set[i])
{
die(error_line,"expected \',\' between scalars");
return true;
}
return false;
}
bool nasal_parse::check_multi_def()
{
return tok_list[ptr+1].type==tok_var;
}
bool nasal_parse::check_multi_scalar()
{
int check_ptr=ptr,curve_cnt=1,bracket_cnt=0,brace_cnt=0;
@@ -216,7 +202,6 @@ bool nasal_parse::check_multi_scalar()
}
return false;
}
bool nasal_parse::check_function_end(nasal_ast& node)
{
int type=node.get_type();
@@ -227,7 +212,7 @@ bool nasal_parse::check_function_end(nasal_ast& node)
if(
node.get_children().empty() ||
(
type!=ast_definition &&
type!=ast_def &&
type!=ast_equal &&
type!=ast_addeq &&
type!=ast_subeq &&
@@ -241,7 +226,6 @@ bool nasal_parse::check_function_end(nasal_ast& node)
return check_function_end(node.get_children().back());
return false;
}
bool nasal_parse::check_special_call()
{
// special call means like this:
@@ -266,7 +250,6 @@ bool nasal_parse::check_special_call()
}
return false;
}
bool nasal_parse::need_semi_check(nasal_ast& node)
{
int type=node.get_type();
@@ -274,63 +257,52 @@ bool nasal_parse::need_semi_check(nasal_ast& node)
return false;
return !check_function_end(node);
}
void nasal_parse::check_memory_reachable(nasal_ast& node)
{
if(node.get_type()==ast_call)
{
if(node.get_children()[0].get_type()!=ast_id)
die(node.get_line(),"cannot get the memory of a temporary data");
int size=node.get_children().size();
for(int i=0;i<size;++i)
{
nasal_ast& tmp=node.get_children()[i];
if(tmp.get_type()==ast_callf)
die(tmp.get_line(),"cannot get the memory of function-returned value");
if(tmp.get_type()==ast_callv && (tmp.get_children().size()>1 || tmp.get_children()[0].get_type()==ast_subvec))
die(tmp.get_line(),"cannot get the memory in temporary sliced vector");
}
nasal_ast& tmp=node.get_children().back();
if(tmp.get_type()==ast_callf)
die(tmp.get_line(),"bad left-value");
if(tmp.get_type()==ast_callv && (tmp.get_children().size()>1 || tmp.get_children()[0].get_type()==ast_subvec))
die(tmp.get_line(),"bad left-value");
}
else if(node.get_type()!=ast_id)
die(node.get_line(),"cannot use calculation as the memory of scalar");
die(node.get_line(),"bad left-value");
return;
}
nasal_ast nasal_parse::null_node_gen()
{
nasal_ast node(tok_list[ptr].line,ast_null);
return node;
return nasal_ast(tok_list[ptr].line,ast_null);
}
nasal_ast nasal_parse::nil_gen()
{
nasal_ast node(tok_list[ptr].line,ast_nil);
return node;
return nasal_ast(tok_list[ptr].line,ast_nil);
}
nasal_ast nasal_parse::num_gen()
{
nasal_ast node(tok_list[ptr].line,ast_num);
node.set_num(trans_string_to_number(tok_list[ptr].str));
node.set_num(str2num(tok_list[ptr].str.c_str()));
return node;
}
nasal_ast nasal_parse::str_gen()
{
nasal_ast node(tok_list[ptr].line,ast_str);
node.set_str(tok_list[ptr].str);
return node;
}
nasal_ast nasal_parse::id_gen()
{
nasal_ast node(tok_list[ptr].line,ast_id);
node.set_str(tok_list[ptr].str);
return node;
}
nasal_ast nasal_parse::vec_gen()
{
// panic set for this token is not ','
// this is the FIRST set of calculation
// array end with tok_null=0
int panic_set[]={tok_id,tok_str,tok_num,tok_not,tok_sub,tok_nil,tok_func,tok_var,tok_lcurve,tok_lbrace,tok_lbracket,tok_null};
nasal_ast node(tok_list[ptr].line,ast_vec);
match(tok_lbracket);
while(tok_list[ptr].type!=tok_rbracket)
@@ -338,25 +310,29 @@ nasal_ast nasal_parse::vec_gen()
node.add_child(calc());
if(tok_list[ptr].type==tok_comma)
match(tok_comma);
else if(tok_list[ptr].type!=tok_rbracket)
else if(tok_list[ptr].type==tok_eof)
break;
else if(tok_list[ptr].type!=tok_rbracket && !check_comma(panic_set))
break;
}
match(tok_rbracket);
match(tok_rbracket,"expected \']\' when generating vector");
return node;
}
nasal_ast nasal_parse::hash_gen()
{
nasal_ast node(tok_list[ptr].line,ast_hash);
match(tok_lbrace);
while (tok_list[ptr].type!=tok_rbrace)
while(tok_list[ptr].type!=tok_rbrace)
{
node.add_child(hmem_gen());
if(tok_list[ptr].type==tok_comma)
match(tok_comma);
else if(tok_list[ptr].type!=tok_rbrace)
else if(tok_list[ptr].type==tok_id || tok_list[ptr].type==tok_str)// first set of hashmember
die(error_line,"expected \',\' between hash members");
else
break;
}
match(tok_rbrace);
match(tok_rbrace,"expected \'}\' when generating hash");
return node;
}
nasal_ast nasal_parse::hmem_gen()
@@ -395,72 +371,72 @@ nasal_ast nasal_parse::args_gen()
match(tok_lcurve);
while(tok_list[ptr].type!=tok_rcurve)
{
nasal_ast tmp;
tmp=id_gen();
nasal_ast tmp=id_gen();
match(tok_id);
if(tok_list[ptr].type==tok_eq || tok_list[ptr].type==tok_ellipsis)
{
nasal_ast special_arg(tok_list[ptr].line);
nasal_ast special_arg(tok_list[ptr].line,ast_null);
if(tok_list[ptr].type==tok_eq)
{
special_arg.add_child(tmp);
match(tok_eq);
special_arg.add_child(calc());
special_arg=std::move(tmp);
special_arg.set_type(ast_default_arg);
special_arg.add_child(calc());
}
else
{
match(tok_ellipsis);
special_arg=tmp;
special_arg=std::move(tmp);
special_arg.set_type(ast_dynamic_id);
}
node.add_child(special_arg);
node.add_child(std::move(special_arg));
}
else
node.add_child(tmp);
node.add_child(std::move(tmp));
if(tok_list[ptr].type==tok_comma)
match(tok_comma);
else if(tok_list[ptr].type!=tok_rcurve)
else if(tok_list[ptr].type==tok_id)// first set of identifier
die(error_line,"expected \',\' between identifiers");
else
break;
}
match(tok_rcurve);
match(tok_rcurve,"expected \')\' after parameter list");
std::string args_format="func(";
int node_child_size=node.get_children().size();
for(int i=0;i<node_child_size;++i)
for(auto& tmp:node.get_children())
{
switch(node.get_children()[i].get_type())
switch(tmp.get_type())
{
case ast_id: args_format+="val";break;
case ast_default_arg: args_format+="val=scalar";break;
case ast_dynamic_id: args_format+="val...";break;
case ast_id: args_format+=tmp.get_str();break;
case ast_default_arg: args_format+=tmp.get_str()+"=val";break;
case ast_dynamic_id: args_format+=tmp.get_str()+"...";break;
}
args_format+=",)"[i==node_child_size-1];
args_format+=",)"[&tmp==&node.get_children().back()];
}
bool checked_default_val=false,checked_dynamic_ids=false;
for(int i=0;i<node_child_size;++i)
for(auto& tmp:node.get_children())
{
if(node.get_children()[i].get_type()==ast_default_arg)
if(tmp.get_type()==ast_default_arg)
checked_default_val=true;
else if(node.get_children()[i].get_type()==ast_dynamic_id)
else if(tmp.get_type()==ast_dynamic_id)
checked_dynamic_ids=true;
if(checked_default_val && node.get_children()[i].get_type()!=ast_default_arg)
die(node.get_children()[i].get_line(),"default argument must be the end of argument list: "+args_format);
if(checked_dynamic_ids && i!=node_child_size-1)
die(node.get_children()[i].get_line(),"dynamic identifier must be the end of argument list: "+args_format);
if(checked_default_val && tmp.get_type()!=ast_default_arg)
die(tmp.get_line(),"must use default paras after using it once: "+args_format);
if(checked_dynamic_ids && &tmp!=&node.get_children().back())
die(tmp.get_line(),"dynamic para must be the end: "+args_format);
}
std::unordered_map<std::string,bool> argname_table;
for(int i=0;i<node_child_size;++i)
for(auto& tmp:node.get_children())
{
std::string new_name;
switch(node.get_children()[i].get_type())
switch(tmp.get_type())
{
case ast_dynamic_id:
case ast_id:new_name=node.get_children()[i].get_str();break;
case ast_default_arg:new_name=node.get_children()[i].get_children()[0].get_str();break;
case ast_id: new_name=tmp.get_str();break;
case ast_default_arg:new_name=tmp.get_str();break;
}
if(argname_table.find(new_name)!=argname_table.end())
die(node.get_children()[i].get_line(),"argument name should not repeat");
if(argname_table.count(new_name))
die(tmp.get_line(),"parameter's name repeats: "+new_name);
else
argname_table[new_name]=true;
}
@@ -468,14 +444,14 @@ nasal_ast nasal_parse::args_gen()
}
nasal_ast nasal_parse::expr()
{
nasal_ast node(tok_list[ptr].line);
nasal_ast node(tok_list[ptr].line,ast_null);
int tok_type=tok_list[ptr].type;
if((tok_type==tok_break || tok_type==tok_continue) && !in_loop)
die(error_line,"cannot use break/continue outside loop");
die(error_line,"use break/continue in the loop");
if(tok_type==tok_ret && !in_function)
die(error_line,"cannot use return outside function");
die(error_line,"use return in the function");
switch(tok_type)
{
{
case tok_nil:
case tok_num:
case tok_str:
@@ -494,9 +470,9 @@ nasal_ast nasal_parse::expr()
case tok_if: node=conditional(); break;
case tok_continue: node=continue_expr(); break;
case tok_break: node=break_expr(); break;
case tok_ret: node=return_expr(); break;
case tok_ret: node=ret_expr(); break;
case tok_semi: break;
default: die(error_line,"error token \""+tok_list[ptr].str+"\"");break;
default:error_token.push_back(tok_list[ptr]);++ptr;break;
}
return node;
}
@@ -511,22 +487,20 @@ nasal_ast nasal_parse::exprs_gen()
if(tok_list[ptr].type==tok_lbrace)
{
match(tok_lbrace);
while(tok_list[ptr].type!=tok_rbrace)
while(tok_list[ptr].type!=tok_rbrace && tok_list[ptr].type!=tok_eof)
{
int err_tok_size=error_token.size();
node.add_child(expr());
if(tok_list[ptr].type==tok_semi)
match(tok_semi);
else if(need_semi_check(node.get_children().back()))
{
// the last expression can be recognized without semi
if(tok_list[ptr].type!=tok_rbrace)
{
die(error_line,"expected \";\"");
break;
}
}
// if detect error token, avoid checking semicolon
else if(error_token.size()>err_tok_size)
continue;
// the last expression can be recognized without semi
else if(need_semi_check(node.get_children().back()) && tok_list[ptr].type!=tok_rbrace)
die(error_line,"expected \";\"");
}
match(tok_rbrace);
match(tok_rbrace,"expected \'}\' when generating expressions");
}
else
{
@@ -538,111 +512,105 @@ nasal_ast nasal_parse::exprs_gen()
}
nasal_ast nasal_parse::calc()
{
nasal_ast node;
node=or_expr();
nasal_ast node=or_expr();
if(tok_list[ptr].type==tok_quesmark)
{
// trinocular calculation
nasal_ast tmp(tok_list[ptr].line,ast_trino);
match(tok_quesmark);
tmp.add_child(node);
tmp.add_child(std::move(node));
tmp.add_child(calc());
match(tok_colon);
tmp.add_child(calc());
node=tmp;
node=std::move(tmp);
}
else if(tok_eq<=tok_list[ptr].type && tok_list[ptr].type<=tok_lnkeq)
{
check_memory_reachable(node);
// tok_eq~tok_lnkeq is 37 to 42,ast_equal~ast_lnkeq is 21~26
nasal_ast tmp(tok_list[ptr].line,tok_list[ptr].type-tok_eq+ast_equal);
tmp.add_child(node);
tmp.add_child(std::move(node));
match(tok_list[ptr].type);
tmp.add_child(calc());
node=tmp;
node=std::move(tmp);
}
return node;
}
nasal_ast nasal_parse::or_expr()
{
nasal_ast node;
node=and_expr();
nasal_ast node=and_expr();
while(tok_list[ptr].type==tok_or)
{
nasal_ast tmp(tok_list[ptr].line,ast_or);
tmp.add_child(node);
tmp.add_child(std::move(node));
match(tok_or);
tmp.add_child(and_expr());
node=tmp;
node=std::move(tmp);
}
return node;
}
nasal_ast nasal_parse::and_expr()
{
nasal_ast node;
node=cmp_expr();
nasal_ast node=cmp_expr();
while(tok_list[ptr].type==tok_and)
{
nasal_ast tmp(tok_list[ptr].line,ast_and);
tmp.add_child(node);
tmp.add_child(std::move(node));
match(tok_and);
tmp.add_child(cmp_expr());
node=tmp;
node=std::move(tmp);
}
return node;
}
nasal_ast nasal_parse::cmp_expr()
{
nasal_ast node;
node=additive_expr();
nasal_ast node=additive_expr();
while(tok_cmpeq<=tok_list[ptr].type && tok_list[ptr].type<=tok_geq)
{
// tok_cmpeq~tok_geq is 43~48,ast_cmpeq~ast_geq is 27~32
nasal_ast tmp(tok_list[ptr].line,tok_list[ptr].type-tok_cmpeq+ast_cmpeq);
tmp.add_child(node);
tmp.add_child(std::move(node));
match(tok_list[ptr].type);
tmp.add_child(additive_expr());
node=tmp;
node=std::move(tmp);
}
return node;
}
nasal_ast nasal_parse::additive_expr()
{
nasal_ast node;
node=multive_expr();
nasal_ast node=multive_expr();
while(tok_list[ptr].type==tok_add || tok_list[ptr].type==tok_sub || tok_list[ptr].type==tok_link)
{
nasal_ast tmp(tok_list[ptr].line);
nasal_ast tmp(tok_list[ptr].line,ast_null);
switch(tok_list[ptr].type)
{
case tok_add: tmp.set_type(ast_add); break;
case tok_sub: tmp.set_type(ast_sub); break;
case tok_link: tmp.set_type(ast_link); break;
}
tmp.add_child(node);
tmp.add_child(std::move(node));
match(tok_list[ptr].type);
tmp.add_child(multive_expr());
node=tmp;
node=std::move(tmp);
}
return node;
}
nasal_ast nasal_parse::multive_expr()
{
nasal_ast node;
node=(tok_list[ptr].type==tok_sub || tok_list[ptr].type==tok_not)?unary():scalar();
nasal_ast node=(tok_list[ptr].type==tok_sub || tok_list[ptr].type==tok_not)?unary():scalar();
while(tok_list[ptr].type==tok_mult || tok_list[ptr].type==tok_div)
{
nasal_ast tmp(tok_list[ptr].line,tok_list[ptr].type-tok_mult+ast_mult);
tmp.add_child(node);
tmp.add_child(std::move(node));
match(tok_list[ptr].type);
tmp.add_child((tok_list[ptr].type==tok_sub || tok_list[ptr].type==tok_not)?unary():scalar());
node=tmp;
node=std::move(tmp);
}
return node;
}
nasal_ast nasal_parse::unary()
{
nasal_ast node(tok_list[ptr].line);
nasal_ast node(tok_list[ptr].line,ast_null);
switch(tok_list[ptr].type)
{
case tok_sub:node.set_type(ast_neg);match(tok_sub);break;
@@ -653,11 +621,11 @@ nasal_ast nasal_parse::unary()
}
nasal_ast nasal_parse::scalar()
{
nasal_ast node(tok_list[ptr].line);
nasal_ast node(tok_list[ptr].line,ast_null);
if(tok_list[ptr].type==tok_nil) {node=nil_gen(); match(tok_nil);}
else if(tok_list[ptr].type==tok_num){node=num_gen(); match(tok_num);}
else if(tok_list[ptr].type==tok_str){node=str_gen(); match(tok_str);}
else if(tok_list[ptr].type==tok_id) {node= id_gen(); match(tok_id );}
else if(tok_list[ptr].type==tok_id) {node=id_gen(); match(tok_id); }
else if(tok_list[ptr].type==tok_func)
{
if(tok_list[ptr+1].type==tok_id)
@@ -686,7 +654,7 @@ nasal_ast nasal_parse::scalar()
else if(tok_list[ptr].type==tok_var)
{
match(tok_var);
node.set_type(ast_definition);
node.set_type(ast_def);
node.add_child(id_gen());
match(tok_id);
match(tok_eq);
@@ -699,11 +667,10 @@ nasal_ast nasal_parse::scalar()
}
if(is_call(tok_list[ptr].type))
{
nasal_ast tmp=node;
node.clear();
nasal_ast tmp=std::move(node);
node.set_line(tok_list[ptr].line);
node.set_type(ast_call);
node.add_child(tmp);
node.add_child(std::move(tmp));
}
while(is_call(tok_list[ptr].type))
node.add_child(call_scalar());
@@ -711,16 +678,14 @@ nasal_ast nasal_parse::scalar()
}
nasal_ast nasal_parse::call_scalar()
{
nasal_ast node;
switch(tok_list[ptr].type)
{
case tok_lcurve: node=call_func(); break;
case tok_lbracket: node=call_vec(); break;
case tok_dot: node=call_hash(); break;
case tok_lcurve: return callf(); break;
case tok_lbracket: return callv(); break;
case tok_dot: return callh(); break;
}
return node;
}
nasal_ast nasal_parse::call_hash()
nasal_ast nasal_parse::callh()
{
nasal_ast node(tok_list[ptr].line,ast_callh);
match(tok_dot);
@@ -728,8 +693,12 @@ nasal_ast nasal_parse::call_hash()
match(tok_id);
return node;
}
nasal_ast nasal_parse::call_vec()
nasal_ast nasal_parse::callv()
{
// panic set for this token is not ','
// this is the FIRST set of subvec
// array end with tok_null=0
int panic_set[]={tok_id,tok_str,tok_num,tok_not,tok_sub,tok_nil,tok_func,tok_var,tok_lcurve,tok_lbrace,tok_lbracket,tok_colon,tok_null};
nasal_ast node(tok_list[ptr].line,ast_callv);
match(tok_lbracket);
while(tok_list[ptr].type!=tok_rbracket)
@@ -737,14 +706,20 @@ nasal_ast nasal_parse::call_vec()
node.add_child(subvec());
if(tok_list[ptr].type==tok_comma)
match(tok_comma);
else if(tok_list[ptr].type!=tok_rbracket)
else if(tok_list[ptr].type==tok_eof)
break;
else if(tok_list[ptr].type!=tok_rbracket && !check_comma(panic_set))
break;
}
match(tok_rbracket);
match(tok_rbracket,"expected \']\' when calling vector");
return node;
}
nasal_ast nasal_parse::call_func()
nasal_ast nasal_parse::callf()
{
// panic set for this token is not ','
// this is the FIRST set of calculation/hashmember
// array end with tok_null=0
int panic_set[]={tok_id,tok_str,tok_num,tok_not,tok_sub,tok_nil,tok_func,tok_var,tok_lcurve,tok_lbrace,tok_lbracket,tok_null};
nasal_ast node(tok_list[ptr].line,ast_callf);
bool special_call=check_special_call();
match(tok_lcurve);
@@ -753,35 +728,30 @@ nasal_ast nasal_parse::call_func()
node.add_child(special_call?hmem_gen():calc());
if(tok_list[ptr].type==tok_comma)
match(tok_comma);
else if(tok_list[ptr].type!=tok_rcurve)
else if(tok_list[ptr].type==tok_eof)
break;
else if(tok_list[ptr].type!=tok_rcurve && !check_comma(panic_set))
break;
}
match(tok_rcurve);
match(tok_rcurve,"expected \')\' when calling function");
return node;
}
nasal_ast nasal_parse::subvec()
{
nasal_ast node;
if(tok_list[ptr].type==tok_colon)
node=nil_gen();
else
node=calc();
nasal_ast node=tok_list[ptr].type==tok_colon?nil_gen():calc();
if(tok_list[ptr].type==tok_colon)
{
nasal_ast tmp(node.get_line(),ast_subvec);
match(tok_colon);
tmp.add_child(node);
if(tok_list[ptr].type==tok_comma || tok_list[ptr].type==tok_rbracket)
tmp.add_child(nil_gen());
else
tmp.add_child(calc());
node=tmp;
tmp.add_child(std::move(node));
tmp.add_child((tok_list[ptr].type==tok_comma || tok_list[ptr].type==tok_rbracket)?nil_gen():calc());
node=std::move(tmp);
}
return node;
}
nasal_ast nasal_parse::definition()
{
nasal_ast node(tok_list[ptr].line,ast_definition);
nasal_ast node(tok_list[ptr].line,ast_def);
if(tok_list[ptr].type==tok_var)
{
match(tok_var);
@@ -789,7 +759,7 @@ nasal_ast nasal_parse::definition()
{
case tok_id: node.add_child(id_gen());match(tok_id); break;
case tok_lcurve: node.add_child(var_outcurve_def()); break;
default: die(error_line,"expected identifier"); return node;
default: die(error_line,"expected identifier"); break;
}
}
else if(tok_list[ptr].type==tok_lcurve)
@@ -808,43 +778,44 @@ nasal_ast nasal_parse::definition()
}
nasal_ast nasal_parse::var_incurve_def()
{
nasal_ast node;
match(tok_lcurve);
match(tok_var);
node=multi_id();
if(is_call(tok_list[ptr].type))
die(error_line,"don\'t call identifier in multi-definition");
nasal_ast node=multi_id();
match(tok_rcurve);
return node;
}
nasal_ast nasal_parse::var_outcurve_def()
{
nasal_ast node;
match(tok_lcurve);
node=multi_id();
if(is_call(tok_list[ptr].type))
die(error_line,"don\'t call identifier in multi-definition");
nasal_ast node=multi_id();
match(tok_rcurve);
return node;
}
nasal_ast nasal_parse::multi_id()
{
nasal_ast node;
node.set_line(tok_list[ptr].line);
node.set_type(ast_multi_id);
nasal_ast node(tok_list[ptr].line,ast_multi_id);
while(tok_list[ptr].type!=tok_eof)
{
node.add_child(id_gen());
match(tok_id);
if(tok_list[ptr].type!=tok_comma)
if(is_call(tok_list[ptr].type))
{
call_scalar();// recognize calls but this is still a syntax error
die(error_line,"cannot call identifier in multi-definition");
}
if(tok_list[ptr].type==tok_comma)
match(tok_comma);
else if(tok_list[ptr].type==tok_id)// first set of identifier
die(error_line,"expected \',\' between identifiers");
else
break;
match(tok_comma);
}
return node;
}
nasal_ast nasal_parse::multi_scalar(bool check_call_memory)
{
// if check_call_memory is true,we will check if value called here can reach a memory space
int panic_set[]={tok_id,tok_str,tok_num,tok_not,tok_sub,tok_nil,tok_func,tok_var,tok_lcurve,tok_lbrace,tok_lbracket,tok_null};
nasal_ast node(tok_list[ptr].line,ast_multi_scalar);
match(tok_lcurve);
while(tok_list[ptr].type!=tok_rcurve)
@@ -854,10 +825,12 @@ nasal_ast nasal_parse::multi_scalar(bool check_call_memory)
check_memory_reachable(node.get_children().back());
if(tok_list[ptr].type==tok_comma)
match(tok_comma);
else if(tok_list[ptr].type!=tok_rcurve)
else if(tok_list[ptr].type==tok_eof)
break;
else if(tok_list[ptr].type!=tok_rcurve && !check_comma(panic_set))
break;
}
match(tok_rcurve);
match(tok_rcurve,"expected \')\' after multi-scalar");
return node;
}
nasal_ast nasal_parse::multi_assgin()
@@ -927,15 +900,17 @@ nasal_ast nasal_parse::for_loop()
);
else
node.add_child(calc());
match(tok_semi);
// check first semi
match(tok_semi,"expected \';\' in for(;;)");
// conditional expression
if(tok_list[ptr].type==tok_eof)
die(error_line,"expected conditional expression");
die(error_line,"expected conditional expr");
if(tok_list[ptr].type==tok_semi)
node.add_child(null_node_gen());
else
node.add_child(calc());
match(tok_semi);
// check second semi
match(tok_semi,"expected \';\' in for(;;)");
//after loop expression
if(tok_list[ptr].type==tok_eof)
die(error_line,"expected calculation");
@@ -949,7 +924,7 @@ nasal_ast nasal_parse::for_loop()
}
nasal_ast nasal_parse::forei_loop()
{
nasal_ast node(tok_list[ptr].line);
nasal_ast node(tok_list[ptr].line,ast_null);
switch(tok_list[ptr].type)
{
case tok_forindex: node.set_type(ast_forindex);match(tok_forindex); break;
@@ -959,9 +934,11 @@ nasal_ast nasal_parse::forei_loop()
// first expression
// foreach/forindex must have an iterator to loop through
if(tok_list[ptr].type!=tok_var && tok_list[ptr].type!=tok_id)
die(error_line,"expected iterable value");
die(error_line,"expected iterator");
node.add_child(new_iter_gen());
match(tok_semi);
// check semi
match(tok_semi,"expected \';\' in foreach/forindex(iter;vector)");
// check vector
if(tok_list[ptr].type==tok_eof)
die(error_line,"expected vector");
node.add_child(calc());
@@ -969,10 +946,9 @@ nasal_ast nasal_parse::forei_loop()
node.add_child(exprs_gen());
return node;
}
nasal_ast nasal_parse::new_iter_gen()
{
nasal_ast node(tok_list[ptr].line);
nasal_ast node(tok_list[ptr].line,ast_null);
if(tok_list[ptr].type==tok_var)
{
match(tok_var);
@@ -990,7 +966,6 @@ nasal_ast nasal_parse::new_iter_gen()
}
return node;
}
nasal_ast nasal_parse::conditional()
{
nasal_ast node(tok_list[ptr].line,ast_conditional);
@@ -1000,7 +975,7 @@ nasal_ast nasal_parse::conditional()
tmp.add_child(calc());
match(tok_rcurve);
tmp.add_child(exprs_gen());
node.add_child(tmp);
node.add_child(std::move(tmp));
// end of if-expression
while(tok_list[ptr].type==tok_elsif)
{
@@ -1010,14 +985,14 @@ nasal_ast nasal_parse::conditional()
tmp.add_child(calc());
match(tok_rcurve);
tmp.add_child(exprs_gen());
node.add_child(tmp);
node.add_child(std::move(tmp));
}
if(tok_list[ptr].type==tok_else)
{
nasal_ast tmp(tok_list[ptr].line,ast_else);
match(tok_else);
tmp.add_child(exprs_gen());
node.add_child(tmp);
node.add_child(std::move(tmp));
}
return node;
}
@@ -1033,9 +1008,9 @@ nasal_ast nasal_parse::break_expr()
match(tok_break);
return node;
}
nasal_ast nasal_parse::return_expr()
nasal_ast nasal_parse::ret_expr()
{
nasal_ast node(tok_list[ptr].line,ast_return);
nasal_ast node(tok_list[ptr].line,ast_ret);
match(tok_ret);
int type=tok_list[ptr].type;
if(type==tok_nil || type==tok_num || type==tok_str || type==tok_id || type==tok_func ||

1865
nasal_vm.h

File diff suppressed because it is too large Load Diff

144
stl/lib.nas Normal file
View File

@@ -0,0 +1,144 @@
var import=func(filename)
{
return __builtin_import(filename);
}
var print=func(elems...)
{
return __builtin_print(elems);
};
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);}
};
var bits=
{
bitxor: func(a,b){return __builtin_xor(a,b); },
bitand: func(a,b){return __builtin_and(a,b); },
bitor: func(a,b){return __builtin_or(a,b); },
bitnand: func(a,b){return __builtin_nand(a,b);},
bitnot: func(a) {return __builtin_not(a); }
};
var math=
{
e: 2.7182818284590452354,
pi: 3.14159265358979323846264338327950288,
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); },
ln: func(x) {return __builtin_ln(x); },
sqrt: func(x) {return __builtin_sqrt(x); },
atan2: func(x,y){return __builtin_atan2(x,y);}
};
var D2R=math.pi/180;

73
stl/list.nas Normal file
View File

@@ -0,0 +1,73 @@
# lib list.nas
# valkmjolnir 2021/3/31
var list=func()
{
var _={begin:nil,end:nil};
return
{
push_back:func(elem)
{
var tmp={elem:elem,prev:nil,next:nil};
if(_.end!=nil)
{
_.end.next=tmp;
tmp.prev=_.end;
_.end=tmp;
}
else
{
_.begin=tmp;
_.end=tmp;
}
return;
},
push_front:func(elem)
{
var tmp={elem:elem,prev:nil,next:nil};
if(_.begin!=nil)
{
_.begin.prev=tmp;
tmp.next=_.begin;
_.begin=tmp;
}
else
{
_.begin=tmp;
_.end=tmp;
}
return;
},
pop_back:func()
{
if(_.end!=nil)
_.end=_.end.prev;
if(_.end==nil)
_.begin=nil;
else
_.end.next=nil;
return;
},
pop_front:func()
{
if(_.begin!=nil)
_.begin=_.begin.next;
if(_.begin==nil)
_.end=nil;
else
_.begin.prev=nil;
return;
},
front:func()
{
if(_.begin!=nil)
return _.begin.elem;
return nil;
},
back:func()
{
if(_.end!=nil)
return _.end.elem;
return nil;
},
};
}

46
stl/queue.nas Normal file
View File

@@ -0,0 +1,46 @@
# lib queue.nas
# valkmjolnir 2021/3/31
var queue=func()
{
var _={begin:nil,end:nil};
return
{
push:func(elem)
{
var new_node=
{
elem:elem,
next:nil
};
if(_.begin==nil)
_.begin=_.end=new_node;
else
{
_.end.next=new_node;
_.end=new_node;
}
return;
},
pop:func()
{
if(_.begin!=nil)
_.begin=_.begin.next;
if(_.begin==nil)
_.end=nil;
},
front:func()
{
if(_.begin!=nil)
return _.begin.elem;
return nil;
},
clear:func()
{
_.begin=_.end=nil;
},
empty:func()
{
return _.begin==nil;
}
};
}

27
stl/sort.nas Normal file
View File

@@ -0,0 +1,27 @@
# lib sort.nas
# valkmjolnir 2021/4/2
var sort=func(vec,left,right,cmp=func(a,b){return a<=b;})
{
if(left>=right) return nil;
var L=left;
var R=right;
var tmp=vec[L];
while(left<right)
{
while(left<right and cmp(tmp,vec[right]))
right-=1;
while(left<right and cmp(vec[left],tmp))
left+=1;
if(left!=right)
{
var t=vec[left];
vec[left]=vec[right];
vec[right]=t;
}
}
vec[L]=vec[left];
vec[left]=tmp;
sort(vec,L,left-1,cmp);
sort(vec,left+1,R,cmp);
return nil;
}

36
stl/stack.nas Normal file
View File

@@ -0,0 +1,36 @@
# lib stack.nas
# valkmjolnir 2021/3/31
var stack=func()
{
var _={next:nil};
return
{
push:func(elem)
{
_.next={elem:elem,next:_.next};
return;
},
pop:func()
{
var tmp=_.next;
if(tmp!=nil)
_.next=tmp.next;
return;
},
top:func()
{
var tmp=_.next;
if(tmp!=nil)
return tmp.elem;
return nil;
},
clear:func()
{
_.next=nil;
},
empty:func()
{
return _.next==nil;
}
};
}

View File

@@ -1,332 +0,0 @@
import("lib.nas");
var activate_function=
{
sigmoid_func:func(x)
{
return 1.0/(1.0+math.exp(-x));
},
diffsigmoid_func:func(x)
{
var t=func(x){return 1.0/(1.0+math.exp(-x));}(x);
return t*(1-t);
},
tanh_func:func(x)
{
var t1=math.exp(x);
var t2=math.exp(-x);
return (t1-t2)/(t1+t2);
},
difftanh_func:func(x)
{
var t1=math.exp(x);
var t2=math.exp(-x);
var t=(t1-t2)/(t1+t2);
return 1-t*t;
},
relu_func:func(x)
{
return x>0? x:0;
},
diffrelu_func:func(x)
{
return x>0;
},
leaky_relu_func:func(k,x)
{
return x>0? x:k*x;
},
diffleaky_relu_func:func(k,x)
{
return x>0? 1:k;
}
};
var matrix=
{
new:func(col,row)
{
var new_mat=
{
col:col,
row:row,
mat:[]
};
for(var i=0;i<row;i+=1)
{
append(new_mat.mat,[]);
for(var j=0;j<col;j+=1)
append(new_mat.mat[i],nil);
}
return new_mat;
},
srand:func(x)
{
rand(x);
return nil;
},
rand_init:func(mat)
{
for(var i=0;i<mat.row;i+=1)
for(var j=0;j<mat.col;j+=1)
{
if(rand()>0.5)
mat.mat[i][j]=-rand();
else
mat.mat[i][j]=rand();
}
return;
},
prt_mat:func(mat)
{
var prt_s='[\n';
foreach(var i;mat.mat)
{
var s='[';
foreach(var j;i)
s~=(j~',');
s~='],\n';
prt_s~=s;
}
prt_s~=']';
print(prt_s);
return nil;
},
mult_mat:func(mat1,mat2)
{
if(mat1.col!=mat2.row)
{
die("[error-mult] mat1\'s col does not match mat2\'s row.");
return nil;
}
var new_mat=me.new(mat2.col,mat1.row);
for(var i=0;i<new_mat.row;i+=1)
for(var j=0;j<new_mat.col;j+=1)
{
var sum=0;
for(var k=0;k<mat1.col;k+=1)
sum+=mat1.mat[i][k]*mat2.mat[k][j];
new_mat.mat[i][j]=sum;
}
return new_mat;
},
add_mat:func(mat1,mat2)
{
if(mat1.col!=mat2.col or mat1.row!=mat2.row)
{
die("[error-add] mat1\'s col or row does not match mat2\'s.");
return nil;
}
var new_mat=me.new(mat1.col,mat1.row);
for(var i=0;i<new_mat.row;i+=1)
for(var j=0;j<new_mat.col;j+=1)
new_mat.mat[i][j]=mat1.mat[i][j]+mat2.mat[i][j];
return new_mat;
},
sub_mat:func(mat1,mat2)
{
if(mat1.col!=mat2.col or mat1.row!=mat2.row)
{
die("[error-sub] mat1\'s col or row does not match mat2\'s.");
return nil;
}
var new_mat=me.new(mat1.col,mat1.row);
for(var i=0;i<new_mat.row;i+=1)
for(var j=0;j<new_mat.col;j+=1)
new_mat.mat[i][j]=mat1.mat[i][j]-mat2.mat[i][j];
return new_mat;
},
hadamard:func(mat1,mat2)
{
if(mat1.col!=mat2.col or mat1.row!=mat2.row)
{
die("[error-hadamard] mat1\'s col or row does not match mat2\'s.");
return nil;
}
var new_mat=me.new(mat1.col,mat1.row);
for(var i=0;i<new_mat.row;i+=1)
for(var j=0;j<new_mat.col;j+=1)
new_mat.mat[i][j]=mat1.mat[i][j]*mat2.mat[i][j];
return new_mat;
},
transpose:func(mat)
{
var new_mat=me.new(mat.row,mat.col);
for(var i=0;i<new_mat.row;i+=1)
for(var j=0;j<new_mat.col;j+=1)
new_mat.mat[i][j]=mat.mat[j][i];
return new_mat;
},
sigmoid:func(mat)
{
var new_mat=me.new(mat.col,mat.row);
for(var i=0;i<new_mat.row;i+=1)
for(var j=0;j<new_mat.col;j+=1)
new_mat.mat[i][j]=activate_function.sigmoid_func(mat.mat[i][j]);
return new_mat;
},
diffsigmoid:func(mat)
{
var new_mat=me.new(mat.col,mat.row);
for(var i=0;i<new_mat.row;i+=1)
for(var j=0;j<new_mat.col;j+=1)
new_mat.mat[i][j]=activate_function.diffsigmoid_func(mat.mat[i][j]);
return new_mat;
},
tanh:func(mat)
{
var new_mat=me.new(mat.col,mat.row);
for(var i=0;i<new_mat.row;i+=1)
for(var j=0;j<new_mat.col;j+=1)
new_mat.mat[i][j]=activate_function.tanh_func(mat.mat[i][j]);
return new_mat;
},
difftanh:func(mat)
{
var new_mat=me.new(mat.col,mat.row);
for(var i=0;i<new_mat.row;i+=1)
for(var j=0;j<new_mat.col;j+=1)
new_mat.mat[i][j]=activate_function.difftanh_func(mat.mat[i][j]);
return new_mat;
},
relu:func(mat)
{
var new_mat=me.new(mat.col,mat.row);
for(var i=0;i<new_mat.row;i+=1)
for(var j=0;j<new_mat.col;j+=1)
new_mat.mat[i][j]=activate_function.relu_func(mat.mat[i][j]);
return new_mat;
},
diffrelu:func(mat)
{
var new_mat=me.new(mat.col,mat.row);
for(var i=0;i<new_mat.row;i+=1)
for(var j=0;j<new_mat.col;j+=1)
new_mat.mat[i][j]=activate_function.diffrelu_func(mat.mat[i][j]);
return new_mat;
},
leaky_relu:func(k,mat)
{
var new_mat=me.new(mat.col,mat.row);
for(var i=0;i<new_mat.row;i+=1)
for(var j=0;j<new_mat.col;j+=1)
new_mat.mat[i][j]=activate_function.leaky_relu_func(k,mat.mat[i][j]);
return new_mat;
},
diffleaky_relu:func(k,mat)
{
var new_mat=me.new(mat.col,mat.row);
for(var i=0;i<new_mat.row;i+=1)
for(var j=0;j<new_mat.col;j+=1)
new_mat.mat[i][j]=activate_function.diffleaky_relu_func(k,mat.mat[i][j]);
return new_mat;
}
};
var bp=
{
inum:2,
hnum:4,
onum:1,
learning_rate:nil,
hidden_layer:nil,
hidden_res:nil,
output_layer:nil,
output_res:nil,
result:nil,
training_set:[],
expect_set:[],
init:func()
{
matrix.srand(time(0));
me.hidden_layer=matrix.new(me.hnum,me.inum);
matrix.rand_init(me.hidden_layer);
me.output_layer=matrix.new(me.onum,me.hnum);
matrix.rand_init(me.output_layer);
return;
},
set_learning_rate:func(lr)
{
me.learning_rate=matrix.new(me.onum,1);
for(var i=0;i<me.onum;i+=1)
me.learning_rate.mat[i][0]=lr;
return;
},
set_training_set:func()
{
for(var i=0;i<4;i+=1)
append(me.training_set,matrix.new(me.inum,1));
me.training_set[0].mat[0][0]=0;
me.training_set[0].mat[0][1]=0;
me.training_set[1].mat[0][0]=0;
me.training_set[1].mat[0][1]=1;
me.training_set[2].mat[0][0]=1;
me.training_set[2].mat[0][1]=0;
me.training_set[3].mat[0][0]=1;
me.training_set[3].mat[0][1]=1;
return;
},
set_expect_set:func()
{
for(var i=0;i<4;i+=1)
append(me.expect_set,matrix.new(me.onum,1))
me.expect_set[0].mat[0][0]=0;
me.expect_set[1].mat[0][0]=1;
me.expect_set[2].mat[0][0]=1;
me.expect_set[3].mat[0][0]=0;
return;
},
forward:func(i)
{
var tmp=nil;
me.hidden_res=matrix.mult_mat(me.training_set[i],me.hidden_layer);
tmp=matrix.sigmoid(me.hidden_res);
me.output_res=matrix.mult_mat(tmp,me.output_layer);
tmp=matrix.sigmoid(me.output_res);
me.result=tmp;
return;
},
backward:func(i)
{
var output_diff=matrix.sub_mat(me.expect_set[i],me.result);
output_diff=matrix.hadamard(output_diff,me.learning_rate);
output_diff=matrix.hadamard(output_diff,matrix.diffsigmoid(me.output_res));
output_diff=matrix.mult_mat(output_diff,matrix.transpose(me.output_layer));
matrix.prt_mat(output_diff);
var hidden_diff=matrix.mult_mat();
matrix.prt_mat(hidden_diff);
output_layer=matrix.add_mat(output_layer,output_diff);
var error=0;
foreach(var i;tmp.mat[0])
error+=i;
error*=0.5;
return error;
},
training_process:func()
{
var cnt=0;
var error=1e8;
while(error>0.01)
{
error=0;
for(var i=0;i<4;i+=1)
{
me.forward(i);
error+=me.backward(i);
}
print(error);
}
return;
}
};
var main=func()
{
bp.init();
bp.set_learning_rate(0.1);
bp.set_training_set();
bp.set_expect_set();
bp.training_process();
return nil;
}
main();

View File

@@ -4,7 +4,7 @@ var char_ttf=[
[" ████╗"," ██╔██║"," ██╔╝██║"," ███████║","██╔═══██║","╚═╝ ╚═╝"],
["██████╗ ","██╔══██╗","██████╔╝","██╔══██╗","██████╔╝","╚═════╝ "],
[" ██████╗","██╔════╝","██║ ","██║ ","╚██████╗"," ╚═════╝"],
["██████╗ ","██╔══██╗","██║ ██║","██║ ██║","██████╔╝","╚═════╝ "],
["██████╗ ","██╔══██╗","██║ ██║","██║ ██║","██████╔╝","╚═════╝ "],
["███████╗","██╔════╝","█████╗ ","██╔══╝ ","███████╗","╚══════╝"],
["███████╗","██╔════╝","█████╗ ","██╔══╝ ","██║ ","╚═╝ "],
[" █████╗ ","██╔═══╝ ","██║ ██╗ ","██║ ╚██╗","╚█████╔╝"," ╚════╝ "],
@@ -53,9 +53,9 @@ var curve1=func()
var shadow=["░","▒","▓","█","▀","▄","▐","▌"];
rand(100);
var s="";
for(var i=0;i<25;i+=1)
for(var i=0;i<10;i+=1)
{
for(var j=0;j<100;j+=1)
for(var j=0;j<40;j+=1)
s~=shadow[int(8*rand())];
s~='\n';
}
@@ -66,28 +66,15 @@ var curve2=func()
var table=["╚","═","╝","╔","║","╗"];
rand(100);
var s="";
for(var i=0;i<25;i+=1)
for(var i=0;i<10;i+=1)
{
for(var j=0;j<100;j+=1)
for(var j=0;j<40;j+=1)
s~=table[int(6*rand())];
s~='\n';
}
print(s);
}
var curve3=func()
{
var block=["░░","▒▒","▓▓","██","▀▀","▄▄","▄▀","▀▄","▐▐","▌▌"];
rand(100);
var s="";
for(var i=0;i<25;i+=1)
{
for(var j=0;j<50;j+=1)
s~=block[int(10*rand())];
s~='\n';
}
print(s);
}
var curve4=func()
{
var s=["","","","","",""];
var cnt=0;
@@ -108,12 +95,12 @@ var curve4=func()
}
return;
}
var curve5=func()
var curve4=func()
{
for(var loop=0;loop<100;loop+=1)
var arr=[0,1,2,3,4,5,6,7,8,0,1,2,3,4,5,6,7,8,0,1,2,3,4,5,6,7,8];
for(var loop=0;loop<10;loop+=1)
{
var arr=[0,1,2,3,4,5,6,7,8,0,1,2,3,4,5,6,7,8];
for(var i=17;i>=0;i-=1)
for(var i=26;i>=0;i-=1)
{
var rand_index=int(i*rand());
(arr[i],arr[rand_index])=(arr[rand_index],arr[i]);
@@ -128,9 +115,8 @@ var curve5=func()
return;
}
trans_ttf("just for test");
trans_ttf("ValKmjolnir");
trans_ttf(" ValKmjolnir ");
curve1();
curve2();
curve3();
curve4();
curve5();
curve4();

View File

@@ -1,5 +1,10 @@
# Road check and auto pilot(??) by ValKmjolnir
# Road check and auto pilot by ValKmjolnir
import("lib.nas");
import("props.nas");
var dt=0.01;
var intergral=0;
var derivative=0;
var previous_error=0;
var position_change = func(position_val,value){
if(position_val+value>180)
position_val += value-360;
@@ -10,12 +15,11 @@ var position_change = func(position_val,value){
return position_val;
}
var road_check_func = func(){
var lat = props.getNode("/position/latitude-deg",1).getValue();
var lon = props.getNode("/position/longitude-deg",1).getValue();
var position_info = geodinfo(lat,lon);
var position_names = position_info[1].names;
# the friction_factor of freeway runway and road is 1
if((position_names[0]=="Freeway") or (position_names[0]=="Road"))
{
@@ -24,14 +28,14 @@ var road_check_func = func(){
var lon_change = 0;
var left_range = 0;
var right_range = 0;
for(var i=0;i>-0.00005;i-=0.000001)
{
car_heading = props.getNode("/orientation/heading-deg",1).getValue();
lat_change = math.sin(math.pi*car_heading/180);
lon_change = -math.cos(math.pi*car_heading/180);
lat = props.getNode("/position/latitude-deg",1).getValue()+0.0001*math.cos(math.pi*car_heading/180);
lon = props.getNode("/position/longitude-deg",1).getValue()+0.0001*math.sin(math.pi*car_heading/180);
lat_change = math.sin(D2R*car_heading);
lon_change = -math.cos(D2R*car_heading);
lat = props.getNode("/position/latitude-deg",1).getValue()+0.0001*math.cos(D2R*car_heading);
lon = props.getNode("/position/longitude-deg",1).getValue()+0.0001*math.sin(D2R*car_heading);
var other_position_info = geodinfo(position_change(lat,i*lat_change),position_change(lon,i*lon_change));
var other_names = other_position_info[1].names;
if((other_names[0]=="Freeway") or (other_names[0]=="Road"))
@@ -42,10 +46,10 @@ var road_check_func = func(){
for(var i=0;i<0.00005;i+=0.000001)
{
car_heading = props.getNode("/orientation/heading-deg",1).getValue();
lat_change = math.sin(math.pi*car_heading/180);
lon_change = -math.cos(math.pi*car_heading/180);
lat = props.getNode("/position/latitude-deg",1).getValue()+0.0001*math.cos(math.pi*car_heading/180);
lon = props.getNode("/position/longitude-deg",1).getValue()+0.0001*math.sin(math.pi*car_heading/180);
lat_change = math.sin(D2R*car_heading);
lon_change = -math.cos(D2R*car_heading);
lat = props.getNode("/position/latitude-deg",1).getValue()+0.0001*math.cos(D2R*car_heading);
lon = props.getNode("/position/longitude-deg",1).getValue()+0.0001*math.sin(D2R*car_heading);
var other_position_info = geodinfo(position_change(lat,i*lat_change),position_change(lon,i*lon_change));
var other_names = other_position_info[1].names;
if((other_names[0]=="Freeway") or (other_names[0]=="Road"))
@@ -53,25 +57,26 @@ var road_check_func = func(){
else
break;
}
#if(left_range>right_range)
#{
# setprop("/controls/flight/rudder",-(right_range-left_range)*(right_range-left_range)/10000);
# print("right ",right_range);
#}
#else if(left_range<right_range)
#{
# setprop("/controls/flight/rudder",(right_range-left_range)*(right_range-left_range)/10000);
# print("left ",left_range);
#}
#else
# setprop("/controls/flight/rudder",0);
props.getNode("/controls/flight/rudder",1).setValue((right_range-left_range)/200);
var error=right_range-left_range;
intergral+=error*dt;
derivative=(error-previous_error)/dt;
var (Kp,Ki,Kd)=(1/900,0.05,0.005);
# print("change p ",Kp*error*error,' i ',Ki*intergral,' d ',Kd*derivative);
if(error<0)
props.getNode("/", 1).setValue("/controls/flight/rudder",-Kp*error*error+Ki*intergral+Kd*derivative);
else if(error>0)
props.getNode("/", 1).setValue("/controls/flight/rudder",Kp*error*error+Ki*intergral+Kd*derivative);
else
props.getNode("/", 1).setValue("/controls/flight/rudder",0);
previous_error=error;
}
};
var road_check_timer = maketimer(0.1,road_check_func);
var road_check_timer = maketimer(0.01,road_check_func);
var toggle_auto_pilot = func(){
if(!road_check_timer.isRunning)
{
intergral=0;
road_check_timer.start();
props.getNode("/sim/messages/copilot",1).setValue("ze dong sheng teaan see tong yee tse yung. Auto Sheng Teaan System Activated!");
}
@@ -80,4 +85,4 @@ var toggle_auto_pilot = func(){
road_check_timer.stop();
props.getNode("/sim/messages/copilot",1).setValue("ze dong sheng teaan see tong yee guan bee. Auto Sheng Teaan System is off.");
}
}
}

240
test/bf.nas Normal file
View File

@@ -0,0 +1,240 @@
import("lib.nas");
var mandelbrot=
"[A mandelbrot set fractal viewer in brainf*** written by Erik Bosman]
+++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++++++++[[
>>>>>>>>>]+[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-]>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+
<<<<<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>>+>>>>>>>>>>>>>>>>>>>>>>>>>>
>+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+[>>>>>>[>>>>>>>[-]>>]<<<<<<<<<[<<<<<<<<<]>>
>>>>>[-]+<<<<<<++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<+++++++[-[->>>
>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[[-]>>>>>>[>>>>>
>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>
[>>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<
<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>+++++++++++++++[[
>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[
>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[
-<<+>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<
<<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<
[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>
>>>>[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+
<<<<<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>
>>>>>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<
+>>>>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<
<]<+<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>
>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<
<<<]>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<
<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->
>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<
<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]<<<<<<<[->+>>>-<<<<]>>>>>>>>>+++++++++++++++++++
+++++++>>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>[<<<<<<<+<[-<+>>>>+<<[-]]>[-<<[->+>>>-
<<<<]>>>]>>>>>>>>>>>>>[>>[-]>[-]>[-]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>>>>>>[>>>>>
[-<<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>[-<<<<<<<<
<+>>>>>>>>>]>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>>]+>[-
]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>>>>>>>]<<<
<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+>>]<
<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[->>>>
>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-]<->>>
[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[>>>>>>[-<
<<<<+>>>>>]<<<<<[->>>>>+<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>+>>>>>>>>
]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+
>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>
[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-
]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>>
[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++
+++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-<<<<<<<+
>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[
-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>>]>[-<<<<<<[->>>>>+<++<<<<]>>>>>[-<
<<<<+>>>>>]<->+>]<[->+<]<<<<<[->>>>>+<<<<<]>>>>>>[-]<<<<<<+>>>>[-<<<<->>>>]+<<<<
[->>>>->>>>>[>>[-<<->>]+<<[->>->[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]
+>>>>>>[>>>>>>>>>]>+<]]+>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<<<<<<<<<<[<<<<<
<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<
[<<<<<<<<<]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<
<<<+<[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<
<<<<<+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<
<<<<<<<<<<]>>>>[-]<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+<]>>>>>>>>]<<<
<<<<<+<[>[->>>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>[->>>>+<<<<]>]<[->>>>-<<<<<<<
<<<<<<<+>>>>>>>>>>]<]>>[->>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>>+<<<<
]<<<<<<<<<<<]>>>>>>+<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>>>>>>>>>]<<<<<<<<<
[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<<<<<<
+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<<<<<<
<<<<<]]>[-]>>[-]>[-]>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<
<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[
[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+
[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>
[-<<+>>]<<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<
<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[
>[-]<->>>[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[
>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>
>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>[-]>>>>+++++++++++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<
<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<
<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-
<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>
>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>>>
[-<<<->>>]<<<[->>>+<<<]>>>>>>>>]<<<<<<<<+<[>[->+>[-<-<<<<<<<<<<+>>>>>>>>>>>>[-<<
+>>]<]>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<<<]>>[-<+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<]>
[-<<+>>]<<<<<<<<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>
>>>>>>]<<<<<<<<+<[>[->+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>[-<+>]>]<[-<-<<<<<<<<<<+>>>>
>>>>>>>]<<]>>>[-<<+>[-<-<<<<<<<<<<+>>>>>>>>>>>]>]<[-<+>]<<<<<<<<<<<<]>>>>>+<<<<<
]>>>>>>>>>[>>>[-]>[-]>[-]>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>>>[-<<<<<
<+>>>>>>]<<<<<<[->>>>>>+<<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>
>]>>[-<<<<<<<[->>>>>+<++<<<<]>>>>>[-<<<<<+>>>>>]<->+>>]<<[->>+<<]<<<<<[->>>>>+<<
<<<]+>>>>[-<<<<->>>>]+<<<<[->>>>->>>>>[>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<
<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>[-<<->>]+<<[->>->[-<<<+>>>]<
<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<
<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+
<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>[->>>+<<<]>]<[->>>-
<<<<<<<<<<<<<+>>>>>>>>>>]<]>>[->>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>+<<<
]<<<<<<<<<<<]>>>>>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]]>>>>[-<<<<+>
>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<<[->>>-
<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[
->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<<<<<]]>>>>[-]<<<<]>>>>[-<<<<+>>
>>]<<<<[->>>>+>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>[>>>>>>
>>>]<<<<<<<<<[>[->>>>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<
<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<
<<<<]]>>>>>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>[-<<<<+
>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<+>>>>>
]<<<<<[->>>>>+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>
>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>
>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[-<<+
>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>
[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-
]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>>
[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<
<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>
>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<+>>>
>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+
<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>
>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<<<<]
>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<<
]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->>>+<
<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>
>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>->>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>]<<+>>>>[-<<<<
->>>>]+<<<<[->>>>-<<<<<<.>>]>>>>[-<<<<<<<.>>>>>>>]<<<[-]>[-]>[-]>[-]>[-]>[-]>>>[
>[-]>[-]>[-]>[-]>[-]>[-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-]>>>>]<<<<<<<<<
[<<<<<<<<<]>+++++++++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+>>>>>>>>>+<<<<<<<<
<<<<<<[<<<<<<<<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+[-]>>[>>>>>>>>>]<<<<<
<<<<[>>>>>>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<[<<<<<<<<<]>>>>>>>[-]+>>>]<<<<
<<<<<<]]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+>>[>+>>>>[-<<<<->>>>]<<<<[->>>
>+<<<<]>>>>>>>>]<<+<<<<<<<[>>>>>[->>+<<]<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<
<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<<<<<[->>>>>>+<<<<<<]<
+<<<<<<<<<]>>>>>>>-<<<<[-]+<<<]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>->>[>>
>>>[->>+<<]>>>>]<<<<<<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<
<<<<[->>>>>>+<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+<<<
<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<<<<<->>>>>]+<<<<<[->>>>>->>[-<<<<<<<+>>>>>>>]<<<<
<<<[->>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>[-<
<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<<<<<<<<<[<<<
<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<
<<[<<<<<<<<<]>>>>[-]<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>-<<<<<[<<<<<<<
<<]]>>>]<<<<.>>>>>>>>>>[>>>>>>[-]>>>]<<<<<<<<<[<<<<<<<<<]>++++++++++[-[->>>>>>>>
>+<<<<<<<<<]>>>>>>>>>]>>>>>+>>>>>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-<<<<<<
<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+[-]>[>>>>>>>>>]<<<<<<<<<[>>>>>>>>[-<<<<<<<+>>>>>>
>]<<<<<<<[->>>>>>>+<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+>>]<<<<<<<<<<]]>>>>>>>>[-<<<<<
<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+>[>+>>>>>[-<<<<<->>>>>]<<<<<[->>>>>+<<<<<]>>>>>>
>>]<+<<<<<<<<[>>>>>>[->>+<<]<<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-]<-
>>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<]<+<<<<<<
<<<]>>>>>>>>-<<<<<[-]+<<<]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>->[>>>
>>>[->>+<<]>>>]<<<<<<<<<[>[-]<->>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<
<<<<<[->>>>>>>+<<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>
+>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<->>>>>>]+<
<<<<<[->>>>>>->>[-<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<<
<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>
-<<[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>
>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<<<++++
+[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>->>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<[<<<<
<<<<<]]>>>]";
var paper=[];
var (ptr,pc)=(0,0);
var (code,inum,stack)=(nil,nil,nil);
var (add,mov,jt,jf,in,out)=(0,1,2,3,4,5);
var func_table=[
func(){paper[ptr]+=inum[pc];return;},
func(){ptr+=inum[pc];return;},
func(){if(paper[ptr])pc=inum[pc];return;},
func(){if(!paper[ptr])pc=inum[pc];return;},
func(){paper[ptr]=input()[0];return;},
func(){print(chr(paper[ptr]));return;}
];
var bf=func(program)
{
setsize(paper,131072);
(ptr,code,inum,stack)=(0,[],[],[]);
var len=size(program);
for(var i=0;i<len;i+=1)
{
var c=chr(program[i]);
if(c=='+' or c=='-')
{
append(code,func_table[add]);
append(inum,0);
for(;i<len;i+=1)
{
if(chr(program[i])=='+')
inum[-1]+=1;
elsif(chr(program[i])=='-')
inum[-1]-=1;
else
{
i-=1;
break;
}
}
}
elsif(c=='<' or c=='>')
{
append(code,func_table[mov]);
append(inum,0);
for(;i<len;i+=1)
{
if(chr(program[i])=='>')
inum[-1]+=1;
elsif(chr(program[i])=='<')
inum[-1]-=1;
else
{
i-=1;
break;
}
}
}
elsif(c==',')
{
append(code,func_table[in]);
append(inum,0);
}
elsif(c=='.')
{
append(code,func_table[out]);
append(inum,0);
}
elsif(c=='[')
{
append(code,func_table[jf]);
append(inum,0);
append(stack,size(code)-1);
}
elsif(c==']')
{
if(!size(stack))
die("lack [");
var label=pop(stack);
append(code,func_table[jt]);
append(inum,label-1);
inum[label]=size(code)-2;
}
}
if(size(stack))
die("lack ]");
len=size(code);
for(pc=0;pc<len;pc+=1)
code[pc]();
return;
}
bf(mandelbrot);

248
test/bfconvertor.nas Normal file
View File

@@ -0,0 +1,248 @@
import("lib.nas");
var mandelbrot=
"[A mandelbrot set fractal viewer in brainf*** written by Erik Bosman]
+++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++++++++[[
>>>>>>>>>]+[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-]>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+
<<<<<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>>+>>>>>>>>>>>>>>>>>>>>>>>>>>
>+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+[>>>>>>[>>>>>>>[-]>>]<<<<<<<<<[<<<<<<<<<]>>
>>>>>[-]+<<<<<<++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<+++++++[-[->>>
>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[[-]>>>>>>[>>>>>
>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>
[>>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<
<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>+++++++++++++++[[
>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[
>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[
-<<+>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<
<<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<
[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>
>>>>[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+
<<<<<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>
>>>>>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<
+>>>>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<
<]<+<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>
>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<
<<<]>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<
<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->
>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<
<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]<<<<<<<[->+>>>-<<<<]>>>>>>>>>+++++++++++++++++++
+++++++>>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>[<<<<<<<+<[-<+>>>>+<<[-]]>[-<<[->+>>>-
<<<<]>>>]>>>>>>>>>>>>>[>>[-]>[-]>[-]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>>>>>>[>>>>>
[-<<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>[-<<<<<<<<
<+>>>>>>>>>]>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>>]+>[-
]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>>>>>>>]<<<
<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+>>]<
<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[->>>>
>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-]<->>>
[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[>>>>>>[-<
<<<<+>>>>>]<<<<<[->>>>>+<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>+>>>>>>>>
]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+
>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>
[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-
]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>>
[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++
+++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-<<<<<<<+
>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[
-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>>]>[-<<<<<<[->>>>>+<++<<<<]>>>>>[-<
<<<<+>>>>>]<->+>]<[->+<]<<<<<[->>>>>+<<<<<]>>>>>>[-]<<<<<<+>>>>[-<<<<->>>>]+<<<<
[->>>>->>>>>[>>[-<<->>]+<<[->>->[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]
+>>>>>>[>>>>>>>>>]>+<]]+>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<<<<<<<<<<[<<<<<
<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<
[<<<<<<<<<]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<
<<<+<[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<
<<<<<+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<
<<<<<<<<<<]>>>>[-]<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+<]>>>>>>>>]<<<
<<<<<+<[>[->>>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>[->>>>+<<<<]>]<[->>>>-<<<<<<<
<<<<<<<+>>>>>>>>>>]<]>>[->>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>>+<<<<
]<<<<<<<<<<<]>>>>>>+<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>>>>>>>>>]<<<<<<<<<
[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<<<<<<
+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<<<<<<
<<<<<]]>[-]>>[-]>[-]>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<
<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[
[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+
[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>
[-<<+>>]<<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<
<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[
>[-]<->>>[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[
>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>
>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>[-]>>>>+++++++++++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<
<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<
<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-
<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>
>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>>>
[-<<<->>>]<<<[->>>+<<<]>>>>>>>>]<<<<<<<<+<[>[->+>[-<-<<<<<<<<<<+>>>>>>>>>>>>[-<<
+>>]<]>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<<<]>>[-<+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<]>
[-<<+>>]<<<<<<<<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>
>>>>>>]<<<<<<<<+<[>[->+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>[-<+>]>]<[-<-<<<<<<<<<<+>>>>
>>>>>>>]<<]>>>[-<<+>[-<-<<<<<<<<<<+>>>>>>>>>>>]>]<[-<+>]<<<<<<<<<<<<]>>>>>+<<<<<
]>>>>>>>>>[>>>[-]>[-]>[-]>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>>>[-<<<<<
<+>>>>>>]<<<<<<[->>>>>>+<<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>
>]>>[-<<<<<<<[->>>>>+<++<<<<]>>>>>[-<<<<<+>>>>>]<->+>>]<<[->>+<<]<<<<<[->>>>>+<<
<<<]+>>>>[-<<<<->>>>]+<<<<[->>>>->>>>>[>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<
<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>[-<<->>]+<<[->>->[-<<<+>>>]<
<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<
<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+
<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>[->>>+<<<]>]<[->>>-
<<<<<<<<<<<<<+>>>>>>>>>>]<]>>[->>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>+<<<
]<<<<<<<<<<<]>>>>>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]]>>>>[-<<<<+>
>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<<[->>>-
<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[
->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<<<<<]]>>>>[-]<<<<]>>>>[-<<<<+>>
>>]<<<<[->>>>+>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>[>>>>>>
>>>]<<<<<<<<<[>[->>>>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<
<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<
<<<<]]>>>>>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>[-<<<<+
>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<+>>>>>
]<<<<<[->>>>>+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>
>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>
>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[-<<+
>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>
[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-
]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>>
[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<
<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>
>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<+>>>
>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+
<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>
>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<<<<]
>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<<
]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->>>+<
<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>
>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>->>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>]<<+>>>>[-<<<<
->>>>]+<<<<[->>>>-<<<<<<.>>]>>>>[-<<<<<<<.>>>>>>>]<<<[-]>[-]>[-]>[-]>[-]>[-]>>>[
>[-]>[-]>[-]>[-]>[-]>[-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-]>>>>]<<<<<<<<<
[<<<<<<<<<]>+++++++++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+>>>>>>>>>+<<<<<<<<
<<<<<<[<<<<<<<<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+[-]>>[>>>>>>>>>]<<<<<
<<<<[>>>>>>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<[<<<<<<<<<]>>>>>>>[-]+>>>]<<<<
<<<<<<]]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+>>[>+>>>>[-<<<<->>>>]<<<<[->>>
>+<<<<]>>>>>>>>]<<+<<<<<<<[>>>>>[->>+<<]<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<
<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<<<<<[->>>>>>+<<<<<<]<
+<<<<<<<<<]>>>>>>>-<<<<[-]+<<<]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>->>[>>
>>>[->>+<<]>>>>]<<<<<<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<
<<<<[->>>>>>+<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+<<<
<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<<<<<->>>>>]+<<<<<[->>>>>->>[-<<<<<<<+>>>>>>>]<<<<
<<<[->>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>[-<
<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<<<<<<<<<[<<<
<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<
<<[<<<<<<<<<]>>>>[-]<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>-<<<<<[<<<<<<<
<<]]>>>]<<<<.>>>>>>>>>>[>>>>>>[-]>>>]<<<<<<<<<[<<<<<<<<<]>++++++++++[-[->>>>>>>>
>+<<<<<<<<<]>>>>>>>>>]>>>>>+>>>>>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-<<<<<<
<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+[-]>[>>>>>>>>>]<<<<<<<<<[>>>>>>>>[-<<<<<<<+>>>>>>
>]<<<<<<<[->>>>>>>+<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+>>]<<<<<<<<<<]]>>>>>>>>[-<<<<<
<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+>[>+>>>>>[-<<<<<->>>>>]<<<<<[->>>>>+<<<<<]>>>>>>
>>]<+<<<<<<<<[>>>>>>[->>+<<]<<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-]<-
>>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<]<+<<<<<<
<<<]>>>>>>>>-<<<<<[-]+<<<]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>->[>>>
>>>[->>+<<]>>>]<<<<<<<<<[>[-]<->>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<
<<<<<[->>>>>>>+<<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>
+>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<->>>>>>]+<
<<<<<[->>>>>>->>[-<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<<
<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>
-<<[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>
>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<<<++++
+[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>->>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<[<<<<
<<<<<]]>>>]";
var bf=func(program)
{
var stack=[];
var len=size(program);
var f="import('lib.nas');\nvar ptr=0;\nvar paper=[];\nsetsize(paper,131072);\n";
for(var i=0;i<len;i+=1)
{
var c=chr(program[i]);
if(c=='+' or c=='-')
{
var cnt=0;
for(;i<len;i+=1)
{
if(chr(program[i])=='+')
cnt+=1;
elsif(chr(program[i])=='-')
cnt-=1;
else
{
i-=1;
break;
}
}
if(cnt!=0)
for(var j=0;j<size(stack);j+=1)
f~='\t';
if(cnt>0)
f~="paper[ptr]+="~cnt~";\n";
elsif(cnt<0)
f~="paper[ptr]-="~(-cnt)~";\n";
}
elsif(c=='<' or c=='>')
{
var cnt=0;
for(;i<len;i+=1)
{
if(chr(program[i])=='>')
cnt+=1;
elsif(chr(program[i])=='<')
cnt-=1;
else
{
i-=1;
break;
}
}
if(cnt!=0)
for(var j=0;j<size(stack);j+=1)
f~='\t';
if(cnt>0)
f~="ptr+="~cnt~";\n";
elsif(cnt<0)
f~="ptr-="~(-cnt)~";\n";
}
elsif(c==',')
{
for(var j=0;j<size(stack);j+=1)
f~='\t';
f~="paper[ptr]=input();\n";
}
elsif(c=='.')
{
for(var j=0;j<size(stack);j+=1)
f~='\t';
f~="print(chr(paper[ptr]));\n";
}
elsif(c=='[')
{
for(var j=0;j<size(stack);j+=1)
f~='\t';
f~="while(paper[ptr])\n";
for(var j=0;j<size(stack);j+=1)
f~='\t';
f~="{\n";
append(stack,0);
}
elsif(c==']')
{
if(!size(stack))
{
println("lack [");
return;
}
pop(stack);
for(var j=0;j<size(stack);j+=1)
f~='\t';
f~="}\n";
}
}
if(size(stack))
{
println("lack ]");
return;
}
io.fout("mandel.nas",f);
return;
}
bf(mandelbrot);

View File

@@ -1,5 +1,5 @@
import("lib.nas");
import("queue.nas");
import("stl/lib.nas");
import("stl/queue.nas");
rand(time(0));
@@ -20,19 +20,20 @@ var prt=func()
s~=map[i][j];
s~='\n';
}
print(s,'\n');
s~='----------\n';
print(s);
}
var bfs=func(begin,end)
{
var move=[[1,0],[0,1],[-1,0],[0,-1]];
var queue=new_queue();
queue_push(queue,begin);
var que=queue();
que.push(begin);
map[begin[0]][begin[1]]=3;
while(!queue_empty(queue))
while(!que.empty())
{
var vertex=queue_front(queue);
queue_pop(queue);
var vertex=que.front();
que.pop();
foreach(var i;move)
{
var x=vertex[0]+i[0];
@@ -44,7 +45,7 @@ var bfs=func(begin,end)
}
if(0<=x and x<10 and 0<=y and y<10 and map[x][y]==0)
{
queue_push(queue,[x,y]);
que.push([x,y]);
map[x][y]=3;
}
}
@@ -54,8 +55,4 @@ var bfs=func(begin,end)
return;
}
prt();
var begin=[input(),input()];
var end=[input(),input()];
bfs(begin,end);
prt();
bfs([0,0],[9,9]);

View File

@@ -1 +1 @@
for(var i=0;i<4000000;i+=1);
for(var i=0;i<4e6;i+=1);

View File

@@ -4,14 +4,13 @@ rand(time(0));
var new_neuron=func()
{
var neuron={
return {
in:0,
out:0,
w:[],
bia:0,
diff:0
};
return neuron;
}
var sigmoid=func(x)
@@ -24,12 +23,9 @@ var diffsigmoid=func(x)
return x*(1-x);
}
var inum=2;
var hnum=4;
var onum=1;
var lr=0.1;
var (inum,hnum,onum,lr)=(2,4,1,0.1);
var training_set=[[0,0],[0,1],[1,0],[1,1]];
var expect=[[0],[1],[1],[0]];
var expect=[0,1,1,0];
var hidden=[];
for(var i=0;i<hnum;i+=1)
@@ -89,19 +85,12 @@ var run=func(vec)
}
var get_error=func(x)
{
var error=0;
var expect_set=expect[x];
for(var i=0;i<onum;i+=1)
error+=(expect_set[i]-output[i].out)*(expect_set[i]-output[i].out);
error*=0.5;
return error;
return 0.5*(expect[x]-output[0].out)*(expect[x]-output[0].out);
}
var backward=func(x)
{
var input=training_set[x];
var expect_set=expect[x];
for(var i=0;i<onum;i+=1)
output[i].diff=(expect_set[i]-output[i].out)*diffsigmoid(output[i].in);
output[0].diff=(expect[x]-output[0].out)*diffsigmoid(output[0].in);
for(var i=0;i<hnum;i+=1)
{
hidden[i].diff=0;
@@ -124,9 +113,7 @@ var backward=func(x)
return;
}
var cnt=0;
var show=0;
var error=1e8;
var (cnt,error)=(0,100);
while(error>0.0005)
{
error=0;
@@ -137,21 +124,9 @@ while(error>0.0005)
backward(i);
}
cnt+=1;
show+=1;
if(show==200)
{
show=0;
print('epoch ',cnt,':',error,'\r');
}
}
print('finished after ',cnt,' epoch.\n');
var vec=[
[0,0],
[0,1],
[1,0],
[1,1]
];
foreach(var v;vec)
foreach(var v;training_set)
{
run(v);
print(v,': ',output[0].out,'\n');

View File

@@ -1,30 +1,32 @@
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]);
for(var i=0;i<len;i+=1)
cnt+=(s[i]==enter);
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 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 max_size=size('nasal_codegen.h');
var (cnt,semi)=[0,0];
foreach(var file;filename)
var (bytes,line,semi)=(0,0,0);
forindex(var i;filename)
{
var s=io.fin(file);
var name=file;
for(var i=size(name);i<max_size;i+=1)
name~=' ';
var line_cnt=size(split('\n',s));
var semi_cnt=size(split(';' ,s))-1;
println(name,'| ',line_cnt,' \tline | ',semi_cnt,' \tsemi');
cnt +=line_cnt;
var s=io.fin(filename[i]);
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: ',cnt,' line | ',semi,' semi');
println('total: | ',line,' \tline | ',semi,' \tsemi');
println('bytes: | ',bytes,' bytes| ',int(bytes/1024),' \tkb');
}();

View File

@@ -1,30 +0,0 @@
id[0] and id[1];
1 or 2;
"str" ==1;
1*1/1+1;
2*3*4/1-2+3;
1-1+20-2*10;
1+s1*(s2+s3[0])-1;
var e=1+s1*(s2+s3[0])-1;
id;
"str";
id(id);
id("str",1,1);
var e=1;
var x=10*2-20;
var id;
var id=[1,2,3,4];
var id={id:"str"};
id();
id.id();
id.id.id();
id[0].id.id(id,"str",1,2,3,4).id[10];
id(0)[1].id;
var hash={
h:"hello",
parent:[id],
};
function_test([1,2,3,4,55],1,2,3,{str:"str"});
var (i,j,k,l,m,n) =[1,2,3,4,5,6];
(var i,j,k)=[1,2,3];
e=e[1:][0];

View File

@@ -1,4 +1,4 @@
import("lib.nas");
var condition_true=1;
var condition_false=0;
if(condition_true)

View File

@@ -1,19 +1,27 @@
import("lib.nas");
var student=
var student=func(name,age)
{
new:func(name,age)
{
return {
parents:[student],
name:name,
age:age
};
},
print_info:func(){println(me.name,' ',me.age);},
get_age:func(){return me.age;},
get_name:func(){return me.name;}
};
var s=student.new('tiansuohaoer',24);
var val={
name:name,
age:age
};
return {
print_info:func(){println(val.name,' ',val.age);},
set_age: func(age){val.age=age;},
get_age: func(){return val.age;},
set_name: func(name){val.name=name;},
get_name: func(){return val.name;}
};
}
var s=student('valk',24);
s.print_info();
println(s.get_age(),' ',s.get_name());
s.set_age(20);
s.set_name('aluo');
s.print_info();
println(s.get_age(),' ',s.get_name());
s.set_age(20);
s.set_name('Sidi Liang');
s.print_info();
println(s.get_age(),' ',s.get_name());

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +1,9 @@
var print=func(elements...)
{
nasal_call_builtin_std_cout(elements);
return nil;
};
var setsize=func(vector,size)
{
nasal_call_builtin_set_size(vector,size);
return nil;
}
import("lib.nas");
var fib=func(x)
{
if(x<2) return x;
return fib(x-1)+fib(x-2);
}
print(fib(30),'\n');
var m=[0,1,1,2,3,5,8];
setsize(m,101);
var fib=func(n)
{
if(m[n]!=nil) return m[n];
var t=fib(n-1)+fib(n-2);
m[n]=t;
return t;
}
print(fib(100),'\n');
for(var i=0;i<31;i+=1)
print(fib(i),'\n');

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
#lib json.nas
import("lib.nas");
var json={
text:'',
line:1,

View File

@@ -1,5 +1,5 @@
import("lib.nas");
# 并查集
# union set
var n=4;
var input=[[0,1],[0,2],[1,2]];
@@ -23,10 +23,10 @@ var makeConnect=func(n,connections)
var cnt=n-1;
var parent=[];
setsize(parent,n);
for(var i=0;i<size(connections);i+=1)
if(union_root(connections[i][0],connections[i][1],parent))
foreach(var i;connections)
if(union_root(i[0],i[1],parent))
cnt-=1;
return cnt;
}
print(makeConnect(n,input));
println(makeConnect(n,input));

View File

@@ -1,182 +1,191 @@
import("lib.nas");
var s=split('',io.fin(input()));
var len=size(s);
var ptr=0;
var jump_note=func()
var lexer=func(file)
{
while(ptr<len and s[ptr]!='\n')
ptr+=1;
ptr+=1;
return;
var _={s:io.fin(file),len:0,ptr:0,token:[]};
_.len=size(_.s);
return
{
jmp_note:func()
{
while(_.ptr<_.len and chr(_.s[_.ptr])!='\n')
_.ptr+=1;
_.ptr+=1;
},
id_gen:func()
{
var tmp="";
while(_.ptr<_.len)
{
var c=_.s[_.ptr];
if(('a'[0]<=c and c<='z'[0])
or ('A'[0]<=c and c<='Z'[0])
or ('0'[0]<=c and c<='9'[0])
or c=='_'[0])
tmp~=chr(c);
else
break;
_.ptr+=1;
}
append(_.token,tmp);
},
str_gen:func()
{
var str="";
var mark=chr(_.s[_.ptr]);
_.ptr+=1;
while(_.ptr<_.len and chr(_.s[_.ptr])!=mark)
{
if(chr(_.s[_.ptr])=='\\')
{
_.ptr+=1;
var c=chr(_.s[_.ptr]);
if (c=='a' ) str~='\a';
elsif(c=='b' ) str~='\b';
elsif(c=='f' ) str~='\f';
elsif(c=='n' ) str~='\n';
elsif(c=='r' ) str~='\r';
elsif(c=='t' ) str~='\t';
elsif(c=='v' ) str~='\v';
elsif(c=='?' ) str~='?';
elsif(c=='0' ) str~='\0';
elsif(c=='\\') str~='\\';
elsif(c=='\'') str~='\'';
elsif(c=='\"') str~='\"';
else str~=c;
}
else
str~=chr(_.s[_.ptr]);
_.ptr+=1;
}
if(_.ptr>=_.len)
print("read eof when generating string.\n");
_.ptr+=1;
append(_.token,str);
},
num_gen:func()
{
var number=chr(_.s[_.ptr]);
_.ptr+=1;
if(_.ptr<_.len and chr(_.s[_.ptr])=='x')
{
_.ptr+=1;
while(_.ptr<_.len and
('a'[0]<=_.s[_.ptr] and _.s[_.ptr]<='f'[0]
or '0'[0]<=_.s[_.ptr] and _.s[_.ptr]<='9'[0]))
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
}
append(_.token,num(number));
return;
}
elsif(_.ptr<_.len and chr(_.s[_.ptr])=='o')
{
_.ptr+=1;
while(_.ptr<_.len and ('0'[0]<=_.s[_.ptr] and _.s[_.ptr]<='7'[0]))
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
}
append(_.token,num(number));
return;
}
while(_.ptr<_.len and ('0'[0]<=_.s[_.ptr] and _.s[_.ptr]<='9'[0]))
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
}
if(_.ptr<_.len and chr(_.s[_.ptr])=='.')
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
while(_.ptr<_.len and ('0'[0]<=_.s[_.ptr] and _.s[_.ptr]<='9'[0]))
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
}
}
if(chr(_.s[_.ptr])=='e' or chr(_.s[_.ptr])=='E')
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
if(chr(_.s[_.ptr])=='-' or chr(_.s[_.ptr])=='+')
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
}
while(_.ptr<_.len and ('0'[0]<=_.s[_.ptr] and _.s[_.ptr]<='9'[0]))
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
}
}
var last_c=chr(number[-1]);
if(last_c=='.' or last_c=='e' or last_c=='E' or last_c=='-' or last_c=='+')
println("error number: ",number);
append(_.token,num(number));
},
opr_gen:func()
{
var c=chr(_.s[_.ptr]);
if(c=='+' or c=='-' or c=='~' or c=='/' or c=='*' or c=='>' or c=='<' or c=='!' or c=='=')
{
var tmp=c;
_.ptr+=1;
if(_.ptr<_.len and chr(_.s[_.ptr])=='=')
{
tmp~=chr(_.s[_.ptr]);
_.ptr+=1;
}
append(_.token,tmp);
return;
}
elsif(c=='.')
{
if(_.ptr+2<_.len and chr(_.s[_.ptr+1])=='.' and chr(_.s[_.ptr+2])=='.')
{
append(_.token,"...");
_.ptr+=3;
}
else
{
append(_.token,".");
_.ptr+=1;
}
return;
}
elsif(c!=' ' and c!='\t' and c!='\n' and c!='\r' and _.s[_.ptr]>0)
append(_.token,c);
_.ptr+=1;
return;
},
main:func()
{
while(_.ptr<_.len)
{
var c=_.s[_.ptr];
if(c=='#'[0])
me.jmp_note();
elsif('a'[0]<=c and c<='z'[0]
or 'A'[0]<=c and c<='Z'[0]
or c=='_'[0])
me.id_gen();
elsif(c=='\''[0] or c=='\"'[0])
me.str_gen();
elsif('0'[0]<=c and c<='9'[0])
me.num_gen();
else
me.opr_gen();
}
return;
},
get_token:func(){return _.token;}
};
}
var generate_id=func()
{
var tmp="";
while(ptr<len)
{
if('a'<=s[ptr] and s[ptr]<='z'
or 'A'<=s[ptr] and s[ptr]<='Z'
or s[ptr]=='_'
or '0'<=s[ptr] and s[ptr]<='9')
tmp~=s[ptr];
else
break;
ptr+=1;
}
return tmp;
}
var generate_str=func()
{
var tok_str="";
var mark=s[ptr];
ptr+=1;
while(ptr<len and s[ptr]!=mark)
{
if(s[ptr]=='\\')
{
ptr+=1;
if(s[ptr]=='a') tok_str~='\a';
elsif(s[ptr]=='b') tok_str~='\b';
elsif(s[ptr]=='f') tok_str~='\f';
elsif(s[ptr]=='n') tok_str~='\n';
elsif(s[ptr]=='r') tok_str~='\r';
elsif(s[ptr]=='t') tok_str~='\t';
elsif(s[ptr]=='v') tok_str~='\v';
elsif(s[ptr]=='?') tok_str~='?';
elsif(s[ptr]=='0') tok_str~='\0';
elsif(s[ptr]=='\\') tok_str~='\\';
elsif(s[ptr]=='\'') tok_str~='\'';
elsif(s[ptr]=='\"') tok_str~='\"';
else tok_str~=s[ptr];
}
else
tok_str~=s[ptr];
ptr+=1;
}
if(ptr>=len)
print("read eof when generating string.\n");
ptr+=1;
return tok_str;
}
var generate_number=func()
{
var number=s[ptr];
ptr+=1;
if(s[ptr]=='x')
{
ptr+=1;
while(ptr<len and ('a'<=s[ptr] and s[ptr]<='f' or '0'<=s[ptr] and s[ptr]<='9'))
{
number~=s[ptr];
ptr+=1;
}
return num(number);
}
elsif(s[ptr]=='o')
{
ptr+=1;
while(ptr<len and ('0'<=s[ptr] and s[ptr]<='7'))
{
number~=s[ptr];
ptr+=1;
}
return num(number);
}
while(ptr<len and ('0'<=s[ptr] and s[ptr]<='9'))
{
number~=s[ptr];
ptr+=1;
}
if(s[ptr]=='.')
number~=s[ptr];
else
return num(number);
ptr+=1;
while(ptr<len and ('0'<=s[ptr] and s[ptr]<='9'))
{
number~=s[ptr];
ptr+=1;
}
if(s[ptr]=='e' or s[ptr]=='E')
number~=s[ptr];
else
return num(number);
ptr+=1;
if(s[ptr]=='-' or s[ptr]=='+')
{
number~=s[ptr];
ptr+=1;
}
while(ptr<len and ('0'<=s[ptr] and s[ptr]<='9'))
{
number~=s[ptr];
ptr+=1;
}
return num(number);
}
var generate_operator=func()
{
var tmp="";
if(s[ptr]=='+' or s[ptr]=='-' or s[ptr]=='~' or s[ptr]=='/' or s[ptr]=='*' or s[ptr]=='>' or s[ptr]=='<' or s[ptr]=='!' or s[ptr]=='=')
{
tmp=s[ptr];
ptr+=1;
if(ptr<len and s[ptr]=='=')
{
tmp~=s[ptr];
ptr+=1;
}
return tmp;
}
elsif(s[ptr]=='.')
{
if(ptr+2<len and s[ptr+1]=='.' and s[ptr+2]=='.')
{
tmp='...';
ptr+=3;
}
else
{
tmp='.';
ptr+=1;
}
return tmp;
}
elsif(s[ptr]!=' ' and s[ptr]!='\t' and s[ptr]!='\n' and s[ptr]!='\r' and s[ptr][0]>0)
tmp=s[ptr];
ptr+=1;
return tmp;
}
var cnt=0;
var token=[];
while(ptr<len)
{
if(s[ptr]=='#')
jump_note();
elsif('a'<=s[ptr] and s[ptr]<='z' or 'A'<=s[ptr] and s[ptr]<='Z' or s[ptr]=='_')
append(token,generate_id());
elsif(s[ptr]=='\'' or s[ptr]=='\"')
append(token,generate_str());
elsif('0'<=s[ptr] and s[ptr]<='9')
append(token,generate_number());
else
{
var tmp=generate_operator();
if(size(tmp))
append(token,tmp);
}
if(ptr>=len)
break;
}
foreach(var i;token)
{
print("(",cnt," | ",i,")\n");
cnt+=1;
}
var nasal_lexer=lexer("test/lexer.nas");
nasal_lexer.main();
foreach(var tok;nasal_lexer.get_token())
print(tok,' ');
println();

View File

@@ -1,157 +0,0 @@
var import=func(filename)
{
nasal_call_import(filename);
return nil;
}
var print=func(elements...)
{
nasal_call_builtin_std_cout(elements);
return nil;
};
var println=func(elements...)
{
nasal_call_builtin_std_cout(elements);
print('\n');
return nil;
}
var append=func(vector,elements...)
{
nasal_call_builtin_push_back(vector,elements);
return nil;
}
var setsize=func(vector,size)
{
nasal_call_builtin_set_size(vector,size);
return nil;
}
var system=func(str)
{
nasal_call_builtin_system(str);
return;
}
var input=func()
{
return nasal_call_builtin_input();
}
var sleep=func(duration)
{
nasal_call_builtin_sleep(duration);
return;
}
var split=func(delimeter,string)
{
return nasal_call_builtin_split(delimeter,string);
}
var rand=func(seed=nil)
{
return nasal_call_builtin_rand(seed);
}
var id=func(thing)
{
return nasal_call_builtin_get_id(thing);
}
var int=func(value)
{
return nasal_call_builtin_trans_int(value);
}
var num=func(value)
{
return nasal_call_builtin_trans_num(value);
}
var pop=func(vector)
{
return nasal_call_builtin_pop_back(vector);
}
var str=func(number)
{
return nasal_call_builtin_trans_str(number);
}
var size=func(object)
{
return nasal_call_builtin_size(object);
}
var contains=func(hash,key)
{
return nasal_call_builtin_contains(hash,key);
}
var delete=func(hash,key)
{
nasal_call_builtin_delete(hash,key);
return;
}
var keys=func(hash)
{
return nasal_call_builtin_get_keys(hash);
}
var time=func(begin_time)
{
return nasal_call_builtin_time(begin_time);
}
var die=func(str)
{
nasal_call_builtin_die(str);
return nil;
}
var typeof=func(object)
{
return nasal_call_builtin_type(object);
}
var substr=func(str,begin,length)
{
return nasal_call_builtin_substr(str,begin,length);
}
var streq=func(a,b)
{
return nasal_call_builtin_streq(a,b);
}
var left=func(string,length)
{
return nasal_call_builtin_left(string,length);
}
var right=func(string,length)
{
return nasal_call_builtin_right(string,length);
}
var cmp=func(a,b)
{
return nasal_call_builtin_cmp(a,b);
}
var chr=func(code) #//Unlike in FG, this chr does not support Extended ASCII
{
return nasal_call_builtin_chr(code);
}
var io=
{
fin:func(filename)
{
return nasal_call_builtin_finput(filename);
},
fout:func(filename,str)
{
nasal_call_builtin_foutput(filename,str);
return;
}
};
var bits=
{
bitxor: func(a,b){return nasal_call_builtin_xor(a,b); },
bitand: func(a,b){return nasal_call_builtin_and(a,b); },
bitor: func(a,b){return nasal_call_builtin_or(a,b); },
bitnand: func(a,b){return nasal_call_builtin_nand(a,b);},
bitnot: func(a) {return nasal_call_builtin_not(a); }
};
var math=
{
e: 2.7182818284590452354,
pi: 3.14159265358979323846264338327950288,
sin: func(x) {return nasal_call_builtin_sin(x); },
cos: func(x) {return nasal_call_builtin_cos(x); },
tan: func(x) {return nasal_call_builtin_tan(x); },
exp: func(x) {return nasal_call_builtin_exp(x); },
ln: func(x) {return nasal_call_builtin_cpp_math_ln(x); },
sqrt: func(x) {return nasal_call_builtin_cpp_math_sqrt(x);},
atan2: func(x,y){return nasal_call_builtin_cpp_atan2(x,y); }
};

View File

@@ -4,21 +4,19 @@ var map=nil;
var check=func(x,y)
{
if(x>=30) x=0;
if(x<0) x=19;
if(y>=40) y=0;
if(y<0) y=39;
if(x>14) x=0;
if(y>19) y=0;
return map[x][y];
}
var new_map=func()
{
var tmp=[];
setsize(tmp,30);
setsize(tmp,15);
forindex(var i;tmp)
{
tmp[i]=[];
setsize(tmp[i],40);
setsize(tmp[i],20);
}
return tmp;
}
@@ -44,12 +42,12 @@ func()
forindex(var j;map[i])
map[i][j]=rand()>0.7?'O':' ';
var calc=[[0,1],[1,0],[0,-1],[-1,0],[1,1],[1,-1],[-1,-1],[-1,1]];
for(var r=0;r<200;r+=1)
for(var r=0;r<100;r+=1)
{
prt(map);
var tmp=new_map();
forindex(var i;map)
forindex(var j;map[i])
for(var i=0;i<15;i+=1)
for(var j=0;j<20;j+=1)
{
var cnt=0;
foreach(var k;calc)

27
test/mandelbrot.nas Normal file
View File

@@ -0,0 +1,27 @@
import("lib.nas");
var (yMin,yMax,xMin,xMax,line)=(-0.2,0.2,-1.5,-1.0,"");
var (yDel,xDel)=(yMax-yMin,xMax-xMin);
for(var yPixel=0;yPixel<24;yPixel+=1)
{
var y=(yPixel/24)*yDel+yMin;
for(var xPixel=0;xPixel<80;xPixel+=1)
{
var x=(xPixel/80)*xDel+xMin;
var pixel=" ";
var (x0,y0)=(x,y);
for(var iter=0;iter<80;iter+=1)
{
var x1=(x0*x0)-(y0*y0)+x;
var y1=2*x0*y0+y;
(x0,y0)=(x1,y1);
if((x0*x0)+(y0*y0)>4)
{
pixel=chr(" .:;+=xX$&"[iter/8]);
break;
}
}
line~=pixel;
}
line~='\n';
}
print(line);

View File

@@ -1,643 +0,0 @@
###############################################################################
##
## Nasal module for dual control over the multiplayer network.
##
## Copyright (C) 2007 - 2010 Anders Gidenstam (anders(at)gidenstam.org)
## This file is licensed under the GPL license version 2 or later.
##
###############################################################################
## MP properties
var lat_mpp = "position/latitude-deg";
var lon_mpp = "position/longitude-deg";
var alt_mpp = "position/altitude-ft";
var heading_mpp = "orientation/true-heading-deg";
var pitch_mpp = "orientation/pitch-deg";
var roll_mpp = "orientation/roll-deg";
# Import components from the mp_broadcast module.
var Binary = mp_broadcast.Binary;
var MessageChannel = mp_broadcast.MessageChannel;
###############################################################################
# Utility classes
############################################################
# Translate a property into another.
# Factor and offsets are only used for numeric values.
# src - source : property node
# dest - destination : property node
# factor - : double
# offset - : double
var Translator = {};
Translator.new = func (src = nil, dest = nil, factor = 1, offset = 0) {
var obj = { parents : [Translator],
src : src,
dest : dest,
factor : factor,
offset : offset };
if (obj.src == nil or obj.dest == nil) {
print("Translator[");
print(" ", debug.string(obj.src));
print(" ", debug.string(obj.dest));
print("]");
fail();
}
return obj;
}
Translator.update = func () {
var v = me.src.getValue();
if (is_num(v)) {
me.dest.setValue(me.factor * v + me.offset);
} else {
if (typeof(v) == "scalar")
me.dest.setValue(v);
}
}
############################################################
# Detects flanks on two insignals encoded in a property.
# - positive signal up/down flank
# - negative signal up/down flank
# n - source : property node
# on_positive_flank - action : func (v)
# on_negative_flank - action : func (v)
var EdgeTrigger = {};
EdgeTrigger.new = func (n, on_positive_flank, on_negative_flank) {
var obj = { parents : [EdgeTrigger],
old : 0,
node : n,
pos_flank : on_positive_flank,
neg_flank : on_negative_flank };
if (obj.node == nil) {
print("EdgeTrigger[");
print(" ", debug.string(obj.node));
print("]");
fail();
}
return obj;
}
EdgeTrigger.update = func {
# NOTE: float MP properties get interpolated.
# This detector relies on that steady state is reached between
# flanks.
var val = me.node.getValue();
if (!is_num(val)) return;
if (me.old == 1) {
if (val < me.old) {
me.pos_flank(0);
}
} elsif (me.old == 0) {
if (val > me.old) {
me.pos_flank(1);
} elsif (val < me.old) {
me.neg_flank(1);
}
} elsif (me.old == -1) {
if (val > me.old) {
me.neg_flank(0);
}
}
me.old = val;
}
############################################################
# StableTrigger: Triggers an action when a MPP property
# becomes stable (i.e. doesn't change for
# MIN_STABLE seconds).
# src - MP prop : property node
# action - action to take when the value becomes stable : [func(v)]
# An action is triggered when value has stabilized.
var StableTrigger = {};
StableTrigger.new = func (src, action) {
var obj = { parents : [StableTrigger],
src : src,
action : action,
old : 0,
stable_since : 0,
wait : 0,
MIN_STABLE : 0.01 };
# Error checking.
var bad = (obj.src == nil) or (action = nil);
if (bad) {
print("StableTrigger[");
print(" ", debug.string(obj.src));
print(" ", debug.string(obj.action));
print("]");
fail();
}
return obj;
}
StableTrigger.update = func () {
var v = me.src.getValue();
if (!is_num(v)) return;
var t = getprop("/sim/time/elapsed-sec"); # NOTE: simulated time.
if ((me.old == v) and
((t - me.stable_since) > me.MIN_STABLE) and (me.wait == 1)) {
# Trigger action.
me.action(v);
me.wait = 0;
} elsif (me.old == v) {
# Wait. This is either before the signal is stable or after the action.
} else {
me.stable_since = t;
me.wait = 1;
me.old = me.src.getValue();
}
}
############################################################
# Selects the most recent value of two properties.
# src1 - : property node
# src2 - : property node
# dest - : property node
# threshold - : double
var MostRecentSelector = {};
MostRecentSelector.new = func (src1, src2, dest, threshold) {
var obj = { parents : [MostRecentSelector],
old1 : 0,
old2 : 0,
src1 : src1,
src2 : src2,
dest : dest,
thres : threshold };
if (obj.src1 == nil or obj.src2 == nil or obj.dest == nil) {
print("MostRecentSelector[");
print(" ", debug.string(obj.src1));
print(" ", debug.string(obj.src2));
print(" ", debug.string(obj.dest));
print("]");
}
return obj;
}
MostRecentSelector.update = func {
var v1 = me.src1.getValue();
var v2 = me.src2.getValue();
if (!is_num(v1) and !is_num(v2)) return;
elsif (!is_num(v1)) me.dest.setValue(v2);
elsif (!is_num(v2)) me.dest.setValue(v1);
else {
if (abs (v2 - me.old2) > me.thres) {
me.old2 = v2;
me.dest.setValue(me.old2);
}
if (abs (v1 - me.old1) > me.thres) {
me.old1 = v1;
me.dest.setValue(me.old1);
}
}
}
############################################################
# Adds two input properties.
# src1 - : property node
# src2 - : property node
# dest - : property node
var Adder = {};
Adder.new = func (src1, src2, dest) {
var obj = { parents : [DeltaAccumulator],
src1 : src1,
src2 : src2,
dest : dest };
if (obj.src1 == nil or obj.src2 == nil or obj.dest == nil) {
print("Adder[");
print(" ", debug.string(obj.src1));
print(" ", debug.string(obj.src2));
print(" ", debug.string(obj.dest));
print("]");
fail();
}
return obj;
}
Adder.update = func () {
var v1 = me.src1.getValue();
var v2 = me.src2.getValue();
if (!is_num(v1) or !is_num(v2)) return;
me.dest.setValue(v1 + v2);
}
############################################################
# Adds the delta of src to dest.
# src - : property node
# dest - : property node
var DeltaAdder = {};
DeltaAdder.new = func (src, dest) {
var obj = { parents : [DeltaAdder],
old : 0,
src : src,
dest : dest };
if (obj.src == nil or obj.dest == nil) {
print("DeltaAdder[", debug.string(obj.src), ", ",
debug.string(obj.dest), "]");
fail();
}
return obj;
}
DeltaAdder.update = func () {
var v = me.src.getValue();
if (!is_num(v)) return;
me.dest.setValue((v - me.old) + me.dest.getValue());
me.old = v;
}
############################################################
# Switch encoder: Encodes upto 32 boolean properties in one
# int property.
# inputs - list of property nodes
# dest - where the bitmask is stored : property node
var SwitchEncoder = {};
SwitchEncoder.new = func (inputs, dest) {
var obj = { parents : [SwitchEncoder],
inputs : inputs,
dest : dest };
# Error checking.
var bad = (obj.dest == nil);
foreach (var i; inputs) {
if (i == nil) { bad = 1; }
}
if (bad) {
print("SwitchEncoder[");
foreach (var i; inputs) {
print(" ", debug.string(i));
}
print(" ", debug.string(obj.dest));
print("]");
fail();
}
return obj;
}
SwitchEncoder.update = func () {
var v = 0;
var b = 1;
forindex (var i; me.inputs) {
if (me.inputs[i].getBoolValue()) {
v = v + b;
}
b *= 2;
}
me.dest.setIntValue(v);
}
############################################################
# Switch decoder: Decodes a bitmask in an int property.
# src - : property node
# actions - list of actions : [func(b)]
# Actions are triggered when their input bit change.
# Due to interpolation the decoder needs to wait for a
# stable input value.
var SwitchDecoder = {};
SwitchDecoder.new = func (src, actions) {
var obj = { parents : [SwitchDecoder],
wait : 0,
old : 0,
old_stable : 0,
stable_since : 0,
reset : 1,
src : src,
actions : actions,
MIN_STABLE : 0.1 };
# Error checking.
var bad = (obj.src == nil);
foreach (var a; obj.actions) {
if (a == nil) { bad = 1; }
}
if (bad) {
print("SwitchDecoder[");
print(" ", debug.string(obj.src));
foreach (var a; obj.actions) {
print(" ", debug.string(a));
}
print("]");
fail();
}
return obj;
}
SwitchDecoder.update = func () {
var t = getprop("/sim/time/elapsed-sec"); # NOTE: simulated time.
var v = me.src.getValue();
if (!is_num(v)) return;
if ((me.old == v) and ((t - me.stable_since) > me.MIN_STABLE) and
(me.wait == 1)) {
var ov = me.old_stable;
# Use this to improve.
#<cptf> here's the boring version: var bittest = func(u, b) { while (b) { u = int(u / 2); b -= 1; } u != int(u / 2) * 2; }
forindex (var i; me.actions) {
var m = math.mod(v, 2);
var om = math.mod(ov, 2);
if ((m != om or me.reset)) { me.actions[i](m?1:0); }
v = (v - m)/2;
ov = (ov - om)/2;
}
me.old_stable = me.src.getValue();
me.wait = 0;
me.reset = 0;
} elsif (me.old == v) {
# Wait. This is either before the bitmask is stable or after
# it has been processed.
} else {
me.stable_since = t;
me.wait = 1;
me.old = me.src.getValue();
}
}
############################################################
# Time division multiplexing encoder: Transmits a list of
# properties over a MP enabled string property.
# inputs - input properties : [property node]
# dest - MP string prop : property node
# Note: TDM can have high latency so it is best used for
# non-time critical properties.
var TDMEncoder = {};
TDMEncoder.new = func (inputs, dest) {
var obj = { parents : [TDMEncoder],
inputs : inputs,
channel : MessageChannel.new(dest,
func (msg) {
print("This should not happen!");
}),
MIN_INT : 0.25,
last_time : 0,
next_item : 0,
old : [] };
# Error checking.
var bad = (dest == nil) or (obj.channel == nil);
foreach (var i; inputs) {
if (i == nil) { bad = 1; }
}
if (bad) {
print("TDMEncoder[");
foreach (var i; inputs) {
print(" ", debug.string(i));
}
print(" ", debug.string(dest));
print("]");
}
setsize(obj.old, size(obj.inputs));
return obj;
}
TDMEncoder.update = func () {
var t = getprop("/sim/time/elapsed-sec"); # NOTE: simulated time.
if (t > me.last_time + me.MIN_INT) {
var n = size(me.inputs);
while (1) {
var v = me.inputs[me.next_item].getValue();
if ((n <= 0) or (me.old[me.next_item] != v)) {
# Set the MP properties to send the next item.
me.channel.send(Binary.encodeByte(me.next_item) ~
Binary.encodeDouble(v));
me.old[me.next_item] = v;
me.last_time = t;
me.next_item += 1;
if (me.next_item >= size(me.inputs)) { me.next_item = 0; }
return;
} else {
# Search for changed property.
n -= 1;
me.next_item += 1;
if (me.next_item >= size(me.inputs)) { me.next_item = 0; }
}
}
}
}
############################################################
# Time division multiplexing decoder: Receives a list of
# properties over a MP enabled string property.
# src - MP string prop : property node
# actions - list of actions : [func(v)]
# An action is triggered when its value is received.
# Note: TDM can have high latency so it is best used for
# non-time critical properties.
var TDMDecoder = {};
TDMDecoder.new = func (src, actions) {
var obj = { parents : [TDMDecoder],
actions : actions };
obj.channel = MessageChannel.new(src,
func (msg) {
obj.process(msg);
});
# Error checking.
var bad = (src == nil) or (obj.channel == nil);
foreach (var a; actions) {
if (a == nil) { bad = 1; }
}
if (bad) {
print("TDMDecoder[");
print(" ", debug.string(src));
foreach (var a; actions) {
print(" ", debug.string(a));
}
print("]");
fail();
}
return obj;
}
TDMDecoder.process = func (msg) {
var v1 = Binary.decodeByte(msg);
var v2 = Binary.decodeDouble(substr(msg, 1));
# Trigger action.
me.actions[v1](v2);
}
TDMDecoder.update = func {
me.channel.update();
}
###############################################################################
# Internal utility functions
var is_num = func (v) {
return num(v) != nil;
}
# fail causes a Nasal runtime error so we get a backtrace.
var fail = func {
error_detected_in_calling_context();
}
###############################################################################
###############################################################################
# Copilot selection dialog.
#
# Usage: dual_control_tools.copilot_dialog.show(<copilot type string>);
#
var COPILOT_DLG = 0;
var copilot_dialog = {};
############################################################
copilot_dialog.init = func (copilot_type, x = nil, y = nil) {
me.x = x;
me.y = y;
me.bg = [0, 0, 0, 0.3]; # background color
me.fg = [[1.0, 1.0, 1.0, 1.0]];
#
# "private"
if (contains(aircraft_dual_control, "copilot_view")) {
me.title = "Pilot selection";
} else {
me.title = "Copilot selection";
}
me.basenode = props.globals.getNode("sim/remote", 1);
me.dialog = nil;
me.namenode = props.Node.new({"dialog-name" : me.title });
me.listeners = [];
me.copilot_type = copilot_type;
}
############################################################
copilot_dialog.create = func {
if (me.dialog != nil)
me.close();
me.dialog = gui.Widget.new();
me.dialog.set("name", me.title);
if (me.x != nil)
me.dialog.set("x", me.x);
if (me.y != nil)
me.dialog.set("y", me.y);
me.dialog.set("layout", "vbox");
me.dialog.set("default-padding", 0);
var titlebar = me.dialog.addChild("group");
titlebar.set("layout", "hbox");
titlebar.addChild("empty").set("stretch", 1);
if (contains(aircraft_dual_control, "copilot_view")) {
titlebar.addChild("text").set("label", "Book your flight");
} else {
titlebar.addChild("text").set("label", "Passengers online");
}
var w = titlebar.addChild("button");
w.set("pref-width", 16);
w.set("pref-height", 16);
w.set("legend", "");
w.set("default", 0);
w.set("key", "esc");
w.setBinding("nasal", "dual_control_tools.copilot_dialog.destroy(); ");
w.setBinding("dialog-close");
me.dialog.addChild("hrule");
var content = me.dialog.addChild("group");
content.set("layout", "vbox");
content.set("halign", "center");
content.set("default-padding", 5);
# Generate the dialog contents.
me.players = me.find_copilot_players();
var i = 0;
var tmpbase = me.basenode.getNode("dialog", 1);
var selected = me.basenode.getNode("pilot-callsign").getValue();
foreach (var p; me.players) {
var tmp = tmpbase.getNode("b[" ~ i ~ "]", 1);
tmp.setBoolValue(streq(selected, p));
var w = content.addChild("checkbox");
w.node.setValues({"label" : p,
"halign" : "left",
"property" : tmp.getPath()});
w.setBinding
("nasal",
"dual_control_tools.copilot_dialog.select_action(" ~ i ~ ");");
i = i + 1;
}
me.dialog.addChild("hrule");
# Display the dialog.
fgcommand("dialog-new", me.dialog.prop());
fgcommand("dialog-show", me.namenode);
}
############################################################
copilot_dialog.close = func {
fgcommand("dialog-close", me.namenode);
}
############################################################
copilot_dialog.destroy = func {
COPILOT_DLG = 0;
me.close();
foreach(var l; me.listeners)
removelistener(l);
delete(gui.dialog, "\"" ~ me.title ~ "\"");
}
############################################################
copilot_dialog.show = func (copilot_type) {
# print("Showing MPCopilots dialog!");
if (!COPILOT_DLG) {
COPILOT_DLG = int(getprop("/sim/time/elapsed-sec"));
me.init(copilot_type);
me.create();
me._update_(COPILOT_DLG);
}
}
############################################################
copilot_dialog._redraw_ = func {
if (me.dialog != nil) {
me.close();
me.create();
}
}
############################################################
copilot_dialog._update_ = func (id) {
if (COPILOT_DLG != id) return;
me._redraw_();
settimer(func { me._update_(id); }, 4.1);
}
############################################################
copilot_dialog.select_action = func (n) {
var selected = me.basenode.getNode("pilot-callsign").getValue();
var bs = me.basenode.getNode("dialog").getChildren();
# Assumption: There are two true b:s or none. The one not matching selected
# is the new selection.
var i = 0;
me.basenode.getNode("pilot-callsign").setValue("");
foreach (var b; bs) {
if (!b.getValue() and (i == n)) {
b.setValue(1);
me.basenode.getNode("pilot-callsign").setValue(me.players[i]);
} else {
b.setValue(0);
}
i = i + 1;
}
dual_control.main.reset();
me._redraw_();
}
############################################################
# Return a list containing all nearby copilot players of the right type.
copilot_dialog.find_copilot_players = func {
var mpplayers =
props.globals.getNode("ai/models").getChildren("multiplayer");
var res = [];
foreach (var pilot; mpplayers) {
if ((pilot.getNode("valid") != nil) and
(pilot.getNode("valid").getValue()) and
(pilot.getNode("sim/model/path") != nil)) {
var type = pilot.getNode("sim/model/path").getValue();
if (type == me.copilot_type) {
append(res, pilot.getNode("callsign").getValue());
}
}
}
# debug.dump(res);
return res;
}
###############################################################################

View File

@@ -1,10 +1,10 @@
#//This is written for Nasal Intepreter
#//Sidi Liang
# This is written for Nasal Intepreter
# Sidi Liang
import("lib.nas");
var w = 1;
var x = "hello";
var f = func(){
print("f is called");
println("f is called");
}
var f2 = func(){
return 2;
@@ -28,71 +28,27 @@ var z1 = {
hashh:z
};
var y2 = [w, x, y, z1];
var z2 = {
hashh: z1,
listt2: y2,
};
print(w);#//1
print("\n");
print(x);#//hello
print("\n");
print(y);#//Empty
print("\n");
print(z);#//Empty
print("\n");
print(z1);#//Empty
print("\n");
print(y2);#//Empty
print("\n");
print(y[0]);#//1
print("\n");
print(y1[2][1]);#//hello
print("\n");
print(z.numb);#//1
print("\n");
print(z.listt[2][1]);#//hello
print("\n");
print(z1.hashh.listt[2][1]);#//hello
print("\n");
print(y2[3].hashh.listt[2][1]);#//hello
print("\n");
print(f);#//Empty
print("\n");
println(w);#//1
println(x);#//hello
println(y);#//[1,hello]
println(z);#//{...}
println(z1);#//{...}
println(y2);#//[...]
println(y[0]);#//1
println(y1[2][1]);#//hello
println(z.numb);#//1
println(z.listt[2][1]);#//hello
println(z1.hashh.listt[2][1]);#//hello
println(y2[3].hashh.listt[2][1]);#//hello
println(f);#//func(...){...}
f();#//f is called
print("\n");
print(z.funcc);#//Empty
print("\n");
println(z.funcc);#//func(...){...}
z.funcc();#//f is called
print("\n");
print(z.funcccall);#//Empty
print("\n");
z.funcccall();#//f is called
print("\n");
println(z.funcccall);#//nil
z2.listt2[3].hashh.funcc();#//f is called
print("\n");
print(y1[f2()][w]);#//hello
print("\n");
#//print(z.f3()); Error
call(f);#//f is called
print("\n");
call(z.funcc);#//f is called
print("\n");
println(y1[f2()][w]);#//hello

View File

@@ -1,162 +0,0 @@
import("lib.nas");
rand(time(0));
var chartable=split('','abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');
var node=func(type)
{
var s="";
for(var i=0;i<10;i+=1)
s~=chartable[rand()*62];
return {name:s,type:type,next:[]};
}
var film_node=[];
for(var i=0;i<1000;i+=1)
append(film_node,node("film"));
var director_node=[];
for(var i=0;i<200;i+=1)
append(director_node,node("direct"));
var actor_node=[];
for(var i=0;i<400;i+=1)
append(actor_node,node("actor"));
var writer_node=[];
for(var i=0;i<100;i+=1)
append(writer_node,node("writer"));
var type_node=[];
for(var i=0;i<40;i+=1)
append(type_node,node("type"));
var lang_node=[];
for(var i=0;i<120;i+=1)
append(lang_node,node("lang"));
var country_node=[];
for(var i=0;i<120;i+=1)
append(country_node,node("country"));
func()
{
var director_size=size(director_node);
var actor_size=size(actor_node);
var writer_size=size(writer_node);
var type_size=size(type_node);
var lang_size=size(lang_node);
var country_size=size(country_node);
foreach(var film;film_node)
{
var director_link=int(1+rand()*2);
var actor_link=int(1+rand()*20);
var writer_link=int(1+rand()*2);
var type_link=int(1+rand()*5);
var lang_link=int(1+rand()*4);
var country_link=int(1+rand()*4);
for(var i=0;i<director_link;i+=1)
{
var director=director_node[rand()*director_size];
append(film.next,director);
append(director.next,film);
}
for(var i=0;i<actor_link;i+=1)
{
var actor=actor_node[rand()*actor_size];
append(film.next,actor);
append(actor.next,film);
}
for(var i=0;i<writer_link;i+=1)
{
var writer=writer_node[rand()*writer_size];
append(film.next,writer);
append(writer.next,film);
}
for(var i=0;i<type_link;i+=1)
{
var _type=type_node[rand()*type_size];
append(film.next,_type);
append(_type.next,film);
}
for(var i=0;i<lang_link;i+=1)
{
var lang=lang_node[rand()*lang_size];
append(film.next,lang);
append(lang.next,film);
}
for(var i=0;i<country_link;i+=1)
{
var country=country_node[rand()*country_size];
append(film.next,country);
append(country.next,film);
}
}
return;
}();
var film_list=[];
var count_list=[];
for(var i=0;i<10;i+=1)
{
append(film_list,film_node[i]);
append(count_list,1);
}
var sort_list=func(begin,end)
{
for(var i=begin;i<end;i+=1)
{
var index=i;
for(var j=i+1;j<end;j+=1)
if(count_list[index]<count_list[j])
index=j;
if(index!=i)
{
var tmp=film_list[i];
film_list[i]=film_list[index];
film_list[index]=tmp;
tmp=count_list[i];
count_list[i]=count_list[index];
count_list[index]=tmp;
}
}
return;
}
var get_next=func(index)
{
var label_list=film_list[index].next;
film_list=[];
count_list=[];
foreach(var label;label_list)
foreach(var film;label.next)
{
var has=0;
for(var i=0;i<size(film_list);i+=1)
if(film_list[i].name==film.name)
{
has=1;
count_list[i]+=1;
break;
}
if(has==0)
{
append(film_list,film);
append(count_list,1);
}
}
sort_list(0,size(film_list));
return;
}
while(1)
{
var list_size=size(film_list);
list_size=list_size>10?10:list_size;
for(var i=1;i<list_size;i+=1)
println('| ',i,'\t:',film_list[i].name,'\t',count_list[i]);
var choose=input();
if(choose=="exit")
break;
if(num(choose)==0 or num(choose)>=list_size)
die("choose a correct index");
get_next(num(choose));
}
foreach(var film;film_node)
setsize(film.next,0);

9
test/pi.nas Normal file
View File

@@ -0,0 +1,9 @@
import("lib.nas");
var (t,res)=(1,0);
for(var m=1;m<4e6;m+=2)
{
res+=t*1/m;
t=-t;
}
println(res*4);

View File

@@ -1,40 +0,0 @@
# lib queue.nas
# valkmjolnir 2021/3/3
var new_queue=func()
{
return {begin:nil,end:nil};
}
var queue_push=func(queue_head,elem)
{
var new_node=
{
elem:elem,
next:nil
};
if(queue_head.begin==nil)
queue_head.begin=queue_head.end=new_node;
else
{
queue_head.end.next=new_node;
queue_head.end=new_node;
}
return;
}
var queue_pop=func(queue_head)
{
var t=queue_head.begin;
queue_head.begin=queue_head.begin.next;
if(queue_head.begin==nil)
queue_head.end=nil;
return t;
}
var queue_front=func(queue_head)
{
if(queue_head.begin!=nil)
return queue_head.begin.elem;
return nil;
}
var queue_empty=func(queue_head)
{
return queue_head.begin==nil;
}

25
test/quick_sort.nas Normal file
View File

@@ -0,0 +1,25 @@
import("lib.nas");
var sort=func(vec,left,right)
{
if(left>=right) return;
var (L,R,tmp)=(left,right,vec[left]);
while(left<right)
{
while(left<right and tmp<=vec[right])
right-=1;
while(left<right and tmp>=vec[left])
left+=1;
if(left!=right)
(vec[left],vec[right])=(vec[right],vec[left]);
}
(vec[L],vec[left])=(vec[left],tmp);
sort(vec,L,left-1);
sort(vec,left+1,R);
return;
}
var vec=[];
rand(time(0));
for(var i=0;i<200;i+=1)
append(vec,int(rand()*1000));
sort(vec,0,size(vec)-1);
println(vec);

View File

@@ -115,7 +115,7 @@ var multi_assign_2=[10,9,8,7];
((-1*2+9))/7-1;
((({num:2})))["num"]*2*2*2;
((((([0,1,2])[0:2]))[0:2]))[1]-1;
(((((((((((((((((((1+1+2+3+5)+8))+13)))+21))))+34)))))+55))))*89;
println((((((((((((((((((((1+1+2+3+5)+8))+13)))+21))))+34)))))+55))))*89); # 12727
number_1*(number_2+number_3)/90-number_4;
(func test_func)()-1;
hash_3.member_3+(func {return {what:"i don't tell you.",case_small:80,case_large:100}})()["case_large"]/10;
@@ -129,7 +129,7 @@ nil and 1+7*8;
var hash={str:'hello',f:func{return me.str;}};
var tmp_f=hash.f;
hash=1;
print(tmp_f());
println(tmp_f());
# undefined symbol 'me'
# this means that
# when generating local_scope for function f,
@@ -138,13 +138,13 @@ print(tmp_f());
var h1={str:'hello',f:func{return me.str;}};
var h2={str:'world',f:func{return nil;}};
h2.f=h1.f;
print(h2.f());
println(h2.f());
# print 'world'
# this means that 'me' in hash's functions
# only points to the hash this function belongs to
var f1=func(){print(1);return 1;}
var f2=func(){print(2);return 0;}
var f1=func(){println(1);return 1;}
var f2=func(){println(2);return 0;}
f1() or f2();
# print '1'
# this means that when using 'or' or 'and',

View File

@@ -1,62 +0,0 @@
import("lib.nas");
var global_value=0;
var global_hash=
{
var1:1,
var2:2,
var3:func(){return me.var2;}
};
println(global_value);
println(global_hash.var3());
var func1=func()
{
global_value=1;
println(global_value);
var closure_value=1;
var temp_value=1;
println(temp_value);
return func{return closure_value;};
}
var func2=func()
{
for(var temp_value=0;temp_value<100;temp_value+=1)
{
if(temp_value<10)
println(temp_value,"< 10");
elsif(10<=temp_value and temp_value<50)
println(temp_value,"< 50");
}
return;
}
var func3=func()
{
var fake_closure_value=1;
return func()
{
var fake_closure_value=2;
return fake_closure_value;
};
}
println(func1()());
func2();
println(func3()());
if(!global_value)
{
var temp_value=1;
if(temp_value)
{
var temp_value=2;
if(temp_value>=1)
{
var temp_value=3;
print(temp_value);
}
print(temp_value);
}
print(temp_value);
}

View File

@@ -1,210 +0,0 @@
var smartScreen = canvas.new({
"name": "smartScreen", # The name is optional but allow for easier identification
"size": [2048, 2048], # Size of the underlying texture (should be a power of 2, required) [Resolution]
"view": [768, 768], # Virtual resolution (Defines the coordinate system of the canvas [Dimensions]
# which will be stretched the size of the texture, required)
"mipmapping": 1 # Enable mipmapping (optional)
});
smartScreen.addPlacement({"node": "screen", "texture": "screen.jpeg"});
var group = smartScreen.createGroup();
# Create a text element and set some values
var text = group.createChild("text", "optional-id-for element")
.setTranslation(10, 20) # The origin is in the top left corner
.setAlignment("left-center") # All values from osgText are supported (see $FG_ROOT/Docs/README.osgtext)
.setFont("LiberationFonts/LiberationSans-Regular.ttf") # Fonts are loaded either from $AIRCRAFT_DIR/Fonts or $FG_ROOT/Fonts
.setFontSize(14, 1.2) # Set fontsize and optionally character aspect ratio
.setColor(1,0,0) # Text color
.setText("This is a text element");
text.hide();
text.setText("SELF TEST NORMAL").show();
var ui_root = smartScreen.createGroup();
var vbox = canvas.VBoxLayout.new();
smartScreen.setLayout(vbox);
var button_onl = canvas.gui.widgets.Button.new(ui_root, canvas.style, {}).setText("Online OSM").listen("clicked", func showOnlineMap());
var button_offl = canvas.gui.widgets.Button.new(ui_root, canvas.style, {}).setText("Offline OSM").listen("clicked", func showOfflineMap());
button_onl.setSizeHint([32, 128]);
button_offl.setSizeHint([32, 128]);
var label = canvas.gui.widgets.Label.new(ui_root, canvas.style, {});
var button_box = canvas.HBoxLayout.new();
button_box.addItem(button_onl);
button_box.addItem(button_offl);
button_box.addItem(label);
button_box.addStretch(1);
vbox.addItem(button_box);
vbox.addStretch(1);
var showOnlineMap = func(){
TestMap.show();
g.hide();
label.setText("Online Mode");
}
var showOfflineMap = func(){
TestMap.hide();
g.show();
label.setText("Offline Mode");
}
# Online Map using MapStructure
var TestMap = smartScreen.createGroup().createChild("map");
TestMap.setTranslation(smartScreen.get("view[0]")/2,smartScreen.get("view[1]")/2);
var ctrl_ns = canvas.Map.Controller.get("Aircraft position");
var source = ctrl_ns.SOURCES["map-dialog"];
if (source == nil) {
# TODO: amend
var source = ctrl_ns.SOURCES["map-dialog"] = {
getPosition: func subvec(geo.aircraft_position().latlon(), 0, 2),# ? ? ?
getAltitude: func getprop('/position/altitude-ft'),
getHeading: func {
if (me.aircraft_heading)
getprop('/orientation/heading-deg');
else
0;
},
aircraft_heading: 1,
};
}
setlistener("/sim/gui/dialogs/map-canvas/aircraft-heading-up", func(n){source.aircraft_heading = n.getBoolValue();}, 1);
TestMap.setController("Aircraft position", "map-dialog");
TestMap.setRange(1);
var r = func(name,vis=1,zindex=nil){return caller(0)[0];};
# TODO: we'll need some z-indexing here, right now it's just random
foreach(var type; [r('APS')] ){
TestMap.addLayer(factory: canvas.SymbolLayer, type_arg: type.name, visible: type.vis, priority: 2);
}
foreach(var type; [ r('OSM')]) {
TestMap.addLayer(factory: canvas.OverlayLayer,
type_arg: type.name,
visible: type.vis,
priority: 1);
}
TestMap.hide();
# Offline map
var g = smartScreen.createGroup();
var zoom = 15;
var type = "intl";
var tile_size = 256;
var changeZoom = func(d)
{
zoom = math.max(2, math.min(19, zoom + d));
updateTiles();
}
# http://polymaps.org/docs/
# https://github.com/simplegeo/polymaps
# https://github.com/Leaflet/Leaflet
var maps_base = getprop("/sim/fg-home") ~ '/cache/maps';
var makePath =
string.compileTemplate(maps_base ~ '/osm-{type}/{z}/{x}/{y}.jpg');
var num_tiles = [4, 4];
var center_tile_offset = [(num_tiles[0]-1)/2, (num_tiles[1]-1)/ 2];
# simple aircraft icon at current position/center of the map
g.createChild("path")
.moveTo( tile_size*center_tile_offset[0]-10, tile_size*center_tile_offset[1])
.horiz(20)
.move(-10,-10)
.vert(20)
.set("stroke", "red")
.set("stroke-width", 2)
.set("z-index", 1);
# initialize the map by setting up
# a grid of raster images
var tiles = setsize([], num_tiles[0]);
for(var x=0; x<num_tiles[0]; x+=1)
{
tiles[x] = setsize([], num_tiles[1]);
for(var y=0; y<num_tiles[1]; y+=1)
tiles[x][y] = g.createChild("image", "map-tile");
}
var last_tile = [-1,-1];
var last_type = type;
# this is the callback that will be regularly called by the timer
# to update the map
var updateTiles = func()
{
# get current position
var lat = getprop('/position/latitude-deg');
var lon = getprop('/position/longitude-deg');
var n = math.pow(2, zoom);
var offset = [n*((lon+180)/360)-center_tile_offset[0], (1-math.ln(math.tan(lat*math.pi/180)+1/math.cos(lat*math.pi/180))/math.pi)/2*n-center_tile_offset[1]];
var tile_index = [int(offset[0]), int(offset[1])];
var ox = tile_index[0] - offset[0];
var oy = tile_index[1] - offset[1];
for(var x = 0; x < num_tiles[0]; x += 1)
for(var y = 0; y < num_tiles[1]; y += 1)
tiles[x][y].setTranslation(int((ox + x) * tile_size + 0.5), int((oy + y) * tile_size + 0.5));
if( tile_index[0] != last_tile[0]
or tile_index[1] != last_tile[1]
or type != last_type )
{
for(var x = 0; x < num_tiles[0]; x += 1)
for(var y = 0; y < num_tiles[1]; y += 1)
{
var pos = {
z: zoom,
x: int(offset[0] + x),
y: int(offset[1] + y),
type: type
};
(func {
var img_path = makePath(pos);
var tile = tiles[x][y];
print('loading ' ~ img_path);
tile.set("src", img_path);
})();
# lambda
}
last_tile = tile_index;
last_type = type;
}
};
# set up a timer that will invoke updateTiles at 2-second intervals
var update_timer = maketimer(2, updateTiles);
# actually start the timer
update_timer.start();
# set up default zoom level
changeZoom(0);
#g.hide();

View File

@@ -1,24 +0,0 @@
var hash={str:'hello',f:func{return me.str;}};
var tmp_f=hash.f;
hash=1;
print(tmp_f());
# undefined symbol 'me'
# this means that
# when generating local_scope for function f,
# nasal_gc will not count 'me' as one reference of this hash
var h1={str:'hello',f:func{return me.str;}};
var h2={str:'world',f:func{return nil;}};
h2.f=h1.f;
print(h2.f());
# print 'world'
# this means that 'me' in hash's functions
# only points to the hash this function belongs to
var f1=func(){print(1);return 1;}
var f2=func(){print(2);return 0;}
f1() or f2();
# print '1'
# this means that when using 'or' or 'and',
# if the result is clear when calculating,
# objects behind will not be calculated

View File

@@ -1,34 +0,0 @@
# lib stack.nas
var block_alloc=func()
{
return {elem:nil,next:nil};
}
var new_stack=func()
{
return {next:nil};
}
var stack_push=func(stack,elem)
{
var tmp=stack.next;
stack.next=block_alloc();
stack.next.elem=elem;
stack.next.next=tmp;
}
var stack_pop=func(stack)
{
var tmp=stack.next;
if(tmp!=nil)
stack.next=tmp.next;
return;
}
var stack_top=func(stack)
{
var tmp=stack.next;
if(tmp!=nil)
return tmp.elem;
return nil;
}
var stack_empty=func(stack)
{
return stack.next==nil;
}