This commit is contained in:
Valk Richard Li 2021-01-23 19:21:37 +08:00
parent bb746dfbfb
commit 125d6d3a7d
2 changed files with 306 additions and 34 deletions

338
README.md
View File

@ -6,21 +6,19 @@
[Nasal](http://wiki.flightgear.org/Nasal_scripting_language) is a script language that used in [FlightGear](https://www.flightgear.org/). [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.
So this is an interpreter for Nasal written by C++.
The interpreter is still in development. 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 # Why Writing Nasal Interpreter
Nasal is a script language first used in Flightgear. Nasal is a script language first used in Flightgear.
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. 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. 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 runtime(bytecode virtual machine/ast-runtime virtual machine) to help checking errors.
They found it easier for them to check errors before copying nasal-codes in nasal-console in Flightgear to test. They found it easier for them to check errors before copying nasal-codes in nasal-console in Flightgear to test.
@ -28,27 +26,21 @@ They found it easier for them to check errors before copying nasal-codes in nasa
> g++ -std=c++11 main.cpp -o main.exe > g++ -std=c++11 main.cpp -o main.exe
# Lexical Analysis
The flow chart of lexer is here:
[![nasal_lexer.png](pic/nasal_lexer.png?raw=true)](https://github.com/ValKmjolnir/Nasal-Interpreter/blob/master/pic/nasal_lexer.png)
This picture seems ugly. I will re-draw it later(maybe 1000 years later).
# Parser # Parser
## Version 3.0 LL(k) parser.
I refactored parser and make it easier to maintain. ```javascript
The EBNF is also refactored. (var a,b,c)=[{b:nil},[1,2],func{return 0;}];
## Version 4.0 (a.b,b[0],c)=(1,2,3);
Parser in this version will pre-calculate some mathematical equations. ```
This will make bytecode vm running more quickly. have the same first set,so LL(1) is useless for this language.
Maybe in the future i can refactor it to LL(1) with special checks.
# Abstract Syntax Tree # Abstract Syntax Tree
@ -89,23 +81,26 @@ Now i am trying to search hidden bugs in this interpreter.Hope you could help me
There's an example of byte code below: There's an example of byte code below:
```javascript ```javascript
var (a,b,c)=(1,2,3); for(var i=0;i<4000000;i+=1);
``` ```
```asm ```asm
.number 0
.number 4e+006
.number 1 .number 1
.number 2 .symbol i
.number 3 0x00000000: pzero 0x00000000
.symbol a 0x00000001: load 0x00000000 (i)
.symbol b 0x00000002: call 0x00000000 (i)
.symbol c 0x00000003: pnum 0x00000001 (4e+006)
0x00000000: pone 0x00000000 0x00000004: less 0x00000000
0x00000001: load 0x00000000 (a) 0x00000005: jf 0x0000000b
0x00000002: pnum 0x00000001 (2) 0x00000006: pone 0x00000000
0x00000003: load 0x00000001 (b) 0x00000007: mcall 0x00000000 (i)
0x00000004: pnum 0x00000002 (3) 0x00000008: addeq 0x00000000
0x00000005: load 0x00000002 (c) 0x00000009: pop 0x00000000
0x00000006: nop 0x00000000 0x0000000a: jmp 0x00000002
0x0000000b: nop 0x00000000
``` ```
## Version 5.0 ## Version 5.0
@ -113,3 +108,280 @@ var (a,b,c)=(1,2,3);
I decide to optimize bytecode vm in this version. 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! 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.
# 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;
a=0x7fffffff;
a=0o170001;
var b='str';
b="another string";
b=`c`;
var c=[];
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"
};
var e=func(x,y,z)
{
return nil;
}
e=func
{
return 1024;
}
e=func(x,y,z,default_parameter1=1,default_parameter2=2)
{
return x+y+z+default_parameter1+default_parameter2;
}
e=func(x,y,z,dynamic_parameter...)
{
var sum=0;
foreach(var i;dynamic_parameter)
sum+=i;
return sum+x+y+z;
}
```
## operators
```javascript
1+2;
1-2;
1*2;
1/2;
'str1'~'str2';
1+1 and 0;
1+2*3 or 0;
1<0;
1>0;
1<=0;
1>=0;
1==0;
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);
```
## conditional expression
```javascript
if(1)
{
;
}
elsif(2)
{
;
}
else if(3)
{
;
}
else
{
;
}
```
## loop
```javascript
while(condition)
continue;
for(var i=0;i<10;i+=1)
break;
forindex(var i;elem)
print(elem[i]);
foreach(var i;elem)
print(i);
```
## subvec
```javascript
a[-1,1,0:2,0:,:3,:,nil:8,3:nil,nil:nil];
```
## special function call
```javascript
a(x:0,y:1,z:2);
```
## often used builtin 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)
```javascript
var import=func(filename)
{
nasal_call_import(filename);
return nil;
}
var print=func(elements...)
{
nasal_call_builtin_std_cout(elements);
return nil;
};
var append=func(vector,elements...)
{
nasal_call_builtin_push_back(vector,elements);
return nil;
}
var setsize=func(vector,size)
{
nasal_call_builtin_set_size(vector,size);
return nil;
}
var split=func(delimeter,string)
{
return nasal_call_builtin_split(delimeter,string);
}
var rand=func(seed=nil)
{
return nasal_call_builtin_rand(seed);
}
var id=func(thing)
{
return nasal_call_builtin_get_id(thing);
}
var int=func(value)
{
return nasal_call_builtin_trans_int(value);
}
var num=func(value)
{
return nasal_call_builtin_trans_num(value);
}
var pop=func(vector)
{
return nasal_call_builtin_pop_back(vector);
}
var str=func(number)
{
return nasal_call_builtin_trans_str(number);
}
var size=func(object)
{
return nasal_call_builtin_size(object);
}
var contains=func(hash,key)
{
return nasal_call_builtin_contains(hash,key);
}
var delete=func(hash,key)
{
nasal_call_builtin_delete(hash,key);
return;
}
var keys=func(hash)
{
return nasal_call_builtin_get_keys(hash);
}
var die=func(str)
{
nasal_call_builtin_die(str);
return nil;
}
var typeof=func(object)
{
return nasal_call_builtin_type(object);
}
var substr=func(str,begin,length)
{
return nasal_call_builtin_substr(str,begin,length);
}
var math=
{
e:2.7182818284590452354,
pi:3.14159265358979323846264338327950288,
sin:func(x)
{
return nasal_call_builtin_sin(x);
},
cos:func(x)
{
return nasal_call_builtin_cos(x);
},
tan:func(x)
{
return nasal_call_builtin_tan(x);
},
exp:func(x)
{
return nasal_call_builtin_exp(x);
},
ln:func(x)
{
return nasal_call_builtin_cpp_math_ln(x);
},
sqrt:func(x)
{
return nasal_call_builtin_cpp_math_sqrt(x);
},
atan2:func(x,y)
{
return nasal_call_builtin_cpp_atan2(x,y);
},
};
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB