#include "ctype.h"
#include "stddef.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef struct DynArr {
void *items;
size_t item_size;
size_t item_cnts;
size_t capacity;
} DynArr;
void da_init(DynArr *dyn_arr, size_t item_size, size_t capacity);
DynArr *da_create(size_t item_size, size_t capacity);
void *da_try_push_back(DynArr *dyn_arr);
void *da_push_back(DynArr *dyn_arr, void *item);
static inline void *da_get(DynArr *dyn_arr, size_t idx) {
void *item = dyn_arr->items + idx * dyn_arr->item_size;
return item;
}
static inline void da_set(DynArr *dyn_arr, size_t idx, void *item) {
void *dest = dyn_arr->items + idx * dyn_arr->item_size;
memcpy(dest, item, dyn_arr->item_size);
return;
}
void da_free(DynArr *dyn_arr);
typedef struct StrPoolNode {
char *str;
size_t len;
char alloc_by_pool;
} StrPoolNode;
typedef struct StrPool {
char *mempool;
size_t mempool_offset;
size_t mempool_size;
DynArr pool_nodes;
} StrPool;
void str_pool_init(StrPool *pool, size_t mempool_size, size_t capacity);
StrPool *str_pool_create(size_t mempool_size, size_t capacity);
void str_pool_free(StrPool *str_pool);
char *str_pool_intern(StrPool *str_pool, const char *string, size_t len);
typedef struct VarIntData {
int val;
} VarIntData;
typedef struct VarArrData {
int *arr;
} VarArrData;
typedef union VarData {
VarIntData i;
VarArrData a;
} VarData;
typedef struct Interpreter {
DynArr *stmts;
DynArr *var_decls;
} Interpreter;
Interpreter *interpreter_create(DynArr *stmts, DynArr *var_decls);
void interpreter_free(Interpreter *interpreter);
void interpreter_execute(Interpreter *interpreter);
enum TokType {
TOK_EOF,
TOK_IDENT,
TOK_INT,
TOK_PLUS,
TOK_MINUS,
TOK_COMMA,
TOK_COLON,
TOK_LBRACE,
TOK_RBRACE,
TOK_LBRACKET,
TOK_RBRACKET,
TOK_DOTDOT,
TOK_KEYWORD_VARS,
TOK_KEYWORD_SET,
TOK_KEYWORD_YOSORO,
TOK_KEYWORD_IHU,
TOK_KEYWORD_HOR,
TOK_KEYWORD_WHILE,
TOK_KEYWORD_INT,
TOK_KEYWORD_ARRAY,
TOK_CMP_LT,
TOK_CMP_GT,
TOK_CMP_LE,
TOK_CMP_GE,
TOK_CMP_EQ,
TOK_CMP_NEQ,
};
typedef struct Token {
enum TokType type;
const char *str;
} Token;
typedef struct Lexer {
char *src;
size_t src_len;
size_t ch_pos;
DynArr toks;
StrPool tok_val_pool;
} Lexer;
Lexer *lexer_create(char *src);
void lexer_free(Lexer *lexer);
void token_init(Token *tok, enum TokType tok_type, const char *str);
Token *token_create(enum TokType tok_type, const char *str);
void lexer_tokenize(Lexer *lexer);
enum OperandTyp {
OPERAND_INT_VAR,
OPERAND_ARR_ELEM,
};
enum ExprTermTyp {
EXPR_TERM_CONST,
EXPR_TERM_OPERAND,
};
typedef struct Expr {
DynArr terms;
} Expr;
typedef struct VarDecl VarDecl;
typedef struct Operand {
enum OperandTyp typ;
size_t decl_idx;
union {
Expr idx_expr;
};
} Operand;
typedef struct ExprTerm {
int coefficient;
enum ExprTermTyp typ;
union {
int constant;
Operand operand;
};
} ExprTerm;
enum StmtType {
STMT_IHU_BLK = 0x00,
STMT_WHILE_BLK,
STMT_HOR_BLK,
STMT_YOSORO_CMD = 0xf0,
STMT_SET_CMD,
};
enum VarType {
VAR_INT,
VAR_ARR,
};
typedef struct VarDecl {
enum VarType typ;
VarData data;
const char *name;
struct {
size_t start;
size_t end;
};
} VarDecl;
typedef struct Cond {
enum TokType typ;
Expr left;
Expr right;
} Cond;
typedef struct IhuStmt {
Cond cond;
DynArr stmts;
} IhuStmt;
typedef struct WhileStmt {
Cond cond;
DynArr stmts;
} WhileStmt;
typedef struct HorStmt {
Operand var;
Expr start;
Expr end;
DynArr stmts;
} HorStmt;
typedef struct YosoroStmt {
Expr expr;
} YosoroStmt;
typedef struct SetStmt {
Operand operand;
Expr expr;
} SetStmt;
typedef struct Stmt {
enum StmtType typ;
union {
IhuStmt ihu;
WhileStmt while_stmt;
HorStmt hor;
YosoroStmt yosoro;
SetStmt set;
} inner;
} Stmt;
typedef struct Parser {
DynArr *toks;
size_t pos;
DynArr stmts;
DynArr var_decls;
} Parser;
Parser *parser_create(DynArr *toks);
void parser_free(Parser *parser);
size_t operand_finder(Parser *parser, const char *var_name,
enum OperandTyp type);
DynArr *parser_parse(Parser *parser);
void var_decls_init_data(DynArr *var_decls) {
for (int i = 0; i < var_decls->item_cnts; i++) {
VarDecl *var_decl = da_get(var_decls, i);
switch (var_decl->typ) {
case VAR_INT: {
VarIntData *int_data = &var_decl->data.i;
int_data->val = 0;
} break;
case VAR_ARR: {
VarArrData *arr_data = &var_decl->data.a;
arr_data->arr =
malloc((var_decl->end - var_decl->start + 1) * sizeof(int));
} break;
}
}
}
void var_decls_free_data(DynArr *var_decls) {
for (int i = 0; i < var_decls->item_cnts; i++) {
VarDecl *var_decl = da_get(var_decls, i);
switch (var_decl->typ) {
case VAR_INT:
break;
case VAR_ARR: {
VarArrData *arr_data = &var_decl->data.a;
free(arr_data->arr);
} break;
}
}
}
Interpreter *interpreter_create(DynArr *stmts, DynArr *var_decls) {
Interpreter *interpreter = malloc(sizeof(Interpreter));
interpreter->stmts = stmts;
var_decls_init_data(var_decls);
interpreter->var_decls = var_decls;
return interpreter;
}
void interpreter_free(Interpreter *interpreter) {
var_decls_free_data(interpreter->var_decls);
free(interpreter);
}
int eval_expr(Interpreter *interpreter, Expr *expr);
void write_operand(Interpreter *interpreter, Operand *operand,
int data) {
size_t decl_idx = operand->decl_idx;
VarDecl *decl = da_get(interpreter->var_decls, decl_idx);
switch (operand->typ) {
case OPERAND_INT_VAR:
decl->data.i.val = data;
return;
case OPERAND_ARR_ELEM:
decl->data.a.arr[eval_expr(interpreter, &operand->idx_expr) - decl->start] =
data;
return;
}
}
int read_operand(Interpreter *interpreter, Operand *operand) {
size_t decl_idx = operand->decl_idx;
VarDecl *decl = da_get(interpreter->var_decls, decl_idx);
int data = 0;
switch (operand->typ) {
case OPERAND_INT_VAR:
data = decl->data.i.val;
break;
case OPERAND_ARR_ELEM:
data = decl->data.a
.arr[eval_expr(interpreter, &operand->idx_expr) - decl->start];
break;
}
return data;
}
inline int eval_expr(Interpreter *interpreter, Expr *expr) {
DynArr *terms = &expr->terms;
int res = 0;
for (int i = 0; i < terms->item_cnts; i++) {
ExprTerm *term = da_get(terms, i);
switch (term->typ) {
case EXPR_TERM_CONST:
res += term->coefficient * term->constant;
break;
case EXPR_TERM_OPERAND:
res += term->coefficient * read_operand(interpreter, &term->operand);
break;
}
}
return res;
}
void execute_stmts(Interpreter *interpreter, DynArr *stmts);
char execute_cond(Interpreter *interpreter, Cond *cond) {
int left = eval_expr(interpreter, &cond->left);
int right = eval_expr(interpreter, &cond->right);
switch (cond->typ) {
case TOK_CMP_LT:
return left < right;
case TOK_CMP_GT:
return left > right;
case TOK_CMP_LE:
return left <= right;
case TOK_CMP_GE:
return left >= right;
case TOK_CMP_EQ:
return left == right;
case TOK_CMP_NEQ:
return left != right;
default:
return 0;
}
}
void execute_stmt(Interpreter *interpreter, Stmt *stmt) {
switch (stmt->typ) {
case STMT_IHU_BLK: {
IhuStmt *ihu = &stmt->inner.ihu;
if (execute_cond(interpreter, &ihu->cond)) {
execute_stmts(interpreter, &ihu->stmts);
}
} break;
case STMT_WHILE_BLK: {
WhileStmt *while_stmt = &stmt->inner.while_stmt;
while (execute_cond(interpreter, &while_stmt->cond)) {
execute_stmts(interpreter, &while_stmt->stmts);
}
} break;
case STMT_HOR_BLK: {
HorStmt *hor = &stmt->inner.hor;
int start = eval_expr(interpreter, &hor->start);
int end = eval_expr(interpreter, &hor->end);
for (int i = start; i <= end; i++) {
write_operand(interpreter, &hor->var, i);
execute_stmts(interpreter, &hor->stmts);
}
write_operand(interpreter, &hor->var, end);
} break;
case STMT_YOSORO_CMD: {
YosoroStmt *yosoro = &stmt->inner.yosoro;
int res = eval_expr(interpreter, &yosoro->expr);
printf("%d ", res);
} break;
case STMT_SET_CMD: {
SetStmt *set = &stmt->inner.set;
int res = eval_expr(interpreter, &set->expr);
write_operand(interpreter, &set->operand, res);
} break;
}
}
void execute_stmts(Interpreter *interpreter, DynArr *stmts) {
Stmt *stmt;
for (int i = 0; i < stmts->item_cnts; i++) {
stmt = da_get(stmts, i);
execute_stmt(interpreter, stmt);
}
}
void interpreter_execute(Interpreter *interpreter) {
DynArr *stmts = interpreter->stmts;
execute_stmts(interpreter, stmts);
}
Lexer *lexer_create(char *src) {
Lexer *lexer = malloc(sizeof(Lexer));
str_pool_init(&lexer->tok_val_pool, 512, 16);
lexer->src_len = strlen(src);
lexer->src = src;
lexer->ch_pos = 0;
da_init(&lexer->toks, sizeof(Token), 128);
return lexer;
}
void lexer_free(Lexer *lexer) {
da_free(&lexer->toks);
str_pool_free(&lexer->tok_val_pool);
free(lexer);
}
void token_init(Token *tok, enum TokType tok_type, const char *str) {
tok->type = tok_type;
tok->str = str;
return;
}
Token *token_create(enum TokType tok_type, const char *str) {
Token *tok = malloc(sizeof(Token));
token_init(tok, tok_type, str);
return tok;
}
inline static void add_token(Lexer *lexer, enum TokType tok_type,
const char *val) {
Token *tok = da_try_push_back(&lexer->toks);
token_init(tok, tok_type, val);
return;
}
inline static char is_identifier_char(char c) { return isalpha(c) || c == '_'; }
const struct KeyWords {
const enum TokType typ;
const char *val;
const size_t len;
} keywords[] = {
{TOK_KEYWORD_VARS, "vars", sizeof("vars") - 1},
{TOK_KEYWORD_SET, "set", sizeof("set") - 1},
{TOK_KEYWORD_YOSORO, "yosoro", sizeof("yosoro") - 1},
{TOK_KEYWORD_IHU, "ihu", sizeof("ihu") - 1},
{TOK_KEYWORD_HOR, "hor", sizeof("hor") - 1},
{TOK_KEYWORD_WHILE, "while", sizeof("while") - 1},
{TOK_KEYWORD_INT, "int", sizeof("int") - 1},
{TOK_KEYWORD_ARRAY, "array", sizeof("array") - 1},
{TOK_CMP_LT, "lt", sizeof("lt") - 1},
{TOK_CMP_GT, "gt", sizeof("gt") - 1},
{TOK_CMP_LE, "le", sizeof("le") - 1},
{TOK_CMP_GE, "ge", sizeof("ge") - 1},
{TOK_CMP_EQ, "eq", sizeof("eq") - 1},
{TOK_CMP_NEQ, "neq", sizeof("neq") - 1},
};
const size_t keyword_cnts = sizeof(keywords) / sizeof(*keywords);
int check_keyword(const char *tok_val, size_t len) {
for (int i = 0; i < keyword_cnts; ++i) {
if (keywords[i].len == len && strncmp(tok_val, keywords[i].val, len) == 0) {
return i;
}
}
return -1;
}
void lexer_tokenize(Lexer *lexer) {
while (lexer->ch_pos < lexer->src_len) {
char ch = lexer->src[lexer->ch_pos];
if (isspace(ch)) {
lexer->ch_pos++;
continue;
}
if (isdigit(ch)) {
size_t start = lexer->ch_pos;
while (lexer->ch_pos < lexer->src_len &&
isdigit(lexer->src[lexer->ch_pos])) {
lexer->ch_pos++;
}
size_t len = lexer->ch_pos - start;
char *val = lexer->src + start;
val = str_pool_intern(&lexer->tok_val_pool, val, len);
add_token(lexer, TOK_INT, val);
continue;
}
if (is_identifier_char(ch)) {
size_t start = lexer->ch_pos;
while (lexer->ch_pos < lexer->src_len &&
isalnum(lexer->src[lexer->ch_pos])) {
lexer->ch_pos++;
}
size_t len = lexer->ch_pos - start;
const char *val = lexer->src + start;
int keyword_idx = check_keyword(val, len);
enum TokType type;
if (keyword_idx != -1) {
type = keywords[keyword_idx].typ;
val = keywords[keyword_idx].val;
} else {
type = TOK_IDENT;
val = str_pool_intern(&lexer->tok_val_pool, val, len);
}
add_token(lexer, type, val);
continue;
}
switch (ch) {
case '+':
add_token(lexer, TOK_PLUS, "'+'");
break;
case '-':
add_token(lexer, TOK_MINUS, "'-'");
break;
case ',':
add_token(lexer, TOK_COMMA, "','");
break;
case ':':
add_token(lexer, TOK_COLON, "':'");
break;
case '{':
add_token(lexer, TOK_LBRACE, "'{'");
break;
case '}':
add_token(lexer, TOK_RBRACE, "'}'");
break;
case '[':
add_token(lexer, TOK_LBRACKET, "'['");
break;
case ']':
add_token(lexer, TOK_RBRACKET, "']'");
break;
default:
if (ch == '.' && lexer->ch_pos + 1 < lexer->src_len &&
lexer->src[lexer->ch_pos + 1] == '.') {
add_token(lexer, TOK_DOTDOT, "..");
lexer->ch_pos += 2;
continue;
} else {
lexer->ch_pos++;
continue;
}
break;
}
lexer->ch_pos++;
}
add_token(lexer, TOK_EOF, NULL);
return;
}
void read_src(char **src) {
// FILE *input = stdin;
// fseek(input, 0, SEEK_END);
// size_t input_size = ftell(input);
// fseek(input, 0, SEEK_SET);
// *src = malloc(input_size + 1);
// fread(*src, 512, input_size / 512, input);
// size_t remaining = input_size % 512;
// fread(*src + input_size - remaining, 1, remaining, input);
// (*src)[input_size] = '\0';
const char test_src[] =
"{ vars\n"
"fuck:int\n"
"ccf:int\n"
"}\n"
":set ccf, 38\n"
":set fuck, 250\n"
":yosoro 114514 - ccf + fuck\n"
;
*src = malloc(sizeof(test_src));
memcpy(*src,test_src,sizeof(test_src));
}
int main() {
const char *src;
read_src(&src);
Lexer *lexer = lexer_create(src);
lexer_tokenize(lexer);
Parser *parser = parser_create(&lexer->toks);
parser_parse(parser);
Interpreter *interpreter =
interpreter_create(&parser->stmts, &parser->var_decls);
interpreter_execute(interpreter);
interpreter_free(interpreter);
parser_free(parser);
lexer_free(lexer);
free(src);
return 0;
}
Parser *parser_create(DynArr *toks) {
Parser *parser = malloc(sizeof(Parser));
parser->toks = toks;
parser->pos = 0;
da_init(&parser->stmts, sizeof(Stmt), 16);
da_init(&parser->var_decls, sizeof(VarDecl), 16);
return parser;
}
void free_operand(Operand *op);
void free_expr(Expr *expr) {
for (int i = 0; i < expr->terms.item_cnts; i++) {
ExprTerm *term = da_get(&expr->terms, i);
switch (term->typ) {
case EXPR_TERM_CONST:
continue;
case EXPR_TERM_OPERAND:
free_operand(&term->operand);
break;
}
}
da_free(&expr->terms);
}
void free_operand(Operand *op) {
if (op->typ == OPERAND_ARR_ELEM) {
free_expr(&op->idx_expr);
}
}
void free_stmts(DynArr *stmts) {
for (int i = 0; i < stmts->item_cnts; i++) {
Stmt *stmt = da_get(stmts, i);
switch (stmt->typ) {
case STMT_YOSORO_CMD:
free_expr(&stmt->inner.yosoro.expr);
break;
case STMT_SET_CMD:
free_operand(&stmt->inner.set.operand);
free_expr(&stmt->inner.set.expr);
break;
case STMT_IHU_BLK:
free_expr(&stmt->inner.ihu.cond.left);
free_expr(&stmt->inner.ihu.cond.right);
free_stmts(&stmt->inner.ihu.stmts);
break;
case STMT_WHILE_BLK:
free_expr(&stmt->inner.while_stmt.cond.left);
free_expr(&stmt->inner.while_stmt.cond.right);
free_stmts(&stmt->inner.while_stmt.stmts);
break;
case STMT_HOR_BLK:
free_operand(&stmt->inner.hor.var);
free_expr(&stmt->inner.hor.start);
free_expr(&stmt->inner.hor.end);
free_stmts(&stmt->inner.hor.stmts);
}
}
da_free(stmts);
}
void parser_free(Parser *parser) {
free_stmts(&parser->stmts);
da_free(&parser->var_decls);
free(parser);
}
static Token *current_token(Parser *parser) {
if (parser->pos >= parser->toks->item_cnts) {
return NULL;
}
return da_get(parser->toks, parser->pos);
}
static Token *peek_token(Parser *parser, size_t offset) {
if (parser->pos + offset >= parser->toks->item_cnts) {
return NULL;
}
return da_get(parser->toks, parser->pos + offset);
}
static void consume_token(Parser *parser) { parser->pos++; }
static int match_token(Parser *parser, enum TokType typ) {
Token *token = current_token(parser);
return token && token->type == typ;
}
static Token *next_token(Parser *parser) {
Token *token = current_token(parser);
consume_token(parser);
return token;
}
void parse_vars(Parser *parser) {
consume_token(parser);
consume_token(parser);
DynArr *var_decls = &parser->var_decls;
size_t cnt = 0;
while (!match_token(parser, TOK_RBRACE)) {
Token *ident = next_token(parser);
consume_token(parser);
VarDecl *decl = da_try_push_back(var_decls);
decl->name = ident->str;
if (match_token(parser, TOK_KEYWORD_INT)) {
consume_token(parser);
decl->typ = VAR_INT;
} else if (match_token(parser, TOK_KEYWORD_ARRAY)) {
consume_token(parser);
consume_token(parser);
consume_token(parser);
consume_token(parser);
decl->typ = VAR_ARR;
decl->start = atoll(next_token(parser)->str);
consume_token(parser);
decl->end = atoll(next_token(parser)->str);
consume_token(parser);
}
cnt++;
}
consume_token(parser);
}
void parse_blk(Parser *parser, DynArr *stmts);
void parse_expr(Parser *parser, Expr *expr);
size_t operand_finder(Parser *parser, const char *var_name,
enum OperandTyp type) {
enum VarType target_type = 0xff;
switch (type) {
case OPERAND_INT_VAR:
target_type = VAR_INT;
break;
case OPERAND_ARR_ELEM:
target_type = VAR_ARR;
break;
}
for (int i = 0; i < parser->var_decls.item_cnts; i++) {
VarDecl *decl = da_get(&parser->var_decls, i);
if ((target_type == 0xff || decl->typ == target_type) &&
decl->name == var_name) {
return i;
}
}
return (size_t)-1;
}
void parse_operand(Parser *parser, Operand *operand) {
Token *operand_tok = current_token(parser);
consume_token(parser);
operand->typ = OPERAND_INT_VAR;
if (match_token(parser, TOK_LBRACKET)) {
operand->typ = OPERAND_ARR_ELEM;
consume_token(parser);
parse_expr(parser, &operand->idx_expr);
consume_token(parser);
}
operand->decl_idx = operand_finder(parser, operand_tok->str, operand->typ);
}
int is_operand_eq(Operand *a, Operand *b);
int is_expr_eq(Expr *a, Expr *b) {
int cnts = a->terms.item_cnts;
if (cnts != b->terms.item_cnts) {
return 0;
}
for (int i = 0; i < cnts; i++) {
ExprTerm *a_term = da_get(&a->terms, i);
ExprTerm *b_term = da_get(&b->terms, i);
if (a_term->typ != b_term->typ) {
return 0;
}
switch (a_term->typ) {
case EXPR_TERM_CONST:
return a_term->constant == b_term->constant;
case EXPR_TERM_OPERAND:
return is_operand_eq(&a_term->operand, &b_term->operand);
}
}
return 1;
}
int is_operand_eq(Operand *a, Operand *b) {
if (a->typ != b->typ || a->decl_idx != b->decl_idx) {
return 0;
}
if (a->typ == OPERAND_INT_VAR) {
return 1;
} else {
return is_expr_eq(&a->idx_expr, &b->idx_expr);
}
}
void terms_add_operand(DynArr *terms, Operand op, int sign) {
for (int i = 0; i < terms->item_cnts; i++) {
ExprTerm *term = da_get(terms, i);
if (term->typ == EXPR_TERM_OPERAND && is_operand_eq(&term->operand, &op)) {
term->coefficient += sign;
if (op.typ == OPERAND_ARR_ELEM) {
da_free(&op.idx_expr.terms);
}
return;
}
}
ExprTerm *term = da_try_push_back(terms);
term->coefficient = sign;
term->typ = EXPR_TERM_OPERAND;
term->operand = op;
return;
}
void parse_expr(Parser *parser, Expr *expr) {
da_init(&expr->terms, sizeof(ExprTerm), 8);
DynArr *terms = &expr->terms;
int const_val = 0;
short sign = 1;
while (current_token(parser) &&
!(match_token(parser, TOK_EOF) || match_token(parser, TOK_COLON) ||
match_token(parser, TOK_COMMA) || match_token(parser, TOK_RBRACE) ||
match_token(parser, TOK_LBRACE) ||
match_token(parser, TOK_RBRACKET))) {
sign = 1;
if (match_token(parser, TOK_PLUS)) {
consume_token(parser);
} else if (match_token(parser, TOK_MINUS)) {
sign = -1;
consume_token(parser);
}
Token *term_tok = current_token(parser);
if (term_tok->type == TOK_INT) {
const_val += atoi(term_tok->str) * sign;
consume_token(parser);
continue;
}
Operand op;
parse_operand(parser, &op);
terms_add_operand(terms, op, sign);
}
if (const_val != 0 || terms->item_cnts == 0) {
ExprTerm *const_term = da_try_push_back(terms);
const_term->coefficient = 1;
const_term->typ = EXPR_TERM_CONST;
const_term->constant = const_val;
}
}
void parse_cond(Parser *parser, Cond *cond) {
cond->typ = next_token(parser)->type;
consume_token(parser);
parse_expr(parser, &cond->left);
consume_token(parser);
parse_expr(parser, &cond->right);
}
void parse_ihu(Parser *parser, Stmt *stmt) {
consume_token(parser);
consume_token(parser);
stmt->typ = STMT_IHU_BLK;
IhuStmt *ihu = &stmt->inner.ihu;
parse_cond(parser, &ihu->cond);
da_init(&ihu->stmts, sizeof(Stmt), 16);
parse_blk(parser, &ihu->stmts);
consume_token(parser);
}
void parse_while(Parser *parser, Stmt *stmt) {
consume_token(parser);
consume_token(parser);
stmt->typ = STMT_WHILE_BLK;
WhileStmt *while_stmt = &stmt->inner.while_stmt;
parse_cond(parser, &while_stmt->cond);
da_init(&while_stmt->stmts, sizeof(Stmt), 16);
parse_blk(parser, &while_stmt->stmts);
consume_token(parser);
}
void parse_hor(Parser *parser, Stmt *stmt) {
consume_token(parser);
consume_token(parser);
stmt->typ = STMT_HOR_BLK;
HorStmt *hor = &stmt->inner.hor;
parse_operand(parser, &hor->var);
consume_token(parser);
parse_expr(parser, &hor->start);
consume_token(parser);
parse_expr(parser, &hor->end);
da_init(&hor->stmts, sizeof(Stmt), 16);
parse_blk(parser, &hor->stmts);
consume_token(parser);
}
void parse_yosoro(Parser *parser, Stmt *stmt) {
consume_token(parser);
consume_token(parser);
stmt->typ = STMT_YOSORO_CMD;
YosoroStmt *yosoro = &stmt->inner.yosoro;
parse_expr(parser, &yosoro->expr);
}
void parse_set(Parser *parser, Stmt *stmt) {
consume_token(parser);
consume_token(parser);
stmt->typ = STMT_SET_CMD;
SetStmt *set = &stmt->inner.set;
parse_operand(parser, &set->operand);
consume_token(parser);
parse_expr(parser, &set->expr);
}
static void parse_stmts(Parser *parser, DynArr *stmts) {
Token *tok = current_token(parser);
if (!tok) {
return;
}
Stmt *cur_stmt;
switch (tok->type) {
case TOK_LBRACE:
tok = peek_token(parser, 1);
if (!tok) {
consume_token(parser);
return;
}
switch (tok->type) {
case TOK_KEYWORD_VARS:
parse_vars(parser);
break;
case TOK_KEYWORD_IHU:
cur_stmt = da_try_push_back(stmts);
parse_ihu(parser, cur_stmt);
break;
case TOK_KEYWORD_WHILE:
cur_stmt = da_try_push_back(stmts);
parse_while(parser, cur_stmt);
break;
case TOK_KEYWORD_HOR:
cur_stmt = da_try_push_back(stmts);
parse_hor(parser, cur_stmt);
break;
default:
break;
}
return;
case TOK_COLON:
tok = peek_token(parser, 1);
if (!tok) {
consume_token(parser);
return;
}
cur_stmt = da_try_push_back(stmts);
switch (tok->type) {
case TOK_KEYWORD_YOSORO:
parse_yosoro(parser, cur_stmt);
break;
case TOK_KEYWORD_SET:
parse_set(parser, cur_stmt);
break;
default:
break;
}
break;
default:
consume_token(parser);
return;
}
}
void parse_blk(Parser *parser, DynArr *stmts) {
while (!match_token(parser, TOK_RBRACE) &&
parser->pos < parser->toks->item_cnts &&
!match_token(parser, TOK_EOF)) {
parse_stmts(parser, stmts);
}
}
DynArr *parser_parse(Parser *parser) {
while (parser->pos < parser->toks->item_cnts &&
!match_token(parser, TOK_EOF)) {
parse_stmts(parser, &parser->stmts);
}
return &parser->stmts;
}
void da_init(DynArr *dyn_arr, size_t item_size, size_t capacity) {
dyn_arr->item_cnts = 0;
dyn_arr->capacity = capacity;
dyn_arr->item_size = item_size;
dyn_arr->items = malloc(capacity * dyn_arr->item_size);
}
DynArr *da_create(size_t item_size, size_t capacity) {
DynArr *dyn_arr = malloc(sizeof(DynArr));
da_init(dyn_arr, item_size, capacity);
return dyn_arr;
}
void *da_try_push_back(DynArr *dyn_arr) {
if (dyn_arr->item_cnts >= dyn_arr->capacity) {
dyn_arr->capacity *= 2;
dyn_arr->items =
realloc(dyn_arr->items, dyn_arr->capacity * dyn_arr->item_size);
}
void *dest = dyn_arr->items + dyn_arr->item_cnts * dyn_arr->item_size;
++dyn_arr->item_cnts;
return dest;
}
void *da_push_back(DynArr *dyn_arr, void *item) {
void *dest = da_try_push_back(dyn_arr);
memcpy(dest, item, dyn_arr->item_size);
return dest;
}
void da_free(DynArr *dyn_arr) { free(dyn_arr->items); }
void str_pool_init(StrPool *pool, size_t mempool_size, size_t capacity) {
pool->mempool_size = mempool_size;
pool->mempool = malloc(mempool_size);
da_init(&pool->pool_nodes, sizeof(StrPoolNode), capacity);
return;
}
StrPool *str_pool_create(size_t mempool_size, size_t capacity) {
StrPool *pool = malloc(sizeof(StrPool));
str_pool_init(pool, mempool_size, capacity);
return pool;
}
void str_pool_free(StrPool *str_pool) {
StrPoolNode *node;
for (size_t i = 0; i < str_pool->pool_nodes.item_cnts; i++) {
node = da_get(&str_pool->pool_nodes, i);
if (!node->alloc_by_pool) {
free(node->str);
}
}
da_free(&str_pool->pool_nodes);
free(str_pool->mempool);
return;
}
char *str_pool_intern(StrPool *str_pool, const char *string, size_t len) {
StrPoolNode *dest_node = NULL;
size_t str_node_cnts = str_pool->pool_nodes.item_cnts;
for (size_t i = 0; i < str_node_cnts; i++) {
dest_node = da_get(&str_pool->pool_nodes, i);
if (dest_node->len == len && (strncmp(dest_node->str, string, len) == 0)) {
return dest_node->str;
}
}
dest_node = da_try_push_back(&str_pool->pool_nodes);
dest_node->len = len;
if (len + 1 < str_pool->mempool_size - str_pool->mempool_offset) {
dest_node->alloc_by_pool = 1;
dest_node->str = &str_pool->mempool[str_pool->mempool_offset];
str_pool->mempool_offset += len + 1;
} else {
dest_node->alloc_by_pool = 0;
dest_node->str = malloc(len + 1);
}
memcpy(dest_node->str, string, len);
dest_node->str[len] = '\0';
return dest_node->str;
}