#include "efuns.h" #include <ctype.h> #include <math.h> #include "array.h" #include "lex.h" #include "instrs.h" #include "efun_protos.h" #include "opc_cost.h" #include "main.h" #include "stralloc.h" #include "simulate.h" #include "dynamic_buffer.h" #include "simul_efun.h" #define LEXDEBUG 0 int current_line; int total_lines; static int old_line; char *current_file; int pragma_strict_types; /* Force usage of strict types. */ int pragma_save_types; /* Save argument types after compilation */ int pragma_all_inline; /* inline all possible inlines */ char **inc_list; int inc_list_size; struct lpc_predef_s *lpc_predefs=NULL; #define EXPANDMAX 50000 static int nexpands; #define MIN(X,Y) ((X)<(Y)?(X):(Y)) #define isidchar(X) (isalnum(X) || (X)=='_') static int calc(); static void calc1(); void free_memory_in_lex_at_exit() { int i; extern char **local_names; extern unsigned short *type_of_locals; if(local_names) free((char *)local_names); if(type_of_locals) free((char *)type_of_locals); if(inc_list) { for(i=0;i<inc_list_size;i++) free_string(inc_list[i]); free((char *)inc_list); } } /* * The number of arguments stated below, are used by the compiler. * If min == max, then no information has to be coded about the * actual number of arguments. Otherwise, the actual number of arguments * will be stored in the byte after the instruction. * A maximum value of -1 means unlimited maximum value. * * If an argument has type 0 (T_INVALID) specified, then no checks will * be done at run time. * * The argument types are currently not checked by the compiler, * only by the runtime. */ struct keyword predefs[] = #include "efun_defs.c" struct keyword reswords[] = { { "break", F_BREAK, }, { "case", F_CASE, }, { "catch", F_CATCH, }, { "continue", F_CONTINUE, }, { "default", F_DEFAULT, }, { "do", F_DO, }, { "efun", F_EFUN, }, { "else", F_ELSE, }, { "float", F_FLOAT_TOKEN, }, { "for", F_FOR, }, { "foreach", F_FOREACH, }, { "function", F_FUNCTION, }, { "gauge", F_GAUGE, }, { "if", F_IF, }, { "inherit", F_INHERIT, }, { "inline", F_INLINE, }, { "int", F_INT, }, { "lambda", F_LAMBDA, }, { "list", F_LIST, }, { "mapping", F_MAPPING, }, { "mixed", F_MIXED, }, { "nomask", F_NO_MASK, }, { "object", F_OBJECT, }, { "private", F_PRIVATE, }, { "protected", F_PROTECTED, }, { "public", F_PUBLIC, }, { "regular_expression", F_REGULAR_EXPRESSION, }, { "return", F_RETURN, }, { "sscanf", F_SSCANF, }, { "swap", F_SWAP_VARIABLES, }, { "static", F_STATIC, }, { "status", F_STATUS, }, { "string", F_STRING_DECL, }, { "switch", F_SWITCH, }, { "varargs", F_VARARGS, }, { "void", F_VOID, }, { "while", F_WHILE, }, { "call_other", F_CALL_OTHER, }, }; int number_predefs=NELEM(predefs); int number_reswords=NELEM(reswords); int real_number_predefs=NELEM(predefs); struct instr instrs[F_MAX_INSTR-F_OFFSET]; static void add_instr_name(char *name,int n) { if(n>=F_MAX_INSTR) { fatal("invalid add_instr_name (%s,%d)\n",name,n); } instrs[n - F_OFFSET].name = name; instrs[n - F_OFFSET].efunc = NULL; } static int keword_sort_fun(const void *a,const void *b) { return ((struct keyword *)a)->word - ((struct keyword *)b)->word; } void init_num_args() { int i, n; #ifdef YYOPT for(i=0; i<NELEM(reswords); i++) { reswords[i].word=make_shared_string(reswords[i].word); } #endif for(i=0; i<NELEM(instrs);i++) instrs[i].eval_cost=AVERAGE_COST; for(i=0; i<NELEM(predefs); i++) { #ifdef YYOPT predefs[i].word=make_shared_string(predefs[i].word); #endif n = predefs[i].token - F_OFFSET; if (n < 0 || n > NELEM(instrs)) fatal("Token %s has illegal value %d.\n", predefs[i].word,n); instrs[n].min_arg = predefs[i].min_args; instrs[n].max_arg = predefs[i].max_args; instrs[n].name = predefs[i].word; instrs[n].type[0] = predefs[i].arg_type1; instrs[n].type[1] = predefs[i].arg_type2; instrs[n].Default = predefs[i].Default; instrs[n].ret_type = predefs[i].ret_type; instrs[n].arg_index = predefs[i].arg_index; instrs[n].efunc=predefs[i].efunc; } for(i=0;i<NELEM(func_cost_alist);i+=2) { n = func_cost_alist[i] - F_OFFSET; instrs[n].eval_cost=func_cost_alist[i+1]; } i=0; number_predefs--; while(i<number_predefs) { struct keyword tmp; while(predefs[i].efunc) i++; while(!predefs[number_predefs].efunc) number_predefs--; if(i<number_predefs) { tmp=predefs[i]; predefs[i]=predefs[number_predefs]; predefs[number_predefs]=tmp; } } number_predefs++; #ifdef YYOPT fsort((char *)reswords,NELEM(reswords),sizeof(reswords[0]),keword_sort_fun); fsort((char *)predefs,number_predefs,sizeof(predefs[0]),keword_sort_fun); #endif add_instr_name("add 256 to opcode",F_ADD_256); add_instr_name("add 512 to opcode",F_ADD_512); add_instr_name("add 768 to opcode",F_ADD_768); add_instr_name("add X*256 to opcode",F_ADD_256X); add_instr_name("sscanf",F_SSCANF); add_instr_name("swap",F_SWAP_VARIABLES); add_instr_name("swap on stack",F_SWAP); add_instr_name("(function)",F_CAST_TO_FUNCTION); add_instr_name("(string)",F_CAST_TO_STRING); add_instr_name("<", F_LT); add_instr_name(">", F_GT); add_instr_name("<=", F_LE); add_instr_name(">=", F_GE); add_instr_name("==", F_EQ); add_instr_name("!", F_NOT); add_instr_name("local", F_LOCAL); add_instr_name("-", F_SUBTRACT); add_instr_name("pop", F_POP_VALUE); add_instr_name("const-1", F_CONST_1); add_instr_name("+", F_ADD); add_instr_name("-", F_SUBTRACT); add_instr_name("*", F_MULTIPLY); add_instr_name("/", F_DIVIDE); add_instr_name("%", F_MOD); add_instr_name("!=", F_NE); add_instr_name("++x", F_INC); add_instr_name("x++", F_POST_INC); add_instr_name("x++ and pop", F_INC_AND_POP); add_instr_name("--x", F_DEC); add_instr_name("x--", F_POST_DEC); add_instr_name("x-- and pop", F_DEC_AND_POP); add_instr_name("branch when zero",F_BRANCH_WHEN_ZERO); add_instr_name("branch non zero",F_BRANCH_WHEN_NON_ZERO); add_instr_name("constant function",F_CONSTANT_FUNCTION); add_instr_name("push simulated efun",F_PUSH_SIMUL_EFUN); add_instr_name("(int)",F_CAST_TO_INT); add_instr_name("(float)",F_CAST_TO_FLOAT); add_instr_name("(object)",F_CAST_TO_OBJECT); add_instr_name("&=",F_AND_EQ); add_instr_name("|=",F_OR_EQ); add_instr_name("^=",F_XOR_EQ); add_instr_name("<<=",F_LSH_EQ); add_instr_name(">>=",F_RSH_EQ); add_instr_name("<<",F_LSH); add_instr_name(">>",F_RSH); add_instr_name("+=",F_ADD_EQ); add_instr_name("-=",F_SUB_EQ); add_instr_name("*=",F_MULT_EQ); add_instr_name("%=",F_MOD_EQ); add_instr_name("/=",F_DIV_EQ); add_instr_name("&&",F_LAND); add_instr_name("||",F_LOR); add_instr_name("case",F_CASE); add_instr_name("default",F_DEFAULT); add_instr_name("while",F_WHILE); add_instr_name("lvalue_list",F_LVALUE_LIST); add_instr_name("push_ltosval",F_PUSH_LTOSVAL); add_instr_name("do-while",F_DO); add_instr_name("++Loop",F_INC_LOOP); add_instr_name("--Loop",F_DEC_LOOP); add_instr_name("dumb return",F_DUMB_RETURN); add_instr_name("break",F_BREAK); add_instr_name("continue",F_CONTINUE); add_instr_name("for",F_FOR); } void free_reswords() { #ifdef YYOPT int i; for(i=0; i<NELEM(reswords); i++) free_string(reswords[i].word); for(i=0; i<NELEM(predefs); i++) free_string(predefs[i].word); #endif } char *get_f_name(int n) { if (n<F_MAX_INSTR &&instrs[n-F_OFFSET].name) { return instrs[n-F_OFFSET].name; }else { static char buf[30]; sprintf(buf, "<OTHER %d>", n); return buf; } } char *get_instruction_name(int n) { static char buf[40]; if(n<F_MAX_OPCODE) { if(n>0) { if (instrs[n-F_OFFSET].name) { return instrs[n-F_OFFSET].name; }else { sprintf(buf, "<OTHER %d>", n); } }else{ sprintf(buf, "<ILLIGAL %d>", n); } }else{ sprintf(buf, "<FUNCTION %d>", n); } return buf; } /* foo must be a shared string */ static int lookupword(char *foo, struct keyword *words,int h) { int i,l; if(!foo) return -1; for(l=0;;) { i=(l+h)/2; if(foo==words[i].word) return words[i].token; else if(l==i) return -1; else if(foo>words[i].word) l=i; else h=i; } } int lookup_predef(char *s) { s=findstring(s); if(!s) return -1; return lookupword(s, predefs, number_predefs); } /*** input routines ***/ struct inputstate { struct inputstate *next; FILE *f; char *data; int buflen; int pos; int (*my_getc)(); int (*gobble)(int); int (*look)(); void (*my_ungetc)(int); void (*ungetstr)(char *,int); }; static struct inputstate *istate=NULL; static void link_inputstate(struct inputstate *i) { i->next=istate; istate=i; } static void free_inputstate(struct inputstate *i) { if(!i) return; if(i->f) fclose(i->f); if(i->data) free(i->data); free_inputstate(i->next); free((char *)i); } static struct inputstate *new_inputstate(); static struct inputstate *memory_inputstate(int size); static int default_gobble(int c) { if(istate->look()==c) { istate->my_getc(); return 1; }else{ return 0; } } static void default_ungetstr(char *s,int len) { link_inputstate(memory_inputstate(len+1000)); istate->ungetstr(s,len); } static void default_ungetc(int s) { char c=s; istate->ungetstr(&c,1); } static struct inputstate *new_inputstate() { struct inputstate *i; i=(struct inputstate *)xalloc(sizeof(struct inputstate)); i->f=NULL; i->data=NULL; i->next=NULL; i->gobble=default_gobble; i->ungetstr=default_ungetstr; i->my_ungetc=default_ungetc; return i; } /*** EOF input ***/ static int end_getc() { return EOF; } static int end_gobble(int c) { return c==EOF; } static void end_ungetc(int c) { if(c==EOF) return; default_ungetc(c); } static struct inputstate *end_inputstate() { struct inputstate *i; i=new_inputstate(); i->gobble=end_gobble; i->look=end_getc; i->my_getc=end_getc; i->my_ungetc=end_ungetc; return i; } /*** MEMORY input ***/ static void memory_ungetstr(char *s,int len) { int tmp; tmp=MIN(len,istate->pos); if(tmp) { MEMCPY(istate->data + istate->pos - tmp, s+len-tmp , tmp); istate->pos-=tmp; len-=tmp; } if(len) default_ungetstr(s,len); } static int memory_getc() { if(istate->pos<istate->buflen) { #if LEXDEBUG>9 fprintf(stderr,"lex: reading from memory '%c' (%d).\n",istate->data[istate->pos],istate->data[istate->pos]); #endif return istate->data[(istate->pos)++]; }else{ struct inputstate *i; i=istate; istate=i->next; free((char *)i->data); free((char *)i); return istate->my_getc(); } } static int memory_look() { if(istate->pos<istate->buflen) { return istate->data[istate->pos]; }else{ struct inputstate *i; i=istate; istate=i->next; free((char *)i->data); free((char *)i); return istate->look(); } } /* allocate an empty memory state */ static struct inputstate *memory_inputstate(int size) { struct inputstate *i; if(!size) size=10000; i=new_inputstate(); i->data=xalloc(size); i->buflen=size; i->pos=size; i->ungetstr=memory_ungetstr; i->my_getc=memory_getc; i->look=memory_look; return i; } /*** FILE input ***/ static int file_getc() { int c; c=getc(istate->f); #if LEXDEBUG>9 fprintf(stderr,"lex: reading '%c' (%d)\n",c,c); #endif if(c!=EOF) { return c; }else{ struct inputstate *i; i=istate->next; fclose(istate->f); free((char *)istate); istate=i; return istate->my_getc(); } } static int file_look() { int c; c=getc(istate->f); if(c!=EOF) { ungetc(c,istate->f); return c; }else{ struct inputstate *i; i=istate->next; fclose(istate->f); free((char *)istate); istate=i; return istate->look(); } } static void file_ungetc(int c) { ungetc(c,istate->f); } static struct inputstate *file_inputstate(FILE *f) { struct inputstate *i; i=new_inputstate(); i->f=f; i->look=file_look; i->my_getc=file_getc; i->my_ungetc=file_ungetc; return i; } static int GETC() { int c; c=istate->my_getc(); if(c=='\n') current_line++; return c; } static void UNGETC(int c) { if(c=='\n') current_line--; istate->my_ungetc(c); } static void UNGETSTR(char *s,int len) { int e; for(e=0;e<len;e++) if(s[e]=='\n') current_line--; istate->ungetstr(s,len); } static int GOBBLE(char c) { if(istate->gobble(c)) { if(c=='\n') current_line++; return 1; }else{ return 0; } } #define LOOK() (istate->look()) #define SKIPWHITE() { int c; while(isspace(c=GETC())); UNGETC(c); } #define SKIPTO(X) { int c; while((c=GETC())!=(X) && (c!=EOF)); } #define SKIPUPTO(X) { int c; while((c=GETC())!=(X) && (c!=EOF)); UNGETC(c); } #define READBUF(X) { \ register int p,C; \ for(p=0;(C=GETC())!=EOF && p<sizeof(buf) && (X);p++) \ buf[p]=C; \ if(p==sizeof(buf)) { \ yyerror("Internal buffer overflow.\n"); p--; \ } \ UNGETC(C); \ buf[p]=0; \ } static char buf[1024]; /*** Define handling ***/ struct define { struct define *next; char *name; int args; struct vector *parts; }; typedef struct define *definep; definep define_hash[DEFINE_HASHSIZE]; /* argument must be shared string */ static void undefine(char *name) { int h; definep d,*prev; h=(((int)name) & 0x7fffffff) % DEFINE_HASHSIZE; for(prev=define_hash+h;(d=*prev);prev=&(d->next)) { if(d->name==name) { *prev=d->next; free_string(d->name); if(d->parts) free_vector(d->parts); free((char *)d); } } } /* argument must be shared string */ static definep find_define(char *name) { int h; definep d,*prev; h=(((int)name) & 0x7fffffff) % DEFINE_HASHSIZE; for(prev=define_hash+h;(d=*prev);prev=&(d->next)) { if(d->name==name) { *prev=d->next; d->next=define_hash[h]; define_hash[h]=d; return d; } } return NULL; } /* name and as are supposed to be SHARED strings */ static void add_define(char *name,int args,int parts_on_stack) { int h; definep d; f_aggregate(parts_on_stack,sp-parts_on_stack+1); if(sp->type!=T_POINTER) { yyerror("Define failed for unknown reason.\n"); free_string(name); pop_stack(); return; } if(find_define(name)) { char *a; a=(char *)alloca(strlen(name)+40); sprintf(a,"Redefining '%s'",name); yyerror(a); free_string(name); pop_stack(); return; } undefine(name); d=(definep)xalloc(sizeof(struct define)); d->name=name; d->args=args; d->parts=sp->u.vec; SET_TO_ZERO(*sp); pop_stack(); h=(((int)name) & 0x7fffffff) % DEFINE_HASHSIZE; d->next=define_hash[h]; define_hash[h]=d; } static void simple_add_define(char *name,char *as) { push_new_shared_string(as); add_define(make_shared_string(name),0,1); } static void free_all_defines() { int e; definep d,next; for(e=0;e<DEFINE_HASHSIZE;e++) { for(d=define_hash[e];d;d=next) { next=d->next; free_string(d->name); if(d->parts) free_vector(d->parts); free((char *)d); } define_hash[e]=NULL; } } static void do_define() { int c,e,t,argc; char *s,*s2; struct svalue *save_sp=sp; SKIPWHITE(); READBUF(isidchar(C)); s=make_shared_string(buf); if(GOBBLE('(')) { argc=0; SKIPWHITE(); READBUF(isidchar(C)); if(buf[0]) { push_new_shared_string(buf); argc++; SKIPWHITE(); while(GOBBLE(',')) { SKIPWHITE(); READBUF(isidchar(C)); push_new_shared_string(buf); argc++; } } SKIPWHITE(); if(!GOBBLE(')')) yyerror("Missing ')'"); }else{ argc=0; } init_buf(); t=0; push_svalue(&const_empty_string); while(1) { c=GETC(); if(c=='\\') if(GOBBLE('\n')) continue; if( (t!=!!isidchar(c) && argc>0) || c=='\n' || c==EOF) { s2=free_buf(); for(e=0;e<argc;e++) { if(strptr(save_sp+e+1)==s2) { free_string(s2); push_number(e); break; } } if(e==argc) { push_shared_string(s2); if(sp[-1].type==T_STRING) f_add(); } if(c=='\n' || c==EOF) { push_new_shared_string(" "); if(sp[-1].type==T_STRING) f_add(); break; } t=!!isidchar(c); init_buf(); } my_putchar(c); } UNGETC(c); add_define(s,argc,sp-save_sp-argc); while(sp>save_sp) pop_stack(); } /* s is a shared string */ static int expand_define(char *s) { struct svalue *save_sp=sp; definep d; int len,e,tmp,args; d=find_define(s); if(!d) return 0; if(nexpands>EXPANDMAX) { yyerror("Macro limit exceeded."); return 0; } SKIPWHITE(); if(GOBBLE('(')) { int parlvl,quote; int c; args=0; SKIPWHITE(); init_buf(); parlvl=1; quote=0; while(parlvl) { switch(c=GETC()) { case EOF: yyerror("Unexpected end of file."); while(sp>save_sp) pop_stack(); return 0; case '"': if(!(quote&2)) quote^=1; break; case '\'': if(!(quote&1)) quote^=2; break; case '(': if(!quote) parlvl++; break; case ')': if(!quote) parlvl--; break; case '\\': my_putchar(c); c=GETC(); break; case ',': if(!quote && parlvl==1) { push_shared_string(free_buf()); init_buf(); args++; continue; } } if(parlvl) my_putchar(c); } push_shared_string(free_buf()); if(args==0 && !d->args && !my_strlen(sp)) { pop_stack(); }else{ args++; } }else{ args=0; } if(args>d->args) { char *fel=(char *)alloca(strlen(s)+80); sprintf(fel,"Too many arguments to marco '%s'.",s); yyerror(fel); while(sp>save_sp) pop_stack(); return 0; } if(args<d->args) { char *fel=(char *)alloca(strlen(s)+80); sprintf(fel,"Too few arguments to marco '%s'.",s); yyerror(fel); while(sp>save_sp) pop_stack(); return 0; } len=0; for(e=d->parts->size-1;e>=0;e--) { switch(d->parts->item[e].type) { case T_STRING: tmp=my_strlen(d->parts->item+e); UNGETSTR(strptr(d->parts->item+e),tmp); break; case T_NUMBER: tmp=my_strlen(save_sp+d->parts->item[e].u.number+1); UNGETSTR(strptr(save_sp+d->parts->item[e].u.number+1),tmp); break; default: tmp=0; } len+=tmp; } while(sp>save_sp) pop_stack(); nexpands+=len; return 1; } /*** Handle include ****/ static void handle_include(char *name) { FILE *f; char buf[400],*p; int i; if(current_file[0]!='/' && !batch_mode) { buf[0]='/'; strncpy(buf+1, current_file,sizeof(buf)-1); buf[sizeof(buf)-1]=0; }else{ strncpy(buf, current_file,sizeof(buf)); buf[sizeof(buf)-1]=0; } if ((p = STRRCHR(buf, '/'))) { *p = 0; }else{ buf[0]='/'; buf[1]=0; } p=combine_path(buf,name); /* DON'T LOOK!!!!! /Profezzorn */ if((f=fopen(p+!batch_mode,"r"))==NULL) { free(p); for (p=STRCHR(name, '.'); p; p = STRCHR(p+1, '.')) { if (p[1] == '.') { yyerror("Illigal to have '..' in includes from standard includepath."); return; } } for (i=0; i < inc_list_size; i++) { sprintf(buf,inc_list[i],name); if((f = fopen(buf, "r"))) { p=string_copy(buf); break; } } if(!p) { yyerror("Couldn't find file to include."); return; } } UNGETSTR("\"",2); UNGETSTR(current_file,strlen(current_file)); sprintf(buf,"\n# %d \"",current_line+1); UNGETSTR(buf,strlen(buf)); total_lines+=current_line-old_line; old_line=current_line=1; free(current_file); current_file=p; link_inputstate(file_inputstate(f)); UNGETSTR("\n",1); } /*** Lexical analyzing ***/ static int char_const() { int c; switch(c=GETC()) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c-='0'; if(LOOK()<'0' || LOOK()>'8') return c; c=c*8+(GETC()-'0'); if(LOOK()<'0' || LOOK()>'8') return c; c=c*8+(GETC()-'0'); return c; case 'r': return '\r'; case 'n': return '\n'; case 't': return '\t'; case 'b': return '\b'; } return c; } static void do_skip() { char *s; int lvl,c; #if LEXDEBUG>3 fprintf(stderr,"Skipping from %d to ",current_line); #endif lvl=1; while(lvl) { switch(c=GETC()) { case '/': if(GOBBLE('*')) { do{ SKIPTO('*'); }while(!GOBBLE('/')); } continue; case EOF: yyerror("Unexpected end of file while skipping."); return; case '\\': GETC(); continue; case '\n': if(GOBBLE('#')) { SKIPWHITE(); READBUF(C!=' ' && C!='\t' && C!='\n'); switch(buf[0]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': continue; case 'i': if(!strcmp("include",buf)) continue; if(!strcmp("if",buf) || !strcmp("ifdef",buf) || !strcmp("ifndef",buf)) { lvl++; continue; } break; case 'e': if(!strcmp("endif",buf)) { lvl--; continue; } if(!strcmp("else",buf)) { if(lvl==1) lvl=0; continue; } if(!strcmp("elif",buf) || !strcmp("elseif",buf)) { if(lvl==1 && calc()) lvl--; continue; } break; case 'l': if(!strcmp("line",buf)) continue; break; case 'd': if(!strcmp("define",buf)) continue; break; case 'u': if(!strcmp("undef",buf)) continue; break; case 'p': if(!strcmp("pragma",buf)) continue; break; } s=(char *)alloca(strlen(buf)+80); sprintf(s,"Unknown directive #%s.",buf); yyerror(s); SKIPUPTO('\n'); continue; } } } #if LEXDEBUG>3 fprintf(stderr,"%d in %s.\n",current_line,current_file); #endif } static int do_lex(int literal) #if LEXDEBUG>4 { int t; int do_lex2(int literal); t=do_lex2(literal); if(t<256) { fprintf(stderr,"do_lex(%d) -> '%c' (%d)\n",literal,t,t); }else{ fprintf(stderr,"do_lex(%d) -> %s (%d)\n",literal,get_f_name(t),t); } return t; } static int do_lex2(int literal) #endif { int c; #ifdef MALLOC_DEBUG check_sfltable(); #endif while(1) { switch(c=GETC()) { case '\n': if(literal) { UNGETC('\n'); return '\n'; } if(GOBBLE('#')) { if(GOBBLE('!')) { SKIPUPTO('\n'); continue; } SKIPWHITE(); READBUF(C!=' ' && C!='\t' && C!='\n'); switch(buf[0]) { char *p; case 'l': if(strcmp("line",buf)) goto badhash; READBUF(C!=' ' && C!='\t' && C!='\n'); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': total_lines+=current_line-old_line; old_line=current_line=atoi(buf)-1; SKIPWHITE(); READBUF(C!='\n'); p=buf; if(*p=='"' && STRCHR(p+1,'"')) { char *p2; p++; if((p2=STRCHR(p+1,'"'))) { *p2=0; p=combine_path("/",p); free(current_file); current_file=p; } } break; case 'i': if(!strcmp("include",buf)) { SKIPWHITE(); c=do_lex(1); if(c=='<') { READBUF(C!='>' && C!='\n'); if(!GOBBLE('>')) { yyerror("Missing `>`"); SKIPUPTO('\n'); continue; } }else{ if(c!=F_STRING) { yyerror("Couldn't find include filename.\n"); SKIPUPTO('\n'); continue; } } handle_include(buf); break; } if(!strcmp("if",buf)) { if(!calc()) do_skip(); break; } if(!strcmp("ifdef",buf)) { SKIPWHITE(); READBUF(isidchar(C)); p=findstring(buf); if(!p || !find_define(p)) do_skip(); break; } if(!strcmp("ifndef",buf)) { SKIPWHITE(); READBUF(isidchar(C)); p=findstring(buf); if(p && find_define(p)) do_skip(); break; } goto badhash; case 'e': if(!strcmp("endif",buf)) break; if(!strcmp("else",buf)) { SKIPUPTO('\n'); do_skip(); break; } if(!strcmp("elif",buf) || !strcmp("elseif",buf)) { SKIPUPTO('\n'); do_skip(); break; } goto badhash; case 'u': if(!strcmp("undef",buf)) { SKIPWHITE(); READBUF(isidchar(C)); if((p=findstring(buf))) undefine(p); break; } goto badhash; case 'd': if(!strcmp("define",buf)) { do_define(); break; } goto badhash; case 'p': if(!strcmp("pragma",buf)) { SKIPWHITE(); READBUF(C!='\n'); if (strcmp(buf, "strict_types") == 0) { pragma_strict_types = 1; }else if (strcmp(buf, "unpragma_strict_types") == 0) { pragma_strict_types = 0; } else if (strcmp(buf, "save_types") == 0) { pragma_save_types = 1; } else if (strcmp(buf, "all_inline") == 0) { pragma_all_inline = 1; } break; } badhash: p=(char *)alloca(strlen(buf)+80); sprintf(p,"Unknown directive #%s.",buf); yyerror(p); SKIPUPTO('\n'); continue; } } continue; case ' ': case '\t': continue; case EOF: return 0; case '\'': c=GETC(); if(c=='\\') c=char_const(); if(GETC()!='\'') yyerror("Unterminated character constant.\n"); yylval.number=c; return F_NUMBER; case '"': init_buf(); while(1) { c=GETC(); if(c==-1) { yyerror("End of file in string.\n"); free(simple_free_buf()); return 0; } if(c=='\n') { yyerror("Newline in string.\n"); free(simple_free_buf()); return 0; } if(c=='\\') { c=char_const(); }else{ if(c=='"') break; } my_putchar(c); } if(literal) { strncpy(buf,return_buf(),sizeof(buf)); buf[sizeof(buf)-1]=0; yylval.string=buf; }else{ yylval.string=free_buf(); } return F_STRING; case ':': if(GOBBLE(':')) return F_COLON_COLON; return c; case '.': if(GOBBLE('.')) { if(GOBBLE('.')) return F_DOT_DOT_DOT; return F_DOT_DOT; } return c; case '0': if(GOBBLE('x')) { READBUF(isxdigit(C)); yylval.number=STRTOL(buf,NULL,16); return F_NUMBER; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { char *p; UNGETC(c); READBUF(isdigit(C) || C=='.'); p=STRCHR(buf,'.'); if(p) { if(p[1]=='.') { UNGETSTR(p,strlen(p)); *p=0; p=NULL; }else if((p=STRCHR(p+1,'.'))) { UNGETSTR(p,strlen(p)); *p=0; } if((p=STRCHR(buf,'.'))) { yylval.fnum=STRTOD(buf,NULL); return F_FLOAT; } } yylval.number=STRTOL(buf,NULL,10); return F_NUMBER; } case '-': if(GOBBLE('=')) return F_SUB_EQ; if(GOBBLE('>')) return F_ARROW; if(GOBBLE('-')) return F_DEC; return '-'; case '+': if(GOBBLE('=')) return F_ADD_EQ; if(GOBBLE('+')) return F_INC; return '+'; case '&': if(GOBBLE('=')) return F_AND_EQ; if(GOBBLE('&')) return F_LAND; return '&'; case '|': if(GOBBLE('=')) return F_OR_EQ; if(GOBBLE('|')) return F_LOR; return '|'; case '^': if(GOBBLE('=')) return F_XOR_EQ; return '^'; case '*': if(GOBBLE('=')) return F_MULT_EQ; return '*'; case '%': if(GOBBLE('=')) return F_MOD_EQ; return '%'; case '/': if(GOBBLE('*')) { do{ SKIPTO('*'); }while(!GOBBLE('/')); continue; }else if(GOBBLE('/')) { SKIPUPTO('\n'); continue; } if(GOBBLE('=')) return F_DIV_EQ; return '/'; case '=': if(GOBBLE('=')) return F_EQ; return '='; case '<': if(GOBBLE('<')) { if(GOBBLE('=')) return F_LSH_EQ; return F_LSH; } if(GOBBLE('=')) return F_LE; return '<'; case '>': if(GOBBLE(')')) return F_LIST_END; if(GOBBLE('=')) return F_GE; if(GOBBLE('>')) { if(GOBBLE('=')) return F_RSH_EQ; return F_RSH; } return '>'; case '!': if(GOBBLE('=')) return F_NE; return F_NOT; case '(': case '?': case ',': case '~': case '@': case ')': case '[': case ']': case '{': case ';': case '}': return c; default: if(isidchar(c)) { UNGETC(c); READBUF(isidchar(C)); if(!literal) { char *s; /* identify indetifier, if it is not a shared string, * then it is neither a define, reserved word or efun */ if((s=findstring(buf))) { int i; if(expand_define(s)) continue; i=lookupword(s, reswords, NELEM(reswords)); if(i>=0) return i; if(islocal(s)>=0) { yylval.string = copy_shared_string(s); return F_IDENTIFIER; } i=defined_function(s); if(i>=0) { yylval.number=i; return F_FUNCTION_NAME; } i=lookupword(s, predefs, number_predefs); if(i>=0) { if(find_simul_efun(s)<0) { yylval.number=i; return F_EFUN_NAME; } } s=copy_shared_string(s); }else{ s=make_shared_string(buf); } yylval.string=s; return F_IDENTIFIER; } yylval.string=buf; return F_IDENTIFIER; }else{ char buff[100]; sprintf(buff, "Illegal character (hex %02x) '%c'", c, c); yyerror(buff); return ' '; } } } } int yylex() { return do_lex(0); } static int lookahead; static void low_lex() { while(1) { lookahead=do_lex(1); if(lookahead==F_IDENTIFIER) { if(!strcmp("defined",yylval.string)) { char *s; SKIPWHITE(); if(!GOBBLE('(')) { yyerror("Missing '(' in defined.\n"); return; } READBUF(isidchar(C)); if(!GOBBLE(')')) { yyerror("Missing ')' in defined.\n"); return; } s=findstring(buf); if(s && find_define(s)) { UNGETSTR(" 1 ",3); }else{ UNGETSTR(" 0 ",3); } continue; } if(!strcmp("efun",yylval.string)) { char *s; SKIPWHITE(); if(!GOBBLE('(')) { yyerror("Missing '(' in #if efun().\n"); return; } READBUF(isidchar(C)); if(!GOBBLE(')')) { yyerror("Missing ')' in #if efun().\n"); return; } s=findstring(buf); if(s && lookupword(s, predefs, number_predefs)>=0) { UNGETSTR(" 1 ",3); }else{ UNGETSTR(" 0 ",3); } continue; } if(!expand_define(yylval.string)) { UNGETSTR(" 0 ",3); continue; } } break; } } static void calcC() { switch(lookahead) { case '(': low_lex(); calc1(); if(lookahead!=')') error("Missing ')'\n"); break; case F_FLOAT: push_float(yylval.fnum); break; case F_STRING: push_new_shared_string(yylval.string); break; case F_NUMBER: push_number(yylval.number); break; default: yyerror("Syntax error in #if."); return; } low_lex(); while(lookahead=='[') { low_lex(); calc1(); f_index(); if(lookahead!=']') error("Missing ']'\n"); low_lex(); } } static void calcB() { switch(lookahead) { case F_NOT: low_lex(); calcB(); f_not(); break; case '~': low_lex(); calcB(); f_compl(); break; default: calcC(); } } static void calcA() { calcB(); while(1) { switch(lookahead) { case '/': low_lex(); calcB(); f_divide(); continue; case '*': low_lex(); calcB(); f_multiply(); continue; case '%': low_lex(); calcB(); f_mod(); continue; } break; } } static void calc9() { calcA(); while(1) { switch(lookahead) { case '+': low_lex(); calcA(); f_add(); continue; case '-': low_lex(); calcA(); f_subtract(); continue; } break; } } static void calc8() { calc9(); while(1) { switch(lookahead) { case F_LSH: low_lex(); calc9(); f_lsh(); continue; case F_RSH: low_lex(); calc9(); f_rsh(); continue; } break; } } static void calc7b() { calc8(); while(1) { switch(lookahead) { case '<': low_lex(); calc8(); f_lt(); continue; case '>': low_lex(); calc8(); f_gt(); continue; case F_GE: low_lex(); calc8(); f_ge(); continue; case F_LE: low_lex(); calc8(); f_le(); continue; } break; } } static void calc7() { calc7b(); while(1) { switch(lookahead) { case F_EQ: low_lex(); calc7b(); f_eq(); continue; case F_NE: low_lex(); calc7b(); f_ne(); continue; } break; } } static void calc6() { calc7(); while(lookahead=='&') { low_lex(); calc7(); f_and(); } } static void calc5() { calc6(); while(lookahead=='^') { low_lex(); calc6(); f_and(); } } static void calc4() { calc5(); while(lookahead=='|') { low_lex(); calc5(); f_or(); } } static void calc3() { calc4(); while(lookahead==F_LAND) { low_lex(); if(IS_ZERO(sp)) { calc4(); pop_stack(); }else{ pop_stack(); calc4(); } } } static void calc2() { calc3(); while(lookahead==F_LOR) { low_lex(); if(!IS_ZERO(sp)) { calc3(); pop_stack(); }else{ pop_stack(); calc3(); } } } static void calc1() { calc2(); if(lookahead=='?') { low_lex(); calc1(); if(lookahead!=':') error("Colon expected.\n"); low_lex(); calc1(); if(IS_ZERO(sp-3)) f_swap(); pop_stack(); f_swap(); pop_stack(); } if(lookahead!='\n') { SKIPUPTO('\n'); yyerror("Extra characters after #if expression."); }else{ UNGETC('\n'); } } static int calc() { extern int error_recovery_context_exists; jmp_buf error_recovery_context; struct svalue *save_sp; extern struct svalue catch_value; int ret; save_sp=sp; push_control_stack(0); push_pop_error_context (1); error_recovery_context_exists=2; if (setjmp(error_recovery_context)) { ret=0; push_pop_error_context(-1); pop_control_stack(); if(catch_value.type==T_STRING) { yyerror(strptr(&catch_value)); }else{ yyerror("Eval error"); } ret=-1; }else{ low_lex(); calc1(); pop_control_stack(); push_pop_error_context(0); ret=!IS_ZERO(sp); } while(sp>save_sp) pop_stack(); return ret; } void set_inc_list(struct svalue *sv) { int i; struct vector *v; char *p; if (sv == 0) { fprintf(stderr, "There must be a function 'define_include_dirs' in master.c.\n"); fprintf(stderr, "This function should return an array of all directories to be searched\n"); fprintf(stderr, "for include files.\n"); exit(1); } if (sv->type != T_POINTER) { fprintf(stderr, "'define_include_dirs' in master.c did not return an array.\n"); exit(1); } v = sv->u.vec; inc_list = (char **)xalloc(v->size * sizeof (char *)); inc_list_size = v->size; for (i=0; i < v->size; i++) { if (v->item[i].type != T_STRING) { fprintf(stderr, "Illegal value returned from 'define_include_dirs' in master.c\n"); exit(1); } p = strptr(v->item+i); if(!batch_mode) if (*p == '/') p++; /* * Even make sure that the game administrator has not made an error. */ if (!legal_path(p)) { fprintf(stderr, "'define_include_dirs' must give paths without any '..'\n"); exit(1); } inc_list[i] = make_shared_string(p); } } static void start_new() { struct lpc_predef_s *tmpf; extern char **local_names; extern unsigned short *type_of_locals; if(!local_names) local_names=(char **)malloc((sizeof(char *))*MAX_LOCAL); if(!type_of_locals) type_of_locals=(unsigned short *)malloc((sizeof(unsigned short))*MAX_LOCAL); free_all_defines(); simple_add_define("LPC4", "1"); simple_add_define("__LPC4__", "1"); for (tmpf=lpc_predefs; tmpf; tmpf=tmpf->next) { char namebuf[100],mtext[400]; *mtext='\0'; sscanf(tmpf->flag,"%[^=]=%[ -~=]",namebuf,mtext); if ( strlen(namebuf) >= sizeof(namebuf) ) fatal("Define buffer overflow\n"); if ( strlen(mtext) >= sizeof(mtext) ) fatal("Define buffer overflow\n"); simple_add_define(namebuf,mtext); } free_inputstate(istate); istate=NULL; link_inputstate(end_inputstate()); old_line=current_line = 1; pragma_all_inline=0; pragma_strict_types = 1; nexpands=0; } void start_new_file(FILE *f) { start_new(); link_inputstate(file_inputstate(f)); UNGETSTR("\n",1); } void start_new_string(char *s,int len) { start_new(); UNGETSTR(s,len); old_line=current_line = 1; UNGETSTR("\n",1); } void end_new_file() { free_inputstate(istate); istate=NULL; free_all_defines(); total_lines+=current_line-old_line; }