170 Commits
v3.0 ... v7.0

Author SHA1 Message Date
ValKmjolnir
d71b4f09e2 prepare for version 8.0 2021-10-08 15:32:18 +08:00
ValKmjolnir
13d40e886e update 2021-09-25 23:25:31 +08:00
Li Haokun
618ce59233 bad access bug fixed 2021-09-13 19:55:03 +08:00
Li Haokun
071d8bd1ce update 2021-09-10 19:13:42 +08:00
Li Haokun
c498d5c8c4 add fg constants & change int(), num() 2021-09-02 19:10:49 +08:00
Li Haokun
11971267dc add math.nan math.inf 2021-09-01 19:15:32 +08:00
Li Haokun
418531a44a add result.nas 2021-09-01 19:14:03 +08:00
Li Haokun
59dc0d1423 add isnan 2021-08-27 17:43:01 +08:00
Li Haokun
385f0af17e nothing changed 2021-08-24 19:34:52 +08:00
Li Haokun
ef9b781961 security holes fixed 2021-08-19 17:54:36 +08:00
ValKmjolnir
80cc8e9db7 closure bugs fixed 2021-08-17 01:18:35 +08:00
Li Haokun
b2be386be8 update hexdump.nas 2021-08-13 15:10:20 +08:00
Li Haokun
e4c598cae6 add hexdump.nas 2021-08-12 20:01:51 +08:00
Li Haokun
5fe6681b0d update lexer 2021-08-12 19:00:17 +08:00
Li Haokun
35fc848672 fully functional closure 2021-08-11 14:54:17 +08:00
Li Haokun
e3f3bd7387 update readme 2021-08-10 17:55:49 +08:00
ValKmjolnir
638ec1c3a3 use same indentation 2021-08-09 21:30:18 +08:00
Li Haokun
90ac468aa9 update 2021-08-09 19:13:39 +08:00
ValKmjolnir
65dfef0a33 update 2021-08-09 01:02:27 +08:00
Li Haokun
76a2548e95 update 2021-08-06 18:57:06 +08:00
Li Haokun
40b690b67b update 2021-08-05 19:02:41 +08:00
Li Haokun
2b17f3d702 update debug info 2021-08-04 14:32:56 +08:00
ValKmjolnir
5b6c78783e update README 2021-08-04 00:03:49 +08:00
Li Haokun
fa618eb97f variables can be used before definition
change program to command line
change trace back info
change print function of nasal_vec and nasal_hash
2021-08-03 18:55:11 +08:00
ValKmjolnir
d0616ef028 update 2021-08-01 22:37:42 +08:00
ValKmjolnir
91771297d3 add test file 2021-08-01 22:34:02 +08:00
ValKmjolnir
4e1a3c5f2d syntax bug fixed
syntax like:
var f=func(){}
(var a,b,c)=(1,2,3);
will be incorrectly recognized like:
var f=func(){}(var a,b,c)

