/* compile.c */ /* This file contains the functions to compile CI-C into an easily interpreted form */ #include "config.h" #include "object.h" #include "instr.h" #include "construct.h" #include "file.h" #include "token.h" #include "globals.h" /* The precedence array - keeps track of operator precedences */ struct { int comp_prec; /* precedence used in comparison */ int res_prec; /* result precedence passed on */ } prec_array[NUM_OPERS]={ 1,1, 3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2, 5,4, 6,6, 7,7, 8,8, 9,9, 10,10, 11,11,11,11, 12,12,12,12,12,12,12,12, 13,13,13,13, 14,14,14,14, 15,15,15,15,15,15, 17,16,17,16,17,16,17,16,17,16,17,16,17,16 }; /* scall_array contains the names of system calls */ char *scall_array[NUM_SCALLS]={ "add_verb","add_xverb","call_other", "alarm","remove_alarm","caller_object","clone_object","destruct", "contents","next_object","location","next_child","parent","next_proto", "move_object","this_object","this_player","set_interactive","interactive", "set_priv","priv","in_editor","connected","get_devconn","send_device", "reconnect_device","disconnect_device","random","time","mktime", "typeof","command","compile_object","edit","cat","ls","rm","cp","mv", "mkdir","rmdir","hide","unhide","chown","syslog","sscanf","sprintf", "midstr","strlen","leftstr","rightstr","subst","instr","otoa","itoa", "atoi","atoo","upcase","downcase","is_legal","otoi","itoo","chmod", "fread","fwrite","remove_verb","ferase","chr","asc","sysctl","prototype", "iterate","next_who" }; /* The functions themselves */ void set_c_err_msg(char *msg) { if (!c_err_msg) c_err_msg=msg; } void resize(fn_t *fn, unsigned long newsize) { struct var *tmp; unsigned long x,size; if (newsize) { tmp=(struct var *) MALLOC(newsize*sizeof(struct var)); for (x=0;x<(fn->num_code);x++) tmp[x]=fn->code[x]; FREE(fn->code); fn->code=tmp; } } #define make_new(fn) \ if ((fn->num_code)++) { \ if ((fn->num_code)>(fn->num_alloc)) \ resize(fn,(fn->num_alloc)+=FN_BLK); \ } else { \ fn->code=(struct var *) MALLOC(FN_BLK*sizeof(struct var)); \ fn->num_alloc=FN_BLK; \ } #define DO_FUNC1(A,B,C,D) \ void A(fn_t *curr_fn, B val) \ { \ unsigned long x; \ \ x=curr_fn->num_code; \ make_new(curr_fn) \ curr_fn->code[x].type=C; \ curr_fn->code[x].value.D=val; \ } #define DO_FUNC2(A,B) \ void A(fn_t *curr_fn) \ { \ make_new(curr_fn) \ curr_fn->code[curr_fn->num_code-1].type=B; \ } #define DO_FUNC3(A,B) \ void A(fn_t *curr_fn, unsigned int ref, unsigned int size) \ { \ unsigned long x; \ \ x=curr_fn->num_code; \ make_new(curr_fn) \ curr_fn->code[x].type=B; \ curr_fn->code[x].value.l_value.ref=ref; \ curr_fn->code[x].value.l_value.size=size; \ } DO_FUNC1(add_code_branch, unsigned long, BRANCH, num) DO_FUNC1(add_code_new_line, unsigned int, NEW_LINE, num) DO_FUNC1(add_code_instr, unsigned char, ASM_INSTR, instruction) DO_FUNC1(add_code_jump, unsigned long, JUMP, num) DO_FUNC1(add_code_integer, signed long, INTEGER, integer) DO_FUNC1(add_code_func_call, struct fns *, FUNC_CALL, func_call) DO_FUNC1(add_code_func_name, char *, FUNC_NAME, string) DO_FUNC1(add_code_num_args, unsigned int, NUM_ARGS, num) DO_FUNC2(add_code_return, RETURN) DO_FUNC2(add_code_gr, GLOBAL_REF) DO_FUNC2(add_code_lr, LOCAL_REF) DO_FUNC3(add_code_glv, GLOBAL_L_VALUE) DO_FUNC3(add_code_llv, LOCAL_L_VALUE) void add_code_string(fn_t *curr_fn, char *val) { unsigned long x; x=curr_fn->num_code; make_new(curr_fn); if (*val) { curr_fn->code[x].type=STRING; curr_fn->code[x].value.string=copy_string(val); } else { curr_fn->code[x].type=INTEGER; curr_fn->code[x].value.integer=0; } } void free_sym_t(sym_tab_t *sym) { struct var_tab *curr_var, *next_var; struct array_size *curr_array, *next_array; curr_var=sym->varlist; while (curr_var) { next_var=curr_var->next; curr_array=curr_var->array; while (curr_array) { next_array=curr_array->next; FREE(curr_array); curr_array=next_array; } FREE(curr_var->name); FREE(curr_var); curr_var=next_var; } } void free_file_stack(filptr *file_info) { struct file_stack *curr, *next; curr=file_info->previous; while (curr) { close_file(curr->file_ptr); next=curr->previous; FREE(curr); curr=next; } } void free_define(filptr *file_info) { struct define *curr, *next; struct parm *currparm, *nextparm; curr=file_info->defs; while (curr) { next=curr->next; currparm=curr->params; while (currparm) { nextparm=currparm->next; FREE(currparm->name); if (currparm->exp) FREE(currparm->exp); FREE(currparm); currparm=nextparm; } FREE(curr->name); FREE(curr->definition); FREE(curr); curr=next; } } unsigned int calc_size(struct array_size *array) { if (array==NULL) return 1; else return (array->size)*calc_size(array->next); } unsigned char find_syscall(char *name) { int x; for (x=0;x<NUM_SCALLS;x++) if (!strcmp(name,scall_array[x])) return x+NUM_OPERS; return 0; } struct fns *find_func(struct fns *position, char *name) { while (position) { if (!strcmp(position->funcname,name)) return position; position=position->next; } return NULL; } struct var_tab *find_var(char *name, sym_tab_t *sym) { struct var_tab *curr; curr=sym->varlist; while (curr) { if (!strcmp(curr->name,name)) return curr; curr=curr->next; } return NULL; } unsigned int add_var(filptr *file_info, sym_tab_t *sym) { token_t token; struct var_tab *curr_var; int done; struct array_size **rest; get_token(file_info,&token); if (token.type!=NAME_TOK) { set_c_err_msg("expected variable name declaration"); return file_info->phys_line; } curr_var=(struct var_tab *) MALLOC(sizeof(struct var_tab)); curr_var->name=copy_string(token.token_data.name); curr_var->base=sym->num; curr_var->array=NULL; curr_var->next=sym->varlist; sym->varlist=curr_var; rest=&(curr_var->array); done=0; while (!done) { get_token(file_info,&token); if (token.type!=LARRAY_TOK) done=1; else { get_token(file_info,&token); if (token.type!=INTEGER_TOK) { set_c_err_msg("array size must be integer constant"); return file_info->phys_line; } *rest=(struct array_size *) MALLOC(sizeof(struct array_size)); (*rest)->size=token.token_data.integer; (*rest)->next=NULL; rest=&((*rest)->next); get_token(file_info,&token); if (token.type!=RARRAY_TOK) { set_c_err_msg("expected ]"); return file_info->phys_line; } } } unget_token(file_info,&token); sym->num+=calc_size(curr_var->array); return 0; } unsigned int parse_base(filptr *file_info,fn_t *curr_fn, sym_tab_t *loc_sym, struct array_size **rest) { token_t token; if (*rest==NULL) { set_c_err_msg("array reference on non-array type"); return file_info->phys_line; } (*rest)=(*rest)->next; if (parse_exp(file_info,curr_fn,loc_sym,0,0)) return file_info->phys_line; add_code_integer(curr_fn,calc_size(*rest)); add_code_instr(curr_fn,MUL_OPER); add_code_instr(curr_fn,ADD_OPER); get_token(file_info,&token); if (token.type!=RARRAY_TOK) { set_c_err_msg("expected ]"); return file_info->phys_line; } get_token(file_info,&token); if (token.type==LARRAY_TOK) return parse_base(file_info,curr_fn,loc_sym,rest); unget_token(file_info,&token); return 0; } unsigned int parse_var(char *name,filptr *file_info,fn_t *curr_fn,sym_tab_t *loc_sym) { token_t token; int global; struct var_tab *the_var; struct array_size *rest; if (the_var=find_var(name,loc_sym)) global=0; else if (the_var=find_var(name,file_info->glob_sym)) global=1; else { set_c_err_msg("variable undefined"); return file_info->phys_line; } get_token(file_info,&token); if (token.type!=LARRAY_TOK) { unget_token(file_info,&token); if (global) add_code_glv(curr_fn,the_var->base,calc_size(the_var->array)); else add_code_llv(curr_fn,the_var->base,calc_size(the_var->array)); } else { rest=the_var->array; add_code_integer(curr_fn,the_var->base); if (parse_base(file_info,curr_fn,loc_sym,&rest)) return file_info->phys_line; add_code_integer(curr_fn,calc_size(rest)); if (global) add_code_gr(curr_fn); else add_code_lr(curr_fn); } return 0; } unsigned int parse_arglist(filptr *file_info, fn_t *curr_fn, sym_tab_t *loc_sym) { token_t token; int done,argcount; done=0; get_token(file_info,&token); if (token.type==RPAR_TOK) argcount=0; else argcount=1; unget_token(file_info,&token); while (!done) { if (parse_exp(file_info,curr_fn,loc_sym,1,0)) return file_info->phys_line; get_token(file_info,&token); if (token.type==RPAR_TOK) done=1; else if (token.type!=COMMA_TOK) { set_c_err_msg("expected )"); return file_info->phys_line; } else argcount++; } add_code_num_args(curr_fn,argcount); return 0; } unsigned int parse_exp(filptr *file_info, fn_t *curr_fn, sym_tab_t *loc_sym, int prec, int last_was_arg) { token_t token; char name[MAX_TOK_LEN+1]; unsigned char instr; struct fns *func,*sec_func; unsigned long marker1,marker2; get_token(file_info,&token); if (token.type==LPAR_TOK) { if (last_was_arg) { set_c_err_msg("expected arithmetic operation"); return file_info->phys_line; } if (parse_exp(file_info,curr_fn,loc_sym,0,0)) return file_info->phys_line; get_token(file_info,&token); if (token.type!=RPAR_TOK) { set_c_err_msg("expected )"); return file_info->phys_line; } last_was_arg=1; get_token(file_info,&token); } if (token.type==INTEGER_TOK) { if (last_was_arg) { set_c_err_msg("expected arithmetic operation"); return file_info->phys_line; } add_code_integer(curr_fn,token.token_data.integer); last_was_arg=1; get_token(file_info,&token); } if (token.type==STRING_TOK) { if (last_was_arg) { set_c_err_msg("expected arithmetic operation"); return file_info->phys_line; } add_code_string(curr_fn,token.token_data.name); last_was_arg=1; get_token(file_info,&token); } if (token.type==NAME_TOK) { strcpy(name,token.token_data.name); if (last_was_arg) { set_c_err_msg("expected arithmetic operation"); return file_info->phys_line; } get_token(file_info,&token); if (token.type==LPAR_TOK) { if (parse_arglist(file_info,curr_fn,loc_sym)) return file_info->phys_line; if (func=find_func(file_info->curr_code->func_list,name)) add_code_func_call(curr_fn,func); else if (instr=find_syscall(name)) add_code_instr(curr_fn,instr); else add_code_func_name(curr_fn,copy_string(name)); } else { unget_token(file_info,&token); if (parse_var(name,file_info,curr_fn,loc_sym)) return file_info->phys_line; } last_was_arg=1; get_token(file_info,&token); } if (token.type==SECOND_TOK) { set_c_err_msg("operation \'::\' unsupported"); return file_info->phys_line; } if (token.type<NUM_OPERS) { if ((token.type==MIN_OPER) && (!last_was_arg)) token.type=UMIN_OPER; if ((token.type==POSTADD_OPER) && (!last_was_arg)) token.type=PREADD_OPER; if ((token.type==POSTMIN_OPER) && (!last_was_arg)) token.type=PREMIN_OPER; instr=token.type; if (prec_array[instr].comp_prec<=prec) { unget_token(file_info,&token); return 0; } if ((instr!=PREADD_OPER) && (instr!=PREMIN_OPER) && (instr!=UMIN_OPER) && (instr!=BITNOT_OPER) && (instr!=NOT_OPER) && (!last_was_arg)) { set_c_err_msg("malformed expression"); return file_info->phys_line; } if (instr==COND_OPER) { add_code_branch(curr_fn,0); marker1=curr_fn->num_code-1; if (parse_exp(file_info,curr_fn,loc_sym,0,0)) return file_info->phys_line; add_code_jump(curr_fn,0); marker2=curr_fn->num_code-1; add_code_instr(curr_fn,instr); curr_fn->code[marker1].value.num=curr_fn->num_code-1; get_token(file_info,&token); if (token.type!=COLON_TOK) { set_c_err_msg("expected :"); return file_info->phys_line; } if (parse_exp(file_info,curr_fn,loc_sym,prec_array[instr].res_prec,0)) return file_info->phys_line; add_code_instr(curr_fn,instr); curr_fn->code[marker2].value.num=curr_fn->num_code-1; } else { if ((instr!=POSTADD_OPER) && (instr!=POSTMIN_OPER)) if (parse_exp(file_info,curr_fn,loc_sym,prec_array[instr].res_prec, 0)) return file_info->phys_line; add_code_instr(curr_fn,instr); } return parse_exp(file_info,curr_fn,loc_sym,prec,1); } unget_token(file_info,&token); return 0; } unsigned int parse_block(filptr *file_info, fn_t *curr_fn, sym_tab_t *loc_sym) { int done; token_t token; done=0; while (!done) { get_token(file_info,&token); if (token.type==RBRACK_TOK) done=1; else { unget_token(file_info,&token); if (parse_line(file_info,curr_fn,loc_sym)) return file_info->phys_line; } } return 0; } unsigned int parse_line(filptr *file_info, fn_t *curr_fn, sym_tab_t *loc_sym) { token_t token; unsigned long marker1,marker2; int done; get_token(file_info,&token); switch (token.type) { case VAR_DCL_TOK: done=0; while (!done) { if (add_var(file_info,loc_sym)) return file_info->phys_line; get_token(file_info,&token); if (token.type==SEMI_TOK) done=1; else if (token.type!=COMMA_TOK) { set_c_err_msg("expected ;"); return file_info->phys_line; } } break; case IF_TOK: get_token(file_info,&token); if (token.type!=LPAR_TOK) { set_c_err_msg("expected ("); return file_info->phys_line; } if (parse_exp(file_info,curr_fn,loc_sym,0,0)) return file_info->phys_line; get_token(file_info,&token); if (token.type!=RPAR_TOK) { set_c_err_msg("expected )"); return file_info->phys_line; } add_code_branch(curr_fn,0); marker1=curr_fn->num_code-1; get_token(file_info,&token); if (token.type==LBRACK_TOK) { if (parse_block(file_info,curr_fn,loc_sym)) return file_info->phys_line; } else { unget_token(file_info,&token); if (parse_line(file_info,curr_fn,loc_sym)) return file_info->phys_line; } get_token(file_info,&token); if (token.type==ELSE_TOK) { add_code_jump(curr_fn,0); marker2=curr_fn->num_code-1; get_token(file_info,&token); add_code_new_line(curr_fn,file_info->phys_line); curr_fn->code[marker1].value.num=curr_fn->num_code-1; if (token.type==LBRACK_TOK) { if (parse_block(file_info,curr_fn,loc_sym)) return file_info->phys_line; } else { unget_token(file_info,&token); if (parse_line(file_info,curr_fn,loc_sym)) return file_info->phys_line; } marker1=marker2; } else unget_token(file_info,&token); get_token(file_info,&token); unget_token(file_info,&token); add_code_new_line(curr_fn,file_info->phys_line); curr_fn->code[marker1].value.num=curr_fn->num_code-1; break; case WHILE_TOK: get_token(file_info,&token); if (token.type!=LPAR_TOK) { set_c_err_msg("exepcted ("); return file_info->phys_line; } add_code_new_line(curr_fn,file_info->phys_line); marker1=curr_fn->num_code-1; if (parse_exp(file_info,curr_fn,loc_sym,0,0)) return file_info->phys_line; get_token(file_info,&token); if (token.type!=RPAR_TOK) { set_c_err_msg("expected )"); return file_info->phys_line; } add_code_branch(curr_fn,0); marker2=curr_fn->num_code-1; get_token(file_info,&token); if (token.type==LBRACK_TOK) { if (parse_block(file_info,curr_fn,loc_sym)) return file_info->phys_line; } else { unget_token(file_info,&token); if (parse_line(file_info,curr_fn,loc_sym)) return file_info->phys_line; } add_code_jump(curr_fn,marker1); get_token(file_info,&token); unget_token(file_info,&token); add_code_new_line(curr_fn,file_info->phys_line); curr_fn->code[marker2].value.num=curr_fn->num_code-1; break; case FOR_TOK: get_token(file_info,&token); if (token.type!=LPAR_TOK) { set_c_err_msg("expected ("); return file_info->phys_line; } if (parse_exp(file_info,curr_fn,loc_sym,0,0)) return file_info->phys_line; get_token(file_info,&token); if (token.type!=SEMI_TOK) { set_c_err_msg("expected ;"); return file_info->phys_line; } add_code_new_line(curr_fn,file_info->phys_line); marker1=curr_fn->num_code-1; add_code_integer(curr_fn,1); if (parse_exp(file_info,curr_fn,loc_sym,0,0)) return file_info->phys_line; get_token(file_info,&token); if (token.type!=SEMI_TOK) { set_c_err_msg("expected ;"); return file_info->phys_line; } add_code_branch(curr_fn,0); marker2=curr_fn->num_code-1; add_code_jump(curr_fn,0); add_code_new_line(curr_fn,file_info->phys_line); if (parse_exp(file_info,curr_fn,loc_sym,0,0)) return file_info->phys_line; get_token(file_info,&token); if (token.type!=RPAR_TOK) { set_c_err_msg("expected ("); return file_info->phys_line; } add_code_jump(curr_fn,marker1); add_code_new_line(curr_fn,file_info->phys_line); curr_fn->code[marker2+1].value.num=curr_fn->num_code-1; get_token(file_info,&token); if (token.type==LBRACK_TOK) { if (parse_block(file_info,curr_fn,loc_sym)) return file_info->phys_line; } else { unget_token(file_info,&token); if (parse_line(file_info,curr_fn,loc_sym)) return file_info->phys_line; } add_code_jump(curr_fn,marker2+2); add_code_new_line(curr_fn,file_info->phys_line); curr_fn->code[marker2].value.num=curr_fn->num_code-1; break; case DO_TOK: add_code_new_line(curr_fn,file_info->phys_line); marker1=curr_fn->num_code-1; get_token(file_info,&token); if (token.type==LBRACK_TOK) { if (parse_block(file_info,curr_fn,loc_sym)) return file_info->phys_line; } else { unget_token(file_info,&token); if (parse_line(file_info,curr_fn,loc_sym)) return file_info->phys_line; } get_token(file_info,&token); if (token.type!=WHILE_TOK) { set_c_err_msg("expected \'while\'"); return file_info->phys_line; } get_token(file_info,&token); if (token.type!=LPAR_TOK) { set_c_err_msg("expected ("); return file_info->phys_line; } if (parse_exp(file_info,curr_fn,loc_sym,0,0)) return file_info->phys_line; get_token(file_info,&token); if (token.type!=RPAR_TOK) { set_c_err_msg("expected )"); return file_info->phys_line; } get_token(file_info,&token); if (token.type!=SEMI_TOK) { set_c_err_msg("expected ;"); return file_info->phys_line; } add_code_branch(curr_fn,0); marker2=curr_fn->num_code-1; add_code_jump(curr_fn,marker1); add_code_new_line(curr_fn,file_info->phys_line); curr_fn->code[marker2].value.num=curr_fn->num_code-1; break; case RETURN_TOK: get_token(file_info,&token); if (token.type==SEMI_TOK) add_code_integer(curr_fn,0); else { unget_token(file_info,&token); if (parse_exp(file_info,curr_fn,loc_sym,0,0)) return file_info->phys_line; get_token(file_info,&token); if (token.type!=SEMI_TOK) { set_c_err_msg("expected ;"); return file_info->phys_line; } } add_code_return(curr_fn); break; default: add_code_new_line(curr_fn,file_info->phys_line); unget_token(file_info,&token); if (parse_exp(file_info,curr_fn,loc_sym,0,0)) return file_info->phys_line; get_token(file_info,&token); if (token.type!=SEMI_TOK) { set_c_err_msg("expected ;"); return file_info->phys_line; } } return 0; } unsigned int top_level_parse(filptr *file_info) { token_t token; sym_tab_t loc_sym; int done, is_static; fn_t curr_func; struct fns *tmp_fns; while (1) { is_static=0; done=0; get_token(file_info,&token); if (token.type==STATIC_TOK) { is_static=1; get_token(file_info,&token); } switch (token.type) { case EOF_TOK: return 0; break; case VAR_DCL_TOK: while (!done) { if (add_var(file_info,file_info->glob_sym)) return file_info->phys_line; get_token(file_info,&token); if (token.type==SEMI_TOK) done=1; else if (token.type!=COMMA_TOK) { set_c_err_msg("expected ;"); return file_info->phys_line; } } break; case NAME_TOK: curr_func.code=NULL; curr_func.num_code=0; curr_func.num_alloc=0; loc_sym.num=0; loc_sym.varlist=NULL; tmp_fns=(struct fns *) MALLOC(sizeof(struct fns)); tmp_fns->is_static=is_static; tmp_fns->num_args=0; tmp_fns->num_instr=0; tmp_fns->num_locals=0; tmp_fns->code=NULL; tmp_fns->funcname=copy_string(token.token_data.name); tmp_fns->next=file_info->curr_code->func_list; file_info->curr_code->func_list=tmp_fns; get_token(file_info,&token); if (token.type!=LPAR_TOK) { set_c_err_msg("expected ("); return file_info->phys_line; } while (!done) { get_token(file_info,&token); if (token.type==RPAR_TOK) done=1; else { if (token.type!=VAR_DCL_TOK) unget_token(file_info,&token); if (add_var(file_info,&loc_sym)) { free_sym_t(&loc_sym); return file_info->phys_line; } get_token(file_info,&token); if (token.type==RPAR_TOK) unget_token(file_info,&token); else if (token.type!=COMMA_TOK) { set_c_err_msg("expected )"); free_sym_t(&loc_sym); return file_info->phys_line; } } } tmp_fns->num_args=loc_sym.num; get_token(file_info,&token); if (token.type!=LBRACK_TOK) { set_c_err_msg("expected {"); free_sym_t(&loc_sym); return file_info->phys_line; } add_code_new_line(&curr_func,file_info->phys_line); if (parse_block(file_info,&curr_func,&loc_sym)) { tmp_fns->code=curr_func.code; tmp_fns->num_instr=curr_func.num_code; free_sym_t(&loc_sym); return file_info->phys_line; } add_code_integer(&curr_func,0); add_code_return(&curr_func); resize(&curr_func,curr_func.num_code); tmp_fns->code=curr_func.code; tmp_fns->num_locals=loc_sym.num; tmp_fns->num_instr=curr_func.num_code; free_sym_t(&loc_sym); break; default: return file_info->phys_line; break; } } }