Compare commits

...

2 Commits

Author SHA1 Message Date
ZZY
2b4857001c feat(frontend): 重构词法分析器
- 添加 .gitignore 文件,忽略编译器生成的二进制文件
- 重构 lexer.c 文件,改进了关键字处理和字符串处理
- 更新前端的前端、解析器和 AST 相关文件,以适应新的词法分析器
- 优化了 token 相关的定义和函数,引入了新的 token 类型
2025-03-23 12:13:16 +08:00
ZZY
05c637e594 refactor: 重构前端代码并添加日志功能
- 重命名和重构了多个文件,包括 lexer、parser 和 AST 相关代码
- 添加了日志功能,使用 LOG_* 宏替代原有的 error 和 warn 函数
- 优化了错误处理和内存分配方式
- 调整了代码结构,提高了模块化和可读性
2025-03-19 12:22:55 +08:00
85 changed files with 1836 additions and 759 deletions

22
.gitignore vendored Normal file
View File

@ -0,0 +1,22 @@
.vscode/
# smcc compiler generated files
*.bin
# linux binary files
*.o
*.a
*.so
*.out
# windows binary files
*.obj
*.lib
*.dll
*.exe
# developed notes
note.md
# python
.venv

View File

@ -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

View File

@ -1,6 +1,7 @@
#define RISCV_VM_BUILDIN_ECALL
#include "rv32gen.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
// 指令编码联合体(自动处理小端序)
@ -10,7 +11,8 @@ typedef union rv32code {
} 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[] = {

View 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

View File

@ -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);

View File

@ -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

View File

@ -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 \

View File

@ -1,15 +1,19 @@
#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();
strpool_t strpool;
init_strpool(&strpool);
struct ASTNode* frontend(const char* file, void* stream, sread_fn sread) {
lexer_t lexer;
init_lexer(&lexer, file, stream, sread);
init_lexer(&lexer, file, stream, sread, &strpool);
symtab_t symtab;
init_symtab(&symtab);
parser_t parser;
parser_t parser;
init_parser(&parser, &lexer, &symtab);
parse_prog(&parser);

View File

@ -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

View File

@ -26,15 +26,15 @@ 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"
static const struct {
const char* name;
enum CSTD_KEYWORD std_type;
tok_type_t tok;
cc_tktype_t tok;
} keywords[] = {
#define X(name, std_type, tok, ...) { #name, std_type, tok },
KEYWORD_TABLE
@ -74,18 +74,17 @@ 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)
{
lexer->cur_ptr = lexer->end_ptr = (unsigned char*)&(lexer->buffer);
lexer->index = 1;
lexer->line = 1;
void init_lexer(lexer_t* lexer, const char* file_name, void* stream, lexer_sread_fn sread, strpool_t* strpool) {
lexer->strpool = strpool;
lexer->cur_ptr = lexer->end_ptr = (char*)&(lexer->buffer);
lexer->loc.fname = strpool_intern(lexer->strpool, file_name);
lexer->loc.line = 1;
lexer->loc.col = 1;
lexer->stream = stream;
lexer->sread = sread;
for (int i = 0; i < sizeof(lexer->buffer) / sizeof(lexer->buffer[0]); i++) {
lexer->buffer[i] = 0;
}
rt_memset(lexer->buffer, 0, sizeof(lexer->buffer));
}
static void flush_buffer(lexer_t* lexer) {
@ -93,13 +92,13 @@ static void flush_buffer(lexer_t* lexer) {
for (int i = 0; i < num; i++) {
lexer->buffer[i] = lexer->cur_ptr[i];
}
lexer->cur_ptr = (unsigned char*)lexer->buffer;
lexer->cur_ptr = 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 +106,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?");
}
}
@ -127,19 +126,20 @@ static void goto_block_comment(lexer_t* lexer) {
flush_buffer(lexer);
}
if (*lexer->cur_ptr == '\0') {
if (lexer->cur_ptr[0] == '\0') {
break;
} else if (lexer->cur_ptr[0] == '*' && lexer->cur_ptr[1] == '/') {
lexer->cur_ptr += 2;
break;
} else {
if (lexer->cur_ptr[0] == '\n') lexer->loc.line++;
lexer->cur_ptr++;
}
}
}
// TODO escape character not enough
static char got_slash(unsigned char* peek) {
static char got_slash(char* peek) {
switch (*peek) {
case '\\': return '\\';
case '\'': return '\'';
@ -153,13 +153,15 @@ 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) {
char val = 0;
unsigned char* peek = lexer->cur_ptr + 1;
char* peek = lexer->cur_ptr + 1;
if (*peek == '\\') {
peek++;
val = got_slash(peek);
@ -168,17 +170,15 @@ static void parse_char_literal(lexer_t* lexer, tok_t* token) {
val = *peek++;
}
if (*peek++ != '\'') error("Unclosed character literal");
token->val.ch = val;
if (*peek++ != '\'') LEX_ERROR("Unclosed character literal");
lexer->cur_ptr = peek;
token->val.have = 1;
token->type = TOKEN_CHAR_LITERAL;
token->val.ch = val;
}
static void parse_string_literal(lexer_t* lexer, tok_t* token) {
unsigned char* peek = lexer->cur_ptr + 1;
char* peek = lexer->cur_ptr + 1;
// TODO string literal size check
char* dest = token->val.str = xmalloc(LEXER_MAX_TOKEN_SIZE + 1);
static char dest[LEXER_MAX_TOKEN_SIZE + 1];
int len = 0;
while (*peek != '"') {
@ -189,18 +189,19 @@ 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';
lexer->cur_ptr = peek + 1;
token->val.have = 1;
token->type = TOKEN_STRING_LITERAL;
lexer->cur_ptr = peek + 1; // 1 is `"`
lexer->loc.len = len + 2; // 2 is `"` `"`
token->val.str = strpool_intern(lexer->strpool, dest);
}
// FIXME it write by AI maybe error
static void parse_number(lexer_t* lexer, tok_t* token) {
unsigned char* peek = lexer->cur_ptr;
char* peek = lexer->cur_ptr;
int base = 10;
int is_float = 0;
long long int_val = 0;
@ -275,14 +276,15 @@ static void parse_number(lexer_t* lexer, tok_t* token) {
}
// 存储结果
// TODO
lexer->loc.len = peek - lexer->cur_ptr;
lexer->cur_ptr = peek;
token->val.have = 1;
if (is_float) {
token->val.d = float_val;
token->type = TOKEN_FLOAT_LITERAL;
token->val.f32 = float_val;
token->sub_type = TOKEN_FLOAT_LITERAL;
} else {
token->val.ll = int_val;
token->type = TOKEN_INT_LITERAL;
token->val.i = int_val;
token->sub_type = TOKEN_INT_LITERAL;
}
}
@ -293,160 +295,159 @@ void get_token(lexer_t* lexer, tok_t* token) {
if (lexer->end_ptr - lexer->cur_ptr < GOT_ONE_TOKEN_BUF_SIZE) {
flush_buffer(lexer);
}
register unsigned char* peek = lexer->cur_ptr;
// 快速跳过空白符
while (*peek == ' ' || *peek == '\t') {
if (peek == lexer->end_ptr) {
break;
}
peek++;
}
if (peek != lexer->cur_ptr) {
// To TOKEN_FLUSH
lexer->cur_ptr = peek;
token->type = TOKEN_FLUSH;
}
tok_type_t tok = TOKEN_INIT;
tok_val_t constant;
constant.have = 0;
register char* peek = lexer->cur_ptr;
cc_tktype_t tk_type = TOKEN_INIT;
ctype_t literal = { 0 };
// once step
switch (*peek++) {
case '=':
case '=':
switch (*peek++) {
case '=': tok = TOKEN_EQ; break;
default: peek--, tok = TOKEN_ASSIGN; break;
case '=': tk_type = TOKEN_EQ; break;
default: peek--, tk_type = TOKEN_ASSIGN; break;
} break;
case '+':
switch (*peek++) {
case '+': tok = TOKEN_ADD_ADD; break;
case '=': tok = TOKEN_ASSIGN_ADD; break;
default: peek--, tok = TOKEN_ADD; break;
case '+': tk_type = TOKEN_ADD_ADD; break;
case '=': tk_type = TOKEN_ASSIGN_ADD; break;
default: peek--, tk_type = TOKEN_ADD; break;
} break;
case '-':
switch (*peek++) {
case '-': tok = TOKEN_SUB_SUB; break;
case '=': tok = TOKEN_ASSIGN_SUB; break;
case '-': tk_type = TOKEN_SUB_SUB; break;
case '=': tk_type = TOKEN_ASSIGN_SUB; break;
case '>': tok = TOKEN_DEREF; break;
default: peek--, tok = TOKEN_SUB; break;
case '>': tk_type = TOKEN_DEREF; break;
default: peek--, tk_type = TOKEN_SUB; break;
} break;
case '*':
switch (*peek++) {
case '=': tok = TOKEN_ASSIGN_MUL; break;
default: peek--, tok = TOKEN_MUL; break;
case '=': tk_type = TOKEN_ASSIGN_MUL; break;
default: peek--, tk_type = TOKEN_MUL; break;
} break;
case '/':
switch (*peek++) {
case '=': tok = TOKEN_ASSIGN_DIV; break;
case '=': tk_type = TOKEN_ASSIGN_DIV; break;
case '/': {
// need get a new line to parse
goto_newline(lexer);
tok = TOKEN_LINE_COMMENT;
tk_type = TOKEN_LINE_COMMENT;
goto END;
}
case '*': {
lexer->cur_ptr = peek;
goto_block_comment(lexer);
tok = TOKEN_BLOCK_COMMENT;
tk_type = TOKEN_BLOCK_COMMENT;
goto END;
}
default: peek--, tok = TOKEN_DIV; break;
default: peek--, tk_type = TOKEN_DIV; break;
} break;
case '%':
switch (*peek++) {
case '=': tok = TOKEN_ASSIGN_MOD; break;
default: peek--, tok = TOKEN_MOD; break;
case '=': tk_type = TOKEN_ASSIGN_MOD; break;
default: peek--, tk_type = TOKEN_MOD; break;
} break;
case '&':
switch (*peek++) {
case '&': tok = TOKEN_AND_AND; break;
case '=': tok = TOKEN_ASSIGN_AND; break;
default: peek--, tok = TOKEN_AND; break;
case '&': tk_type = TOKEN_AND_AND; break;
case '=': tk_type = TOKEN_ASSIGN_AND; break;
default: peek--, tk_type = TOKEN_AND; break;
} break;
case '|':
switch (*peek++) {
case '|': tok = TOKEN_OR_OR; break;
case '=': tok = TOKEN_ASSIGN_OR; break;
default: peek--, tok = TOKEN_OR; break;
case '|': tk_type = TOKEN_OR_OR; break;
case '=': tk_type = TOKEN_ASSIGN_OR; break;
default: peek--, tk_type = TOKEN_OR; break;
} break;
case '^':
switch (*peek++) {
case '=': tok = TOKEN_ASSIGN_XOR; break;
default: peek--, tok = TOKEN_XOR; break;
case '=': tk_type = TOKEN_ASSIGN_XOR; break;
default: peek--, tk_type = TOKEN_XOR; break;
} break;
case '<':
switch (*peek++) {
case '=': tok = TOKEN_LE; break;
case '<': tok = (*peek == '=') ? (peek++, TOKEN_ASSIGN_L_SH) : TOKEN_L_SH; break;
default: peek--, tok = TOKEN_LT; break;
case '=': tk_type = TOKEN_LE; break;
case '<': tk_type = (*peek == '=') ? (peek++, TOKEN_ASSIGN_L_SH) : TOKEN_L_SH; break;
default: peek--, tk_type = TOKEN_LT; break;
} break;
case '>':
switch (*peek++) {
case '=': tok = TOKEN_GE; break;
case '>': tok = (*peek == '=') ? (peek++, TOKEN_ASSIGN_R_SH) : TOKEN_R_SH; break;
default: peek--, tok = TOKEN_GT; break;
case '=': tk_type = TOKEN_GE; break;
case '>': tk_type = (*peek == '=') ? (peek++, TOKEN_ASSIGN_R_SH) : TOKEN_R_SH; break;
default: peek--, tk_type = TOKEN_GT; break;
} break;
case '~':
tok = TOKEN_BIT_NOT; break;
tk_type = TOKEN_BIT_NOT; break;
case '!':
switch (*peek++) {
case '=': tok = TOKEN_NEQ; break;
default: peek--, tok = TOKEN_NOT; break;
case '=': tk_type = TOKEN_NEQ; break;
default: peek--, tk_type = TOKEN_NOT; break;
} break;
case '[':
tok = TOKEN_L_BRACKET; break;
tk_type = TOKEN_L_BRACKET; break;
case ']':
tok = TOKEN_R_BRACKET; break;
tk_type = TOKEN_R_BRACKET; break;
case '(':
tok = TOKEN_L_PAREN; break;
tk_type = TOKEN_L_PAREN; break;
case ')':
tok = TOKEN_R_PAREN; break;
tk_type = TOKEN_R_PAREN; break;
case '{':
tok = TOKEN_L_BRACE; break;
tk_type = TOKEN_L_BRACE; break;
case '}':
tok = TOKEN_R_BRACE; break;
tk_type = TOKEN_R_BRACE; break;
case ';':
tok = TOKEN_SEMICOLON; break;
tk_type = TOKEN_SEMICOLON; break;
case ',':
tok = TOKEN_COMMA; break;
tk_type = TOKEN_COMMA; break;
case ':':
tok = TOKEN_COLON; break;
tk_type = TOKEN_COLON; break;
case '.':
if (peek[0] == '.' && peek[1] == '.') {
peek += 2;
tok = TOKEN_ELLIPSIS;
tk_type = TOKEN_ELLIPSIS;
} else {
tok = TOKEN_DOT;
tk_type = TOKEN_DOT;
}
break;
case '?':
tok = TOKEN_COND; break;
case '\v': case '\r': case '\f': // FIXME it parse as a blank character
tok = TOKEN_FLUSH; break;
case '\n':
tk_type = TOKEN_COND; break;
case '\v': case '\r': case '\f':
case ' ': case '\t':
tk_type = TOKEN_BLANK; break;
case '\n':
// you need to flush a newline or blank
lexer->line++;
tok = TOKEN_FLUSH; break;
lexer->loc.line += 1;
lexer->loc.col = -1;
lexer->loc.len = 1;
tk_type = TOKEN_BLANK;
break;
case '#':
warn("TODO: #define\n");
// TODO make line or file comment to change
LEX_WARN("Maroc does not support in lexer rather in preprocessor, it will be ignored");
goto_newline(lexer);
tok = TOKEN_FLUSH;
tk_type = TOKEN_BLANK;
goto END;
case '\0':
// EOF
tok = TOKEN_EOF;
tk_type = TOKEN_EOF;
goto END;
case '\'':
return parse_char_literal(lexer, token);
return;
parse_char_literal(lexer, token);
literal = token->val;
tk_type = TOKEN_CHAR_LITERAL;
goto END; break;
case '"':
return parse_string_literal(lexer, token);
parse_string_literal(lexer, token);
literal = token->val;
tk_type = TOKEN_STRING_LITERAL;
goto END; break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
return parse_number(lexer, token);
parse_number(lexer, token);
// TODO Make it easy
literal = token->val;
tk_type = token->sub_type;
goto END; break;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
@ -458,53 +459,67 @@ 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;
}
break;
}
int res = keyword_cmp((const char*)lexer->cur_ptr, peek - (lexer->cur_ptr));
int strlen = peek - lexer->cur_ptr;
int res = keyword_cmp((const char*)lexer->cur_ptr, strlen);
if (res == -1) {
int strlen = peek - lexer->cur_ptr;
unsigned char* str = xmalloc(strlen + 1);
constant.have = 1;
constant.str = (char*)str;
for (int i = 0; i < strlen; i++) {
str[i] = lexer->cur_ptr[i];
}
str[strlen] = '\0';
constant.have = 1;
constant.str = (char*)str;
tok = TOKEN_IDENT; break;
char prev = lexer->cur_ptr[strlen];
lexer->cur_ptr[strlen] = '\0';
literal.str = strpool_intern(lexer->strpool, lexer->cur_ptr);
lexer->cur_ptr[strlen] = prev;
tk_type = TOKEN_IDENT; break;
} else {
tok = keywords[res].tok; break;
tk_type = 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;
}
lexer->loc.len = peek - lexer->cur_ptr;
lexer->cur_ptr = peek;
END:
token->val = constant;
token->type = tok;
lexer->loc.col += lexer->loc.len;
lexer->loc.len = 0;
token->val = literal;
token->sub_type = tk_type;
token->loc = lexer->loc;
static const tok_basic_type_t tok_type_map[] = {
// 普通token使用#str
#define X(str, basic, tok) [tok] = basic,
TOKEN_TABLE
#undef X
// 关键字使用#name
#define X(name, std, tok) [tok] = TK_BASIC_KEYWORD,
KEYWORD_TABLE
#undef X
};
token->type = tok_type_map[tk_type];
LEX_DEBUG("get token `%s` in %s:%d:%d", get_tok_name(tk_type),
token->loc.fname, token->loc.line, token->loc.col);
}
// get_token maybe got invalid (with parser)
void get_valid_token(lexer_t* lexer, tok_t* token) {
tok_type_t type;
tok_basic_type_t type;
do {
get_token(lexer, token);
type = token->type;
} while (type == TOKEN_FLUSH || type == TOKEN_LINE_COMMENT || type == TOKEN_BLOCK_COMMENT);
Assert(type != TK_BASIC_INVALID);
} while (type == TK_BASIC_WHITESPACE || type == TK_BASIC_COMMENT);
}

View File

@ -1,6 +1,7 @@
#ifndef __LEXER_H__
#define __LEXER_H__
#ifndef __SMCC_CC_LEXER_H__
#define __SMCC_CC_LEXER_H__
#include <lib/core.h>
#include "token.h"
#ifndef LEXER_MAX_TOKEN_SIZE
#define LEXER_MAX_TOKEN_SIZE 63
@ -13,25 +14,25 @@ typedef int (*lexer_sread_fn)(void *dst_buf, int dst_size,
int elem_size, int count, void *stream);
typedef struct lexer {
int line;
int index;
// const char current_file_name[LEXER_BUFFER_SIZE+1];
loc_t loc;
unsigned char* cur_ptr; // 当前扫描的字符,但是还没有开始扫描
unsigned char* end_ptr; // 缓冲区最后一个字符的下一个位置
char* cur_ptr; // 当前扫描的字符,但是还没有开始扫描
char* end_ptr; // 缓冲区最后一个字符的下一个位置
char buffer[LEXER_BUFFER_SIZE+1];
lexer_sread_fn sread;
void* stream;
strpool_t* strpool;
} lexer_t;
void init_lexer(lexer_t* lexer, const char* file_name, void* stream,
lexer_sread_fn sread);
lexer_sread_fn sread, strpool_t* strpool);
// pure token getter it will included empty token like TOKEN_FLUSH
// pure token getter it will included empty token like TOKEN_BLANK
void get_token(lexer_t* lexer, tok_t* token);
// get_token maybe got invalid (with parser as TOKEN_FLUSH)
// get_token maybe got invalid (with parser as TOKEN_BLANK)
void get_valid_token(lexer_t* lexer, tok_t* token);
#endif

View File

@ -0,0 +1,46 @@
#ifndef __SMCC_LEXER_LOG_H__
#define __SMCC_LEXER_LOG_H__
#include <lib/rt/rt.h>
#ifndef LEX_LOG_LEVEL
#define LEX_LOG_LEVEL 4
#endif
#if LEX_LOG_LEVEL <= 1
#define LEX_NOTSET( fmt, ...) LOG_NOTSET("LEXER: " fmt, ##__VA_ARGS__)
#else
#define LEX_NOTSET( fmt, ...)
#endif
#if LEX_LOG_LEVEL <= 2
#define LEX_DEBUG( fmt, ...) LOG_DEBUG( "LEXER: " fmt, ##__VA_ARGS__)
#else
#define LEX_DEBUG( fmt, ...)
#endif
#if LEX_LOG_LEVEL <= 3
#define LEX_INFO( fmt, ...) LOG_INFO( "LEXER: " fmt, ##__VA_ARGS__)
#else
#define LEX_INFO( fmt, ...)
#endif
#if LEX_LOG_LEVEL <= 4
#define LEX_WARN( fmt, ...) LOG_WARN( "LEXER: " fmt, ##__VA_ARGS__)
#else
#define LEX_WARN( fmt, ...)
#endif
#if LEX_LOG_LEVEL <= 5
#define LEX_ERROR( fmt, ...) LOG_ERROR("LEXER: " fmt, ##__VA_ARGS__)
#else
#define LEX_ERROR( fmt, ...)
#endif
#if LEX_LOG_LEVEL <= 6
#define LEX_FATAL( fmt, ...) LOG_FATAL("LEXER: " fmt, ##__VA_ARGS__)
#else
#define LEX_FATAL( fmt, ...)
#endif
#endif // __SMCC_LEXER_LOG_H__

View File

@ -1,6 +1,7 @@
CC = gcc
CFLAGS = -g -Wall
CFLAGS = -g -Wall -I../../../.. -DLEX_LOG_LEVEL=4
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

View File

@ -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,15 +38,19 @@ 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);
strpool_t strpool;
init_strpool(&strpool);
init_lexer(&lexer, file_name, fp, (lexer_sread_fn)fread_s, &strpool);
tok_t tok;
while (1) {
get_valid_token(&lexer, &tok);
if (tok.type == TOKEN_EOF) {
if (tok.sub_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));
LOG_DEBUG("tk type `%s` in %s:%d:%d", get_tok_name(tok.sub_type), tok.loc.fname, tok.loc.line, tok.loc.col);
// LOG_DEBUG("%s", tok.val.str);
// printf("line: %d, column: %d, type: %3d, typename: %s\n",
// lexer.line, lexer.index, tok.type, get_tok_name(tok.type));
}
}

View File

@ -1,5 +1,5 @@
// test_lexer.c
#include "../../../../libcore/acutest.h"
#include <lib/acutest.h>
#include "../lexer.h"
#include <string.h>
@ -13,7 +13,7 @@ int test_read(void *dst_buf, int dst_size, int elem_size, int count, void *strea
}
// 测试辅助函数
static inline void test_lexer_string(const char* input, tok_type_t expected_type) {
static inline void test_lexer_string(const char* input, cc_tktype_t expected_type) {
lexer_t lexer;
tok_t token;

View File

@ -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) {
return peek_tok(tokbuf)->type;
cc_tktype_t peek_tok_type(tok_stream_t* tokbuf) {
return peek_tok(tokbuf)->sub_type;
}
int expect_pop_tok(tok_buf_t* tokbuf, tok_type_t type) {
int expect_pop_tok(tok_stream_t* tokbuf, cc_tktype_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));
if (tok->sub_type != type) {
LEX_ERROR("expected tok `%s` but got `%s`", get_tok_name(type), get_tok_name(tok->type));
return 0;
} else {
pop_tok(tokbuf);
}
@ -69,7 +71,7 @@ int expect_pop_tok(tok_buf_t* tokbuf, tok_type_t type) {
// 生成字符串映射(根据需求选择#str或#name
static const char* token_strings[] = {
// 普通token使用#str
#define X(str, tok) [tok] = #str,
#define X(str, basic, tok) [tok] = #str,
TOKEN_TABLE
#undef X
@ -79,6 +81,6 @@ static const char* token_strings[] = {
#undef X
};
const char* get_tok_name(tok_type_t type) {
const char* get_tok_name(cc_tktype_t type) {
return token_strings[type];
}

View File

@ -1,5 +1,7 @@
#ifndef __TOKEN_H__
#define __TOKEN_H__
#ifndef __SMCC_CC_TOKEN_H__
#define __SMCC_CC_TOKEN_H__
#include <lib/utils/utils.h>
enum CSTD_KEYWORD {
CSTD_C89,
@ -46,68 +48,68 @@ enum CSTD_KEYWORD {
// KEYWORD_TABLE
#define TOKEN_TABLE \
X(EOF , TOKEN_EOF) \
X(init , TOKEN_INIT) \
X(flush , TOKEN_FLUSH) \
X("==" , TOKEN_EQ) \
X("=" , TOKEN_ASSIGN) \
X("++" , TOKEN_ADD_ADD) \
X("+=" , TOKEN_ASSIGN_ADD) \
X("+" , TOKEN_ADD) \
X("--" , TOKEN_SUB_SUB) \
X("-=" , TOKEN_ASSIGN_SUB) \
X("->" , TOKEN_DEREF) \
X("-" , TOKEN_SUB) \
X("*=" , TOKEN_ASSIGN_MUL) \
X("*" , TOKEN_MUL) \
X("/=" , TOKEN_ASSIGN_DIV) \
X("/" , TOKEN_DIV) \
X("//" , TOKEN_LINE_COMMENT) \
X("/* */" , TOKEN_BLOCK_COMMENT) \
X("%=" , TOKEN_ASSIGN_MOD) \
X("%" , TOKEN_MOD) \
X("&&" , TOKEN_AND_AND) \
X("&=" , TOKEN_ASSIGN_AND) \
X("&" , TOKEN_AND) \
X("||" , TOKEN_OR_OR) \
X("|=" , TOKEN_ASSIGN_OR) \
X("|" , TOKEN_OR) \
X("^=" , TOKEN_ASSIGN_XOR) \
X("^" , TOKEN_XOR) \
X("<<=" , TOKEN_ASSIGN_L_SH) \
X("<<" , TOKEN_L_SH) \
X("<=" , TOKEN_LE) \
X("<" , TOKEN_LT) \
X(">>=" , TOKEN_ASSIGN_R_SH) \
X(">>" , TOKEN_R_SH) \
X(">=" , TOKEN_GE) \
X(">" , TOKEN_GT) \
X("!" , TOKEN_NOT) \
X("!=" , TOKEN_NEQ) \
X("~" , TOKEN_BIT_NOT) \
X("[" , TOKEN_L_BRACKET) \
X("]" , TOKEN_R_BRACKET) \
X("(" , TOKEN_L_PAREN) \
X(")" , TOKEN_R_PAREN) \
X("{" , TOKEN_L_BRACE) \
X("}" , TOKEN_R_BRACE) \
X(";" , TOKEN_SEMICOLON) \
X("," , TOKEN_COMMA) \
X(":" , TOKEN_COLON) \
X("." , TOKEN_DOT) \
X("..." , TOKEN_ELLIPSIS) \
X("?" , TOKEN_COND) \
X(identifier , TOKEN_IDENT) \
X(int_literal , TOKEN_INT_LITERAL) \
X(float_literal , TOKEN_FLOAT_LITERAL) \
X(char_literal , TOKEN_CHAR_LITERAL) \
X(string_literal , TOKEN_STRING_LITERAL) \
X(init , TK_BASIC_INVALID, TOKEN_INIT) \
X(EOF , TK_BASIC_EOF, TOKEN_EOF) \
X(blank , TK_BASIC_WHITESPACE, TOKEN_BLANK) \
X("==" , TK_BASIC_OPERATOR, TOKEN_EQ) \
X("=" , TK_BASIC_OPERATOR, TOKEN_ASSIGN) \
X("++" , TK_BASIC_OPERATOR, TOKEN_ADD_ADD) \
X("+=" , TK_BASIC_OPERATOR, TOKEN_ASSIGN_ADD) \
X("+" , TK_BASIC_OPERATOR, TOKEN_ADD) \
X("--" , TK_BASIC_OPERATOR, TOKEN_SUB_SUB) \
X("-=" , TK_BASIC_OPERATOR, TOKEN_ASSIGN_SUB) \
X("->" , TK_BASIC_OPERATOR, TOKEN_DEREF) \
X("-" , TK_BASIC_OPERATOR, TOKEN_SUB) \
X("*=" , TK_BASIC_OPERATOR, TOKEN_ASSIGN_MUL) \
X("*" , TK_BASIC_OPERATOR, TOKEN_MUL) \
X("/=" , TK_BASIC_OPERATOR, TOKEN_ASSIGN_DIV) \
X("/" , TK_BASIC_OPERATOR, TOKEN_DIV) \
X("//" , TK_BASIC_COMMENT , TOKEN_LINE_COMMENT) \
X("/* */" , TK_BASIC_COMMENT , TOKEN_BLOCK_COMMENT) \
X("%=" , TK_BASIC_OPERATOR, TOKEN_ASSIGN_MOD) \
X("%" , TK_BASIC_OPERATOR, TOKEN_MOD) \
X("&&" , TK_BASIC_OPERATOR, TOKEN_AND_AND) \
X("&=" , TK_BASIC_OPERATOR, TOKEN_ASSIGN_AND) \
X("&" , TK_BASIC_OPERATOR, TOKEN_AND) \
X("||" , TK_BASIC_OPERATOR, TOKEN_OR_OR) \
X("|=" , TK_BASIC_OPERATOR, TOKEN_ASSIGN_OR) \
X("|" , TK_BASIC_OPERATOR, TOKEN_OR) \
X("^=" , TK_BASIC_OPERATOR, TOKEN_ASSIGN_XOR) \
X("^" , TK_BASIC_OPERATOR, TOKEN_XOR) \
X("<<=" , TK_BASIC_OPERATOR, TOKEN_ASSIGN_L_SH) \
X("<<" , TK_BASIC_OPERATOR, TOKEN_L_SH) \
X("<=" , TK_BASIC_OPERATOR, TOKEN_LE) \
X("<" , TK_BASIC_OPERATOR, TOKEN_LT) \
X(">>=" , TK_BASIC_OPERATOR, TOKEN_ASSIGN_R_SH) \
X(">>" , TK_BASIC_OPERATOR, TOKEN_R_SH) \
X(">=" , TK_BASIC_OPERATOR, TOKEN_GE) \
X(">" , TK_BASIC_OPERATOR, TOKEN_GT) \
X("!" , TK_BASIC_OPERATOR, TOKEN_NOT) \
X("!=" , TK_BASIC_OPERATOR, TOKEN_NEQ) \
X("~" , TK_BASIC_OPERATOR, TOKEN_BIT_NOT) \
X("[" , TK_BASIC_OPERATOR, TOKEN_L_BRACKET) \
X("]" , TK_BASIC_OPERATOR, TOKEN_R_BRACKET) \
X("(" , TK_BASIC_OPERATOR, TOKEN_L_PAREN) \
X(")" , TK_BASIC_OPERATOR, TOKEN_R_PAREN) \
X("{" , TK_BASIC_OPERATOR, TOKEN_L_BRACE) \
X("}" , TK_BASIC_OPERATOR, TOKEN_R_BRACE) \
X(";" , TK_BASIC_OPERATOR, TOKEN_SEMICOLON) \
X("," , TK_BASIC_OPERATOR, TOKEN_COMMA) \
X(":" , TK_BASIC_OPERATOR, TOKEN_COLON) \
X("." , TK_BASIC_OPERATOR, TOKEN_DOT) \
X("..." , TK_BASIC_OPERATOR, TOKEN_ELLIPSIS) \
X("?" , TK_BASIC_OPERATOR, TOKEN_COND) \
X(ident , TK_BASIC_IDENTIFIER, TOKEN_IDENT) \
X(int_literal , TK_BASIC_LITERAL, TOKEN_INT_LITERAL) \
X(float_literal , TK_BASIC_LITERAL, TOKEN_FLOAT_LITERAL) \
X(char_literal , TK_BASIC_LITERAL, TOKEN_CHAR_LITERAL) \
X(string_literal , TK_BASIC_LITERAL, TOKEN_STRING_LITERAL) \
// END
// 定义TokenType枚举
typedef enum tok_type {
typedef enum cc_tktype {
// 处理普通token
#define X(str, tok) tok,
#define X(str, basic, tok) tok,
TOKEN_TABLE
#undef X
@ -115,26 +117,9 @@ typedef enum tok_type {
#define X(name, std, tok) tok,
KEYWORD_TABLE
#undef X
} tok_type_t;
} cc_tktype_t;
typedef struct tok_val {
int have;
union {
char ch;
int i;
float f;
double d;
long long ll;
char* str;
};
} tok_val_t;
typedef struct tok {
tok_type_t type;
tok_val_t val;
} tok_t;
typedef struct tok_buf {
typedef struct tok_stream {
int cur;
int end;
int peek;
@ -143,15 +128,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);
const char* get_tok_name(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);
cc_tktype_t peek_tok_type(tok_stream_t* tokbuf);
int expect_pop_tok(tok_stream_t* tokbuf, cc_tktype_t type);
const char* get_tok_name(cc_tktype_t type);
#endif
#endif

View File

@ -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) {

View File

@ -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

View File

@ -1,5 +1,5 @@
#include "ast.h"
#include "../ast.h"
#include "../parser.h"
#include "../symtab/symtab.h"
@ -17,9 +17,9 @@ 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;
cc_tktype_t ttype;
ast_node_t* node = new_ast_node_block();
expect_pop_tok(tokbuf, TOKEN_L_BRACE);

View File

@ -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,8 +36,8 @@ int peek_decl(tok_buf_t* tokbuf) {
}
ast_node_t* parse_decl_val(parser_t* parser) {
tok_buf_t* tokbuf = &parser->tokbuf;
tok_type_t ttype;
tok_stream_t* tokbuf = &parser->tokbuf;
cc_tktype_t ttype;
flush_peek_tok(tokbuf);
ast_node_t* node;
@ -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;
cc_tktype_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;

View File

@ -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,9 +80,9 @@ 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);
cc_tktype_t ttype = peek_tok_type(tokbuf);
pop_tok(tokbuf);
ast_node_t* node = new_ast_node();
node->type = NT_ASSIGN;
@ -124,16 +124,16 @@ 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);
cc_tktype_t ttype = peek_tok_type(tokbuf);
pop_tok(tokbuf);
ast_node_t* node = new_ast_node();
// saved left
@ -164,14 +164,14 @@ 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);
cc_tktype_t ttype = peek_tok_type(tokbuf);
pop_tok(tokbuf);
ast_node_t* node = new_ast_node();
node->expr.left = left;
@ -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;
@ -238,7 +238,7 @@ static ast_node_t* parse_call(tok_buf_t* tokbuf, symtab_t *symtab, ast_node_t* i
vector_init(node->call.params->params.params);
pop_tok(tokbuf); // 跳过 '('
tok_type_t ttype;
cc_tktype_t ttype;
while (1) {
flush_peek_tok(tokbuf);
ttype = peek_tok_type(tokbuf);
@ -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);
@ -330,12 +330,12 @@ static ast_node_t *parse_primary_expression(tok_buf_t* tokbuf, symtab_t *symtab)
node->type = NT_TERM_VAL;
node->syms.tok = *tok;
switch (tok->type) {
switch (tok->sub_type) {
case TOKEN_INT_LITERAL:
// 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;
@ -344,13 +344,13 @@ static ast_node_t *parse_primary_expression(tok_buf_t* tokbuf, symtab_t *symtab)
// node->data.data_type = TYPE_POINTER;
case TOKEN_IDENT:
node = expect_pop_ident(tokbuf);
tok_type_t ttype = peek_tok_type(tokbuf);
cc_tktype_t ttype = peek_tok_type(tokbuf);
if (ttype == TOKEN_L_PAREN) {
node = parse_call(tokbuf, symtab, node);
} 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,8 +364,8 @@ END:
return node;
}
static ast_node_t *parse_subexpression(tok_buf_t* tokbuf, symtab_t *symtab, enum Precedence prec) {
tok_type_t ttype;
static ast_node_t *parse_subexpression(tok_stream_t* tokbuf, symtab_t *symtab, enum Precedence prec) {
cc_tktype_t ttype;
struct expr_prec_table_t* work;
ast_node_t* left;
@ -397,10 +397,10 @@ 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);
cc_tktype_t ttype = peek_tok_type(tokbuf);
switch (ttype) {
case TOKEN_NOT:
case TOKEN_AND:
@ -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;
}
}

View File

@ -1,15 +1,15 @@
#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;
cc_tktype_t ttype;
ast_node_t *params = new_ast_node();
node->decl_func.params = params;
vector_init(params->params.params);
@ -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,10 +76,10 @@ 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) {
switch (tok->sub_type) {
case TOKEN_L_PAREN:
depth++;
break;
@ -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();

View File

@ -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;

View File

@ -1,10 +1,10 @@
#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);
cc_tktype_t ttype = peek_tok_type(tokbuf);
ast_node_t* node = new_ast_node();
switch (ttype) {
case TOKEN_IF: {
@ -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;

View File

@ -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);
if (tok->sub_type != TOKEN_IDENT) {
LOG_ERROR("syntax error: want identifier but got %d", tok->sub_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,9 +22,9 @@ 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);
cc_tktype_t ttype = peek_tok_type(tokbuf);
data_type_t dtype;
switch(ttype) {
case TOKEN_VOID: dtype = TYPE_VOID; break;
@ -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();

View File

@ -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;
}

View File

@ -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;

View File

@ -1,53 +0,0 @@
// hashmap.c
#include "hashmap.h"
#include <stdlib.h>
#include <string.h>
// DJB2哈希算法
static unsigned long hash(const char* str) {
unsigned long hash = 5381;
int c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash % HMAP_SIZE;
}
void hmap_init(HashMap* map) {
memset(map->buckets, 0, sizeof(map->buckets));
}
void hmap_put(HashMap* map, const char* key, void* value) {
unsigned long idx = hash(key);
HashMapEntry* entry = malloc(sizeof(HashMapEntry));
entry->key = strdup(key);
entry->value = value;
entry->next = map->buckets[idx];
map->buckets[idx] = entry;
}
void* hmap_get(HashMap* map, const char* key) {
unsigned long idx = hash(key);
HashMapEntry* entry = map->buckets[idx];
while (entry) {
if (strcmp(entry->key, key) == 0)
return entry->value;
entry = entry->next;
}
return NULL;
}
int hmap_contains(HashMap* map, const char* key) {
return hmap_get(map, key) != NULL;
}
void hmap_destroy(HashMap* map) {
for (int i = 0; i < HMAP_SIZE; i++) {
HashMapEntry* entry = map->buckets[i];
while (entry) {
HashMapEntry* next = entry->next;
free(entry->key);
free(entry);
entry = next;
}
}
}

View File

@ -1,31 +0,0 @@
#ifndef HASHMAP_H
#define HASHMAP_H
#define HMAP_SIZE 64
typedef struct HashMapEntry {
char* key;
void* value;
struct HashMapEntry* next;
} HashMapEntry;
typedef struct {
HashMapEntry* buckets[HMAP_SIZE];
} HashMap;
// 初始化哈希表
void hmap_init(HashMap* map);
// 插入键值对
void hmap_put(HashMap* map, const char* key, void* value);
// 查找键值
void* hmap_get(HashMap* map, const char* key);
// 检查键是否存在
int hmap_contains(HashMap* map, const char* key);
// 释放哈希表内存不释放value
void hmap_destroy(HashMap* map);
#endif

View File

@ -1,43 +0,0 @@
// scope.c
#include "scope.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct Scope Scope;
Scope* scope_create(Scope* parent) {
Scope* scope = malloc(sizeof(Scope));
hmap_init(&scope->symbols);
scope->parent = parent;
scope->base_offset = 0;
scope->cur_offset = 0;
return scope;
}
void scope_destroy(Scope* scope) {
hmap_destroy(&scope->symbols);
free(scope);
}
void scope_insert(Scope* scope, const char* name, void* symbol) {
if (hmap_contains(&scope->symbols, name)) {
// 处理重复定义错误
fprintf(stderr, "Error: Symbol '%s' already defined\n", name);
exit(EXIT_FAILURE);
}
hmap_put(&scope->symbols, name, symbol);
}
void* scope_lookup(Scope* scope, const char* name) {
void* symbol = NULL;
while (scope) {
symbol = hmap_get(&scope->symbols, name);
if (symbol) break;
scope = scope->parent;
}
return symbol;
}
void* scope_lookup_current(Scope* scope, const char* name) {
return hmap_get(&scope->symbols, name);
}

View File

@ -1,28 +0,0 @@
#ifndef SCOPE_H
#define SCOPE_H
#include "hashmap.h"
struct Scope {
HashMap symbols; // 当前作用域符号表
struct Scope* parent; // 上层作用域
int base_offset;
int cur_offset;
};
// 创建新作用域父作用域可为NULL
struct Scope* scope_create(struct Scope* parent);
// 销毁作用域
void scope_destroy(struct Scope* scope);
// 在当前作用域插入符号
void scope_insert(struct Scope* scope, const char* name, void* symbol);
// 逐级查找符号
void* scope_lookup(struct Scope* scope, const char* name);
// 仅在当前作用域查找
void* scope_lookup_current(struct Scope* scope, const char* name);
#endif

View File

@ -1,49 +0,0 @@
// symtab.c
#include "../../frontend.h"
#include "scope.h"
#include "symtab.h"
typedef symtab_t symtab_t;
typedef struct Scope Scope;
void init_symtab(symtab_t* symtab) {
symtab->global_scope = scope_create(NULL);
symtab->cur_scope = symtab->global_scope;
}
void del_symtab(symtab_t* symtab) {
scope_destroy(symtab->global_scope);
}
void symtab_enter_scope(symtab_t* symtab) {
struct Scope* scope = scope_create(symtab->cur_scope);
scope->base_offset = symtab->cur_scope->base_offset + symtab->cur_scope->cur_offset;
symtab->cur_scope = scope;
}
void symtab_leave_scope(symtab_t* symtab) {
Scope * scope = symtab->cur_scope;
if (scope == NULL) {
error("cannot leave NULL scope or global scope");
}
symtab->cur_scope = symtab->cur_scope->parent;
scope_destroy(scope);
}
void* symtab_add_symbol(symtab_t* symtab, const char* name, void* ast_node, int can_duplicate) {
struct Scope* scope = symtab->cur_scope;
void* node = scope_lookup_current(scope, name);
if (node != NULL) {
if (!can_duplicate) {
error("duplicate symbol %s", name);
}
return node;
}
scope_insert(scope, name, ast_node);
return node;
}
void* symtab_lookup_symbol(symtab_t* symtab, const char* name) {
return scope_lookup(symtab->cur_scope, name);
}

View File

@ -1,18 +0,0 @@
// symtab.h
#ifndef __SYMTAB_H__
#define __SYMTAB_H__
typedef struct symtab {
struct Scope* cur_scope;
struct Scope* global_scope;
} symtab_t;
void init_symtab(symtab_t* symtab);
void del_symtab(symtab_t* symtab);
void symtab_enter_scope(symtab_t* symtab);
void symtab_leave_scope(symtab_t* symtab);
void* symtab_add_symbol(symtab_t* symtab, const char* name, void* ast_node, int can_duplicate);
void* symtab_lookup_symbol(symtab_t* symtab, const char* name);
#endif

View File

@ -6,6 +6,7 @@
// gcc -g ../parser.c ../../lexer/lexer.c ../ast/ast.c ../ast/block.c ../ast/decl.c ../ast/expr.c ../ast/func.c ../ast/program.c ../ast/stmt.c ../ast/term.c ../symtab/hashmap.c ../symtab/scope.c ../symtab/symtab.c test_parser.c -o test_parser
// gcc -g test_parser.c -L../.. -lfrontend -o test_parser
int main(int argc, char** argv) {
init_lib_core();
const char* file_name = "test_file.c";
if (argc == 2) {
file_name = argv[1];
@ -17,8 +18,10 @@ int main(int argc, char** argv) {
}
printf("open file success\n");
struct Lexer lexer;
init_lexer(&lexer, file_name, fp, (lexer_sread_fn)fread_s);
lexer_t lexer;
strpool_t strpool;
init_strpool(&strpool);
init_lexer(&lexer, file_name, fp, (lexer_sread_fn)fread_s, &strpool);
struct SymbolTable symtab;
init_symtab(&symtab);

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View 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 //

View 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) {
}

View File

@ -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() {
}

View File

View 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__

48
lib/Makefile Normal file
View File

@ -0,0 +1,48 @@
# 编译器设置
CC = gcc
AR = ar
CFLAGS = -g -Wall -I..
# 源文件路径
RT_DIR = ./rt
LOG_DIR = ./rt/log
# basic rt lib
SRCS = \
$(RT_DIR)/std/rt_std.c \
./core.c \
$(RT_DIR)/rt.c \
$(RT_DIR)/rt_alloc.c \
$(RT_DIR)/rt_string.c \
$(LOG_DIR)/log.c
# utils lib
UTILS_DIR = ./utils
DS_DIR = $(UTILS_DIR)/ds
STRPOOL_DIR = $(UTILS_DIR)/strpool
SYMTAB_DIR = $(UTILS_DIR)/symtab
TOKBUF_DIR = $(UTILS_DIR)/tokbuf
SRCS += \
$(DS_DIR)/hashtable.c \
$(STRPOOL_DIR)/strpool.c \
# $(SYMTAB_DIR)/symtab.c \
# $(TOKBUF_DIR)/tokbuf.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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

0
lib/test/test_alloc..c Normal file
View File

15
lib/test/test_log.c Normal file
View 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");
}

129
lib/utils/ds/hashtable.c Normal file
View File

@ -0,0 +1,129 @@
#include "hashtable.h"
#define INIT_HASH_TABLE_SIZE (32)
void hashtable_init(hash_table_t* ht) {
vector_init(ht->entries);
ht->count = 0;
ht->tombstone_count = 0;
Assert(ht->key_cmp != NULL && ht->hash_func != NULL);
}
static int next_power_of_two(int n) {
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return n + 1;
}
static hash_entry_t* find_entry(hash_table_t* ht, const void* key, u32_t hash) {
if (ht->entries.cap == 0) return NULL;
u32_t index = hash & (ht->entries.cap - 1); // 容量是2的幂
u32_t probe = 0;
hash_entry_t* tombstone = NULL;
while (1) {
hash_entry_t* entry = &vector_at(ht->entries, index);
if (entry->state == ENTRY_EMPTY) {
return tombstone ? tombstone : entry;
}
if (entry->state == ENTRY_TOMBSTONE) {
if (!tombstone) tombstone = entry;
} else if (entry->hash == hash && ht->key_cmp(entry->key, key) == 0) {
return entry;
}
// Liner finding
index = (index + 1) & (ht->entries.cap - 1);
probe++;
if (probe >= ht->entries.cap) break;
}
LOG_ERROR("hashset_find: hash table is full");
return NULL;
}
static void adjust_capacity(hash_table_t* ht, int new_cap) {
new_cap = next_power_of_two(new_cap);
Assert(new_cap >= ht->entries.cap);
vector_header(old_entries, hash_entry_t);
old_entries.data = ht->entries.data;
old_entries.cap = ht->entries.cap;
// Not used size but for gdb python extention debug
ht->entries.size = new_cap;
ht->entries.cap = new_cap;
ht->entries.data = salloc_realloc(NULL, new_cap * sizeof(hash_entry_t));
rt_memset(ht->entries.data, 0, new_cap * sizeof(hash_entry_t));
// rehash the all of the old data
for (rt_size_t i = 0; i < old_entries.cap; i++) {
hash_entry_t* entry = &vector_at(old_entries, i);
if (entry->state == ENTRY_ACTIVE) {
hash_entry_t* dest = find_entry(ht, entry->key, entry->hash);
*dest = *entry;
}
}
vector_free(old_entries);
ht->tombstone_count = 0;
}
void* hashtable_set(hash_table_t* ht, const void* key, void* value) {
if (ht->count + ht->tombstone_count >= ht->entries.cap * 0.75) {
int new_cap = ht->entries.cap < INIT_HASH_TABLE_SIZE ? INIT_HASH_TABLE_SIZE : ht->entries.cap * 2;
adjust_capacity(ht, new_cap);
}
u32_t hash = ht->hash_func(key);
hash_entry_t* entry = find_entry(ht, key, hash);
void* old_value = NULL;
if (entry->state == ENTRY_ACTIVE) {
old_value = entry->value;
} else {
if (entry->state == ENTRY_TOMBSTONE) ht->tombstone_count--;
ht->count++;
}
entry->key = key;
entry->value = value;
entry->hash = hash;
entry->state = ENTRY_ACTIVE;
return old_value;
}
void* hashtable_get(hash_table_t* ht, const void* key) {
if (ht->entries.cap == 0) return NULL;
u32_t hash = ht->hash_func(key);
hash_entry_t* entry = find_entry(ht, key, hash);
return (entry && entry->state == ENTRY_ACTIVE) ? entry->value : NULL;
}
void* hashtable_del(hash_table_t* ht, const void* key) {
if (ht->entries.cap == 0) return NULL;
u32_t hash = ht->hash_func(key);
hash_entry_t* entry = find_entry(ht, key, hash);
if (entry == NULL || entry->state != ENTRY_ACTIVE) return NULL;
void* value = entry->value;
entry->state = ENTRY_TOMBSTONE;
ht->count--;
ht->tombstone_count++;
return value;
}
void hashtable_destory(hash_table_t* ht) {
vector_free(ht->entries);
ht->count = 0;
ht->tombstone_count = 0;
}

39
lib/utils/ds/hashtable.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef __SMCC_HASHTABLE_H__
#define __SMCC_HASHTABLE_H__
#include <lib/rt/rt_alloc.h>
#include "vector.h"
// 哈希表条目状态标记
typedef enum hash_table_entry_state {
ENTRY_EMPTY,
ENTRY_ACTIVE,
ENTRY_TOMBSTONE
} ht_entry_state_t;
// 哈希表条目结构不管理key/value内存
typedef struct hash_entry {
const void* key; // 由调用者管理
void* value; // 由调用者管理
u32_t hash; // 预计算哈希值
ht_entry_state_t state; // 条目状态
} hash_entry_t;
// 哈希表主体结构
typedef struct hash_table {
vector_header(entries, hash_entry_t); // 使用vector管理条目
u32_t count; // 有效条目数(不含墓碑)
u32_t tombstone_count; // 墓碑数量
u32_t (*hash_func)(const void* key);
int(*key_cmp)(const void* key1, const void* key2);
} hash_table_t;
// WARN you need set hash_func and key_cmp before use
void hashtable_init(hash_table_t* ht) ;
void* hashtable_set(hash_table_t* ht, const void* key, void* value);
void* hashtable_get(hash_table_t* ht, const void* key);
void* hashtable_get(hash_table_t* ht, const void* key);
void hashtable_destory(hash_table_t* ht);
#endif // __SMCC_HASHTABLE_H__

158
lib/utils/ds/kllist.h Normal file
View 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

View File

@ -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:
"""兼容新旧注册方式的最终方案"""

View File

@ -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
View File

View File

@ -0,0 +1,32 @@
#include "strpool.h"
void init_strpool(strpool_t* pool) {
lalloc_init(&pool->stralloc);
pool->ht.hash_func = (u32_t(*)(const void*))rt_strhash;
pool->ht.key_cmp = (int(*)(const void*, const void*))rt_strcmp;
hashtable_init(&pool->ht);
}
const char* strpool_intern(strpool_t* pool, const char* str) {
void* existing = hashtable_get(&pool->ht, str);
if (existing) {
return existing;
}
rt_size_t len = rt_strlen(str) + 1;
char* new_str = lalloc_alloc(&pool->stralloc, len);
if (!new_str) {
LOG_ERROR("strpool: Failed to allocate memory for string");
return NULL;
}
rt_memcpy(new_str, str, len);
hashtable_set(&pool->ht, new_str, new_str);
return new_str;
}
void strpool_destroy(strpool_t* pool) {
hashtable_destory(&pool->ht);
lalloc_destroy(&pool->stralloc);
}

View File

@ -0,0 +1,17 @@
#ifndef __SMCC_STRPOOL_H__
#define __SMCC_STRPOOL_H__
#include <lib/core.h>
#include <lib/rt/rt_alloc.h>
#include <lib/utils/ds/hashtable.h>
typedef struct strpool {
hash_table_t ht; // 用于快速查找字符串
long_alloc_t stralloc; // 专门用于字符串存储的分配器
} strpool_t;
void init_strpool(strpool_t* pool);
const char* strpool_intern(strpool_t* pool, const char* str);
void strpool_destroy(strpool_t* pool);
#endif // __SMCC_STRPOOL_H__

View File

View File

@ -0,0 +1,6 @@
#ifndef __SMCC_SYMTABL_H__
#define __SMCC_SYMTABL_H__
#endif

19
lib/utils/tokbuf/tokbuf.c Normal file
View 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);

75
lib/utils/tokbuf/tokbuf.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef __SMCC_TOKBUF_H__
#define __SMCC_TOKBUF_H__
#include <lib/rt/rt.h>
typedef struct loc {
const char *fname;
int line;
int col;
int len;
} loc_t;
typedef enum tok_basic_type {
TK_BASIC_INVALID, // 错误占位
TK_BASIC_KEYWORD, // 关键字
TK_BASIC_OPERATOR, // 操作符
TK_BASIC_IDENTIFIER, // 标识符
TK_BASIC_LITERAL, // 字面量
TK_BASIC_WHITESPACE, // 空白
TK_BASIC_COMMENT, // 注释
TK_BASIC_EOF // 结束标记
} tok_basic_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;
char ch;
int i;
// MUST BE strpool ptr
const char* str;
} ctype_t;
typedef struct tok {
tok_basic_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__

8
lib/utils/utils.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef __SMCC_LIB_UTILS_H__
#define __SMCC_LIB_UTILS_H__
#include "strpool/strpool.h"
#include "symtab/symtab.h"
#include "tokbuf/tokbuf.h"
#endif

View File

@ -1,10 +0,0 @@
#ifndef __STDCORE_H__
#define __STDCORE_H__
#ifndef __NO_LINK_STDLIB
#include <stdlib.h>
#else
#error "__NO_LINK_STDLIB"
#endif
#endif