this bug is fixed now.
2021-08-01 02:11:27 +08:00
ValKmjolnir
df634cb1b2 update readme:difference between this and andy's interpreter 2021-08-01 01:54:14 +08:00
Li Haokun
aa797142d1 update parser
one bug found, waiting to be fixed
2021-07-28 18:22:40 +08:00
Li Haokun
816be43a98 update 2021-07-24 19:59:56 +08:00
Li Haokun
9ebabfe737 fixed bug in nasal_parse 2021-07-21 17:38:11 +08:00
ValKmjolnir
884b56ac09 bug fixed & raw string print 2021-07-21 00:20:25 +08:00
Li Haokun
61677101e4 show vm stack top's info when error occurs 2021-07-20 19:21:05 +08:00
Li Haokun
7a93f5b89b update 2021-07-19 17:04:45 +08:00
Li Haokun
9fe7a86a3b add trace back info 2021-07-16 17:18:13 +08:00
ValKmjolnir
9da029b8fe prepare for debugger 2021-07-16 02:17:53 +08:00
ValKmjolnir
8b8e72c879 update 2021-07-14 01:24:15 +08:00
ValKmjolnir
590c595522 delete slice_stack 2021-07-07 14:46:46 +08:00
ValKmjolnir
57d6bcdc52 add const compare instructions 2021-07-03 15:22:23 +08:00
ValKmjolnir
0b2fe61e6e add instruction & changes in codegen
add some instructions that execute const values.
the first symbol called in assignment will use op_load instead of op_meq,op_pop to assign.
2021-06-29 17:18:05 +08:00
ValKmjolnir
706659ba3d change instruction dispatch to computed-goto
bug fixed
prepare for version 7.0
2021-06-26 14:53:10 +08:00
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
Valk Richard Li
c4e6a89959 update test files and prepare the release of v5.0 2021-03-07 16:33:43 +08:00
Valk Richard Li
f60f674845 delete op_entry 2021-03-04 15:53:34 +08:00
Valk Richard Li
c21d40c466 change test files 2021-03-03 09:20:42 +08:00
Valk Richard Li
19b590f3bb add test files 2021-03-03 01:09:57 +08:00
Valk Richard Li
a421470715 change map to unordered_map 2021-03-01 15:54:58 +08:00
Valk Richard Li
79dc13f419 update 2021-02-27 22:45:51 +08:00
Valk Richard Li
2e8208a752 add getParent & getPath 2021-02-25 22:30:28 +08:00
Valk Richard Li
1c40cca673 add tutorial of how to add built-in function 2021-02-23 23:33:01 +08:00
Valk Richard Li
b1a5a5f6c0 clear memory footprint when codegen complete 2021-02-23 22:53:28 +08:00
Valk Richard Li
64961877de Add props lib & bug fixed(op_ret in foreach/index got SIGSEGV) 2021-02-18 23:49:29 +08:00
Valk Richard Li
9c9bb52818 codegen will not generate 'jmp' if 'if' and 'elsif' is the last condition 2021-02-18 11:45:47 +08:00
Valk Richard Li
02148f4766 bug fixed & more efficient function call
fixed a bug when different hash calling the same function,'me' will be set to the latest called hash's address.
changed the way of pushing the scope to the stack by copying a new scope from the function's scope address.
use map as the nasal_scop instead of list<map>,it'll be more efficient.
2021-02-17 19:31:44 +08:00
Valk Richard Li
767711c93a change identifier name to avoid misunderstanding 2021-02-15 15:29:55 +08:00
Valk Richard Li
78ba0641a6 change the way of calling built-in functions
change std::map to struct array,use index to call built-in functions.this may be more efficient.
2021-02-14 17:36:42 +08:00
Valk Richard Li
80683c381f bug fixed 2021-02-13 23:57:53 +08:00
Li Haokun
6aac46adaf Merge pull request #5 from sidi762/master
Added left, right, streq, cmp, chr to library functions
2021-02-13 07:24:17 -08:00
Sidi Liang
388ef66308 Library: added comment for chr 2021-02-13 21:43:07 +08:00
Sidi Liang
8faa4ef2db Library: Added core library function chr according to FlightGear Nasal 2021-02-13 21:40:10 +08:00
Sidi Liang
441c02d0fb Library: Added core library function streq and cmp according to FlightGear Nasal 2021-02-13 21:09:13 +08:00
Sidi Liang
953ad80482 Library: Added core library function left and right according to FlightGear Nasal 2021-02-13 20:19:49 +08:00
Valk Richard Li
e2ee9cff4c update 2021-02-13 14:37:21 +08:00
Valk Richard Li
996ac59c79 update parser to LL(1) 2021-02-13 13:28:20 +08:00
Valk Richard Li
944f713ee9 update 2021-02-13 11:09:31 +08:00
Valk Richard Li
7329c70492 identifiers' name changed 2021-02-12 23:48:51 +08:00
Valk Richard Li
b5514fd269 update 2021-02-12 22:27:41 +08:00
Valk Richard Li
3be50116fa update 2021-02-10 00:12:22 +08:00
Valk Richard Li
125d6d3a7d update 2021-01-23 19:21:37 +08:00
Valk Richard Li
bb746dfbfb update 2021-01-23 17:57:05 +08:00
Valk Richard Li
8069a1b659 update 2021-01-06 22:12:19 +08:00
Valk Richard Li
f0cb8b6ef3 update 2021-01-06 21:07:34 +08:00
Valk Richard Li
9474ac9ef0 update & bug fixed 2021-01-05 23:17:32 +08:00
Valk Richard Li
b862aa91eb update 2021-01-05 01:55:17 +08:00
Valk Richard Li
bc64d530be update 2021-01-02 23:57:21 +08:00
Valk Richard Li
ea5116e963 update 2020-12-29 19:09:20 +08:00
Valk Richard Li
cc4e697246 bug fixed 2020-12-26 19:05:04 +08:00
Valk Richard Li
515bef3f5d bug fixed 2020-12-25 22:06:42 +08:00
Valk Richard Li
05800fe518 bug fixed 2020-12-25 13:22:57 +08:00
Valk Richard Li
33d37771ce update 2020-12-24 23:53:31 +08:00
Valk Richard Li
89540475cf update 2020-12-20 20:18:02 +08:00
Valk Richard Li
e03da2f737 update 2020-12-20 13:39:24 +08:00
Valk Richard Li
4617eb8f17 update 2020-12-19 23:47:04 +08:00
Valk Richard Li
fed1e20085 update 2020-12-19 21:02:02 +08:00
Valk Richard Li
9f30440286 preparation for v5.0 2020-12-19 01:26:15 +08:00
Valk Richard Li
99189d4f95 update 2020-12-17 22:32:28 +08:00
Valk Richard Li
ae16f36baa update 2020-12-17 00:14:22 +08:00
Valk Richard Li
19ce1c5f34 update 2020-12-15 21:13:22 +08:00
Valk Richard Li
7c026b62b7 update 2020-12-15 13:00:24 +08:00
Valk Richard Li
9eb72f8754 update 2020-12-14 23:43:00 +08:00
Valk Richard Li
73c9f98f4f update 2020-12-14 00:10:31 +08:00
Valk Richard Li
09e5b3fa90 Update README.md 2020-12-12 20:13:23 +08:00
Valk Richard Li
d8ce203ab3 update 2020-12-12 19:58:43 +08:00
Valk Richard Li
71f501a323 update 2020-12-12 01:58:40 +08:00
Valk Richard Li
a5825e0e92 update 2020-12-11 13:46:56 +08:00
Valk Richard Li
230bbd5eb5 update 2020-12-11 00:35:52 +08:00
Valk Richard Li
c9aa6cb6c4 update 2020-12-10 23:53:38 +08:00
Valk Richard Li
789300e5f6 update 2020-12-10 00:01:25 +08:00
Valk Richard Li
7f6a521ad7 bug fixed 2020-12-09 18:34:49 +08:00
Valk Richard Li
14852bfc2e update 2020-12-09 15:33:33 +08:00
Valk Richard Li
d0206abb8d update 2020-12-07 19:37:19 +08:00
Valk Richard Li
35cd1bd1e2 update 2020-12-06 21:07:40 +08:00
Valk Richard Li
1d941354ca update 2020-12-04 00:15:02 +08:00
Valk Richard Li
2bb0f0bf47 update 2020-12-04 00:00:29 +08:00
Valk Richard Li
c5d700d0bc bug fixed 2020-12-01 20:43:56 +08:00
Valk Richard Li
33e544387e update 2020-12-01 19:35:32 +08:00
Valk Richard Li
f336e5c3ae update 2020-11-30 23:54:32 +08:00
Valk Richard Li
fce34c12b3 update 2020-11-29 00:54:54 +08:00
Valk Richard Li
bbf5217374 update 2020-11-28 01:14:23 +08:00
Valk Richard Li
ffdc8993c4 update 2020-11-26 00:03:05 +08:00
Valk Richard Li
ab28657c78 update 2020-11-25 00:05:15 +08:00
Valk Richard Li
f811368491 update 2020-11-20 19:15:12 +08:00
Valk Richard Li
e9fd953273 update 2020-11-20 00:18:17 +08:00
Valk Richard Li
4a5083f5cf update 2020-11-19 23:42:51 +08:00
Valk Richard Li
1625f241fa update 2020-11-19 15:20:43 +08:00
Valk Richard Li
d7f1de5d7f update 2020-11-15 23:24:37 +08:00
Valk Richard Li
a0a22f701d update 2020-11-14 00:33:11 +08:00
Valk Richard Li
5aabbd8d42 update 2020-11-13 00:02:12 +08:00
Valk Richard Li
dc81773e7d update 2020-11-11 15:04:52 +08:00
Valk Richard Li
405172b317 update 2020-11-11 00:26:46 +08:00
Valk Richard Li
5c253bac88 print can show more details. 2020-11-10 22:30:54 +08:00
Valk Richard Li
2b4b1af72c update 2020-11-09 12:54:46 +08:00
Valk Richard Li
a09b748093 update math.pi :) 2020-11-09 00:33:15 +08:00
Valk Richard Li
fd8d3acfed update 2020-11-09 00:26:15 +08:00
Valk Richard Li
b9a53b3c4a update 2020-11-07 21:23:17 +08:00
Valk Richard Li
155ce6fc0d update & bug fixed 2020-11-03 19:27:21 +08:00
Valk Richard Li
6f5143657e update 2020-11-02 12:24:12 +08:00
Valk Richard Li
269d81ae5b fixed bug of subvec 2020-10-28 22:43:02 +08:00
Valk Richard Li
2923d24e6c update 2020-10-27 19:54:47 +08:00
Valk Richard Li
b612f73ff7 update 2020-10-26 22:42:16 +08:00
Valk Richard Li
ab8db5dd62 fixed bug of codegen 2020-10-25 23:39:27 +08:00
Valk Richard Li
e806b5f0a2 fixed bug of operator 'and' 2020-10-25 22:44:34 +08:00
Valk Richard Li
9a9277c505 update 2020-10-25 22:15:49 +08:00
Valk Richard Li
67ae3505fb update 2020-10-24 12:16:55 +08:00
Valk Richard Li
6daae85740 fixed another bug (:() 2020-10-24 00:24:49 +08:00
Valk Richard Li
cc05fbb597 fixed a bug of finding hash member 2020-10-24 00:12:35 +08:00
Valk Richard Li
9958431b58 update 2020-10-23 17:10:02 +08:00
58 changed files with 8376 additions and 7038 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.

910
README.md
View File

@@ -1,72 +1,910 @@
# Nasal Interpreter
# Nasal Script Language
[![nasal_new_logo](pic/nasal.png?raw=true)](http://wiki.flightgear.org/File:Nasallogo3.png)
# Nasal script language
## Introduction
[Nasal](http://wiki.flightgear.org/Nasal_scripting_language) is a script language that used in [FlightGear](https://www.flightgear.org/).
There is a Nasal console in FlightGear but sometimes it is not so easy for every developer to use.
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.
So this is an interpreter for Nasal written by C++.
The interpreter is still in development(now it works well --2021/2/15). We really need your support!
The interpreter is still in development.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
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 error.
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(nasal 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.
# Lexical Analysis
They found it much easier to check syntax and runtime errors before copying nasal-codes in nasal-console in Flightgear to test.
The flow chart of lexer is here:
Also, you could use this language to write some interesting programs and run them without the lib of Flightgear.
[![nasal_lexer.png](pic/nasal_lexer.png?raw=true)](https://github.com/ValKmjolnir/Nasal-Interpreter/blob/master/pic/nasal_lexer.png)
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!
Also remember to use g++ or clang++.
> [cpp compiler] -std=c++11 -O2 main.cpp -o nasal.exe
Or use this in linux/macOS/Unix
> [cpp compiler] -std=c++11 -O2 main.cpp -o nasal
## How to Use?
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(see more debug commands in 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.
## In __version 2.0__
```javascript
(var a,b,c)=(1,2,3);
var (r,g,b)=color;
(var a,b,c)=[{b:nil},[1,2],func return 0;];
(a.b,b[0],c)=(1,2,3);
```
These two types of statements are both definition_expr.
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.
Problems mentioned above have been solved for a long time, but recently i found a new problem here:
```javascript
(a,b,c)=(1,2,3);
var f=func(x,y,z){return x+y+z}
(a,b,c)=(0,1,2);
```
This will be recognized as this:
```javascript
var f=func(x,y,z){return x+y+z}(a,b,c)
=(0,1,2);
```
and causes fatal syntax error.
And i tried this program in flightgear nasal console.
It also found this is a syntax error.
I think this is a serious design fault.
To avoid this syntax error, change program like this, just add a semicolon:
```javascript
var f=func(x,y,z){return x+y+z};
^ here
(a,b,c)=(0,1,2);
```
### version 1.0(last update 2019/10/14)
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(last update 2020/8/31)
A completed ast-interpreter with unfinished lib functions.
### Version 3.0(last update 2020/10/23)
The ast is refactored and is now easier to read and maintain.
Ast-interpreter uses new techniques so it can run codes more efficiently.
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(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
### Version 4.0 (last update 2020/12/17)
I have just finished the first version of byte-code-interpreter.
This interpreter is still in test.After this test,i will release version 4.0!
Now i am trying to search hidden bugs in this interpreter.Hope you could help me! :)
There's an example of byte code below:
```javascript
for(var i=0;i<4000000;i+=1);
```
```asm
.number 0
.number 4e+006
.number 1
.symbol i
0x00000000: pzero 0x00000000
0x00000001: loadg 0x00000000 (i)
0x00000002: callg 0x00000000 (i)
0x00000003: pnum 0x00000001 (4e+006)
0x00000004: less 0x00000000
0x00000005: jf 0x0000000b
0x00000006: pone 0x00000000
0x00000007: mcallg 0x00000000 (i)
0x00000008: addeq 0x00000000
0x00000009: pop 0x00000000
0x0000000a: jmp 0x00000002
0x0000000b: nop 0x00000000
```
### Version 5.0 (last update 2021/3/7)
I decide to optimize bytecode vm in this version.
Because it takes more than 1.5s to count i from 0 to 4000000-1.This is not efficient at all!
2021/1/23 update: Now it can count from 0 to 4000000-1 in 1.5s.
### Version 6.0 (last update 2021/6/1)
Use loadg loadl callg calll mcallg mcalll to avoid branches.
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 (last update 2021/6/24)
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.
### version 7.0 (latest)
2021/6/26 update:
Instruction dispatch is changed from call-threading to computed-goto(with inline function).After changing the way of instruction dispatch,there is a great improvement in nasal_vm.Now vm can run test/bigloop and test/pi in 0.2s!And vm runs test/fib in 0.8s on linux.You could see the time use data below,in Test data section.
This version uses g++ extension "labels as values", which is also supported by clang++.(But i don't know if MSVC supports this)
There is also a change in nasal_gc: std::vector global is deleted,now the global values are all stored on stack(from val_stack+0 to val_stack+intg-1).
2021/6/29 update:
Add some instructions that execute const values:op_addc,op_subc,op_mulc,op_divc,op_lnkc,op_addeqc,op_subeqc,op_muleqc,op_diveqc,op_lnkeqc.
Now the bytecode of test/bigloop.nas seems like this:
```asm
.number 4e+006
.number 1
0x00000000: intg 0x00000001
0x00000001: pzero 0x00000000
0x00000002: loadg 0x00000000
0x00000003: callg 0x00000000
0x00000004: pnum 0x00000000 (4000000)
0x00000005: less 0x00000000
0x00000006: jf 0x0000000b
0x00000007: mcallg 0x00000000
0x00000008: addeqc 0x00000001 (1)
0x00000009: pop 0x00000000
0x0000000a: jmp 0x00000003
0x0000000b: nop 0x00000000
```
And this test file runs in 0.1s after this update.Most of the calculations are accelerated.
Also, assignment bytecode has changed a lot. Now the first identifier that called in assignment will use op_load to assign, instead of op_meq,op_pop.
```javascript
var (a,b)=(1,2);
a=b=0;
```
```asm
.number 2
0x00000000: intg 0x00000002
0x00000001: pone 0x00000000
0x00000002: loadg 0x00000000
0x00000003: pnum 0x00000000 (2)
0x00000004: loadg 0x00000001
0x00000005: pzero 0x00000000
0x00000006: mcallg 0x00000001
0x00000007: meq 0x00000000 (b=2 use meq,pop->a)
0x00000008: loadg 0x00000000 (a=b use loadg)
0x00000009: nop 0x00000000
```
## 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|
### version 7.0(i5-8250U ubuntu-WSL on windows10 2021/6/29)
running time:
|file|total time|info|
|:----|:----|:----|
|pi.nas|0.15625s|great improvement|
|fib.nas|0.75s|great improvement|
|bp.nas|0.4218s(7162 epoch)|good improvement|
|bigloop.nas|0.09375s|great improvement|
|mandelbrot.nas|0.0312s|great improvement|
|life.nas|8.80s(windows) 1.25(ubuntu WSL)|little improvement|
|ascii-art.nas|0.015s|little improvement|
|calc.nas|0.0468s|little improvement|
|quick_sort.nas|0s|great improvement|
|bfs.nas|0.0156s|great improvement|
## 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;
__String__ has 3 formats.But the third one is often used to declare a character.
__Vector__ has unlimited length and can store all types of values.
__Hash__ is a hashmap that stores values with strings/identifiers as the key.
__Function__ is also a value type in nasal.
```javascript
var spc=nil;
var a=1;
var a=2.71828;
var a=2.147e16;
var a=1e-10;
var a=0x7fffffff;
var a=0xAA55;
var a=0o170001;
var b='str';
var b="another string";
var b=`c`;
var c=[];
var c=[
0,
nil,
{},
[],
func(){return 0;}
];
append(c,0,1,2);
var d={
member1:nil,
member2:'str',
'member3':'member\'s name can also be a string constant',
"member4":"also this",
function:func()
{
var a=me.member2~me.member3;
return a;
}
};
var f=func(x,y,z)
{
return nil;
}
var f=func
{
return 1024;
}
var f=func(x,y,z,default_para1=1,default_para2=2)
{
return x+y+z+default_para1+default_para2;
}
var f=func(x,y,z,dynamic_para...)
{
var sum=0;
foreach(var i;dynamic_para)
sum+=i;
return sum+x+y+z;
}
```
### operators
```javascript
1+2-1*2/1;
'str1'~'str2';
(1+2)*(3+4)
1+1 and 0;
1<0 or 1>0;
1<=0 and 1>=0;
1==0 or 1!=0;
-1;
!0;
a=b=c=d=1;
a+=1;
a-=1;
a*=1;
a/=1;
a~='string';
```
### definition
```javascript
var a=1;
var (a,b,c)=[0,1,2];
var (a,b,c)=(0,1,2);
(var a,b,c)=[0,1,2];
(var a,b,c)=(0,1,2);
```
### multi-assignment
```javascript
(a,b[0],c.d)=[0,1,2];
(a,b[1],c.e)=(0,1,2);
(a,b)=(b,a);
```
This type of statement is multi_assignment.
And to check if an expr in '(' ')' is multi_scalar or multi_id.
### conditional expression
i used bool nasal_parse::check_multi_scalar() and bool nasal_parse::check_multi_assignment().
```javascript
if(1){
;
}elsif(2){
;
}else if(3){
;
}else{
;
}
```
## In __version 3.0__
### loop
I refactored parser and make it easier to maintain.
```javascript
while(condition)
continue;
the EBNF is also refactored.
for(var i=0;i<10;i+=1)
break;
# Abstract Syntax Tree
forindex(var i;elem)
print(elem[i]);
In __version 1.2__ the ast has been completed.
foreach(var i;elem)
print(i);
```
In __version 3.0__ the ast is refactored and is now easier to read and maintain.
### subvec
# Version 2.0
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().
a completed ast-interpreter with unfinished lib functions.
```javascript
a[-1,1,0:2,0:,:3,:,nil:8,3:nil,nil:nil];
"hello world"[0];
```
# Version 3.0
### special function call
ast-interpreter uses new techniques so it can run codes more efficiently.
This is of great use but is not very efficient(because hashmap use string as the key to compare).
byte-code-interpreter is in progress(i need a lot of time to learn that :( ).
```javascript
a(x:0,y:1,z:2);
```
### 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()
{
var a=1;
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
Must import lib.nas or has these functions' definitions inside your code.
Also you could add builtin functions of your own(written in C/C++) to help you calculate things more quickly.(Advanced usage)
Check built-in functions in lib.nas!
If you want to add your own built-in functions,define the function in nasal_builtin.h.
Definition:
```C++
nasal_val* builtin_chr(std::vector<nasal_val*>&,nasal_gc&);
```
Then complete this function using C++:
```C++
nasal_val* builtin_print(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
{
// 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 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<<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<<std::flush;
// if a nasal value is not in use,use gc::del_reference to delete it
// generate return value,use gc::gc_alloc(type) to make a new value
// or use reserved reference gc.nil_addr/gc.one_addr/gc.zero_addr
return gc.nil_addr;
}
```
After that, write the built-in function's name(in nasal) and the function's pointer in this table:
```C++
struct FUNC_TABLE
{
const char* name;
nasal_val* (*func)(std::vector<nasal_val*>&,nasal_gc&);
} builtin_func[]=
{
{"__builtin_print",builtin_print},
{nullptr, nullptr }
};
```
At last,warp the '__builtin_print' in a nasal file:
```javascript
var print=func(elems...)
{
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 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 than 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;
}
```
## Difference Between Andy's Nasal Interpreter and This Interpreter
This interpreter uses more strict syntax to make sure it is easier for you to program and debug.
In Andy's interpreter:
```javascript
foreach(i;[0,1,2,3])
print(i)
```
This program can run normally with output 0 1 2 3.
But take a look at the iterator 'i',this symbol is defined in foreach without using keyword 'var'.
I think this design will make programmers filling confused.
This is ambiguous that programmers maybe difficult to find the 'i' is defined here.
Without 'var',programmers may think this 'i' is defined anywhere else.
So in this new interpreter i use a more strict syntax to force users to use 'var' to define iterator of forindex and foreach.
If you forget to add the keyword 'var', and you haven't defined this symbol before, you will get this:
```javascript
[code] <test.nas> line 1: undefined symbol "i".
[codegen] in <test.nas>: error(s) occurred,stop.
```
Also there's another difference.
In Andy's interpreter:
```javascript
var a=func {print(b);}
var b=1;
a();
```
This program runs normally with output 1.
But in this new interpreter, it will get:
```javascript
[code] <test.nas> line 1: undefined symbol "b".
[codegen] in <test.nas>: error(s) occurred,stop.
```
(outdated)This difference is caused by different kinds of ways of lexical analysis.
In most script language interpreters, they use dynamic analysis to check if this symbol is defined yet.
However, this kind of analysis is at the cost of lower efficiency.
To make sure the interpreter runs at higher efficiency, i choose static analysis to manage the memory space of each symbol.
By this way, runtime will never need to check if a symbol exists or not.
But this causes a difference.
You will get an error of 'undefined symbol', instead of nothing happening in most script language interpreters.
This change is __controversial__ among FGPRC's members.
So maybe in the future i will use dynamic analysis again to cater to the habits of senior programmers.
(2021/8/3 update) __Now i use scanning ast twice to reload symbols.
So this difference does not exist from this update.__
But a new difference is that if you call a variable before defining it, you'll get nil instead of 'undefined error'.
In this new interpreter, function doesn't put dynamic arguments into vector 'arg' automatically.
So if you use 'arg' without definition, you'll get an error of 'undefined symbol'.
## Trace Back Info
Now when the interpreter crashes,it will print trace back information:
```javascript
func()
{
println("hello");
die("error occurred this line");
return;
}();
```
Function 'die' is used to throw error and crash.
```javascript
hello
[vm] error: error occurred this line
[vm] error at 0x000000b0: native function error.
trace back:
0x000000b0: callb 0x00000021:__builtin_die (lib.nas line 85)
0x0000017f: callfv 0x00000001 (a.nas line 19)
0x00000183: callfv 0x00000000 (a.nas line 21)
vm stack(limit 10):
0x0 nullptr
0x7fa5f8e19c80 func | func(1 para){..}
0x7fa5f8e1a780 func | func(0 para){..}
0x7fa5f8c0c040 num | 0.017453
0x7fa5f8e33370 hash | {9 member}
0x7fa5f8e33330 hash | {5 member}
0x7fa5f8e332e0 hash | {2 member}
0x7fa5f8e1a000 func | func(1 para){..}
0x7fa5f8e19f80 func | func(2 para){..}
0x7fa5f8e19f00 func | func(2 para){..}
```
Here is an example of stack overflow:
```javascript
func(f){
return f(f);
}(
func(f){
f(f);
}
)();
```
And the trace back info:
```javascript
[vm] stack overflow
trace back:
0x00000011: callfv 0x00000001 (a.nas line 5)
0x00000011: 4076 same call(s) ...
0x00000008: callfv 0x00000001 (a.nas line 2)
0x00000015: callfv 0x00000001 (a.nas line 3)
vm stack(limit 10):
0x7fcc3110ad00 func | func(1 para){..}
0x7fcc3110ad00 ... | 9 same value(s)
```

195
lib.nas
View File

@@ -1,163 +1,162 @@
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 append=func(vector,elements...)
var println=func(elems...)
{
nasal_call_builtin_push_back(vector,elements);
return nil;
__builtin_print(elems);
elems=['\n'];
return __builtin_print(elems);
}
var setsize=func(vector,size)
var append=func(vec,elems...)
{
nasal_call_builtin_set_size(vector,size);
return nil;
return __builtin_append(vec,elems);
}
var setsize=func(vec,size)
{
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 type=func(object)
var typeof=func(object)
{
return nasal_call_builtin_type(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 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.14159265358979323846,
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);
},
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);},
inf: 1/0,
nan: 0/0,
isnan: func(x) {return __builtin_isnan(x); }
};
var D2R=math.pi/180;
var FPS2KT=0.5925;
var FT2M=0.3048;
var GAL2L=3.7854;
var IN2M=0.0254;
var KG2LB=2.2046;
var KT2FPS=1.6878;
var KT2MPS=0.5144;
var L2GAL=0.2642;
var LB2KG=0.4536;
var M2FT=3.2808;
var M2IN=39.3701;
var M2NM=0.00054;
var MPS2KT=1.9438;
var NM2M=1852;
var R2D=180/math.pi;

356
main.cpp
View File

@@ -1,248 +1,144 @@
#include "nasal.h"
nasal_resource resource;
nasal_lexer lexer;
nasal_parse parse;
nasal_import preprocessor;
nasal_codegen code_generator;
std::string command;
std::string inputfile="null";
nasal_runtime runtime;
void help()
void help_cmd()
{
std::cout<<">> [\"file\"] input a file name.\n";
std::cout<<">> [clear ] clear the screen.\n";
std::cout<<">> [del ] clear the input filename.\n";
std::cout<<">> [rs ] print source code.\n";
std::cout<<">> [lex ] use lexer to turn code into tokens.\n";
std::cout<<">> [ast ] do parsing and check the abstract syntax tree.\n";
std::cout<<">> [run ] run abstract syntax tree.\n";
std::cout<<">> [exec ] generate byte code.\n";
std::cout<<">> [erun ] run byte code.\n";
std::cout<<">> [logo ] print logo of nasal .\n";
std::cout<<">> [exit ] quit nasal interpreter.\n";
return;
std::cout
#ifdef _WIN32
<<"use command \'chcp 65001\' if want to use unicode.\n"
#endif
<<"nasal [option]\n"
<<"option:\n"
<<" -h, --help | get help.\n"
<<" -v, --version | get version of nasal interpreter.\n\n"
<<"nasal [file]\n"
<<"file:\n"
<<" input file name to execute script file.\n\n"
<<"nasal [option] [file]\n"
<<"option:\n"
<<" -l, --lex | view token info.\n"
<<" -a, --ast | view abstract syntax tree.\n"
<<" -c, --code | view bytecode.\n"
<<" -e, --exec | execute script file.\n"
<<" -t, --time | execute and get the running time.\n"
<<" -o, --opcnt | count operands while running.\n"
<<"file:\n"
<<" input file name to execute script file.\n";
return;
}
void logo()
{
std::cout<<" __ _ \n";
std::cout<<" /\\ \\ \\__ _ ___ __ _| | \n";
std::cout<<" / \\/ / _` / __|/ _` | | \n";
std::cout<<" / /\\ / (_| \\__ \\ (_| | | \n";
std::cout<<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n";
std::cout
<<" __ _ \n"
<<" /\\ \\ \\__ _ ___ __ _| | \n"
<<" / \\/ / _` / __|/ _` | | \n"
<<" / /\\ / (_| \\__ \\ (_| | | \n"
<<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
<<"nasal interpreter ver 7.0\n"
<<"thanks to : https://github.com/andyross/nasal\n"
<<"code repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
<<"code repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
<<"lang info : http://wiki.flightgear.org/Nasal_scripting_language\n"
<<"input \"nasal -h\" to get help .\n";
return;
}
void del_func()
void die(const char* stage,const std::string& filename)
{
resource.clear();
lexer.clear();
parse.clear();
inputfile="null";
std::cout<<">> [Delete] complete.\n";
return;
std::cout<<"["<<stage<<"] in <"<<filename<<">: error(s) occurred,stop.\n";
std::exit(1);
return;
}
void die(std::string stage,std::string filename)
void execute(const std::string& file,const std::string& command)
{
std::cout<<">> ["<<stage<<"] in <\""<<filename<<"\">: error(s) occurred,stop.\n";
return;
nasal_lexer lexer;
nasal_parse parse;
nasal_import import;
nasal_codegen codegen;
nasal_vm vm;
lexer.openfile(file);
lexer.scanner();
if(lexer.get_error())
die("lexer",file);
if(command=="--lex" || command=="-l")
{
lexer.print_token();
return;
}
parse.main_process(lexer.get_token_list());
if(parse.get_error())
die("parse",file);
if(command=="--ast" || command=="-a")
{
parse.get_root().print_ast(0);
return;
}
// first used file is itself
import.link(parse.get_root(),file);
if(import.get_error())
die("import",file);
codegen.main_progress(import.get_root(),import.get_file());
if(codegen.get_error())
die("code",file);
if(command=="--code" || command=="-c")
{
codegen.print_byte_code();
return;
}
vm.init(
codegen.get_str_table(),
codegen.get_num_table(),
import.get_file()
);
if(command=="--exec" || command=="-e" || command=="--opcnt" || command=="-o")
vm.run(codegen.get_exec_code(),command=="--opcnt" || command=="-o");
else if(command=="--time" || command=="-t")
{
clock_t begin=clock();
vm.run(codegen.get_exec_code(),false);
std::cout<<"process exited after "<<((double)(clock()-begin))/CLOCKS_PER_SEC<<"s.\n";
}
vm.clear();
return;
}
void lex_func()
int main(int argc,const char* argv[])
{
if(!resource.input_file(inputfile))
{
die("resource",inputfile);
return;
}
lexer.scanner(resource.get_file());
if(lexer.get_error())
{
die("lexer",inputfile);
return;
}
lexer.print_token();
return;
}
void ast_print()
{
if(!resource.input_file(inputfile))
{
die("resource",inputfile);
return;
}
lexer.scanner(resource.get_file());
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);
return;
}
void runtime_start()
{
if(!resource.input_file(inputfile))
{
die("resource",inputfile);
return;
}
lexer.scanner(resource.get_file());
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;
}
preprocessor.preprocessing(parse.get_root());
if(preprocessor.get_error())
{
die("import",inputfile);
return;
}
runtime.set_root(preprocessor.get_root());
runtime.run();
return;
}
void codegen_start()
{
if(!resource.input_file(inputfile))
{
die("resource",inputfile);
return;
}
lexer.scanner(resource.get_file());
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;
}
preprocessor.preprocessing(parse.get_root());
if(preprocessor.get_error())
{
die("import",inputfile);
return;
}
runtime.set_root(preprocessor.get_root());
code_generator.output_exec(inputfile+".naexec",preprocessor.get_root());
if(code_generator.get_error())
{
die("code",inputfile);
return;
}
return;
}
void execution_start()
{
code_generator.load_exec(inputfile,preprocessor.get_root());
if(code_generator.get_error())
{
die("code",inputfile);
return;
}
runtime.set_root(preprocessor.get_root());
runtime.run();
return;
}
int main()
{
#ifdef _WIN32
// use chcp 65001 to use unicode io
system("chcp 65001");
system("cls");
#endif
logo();
#ifdef _WIN32
std::cout<<">> [system] Windows system.\n";
#endif
#ifdef _linux_
std::cout<<">> [system] Linux system.\n";
#endif
#ifdef TARGET_OS_MAC
std::cout<<">> [system] MacOS system.\n";
#endif
std::cout<<">> Nasal interpreter ver 3.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";
while(1)
{
std::cout<<">> ";
std::cin>>command;
if(command=="help")
help();
else if(command=="clear")
{
#ifdef _WIN32
system("cls");
#endif
#ifdef _linux_
system("clear");
#endif
#ifdef TARGET_OS_MAC
system("clear");
#endif
}
else if(command=="del")
del_func();
else if(command=="rs")
{
if(resource.input_file(inputfile))
resource.print_file();
}
else if(command=="lex")
lex_func();
else if(command=="ast")
ast_print();
else if(command=="run")
runtime_start();
else if(command=="exec")
codegen_start();
else if(command=="erun")
execution_start();
else if(command=="logo")
logo();
else if(command=="exit")
break;
else
{
inputfile=command;
std::ifstream fin(command);
if(fin.fail())
{
std::cout<<">> [file] cannot open file \""<<command<<"\".\n";
inputfile="null";
}
fin.close();
}
}
std::string command,file;
if(argc==2 && (!strcmp(argv[1],"-v") || !strcmp(argv[1],"--version")))
logo();
else if(argc==2 && (!strcmp(argv[1],"-h") || !strcmp(argv[1],"--help")))
help_cmd();
else if(argc==2 && argv[1][0]!='-')
{
file=argv[1];
command="-e";
execute(file,command);
}
else if(argc==3 &&
(!strcmp(argv[1],"--lex") ||
!strcmp(argv[1],"-l") ||
!strcmp(argv[1],"--ast") ||
!strcmp(argv[1],"-a") ||
!strcmp(argv[1],"--code") ||
!strcmp(argv[1],"-c") ||
!strcmp(argv[1],"--exec") ||
!strcmp(argv[1],"-e") ||
!strcmp(argv[1],"--opcnt")||
!strcmp(argv[1],"-o") ||
!strcmp(argv[1],"--time") ||
!strcmp(argv[1],"-t")))
{
file=argv[2];
command=argv[1];
execute(file,command);
}
else
{
std::cout
<<"invalid argument(s).\n"
<<"use nasal -h to get help.\n";
exit(1);
}
return 0;
}

View File

@@ -20,7 +20,7 @@ hashmember::=
id|string ':' calculation
;
function::=
func argument_list expressions
func {argument_list} exprs|expr
;
argument_list::=
'(' [{id ','} ([id '...']|{id '=' scalar ','})] ')'
@@ -35,7 +35,7 @@ expr::=
|continue_expr
|break_expr
;
expressions::=
exprs::=
'{' {expr} '}'
;
calculation::=
@@ -59,15 +59,15 @@ multive_expr::=
(unary|scalar) ('*' | '/') (unary|scalar)
;
unary::=
('-'|'!') scalar
('-'|'!') (unary|scalar)
;
scalar::=
function {call_scalar}
|identifier {call_scalar}
|vector {call_scalar}
|hash {call_scalar}
|number
|string
|nil
|'(' calculation ')' {call_scalar}
;
call_scalar::=
@@ -108,18 +108,18 @@ loop::=
|forei_loop
;
while_loop::=
while '(' calculation ')' expressions
while '(' calculation ')' exprs
;
for_loop::=
for '(' [definition|calculation] ';' [calculation] ';' [calculation] ')' expressions
for '(' [definition|calculation] ';' [calculation] ';' [calculation] ')' exprs
;
forei_loop::=
(forindex | foreach) '(' (definition | calculation) ';' calculation ')' expressions
(forindex | foreach) '(' (definition | calculation) ';' calculation ')' exprs
;
conditional::=
if '(' calculation ')' expressions
{elsif '(' calculation ')' expressions}
[else expressions]
if '(' calculation ')' exprs
{elsif '(' calculation ')' exprs}
[else exprs]
;
continue_expr::=
continue

119
nasal.h
View File

@@ -1,34 +1,137 @@
#ifndef __NASAL_H__
#define __NASAL_H__
#pragma GCC optimize(2)
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cmath>
/* if thread is used, don't forget to add -std=c++11 or higher standard before executing */
// #include <thread>
#include <list>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <unordered_map>
#include "nasal_enum.h"
#include "nasal_misc.h"
#include "nasal_resource.h"
/*
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(const char* str)
{
double ret=0;
for(;*str;++str)
{
ret*=16;
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 nan("");
}
return ret;
}
inline double oct_to_double(const char* str)
{
double ret=0;
for(;*str;++str)
{
ret*=8;
if('0'<=*str && *str<'8')
ret+=(*str-'0');
else
return nan("");
}
return ret;
}
inline double dec_to_double(const char* str)
{
double ret=0,negative=1,num_pow=0;
while('0'<=*str && *str<='9')
ret=ret*10+(*str++-'0');
if(!*str) return ret;
if(*str=='.')
{
if(!*++str) return nan("");
num_pow=0.1;
while('0'<=*str && *str<='9')
{
ret+=num_pow*(*str++-'0');
num_pow*=0.1;
}
if(!*str) return ret;
}
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 && *str<='9')
num_pow=num_pow*10+(*str-'0');
else
return nan("");
}
return ret*std::pow(10,negative*num_pow);
}
double str2num(const char* str)
{
bool is_negative=false;
double ret_num=0;
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);
return is_negative?-ret_num:ret_num;
}
/*
show raw string
*/
void raw_string(const std::string& str)
{
for(auto i:str)
switch(i)
{
case '\a': std::cout<<"\\a";break;
case '\b': std::cout<<"\\b";break;
case '\f': std::cout<<"\\f";break;
case '\n': std::cout<<"\\n";break;
case '\r': std::cout<<"\\r";break;
case '\t': std::cout<<"\\t";break;
case '\v': std::cout<<"\\v";break;
case '\0': std::cout<<"\\0";break;
default: std::cout<<i; break;
}
return;
}
#include "nasal_lexer.h"
#include "nasal_ast.h"
#include "nasal_parse.h"
#include "nasal_import.h"
#include "nasal_codegen.h"
#include "nasal_gc.h"
#include "nasal_runtime.h"
#include "nasal_builtin.h"
#include "nasal_codegen.h"
#include "nasal_vm.h"
#endif

View File

@@ -1,128 +1,153 @@
#ifndef __NASAL_AST_H__
#define __NASAL_AST_H__
enum ast_node
{
ast_null=0,
ast_root,ast_block,
ast_file, // ast_file is only used to store which file the subtree is on,codegen will generate nothing
ast_nil,ast_num,ast_str,ast_id,ast_func,ast_hash,ast_vec,
ast_hashmember,ast_call,ast_callh,ast_callv,ast_callf,ast_subvec,
ast_args,ast_default_arg,ast_dynamic_id,
ast_and,ast_or,
ast_equal,ast_addeq,ast_subeq,ast_multeq,ast_diveq,ast_lnkeq,
ast_cmpeq,ast_neq,
ast_less,ast_leq,
ast_grt,ast_geq,
ast_add,ast_sub,ast_mult,ast_div,ast_link,
ast_neg,ast_not,
ast_trino,
ast_for,ast_forindex,ast_foreach,ast_while,ast_new_iter,
ast_conditional,ast_if,ast_elsif,ast_else,
ast_multi_id,ast_multi_scalar,
ast_def,ast_multi_assign,
ast_continue,ast_break,ast_ret
};
const char* ast_name[]=
{
"null",
"root","block",
"file",
"nil","num","str","id","func","hash","vec",
"hashmember","call","callh","callv","callf","subvec",
"args","deflt_arg","dyn_id",
"and","or",
"=","+=","-=","*=","/=","~=",
"==","!=",
"<","<=",
">",">=",
"+","-","*","/","~",
"unary-","unary!",
"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;
std::vector<nasal_ast> children;
public:
nasal_ast();
nasal_ast(){line=0;type=ast_null;}
nasal_ast(const int l,const 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 add_child(nasal_ast);
int get_line();
int get_type();
std::string get_str();
std::vector<nasal_ast>& get_children();
void print_ast(int);
};
nasal_ast& operator=(nasal_ast&&);
void print_ast(const int);
void clear();
void add_child(nasal_ast&& ast){children.push_back(std::move(ast));}
void add_child(const nasal_ast& ast){children.push_back(ast);}
void set_line(const int l){line=l;}
void set_type(const int t){type=t;}
void set_str(const std::string& s){str=s;}
void set_num(const double n){num=n;}
int get_line(){return line;}
int get_type(){return type;}
double get_num() {return num;}
std::string& get_str(){return str;}
std::vector<nasal_ast>& get_children(){return children;}
nasal_ast::nasal_ast()
{
this->line=0;
this->type=ast_null;
this->str="";
return;
}
int get_line() const {return line;}
int get_type() const {return type;}
double get_num() const {return num;}
const std::string& get_str() const {return str;}
const std::vector<nasal_ast>& get_children() const {return children;}
};
nasal_ast::nasal_ast(const nasal_ast& tmp)
{
this->line=tmp.line;
this->type=tmp.type;
this->str=tmp.str;
this->children=tmp.children;
line=tmp.line;
type=tmp.type;
num =tmp.num;
str =tmp.str;
children=tmp.children;
return;
}
nasal_ast::~nasal_ast()
nasal_ast::nasal_ast(nasal_ast&& tmp)
{
this->str.clear();
this->children.clear();
line=tmp.line;
type=tmp.type;
num =tmp.num;
str.swap(tmp.str);
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->children=tmp.children;
line=tmp.line;
type=tmp.type;
num=tmp.num;
str=tmp.str;
children=tmp.children;
return *this;
}
nasal_ast& nasal_ast::operator=(nasal_ast&& tmp)
{
line=tmp.line;
type=tmp.type;
num=tmp.num;
str.swap(tmp.str);
children.swap(tmp.children);
return *this;
}
void nasal_ast::clear()
{
this->line=0;
this->type=ast_null;
this->str="";
this->children.clear();
line=0;
num=0;
str="";
type=ast_null;
children.clear();
return;
}
void nasal_ast::set_line(int l)
void nasal_ast::print_ast(const int depth)
{
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::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;
}
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_str(this->type);
std::cout<<indentation;
if(this->type==ast_number || this->type==ast_string || this->type==ast_identifier || this->type==ast_dynamic_id || this->type==ast_call_hash)
std::cout<<":"<<this->str;
std::cout<<std::endl;
int child_size=this->children.size();
for(int i=0;i<child_size;++i)
this->children[i].print_ast(depth+1);
for(int i=0;i<depth;++i)
std::cout<<"| ";
std::cout<<ast_name[type];
if(type==ast_str || type==ast_id || type==ast_default_arg || type==ast_dynamic_id || type==ast_callh)
{
std::cout<<":";
raw_string(str);
}
else if(type==ast_num || type==ast_file)
std::cout<<":"<<num;
std::cout<<'\n';
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,190 +0,0 @@
#ifndef __NASAL_ENUM_H__
#define __NASAL_ENUM_H__
/* token_type is used in lexer */
enum token_type
{
tok_null=0,
tok_number,tok_string,tok_identifier,
tok_for,tok_forindex,tok_foreach,tok_while,
tok_var,tok_func,tok_break,tok_continue,
tok_return,tok_if,tok_elsif,tok_else,tok_nil,
tok_left_curve,tok_right_curve,
tok_left_bracket,tok_right_bracket,
tok_left_brace,tok_right_brace,
tok_semi,tok_and,tok_or,tok_comma,tok_dot,tok_ellipsis,tok_quesmark,
tok_colon,tok_add,tok_sub,tok_mult,tok_div,tok_link,tok_not,
tok_equal,
tok_add_equal,tok_sub_equal,tok_mult_equal,tok_div_equal,tok_link_equal,
tok_cmp_equal,tok_cmp_not_equal,tok_less_than,tok_greater_than,tok_less_equal,tok_greater_equal
};
enum ast_node
{
ast_null=0,ast_root,ast_block,
ast_nil,ast_number,ast_string,ast_identifier,ast_function,ast_hash,ast_vector,
ast_hashmember,ast_call,ast_call_hash,ast_call_vec,ast_call_func,ast_subvec,
ast_args,ast_default_arg,ast_dynamic_id,
ast_and,ast_or,
ast_equal,ast_add_equal,ast_sub_equal,ast_mult_equal,ast_div_equal,ast_link_equal,
ast_cmp_equal,ast_cmp_not_equal,ast_less_than,ast_less_equal,ast_greater_than,ast_greater_equal,
ast_add,ast_sub,ast_mult,ast_div,ast_link,
ast_unary_sub,ast_unary_not,
ast_trinocular,
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
};
std::string ast_str(int type)
{
std::string str;
switch(type)
{
case ast_null: str="null";break;
case ast_root: str="root";break;
case ast_block: str="block";break;
case ast_nil: str="nil";break;
case ast_number: str="number";break;
case ast_string: str="string";break;
case ast_identifier: str="id";break;
case ast_function: str="function";break;
case ast_hash: str="hash";break;
case ast_vector: str="vector";break;
case ast_hashmember: str="hashmember";break;
case ast_call: str="call";break;
case ast_call_hash: str="call_hash";break;
case ast_call_vec: str="call_vector";break;
case ast_call_func: str="call_func";break;
case ast_subvec: str="subvec";break;
case ast_args: str="arguments";break;
case ast_default_arg: str="default_arg";break;
case ast_dynamic_id: str="dynamic_id";break;
case ast_and: str="and";break;
case ast_or: str="or";break;
case ast_equal: str="=";break;
case ast_add_equal: str="+=";break;
case ast_sub_equal: str="-=";break;
case ast_mult_equal: str="*=";break;
case ast_div_equal: str="/=";break;
case ast_link_equal: str="~=";break;
case ast_cmp_equal: str="==";break;
case ast_cmp_not_equal:str="!=";break;
case ast_less_than: str="<";break;
case ast_less_equal: str="<=";break;
case ast_greater_than: str=">";break;
case ast_greater_equal:str=">=";break;
case ast_add: str="+";break;
case ast_sub: str="-";break;
case ast_mult: str="*";break;
case ast_div: str="/";break;
case ast_link: str="~";break;
case ast_unary_sub: str="unary-";break;
case ast_unary_not: str="unary!";break;
case ast_trinocular: str="trinocular";break;
case ast_for: str="for";break;
case ast_forindex: str="forindex";break;
case ast_foreach: str="foreach";break;
case ast_while: str="while";break;
case ast_new_iter: str="new_iterator";break;
case ast_conditional: str="conditional";break;
case ast_if: str="if";break;
case ast_elsif: str="elsif";break;
case ast_else: str="else";break;
case ast_multi_id: str="multi_id";break;
case ast_multi_scalar: str="multi_scalar";break;
case ast_definition: str="definition";break;
case ast_multi_assign: str="multi_assignment";break;
case ast_continue: str="continue";break;
case ast_break: str="break";break;
case ast_return: str="return";break;
}
return str;
}
enum parse_error
{
unknown,
error_token,
error_expr,
lack_left_curve,
lack_right_curve,
lack_left_bracket,
lack_right_bracket,
lack_left_brace,
lack_right_brace,
exprs_lack_rbrace,
lack_semi,
lack_comma,
lack_colon,
lack_equal,
lack_scalar,
lack_identifier,
lack_calculation,
lack_exprs,
lack_token,
lack_args,
default_arg_not_end,
dynamic_id_not_end,
name_repetition,
definition_use_call,
multi_id_use_call,
multi_assign_lack_val,
lack_definition,
lack_loop_iter,
lack_func_content
};
void error_info(int line,int error_type,std::string error_str="")
{
std::string detail;
std::cout<<">> [parse] error_info: [line "<<line<<"] ";
switch(error_type)
{
case unknown: std::cout<<"unknown error.\n"; break;
case error_token: std::cout<<"error token \""+error_str+"\".\n"; break;
case error_expr: std::cout<<"error expression \""+error_str+"\".\n"; break;
case lack_left_curve: std::cout<<"expected \"(\".\n"; break;
case lack_right_curve: std::cout<<"expected \")\".\n"; break;
case lack_left_bracket: std::cout<<"expected \"[\".\n"; break;
case lack_right_bracket: std::cout<<"expected \"]\".\n"; break;
case lack_left_brace: std::cout<<"expected \"{\".\n"; break;
case lack_right_brace: std::cout<<"expected \"}\".\n"; break;
case exprs_lack_rbrace: std::cout<<"expected \"}\" with this line\'s \"{\".\n";break;
case lack_semi: std::cout<<"expected \";\".\n"; break;
case lack_comma: std::cout<<"expected \",\".\n"; break;
case lack_colon: std::cout<<"expected \":\".\n"; break;
case lack_equal: std::cout<<"expected \"=\".\n"; break;
case lack_scalar: std::cout<<"expected scalar here.\n"; break;
case lack_identifier: std::cout<<"expected identifier here.\n"; break;
case lack_calculation: std::cout<<"expected arithmetic-expression here.\n"; break;
case lack_exprs: std::cout<<"expected expression block here.\n"; break;
case lack_token: std::cout<<"expected \""+error_str+"\" here.\n"; break;
case lack_args: std::cout<<"expected arguments here.\n"; break;
case default_arg_not_end: std::cout<<"default argument missing for parameter of "+error_str+".\n";break;
case dynamic_id_not_end: std::cout<<"dynamic id must be the end of "+error_str+".\n";break;
case name_repetition: std::cout<<"this identifier name has existed.\n";break;
case definition_use_call: std::cout<<"should not use call_scalar in definition progress.\n";break;
case multi_id_use_call: std::cout<<"should not use call_scalar in multi_id progress.\n";break;
case multi_assign_lack_val:std::cout<<"multi-assignment lacks value list.\n";break;
case lack_definition: std::cout<<"expected a definition expression here.\n";break;
case lack_loop_iter: std::cout<<"expected an iterator to loop through.\n";break;
case lack_func_content: std::cout<<"expected arguments or expression block here.\n";break;
}
return;
}
enum runtime_scalar_type
{
vm_nil=0,
vm_number,
vm_string,
vm_closure,
vm_function,
vm_vector,
vm_hash
};
#endif

1946
nasal_gc.h

File diff suppressed because it is too large Load Diff

View File

@@ -4,56 +4,37 @@
class nasal_import
{
private:
nasal_resource import_src;
nasal_lexer import_lex;
nasal_parse import_par;
nasal_ast import_ast;
int error;
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);
void init();
bool check_import(nasal_ast&);
bool check_exist(std::string);
void linker(nasal_ast&,nasal_ast&);
void die(const std::string&,const char*);
bool check_import(const nasal_ast&);
bool check_exist(const std::string&);
void linker(nasal_ast&,nasal_ast&&);
nasal_ast file_import(nasal_ast&);
nasal_ast load(nasal_ast&);
nasal_ast load(nasal_ast&,uint16_t);
public:
nasal_import();
int get_error();
void preprocessing(nasal_ast&);
nasal_ast& get_root();
const int get_error(){return error;}
void link(nasal_ast&,const std::string&);
const nasal_ast&
get_root(){return import_ast;}
const std::vector<std::string>&
get_file(){return filename_table;}
};
nasal_import::nasal_import()
{
import_src.clear();
import_lex.clear();
import_par.clear();
import_ast.clear();
filename_table.clear();
return;
}
void nasal_import::die(std::string filename,std::string error_stage)
void nasal_import::die(const 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;
}
void nasal_import::init()
{
import_src.clear();
import_lex.clear();
import_par.clear();
return;
}
bool nasal_import::check_import(nasal_ast& node)
bool nasal_import::check_import(const 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
@@ -61,124 +42,93 @@ bool nasal_import::check_import(nasal_ast& node)
*/
if(node.get_type()!=ast_call)
return false;
std::vector<nasal_ast>& ref_vec=node.get_children();
const std::vector<nasal_ast>& ref_vec=node.get_children();
if(ref_vec.size()!=2)
return false;
if(ref_vec[0].get_str()!="import")
return false;
if(ref_vec[1].get_type()!=ast_call_func)
if(ref_vec[1].get_type()!=ast_callf)
return false;
if(ref_vec[1].get_children().size()!=1 || ref_vec[1].get_children()[0].get_type()!=ast_string)
if(ref_vec[1].get_children().size()!=1 || ref_vec[1].get_children()[0].get_type()!=ast_str)
return false;
return true;
}
bool nasal_import::check_exist(std::string filename)
bool nasal_import::check_exist(const 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;
}
nasal_ast nasal_import::file_import(nasal_ast& node)
{
// initializing
nasal_ast tmp;
tmp.set_line(0);
tmp.set_type(ast_root);
init();
nasal_ast tmp(0,ast_root);
// get filename and set node to ast_null
std::string filename=node.get_children()[1].get_children()[0].get_str();
node.clear();
node.set_type(ast_null);
// avoid infinite loading loop
if(check_exist(filename))
return tmp;
// start importing...
if(!import_src.input_file(filename))
{
this->die(filename,"resource");
return tmp;
}
import_lex.scanner(import_src.get_file());
import_lex.openfile(filename);
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_par.main_process();
import_par.main_process(import_lex.get_token_list());
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());
// check if tmp has 'import'
return load(tmp);
return load(tmp,filename_table.size()-1);
}
nasal_ast nasal_import::load(nasal_ast& root)
nasal_ast nasal_import::load(nasal_ast& root,uint16_t fileindex)
{
nasal_ast new_root;
new_root.set_line(0);
new_root.set_type(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);
}
}
nasal_ast new_root(0,ast_root);
for(auto& i:root.get_children())
if(check_import(i))
linker(new_root,file_import(i));
// add root to the back of new_root
linker(new_root,root);
// oops,i think it is not efficient if the root is too ... large?
nasal_ast file_head(0,ast_file);
file_head.set_num(fileindex);
new_root.add_child(std::move(file_head));
linker(new_root,std::move(root));
return new_root;
}
void nasal_import::preprocessing(nasal_ast& root)
void nasal_import::link(nasal_ast& root,const std::string& self)
{
// initializing
error=0;
filename_table.clear();
filename_table.push_back(self);
import_ast.clear();
// scan root and import files,then generate a new ast and return to import_ast
import_ast=load(root);
// the main file's index is 0
import_ast=load(root,0);
return;
}
nasal_ast& nasal_import::get_root()
{
return import_ast;
}
int nasal_import::get_error()
{
return error;
}
#endif

View File

@@ -1,317 +1,320 @@
#ifndef __NASAL_LEXER_H__
#define __NASAL_LEXER_H__
#define IS_IDENTIFIER_HEAD(c) ((c=='_')||('a'<=c && c<='z')||('A'<=c&&c<='Z'))
#define IS_IDENTIFIER_BODY(c) ((c=='_')||('a'<=c && c<='z')||('A'<=c&&c<='Z')||('0'<=c&&c<='9'))
#define IS_IDENTIFIER(c) ((c=='_')||('a'<=c && c<='z')||('A'<=c&&c<='Z'))
#define IS_HEX_NUMBER(c) (('0'<=c&&c<='9')||('a'<=c&&c<='f')||('A'<=c && c<='F'))
#define IS_OCT_NUMEBR(c) ('0'<=c&&c<='7')
#define IS_DIGIT(c) ('0'<=c&&c<='9')
#define IS_STRING_HEAD(c) (c=='\''||c=='\"')
#define IS_STRING(c) (c=='\''||c=='\"'||c=='`')
// single operators have only one character
#define IS_SINGLE_OPRATOR(c) (c=='('||c==')'||c=='['||c==']'||c=='{'||c=='}'||c==','||c==';'||c=='|'||c==':'||\
c=='?'||c=='`'||c=='&'||c=='@'||c=='%'||c=='$'||c=='^'||c=='\\')
#define IS_SINGLE_OPERATOR(c) (c=='('||c==')'||c=='['||c==']'||c=='{'||c=='}'||c==','||c==';'||c=='|'||c==':'||\
c=='?'||c=='`'||c=='&'||c=='@'||c=='%'||c=='$'||c=='^'||c=='\\')
// calculation operators may have two chars, for example: += -= *= /= ~= != == >= <=
#define IS_CALC_OPERATOR(c) (c=='='||c=='+'||c=='-'||c=='*'||c=='!'||c=='/'||c=='<'||c=='>'||c=='~')
#define IS_NOTE_HEAD(c) (c=='#')
#define IS_NOTE(c) (c=='#')
#ifndef TOKEN_TABLE_SIZE
#define TOKEN_TABLE_SIZE 45
struct token_table
enum token_type
{
std::string str;
int tok_type;
}tok_tbl[TOKEN_TABLE_SIZE]=
{
{"for" ,tok_for },
{"forindex",tok_forindex },
{"foreach" ,tok_foreach },
{"while" ,tok_while },
{"var" ,tok_var },
{"func" ,tok_func },
{"break" ,tok_break },
{"continue",tok_continue },
{"return" ,tok_return },
{"if" ,tok_if },
{"elsif" ,tok_elsif },
{"else" ,tok_else },
{"nil" ,tok_nil },
{"(" ,tok_left_curve },
{")" ,tok_right_curve },
{"[" ,tok_left_bracket },
{"]" ,tok_right_bracket},
{"{" ,tok_left_brace },
{"}" ,tok_right_brace },
{";" ,tok_semi },
{"and" ,tok_and },
{"or" ,tok_or },
{"," ,tok_comma },
{"." ,tok_dot },
{"..." ,tok_ellipsis },
{"?" ,tok_quesmark },
{":" ,tok_colon },
{"+" ,tok_add },
{"-" ,tok_sub },
{"*" ,tok_mult },
{"/" ,tok_div },
{"~" ,tok_link },
{"!" ,tok_not },
{"=" ,tok_equal },
{"+=" ,tok_add_equal },
{"-=" ,tok_sub_equal },
{"*=" ,tok_mult_equal },
{"/=" ,tok_div_equal },
{"~=" ,tok_link_equal },
{"==" ,tok_cmp_equal },
{"!=" ,tok_cmp_not_equal},
{"<" ,tok_less_than },
{">" ,tok_greater_than },
{"<=" ,tok_less_equal },
{">=" ,tok_greater_equal},
tok_null=0,
tok_num,tok_str,tok_id,
tok_for,tok_forindex,tok_foreach,tok_while,
tok_var,tok_func,tok_break,tok_continue,
tok_ret,tok_if,tok_elsif,tok_else,tok_nil,
tok_lcurve,tok_rcurve,
tok_lbracket,tok_rbracket,
tok_lbrace,tok_rbrace,
tok_semi,tok_and,tok_or,tok_comma,tok_dot,tok_ellipsis,tok_quesmark,
tok_colon,tok_add,tok_sub,tok_mult,tok_div,tok_link,tok_not,
tok_eq,
tok_addeq,tok_subeq,tok_multeq,tok_diveq,tok_lnkeq,
tok_cmpeq,tok_neq,tok_less,tok_leq,tok_grt,tok_geq,
tok_eof
};
struct
{
const char* str;
const int tok_type;
}token_table[]=
{
{"for" ,tok_for },
{"forindex",tok_forindex },
{"foreach" ,tok_foreach },
{"while" ,tok_while },
{"var" ,tok_var },
{"func" ,tok_func },
{"break" ,tok_break },
{"continue",tok_continue },
{"return" ,tok_ret },
{"if" ,tok_if },
{"elsif" ,tok_elsif },
{"else" ,tok_else },
{"nil" ,tok_nil },
{"(" ,tok_lcurve },
{")" ,tok_rcurve },
{"[" ,tok_lbracket },
{"]" ,tok_rbracket },
{"{" ,tok_lbrace },
{"}" ,tok_rbrace },
{";" ,tok_semi },
{"and" ,tok_and },
{"or" ,tok_or },
{"," ,tok_comma },
{"." ,tok_dot },
{"..." ,tok_ellipsis },
{"?" ,tok_quesmark },
{":" ,tok_colon },
{"+" ,tok_add },
{"-" ,tok_sub },
{"*" ,tok_mult },
{"/" ,tok_div },
{"~" ,tok_link },
{"!" ,tok_not },
{"=" ,tok_eq },
{"+=" ,tok_addeq },
{"-=" ,tok_subeq },
{"*=" ,tok_multeq },
{"/=" ,tok_diveq },
{"~=" ,tok_lnkeq },
{"==" ,tok_cmpeq },
{"!=" ,tok_neq },
{"<" ,tok_less },
{"<=" ,tok_leq },
{">" ,tok_grt },
{">=" ,tok_geq },
{nullptr ,-1 }
};
#endif
struct token
{
int line;
int type;
std::string str;
token(int l=0,int t=tok_null,std::string s=""){line=l;type=t;str=s;}
};
class nasal_lexer
{
private:
int error;
int res_size;
int line;
int ptr;
std::string line_code;
std::string res;
std::vector<token> token_list;
std::string identifier_gen(std::vector<char>&,int&,int&);
void generate_number_error(int,std::string);
std::string number_gen(std::vector<char>&,int&,int&);
std::string string_gen(std::vector<char>&,int&,int&);
int get_tok_type(const std::string&);
void die(const char*);
std::string id_gen();
std::string num_gen();
std::string str_gen();
public:
void clear();
void scanner(std::vector<char>&);
void openfile(const 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::clear()
void nasal_lexer::openfile(const std::string& filename)
{
token_list.clear();
error=0;
res.clear();
std::ifstream fin(filename,std::ios::binary);
if(fin.fail())
{
++error;
std::cout<<"[lexer] cannot open file <"<<filename<<">.\n";
return;
}
while(!fin.eof())
{
char c=fin.get();
if(fin.eof())
break;
res+=c;
}
return;
}
std::string nasal_lexer::identifier_gen(std::vector<char>& res,int& ptr,int& line)
int nasal_lexer::get_tok_type(const std::string& tk_str)
{
int res_size=res.size();
std::string token_str="";
while(ptr<res_size && IS_IDENTIFIER_BODY(res[ptr]))
token_str+=res[ptr++];
return token_str;
// after running this process, ptr will point to the next token's beginning character
for(int i=0;token_table[i].str;++i)
if(tk_str==token_table[i].str)
return token_table[i].tok_type;
return tok_null;
}
void nasal_lexer::generate_number_error(int line,std::string token_str)
void nasal_lexer::die(const char* error_info)
{
++error;
std::cout<<">> [lexer] line "<<line<<": \""<<token_str<<"\" is not a correct number.\n";
return;
}
std::string nasal_lexer::number_gen(std::vector<char>& res,int& ptr,int& line)
{
int res_size=res.size();
bool scientific_notation=false;// numbers like 1e8 are scientific_notation
std::string token_str="";
// generate hex number
if(res[ptr]=='0' && ptr+1<res_size && res[ptr+1]=='x')
{
token_str="0x";
ptr+=2;
while(ptr<res_size && IS_HEX_NUMBER(res[ptr]))
token_str+=res[ptr++];
if(token_str=="0x")
{
generate_number_error(line,token_str);
return "0";
}
return token_str;
}
// generate oct number
else if(res[ptr]=='0' && ptr+1<res_size && res[ptr+1]=='o')
{
token_str="0o";
ptr+=2;
while(ptr<res_size && IS_OCT_NUMEBR(res[ptr]))
token_str+=res[ptr++];
if(token_str=="0o")
{
generate_number_error(line,token_str);
return "0";
}
return token_str;
}
// generate dec number
// dec number -> 0|[1~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
if(ptr<res_size && res[ptr]=='0')
token_str+=res[ptr++];
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)
{
generate_number_error(line,token_str);
return "0";
}
while(ptr<res_size && IS_DIGIT(res[ptr]))
token_str+=res[ptr++];
// "xxxx." is not a correct number
if(token_str.back()=='.')
{
generate_number_error(line,token_str);
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)
{
generate_number_error(line,token_str);
return "0";
}
if(ptr<res_size && (res[ptr]=='-' || res[ptr]=='+'))
token_str+=res[ptr++];
if(ptr>=res_size)
{
generate_number_error(line,token_str);
return "0";
}
if(ptr<res_size && res[ptr]=='0')
token_str+=res[ptr++];
while(ptr<res_size && IS_DIGIT(res[ptr]))
token_str+=res[ptr++];
// "xxxe(-|+)" is not a correct number
if(token_str.back()=='e' || token_str.back()=='E' || token_str.back()=='-' || token_str.back()=='+')
{
generate_number_error(line,token_str);
return "0";
}
}
return token_str;
++error;
std::cout<<"[lexer] line "<<line<<" column "<<line_code.length()<<": \n"<<line_code<<"\n";
for(auto i:line_code)
std::cout<<(i=='\t'?'\t':' ');
std::cout<<"^"<<error_info<<'\n';
return;
}
std::string nasal_lexer::string_gen(std::vector<char>& res,int& ptr,int& line)
std::string nasal_lexer::id_gen()
{
int res_size=res.size();
std::string token_str="";
char str_begin=res[ptr++];
if(ptr>=res_size) return token_str;
while(ptr<res_size && res[ptr]!=str_begin)
{
if(res[ptr]=='\n') ++line;
if(res[ptr]=='\\' && ptr+1<res.size())
{
++ptr;
switch(res[ptr])
{
case 'a':token_str.push_back('\a');break;
case 'b':token_str.push_back('\b');break;
case 'f':token_str.push_back('\f');break;
case 'n':token_str.push_back('\n');break;
case 'r':token_str.push_back('\r');break;
case 't':token_str.push_back('\t');break;
case 'v':token_str.push_back('\v');break;
case '?':token_str.push_back('\?');break;
case '0':token_str.push_back('\0');break;
case '\\':token_str.push_back('\\');break;
case '\'':token_str.push_back('\'');break;
case '\"':token_str.push_back('\"');break;
default: token_str.push_back(res[ptr]);break;
}
}
else
token_str+=res[ptr];
++ptr;
}
// check if this string ends with a " or '
if(ptr>=res_size)
{
++error;
std::cout<<">> [lexer] line "<<line<<": get EOF when generating string.\n";
}
++ptr;
return token_str;
std::string token_str="";
while(ptr<res_size && (IS_IDENTIFIER(res[ptr])||IS_DIGIT(res[ptr])))
token_str+=res[ptr++];
line_code+=token_str;
return token_str;
// after running this process, ptr will point to the next token's beginning character
}
void nasal_lexer::scanner(std::vector<char>& res)
std::string nasal_lexer::num_gen()
{
// generate hex number
if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='x')
{
std::string token_str="0x";
ptr+=2;
while(ptr<res_size && IS_HEX_NUMBER(res[ptr]))
token_str+=res[ptr++];
line_code+=token_str;
if(token_str.length()<3)// "0x"
die("incorrect number.");
return token_str;
}
// generate oct number
else if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='o')
{
std::string token_str="0o";
ptr+=2;
while(ptr<res_size && IS_OCT_NUMEBR(res[ptr]))
token_str+=res[ptr++];
line_code+=token_str;
if(token_str.length()<3)// "0o"
die("incorrect number.");
return token_str;
}
// generate dec number
// dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
std::string token_str="";
while(ptr<res_size && IS_DIGIT(res[ptr]))
token_str+=res[ptr++];
if(ptr<res_size && res[ptr]=='.')
{
token_str+=res[ptr++];
while(ptr<res_size && IS_DIGIT(res[ptr]))
token_str+=res[ptr++];
// "xxxx." is not a correct number
if(token_str.back()=='.')
{
line_code+=token_str;
die("incorrect number.");
return "0";
}
}
if(ptr<res_size && (res[ptr]=='e' || res[ptr]=='E'))
{
token_str+=res[ptr++];
if(ptr<res_size && (res[ptr]=='-' || res[ptr]=='+'))
token_str+=res[ptr++];
while(ptr<res_size && IS_DIGIT(res[ptr]))
token_str+=res[ptr++];
// "xxxe(-|+)" is not a correct number
if(token_str.back()=='e' || token_str.back()=='E' || token_str.back()=='-' || token_str.back()=='+')
{
line_code+=token_str;
die("incorrect number.");
return "0";
}
}
line_code+=token_str;
return token_str;
}
std::string nasal_lexer::str_gen()
{
std::string token_str="";
char str_begin=res[ptr];
line_code+=str_begin;
while(++ptr<res_size && res[ptr]!=str_begin)
{
line_code+=res[ptr];
if(res[ptr]=='\n')
{
line_code="";
++line;
}
if(res[ptr]=='\\' && ptr+1<res_size)
{
line_code+=res[++ptr];
switch(res[ptr])
{
case 'a': token_str.push_back('\a');break;
case 'b': token_str.push_back('\b');break;
case 'f': token_str.push_back('\f');break;
case 'n': token_str.push_back('\n');break;
case 'r': token_str.push_back('\r');break;
case 't': token_str.push_back('\t');break;
case 'v': token_str.push_back('\v');break;
case '?': token_str.push_back('\?');break;
case '0': token_str.push_back('\0');break;
case '\\':token_str.push_back('\\');break;
case '\'':token_str.push_back('\'');break;
case '\"':token_str.push_back('\"');break;
default: token_str.push_back(res[ptr]);break;
}
continue;
}
token_str+=res[ptr];
}
// check if this string ends with a " or '
if(ptr++>=res_size)
die("get EOF when generating string.");
if(str_begin=='`' && token_str.length()!=1)
die("\'`\' is used for string that includes one character.");
return token_str;
}
void nasal_lexer::scanner()
{
error=0;
token_list.clear();
int line=1,ptr=0,res_size=res.size();
std::string token_str;
while(ptr<res_size)
{
while(ptr<res_size && (res[ptr]==' ' || res[ptr]=='\n' || res[ptr]=='\t' || res[ptr]=='\r' || res[ptr]<0))
{
// these characters will be ignored, and '\n' will cause ++line
if(res[ptr]=='\n') ++line;
++ptr;
}
if(ptr>=res_size) break;
if(IS_IDENTIFIER_HEAD(res[ptr]))
{
token_str=identifier_gen(res,ptr,line);
token new_token;
new_token.line=line;
new_token.str=token_str;
new_token.type=0;
for(int i=0;i<TOKEN_TABLE_SIZE;++i)
if(token_str==tok_tbl[i].str)
{
new_token.type=tok_tbl[i].tok_type;
break;
}
if(!new_token.type)
new_token.type=tok_identifier;
token_list.push_back(new_token);
}
else if(IS_DIGIT(res[ptr]))
{
token_str=number_gen(res,ptr,line);
token new_token;
new_token.line=line;
new_token.str=token_str;
new_token.type=tok_number;
token_list.push_back(new_token);
}
else if(IS_STRING_HEAD(res[ptr]))
{
token_str=string_gen(res,ptr,line);
token new_token;
new_token.line=line;
new_token.type=tok_string;
new_token.str=token_str;
token_list.push_back(new_token);
}
else if(IS_SINGLE_OPRATOR(res[ptr]))
{
token_str="";
token_str+=res[ptr];
token new_token;
new_token.line=line;
new_token.str=token_str;
for(int i=0;i<TOKEN_TABLE_SIZE;++i)
if(token_str==tok_tbl[i].str)
{
new_token.type=tok_tbl[i].tok_type;
break;
}
token_list.push_back(new_token);
++ptr;
}
line=1;
ptr=0;
line_code="";
res_size=res.size();
std::string token_str;
while(ptr<res_size)
{
while(ptr<res_size && (res[ptr]==' ' || res[ptr]=='\n' || res[ptr]=='\t' || res[ptr]=='\r' || res[ptr]<0))
{
// these characters will be ignored, and '\n' will cause ++line
line_code+=res[ptr];
if(res[ptr++]=='\n')
{
++line;
line_code="";
}
}
if(ptr>=res_size) break;
if(IS_IDENTIFIER(res[ptr]))
{
token_str=id_gen();
token_list.push_back({line,get_tok_type(token_str),token_str});
if(!token_list.back().type)
token_list.back().type=tok_id;
}
else if(IS_DIGIT(res[ptr]))
token_list.push_back({line,tok_num,num_gen()});
else if(IS_STRING(res[ptr]))
token_list.push_back({line,tok_str,str_gen()});
else if(IS_SINGLE_OPERATOR(res[ptr]))
{
token_str=res[ptr];
line_code+=res[ptr];
int type=get_tok_type(token_str);
if(!type)
die("incorrect operator.");
token_list.push_back({line,type,token_str});
++ptr;
}
else if(res[ptr]=='.')
{
if(ptr+2<res_size && res[ptr+1]=='.' && res[ptr+2]=='.')
@@ -324,71 +327,36 @@ void nasal_lexer::scanner(std::vector<char>& res)
token_str=".";
++ptr;
}
token new_token;
new_token.line=line;
new_token.str=token_str;
for(int i=0;i<TOKEN_TABLE_SIZE;++i)
if(token_str==tok_tbl[i].str)
{
new_token.type=tok_tbl[i].tok_type;
break;
}
token_list.push_back(new_token);
line_code+=token_str;
token_list.push_back({line,get_tok_type(token_str),token_str});
}
else if(IS_CALC_OPERATOR(res[ptr]))
{
// get calculation operator
token_str="";
token_str+=res[ptr];
++ptr;
if(ptr<res.size() && res[ptr]=='=')
{
token_str+=res[ptr];
++ptr;
}
token new_token;
new_token.line=line;
new_token.str=token_str;
for(int i=0;i<TOKEN_TABLE_SIZE;++i)
if(token_str==tok_tbl[i].str)
{
new_token.type=tok_tbl[i].tok_type;
break;
}
token_list.push_back(new_token);
}
else if(IS_NOTE_HEAD(res[ptr]))
{
// avoid note
while(ptr<res_size && res[ptr]!='\n') ++ptr;
// after this process ptr will point to a '\n'
// don't ++ptr then the counter for line can work correctly
}
else
{
++error;
std::cout<<">> [lexer] line "<<line<<": unknown char "<<(int)res[ptr]<<'.'<<std::endl;
++ptr;
}
}
return;
else if(IS_CALC_OPERATOR(res[ptr]))
{
// get calculation operator
token_str=res[ptr++];
if(ptr<res_size && res[ptr]=='=')
token_str+=res[ptr++];
line_code+=token_str;
token_list.push_back({line,get_tok_type(token_str),token_str});
}
else if(IS_NOTE(res[ptr]))// avoid note, after this process ptr will point to a '\n', so next loop line counter+1
while(++ptr<res_size && res[ptr]!='\n');
else
{
line_code+=res[ptr++];
die("unknown character.");
}
}
token_list.push_back({line,tok_eof,""});
res.clear();
return;
}
void nasal_lexer::print_token()
{
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

@@ -1,258 +0,0 @@
#ifndef __NASAL_MISC_H__
#define __NASAL_MISC_H__
/*
check_numerable_string:
check if a string can be converted to a number
strings like these below is correct:
'0.00012'
'12314.234'
'1234'
'0xdeadbeef'
'0xDEADBEEF'
'0o71230'
'1e23'
'1E-123'
'1.34E10'
*/
inline bool check_hex_string(std::string str,int len)
{
for(int i=2;i<len;++i)
if(!(('0'<=str[i] && str[i]<='9') || ('a'<=str[i] && str[i]<='f') || ('A'<=str[i] && str[i]<='F')))
return false;
return true;
}
inline bool check_oct_string(std::string str,int len)
{
for(int i=2;i<len;++i)
if(str[i]<'0' || str[i]>'7')
return false;
return true;
}
inline bool check_dec_string(std::string str,int len)
{
int i=0;
// check integer part
while('0'<=str[i] && str[i]<='9' && i<len) ++i;
if(i==len) return true;
if(str[i]!='e' && str[i]!='E' && str[i]!='.') return false;
// check decimal part
if(str[i]=='.')
{
++i;
if(i==len) return false;
while('0'<=str[i] && str[i]<='9' && i<len) ++i;
}
if(i==len) return true;
if(str[i]!='e' && str[i]!='E') return false;
// check scientific notation
if(str[i]=='e' || str[i]=='E')
{
++i;
if(i==len) return false;
if(str[i]=='-' || str[i]=='+')
{
++i;
if(i==len) return false;
}
for(;i<len;++i)
if(str[i]<'0' || str[i]>'9')
return false;
}
return true;
}
bool check_numerable_string(std::string str)
{
int len=str.length();
if(!len) return false;
if(str[0]=='-' || str[0]=='+')
{
if(len==1) return false;
std::string tmp="";
for(int i=1;i<len;++i)
tmp+=str[i];
str=tmp;
--len;
}
if(len>2 && str[0]=='0' && str[1]=='x')
return check_hex_string(str,len);
else if(len>2 && str[0]=='0' && str[1]=='o')
return check_oct_string(str,len);
else if('0'<=str[0] && str[0]<='9')
return check_dec_string(str,len);
return false;
}
/*
trans_string_to_number:
convert string to number
*/
inline double hex_to_double(std::string str,int len)
{
double ret=0,num_pow=1;
for(int i=len-1;i>1;--i)
{
if('0'<=str[i] && str[i]<='9')
ret+=num_pow*(str[i]-'0');
else if('a'<=str[i] && str[i]<='f')
ret+=num_pow*(str[i]-'a'+10);
else if('A'<=str[i] && str[i]<='F')
ret+=num_pow*(str[i]-'A'+10);
num_pow*=16;
}
return ret;
}
inline double oct_to_double(std::string str,int len)
{
double ret=0,num_pow=1;
for(int i=len-1;i>1;--i)
{
ret+=num_pow*(str[i]-'0');
num_pow*=8;
}
return ret;
}
inline double dec_to_double(std::string str,int len)
{
double ret=0;
int i=0;
while('0'<=str[i] && str[i]<='9' && i<len)
{
ret=ret*10+(str[i]-'0');
++i;
}
if(i==len) return ret;
if(str[i]=='.')
{
++i;
double num_pow=0.1;
while('0'<=str[i] && str[i]<='9' && i<len)
{
ret+=num_pow*(str[i]-'0');
num_pow*=0.1;
++i;
}
}
if(i==len) return ret;
if(str[i]=='e' || str[i]=='E')
{
++i;
bool is_negative=(str[i]=='-');
if(str[i]=='-' || str[i]=='+') ++i;
double num_pow=0;
for(;i<len;++i) num_pow=num_pow*10+(str[i]-'0');
num_pow=std::pow(10,is_negative?-num_pow:num_pow);
ret*=num_pow;
}
return ret;
}
double trans_string_to_number(std::string str)
{
bool is_negative=false;
int len=str.length();
double ret_num=0;
if(!len) return 0;
if(str[0]=='-' || str[0]=='+')
{
is_negative=(str[0]=='-');
std::string tmp="";
for(int i=1;i<len;++i)
tmp.push_back(str[i]);
str=tmp;
--len;
}
if(len>2 && str[0]=='0' && str[1]=='x')
ret_num=hex_to_double(str,len);
else if(len>2 && str[0]=='0' && str[1]=='o')
ret_num=oct_to_double(str,len);
else if('0'<=str[0] && str[0]<='9')
ret_num=dec_to_double(str,len);
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 trans_num_string="";
if(number<0)
{
trans_num_string+='-';
number=-number;
}
if(number==0)
return "0";
double integer_bit=1;
while(number>=integer_bit)
integer_bit*=10;
integer_bit/=10;
if(integer_bit==0.1)
trans_num_string+='0';
while(integer_bit!=0.1)
{
trans_num_string+=(char)('0'+(int(number/integer_bit)));
number-=(double)(int(number/integer_bit))*integer_bit;
integer_bit/=10;
}
if(number!=0)
trans_num_string+='.';
while(number!=0)
{
trans_num_string+=(char)('0'+int(number*10));
number*=10;
number-=(double)(int(number));
}
return trans_num_string;
}
/*
prt_hex:
transform int to hex format and print it out (std::cout)
*/
void prt_hex(const int ptr)
{
char hex[9];
hex[8]=0;
int tmp_plc=ptr;
if(tmp_plc<0)
{
tmp_plc=-tmp_plc;
std::cout<<"-0x";
}
else
std::cout<<"0x";
/*
int: 00000000 00000000 00000000 00000000
int: 0x00 00 00 00
example:
a=0x13 57 9b df
a=00010011 01010111 10011011 11011111
a & 0x00 00 00 0f:
00010011 01010111 10011011 11011111
and 00000000 00000000 00000000 00001111
---------------------------------------
00000000 00000000 00000000 00001111
a>>=4:
00000001 00110101 01111001 10111101
a & 0x00 00 00 0f
00000001 00110101 01111001 10111101
and 00000000 00000000 00000000 00001111
---------------------------------------
00000000 00000000 00000000 00001101
then convert 0~15 to 0~9 a~f
*/
for(int j=7;j>=0;--j)
{
int tmp=(tmp_plc & 0x0000000f);
hex[j]=tmp<10? (char)('0'+tmp):(char)('a'+tmp-10);
tmp_plc>>=4;
}
std::cout<<hex;
return;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,75 +0,0 @@
#ifndef __NASAL_RESOURCE_H__
#define __NASAL_RESOURCE_H__
class nasal_resource
{
private:
std::vector<char> res;
public:
bool input_file(std::string);
void clear();
void print_file();
std::vector<char>& get_file();
};
bool nasal_resource::input_file(std::string filename)
{
res.clear();
std::ifstream fin(filename,std::ios::binary);
if(fin.fail())
{
std::cout<<">> [resource] cannot open file \""<<filename<<"\".\n";
fin.close();
return false;
}
while(!fin.eof())
{
char c=fin.get();
if(fin.eof())
break;
res.push_back(c);
}
fin.close();
return true;
}
void nasal_resource::clear()
{
res.clear();
return;
}
void nasal_resource::print_file()
{
int size=res.size(),line=1;
std::cout<<line<<"\t";
std::string unicode_str="";
for(int i=0;i<size;++i)
{
if(res[i]>=0 && unicode_str.length())
{
std::cout<<unicode_str;
unicode_str="";
}
if(32<=res[i])
std::cout<<res[i];
else if(res[i]<0)
unicode_str+=res[i];
else
std::cout<<" ";
if(res[i]=='\n')
{
++line;
std::cout<<std::endl<<line<<"\t";
}
}
std::cout<<(unicode_str.length()?unicode_str:"")<<'\n';
return;
}
std::vector<char>& nasal_resource::get_file()
{
return res;
}
#endif

File diff suppressed because it is too large Load Diff

1040
nasal_vm.h Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

157
props.nas Normal file
View File

@@ -0,0 +1,157 @@
import("lib.nas");
var props=
{
globals:nil,
Node:nil,
getNode:func(path,index)
{
path=split('/',path);
var tmp=me.globals;
var path_size=size(path);
for(var i=0;i<path_size-1;i+=1)
tmp=tmp.val[path[i]];
if(path_size>0)
{
if(contains(tmp.val,path[i]~'['~index~']'))
return tmp.val[path[i]~'['~index~']'];
else
return tmp.val[path[i]];
}
return tmp;
}
};
props.Node=
{
new:func(values=nil)
{
var result={
parents:[props.Node],
val:{},
type:'GHOST',
parent:nil
};
if(typeof(values)=="hash")
result.val=values;
return result;
},
addChild:func(name)
{
if(!contains(me.val,name))
{
me.val[name]=props.Node.new();
me.val[name].parent=me;
return 1;
}
return 0;
},
addChildren:func(name,cnt=0)
{
for(var i=0;i<cnt;i+=1)
{
var label=name~'['~i~']';
me.val[label]=props.Node.new();
me.val[label].parent=me;
}
return;
},
setValue:func(path,val)
{
path=split('/',path);
var tmp=me;
foreach(var label;path)
tmp=tmp.val[label];
tmp.val=val;
if(typeof(val)=='str')
{
if(val=='true' or val=='false')
tmp.type='BOOL';
else
tmp.type='STRING';
}
elsif(typeof(val)=='num')
tmp.type='DOUBLE';
return;
},
setIntValue:func(num)
{
me.val=num;
me.type='INT';
return;
},
setBoolValue:func(state)
{
me.val=state;
me.type='BOOL';
return;
},
setDoubleValue:func(num)
{
me.val=num;
me.type='DOUBLE';
return;
},
getValue:func(){return me.val;},
getName:func()
{
var val=me.parent.val;
var key=keys(val);
foreach(var k;key)
if(val[k]==me)
return k;
return '';
},
getParent:func()
{
return me.parent;
},
getPath:func()
{
if(me.parent==nil) return '';
return me.parent.getPath()~'/'~me.getName();
},
equals:func(node){return me==node;},
debug:func(s='')
{
if(typeof(me.val)=='hash')
{
var key=keys(me.val);
if(!size(key))
{
println("{}");
return;
}
println('{');
foreach(var k;key)
{
print(s~' ',k,':');
me.val[k].debug(s~' ');
}
println(s,'}');
}
else
println(me.val,' (',me.type,')');
return;
}
};
props.globals=props.Node.new();
var c=['aircraft','ai','models','position','orientation','controls','sim'];
foreach(var i;c)
props.getNode('/',1).addChild(i);
props.getNode('/ai',1).addChildren('ai',4);
props.getNode('/aircraft',1).setValue('/','IDG MD-11');
for(var i=0;i<4;i+=1)
props.getNode('/ai/ai['~i~']',1).setBoolValue('true');
props.getNode('/models',1).addChildren('building',4);
for(var i=0;i<4;i+=1)
props.getNode('/models/building['~i~']',1).setIntValue(i);
props.getNode('/',1).addChild('test');
props.getNode('/test',1).addChildren('in',4);
props.getNode('/test/in',0).setValue('/','true');
props.getNode('/test/in',1).setValue('/','false');
props.getNode('/test/in',2).setValue('/','welcome aboard,need help? use help->tutorial');
props.getNode('/test/in',3).setValue('/',2147483648);
props.globals.debug();
println(props.getNode('/test/in',3).getPath());

162
stl/lib.nas Normal file
View File

@@ -0,0 +1,162 @@
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);},
inf: 1/0,
nan: 0/0,
isnan: func(x) {return __builtin_isnan(x); }
};
var D2R=math.pi/180;
var FPS2KT=0.5925;
var FT2M=0.3048;
var GAL2L=3.7854;
var IN2M=0.0254;
var KG2LB=2.2046;
var KT2FPS=1.6878;
var KT2MPS=0.5144;
var L2GAL=0.2642;
var LB2KG=0.4536;
var M2FT=3.2808;
var M2IN=39.3701;
var M2NM=0.00054;
var MPS2KT=1.9438;
var NM2M=1852;
var R2D=180/math.pi;

