|
|
|
|
|
#include "global.h" |
RCSID("$Id: lex.c,v 1.35 1998/03/03 11:24:33 hubbe Exp $"); |
#include "language.h" |
#include "array.h" |
#include "lex.h" |
#include "stralloc.h" |
#include "dynamic_buffer.h" |
#include "constants.h" |
#include "hashtable.h" |
#include "stuff.h" |
#include "pike_memory.h" |
#include "interpret.h" |
#include "error.h" |
#include "object.h" |
#include "las.h" |
#include "operators.h" |
#include "opcodes.h" |
#include "builtin_functions.h" |
#include "main.h" |
#include "mapping.h" |
|
#include "pike_macros.h" |
#include <sys/param.h> |
#include <ctype.h> |
#include <math.h> |
#include <fcntl.h> |
#include <errno.h> |
#include "time_stuff.h" |
|
#define LEXDEBUG 0 |
#define EXPANDMAX 500000 |
|
struct pike_string *current_file; |
|
INT32 current_line; |
INT32 old_line; |
INT32 total_lines; |
INT32 nexpands; |
int pragma_all_inline; |
|
struct pike_predef_s |
{ |
char *name; |
char *value; |
struct pike_predef_s *next; |
}; |
|
struct pike_predef_s *pike_predefs=0; |
|
static int calc(void); |
static void calc1(void); |
|
void exit_lex(void) |
{ |
extern struct pike_string *last_identifier; |
free_string(last_identifier); |
last_identifier=0; |
|
#ifdef DEBUG |
if(p_flag) |
{ |
int e; |
fprintf(stderr,"Opcode usage: (opcode, runned, compiled)\n"); |
for(e=0;e<F_MAX_OPCODE-F_OFFSET;e++) |
{ |
fprintf(stderr,":: %-20s %8ld %8ld\n", |
low_get_f_name(e+F_OFFSET,0), |
(long)instrs[e].runs, |
(long)instrs[e].compiles); |
} |
} |
#endif |
|
|
while(local_variables) |
{ |
int e; |
struct locals *l; |
for(e=0;e<local_variables->current_number_of_locals;e++) |
{ |
free_string(local_variables->variable[e].name); |
free_string(local_variables->variable[e].type); |
} |
if(local_variables->current_type) |
free_string(local_variables->current_type); |
if(local_variables->current_return_type) |
free_string(local_variables->current_return_type); |
l=local_variables->next; |
free((char *)local_variables); |
local_variables=l; |
} |
|
if(current_file) free_string(current_file); |
free_reswords(); |
|
while(pike_predefs) |
{ |
struct pike_predef_s *tmp; |
tmp=pike_predefs; |
pike_predefs=tmp->next; |
free(tmp->name); |
free(tmp->value); |
free(tmp); |
} |
} |
|
struct keyword reserved_words[] = |
{ |
{ "array", F_ARRAY_ID, }, |
{ "break", F_BREAK, }, |
{ "case", F_CASE, }, |
{ "catch", F_CATCH, }, |
{ "class", F_CLASS, }, |
{ "constant", F_CONSTANT, }, |
{ "continue", F_CONTINUE, }, |
{ "default", F_DEFAULT, }, |
{ "do", F_DO, }, |
{ "else", F_ELSE, }, |
{ "float", F_FLOAT_ID, }, |
{ "for", F_FOR, }, |
{ "foreach", F_FOREACH, }, |
{ "function", F_FUNCTION_ID, }, |
{ "gauge", F_GAUGE, }, |
{ "if", F_IF, }, |
{ "import", F_IMPORT, }, |
{ "inherit", F_INHERIT, }, |
{ "inline", F_INLINE, }, |
{ "int", F_INT_ID, }, |
{ "lambda", F_LAMBDA, }, |
{ "mapping", F_MAPPING_ID, }, |
{ "mixed", F_MIXED_ID, }, |
{ "multiset", F_MULTISET_ID, }, |
{ "nomask", F_NO_MASK, }, |
{ "object", F_OBJECT_ID, }, |
{ "predef", F_PREDEF, }, |
{ "private", F_PRIVATE, }, |
{ "program", F_PROGRAM_ID, }, |
{ "protected", F_PROTECTED, }, |
{ "public", F_PUBLIC, }, |
{ "return", F_RETURN, }, |
{ "sscanf", F_SSCANF, }, |
{ "static", F_STATIC, }, |
{ "string", F_STRING_ID, }, |
{ "switch", F_SWITCH, }, |
{ "typeof", F_TYPEOF, }, |
{ "varargs", F_VARARGS, }, |
{ "void", F_VOID_ID, }, |
{ "while", F_WHILE, }, |
}; |
|
struct keyword instr_names[]= |
{ |
{ "!", F_NOT }, |
{ "!=", F_NE }, |
{ "%", F_MOD }, |
{ "%=", F_MOD_EQ }, |
{ "& global", F_GLOBAL_LVALUE, I_HASARG }, |
{ "& local", F_LOCAL_LVALUE, I_HASARG }, |
{ "&", F_AND }, |
{ "&=", F_AND_EQ }, |
{ "*", F_MULTIPLY }, |
{ "*=", F_MULT_EQ }, |
{ "+", F_ADD }, |
{ "++x", F_INC }, |
{ "+=", F_ADD_EQ }, |
{ "-", F_SUBTRACT }, |
{ "--x", F_DEC }, |
{ "-=", F_SUB_EQ }, |
{ "/", F_DIVIDE }, |
{ "/=", F_DIV_EQ }, |
{ "<", F_LT }, |
{ "<<", F_LSH }, |
{ "<<=", F_LSH_EQ }, |
{ "<=", F_LE }, |
{ "==", F_EQ }, |
{ ">", F_GT }, |
{ ">=", F_GE }, |
{ ">>", F_RSH }, |
{ ">>=", F_RSH_EQ }, |
{ "@", F_PUSH_ARRAY }, |
{ "^", F_XOR }, |
{ "^=", F_XOR_EQ }, |
{ "arg+=1024", F_PREFIX_1024 }, |
{ "arg+=256", F_PREFIX_256 }, |
{ "arg+=256*X", F_PREFIX_CHARX256 }, |
{ "arg+=256*XX", F_PREFIX_WORDX256 }, |
{ "arg+=256*XXX", F_PREFIX_24BITX256 }, |
{ "arg+=512", F_PREFIX_512 }, |
{ "arg+=768", F_PREFIX_768 }, |
{ "assign and pop", F_ASSIGN_AND_POP }, |
{ "assign global", F_ASSIGN_GLOBAL, I_HASARG }, |
{ "assign global and pop", F_ASSIGN_GLOBAL_AND_POP, I_HASARG }, |
{ "assign local", F_ASSIGN_LOCAL, I_HASARG }, |
{ "assign local and pop", F_ASSIGN_LOCAL_AND_POP, I_HASARG }, |
{ "assign", F_ASSIGN }, |
{ "break", F_BREAK }, |
{ "case", F_CASE }, |
{ "cast", F_CAST }, |
{ "const-1", F_CONST_1 }, |
{ "constant", F_CONSTANT, I_HASARG }, |
{ "continue", F_CONTINUE }, |
{ "copy_value", F_COPY_VALUE }, |
{ "default", F_DEFAULT }, |
{ "do-while", F_DO }, |
{ "dumb return", F_DUMB_RETURN }, |
{ "float number", F_FLOAT }, |
{ "for", F_FOR }, |
{ "global", F_GLOBAL, I_HASARG }, |
{ "index", F_INDEX }, |
{ "->", F_ARROW, I_HASARG }, |
{ "clear string subtype", F_CLEAR_STRING_SUBTYPE }, |
{ "arrow string", F_ARROW_STRING, I_HASARG }, |
{ "indirect", F_INDIRECT }, |
|
{ "branch", F_BRANCH, I_ISJUMP }, |
{ "branch non zero", F_BRANCH_WHEN_NON_ZERO, I_ISJUMP }, |
{ "branch when zero", F_BRANCH_WHEN_ZERO, I_ISJUMP }, |
{ "branch if <", F_BRANCH_WHEN_LT, I_ISJUMP }, |
{ "branch if >", F_BRANCH_WHEN_GT, I_ISJUMP }, |
{ "branch if <=", F_BRANCH_WHEN_LE, I_ISJUMP }, |
{ "branch if >=", F_BRANCH_WHEN_GE, I_ISJUMP }, |
{ "branch if ==", F_BRANCH_WHEN_EQ, I_ISJUMP }, |
{ "branch if !=", F_BRANCH_WHEN_NE, I_ISJUMP }, |
{ "++Loop", F_INC_LOOP, I_ISJUMP }, |
{ "++Loop!=", F_INC_NEQ_LOOP, I_ISJUMP }, |
{ "--Loop", F_DEC_LOOP, I_ISJUMP }, |
{ "--Loop!=", F_DEC_NEQ_LOOP, I_ISJUMP }, |
{ "&&", F_LAND, I_ISJUMP }, |
{ "||", F_LOR, I_ISJUMP }, |
{ "==||", F_EQ_OR, I_ISJUMP }, |
{ "==&&", F_EQ_AND, I_ISJUMP }, |
{ "catch", F_CATCH, I_ISJUMP }, |
{ "foreach", F_FOREACH, I_ISJUMP }, |
{ "data", F_POINTER, I_ISPOINTER }, |
|
{ "local function call",F_CALL_LFUN, I_HASARG }, |
{ "local function call and pop",F_CALL_LFUN_AND_POP, I_HASARG }, |
{ "local function", F_LFUN, I_HASARG }, |
{ "local", F_LOCAL, I_HASARG }, |
{ "mark & local", F_MARK_AND_LOCAL, I_HASARG }, |
{ "ltosval2", F_LTOSVAL2 }, |
{ "lvalue to svalue", F_LTOSVAL }, |
{ "lvalue_list", F_LVALUE_LIST }, |
{ "mark", F_MARK }, |
{ "mark mark", F_MARK2 }, |
{ "negative number", F_NEG_NUMBER, I_HASARG }, |
{ "number", F_NUMBER, I_HASARG }, |
{ "pop", F_POP_VALUE }, |
{ "pop_n_elems", F_POP_N_ELEMS, I_HASARG }, |
{ "push 0", F_CONST0 }, |
{ "push 1", F_CONST1 }, |
{ "push 0x7fffffff", F_BIGNUM }, |
{ "range", F_RANGE }, |
{ "return", F_RETURN }, |
{ "return 0", F_RETURN_0 }, |
{ "return 1", F_RETURN_1 }, |
{ "sscanf", F_SSCANF, I_HASARG }, |
{ "string", F_STRING, I_HASARG }, |
{ "switch", F_SWITCH, I_HASARG }, |
{ "unary minus", F_NEGATE }, |
{ "while", F_WHILE }, |
{ "x++ and pop", F_INC_AND_POP }, |
{ "x++", F_POST_INC }, |
{ "x-- and pop", F_DEC_AND_POP }, |
{ "x--", F_POST_DEC }, |
{ "|", F_OR }, |
{ "|=", F_OR_EQ }, |
{ "~", F_COMPL }, |
{ "label", F_LABEL,I_HASARG }, |
{ "align", F_ALIGN, I_HASARG }, |
{ "call", F_APPLY, I_HASARG }, |
{ "clear local", F_CLEAR_LOCAL, I_HASARG }, |
{ "clear 2 local", F_CLEAR_2_LOCAL, I_HASARG }, |
{ "++local", F_INC_LOCAL, I_HASARG }, |
{ "++local and pop", F_INC_LOCAL_AND_POP, I_HASARG }, |
{ "local++", F_POST_INC_LOCAL, I_HASARG }, |
{ "--local", F_DEC_LOCAL, I_HASARG }, |
{ "--local and pop", F_DEC_LOCAL_AND_POP, I_HASARG }, |
{ "local--", F_POST_DEC_LOCAL, I_HASARG }, |
{ "sizeof", F_SIZEOF }, |
{ "sizeof local", F_SIZEOF_LOCAL, I_HASARG }, |
{ "throw(0)", F_THROW_ZERO }, |
{ "string index", F_STRING_INDEX, I_HASARG }, |
{ "local index", F_LOCAL_INDEX, I_HASARG }, |
{ "int index", F_POS_INT_INDEX, I_HASARG }, |
{ "-int index", F_NEG_INT_INDEX, I_HASARG }, |
{ "apply and pop", F_APPLY_AND_POP, I_HASARG }, |
{ "2 locals", F_2_LOCALS, I_HASARG }, |
{ "byte", F_BYTE, I_HASARG }, |
{ "nop", F_NOP }, |
{ "add integer", F_ADD_INT, I_HASARG }, |
{ "add -integer", F_ADD_NEG_INT, I_HASARG }, |
{ "mark & call", F_MARK_APPLY, I_HASARG }, |
{ "mark, call & pop", F_MARK_APPLY_POP, I_HASARG }, |
{ "+= and pop", F_ADD_TO_AND_POP }, |
}; |
|
struct instr instrs[F_MAX_INSTR - F_OFFSET]; |
|
struct reserved |
{ |
struct hash_entry link; |
int token; |
}; |
|
struct hash_table *reswords; |
|
void init_lex(void) |
{ |
unsigned int i; |
for(i=0; i<NELEM(instr_names);i++) |
{ |
if(instr_names[i].token >= F_MAX_INSTR) |
fatal("Error in instr_names[%u]\n\n",i); |
|
if(instrs[instr_names[i].token - F_OFFSET].name) |
fatal("Duplicate name for %s\n",instr_names[i].word); |
|
instrs[instr_names[i].token - F_OFFSET].name = instr_names[i].word; |
instrs[instr_names[i].token - F_OFFSET].flags=instr_names[i].flags; |
} |
|
reswords=create_hash_table(); |
|
for(i=0; i<NELEM(reserved_words); i++) |
{ |
struct reserved *r=ALLOC_STRUCT(reserved); |
r->token = reserved_words[i].token; |
r->link.s = make_shared_string(reserved_words[i].word); |
reswords=hash_insert(reswords, &r->link); |
} |
|
|
reswords = hash_rehash(reswords, 2<<my_log2(NELEM(reserved_words))); |
} |
|
void free_reswords(void) |
{ |
free_hashtable(reswords,0); |
} |
|
char *low_get_f_name(int n,struct program *p) |
{ |
static char buf[30]; |
|
if (n<F_MAX_OPCODE && instrs[n-F_OFFSET].name) |
{ |
return instrs[n-F_OFFSET].name; |
}else if(n >= F_MAX_OPCODE) { |
if(p && |
(int)p->num_constants > (int)(n-F_MAX_OPCODE) && |
p->constants[n-F_MAX_OPCODE].type==T_FUNCTION && |
(p->constants[n-F_MAX_OPCODE].subtype == FUNCTION_BUILTIN) && |
p->constants[n-F_MAX_OPCODE].u.efun) |
{ |
return p->constants[n-F_MAX_OPCODE].u.efun->name->str; |
}else{ |
sprintf(buf, "Call efun %d", n - F_MAX_OPCODE); |
return buf; |
} |
}else{ |
sprintf(buf, "<OTHER %d>", n); |
return buf; |
} |
} |
|
char *get_f_name(int n) |
{ |
static char buf[30]; |
if (n<F_MAX_OPCODE && instrs[n-F_OFFSET].name) |
{ |
return instrs[n-F_OFFSET].name; |
}else if(n >= F_MAX_OPCODE) { |
if(fp && fp->context.prog && |
(int)fp->context.prog->num_constants > (int)(n-F_MAX_OPCODE) && |
fp->context.prog->constants[n-F_MAX_OPCODE].type==T_FUNCTION && |
fp->context.prog->constants[n-F_MAX_OPCODE].subtype == FUNCTION_BUILTIN && |
fp->context.prog->constants[n-F_MAX_OPCODE].u.efun) |
{ |
return fp->context.prog->constants[n-F_MAX_OPCODE].u.efun->name->str; |
}else{ |
sprintf(buf, "Call efun %d", n - F_MAX_OPCODE); |
return buf; |
} |
}else{ |
sprintf(buf, "<OTHER %d>", n); |
return buf; |
} |
} |
|
char *get_token_name(int n) |
{ |
static char buf[30]; |
if (n<F_MAX_INSTR && instrs[n-F_OFFSET].name) |
{ |
return instrs[n-F_OFFSET].name; |
}else{ |
sprintf(buf, "<OTHER %d>", n); |
return buf; |
} |
} |
|
|
static int lookup_resword(struct pike_string *s) |
{ |
struct hash_entry *h; |
h=hash_lookup(reswords, s); |
if(!h) return -1; |
return BASEOF(h, reserved, link)->token; |
} |
|
|
|
|
struct inputstate |
{ |
struct inputstate *next; |
int fd; |
unsigned char *data; |
INT32 buflen; |
INT32 pos; |
int dont_free_data; |
|
int (*my_getc)(void); |
int (*gobble)(int); |
int (*look)(void); |
void (*my_ungetc)(int); |
void (*ungetstr)(char *,INT32); |
}; |
|
#define MY_EOF 4711 |
|
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->fd>=0) |
{ |
retry: |
if(close(i->fd)< 0) |
if(errno == EINTR) |
goto retry; |
} |
if(i->data && !i->dont_free_data) free(i->data); |
free_inputstate(i->next); |
free((char *)i); |
} |
|
static struct inputstate *new_inputstate(void); |
static struct inputstate *memory_inputstate(INT32 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,INT32 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 int default_look(void) |
{ |
int c; |
c=istate->my_getc(); |
istate->my_ungetc(c); |
return c; |
} |
|
static struct inputstate *new_inputstate(void) |
{ |
struct inputstate *i; |
i=(struct inputstate *)xalloc(sizeof(struct inputstate)); |
i->fd=-1; |
i->data=NULL; |
i->next=NULL; |
i->dont_free_data=0; |
i->gobble=default_gobble; |
i->ungetstr=default_ungetstr; |
i->my_ungetc=default_ungetc; |
i->look=default_look; |
return i; |
} |
|
|
static int end_getc(void) { return MY_EOF; } |
static int end_gobble(int c) { return c==MY_EOF; } |
static void end_ungetc(int c) |
{ |
if(c==MY_EOF) return; |
default_ungetc(c); |
} |
|
static struct inputstate *end_inputstate(void) |
{ |
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; |
} |
|
|
static void memory_ungetstr(char *s,INT32 len) |
{ |
INT32 tmp; |
tmp=MINIMUM(len,istate->pos); |
if(tmp) |
{ |
istate->pos -= tmp; |
MEMCPY(istate->data + istate->pos , s+len-tmp , tmp); |
len-=tmp; |
} |
if(len) default_ungetstr(s,len); |
} |
|
static void memory_ungetc(int s) |
{ |
if(istate->pos) |
{ |
istate->pos --; |
istate->data[istate->pos]=s; |
}else{ |
default_ungetc(s); |
} |
} |
|
static int memory_getc(void) |
{ |
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; |
if(!i->dont_free_data) free(i->data); |
free((char *)i); |
return istate->my_getc(); |
} |
} |
|
static int memory_look(void) |
{ |
if(istate->pos<istate->buflen) |
{ |
return istate->data[istate->pos]; |
}else{ |
struct inputstate *i; |
i=istate; |
istate=i->next; |
if(!i->dont_free_data) free(i->data); |
free((char *)i); |
return istate->look(); |
} |
} |
|
|
static struct inputstate *memory_inputstate(INT32 size) |
{ |
struct inputstate *i; |
if(!size) size=10000; |
i=new_inputstate(); |
i->data=(unsigned char *)xalloc(size); |
i->buflen=size; |
i->pos=size; |
i->ungetstr=memory_ungetstr; |
i->my_getc=memory_getc; |
i->look=memory_look; |
i->my_ungetc=memory_ungetc; |
return i; |
} |
|
static void prot_memory_ungetstr(char *s,INT32 len) |
{ |
INT32 tmp; |
tmp=MINIMUM(len,istate->pos); |
if(tmp) |
{ |
if(!MEMCMP(istate->data + istate->pos - tmp, s+len-tmp , tmp)) |
{ |
istate->pos-=tmp; |
len-=tmp; |
} |
} |
if(len) default_ungetstr(s,len); |
} |
|
static void prot_memory_ungetc(int s) |
{ |
if(istate->pos && istate->data[istate->pos-1] == s) |
{ |
istate->pos--; |
}else{ |
default_ungetc(s); |
} |
} |
|
|
static struct inputstate *prot_memory_inputstate(char *data,INT32 len) |
{ |
struct inputstate *i; |
i=new_inputstate(); |
i->data=(unsigned char *)data; |
i->buflen=len; |
i->dont_free_data=1; |
i->pos=0; |
i->my_getc=memory_getc; |
i->look=memory_look; |
i->ungetstr=prot_memory_ungetstr; |
i->my_ungetc=prot_memory_ungetc; |
return i; |
} |
|
|
|
#define READAHEAD 8192 |
static int file_getc(void) |
{ |
unsigned char buf[READAHEAD]; |
int got; |
do { |
got=read(istate->fd, buf, READAHEAD); |
if(got > 0) |
{ |
default_ungetstr((char *)buf, got); |
return istate->my_getc(); |
} |
else if(got==0 || errno != EINTR) |
{ |
struct inputstate *i; |
if(got<0 && errno != EINTR) |
my_yyerror("Lex: Read failed with error %d\n",errno); |
|
i=istate->next; |
close(istate->fd); |
free((char *)istate); |
istate=i; |
return istate->my_getc(); |
} |
}while(1); |
} |
|
static struct inputstate *file_inputstate(int fd) |
{ |
struct inputstate *i; |
i=new_inputstate(); |
i->fd=fd; |
i->my_getc=file_getc; |
return i; |
} |
|
static int GETC(void) |
{ |
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,INT32 len) |
{ |
INT32 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!=MY_EOF)); } |
#define SKIPUPTO(X) { int c; while((c=GETC())!=(X) && (c!=MY_EOF)); UNGETC(c); } |
#define READBUF(X) { \ |
register unsigned INT32 p; \ |
register int C; \ |
for(p=0;(C=GETC())!=MY_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]; |
|
|
|
struct define |
{ |
struct hash_entry link; |
void (*magic)(void); |
int args; |
struct array *parts; |
}; |
|
struct hash_table *defines = 0; |
|
#define find_define(N) (defines?BASEOF(hash_lookup(defines, N), define, link):0) |
|
|
static void undefine(struct pike_string *name) |
{ |
struct define *d; |
|
d=find_define(name); |
|
if(!d) return; |
|
defines=hash_unlink(defines, & d->link); |
free_string(d->link.s); |
free_array(d->parts); |
free((char *)d); |
} |
|
|
static void add_define(struct pike_string *name, |
int args, |
int parts_on_stack, |
void (*magic)(void)) |
{ |
struct define *d; |
|
f_aggregate(parts_on_stack); |
if(sp[-1].type != T_ARRAY) |
{ |
yyerror("Define failed for unknown reason.\n"); |
free_string(name); |
pop_stack(); |
return; |
} |
|
#if 0 |
if(find_define(name)) |
{ |
my_yyerror("Redefining '%s'",name->str); |
free_string(name); |
pop_stack(); |
return; |
} |
#else |
undefine(name); |
#endif |
|
d=(struct define *)xalloc(sizeof(struct define)); |
d->link.s=name; |
d->args=args; |
d->magic=magic; |
d->parts=sp[-1].u.array; |
sp--; |
|
defines=hash_insert(defines, & d->link); |
} |
|
static void simple_add_define(char *name,char *as,void (*magic)(void)) |
{ |
if(magic) |
{ |
add_define(make_shared_string(name),-1,0,magic); |
}else{ |
push_string(make_shared_string(as)); |
add_define(make_shared_string(name),-1,1,magic); |
} |
} |
|
void free_one_define(struct hash_entry *h) |
{ |
struct define *d; |
d=BASEOF(h, define, link); |
if(d->parts) free_array(d->parts); |
free((void *)d); |
} |
|
static void free_all_defines(void) |
{ |
if(defines) |
free_hashtable(defines, free_one_define); |
defines=0; |
} |
|
static void do_define(void) |
{ |
int c,e,t,argc; |
struct svalue *save_sp=sp; |
struct svalue *args_sp; |
struct pike_string *s, *s2; |
|
SKIPWHITE(); |
READBUF(isidchar(C)); |
|
s=make_shared_string(buf); |
|
if(GOBBLE('(')) |
{ |
argc=0; |
|
SKIPWHITE(); |
READBUF(isidchar(C)); |
if(buf[0]) |
{ |
push_string(make_shared_string(buf)); |
argc++; |
SKIPWHITE(); |
while(GOBBLE(',')) |
{ |
SKIPWHITE(); |
READBUF(isidchar(C)); |
push_string(make_shared_string(buf)); |
argc++; |
} |
} |
SKIPWHITE(); |
|
if(!GOBBLE(')')) |
yyerror("Missing ')'"); |
}else{ |
argc=-1; |
} |
|
args_sp=sp; |
|
init_buf(); |
t=0; |
sp->type=T_STRING; |
sp->u.string=make_shared_string(""); |
sp++; |
|
while(1) |
{ |
int tmp; |
|
c=GETC(); |
if(c=='\\') if(GOBBLE('\n')) continue; |
if( (t!=!!isidchar(c) && argc>0) || c=='\n' || c==MY_EOF) |
{ |
s2=free_buf(); |
tmp=0; |
for(e=0;e<argc;e++) |
{ |
if(save_sp[e].u.string==s2) |
{ |
free_string(s2); |
push_int(e); |
tmp=1; |
break; |
} |
} |
if(!tmp) |
{ |
push_string(s2); |
if(sp[-2].type==T_STRING) f_add(2); |
} |
if(c=='\n' || c==MY_EOF) |
{ |
push_string(make_shared_string(" ")); |
if(sp[-2].type==T_STRING) f_add(2); |
break; |
} |
t=!!isidchar(c); |
init_buf(); |
} |
my_putchar(c); |
} |
UNGETC(c); |
add_define(s,argc,sp-args_sp,0); |
while(sp>save_sp) pop_stack(); |
} |
|
|
static int expand_define(struct pike_string *s, int save_newline) |
{ |
struct svalue *save_sp=sp; |
struct define *d; |
int len,e,tmp,args; |
d=find_define(s); |
if(!d) return 0; |
|
if(nexpands>EXPANDMAX) |
{ |
yyerror("Macro limit exceeded."); |
return 0; |
} |
|
if(d->magic) |
{ |
d->magic(); |
return 1; |
} |
|
if(d->args >= 0) |
{ |
if(!save_newline) |
{ |
SKIPWHITE(); |
}else{ |
do { e=GETC(); }while(ISSPACE(e) && e!='\n'); |
UNGETC(e); |
} |
|
if(GOBBLE('(')) |
{ |
int parlvl,quote; |
int c; |
args=0; |
|
SKIPWHITE(); |
init_buf(); |
parlvl=1; |
quote=0; |
while(parlvl) |
{ |
switch(c=GETC()) |
{ |
case MY_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_string(free_buf()); |
init_buf(); |
args++; |
continue; |
} |
} |
if(parlvl) my_putchar(c); |
} |
push_string(free_buf()); |
if(args==0 && !d->args && !sp[-1].u.string->len) |
{ |
pop_stack(); |
}else{ |
args++; |
} |
}else{ |
args=0; |
} |
} else { |
args=-1; |
} |
|
if(args>d->args) |
{ |
my_yyerror("Too many arguments to macro '%s'.\n",s->str); |
while(sp>save_sp) pop_stack(); |
return 0; |
} |
|
if(args<d->args) |
{ |
my_yyerror("Too few arguments to macro '%s'.\n",s->str); |
while(sp>save_sp) pop_stack(); |
return 0; |
} |
len=0; |
for(e=d->parts->size-1;e>=0;e--) |
{ |
switch(ITEM(d->parts)[e].type) |
{ |
case T_STRING: |
tmp=ITEM(d->parts)[e].u.string->len; |
UNGETSTR(ITEM(d->parts)[e].u.string->str,tmp); |
break; |
|
case T_INT: |
tmp=save_sp[ITEM(d->parts)[e].u.integer].u.string->len; |
UNGETSTR(save_sp[ITEM(d->parts)[e].u.integer].u.string->str,tmp); |
break; |
|
default: tmp=0; |
} |
len+=tmp; |
} |
while(sp>save_sp) pop_stack(); |
nexpands+=len; |
return 1; |
} |
|
|
|
static void handle_include(char *name, int local_include) |
{ |
int fd; |
char buf[400]; |
struct pike_string *s; |
|
s=make_shared_string(name); |
push_string(s); |
reference_shared_string(s); |
push_string(current_file); |
reference_shared_string(current_file); |
push_int(local_include); |
|
SAFE_APPLY_MASTER("handle_include",3); |
|
if(sp[-1].type != T_STRING) |
{ |
my_yyerror("Couldn't include file '%s'.",s->str); |
return; |
} |
free_string(s); |
|
retry: |
fd=open(sp[-1].u.string->str,O_RDONLY); |
if(fd < 0) |
{ |
if(errno == EINTR) goto retry; |
|
#ifdef HAVE_STRERROR |
my_yyerror("Couldn't open file to include '%s'. (%s)",sp[-1].u.string->str,strerror(errno)); |
#else |
my_yyerror("Couldn't open file to include '%s'. (ERRNO=%d)",sp[-1].u.string->str,errno); |
#endif |
return; |
} |
|
UNGETSTR("\" 2",3); |
UNGETSTR(current_file->str,current_file->len); |
sprintf(buf,"\n# %ld \"",(long)current_line+1); |
UNGETSTR(buf,strlen(buf)); |
|
total_lines+=current_line-old_line; |
old_line=current_line=1; |
free_string(current_file); |
current_file=sp[-1].u.string; |
sp--; |
link_inputstate(file_inputstate(fd)); |
UNGETSTR("\n",1); |
} |
|
|
|
static int char_const(void) |
{ |
int c; |
switch(c=GETC()) |
{ |
case 'x': |
switch(LOOK()) |
{ |
default: return c; |
case '0': case '1': case '2': case '3': |
case '4': case '5': case '6': case '7': |
case '8': case '9': |
c=GETC()-'0'; |
break; |
|
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': |
c=GETC()-'a'+10; |
break; |
|
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': |
c=GETC()-'A'+10; |
break; |
} |
switch(LOOK()) |
{ |
default: return c; |
case '0': case '1': case '2': case '3': |
case '4': case '5': case '6': case '7': |
case '8': case '9': |
c=c*16+GETC()-'0'; |
break; |
|
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': |
c=c*16+GETC()-'a'+10; |
break; |
|
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': |
c=c*16+GETC()-'a'+10; |
break; |
} |
return c; |
|
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; |
} |
|
#define SKIPTO_ENDIF 1 |
#define SKIPTO_ELSE 2 |
|
static void do_skip(int to) |
{ |
int lvl; |
#if LEXDEBUG>3 |
fprintf(stderr,"Skipping from %ld to ",(long)current_line); |
#endif |
lvl=1; |
while(lvl) |
{ |
switch(GETC()) |
{ |
case '/': |
if(GOBBLE('*')) |
{ |
do{ |
SKIPTO('*'); |
if(LOOK()==MY_EOF) |
{ |
yyerror("Unexpected end of file while skipping comment."); |
return; |
} |
}while(!GOBBLE('/')); |
} |
continue; |
|
case MY_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 'l': |
if(strcmp("line",buf)) break; |
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': |
SKIPWHITE(); |
READBUF(C!='\n'); |
if(buf[0]=='"' && |
buf[strlen(buf)-1]=='2' && |
ISSPACE(buf[strlen(buf)-2])) |
{ |
if(lvl) |
{ |
yyerror("Unterminated '#if' conditional."); |
num_parse_error+=1000; |
} |
} |
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--; |
if(lvl<0) |
{ |
yyerror("Unbalanced '#endif'\n"); |
lvl=0; |
} |
continue; |
} |
if(!strcmp("else",buf)) |
{ |
if(lvl==1 && to==SKIPTO_ELSE) lvl=0; |
continue; |
} |
if(!strcmp("elif",buf) || !strcmp("elseif",buf)) |
{ |
if(lvl==1 && to==SKIPTO_ELSE && calc()) lvl--; |
continue; |
} |
if(!strcmp("error",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; |
} |
|
my_yyerror("Unknown directive #%s.",buf); |
SKIPUPTO('\n'); |
continue; |
} |
} |
} |
#if LEXDEBUG>3 |
fprintf(stderr,"%ld in %s.\n",(long)current_line,current_file->str); |
#endif |
} |
|
static int do_lex(int literal, YYSTYPE *yylval) |
#if LEXDEBUG>4 |
{ |
int t; |
int do_lex2(int literal, YYSTYPE *yylval); |
t=do_lex2(literal, yylval); |
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, YYSTYPE *yylval) |
#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; |
free_string(current_file); |
current_file=make_shared_string(p); |
} |
} |
break; |
|
case 'i': |
if(!strcmp("include",buf)) |
{ |
SKIPWHITE(); |
c=do_lex(1, yylval); |
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, c==F_STRING); |
break; |
} |
|
if(!strcmp("if",buf)) |
{ |
if(!calc()) do_skip(SKIPTO_ELSE); |
break; |
} |
|
if(!strcmp("ifdef",buf)) |
{ |
struct pike_string *s; |
SKIPWHITE(); |
READBUF(isidchar(C)); |
s=findstring(buf); |
if(!s || !find_define(s)) do_skip(SKIPTO_ELSE); |
break; |
} |
|
if(!strcmp("ifndef",buf)) |
{ |
struct pike_string *s; |
SKIPWHITE(); |
READBUF(isidchar(C)); |
s=findstring(buf); |
if(s && find_define(s)) do_skip(SKIPTO_ELSE); |
break; |
} |
goto badhash; |
|
case 'e': |
if(!strcmp("endif",buf)) break; |
if(!strcmp("else",buf)) |
{ |
SKIPUPTO('\n'); |
do_skip(SKIPTO_ENDIF); |
break; |
} |
if(!strcmp("elif",buf) || !strcmp("elseif",buf)) |
{ |
SKIPUPTO('\n'); |
do_skip(SKIPTO_ENDIF); |
break; |
} |
if(!strcmp("error",buf)) |
{ |
SKIPWHITE(); |
READBUF(C!='\n'); |
yyerror(buf); |
break; |
} |
goto badhash; |
|
case 'u': |
if(!strcmp("undef",buf)) |
{ |
struct pike_string *s; |
SKIPWHITE(); |
READBUF(isidchar(C)); |
if((s=findstring(buf))) undefine(s); |
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, "all_inline") == 0) |
{ |
pragma_all_inline = 1; |
} |
break; |
} |
|
badhash: |
my_yyerror("Unknown directive #%s.",buf); |
SKIPUPTO('\n'); |
continue; |
|
} |
} |
continue; |
|
case ' ': |
case '\t': |
continue; |
|
case MY_EOF: |
return 0; |
|
case '\'': |
c=GETC(); |
if(c=='\\') c=char_const(); |
if(GETC()!='\'') |
yyerror("Unterminated character constant."); |
yylval->number=c; |
return F_NUMBER; |
|
case '"': |
init_buf(); |
while(1) |
{ |
c=GETC(); |
|
switch(c) |
{ |
case MY_EOF: |
yyerror("End of file in string."); |
free(simple_free_buf()); |
return 0; |
|
case '\n': |
yyerror("Newline in string."); |
free(simple_free_buf()); |
return 0; |
|
case '\\': |
my_putchar(char_const()); |
continue; |
|
case '"': |
break; |
|
default: |
my_putchar(c); |
continue; |
} |
break; |
} |
if(literal) |
{ |
strncpy(buf,return_buf(),sizeof(buf)); |
buf[sizeof(buf)-1]=0; |
yylval->str=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, *p2; |
int isfloat=0; |
double d; |
|
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,'.'))) |
{ |
isfloat=1; |
} |
} |
|
d=STRTOD(buf, NULL); |
|
if(GOBBLE('e') || GOBBLE('E')) |
{ |
int neg; |
if(GOBBLE('-')) |
neg=1; |
else if(GOBBLE('+')) |
neg=0; |
else |
neg=0; |
|
READBUF(isdigit(C)); |
if(neg) |
d /= pow(10.0,STRTOD(buf,NULL)); |
else |
d *= pow(10.0,STRTOD(buf,NULL)); |
isfloat=1; |
} |
if(isfloat) |
{ |
yylval->fnum=(float)d; |
return F_FLOAT; |
} |
|
if(buf[0]=='0') |
yylval->number=STRTOL(buf,NULL,8); |
else |
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('*'); |
if(LOOK()==MY_EOF) |
{ |
yyerror("Unexpected end of file while skipping comment."); |
return 0; |
} |
} 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_MULTISET_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 '(': |
if(GOBBLE('<')) return F_MULTISET_START; |
return '('; |
|
case '?': |
case ',': |
case '~': |
case '@': |
case ')': |
case '[': |
case ']': |
case '{': |
case ';': |
case '}': return c; |
|
case '`': |
{ |
char *tmp; |
int offset=2; |
if(GOBBLE('`')) offset--; |
if(GOBBLE('`')) offset--; |
|
switch(GETC()) |
{ |
case '+': tmp="```+"; break; |
case '/': tmp="```/"; break; |
case '%': tmp="```%"; break; |
case '*': tmp="```*"; break; |
case '&': tmp="```&"; break; |
case '|': tmp="```|"; break; |
case '^': tmp="```^"; break; |
case '~': tmp="```~"; break; |
case '<': |
if(GOBBLE('<')) { tmp="```<<"; break; } |
if(GOBBLE('=')) { tmp="```<="; break; } |
tmp="```<"; |
break; |
|
case '>': |
if(GOBBLE('>')) { tmp="```>>"; break; } |
if(GOBBLE('=')) { tmp="```>="; break; } |
tmp="```>"; |
break; |
|
case '!': |
if(GOBBLE('=')) { tmp="```!="; break; } |
tmp="```!"; |
break; |
|
case '=': |
if(GOBBLE('=')) { tmp="```=="; break; } |
tmp="```="; |
break; |
|
case '(': |
if(GOBBLE(')')) |
{ |
tmp="```()"; |
break; |
} |
yyerror("Illegal ` identifier."); |
tmp="``"; |
break; |
|
case '-': |
if(GOBBLE('>')) |
{ |
tmp="```->"; |
if(GOBBLE('=')) tmp="```->="; |
}else{ |
tmp="```-"; |
} |
break; |
|
case '[': |
if(GOBBLE(']')) |
{ |
tmp="```[]"; |
if(GOBBLE('=')) tmp="```[]="; |
break; |
} |
|
default: |
yyerror("Illegal ` identifier."); |
tmp="``"; |
break; |
|
} |
|
if(literal) |
{ |
yylval->str=tmp+offset; |
}else{ |
yylval->string=make_shared_string(tmp+offset); |
} |
return F_IDENTIFIER; |
} |
|
|
default: |
if(isidchar(c)) |
{ |
struct pike_string *s; |
UNGETC(c); |
READBUF(isidchar(C)); |
|
if(!literal) |
{ |
|
|
|
|
|
s=findstring(buf); |
if(s) |
{ |
int i; |
if(expand_define(s,0)) continue; |
|
i=lookup_resword(s); |
if(i >= 0) |
{ |
yylval->number=current_line; |
return i; |
} |
|
reference_shared_string(s); |
}else{ |
s=make_shared_string(buf); |
} |
yylval->string=s; |
return F_IDENTIFIER; |
} |
|
yylval->str=buf; |
return F_IDENTIFIER; |
}else{ |
char buff[100]; |
sprintf(buff, "Illegal character (hex %02x) '%c'", c, c); |
yyerror(buff); |
return ' '; |
} |
} |
} |
} |
|
int yylex(YYSTYPE *yylval) |
{ |
#ifdef __CHECKER__ |
MEMSET((char *)yylval,0,sizeof(YYSTYPE)); |
#endif |
return do_lex(0, yylval); |
} |
|
static YYSTYPE my_yylval; |
static int lookahead; |
|
static void low_lex(void) |
{ |
while(1) |
{ |
struct pike_string *s; |
|
lookahead=do_lex(1, &my_yylval); |
if(lookahead == F_IDENTIFIER) |
{ |
if(!strcmp("defined",my_yylval.str)) |
{ |
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",my_yylval.str) || !strcmp("constant",my_yylval.str)) |
{ |
volatile int res = 0; |
struct svalue *oldsp = sp; |
struct svalue *sv; |
|
SKIPWHITE(); |
if (!GOBBLE('(')) { |
yyerror("Missing '(' in #if constant().\n"); |
return; |
} |
READBUF(isidchar(C)); |
|
push_text(buf); |
if ((sv = low_mapping_string_lookup(get_builtin_constants(), |
sp[-1].u.string))) { |
pop_stack(); |
push_svalue(sv); |
res = 1; |
} else if (get_master()) { |
current_file->refs++; |
push_string(current_file); |
|
SAFE_APPLY_MASTER("resolv", 2); |
|
if ((throw_value.type != T_STRING) && |
(!(IS_ZERO(sp-1) && sp[-1].subtype == 1))) { |
res = 1; |
} |
} |
|
while(GOBBLE('.')) { |
READBUF(isidchar(C)); |
if (res) { |
JMP_BUF recovery; |
|
push_text(buf); |
|
free_svalue(&throw_value); |
throw_value.type = T_INT; |
|
if (SETJMP(recovery)) { |
res = 0; |
} else { |
f_index(2); |
if (IS_ZERO(sp-1) && sp[-1].subtype == 1) { |
res = 0; |
} |
} |
UNSETJMP(recovery); |
} |
} |
|
if (!GOBBLE(')')) { |
yyerror("Missing ')' in #if constant().\n"); |
return; |
} |
|
if (sp > oldsp) { |
pop_n_elems(sp - oldsp); |
} |
|
if (res) { |
UNGETSTR(" 1 ", 3); |
} else { |
UNGETSTR(" 0 ", 3); |
} |
continue; |
} |
|
s=findstring(my_yylval.str); |
if(!s || !expand_define(s,1)) |
UNGETSTR(" 0 ",3); |
continue; |
} |
|
break; |
} |
} |
|
static void calcC(void) |
{ |
switch(lookahead) |
{ |
case '(': |
low_lex(); |
calc1(); |
if(lookahead != ')') |
error("Missing ')'\n"); |
break; |
|
case F_FLOAT: |
push_float(my_yylval.fnum); |
break; |
|
case F_STRING: |
push_string(make_shared_string(my_yylval.str)); |
break; |
|
case F_NUMBER: |
push_int(my_yylval.number); |
break; |
|
default: |
push_int(0); |
yyerror("Syntax error in #if."); |
return; |
} |
|
low_lex(); |
|
while(lookahead=='[') |
{ |
low_lex(); |
calc1(); |
f_index(2); |
if(lookahead!=']') |
error("Missing ']'\n"); |
else |
low_lex(); |
} |
} |
|
static void calcB(void) |
{ |
switch(lookahead) |
{ |
case '-': low_lex(); calcB(); o_negate(); break; |
case F_NOT: low_lex(); calcB(); o_not(); break; |
case '~': low_lex(); calcB(); o_compl(); break; |
default: calcC(); |
} |
} |
|
static void calcA(void) |
{ |
calcB(); |
while(1) |
{ |
switch(lookahead) |
{ |
case '/': low_lex(); calcB(); o_divide(); continue; |
case '*': low_lex(); calcB(); o_multiply(); continue; |
case '%': low_lex(); calcB(); o_mod(); continue; |
} |
break; |
} |
} |
|
static void calc9(void) |
{ |
calcA(); |
|
while(1) |
{ |
switch(lookahead) |
{ |
case '+': low_lex(); calcA(); f_add(2); continue; |
case '-': low_lex(); calcA(); o_subtract(); continue; |
} |
break; |
} |
} |
|
static void calc8(void) |
{ |
calc9(); |
|
while(1) |
{ |
switch(lookahead) |
{ |
case F_LSH: low_lex(); calc9(); o_lsh(); continue; |
case F_RSH: low_lex(); calc9(); o_rsh(); continue; |
} |
break; |
} |
} |
|
static void calc7b(void) |
{ |
calc8(); |
|
while(1) |
{ |
switch(lookahead) |
{ |
case '<': low_lex(); calc8(); f_lt(2); continue; |
case '>': low_lex(); calc8(); f_gt(2); continue; |
case F_GE: low_lex(); calc8(); f_ge(2); continue; |
case F_LE: low_lex(); calc8(); f_le(2); continue; |
} |
break; |
} |
} |
|
static void calc7(void) |
{ |
calc7b(); |
|
while(1) |
{ |
switch(lookahead) |
{ |
case F_EQ: low_lex(); calc7b(); f_eq(2); continue; |
case F_NE: low_lex(); calc7b(); f_ne(2); continue; |
} |
break; |
} |
} |
|
static void calc6(void) |
{ |
calc7(); |
|
while(lookahead=='&') |
{ |
low_lex(); |
calc7(); |
o_and(); |
} |
} |
|
static void calc5(void) |
{ |
calc6(); |
|
while(lookahead=='^') |
{ |
low_lex(); |
calc6(); |
o_xor(); |
} |
} |
|
static void calc4(void) |
{ |
calc5(); |
|
while(lookahead=='|') |
{ |
low_lex(); |
calc5(); |
o_or(); |
} |
} |
|
static void calc3(void) |
{ |
calc4(); |
|
while(lookahead==F_LAND) |
{ |
low_lex(); |
check_destructed(sp-1); |
if(IS_ZERO(sp-1)) |
{ |
calc4(); |
pop_stack(); |
}else{ |
pop_stack(); |
calc4(); |
} |
} |
} |
|
static void calc2(void) |
{ |
calc3(); |
|
while(lookahead==F_LOR) |
{ |
low_lex(); |
check_destructed(sp-1); |
if(!IS_ZERO(sp-1)) |
{ |
calc3(); |
pop_stack(); |
}else{ |
pop_stack(); |
calc3(); |
} |
} |
} |
|
static void calc1(void) |
{ |
calc2(); |
|
if(lookahead=='?') |
{ |
low_lex(); |
calc1(); |
if(lookahead!=':') |
error("Colon expected.\n"); |
low_lex(); |
calc1(); |
|
check_destructed(sp-3); |
assign_svalue(sp-3,IS_ZERO(sp-3)?sp-1:sp-2); |
pop_n_elems(2); |
} |
|
} |
|
static int calc(void) |
{ |
JMP_BUF recovery; |
int ret; |
|
ret=0; |
if (SETJMP(recovery)) |
{ |
if(throw_value.type == T_ARRAY && throw_value.u.array->size) |
{ |
union anything *a; |
a=low_array_get_item_ptr(throw_value.u.array, 0, T_STRING); |
if(a) |
{ |
yyerror(a->string->str); |
}else{ |
yyerror("Nonstandard error format.\n"); |
} |
}else{ |
yyerror("Nonstandard error format.\n"); |
} |
ret=-1; |
}else{ |
low_lex(); |
calc1(); |
if(lookahead!='\n') |
{ |
SKIPUPTO('\n'); |
yyerror("Extra characters after #if expression."); |
}else{ |
UNGETC('\n'); |
} |
check_destructed(sp-1); |
ret=!IS_ZERO(sp-1); |
pop_stack(); |
} |
UNSETJMP(recovery); |
|
return ret; |
} |
|
|
void insert_current_line(void) |
{ |
char buf[20]; |
sprintf(buf," %ld ",(long)current_line); |
UNGETSTR(buf,strlen(buf)); |
} |
|
void insert_current_file_as_string(void) |
{ |
UNGETSTR("\"",1); |
UNGETSTR(current_file->str, current_file->len); |
UNGETSTR("\"",1); |
} |
|
void insert_current_time_as_string(void) |
{ |
time_t tmp; |
char *buf; |
time(&tmp); |
buf=ctime(&tmp); |
|
UNGETSTR("\"",1); |
UNGETSTR(buf+11, 8); |
UNGETSTR("\"",1); |
} |
|
void insert_current_date_as_string(void) |
{ |
time_t tmp; |
char *buf; |
time(&tmp); |
buf=ctime(&tmp); |
|
UNGETSTR("\"",1); |
UNGETSTR(buf+19, 5); |
UNGETSTR(buf+4, 6); |
UNGETSTR("\"",1); |
} |
|
|
|
static void start_new(void) |
{ |
struct pike_predef_s *tmpf; |
|
free_all_defines(); |
|
simple_add_define("__PIKE__", "1",0); |
|
for (tmpf=pike_predefs; tmpf; tmpf=tmpf->next) |
simple_add_define(tmpf->name, tmpf->value,0); |
|
simple_add_define("__LINE__",0,insert_current_line); |
simple_add_define("__FILE__",0,insert_current_file_as_string); |
simple_add_define("__DATE__",0,insert_current_date_as_string); |
simple_add_define("__TIME__",0,insert_current_time_as_string); |
|
free_inputstate(istate); |
istate=NULL; |
link_inputstate(end_inputstate()); |
old_line=current_line = 1; |
pragma_all_inline=0; |
nexpands=0; |
if(current_file) free_string(current_file); |
current_file=0; |
} |
|
void start_new_file(int fd,struct pike_string *filename) |
{ |
start_new(); |
copy_shared_string(current_file,filename); |
|
link_inputstate(file_inputstate(fd)); |
UNGETSTR("\n",1); |
} |
|
void start_new_string(char *s,INT32 len,struct pike_string *name) |
{ |
start_new(); |
copy_shared_string(current_file,name); |
link_inputstate(prot_memory_inputstate(s,len)); |
UNGETSTR("\n",1); |
} |
|
void end_new_file(void) |
{ |
if(current_file) |
{ |
free_string(current_file); |
current_file=0; |
} |
|
free_inputstate(istate); |
istate=NULL; |
free_all_defines(); |
total_lines+=current_line-old_line; |
} |
|
|
void add_predefine(char *s) |
{ |
char buffer1[100],buffer2[10000]; |
struct pike_predef_s *tmp; |
|
if(sscanf(s,"%[^=]=%[ -~=]",buffer1,buffer2) ==2) |
{ |
s=buffer1; |
}else{ |
buffer2[0]='1'; |
buffer2[1]=0; |
} |
tmp=ALLOC_STRUCT(pike_predef_s); |
tmp->name=(char *)xalloc(strlen(s)+1); |
strcpy(tmp->name,s); |
tmp->value=(char *)xalloc(strlen(buffer2)+1); |
strcpy(tmp->value,buffer2); |
tmp->next=pike_predefs; |
pike_predefs=tmp; |
} |
|
|