pike.git / src / docode.c

version» Context lines:

pike.git/src/docode.c:1: + #include "machine.h" + #include <stdlib.h> + #include <stdio.h> + #include "config.h" + #include "las.h" + #include "program.h" + #include "language.h" + #include "lpc_types.h" + #include "stralloc.h" + #include "interpret.h" + #include "add_efun.h" + #include "array.h" + #include "macros.h" + #include "error.h" + #include "memory.h" + #include "svalue.h" + #include "main.h" + #include "lex.h" + #include "builtin_efuns.h"    -  + int *break_stack=0; + static int current_break,break_stack_size; + int *continue_stack=0; + static int current_continue,continue_stack_size; +  + static INT32 current_switch_case; + static INT32 current_switch_default; + static INT32 current_switch_values_on_stack; + static INT32 *current_switch_jumptable =0; +  + void ins_byte(unsigned char b,int area) + { +  add_to_mem_block(area, (char *)&b, 1); + } +  + void ins_signed_byte(char b,int area) + { +  add_to_mem_block(area, (char *)&b, 1); + } +  + void ins_short(INT16 l,int area) + { +  add_to_mem_block(area, (char *)&l, sizeof(INT16)); + } +  + static void upd_short(int offset, INT16 l) + { + #ifdef HANDLES_UNALIGNED_MEMORY_ACCESS +  *((INT16 *)(areas[A_PROGRAM].s.str+offset))=l; + #else +  areas[A_PROGRAM].s.str[offset + 0] = ((char *)&l)[0]; +  areas[A_PROGRAM].s.str[offset + 1] = ((char *)&l)[1]; + #endif + } +  + static void upd_int(int offset, INT32 tmp) + { + #ifdef HANDLES_UNALIGNED_MEMORY_ACCESS +  *((int *)(areas[A_PROGRAM].s.str+offset))=tmp; + #else +  areas[A_PROGRAM].s.str[offset + 0] = ((char *)&tmp)[0]; +  areas[A_PROGRAM].s.str[offset + 1] = ((char *)&tmp)[1]; +  areas[A_PROGRAM].s.str[offset + 2] = ((char *)&tmp)[2]; +  areas[A_PROGRAM].s.str[offset + 3] = ((char *)&tmp)[3]; + #endif + } +  + /* +  * Store a 4 byte number. It is stored in such a way as to be sure +  * that correct byte order is used, regardless of machine architecture. +  */ + void ins_long(long l,int area) + { +  add_to_mem_block(area, (char *)&l+0, sizeof(long)); + } +  + int store_linenumbers=1; +  + static void low_ins_f_byte(unsigned int b) + { +  if(store_linenumbers) store_linenumber(); +  + #if defined(LASDEBUG) +  if(lasdebug>1) +  if(store_linenumbers) +  fprintf(stderr,"Inserting f_byte %s (%d) at %ld\n", +  get_instruction_name(b), b, +  (long)PC); + #endif +  b-=F_OFFSET; + #ifdef OPCPROF +  if(store_linenumbers) add_compiled(b); + #endif +  if(b>255) +  { +  switch(b >> 8) +  { +  case 1: low_ins_f_byte(F_ADD_256); break; +  case 2: low_ins_f_byte(F_ADD_512); break; +  case 3: low_ins_f_byte(F_ADD_768); break; +  case 4: low_ins_f_byte(F_ADD_1024); break; +  default: +  low_ins_f_byte(F_ADD_256X); +  ins_byte(b/256,A_PROGRAM); +  } +  b&=255; +  } +  ins_byte((unsigned char)b,A_PROGRAM); + } +  + void ins_f_byte(unsigned int b) + { + #ifdef DEBUG +  if(a_flag>2) +  fprintf(stderr,">%6lx: %s\n",PC,get_f_name(b)); + #endif +  low_ins_f_byte(b); + } +  + static void ins_f_byte_with_numerical_arg(unsigned int a,unsigned int b) + { +  switch(b >> 8) +  { +  case 0 : break; +  case 1 : low_ins_f_byte(F_PREFIX_256); break; +  case 2 : low_ins_f_byte(F_PREFIX_512); break; +  case 3 : low_ins_f_byte(F_PREFIX_768); break; +  case 4 : low_ins_f_byte(F_PREFIX_1024); break; +  default: +  if( b < 256*256) +  { +  low_ins_f_byte(F_PREFIX_CHARX256); +  ins_byte(b>>8, A_PROGRAM); +  }else if(b < 256*256*256) { +  low_ins_f_byte(F_PREFIX_WORDX256); +  ins_byte(b >> 16, A_PROGRAM); +  ins_byte(b >> 8, A_PROGRAM); +  }else{ +  low_ins_f_byte(F_PREFIX_24BITX256); +  ins_byte(b >> 24, A_PROGRAM); +  ins_byte(b >> 16, A_PROGRAM); +  ins_byte(b >> 8, A_PROGRAM); +  } +  } +  ins_f_byte(a); + #ifdef DEBUG +  if(a_flag>2) +  fprintf(stderr,">%6lx: argument = %u\n",PC,b); + #endif +  ins_byte(b, A_PROGRAM); + } +  +  + static void ins_int(int i) + { +  switch(i) +  { +  case 0: ins_f_byte(F_CONST0); break; +  case 1: ins_f_byte(F_CONST1); break; +  case -1: ins_f_byte(F_CONST_1); break; +  default: +  if(i<0) +  { +  ins_f_byte_with_numerical_arg(F_NEG_NUMBER,-i); +  }else{ +  ins_f_byte_with_numerical_arg(F_NUMBER,i); +  } +  } + } +  + static void ins_float(FLOAT_TYPE f) + { +  ins_f_byte(F_FLOAT); +  add_to_mem_block(A_PROGRAM,(char *)&f,sizeof(FLOAT_TYPE)); + } +  + /* +  * A mechanism to remember addresses on a stack. The size of the stack is +  * defined in config.h. +  */ + int comp_stackp; + INT32 comp_stack[COMPILER_STACK_SIZE]; +  + void push_address() + { +  if (comp_stackp >= COMPILER_STACK_SIZE) +  { +  yyerror("Compiler stack overflow"); +  comp_stackp++; +  return; +  } +  comp_stack[comp_stackp++] = PC; + } +  + void push_explicit(INT32 address) + { +  if (comp_stackp >= COMPILER_STACK_SIZE) +  { +  yyerror("Compiler stack overflow"); +  comp_stackp++; +  return; +  } +  comp_stack[comp_stackp++] = address; + } +  + INT32 pop_address() + { +  if (comp_stackp == 0) +  fatal("Compiler stack underflow.\n"); +  if (comp_stackp > COMPILER_STACK_SIZE) +  { +  --comp_stackp; +  return 0; +  } +  return comp_stack[--comp_stackp]; + } +  + static void do_pop(int nr) + { +  if(!nr) return; +  if(nr==1) +  { +  ins_f_byte(F_POP_VALUE); +  }else if(nr<256){ +  ins_f_byte(F_POP_N_ELEMS); +  ins_byte(nr,A_PROGRAM); +  }else{ +  ins_f_byte(F_POP_N_ELEMS); +  ins_byte(255,A_PROGRAM); +  do_pop(nr-255); +  } + } +  + /* routines to optimize jumps */ +  + #define JUMP_CONDITIONAL 1 + #define JUMP_UNSET 2 +  + struct jump + { +  INT32 relative; +  INT32 whereto; +  INT32 wherefrom; +  INT32 address; +  unsigned char flags; +  short token; + }; +  + static int jump_ptr=0, max_jumps=0; + static struct jump jumps[256]; +  + static void low_set_branch(INT32 address,INT32 whereto,INT32 relative) + { +  int j,e; +  +  if(address<0) return; +  j=jump_ptr; +  e=max_jumps; +  while(e>=0) +  { +  if(jumps[j].address==address && (jumps[j].flags & JUMP_UNSET)) +  break; +  if(j) j--; else j=max_jumps; +  e--; +  } +  if(e<0) j=-1; /* not found */ +  +  for(e=0;e<=max_jumps;e++) +  { +  if(jumps[e].flags & JUMP_UNSET) continue; +  if(jumps[e].flags & JUMP_CONDITIONAL) continue; +  if(jumps[e].wherefrom!=whereto) continue; + #if defined(LASDEBUG) +  if(lasdebug>1) printf("Optimized Jump to a jump\n"); + #endif +  whereto=jumps[e].whereto; +  break; +  } +  +  if(j>=0) +  { +  if(!(jumps[j].flags & JUMP_CONDITIONAL)) +  { +  for(e=0;e<=max_jumps;e++) +  { +  if(jumps[e].flags & JUMP_UNSET) continue; +  if(jumps[e].whereto==jumps[j].wherefrom) +  { +  upd_int(jumps[e].address,whereto - jumps[e].relative); +  jumps[e].whereto=whereto; + #if defined(LASDEBUG) +  if(lasdebug>1) printf("Optimized Jump to a jump\n"); + #endif +  } +  } +  } +  jumps[j].relative=relative; +  jumps[j].whereto=whereto; +  jumps[j].flags&=~JUMP_UNSET; +  } +  upd_int(address,whereto - relative); + } +  + static void set_branch(INT32 address,INT32 whereto) + { +  low_set_branch(address,whereto,address); + } +  + static INT32 do_jump(int token,INT32 whereto) + { +  jump_ptr=(jump_ptr+1)%NELEM(jumps); +  if(jump_ptr>max_jumps) max_jumps=jump_ptr; +  +  jumps[jump_ptr].flags=JUMP_UNSET; +  jumps[jump_ptr].whereto=-1; +  jumps[jump_ptr].token=token; +  +  if(token!=F_BRANCH) +  jumps[jump_ptr].flags|=JUMP_CONDITIONAL; +  +  if(token>=0) +  { +  jumps[jump_ptr].wherefrom=PC; +  ins_f_byte(token); +  }else{ +  jumps[jump_ptr].wherefrom=-1; +  } +  jumps[jump_ptr].relative=PC; +  jumps[jump_ptr].address=PC; +  ins_long(0, A_PROGRAM); +  if(whereto!=-1) set_branch(jumps[jump_ptr].address, whereto); +  return jumps[jump_ptr].address; + } +  + static void clean_jumptable() { max_jumps=jump_ptr=-1; } +  + static void push_break_stack() + { +  push_explicit((int)break_stack); +  push_explicit(current_break); +  push_explicit(break_stack_size); +  break_stack_size=10; +  break_stack=(int *)xalloc(sizeof(int)*break_stack_size); +  current_break=0; + } +  + static void pop_break_stack(int jump) + { +  for(current_break--;current_break>=0;current_break--) +  set_branch(break_stack[current_break],jump); +  +  free((char *)break_stack); +  break_stack_size=pop_address(); +  current_break=pop_address(); +  break_stack=(int *)pop_address(); + } +  + static void push_continue_stack() + { +  push_explicit((int)continue_stack); +  push_explicit(current_continue); +  push_explicit(continue_stack_size); +  continue_stack_size=10; +  continue_stack=(int *)xalloc(sizeof(int)*continue_stack_size); +  current_continue=0; + } +  + static void pop_continue_stack(int jump) + { +  for(current_continue--;current_continue>=0;current_continue--) +  set_branch(continue_stack[current_continue],jump); +  +  free((char *)continue_stack); +  continue_stack_size=pop_address(); +  current_continue=pop_address(); +  continue_stack=(int *)pop_address(); + } +  + static int do_docode2(node *n,int flags); +  + #define DO_LVALUE 1 + #define DO_NOT_COPY 2 + #define DO_POP 4 +  + #define DO_CODE_BLOCK(N) do_pop(do_docode(N,DO_NOT_COPY | DO_POP)) +  + static int do_docode(node *n,INT16 flags) + { +  int i; +  int save_current_line=current_line; +  if(!n) return 0; +  current_line=n->line_number; +  i=do_docode2(n, flags); +  +  current_line=save_current_line; +  return i; + } +  +  + int docode(node *n) + { +  clean_jumptable(); +  return do_docode(n,0); + } +  + static INT32 do_jump_when_zero(node *n,int j); +  + static int do_jump_when_non_zero(node *n,int j) + { +  if(!node_is_tossable(n)) +  { +  if(node_is_true(n)) +  return do_jump(F_BRANCH,j); +  +  if(node_is_false(n)) +  return -1; +  } +  +  if(n->token == F_NOT) +  return do_jump_when_zero(CAR(n), j); +  +  if(do_docode(n, DO_NOT_COPY)!=1) +  fatal("Infernal compiler skiterror.\n"); +  return do_jump(F_BRANCH_WHEN_NON_ZERO,j); + } +  + static INT32 do_jump_when_zero(node *n,int j) + { +  if(!node_is_tossable(n)) +  { +  if(node_is_true(n)) +  return -1; +  +  if(node_is_false(n)) +  return do_jump(F_BRANCH,j); +  } +  +  if(n->token == F_NOT) +  return do_jump_when_non_zero(CAR(n), j); +  +  if(do_docode(n, DO_NOT_COPY)!=1) +  fatal("Infernal compiler skiterror.\n"); +  return do_jump(F_BRANCH_WHEN_ZERO,j); + } +  + static INT32 count_cases(node *n) + { +  INT32 ret; +  if(!n) return 0; +  switch(n->token) +  { +  case F_DO: +  case F_FOR: +  case F_FOREACH: +  case F_INC_LOOP: +  case F_DEC_LOOP: +  case F_INC_NEQ_LOOP: +  case F_DEC_NEQ_LOOP: +  case F_SWITCH: +  case '?': +  return 0; +  +  case F_CASE: +  return !!CAR(n)+!!CDR(n); +  +  default: +  ret=0; +  if(car_is_node(n)) ret += count_cases(CAR(n)); +  if(cdr_is_node(n)) ret += count_cases(CDR(n)); +  return ret; +  } + } +  + static int do_docode2(node *n,int flags) + { +  INT32 tmp1,tmp2,tmp3; +  +  if(!n) return 0; +  +  if(flags & DO_LVALUE) +  { +  switch(n->token) +  { +  default: +  yyerror("Illegal lvalue."); +  ins_int(0); +  return 1; +  +  case F_LVALUE_LIST: +  case F_LOCAL: +  case F_GLOBAL: +  case F_IDENTIFIER: +  case F_INDEX: +  case F_ARG_LIST: +  break; +  } +  } +  +  switch(n->token) +  { +  case F_PUSH_ARRAY: +  tmp1=do_docode(CAR(n),0); +  if(tmp1!=1) +  { +  fatal("Internal compiler error, Yikes!\n"); +  } +  ins_f_byte(F_PUSH_ARRAY); +  return -0x7ffffff; +  +  case '?': +  { +  if(!CDDR(n)) +  { +  tmp1=do_jump_when_zero(CAR(n), -1); +  DO_CODE_BLOCK(CADR(n)); +  set_branch(tmp1, PC); +  return 0; +  } +  +  if(!CADR(n)) +  { +  tmp1=do_jump_when_non_zero(CAR(n), -1); +  DO_CODE_BLOCK(CDDR(n)); +  set_branch(tmp1, PC); +  return 0; +  } +  +  tmp1=count_args(CDDR(n)); +  tmp2=count_args(CADR(n)); +  +  if(tmp2 < tmp1) tmp1=tmp2; +  +  tmp2=do_jump_when_zero(CAR(n),-1); +  +  tmp3=do_docode(CADR(n), flags); +  if(tmp3 < tmp1) fatal("Count arguments was wrong.\n"); +  do_pop(tmp3 - tmp1); +  +  tmp3=do_jump(F_BRANCH,-1); +  set_branch(tmp2, PC); +  +  tmp2=do_docode(CDDR(n), flags); +  if(tmp2 < tmp1) fatal("Count arguments was wrong.\n"); +  do_pop(tmp2 - tmp1); +  set_branch(tmp3, PC); +  return tmp1; +  } +  +  case F_AND_EQ: +  case F_OR_EQ: +  case F_XOR_EQ: +  case F_LSH_EQ: +  case F_RSH_EQ: +  case F_ADD_EQ: +  case F_SUB_EQ: +  case F_MULT_EQ: +  case F_MOD_EQ: +  case F_DIV_EQ: +  tmp1=do_docode(CAR(n),DO_LVALUE); + #ifdef DEBUG +  if(tmp1 != 2) +  fatal("HELP! FATAL INTERNAL COMPILER ERROR\n"); + #endif +  +  if(CAR(n)->type->str[0] == T_ARRAY) +  { +  if(do_docode(CDR(n), 0)!=1) +  fatal("Internal compiler error, shit happens\n"); +  ins_f_byte(F_LTOSVAL2); +  }else{ +  ins_f_byte(F_LTOSVAL); +  if(do_docode(CDR(n), 0)!=1) +  fatal("Internal compiler error, shit happens (again)\n"); +  } +  +  +  switch(n->token) +  { +  case F_ADD_EQ: ins_f_byte(F_ADD); break; +  case F_AND_EQ: ins_f_byte(F_AND); break; +  case F_OR_EQ: ins_f_byte(F_OR); break; +  case F_XOR_EQ: ins_f_byte(F_XOR); break; +  case F_LSH_EQ: ins_f_byte(F_LSH); break; +  case F_RSH_EQ: ins_f_byte(F_RSH); break; +  case F_SUB_EQ: ins_f_byte(F_SUBTRACT); break; +  case F_MULT_EQ:ins_f_byte(F_MULTIPLY);break; +  case F_MOD_EQ: ins_f_byte(F_MOD); break; +  case F_DIV_EQ: ins_f_byte(F_DIVIDE); break; +  } +  +  if(flags & DO_POP) +  { +  ins_f_byte(F_ASSIGN_AND_POP); +  return 0; +  }else{ +  ins_f_byte(F_ASSIGN); +  return 1; +  } +  +  case F_ASSIGN: +  switch(CAR(n)->token) +  { +  case F_AND: +  case F_OR: +  case F_XOR: +  case F_LSH: +  case F_RSH: +  case F_ADD: +  case F_MOD: +  case F_SUBTRACT: +  case F_DIVIDE: +  case F_MULTIPLY: +  if(node_is_eq(CDR(n),CAAR(n))) +  { +  tmp1=do_docode(CDR(n),DO_LVALUE); +  if(match_types(CDR(n)->type,array_type_string)) +  { +  if(do_docode(CDAR(n),DO_NOT_COPY)!=1) +  fatal("Infernal compiler error (dumpar core |ver hela mattan).\n"); +  ins_f_byte(F_LTOSVAL2); +  }else{ +  ins_f_byte(F_LTOSVAL); +  if(do_docode(CDAR(n),DO_NOT_COPY)!=1) +  fatal("Infernal compiler error (dumpar core).\n"); +  } +  +  ins_f_byte(CAR(n)->token); +  +  ins_f_byte(n->token); +  return n->token==F_ASSIGN; +  } +  +  default: +  if(CDR(n)->token!=F_LOCAL && CDR(n)->token!=F_GLOBAL) +  tmp1=do_docode(CDR(n),DO_LVALUE); +  +  if(do_docode(CAR(n),0)!=1) +  yyerror("RHS is void!"); +  +  switch(CDR(n)->token) +  { +  case F_LOCAL: +  ins_f_byte(flags & DO_POP ? F_ASSIGN_LOCAL_AND_POP:F_ASSIGN_LOCAL); +  ins_byte(CDR(n)->u.number,A_PROGRAM); +  break; +  +  case F_GLOBAL: +  ins_f_byte(flags & DO_POP ? F_ASSIGN_GLOBAL_AND_POP:F_ASSIGN_GLOBAL); +  ins_byte(CDR(n)->u.number,A_PROGRAM); +  break; +  +  default: +  ins_f_byte(flags & DO_POP ? F_ASSIGN_AND_POP:F_ASSIGN); +  break; +  } +  return flags & DO_POP ? 0 : 1; +  } +  +  case F_LAND: +  case F_LOR: +  if(do_docode(CAR(n),0)!=1) +  fatal("Compiler internal error.\n"); +  tmp1=do_jump(n->token,-1); +  if(do_docode(CDR(n),0)!=1) +  fatal("Compiler internal error.\n"); +  set_branch(tmp1,PC); +  return 1; +  +  case F_EQ: +  case F_NE: +  if(flags & DO_POP) +  { +  do_pop(do_docode(CAR(n),DO_NOT_COPY|DO_POP)+ +  do_docode(CDR(n),DO_NOT_COPY|DO_POP)); +  return 0; +  } +  tmp1=do_docode(CAR(n),0); +  if(do_docode(CDR(n),0)!=1) +  fatal("Compiler internal error (gnng!).\n"); +  ins_f_byte(n->token); +  return tmp1; +  +  case F_ADD: +  case F_LT: +  case F_LE: +  case F_GT: +  case F_GE: +  case F_SUBTRACT: +  case F_MULTIPLY: +  case F_DIVIDE: +  case F_MOD: +  case F_LSH: +  case F_RSH: +  case F_XOR: +  case F_OR: +  case F_AND: +  if(flags & DO_POP) +  { +  do_pop(do_docode(CAR(n),DO_NOT_COPY|DO_POP)+ +  do_docode(CDR(n),DO_NOT_COPY|DO_POP)); +  return 0; +  } +  tmp1=do_docode(CAR(n),DO_NOT_COPY); +  if(do_docode(CDR(n),DO_NOT_COPY)!=1) +  fatal("Compiler internal error.\n"); +  ins_f_byte(n->token); +  return tmp1; +  +  case F_RANGE: +  tmp1=do_docode(CAR(n),DO_NOT_COPY); +  if(do_docode(CDR(n),DO_NOT_COPY)!=2) +  fatal("Compiler internal error.\n"); +  ins_f_byte(n->token); +  return tmp1; +  +  case F_INC: +  case F_POST_INC: +  tmp1=do_docode(CAR(n),DO_LVALUE); + #ifdef DEBUG +  if(tmp1 != 2) +  fatal("HELP! FATAL INTERNAL COMPILER ERROR\n"); + #endif +  +  if(flags & DO_POP) +  { +  ins_f_byte(F_INC_AND_POP); +  return 0; +  }else{ +  ins_f_byte(n->token); +  return 1; +  } +  +  case F_DEC: +  case F_POST_DEC: +  tmp1=do_docode(CAR(n),DO_LVALUE); + #ifdef DEBUG +  if(tmp1 != 2) +  fatal("HELP! FATAL INTERNAL COMPILER ERROR\n"); + #endif +  if(flags & DO_POP) +  { +  ins_f_byte(F_DEC_AND_POP); +  return 0; +  }else{ +  ins_f_byte(n->token); +  return 1; +  } +  +  case F_NOT: +  case F_COMPL: +  case F_NEGATE: +  tmp1=do_docode(CAR(n),DO_NOT_COPY | (flags & ~DO_LVALUE)); +  if(flags & DO_POP) +  { +  do_pop(tmp1); +  return 0; +  } +  ins_f_byte(n->token); +  return tmp1; +  +  case F_FOR: +  { +  INT32 *prev_switch_jumptable = current_switch_jumptable; +  current_switch_jumptable=0; +  +  push_break_stack(); +  push_continue_stack(); +  if(CDR(n)) +  { +  tmp1=do_jump(F_BRANCH,-1); +  tmp2=PC; +  if(CDR(n)) DO_CODE_BLOCK(CADR(n)); +  pop_continue_stack(PC); +  if(CDR(n)) DO_CODE_BLOCK(CDDR(n)); +  set_branch(tmp1,PC); +  }else{ +  tmp2=PC; +  } +  do_jump_when_non_zero(CAR(n),tmp2); +  pop_break_stack(PC); +  +  current_switch_jumptable = prev_switch_jumptable; +  return 0; +  } +  +  case ' ': +  return do_docode(CAR(n),0)+do_docode(CDR(n),DO_LVALUE); +  +  case F_FOREACH: +  { +  INT32 *prev_switch_jumptable = current_switch_jumptable; +  current_switch_jumptable=0; +  +  tmp2=do_docode(CAR(n),DO_NOT_COPY); +  ins_f_byte(F_CONST0); +  tmp3=do_jump(F_BRANCH,-1); +  tmp1=PC; +  push_break_stack(); +  push_continue_stack(); +  DO_CODE_BLOCK(CDR(n)); +  pop_continue_stack(PC); +  set_branch(tmp3,PC); +  do_jump(n->token,tmp1); +  pop_break_stack(PC); +  +  current_switch_jumptable = prev_switch_jumptable; +  return 0; +  } +  +  case F_INC_NEQ_LOOP: +  case F_DEC_NEQ_LOOP: +  case F_INC_LOOP: +  case F_DEC_LOOP: +  { +  INT32 *prev_switch_jumptable = current_switch_jumptable; +  current_switch_jumptable=0; +  +  tmp2=do_docode(CAR(n),0); +  tmp3=do_jump(F_BRANCH,-1); +  tmp1=PC; +  push_break_stack(); +  push_continue_stack(); +  DO_CODE_BLOCK(CDR(n)); +  pop_continue_stack(PC); +  set_branch(tmp3,PC); +  do_jump(n->token,tmp1); +  pop_break_stack(PC); +  +  current_switch_jumptable = prev_switch_jumptable; +  return 0; +  } +  +  case F_DO: +  { +  INT32 *prev_switch_jumptable = current_switch_jumptable; +  current_switch_jumptable=0; +  +  tmp2=PC; +  push_break_stack(); +  push_continue_stack(); +  DO_CODE_BLOCK(CAR(n)); +  pop_continue_stack(PC); +  do_jump_when_non_zero(CDR(n),tmp2); +  pop_break_stack(PC); +  +  current_switch_jumptable = prev_switch_jumptable; +  return 0; +  } +  +  case F_CAST: +  if(n->type==void_type_string) +  { +  DO_CODE_BLOCK(CAR(n)); +  return 0; +  } +  +  tmp1=do_docode(CAR(n),0); +  if(!tmp1) { ins_f_byte(F_CONST0); tmp1=1; } +  if(tmp1>1) do_pop(tmp1-1); +  +  tmp1=store_prog_string(n->type); +  ins_f_byte_with_numerical_arg(F_STRING,tmp1); +  ins_f_byte(F_CAST); +  return 1; +  +  case F_APPLY: +  ins_f_byte(F_MARK); +  if(CAR(n)->token == F_CONSTANT) +  { +  do_docode(CDR(n),0); +  if(CAR(n)->u.sval.type == T_FUNCTION && +  CAR(n)->u.sval.subtype != -1 && +  CAR(n)->u.sval.u.object == &fake_object) +  { +  ins_f_byte_with_numerical_arg(F_CALL_LFUN, CAR(n)->u.sval.subtype); +  }else{ +  tmp1=store_constant(& CAR(n)->u.sval); +  ins_f_byte(F_MAX_OPCODE + tmp1); +  if(n->type == void_type_string) return 0; +  } +  return 1; +  } +  else if(CAR(n)->token == F_IDENTIFIER && +  ID_FROM_INT(& fake_program, CAR(n)->u.number)->flags & IDENTIFIER_FUNCTION) +  { +  do_docode(CDR(n),0); +  ins_f_byte_with_numerical_arg(F_CALL_LFUN, CAR(n)->u.number); +  return 1; +  } +  else +  { +  struct lpc_string *tmp; +  struct efun *fun; +  +  tmp=make_shared_string("call_function"); +  if(!tmp) yyerror("No call_function efun."); +  fun=lookup_efun(tmp); +  if(!fun) yyerror("No call_function efun."); +  free_string(tmp); +  +  do_docode(CAR(n),0); +  do_docode(CDR(n),0); +  tmp1=store_constant(& fun->function); +  ins_f_byte(tmp1 + F_MAX_OPCODE); +  return 1; +  } +  +  case F_ARG_LIST: +  tmp1=do_docode(CAR(n),flags & ~DO_LVALUE); +  tmp1+=do_docode(CDR(n),flags); +  return tmp1; +  +  +  /* Switch: +  * So far all switches are implemented with a binsearch lookup. +  * It stores the case values in the programs area for constants. +  * It also has a jump-table in the program itself, for every index in +  * the array of cases, there is 2 indexes in the jumptable, and one extra. +  * The first entry in the jumptable is used if you call switch with +  * a value that is ranked lower than all the indexes in the array of +  * cases. (Ranked by the binsearch that is) The second is used if it +  * is equal to the first index. The third if it is greater than the +  * first, but lesser than the second. The fourth if it is equal to +  * the second.... etc. etc. +  */ +  +  case F_SWITCH: +  { +  INT32 e,cases,*order; +  INT32 *jumptable; +  INT32 prev_switch_values_on_stack = current_switch_values_on_stack; +  INT32 prev_switch_case = current_switch_case; +  INT32 prev_switch_default = current_switch_default; +  INT32 *prev_switch_jumptable = current_switch_jumptable; +  +  if(do_docode(CAR(n),0)!=1) +  fatal("Internal compiler error, time to panic\n"); +  +  push_break_stack(); +  +  cases=count_cases(CDR(n)); +  +  ins_f_byte(F_SWITCH); +  tmp1=PC; +  ins_short(0, A_PROGRAM); +  while(PC != (unsigned int)ALIGN(PC)) ins_byte(0, A_PROGRAM); +  tmp2=PC; +  current_switch_values_on_stack=0; +  current_switch_case=0; +  current_switch_default=-1; +  current_switch_jumptable=(INT32 *)xalloc(sizeof(INT32)*(cases*2+1)); +  jumptable=(INT32 *)xalloc(sizeof(INT32)*(cases*2+1)); +  +  for(e=0; e<cases*2+1; e++) +  { +  jumptable[e]=do_jump(-1,-1); +  current_switch_jumptable[e]=-1; +  } +  +  current_switch_jumptable[current_switch_case++]=-1; +  +  DO_CODE_BLOCK(CDR(n)); +  +  f_aggregate(cases); +  sp[-1].u.array=compact_array(sp[-1].u.array); +  order=get_switch_order(sp[-1].u.array); +  +  for(e=0; e<cases-1; e++) +  { +  if(current_switch_jumptable[order[e]*2+2] != -1) +  { +  if(current_switch_jumptable[order[e]*2+2] != +  current_switch_jumptable[order[e+1]*2+1]) +  yyerror("Case inside range."); +  } +  } +  +  if(current_switch_default < 0) current_switch_default = PC; +  +  for(e=0;e<cases*2+1;e++) +  if(current_switch_jumptable[e]==-1) +  current_switch_jumptable[e]=current_switch_default; +  +  sp[-1].u.array=order_array(sp[-1].u.array,order); +  +  reorder((void *)(current_switch_jumptable+1),cases,sizeof(INT32)*2,order); +  free((char *)order); +  +  for(e=0; e<cases*2+1; e++) +  low_set_branch(jumptable[e], current_switch_jumptable[e],tmp2); +  +  e=store_constant(sp-1); +  upd_short(tmp1,e); +  +  pop_stack(); +  free((char *)jumptable); +  free((char *)current_switch_jumptable); +  +  current_switch_jumptable = prev_switch_jumptable; +  current_switch_default = prev_switch_default; +  current_switch_case = prev_switch_case; +  current_switch_values_on_stack = prev_switch_values_on_stack ; +  +  pop_break_stack(PC); +  +  return 0; +  } +  +  case F_CASE: +  { +  if(!current_switch_jumptable) +  { +  yyerror("Case outside switch."); +  }else{ +  if(!is_const(CAR(n))) +  yyerror("Case label isn't constant."); +  +  tmp1=eval_low(CAR(n)); +  if(tmp1<1) +  { +  yyerror("Error in case label."); +  return 0; +  } +  pop_n_elems(tmp1-1); +  current_switch_values_on_stack++; +  for(tmp1=current_switch_values_on_stack; tmp1 > 1; tmp1--) +  if(is_equal(sp-tmp1, sp-1)) +  yyerror("Duplicate case."); +  +  current_switch_jumptable[current_switch_case++]=PC; +  +  if(CDR(n)) +  { +  current_switch_jumptable[current_switch_case++]=PC; +  tmp1=eval_low(CDR(n)); +  if(tmp1<1) +  { +  pop_stack(); +  yyerror("Error in case label."); +  return 0; +  } +  pop_n_elems(tmp1-1); +  current_switch_values_on_stack++; +  for(tmp1=current_switch_values_on_stack; tmp1 > 1; tmp1--) +  if(is_equal(sp-tmp1, sp-1)) +  yyerror("Duplicate case."); +  current_switch_jumptable[current_switch_case++]=PC; +  } +  current_switch_jumptable[current_switch_case++]=-1; +  } +  return 0; +  } +  +  case F_DEFAULT: +  if(!current_switch_jumptable) +  { +  yyerror("Default outside switch."); +  }else if(current_switch_default!=-1){ +  yyerror("Duplicate switch default."); +  }else{ +  current_switch_default = PC; +  } +  return 0; +  +  case F_BREAK: +  if(!break_stack) +  { +  yyerror("Break outside loop or switch."); +  }else{ +  if(current_break>=break_stack_size) +  { +  break_stack_size*=2; +  break_stack=(int *)realloc((char *)break_stack, +  sizeof(int)*break_stack_size); +  if(!break_stack) +  fatal("Out of memory.\n"); +  } +  break_stack[current_break++]=do_jump(F_BRANCH,-1); +  } +  return 0; +  +  case F_CONTINUE: +  if(!continue_stack) +  { +  yyerror("continue outside loop or switch."); +  }else{ +  if(current_continue>=continue_stack_size) +  { +  continue_stack_size*=2; +  continue_stack=(int *)realloc((char *)continue_stack, +  sizeof(int)*continue_stack_size); +  } +  continue_stack[current_continue++]=do_jump(F_BRANCH,-1); +  } +  return 0; +  +  case F_RETURN: +  if(!CAR(n) || +  (CAR(n)->token == F_CONSTANT && IS_ZERO(&CAR(n)->u.sval)) || +  do_docode(CAR(n),0)<0) +  { +  ins_f_byte(F_RETURN_0); +  }else{ +  ins_f_byte(F_RETURN); +  } +  return 0; +  +  case F_SSCANF: +  tmp1=do_docode(CAR(n),DO_NOT_COPY); +  tmp2=do_docode(CDR(n),DO_NOT_COPY | DO_LVALUE); +  ins_f_byte_with_numerical_arg(F_SSCANF,tmp1+tmp2); +  return 1; +  +  case F_CATCH: +  { +  INT32 *prev_switch_jumptable = current_switch_jumptable; +  current_switch_jumptable=0; +  +  tmp1=do_jump(F_CATCH,-1); +  push_break_stack(); +  push_continue_stack(); +  DO_CODE_BLOCK(CAR(n)); +  pop_continue_stack(PC); +  pop_break_stack(PC); +  ins_f_byte(F_DUMB_RETURN); +  set_branch(tmp1,PC); +  +  current_switch_jumptable = prev_switch_jumptable; +  return 1; +  } +  +  case F_LVALUE_LIST: +  return do_docode(CAR(n),DO_LVALUE)+do_docode(CDR(n),DO_LVALUE); +  +  case F_INDEX: +  if(flags & DO_LVALUE) +  { +  tmp1=do_docode(CAR(n), 0); +  if(do_docode(CDR(n),0) != 1) +  fatal("Internal compiler error, please report this (1)."); +  return 2; +  }else{ +  tmp1=do_docode(CAR(n), DO_NOT_COPY); +  if(do_docode(CDR(n),DO_NOT_COPY) != 1) +  fatal("Internal compiler error, please report this (1)."); +  ins_f_byte(F_INDEX); +  if(!(flags & DO_NOT_COPY)) +  { +  while(n && n->token==F_INDEX) n=CAR(n); +  if(n->token==F_CONSTANT) +  ins_f_byte(F_COPY_VALUE); +  } +  } +  return tmp1; +  +  case F_CONSTANT: +  switch(n->u.sval.type) +  { +  case T_INT: +  ins_int(n->u.sval.u.integer); +  return 1; +  +  case T_FLOAT: +  ins_float(n->u.sval.u.float_number); +  return 1; +  +  case T_STRING: +  tmp1=store_prog_string(n->u.sval.u.string); +  ins_f_byte_with_numerical_arg(F_STRING,tmp1); +  return 1; +  +  case T_FUNCTION: +  if(n->u.sval.subtype!=-1) +  { +  if(n->u.sval.u.object == &fake_object) +  { +  ins_f_byte_with_numerical_arg(F_LFUN,n->u.sval.subtype); +  return 1; +  } +  } +  +  default: +  tmp1=store_constant(&(n->u.sval)); +  ins_f_byte_with_numerical_arg(F_CONSTANT,tmp1); +  return 1; +  +  case T_ARRAY: +  case T_MAPPING: +  case T_LIST: +  tmp1=store_constant(&(n->u.sval)); +  ins_f_byte_with_numerical_arg(F_CONSTANT,tmp1); +  if(!(flags & DO_NOT_COPY)) /* copy later */ +  ins_f_byte(F_COPY_VALUE); +  return 1; +  +  } +  +  case F_LOCAL: +  if(flags & DO_LVALUE) +  { +  ins_f_byte_with_numerical_arg(F_LOCAL_LVALUE,n->u.number); +  return 2; +  }else{ +  ins_f_byte_with_numerical_arg(F_LOCAL,n->u.number); +  return 1; +  } +  +  case F_IDENTIFIER: +  if(ID_FROM_INT(& fake_program, n->u.number)->flags & IDENTIFIER_FUNCTION) +  { +  if(flags & DO_LVALUE) +  { +  yyerror("Cannot assign functions.\n"); +  }else{ +  ins_f_byte_with_numerical_arg(F_LFUN,n->u.number); +  } +  }else{ +  if(flags & DO_LVALUE) +  { +  ins_f_byte_with_numerical_arg(F_GLOBAL_LVALUE,n->u.number); +  return 2; +  }else{ +  ins_f_byte_with_numerical_arg(F_GLOBAL,n->u.number); +  } +  } +  return 1; +  +  case F_EFUN: +  ins_f_byte_with_numerical_arg(n->token,n->u.number); +  return 1; +  +  case F_VAL_LVAL: +  return do_docode(CAR(n),flags)+do_docode(CDR(n),flags | DO_LVALUE); +  +  default: +  fatal("Infernal compiler error (unknown parse-tree-token).\n"); +  return 0; /* make gcc happy */ +  } + } +  + void do_code_block(node *n) + { +  clean_jumptable(); +  DO_CODE_BLOCK(n); + }   Newline at end of file added.