#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include "ast.h"
#include "cibic.tab.h"
#define NEW_CNODE ((CNode *)malloc(sizeof(CNode)))
CNode *ast_root;
void cnode_reverse_chd(CNode *node) {
static CNode *chdn[MAX_CHDN];
CNode *p;
int n = 0;
for (p = node->chd; p; p = p->next)
cnode_reverse_chd(p);
for (p = node->chd; p; p = p->next)
chdn[n++] = p;
if (n)
{
node->chd = chdn[--n];
for (; n; n--)
chdn[n]->next = chdn[n - 1];
chdn[0]->next = NULL;
}
}
CNode *cnode_create_ast(CNode *wrapped) {
cnode_reverse_chd(wrapped);
return wrapped;
}
CNode *cnode_create_nop(void) {
CNode *nop = NEW_CNODE;
nop->type = NOP;
nop->next = nop->chd = NULL;
return nop;
}
CNode *cnode_create_general(int type, int subtype, int pnum, va_list ap) {
int i;
CNode *exp = NEW_CNODE;
exp->type = type;
exp->rec.subtype = subtype;
exp->next = exp->chd = NULL;
exp->ext.type = NULL;
exp->ext.offset = 0;
for (i = 0; i < pnum; i++)
{
CNode *subexp = va_arg(ap, CNode*);
#ifdef CIBIC_DEBUG
assert(subexp->next == NULL);
#endif
subexp->next = exp->chd;
exp->chd = subexp;
}
return exp;
}
CNode *cnode_list_append(CNode *list, CNode *tail) {
if (list->type == NOP)
{
free(list);
return tail;
}
tail->next = list;
return tail;
}
CNode *cnode_create_identifier(char *val) {
CNode *exp = NEW_CNODE;
exp->type = ID;
exp->chd = exp->next = NULL;
exp->rec.strval = val;
exp->ext.type = NULL;
exp->ext.offset = 0;
return exp;
}
CNode *cnode_create_int_const(int val) {
/* TODO: overflow checking */
CNode *exp = NEW_CNODE;
exp->type = INT;
exp->chd = exp->next = NULL;
exp->rec.intval = val;
exp->ext.type = NULL;
return exp;
}
CNode *cnode_create_char_const(char *val) {
/* TODO: overflow checking */
CNode *exp = NEW_CNODE;
exp->type = CHAR;
exp->chd = exp->next = NULL;
exp->rec.strval = val;
exp->ext.type = NULL;
return exp;
}
CNode *cnode_create_str_const(char *val) {
CNode *exp = NEW_CNODE;
exp->type = STR;
exp->chd = exp->next = NULL;
exp->rec.strval = val;
exp->ext.type = NULL;
return exp;
}
CNode *cnode_create_exp(int exp_type, int pnum, ...) {
CNode *ret;
va_list ap;
va_start(ap, pnum);
ret = cnode_create_general(EXP, exp_type, pnum, ap);
va_end(ap);
return ret;
}
CNode *cnode_create_type_spec(int spec_type, int pnum, ...) {
CNode *ret;
va_list ap;
va_start(ap, pnum);
ret = cnode_create_general(TYPE_SPEC, spec_type, pnum, ap);
va_end(ap);
return ret;
}
CNode *cnode_create_declr(int declr_type, int pnum, ...) {
CNode *ret;
va_list ap;
va_start(ap, pnum);
ret = cnode_create_general(DECLR, declr_type, pnum, ap);
va_end(ap);
return ret;
}
CNode *cnode_create_stmt(int stmt_type, int pnum, ...) {
CNode *ret;
va_list ap;
va_start(ap, pnum);
ret = cnode_create_general(STMT, stmt_type, pnum, ap);
va_end(ap);
return ret;
}
CNode *cnode_create_initr(int initr_type, CNode *body) {
CNode *initr = NEW_CNODE;
initr->type = INITR;
initr->rec.subtype = initr_type;
initr->chd = body;
initr->next = NULL;
initr->ext.type = NULL;
return initr;
}
CNode *cnode_create_decl(CNode *type, CNode *init_declrs) {
CNode *decl = NEW_CNODE;
#ifdef CIBIC_DEBUG
assert(type->next == NULL);
assert(init_declrs->next == NULL);
#endif
decl->type = DECL;
decl->next = NULL;
decl->ext.type = NULL;
decl->chd = init_declrs;
init_declrs->next = type;
return decl;
}
CNode *cnode_create_func(CNode *type, CNode *declr, CNode *stmt) {
CNode *func = NEW_CNODE;
#ifdef CIBIC_DEBUG
assert(type->next == NULL);
assert(declr->next == NULL);
assert(stmt->next == NULL);
#endif
func->type = FUNC_DEF;
func->next = NULL;
func->ext.type = NULL;
func->chd = stmt;
stmt->next = declr;
declr->next = type;
return func;
}
CNode *cnode_create_init_declr(CNode *declr, CNode *initr) {
CNode *init_declr = NEW_CNODE;
#ifdef CIBIC_DEBUG
assert(declr->next == NULL);
assert(initr->next == NULL);
#endif
init_declr->type = INIT_DECLR;
init_declr->next = NULL;
init_declr->ext.type = NULL;
init_declr->chd = initr;
initr->next = declr;
return init_declr;
}
CNode *cnode_create_struct_field(CNode *type_spec, CNode *declrs) {
CNode *field = NEW_CNODE;
#ifdef CIBIC_DEBUG
assert(type_spec->next == NULL);
assert(declrs->next == NULL);
#endif
field->type = FIELD;
field->next = NULL;
field->ext.type = NULL;
field->chd = declrs;
declrs->next = type_spec;
return field;
}
CNode *cnode_create_plain_decl(CNode *type_spec, CNode *declr) {
CNode *pdecl = NEW_CNODE;
#ifdef CIBIC_DEBUG
assert(type_spec->next == NULL);
assert(declr->next == NULL);
#endif
pdecl->type = PLAIN_DECL;
pdecl->next = NULL;
pdecl->ext.type = NULL;
pdecl->chd = declr;
declr->next = type_spec;
return pdecl;
}
CNode *cnode_create_typedef(CNode *type, CNode *declrs) {
#ifdef CIBIC_DEBUG
assert(type->next == NULL);
assert(declrs->next == NULL);
#endif
CNode *def = NEW_CNODE;
def->type = TYPEDEF;
def->next = NULL;
def->ext.type = NULL;
def->chd = declrs;
declrs->next = type;
return def;
}
CNode *cnode_list_wrap(int type, CNode *list) {
CNode *wlist = NEW_CNODE;
wlist->type = type;
wlist->next = NULL;
wlist->ext.type = NULL;
wlist->chd = list;
return wlist;
}
char *cnode_debug_type_repr(CNode *ast) {
static char buffer[MAX_DEBUG_PRINT_BUFF],
abuff[MAX_DEBUG_PRINT_BUFF];
char *type, *aptr = abuff;
switch (ast->type)
{
case PROG: type = "prog"; break;
case FUNC_DEF: type = "func_def"; break;
case DECLS: type = "prg_decls"; break;
case FUNCS: type = "prg_funcs"; break;
case DECL: type = "decl"; break;
case INIT_DECLR: type = "init_declr"; break;
case PLAIN_DECL: type = "p_decl"; break;
case COMP_STMTS: type = "blk_stmts"; break;
case COMP_DECLS: type = "blk_decls"; break;
case DECLRS: type = "declrs"; break;
case INIT_DECLRS: type = "init_declrs"; break;
case ARGS: type = "args"; break;
case PARAMS: type = "params"; break;
case TYPEDEF: type = "typedef"; break;
case ID:
type = "id";
aptr += sprintf(abuff, "%s", ast->rec.strval);
break;
case INT:
type = "int";
aptr += sprintf(abuff, "%d", ast->rec.intval);
break;
case CHAR:
type = "char";
aptr += sprintf(abuff, "%s", ast->rec.strval);
break;
case STR:
type = "str";
aptr += sprintf(abuff, "\"%s\"", ast->rec.strval);
break;
case FIELD: type = "field"; break;
case FIELDS: type = "fields"; break;
case NOP: type = "nop"; break;
case EXP:
case INITR:
case TYPE_SPEC:
case STMT:
case DECLR:
type = NULL; break;
}
if (ast->type == EXP)
{
switch (ast->rec.subtype)
{
case ',': type = ","; break;
case '=': type = "="; break;
case ASS_MUL: type = "*="; break;
case ASS_DIV: type = "/="; break;
case ASS_MOD: type = "%="; break;
case ASS_ADD: type = "+="; break;
case ASS_SUB: type = "-="; break;
case ASS_SHL: type = "<<="; break;
case ASS_SHR: type = ">>="; break;
case ASS_AND: type = "&="; break;
case ASS_XOR: type = "^="; break;
case ASS_OR: type = "|="; break;
case OPT_OR: type = "||"; break;
case OPT_AND: type = "&&"; break;
case '|': type = "|"; break;
case '^': type = "^"; break;
case '&': type = "&"; break;
case OPT_EQ: type = "=="; break;
case OPT_NE: type = "!="; break;
case '<': type = "<"; break;
case '>': type = ">"; break;
case OPT_LE: type = "<="; break;
case OPT_GE: type = ">="; break;
case OPT_SHL: type = "<<"; break;
case OPT_SHR: type = ">>"; break;
case '+': type = "+"; break;
case '-': type = "-"; break;
case '*': type = "*"; break;
case '/': type = "/"; break;
case '%': type = "%"; break;
case EXP_CAST: type = "cast"; break;
case OPT_INC: type = "++"; break;
case OPT_DEC: type = "--"; break;
case '~': type = "~"; break;
case '!': type = "!"; break;
case KW_SIZEOF: type = "sizeof"; break;
case EXP_POSTFIX: type = "postfix"; break;
case POSTFIX_ARR: type = "arr"; break;
case POSTFIX_CALL: type = "call"; break;
case POSTFIX_DOT: type = "dot"; break;
case POSTFIX_PTR: type = "ptr"; break;
default: assert(0);
}
}
else if (ast->type == TYPE_SPEC)
{
switch (ast->rec.subtype)
{
case KW_VOID: type = "void"; break;
case KW_CHAR: type = "char"; break;
case KW_INT: type = "int"; break;
case KW_STRUCT: type = "struct"; break;
case KW_UNION: type = "union"; break;
case USER_TYPE: type = "user_type"; break;
default: assert(0);
}
}
else if (ast->type == DECLR)
{
switch (ast->rec.subtype)
{
case DECLR_FUNC: type = "func"; break;
case DECLR_ARR: type = "arr"; break;
case '*': type = "*"; break;
case 0: type = "typename"; break;
default: assert(0);
}
}
else if (ast->type == STMT) { switch (ast->rec.subtype)
{
case STMT_EXP: type = "exp"; break;
case STMT_COMP: type = "blk"; break;
case STMT_IF: type = "if"; break;
case STMT_WHILE: type = "while"; break;
case STMT_FOR: type = "for"; break;
case STMT_CONT: type = "cont"; break;
case STMT_BREAK: type = "break"; break;
case STMT_RET: type = "ret"; break;
default: assert(0);
}
}
else if (ast->type == INITR)
{
switch (ast->rec.subtype)
{
case INITR_NORM: type = "initr_n"; break;
case INITR_ARR: type = "initr_a"; break;
default: assert(0);
}
}
else
{
if (type == NULL) puts("");
assert(type);
}
{
char *head = buffer;
head += sprintf(head, "%s", type);
if (aptr != abuff)
{
*aptr = '\0';
head += sprintf(head, ":%s", abuff);
}
head += sprintf(head, "(%d:%d)", ast->loc.row, ast->loc.col);
if (ast->ext.type)
sprintf(head, "->(var:%lx type:%lx ic:%d cv:%ld off:%d)",
(size_t)ast->ext.var, (size_t)ast->ext.type,
ast->ext.is_const, ast->ext.const_val, ast->ext.offset);
}
return buffer;
}
void cnode_debug_print_plain(CNode *ast) {
fprintf(stderr, "(%s", cnode_debug_type_repr(ast));
for (ast = ast->chd; ast; ast = ast->next)
{
fprintf(stderr, " ");
cnode_debug_print_plain(ast);
}
fprintf(stderr, ")");
}
void cnode_debug_print_fancy(CNode *ast, int lvl) {
static int show[MAX_DEBUG_PRINT_LVL];
int i;
show[lvl] = 1;
for (i = 0; i < lvl - 1; i++)
fprintf(stderr, "%c ", show[i] ? '|' : ' ');
if (lvl)
fprintf(stderr, "|____");
fprintf(stderr, "[%s]\n", cnode_debug_type_repr(ast));
for (ast = ast->chd; ast; ast = ast->next)
{
if (!ast->next) show[lvl] = 0;
cnode_debug_print_fancy(ast, lvl + 1);
}
}
void cnode_debug_print(CNode *ast, int fancy) {
if (fancy)
cnode_debug_print_fancy(ast, 0);
else
cnode_debug_print_plain(ast);
puts("");
}
CNode *cnode_add_loc(CNode *node, YYLTYPE loc) {
node->loc.row = loc.first_line;
node->loc.col = loc.first_column;
return node;
}