cb22561995-10-11Fredrik Hübinette (Hubbe) /*\
06983f1996-09-22Fredrik Hübinette (Hubbe) ||| This file a part of Pike, and is copyright by Fredrik Hubinette ||| Pike is distributed as GPL (General Public License)
cb22561995-10-11Fredrik Hübinette (Hubbe) ||| See the files COPYING and DISCLAIMER for more information. \*/
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "global.h"
dc7cc91998-01-14Fredrik Hübinette (Hubbe) RCSID("$Id: las.c,v 1.41 1998/01/15 05:59:41 hubbe Exp $");
419ede1996-11-13Fredrik Hübinette (Hubbe) 
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "language.h" #include "interpret.h" #include "las.h" #include "array.h" #include "object.h" #include "stralloc.h" #include "dynamic_buffer.h" #include "lex.h"
06983f1996-09-22Fredrik Hübinette (Hubbe) #include "pike_types.h" #include "constants.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "mapping.h"
06983f1996-09-22Fredrik Hübinette (Hubbe) #include "multiset.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "error.h" #include "docode.h" #include "main.h"
9aa6fa1997-05-19Fredrik Hübinette (Hubbe) #include "pike_memory.h"
6891181996-08-06Fredrik Hübinette (Hubbe) #include "operators.h"
a29e021996-10-15Fredrik Hübinette (Hubbe) #include "callback.h"
bb55f81997-03-16Fredrik Hübinette (Hubbe) #include "pike_macros.h"
9c6f7d1997-04-15Fredrik Hübinette (Hubbe) #include "peep.h"
5267b71995-08-09Fredrik Hübinette (Hubbe)  #define LASDEBUG int lasdebug=0; static node *eval(node *); static void optimize(node *n); node *init_node = 0; int num_parse_error;
c3c7031996-12-04Fredrik Hübinette (Hubbe) int cumulative_parse_error=0;
5267b71995-08-09Fredrik Hübinette (Hubbe) extern char *get_type_name(int);
e82b301997-01-29Fredrik Hübinette (Hubbe) #define MAX_GLOBAL 2048
5267b71995-08-09Fredrik Hübinette (Hubbe)  int car_is_node(node *n) { switch(n->token) {
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  case F_EXTERNAL:
5267b71995-08-09Fredrik Hübinette (Hubbe)  case F_IDENTIFIER: case F_CONSTANT: case F_LOCAL: return 0; default: return !!CAR(n); } } int cdr_is_node(node *n) { switch(n->token) {
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  case F_EXTERNAL:
5267b71995-08-09Fredrik Hübinette (Hubbe)  case F_IDENTIFIER: case F_CONSTANT: case F_LOCAL: case F_CAST: return 0; default: return !!CDR(n); } } INT32 count_args(node *n) {
7bd0ea1996-02-19Fredrik Hübinette (Hubbe)  int a,b;
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(!n) return 0; switch(n->token) { case F_VAL_LVAL: case F_ARG_LIST:
7bd0ea1996-02-19Fredrik Hübinette (Hubbe)  a=count_args(CAR(n)); if(a==-1) return -1; b=count_args(CDR(n)); if(b==-1) return -1; return a+b;
5267b71995-08-09Fredrik Hübinette (Hubbe)  case F_CAST: if(n->type == void_type_string) return 0; else return count_args(CAR(n)); case F_CASE: case F_FOR: case F_DO: case F_INC_LOOP: case F_DEC_LOOP: case F_DEC_NEQ_LOOP: case F_INC_NEQ_LOOP: case F_BREAK: case F_RETURN: case F_CONTINUE: case F_FOREACH: return 0; case '?': { int tmp1,tmp2;
e260681996-04-11Fredrik Hübinette (Hubbe)  tmp1=count_args(CADR(n)); tmp2=count_args(CDDR(n));
7bd0ea1996-02-19Fredrik Hübinette (Hubbe)  if(tmp1==-1 || tmp2==-2) return -1;
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(tmp1 < tmp2) return tmp1; return tmp2; }
b95bef1996-03-29Fredrik Hübinette (Hubbe)  case F_PUSH_ARRAY: return -1;
5267b71995-08-09Fredrik Hübinette (Hubbe)  default: if(n->type == void_type_string) return 0; return 1; } }
a8ef6e1996-12-03Fredrik Hübinette (Hubbe)  #define NODES 256 struct node_chunk { struct node_chunk *next; node nodes[NODES]; }; static struct node_chunk *node_chunks=0; static node *free_nodes=0;
b1f4eb1998-01-13Fredrik Hübinette (Hubbe) void free_all_nodes()
a8ef6e1996-12-03Fredrik Hübinette (Hubbe) {
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  if(!compiler_frame)
a8ef6e1996-12-03Fredrik Hübinette (Hubbe)  { node *tmp; struct node_chunk *tmp2; int e=0;
c3c7031996-12-04Fredrik Hübinette (Hubbe)  if(cumulative_parse_error)
a8ef6e1996-12-03Fredrik Hübinette (Hubbe)  {
c3c7031996-12-04Fredrik Hübinette (Hubbe)  for(tmp2=node_chunks;tmp2;tmp2=tmp2->next) e+=NODES; for(tmp=free_nodes;tmp;tmp=CAR(tmp)) e--; if(e)
a8ef6e1996-12-03Fredrik Hübinette (Hubbe)  {
c3c7031996-12-04Fredrik Hübinette (Hubbe)  int e2=e; for(tmp2=node_chunks;tmp2;tmp2=tmp2->next)
a8ef6e1996-12-03Fredrik Hübinette (Hubbe)  {
c3c7031996-12-04Fredrik Hübinette (Hubbe)  for(e=0;e<NODES;e++) { for(tmp=free_nodes;tmp;tmp=CAR(tmp)) if(tmp==tmp2->nodes+e) break; if(!tmp) { tmp=tmp2->nodes+e; #ifdef DEBUG if(!cumulative_parse_error) { fprintf(stderr,"Free node at %p.\n",tmp); } else #endif { /* Free the node and be happy */ /* Make sure we don't free any nodes twice */ if(car_is_node(tmp)) CAR(tmp)=0; if(cdr_is_node(tmp)) CDR(tmp)=0; free_node(tmp); } } }
a8ef6e1996-12-03Fredrik Hübinette (Hubbe)  }
c3c7031996-12-04Fredrik Hübinette (Hubbe) #ifdef DEBUG if(!cumulative_parse_error) fatal("Failed to free %d nodes when compiling!\n",e2); #endif
a8ef6e1996-12-03Fredrik Hübinette (Hubbe)  } } while(node_chunks) { tmp2=node_chunks; node_chunks=tmp2->next; free((char *)tmp2); } free_nodes=0;
c3c7031996-12-04Fredrik Hübinette (Hubbe)  cumulative_parse_error=0;
a8ef6e1996-12-03Fredrik Hübinette (Hubbe)  } }
5267b71995-08-09Fredrik Hübinette (Hubbe) void free_node(node *n) { if(!n) return; switch(n->token) {
a8ef6e1996-12-03Fredrik Hübinette (Hubbe)  case USHRT_MAX: fatal("Freeing node again!\n"); break;
5267b71995-08-09Fredrik Hübinette (Hubbe)  case F_CONSTANT: free_svalue(&(n->u.sval)); break; default: if(car_is_node(n)) free_node(CAR(n)); if(cdr_is_node(n)) free_node(CDR(n)); }
a8ef6e1996-12-03Fredrik Hübinette (Hubbe)  n->token=USHRT_MAX; if(n->type) free_string(n->type); CAR(n)=free_nodes; free_nodes=n;
5267b71995-08-09Fredrik Hübinette (Hubbe) } /* here starts routines to make nodes */
be478c1997-08-30Henrik Grubbström (Grubba) static node *mkemptynode(void)
5267b71995-08-09Fredrik Hübinette (Hubbe) { node *res;
a8ef6e1996-12-03Fredrik Hübinette (Hubbe)  if(!free_nodes) { int e; struct node_chunk *tmp=ALLOC_STRUCT(node_chunk); tmp->next=node_chunks; node_chunks=tmp; for(e=0;e<NODES-1;e++) CAR(tmp->nodes+e)=tmp->nodes+e+1; CAR(tmp->nodes+e)=0; free_nodes=tmp->nodes; } res=free_nodes; free_nodes=CAR(res); res->token=0;
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  res->line_number=lex.current_line;
5267b71995-08-09Fredrik Hübinette (Hubbe)  res->type=0; res->node_info=0; res->tree_info=0; res->parent=0; return res; } node *mknode(short token,node *a,node *b) { node *res; res = mkemptynode(); CAR(res) = a; CDR(res) = b; res->node_info = 0; res->tree_info = 0; switch(token) { case F_CATCH: res->node_info |= OPT_SIDE_EFFECT; break; case F_APPLY:
d334771996-04-13Fredrik Hübinette (Hubbe)  if(a && a->token == F_CONSTANT && a->u.sval.type == T_FUNCTION &&
bdb5091996-09-25Fredrik Hübinette (Hubbe)  a->u.sval.subtype == FUNCTION_BUILTIN)
e260681996-04-11Fredrik Hübinette (Hubbe)  { res->node_info |= a->u.sval.u.efun->flags; }else{ res->node_info |= OPT_SIDE_EFFECT | OPT_EXTERNAL_DEPEND; /* for now */ }
5267b71995-08-09Fredrik Hübinette (Hubbe)  break;
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  case F_UNDEFINED: res->node_info |= OPT_EXTERNAL_DEPEND | OPT_SIDE_EFFECT; break;
5267b71995-08-09Fredrik Hübinette (Hubbe)  case F_RETURN: res->node_info |= OPT_RETURN; break; case F_BREAK: res->node_info |= OPT_BREAK; break; case F_CONTINUE: res->node_info |= OPT_CONTINUE; break; case F_DEFAULT: case F_CASE: res->node_info |= OPT_CASE; break; case F_SSCANF: if(!b || count_args(b) == 0) break; /* fall through */ case F_ASSIGN: case F_INC: case F_DEC: case F_POST_INC: case F_POST_DEC: res->node_info |= OPT_ASSIGNMENT; } res->token = token; res->type = 0; /* We try to optimize most things, but argument lists are hard... */ if(token != F_ARG_LIST && (a || b)) res->node_info |= OPT_TRY_OPTIMIZE; if(a) a->parent = res; if(b) b->parent = res;
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  if(!num_parse_error && compiler_pass==2) optimize(res);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
66d51c1997-03-04Fredrik Hübinette (Hubbe) #ifdef DEBUG if(d_flag > 3) verify_shared_strings_tables(); #endif
5267b71995-08-09Fredrik Hübinette (Hubbe)  return res; }
06983f1996-09-22Fredrik Hübinette (Hubbe) node *mkstrnode(struct pike_string *str)
5267b71995-08-09Fredrik Hübinette (Hubbe) { node *res = mkemptynode(); res->token = F_CONSTANT; copy_shared_string(res->type, string_type_string); res->node_info = 0; res->u.sval.type = T_STRING; #ifdef __CHECKER__ res->u.sval.subtype = 0; #endif copy_shared_string(res->u.sval.u.string, str); return res; } node *mkintnode(int nr) { node *res = mkemptynode(); res->token = F_CONSTANT; if(nr) copy_shared_string(res->type, int_type_string); else copy_shared_string(res->type, mixed_type_string); res->node_info = 0; res->u.sval.type = T_INT; res->u.sval.subtype = NUMBER_NUMBER; res->u.sval.u.integer = nr; return res; } node *mkfloatnode(FLOAT_TYPE foo) { node *res = mkemptynode(); res->token = F_CONSTANT; copy_shared_string(res->type, float_type_string); res->u.sval.type = T_FLOAT; #ifdef __CHECKER__ res->u.sval.subtype = 0; #endif res->u.sval.u.float_number = foo; return res; } node *mkapplynode(node *func,node *args) { return mknode(F_APPLY, func, args); } node *mkefuncallnode(char *function, node *args) {
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *name;
45e8a81997-01-26Fredrik Hübinette (Hubbe)  node *n;
5267b71995-08-09Fredrik Hübinette (Hubbe)  name = findstring(function);
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  if(!name || !(n=find_module_identifier(name)))
5267b71995-08-09Fredrik Hübinette (Hubbe)  { my_yyerror("Internally used efun undefined: %s",function); return mkintnode(0); }
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  n=mkapplynode(n, args);
45e8a81997-01-26Fredrik Hübinette (Hubbe)  return n;
5267b71995-08-09Fredrik Hübinette (Hubbe) }
7bd0ea1996-02-19Fredrik Hübinette (Hubbe) node *mkopernode(char *oper_id, node *arg1, node *arg2) { if(arg1 && arg2) arg1=mknode(F_ARG_LIST,arg1,arg2); return mkefuncallnode(oper_id, arg1); }
5267b71995-08-09Fredrik Hübinette (Hubbe) node *mklocalnode(int var) { node *res = mkemptynode(); res->token = F_LOCAL;
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  copy_shared_string(res->type, compiler_frame->variable[var].type);
5267b71995-08-09Fredrik Hübinette (Hubbe)  res->node_info = OPT_NOT_CONST;
66d51c1997-03-04Fredrik Hübinette (Hubbe)  res->tree_info=res->node_info;
5267b71995-08-09Fredrik Hübinette (Hubbe) #ifdef __CHECKER__ CDR(res)=0; #endif res->u.number = var; return res; } node *mkidentifiernode(int i) { node *res = mkemptynode(); res->token = F_IDENTIFIER;
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  copy_shared_string(res->type, ID_FROM_INT(new_program, i)->type);
5267b71995-08-09Fredrik Hübinette (Hubbe)  /* FIXME */
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  if(IDENTIFIER_IS_CONSTANT(ID_FROM_INT(new_program, i)->identifier_flags))
3856c31996-11-25Fredrik Hübinette (Hubbe)  { res->node_info = OPT_EXTERNAL_DEPEND; }else{ res->node_info = OPT_NOT_CONST; }
66d51c1997-03-04Fredrik Hübinette (Hubbe)  res->tree_info=res->node_info;
5267b71995-08-09Fredrik Hübinette (Hubbe)  #ifdef __CHECKER__ CDR(res)=0; #endif res->u.number = i; return res; }
b1f4eb1998-01-13Fredrik Hübinette (Hubbe) node *mkexternalnode(int level, int i, struct identifier *id) { node *res = mkemptynode(); res->token = F_EXTERNAL; copy_shared_string(res->type, id->type); /* FIXME */ res->node_info = OPT_NOT_CONST; res->tree_info=res->node_info; #ifdef __CHECKER__ CDR(res)=0; #endif res->u.integer.a = level; res->u.integer.b = i; return res; }
06983f1996-09-22Fredrik Hübinette (Hubbe) node *mkcastnode(struct pike_string *type,node *n)
5267b71995-08-09Fredrik Hübinette (Hubbe) { node *res; if(!n) return 0; if(type==n->type) return n; res = mkemptynode(); res->token = F_CAST; copy_shared_string(res->type,type); if(match_types(object_type_string, type) || match_types(object_type_string, type)) res->node_info |= OPT_SIDE_EFFECT; CAR(res) = n; #ifdef __CHECKER__ CDR(res)=0; #endif n->parent=res; return res; }
591c0c1997-01-19Fredrik Hübinette (Hubbe) void resolv_constant(node *n) { struct identifier *i;
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  struct program *p; INT32 numid;
591c0c1997-01-19Fredrik Hübinette (Hubbe)  if(!n) { push_int(0); }else{ switch(n->token) { case F_CONSTANT: push_svalue(& n->u.sval);
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  return;
591c0c1997-01-19Fredrik Hübinette (Hubbe) 
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  case F_EXTERNAL: p=parent_compilation(n->u.integer.a); if(!p)
591c0c1997-01-19Fredrik Hübinette (Hubbe)  {
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  yyerror("Failed to resolv external constant");
591c0c1997-01-19Fredrik Hübinette (Hubbe)  push_int(0);
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  return;
591c0c1997-01-19Fredrik Hübinette (Hubbe)  }
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  numid=n->u.integer.b; break; case F_IDENTIFIER: p=new_program; numid=n->u.number;
591c0c1997-01-19Fredrik Hübinette (Hubbe)  break; case F_LOCAL:
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  yyerror("Expected constant, got local variable"); push_int(0); return;
591c0c1997-01-19Fredrik Hübinette (Hubbe)  case F_GLOBAL:
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  yyerror("Expected constant, got global variable"); push_int(0); return; default: yyerror("Expected constant, got something else"); push_int(0); return; } i=ID_FROM_INT(p, numid); if(IDENTIFIER_IS_CONSTANT(i->identifier_flags)) { push_svalue(PROG_FROM_INT(new_program, numid)->constants + i->func.offset); }else{ yyerror("Identifier is not a constant"); push_int(0);
591c0c1997-01-19Fredrik Hübinette (Hubbe)  } } } node *index_node(node *n, struct pike_string * id) { node *ret; JMP_BUF tmp; if(SETJMP(tmp)) { ONERROR tmp; SET_ONERROR(tmp,exit_on_error,"Error in handle_error in master object!"); assign_svalue_no_free(sp++, & throw_value); APPLY_MASTER("handle_error", 1); pop_stack(); UNSET_ONERROR(tmp); yyerror("Couldn't index module.");
05533f1997-02-06Fredrik Hübinette (Hubbe)  push_int(0);
591c0c1997-01-19Fredrik Hübinette (Hubbe)  }else{ resolv_constant(n);
1470d81997-02-27Fredrik Hübinette (Hubbe)  switch(sp[-1].type)
d6aef21997-02-27Fredrik Hübinette (Hubbe)  {
1470d81997-02-27Fredrik Hübinette (Hubbe)  case T_INT:
d6aef21997-02-27Fredrik Hübinette (Hubbe)  yyerror("Failed to index module (module doesn't exist?)");
1470d81997-02-27Fredrik Hübinette (Hubbe)  break; case T_PROGRAM: case T_FLOAT: case T_STRING: case T_ARRAY: yyerror("Failed to index module (Not a module?)");
e319bb1997-02-28Fredrik Hübinette (Hubbe)  pop_stack(); push_int(0);
1470d81997-02-27Fredrik Hübinette (Hubbe)  break; default:
e0e5711997-09-28Fredrik Hübinette (Hubbe)  ref_push_string(id);
d6aef21997-02-27Fredrik Hübinette (Hubbe)  f_index(2);
7485201997-02-27Fredrik Hübinette (Hubbe)  if(sp[-1].type == T_INT &&
a1d9c11997-02-27Fredrik Hübinette (Hubbe)  !sp[-1].u.integer &&
57db8d1997-02-27Fredrik Hübinette (Hubbe)  sp[-1].subtype==NUMBER_UNDEFINED)
7485201997-02-27Fredrik Hübinette (Hubbe)  {
57db8d1997-02-27Fredrik Hübinette (Hubbe)  my_yyerror("Index '%s' not present in module.",id->str);
7485201997-02-27Fredrik Hübinette (Hubbe)  }
d6aef21997-02-27Fredrik Hübinette (Hubbe)  }
591c0c1997-01-19Fredrik Hübinette (Hubbe)  } UNSETJMP(tmp); ret=mkconstantsvaluenode(sp-1); pop_stack(); return ret; }
5267b71995-08-09Fredrik Hübinette (Hubbe) int node_is_eq(node *a,node *b) { if(a == b) return 1; if(!a || !b) return 0; if(a->token != b->token) return 0; switch(a->token) { case F_LOCAL:
afa3651996-02-10Fredrik Hübinette (Hubbe)  case F_IDENTIFIER:
5267b71995-08-09Fredrik Hübinette (Hubbe)  return a->u.number == b->u.number; case F_CAST: return a->type == b->type && node_is_eq(CAR(a), CAR(b)); case F_CONSTANT: return is_equal(&(a->u.sval), &(b->u.sval)); default: if( a->type != b->type ) return 0; if(car_is_node(a) && !node_is_eq(CAR(a), CAR(b))) return 0; if(cdr_is_node(a) && !node_is_eq(CDR(a), CDR(b))) return 0; return 1; } } node *mkconstantsvaluenode(struct svalue *s) { node *res = mkemptynode(); res->token = F_CONSTANT; assign_svalue_no_free(& res->u.sval, s);
e82b301997-01-29Fredrik Hübinette (Hubbe)  if(s->type == T_OBJECT || (s->type==T_FUNCTION && s->subtype!=FUNCTION_BUILTIN)) {
5267b71995-08-09Fredrik Hübinette (Hubbe)  res->node_info|=OPT_EXTERNAL_DEPEND;
e82b301997-01-29Fredrik Hübinette (Hubbe)  }
5267b71995-08-09Fredrik Hübinette (Hubbe)  res->type = get_type_of_svalue(s); return res; }
5683de1995-11-06Fredrik Hübinette (Hubbe) node *mkliteralsvaluenode(struct svalue *s) { node *res = mkconstantsvaluenode(s); if(s->type!=T_STRING && s->type!=T_INT && s->type!=T_FLOAT) res->node_info|=OPT_EXTERNAL_DEPEND; return res; }
5267b71995-08-09Fredrik Hübinette (Hubbe) node *mksvaluenode(struct svalue *s) { switch(s->type) { case T_ARRAY: return make_node_from_array(s->u.array);
06983f1996-09-22Fredrik Hübinette (Hubbe)  case T_MULTISET: return make_node_from_multiset(s->u.multiset);
5267b71995-08-09Fredrik Hübinette (Hubbe)  case T_MAPPING: return make_node_from_mapping(s->u.mapping); case T_OBJECT: if(s->u.object == &fake_object) { return mkefuncallnode("this_object", 0); /* }else{ yyerror("Non-constant object pointer! (should not happen!)"); */ } break; case T_FUNCTION: {
bdb5091996-09-25Fredrik Hübinette (Hubbe)  if(s->subtype != FUNCTION_BUILTIN)
5267b71995-08-09Fredrik Hübinette (Hubbe)  { if(s->u.object == &fake_object) return mkidentifiernode(s->subtype); /* yyerror("Non-constant function pointer! (should not happen!)"); */ } } } return mkconstantsvaluenode(s); } /* these routines operates on parsetrees and are mostly used by the * optimizer */ node *copy_node(node *n) { node *b; if(!n) return n; switch(n->token) { case F_LOCAL:
06983f1996-09-22Fredrik Hübinette (Hubbe)  case F_IDENTIFIER:
5267b71995-08-09Fredrik Hübinette (Hubbe)  b=mkintnode(0); *b=*n; copy_shared_string(b->type, n->type); return b; case F_CAST: b=mkcastnode(n->type,copy_node(CAR(n))); break; case F_CONSTANT: b=mksvaluenode(&(n->u.sval)); break; default: switch((car_is_node(n) << 1) | cdr_is_node(n)) { default: fatal("fooo?\n"); case 3: b=mknode(n->token, copy_node(CAR(n)), copy_node(CDR(n))); break; case 2: b=mknode(n->token, copy_node(CAR(n)), CDR(n)); break; case 1: b=mknode(n->token, CAR(n), copy_node(CDR(n))); break; case 0: b=mknode(n->token, CAR(n), CDR(n)); } if(n->type) copy_shared_string(b->type, n->type); else b->type=0; } b->line_number = n->line_number; b->node_info = n->node_info; b->tree_info = n->tree_info; return b; } int is_const(node *n) {
05533f1997-02-06Fredrik Hübinette (Hubbe)  if(!n) return 1;
5267b71995-08-09Fredrik Hübinette (Hubbe)  return !(n->tree_info & (OPT_SIDE_EFFECT | OPT_NOT_CONST | OPT_ASSIGNMENT | OPT_CASE | OPT_CONTINUE | OPT_BREAK | OPT_RETURN )); } int node_is_tossable(node *n) { return !(n->tree_info & (OPT_SIDE_EFFECT | OPT_ASSIGNMENT | OPT_CASE | OPT_CONTINUE | OPT_BREAK | OPT_RETURN )); } /* this one supposes that the value is optimized */ int node_is_true(node *n) { if(!n) return 0; switch(n->token) { case F_CONSTANT: return !IS_ZERO(& n->u.sval); default: return 0; } } /* this one supposes that the value is optimized */ int node_is_false(node *n) { if(!n) return 0; switch(n->token) { case F_CONSTANT: return IS_ZERO(& n->u.sval); default: return 0; } }
6930181996-02-25Fredrik Hübinette (Hubbe) node **last_cmd(node **a)
5267b71995-08-09Fredrik Hübinette (Hubbe) { node **n; if(!a || !*a) return (node **)NULL; if((*a)->token == F_CAST) return last_cmd(&CAR(*a)); if((*a)->token != F_ARG_LIST) return a; if(CDR(*a)) { if(CDR(*a)->token != F_CAST && CAR(*a)->token != F_ARG_LIST) return &CDR(*a); if((n=last_cmd(&CDR(*a)))) return n; } if(CAR(*a)) { if(CAR(*a)->token != F_CAST && CAR(*a)->token != F_ARG_LIST) return &CAR(*a); if((n=last_cmd(&CAR(*a)))) return n; } return 0; } static node **low_get_arg(node **a,int *nr) { node **n; if(a[0]->token != F_ARG_LIST) { if(!(*nr)--) return a; else return NULL; } if(CAR(*a)) if((n=low_get_arg(&CAR(*a),nr))) return n; if(CDR(*a)) if((n=low_get_arg(&CDR(*a),nr))) return n; return 0; }
6930181996-02-25Fredrik Hübinette (Hubbe) node **my_get_arg(node **a,int n) { return low_get_arg(a,&n); }
5267b71995-08-09Fredrik Hübinette (Hubbe) /* static node **first_arg(node **a) { return my_get_arg(a,0); } */ static void low_print_tree(node *foo,int needlval) { if(!foo) return; switch(foo->token) { case F_LOCAL: if(needlval) putchar('&'); printf("$%ld",(long)foo->u.number); break; case '?': printf("("); low_print_tree(CAR(foo),0); printf(")?("); low_print_tree(CADR(foo),0); printf("):("); low_print_tree(CDDR(foo),0); printf(")"); break; case F_IDENTIFIER: if(needlval) putchar('&');
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  printf("%s",ID_FROM_INT(new_program, foo->u.number)->name->str);
5267b71995-08-09Fredrik Hübinette (Hubbe)  break; case F_ASSIGN: low_print_tree(CDR(foo),1); printf("="); low_print_tree(CAR(foo),0); break; case F_CAST: { char *s; init_buf(); low_describe_type(foo->type->str); s=simple_free_buf(); printf("(%s){",s); free(s); low_print_tree(CAR(foo),0); printf("}"); break; } case F_ARG_LIST: low_print_tree(CAR(foo),0); if(CAR(foo) && CDR(foo)) { if(CAR(foo)->type == void_type_string && CDR(foo)->type == void_type_string) printf(";\n"); else putchar(','); } low_print_tree(CDR(foo),needlval); return; case F_LVALUE_LIST: low_print_tree(CAR(foo),1); if(CAR(foo) && CDR(foo)) putchar(','); low_print_tree(CDR(foo),1); return; case F_CONSTANT: { char *s; init_buf(); describe_svalue(& foo->u.sval, 0, 0); s=simple_free_buf(); printf("%s",s); free(s); break; } case F_VAL_LVAL: low_print_tree(CAR(foo),0); printf(",&"); low_print_tree(CDR(foo),0); return; case F_APPLY: low_print_tree(CAR(foo),0); printf("("); low_print_tree(CDR(foo),0); printf(")"); return; default: if(!car_is_node(foo) && !cdr_is_node(foo)) {
0d202a1995-10-20Fredrik Hübinette (Hubbe)  printf("%s",get_token_name(foo->token));
5267b71995-08-09Fredrik Hübinette (Hubbe)  return; } if(foo->token<256) { printf("%c(",foo->token); }else{
0d202a1995-10-20Fredrik Hübinette (Hubbe)  printf("%s(",get_token_name(foo->token));
5267b71995-08-09Fredrik Hübinette (Hubbe)  } if(car_is_node(foo)) low_print_tree(CAR(foo),0); if(car_is_node(foo) && cdr_is_node(foo)) putchar(','); if(cdr_is_node(foo)) low_print_tree(CDR(foo),0); printf(")"); return; } } void print_tree(node *n) { low_print_tree(n,0); printf("\n"); fflush(stdout); } /* The following routines needs much better commenting */ struct used_vars {
e82b301997-01-29Fredrik Hübinette (Hubbe)  int err;
5267b71995-08-09Fredrik Hübinette (Hubbe)  char locals[MAX_LOCAL]; char globals[MAX_GLOBAL]; }; #define VAR_BLOCKED 0 #define VAR_UNUSED 1 #define VAR_USED 3 static void do_and_vars(struct used_vars *a,struct used_vars *b) { int e; for(e=0;e<MAX_LOCAL;e++) a->locals[e]|=b->locals[e]; for(e=0;e<MAX_GLOBAL;e++) a->globals[e]|=b->globals[e];
e82b301997-01-29Fredrik Hübinette (Hubbe)  a->err|=b->err;
5267b71995-08-09Fredrik Hübinette (Hubbe)  free((char *)b); } static struct used_vars *copy_vars(struct used_vars *a) { struct used_vars *ret; ret=(struct used_vars *)xalloc(sizeof(struct used_vars)); MEMCPY((char *)ret,(char *)a,sizeof(struct used_vars)); return ret; } static int find_used_variables(node *n, struct used_vars *p, int noblock, int overwrite) { struct used_vars *a; char *q; if(!n) return 0; switch(n->token) { case F_LOCAL: q=p->locals+n->u.number; goto set_pointer; case F_IDENTIFIER: q=p->globals+n->u.number;
e82b301997-01-29Fredrik Hübinette (Hubbe)  if(n->u.number > MAX_GLOBAL) { p->err=1; return 0; }
5267b71995-08-09Fredrik Hübinette (Hubbe)  set_pointer: if(overwrite) { if(*q == VAR_UNUSED && !noblock) *q = VAR_BLOCKED; } else {
e82b301997-01-29Fredrik Hübinette (Hubbe)  if(*q == VAR_UNUSED) *q = VAR_USED;
5267b71995-08-09Fredrik Hübinette (Hubbe)  } break; case F_ASSIGN: find_used_variables(CAR(n),p,noblock,0); find_used_variables(CDR(n),p,noblock,1); break; case '?': find_used_variables(CAR(n),p,noblock,0); a=copy_vars(p); find_used_variables(CADR(n),a,noblock,0); find_used_variables(CDDR(n),p,noblock,0); do_and_vars(p,a); break; case F_INC_NEQ_LOOP: case F_DEC_NEQ_LOOP: case F_INC_LOOP: case F_DEC_LOOP: case F_FOREACH: case F_FOR: find_used_variables(CAR(n),p,noblock,0); a=copy_vars(p); find_used_variables(CDR(n),a,noblock,0); do_and_vars(p,a); break; case F_SWITCH: find_used_variables(CAR(n),p,noblock,0); a=copy_vars(p); find_used_variables(CDR(n),a,1,0); do_and_vars(p,a); break; case F_DO: a=copy_vars(p); find_used_variables(CAR(n),a,noblock,0); do_and_vars(p,a); find_used_variables(CDR(n),p,noblock,0); break; default: if(car_is_node(n)) find_used_variables(CAR(n),p,noblock,0); if(cdr_is_node(n)) find_used_variables(CDR(n),p,noblock,0); } return 0; } /* no subtility needed */ static void find_written_vars(node *n, struct used_vars *p, int lvalue) { if(!n) return; switch(n->token) { case F_LOCAL: if(lvalue) p->locals[n->u.number]=VAR_USED; break; case F_GLOBAL:
e82b301997-01-29Fredrik Hübinette (Hubbe)  if(lvalue) { if(n->u.number>=MAX_GLOBAL) { p->err=1; return; } p->globals[n->u.number]=VAR_USED; } break; case F_APPLY: if(n->tree_info & OPT_SIDE_EFFECT)
49e54b1997-02-10Fredrik Hübinette (Hubbe)  MEMSET(p->globals, VAR_USED, MAX_GLOBAL);
5267b71995-08-09Fredrik Hübinette (Hubbe)  break; case F_INDEX:
dffa011997-01-15Fredrik Hübinette (Hubbe)  case F_ARROW:
5267b71995-08-09Fredrik Hübinette (Hubbe)  find_written_vars(CAR(n), p, lvalue); find_written_vars(CDR(n), p, 0); break; case F_INC: case F_DEC: case F_POST_INC: case F_POST_DEC: find_written_vars(CAR(n), p, 1); break; case F_ASSIGN: find_written_vars(CAR(n), p, 0); find_written_vars(CDR(n), p, 1); break; case F_SSCANF: find_written_vars(CAR(n), p, 0); find_written_vars(CDR(n), p, 1); break; case F_LVALUE_LIST: find_written_vars(CAR(n), p, 1); find_written_vars(CDR(n), p, 1); break; case F_VAL_LVAL: find_written_vars(CAR(n), p, 0); find_written_vars(CDR(n), p, 1); break; default: if(car_is_node(n)) find_written_vars(CAR(n), p, 0); if(cdr_is_node(n)) find_written_vars(CDR(n), p, 0); } } /* return 1 if A depends on B */ static int depend_p2(node *a,node *b) { struct used_vars aa,bb; int e; if(!a || !b || is_const(a)) return 0;
3b79fa1997-02-10Fredrik Hübinette (Hubbe)  aa.err=0; bb.err=0;
49e54b1997-02-10Fredrik Hübinette (Hubbe)  MEMSET((char *)aa.locals, VAR_UNUSED, MAX_LOCAL); MEMSET((char *)bb.locals, VAR_UNUSED, MAX_LOCAL); MEMSET((char *)aa.globals, VAR_UNUSED, MAX_GLOBAL); MEMSET((char *)bb.globals, VAR_UNUSED, MAX_GLOBAL);
5267b71995-08-09Fredrik Hübinette (Hubbe)  find_used_variables(a,&aa,0,0); find_written_vars(b,&bb,0);
e82b301997-01-29Fredrik Hübinette (Hubbe)  if(aa.err || bb.err) return 1;
5267b71995-08-09Fredrik Hübinette (Hubbe)  for(e=0;e<MAX_LOCAL;e++) if(aa.locals[e]==VAR_USED && bb.locals[e]!=VAR_UNUSED) return 1; for(e=0;e<MAX_GLOBAL;e++) if(aa.globals[e]==VAR_USED && bb.globals[e]!=VAR_UNUSED) return 1; return 0; } static int depend_p(node *a,node *b) { if(!b) return 0;
e82b301997-01-29Fredrik Hübinette (Hubbe) #if 0
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(!(b->tree_info & OPT_SIDE_EFFECT) && (b->tree_info & OPT_EXTERNAL_DEPEND)) return 1;
e82b301997-01-29Fredrik Hübinette (Hubbe) #endif if((a->tree_info & OPT_EXTERNAL_DEPEND)) return 1;
5267b71995-08-09Fredrik Hübinette (Hubbe)  return depend_p2(a,b); } static int cntargs(node *n) { if(!n) return 0; switch(n->token) { case F_CAST: case F_APPLY: return n->type != void_type_string; case F_FOREACH: case F_INC_NEQ_LOOP: case F_DEC_NEQ_LOOP: case F_INC_LOOP: case F_DEC_LOOP: return 0; case F_VAL_LVAL: case F_LVALUE_LIST: case F_ARG_LIST: return cntargs(CAR(n))+cntargs(CDR(n)); /* this might not be true, but it doesn't matter very much */ default: return 1; } } static void low_build_function_type(node *n) { if(!n) return; switch(n->token) { case F_ARG_LIST: low_build_function_type(CDR(n)); low_build_function_type(CAR(n)); break; case F_PUSH_ARRAY: /* We let this ruin type-checking for now.. */ reset_type_stack();
0d202a1995-10-20Fredrik Hübinette (Hubbe)  push_type(T_MIXED);
5267b71995-08-09Fredrik Hübinette (Hubbe)  push_type(T_MIXED); /* is varargs */ push_type(T_MANY); return; default: if(n->type) { if(n->type == void_type_string) return; push_finished_type(n->type); }else{ push_type(T_MIXED); } } } void fix_type_field(node *n) {
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *type_a,*type_b;
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(n->type) return; /* assume it is correct */ switch(n->token) {
cb22561995-10-11Fredrik Hübinette (Hubbe)  case F_LAND: case F_LOR: if(!match_types(CAR(n)->type,mixed_type_string)) yyerror("Bad conditional expression.\n"); if(!match_types(CDR(n)->type,mixed_type_string)) yyerror("Bad conditional expression.\n"); if(CAR(n)->type == CDR(n)->type) { copy_shared_string(n->type,CAR(n)->type); }else{ copy_shared_string(n->type,mixed_type_string); } break;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
da55f91996-05-03Fredrik Hübinette (Hubbe)  case F_ASSIGN: if(CAR(n) && CDR(n) && !match_types(CDR(n)->type,CAR(n)->type))
3856c31996-11-25Fredrik Hübinette (Hubbe)  my_yyerror("Bad type in assignment.");
d8632c1996-05-04Fredrik Hübinette (Hubbe)  copy_shared_string(n->type, CDR(n)->type);
da55f91996-05-03Fredrik Hübinette (Hubbe)  break;
5267b71995-08-09Fredrik Hübinette (Hubbe)  case F_INDEX:
b8cda21997-01-21Fredrik Hübinette (Hubbe)  type_a=CAR(n)->type; type_b=CDR(n)->type; if(!check_indexing(type_a, type_b, n)) my_yyerror("Indexing on illegal type."); n->type=index_type(type_a,n); break;
dffa011997-01-15Fredrik Hübinette (Hubbe)  case F_ARROW:
5267b71995-08-09Fredrik Hübinette (Hubbe)  type_a=CAR(n)->type; type_b=CDR(n)->type;
b8cda21997-01-21Fredrik Hübinette (Hubbe)  if(!check_indexing(type_a, type_b, n))
5267b71995-08-09Fredrik Hübinette (Hubbe)  my_yyerror("Indexing on illegal type.");
b8cda21997-01-21Fredrik Hübinette (Hubbe)  n->type=index_type(type_a,n);
5267b71995-08-09Fredrik Hübinette (Hubbe)  break; case F_APPLY: {
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *s;
b8cda21997-01-21Fredrik Hübinette (Hubbe)  struct pike_string *f;
0d202a1995-10-20Fredrik Hübinette (Hubbe)  push_type(T_MIXED); /* match any return type, even void */
5267b71995-08-09Fredrik Hübinette (Hubbe)  push_type(T_VOID); /* not varargs */ push_type(T_MANY); low_build_function_type(CDR(n)); push_type(T_FUNCTION); s=pop_type();
b8cda21997-01-21Fredrik Hübinette (Hubbe)  f=CAR(n)->type?CAR(n)->type:mixed_type_string; n->type=check_call(s,f);
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(!n->type) {
b8cda21997-01-21Fredrik Hübinette (Hubbe)  char *name; int args;
3856c31996-11-25Fredrik Hübinette (Hubbe)  switch(CAR(n)->token) { case F_IDENTIFIER:
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  name=ID_FROM_INT(new_program, CAR(n)->u.number)->name->str;
3856c31996-11-25Fredrik Hübinette (Hubbe)  break;
b8cda21997-01-21Fredrik Hübinette (Hubbe) 
3856c31996-11-25Fredrik Hübinette (Hubbe)  case F_CONSTANT: default:
31c3c51997-10-05Henrik Grubbström (Grubba)  name="`() (function call)";
b8cda21997-01-21Fredrik Hübinette (Hubbe)  } if(max_correct_args == count_arguments(s)) { my_yyerror("To few arguments to %s.\n",name); }else{ my_yyerror("Bad argument %d to %s.", max_correct_args+1, name);
3856c31996-11-25Fredrik Hübinette (Hubbe)  }
5267b71995-08-09Fredrik Hübinette (Hubbe)  copy_shared_string(n->type, mixed_type_string); } free_string(s);
cb22561995-10-11Fredrik Hübinette (Hubbe)  break;
5267b71995-08-09Fredrik Hübinette (Hubbe)  } case '?':
cb22561995-10-11Fredrik Hübinette (Hubbe)  if(!match_types(CAR(n)->type,mixed_type_string)) yyerror("Bad conditional expression.\n");
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(!CADR(n) || !CDDR(n)) { copy_shared_string(n->type,void_type_string); return; } if(CADR(n)->type == CDDR(n)->type) { copy_shared_string(n->type,CADR(n)->type); return; } copy_shared_string(n->type,mixed_type_string);
cb22561995-10-11Fredrik Hübinette (Hubbe)  break; case F_RETURN:
fcb8041997-05-22Fredrik Hübinette (Hubbe)  if(CAR(n)->type == void_type_string) { yyerror("You cannot return a void expression"); }
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  if(compiler_frame && compiler_frame->current_return_type && !match_types(compiler_frame->current_return_type,CAR(n)->type) &&
cb22561995-10-11Fredrik Hübinette (Hubbe)  !(
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  compiler_frame->current_return_type==void_type_string &&
cb22561995-10-11Fredrik Hübinette (Hubbe)  CAR(n)->token == F_CONSTANT && IS_ZERO(& CAR(n)->u.sval) ) ) { yyerror("Wrong return type."); } /* Fall through */
5267b71995-08-09Fredrik Hübinette (Hubbe)  case F_INC_LOOP: case F_DEC_LOOP: case F_DEC_NEQ_LOOP: case F_INC_NEQ_LOOP: case F_CASE: case F_CONTINUE: case F_BREAK: copy_shared_string(n->type,void_type_string);
cb22561995-10-11Fredrik Hübinette (Hubbe)  break; case F_DO: if(!match_types(CDR(n)->type,mixed_type_string)) yyerror("Bad conditional expression do - while().\n"); copy_shared_string(n->type,void_type_string); break; case F_FOR: if(!match_types(CAR(n)->type,mixed_type_string)) yyerror("Bad conditional expression for().\n"); copy_shared_string(n->type,void_type_string); break; case F_SWITCH: if(!match_types(CAR(n)->type,mixed_type_string)) yyerror("Bad switch expression.\n"); copy_shared_string(n->type,void_type_string); break;
5267b71995-08-09Fredrik Hübinette (Hubbe)  case F_CONSTANT: n->type = get_type_of_svalue(& n->u.sval);
cb22561995-10-11Fredrik Hübinette (Hubbe)  break;
5267b71995-08-09Fredrik Hübinette (Hubbe)  case F_ARG_LIST: if(!CAR(n) || CAR(n)->type==void_type_string) { if(CDR(n)) copy_shared_string(n->type,CDR(n)->type); else copy_shared_string(n->type,void_type_string); return; } if(!CDR(n) || CDR(n)->type==void_type_string) { if(CAR(n)) copy_shared_string(n->type,CAR(n)->type); else copy_shared_string(n->type,void_type_string); return; } default: copy_shared_string(n->type,mixed_type_string); } } static void zapp_try_optimize(node *n) {
86bea91997-01-31Fredrik Hübinette (Hubbe)  if(!n) return;
5267b71995-08-09Fredrik Hübinette (Hubbe)  n->node_info &=~ OPT_TRY_OPTIMIZE; n->tree_info &=~ OPT_TRY_OPTIMIZE; if(car_is_node(n)) zapp_try_optimize(CAR(n)); if(cdr_is_node(n)) zapp_try_optimize(CDR(n)); } static void optimize(node *n) { node *tmp1, *tmp2, *tmp3;
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  INT32 save_line = lex.current_line;
5267b71995-08-09Fredrik Hübinette (Hubbe)  do { if(car_is_node(n) && !(CAR(n)->node_info & OPT_OPTIMIZED)) { n=CAR(n); continue; } if(cdr_is_node(n) && !(CDR(n)->node_info & OPT_OPTIMIZED)) { n=CDR(n); continue; }
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  lex.current_line = n->line_number;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
66d51c1997-03-04Fredrik Hübinette (Hubbe) 
5267b71995-08-09Fredrik Hübinette (Hubbe)  n->tree_info = n->node_info; if(car_is_node(n)) n->tree_info |= CAR(n)->tree_info; if(cdr_is_node(n)) n->tree_info |= CDR(n)->tree_info;
66d51c1997-03-04Fredrik Hübinette (Hubbe)  if(!n->parent) break;
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(n->tree_info & (OPT_NOT_CONST| OPT_SIDE_EFFECT| OPT_EXTERNAL_DEPEND| OPT_ASSIGNMENT)) { if(car_is_node(n) && !(CAR(n)->tree_info & (OPT_NOT_CONST| OPT_SIDE_EFFECT| OPT_EXTERNAL_DEPEND| OPT_ASSIGNMENT)) && (CAR(n)->tree_info & OPT_TRY_OPTIMIZE) && CAR(n)->token != ':') { CAR(n) = eval(CAR(n)); if(CAR(n)) CAR(n)->parent = n; zapp_try_optimize(CAR(n)); /* avoid infinite loops */ continue; } if(cdr_is_node(n) && !(CDR(n)->tree_info & (OPT_NOT_CONST| OPT_SIDE_EFFECT| OPT_EXTERNAL_DEPEND| OPT_ASSIGNMENT)) && (CDR(n)->tree_info & OPT_TRY_OPTIMIZE) && CDR(n)->token != ':') { CDR(n) = eval(CDR(n)); if(CDR(n)) CDR(n)->parent = n; zapp_try_optimize(CDR(n)); /* avoid infinite loops */ continue; } } fix_type_field(n); #ifdef DEBUG
66d51c1997-03-04Fredrik Hübinette (Hubbe)  if(l_flag > 3 && n)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
66d51c1997-03-04Fredrik Hübinette (Hubbe)  fprintf(stderr,"Optimizing (tree info=%x):",n->tree_info);
5267b71995-08-09Fredrik Hübinette (Hubbe)  print_tree(n); } #endif switch(n->token) {
6930181996-02-25Fredrik Hübinette (Hubbe)  case F_APPLY: if(CAR(n)->token == F_CONSTANT && CAR(n)->u.sval.type == T_FUNCTION &&
bdb5091996-09-25Fredrik Hübinette (Hubbe)  CAR(n)->u.sval.subtype == FUNCTION_BUILTIN && /* driver fun? */
6930181996-02-25Fredrik Hübinette (Hubbe)  CAR(n)->u.sval.u.efun->optimize) {
9c6f7d1997-04-15Fredrik Hübinette (Hubbe)  if((tmp1=CAR(n)->u.sval.u.efun->optimize(n)))
66d51c1997-03-04Fredrik Hübinette (Hubbe)  {
6930181996-02-25Fredrik Hübinette (Hubbe)  goto use_tmp1;
66d51c1997-03-04Fredrik Hübinette (Hubbe)  }
6930181996-02-25Fredrik Hübinette (Hubbe)  } break;
5267b71995-08-09Fredrik Hübinette (Hubbe)  case F_ARG_LIST: case F_LVALUE_LIST: if(!CAR(n)) goto use_cdr; if(!CDR(n)) goto use_car; /* * { X; break; Y; } -> { X; return; } * { X; return; Y; } -> { X; return; } * { X; continue; Y; } -> { X; return; } */ if((CAR(n)->token==F_RETURN || CAR(n)->token==F_BREAK || CAR(n)->token==F_CONTINUE || (CAR(n)->token==F_ARG_LIST && CDAR(n) && (CDAR(n)->token==F_RETURN || CDAR(n)->token==F_BREAK || CDAR(n)->token==F_CONTINUE))) && !(CDR(n)->tree_info & OPT_CASE)) goto use_car; break; case F_LOR: /* !x || !y -> !(x && y) */ if(CAR(n)->token==F_NOT && CDR(n)->token==F_NOT) { tmp1=mknode(F_NOT,mknode(F_LAND,CAAR(n),CADR(n)),0); CAAR(n)=CADR(n)=0; goto use_tmp1; } break; case F_LAND: /* !x && !y -> !(x || y) */ if(CAR(n)->token==F_NOT && CDR(n)->token==F_NOT) { tmp1=mknode(F_NOT,mknode(F_LOR,CAAR(n),CADR(n)),0); CAAR(n)=CADR(n)=0; goto use_tmp1; } break; case '?': /* (! X) ? Y : Z -> X ? Z : Y */ if(CAR(n)->token == F_NOT) { tmp1=mknode('?',CAAR(n),mknode(':',CDDR(n),CADR(n))); CAAR(n)=CDDR(n)=CADR(n)=0; goto use_tmp1; } break; case F_ADD_EQ: if(CDR(n)->type == int_type_string) { if(CDR(n)->token == F_CONSTANT && CDR(n)->u.sval.type == T_INT) { /* a+=0 -> a */ if(n->u.sval.u.integer == 0) goto use_car; /* a+=1 -> ++a */ if(n->u.sval.u.integer == 1) { tmp1=mknode(F_INC,CDR(n),0); CDR(n)=0; goto use_tmp1; } /* a+=-1 -> --a */ if(n->u.sval.u.integer == -1) { tmp1=mknode(F_DEC, CDR(n), 0); CDR(n)=0; goto use_tmp1; } } } break; case F_SUB_EQ: if(CDR(n)->type == int_type_string) { if(CDR(n)->token == F_CONSTANT && CDR(n)->u.sval.type == T_INT) { /* a-=0 -> a */ if(n->u.sval.u.integer == 0) goto use_car; /* a-=-1 -> ++a */ if(n->u.sval.u.integer == -1) { tmp1=mknode(F_INC, CDR(n), 0); CDR(n)=0; goto use_tmp1; } /* a-=-1 -> --a */ if(n->u.sval.u.integer == 1) { tmp1=mknode(F_DEC, CDR(n), 0); CDR(n)=0; goto use_tmp1; } } } break;
b770dc1997-04-17Fredrik Hübinette (Hubbe)  case F_ARROW: if(CAR(n)->token==F_CONSTANT && CAR(n)->u.sval.type==T_OBJECT && CAR(n)->u.sval.u.object->prog && CDR(n)->token==F_CONSTANT && CAR(n)->u.sval.type==T_STRING && find_identifier("`->",CAR(n)->u.sval.u.object->prog)==-1) { int i; i=find_shared_string_identifier(CDR(n)->u.sval.u.string, CAR(n)->u.sval.u.object->prog); if(i) { struct identifier *id; id=ID_FROM_INT(CAR(n)->u.sval.u.object->prog, i);
7fda7a1997-09-08Fredrik Hübinette (Hubbe)  if(IDENTIFIER_IS_VARIABLE(id->identifier_flags)) break;
b770dc1997-04-17Fredrik Hübinette (Hubbe)  } ref_push_object(CAR(n)->u.sval.u.object); ref_push_string(CDR(n)->u.sval.u.string); f_index(2); tmp1=mksvaluenode(sp-1); pop_stack(); goto use_tmp1; } break;
5267b71995-08-09Fredrik Hübinette (Hubbe)  case F_FOR: { node **last; int inc; int token; /* for(;0; X) Y; -> 0; */ if(node_is_false(CAR(n))) { tmp1=mkintnode(0); goto use_tmp1; }
a29e021996-10-15Fredrik Hübinette (Hubbe)  /* for(;1;); -> for(;1;) sleep(255); (saves cpu) */ if(node_is_true(CAR(n)) && (!CDR(n) || (CDR(n)->token==':' && !CADR(n) && !CDDR(n)))) { tmp1=mknode(F_FOR, CAR(n), mknode(':',mkefuncallnode("sleep",mkintnode(255)),0)); CAR(n)=0; goto use_tmp1; }
5267b71995-08-09Fredrik Hübinette (Hubbe)  /*
06983f1996-09-22Fredrik Hübinette (Hubbe)  * if X and Y are free from 'continue' or X is null, * then the following optimizations can be done:
5267b71995-08-09Fredrik Hübinette (Hubbe)  * for(;++e; X) Y; -> ++ne_loop(e, -1) { Y ; X } * for(;e++; X) Y; -> ++ne_loop(e, 0) { Y; X } * for(;--e; X) Y; -> --ne_loop(e, 1) { Y; X } * for(;e--; X) Y; -> --ne_loop(e, 0) { Y; X } */ if(CAR(n) && (CAR(n)->token==F_INC || CAR(n)->token==F_POST_INC || CAR(n)->token==F_DEC || CAR(n)->token==F_POST_DEC ) && (!CDDR(n) || !(CDDR(n)->tree_info & OPT_CONTINUE)) && (!CADR(n) || !(CADR(n)->tree_info & OPT_CONTINUE)) ) {
06983f1996-09-22Fredrik Hübinette (Hubbe)  /* Check which of the above cases.. */
5267b71995-08-09Fredrik Hübinette (Hubbe)  switch(CAR(n)->token) { case F_POST_DEC: token=F_DEC_NEQ_LOOP; inc=-1; break; case F_DEC: token=F_DEC_NEQ_LOOP; inc=0; break; case F_POST_INC: token=F_INC_NEQ_LOOP; inc=1; break; case F_INC: token=F_INC_NEQ_LOOP; inc=0; break; default: fatal("Impossible error\n"); return; }
06983f1996-09-22Fredrik Hübinette (Hubbe)  /* Build new tree */
5267b71995-08-09Fredrik Hübinette (Hubbe)  tmp1=mknode(token, mknode(F_VAL_LVAL, mkintnode(inc), CAAR(n)), mknode(F_ARG_LIST, mkcastnode(void_type_string, CADR(n)), mkcastnode(void_type_string, CDDR(n))));
0d202a1995-10-20Fredrik Hübinette (Hubbe)  CDDR(n)=CADR(n)=CAAR(n)=0;
5267b71995-08-09Fredrik Hübinette (Hubbe)  goto use_tmp1; }
06983f1996-09-22Fredrik Hübinette (Hubbe)  /* Last is a pointer to the place where the incrementor is in the * tree. This is needed so we can nullify this pointer later and * free the rest of the tree */
5267b71995-08-09Fredrik Hübinette (Hubbe)  last=&(CDDR(n));
6891181996-08-06Fredrik Hübinette (Hubbe)  tmp1=*last;
06983f1996-09-22Fredrik Hübinette (Hubbe)  /* We're not interested in casts to void */
6891181996-08-06Fredrik Hübinette (Hubbe)  while(tmp1 && tmp1->token == F_CAST && tmp1->type == void_type_string) { last=&CAR(tmp1); tmp1=*last; }
06983f1996-09-22Fredrik Hübinette (Hubbe)  /* If there is an incrementor, and it is one of x++, ++x, x-- or ++x */
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(tmp1 && (tmp1->token==F_INC || tmp1->token==F_POST_INC || tmp1->token==F_DEC || tmp1->token==F_POST_DEC)) {
6891181996-08-06Fredrik Hübinette (Hubbe)  node *opnode, **arg1, **arg2; int oper;
5267b71995-08-09Fredrik Hübinette (Hubbe)  /* does it increment or decrement ? */ if(tmp1->token==F_INC || tmp1->token==F_POST_INC) inc=1; else inc=0;
06983f1996-09-22Fredrik Hübinette (Hubbe)  /* for(; arg1 oper arg2; z ++) p; */
5267b71995-08-09Fredrik Hübinette (Hubbe) 
6891181996-08-06Fredrik Hübinette (Hubbe)  opnode=CAR(n); if(opnode->token == F_APPLY && CAR(opnode) && CAR(opnode)->token == F_CONSTANT && CAR(opnode)->u.sval.type == T_FUNCTION &&
bdb5091996-09-25Fredrik Hübinette (Hubbe)  CAR(opnode)->u.sval.subtype == FUNCTION_BUILTIN)
6891181996-08-06Fredrik Hübinette (Hubbe)  { if(CAR(opnode)->u.sval.u.efun->function == f_gt) oper=F_GT; else if(CAR(opnode)->u.sval.u.efun->function == f_ge) oper=F_GE; else if(CAR(opnode)->u.sval.u.efun->function == f_lt) oper=F_LT; else if(CAR(opnode)->u.sval.u.efun->function == f_le) oper=F_LE; else if(CAR(opnode)->u.sval.u.efun->function == f_ne) oper=F_NE; else break; }else{
5267b71995-08-09Fredrik Hübinette (Hubbe)  break;
6891181996-08-06Fredrik Hübinette (Hubbe)  }
5267b71995-08-09Fredrik Hübinette (Hubbe) 
6891181996-08-06Fredrik Hübinette (Hubbe)  if(count_args(CDR(opnode)) != 2) break; arg1=my_get_arg(&CDR(opnode), 0); arg2=my_get_arg(&CDR(opnode), 1);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
6891181996-08-06Fredrik Hübinette (Hubbe)  /* it was not on the form for(; x op y; z++) p; */ if(!node_is_eq(*arg1,CAR(tmp1)) || /* x == z */ depend_p(*arg2,*arg2) || /* does y depend on y? */ depend_p(*arg2,*arg1) || /* does y depend on x? */ depend_p(*arg2,CADR(n))) /* does y depend on p? */
5267b71995-08-09Fredrik Hübinette (Hubbe)  { /* it was not on the form for(; x op y; x++) p; */
6891181996-08-06Fredrik Hübinette (Hubbe)  if(!node_is_eq(*arg2,CAR(tmp1)) || /* y == z */ depend_p(*arg1,*arg2) || /* does x depend on y? */ depend_p(*arg1,*arg1) || /* does x depend on x? */ depend_p(*arg1,CADR(n)) /* does x depend on p? */
5267b71995-08-09Fredrik Hübinette (Hubbe)  ) { /* it was not on the form for(; x op y; y++) p; */ break; }else{
6891181996-08-06Fredrik Hübinette (Hubbe)  node **tmparg;
5267b71995-08-09Fredrik Hübinette (Hubbe)  /* for(; x op y; y++) p; -> for(; y op^-1 x; y++) p; */
6891181996-08-06Fredrik Hübinette (Hubbe)  switch(oper)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
6891181996-08-06Fredrik Hübinette (Hubbe)  case F_LT: oper=F_GT; break; case F_LE: oper=F_GE; break; case F_GT: oper=F_LT; break; case F_GE: oper=F_LE; break;
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
6891181996-08-06Fredrik Hübinette (Hubbe)  tmparg=arg1; arg1=arg2; arg2=tmparg;
5267b71995-08-09Fredrik Hübinette (Hubbe)  } } if(inc) {
6891181996-08-06Fredrik Hübinette (Hubbe)  if(oper==F_LE) tmp3=mkopernode("`+",*arg2,mkintnode(1)); else if(oper==F_LT) tmp3=*arg2;
5267b71995-08-09Fredrik Hübinette (Hubbe)  else break; }else{
6891181996-08-06Fredrik Hübinette (Hubbe)  if(oper==F_GE) tmp3=mkopernode("`-",*arg2,mkintnode(1)); else if(oper==F_GT) tmp3=*arg2;
5267b71995-08-09Fredrik Hübinette (Hubbe)  else break; } *last=0;
6891181996-08-06Fredrik Hübinette (Hubbe)  if(oper==F_NE)
5267b71995-08-09Fredrik Hübinette (Hubbe)  { if(inc) token=F_INC_NEQ_LOOP; else token=F_DEC_NEQ_LOOP; }else{ if(inc) token=F_INC_LOOP; else token=F_DEC_LOOP; }
6891181996-08-06Fredrik Hübinette (Hubbe)  tmp2=mknode(token,mknode(F_VAL_LVAL,tmp3,*arg1),CADR(n));
06983f1996-09-22Fredrik Hübinette (Hubbe)  *arg1 = *arg2 = CADR(n) =0;
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(inc) { tmp1->token=F_DEC; }else{ tmp1->token=F_INC; }
6891181996-08-06Fredrik Hübinette (Hubbe) 
5267b71995-08-09Fredrik Hübinette (Hubbe)  tmp1=mknode(F_ARG_LIST,mkcastnode(void_type_string,tmp1),tmp2); goto use_tmp1; } break; } use_car: tmp1=CAR(n); CAR(n)=0; goto use_tmp1; use_cdr: tmp1=CDR(n); CDR(n)=0; goto use_tmp1; use_tmp1: if(CAR(n->parent) == n) CAR(n->parent) = tmp1; else CDR(n->parent) = tmp1; if(tmp1) tmp1->parent = n->parent; free_node(n); n=tmp1; #ifdef DEBUG if(l_flag > 3) { fprintf(stderr,"Result: "); print_tree(n); } #endif continue; } n->node_info |= OPT_OPTIMIZED; n=n->parent; }while(n);
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  lex.current_line = save_line;
5267b71995-08-09Fredrik Hübinette (Hubbe) }
a29e021996-10-15Fredrik Hübinette (Hubbe) struct timer_oflo { INT32 counter; int yes; };
d085c71996-11-18Fredrik Hübinette (Hubbe) static void check_evaluation_time(struct callback *cb,void *tmp,void *ignored)
a29e021996-10-15Fredrik Hübinette (Hubbe) { struct timer_oflo *foo=(struct timer_oflo *)tmp; if(foo->counter-- < 0) { foo->yes=1;
dc7cc91998-01-14Fredrik Hübinette (Hubbe)  pike_throw();
a29e021996-10-15Fredrik Hübinette (Hubbe)  } }
5267b71995-08-09Fredrik Hübinette (Hubbe) int eval_low(node *n) {
5c8e891995-10-29Fredrik Hübinette (Hubbe)  unsigned INT16 num_strings, num_constants; INT32 jump;
5267b71995-08-09Fredrik Hübinette (Hubbe)  struct svalue *save_sp = sp; int ret;
66d51c1997-03-04Fredrik Hübinette (Hubbe) #ifdef DEBUG if(l_flag > 3 && n) { fprintf(stderr,"Evaluating (tree info=%x):",n->tree_info); print_tree(n); } #endif
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(num_parse_error) return -1;
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  num_strings=new_program->num_strings; num_constants=new_program->num_constants;
5267b71995-08-09Fredrik Hübinette (Hubbe)  jump=PC; store_linenumbers=0; docode(n); ins_f_byte(F_DUMB_RETURN); store_linenumbers=1; ret=-1; if(!num_parse_error) {
a29e021996-10-15Fredrik Hübinette (Hubbe)  struct callback *tmp_callback; struct timer_oflo foo; /* This is how long we try to optimize before giving up... */ foo.counter=10000; foo.yes=0;
5267b71995-08-09Fredrik Hübinette (Hubbe)  setup_fake_object();
a29e021996-10-15Fredrik Hübinette (Hubbe)  tmp_callback=add_to_callback(&evaluator_callbacks, check_evaluation_time, (void *)&foo,0);
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(apply_low_safe_and_stupid(&fake_object, jump)) { /* Generate error message */ 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."); } }else{ yyerror("Nonstandard error format."); } }else{
a29e021996-10-15Fredrik Hübinette (Hubbe)  if(foo.yes) pop_n_elems(sp-save_sp); else ret=sp-save_sp;
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
a29e021996-10-15Fredrik Hübinette (Hubbe)  remove_callback(tmp_callback);
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  while(new_program->num_strings > num_strings)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  new_program->num_strings--; free_string(new_program->strings[new_program->num_strings]);
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  while(new_program->num_constants > num_constants)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  new_program->num_constants--; free_svalue(new_program->constants + new_program->num_constants);
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  new_program->num_program=jump;
5267b71995-08-09Fredrik Hübinette (Hubbe)  return ret; } static node *eval(node *n) { int args; extern struct svalue *sp; if(!is_const(n) || n->token==':') return n; args=eval_low(n); switch(args) { case -1: return n; break; case 0: free_node(n); n=0; break; case 1: free_node(n); n=mksvaluenode(sp-1); pop_stack(); break; default: free_node(n); n=NULL; while(args--) { n=mknode(F_ARG_LIST,mksvaluenode(sp-1),n); pop_stack(); } } return n; } INT32 last_function_opt_info;
329cc01997-02-17Fredrik Hübinette (Hubbe) static int stupid_args(node *n, int expected,int vargs)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
329cc01997-02-17Fredrik Hübinette (Hubbe)  if(!n) return expected; switch(n->token) { case F_PUSH_ARRAY: if(!vargs) return -1; if(stupid_args(CAR(n), expected,vargs) == expected+1) return 65535; return -1; case F_ARG_LIST: expected=stupid_args(CAR(n), expected,vargs); if(expected==-1) return -1; return stupid_args(CDR(n), expected,vargs); case F_LOCAL: return n->u.number==expected ? expected + 1 : -1; default: return -1; } }
9c6f7d1997-04-15Fredrik Hübinette (Hubbe) static int is_null_branch(node *n)
329cc01997-02-17Fredrik Hübinette (Hubbe) { if(!n) return 1; if(n->token==F_CAST && n->type==void_type_string) return is_null_branch(CAR(n)); if(n->token==F_ARG_LIST) return is_null_branch(CAR(n)) && is_null_branch(CDR(n)); return 0; } static struct svalue *is_stupid_func(node *n, int args, int vargs) { node *a,*b; int tmp; while(1) { if(!n) return 0; if(n->token == F_ARG_LIST) { if(is_null_branch(CAR(n))) n=CDR(n); else n=CAR(n); continue; } if(n->token == F_CAST && n->type==void_type_string) { n=CAR(n); continue; } break; }
9669e81997-02-27Fredrik Hübinette (Hubbe)  if(!n || n->token != F_RETURN) return 0;
329cc01997-02-17Fredrik Hübinette (Hubbe)  n=CAR(n);
9669e81997-02-27Fredrik Hübinette (Hubbe)  if(!n || n->token != F_APPLY) return 0;
329cc01997-02-17Fredrik Hübinette (Hubbe)  tmp=stupid_args(CDR(n),0,vargs); if(!(vargs?tmp==65535:tmp==args)) return 0; n=CAR(n);
9669e81997-02-27Fredrik Hübinette (Hubbe)  if(!n || n->token != F_CONSTANT) return 0;
329cc01997-02-17Fredrik Hübinette (Hubbe)  return &n->u.sval; } int dooptcode(struct pike_string *name, node *n, struct pike_string *type, int modifiers) { union idptr tmp; int args, vargs, ret; struct svalue *foo;
5267b71995-08-09Fredrik Hübinette (Hubbe) #ifdef DEBUG if(a_flag > 1)
d334771996-04-13Fredrik Hübinette (Hubbe)  fprintf(stderr,"Doing function '%s' at %x\n",name->str,PC);
5267b71995-08-09Fredrik Hübinette (Hubbe) #endif
329cc01997-02-17Fredrik Hübinette (Hubbe)  args=count_arguments(type); if(args < 0) { args=~args; vargs=IDENTIFIER_VARARGS; }else{ vargs=0; }
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  if(compiler_pass==1)
329cc01997-02-17Fredrik Hübinette (Hubbe)  {
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  tmp.offset=-1; }else{ n=mknode(F_ARG_LIST,n,0); if((foo=is_stupid_func(n, args, vargs)))
329cc01997-02-17Fredrik Hübinette (Hubbe)  {
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  if(foo->type == T_FUNCTION && foo->subtype==FUNCTION_BUILTIN) { tmp.c_fun=foo->u.efun->function; ret=define_function(name, type, modifiers, IDENTIFIER_C_FUNCTION | vargs, &tmp); free_node(n); return ret; }
329cc01997-02-17Fredrik Hübinette (Hubbe)  }
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  tmp.offset=PC; add_to_program(compiler_frame->max_number_of_locals); add_to_program(args);
329cc01997-02-17Fredrik Hübinette (Hubbe) 
5267b71995-08-09Fredrik Hübinette (Hubbe) #ifdef DEBUG
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  if(a_flag > 2) { fprintf(stderr,"Coding: "); print_tree(n); }
5267b71995-08-09Fredrik Hübinette (Hubbe) #endif
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  if(!num_parse_error) { do_code_block(n); }
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
329cc01997-02-17Fredrik Hübinette (Hubbe)  ret=define_function(name, type, modifiers, IDENTIFIER_PIKE_FUNCTION | vargs, &tmp);
5267b71995-08-09Fredrik Hübinette (Hubbe)  free_node(n);
329cc01997-02-17Fredrik Hübinette (Hubbe)  return ret;
5267b71995-08-09Fredrik Hübinette (Hubbe) }
66d51c1997-03-04Fredrik Hübinette (Hubbe)