Skip to content

Commit b2b917f

Browse files
Refactor/more refactoring (#4)
* Created "http" library, moved platform-dependent utilities to "utility" library * fix: forgot to add building of platform.c * Added "main" program - interprets the given .bas file More refactoring of code * Fixed build issue on linux due to fread/fread_s * Added interactive shell, runs when no arguments are passed * Added option in interactive mode (prefix $) to parse and display AST only * refactor: split basic.h into various headers, move built-in basic functions to `basic_runtime_builtin_functions.c` * Added explicitly ',' and ';' as expression delimiters and as "whitespace characters" Added whitespace printing in lexer Improved expression parsing logic * fix used incorrect `exit` method for error case in interpreter * Added example .bas files, updated readme * forgot to add \n as expression delimiter * moved tty io-related system calls to system.c/system.h * fix indenting
1 parent da6186f commit b2b917f

41 files changed

Lines changed: 774 additions & 431 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CMakeLists.txt

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,44 @@ project(
1111
add_subdirectory("lib/basic/")
1212
add_subdirectory("lib/basic_system_interface/")
1313
add_subdirectory("lib/data_structures/")
14+
add_subdirectory("lib/utility/")
15+
add_subdirectory("lib/http/")
1416

1517
# Build the main project executable
16-
add_executable(server
17-
"src/http_server_main.c"
18+
add_executable(${CMAKE_PROJECT_NAME}
19+
"src/main.c"
20+
)
1821

19-
"src/http.c"
20-
"src/http.h"
21-
"src/tcpserver.c"
22-
"src/tcpserver.h"
23-
"src/utils.c"
24-
"src/utils.h"
25-
"src/platform/platform.c"
26-
"src/platform/platform.h"
22+
add_dependencies(${CMAKE_PROJECT_NAME}
23+
basic
24+
data_structures
25+
utility
2726
)
2827

29-
# Add some preprocessor defines
30-
target_compile_definitions(server
31-
PUBLIC "$<$<CONFIG:DEBUG>:DEBUG>"
28+
target_link_libraries(${CMAKE_PROJECT_NAME}
29+
PRIVATE
30+
basic::basic
31+
data_structures::data_structures
32+
utility::utility
3233
)
3334

34-
add_dependencies(server
35-
basic
36-
data_structures
35+
# Server
36+
add_executable(server
37+
"src/http_server_main.c"
3738
)
3839

3940
target_link_libraries(server
4041
PRIVATE
4142
basic::basic
4243
data_structures::data_structures
44+
utility::utility
45+
http::http
4346
)
4447

45-
# Build the main project executable
48+
# Build the test executables
49+
4650
add_executable(${CMAKE_PROJECT_NAME}-test_ast
4751
"src/test_ast.c"
48-
"src/utils.c"
49-
"src/utils.h"
5052
)
5153

5254
target_link_libraries(${CMAKE_PROJECT_NAME}-test_ast

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ while true then
155155
end
156156
157157
if is_prime then
158-
print(i)
158+
print(i)
159159
end
160160
161161
i = i + 2
@@ -168,7 +168,8 @@ Some features I would like to implement in this project:
168168

169169
- [ ] Refactor the whole thing :)
170170
- [ ] Add more built-in functions and constants
171+
- [ ] Make constants actually constant
171172
- [ ] Add ability to create user-defined functions
172-
- [ ] Make use of WebSocket to allow real-time communication
173-
- [ ] Remove the Web server entirely so that the Pages can be served by a real Web server. The BASIC interpreter will run using only WebSocket.
173+
- [ ] Allow `stdin`
174+
- [ ] Port to C++
174175
- [ ] Remove dependencies on Linux (it was made for Linux as that was the subject I wrote it for)

examples/condition.bas

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
val = 5
2+
if val < 10 then
3+
print("Success")
4+
else
5+
print("Failure")
6+
end

examples/counting_up.bas

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
val = 0
2+
while val < 10 then
3+
print("Counting at", val)
4+
val = val + 1
5+
end

examples/hello.bas

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
print("Hello world!")

examples/primes.bas

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
print(2)
2+
3+
i = 3
4+
5+
while true then
6+
p_sub = 2
7+
is_prime = true
8+
while p_sub < i then
9+
if (i % p_sub) = 0 then
10+
is_prime = false
11+
end
12+
p_sub = p_sub + 1
13+
end
14+
15+
if is_prime then
16+
print(i)
17+
end
18+
19+
i = i + 2
20+
end

lib/basic/CMakeLists.txt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,18 @@ add_library(${PROJECT_NAME}
1515
"src/basic_parser.c"
1616
"src/basic_program.c"
1717
"src/basic_runner.c"
18-
"src/utils.c"
19-
"src/utils.h"
18+
"src/basic_runtime_builtin_functions.c"
2019
)
2120

2221
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
2322

24-
# Add some preprocessor defines
25-
target_compile_definitions(${PROJECT_NAME} PUBLIC "$<$<CONFIG:DEBUG>:DEBUG>")
26-
27-
add_dependencies(${PROJECT_NAME} basic_system_interface data_structures)
23+
add_dependencies(${PROJECT_NAME} basic_system_interface data_structures utility)
2824

2925
target_link_libraries(${PROJECT_NAME}
3026
PRIVATE
3127
basic_system_interface::basic_system_interface
3228
data_structures::data_structures
29+
utility::utility
3330
)
3431

3532
target_include_directories(${PROJECT_NAME} PUBLIC

lib/basic/include/basic/basic.h

Lines changed: 6 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -10,149 +10,12 @@
1010
* 2. BASIC Parser (Tokens to AST)
1111
* 3. Execute AST sequentially (Program run)
1212
*
13-
* */
13+
*/
1414

15-
#include "ast.h"
1615
#include <data_structures/stack.h>
1716

18-
/* For printing Log messages */
19-
extern unsigned int log_print_mask;
20-
21-
// Log level mask
22-
#define LOGTYPE_DEBUG (1 << 0)
23-
#define LOGTYPE_INFO (1 << 1)
24-
#define LOGTYPE_MESSAGE (1 << 2)
25-
#define LOGTYPE_ERROR (1 << 3)
26-
#define LOGMASK_ALL 0xffff
27-
28-
// Printf modified to allow only selected messages
29-
void lprintf(const char *tag, unsigned int level_mask, const char *format, ...);
30-
31-
/* AST parser (tokenizer) */
32-
33-
typedef enum
34-
{
35-
TOKEN_IDENTIFIER,
36-
TOKEN_KEYWORD,
37-
TOKEN_WHITESPACE,
38-
TOKEN_OPERATOR,
39-
TOKEN_SEPARATOR,
40-
TOKEN_NUM,
41-
TOKEN_BOOL,
42-
TOKEN_STRING,
43-
TOKEN_END
44-
} BASICTokenType;
45-
46-
typedef struct
47-
{
48-
StringLiteral token;
49-
BASICTokenType token_type;
50-
char *token_at;
51-
} BASICToken;
52-
53-
// Structure with all the stuff needed to convert a BASIC program to an AST
54-
typedef struct
55-
{
56-
// List of tokens
57-
BASICToken *tokens;
58-
int tokens_length;
59-
// Stack for knowning current scope
60-
} BASICParseTree;
61-
62-
typedef struct
63-
{
64-
char *program_source;
65-
BASICParseTree program_tokens;
66-
ASTNode *program_sequence;
67-
// Map between line number and which instruction to execute on that line. For non-linear control flow
68-
// BASICLineNode program_line_instruction;
69-
} BASICProgram;
70-
71-
BASICProgram *basic_create_program();
72-
void basic_clear_program(BASICProgram *program);
73-
void basic_destroy_program(BASICProgram *program);
74-
75-
// Recognized tokens
76-
extern char *PARSE_KEYWORDS[];
77-
extern int PARSE_KW_COUNT;
78-
extern char *PARSE_BOOLEAN[];
79-
extern char PARSE_OPERATORS[];
80-
extern char PARSE_SEPARATOR[];
81-
extern char PARSE_WS_CHAR[];
82-
83-
// Index of the keyword in the above PARSE_KEYWORDS array
84-
#define KEYWORD_IDX_WHILE 0
85-
#define KEYWORD_IDX_IF 1
86-
#define KEYWORD_IDX_THEN 2
87-
#define KEYWORD_IDX_ELSE 3
88-
#define KEYWORD_IDX_END 4
89-
#define KEYWORD_IDX_GOTO 5
90-
91-
// Lexer
92-
int basic_tokenize(BASICProgram *program);
93-
94-
// Parser
95-
int basic_parse_form_expression(BASICParseTree *ptree, ASTNode *root, int parse_from, int parse_to, int *parse_new_pos);
96-
int basic_parse_form_function(BASICParseTree *ptree, ASTNode *root, int parse_from, int parse_to, int *parse_new_pos);
97-
98-
int basic_parse_to_ast_between_level(BASICParseTree *ptree, ASTNode *root, int from, int to, int level, int allow_keyword, int *next_ptr);
99-
int basic_parse_to_ast_between_onlyexpr(BASICParseTree *ptree, ASTNode *root, int from, int to);
100-
int basic_parse_to_ast_between(BASICParseTree *ptree, ASTNode *root, int from, int to);
101-
int basic_parse_to_ast(BASICProgram *program);
102-
103-
/* BASIC interpreter */
104-
105-
typedef enum
106-
{
107-
KW_DO_NOTHING,
108-
KW_JMP_ONLY,
109-
KW_JMP_AND_RET_NEXT,
110-
KW_JMP_AND_RET_CURR
111-
} KeywordAction;
112-
113-
typedef struct
114-
{
115-
ASTNodeData value;
116-
StringLiteral name;
117-
} BASICVariable;
118-
119-
typedef struct
120-
{
121-
BASICProgram *program;
122-
int halt;
123-
BASICVariable *variables;
124-
int var_count;
125-
StackNode *traverse_stack;
126-
} BASICRuntime;
127-
128-
typedef ASTNodeData (*basic_function)(BASICRuntime *runtime, ASTNode *args);
129-
130-
/* Public functions */
131-
BASICRuntime *basic_create_runtime(BASICProgram *program);
132-
void basic_free_runtime(BASICRuntime *runtime);
133-
134-
ASTNodeData basic_evaluate_node(BASICRuntime *runtime, ASTNode *node);
135-
ASTNodeData basic_execute(BASICRuntime *runtime, ASTNode *pc);
136-
137-
/* Private functions */
138-
139-
BASICVariable *basic_find_variable(BASICRuntime *runtime, char var_name[]);
140-
ASTNodeData basic_get_variable(BASICRuntime *runtime, char var_name[]);
141-
void basic_set_variable(BASICRuntime *runtime, char var_name[], ASTNodeData value);
142-
void basic_var_assignment(BASICRuntime *runtime, ASTNode *args);
143-
void basic_init_constants(BASICRuntime *runtime);
144-
KeywordAction basic_evaluate_keyword_block(BASICRuntime *runtime, ASTNode *pc, ASTNode **nextpc);
145-
146-
// Keyword handlers
147-
KeywordAction basic_eval_kw_if(BASICRuntime *runtime, ASTNode *pc, ASTNode **nextpc);
148-
KeywordAction basic_eval_kw_while(BASICRuntime *runtime, ASTNode *pc, ASTNode **nextpc);
149-
150-
// Built-in functions
151-
ASTNodeData _basic_fn_print(BASICRuntime *runtime, ASTNode *args);
152-
ASTNodeData _basic_fn_max(BASICRuntime *runtime, ASTNode *args);
153-
ASTNodeData _basic_fn_min(BASICRuntime *runtime, ASTNode *args);
154-
ASTNodeData _basic_fn_sleep(BASICRuntime *runtime, ASTNode *arg);
155-
ASTNodeData _basic_fn_toint(BASICRuntime *runtime, ASTNode *arg);
156-
ASTNodeData _basic_fn_toflt(BASICRuntime *runtime, ASTNode *arg);
157-
ASTNodeData _basic_fn_rand(BASICRuntime *runtime, ASTNode *arg);
158-
ASTNodeData _basic_fn_irand(BASICRuntime *runtime, ASTNode *arg);
17+
#include "ast.h"
18+
#include "basic_token.h"
19+
#include "basic_parser.h"
20+
#include "basic_program.h"
21+
#include "basic_runner.h"
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#pragma once
2+
3+
#include "ast.h"
4+
#include "basic_token.h"
5+
#include "basic_program.h"
6+
7+
// Recognized tokens
8+
extern char *PARSE_KEYWORDS[];
9+
extern int PARSE_KW_COUNT;
10+
extern char *PARSE_BOOLEAN[];
11+
extern char PARSE_OPERATORS[];
12+
extern char PARSE_SEPARATOR[];
13+
extern char PARSE_WS_CHAR[];
14+
15+
// Index of the keyword in the above PARSE_KEYWORDS array
16+
#define KEYWORD_IDX_WHILE 0
17+
#define KEYWORD_IDX_IF 1
18+
#define KEYWORD_IDX_THEN 2
19+
#define KEYWORD_IDX_ELSE 3
20+
#define KEYWORD_IDX_END 4
21+
#define KEYWORD_IDX_GOTO 5
22+
23+
// Parser
24+
int basic_parse_form_expression(BASICParseTree *ptree, ASTNode *root, int parse_from, int parse_to, int *parse_new_pos);
25+
int basic_parse_form_function(BASICParseTree *ptree, ASTNode *root, int parse_from, int parse_to, int *parse_new_pos);
26+
27+
int basic_parse_to_ast_between_level(BASICParseTree *ptree, ASTNode *root, int from, int to, int level, int allow_keyword, int *next_ptr);
28+
int basic_parse_to_ast_between_onlyexpr(BASICParseTree *ptree, ASTNode *root, int from, int to);
29+
int basic_parse_to_ast_between(BASICParseTree *ptree, ASTNode *root, int from, int to);
30+
int basic_parse_to_ast(BASICProgram *program);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#pragma once
2+
3+
#include "ast.h"
4+
#include "basic_token.h"
5+
6+
/* Basic Program */
7+
8+
typedef struct
9+
{
10+
char *program_source;
11+
BASICParseTree program_tokens;
12+
ASTNode *program_sequence;
13+
// Map between line number and which instruction to execute on that line. For non-linear control flow
14+
// BASICLineNode program_line_instruction;
15+
} BASICProgram;
16+
17+
BASICProgram *basic_create_program();
18+
void basic_clear_program(BASICProgram *program);
19+
void basic_destroy_program(BASICProgram *program);
20+
21+
// Lexer
22+
int basic_tokenize(BASICProgram *program);

0 commit comments

Comments
 (0)