67
stl/list.nas Normal file
View File

@@ -0,0 +1,67 @@
# lib list.nas
# valkmjolnir 2021/3/31
var list=func()
{
var (begin,end)=(nil,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=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=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,end)=(nil,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;
}
};
}

28
stl/result.nas Normal file
View File

@@ -0,0 +1,28 @@
import("lib.nas");
var ResultTrait={
Ok:func(val){
me.ok=val;
me.flag=0;
return me;
},
Err:func(info){
me.err=info;
me.flag=1;
return me;
},
unwrap:func(){
if(me.flag)
die("error: "~me.err);
return me.ok;
}
};
var Result=func(){
return{
ok:nil,
err:"",
flag:1,
parents:[ResultTrait]
};
};

20
stl/sort.nas Normal file
View File

@@ -0,0 +1,20 @@
# 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,R,tmp)=(left,right,vec[left]);
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)
(vec[left],vec[right])=(vec[right],vec[left]);
}
(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,335 +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;
}
# var (a,b,c)=[1,2,3];
# (a,b,c)=(b,c,a);
# print(a,b,c);
main();

View File

@@ -4,7 +4,7 @@ var char_ttf=[
[" ████╗"," ██╔██║"," ██╔╝██║"," ███████║","██╔═══██║","╚═╝ ╚═╝"],
["██████╗ ","██╔══██╗","██████╔╝","██╔══██╗","██████╔╝","╚═════╝ "],
[" ██████╗","██╔════╝","██║ ","██║ ","╚██████╗"," ╚═════╝"],
["██████╗ ","██╔══██╗","██║ ██║","██║ ██║","██████╔╝","╚═════╝ "],
["██████╗ ","██╔══██╗","██║ ██║","██║ ██║","██████╔╝","╚═════╝ "],
["███████╗","██╔════╝","█████╗ ","██╔══╝ ","███████╗","╚══════╝"],
["███████╗","██╔════╝","█████╗ ","██╔══╝ ","██║ ","╚═╝ "],
[" █████╗ ","██╔═══╝ ","██║ ██╗ ","██║ ╚██╗","╚█████╔╝"," ╚════╝ "],
@@ -45,7 +45,7 @@ var trans_ttf=func(string)
str[j]~=char_ttf[0][j];
}
foreach(var i;str)
print(i);
println(i);
return;
}
var curve1=func()
@@ -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;
@@ -100,7 +87,7 @@ var curve4=func()
{
forindex(var i;s)
{
print(s[i]);
println(s[i]);
s[i]='';
}
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]);
@@ -123,13 +110,13 @@ var curve5=func()
var s="";
for(var i=0;i<size(arr);i+=1)
s~=shadow[arr[i]];
print(s);
println(s);
}
return;
}
trans_ttf("just for test");
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.");
}
}
}

243
test/bf.nas Normal file
View File

@@ -0,0 +1,243 @@
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],
func ptr+=inum[pc],
func if(paper[ptr])pc=inum[pc],
func if(!paper[ptr])pc=inum[pc],
func paper[ptr]=input()[0],
func print(chr(paper[ptr]))
];
var bf=func(program)
{
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;
elsif(chr(program[i])!='\n')
{
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;
elsif(chr(program[i])!='\n')
{
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 ]");
return;
}
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;
elsif(chr(program[i])!='\n')
{
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;
elsif(chr(program[i])!='\n')
{
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);

60
test/bfs.nas Normal file
View File

@@ -0,0 +1,60 @@
import("stl/lib.nas");
import("stl/queue.nas");
rand(time(0));
var pixel=[' ','#','.','*'];
var map=[];
for(var i=0;i<10;i+=1)
{
append(map,[]);
for(var j=0;j<10;j+=1)
append(map[i],(rand()>0.7));
}
var prt=func()
{
var s="";
for(var i=0;i<10;i+=1)
{
for(var j=0;j<10;j+=1)
s~=pixel[map[i][j]];
s~='\n';
}
s~='----------\n';
print(s);
}
var bfs=func(begin,end)
{
var move=[[1,0],[0,1],[-1,0],[0,-1]];
var que=queue();
que.push(begin);
map[begin[0]][begin[1]]=2;
while(!que.empty())
{
var vertex=que.front();
que.pop();
foreach(var i;move)
{
var x=vertex[0]+i[0];
var y=vertex[1]+i[1];
if(x==end[0] and y==end[1])
{
map[x][y]=3;
prt();
return;
}
if(0<=x and x<10 and 0<=y and y<10 and map[x][y]==0)
{
que.push([x,y]);
map[x][y]=2;
}
}
prt();
}
print("cannot reach.\n");
return;
}
bfs([0,0],[9,9]);

1
test/bigloop.nas Normal file
View File

@@ -0,0 +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,8 @@ var backward=func(x)
return;
}
var cnt=0;
var error=1e8;
while(error>0.01)
var (cnt,error)=(0,100);
while(error>0.0005)
{
error=0;
for(var i=0;i<4;i+=1)
@@ -136,18 +124,10 @@ while(error>0.01)
backward(i);
}
cnt+=1;
print('epoch ',cnt,':',error);
}
print('\afinished.');
while(1)
print('finished after ',cnt,' epoch.\n');
foreach(var v;training_set)
{
var vec=[];
var command=input();
if(command=="exit")break;
append(vec,num(command));
command=input();
if(command=="exit")break;
append(vec,num(command));
run(vec);
print(output[0].out);
run(v);
print(v,': ',output[0].out,'\n');
}

32
test/calc.nas Normal file
View File

@@ -0,0 +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 (bytes,line,semi)=(0,0,0);
forindex(var i;filename)
{
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: | ',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];

29
test/choice.nas Normal file
View File

@@ -0,0 +1,29 @@
import("lib.nas");
var condition_true=1;
var condition_false=0;
if(condition_true)
{
var a=1;
}
else if(!condition_false)
{
var b=1;
}
elsif(!condition_true and condition_false)
{
print("impossible");
}
else
{
var c=1;
var d=1;
}
if(condition_true)
var a=1;
else if(!condition_false)
var b=1;
elsif(!condition_true and condition_false)
print("impossible");
else
var c=1;

View File

@@ -1,38 +0,0 @@
if(this_token.type==__if)
{
parse.push(this_token);
return;
}
elsif(this_token.type==__elsif)
{
parse.push(this_token);
return;
}
else if(this_token.type!=__else)
{
exit(0);
}
elsif(this_token.type==__elsif)
{
parse.push(this_token);
return;
}
elsif(this_token.type==__elsif)
{
parse.push(this_token);
return;
}
else if(this==(1+2+3*1))
{
return nil;
}
else
{
parse.push(this_token);
return;
}
if(!id)
{
exit(0);
}

68
test/class.nas Normal file
View File

@@ -0,0 +1,68 @@
import("lib.nas");
var student=func(name,age)
{
var (n,a)=(name,age);
return {
print_info:func println(n,' ',a),
set_age: func(age) a=age,
get_age: func return a,
set_name: func(name) n=name,
get_name: func return n
};
}
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());
# flightgear nasal-console cannot use this kind of object initializing
var m=func(){
var (_1,_2)=(0,1);
return {
a:func(){
print(_1,' ',_2,'\n');
},
b:func(x){
_1=x;
},
c:func(x){
_2=x;
},
d:func(x){
return func{
print(_1,' ',_2,' ',x,'\n');
};
},
g:func(x){
var y=x;
return func{
print(_1,' ',_2,' ',x,' ',y,'\n');
}
},
h:func(){
return func(x){
_1=x;
}
}
};
}();
m.a(); # 0 1
m.b(2048);
m.c(1024);
var a=m.d(-1);
var b=m.g(1);
a(); # 2048 1024 -1
b(); # 2048 1024 1 1
m.h()(2147483647);
m.a();
# flightgear-nasal-console: 2147483647 1024
# nasal-interpreter 2048 1024

39
test/exception.nas Normal file
View File

@@ -0,0 +1,39 @@
import("lib.nas");
var ResultTrait={
Ok:func(val){
me.ok=val;
me.flag=0;
return me;
},
Err:func(info){
me.err=info;
me.flag=1;
return me;
},
unwrap:func(){
if(me.flag)
die("error: "~me.err);
return me.ok;
}
};
var Result=func(){
return{
ok:nil,
err:"",
flag:1,
parents:[ResultTrait]
};
};
var a=func(){
return Result().Ok("hello world");
}
var b=func(){
return Result().Err("unknown");
}
println(a().unwrap());
b().unwrap();

9
test/fib.nas Normal file
View File

@@ -0,0 +1,9 @@
import("lib.nas");
var fib=func(x)
{
if(x<2) return x;
return fib(x-1)+fib(x-2);
}
for(var i=0;i<31;i+=1)
print(fib(i),'\n');

View File

@@ -1,6 +0,0 @@
print("hello world!\n");
print("This is the first program for nasal--\n");
var cnt=0;
for(var i=1;i<101;i+=1)
cnt+=i;
print(cnt);

View File

@@ -1,10 +0,0 @@
var f=func(n,m,dynamic...)
{
print(n+m," ",dynamic);
n=dynamic;
m=dynamic;
n+=m;
return dynamic;
};
print(f(1,1,0,0,0,0,0,(1+2+3+(1+2+3+4)))[3]);
function([0,1,2,3],{str:"str"});

91
test/hexdump.nas Normal file
View File

