refactor: 重构前端代码并添加日志功能
- 重命名和重构了多个文件,包括 lexer、parser 和 AST 相关代码 - 添加了日志功能,使用 LOG_* 宏替代原有的 error 和 warn 函数 - 优化了错误处理和内存分配方式 - 调整了代码结构,提高了模块化和可读性
This commit is contained in:
		| @ -3,8 +3,11 @@ all: ccompiler | ||||
| run: ccompiler | ||||
| 	./ccompiler test.c flat.bin | ||||
|  | ||||
| simple_test: | ||||
| 	make -C tests/simple | ||||
|  | ||||
| ccompiler: frontend ir | ||||
| 	gcc -g rv32ima_codegen.c -L../../frontend -lfrontend -L../../middleend -lir -o ccompiler | ||||
| 	gcc -g rv32.c -I../../.. -L../../frontend -lfrontend -L../../middleend -lmiddleend -L../../../lib -lcore -o ccompiler | ||||
|  | ||||
| frontend: | ||||
| 	make -C ../../frontend | ||||
|  | ||||
| @ -1,16 +1,18 @@ | ||||
| #define RISCV_VM_BUILDIN_ECALL | ||||
| #include "rv32gen.h" | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <assert.h> | ||||
| 
 | ||||
| // 指令编码联合体(自动处理小端序)
 | ||||
| typedef union rv32code { | ||||
|     uint32_t code; | ||||
|     uint8_t bytes[4]; | ||||
|     u8_t bytes[4]; | ||||
| } rv32code_t; | ||||
| 
 | ||||
| #include "../../frontend/frontend.h" | ||||
| #include "../../middleend/ir.h" | ||||
| #include "../../middleend/middleend.h" | ||||
| 
 | ||||
