An interpretive language realized by C++
A Basic(literally) language interpreter.
- Lexer. Separate input into a list of Tokens
- Parser. Read the Tokens and generate a AST Tree
- Interpreter. Analyze the AST Tree and Interpretes it.
- clone the repo
- under root folder, use
make
- in folder
output
, there will be a basic executable file make clean
can clear the.o
filesmake clean_all
can clear everything that's compiled
For complete Grammar Definition see grammar.txt
We have type of Number
、String
、List
、Dict
、Function
, you can declare one as follow:
VAR num = 1 // both Int and Float are Number
VAR str = "hello"
VAR list = [1,"2",[3,4]] // List can store any type of value
VAR dict = { name:"David", age:18 }
VAR lambda = FUNC (a,b)->a+b // you can define a lambda function, or a function with name(see below)
For type Number
, you can do these things:
- Arithmetic
basic > 123 + 456
579
basic > 456 - 123
333
basic > 123 * 456
56088
basic > 233 / 1314
0.177321
basic > 426 ^ 3
77308776
- Bool logic
basic > 123 < 456
1
basic > 123 > 456
0
basic > 123 == 123
1
basic > 123 != 456
1
basic > 123 <= 456
1
basic > 123 >= 456
0
- Logic
basic > 123 AND 456 // Equivalent to & in C
72
basic > 123 OR 456 // Equivalent to | in C
507
basic > NOT 1
0
- True/False
There is not type of Boolean, so 1 stands for True
, and 0 stands for False
For type String
, you can add(+)
、multiply(*)
and index[]
:
basic > VAR str = "123"
basic > str + "456"
"123456"
basic > str * 3
"123123123"
basic > 3 * str
"123123123"
basic > str[0]
"1"
Please Notice: These operations are not Mutable
For type List
, you can add(+)
、concat(*)
、del(-)
、index([])
:
basic > VAR list1 = []
basic > VAR list2 = [4,5,6]
basic > list1 + 1
[1]
basic > list1 * list2
[4,5,6]
basic > list2 - 1
[5,6]
basic > list2[0]
4
Please Notice: These operations are not Mutable
For type Dict
, you can index by key["key"]
or attr_by(a.name)
basic > VAR dict = { name:"David", age:18}
basic > dict["name"]
"David"
basic > dict.gender
undefined
basic > dict
{ age:18, gender:undefined, name:"David" }
You might notice that, attr_by an undefined attribute will automatically insert and set to undefined
Function can be anonymous or have a name. Also it can be single line or multiline, see example:
- Multiline
basic > FUNC add(a,b):
... IF IS_NUM(a) AND IS_NUM(b) THEN:
... PRINT(a+b)
... ELSE:
... PRINT("operator must be Numbers");
... END;
... END
<function add>
basic > add(1,5)
6
basic > add("1",5)
operator must be Numbers
- Single-line(use ->)
basic > VAR check = FUNC (a)-> IF IS_NUM(a) THEN PRINT("value is Number") ELIF IS_STR(a) THEN PRINT("value is String") ELSE PRINT("value is other type")
basic > check(1)
value is Number
basic > check("1")
value is String
- Single-Line
basic > VAR age = 14
14
basic > IF age < 13 THEN PRINT("child") ELIF age < 18 THEN PRINT("teenager") ELSE PRINT("adult")
"teenager"
- Multi-Line With END
Whether you need to end with END, depend on the last condition statement is multi-line or single-line. In the case below, Else followed by ":", means that it's a multiline statement.
basic > IF age<13 THEN:
... PRINT("child");
... ELIF age<18 THEN:
... PRINT("teenager");
... ELSE:
... PRINT("Adult");
... END
- Cross-Line
basic > IF age<13 THEN:
... PRINT("child") ELIF age<18 THEN:
... PRINT("teenager") ELSE PRINT("Adult")
WHILE <condition> THEN <expr>
- Single-Line
It's not really useable, since the "i" won't auto-increase
basic > VAR i = 0
basic > WHILE i < 10 THEN VAR i = i + 1
- Multi-Line
basic > VAR i = 1
basic > WHILE i<10 THEN:
... PRINT(i);
... VAR i = i + 1;
... END
FOR <var_name> = <start_value> TO <end_value> (STEP <step_length>)? THEN <expr>
- Single-Line
For loop have auto-increment, so you can do some basic things with single-line statement.
basic > FOR i = 1 TO 10 STEP 2 THEN PRINT(i)
13579
- Multi-Line
basic > FOR i=1 TO 9 THEN:
... FOR j = 1 TO 9 THEN:
... PRINT(i*j);
... PRINT("\t");
... END;
... PRINT("\n");
... END
提供了几个内置函数, 这些函数的功能可能还会有变化.
PRINT(value)
. print the given valuePRINTS(list, ends_with)
. call it like: PRINTS([1,2],"\n")PRINT_RET(value)
. this will return the value that have been given.INPUT()
. receive user input as StringINPUT_NUM()
. receive user input as NumberCLEAR()
. clear the terminalIS_NUM(value)
. check if value is a NumberIS_STR(value)
. check if value is a StringIS_List(value)
. check if value is a ListIS_FUNC(value)
. check if value is a FunctionAPPEND(list, elem)
. mutable function, append elem to the back of listPOP(list, index)
. mutable function, delete elem at index in list, return elem.POP_BACK(list)
. mutable function, delete the last elem in list, return elemPOP_FRONT(list)
. mutable function, delete the first elem in list, return elemEXTEND(list1, list2)
. mutable function, append list2 to list1.RUN(filepath)
. You can save basic code in file, then use RUN to execute. This also equivalent to import- SWAP(&a,&b). You should call this function by Ref, see below Reference.
- RETURN
basic > FUNC test():
... VAR foo = 5;
... RETURN foo;
... END
basic > test()
5
- For-loop
basic > VAR list = []
basic > FOR i = 1 TO 10 THEN:
... IF i == 4 THEN:
... CONTINUE;
... ELIF i == 8 THEN BREAK;
... APPEND(list, i)
... END
basic > list
[1,2,3,5,6,7]
- While-loop
basic > VAR i = 0
basic > VAR list = []
basic > WHILE i < 10 THEN:
... VAR i = i + 1;
... IF i==4 THEN CONTINUE;
... IF i==8 THEN BREAK;
... APPEND(a,i);
... END
basic > list
[1,2,3,5,6,7]
Sometime, we want to pass arguments by its value, othertime, reference. So I'll introduce &
to represent reference:
basic > VAR a = 1, b = "hello"
basic > SWAP(a,b)
// passing by value, it won't do anything
basic > SWAP(&a,&b)
// passing by reference, a will be "hello" while b will be 1
For your own function, call it like that:
basic > FUNC test(a)-> VAR &a = a + 1
basic > VAR a = 1
basic > test(&a)
2
Please notice: such as
VAR &IDENTIFIER = expr
, I call it mutation, that requires the IDENTIFIER to be already existed. WhileVAR IDENTIFIER = expr
is called definition, so the IDENTIFIER can be brand new.
line that starts with "#" is comment.
In order to ease the use of running script, I implemented command line mode beside interactive mode. Available args are as follows:
$ ./basic -h
Welcome to Basic!
Usage: ./basic [options...]
Options:
-f,--file : Execute Basic script from given file_path [default: none]
-t,--text : Execute Basic script from given text [default: none]
-i : A flag to toggle interactive mode [implicit: "true", default: false]
-v,--verbose : A flag to toggle verbose [implicit: "true", default: false]
-D,--Debug : A flag to toggle debug mode [implicit: "true", default: false]
-h,--help : print help [implicit: "true", default: false]
When input no args or explicitly -i
, will enter interactive mode.
David Callanan |
---|