@@ -0,0 +1,91 @@
# hexdump.nas by ValKmjolnir
# 2021/8/13
import("lib.nas");
# init
var hex_num=[
'0','1','2','3',
'4','5','6','7',
'8','9','a','b',
'c','d','e','f'
];
var hex=[];
foreach(var i;hex_num)
foreach(var j;hex_num)
append(hex,i~j);
# read file
var s=func()
{
var filename=[
"nasal.h",
"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",
];
var ret="";
foreach(var elem;filename)
ret~=io.fin(elem);
return ret;
}();
# used to change line and control the spaces
var cnt=0;
# used to print hex index
var hex_index=[0,0,0,0];
# print binary in text format
var textprint=func(index)
{
print(' |');
for(var i=index-cnt;i<index;i+=1)
print((0<=s[i] and s[i]<32)?'.':chr(s[i]));
for(var i=cnt;i<16;i+=1)
print('.');
print('|\n');
}
# print index
var indexprint=func(index)
{
forindex(var i;hex_index)
{
hex_index[i]=index-int(index/256)*256;
index=int(index/256);
}
for(var i=3;i>=0;i-=1)
print(hex[hex_index[i]]);
print(' ');
return;
}
# main
func()
{
indexprint(0);
for(var i=0;i<size(s);i+=1)
{
if(cnt==16){
textprint(i);
cnt=0;
indexprint(i);
}elsif(cnt==8){
print(' ');
}
cnt+=1;
print(hex[s[i]],' ');
}
for(var l=cnt;l<16;l+=1)
print(' ');
if(cnt<=8)
print(' ');
textprint(i);
}();

196
test/json.nas Normal file
View File

@@ -0,0 +1,196 @@
#lib json.nas
import("lib.nas");
var json={
text:'',
line:1,
size:0,
ptr:0,
get:nil,
check:nil,
next:nil,
match:nil,
hash_gen:nil,
vec_gen:nil,
member:nil,
parse:nil,
token:{content:'',type:''},
content:[],
};
json.get=func(filename)
{
me.line=1;
me.ptr=0;
me.content=[];
me.token={content:'',type:''};
me.text=io.fin(filename);
if(!size(me.text))
die("cannot open "~filename);
me.text=split('',me.text);
me.size=size(me.text);
return;
}
json.check=func(ptr)
{
var str=me.text[ptr];
return (str=='{' or str=='}' or str=='[' or str==']' or str==',' or str==':' or str=='\"' or ('0'<=str and str<='9'));
}
json.next=func()
{
while(me.ptr<me.size and !json.check(me.ptr))
{
if(me.text[me.ptr]=='\n')
me.line+=1;
me.ptr+=1;
}
if(me.ptr>=me.size)
{
me.token.content="";
me.token.type="eof";
return;
}
if(me.text[me.ptr]=='{')
{
me.token.content='{';
me.token.type="left brace";
}
elsif(me.text[me.ptr]=='}')
{
me.token.content='}';
me.token.type="right brace";
}
elsif(me.text[me.ptr]=='[')
{
me.token.content='[';
me.token.type="left bracket";
}
elsif(me.text[me.ptr]==']')
{
me.token.content=']';
me.token.type="right bracket";
}
elsif(me.text[me.ptr]==',')
{
me.token.content=',';
me.token.type="comma";
}
elsif(me.text[me.ptr]==':')
{
me.token.content=':';
me.token.type="colon";
}
elsif(me.text[me.ptr]=='\"')
{
var s="";
me.ptr+=1;
while(me.ptr<me.size and me.text[me.ptr]!='\"')
{
s~=me.text[me.ptr];
me.ptr+=1;
}
me.token.content=s;
me.token.type="string";
}
elsif('0'<=me.text[me.ptr] and me.text[me.ptr]<='9')
{
var s=me.text[me.ptr];
me.ptr+=1;
while(me.ptr<me.size and (('0'<=me.text[me.ptr] and me.text[me.ptr]<='9') or me.text[me.ptr]=='.'))
{
s~=me.text[me.ptr];
me.ptr+=1;
}
me.ptr-=1;
me.token.content=num(s);
me.token.type="number";
}
me.ptr+=1;
return;
}
json.match=func(type)
{
if(me.token.type!=type)
print("line ",me.line,": expect ",type," but get ",me.token.content,".");
me.next();
return;
}
json.hash_gen=func()
{
var hash={};
me.match("left brace");
me.member(hash);
while(me.token.type=="comma")
{
me.match("comma");
me.member(hash);
}
me.match("right brace");
return hash;
}
json.vec_gen=func()
{
var vec=[];
me.match("left bracket");
if(me.token.type=="left brace")
append(vec,me.hash_gen());
elsif(me.token.type=="left bracket")
append(vec,me.vec_gen());
elsif(me.token.type=="string" or me.token.type=="number")
{
append(vec,me.token.content);
me.next();
}
while(me.token.type=="comma")
{
me.match("comma");
if(me.token.type=="left brace")
append(vec,me.hash_gen());
elsif(me.token.type=="left bracket")
append(vec,me.vec_gen());
elsif(me.token.type=="string" or me.token.type=="number")
{
append(vec,me.token.content);
me.next();
}
}
me.match("right bracket");
return vec;
}
json.member=func(hash)
{
var name=me.token.content;
me.match("string");
me.match("colon");
if(me.token.type=="left brace")
hash[name]=me.hash_gen();
elsif(me.token.type=="left bracket")
hash[name]=me.vec_gen();
elsif(me.token.type=="string" or me.token.type=="number")
{
hash[name]=me.token.content;
me.next();
}
return;
}
json.parse=func()
{
me.content={};
me.next();
me.match("left brace");
me.member(me.content);
while(me.token.type=="comma")
{
me.match("comma");
me.member(me.content);
}
me.match("right brace");
return;
}

32
test/leetcode1319.nas Normal file
View File

@@ -0,0 +1,32 @@
import("lib.nas");
# union set
var n=4;
var input=[[0,1],[0,2],[1,2]];
var find_root=func(x,parent)
{
while(parent[x]!=nil)
x=parent[x];
return x;
}
var union_root=func(x,y,parent)
{
var x_root=find_root(x,parent);
var y_root=find_root(y,parent);
if(x_root==y_root) return 0;
else parent[x_root]=y_root;
return 1;
}
var makeConnect=func(n,connections)
{
if(size(connections)<n-1) return -1;
var cnt=n-1;
var parent=[];
setsize(parent,n);
foreach(var i;connections)
if(union_root(i[0],i[1],parent))
cnt-=1;
return cnt;
}
println(makeConnect(n,input));

193
test/lexer.nas Normal file
View File

@@ -0,0 +1,193 @@
import("lib.nas");
var lexer=func(file)
{
var (ptr,token)=(0,[]);
var s=io.fin(file);
var 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 nasal_lexer=lexer("test/lexer.nas");
nasal_lexer.main();
var info="";
foreach(var tok;nasal_lexer.get_token())
info~=tok~' ';
println(info);

62
test/life.nas Normal file
View File

@@ -0,0 +1,62 @@
import("lib.nas");
var map=nil;
var check=func(x,y)
{
if(x>14) x=0;
if(y>19) y=0;
return map[x][y];
}
var new_map=func()
{
var tmp=[];
setsize(tmp,15);
forindex(var i;tmp)
{
tmp[i]=[];
setsize(tmp[i],20);
}
return tmp;
}
var prt=func()
{
var s='';
foreach(var line;map)
{
foreach(var elem;line)
s~=elem~' ';
s~='\n';
}
system("cls");
print(s);
}
func()
{
rand(time(0));
map=new_map();
forindex(var i;map)
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<100;r+=1)
{
prt(map);
var tmp=new_map();
for(var i=0;i<15;i+=1)
for(var j=0;j<20;j+=1)
{
var cnt=0;
foreach(var k;calc)
cnt+=(check(i+k[0],j+k[1])=='O');
if(cnt==2) tmp[i][j]=map[i][j];
elsif(cnt==3) tmp[i][j]='O';
else tmp[i][j]=' ';
}
map=tmp;
}
return;
}();

View File

@@ -1,38 +1,31 @@
while(n==1 )
import("lib.nas");
for(;;)break;
for(;;)
{
i=i+1;
f(i);
print("str");
var a=1;
break;
}
for(var i=1;;)break;
for(var i=1;;i+=1)break;
for(var i=1;i<10;i+=1)print(i);
while(1)break;
var j=0;
while(j<10)
{
print(j);
j+=1;
}
while(n==1 and "str"==str)
forindex(var j;[0,1,2,3])print(j);
forindex(var j;[0,1,2,3])
{
print("str");
var a=j;
print(a*a);
}
i+=i1;
i+=i.i[0];
i=i.i[0].i(0);
var hash={
f:func {var e=1;return 0;},
};
for(var i=0;i<1024;i+=1)
foreach(var j;[0,1,2,3])print([0,1,2,3][j]);
foreach(var j;[0,1,2,3])
{
print(i);
var a=[0,1,2,3][j];
print(a*a-1);
}
for(var i=0;(2*512)>=i;i+=1)
{
print(i);
}
foreach(var i;[1+(1+1),2,3,4])
{
print(i);
}
forindex(var i=list;[1,2,3,4])
{
print(i[0]);
}
while(!id)
{
print("yes");
}

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,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);#//func(...){...}
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

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

40
test/prime.nas Normal file
View File

@@ -0,0 +1,40 @@
import("lib.nas");
var is_prime=func(x){
for(var i=2;i<x;i+=1)
if(x/i==int(x/i))
return 0;
return 1;
}
var is_prime_sqrt=func(x){
for(var i=2;i<=math.sqrt(x);i+=1)
if(x/i==int(x/i))
return 0;
return 1;
}
var primes=[];
var filter=func(x){
foreach(var i;primes){
if(x/i==int(x/i))
return 0;
if(x>=i){
for(var j=i+1;j<=math.sqrt(x);j+=1)
if(x/j==int(x/j))
return 0;
append(primes,x);
return 1;
}
}
append(primes,x);
return 1;
}
func(){
var cnt=0;
for(var i=2;i<50000;i+=1)
if(filter(i))
cnt+=1;
println(cnt);
}();

577
test/props.nas Normal file
View File

