📄 symtab.c
字号:
#include "SymTab.h"
#include "GenCode.h"
#include "Error.h"
#include "Debug.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <memory.h>
#include <assert.h>
#include <math.h>
#define COMPOUND_STACK_SIZE 64
const char _COMPOUND_SYMTAB_NAME[] = "%d_703027";
const char _FUNCTION_SYMTAB_NAME[] = "51911080";
const char _UNUSED_SYM_NAME[] = "5yong_%d";
const char _GOTO_LABEL_SYMTAB_NAME[] = "041249";
// for compound stack
typedef struct _comp_element_
{
// symtab pointer
symbol *p_symtab;
// this layer's start offset
// in bytes
int offset;
} comp_element;
static comp_element sg_compound_stack[COMPOUND_STACK_SIZE];
static int sg_compound_stack_sp = -1;
// used for alloc space in stack for local value
static int sg_local_offset = 0;
static int sg_local_offset_top = 0;
#define CHECK_COMPOUND_STACK_OVERFLOW assert(sg_compound_stack_sp < COMPOUND_STACK_SIZE);
#define CHECK_COMPOUND_STACK_BOTTOM \
if ( sg_compound_stack_sp <= -1 ) \
{ \
yyerror("compound statement not match");\
user_exit(1); \
}
#define ALIGN_OFFSET(x) if ((x) % 2) \
x++;
#define JUST_OFFSET_TOP if ( sg_local_offset_top \
< sg_local_offset ) \
sg_local_offset_top = \
sg_local_offset;
// record the globe vlaue
// only globe value no function, no ...
symbol *sg_function_symtab = NULL;
// goto label symtab
symbol *sg_goto_label_symtab = NULL;
static char *get_compound_symtab_name()
{
static char buf[NAME_LEN];
sprintf(buf, _COMPOUND_SYMTAB_NAME, sg_compound_stack_sp);
return buf;
}
symbol *new_symbol()
{
symbol *tmp;
tmp = (symbol *)malloc( sizeof(symbol) );
if ( !tmp )
{
yyerror("Out of memory in new_symbol()");
user_exit(1);
}
// init the symbol, set to zero
// can think init is zero include point & other
memset( tmp, 0, sizeof( symbol ));
return tmp;
}
void del_symbol(symbol *p)
{
assert( p );
free( p );
}
// delete a symtab all
void remove_symtab(symbol *head)
{
// use ->lchild & ->rchild to remove child ,
// becuse ->next only used for search
if ( !head ) //eg . remove_symtab(NULL)
return;
if ( head->lchild )
remove_symtab(head->lchild);
if ( head->rchild )
remove_symtab(head->rchild);
del_symbol(head);
}
// delete a symtab except function args
void remove_symtab_except_args(symbol *head)
{
// use ->lchild & ->rchild to remove child ,
// becuse ->next only used for search
if ( !head )
return;
if ( head->lchild )
remove_symtab_except_args(head->lchild);
if ( head->rchild )
remove_symtab_except_args(head->rchild);
if ( !IS_ARGUMENT(head) )
del_symbol(head);
else
// is args
head->rchild = head->lchild = NULL;
}
// delete a function symtab include function args
void remove_function_symtab_include_args(symbol *func)
{
// use ->lchild & ->rchild to remove child ,
// and remove ->args
symbol *tmp;
if ( !func )
return;
if ( !IS_FUNCTION(func) )
{
yyerror("not function in remove_function_symtab_include_args()");
user_exit(1);
}
if ( IS_FUNC_DECL(func) && func->IS_EXTERN )
gen_extern_func(func);
if ( func->lchild )
remove_function_symtab_include_args(func->lchild);
if ( func->rchild )
remove_function_symtab_include_args(func->rchild);
// delete the args
tmp = func->args;
while ( tmp )
{
symbol *p;
if ( !IS_ARGUMENT(tmp) )
{
yyerror("not args in remove_function_symtab_include_args()");
user_exit(1);
}
p = tmp;
tmp = tmp->next;
del_symbol(p);
}
// delete function symbol
del_symbol(func);
}
// remove the linked symbol use ->next
// eg. not use declaration list
void remove_symbol_list(symbol *p)
{
while ( p )
{
symbol *tmp = p;
p = p->next;
del_symbol(tmp);
}
}
symbol *create_symtab(const char *name)
{
symbol *tmp;
tmp = new_symbol();
tmp->is_symtab = 1;
strncpy( tmp->name, name, NAME_LEN );
return tmp;
}
// return NULL means not found
symbol *search_symbol_in_symtab(symbol *tab, char *name)
{
if ( !IS_SYMTAB(tab) )
{
yyerror("not symtab in search_symbol_in_symtab()");
user_exit(1);
}
while( tab )
{
int i;
i = strcmp(name, tab->name);
if ( i < 0 )
// name < tab->name
tab = tab->lchild;
else if ( i > 0 )
// name > tab->name
tab = tab->rchild;
else
// found
break;
}
// because tab is NULL
// so only return tab means return NULL;
return tab;
}
// return NULL means not found
symbol *search_symbol_to_top(char *name)
{
symbol *tmp;
int level = sg_compound_stack_sp;
for ( ; level >= 0; level-- )
{
tmp = sg_compound_stack[level].p_symtab;
if (tmp = search_symbol_in_symtab(tmp, name))
// found
goto lab_found;
}
// search in function symtab
tmp = search_symbol_in_symtab(sg_function_symtab, name);
lab_found:
return tmp;
}
int add_symbol_to_symtab(symbol *tab, symbol *p)
{
if (!tab || !p)
return 1;
if ( !IS_SYMTAB(tab) )
{
yyerror("not a symtab in add_symbol_to_symtab()");
user_exit(1);
}
while(1)
{
int i;
i = strcmp(p->name, tab->name);
if ( i < 0 )
// p->name < tab->name
{
if ( tab->lchild )
tab = tab->lchild;
else
{
tab->lchild = p;
break;
}
}
else if ( i > 0 )
// p->name > tab->name
{
if ( tab->rchild )
tab = tab->rchild;
else
{
tab->rchild = p;
break;
}
}
else
// equal
{
parse_error("Duplicate identifier.", p->name);
user_exit(1);
}
}
return 0;
}
int add_symbol_to_current_symtab(symbol *p)
{
// if p is function symbol, then don't add to current symtab
// because in C language every function is globe function
// it must be add to function symtab
if ( IS_FUNCTION(p) )
// just return successful flag
return 0;
// we must record the added symbol size ,
// and add to sg_local_offset, so access the word ptr [bp - offset]
// except some symbol like typedef or function definition
// so, call a method
if ( IS_LOCAL_VAR(p) )
{
if ( sg_compound_stack_sp )
// means symbol p is a var and current layer is not globe
{
sg_local_offset += get_symbol_size(p);
// the offset was bp -... so is '-'
p->offset = - sg_local_offset;
set_local_or_args_rname(p);
ALIGN_OFFSET(sg_local_offset)
JUST_OFFSET_TOP
}
else
// globe val, assign ->rname only
{
sprintf(p->rname, _GLOBE_VAL_NAME, p->name);
}
}
return add_symbol_to_symtab(sg_compound_stack[sg_compound_stack_sp].p_symtab, p);
}
int add_symbol_list_to_current_symtab(symbol *p)
{
while ( p )
{
if ( add_symbol_to_current_symtab(p) )
return 1;
p = p->next;
}
return 0;
}
// link two symbol list to one list
// link p2 at ->next of p1's last symbol
symbol *link_symbol_list(symbol *p1, symbol *p2)
{
symbol *tmp = p1;
if (!p1 || !p2)
return p1;
while ( tmp->next )
tmp = tmp->next;
tmp->next = p2;
return p1;
}
// change p1
void union_specifier_symbol(symbol *p1, symbol *p2)
{
if ( !p1 || !p2 )
return;
if ( p1->NOUN == SPEC_UNKNOW )
p1->NOUN = p2->NOUN;
if ( p1->SCLASS == SPEC_UNKNOW )
p1->SCLASS = p2->SCLASS;
if ( !p1->IS_LONG )
p1->IS_LONG = p2->IS_LONG;
if ( !p1->IS_UNSIGNED )
p1->IS_UNSIGNED = p2->IS_UNSIGNED;
if ( !p1->IS_STATIC )
p1->IS_STATIC = p2->IS_STATIC;
if ( !p1->IS_EXTERN )
p1->IS_EXTERN = p2->IS_EXTERN;
}
// check var declarator
void check_var_declarator(symbol *decl)
{
assert(decl);
if (decl->NOUN == SPEC_VOID )
{
yyerror("illegal use of type 'void'");
user_exit(1);
}
}
// union the specifier to declarator
// at same time check declarator , not be void
void unoin_specifier_to_declarator(symbol *spec, symbol *decl)
{
if ( !spec || !decl )
return;
decl->NOUN = spec->NOUN;
decl->SCLASS = spec->SCLASS;
decl->IS_LONG = spec->IS_LONG;
decl->IS_UNSIGNED = spec->IS_UNSIGNED;
decl->IS_STATIC = spec->IS_STATIC;
decl->IS_EXTERN = spec->IS_EXTERN;
}
// union the specifier to declarator list
void unoin_specifier_to_declarator_list(symbol *spec, symbol *decl_list)
{
if ( !spec )
return;
while ( decl_list )
{
unoin_specifier_to_declarator(spec, decl_list);
decl_list = decl_list->next;
}
}
// new symbol from a typedef symbol
symbol *new_symbol_from_typedef(symbol *def_sym)
{
symbol *tmp;
if ( !def_sym || !IS_TYPEDEF(def_sym) )
return NULL;
tmp = new_symbol();
tmp->NOUN = def_sym->NOUN;
tmp->SCLASS = SPEC_UNKNOW;
tmp->IS_LONG = def_sym->IS_LONG;
tmp->IS_UNSIGNED = def_sym->IS_UNSIGNED;
tmp->IS_STATIC = def_sym->IS_STATIC;
tmp->IS_EXTERN = def_sym->IS_EXTERN;
// for array typedef
tmp->is_array = def_sym->is_array;
tmp->num_ele = def_sym->num_ele;
return tmp;
}
symbol *find_symtab_typedef(char *name)
{
symbol *tmp;
tmp = search_symbol_to_top(name);
if ( tmp && IS_TYPEDEF(tmp) )
return tmp;
return NULL;
}
// create compound symtab , and push it
symbol *new_compound_symtab()
{
sg_compound_stack_sp++;
CHECK_COMPOUND_STACK_OVERFLOW
sg_compound_stack[sg_compound_stack_sp].p_symtab =
create_symtab(get_compound_symtab_name());
sg_compound_stack[sg_compound_stack_sp].offset =
sg_local_offset;
return sg_compound_stack[sg_compound_stack_sp].p_symtab;
}
// pop a compound symtab, and destory it
void del_compound_symtab()
{
sg_local_offset = sg_compound_stack[sg_compound_stack_sp].offset;
// conside the function declaration use this method
// so only delete the symbol not args,
// to common compound statement, it not different between
// this method and remove_symtab, but it important to
// function compound statement
CHECK_COMPOUND_STACK_BOTTOM
remove_symtab_except_args(sg_compound_stack[sg_compound_stack_sp--].p_symtab);
}
// check args type in function call in term of number of args
int check_args_type_in_function_call(symbol *p1,symbol *p2)
{
// for check for function call
assert(p1);
assert(p2);
while ( p1 && p2 )
{
/* if ( p1->NOUN != p2->NOUN )
return 1;
if ( p1->SCLASS != p2->SCLASS )
return 1;
if ( p1->IS_LONG != p2->IS_LONG )
return 1;
if ( p1->IS_UNSIGNED != p2->IS_UNSIGNED )
return 1;
*/ // for call type can be cast in sometimes
/* if ( IS_ARRAY( p1 ) )
{
if ( !IS_ARRAY(p2) || IS_ARRAY_HAS_INDEX(p2) )
return 1;
}
// p1 is not a array
else if ( IS_ARRAY(p2) && !IS_ARRAY_HAS_INDEX(p2) )
return 1;
*/
// can tell the array is or not has index , because the index flags has been
// clear , so.... check it by programer
p1 = p1->next;
p2 = p2->next;
}
if ( p1 != p2 )
return 1;
return 0;
}
// check args type
int check_args_type(symbol *p1,symbol *p2)
{
while ( p1 && p2 )
{
assert( IS_ARGUMENT(p1) );
assert( IS_ARGUMENT(p2) );
if ( p1->NOUN != p2->NOUN )
return 1;
if ( p1->SCLASS != p2->SCLASS )
return 1;
if ( p1->IS_LONG != p2->IS_LONG )
return 1;
if ( p1->IS_UNSIGNED != p2->IS_UNSIGNED )
return 1;
if ( p1->is_array != p2->is_array )
return 1;
// for function , array argument only a pointer, so dont check the num_ele
// if ( IS_ARRAY(p1) && (p1->num_ele != p2->num_ele) )
// return 1;
p1 = p1->next;
p2 = p2->next;
}
if ( p1 != p2 )
return 1;
return 0;
}
// check the function parameter and return type
int check_func_args_type(symbol *func,symbol *decl)
{
// check function itself attribute
if ( !IS_FUNCTION(func) || !IS_FUNCTION(decl) )
return 1;
if ( func->NOUN != decl->NOUN )
return 1;
if ( func->SCLASS != decl->SCLASS )
return 1;
if ( func->IS_LONG != decl->IS_LONG )
return 1;
if ( func->IS_UNSIGNED != decl->IS_UNSIGNED )
return 1;
return check_args_type(func->args, decl->args);
}
// add function definition to function tab
// if declaration if exist, check parameter type,
// and overwrite parameter's name
// actual delete the declaration list
// and add itself to function symtab
// the function could be changed
// so return new symbol pointer
symbol *add_function_def_to_functab(symbol *func)
{
symbol *decl;
if ( !IS_FUNCTION(func) )
{
yyerror("not function in add_function_def_to_functab()");
user_exit(1);
}
if ( decl = search_symbol_in_symtab(sg_function_symtab, func->name) )
{
// found the same name function
// see if the pre declaration
if ( !IS_FUNC_DECL(decl) )
{
// another function has define as the same name
// so, error........
parse_error(func->name," already has a body");
user_exit(1);
}
// only declaration
// chech parameter type
if ( check_func_args_type(func, decl) )
{
// type mismatch
yyerror("function declaration has the different parameter type or return value type with definition");
user_exit(1);
}
// ok, change decl to definition
// delete decl 's parameter list
remove_symbol_list(decl->args);
// link func->args to decl->args
// later see it enough???
decl->args = func->args;
decl->IS_STATIC = func->IS_STATIC;
decl->IS_EXTERN = func->IS_EXTERN;
// delete fun symbol
del_symbol(func);
// clear decl flags, it ture definition, heihei....
decl->is_declaration = 0;
return decl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -