aboutsummaryrefslogblamecommitdiff
path: root/semantics.c
blob: 30a24f74dfdb8af5294dc29e6cbb0fb53700d0c1 (plain) (tree)
1
2
3
4
5
6
7
8
9
                   
                   
                   
                  
                      
                
                                                
                                                     
 








                                                             
                                          

                                                          


                      
      
 
                                                   
                                                      

                             
                                 



                                







                                                                     




                            
             

 

                                                             










                                         
                
                  



                                                     

                                        

                    
             

 
                                             


                    






                                                         

 
                                                


                    






                                                            




                                

                     




                               
                            

              


                                              
                                                 
                                              
                                                  
                

 

                                      
                                        





                                                 
                                                                        

                                  
                                        




                                      
                                                
















                                              
                                                

 
                                                        


                                         
                                                          

                                          





                                            
              
























                                                   


















































































































































                                                                                      
              
 






























                                                                               
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include "semantics.h"
#include "ast.h"
#define NEW(type) ((type *)malloc(sizeof(type)))
#define CHECK_TYPE(p, _type) assert(p->type == _type)

#ifdef CIBIC_DEBUG
CTable_t ctable_create(Hashfunc_t hfunc, Printfunc_t pfunc) {
    CTable_t ct = NEW(CTable);
    memset(ct->head, 0, sizeof(CTNode*) * MAX_TABLE_SIZE);
    ct->hfunc = hfunc;
    ct->pfunc = pfunc;
    return ct;
}
#else
CTable_t ctable_create(Hashfunc_t hfunc) {
    CTable_t ct = NEW(CTable);
    memset(ct->head, 0, sizeof(CTNode*) * MAX_TABLE_SIZE);
    ct->hfunc = hfunc;
    return ct;
}
#endif

void *ctable_lookup(CTable_t ct, const char *key) {
    unsigned int hv = ct->hfunc(key) % MAX_TABLE_SIZE;
    CTNode *p = ct->head[hv];
    for (; p; p = p->next)
        if (!strcmp(p->key, key))
            return p->val;
    return NULL; /* not found */
}

int ctable_insert(CTable_t ct, const char *key, void *val, int lvl) {
    unsigned int hv = ct->hfunc(key) % MAX_TABLE_SIZE;
    CTNode *p = ct->head[hv];
    CTNode *np;
    for (; p && p->lvl == lvl; p = p->next)
        if (!strcmp(p->key, key))
            return 0; /* conflict */
    np = NEW(CTNode);
    np->key = key;
    np->val = val;
    np->lvl = lvl;
    np->next = ct->head[hv];
    ct->head[hv] = np;
    return 1;
}

void ctable_clip(CTable_t ct, const char *key, int max_lvl) {
    unsigned int hv = ct->hfunc(key) % MAX_TABLE_SIZE;
    CTNode *p = ct->head[hv], *np;
    for (; p && p->lvl > max_lvl; p = np)
    {
        np = p->next;
        free(p);
    }
    ct->head[hv] = p;
}

CScope_t cscope_create() {
    CScope_t p = NEW(CScope);
    p->lvl = -1;
    p->top = NULL;
#ifdef CIBIC_DEBUG
    p->tvar = ctable_create(bkdr_hash, cvar_print);
    p->ttype = ctable_create(bkdr_hash, ctype_print);
#else
    p->tvar = ctable_create(bkdr_hash);
    p->ttype = ctable_create(bkdr_hash);
#endif
    cscope_enter(p);
    return p;
}

int cscope_push_var(CScope_t cs, CVar *var) {
#ifdef CIBIC_DEBUG
    assert(cs->top);
#endif
    if (ctable_insert(cs->tvar, var->name, var, cs->lvl))
    {
        var->next = cs->top->vhead;
        cs->top->vhead = var;
        return 1;
    }
    else return 0; /* naming conflict */
}

int cscope_push_type(CScope_t cs, CType *type) {
#ifdef CIBIC_DEBUG
    assert(cs->top);
#endif
    if (ctable_insert(cs->ttype, type->name, type, cs->lvl))
    {
        type->next = cs->top->thead;
        cs->top->thead = type;
        return 1;
    }
    else return 0; /* naming conflict */
}

void cscope_enter(CScope_t cs) {
    CSNode *np = NEW(CSNode);
    np->next = cs->top;
    np->vhead = NULL;
    np->thead = NULL;
    cs->top = np;
    cs->lvl++;
}

void cscope_exit(CScope_t cs) {
    CSNode *top_o = cs->top;
    CVar *vp;
    CType *tp;
    cs->lvl--;
    cs->top = top_o->next;
    for (vp = top_o->vhead; vp; vp = vp->next)
        ctable_clip(cs->tvar, vp->name, cs->lvl);
    for (tp = top_o->thead; tp; tp = tp->next)
        ctable_clip(cs->ttype, tp->name, cs->lvl);
    free(top_o);
}

void ctable_debug_print(CTable_t ct) {
    int i;
    fprintf(stderr, "*** CTable ***\n");
    for (i = 0; i < MAX_TABLE_SIZE; i++)
        if (ct->head[i])
        {
            CTNode *p;
            fprintf(stderr, "[%04d]", i);
            for (p = ct->head[i]; p; p = p->next)
                fprintf(stderr, "->[%s:%d]", ct->pfunc(p->val), p->lvl);
            fprintf(stderr, "\n");
        }
    fprintf(stderr, "*** CTable ***\n");
}

void cscope_debug_print(CScope_t cs) {
    int lvl = cs->lvl;
    CSNode *p;
    fprintf(stderr, "\n****** CScope ******\n");
    for (p = cs->top; p; p = p->next)
    {
        CVar *vp;
        CType *tp;
        fprintf(stderr, "Level %d:\n", lvl--);
        fprintf(stderr, "Vars: ");
        for (vp = p->vhead; vp; vp = vp->next)
            fprintf(stderr, "%s ", vp->name);
        fprintf(stderr, "\nTypes: ");
        for (tp = p->thead; tp; tp = tp->next)
            fprintf(stderr, "%s ", tp->name);
        fprintf(stderr, "\n\n");
    }
    fprintf(stderr, "Var Table:\n");
    ctable_debug_print(cs->tvar);
    fprintf(stderr, "Type Table:\n");
    ctable_debug_print(cs->ttype);
    fprintf(stderr, "****** CScope ******\n\n");
}

CVar *cscope_lookup_var(CScope_t cs, const char *name) {
    return ctable_lookup(cs->tvar, name);
}

CType *cscope_lookup_type(CScope_t cs, const char *name) {
    return ctable_lookup(cs->ttype, name);
}

unsigned int bkdr_hash(const char *str) {
    unsigned int seed = 131;
    unsigned int hv = 0;
    while (*str)
        hv = hv * seed + (unsigned)(*str++);
    return hv;
}

const char *cvar_print(void *var) {
    static char buff[MAX_DEBUG_PRINT_BUFF];
    sprintf(buff, "%s", ((CVar *)var)->name);
    return buff;
}

const char *ctype_print(void *type) {
    static char buff[MAX_DEBUG_PRINT_BUFF];
    sprintf(buff, "%s", ((CType *)type)->name);
    return buff;
}

CVar_t cvar_create(const char *name, CType *type) {
    CVar *cv = NEW(CVar);
    cv->name = name;
    cv->type = type;
    return cv;
}

CType_t ctype_create(const char *name, int type) {
    CType *ct = NEW(CType);
    ct->name = name;
    ct->type = type;
    switch (type)
    {
        case CINT: ct->size = INT_SIZE; break;
        case CCHAR: ct->size = CHAR_SIZE; break;
        case CVOID: ct->size = 0; break;
    }
    return ct;
}


CTable_t semantics_fields(CNode *);
CType *semantics_type_spec(CNode *p) {
    CHECK_TYPE(p, TYPE_SPEC);
    CType *type;
    switch (p->rec.subtype)
    {
        case KW_VOID: type = ctype_create("", CVOID); break;
        case KW_CHAR: type = ctype_create("", CCHAR); break;
        case KW_INT: type = ctype_create("", CINT); break;
        case KW_STRUCT: case KW_UNION:
            {
                CNode *id = p->chd,
                      *fields = p->chd->next;
                type = ctype_create(id->type == NOP ? "" : id->rec.strval,
                                    p->rec.subtype == KW_STRUCT ? CSTRUCT : CUNION);
                if (fields->type == NOP)
                    type->rec.fields = NULL;
                else
                    type->rec.fields = semantics_fields(fields);
            }
            break;
        default: assert(0);
    }
    return type;
}

CVar *semantics_declr(CNode *, CType *);
CVar *semantics_p_decl(CNode *p) {
    CHECK_TYPE(p, PLAIN_DECL);
    return semantics_declr(p->chd->next,
                            semantics_type_spec(p->chd));
}

CVar *semantics_params(CNode *p) {
    CHECK_TYPE(p, PARAMS);
    p = p->chd;
    if (p->type == NOP) return NULL; /* void arguments */
    CVar *params = semantics_p_decl(p);
    for (; p; p = p->next)
    {
        CVar *t = semantics_p_decl(p);
        t->next = params;
        params = t;
    }
    return params;
}

CVar *semantics_p_declr(CNode *p, CType *type_spec) {
    /* deal with pointer prefix */
    CNode *t;
    CType *tt, *ptype;
    const char *name;
    if (p->type == ID) 
    {
        ptype = type_spec;              /* filled by type spec */
        name = p->rec.strval;
    }
    else
    {
        ptype = ctype_create("", CPTR); /* pointer */
        for (t = p, tt = ptype;; t = t->chd)
        {
            if (t->chd->type == ID)
            {
                tt->rec.ref = type_spec; /* filled by type spec */
                name = t->chd->rec.strval;
                break;
            }
            tt->rec.ref = ctype_create("", CPTR);
            tt = tt->rec.ref;
        }
    }
    return cvar_create(name, ptype);
}

CVar *semantics_declr(CNode *p, CType *type_spec) {
    CType *type;
    CHECK_TYPE(p, DECLR);
    const char *name;
    switch (p->rec.subtype)
    {
        case DECLR_FUNC: 
            {
                CVar *p_declr = semantics_p_declr(p->chd, type_spec);
                type = ctype_create("", CFUNC); /* function declr */
                type->rec.func.params = semantics_params(p->chd->next);
                /* incomplete type */
                type->rec.func.local = NULL;
                type->rec.func.ret = p_declr->type;
                name = p_declr->name;
                free(p_declr);
            }
            break;
        case DECLR_ARR:
            {
                CNode *t;
                CType *tt;
                type = ctype_create("", CARR); /* array declr */
                for (t = p, tt = type;; t = t->chd)
                {
                    /* TODO: range checking */
                    tt->rec.arr.len = t->chd->next->rec.intval;     /* array length */
                    if (t->chd->type == ID || t->chd->rec.subtype == '*')
                    {
                        CVar *p_declr = semantics_p_declr(t->chd, type_spec);
                        tt->rec.arr.elem = p_declr->type;
                        name = p_declr->name;
                        free(p_declr);
                        break;
                    }
                    tt->rec.arr.elem = ctype_create("", CARR);
                    tt = tt->rec.arr.elem;
                }
            }
            break;
        default: assert(0);
    }
    return cvar_create(name, type);
}

CTable_t semantics_fields(CNode *p) {
#ifdef CIBIC_DEBUG
    CTable_t ct = ctable_create(bkdr_hash, cvar_print);
#else
    CTable_t ct = ctable_create(bkdr_hash);
#endif
    for (p = p->chd; p; p = p->next)
    {
        CNode *declr = p->chd->next->chd;
        for (; declr; declr = declr->next)
        {
            CVar *var = semantics_declr(declr, 
                                        semantics_type_spec(p->chd));
            /* TODO: conflicts report */
            ctable_insert(ct, var->name, var, 0);
        }
    }
    return ct;
}

CVar *semantics_blk(CNode *p, CScope_t scope) {
}

CType *semantics_func(CNode *p, CScope_t scope) {
    CHECK_TYPE(p, FUNC_DEF);
    CNode *chd = p->chd->next;
    CType *func = ctype_create(chd->rec.strval, CFUNC);
    chd = chd->next;
    func->rec.func.ret = semantics_type_spec(p->chd);   /* check return type */
    func->rec.func.params = semantics_params(chd);       /* check params */
    func->rec.func.local = semantics_blk(chd->next, scope); /* check blk */
    return func;
}

void semantics_check_(CNode *p, CScope_t scope) {
    switch (p->type)
    {
        case FUNC_DEF: semantics_func(p, scope); break;
        default: ;
    }
}

void semantics_check(CNode *ast) {
    CScope_t scope = cscope_create();
    /* add top-level basic types */
    cscope_push_type(scope, ctype_create("int", CINT));
    cscope_push_type(scope, ctype_create("char", CCHAR));
    cscope_push_type(scope, ctype_create("void", CVOID));
    semantics_check_(ast, scope);
}