@@ -0,0 +1,577 @@
##
# Node class definition. The class methods simply wrap the
# low level extension functions which work on a "ghost" handle to a
# SGPropertyNode object stored in the _g field.
#
# Not all of the features of SGPropertyNode are supported. There is
# no support for ties, obviously, as that wouldn't make much sense
# from a Nasal context. The various get/set methods work only on the
# local node, there is no equivalent of the "relative path" variants
# available in C++; just use node.getNode(path).whatever() instead.
#
##
# Utility. Turns any ghosts it finds (either solo, or in an
# array) into Node objects.
#
var wrap = func(node) {
var argtype = typeof(node);
if(argtype == "ghost") {
return wrapNode(node);
} elsif(argtype == "vector") {
var v = node;
var n = size(v);
for(var i=0; i<n; i+=1) { v[i] = wrapNode(v[i]); }
return v;
}
return node;
}
var Node = {
getNode : func wrap(_getNode(me._g, arg)),
getParent : func wrap(_getParent(me._g, arg)),
getChild : func wrap(_getChild(me._g, arg)),
getChildren : func wrap(_getChildren(me._g, arg)),
setChildren : func wrap(_setChildren(me._g, arg)),
addChild : func wrap(_addChild(me._g, arg)),
addChildren : func wrap(_addChildren(me._g, arg)),
removeChild : func wrap(_removeChild(me._g, arg)),
removeChildren : func wrap(_removeChildren(me._g, arg)),
removeAllChildren: func wrap(_removeAllChildren(me._g, arg)),
getAliasTarget : func wrap(_getAliasTarget(me._g, arg)),
getName : func _getName(me._g, arg),
getIndex : func _getIndex(me._g, arg),
getType : func _getType(me._g, arg),
getAttribute : func _getAttribute(me._g, arg),
setAttribute : func _setAttribute(me._g, arg),
getValue : func _getValue(me._g, arg),
setValue : func _setValue(me._g, arg),
setValues : func _setValues(me._g, arg),
setIntValue : func _setIntValue(me._g, arg),
setBoolValue : func _setBoolValue(me._g, arg),
setDoubleValue : func _setDoubleValue(me._g, arg),
unalias : func _unalias(me._g, arg),
alias : func(n) _alias(me._g, [isa(n, Node) ? n._g : n]),
equals : func(n) _equals(me._g, [isa(n, Node) ? n._g : n]),
clearValue : func _alias(me._g, [_globals()]) and me.unalias(),
getPath : func {
var (name, index, parent) = (me.getName(), me.getIndex(), me.getParent());
if(index != 0) { name ~= "[" ~ index ~ "]"; }
if(parent != nil) { name = parent.getPath() ~ "/" ~ name; }
return name;
},
getBoolValue : func {
var val = me.getValue();
var mytype = me.getType();
if((mytype == "STRING" or mytype == "UNSPECIFIED") and val == "false") return 0;
return !!val;
},
remove : func {
if((var p = me.getParent()) == nil) return nil;
p.removeChild(me.getName(), me.getIndex());
},
};
##
# Static constructor for a Node object. Accepts a Nasal hash
# expression to initialize the object a-la setValues().
#
Node.new = func(values = nil) {
var result = wrapNode(_new());
if(typeof(values) == "hash")
result.setValues(values);
return result;
}
##
# Counter piece of setValues(). Returns a hash with all values
# in the subtree. Nodes with same name are returned as vector,
# where the original node indices are lost. The function should
# only be used if all or almost all values are needed, and never
# in performance-critical code paths. If it's called on a node
# without children, then the result is equivalent to getValue().
#
Node.getValues = func {
var children = me.getChildren();
if(!size(children)) return me.getValue();
var val = {};
var numchld = {};
foreach(var c; children) {
var name = c.getName();
if(contains(numchld, name)) { var nc = numchld[name]; }
else {
var nc = size(me.getChildren(name));
numchld[name] = nc;
if(nc > 1 and !contains(val, name)) val[name] = [];
}
if(nc > 1) append(val[name], c.getValues());
else val[name] = c.getValues();
}
return val;
}
##
# Initializes property if it's still undefined. First argument
# is a property name/path. It can also be nil or an empty string,
# in which case the node itself gets initialized, rather than one
# of its children. Second argument is the default value. The third,
# optional argument is a property type (one of "STRING", "DOUBLE",
# "INT", or "BOOL"). If it is omitted, then "DOUBLE" is used for
# numbers, and STRING for everything else. Returns the property
# as props.Node. The fourth optional argument enforces a type if
# non-zero.
#
Node.initNode = func(path = nil, value = 0, type = nil, force = 0) {
var prop = me.getNode(path or "", 1);
if(prop.getType() != "NONE") value = prop.getValue();
if(force) prop.clearValue();
if(type == nil) prop.setValue(value);
elsif(type == "DOUBLE") prop.setDoubleValue(value);
elsif(type == "INT") prop.setIntValue(value);
elsif(type == "BOOL") prop.setBoolValue(value);
elsif(type == "STRING") prop.setValue("" ~ value);
else die("initNode(): unsupported type '" ~ type ~ "'");
return prop;
}
##
# Useful debugging utility. Recursively dumps the full state of a
# Node object to the console. Try binding "props.dump(props.globals)"
# to a key for a fun hack.
#
var dump = func {
if(size(arg) == 1) { prefix = ""; node = arg[0]; }
else { prefix = arg[0]; node = arg[1]; }
index = node.getIndex();
type = node.getType();
name = node.getName();
val = node.getValue();
if(val == nil) { val = "nil"; }
name = prefix ~ name;
if(index > 0) { name = name ~ "[" ~ index ~ "]"; }
print(name, " {", type, "} = ", val);
# Don't recurse into aliases, lest we get stuck in a loop
if(type != "ALIAS") {
children = node.getChildren();
foreach(c; children) { dump(name ~ "/", c); }
}
}
##
# Recursively copy property branch from source Node to
# destination Node. Doesn't copy aliases. Copies attributes
# if optional third argument is set and non-zero.
#
var copy = func(src, dest, attr = 0) {
foreach(var c; src.getChildren()) {
var name = c.getName() ~ "[" ~ c.getIndex() ~ "]";
copy(src.getNode(name), dest.getNode(name, 1), attr);
}
var type = src.getType();
var val = src.getValue();
if(type == "ALIAS" or type == "NONE") return;
elsif(type == "BOOL") dest.setBoolValue(val);
elsif(type == "INT" or type == "LONG") dest.setIntValue(val);
elsif(type == "FLOAT" or type == "DOUBLE") dest.setDoubleValue(val);
else dest.setValue(val);
if(attr) dest.setAttribute(src.getAttribute());
}
##
# Utility. Returns a new object with its superclass/parent set to the
# Node object and its _g (ghost) field set to the specified object.
# Nasal's literal syntax can be pleasingly terse. I like that. :)
#
var wrapNode = func(node) { { parents : [Node], _g : node } }
##
# Global property tree. Set once at initialization. Is that OK?
# Does anything ever call globals.set_props() from C++? May need to
# turn this into a function if so.
#
var globals = wrapNode(_globals());
##
# Shortcut for props.globals.getNode().
#
var getNode = func return call(props.globals.getNode, arg, props.globals);
##
# Sets all indexed property children to a single value. arg[0]
# specifies a property name (e.g. /controls/engines/engine), arg[1] a
# path under each node of that name to set (e.g. "throttle"), arg[2]
# is the value.
#
var setAll = func(base, child, value) {
var node = props.globals.getNode(base);
if(node == nil) return;
var name = node.getName();
node = node.getParent();
if(node == nil) return;
var children = node.getChildren();
foreach(var c; children)
if(c.getName() == name)
c.getNode(child, 1).setValue(value);
}
##
# Turns about anything into a list of props.Nodes, including ghosts,
# path strings, vectors or hashes containing, as well as functions
# returning any of the former and in arbitrary nesting. This is meant
# to be used in functions whose main purpose is to handle collections
# of properties.
#
var nodeList = func {
var list = [];
foreach(var a; arg) {
var t = typeof(a);
if(isa(a, Node))
append(list, a);
elsif(t == "scalar")
append(list, props.globals.getNode(a, 1));
elsif(t == "vector")
foreach(var i; a)
list ~= nodeList(i);
elsif(t == "hash")
foreach(var i; keys(a))
list ~= nodeList(a[i]);
elsif(t == "func")
list ~= nodeList(a());
elsif(t == "ghost" and ghosttype(a) == "prop")
append(list, wrapNode(a));
else
die("nodeList: invalid nil property");
}
return list;
}
##
# Compiles a <condition> property branch according to the rules
# set out in $FG_ROOT/Docs/README.conditions into a Condition object.
# The 'test' method of the returend object can be used to evaluate
# the condition.
# The function returns nil on error.
#
var compileCondition = func(p) {
if(p == nil) return nil;
if(!isa(p, Node)) p = props.globals.getNode(p);
return _createCondition(p._g);
}
##
# Evaluates a <condition> property branch according to the rules
# set out in $FG_ROOT/Docs/README.conditions. Undefined conditions
# and a nil argument are "true". The function dumps the condition
# branch and returns nil on error.
#
var condition = func(p) {
if(p == nil) return 1;
if(!isa(p, Node)) p = props.globals.getNode(p);
return _cond_and(p)
}
var _cond_and = func(p) {
foreach(var c; p.getChildren())
if(!_cond(c)) return 0;
return 1;
}
var _cond_or = func(p) {
foreach(var c; p.getChildren())
if(_cond(c)) return 1;
return 0;
}
var _cond = func(p) {
var n = p.getName();
if(n == "or") return _cond_or(p);
if(n == "and") return _cond_and(p);
if(n == "not") return !_cond_and(p);
if(n == "equals") return _cond_cmp(p, 0);
if(n == "not-equals") return !_cond_cmp(p, 0);
if(n == "less-than") return _cond_cmp(p, -1);
if(n == "greater-than") return _cond_cmp(p, 1);
if(n == "less-than-equals") return !_cond_cmp(p, 1);
if(n == "greater-than-equals") return !_cond_cmp(p, -1);
if(n == "property") return !!getprop(p.getValue());
printlog("alert", "condition: invalid operator ", n);
dump(p);
return nil;
}
var _cond_cmp = func(p, op) {
var left = p.getChild("property", 0, 0);
if(left != nil) { left = getprop(left.getValue()); }
else {
printlog("alert", "condition: no left value");
dump(p);
return nil;
}
var right = p.getChild("property", 1, 0);
if(right != nil) { right = getprop(right.getValue()); }
else {
right = p.getChild("value", 0, 0);
if(right != nil) { right = right.getValue(); }
else {
printlog("alert", "condition: no right value");
dump(p);
return nil;
}
}
if(left == nil or right == nil) {
printlog("alert", "condition: comparing with nil");
dump(p);
return nil;
}
if(op < 0) return left < right;
if(op > 0) return left > right;
return left == right;
}
##
# Runs <binding> as described in $FG_ROOT/Docs/README.commands using
# a given module by default, and returns 1 if fgcommand() succeeded,
# or 0 otherwise. The module name won't override a <module> defined
# in the binding.
#
var runBinding = func(node, module = nil) {
if(module != nil and node.getNode("module") == nil)
node.getNode("module", 1).setValue(module);
var cmd = node.getNode("command", 1).getValue() or "null";
condition(node.getNode("condition")) ? fgcommand(cmd, node) : 0;
}
#---------------------------------------------------------------------------
# Property / object update manager
#
# - Manage updates when a value has changed more than a predetermined amount.
# This class is designed to make updating displays (e.g. canvas), or
# performing actions based on a property (or value in a hash) changing
# by more than the preset amount.
# This can make a significant improvement to performance compared to simply
# redrawing a canvas in an update loop.
# - Author : Richard Harrison (rjh@zaretto.com)
#---------------------------------------------------------------------------*/
#example usage:
# this is using the hashlist (which works well with an Emesary notification)
# basically when the method is called it will call each section (in the lambda)
# when the value changes by more than the amount specified as the second parameter.
# It is possible to reference multiple elements from the hashlist in each FromHashList; if either
# one changes then it will result in the lambda being called.
#
# obj.update_items = [
# UpdateManager.FromHashList(["VV_x","VV_y"], 0.01, func(val)
# {
# obj.VV.setTranslation (val.VV_x, val.VV_y + pitch_offset);
# }),
# UpdateManager.FromHashList(["pitch","roll"], 0.025, func(hdp)
# {
# obj.ladder.setTranslation (0.0, hdp.pitch * pitch_factor+pitch_offset);
# obj.ladder.setCenter (118,830 - hdp.pitch * pitch_factor-pitch_offset);
# obj.ladder.setRotation (-hdp.roll_rad);
# obj.roll_pointer.setRotation (hdp.roll_rad);
# }),
# props.UpdateManager.FromProperty("velocities/airspeed-kt", 0.01, func(val)
# {
# obj.ias_range.setTranslation(0, val * ias_range_factor);
# }),
# props.UpdateManager.FromPropertyHashList(["orientation/alpha-indicated-deg", "orientation/side-slip-deg"], 0.1, func(val)
# {
# obj.VV_x = val.property["orientation/side-slip-deg"].getValue()*10; # adjust for view
# obj.VV_y = val.property["orientation/alpha-indicated-deg"].getValue()*10; # adjust for view
# obj.VV.setTranslation (obj.VV_x, obj.VV_y);
# }),
# ]
#
#==== the update loop then becomes ======
#
# foreach(var update_item; me.update_items)
# {
# # hdp is a data provider that can be used as the hashlist for the property
# # update from hash methods.
# update_item.update(hdp);
# }
#
var UpdateManager =
{
_updateProperty : func(_property)
{
},
FromProperty : func(_propname, _delta, _changed_method)
{
var obj = {parents : [UpdateManager] };
obj.propname = _propname;
obj.property = props.globals.getNode(_propname);
obj.delta = _delta;
obj.curval = obj.property.getValue();
obj.lastval = obj.curval;
obj.changed = _changed_method;
obj.update = func(obj)
{
me.curval = me.property.getValue();
if (me.curval != nil)
{
me.localType = me.property.getType();
if (me.localType == "INT" or me.localType == "LONG" or me.localType == "FLOAT" or me.localType == "DOUBLE")
{
if(me.lastval == nil or math.abs(me.lastval - me.curval) >= me.delta)
{
me.lastval = me.curval;
me.changed(me.curval);
}
}
else if(me.lastval == nil or me.lastval != me.curval)
{
me.lastval = me.curval;
me.changed(me.curval);
}
}
};
obj.update(obj);
return obj;
},
IsNumeric : func(hashkey)
{
me.localType = me.property[hashkey].getType();
if (me.localType == "UNSPECIFIED") {
print("UpdateManager: warning ",hashkey," is ",ty, " excluding from update");
me.property[hashkey] = nil;
}
if (me.localType == "INT" or me.localType == "LONG" or me.localType == "FLOAT" or me.localType == "DOUBLE")
return 1;
else
return 0;
},
FromPropertyHashList : func(_keylist, _delta, _changed_method)
{
var obj = {parents : [UpdateManager] };
obj.hashkeylist = _keylist;
obj.delta = _delta;
obj.lastval = {};
obj.hashkey = nil;
obj.changed = _changed_method;
obj.needs_update = 0;
obj.property = {};
obj.is_numeric = {};
foreach (hashkey; obj.hashkeylist) {
obj.property[hashkey] = props.globals.getNode(hashkey);
obj.lastval[hashkey] = nil;
# var ty = obj.property[hashkey].getType();
# if (ty == "INT" or ty == "LONG" or ty == "FLOAT" or ty == "DOUBLE") {
# obj.is_numeric[hashkey] = 1;
# } else
# obj.is_numeric[hashkey] = 0;
#print("create: ", hashkey," ", ty, " isnum=",obj.is_numeric[hashkey]);
# if (ty == "UNSPECIFIED")
# print("UpdateManager: warning ",hashkey," is ",ty);
}
obj.update = func(obj)
{
if (me.lastval == nil)
me.needs_update = 1;
else {
me.needs_update = 0;
foreach (hashkey; me.hashkeylist) {
if (me.property[hashkey] != nil) {
me.valIsNumeric = me.IsNumeric(hashkey);
if (me.lastval[hashkey] == nil
or (me.valIsNumeric and (math.abs(me.lastval[hashkey] - me.property[hashkey].getValue()) >= me.delta))
or (!me.valIsNumeric and (me.lastval[hashkey] != me.property[hashkey].getValue()))) {
me.needs_update = 1;
break;
}
}
}
}
if (me.needs_update) {
me.changed(me);
foreach (hashkey; me.hashkeylist) {
me.lastval[hashkey] = me.property[hashkey].getValue();
}
}
}
;
return obj;
},
FromHashValue : func(_key, _delta, _changed_method)
{
var obj = {parents : [UpdateManager] };
obj.hashkey = _key;
obj.delta = _delta;
obj.isnum = _delta != nil;
obj.curval = nil;
obj.lastval = nil;
obj.changed = _changed_method;
obj.update = func(obj)
{
me.curval = obj[me.hashkey];
if (me.curval != nil) {
if (me.isnum) {
me.curval = num(me.curval);
if (me.lastval == nil or math.abs(me.lastval - me.curval) >= me.delta) {
me.lastval = me.curval;
me.changed(me.curval);
}
} else {
if (me.lastval == nil or me.lastval != me.curval) {
me.lastval = me.curval;
me.changed(me.curval);
}
}
}
}
;
return obj;
},
FromHashList : func(_keylist, _delta, _changed_method)
{
var obj = {parents : [UpdateManager] };
obj.hashkeylist = _keylist;
obj.delta = _delta;
obj.lastval = {};
obj.hashkey = nil;
obj.changed = _changed_method;
obj.needs_update = 0;
obj.isnum = _delta != nil;
obj.update = func(obj)
{
if (me.lastval == nil)
me.needs_update = 1;
else
me.needs_update = 0;
if (obj != nil or me.lastval == nil) {
foreach (hashkey; me.hashkeylist) {
if (me.isnum) {
if (me.lastval[hashkey] == nil or math.abs(me.lastval[hashkey] - obj[hashkey]) >= me.delta) {
me.needs_update = 1;
break;
}
} elsif (me.lastval[hashkey] == nil or me.lastval[hashkey] != obj[hashkey]) {
me.needs_update = 1;
break;
}
}
}
if (me.needs_update) {
me.changed(obj);
foreach (hashkey; me.hashkeylist) {
me.lastval[hashkey] = obj[hashkey];
}
}
};
return obj;
},
};

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

152
test/scalar.nas Normal file
View File

@@ -0,0 +1,152 @@
# basic type
import("lib.nas");
nil;
2147483647;
0x7fffffff;
0xdeadbeef;
0o70120327;
"hello world!";
'hello world!';
-12;
!0;
-((30));
[];
{};
[0,1,2,3,4,5][2]; # 2
[0,1,2,3,4,5,6,7,8,9,10][0,2,4:7,9];
[0,1,2,3,4,5,6,7,8,9,10,][0,2,4:7,9];
([0,1,2,3,4])[2]; # 2
(([0,1,2,3]))[2]; # 2
[0,1,2,3,4,5][5,4,3,2+1][0:2][0]; # 5
{str:"hello"}.str; # "hello"
{str:"hello"}["str"]; # "hello"
{"str":"hello\"\"\n"}["str"]; # "hello"
20? 1:0;
# normal scalar
var number_1=1;
var number_2=0xdeadbeef;
var number_3=0x13702;
var number_4=0.12341490239423;
var string_1="hello";
var string_2='hello';
var string_3=number_1? 'yes':'no'; # yes
# vector
var vector_1=[];
var vector_2=[0,1,2,"str",number_1,vector_1];
var vector_3=vector_2[-3,-1];
var vector_4=vector_2[0:3];
var vector_5=vector_2[3:];
# hash
var hash_1={};
var hash_2={str1:'str1', str2:'str2', num1:0x7fffffff};
var hash_3={
"member_1":1,
"member_2":2,
"member_3":3,
};
var hash_4={
mem_1:hash_1,
mem_2:hash_2.num1, # also this can be written as hash_2["num1"]
mem_3:hash_3["member_1"]
};
# function
var func_1=func(){return 1;}
var prt=func(x){println(x);return nil;}
var func_with_dynamic_id=func(a,b,c,d...){return [a,b,c,d];}
var func_with_lack_para=func(a,b,c=1,d=2){return a+b+c+d;}
var func_with_func_para=func(a,f){return f(a);}
func_with_lack_para(a:1, b:2, c:3, d:4);
func_with_lack_para(b:1, c:3, a:4, d:1);
func_with_func_para(f:func prt,a:1);
func_with_func_para(func func_1(),func(x){return x;});
func_with_func_para(func_1(),func_1);
prt(func func_1());
var test_func_ret_number_1=func func_1(); # 1
var test_func_ret_number_2=func_1(); # 1
var source={
member_1: func func_1(), # this will get a number
member_2: func {return 2.71828;} # this will get a function
};
println(source['member_2']());
println(source.member_2());
var test_func=func{return 1;}
println(func test_func()); # 1
println(test_func()); # 1
println(func test_func); # nothing
println(test_func); # nothing
println(([0,1,2,3])[1]); # 1
println(({str:"what?"})["str"]); # what?
println(({str:"what?"}).str); # what?
# lambda
(func(x){return x>0? x:0;})(12);
(func{println("hello world");})();
(((func(x){return 1.0/math.exp(x);})))(0);
# flexible definition & assignment
var (r,g,b)=[0x00,0x10,0xff];
(var r,g,b)=[0x00,0x10,0xff];
var color=[0x00,0x10,0xff];
var (r,g,b)=color;
(var r,g,b)=color;
(r,g,b)=(b,g,r);
(number_1,number_2)=(number_2,number_1);
var (swap_a,swap_b)=(0x1,0x80);
(swap_a,swap_b)=(swap_b,swap_a);
# ((swap_a),(swap_b))=(swap_b,swap_a) is wrong
# anything that use multi_assignment must not have curve around them
var multi_assign_1=[0,1,2,3,4];
var multi_assign_2=[10,9,8,7];
(multi_assign_1[1],multi_assign_2[0])=(multi_assign_1[2],multi_assign_2[1]);
# calculation
1+1;
1+1-2+3-4+5-6;
1+1*8-9/3;
1*-1;
1*(1+2*(3+4*(5+6*(7+8*(9+10/(1+1))))));
((-1*2+9))/7-1;
((({num:2})))["num"]*2*2*2;
((((([0,1,2])[0:2]))[0:2]))[1]-1;
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;
-1*10+5 or 10-10;
nil and 1+7*8;
(number_1 or number_2) and (number_3 or number_4-number_4*1);
[0,1,4,3,2][4]*2-4+1*2*2*2*2*2/8;
{num:0}.num or {what_is_the_secret_of_universe:42}["what_is_the_secret_of_universe"];
"123"~"456"-123456*2/2;
var hash={str:'hello',f:func{return me.str;}};
var tmp_f=hash.f;
hash=1;
println(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;
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(){println(1);return 1;}
var f2=func(){println(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

39
test/trait.nas Normal file
View File

@@ -0,0 +1,39 @@
import("lib.nas");
var trait={
get:func{return me.val;},
set:func(x){me.val=x;}
};
var class={
new:func(){
return {
val:nil,
parents:[trait]
};
}
};
var class2={
new:func(){
return {
val:nil,
parents:[trait],
set:func(x){me.val=typeof(x);}
};
}
};
var class_obj=[];
for(var i=0;i<10;i+=1){
append(class_obj,class.new());
class_obj[i].set(i);
}
for(var i=0;i<10;i+=1){
append(class_obj,class2.new());
class_obj[10+i].set(i);
}
foreach(var object;class_obj){
println(object.get(),' ',keys(object));
}

17
test/ycombinator.nas Normal file
View File

@@ -0,0 +1,17 @@
# Y combinator by ValKmjolnir
import("lib.nas");
var fib=func(f){
return f(f);
}(
func(f){
return func(x){
if(x<2) return x;
return f(f)(x-1)+f(f)(x-2);
}
}
);
for(var i=1;i<31;i+=1)
println(fib(i));