| typedef struct { | ||||
|     int code_pos; | ||||
|     int to_idx; | ||||
| @ -200,7 +202,7 @@ static int gen_instr(ir_bblock_t* block, ir_node_t* instr) { | ||||
|                 GENCODE(XOR(REG_T0, REG_T1, REG_T2)); | ||||
|                 break; | ||||
|             default: | ||||
|                 error("ERROR gen_instr op in riscv"); | ||||
|                 LOG_ERROR("ERROR gen_instr op in riscv"); | ||||
|                 break; | ||||
|             } | ||||
|             offset = stack_offset(instr); | ||||
| @ -213,7 +215,7 @@ static int gen_instr(ir_bblock_t* block, ir_node_t* instr) { | ||||
|             int fidx = block_idx(instr->data.branch.false_bblock); | ||||
|             int cidx = block_idx(ctx.cur_block); | ||||
|             jmp_t* jmp; | ||||
|             jmp = xmalloc(sizeof(jmp_t)); | ||||
|             jmp = rt._malloc(sizeof(jmp_t)); | ||||
|             *jmp = (jmp_t) { | ||||
|                 .base_offset = 8, | ||||
|                 .code_pos = ctx.codes.size, | ||||
| @ -223,7 +225,7 @@ static int gen_instr(ir_bblock_t* block, ir_node_t* instr) { | ||||
|             }; | ||||
|             vector_push(ctx.jmp, jmp); | ||||
|             GENCODE(BNEZ(REG_T0, 0)); | ||||
|             jmp = xmalloc(sizeof(jmp_t)); | ||||
|             jmp = rt._malloc(sizeof(jmp_t)); | ||||
|             *jmp = (jmp_t) { | ||||
|                 .base_offset = 4, | ||||
|                 .code_pos = ctx.codes.size, | ||||
| @ -237,7 +239,7 @@ static int gen_instr(ir_bblock_t* block, ir_node_t* instr) { | ||||
|         } | ||||
|         case IR_NODE_JUMP: { | ||||
|             int idx = block_idx(instr->data.jump.target_bblock); | ||||
|             jmp_t* jmp = xmalloc(sizeof(jmp_t)); | ||||
|             jmp_t* jmp = rt._malloc(sizeof(jmp_t)); | ||||
|             *jmp = (jmp_t) { | ||||
|                 .base_offset = 4, | ||||
|                 .code_pos = ctx.codes.size, | ||||
| @ -251,7 +253,7 @@ static int gen_instr(ir_bblock_t* block, ir_node_t* instr) { | ||||
|         } | ||||
|         case IR_NODE_CALL: { | ||||
|             if (instr->data.call.args.size > 8) { | ||||
|                 error("can't add so much params"); | ||||
|                 LOG_ERROR("can't add so much params"); | ||||
|             } | ||||
|             int param_regs[8] = { | ||||
|                 REG_A0, REG_A1, REG_A2, REG_A3, | ||||
| @ -272,7 +274,7 @@ static int gen_instr(ir_bblock_t* block, ir_node_t* instr) { | ||||
|                 goto CALL_END; | ||||
|             } | ||||
|              | ||||
|             jmp_t* jmp = xmalloc(sizeof(jmp_t)); | ||||
|             jmp_t* jmp = rt._malloc(sizeof(jmp_t)); | ||||
|             *jmp = (jmp_t) { | ||||
|                 .base_offset = ctx.cur_func_offset + ctx.cur_block_offset + len, | ||||
|                 .code_pos = ctx.codes.size, | ||||
| @ -289,7 +291,7 @@ static int gen_instr(ir_bblock_t* block, ir_node_t* instr) { | ||||
|             break; | ||||
|         } | ||||
|         default: | ||||
|             error("ERROR gen_instr in riscv"); | ||||
|             LOG_ERROR("ERROR gen_instr in riscv"); | ||||
|     } | ||||
|     return len; | ||||
| } | ||||
| @ -320,7 +322,7 @@ static int gen_func(ir_func_t* func) { | ||||
|         REG_A4, REG_A5, REG_A6, REG_A7 | ||||
|     }; | ||||
|     if (func->params.size > 8) { | ||||
|         error("can't add so much params"); | ||||
|         LOG_ERROR("can't add so much params"); | ||||
|     } | ||||
|     for (int i = 0; i < func->params.size; i++) { | ||||
|         int offset = stack_offset(vector_at(func->params, i)); | ||||
| @ -362,7 +364,7 @@ static int gen_code(ir_prog_t* prog) { | ||||
| 
 | ||||
|     for (int i = 0; i < prog->extern_funcs.size; i++) { | ||||
|         if (system_func(prog->extern_funcs.data[i]->name) == -1) { | ||||
|             error("func %s not defined and not a system func", prog->extern_funcs.data[i]->name); | ||||
|             LOG_ERROR("func %s not defined and not a system func", prog->extern_funcs.data[i]->name); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -397,11 +399,15 @@ static int gen_code(ir_prog_t* prog) { | ||||
|             return jmp_cache[i]; | ||||
|         } | ||||
|     } | ||||
|     error("main not found"); | ||||
|     LOG_ERROR("main not found"); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char** argv) { | ||||
|     // gcc rv32ima_codegen.c -o rv32gen.exe
 | ||||
| 
 | ||||
|     init_lib_core(); | ||||
|     log_set_level(NULL, LOG_LEVEL_NOTSET); | ||||
| 
 | ||||
|     const char* infilename = "test.c"; | ||||
|     const char* outfilename = "flat.bin"; | ||||
|     if (argc >= 2) { | ||||
| @ -417,9 +423,9 @@ int main(int argc, char** argv) { | ||||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     struct ASTNode* root = frontend(infilename, in, (sread_fn)fread_s); | ||||
|     gen_ir_from_ast(root); | ||||
|     int main_pos = gen_code(&prog); | ||||
|     ast_node_t* root = frontend(infilename, in, (sread_fn)fread_s); | ||||
|     ir_prog_t* prog = gen_ir_from_ast(root); | ||||
|     int main_pos = gen_code(prog); | ||||
| 
 | ||||
|     #define CRT_CODE_SIZE 16 | ||||
|     rv32code_t gcodes[] = { | ||||
							
								
								
									
										8
									
								
								ccompiler/backend/riscv32/rv_vm/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								ccompiler/backend/riscv32/rv_vm/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| CC = gcc | ||||
| CFLAGS = -g -Wall | ||||
|  | ||||
| all = rv32-vm | ||||
|  | ||||
| CFLAGS += -DDEFAULT_FILE='\"flat.bin\"' | ||||
| rv32-vm: | ||||
| 	$(CC) $(CFLAGS) -g -o rv32-vm .\ripes-vm.c | ||||
| @ -31,6 +31,10 @@ void ecall_handler(struct MiniRV32IMAState *state) { | ||||
|     case 10: | ||||
|         fprintf(stderr, "\nexit: %d\n", a0); | ||||
|         exit(a0); | ||||
|     case 11: | ||||
|         // PrintChar
 | ||||
|         printf("%c", a0); | ||||
|         break; | ||||
|     case 93: | ||||
|         fprintf(stderr, "\nmain return code: %d\n", a0); | ||||
|         exit(a0); | ||||
| @ -40,7 +44,7 @@ void ecall_handler(struct MiniRV32IMAState *state) { | ||||
|     case SYSCALL(1): | ||||
|         // putchar
 | ||||
|         putchar(a0); | ||||
| 
 | ||||
|         break; | ||||
|     case SYSCALL(4): | ||||
|         // input int
 | ||||
|         scanf("%d", &a0); | ||||
| @ -1,28 +1,30 @@ | ||||
| VM := ../../rv32-vm | ||||
| CC := ../../ccompiler | ||||
| STD_CC := gcc | ||||
| # VM := ../../rv32-vm | ||||
| # CC := ../../ccompiler | ||||
| # STD_CC := gcc | ||||
|  | ||||
| TESTS := $(wildcard *.c) | ||||
| # TESTS := $(wildcard *.c) | ||||
|  | ||||
| # 定义所有测试目标 | ||||
| TEST_TARGETS := $(patsubst %.c, %_test, $(TESTS)) | ||||
| # # 定义所有测试目标 | ||||
| # TEST_TARGETS := $(patsubst %.c, %_test, $(TESTS)) | ||||
|  | ||||
| all: $(TEST_TARGETS) | ||||
| # all: $(TEST_TARGETS) | ||||
|  | ||||
| %_test: %.c | ||||
| 	@$(STD_CC) -g -o $@ $< | ||||
| 	@$(CC) $< flat.bin | ||||
| 	@./$@ ; ret_gcc=$$? | ||||
| 	@$(VM) flat.bin ; ret_vm=$$? | ||||
| 	@echo "Testing $@" | ||||
| 	@if [ $$ret_gcc -eq $$ret_vm ]; then \ | ||||
| 		echo "$@ passed"; \ | ||||
| 	else \ | ||||
| 		echo "$@ failed: GCC returned $$ret_gcc, VM returned $$ret_vm"; \ | ||||
| 		exit 1; \ | ||||
| 	fi | ||||
| # %_test: %.c | ||||
| # 	@$(STD_CC) -g -o $@ $< | ||||
| # 	@$(CC) $< flat.bin | ||||
| # 	@./$@ ; ret_gcc=$$? | ||||
| # 	@$(VM) flat.bin ; ret_vm=$$? | ||||
| # 	@echo "Testing $@" | ||||
| # 	@if [ $$ret_gcc -eq $$ret_vm ]; then \ | ||||
| # 		echo "$@ passed"; \ | ||||
| # 	else \ | ||||
| # 		echo "$@ failed: GCC returned $$ret_gcc, VM returned $$ret_vm"; \ | ||||
| # 		exit 1; \ | ||||
| # 	fi | ||||
|  | ||||
| clean: | ||||
| 	rm -f $(TEST_TARGETS) flat.bin | ||||
| # clean: | ||||
| # 	rm -f $(TEST_TARGETS) flat.bin | ||||
|  | ||||
| .PHONY: all clean | ||||
| # .PHONY: all clean | ||||
| all: | ||||
| 	python test.py | ||||
| @ -1,7 +1,7 @@ | ||||
| # 编译器设置 | ||||
| CC = gcc | ||||
| AR = ar | ||||
| CFLAGS = -g -Wall | ||||
| CFLAGS = -g -Wall -I../.. | ||||
|  | ||||
| # 源文件路径 | ||||
| LEXER_DIR = ./lexer | ||||
| @ -15,7 +15,7 @@ SRCS = \ | ||||
|     $(LEXER_DIR)/lexer.c \ | ||||
|     $(LEXER_DIR)/token.c \ | ||||
|     $(PARSER_DIR)/parser.c \ | ||||
|     $(AST_DIR)/ast.c \ | ||||
|     $(PARSER_DIR)/ast.c \ | ||||
|     $(AST_DIR)/block.c \ | ||||
|     $(AST_DIR)/decl.c \ | ||||
|     $(AST_DIR)/expr.c \ | ||||
|  | ||||
| @ -1,8 +1,10 @@ | ||||
| #include "lexer/lexer.h" | ||||
| #include "parser/symtab/symtab.h" | ||||
| #include <lib/core.h> | ||||
| #include "frontend.h" | ||||
| #include "parser/symtab/symtab.h" | ||||
|  | ||||
| ast_node_t* frontend(const char* file, void* stream, sread_fn sread) { | ||||
|     init_lib_core(); | ||||
|  | ||||
| struct ASTNode* frontend(const char* file, void* stream, sread_fn sread) { | ||||
|     lexer_t lexer; | ||||
|     init_lexer(&lexer, file, stream, sread); | ||||
|      | ||||
|  | ||||
| @ -1,27 +1,9 @@ | ||||
| #ifndef __FRONTEND_H__ | ||||
| #define __FRONTEND_H__ | ||||
| #ifndef __SMCC_FRONTEND_H__ | ||||
| #define __SMCC_FRONTEND_H__ | ||||
|  | ||||
| #ifndef error | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <assert.h> | ||||
| #define STD_LIBRARY | ||||
| #define error(...) do { fprintf(stderr, __VA_ARGS__); assert(0); } while (0) | ||||
| #endif | ||||
| #ifndef warn | ||||
| #include <stdio.h> | ||||
| #define STD_LIBRARY | ||||
| #define warn(...) do { fprintf(stdout, __VA_ARGS__); } while (0) | ||||
| #endif | ||||
|  | ||||
| #define xmalloc(size) malloc(size) | ||||
|  | ||||
| #ifndef FRONTEND_IMPLEMENTATION | ||||
| #include "lexer/lexer.h" | ||||
| #include "parser/parser.h" | ||||
| #include "parser/ast/ast.h" | ||||
|  | ||||
| typedef int (*sread_fn)(void *dst_buf, int dst_size, int elem_size, int count, void *stream); | ||||
| struct ASTNode* frontend(const char* file, void* stream, sread_fn sread); | ||||
| #endif | ||||
| ast_node_t* frontend(const char* file, void* stream, sread_fn sread); | ||||
|  | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| @ -26,8 +26,8 @@ the distribution and installation instructions. | ||||
| Chris Fraser / cwf@aya.yale.edu | ||||
| David Hanson / drh@drhanson.net | ||||
|  */ | ||||
| #define FRONTEND_IMPLEMENTATION | ||||
| #include "../frontend.h" | ||||
| #include <lib/core.h> | ||||
| #include "lexer_log.h" | ||||
| #include "token.h" | ||||
| #include "lexer.h" | ||||
|  | ||||
| @ -74,8 +74,9 @@ static inline int keyword_cmp(const char* name, int len) { | ||||
|     return -1; // Not a keyword. | ||||
| } | ||||
|  | ||||
| void init_lexer(lexer_t* lexer, const char* file_name, void* stream, lexer_sread_fn sread) | ||||
| { | ||||
| void init_lexer(lexer_t* lexer, const char* file_name, void* stream, lexer_sread_fn sread) { | ||||
|     init_lib_core(); | ||||
|  | ||||
|     lexer->cur_ptr = lexer->end_ptr = (unsigned char*)&(lexer->buffer); | ||||
|     lexer->index = 1; | ||||
|     lexer->line = 1; | ||||
| @ -96,10 +97,10 @@ static void flush_buffer(lexer_t* lexer) { | ||||
|     lexer->cur_ptr = (unsigned char*)lexer->buffer; | ||||
|  | ||||
|     int read_size = LEXER_BUFFER_SIZE - num; | ||||
|     // TODO size_t to int maybe lose precision | ||||
|     // TODO rt_size_t to int maybe lose precision | ||||
|     int got_size = lexer->sread(lexer->buffer + num, read_size, 1, read_size, lexer->stream); | ||||
|     if (got_size < 0) { | ||||
|         error("lexer read error"); | ||||
|         LEX_ERROR("lexer read error"); | ||||
|     } else if (got_size < read_size) { | ||||
|         lexer->end_ptr += got_size; | ||||
|         lexer->end_ptr[0] = '\0'; // EOF | ||||
| @ -107,7 +108,7 @@ static void flush_buffer(lexer_t* lexer) { | ||||
|     } else if (got_size == read_size) { | ||||
|         lexer->end_ptr += got_size; | ||||
|     } else { | ||||
|         error("lexer read error imposible got_size > read_size maybe overflow?"); | ||||
|         LEX_ERROR("lexer read error imposible got_size > read_size maybe overflow?"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -153,8 +154,10 @@ static char got_slash(unsigned char* peek) { | ||||
|         case 'r': return '\r'; | ||||
|         case 't': return '\t'; | ||||
|         case 'v': return '\v'; | ||||
|         default: error("Unknown escape character");  | ||||
|         default: break; | ||||
|     } | ||||
|     LEX_ERROR("Unknown escape character"); | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| static void parse_char_literal(lexer_t* lexer, tok_t* token) { | ||||
| @ -168,7 +171,7 @@ static void parse_char_literal(lexer_t* lexer, tok_t* token) { | ||||
|         val = *peek++; | ||||
|     } | ||||
|  | ||||
|     if (*peek++ != '\'') error("Unclosed character literal"); | ||||
|     if (*peek++ != '\'') LEX_ERROR("Unclosed character literal"); | ||||
|     token->val.ch = val; | ||||
|     lexer->cur_ptr = peek; | ||||
|     token->val.have = 1; | ||||
| @ -178,7 +181,7 @@ static void parse_char_literal(lexer_t* lexer, tok_t* token) { | ||||
| static void parse_string_literal(lexer_t* lexer, tok_t* token) { | ||||
|     unsigned char* peek = lexer->cur_ptr + 1; | ||||
|     // TODO string literal size check | ||||
|     char* dest = token->val.str = xmalloc(LEXER_MAX_TOKEN_SIZE + 1); | ||||
|     char* dest = token->val.str = rt._malloc(LEXER_MAX_TOKEN_SIZE + 1); | ||||
|     int len = 0; | ||||
|  | ||||
|     while (*peek != '"') { | ||||
| @ -189,7 +192,7 @@ static void parse_string_literal(lexer_t* lexer, tok_t* token) { | ||||
|             *peek = got_slash(peek); | ||||
|         } | ||||
|          | ||||
|         if (len >= LEXER_MAX_TOKEN_SIZE) error("String too long"); | ||||
|         if (len >= LEXER_MAX_TOKEN_SIZE) LEX_ERROR("String too long"); | ||||
|         dest[len++] = *peek++; | ||||
|     } | ||||
|     dest[len] = '\0'; | ||||
| @ -431,7 +434,7 @@ void get_token(lexer_t* lexer, tok_t* token) { | ||||
|         lexer->line++; | ||||
|         tok = TOKEN_FLUSH; break; | ||||
|     case '#': | ||||
|         warn("TODO: #define\n"); | ||||
|         LEX_WARN("Marroc does not support in lexer rather in preprocessor, it will be ignored"); | ||||
|         goto_newline(lexer); | ||||
|         tok = TOKEN_FLUSH; | ||||
|         goto END; | ||||
| @ -458,14 +461,14 @@ void get_token(lexer_t* lexer, tok_t* token) { | ||||
|     case '_': | ||||
|         // TOKEN_IDENT | ||||
|         if ((*peek == 'L' && *peek == '\'') || (*peek == 'L' && *peek == '"')) { | ||||
|             error("unsupport wide-character char literal by `L` format"); | ||||
|             LEX_ERROR("unsupport wide-character char literal by `L` format"); | ||||
|         } | ||||
|         while (1) { | ||||
|             if (peek == lexer->end_ptr) { | ||||
|                 error("unsupport outof 64 length identifier"); | ||||
|                 LEX_ERROR("unsupport outof 64 length identifier"); | ||||
|             } | ||||
|             if ((*peek >= 'a' && *peek <= 'z') || (*peek >= 'A' && *peek <= 'Z') || | ||||
|             (*peek == '_') || (*peek >= '0' && *peek <= '9')) { | ||||
|                     (*peek == '_') || (*peek >= '0' && *peek <= '9')) { | ||||
|                 peek++; | ||||
|                 continue; | ||||
|             } | ||||
| @ -475,7 +478,7 @@ void get_token(lexer_t* lexer, tok_t* token) { | ||||
|         int res = keyword_cmp((const char*)lexer->cur_ptr, peek - (lexer->cur_ptr)); | ||||
|         if (res == -1) { | ||||
|             int strlen = peek - lexer->cur_ptr; | ||||
|             unsigned char* str = xmalloc(strlen + 1); | ||||
|             unsigned char* str = rt._malloc(strlen + 1); | ||||
|             constant.have = 1; | ||||
|             constant.str = (char*)str; | ||||
|             for (int i = 0; i < strlen; i++) { | ||||
| @ -489,7 +492,7 @@ void get_token(lexer_t* lexer, tok_t* token) { | ||||
|             tok = keywords[res].tok; break; | ||||
|         } | ||||
|     default: | ||||
|         error("unsupport char in sourse code `%c`", *(lexer->cur_ptr)); | ||||
|         LEX_ERROR("unsupport char in sourse code `%c`", *(lexer->cur_ptr)); | ||||
|         break; | ||||
|     } | ||||
|  | ||||
| @ -497,6 +500,7 @@ void get_token(lexer_t* lexer, tok_t* token) { | ||||
| END: | ||||
|     token->val = constant; | ||||
|     token->type = tok; | ||||
|     LEX_DEBUG("get token `%s` (ch: %c, int: %d)", get_tok_name(token->type), token->val.ch, token->val.i); | ||||
| } | ||||
|  | ||||
| // get_token maybe got invalid (with parser) | ||||
| @ -507,4 +511,3 @@ void get_valid_token(lexer_t* lexer, tok_t* token) { | ||||
|         type = token->type; | ||||
|     } while (type == TOKEN_FLUSH || type == TOKEN_LINE_COMMENT || type == TOKEN_BLOCK_COMMENT); | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| #ifndef __LEXER_H__ | ||||
| #define __LEXER_H__ | ||||
| #ifndef __SMCC_LEXER_H__ | ||||
| #define __SMCC_LEXER_H__ | ||||
|  | ||||
| #include <lib/core.h> | ||||
| #include "token.h" | ||||
| #ifndef LEXER_MAX_TOKEN_SIZE  | ||||
| #define LEXER_MAX_TOKEN_SIZE 63 | ||||
|  | ||||
							
								
								
									
										13
									
								
								ccompiler/frontend/lexer/lexer_log.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								ccompiler/frontend/lexer/lexer_log.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| #ifndef __SMCC_LEXER_LOG_H__ | ||||
| #define __SMCC_LEXER_LOG_H__ | ||||
|  | ||||
| #include <lib/rt/rt.h> | ||||
|  | ||||
| #define LEX_NOTSET( fmt, ...)     LOG_NOTSET("LEXER: " fmt, ##__VA_ARGS__) | ||||
| #define LEX_DEBUG(  fmt, ...)      LOG_DEBUG("LEXER: " fmt, ##__VA_ARGS__)  | ||||
| #define LEX_INFO(   fmt, ...)       LOG_INFO("LEXER: " fmt, ##__VA_ARGS__)   | ||||
| #define LEX_WARN(   fmt, ...)       LOG_WARN("LEXER: " fmt, ##__VA_ARGS__)   | ||||
| #define LEX_ERROR(  fmt, ...)      LOG_ERROR("LEXER: " fmt, ##__VA_ARGS__)  | ||||
| #define LEX_FATAL(  fmt, ...)      LOG_FATAL("LEXER: " fmt, ##__VA_ARGS__)  | ||||
|  | ||||
| #endif // __SMCC_LEXER_LOG_H__ | ||||
| @ -1,6 +1,7 @@ | ||||
| CC = gcc | ||||
| CFLAGS = -g -Wall | ||||
| CFLAGS = -g -Wall -I../../../.. | ||||
| SRC = ../lexer.c ../token.c | ||||
| LIB = -L../../../../lib -lcore | ||||
|  | ||||
| all = test_all | ||||
|  | ||||
| @ -8,10 +9,10 @@ test_all: test | ||||
| 	./test | ||||
|  | ||||
| run: | ||||
| 	$(CC) $(CFLAGS) $(SRC) run.c -o run | ||||
| 	$(CC) $(CFLAGS) $(SRC) run.c $(LIB) -o run | ||||
|  | ||||
| test: | ||||
| 	$(CC) $(CFLAGS) $(SRC) -o test test.c | ||||
| 	$(CC) $(CFLAGS) $(SRC) $(LIB) -o test test.c | ||||
|  | ||||
| clean: | ||||
| 	rm -f test run | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "../lexer.h" | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| // gcc -g ../lexer.c ../token.c test_lexer.c -o test_lexer | ||||
| /* | ||||
| tok_tConstant { | ||||
| @ -18,9 +19,14 @@ tok_tConstant { | ||||
| int g_num; | ||||
| int g_num_arr[3]; | ||||
| int main(int argc, char* argv[]) { | ||||
|     int num = 0; | ||||
|     // int num = 0; | ||||
|     // You Must Be Call | ||||
|     init_lib_core(); | ||||
|     if (argc == 3 && strcmp(argv[2], "-nodebug") == 0) { | ||||
|         log_set_level(NULL, LOG_LEVEL_ALL & ~LOG_LEVEL_DEBUG); | ||||
|     } | ||||
|  | ||||
|     const char* file_name = "test_lexer.c"; | ||||
|     const char* file_name = "run.c"; | ||||
|     if (argc == 2) { | ||||
|         file_name = argv[1]; | ||||
|     } | ||||
| @ -32,7 +38,7 @@ int main(int argc, char* argv[]) { | ||||
|     printf("open file success\n"); | ||||
|  | ||||
|     lexer_t lexer; | ||||
|     init_lexer(&lexer, "test_lexter.c", fp, (lexer_sread_fn)fread_s); | ||||
|     init_lexer(&lexer, file_name, fp, (lexer_sread_fn)fread_s); | ||||
|     tok_t tok; | ||||
|  | ||||
|     while (1) { | ||||
| @ -40,7 +46,7 @@ int main(int argc, char* argv[]) { | ||||
|         if (tok.type == TOKEN_EOF) { | ||||
|             break; | ||||
|         } | ||||
|         printf("line: %d, column: %d, type: %3d, typename: %s\n", | ||||
|             lexer.line, lexer.index, tok.type, get_tok_name(tok.type)); | ||||
|         // printf("line: %d, column: %d, type: %3d, typename: %s\n", | ||||
|         //     lexer.line, lexer.index, tok.type, get_tok_name(tok.type)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,12 +1,12 @@ | ||||
| #define FRONTEND_IMPLEMENTATION | ||||
| #include "../frontend.h" | ||||
| #include <lib/core.h> | ||||
| #include "lexer_log.h" | ||||
| #include "token.h" | ||||
|  | ||||
| #define ROUND_IDX(idx) ((idx) % tokbuf->cap) | ||||
|  | ||||
| tok_t* pop_tok(tok_buf_t* tokbuf) { | ||||
| tok_t* pop_tok(tok_stream_t* tokbuf) { | ||||
|     if (tokbuf->size == 0) { | ||||
|         error("no token to pop"); | ||||
|         LEX_ERROR("no token to pop"); | ||||
|         return NULL; | ||||
|     } | ||||
|     int idx = tokbuf->cur; | ||||
| @ -15,11 +15,11 @@ tok_t* pop_tok(tok_buf_t* tokbuf) { | ||||
|     return tokbuf->buf + idx; | ||||
| } | ||||
|  | ||||
| void flush_peek_tok(tok_buf_t* tokbuf) { | ||||
| void flush_peek_tok(tok_stream_t* tokbuf) { | ||||
|     tokbuf->peek = tokbuf->cur; | ||||
| } | ||||
|  | ||||
| void init_tokbuf(tok_buf_t *tokbuf, void *stream, get_tokbuf_func gettok) { | ||||
| void init_tokbuf(tok_stream_t *tokbuf, void *stream, tok_stream_get_func gettok) { | ||||
|     tokbuf->cur = 0; | ||||
|     tokbuf->end = 0; | ||||
|     tokbuf->peek = 0; | ||||
| @ -30,18 +30,19 @@ void init_tokbuf(tok_buf_t *tokbuf, void *stream, get_tokbuf_func gettok) { | ||||
|     tokbuf->cap = 0; | ||||
| } | ||||
|  | ||||
| tok_t *peek_tok(tok_buf_t *tokbuf) { | ||||
| tok_t *peek_tok(tok_stream_t *tokbuf) { | ||||
|     Assert(tokbuf->size <= tokbuf->cap); | ||||
|     int idx = tokbuf->peek; | ||||
|     tokbuf->peek = ROUND_IDX(idx + 1); | ||||
|     if (tokbuf->size >= tokbuf->cap) { | ||||
|         error("peek too deep, outof array size"); | ||||
|     } | ||||
|  | ||||
|     if (idx == tokbuf->end) { | ||||
|         if (tokbuf->size == tokbuf->cap) { | ||||
|             error("peek_tok buffer overflow"); | ||||
|             LEX_ERROR("peek_tok buffer overflow"); | ||||
|             return NULL; | ||||
|         } | ||||
|         if (tokbuf->gettok == NULL) { | ||||
|             error("peek_tok can not got tok"); | ||||
|             LEX_ERROR("peek_tok can not got tok"); | ||||
|             return NULL; | ||||
|         } | ||||
|         tokbuf->gettok(tokbuf->stream, &(tokbuf->buf[idx])); | ||||
|         tokbuf->size++; | ||||
| @ -51,15 +52,16 @@ tok_t *peek_tok(tok_buf_t *tokbuf) { | ||||
|     return &(tokbuf->buf[idx]); | ||||
| } | ||||
|  | ||||
| tok_type_t peek_tok_type(tok_buf_t* tokbuf) { | ||||
| tok_type_t peek_tok_type(tok_stream_t* tokbuf) { | ||||
|     return peek_tok(tokbuf)->type; | ||||
| } | ||||
|  | ||||
| int expect_pop_tok(tok_buf_t* tokbuf, tok_type_t type) { | ||||
| int expect_pop_tok(tok_stream_t* tokbuf, tok_type_t type) { | ||||
|     flush_peek_tok(tokbuf); | ||||
|     tok_t* tok = peek_tok(tokbuf); | ||||
|     if (tok->type != type) { | ||||
|         error("expected tok: %s, got %s", get_tok_name(type), get_tok_name(tok->type)); | ||||
|         LEX_ERROR("expected tok `%s` but got `%s`", get_tok_name(type), get_tok_name(tok->type)); | ||||
|         return 0; | ||||
|     } else { | ||||
|         pop_tok(tokbuf); | ||||
|     } | ||||
|  | ||||
| @ -51,10 +51,10 @@ enum CSTD_KEYWORD { | ||||
|     X(flush          , TOKEN_FLUSH)                         \ | ||||
|     X("=="           , TOKEN_EQ)                            \ | ||||
|     X("="            , TOKEN_ASSIGN)                        \ | ||||
|     X("++"           , TOKEN_ADD_ADD)                           \ | ||||
|     X("++"           , TOKEN_ADD_ADD)                       \ | ||||
|     X("+="           , TOKEN_ASSIGN_ADD)                    \ | ||||
|     X("+"            , TOKEN_ADD)                           \ | ||||
|     X("--"           , TOKEN_SUB_SUB)                           \ | ||||
|     X("--"           , TOKEN_SUB_SUB)                       \ | ||||
|     X("-="           , TOKEN_ASSIGN_SUB)                    \ | ||||
|     X("->"           , TOKEN_DEREF)                         \ | ||||
|     X("-"            , TOKEN_SUB)                           \ | ||||
| @ -134,7 +134,7 @@ typedef struct tok { | ||||
|     tok_val_t val; | ||||
| } tok_t; | ||||
|  | ||||
| typedef struct tok_buf { | ||||
| typedef struct tok_stream { | ||||
|     int cur; | ||||
|     int end; | ||||
|     int peek; | ||||
| @ -143,15 +143,15 @@ typedef struct tok_buf { | ||||
|     tok_t* buf; | ||||
|     void* stream; | ||||
|     void (*gettok)(void* stream, tok_t* token); | ||||
| } tok_buf_t; | ||||
| } tok_stream_t; | ||||
|  | ||||
| typedef void(*get_tokbuf_func)(void* stream, tok_t* token); | ||||
| void init_tokbuf(tok_buf_t* tokbuf, void* stream, get_tokbuf_func gettok); | ||||
| tok_t* peek_tok(tok_buf_t* tokbuf); | ||||
| tok_t* pop_tok(tok_buf_t* tokbuf); | ||||
| void flush_peek_tok(tok_buf_t* tokbuf); | ||||
| tok_type_t peek_tok_type(tok_buf_t* tokbuf); | ||||
| int expect_pop_tok(tok_buf_t* tokbuf, tok_type_t type); | ||||
| typedef void(*tok_stream_get_func)(void* stream, tok_t* token); | ||||
| void init_tokbuf(tok_stream_t* tokbuf, void* stream, tok_stream_get_func gettok); | ||||
| tok_t* peek_tok(tok_stream_t* tokbuf); | ||||
| tok_t* pop_tok(tok_stream_t* tokbuf); | ||||
| void flush_peek_tok(tok_stream_t* tokbuf); | ||||
| tok_type_t peek_tok_type(tok_stream_t* tokbuf); | ||||
| int expect_pop_tok(tok_stream_t* tokbuf, tok_type_t type); | ||||
| const char* get_tok_name(tok_type_t type); | ||||
|  | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| @ -1,12 +1,11 @@ | ||||
| #include "ast.h" | ||||
| #include "../parser.h" | ||||
| struct ASTNode* new_ast_node(void) { | ||||
|     struct ASTNode* node = xmalloc(sizeof(struct ASTNode)); | ||||
| ast_node_t* new_ast_node(void) { | ||||
|     ast_node_t* node = rt._malloc(sizeof(ast_node_t)); | ||||
|     init_ast_node(node); | ||||
|     return node; | ||||
| } | ||||
| 
 | ||||
| void init_ast_node(struct ASTNode* node) { | ||||
| void init_ast_node(ast_node_t* node) { | ||||
|     node->type = NT_INIT; | ||||
|      | ||||
|     for (int i = 0; i < sizeof(node->children) / sizeof(node->children[0]); i++) { | ||||
| @ -14,7 +13,7 @@ void init_ast_node(struct ASTNode* node) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // struct ASTNode* find_ast_node(struct ASTNode* node, ast_type_t type) {
 | ||||
| // ast_node_t* find_ast_node(ast_node_t* node, ast_type_t type) {
 | ||||
|      | ||||
| // }
 | ||||
| 
 | ||||
| @ -25,7 +24,7 @@ static void pnt_depth(int depth) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // void pnt_ast(struct ASTNode* node, int depth) {
 | ||||
| // void pnt_ast(ast_node_t* node, int depth) {
 | ||||
| //     if (!node) return;
 | ||||
| //     pnt_depth(depth);
 | ||||
| //     switch (node->type) {
 | ||||
| @ -1,10 +1,9 @@ | ||||
| #ifndef __AST_H__ | ||||
| #define __AST_H__ | ||||
| 
 | ||||
| #include "../../frontend.h" | ||||
| #include "../../lexer/lexer.h" | ||||
| #include "../../../../libcore/vector.h" | ||||
| #include "../type.h" | ||||
| #include <lib/utils/ds/vector.h> | ||||
| #include "../lexer/lexer.h" | ||||
| #include "type.h" | ||||
| 
 | ||||
| typedef enum { | ||||
|     NT_INIT, | ||||
| @ -78,98 +77,98 @@ typedef enum { | ||||
|     NT_TERM_TYPE, | ||||
| } ast_type_t; | ||||
| 
 | ||||
| typedef struct ASTNode { | ||||
| typedef struct ast_node { | ||||
|     ast_type_t type; | ||||
| 
 | ||||
|     union { | ||||
|         void *children[6]; | ||||
|         struct { | ||||
|             vector_header(children, struct ASTNode*); | ||||
|             vector_header(children, struct ast_node *); | ||||
|         } root; | ||||
|         struct { | ||||
|             vector_header(children, struct ASTNode*); | ||||
|             vector_header(children, struct ast_node *); | ||||
|         } block; | ||||
|         struct { | ||||
|             struct ASTNode* decl_node; | ||||
|             struct ast_node * decl_node; | ||||
|             tok_t tok; | ||||
|         } syms; | ||||
|         struct { | ||||
|             vector_header(params, struct ASTNode*); | ||||
|             vector_header(params, struct ast_node *); | ||||
|         } params; | ||||
|         struct { | ||||
|             struct ASTNode* name; | ||||
|             struct ASTNode* params; | ||||
|             struct ASTNode* func_decl; | ||||
|             struct ast_node * name; | ||||
|             struct ast_node * params; | ||||
|             struct ast_node * func_decl; | ||||
|         } call; | ||||
|         struct { | ||||
|             struct ASTNode *type; | ||||
|             struct ASTNode *name; | ||||
|             struct ASTNode *expr_stmt; // optional
 | ||||
|             struct ast_node *type; | ||||
|             struct ast_node *name; | ||||
|             struct ast_node *expr_stmt; // optional
 | ||||
|             void* data; | ||||
|         } decl_val; | ||||
|         struct { | ||||
|             struct ASTNode *ret; | ||||
|             struct ASTNode *name; | ||||
|             struct ASTNode *params; // array of params
 | ||||
|             struct ASTNode *def; | ||||
|             struct ast_node *ret; | ||||
|             struct ast_node *name; | ||||
|             struct ast_node *params; // array of params
 | ||||
|             struct ast_node *def; | ||||
|         } decl_func; | ||||
|         struct { | ||||
|             struct ASTNode *decl; | ||||
|             struct ASTNode *body; // optional
 | ||||
|             struct ast_node *decl; | ||||
|             struct ast_node *body; // optional
 | ||||
|             void* data; | ||||
|         } func; | ||||
|         struct { | ||||
|             struct ASTNode *left; | ||||
|             struct ASTNode *right; | ||||
|             struct ASTNode *optional; // optional
 | ||||
|             struct ast_node *left; | ||||
|             struct ast_node *right; | ||||
|             struct ast_node *optional; // optional
 | ||||
|         } expr; | ||||
|         struct { | ||||
|             struct ASTNode *cond; | ||||
|             struct ASTNode *if_stmt;  | ||||
|             struct ASTNode *else_stmt; // optional
 | ||||
|             struct ast_node *cond; | ||||
|             struct ast_node *if_stmt;  | ||||
|             struct ast_node *else_stmt; // optional
 | ||||
|         } if_stmt; | ||||
|         struct { | ||||
|             struct ASTNode *cond; | ||||
|             struct ASTNode *body; | ||||
|             struct ast_node *cond; | ||||
|             struct ast_node *body; | ||||
|         } switch_stmt; | ||||
|         struct { | ||||
|             struct ASTNode *cond; | ||||
|             struct ASTNode *body; | ||||
|             struct ast_node *cond; | ||||
|             struct ast_node *body; | ||||
|         } while_stmt; | ||||
|         struct { | ||||
|             struct ASTNode *body; | ||||
|             struct ASTNode *cond; | ||||
|             struct ast_node *body; | ||||
|             struct ast_node *cond; | ||||
|         } do_while_stmt; | ||||
|         struct { | ||||
|             struct ASTNode *init; | ||||
|             struct ASTNode *cond; // optional
 | ||||
|             struct ASTNode *iter; // optional
 | ||||
|             struct ASTNode *body; | ||||
|             struct ast_node *init; | ||||
|             struct ast_node *cond; // optional
 | ||||
|             struct ast_node *iter; // optional
 | ||||
|             struct ast_node *body; | ||||
|         } for_stmt; | ||||
|         struct { | ||||
|             struct ASTNode *expr_stmt; // optional
 | ||||
|             struct ast_node *expr_stmt; // optional
 | ||||
|         } return_stmt; | ||||
|         struct { | ||||
|             struct ASTNode *label; | ||||
|             struct ast_node *label; | ||||
|         } goto_stmt; | ||||
|         struct { | ||||
|             struct ASTNode *label; | ||||
|             struct ast_node *label; | ||||
|         } label_stmt; | ||||
|         struct { | ||||
|             struct ASTNode *block; | ||||
|             struct ast_node *block; | ||||
|         } block_stmt; | ||||
|         struct { | ||||
|             struct ASTNode *expr_stmt; | ||||
|             struct ast_node *expr_stmt; | ||||
|         } expr_stmt; | ||||
|     }; | ||||
| } ast_node_t; | ||||
| 
 | ||||
| struct ASTNode* new_ast_node(void); | ||||
| void init_ast_node(struct ASTNode* node); | ||||
| void pnt_ast(struct ASTNode* node, int depth); | ||||
| ast_node_t* new_ast_node(void); | ||||
| void init_ast_node(ast_node_t* node); | ||||
| void pnt_ast(ast_node_t* node, int depth); | ||||
| 
 | ||||
| typedef struct parser parser_t; | ||||
| typedef struct ASTNode* (*parse_func_t) (parser_t*); | ||||
| typedef ast_node_t* (*parse_func_t) (parser_t*); | ||||
| 
 | ||||
| void parse_prog(parser_t* parser); | ||||
| ast_node_t* parse_decl(parser_t* parser); | ||||
| @ -182,8 +181,8 @@ ast_node_t* parse_expr(parser_t* parser); | ||||
| ast_node_t* parse_type(parser_t* parser); | ||||
| 
 | ||||
| ast_node_t* new_ast_ident_node(tok_t* tok); | ||||
| ast_node_t* expect_pop_ident(tok_buf_t* tokbuf); | ||||
| ast_node_t* expect_pop_ident(tok_stream_t* tokbuf); | ||||
| 
 | ||||
| int peek_decl(tok_buf_t* tokbuf); | ||||
| int peek_decl(tok_stream_t* tokbuf); | ||||
| 
 | ||||
| #endif | ||||
| @ -1,5 +1,5 @@ | ||||
|  | ||||
| #include "ast.h" | ||||
| #include "../ast.h" | ||||
| #include "../parser.h" | ||||
| #include "../symtab/symtab.h" | ||||
|  | ||||
| @ -17,7 +17,7 @@ ast_node_t* new_ast_node_block() { | ||||
|  | ||||
| ast_node_t* parse_block(parser_t* parser) { | ||||
|     symtab_enter_scope(parser->symtab); | ||||
|     tok_buf_t *tokbuf = &parser->tokbuf; | ||||
|     tok_stream_t *tokbuf = &parser->tokbuf; | ||||
|     flush_peek_tok(tokbuf); | ||||
|     tok_type_t ttype; | ||||
|     ast_node_t* node = new_ast_node_block(); | ||||
|  | ||||
| @ -1,19 +1,19 @@ | ||||
| #include "../ast.h" | ||||
| #include "../parser.h" | ||||
| #include "ast.h" | ||||
| #include "../symtab/symtab.h" | ||||
|  | ||||
| /** | ||||
|  * 0 false | ||||
|  * 1 true | ||||
|  */ | ||||
| int peek_decl(tok_buf_t* tokbuf) { | ||||
| int peek_decl(tok_stream_t* tokbuf) { | ||||
|     flush_peek_tok(tokbuf); | ||||
|     switch (peek_tok_type(tokbuf)) { | ||||
|         case TOKEN_STATIC: | ||||
|         case TOKEN_EXTERN: | ||||
|         case TOKEN_REGISTER: | ||||
|         case TOKEN_TYPEDEF: | ||||
|             error("not impliment"); | ||||
|             LOG_ERROR("not impliment"); | ||||
|             break; | ||||
|         default: | ||||
|             flush_peek_tok(tokbuf); | ||||
| @ -36,7 +36,7 @@ int peek_decl(tok_buf_t* tokbuf) { | ||||
| } | ||||
|  | ||||
| ast_node_t* parse_decl_val(parser_t* parser) { | ||||
|     tok_buf_t* tokbuf = &parser->tokbuf; | ||||
|     tok_stream_t* tokbuf = &parser->tokbuf; | ||||
|     tok_type_t ttype; | ||||
|     flush_peek_tok(tokbuf); | ||||
|  | ||||
| @ -55,28 +55,28 @@ ast_node_t* parse_decl_val(parser_t* parser) { | ||||
|     if (ttype == TOKEN_ASSIGN) { | ||||
|         node->decl_val.expr_stmt = parse_stmt(parser); | ||||
|         if (node->decl_val.expr_stmt->type != NT_STMT_EXPR) { | ||||
|             error("parser_decl_val want stmt_expr"); | ||||
|             LOG_ERROR("parser_decl_val want stmt_expr"); | ||||
|         } | ||||
|     } else if (ttype == TOKEN_SEMICOLON) { | ||||
|         pop_tok(tokbuf); | ||||
|         expect_pop_tok(tokbuf, TOKEN_SEMICOLON); | ||||
|     } else { | ||||
|         error("parser_decl_val syntax error"); | ||||
|         LOG_ERROR("parser_decl_val syntax error"); | ||||
|     } | ||||
|     return node; | ||||
| } | ||||
|  | ||||
| ast_node_t* parse_decl(parser_t* parser) { | ||||
|     tok_buf_t* tokbuf = &parser->tokbuf; | ||||
|     tok_stream_t* tokbuf = &parser->tokbuf; | ||||
|     flush_peek_tok(tokbuf); | ||||
|     tok_type_t ttype; | ||||
|     ast_node_t* node; | ||||
|      | ||||
|     if (peek_decl(tokbuf) == 0) { | ||||
|         error("syntax error expect decl_val TYPE"); | ||||
|         LOG_ERROR("syntax error expect decl_val TYPE"); | ||||
|     } | ||||
|     if (peek_tok_type(tokbuf) != TOKEN_IDENT) { | ||||
|         error("syntax error expect decl_val IDENT"); | ||||
|         LOG_ERROR("syntax error expect decl_val IDENT"); | ||||
|     } | ||||
|  | ||||
|     ttype = peek_tok_type(tokbuf); | ||||
| @ -89,7 +89,7 @@ ast_node_t* parse_decl(parser_t* parser) { | ||||
|             node = parse_decl_val(parser); | ||||
|             break; | ||||
|         default: | ||||
|             error("syntax error expect decl_val ASSIGN or SEMICOLON"); | ||||
|             LOG_ERROR("syntax error expect decl_val ASSIGN or SEMICOLON"); | ||||
|             return NULL; | ||||
|     } | ||||
|     return node; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| #include "../ast.h" | ||||
| #include "../parser.h" | ||||
| #include "ast.h" | ||||
| #include "../symtab/symtab.h" | ||||
|  | ||||
| // Copy from `CParse` | ||||
| @ -33,7 +33,7 @@ enum ParseType { | ||||
|     PREFIX_PARSER, | ||||
| }; | ||||
|  | ||||
| static ast_node_t *parse_subexpression(tok_buf_t* tokbuf, symtab_t *symtab, enum Precedence prec); | ||||
| static ast_node_t *parse_subexpression(tok_stream_t* tokbuf, symtab_t *symtab, enum Precedence prec); | ||||
| #define NEXT(prec) parse_subexpression(tokbuf, symtab, prec) | ||||
|  | ||||
| static ast_node_t* gen_node2(ast_node_t* left, ast_node_t* right, | ||||
| @ -72,7 +72,7 @@ static ast_node_t* gen_node2(ast_node_t* left, ast_node_t* right, | ||||
|     // } | ||||
| } | ||||
|  | ||||
| static ast_node_t* parse_comma(tok_buf_t* tokbuf, symtab_t *symtab, ast_node_t* left) { | ||||
| static ast_node_t* parse_comma(tok_stream_t* tokbuf, symtab_t *symtab, ast_node_t* left) { | ||||
|     ast_node_t* node = new_ast_node(); | ||||
|     node->type = NT_COMMA; | ||||
|     node->expr.left = left; | ||||
| @ -80,7 +80,7 @@ static ast_node_t* parse_comma(tok_buf_t* tokbuf, symtab_t *symtab, ast_node_t* | ||||
|     return node; | ||||
| } | ||||
|  | ||||
| static ast_node_t* parse_assign(tok_buf_t* tokbuf, symtab_t *symtab, ast_node_t* left) { | ||||
| static ast_node_t* parse_assign(tok_stream_t* tokbuf, symtab_t *symtab, ast_node_t* left) { | ||||
|     flush_peek_tok(tokbuf); | ||||
|     tok_type_t ttype = peek_tok_type(tokbuf); | ||||
|     pop_tok(tokbuf); | ||||
| @ -124,14 +124,14 @@ static ast_node_t* parse_assign(tok_buf_t* tokbuf, symtab_t *symtab, ast_node_t* | ||||
|             left = gen_node2(left, NEXT(next), NT_XOR); | ||||
|             break; | ||||
|         default: | ||||
|             error("unsupported operator"); | ||||
|             LOG_ERROR("unsupported operator"); | ||||
|             break; | ||||
|     } | ||||
|     node->expr.right = left; | ||||
|     return node; | ||||
| } | ||||
|  | ||||
| static ast_node_t* parse_cmp(tok_buf_t* tokbuf, symtab_t *symtab, ast_node_t* left) { | ||||
| static ast_node_t* parse_cmp(tok_stream_t* tokbuf, symtab_t *symtab, ast_node_t* left) { | ||||
|     flush_peek_tok(tokbuf); | ||||
|     tok_type_t ttype = peek_tok_type(tokbuf); | ||||
|     pop_tok(tokbuf); | ||||
| @ -164,12 +164,12 @@ static ast_node_t* parse_cmp(tok_buf_t* tokbuf, symtab_t *symtab, ast_node_t* le | ||||
|             node->expr.right = NEXT(PREC_RELATIONAL); | ||||
|             break; | ||||
|         default: | ||||
|             error("invalid operator"); | ||||
|             LOG_ERROR("invalid operator"); | ||||
|     } | ||||
|     return node; | ||||
| } | ||||
|  | ||||
| static ast_node_t* parse_cal(tok_buf_t* tokbuf, symtab_t *symtab, ast_node_t* left) { | ||||
| static ast_node_t* parse_cal(tok_stream_t* tokbuf, symtab_t *symtab, ast_node_t* left) { | ||||
|     flush_peek_tok(tokbuf); | ||||
|     tok_type_t ttype = peek_tok_type(tokbuf); | ||||
|     pop_tok(tokbuf); | ||||
| @ -230,7 +230,7 @@ static ast_node_t* parse_cal(tok_buf_t* tokbuf, symtab_t *symtab, ast_node_t* le | ||||
|     return node; | ||||
| } | ||||
|  | ||||
| static ast_node_t* parse_call(tok_buf_t* tokbuf, symtab_t *symtab, ast_node_t* ident) { | ||||
| static ast_node_t* parse_call(tok_stream_t* tokbuf, symtab_t *symtab, ast_node_t* ident) { | ||||
|     ast_node_t* node = new_ast_node(); | ||||
|     node->type = NT_TERM_CALL; | ||||
|     node->call.name = ident; | ||||
| @ -257,14 +257,14 @@ static ast_node_t* parse_call(tok_buf_t* tokbuf, symtab_t *symtab, ast_node_t* i | ||||
|     ast_node_t* sym = symtab_lookup_symbol(symtab, name); | ||||
|     // TODO check func is match | ||||
|     if (sym == NULL || sym->type != NT_DECL_FUNC) { | ||||
|         error("function not decl %s", name); | ||||
|         LOG_ERROR("function not decl %s", name); | ||||
|     } | ||||
|     node->call.name = ident; | ||||
|     node->call.func_decl = sym; | ||||
|     return node; | ||||
| } | ||||
|  | ||||
| static ast_node_t* parse_paren(tok_buf_t* tokbuf, symtab_t *symtab, ast_node_t* left) { | ||||
| static ast_node_t* parse_paren(tok_stream_t* tokbuf, symtab_t *symtab, ast_node_t* left) { | ||||
|     flush_peek_tok(tokbuf); | ||||
|     expect_pop_tok(tokbuf, TOKEN_L_PAREN); | ||||
|     left = NEXT(PREC_EXPRESSION); | ||||
| @ -273,7 +273,7 @@ static ast_node_t* parse_paren(tok_buf_t* tokbuf, symtab_t *symtab, ast_node_t* | ||||
|     return left; | ||||
| } | ||||
|  | ||||
| typedef ast_node_t* (*parse_expr_fun_t)(tok_buf_t*, symtab_t* , ast_node_t*); | ||||
| typedef ast_node_t* (*parse_expr_fun_t)(tok_stream_t*, symtab_t* , ast_node_t*); | ||||
| static struct expr_prec_table_t { | ||||
|     parse_expr_fun_t parser; | ||||
|     enum Precedence prec; | ||||
| @ -322,7 +322,7 @@ static struct expr_prec_table_t { | ||||
|     [TOKEN_L_PAREN] = {parse_paren, PREC_POSTFIX, INFIX_PARSER}, | ||||
| }; | ||||
|  | ||||
| static ast_node_t *parse_primary_expression(tok_buf_t* tokbuf, symtab_t *symtab) { | ||||
| static ast_node_t *parse_primary_expression(tok_stream_t* tokbuf, symtab_t *symtab) { | ||||
|     flush_peek_tok(tokbuf); | ||||
|  | ||||
|     tok_t* tok = peek_tok(tokbuf); | ||||
| @ -335,7 +335,7 @@ static ast_node_t *parse_primary_expression(tok_buf_t* tokbuf, symtab_t *symtab) | ||||
|         // node->data.data_type = TYPE_INT; | ||||
|         break; | ||||
|     case TOKEN_FLOAT_LITERAL: | ||||
|         warn("float not supported"); | ||||
|         LOG_WARN("float not supported"); | ||||
|         break; | ||||
|     case TOKEN_CHAR_LITERAL: | ||||
|         // node->data.data_type = TYPE_CHAR; | ||||
| @ -350,7 +350,7 @@ static ast_node_t *parse_primary_expression(tok_buf_t* tokbuf, symtab_t *symtab) | ||||
|         } else { | ||||
|             void *sym = symtab_lookup_symbol(symtab, tok->val.str); | ||||
|             if (sym == NULL) { | ||||
|                 error("undefined symbol but use %s", tok->val.str); | ||||
|                 LOG_ERROR("undefined symbol but use %s", tok->val.str); | ||||
|             } | ||||
|             node->type = NT_TERM_IDENT; | ||||
|             node->syms.decl_node = sym; | ||||
| @ -364,7 +364,7 @@ END: | ||||
|     return node; | ||||
| } | ||||
|  | ||||
| static ast_node_t *parse_subexpression(tok_buf_t* tokbuf, symtab_t *symtab, enum Precedence prec) { | ||||
| static ast_node_t *parse_subexpression(tok_stream_t* tokbuf, symtab_t *symtab, enum Precedence prec) { | ||||
|     tok_type_t                  ttype; | ||||
|     struct expr_prec_table_t*   work; | ||||
|     ast_node_t*                 left; | ||||
| @ -397,7 +397,7 @@ static ast_node_t *parse_subexpression(tok_buf_t* tokbuf, symtab_t *symtab, enum | ||||
| } | ||||
|  | ||||
| ast_node_t* parse_expr(parser_t* parser) { | ||||
|     tok_buf_t* tokbuf = &(parser->tokbuf); | ||||
|     tok_stream_t* tokbuf = &(parser->tokbuf); | ||||
|     symtab_t *symtab = parser->symtab; | ||||
|     flush_peek_tok(tokbuf); | ||||
|     tok_type_t ttype = peek_tok_type(tokbuf); | ||||
| @ -419,7 +419,7 @@ ast_node_t* parse_expr(parser_t* parser) { | ||||
|     case TOKEN_IDENT: | ||||
|         return NEXT(PREC_EXPRESSION); | ||||
|     default: | ||||
|         error("Want expr but not got %s", get_tok_name(ttype)); | ||||
|         LOG_ERROR("Want expr but not got %s", get_tok_name(ttype)); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,13 +1,13 @@ | ||||
| #include "../ast.h" | ||||
| #include "../parser.h" | ||||
| #include "../symtab/symtab.h" | ||||
| #include "ast.h" | ||||
|  | ||||
| #ifndef FUNC_PARAM_CACHE_SIZE | ||||
| #define FUNC_PARAM_CACHE_SIZE 32  // 合理初始值,可覆盖99%常见情况 | ||||
| #endif | ||||
|  | ||||
| // TODO 语义分析压入符号表 | ||||
| static void parse_params(parser_t* parser, tok_buf_t* cache, ast_node_t* node) { | ||||
| static void parse_params(parser_t* parser, tok_stream_t* cache, ast_node_t* node) { | ||||
|     flush_peek_tok(cache); | ||||
|     tok_type_t ttype; | ||||
|     ast_node_t *params = new_ast_node(); | ||||
| @ -23,10 +23,10 @@ static void parse_params(parser_t* parser, tok_buf_t* cache, ast_node_t* node) { | ||||
|         case TOKEN_ELLIPSIS: | ||||
|             ttype = peek_tok_type(cache); | ||||
|             if (ttype != TOKEN_R_PAREN) { | ||||
|                 error("... must be a last parameter list (expect ')')"); | ||||
|                 LOG_ERROR("... must be a last parameter list (expect ')')"); | ||||
|             } | ||||
|             // TODO | ||||
|             error("not implement"); | ||||
|             LOG_ERROR("not implement"); | ||||
|             break; | ||||
|         case TOKEN_IDENT: | ||||
|             // TODO 静态数组 | ||||
| @ -62,13 +62,13 @@ static void parse_params(parser_t* parser, tok_buf_t* cache, ast_node_t* node) { | ||||
|             //     flush_peek_tok(tokbuf); | ||||
|             //     continue; | ||||
|             // } | ||||
|             // error("function expected ')' or ','\n"); | ||||
|             // LOG_ERROR("function expected ')' or ','\n"); | ||||
|         } | ||||
|         pop_tok(cache); | ||||
|     } | ||||
| } | ||||
|  | ||||
| ast_type_t check_is_func_decl(tok_buf_t* tokbuf, tok_buf_t* cache) { | ||||
| ast_type_t check_is_func_decl(tok_stream_t* tokbuf, tok_stream_t* cache) { | ||||
|     expect_pop_tok(tokbuf, TOKEN_L_PAREN); | ||||
|     int depth = 1; | ||||
|      | ||||
| @ -76,7 +76,7 @@ ast_type_t check_is_func_decl(tok_buf_t* tokbuf, tok_buf_t* cache) { | ||||
|         tok_t* tok = peek_tok(tokbuf); | ||||
|         pop_tok(tokbuf); | ||||
|         if (cache->size >= cache->cap - 1) { | ||||
|             error("function parameter list too long"); | ||||
|             LOG_ERROR("function parameter list too long"); | ||||
|         } | ||||
|         cache->buf[cache->size++] = *tok; | ||||
|         switch (tok->type) { | ||||
| @ -100,7 +100,7 @@ ast_type_t check_is_func_decl(tok_buf_t* tokbuf, tok_buf_t* cache) { | ||||
|             return NT_FUNC; | ||||
|             break; | ||||
|         default: | ||||
|             error("function define or decl need '{' or ';' but you don't got"); | ||||
|             LOG_ERROR("function define or decl need '{' or ';' but you don't got"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -114,14 +114,14 @@ static ast_node_t* new_ast_node_funcdecl(ast_node_t* ret, ast_node_t* name) { | ||||
| } | ||||
|  | ||||
| void parse_func(parser_t* parser) { | ||||
|     tok_buf_t* tokbuf = &(parser->tokbuf); | ||||
|     tok_stream_t* tokbuf = &(parser->tokbuf); | ||||
|     flush_peek_tok(tokbuf); | ||||
|     ast_node_t* ret_node = parse_type(parser); | ||||
|     ast_node_t* name_node = expect_pop_ident(tokbuf); | ||||
|     const char* func_name = name_node->syms.tok.val.str; | ||||
|     ast_node_t* decl = new_ast_node_funcdecl(ret_node, name_node); | ||||
|  | ||||
|     tok_buf_t cache; | ||||
|     tok_stream_t cache; | ||||
|     init_tokbuf(&cache, NULL, NULL); | ||||
|     cache.cap = FUNC_PARAM_CACHE_SIZE; | ||||
|     tok_t buf[FUNC_PARAM_CACHE_SIZE]; | ||||
| @ -132,12 +132,12 @@ void parse_func(parser_t* parser) { | ||||
|     ast_node_t* prev = symtab_add_symbol(parser->symtab, func_name, decl, 1); | ||||
|     if (prev != NULL) { | ||||
|         if (prev->type != NT_DECL_FUNC) { | ||||
|             error("the symbol duplicate old is %d, new is func", prev->type); | ||||
|             LOG_ERROR("the symbol duplicate old is %d, new is func", prev->type); | ||||
|         } | ||||
|         // TODO check redeclare func is match | ||||
|         if (type == NT_FUNC) { | ||||
|             // TODO Free decl; | ||||
|             free(decl); | ||||
|             rt._free(decl); | ||||
|             decl = prev; | ||||
|             goto FUNC; | ||||
|         } | ||||
| @ -151,7 +151,7 @@ void parse_func(parser_t* parser) { | ||||
| FUNC: | ||||
|     // 该data临时用于判断是否重复定义 | ||||
|     if (decl->decl_func.def != NULL) { | ||||
|         error("redefinition of function %s", func_name); | ||||
|         LOG_ERROR("redefinition of function %s", func_name); | ||||
|     } | ||||
|  | ||||
|     ast_node_t* node = new_ast_node(); | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| #include "../ast.h" | ||||
| #include "../parser.h" | ||||
| #include "ast.h" | ||||
|  | ||||
| #ifndef PROG_MAX_NODE_SIZE | ||||
| #define PROG_MAX_NODE_SIZE (1024 * 4) | ||||
| @ -13,7 +13,7 @@ void parse_prog(parser_t* parser) { | ||||
|      * same as | ||||
|      * Program := Declaration* Definition* | ||||
|      */ | ||||
|     tok_buf_t *tokbuf = &(parser->tokbuf); | ||||
|     tok_stream_t *tokbuf = &(parser->tokbuf); | ||||
|     parser->root = new_ast_node(); | ||||
|     ast_node_t* node; | ||||
|     parser->root->type = NT_ROOT; | ||||
|  | ||||
| @ -1,8 +1,8 @@ | ||||
| #include "../ast.h" | ||||
| #include "../parser.h" | ||||
| #include "ast.h" | ||||
|  | ||||
| ast_node_t* parse_stmt(parser_t* parser) { | ||||
|     tok_buf_t* tokbuf = &parser->tokbuf; | ||||
|     tok_stream_t* tokbuf = &parser->tokbuf; | ||||
|     flush_peek_tok(tokbuf); | ||||
|     tok_type_t ttype = peek_tok_type(tokbuf); | ||||
|     ast_node_t* node = new_ast_node(); | ||||
| @ -66,7 +66,7 @@ ast_node_t* parse_stmt(parser_t* parser) { | ||||
|         node->do_while_stmt.body = parse_stmt(parser); | ||||
|         ttype = peek_tok_type(tokbuf); | ||||
|         if (ttype != TOKEN_WHILE) { | ||||
|             error("expected while after do"); | ||||
|             LOG_ERROR("expected while after do"); | ||||
|         } | ||||
|         pop_tok(tokbuf); | ||||
|         expect_pop_tok(tokbuf, TOKEN_L_PAREN); | ||||
| @ -83,7 +83,7 @@ ast_node_t* parse_stmt(parser_t* parser) { | ||||
|         pop_tok(tokbuf); | ||||
|         ttype = peek_tok_type(tokbuf); | ||||
|         if (ttype != TOKEN_L_PAREN) { | ||||
|             error("expected ( after for"); | ||||
|             LOG_ERROR("expected ( after for"); | ||||
|         } | ||||
|         pop_tok(tokbuf); | ||||
|  | ||||
| @ -170,7 +170,7 @@ ast_node_t* parse_stmt(parser_t* parser) { | ||||
|         // find symbol table | ||||
|         ttype = peek_tok_type(tokbuf); | ||||
|         if (ttype != TOKEN_IDENT) { | ||||
|             error("expect identifier after goto"); | ||||
|             LOG_ERROR("expect identifier after goto"); | ||||
|         } | ||||
|         expect_pop_tok(tokbuf, TOKEN_SEMICOLON); | ||||
|         // TODO filling label | ||||
| @ -211,7 +211,7 @@ ast_node_t* parse_stmt(parser_t* parser) { | ||||
|     case TOKEN_CASE: { | ||||
|         // TODO label switch | ||||
|         pop_tok(tokbuf); | ||||
|         error("unimplemented switch label"); | ||||
|         LOG_ERROR("unimplemented switch label"); | ||||
|         node->label_stmt.label = parse_expr(parser); | ||||
|         // TODO 该表达式为const int | ||||
|         expect_pop_tok(tokbuf, TOKEN_COLON); | ||||
| @ -234,7 +234,7 @@ ast_node_t* parse_stmt(parser_t* parser) { | ||||
|         flush_peek_tok(tokbuf); | ||||
|         ttype = peek_tok_type(tokbuf); | ||||
|         if (ttype != TOKEN_SEMICOLON) { | ||||
|             error("exp must end with \";\""); | ||||
|             LOG_ERROR("exp must end with \";\""); | ||||
|         } | ||||
|         pop_tok(tokbuf); | ||||
|         node->type = NT_STMT_EXPR; | ||||
|  | ||||
| @ -1,10 +1,10 @@ | ||||
| #include "../ast.h" | ||||
| #include "../parser.h" | ||||
| #include "../type.h" | ||||
| #include "ast.h" | ||||
|  | ||||
| ast_node_t* new_ast_ident_node(tok_t* tok) { | ||||
|     if (tok->type != TOKEN_IDENT) { | ||||
|         error("syntax error: want identifier but got %d", tok->type); | ||||
|         LOG_ERROR("syntax error: want identifier but got %d", tok->type); | ||||
|     } | ||||
|     ast_node_t* node = new_ast_node(); | ||||
|     node->type = NT_TERM_IDENT; | ||||
| @ -13,7 +13,7 @@ ast_node_t* new_ast_ident_node(tok_t* tok) { | ||||
|     return node; | ||||
| } | ||||
|  | ||||
| ast_node_t* expect_pop_ident(tok_buf_t* tokbuf) { | ||||
| ast_node_t* expect_pop_ident(tok_stream_t* tokbuf) { | ||||
|     flush_peek_tok(tokbuf); | ||||
|     tok_t* tok = peek_tok(tokbuf); | ||||
|     ast_node_t* node = new_ast_ident_node(tok); | ||||
| @ -22,7 +22,7 @@ ast_node_t* expect_pop_ident(tok_buf_t* tokbuf) { | ||||
| } | ||||
|  | ||||
| ast_node_t* parse_type(parser_t* parser) { | ||||
|     tok_buf_t* tokbuf = &parser->tokbuf; | ||||
|     tok_stream_t* tokbuf = &parser->tokbuf; | ||||
|     flush_peek_tok(tokbuf); | ||||
|     tok_type_t ttype = peek_tok_type(tokbuf); | ||||
|     data_type_t dtype; | ||||
| @ -35,7 +35,7 @@ ast_node_t* parse_type(parser_t* parser) { | ||||
|         case TOKEN_FLOAT:   dtype = TYPE_FLOAT; break; | ||||
|         case TOKEN_DOUBLE:  dtype = TYPE_DOUBLE; break; | ||||
|         default: | ||||
|             error("无效的类型说明符"); | ||||
|             LOG_ERROR("无效的类型说明符"); | ||||
|     } | ||||
|  | ||||
|     ast_node_t* node = new_ast_node(); | ||||
|  | ||||
| @ -1,13 +1,16 @@ | ||||
| #include <lib/core.h> | ||||
| #include "parser.h" | ||||
| #include "type.h" | ||||
|  | ||||
| void init_parser(parser_t* parser, lexer_t* lexer, symtab_t* symtab) { | ||||
|     init_lib_core(); | ||||
|      | ||||
|     parser->cur_node = NULL; | ||||
|     parser->root = NULL; | ||||
|  | ||||
|     parser->lexer = lexer; | ||||
|     parser->symtab = symtab; | ||||
|     init_tokbuf(&parser->tokbuf, lexer, (get_tokbuf_func)get_valid_token); | ||||
|     init_tokbuf(&parser->tokbuf, lexer, (tok_stream_get_func)get_valid_token); | ||||
|     parser->tokbuf.cap = sizeof(parser->TokenBuffer) / sizeof(parser->TokenBuffer[0]); | ||||
|     parser->tokbuf.buf = parser->TokenBuffer; | ||||
| } | ||||
|  | ||||
| @ -1,20 +1,19 @@ | ||||
| #ifndef __PARSER_H__ | ||||
| #define __PARSER_H__ | ||||
|  | ||||
| #include "../frontend.h" | ||||
|  | ||||
| #include "../lexer/lexer.h" | ||||
| #include "ast.h" | ||||
| typedef struct lexer lexer_t; | ||||
| typedef struct symtab symtab_t; | ||||
| #define PARSER_MAX_TOKEN_QUEUE 16 | ||||
|  | ||||
| typedef struct parser { | ||||
|     struct ASTNode* root; | ||||
|     struct ASTNode* cur_node; | ||||
|     ast_node_t* root; | ||||
|     ast_node_t* cur_node; | ||||
|      | ||||
|     lexer_t* lexer; | ||||
|     symtab_t* symtab; | ||||
|     tok_buf_t tokbuf; | ||||
|     tok_stream_t tokbuf; | ||||
|     tok_t TokenBuffer[PARSER_MAX_TOKEN_QUEUE]; | ||||
|     int err_level; | ||||
| } parser_t; | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| // symtab.c | ||||
| #include "../../frontend.h" | ||||
| #include <lib/core.h> | ||||
| #include "scope.h" | ||||
| #include "symtab.h" | ||||
|  | ||||
| @ -24,7 +25,7 @@ void symtab_enter_scope(symtab_t* symtab) { | ||||
| void symtab_leave_scope(symtab_t* symtab) { | ||||
|     Scope * scope = symtab->cur_scope; | ||||
|     if (scope == NULL) { | ||||
|         error("cannot leave NULL scope or global scope"); | ||||
|         LOG_ERROR("cannot leave NULL scope or global scope"); | ||||
|     } | ||||
|     symtab->cur_scope = symtab->cur_scope->parent; | ||||
|     scope_destroy(scope); | ||||
| @ -35,7 +36,7 @@ void* symtab_add_symbol(symtab_t* symtab, const char* name, void* ast_node, int | ||||
|     void* node = scope_lookup_current(scope, name); | ||||
|     if (node != NULL) { | ||||
|         if (!can_duplicate) { | ||||
|             error("duplicate symbol %s", name); | ||||
|             LOG_ERROR("duplicate symbol %s", name); | ||||
|         } | ||||
|         return node; | ||||
|     } | ||||
|  | ||||
| @ -1,20 +1,23 @@ | ||||
| # 编译器设置 | ||||
| CC = gcc | ||||
| AR = ar | ||||
| CFLAGS = -g -Wall | ||||
| CFLAGS = -g -Wall -I../.. | ||||
|  | ||||
| IR_DIR = ./ir | ||||
|  | ||||
| # 源文件列表 | ||||
| SRCS = \ | ||||
| 	ir.c \ | ||||
| 	ir_ast.c \ | ||||
| 	ir_lib.c \ | ||||
| 	ir_type.c | ||||
| 	middleend.c \ | ||||
| 	$(IR_DIR)/ir.c \ | ||||
| 	$(IR_DIR)/ir_ast.c \ | ||||
| 	$(IR_DIR)/ir_lib.c \ | ||||
| 	$(IR_DIR)/ir_type.c | ||||
|  | ||||
| # 生成目标文件列表 | ||||
| OBJS = $(SRCS:.c=.o) | ||||
|  | ||||
| # 最终目标 | ||||
| TARGET = libir.a | ||||
| TARGET = libmiddleend.a | ||||
|  | ||||
| all: $(TARGET) | ||||
|  | ||||
| @ -27,4 +30,4 @@ $(TARGET): $(OBJS) | ||||
| clean: | ||||
| 	rm -f $(OBJS) $(TARGET) | ||||
|  | ||||
| .PHONY: all clean | ||||
| .PHONY: all clean | ||||
|  | ||||
| @ -2,9 +2,7 @@ | ||||
| #ifndef IR_CORE_H | ||||
| #define IR_CORE_H | ||||
| 
 | ||||
| #include "../../libcore/vector.h" | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| #include <lib/utils/ds/vector.h> | ||||
| 
 | ||||
| // 错误码定义
 | ||||
| typedef enum { | ||||
| @ -26,12 +24,12 @@ typedef struct { | ||||
|     union { | ||||
|         struct { | ||||
|             struct ir_type *base; | ||||
|             size_t len; | ||||
|             rt_size_t len; | ||||
|         } arr; | ||||
|         struct { | ||||
|             struct ir_type *ret; | ||||
|             struct ir_type **params; | ||||
|             size_t param_cnt; | ||||
|             rt_size_t param_cnt; | ||||
|         } func; | ||||
|     }; | ||||
| } ir_type_t; | ||||
| @ -151,9 +149,4 @@ struct ir_node { | ||||
|     } data; | ||||
| }; | ||||
| 
 | ||||
| extern ir_prog_t prog; | ||||
| struct ASTNode; | ||||
| void gen_ir_from_ast(struct ASTNode* node); | ||||
| 
 | ||||
| 
 | ||||
| #endif // IR_CORE_H
 | ||||
| @ -1,7 +1,8 @@ | ||||
| #include "ir.h" | ||||
| #include "ir_lib.h" | ||||
| #include "ir_type.h" | ||||
| #include "../frontend/frontend.h" | ||||
| #include "../../frontend/frontend.h" | ||||
| #include "../../frontend/parser/ast.h" | ||||
| 
 | ||||
| // 上下文结构,记录生成过程中的状态
 | ||||
| typedef struct { | ||||
| @ -10,6 +11,7 @@ typedef struct { | ||||
| } IRGenContext; | ||||
| IRGenContext ctx; | ||||
| ir_prog_t prog; | ||||
| void _gen_ir_from_ast(ast_node_t* node); | ||||
| 
 | ||||
| static void emit_instr(ir_bblock_t* block, ir_node_t* node) { | ||||
|     if (block == NULL) block = ctx.cur_block; | ||||
| @ -53,7 +55,7 @@ static ir_node_t* gen_ir_term(ast_node_t* node) { | ||||
|             return call; | ||||
|         } | ||||
|         default: { | ||||
|             assert(0); | ||||
|             Panic("gen_ir_expr: unknown node type"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -164,10 +166,10 @@ static ir_node_t* gen_ir_expr(ast_node_t* node) { | ||||
|             BINOP(IR_OP_GE); break; | ||||
|         } | ||||
|         case NT_AND_AND:// (expr) && (expr)
 | ||||
|         error("unimpliment"); | ||||
|         LOG_ERROR("unimpliment"); | ||||
|             break; | ||||
|         case NT_OR_OR:// (expr) || (expr)
 | ||||
|         error("unimpliment"); | ||||
|         LOG_ERROR("unimpliment"); | ||||
|             break; | ||||
|         case NT_NOT: { | ||||
|             // ! (expr)
 | ||||
| @ -189,7 +191,7 @@ static ir_node_t* gen_ir_expr(ast_node_t* node) { | ||||
|         // case NT_COND: // (expr) ? (expr) : (expr)
 | ||||
|         default: { | ||||
|             // TODO self error msg
 | ||||
|             error("Unsupported IR generation for AST node type %d", node->type); | ||||
|             LOG_ERROR("Unsupported IR generation for AST node type %d", node->type); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| @ -198,7 +200,7 @@ static ir_node_t* gen_ir_expr(ast_node_t* node) { | ||||
| } | ||||
| 
 | ||||
| static void gen_ir_func(ast_node_t* node, ir_func_t* func) { | ||||
|     assert(node->type == NT_FUNC); | ||||
|     Assert(node->type == NT_FUNC); | ||||
|     ir_bblock_t *entry = new_ir_bblock("entry"); | ||||
|     vector_push(func->bblocks, entry); | ||||
| 
 | ||||
| @ -217,7 +219,7 @@ static void gen_ir_func(ast_node_t* node, ir_func_t* func) { | ||||
|         decl->type = &type_i32; | ||||
|         param->decl_val.data = decl; | ||||
|     } | ||||
|     gen_ir_from_ast(node->func.body); | ||||
|     _gen_ir_from_ast(node->func.body); | ||||
| 
 | ||||
|     ctx = prev_ctx; | ||||
| } | ||||
| @ -248,13 +250,13 @@ void gen_ir_jmp(ast_node_t* node) { | ||||
|             // true block
 | ||||
|             vector_push(ctx.cur_func->bblocks, trueb); | ||||
|             ctx.cur_block = trueb; | ||||
|             gen_ir_from_ast(node->if_stmt.if_stmt); | ||||
|             _gen_ir_from_ast(node->if_stmt.if_stmt); | ||||
|              | ||||
|             // else block
 | ||||
|             if (node->if_stmt.else_stmt != NULL) { | ||||
|                 vector_push(ctx.cur_func->bblocks, falseb); | ||||
|                 ctx.cur_block = falseb; | ||||
|                 gen_ir_from_ast(node->if_stmt.else_stmt); | ||||
|                 _gen_ir_from_ast(node->if_stmt.else_stmt); | ||||
|                 ir_node_t* jmp; | ||||
|                  | ||||
|                 ctx.cur_block = endb; | ||||
| @ -285,7 +287,7 @@ void gen_ir_jmp(ast_node_t* node) { | ||||
|             // Body:
 | ||||
|             ir_node_t* jmp; | ||||
|             ctx.cur_block = bodyb; | ||||
|             gen_ir_from_ast(node->while_stmt.body); | ||||
|             _gen_ir_from_ast(node->while_stmt.body); | ||||
|             NEW_IR_JMP(jmp, entryb); | ||||
|             emit_instr(NULL, jmp); | ||||
| 
 | ||||
| @ -304,7 +306,7 @@ void gen_ir_jmp(ast_node_t* node) { | ||||
| 
 | ||||
|             // Body:
 | ||||
|             ctx.cur_block = bodyb; | ||||
|             gen_ir_from_ast(node->do_while_stmt.body); | ||||
|             _gen_ir_from_ast(node->do_while_stmt.body); | ||||
|             ir_node_t* jmp; | ||||
|             NEW_IR_JMP(jmp, entryb); | ||||
|             emit_instr(NULL, jmp); | ||||
| @ -324,7 +326,7 @@ void gen_ir_jmp(ast_node_t* node) { | ||||
|             ir_bblock_t* endb   = bblocks[2]; | ||||
| 
 | ||||
|             if (node->for_stmt.init) { | ||||
|                 gen_ir_from_ast(node->for_stmt.init); | ||||
|                 _gen_ir_from_ast(node->for_stmt.init); | ||||
|             } | ||||
|             ir_node_t* entry; | ||||
|             NEW_IR_JMP(entry, entryb); | ||||
| @ -342,7 +344,7 @@ void gen_ir_jmp(ast_node_t* node) { | ||||
| 
 | ||||
|             // Body:
 | ||||
|             ctx.cur_block = bodyb; | ||||
|             gen_ir_from_ast(node->for_stmt.body); | ||||
|             _gen_ir_from_ast(node->for_stmt.body); | ||||
|             if (node->for_stmt.iter) { | ||||
|                 gen_ir_expr(node->for_stmt.iter); | ||||
|             } | ||||
| @ -355,18 +357,21 @@ void gen_ir_jmp(ast_node_t* node) { | ||||
|             break; | ||||
|         } | ||||
|         default: | ||||
|             error("ir jmp can't hit here"); | ||||
|             LOG_ERROR("ir jmp can't hit here"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void gen_ir_from_ast(ast_node_t* node) { | ||||
| ir_prog_t* gen_ir_from_ast(ast_node_t* root) { | ||||
|     Assert(root->type == NT_ROOT); | ||||
|     for (int i = 0; i < root->root.children.size; i ++) { | ||||
|         _gen_ir_from_ast(root->root.children.data[i]); | ||||
|     } | ||||
|     // _gen_ir_from_ast(root);
 | ||||
|     return &prog; | ||||
| } | ||||
| 
 | ||||
| void _gen_ir_from_ast(ast_node_t* node) { | ||||
|     switch (node->type) { | ||||
|         case NT_ROOT: { | ||||
|             for (int i = 0; i < node->root.children.size; i ++) { | ||||
|                 gen_ir_from_ast(node->root.children.data[i]); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
|         case NT_DECL_FUNC: { | ||||
|             ir_func_t* func = new_ir_func(node->decl_func.name->syms.tok.val.str, &type_i32); | ||||
|             if (node->decl_func.def == NULL) { | ||||
| @ -398,12 +403,12 @@ void gen_ir_from_ast(ast_node_t* node) { | ||||
|             break; | ||||
|         } | ||||
|         case NT_STMT_BLOCK: { | ||||
|             gen_ir_from_ast(node->block_stmt.block); | ||||
|             _gen_ir_from_ast(node->block_stmt.block); | ||||
|             break; | ||||
|         } | ||||
|         case NT_BLOCK: { | ||||
|             for (int i = 0; i < node->block.children.size; i ++) { | ||||
|                 gen_ir_from_ast(node->block.children.data[i]); | ||||
|                 _gen_ir_from_ast(node->block.children.data[i]); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| @ -420,7 +425,7 @@ void gen_ir_from_ast(ast_node_t* node) { | ||||
|             ir->type = &type_i32; | ||||
|             node->decl_val.data = ir; | ||||
|             if (node->decl_val.expr_stmt != NULL) { | ||||
|                 gen_ir_from_ast(node->decl_val.expr_stmt); | ||||
|                 _gen_ir_from_ast(node->decl_val.expr_stmt); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| @ -433,7 +438,7 @@ void gen_ir_from_ast(ast_node_t* node) { | ||||
|         } | ||||
|         default: | ||||
|             // TODO: 错误处理
 | ||||
|             error("unknown node type"); | ||||
|             LOG_ERROR("unknown node type"); | ||||
|             break; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										7
									
								
								ccompiler/middleend/ir/ir_ast.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								ccompiler/middleend/ir/ir_ast.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| #ifndef __IR_AST_H__ | ||||
| #define __IR_AST_H__ | ||||
|  | ||||
| #include "ir.h" | ||||
| ir_prog_t* gen_ir_from_ast(ast_node_t* node); | ||||
|  | ||||
| #endif // | ||||
							
								
								
									
										76
									
								
								ccompiler/middleend/ir/ir_dump.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								ccompiler/middleend/ir/ir_dump.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,76 @@ | ||||
| #include "ir.h" | ||||
| #include "ir_lib.h" | ||||
| #include "ir_type.h" | ||||
| #include <stdio.h> | ||||
| #include <assert.h> | ||||
|  | ||||
| typedef struct ir_dump { | ||||
|     FILE* fp; | ||||
| } ir_dump_t; | ||||
|  | ||||
|  | ||||
| void dump_ir_node(ir_node_t* node, ir_dump_t* dump) { | ||||
|     fprintf(dump->fp, "%%%p", node); | ||||
|     switch (node->tag) { | ||||
|         case IR_NODE_ALLOC: { | ||||
|             node->type = NULL; | ||||
|             // fprintf(dump->fp, "%p\n", ); | ||||
|             break; | ||||
|         } | ||||
|         case IR_NODE_BRANCH: { | ||||
|             node->data.branch.cond = NULL; | ||||
|             node->data.branch.true_bblock = NULL; | ||||
|             node->data.branch.false_bblock = NULL; | ||||
|             break; | ||||
|         } | ||||
|         case IR_NODE_CALL: { | ||||
|             vector_init(node->data.call.args); | ||||
|             node->data.call.callee = NULL; | ||||
|             break; | ||||
|         } | ||||
|         case IR_NODE_CONST_INT: { | ||||
|             node->data.const_int.val = 0; | ||||
|             break; | ||||
|         } | ||||
|         case IR_NODE_JUMP: { | ||||
|             node->data.jump.target_bblock = NULL; | ||||
|             break; | ||||
|         } | ||||
|         case IR_NODE_LOAD: { | ||||
|             node->data.load.target = NULL; | ||||
|             break; | ||||
|         } | ||||
|         case IR_NODE_STORE: { | ||||
|             node->data.store.target = NULL; | ||||
|             node->data.store.value = NULL; | ||||
|             break; | ||||
|         } | ||||
|         case IR_NODE_OP: { | ||||
|             node->data.op.op = 0; | ||||
|             node->data.op.lhs = NULL; | ||||
|             node->data.op.rhs = NULL; | ||||
|             break; | ||||
|         } | ||||
|         case IR_NODE_RET: { | ||||
|             node->data.ret.ret_val = NULL; | ||||
|             break; | ||||
|         } | ||||
|         case IR_NODE_GET_PTR: { | ||||
|         } | ||||
|         default: { | ||||
|             assert(0); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void dump_ir_bblock(ir_bblock_t* block) { | ||||
|  | ||||
| } | ||||
|  | ||||
| void dump_ir_func(ir_func_t* func) { | ||||
|  | ||||
| } | ||||
|  | ||||
| void dump_ir_prog(ir_prog_t* prog) { | ||||
|  | ||||
| } | ||||
| @ -77,10 +77,6 @@ ir_node_t* new_ir_node(const char* name, ir_node_tag_t tag) { | ||||
|     return node; | ||||
| } | ||||
| 
 | ||||
| void dump_ir_node(ir_node_t* node) { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void free_irnode() { | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										0
									
								
								ccompiler/middleend/middleend.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								ccompiler/middleend/middleend.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										7
									
								
								ccompiler/middleend/middleend.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								ccompiler/middleend/middleend.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| #ifndef __SMCC_MIDDLEEND_H__ | ||||
| #define __SMCC_MIDDLEEND_H__ | ||||
|  | ||||
| #include "ir/ir.h" | ||||
| #include "ir/ir_ast.h" | ||||
|  | ||||
| #endif // __SMCC_MIDDLEEND_H__ | ||||
							
								
								
									
										35
									
								
								lib/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								lib/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| # 编译器设置 | ||||
| CC = gcc | ||||
| AR = ar | ||||
| CFLAGS = -g -Wall -I.. | ||||
|  | ||||
| # 源文件路径 | ||||
| RT_DIR = ./rt | ||||
| LOG_DIR = ./rt/log | ||||
|  | ||||
| # 源文件列表 | ||||
| SRCS = \ | ||||
| 	$(RT_DIR)/std/rt_std.c \ | ||||
| 	./core.c \ | ||||
| 	$(RT_DIR)/rt.c \ | ||||
| 	$(RT_DIR)/rt_alloc.c \ | ||||
| 	$(LOG_DIR)/log.c | ||||
|  | ||||
| # 生成目标文件列表 | ||||
| OBJS = $(SRCS:.c=.o) | ||||
|  | ||||
| # 最终目标 | ||||
| TARGET = libcore.a | ||||
|  | ||||
| all: $(TARGET) | ||||
|  | ||||
| $(TARGET): $(OBJS) | ||||
| 	$(AR) rcs $@ $^ | ||||
|  | ||||
| %.o: %.c | ||||
| 	$(CC) $(CFLAGS) -c -o $@ $< | ||||
|  | ||||
| clean: | ||||
| 	rm -f $(OBJS) $(TARGET) | ||||
|  | ||||
| .PHONY: all clean | ||||
							
								
								
									
										10
									
								
								lib/core.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								lib/core.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| #include "core.h" | ||||
|  | ||||
| void init_lib_core() { | ||||
|     static int init = 0; | ||||
|     if (init) return; | ||||
|     init_rt(); | ||||
|  | ||||
|     init += 1; | ||||
|     Assert(init == 1); | ||||
| } | ||||
							
								
								
									
										9
									
								
								lib/core.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/core.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| #ifndef __SMCC_LIB_CORE_H__ | ||||
| #define __SMCC_LIB_CORE_H__ | ||||
|  | ||||
| #include "rt/rt.h" | ||||
|  | ||||
| // You MUST BE call this by the start | ||||
| void init_lib_core(); | ||||
|  | ||||
| #endif // __SMCC_LIB_CORE_H__ | ||||
							
								
								
									
										33
									
								
								lib/rt/log/color.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								lib/rt/log/color.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| #ifndef __SMCC_TERMINAL_COLOR_H__ | ||||
| #define __SMCC_TERMINAL_COLOR_H__ | ||||
|  | ||||
| #define ANSI_FG_BLACK   "\33[30m" | ||||
| #define ANSI_FG_RED     "\33[31m" | ||||
| #define ANSI_FG_GREEN   "\33[32m" | ||||
| #define ANSI_FG_YELLOW  "\33[33m" | ||||
| #define ANSI_FG_BLUE    "\33[34m" | ||||
| #define ANSI_FG_MAGENTA "\33[35m" | ||||
| #define ANSI_FG_CYAN    "\33[36m" | ||||
| #define ANSI_FG_WHITE   "\33[37m" | ||||
|  | ||||
| #define ANSI_BG_BLACK   "\33[40m" | ||||
| #define ANSI_BG_RED     "\33[41m" | ||||
| #define ANSI_BG_GREEN   "\33[42m" | ||||
| #define ANSI_BG_YELLOW  "\33[43m" | ||||
| #define ANSI_BG_BLUE    "\33[44m" | ||||
| #define ANSI_BG_MAGENTA "\33[35m" | ||||
| #define ANSI_BG_CYAN    "\33[46m" | ||||
| #define ANSI_BG_WHITE   "\33[47m" | ||||
|  | ||||
| #define ANSI_UNDERLINED "\33[4m" | ||||
| #define ANSI_BOLD       "\33[1m" | ||||
| #define ANSI_NONE       "\33[0m" | ||||
|  | ||||
| // Maybe Some Terminal Doesn't Support Color | ||||
| #ifndef ANSI_FMT_DISABLE | ||||
| #define ANSI_FMT(str, fmt) fmt str ANSI_NONE | ||||
| #else | ||||
| #define ANSI_FMT(str, fmt) str | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										65
									
								
								lib/rt/log/log.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								lib/rt/log/log.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | ||||
| #include "log.h" | ||||
|  | ||||
| typedef void (*log_handler)( | ||||
|     log_level_t level, | ||||
|     const char* module, | ||||
|     const char* file, | ||||
|     int line, | ||||
|     const char* message | ||||
| ); | ||||
|  | ||||
| static void default_handler(log_level_t level, const char* module, const char* file, int line, const char* message) { | ||||
|     if (!rt_stderr) return; | ||||
|     const char* level_str; | ||||
|     switch (level) { | ||||
|         case LOG_LEVEL_DEBUG: level_str = "DEBUG"; break; | ||||
|         case LOG_LEVEL_INFO:  level_str = "INFO ";  break; | ||||
|         case LOG_LEVEL_WARN:  level_str = "WARN ";  break; | ||||
|         case LOG_LEVEL_ERROR: level_str = "ERROR"; break; | ||||
|         case LOG_LEVEL_FATAL: level_str = "FATAL"; break; | ||||
|         case LOG_LEVEL_TRACE: level_str = "TRACE"; break; | ||||
|         default:              level_str = "NOTSET"; break; | ||||
|     } | ||||
|      | ||||
| #ifndef __LOG_NO_COLOR__ | ||||
|     const char* color_code = ANSI_NONE; | ||||
|     switch (level) { | ||||
|         case LOG_LEVEL_DEBUG: color_code = ANSI_FG_CYAN; break; | ||||
|         case LOG_LEVEL_INFO:  color_code = ANSI_FG_GREEN; break; | ||||
|         case LOG_LEVEL_TRACE: color_code = ANSI_FG_BLUE; break; | ||||
|         case LOG_LEVEL_WARN:  color_code = ANSI_FG_YELLOW; break; | ||||
|         case LOG_LEVEL_ERROR: color_code = ANSI_FG_RED; break; | ||||
|         case LOG_LEVEL_FATAL: color_code = ANSI_FG_RED ANSI_UNDERLINED; break; // 增强对比度 | ||||
|         default: color_code = ANSI_NONE; | ||||
|     } | ||||
|  | ||||
|     rt.fprintf(rt_stderr, ANSI_BOLD "%s[%s] - %s - %s:%d | %s" ANSI_NONE "\n", color_code, | ||||
|             level_str, module, file, line, message); | ||||
| #else | ||||
|     rt.fprintf(rt_stderr, "[%s] %s:%d | %s: %s\n",  | ||||
|             level_str, file, line, module, message); | ||||
| #endif | ||||
|     if (level & LOG_LEVEL_FATAL) { | ||||
|         rt.exit(-LOG_LEVEL_FATAL); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static logger_t root_logger = { | ||||
|     .name = "root", | ||||
|     .level = LOG_LEVEL_ALL, | ||||
|     .handler = default_handler, | ||||
| }; | ||||
|  | ||||
| logger_t* log_get(const char* name) { | ||||
|     return &root_logger; | ||||
| } | ||||
|  | ||||
| void log_set_level(logger_t* logger, log_level_t level) { | ||||
|     if (logger) logger->level = level; | ||||
|     else root_logger.level = level; | ||||
| } | ||||
|  | ||||
| void log_set_handler(logger_t* logger, log_handler handler) { | ||||
|     if (logger) logger->handler = handler; | ||||
|     else root_logger.handler = handler; | ||||
| } | ||||
							
								
								
									
										75
									
								
								lib/rt/log/log.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								lib/rt/log/log.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | ||||
| #ifndef __SMCC_LOG_H__ | ||||
| #define __SMCC_LOG_H__ | ||||
|  | ||||
| #include "../std/rt_api_def.h" | ||||
| #include "color.h" | ||||
|  | ||||
| typedef enum log_level { | ||||
|     LOG_LEVEL_NOTSET  = 0, | ||||
|     LOG_LEVEL_DEBUG   = 1 << 0, | ||||
|     LOG_LEVEL_INFO    = 1 << 1, | ||||
|     LOG_LEVEL_WARN    = 1 << 2, | ||||
|     LOG_LEVEL_ERROR   = 1 << 3, | ||||
|     LOG_LEVEL_FATAL   = 1 << 4, | ||||
|  | ||||
|     LOG_LEVEL_TRACE   = 1 << 5, | ||||
|     LOG_LEVEL_ALL     = 0xFF, | ||||
| } log_level_t; | ||||
|  | ||||
| typedef void (*log_handler)( | ||||
|     log_level_t level, | ||||
|     const char* module, | ||||
|     const char* file, | ||||
|     int line, | ||||
|     const char* message | ||||
| ); | ||||
|  | ||||
| #ifndef LOGGER_MAX_BUF_SIZE | ||||
| #define LOGGER_MAX_BUF_SIZE 256 | ||||
| #endif | ||||
|  | ||||
| typedef struct logger { | ||||
|     const char* name; | ||||
|     log_level_t level; | ||||
|     log_handler handler; | ||||
|     char buf[LOGGER_MAX_BUF_SIZE]; | ||||
| } logger_t; | ||||
|  | ||||
| logger_t* log_get(const char* name); | ||||
| void log_set_level(logger_t* logger, log_level_t level); | ||||
| void log_set_handler(logger_t* logger, log_handler handler); | ||||
|  | ||||
| #ifndef LOG_MAX_MAROC_BUF_SIZE | ||||
| #define LOG_MAX_MAROC_BUF_SIZE LOGGER_MAX_BUF_SIZE | ||||
| #endif | ||||
| #define _LOG(_level_, _msg_, ...) \ | ||||
|     do { \ | ||||
|         logger_t* _logger = log_get(NULL); \ | ||||
|         if (_logger && _logger->handler && (_logger->level & (_level_))) { \ | ||||
|             rt.snprintf(_logger->buf, sizeof(_logger->buf), (_msg_), ##__VA_ARGS__); \ | ||||
|             _logger->handler((_level_), _logger->name, __FILE__, __LINE__, _logger->buf); \ | ||||
|         } \ | ||||
|     } while(0) | ||||
|  | ||||
| #define LOG_NOTSET(...) _LOG(LOG_LEVEL_NOTSET, __VA_ARGS__) | ||||
| #define LOG_DEBUG(...)  _LOG(LOG_LEVEL_DEBUG,  __VA_ARGS__) | ||||
| #define LOG_INFO(...)   _LOG(LOG_LEVEL_INFO,   __VA_ARGS__) | ||||
| #define LOG_WARN(...)   _LOG(LOG_LEVEL_WARN,   __VA_ARGS__) | ||||
| #define LOG_ERROR(...)  _LOG(LOG_LEVEL_ERROR,  __VA_ARGS__) | ||||
| #define LOG_FATAL(...)  _LOG(LOG_LEVEL_FATAL,  __VA_ARGS__) | ||||
| #define LOG_TRACE(...)  _LOG(LOG_LEVEL_TRACE,  __VA_ARGS__) | ||||
|  | ||||
|  | ||||
| #define _Assert(cond, ...) \ | ||||
|     do { \ | ||||
|         if (!(cond)) { \ | ||||
|             LOG_FATAL(__VA_ARGS__); \ | ||||
|         } \ | ||||
|     } while (0) | ||||
| #define AssertFmt(cond, format, ...) _Assert(cond, "Assertion Failure: " format, ## __VA_ARGS__) | ||||
| #define PanicFmt(format, ...) _Assert(0, "Panic: " format, ## __VA_ARGS__) | ||||
| #define Assert(cond) AssertFmt(cond, "cond is `" SMCC_STR(cond) "`") | ||||
| #define Panic(...) PanicFmt(__VA_ARGS__) | ||||
| #define TODO() PanicFmt("TODO please implement me") | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										10
									
								
								lib/rt/rt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								lib/rt/rt.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| #include "rt.h" | ||||
|  | ||||
| void init_rt() { | ||||
| // TODO Choice OS | ||||
| #ifndef __SMCC_NO_OS_STD__ | ||||
|     #include "std/rt_std.h" | ||||
|     init_rt_std(); | ||||
| #endif | ||||
|     return; | ||||
| } | ||||
							
								
								
									
										18
									
								
								lib/rt/rt.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								lib/rt/rt.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| #ifndef __SMCC_RT_H__ | ||||
| #define __SMCC_RT_H__ | ||||
|  | ||||
| #include "std/rt_api_def.h" | ||||
| #include "std/rt_type.h" | ||||
| #include "log/log.h" | ||||
| #include "rt_alloc.h" | ||||
| #include "rt_string.h" | ||||
|  | ||||
| void init_rt(); | ||||
|  | ||||
| // define | ||||
| #define _SMCC_STR(str) #str | ||||
| #define SMCC_STR(str) _SMCC_STR(str) | ||||
|  | ||||
| #define SMCC_ARRLEN(arr) (sizeof(arr) / sizeof(arr[0])) | ||||
|  | ||||
| #endif // __SMCC_RT_H__ | ||||
							
								
								
									
										135
									
								
								lib/rt/rt_alloc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								lib/rt/rt_alloc.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,135 @@ | ||||
| #include "rt_alloc.h" | ||||
|  | ||||
| #define ALLOCATOR_PAGE_SIZE (4096) | ||||
|  | ||||
| /* Simple / Static Allocator */ | ||||
|  | ||||
| void* salloc_alloc(int size) { | ||||
|     // TODO do some trace | ||||
|     return rt._malloc(size); | ||||
| } | ||||
|  | ||||
| void* salloc_realloc(void* ptr, int size) { | ||||
|     return rt._realloc(ptr, size); | ||||
| } | ||||
|  | ||||
| void salloc_free(void* ptr) { | ||||
|     // TODO do some trace | ||||
|     rt._free(ptr); | ||||
| } | ||||
|  | ||||
| /* Fixed Allocator */ | ||||
|  | ||||
| #define PAGE_ALIGN(size) (((size) + ALLOCATOR_PAGE_SIZE -1) & ~(ALLOCATOR_PAGE_SIZE-1)) | ||||
|  | ||||
| void falloc_init(fixed_alloc_t* fa, int fixed_size, int init_blocks) { | ||||
|     fa->free_list = NULL; | ||||
|     fa->page_list = NULL; | ||||
|  | ||||
|     // 确保块大小至少能存放指针(用于空闲链表) | ||||
|     const int min_size = sizeof(void*); | ||||
|     fa->block_size = (fixed_size < min_size) ? min_size :  | ||||
|                     (fixed_size + 15) & ~15; // 16字节对齐 | ||||
|  | ||||
|     // 计算每页块数(优化缓存利用率) | ||||
|     const int page_size = ALLOCATOR_PAGE_SIZE - sizeof(void*); | ||||
|     fa->blocks_per_page = page_size / fa->block_size; | ||||
|      | ||||
|     // TODO copy paste 需要使用函数抽象 申请过程 | ||||
|     // 预分配初始页 | ||||
|     void* page = salloc_alloc(PAGE_ALIGN(fa->block_size * init_blocks)); | ||||
|     unsigned char* p = (unsigned char*)page; | ||||
|     for (int i = 0; i < init_blocks; ++i) { | ||||
|         void** block = (void**)p; | ||||
|         *block = fa->free_list; | ||||
|         fa->free_list = block; | ||||
|         p += fa->block_size; | ||||
|     } | ||||
|  | ||||
|     *(void**)page = fa->page_list; | ||||
|     fa->page_list = page; | ||||
| } | ||||
|  | ||||
| void* falloc_alloc(fixed_alloc_t* fa) { | ||||
|     if (!fa->free_list) { | ||||
|         // 分配新页(带页头保存链表指针) | ||||
|         void* page = salloc_alloc(ALLOCATOR_PAGE_SIZE); | ||||
|         unsigned char* p = (unsigned char*)page + sizeof(void*); | ||||
|  | ||||
|         // 链接新页块到空闲链表 | ||||
|         for (int i = 0; i < fa->blocks_per_page; ++i) { | ||||
|             void** block = (void**)p; | ||||
|             *block = fa->free_list; | ||||
|             fa->free_list = block; | ||||
|             p += fa->block_size; | ||||
|         } | ||||
|  | ||||
|         *(void**)page = fa->page_list; | ||||
|         fa->page_list = page; | ||||
|     } | ||||
|  | ||||
|     void* block = fa->free_list; | ||||
|     fa->free_list = *(void**)block; | ||||
|     return (void*)((unsigned char*)block + sizeof(void*)); // 跳过链表指针 | ||||
| } | ||||
|  | ||||
| void falloc_free(fixed_alloc_t* fa, void* ptr) { | ||||
|     if (!fa || !ptr) return; | ||||
|  | ||||
|     void** block = (void**)((u8_t*)ptr - sizeof(void*)); | ||||
|     *block = fa->free_list; | ||||
|     fa->free_list = block; | ||||
| } | ||||
|  | ||||
| void falloc_destroy(fixed_alloc_t* fa) { | ||||
|     if (!fa) return; | ||||
|  | ||||
|     // 逆向释放所有内存页(保持地址连续性) | ||||
|     void* current_page = fa->page_list; | ||||
|     while (current_page) { | ||||
|         void* next_page = *(void**)current_page; // 页头保存了链表指针 | ||||
|         salloc_free(current_page); | ||||
|         current_page = next_page; | ||||
|     } | ||||
|  | ||||
|     // 防御性清零(防止悬垂指针) | ||||
|     fa->free_list = NULL; | ||||
|     fa->blocks_per_page = 0; | ||||
|     fa->block_size = 0; | ||||
|     fa->page_list = NULL; | ||||
| } | ||||
|  | ||||
| /* Long Allocator */ | ||||
|  | ||||
| void lalloc_init(long_alloc_t* la) { | ||||
|     la->current = NULL; | ||||
|     la->block_size = ALLOCATOR_PAGE_SIZE; // 初始块大小 | ||||
| } | ||||
|  | ||||
| void* lalloc_alloc(long_alloc_t* la, int size) { | ||||
|     size = (size + 15) & ~15; // 16字节对齐 | ||||
|  | ||||
|     if (!la->current || (la->current->used + size) > la->block_size) { | ||||
|         int new_size = la->block_size; | ||||
|         if (new_size < size + sizeof(long_block_t))  | ||||
|             new_size = size + sizeof(long_block_t); | ||||
|  | ||||
|         long_block_t* new_block = (long_block_t*)salloc_alloc(new_size); | ||||
|         new_block->next = la->current; | ||||
|         new_block->used = sizeof(long_block_t); | ||||
|         la->current = new_block; | ||||
|         la->block_size = new_size; | ||||
|     } | ||||
|      | ||||
|     void* ptr = (unsigned char*)la->current + la->current->used; | ||||
|     la->current->used += size; | ||||
|     return ptr; | ||||
| } | ||||
|  | ||||
| void lalloc_destroy(long_alloc_t* la) { | ||||
|     while (la->current) { | ||||
|         long_block_t* prev = la->current->next; | ||||
|         salloc_free(la->current); | ||||
|         la->current = prev; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										36
									
								
								lib/rt/rt_alloc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								lib/rt/rt_alloc.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| #ifndef __SMCC_RT_ALLOC_H__ | ||||
| #define __SMCC_RT_ALLOC_H__ | ||||
|  | ||||
| #include "std/rt_api_def.h" | ||||
| // Simple or Static Allocator | ||||
|  | ||||
| void* salloc_alloc(int size); | ||||
| void* salloc_realloc(void* ptr, int size); | ||||
| void salloc_free(void* ptr); | ||||
|  | ||||
| typedef struct fixed_alloc { | ||||
|     void* page_list; | ||||
|     void* free_list; | ||||
|     int block_size; | ||||
|     int blocks_per_page; | ||||
| } fixed_alloc_t; | ||||
| void falloc_init(fixed_alloc_t* fa, int fixed_size, int init_size); | ||||
| void* falloc_alloc(fixed_alloc_t* fa); | ||||
| void falloc_free(fixed_alloc_t* fa, void* ptr); | ||||
| void falloc_destroy(fixed_alloc_t* fa); | ||||
|  | ||||
| typedef struct long_block { | ||||
|     struct long_block* next; | ||||
|     int used; | ||||
| } long_block_t; | ||||
|  | ||||
| typedef struct long_alloc { | ||||
|     long_block_t* current; | ||||
|     int block_size; | ||||
| } long_alloc_t; | ||||
| void lalloc_init(long_alloc_t* la); | ||||
| void* lalloc_alloc(long_alloc_t* la, int size); | ||||
| void lalloc_free(long_alloc_t* la, void* ptr); | ||||
| void lalloc_destroy(long_alloc_t* la); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										49
									
								
								lib/rt/rt_string.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								lib/rt/rt_string.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| #include "rt_string.h" | ||||
|  | ||||
| int rt_memcmp(const void* s1, const void* s2, rt_size_t n) { | ||||
|     const unsigned char *p1 = s1, *p2 = s2; | ||||
|     for (rt_size_t i = 0; i < n; ++i) { | ||||
|         if (p1[i] != p2[i]) | ||||
|             return p1[i] - p2[i]; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int rt_strcmp(const char* s1, const char* s2) { | ||||
|     while (*s1 && *s2 && (*s1 == *s2)) { | ||||
|         s1++; | ||||
|         s2++; | ||||
|     } | ||||
|     return *(const unsigned char*)s1 - *(const unsigned char*)s2; | ||||
| } | ||||
|  | ||||
| void* rt_memcpy(void* restrict dest, const void* restrict src, rt_size_t n) { | ||||
|     u8_t* d = dest; | ||||
|     const u8_t* s = src; | ||||
|     for (rt_size_t i = 0; i < n; ++i) | ||||
|         d[i] = s[i]; | ||||
|     return dest; | ||||
| } | ||||
|  | ||||
| void* rt_memset(void* s, int c, rt_size_t n) { | ||||
|     u8_t* p = s; | ||||
|     for (rt_size_t i = 0; i < n; ++i) | ||||
|         p[i] = (u8_t)c; | ||||
|     return s; | ||||
| } | ||||
|  | ||||
| rt_size_t rt_strlen(const char* s) { | ||||
|     const char* p = s; | ||||
|     while (*p) p++; | ||||
|     return p - s; | ||||
| } | ||||
|  | ||||
| /* strhash - 字符串哈希(用于符号表) */ | ||||
| u32_t rt_strhash(const char* s) { | ||||
|     u32_t hash = 2166136261u; // FNV-1a偏移基础值 | ||||
|     while (*s) { | ||||
|         hash ^= *s++; | ||||
|         hash *= 16777619u; | ||||
|     } | ||||
|     return hash; | ||||
| } | ||||
							
								
								
									
										15
									
								
								lib/rt/rt_string.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								lib/rt/rt_string.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| #ifndef __SMCC_RT_STRING_H__ | ||||
| #define __SMCC_RT_STRING_H__ | ||||
|  | ||||
| #include "std/rt_api_def.h" | ||||
|  | ||||
| int rt_memcmp(const void* s1, const void* s2, rt_size_t n); | ||||
| int rt_strcmp(const char* s1, const char* s2); | ||||
|  | ||||
| void* rt_memcpy(void* restrict dest, const void* restrict src, rt_size_t n); | ||||
| void* rt_memset(void* s, int c, rt_size_t n); | ||||
|  | ||||
| rt_size_t rt_strlen(const char* s); | ||||
| u32_t rt_strhash(const char* s); | ||||
|  | ||||
| #endif // __SMCC_RT_STRING_H__ | ||||
							
								
								
									
										64
									
								
								lib/rt/std/rt_api_def.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								lib/rt/std/rt_api_def.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| #ifndef __SMCC_RT_API_DEF_H__ | ||||
| #define __SMCC_RT_API_DEF_H__ | ||||
|  | ||||
| #include "rt_type.h" | ||||
|  | ||||
| #ifndef __RT_SIZE_TYPE__ | ||||
| #define __RT_SIZE_TYPE__ | ||||
| typedef usz_t rt_size_t; | ||||
| #endif | ||||
| typedef void*   (*rt_malloc)(rt_size_t size); | ||||
| typedef void    (*rt_free)(void* ptr); | ||||
| typedef void    (*rt_exit)(int code); | ||||
|  | ||||
| #ifndef __RT_FILE_TYPE__ | ||||
| #define __RT_FILE_TYPE__ | ||||
| typedef void* rt_file_t; | ||||
| #endif | ||||
| extern rt_file_t rt_stdin; | ||||
| extern rt_file_t rt_stdout; | ||||
| extern rt_file_t rt_stderr; | ||||
| typedef rt_file_t   (*rt_fopen_t)(const char* file_name, const char* mode); | ||||
| typedef int     (*rt_fflush_t)(rt_file_t*file); | ||||
| typedef int     (*rt_fclose_t)(rt_file_t file); | ||||
| typedef int     (*rt_freads_t)(void * dst_buf, rt_size_t dst_size, rt_size_t elem_size, rt_size_t count, rt_file_t file); | ||||
| typedef int     (*rt_fwrite_t)(const void * buf, rt_size_t size, rt_size_t count, rt_file_t file); | ||||
|  | ||||
| typedef int     (*rt_fprintf_t)(void * file, const char *format, ...); | ||||
| typedef int     (*rt_snprintf_t)(char * stream, rt_size_t n, const char * format, ...); | ||||
| typedef void*   (*rt_realloc_t)(void *memory, rt_size_t new_size); | ||||
|  | ||||
| typedef struct smcc_rt { | ||||
|     rt_malloc   _malloc; | ||||
|     rt_free     _free; | ||||
|     rt_exit     exit; | ||||
|      | ||||
|     rt_fopen_t    fopen; | ||||
|     rt_fflush_t   fflush; | ||||
|     rt_fclose_t   fclose; | ||||
|     rt_freads_t   freads; | ||||
|     rt_fwrite_t   fwrite; | ||||
|      | ||||
|     // Optional useful runtime | ||||
|     rt_fprintf_t  fprintf; | ||||
|     rt_snprintf_t snprintf; | ||||
|     rt_realloc_t  _realloc; | ||||
| } smcc_rt_t; | ||||
|  | ||||
| extern const smcc_rt_t rt; | ||||
|  | ||||
| // #ifndef NULL | ||||
| // #ifdef __cplusplus | ||||
| // #ifndef _WIN64 | ||||
| // #define NULL 0 | ||||
| // #else | ||||
| // #define NULL 0LL | ||||
| // #endif  /* W64 */ | ||||
| // #else | ||||
| // #define NULL ((void *)0) | ||||
| // #endif | ||||
| // #endif | ||||
|  | ||||
| #define NULL ((void *)0) | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										32
									
								
								lib/rt/std/rt_std.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								lib/rt/std/rt_std.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include "rt_api_def.h" | ||||
|  | ||||
| const smcc_rt_t rt = { | ||||
|     ._malloc = (rt_malloc)malloc, | ||||
|     ._free = (rt_free)free, | ||||
|     .exit = (rt_exit)exit, | ||||
|  | ||||
|     .fopen =  (rt_fopen_t)fopen, | ||||
|     .fflush = (rt_fflush_t)fflush, | ||||
|     .fclose = (rt_fclose_t)fclose, | ||||
|     .freads = (rt_freads_t)fread_s, | ||||
|     .fwrite = (rt_fwrite_t)fwrite, | ||||
|  | ||||
|     ._realloc =  (rt_realloc_t)realloc, | ||||
|     .fprintf =  (rt_fprintf_t)fprintf, | ||||
|     .snprintf = (rt_snprintf_t)snprintf, | ||||
| }; | ||||
|  | ||||
| rt_file_t rt_stdin; | ||||
| rt_file_t rt_stdout; | ||||
| rt_file_t rt_stderr; | ||||
|  | ||||
| void init_rt_std() { | ||||
|     rt_stdin = stdin; | ||||
|     rt_stdout = stdout; | ||||
|     rt_stderr = stderr; | ||||
| } | ||||
							
								
								
									
										6
									
								
								lib/rt/std/rt_std.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								lib/rt/std/rt_std.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| #ifndef __SMCC_RT_STD_H__ | ||||
| #define __SMCC_RT_STD_H__ | ||||
|  | ||||
| void init_rt_std(); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										28
									
								
								lib/rt/std/rt_type.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								lib/rt/std/rt_type.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| #ifndef __SMCC_RT_TYPE_H__ | ||||
| #define __SMCC_RT_TYPE_H__ | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| typedef int8_t      i8_t; | ||||
| typedef int16_t     i16_t; | ||||
| typedef int32_t     i32_t; | ||||
| typedef int64_t     i64_t; | ||||
|  | ||||
| typedef uint8_t     u8_t; | ||||
| typedef uint16_t    u16_t; | ||||
| typedef uint32_t    u32_t; | ||||
| typedef uint64_t    u64_t; | ||||
|  | ||||
| typedef float       f32_t; | ||||
| typedef double      f64_t; | ||||
|  | ||||
| typedef intptr_t    iptr_t; | ||||
| typedef uintptr_t   uptr_t; | ||||
|  | ||||
| typedef size_t      usz_t; | ||||
| typedef ssize_t     isz_t; | ||||
|  | ||||
| // typedef u32_t       uw_t; | ||||
| // typedef i32_t       iw_t; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										0
									
								
								lib/test/test.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								lib/test/test.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								lib/test/test_alloc..c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								lib/test/test_alloc..c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										15
									
								
								lib/test/test_log.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								lib/test/test_log.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| #include <lib/core.h> | ||||
|  | ||||
| int main(void) { | ||||
|     // make -C .. | ||||
|     // gcc -g -Wall -I../.. test_log.c -L.. -lcore -o test_log | ||||
|     // ./test_log | ||||
|     init_lib_core(); | ||||
|  | ||||
|     LOG_NOTSET("Log notset"); | ||||
|     LOG_DEBUG("Log debug"); | ||||
|     LOG_INFO("Log info"); | ||||
|     LOG_WARN("Log warn"); | ||||
|     LOG_ERROR("Log error"); | ||||
|     LOG_FATAL("Log fatal"); | ||||
| } | ||||
							
								
								
									
										142
									
								
								lib/utils/ds/hashtable.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								lib/utils/ds/hashtable.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,142 @@ | ||||
| #include "hashtable.h" | ||||
|  | ||||
| #define LOAD_FACTOR 0.75f | ||||
| // 素数表用于桶扩容(最后一个元素为最大允许容量) | ||||
| static const int PRIME_CAPACITIES[] = {  | ||||
|     11, 23, 47, 97, 193, 389, 769, 1543, 3079,  | ||||
|     6151, 12289, 24593, 49157, 98317, 196613, 393241, | ||||
|     786433, 1572869, 3145739, 6291469, 12582917, 25165843 | ||||
| }; | ||||
|  | ||||
| // 私有函数声明 | ||||
| static u32_t calc_hash(const char* str, int len); | ||||
| static void rehash(hash_table_t* ht); | ||||
|  | ||||
| hash_table_t* new_hash_table(int init_size, int max_cap) { | ||||
|     hash_table_t* ht = salloc_alloc(sizeof(hash_table_t)); | ||||
|     hash_table_init(ht, init_size, max_cap); | ||||
|     return ht; | ||||
| } | ||||
|  | ||||
| static inline get_real_size(int size) { | ||||
|     // 查找第一个不小于size的素数容量 | ||||
|     int cap_idx = 0; | ||||
|     if (size < 0) { | ||||
|         return PRIME_CAPACITIES[SMCC_ARRLEN(PRIME_CAPACITIES)-1]; | ||||
|     } | ||||
|     while (PRIME_CAPACITIES[cap_idx] < size && cap_idx < SMCC_ARRLEN(PRIME_CAPACITIES)-1)  { | ||||
|         cap_idx++; | ||||
|     } | ||||
|     return PRIME_CAPACITIES[cap_idx]; | ||||
| } | ||||
|  | ||||
| void hash_table_init(hash_table_t* ht, int init_size, int max_cap) { | ||||
|     // 限制最大容量索引 | ||||
|     ht->max_cap = get_real_size(max_cap); | ||||
|     // 应用实际容量 | ||||
|     ht->cap = get_real_size(init_size); | ||||
|     ht->size = 0; | ||||
|     ht->buckets = NULL; | ||||
|     ht->buckets = salloc_realloc(ht->buckets, sizeof(hash_node_t*) * ht->cap); | ||||
| } | ||||
|  | ||||
| void hash_table_insert(hash_table_t* ht, const char* str, int len) { | ||||
|     // 自动扩容检查 | ||||
|     if (ht->size >= ht->cap * LOAD_FACTOR && ht->cap < ht->max_cap) { | ||||
|         rehash(ht); | ||||
|     } | ||||
|  | ||||
|     if (ht->size >= ht->cap) { | ||||
|         LOG_TRACE("Hash table size exceeds maximum capacity. Consider increasing max_capacity."); | ||||
|     } | ||||
|  | ||||
|     // 计算哈希值 | ||||
|     u32_t hash = calc_hash(str, len); | ||||
|     int bucket_idx = hash % ht->cap; | ||||
|  | ||||
|     // 检查重复 | ||||
|     hash_node_t* node = ht->buckets[bucket_idx]; | ||||
|     while (node) { | ||||
|         if (node->hash == hash &&  | ||||
|             node->len == len &&  | ||||
|             memcmp(node->str, str, len) == 0) { | ||||
|             return; // 已存在 | ||||
|         } | ||||
|         node = node->next; | ||||
|     } | ||||
|  | ||||
|     // 创建新节点 | ||||
|     hash_node_t* new_node = salloc_alloc(sizeof(hash_node_t)); | ||||
|     new_node->str = str; | ||||
|     new_node->len = len; | ||||
|     new_node->hash = hash; | ||||
|     new_node->next = ht->buckets[bucket_idx]; | ||||
|     ht->buckets[bucket_idx] = new_node; | ||||
|     ht->size++; | ||||
| } | ||||
|  | ||||
| hash_node_t* hash_table_find(hash_table_t* ht, const char* str, int len) { | ||||
|     u32_t hash = calc_hash(str, len); | ||||
|     int bucket_idx = hash % ht->cap; | ||||
|  | ||||
|     hash_node_t* node = ht->buckets[bucket_idx]; | ||||
|     while (node) { | ||||
|         if (node->hash == hash &&  | ||||
|             node->len == len &&  | ||||
|             memcmp(node->str, str, len) == 0) { | ||||
|             return node; | ||||
|         } | ||||
|         node = node->next; | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| static void rehash(hash_table_t* ht) { | ||||
|     int old_cap = ht->cap; | ||||
|     hash_node_t** old_buckets = ht->buckets; | ||||
|  | ||||
|     // 查找下一个素数容量 | ||||
|     int new_cap_idx = 0; | ||||
|     while (PRIME_CAPACITIES[new_cap_idx] <= old_cap &&  | ||||
|            new_cap_idx < ht->max_cap) { | ||||
|         new_cap_idx++; | ||||
|     } | ||||
|     ht->cap = PRIME_CAPACITIES[new_cap_idx]; | ||||
|  | ||||
|     // 分配新桶数组 | ||||
|     ht->buckets = salloc_alloc(sizeof(hash_node_t*) * ht->cap); | ||||
|     memset(ht->buckets, 0, sizeof(hash_node_t*) * ht->cap); | ||||
|  | ||||
|     // 重新哈希所有节点 | ||||
|     for (int i = 0; i < old_cap; i++) { | ||||
|         hash_node_t* node = old_buckets[i]; | ||||
|         while (node) { | ||||
|             hash_node_t* next = node->next; | ||||
|             int new_bucket = node->hash % ht->cap; | ||||
|             node->next = ht->buckets[new_bucket]; | ||||
|             ht->buckets[new_bucket] = node; | ||||
|             node = next; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     salloc_free(old_buckets); | ||||
| } | ||||
|  | ||||
| static u32_t calc_hash(const char* str, int len) { | ||||
|     // 使用与HASH_FNV_1A宏一致的算法 | ||||
|     rt_strhash(str); | ||||
| } | ||||
|  | ||||
| void hash_table_destroy(hash_table_t* ht) { | ||||
|     for (int i = 0; i < ht->cap; i++) { | ||||
|         hash_node_t* node = ht->buckets[i]; | ||||
|         while (node) { | ||||
|             hash_node_t* next = node->next; | ||||
|             salloc_free(node); | ||||
|             node = next; | ||||
|         } | ||||
|     } | ||||
|     salloc_free(ht->buckets); | ||||
|     ht->buckets = NULL; | ||||
|     ht->size = ht->cap = 0; | ||||
| } | ||||
							
								
								
									
										27
									
								
								lib/utils/ds/hashtable.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								lib/utils/ds/hashtable.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| #ifndef __SMCC_HASHTABLE_H__ | ||||
| #define __SMCC_HASHTABLE_H__ | ||||
|  | ||||
| #include <lib/rt/rt.h> | ||||
|  | ||||
| typedef struct hash_node { | ||||
|     const char* str; | ||||
|     int len; | ||||
|     u32_t hash; | ||||
|     struct hash_node* next; | ||||
| } hash_node_t; | ||||
|  | ||||
| typedef struct hash_table { | ||||
|     hash_node_t** buckets; | ||||
|     int size; | ||||
|     int cap; | ||||
|     int max_cap; | ||||
| } hash_table_t; | ||||
|  | ||||
| hash_table_t* new_hash_table(int init_size, int max_cap); | ||||
| void hash_table_init(hash_table_t* ht, int init_size, int max_cap); | ||||
| void hash_table_destroy(hash_table_t* ht); | ||||
|  | ||||
| void hash_table_insert(hash_table_t* ht, const char* str, int len); | ||||
| hash_node_t* hash_table_find(hash_table_t* ht, const char* str, int len); | ||||
|  | ||||
| #endif // __SMCC_HASHTABLE_H__ | ||||
							
								
								
									
										158
									
								
								lib/utils/ds/kllist.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								lib/utils/ds/kllist.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,158 @@ | ||||
| /** | ||||
|  * kllist.h is a list implement by linux kernel list | ||||
|  * @link https://njusecourse.feishu.cn/wiki/I8vkw2zkwiEInUkujTJc7zzOnwf | ||||
|  * @link https://kernelnewlbies.org/FAQ/LinkedLists | ||||
|  * @link https://lwn.net/Articles/887097/ | ||||
|  * @link https://liuluheng.github.io/wiki/public_html/Embedded-System/kernel/list-and-hlist.html | ||||
|  */ | ||||
|  | ||||
| #ifndef __KLLIST_H__ | ||||
| #define __KLLIST_H__ | ||||
|  | ||||
| #ifndef NULL | ||||
| #define NULL (0) | ||||
| #define __NULL_KLIST_DEFINED__ | ||||
| #endif | ||||
|  | ||||
| #ifndef container_of | ||||
| // Magic: https://radek.io/posts/magical-container_of-macro/ | ||||
| // StackOverflow: https://stackoverflow.com/q/15832301/1833118 | ||||
| #ifdef __GNUC__ | ||||
| #define container_of(ptr, type, member) ({                      \ | ||||
|         const typeof( ((type *)0)->member ) *__mptr = (ptr);    \ | ||||
|         (type *)( (char *)__mptr - offsetof(type,member) );}) | ||||
| #else | ||||
| #define container_of(ptr, type, member) ({                      \ | ||||
|         const void *__mptr = (ptr);    \ | ||||
|         (type *)( (char *)__mptr - offsetof(type,member) );}) | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| /** | ||||
|  * used by list | ||||
|  */ | ||||
| struct list_head { | ||||
|     struct list_head *next, *prev; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * list init | ||||
|  * @example  | ||||
|  * 1. struct list_head your_list = LIST_HEAD_INIT(your_list); | ||||
|  * 2. struct list_head your_list; INIT_LIST_HEAD(&your_list); | ||||
|  * 3. LIST_HEAD(your_list); => struct your_list = { &(your_list), &(your_list) }; | ||||
|  */ | ||||
|  | ||||
| #define LIST_HEAD_INIT(name) { &(name), &(name) } | ||||
| static inline void INIT_LIST_HEAD(struct list_head *list) { | ||||
|     list->next = list; | ||||
|     list->prev = list; | ||||
| } | ||||
| #define LIST_HEAD(name) \ | ||||
|     struct list_head name = LIST_HEAD_INIT(name) | ||||
|  | ||||
| /** | ||||
|  * list add | ||||
|  */ | ||||
|  | ||||
| static inline void __list_add(struct list_head *newl, | ||||
|                               struct list_head *prev, | ||||
|                               struct list_head *next) { | ||||
|     next->prev = newl; | ||||
|     newl->next = next; | ||||
|     newl->prev = prev; | ||||
|     prev->next = newl; | ||||
| } | ||||
|  | ||||
| static inline void list_add(struct list_head *newl, struct list_head *head) { | ||||
|     __list_add(newl, head, head->next); | ||||
| } | ||||
|  | ||||
| static inline void list_add_tail(struct list_head *newl, struct list_head *head) { | ||||
|     __list_add(newl, head->prev, head); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * list delete | ||||
|  */ | ||||
|  | ||||
| static inline void __list_del(struct list_head * prev, struct list_head * next) { | ||||
|     next->prev = prev; | ||||
|     prev->next = next; | ||||
| } | ||||
|  | ||||
| static inline void list_del(struct list_head *entry) { | ||||
|     __list_del(entry->prev, entry->next); | ||||
|     entry->next = NULL; | ||||
| 	entry->prev = NULL; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * list_is_first -- tests whether @list is the first entry in list @head | ||||
|  * @list: the entry to test | ||||
|  * @head: the head of the list | ||||
|  */ | ||||
| static inline int list_is_first(const struct list_head *list, const struct list_head *head) { | ||||
| 	return list->prev == head; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * list_is_last - tests whether @list is the last entry in list @head | ||||
|  * @list: the entry to test | ||||
|  * @head: the head of the list | ||||
|  */ | ||||
| static inline int list_is_last(const struct list_head *list, const struct list_head *head) { | ||||
| 	return list->next == head; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * list_is_head - tests whether @list is the list @head | ||||
|  * @list: the entry to test | ||||
|  * @head: the head of the list | ||||
|  */ | ||||
| static inline int list_is_head(const struct list_head *list, const struct list_head *head) { | ||||
| 	return list == head; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * list_empty - tests whether a list is empty | ||||
|  * @head: the list to test. | ||||
|  */ | ||||
| static inline int list_empty(const struct list_head *head) { | ||||
| 	return head->next == head; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * list_for_each	-	iterate over a list | ||||
|  * @pos:	the &struct list_head to use as a loop cursor. | ||||
|  * @head:	the head for your list. | ||||
|  */ | ||||
| #define list_for_each(pos, head) \ | ||||
| 	for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next) | ||||
|  | ||||
| /** | ||||
|  * list_for_each_prev	-	iterate over a list backwards | ||||
|  * @pos:	the &struct list_head to use as a loop cursor. | ||||
|  * @head:	the head for your list. | ||||
|  */ | ||||
| #define list_for_each_prev(pos, head) \ | ||||
| 	for (pos = (head)->prev; !list_is_head(pos, (head)); pos = pos->prev) | ||||
|  | ||||
| /** | ||||
|  * list sort | ||||
|  *   by linux kernel 6.3.1 /lib/list_sort.c | ||||
|  *     it remain use sigle linked list to merge sort | ||||
|  * @link https://www.geeksforgeeks.org/merge-sort-for-linked-list/ | ||||
|  */ | ||||
|  | ||||
| #ifdef HAVE_KLIST_SORT | ||||
| typedef int (*list_cmp_func_t)(void *, | ||||
| 	const struct list_head *, const struct list_head *); | ||||
| static void list_sort(void *priv, struct list_head *head, list_cmp_func_t cmp); | ||||
| #endif | ||||
|  | ||||
| #if defined(__NULL_KLIST_DEFINED__) && !defined(__NULL_KLIST_DEFINED_NOMOVE__) | ||||
| #undef NULL | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
| @ -89,8 +89,8 @@ | ||||
| # register_printers() | ||||
| 
 | ||||
| # vector_gdb.py | ||||
| import gdb | ||||
| from gdb.printing import PrettyPrinter | ||||
| import gdb # type: ignore | ||||
| from gdb.printing import PrettyPrinter # type: ignore | ||||
| 
 | ||||
| class VectorPrinter: | ||||
|     """兼容新旧注册方式的最终方案""" | ||||
| @ -1,15 +1,13 @@ | ||||
| // vector.h
 | ||||
| #ifndef VECTOR_H | ||||
| #define VECTOR_H | ||||
| #ifndef __SMCC_DS_VECTOR_H__ | ||||
| #define __SMCC_DS_VECTOR_H__ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <stdint.h> | ||||
| #include <lib/rt/rt.h> | ||||
| 
 | ||||
| #define vector_header(name, type) \ | ||||
|     struct { \ | ||||
|         size_t size; \ | ||||
|         size_t cap; \ | ||||
|         rt_size_t size; \ | ||||
|         rt_size_t cap; \ | ||||
|         type *data; \ | ||||
|     } name \ | ||||
| 
 | ||||
| @ -24,10 +22,9 @@ | ||||
|     do { \ | ||||
|         if (vec.size >= vec.cap) { \ | ||||
|             int cap = vec.cap ? vec.cap * 2 : 8; \ | ||||
|             void* data = realloc(vec.data, cap * sizeof(*vec.data)); \ | ||||
|             void* data = salloc_realloc(vec.data, cap * sizeof(*vec.data)); \ | ||||
|             if (!data) { \ | ||||
|                 fprintf(stderr, "vector_push: realloc failed\n"); \ | ||||
|                 exit(1); \ | ||||
|                 LOG_FATAL("vector_push: rt_realloc failed\n"); \ | ||||
|             } \ | ||||
|             (vec).cap = cap; \ | ||||
|             (vec).data = data; \ | ||||
| @ -46,7 +43,7 @@ | ||||
| 
 | ||||
| #define vector_free(vec) \ | ||||
|     do { \ | ||||
|         free((vec).data); \ | ||||
|         salloc_free((vec).data); \ | ||||
|         (vec).data = NULL; \ | ||||
|         (vec).size = (vec).cap = 0; \ | ||||
|     } while(0) | ||||
							
								
								
									
										0
									
								
								lib/utils/gdb.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								lib/utils/gdb.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								lib/utils/strpool/strpool.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								lib/utils/strpool/strpool.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										12
									
								
								lib/utils/strpool/strpool.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								lib/utils/strpool/strpool.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| #ifndef __SMCC_STRPOOL_H__ | ||||
| #define __SMCC_STRPOOL_H__ | ||||
|  | ||||
| #include <lib/core.h> | ||||
| #include "../ds/hash.h" | ||||
| typedef struct strpool { | ||||
|     long_alloc_t *long_alloc; | ||||
| } strpool_t;  | ||||
|  | ||||
| void new_strpool(); | ||||
|  | ||||
| #endif // __SMCC_STRPOOL_H__ | ||||
							
								
								
									
										0
									
								
								lib/utils/symtab/symtab.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								lib/utils/symtab/symtab.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								lib/utils/symtab/symtab.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								lib/utils/symtab/symtab.h
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										19
									
								
								lib/utils/tokbuf/token.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								lib/utils/tokbuf/token.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| // #include <lib/rt/rt.h> | ||||
| // #include "token.h" | ||||
|  | ||||
| // #define ROUND_IDX(idx) ((idx) % tokbuf->cap) | ||||
| // #define POW2(x) (1 << (x)) | ||||
|  | ||||
| // void init_toks(tok_stream_t* tokbuf, int cap, | ||||
| //     tok_stream_close_func close, tok_stream_get_func gettok, void* stream) | ||||
| // { | ||||
| //     tokbuf->cap_mask = POW2(cap) - 1; | ||||
| //     // tokbuf->buf =  | ||||
|  | ||||
| // } | ||||
| // int toks_next( tok_stream_t* toks, tok_t* out); | ||||
| // int toks_peek( tok_stream_t* toks, tok_t* out, int lookahead); | ||||
| // const tok_t* toks_peek_ref(tok_stream_t* toks, int lookahead); | ||||
| // int toks_reset(tok_stream_t* toks); | ||||
| // int toks_seek( tok_stream_t* toks, int pos); | ||||
| // int toks_close(tok_stream_t* toks); | ||||
							
								
								
									
										68
									
								
								lib/utils/tokbuf/token.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								lib/utils/tokbuf/token.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | ||||
| #ifndef __SMCC_TOKBUF_H__ | ||||
| #define __SMCC_TOKBUF_H__ | ||||
|  | ||||
| #include <lib/rt/rt.h> | ||||
|  | ||||
| typedef struct loc { | ||||
|     const char *fname; | ||||
|     int line; | ||||
|     int col; | ||||
|     short len; | ||||
| } loc_t; | ||||
|  | ||||
| typedef enum tok_type { | ||||
|     TK_BASIC_INVALID,     // 错误占位 | ||||
|     TK_BASIC_KEYWORD,     // 关键字 | ||||
|     TK_BASIC_OPERATOR,    // 操作符 | ||||
|     TK_BASIC_IDENTIFIER,  // 标识符 | ||||
|     TK_BASIC_LITERAL,     // 字面量 | ||||
|     TK_BASIC_PUNCTUATOR,  // 标点符号 | ||||
|     TK_BASIC_EOF          // 结束标记 | ||||
| } tok_type_t; | ||||
|  | ||||
| typedef union ctype { | ||||
|     u8_t    u8; | ||||
|     u16_t   u16; | ||||
|     u32_t   u32; | ||||
|     u64_t   u64; | ||||
|     i8_t    i8; | ||||
|     i16_t   i16; | ||||
|     i32_t   i32; | ||||
|     i64_t   i64; | ||||
|     f32_t   f32; | ||||
|     f64_t   f64; | ||||
|     iptr_t  iptr; | ||||
|     uptr_t  uptr; | ||||
|     void*   ptr; | ||||
| } ctype_t; | ||||
|  | ||||
| typedef struct tok { | ||||
|     tok_type_t type; | ||||
|     int sub_type; | ||||
|     loc_t loc; | ||||
|     ctype_t val; | ||||
| } tok_t; | ||||
|  | ||||
| // typedef void(*tok_stream_close_func)(void* stream); | ||||
| // typedef void(*tok_stream_get_func)(void* stream, tok_t* token); | ||||
| // typedef struct tok_stream { | ||||
| //     int cur; | ||||
| //     int end; | ||||
| //     int cap_mask; | ||||
| //     tok_t* buf; | ||||
|  | ||||
| //     void* stream; | ||||
| //     tok_stream_close_func close; | ||||
| //     tok_stream_get_func gettok; | ||||
| // } tok_stream_t; | ||||
|  | ||||
| // void init_toks(tok_stream_t* tokbuf, int cap, | ||||
| //     tok_stream_close_func close, tok_stream_get_func gettok, void* stream); | ||||
| // int toks_next( tok_stream_t* toks, tok_t* out); | ||||
| // int toks_peek( tok_stream_t* toks, tok_t* out, int lookahead); | ||||
| // const tok_t* toks_peek_unsafe(tok_stream_t* toks, int lookahead); | ||||
| // int toks_reset(tok_stream_t* toks); | ||||
| // int toks_seek( tok_stream_t* toks, int pos); | ||||
| // int toks_close(tok_stream_t* toks); | ||||
|  | ||||
| #endif // __SMCC_TOKEN_H__ | ||||
| @ -1,10 +0,0 @@ | ||||
| #ifndef __STDCORE_H__ | ||||
| #define __STDCORE_H__ | ||||
|  | ||||
| #ifndef __NO_LINK_STDLIB | ||||
| #include <stdlib.h> | ||||
| #else | ||||
| #error "__NO_LINK_STDLIB" | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
		Reference in New Issue
	
	Block a user