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 cleancan clear the.ofilesmake clean_allcan 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]
4Please 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;
... ENDFOR <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 1For your own function, call it like that:
basic > FUNC test(a)-> VAR &a = a + 1
basic > VAR a = 1
basic > test(&a)
2Please notice: such as
VAR &IDENTIFIER = expr, I call it mutation, that requires the IDENTIFIER to be already existed. WhileVAR IDENTIFIER = expris 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 |
|---|