📄 symbol.c
字号:
/* YABASIC --- a simple Basic Interpreter written by Marc-Oliver Ihm 1995-2004 homepage: www.yabasic.de symbol.c --- code for control structures, symbol and stack management This file is part of yabasic and may be copied only under the terms of either the Artistic License or the GNU General Public License (GPL), both of which can be found at www.yabasic.de*//* ------------- includes ---------------- */#ifndef YABASIC_INCLUDED#include "yabasic.h" /* all prototypes and structures */#endif/* ------------- external references ---------------- */extern int yylineno; /* current line number */extern int yyparse(); /* call bison parser *//* ------------- local defines ---------------- */struct switch_id { int id; int depth; struct switch_id *next; struct switch_id *prev;};/* ------------- local functions ---------------- */static struct symbol *create_symbol(int,char *); /* create a new symbol */static void link_label(struct command *); /* link label into list of labels */static int count_args(int); /* count number of arguments on stack */static void stackdesc(int,char *); /* give back string describing stackentry */static void freesym(struct symbol *); /* free contents of symbol */static int ind_to_off(int *,int *); /* convert array of indices to single offset */static void off_to_ind(int,int *,int *); /* convert a single offset to an array of indices *//* ------------- global variables ---------------- */static struct symstack *symroot=NULL; /* first element in symbol list */static struct symstack *symhead=NULL; /* last element ind symbol list */struct stackentry *stackroot; /* lowest element in stack */struct stackentry *stackhead; /* topmost element in stack */static struct command *labelroot=NULL; /* first label among commands */static struct command *labelhead=NULL; /* last label seen so far */extern char *current_function; /* name of currently defined function */struct command *lastref; /* last command in UDS referencing a symbol */struct command *firstref; /* first command in UDS referencing a symbol */int labelcount=0; /* count self-generated labels */int in_switch=0; /* true, if in switch (at compile-time) */struct switch_id *switch_id_stackhead=NULL; /* topmost (and valid) element of switch_id stack */struct switch_id *switch_id_stackroot=NULL; /* bottommost element of switch_id stack *//* ------------- subroutines ---------------- */void pushsymlist(void) /* push a new list of symbols on symbol stack */{ struct symstack *new; new=my_malloc(sizeof(struct symstack)); if (symhead) symhead->next_in_stack=new; else symroot=new; /* first time called */ new->prev_in_stack=symhead; new->next_in_stack=NULL; new->next_in_list=NULL; symhead=new;} void popsymlist(void) /* pop list of symbols and free symbol contents */{ struct symstack *prevstack; struct symbol *currsym,*nextsym; int count=0; currsym=symhead->next_in_list; while(currsym) { /* loop through symbol list */ freesym(currsym); count++; nextsym=currsym->next_in_list; my_free(currsym); currsym=nextsym; } if (infolevel>=DEBUG) { sprintf(string,"removed symbol list with %d symbols",count); error(DEBUG,string); } prevstack=symhead->prev_in_stack; my_free(symhead); prevstack->next_in_stack=NULL; symhead=prevstack;}static void freesym(struct symbol *s) /* free contents of symbol */{ int i; int total; struct array *ar; if (s->link) { /* it's a link, don't remove memory */ sprintf(string,"removing linked symbol '%s'",s->name); error(DEBUG,string); my_free(s->name); return; } if (s->type==sySTRING) { if (infolevel>=DEBUG) { sprintf(string,"removing string symbol '%s'",s->name); error(DEBUG,string); } my_free(s->pointer); } else if (s->type==syARRAY) { if (infolevel>=DEBUG) { sprintf(string,"removing array symbol '%s()'",s->name); error(DEBUG,string); } ar=s->pointer; if (ar->dimension>0) { /* count total amount of memory */ total=1; for(i=0;i<ar->dimension;i++) total*=(ar->bounds)[i]; if (ar->type=='s') { /* string array */ for(i=0;i<total;i++) my_free(*((char **)ar->pointer+i)); } my_free(ar->pointer); } my_free(ar); } else if (s->type==syNUMBER) { if (infolevel>=DEBUG) { sprintf(string,"removing numeric symbol '%s'",s->name); error(DEBUG,string); } } my_free(s->name); return;}void clearrefs(struct command *cmd) /* clear references for commands within function */{ struct command *curr; int n=0; curr=cmd->nextref; while(curr) { n++; curr->symbol=NULL; curr=curr->nextref; } sprintf(string,"removed references from %d symbols",n); error(DEBUG,string);}struct symbol *get_sym(char *name,int type,int add) /* get the value of a symbol, or create it with given type */{ struct symstack *currstack; struct symbol **currsym; struct symbol *prelink; struct symbol *new; int stackcount=0; int symbolcount=0; int linked=FALSE; if (!name) return NULL; /* go through all lists */ currstack=symhead; /* start with symhead */ if (add==amSEARCH_PRE && symhead->prev_in_stack) currstack=symhead->prev_in_stack; while(TRUE) { stackcount++; currsym=&(currstack->next_in_list); while(*currsym) { prelink=*currsym; symbolcount++; if ((*currsym)->type==type && !strcmp(name,(*currsym)->name)) { /* do the types and names match ? */ if ((*currsym)->link) { currsym=&((*currsym)->link); linked=TRUE; } if (infolevel>=DEBUG) { if (linked) sprintf(string,"found symbol '%s%s', linked to %s after searching %d symbol(s) in %d stack(s)", name,(type==syARRAY)?"()":"",(*currsym)->name,symbolcount,stackcount); else sprintf(string,"found symbol '%s%s' after searching %d symbol(s) in %d stack(s)", name,(type==syARRAY)?"()":"",symbolcount,stackcount); error(DEBUG,string); } return *currsym; /* give back address */ } currsym=&((*currsym)->next_in_list); /* try next entry */ } /* not found in first list */ if (add==amSEARCH_VERY_LOCAL) return NULL; if (add==amADD_LOCAL) { new=create_symbol(type,name); (*currsym)=new; if (infolevel>=DEBUG) { sprintf(string,"created local symbol %s%s",name,(type==syARRAY)?"()":""); error(DEBUG,string); } return new; } if (currstack!=symroot) currstack=symroot; else break; } if (add==amADD_GLOBAL) { new=create_symbol(type,name); (*currsym)=new; if (infolevel>=DEBUG) { sprintf(string,"created global symbol %s%s",name,(type==syARRAY)?"()":""); error(DEBUG,string); } return new; } return NULL;}void link_symbols(struct symbol *from,struct symbol *to) { /* link one symbol to the other */ from->link=to; if (infolevel>=DEBUG) { sprintf(string,"linking symbol '%s' to '%s'",from->name,to->name); error(DEBUG,string); }}void create_retval(int is,int should) /* create command 'cRETVAL' */{ struct command *cmd; cmd=add_command(cRETVAL,NULL); cmd->args=is; cmd->tag=should;}void retval(struct command *cmd) /* check return value of function */{ int is,should; struct stackentry *s; is=cmd->args; should=cmd->tag; if (is==should) { /* okay, function returns expected type */ } else if (is==ftNONE) { /* no element on stack, create one */ s=push(); if (should==ftNUMBER) { s->type=stNUMBER; s->value=0.0; } else { s->type=stSTRING; s->pointer=my_strdup(""); } } else { sprintf(string,"subroutine returns %s but should return %s", (is==ftSTRING)?"a string":"a number",(should==ftSTRING)?"a string":"a number"); error(ERROR,string); } if (infolevel>=DEBUG) { s=stackhead->prev; if (s->type==stNUMBER) sprintf(string,"subroutine returns number %g",s->value); else if (s->type==stSTRING) sprintf(string,"subroutine returns string '%s'",(char *)s->pointer); else sprintf(string,"subroutine returns something strange (%d)",s->type); error(DEBUG,string); } swap();}void create_endfunction(void) /* create command cEND_FUNCTION */{ struct command *cmd; cmd=add_command(cEND_FUNCTION,NULL); link_label(cmd);}void dump_sym(void) /* dump the stack of lists of symbols */{ struct symstack *currstack; struct symbol **currsym; /* go through all lists */ error(DUMP,"head of symbol stack"); currstack=symhead; while(currstack) { /* search 'til last element of stack */ currsym=&(currstack->next_in_list); string[0]='\0'; while(*currsym) { switch((*currsym)->type) { case sySTRING: strcat(string," STRING:"); break; case syNUMBER: strcat(string," NUMBER:"); break; case syFREE: strcat(string," FREE:"); break; case syARRAY: strcat(string," ARRAY:"); break; default:sprintf(string," UNKNOWN:"); break; } strcat(string,(*currsym)->name); currsym=&((*currsym)->next_in_list); /* try next entry */ } error(DUMP,string); currstack=currstack->prev_in_stack; } error(DUMP,"root of symbol stack"); return;}void dump_sub(int short_dump) /* dump the stack of subroutine calls */{ struct stackentry *st=stackhead; struct command *cmd; int first=TRUE; do { if (st->type==stRETADDCALL) { cmd=st->pointer; if (cmd->type==cCALL || cmd->type==cQCALL) { char *dot; dot=strchr(cmd->pointer,'.'); if (first && !short_dump) error(DUMP,"Executing in:"); sprintf(string,"sub %s() called in %s,%d",dot ? (dot+1):cmd->pointer,cmd->lib->l,cmd->line); error(DUMP,string); first=FALSE; } } st=st->prev; } while(st && st!=stackroot); if (first && !short_dump) { if (!short_dump) error(DUMP,"Executing in:"); } if (!short_dump) error(DUMP,"main program"); return;}static struct symbol *create_symbol(int type,char *name) /* create a new symbol */{ struct symbol *new; new=my_malloc(sizeof(struct symbol)); new->type=type; new->next_in_list=NULL; new->name=my_strdup(name); new->pointer=NULL; new->args=NULL; new->value=0.0; new->link=NULL; return new;}void function_or_array(struct command *cmd) /* decide whether to perform function or array */{ struct command *fu; fu=search_label(cmd->name,smSUB|smLINK); if (fu) { cmd->type=cCALL; cmd->pointer=cmd->name; cmd->name=NULL; error(DEBUG,"converting FUNCTION_OR_ARRAY to FUNCTION"); } else { if (cmd->type==cFUNCTION_OR_ARRAY) cmd->tag=CALLARRAY; else cmd->tag=CALLSTRINGARRAY; cmd->type=cDOARRAY; cmd->args=-1; error(DEBUG,"converting FUNCTION_OR_ARRAY to ARRAY"); }}void swap() /* swap topmost elements on stack */{ struct stackentry *a,*b; if ((a=stackhead->prev)==NULL || (b=a->prev)==NULL) { error(ERROR,"Nothing to swap on stack !"); return; } a->prev=b->prev;b->next=a->next; /* just swap the pointers */ a->next=b;b->prev=a; stackhead->prev=b; (a->prev)->next=a;}struct stackentry *push() /* push element on stack and enlarge stack it */{ struct stackentry *new; if (!stackhead->next) { /* no next element */ /* create new element */ new=(struct stackentry *)my_malloc(sizeof(struct stackentry)); /* and initialize it */ new->next=NULL; new->value=0.0; new->type=stFREE; new->prev=stackhead; new->pointer=NULL; stackhead->next=new; } else if (stackhead->pointer!=NULL && (stackhead->type==stSTRING || stackhead->type==stSTRINGARRAYREF || stackhead->type==stNUMBERARRAYREF || stackhead->type==stLABEL)) { /* any content is set free */ my_free(stackhead->pointer); stackhead->pointer=NULL; } stackhead=stackhead->next; /* advance head */ return stackhead->prev;}struct stackentry *pop(int etype)/* pops element to memory and looks for pop-error */{ static char expected[50]; static char found[50]; int ftype; struct stackentry *s; /* test if there is something on the stack */ if (stackhead==stackroot) { error(FATAL,"Popped too much."); return stackhead; } stackhead=stackhead->prev; /* move down in stack */ ftype=stackhead->type; if (etype==ftype || etype==stANY || (etype==stSTRING_OR_NUMBER && (ftype==stNUMBER || ftype==stSTRING)) || (etype==stSTRING_OR_NUMBER_ARRAYREF && (ftype==stSTRINGARRAYREF || ftype==stNUMBERARRAYREF))) return stackhead; /* this is your value; use it quickly ! */ /* expected and found don't match */ stackdesc(etype,expected); stackdesc(ftype,found); sprintf(string,"expected %s but found %s",expected,found); if (etype==stNUMBER || etype==stSTRING || etype==stSTRING_OR_NUMBER) { s=push(); if (etype==stNUMBER) { s->type=stNUMBER; s->value=0.0; } else { s->type=stSTRING; s->pointer=my_strdup(""); } error(ERROR,string); return s; } else { error(FATAL,string); } return stackhead;}static void stackdesc(int type,char *desc) /* give back string describing stackentry */{ switch(type) { case stGOTO: strcpy(desc,"a goto");break; case stSTRING: strcpy(desc,"a string");break; case stSTRINGARRAYREF: strcpy(desc,"a reference to a string array");break; case stNUMBER: strcpy(desc,"a number");break; case stNUMBERARRAYREF: strcpy(desc,"a reference to a numeric array");break; case stLABEL: strcpy(desc,"a label");break; case stRETADD: strcpy(desc,"a return address for gosub");break; case stRETADDCALL: strcpy(desc,"a return address for a subroutine");break; case stFREE: strcpy(desc,"nothing");break; case stROOT: strcpy(desc,"the root of the stack");break; case stANY: strcpy(desc,"anything");break; case stSTRING_OR_NUMBER: strcpy(desc,"a string or a number");break; case stSTRING_OR_NUMBER_ARRAYREF: strcpy(desc,"reference to a string or an array");break; case stSWITCH_STRING: strcpy(desc,"number for switch");break; case stSWITCH_NUMBER: strcpy(desc,"string for switch");break; default: sprintf(desc,"type %d",type);break; }} void pushname(char *name) /* bison: push a name on stack */{ struct stackentry *s; s=push(); s->pointer=my_strdup(name); s->type=stSTRING;}void pushlabel() /* bison: generate goto and push label on stack */{ char *st; struct stackentry *en; st=(char *) my_malloc(sizeof(char)*20); sprintf(st,"***%d",labelcount); labelcount++; create_goto(st); en=push(); en->type=stLABEL; en->pointer=st;}void poplabel() /* bison: pops a label and generates the matching command */{ create_label(pop(stLABEL)->pointer,cLABEL); /* and create it */}void pushgoto() /* bison: generate label and push goto on stack */{ char *st; struct stackentry *en; st=(char *) my_malloc(sizeof(char)*20); sprintf(st,"***%d",labelcount); labelcount++; create_label(st,cLABEL); en=push(); en->type=stGOTO; en->pointer=st;}void popgoto() /* bison: pops a goto and generates the matching command */{ create_goto(pop(stGOTO)->pointer); /* and create it */}void storelabel() /* bison: push label on stack */{ char *st; struct stackentry *en; st=(char *)my_malloc(sizeof(char)*20); sprintf(st,"***%d",labelcount); labelcount++; en=push(); en->type=stLABEL; en->pointer=st;}void matchgoto() /* bison: generate goto matching label on stack */{ create_goto(stackhead->prev->pointer);}void create_pushdbl(double value) /* create command 'cPUSHDBL' */{ struct command *cmd; cmd=add_command(cPUSHDBL,NULL); cmd->pointer=my_malloc(sizeof(double)); *(double *)(cmd->pointer)=value;}void pushdbl(struct command *cmd) { /* push double onto stack */ struct stackentry *p;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -