121 lines
3.5 KiB
C
121 lines
3.5 KiB
C
#include "../parser.h"
|
||
#include "../symtab/symtab.h"
|
||
#include "ast.h"
|
||
|
||
#ifndef FUNC_PARAM_CACHE_SIZE
|
||
#define FUNC_PARAM_CACHE_SIZE 32 // 合理初始值,可覆盖99%常见情况
|
||
#endif
|
||
|
||
struct FuncParamCache {
|
||
struct Token tokens[FUNC_PARAM_CACHE_SIZE];
|
||
int read_pos; // 当前读取位置
|
||
int write_pos; // 写入位置
|
||
int depth; // 当前缓存深度
|
||
};
|
||
|
||
static enum TokenType peekcachetype(struct FuncParamCache* cache) {
|
||
return cache->tokens[cache->read_pos++].type;
|
||
}
|
||
|
||
// TODO 语义分析压入符号表
|
||
static void parse_params(struct Parser* parser, struct FuncParamCache* cache, struct ASTNode* node) {
|
||
// = peekcachetype(cache);
|
||
enum TokenType ttype;
|
||
// if (ttype != TOKEN_L_PAREN) {
|
||
// error("function expected '('\n");
|
||
// }
|
||
struct ASTNode *params = new_ast_node();
|
||
node->func.params = params;
|
||
int params_size = 0;
|
||
|
||
while ((ttype = peekcachetype(cache)) != TOKEN_R_PAREN) {
|
||
switch (ttype) {
|
||
case TOKEN_COMMA:
|
||
break;
|
||
case TOKEN_ELLIPSIS:
|
||
ttype = peekcachetype(cache);
|
||
if (ttype != TOKEN_R_PAREN) {
|
||
error("... must be a last parameter list (expect ')')");
|
||
}
|
||
// TODO
|
||
error("not implement");
|
||
break;
|
||
case TOKEN_IDENT:
|
||
params->children[params_size++] = NULL;
|
||
break;
|
||
default:
|
||
// TODO 使用cache的类型解析
|
||
// parse_type(parser);
|
||
// TODO type parse
|
||
// ttype = peekcachetype(cache);
|
||
// ttype = peekcachetype(cache);
|
||
// if (ttype != TOKEN_IDENT) {
|
||
// node->node_type = NT_DECL_FUNC;
|
||
// flushpeektok(parser);
|
||
// continue;
|
||
// }
|
||
// error("function expected ')' or ','\n");
|
||
}
|
||
}
|
||
}
|
||
|
||
enum ASTType check_is_func_decl(struct Parser* parser, struct FuncParamCache* cache) {
|
||
cache->depth = 1;
|
||
cache->read_pos = 0;
|
||
cache->write_pos = 0;
|
||
|
||
while (cache->depth) {
|
||
struct Token* tok = peektok(parser);
|
||
poptok(parser);
|
||
if (cache->write_pos >= FUNC_PARAM_CACHE_SIZE - 1) {
|
||
error("function parameter list too long");
|
||
}
|
||
cache->tokens[cache->write_pos++] = *tok;
|
||
switch (tok->type) {
|
||
case TOKEN_L_PAREN:
|
||
cache->depth++;
|
||
break;
|
||
case TOKEN_R_PAREN:
|
||
cache->depth--;
|
||
break;
|
||
}
|
||
}
|
||
|
||
switch (peektoktype(parser)) {
|
||
case TOKEN_SEMICOLON:
|
||
poptok(parser);
|
||
return NT_DECL_FUNC;
|
||
case TOKEN_L_BRACE:
|
||
return NT_FUNC;
|
||
break;
|
||
default:
|
||
error("function define or decl need '{' or ';' but you don't got");
|
||
}
|
||
}
|
||
|
||
struct ASTNode* parse_func(struct Parser* parser) {
|
||
struct ASTNode* ret_type = parse_type(parser);
|
||
struct ASTNode* func_name = parse_ident(parser);
|
||
|
||
struct ASTNode* node = new_ast_node();
|
||
node->func.ret = ret_type;
|
||
node->func.name = func_name;
|
||
|
||
flushpeektok(parser);
|
||
expecttok(parser, TOKEN_L_PAREN);
|
||
struct FuncParamCache cache;
|
||
node->type = check_is_func_decl(parser, &cache);
|
||
|
||
symtab_add_symbol(parser->symtab, func_name->syms.tok.constant.str, node);
|
||
if (node->type == NT_DECL_FUNC) {
|
||
return node;
|
||
}
|
||
|
||
symtab_enter_scope(parser->symtab);
|
||
parse_params(parser, &cache, node);
|
||
node->func.body = parse_block(parser);
|
||
symtab_leave_scope(parser->symtab);
|
||
|
||
return node;
|
||
}
|