pike.git
/
src
/
docode.c
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/src/docode.c:1:
-
/*
-
|| This file is part of Pike. For copyright information see COPYRIGHT.
-
|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING
-
|| for more information.
-
*/
+
-
#include "global.h"
-
#include "las.h"
-
#include "program.h"
-
#include "pike_types.h"
-
#include "stralloc.h"
-
#include "interpret.h"
-
#include "constants.h"
-
#include "array.h"
-
#include "pike_macros.h"
-
#include "pike_error.h"
-
#include "pike_memory.h"
-
#include "svalue.h"
-
#include "pike_embed.h"
-
#include "builtin_functions.h"
-
#include "peep.h"
-
#include "docode.h"
-
#include "operators.h"
-
#include "object.h"
-
#include "opcodes.h"
-
#include "lex.h"
-
#include "mapping.h"
-
#include "multiset.h"
-
#include "pike_compiler.h"
-
-
static int do_docode2(node *n, int flags);
-
-
typedef void (*cleanup_func)(void *);
-
-
struct cleanup_frame
-
{
-
struct cleanup_frame *prev;
-
cleanup_func cleanup;
-
void *cleanup_arg;
-
int stack_depth;
-
};
-
-
struct statement_label_name
-
{
-
struct statement_label_name *next;
-
struct pike_string *str;
-
struct pike_string *file;
-
INT_TYPE line_number;
-
int used;
-
};
-
-
struct statement_label
-
{
-
struct statement_label *prev;
-
struct statement_label_name *name;
-
/* -2 in break_label is used to flag "open" statement_label entries.
-
* If an open entry is on top of the stack, it's used instead of a
-
* new one. That's used to associate statement labels to the
-
* following statement. */
-
INT32 break_label, continue_label;
-
int emit_break_label;
-
int stack_depth;
-
struct cleanup_frame *cleanups;
-
};
-
-
static struct statement_label top_statement_label_dummy =
-
{0, 0, -1, -1, 0, -1, 0};
-
static struct statement_label *current_label = &top_statement_label_dummy;
-
#ifdef PIKE_DEBUG
-
static int current_stack_depth = -4711;
-
#else
-
static int current_stack_depth = 0;
-
#endif
-
-
#define PUSH_CLEANUP_FRAME(func, arg) do { \
-
struct cleanup_frame cleanup_frame__; \
-
cleanup_frame__.cleanup = (cleanup_func) (func); \
-
cleanup_frame__.cleanup_arg = (void *)(ptrdiff_t) (arg); \
-
cleanup_frame__.stack_depth = current_stack_depth; \
-
DO_IF_DEBUG( \
-
if (current_label->cleanups == (void *)(ptrdiff_t) -1) \
-
Pike_fatal("current_label points to an unused statement_label.\n"); \
-
) \
-
if (current_label->break_label == -2) { \
-
DO_IF_DEBUG( \
-
if (current_label->prev->break_label == -2) \
-
Pike_fatal("Found two open statement_label entries in a row.\n"); \
-
) \
-
cleanup_frame__.prev = current_label->prev->cleanups; \
-
current_label->prev->cleanups = &cleanup_frame__; \
-
} \
-
else { \
-
cleanup_frame__.prev = current_label->cleanups; \
-
current_label->cleanups = &cleanup_frame__; \
-
}
-
-
#define POP_AND_DONT_CLEANUP \
-
if (current_label->cleanups == &cleanup_frame__) \
-
current_label->cleanups = cleanup_frame__.prev; \
-
else { \
-
DO_IF_DEBUG( \
-
if (current_label->prev->cleanups != &cleanup_frame__) \
-
Pike_fatal("Cleanup frame lost from statement_label cleanup list.\n");\
-
) \
-
current_label->prev->cleanups = cleanup_frame__.prev; \
-
} \
-
} while (0)
-
-
#define POP_AND_DO_CLEANUP \
-
do_pop(current_stack_depth - cleanup_frame__.stack_depth); \
-
cleanup_frame__.cleanup(cleanup_frame__.cleanup_arg); \
-
POP_AND_DONT_CLEANUP
-
-
/* A block in the following sense is a region of code where:
-
* o Execution always enters at the beginning.
-
* o All stack nesting is left intact on exit (both normally and
-
* through jumps, but not through exceptions). This includes the
-
* svalue and mark stacks, and the catch block nesting.
-
*/
-
#ifdef PIKE_DEBUG
-
#define BLOCK_BEGIN \
-
PUSH_CLEANUP_FRAME(do_cleanup_synch_mark, 0); \
-
if (d_flag > 2) emit0(F_SYNCH_MARK);
-
#define BLOCK_END \
-
if (current_stack_depth != cleanup_frame__.stack_depth) { \
-
print_tree(n); \
-
Pike_fatal("Stack not in synch after block: is %d, should be %d.\n", \
-
current_stack_depth, cleanup_frame__.stack_depth); \
-
} \
-
if (d_flag > 2) emit0(F_POP_SYNCH_MARK); \
-
POP_AND_DONT_CLEANUP
-
#else
-
#define BLOCK_BEGIN
-
#define BLOCK_END
-
#endif
-
-
#define PUSH_STATEMENT_LABEL do { \
-
struct statement_label new_label__; \
-
new_label__.prev = current_label; \
-
if (current_label->break_label != -2) { \
-
/* Only cover the current label if it's closed. */ \
-
new_label__.name = 0; \
-
new_label__.break_label = new_label__.continue_label = -1; \
-
new_label__.emit_break_label = 0; \
-
new_label__.cleanups = 0; \
-
new_label__.stack_depth = current_stack_depth; \
-
current_label = &new_label__; \
-
} \
-
else { \
-
DO_IF_DEBUG( \
-
new_label__.cleanups = (void *)(ptrdiff_t) -1; \
-
new_label__.stack_depth = current_stack_depth; \
-
) \
-
current_label->stack_depth = current_stack_depth; \
-
}
-
-
#define POP_STATEMENT_LABEL \
-
current_label = new_label__.prev; \
-
DO_IF_DEBUG( \
-
if (new_label__.cleanups && \
-
new_label__.cleanups != (void *)(ptrdiff_t) -1) \
-
Pike_fatal("Cleanup frames still left in statement_label.\n")); \
-
} while (0)
-
-
struct switch_data
-
{
-
INT32 index;
-
INT32 less_label, greater_label, default_label;
-
INT32 values_on_stack;
-
INT32 *jumptable;
-
struct pike_type *type;
-
};
-
-
static struct switch_data current_switch = {0, 0, 0, 0, 0, NULL, NULL};
-
-
void upd_int(int offset, INT32 tmp)
-
{
-
memcpy(Pike_compiler->new_program->program+offset, &tmp, sizeof(tmp));
-
}
-
-
INT32 read_int(int offset)
-
{
-
return (INT32)get_unaligned32(Pike_compiler->new_program->program+offset);
-
}
-
-
static int label_no=0;
-
-
int alloc_label(void) { return ++label_no; }
-
-
int do_jump(int token,INT32 lbl)
-
{
-
struct compilation *c = THIS_COMPILATION;
-
if(lbl==-1) lbl=alloc_label();
-
emit1(token, lbl);
-
return lbl;
-
}
-
-
-
#define LBLCACHESIZE 4711
-
#define CURRENT_INSTR (buffer_content_length(&instrbuf) / sizeof(p_instr))
-
#define MAX_UNWIND 100
-
-
static int lbl_cache[LBLCACHESIZE];
-
-
static int do_branch(INT32 lbl)
-
{
-
struct compilation *c = THIS_COMPILATION;
-
if(lbl==-1)
-
{
-
lbl=alloc_label();
-
}else{
-
INT32 last,pos=lbl_cache[lbl % LBLCACHESIZE];
-
if(pos < (last=CURRENT_INSTR) && (CURRENT_INSTR - pos) < MAX_UNWIND)
-
{
-
#define BUF ((p_instr *)buffer_ptr(&instrbuf))
-
if(BUF[pos].opcode == F_LABEL && BUF[pos].arg == lbl)
-
{
-
for(;pos < last;pos++)
-
{
-
if(BUF[pos].opcode != F_LABEL)
-
{
-
insert_opcode2(BUF[pos].opcode,
-
BUF[pos].arg,
-
BUF[pos].arg2,
-
BUF[pos].line,
-
BUF[pos].file);
-
}
-
}
-
}
-
}
-
-
}
-
emit1(F_BRANCH, lbl);
-
return lbl;
-
}
-
-
static void low_insert_label(int lbl)
-
{
-
struct compilation *c = THIS_COMPILATION;
-
lbl_cache[ lbl % LBLCACHESIZE ] = CURRENT_INSTR;
-
emit1(F_LABEL, lbl);
-
}
-
-
static int ins_label(int lbl)
-
{
-
if(lbl==-1) lbl=alloc_label();
-
low_insert_label(lbl);
-
return lbl;
-
}
-
-
void modify_stack_depth(int delta)
-
{
-
current_stack_depth += delta;
-
#ifdef PIKE_DEBUG
-
if (current_stack_depth < 0) {
-
Pike_fatal("Popped out of virtual stack.\n");
-
}
-
#endif
-
}
-
-
void do_pop(int x)
-
{
-
struct compilation *c = THIS_COMPILATION;
-
#ifdef PIKE_DEBUG
-
if (x < 0) Pike_fatal("Cannot do pop of %d args.\n", x);
-
#endif
-
switch(x)
-
{
-
case 0: return;
-
case 1: emit0(F_POP_VALUE); break;
-
default: emit1(F_POP_N_ELEMS,x); break;
-
}
-
modify_stack_depth(-x);
-
}
-
-
static void do_pop_mark(void *UNUSED(ignored))
-
{
-
struct compilation *c = THIS_COMPILATION;
-
emit0(F_POP_MARK);
-
}
-
-
static void do_pop_to_mark(void *UNUSED(ignored))
-
{
-
struct compilation *c = THIS_COMPILATION;
-
emit0(F_POP_TO_MARK);
-
}
-
-
#ifdef PIKE_DEBUG
-
static void do_cleanup_synch_mark(void)
-
{
-
struct compilation *c = THIS_COMPILATION;
-
if (d_flag > 2)
-
emit0(F_CLEANUP_SYNCH_MARK);
-
}
-
#endif
-
-
static void do_escape_catch(void)
-
{
-
struct compilation *c = THIS_COMPILATION;
-
emit0(F_ESCAPE_CATCH);
-
}
-
-
#define DO_CODE_BLOCK(X) do_pop(do_docode((X),DO_NOT_COPY | DO_POP ))
-
-
int do_docode(node *n, int flags)
-
{
-
int i;
-
int stack_depth_save = current_stack_depth;
-
struct compilation *c = THIS_COMPILATION;
-
INT_TYPE save_current_line = c->lex.current_line;
-
struct pike_string *save_current_file = c->lex.current_file;
-
if(!n) return 0;
-
c->lex.current_line=n->line_number;
-
c->lex.current_file = n->current_file;
-
#ifdef PIKE_DEBUG
-
if (current_stack_depth == -4711) Pike_fatal("do_docode() used outside docode().\n");
-
#endif
-
i=do_docode2(n, flags);
-
current_stack_depth = stack_depth_save + i;
-
-
c->lex.current_file = save_current_file;
-
c->lex.current_line=save_current_line;
-
return i;
-
}
-
-
static int is_efun(node *n, c_fun fun)
-
{
-
return n && n->token == F_CONSTANT &&
-
SUBTYPEOF(n->u.sval) == FUNCTION_BUILTIN &&
-
n->u.sval.u.efun->function == fun;
-
}
-
-
static void code_expression(node *n, int flags, char *err)
-
{
-
switch(do_docode(n, flags & ~DO_POP))
-
{
-
case 0: my_yyerror("Void expression for %s",err);
-
case 1: return;
-
case 2:
-
Pike_fatal("Internal compiler error (%s), line %ld, file %s\n",
-
err,
-
(long)THIS_COMPILATION->lex.current_line,
-
THIS_COMPILATION->lex.current_file->str);
-
}
-
}
-
-
static void do_cond_jump(node *n, int label, int iftrue, int flags)
-
{
-
iftrue=!!iftrue;
-
if((flags & DO_POP) && node_is_tossable(n))
-
{
-
int t,f;
-
t=!!node_is_true(n);
-
f=!!node_is_false(n);
-
if(t || f)
-
{
-
if(t == iftrue) do_branch( label);
-
return;
-
}
-
}
-
-
switch(n->token)
-
{
-
case F_LAND:
-
case F_LOR:
-
if(iftrue == (n->token==F_LAND))
-
{
-
int tmp=alloc_label();
-
do_cond_jump(CAR(n), tmp, !iftrue, flags | DO_POP);
-
do_cond_jump(CDR(n), label, iftrue, flags);
-
low_insert_label(tmp);
-
}else{
-
do_cond_jump(CAR(n), label, iftrue, flags);
-
do_cond_jump(CDR(n), label, iftrue, flags);
-
}
-
return;
-
-
case F_APPLY:
-
if(!is_efun(CAR(n), f_not)) break;
-
/* FALLTHRU */
-
-
case F_NOT:
-
if(!(flags & DO_POP)) break;
-
do_cond_jump(CDR(n), label , !iftrue, flags | DO_NOT_COPY);
-
return;
-
default:
-
/* Inform gcc that we handle all the values in the enum. */
-
break;
-
}
-
-
code_expression(n, flags | DO_NOT_COPY, "condition");
-
-
if(flags & DO_POP)
-
{
-
if(iftrue)
-
do_jump(F_BRANCH_WHEN_NON_ZERO, label);
-
else
-
do_jump(F_BRANCH_WHEN_ZERO, label);
-
modify_stack_depth(-1);
-
}else{
-
if(iftrue)
-
do_jump(F_LOR, label);
-
else
-
do_jump(F_LAND, label);
-
}
-
}
-
-
#define do_jump_when_zero(N,L) do_cond_jump(N,L,0,DO_POP|DO_NOT_COPY)
-
#define do_jump_when_non_zero(N,L) do_cond_jump(N,L,1,DO_POP|DO_NOT_COPY)
-
-
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_LOOP:
-
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 1;
-
case F_CASE_RANGE:
-
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 has_automap(node *n)
-
{
-
if(!n) return 0;
-
switch(n->token)
-
{
-
case F_AUTO_MAP_MARKER:
-
case F_AUTO_MAP:
-
return 1;
-
-
default:
-
if(car_is_node(n) && has_automap(CAR(n)) )
-
return 1;
-
if( cdr_is_node(n) && has_automap(CDR(n)) )
-
return 1;
-
}
-
return 0;
-
}
-
-
-
int generate_call_function(node *n)
-
{
-
struct compilation *c = THIS_COMPILATION;
-
emit0(F_MARK);
-
PUSH_CLEANUP_FRAME(do_pop_mark, 0);
-
do_docode(CDR(n),DO_NOT_COPY);
-
emit0(F_CALL_FUNCTION);
-
POP_AND_DONT_CLEANUP;
-
return 1;
-
}
-
-
static struct compiler_frame *find_local_frame(INT32 depth)
-
{
-
struct compiler_frame *f=Pike_compiler->compiler_frame;
-
while(--depth>=0) f=f->previous;
-
return f;
-
}
-
-
/* Emit code for a function call to the identifier reference #id,
-
* with the arguments specified by args.
-
*/
-
static int do_lfun_call(int id, node *args)
-
{
-
struct compilation *c = THIS_COMPILATION;
-
struct reference *ref =
-
Pike_compiler->new_program->identifier_references + id;
-
-
if((Pike_compiler->compiler_frame->current_function_number >= 0) &&
-
((id == Pike_compiler->compiler_frame->current_function_number) ||
-
((!ref->inherit_offset) &&
-
(ref->identifier_offset ==
-
Pike_compiler->new_program->
-
identifier_references[Pike_compiler->compiler_frame->
-
current_function_number].identifier_offset))) &&
-
!(Pike_compiler->new_program->
-
identifiers[ref->identifier_offset].identifier_flags &
-
(IDENTIFIER_VARARGS|IDENTIFIER_SCOPE_USED)) &&
-
!(Pike_compiler->compiler_frame->lexical_scope & SCOPE_SCOPE_USED))
-
{
-
PUSH_CLEANUP_FRAME(do_pop_mark, 0);
-
emit0(F_MARK);
-
do_docode(args,0);
-
-
/* Test description:
-
*
-
* * Test if we have a valid current function.
-
*
-
* * Quick check if id is the current function.
-
*
-
* * Check if id is an alternate reference to the current function.
-
*
-
* * Check that the function isn't varargs or contains scoped functions.
-
*
-
* * Check that the current function doesn't contain scoped functions.
-
*/
-
if(Pike_compiler->compiler_frame->is_inline || (ref->id_flags & (ID_INLINE|ID_PRIVATE)))
-
{
-
/* Identifier is declared inline/local
-
* or in inlining pass.
-
*/
-
if ((ref->id_flags & (ID_INLINE|ID_PRIVATE)) &&
-
(!Pike_compiler->compiler_frame->is_inline)) {
-
/* Explicit local:: reference in first pass.
-
*
-
* RECUR directly to label 0.
-
*
-
* Note that we in this case don't know if we are overloaded or
-
* not, and thus can't RECUR to the recur_label.
-
*/
-
do_jump(F_RECUR, 0);
-
} else {
-
Pike_compiler->compiler_frame->recur_label =
-
do_jump(F_RECUR, Pike_compiler->compiler_frame->recur_label);
-
}
-
} else {
-
/* Recur if not overloaded. */
-
emit1(F_COND_RECUR,id);
-
Pike_compiler->compiler_frame->recur_label =
-
do_jump(F_POINTER, Pike_compiler->compiler_frame->recur_label);
-
}
-
POP_AND_DONT_CLEANUP;
-
return 1;
-
}
-
else {
-
#ifdef USE_APPLY_N
-
int nargs = count_args(args);
-
if( nargs == -1 )
-
{
-
#endif
-
PUSH_CLEANUP_FRAME(do_pop_mark, 0);
-
emit0(F_MARK);
-
do_docode(args,0);
-
emit1(F_CALL_LFUN, id);
-
POP_AND_DONT_CLEANUP;
-
return 1;
-
#ifdef USE_APPLY_N
-
}
-
else
-
{
-
do_docode(args,0);
-
emit2(F_CALL_LFUN_N, id, nargs);
-
}
-
#endif
-
}
-
return 1;
-
}
-
-
/*
-
* FIXME: this can be optimized, but is not really used
-
* enough to be worth it yet.
-
*/
-
static void emit_apply_builtin(char *func)
-
{
-
INT32 tmp1;
-
struct compilation *c = THIS_COMPILATION;
-
struct pike_string *n1=make_shared_string(func);
-
node *n=find_module_identifier(n1,0);
-
free_string(n1);
-
-
switch(n?n->token:0)
-
{
-
case F_CONSTANT:
-
tmp1=store_constant(&n->u.sval,
-
!(n->tree_info & OPT_EXTERNAL_DEPEND),
-
n->name);
-
if(TYPEOF(n->u.sval) == T_FUNCTION &&
-
SUBTYPEOF(n->u.sval) == FUNCTION_BUILTIN)
-
emit1(F_CALL_BUILTIN, (INT32)tmp1);
-
else
-
emit1(F_APPLY, (INT32)tmp1);
-
break;
-
-
default:
-
my_yyerror("docode: Failed to make call to %s",func);
-
}
-
free_node(n);
-
}
-
-
static int do_encode_automap_arg_list(node *n,
-
int flags)
-
{
-
struct compilation *c = THIS_COMPILATION;
-
int stack_depth_save = current_stack_depth;
-
if(!n) return 0;
-
switch(n->token)
-
{
-
default:
-
return do_docode(n, flags);
-
-
case F_ARG_LIST:
-
{
-
int ret;
-
ret=do_encode_automap_arg_list(CAR(n), flags);
-
current_stack_depth=stack_depth_save + ret;
-
ret+=do_encode_automap_arg_list(CDR(n), flags);
-
current_stack_depth=stack_depth_save + ret;
-
return ret;
-
}
-
-
case F_AUTO_MAP_MARKER:
-
{
-
int depth=0;
-
while(n->token == F_AUTO_MAP_MARKER)
-
{
-
n=CAR(n);
-
depth++;
-
}
-
emit0(F_MARK);
-
code_expression(n, 0, "[*]");
-
emit1(F_NUMBER, depth);
-
emit_apply_builtin("__builtin.automap_marker");
-
return 1;
-
}
-
}
-
}
-
-
static void emit_builtin_svalue(char *func)
-
{
-
INT32 tmp1;
-
struct compilation *c = THIS_COMPILATION;
-
struct pike_string *n1=make_shared_string(func);
-
node *n=find_module_identifier(n1,0);
-
free_string(n1);
-
-
switch(n?n->token:0)
-
{
-
case F_CONSTANT:
-
tmp1=store_constant(&n->u.sval,
-
(!(n->tree_info & OPT_EXTERNAL_DEPEND)) &&
-
(TYPEOF(n->u.sval) != T_TYPE),
-
n->name);
-
emit1(F_CONSTANT, (INT32)tmp1);
-
break;
-
-
default:
-
my_yyerror("docode: Failed to make svalue for builtin %s",func);
-
}
-
free_node(n);
-
}
-
-
static void emit_range (node *n DO_IF_DEBUG (COMMA int num_args))
-
{
-
struct compilation *c = THIS_COMPILATION;
-
node *low = CADR (n), *high = CDDR (n);
-
int bound_types = 0; /* Got bogus gcc warning here. */
-
-
switch (low->token) {
-
case F_RANGE_FROM_BEG: bound_types = RANGE_LOW_FROM_BEG; break;
-
case F_RANGE_FROM_END: bound_types = RANGE_LOW_FROM_END; break;
-
case F_RANGE_OPEN: bound_types = RANGE_LOW_OPEN; break;
-
#ifdef PIKE_DEBUG
-
default:
-
Pike_fatal ("Unexpected node %d as range lower bound.\n", low->token);
-
#endif
-
}
-
-
switch (high->token) {
-
case F_RANGE_FROM_BEG: bound_types |= RANGE_HIGH_FROM_BEG; break;
-
case F_RANGE_FROM_END: bound_types |= RANGE_HIGH_FROM_END; break;
-
case F_RANGE_OPEN: bound_types |= RANGE_HIGH_OPEN; break;
-
#ifdef PIKE_DEBUG
-
default:
-
Pike_fatal ("Unexpected node %d as range upper bound.\n", high->token);
-
#endif
-
}
-
-
#ifdef PIKE_DEBUG
-
{
-
int expected_args = 0;
-
switch (bound_types & (RANGE_LOW_OPEN|RANGE_HIGH_OPEN)) {
-
case 0:
-
expected_args = 2; break;
-
case RANGE_LOW_OPEN:
-
case RANGE_HIGH_OPEN:
-
expected_args = 1; break;
-
case RANGE_LOW_OPEN|RANGE_HIGH_OPEN:
-
expected_args = 0; break;
-
}
-
if (num_args != expected_args)
-
Pike_fatal ("Wrong number of args to o_range opcode. Expected %d, got %d.\n",
-
expected_args, num_args);
-
}
-
#endif
-
-
emit1 (F_RANGE, bound_types);
-
}
-
-
static void emit_global( int n )
-
{
-
struct compilation *c = THIS_COMPILATION;
-
struct reference *ref = PTR_FROM_INT(Pike_compiler->new_program, n);
-
struct identifier *id = ID_FROM_PTR(Pike_compiler->new_program, ref);
-
-
if(!(id->identifier_flags & IDENTIFIER_NO_THIS_REF)
-
&& !ref->inherit_offset
-
&& !IDENTIFIER_IS_ALIAS(id->identifier_flags)
-
&& IDENTIFIER_IS_VARIABLE(id->identifier_flags))
-
{
-
/* fprintf( stderr, "private global %d\n", (INT32)id->func.offset ); */
-
if( ref->id_flags & (ID_PRIVATE|ID_FINAL) )
-
{
-
if( id->run_time_type == PIKE_T_MIXED )
-
emit1(F_PRIVATE_GLOBAL, id->func.offset);
-
else
-
emit2(F_PRIVATE_TYPED_GLOBAL, id->func.offset, id->run_time_type);
-
return;
-
}
-
-
if( id->run_time_type == PIKE_T_MIXED )
-
{
-
emit2(F_PRIVATE_IF_DIRECT_GLOBAL, id->func.offset, n);
-
return;
-
}
-
/* else if( (id->func.offset < 65536) && (n<65536) ) */
-
/* { */
-
/* INT32 mix = id->func.offset | (n<<16); */
-
/* emit2(F_PRIVATE_IF_DIRECT_TYPED_GLOBAL, mix, id->run_time_type); */
-
/* } */
-
}
-
emit1(F_GLOBAL, n);
-
}
-
-
static void emit_assign_global( int n, int and_pop )
-
{
-
struct compilation *c = THIS_COMPILATION;
-
struct reference *ref = PTR_FROM_INT(Pike_compiler->new_program, n);
-
struct identifier *id = ID_FROM_PTR(Pike_compiler->new_program, ref);
-
-
if( !(id->identifier_flags & IDENTIFIER_NO_THIS_REF)
-
&& !ref->inherit_offset
-
&& !IDENTIFIER_IS_ALIAS(id->identifier_flags)
-
&& IDENTIFIER_IS_VARIABLE(id->identifier_flags))
-
{
-
if( (ref->id_flags & (ID_PRIVATE|ID_FINAL)) )
-
{
-
if( id->run_time_type == PIKE_T_MIXED )
-
emit1((and_pop?F_ASSIGN_PRIVATE_GLOBAL_AND_POP:F_ASSIGN_PRIVATE_GLOBAL),
-
id->func.offset);
-
else
-
emit2((and_pop?F_ASSIGN_PRIVATE_TYPED_GLOBAL_AND_POP:F_ASSIGN_PRIVATE_TYPED_GLOBAL),
-
id->func.offset, id->run_time_type);
-
return;
-
}
-
if( id->run_time_type == PIKE_T_MIXED )
-
{
-
emit2(F_ASSIGN_PRIVATE_IF_DIRECT_GLOBAL, id->func.offset, n );
-
if( and_pop )
-
emit0(F_POP_VALUE);
-
return;
-
}
-
}
-
emit1((and_pop?F_ASSIGN_GLOBAL_AND_POP:F_ASSIGN_GLOBAL), n);
-
}
-
-
static int emit_ltosval_call_and_assign( node *lval, node *func, node *args )
-
{
-
struct compilation *c = THIS_COMPILATION;
-
node **arg;
-
int no = 0;
-
int tmp1=store_constant(&func->u.sval,
-
!(func->tree_info & OPT_EXTERNAL_DEPEND),
-
func->name);
-
-
-
#ifdef PIKE_DEBUG
-
arg = my_get_arg(&args,0);
-
if( !node_is_eq(*arg,lval) )
-
Pike_fatal("lval should be the same as arg1, or this will not work.\n");
-
#endif
-
do_docode(lval, DO_LVALUE);
-
emit0(F_MARK);
-
emit0(F_CONST0);
-
PUSH_CLEANUP_FRAME(do_pop_mark, 0);
-
while ((arg = my_get_arg(&args, ++no)) && *arg) {
-
do_docode(*arg, 0);
-
}
-
emit1(F_LTOSVAL_CALL_BUILTIN_AND_ASSIGN, (INT32)tmp1);
-
POP_AND_DONT_CLEANUP;
-
return 1;
-
}
-
-
static int is_apply_constant_function_arg0( node *n, node *target )
-
{
-
if (/*n->token == F_APPLY &&*/
-
(CAR(n)->token == F_CONSTANT) &&
-
(TYPEOF(CAR(n)->u.sval) == T_FUNCTION) &&
-
(SUBTYPEOF(CAR(n)->u.sval) == FUNCTION_BUILTIN) &&
-
(CAR(n)->u.sval.u.efun->function != f_map) &&
-
(CAR(n)->u.sval.u.efun->function != f_filter)) {
-
/* efuns typically don't access object variables. */
-
node *args = CDR(n), **arg;
-
if (args)
-
{
-
arg = my_get_arg(&args, 0);
-
if (arg && node_is_eq(target, *arg) &&
-
!(args->tree_info & OPT_ASSIGNMENT))
-
{
-
if(match_types(target->type, array_type_string) ||
-
match_types(target->type, string_type_string) ||
-
match_types(target->type, object_type_string) ||
-
match_types(target->type, multiset_type_string) ||
-
match_types(target->type, mapping_type_string))
-
{
-
return emit_ltosval_call_and_assign(target,CAR(n),args);
-
}
-
}
-
}
-
}
-
return 0;
-
}
-
-
static void emit_multi_assign(node *vals, node *vars, int no)
-
{
-
struct compilation *c = THIS_COMPILATION;
-
node *var;
-
node *val;
-
node **valp = my_get_arg(&vals, no);
-
-
if (!vars && (!valp || !*valp)) return;
-
if (!(vars && valp && (val = *valp))) {
-
yyerror("Argument count mismatch for multi-assignment.\n");
-
return;
-
}
-
-
if (vars->token == F_LVALUE_LIST) {
-
var = CAR(vars);
-
vars = CDR(vars);
-
} else {
-
var = vars;
-
vars = NULL;
-
}
-
-
switch(var->token) {
-
case F_LOCAL:
-
if(var->u.integer.a >=
-
find_local_frame(var->u.integer.b)->max_number_of_locals)
-
yyerror("Illegal to use local variable here.");
-
-
if(var->u.integer.b) goto normal_assign;
-
-
if (var->node_info & OPT_ASSIGNMENT) {
-
/* Initialize. */
-
emit0(F_CONST0);
-
emit1(F_ASSIGN_LOCAL_AND_POP, var->u.integer.a);
-
}
-
code_expression(val, 0, "RHS");
-
emit_multi_assign(vals, vars, no+1);
-
emit1(F_ASSIGN_LOCAL_AND_POP, var->u.integer.a );
-
break;
-
-
case F_GET_SET:
-
{
-
/* Check for the setter function. */
-
struct program_state *state = Pike_compiler;
-
int program_id = var->u.integer.a;
-
int level = 0;
-
while (state && (state->new_program->id != program_id)) {
-
state = state->previous;
-
level++;
-
}
-
if (!state) {
-
yyerror("Lost parent.");
-
} else {
-
struct reference *ref =
-
PTR_FROM_INT(state->new_program, var->u.integer.b);
-
struct identifier *id =
-
ID_FROM_PTR(state->new_program, ref);
-
struct inherit *inh =
-
INHERIT_FROM_PTR(state->new_program, ref);
-
int f;
-
#ifdef PIKE_DEBUG
-
if (!IDENTIFIER_IS_VARIABLE(id->identifier_flags) ||
-
(id->run_time_type != PIKE_T_GET_SET)) {
-
Pike_fatal("Not a getter/setter in a F_GET_SET node!\n"
-
" identifier_flags: 0x%08x\n"
-
" run_time_type; %s (%d)\n",
-
id->identifier_flags,
-
get_name_of_type(id->run_time_type),
-
id->run_time_type);
-
}
-
#endif /* PIKE_DEBUG */
-
f = id->func.gs_info.setter;
-
if (f == -1) {
-
yywarning("Variable %S lacks a setter.", id->name);
-
} else if (!level) {
-
f += inh->identifier_level;
-
emit0(F_MARK);
-
code_expression(val, 0, "RHS");
-
emit_multi_assign(vals, vars, no+1);
-
emit1(F_CALL_LFUN, f);
-
emit0(F_POP_VALUE);
-
}
-
}
-
}
-
/* FALLTHRU */
-
case F_EXTERNAL:
-
/* Check that it is in this context */
-
if(Pike_compiler ->new_program->id == var->u.integer.a)
-
{
-
/* Check that it is a variable */
-
if(var->u.integer.b != IDREF_MAGIC_THIS &&
-
IDENTIFIER_IS_VARIABLE( ID_FROM_INT(Pike_compiler->new_program, var->u.integer.b)->identifier_flags))
-
{
-
code_expression(val, 0, "RHS");
-
emit_multi_assign(vals, vars, no+1);
-
emit_assign_global( var->u.integer.b, 1 );
-
break;
-
}
-
}
-
/* fall through */
-
-
default:
-
normal_assign:
-
do_docode(var, DO_LVALUE);
-
if(do_docode(val, 0) != 1) yyerror("RHS is void!");
-
emit_multi_assign(vals, vars, no+1);
-
emit0(F_ASSIGN_AND_POP);
-
break;
-
}
-
}
-
-
static int do_docode2(node *n, int flags)
-
{
-
struct compilation *c = THIS_COMPILATION;
-
ptrdiff_t tmp1,tmp2,tmp3;
-
int ret;
-
-
if(!n) return 0;
-
-
if(flags & DO_LVALUE)
-
{
-
switch(n->token)
-
{
-
default:
-
yyerror("Illegal lvalue.");
-
emit1(F_NUMBER,0);
-
emit1(F_NUMBER,0);
-
return 2;
-
-
case F_ARRAY_LVALUE:
-
case F_LVALUE_LIST:
-
case F_LOCAL:
-
case F_GLOBAL:
-
case F_INDEX:
-
case F_ARROW:
-
case F_ARG_LIST:
-
case F_COMMA_EXPR:
-
case F_EXTERNAL:
-
case F_GET_SET:
-
case F_AUTO_MAP_MARKER:
-
break;
-
}
-
}
-
-
if(flags & DO_LVALUE_IF_POSSIBLE)
-
{
-
flags|=DO_INDIRECT;
-
flags &=~DO_LVALUE_IF_POSSIBLE;
-
}else{
-
flags &=~DO_INDIRECT;
-
}
-
-
/* Stack check */
-
{
-
ptrdiff_t x_= ((char *)&x_) + STACK_DIRECTION * (32768) -
-
Pike_interpreter.stack_top ;
-
x_*=STACK_DIRECTION;
-
if(x_>0)
-
{
-
yyerror("Too deep recursion in compiler. (please report this)");
-
-
emit1(F_NUMBER,0);
-
if(flags & DO_LVALUE)
-
{
-
emit1(F_NUMBER,0);
-
return 2;
-
}
-
return 1;
-
}
-
}
-
-
switch(n->token)
-
{
-
case F_MAGIC_INDEX:
-
case F_MAGIC_SET_INDEX:
-
case F_MAGIC_INDICES:
-
case F_MAGIC_VALUES:
-
case F_MAGIC_TYPES:
-
case F_MAGIC_ANNOTATIONS:
-
emit2(n->token,
-
n->u.node.b->u.sval.u.integer,
-
n->u.node.a->u.sval.u.integer);
-
return 1;
-
-
case F_EXTERNAL:
-
case F_GET_SET:
-
{
-
int level = 0;
-
struct program_state *state = Pike_compiler;
-
while (state && (state->new_program->id != n->u.integer.a)) {
-
if ((flags & WANT_LVALUE) ||
-
(n->node_info & (OPT_EXTERNAL_DEPEND|OPT_NOT_CONST))) {
-
/* Not a reference to a locally bound external constant.
-
* We will thus need true parent pointers. */
-
state->new_program->flags |=
-
PROGRAM_USES_PARENT | PROGRAM_NEEDS_PARENT;
-
}
-
state = state->previous;
-
level++;
-
}
-
if (!state) {
-
my_yyerror("Program parent %d lost during compiling.", n->u.integer.a);
-
emit1(F_NUMBER,0);
-
} else if (flags & WANT_LVALUE) {
-
if (n->u.integer.b == IDREF_MAGIC_THIS) {
-
my_yyerror("this is not an lvalue.");
-
}
-
if (level) {
-
emit2(F_EXTERNAL_LVALUE, n->u.integer.b, level);
-
} else {
-
emit1(F_GLOBAL_LVALUE, n->u.integer.b);
-
}
-
return 2;
-
} else {
-
struct reference *ref =
-
PTR_FROM_INT(state->new_program, n->u.integer.b);
-
struct identifier *id =
-
ID_FROM_PTR(state->new_program, ref);
-
if (n->token == F_GET_SET) {
-
struct inherit *inh =
-
INHERIT_FROM_PTR(state->new_program, ref);
-
int f;
-
#ifdef PIKE_DEBUG
-
if (!IDENTIFIER_IS_VARIABLE(id->identifier_flags) ||
-
(id->run_time_type != PIKE_T_GET_SET)) {
-
Pike_fatal("Not a getter/setter in a F_GET_SET node!\n"
-
" identifier_flags: 0x%08x\n"
-
" run_time_type; %s (%d)\n",
-
id->identifier_flags,
-
get_name_of_type(id->run_time_type),
-
id->run_time_type);
-
}
-
#endif /* PIKE_DEBUG */
-
f = id->func.gs_info.getter;
-
if (f == -1) {
-
yywarning("Variable %S lacks a getter.", id->name);
-
} else if (!level) {
-
return do_lfun_call(f + inh->identifier_level, NULL);
-
} else {
-
/* FIXME: Support inlining for the parent case.
-
*
-
* do_call_external(n->u.integer.a, f + inh->identifier_level,
-
* NULL);
-
*/
-
emit2(F_EXTERNAL, n->u.integer.b, level);
-
}
-
} else if (level) {
-
if (IDENTIFIER_IS_CONSTANT(id->identifier_flags) &&
-
(ref->id_flags & ID_INLINE) &&
-
(id->func.const_info.offset >= 0)) {
-
/* An inline, local or final constant identifier in
-
* a lexically surrounding (aka parent) class.
-
* Avoid vtable traversal during runtime by moving
-
* the constant to this class.
-
*/
-
struct svalue *s = &state->new_program->
-
inherits[ref->inherit_offset].prog->
-
constants[id->func.const_info.offset].sval;
-
if (TYPEOF(*s) == T_PROGRAM &&
-
s->u.program->flags & PROGRAM_USES_PARENT) {
-
/* An external reference is required. */
-
emit2(F_EXTERNAL, n->u.integer.b, level);
-
} else {
-
int tmp1 = store_constant(s, 1, NULL);
-
emit1(F_CONSTANT, tmp1);
-
}
-
} else {
-
struct program_state *state = Pike_compiler;
-
int e;
-
for (e = level; e; e--) {
-
state->new_program->flags |=
-
PROGRAM_USES_PARENT|PROGRAM_NEEDS_PARENT;
-
state = state->previous;
-
}
-
emit2(F_EXTERNAL, n->u.integer.b, level);
-
}
-
} else if (n->u.integer.b == IDREF_MAGIC_THIS) {
-
emit1(F_THIS_OBJECT, 0);
-
} else if(IDENTIFIER_IS_FUNCTION(id->identifier_flags) &&
-
id->identifier_flags & IDENTIFIER_HAS_BODY)
-
{
-
/* Only use this opcode when it's certain that the result
-
* can't zero, i.e. when we know the function isn't just a
-
* prototype. */
-
emit1(F_LFUN, n->u.integer.b);
-
} else if (IDENTIFIER_IS_CONSTANT(id->identifier_flags) &&
-
(ref->id_flags & (ID_INLINE|ID_PRIVATE)) && !ref->inherit_offset &&
-
(id->func.const_info.offset >= 0)) {
-
/* An inline, local or final constant identifier.
-
* No need for vtable traversal during runtime.
-
*/
-
struct svalue *s = &state->new_program->
-
constants[id->func.const_info.offset].sval;
-
if (TYPEOF(*s) == T_PROGRAM &&
-
s->u.program->flags & PROGRAM_USES_PARENT) {
-
/* Program using parent. Convert to an LFUN. */
-
emit1(F_LFUN, n->u.integer.b);
-
} else {
-
emit1(F_CONSTANT, id->func.const_info.offset);
-
}
-
}else{
-
emit_global( n->u.integer.b );
-
}
-
}
-
}
-
return 1;
-
-
case F_THIS:
-
{
-
int level = 0;
-
struct program_state *state = Pike_compiler;
-
int inh = n->u.integer.b;
-
while (state && (state->new_program->id != n->u.integer.a)) {
-
state = state->previous;
-
level++;
-
}
-
if (!state) {
-
my_yyerror("Program parent %d lost during compiling.", n->u.integer.a);
-
emit1(F_NUMBER,0);
-
} else if (!level && (inh < 0)) {
-
emit1(F_THIS_OBJECT, 0);
-
} else {
-
emit2(F_THIS, level, inh);
-
}
-
return 1;
-
}
-
break;
-
-
case F_UNDEFINED:
-
yyerror("Undefined identifier");
-
emit1(F_NUMBER,0);
-
return 1;
-
-
case F_PUSH_ARRAY: {
-
if (current_label != &top_statement_label_dummy || current_label->cleanups) {
-
/* Might not have a surrounding apply node if evaluated as a
-
* constant by the optimizer. */
-
#ifdef PIKE_DEBUG
-
if (!current_label->cleanups ||
-
(current_label->cleanups->cleanup != do_pop_mark &&
-
current_label->cleanups->cleanup != do_pop_to_mark))
-
Pike_fatal("F_PUSH_ARRAY unexpected in this context.\n");
-
#endif
-
current_label->cleanups->cleanup = do_pop_to_mark;
-
}
-
code_expression(CAR(n), 0, "`@");
-
emit0(F_PUSH_ARRAY);
-
return 0;
-
}
-
-
case F_APPEND_ARRAY: {
-
emit0(F_MARK);
-
PUSH_CLEANUP_FRAME(do_pop_mark, 0);
-
do_docode(CAR(n),DO_LVALUE);
-
emit0(F_CONST0); /* Reserved for svalue. */
-
do_docode(CDR(n),0);
-
emit0(F_APPEND_ARRAY);
-
POP_AND_DONT_CLEANUP;
-
return 1;
-
}
-
-
case F_APPEND_MAPPING: {
-
emit0(F_MARK);
-
PUSH_CLEANUP_FRAME(do_pop_mark, 0);
-
do_docode(CAR(n),DO_LVALUE);
-
emit0(F_CONST0); /* Reserved for svalue. */
-
do_docode(CDR(n),0);
-
emit0(F_APPEND_MAPPING);
-
POP_AND_DONT_CLEANUP;
-
return 1;
-
}
-
-
case '?':
-
{
-
INT32 *prev_switch_jumptable = current_switch.jumptable;
-
int adroppings , bdroppings;
-
current_switch.jumptable=0;
-
-
if(!CDDR(n))
-
{
-
tmp1=alloc_label();
-
do_jump_when_zero(CAR(n), (INT32)tmp1);
-
DO_CODE_BLOCK(CADR(n));
-
low_insert_label( (INT32)tmp1 );
-
current_switch.jumptable = prev_switch_jumptable;
-
return 0;
-
}
-
-
if(!CADR(n))
-
{
-
tmp1=alloc_label();
-
do_jump_when_non_zero(CAR(n), (INT32)tmp1);
-
DO_CODE_BLOCK(CDDR(n));
-
low_insert_label( (INT32)tmp1 );
-
current_switch.jumptable = prev_switch_jumptable;
-
return 0;
-
}
-
-
tmp1=alloc_label();
-
do_jump_when_zero(CAR(n), (INT32)tmp1);
-
-
adroppings=do_docode(CADR(n), flags);
-
tmp3=emit1(F_POP_N_ELEMS,0);
-
-
/* Else */
-
tmp2=do_branch(-1);
-
low_insert_label( (INT32)tmp1 );
-
-
bdroppings=do_docode(CDDR(n), flags);
-
if(adroppings < bdroppings)
-
{
-
do_pop(bdroppings - adroppings);
-
}
-
-
if(adroppings > bdroppings)
-
{
-
update_arg((INT32)tmp3, adroppings - bdroppings);
-
adroppings=bdroppings;
-
}
-
-
low_insert_label( (INT32)tmp2 );
-
-
current_switch.jumptable = prev_switch_jumptable;
-
return adroppings;
-
}
-
-
case F_MULTI_ASSIGN:
-
if (flags & DO_POP) {
-
emit_multi_assign(CDR(n), CAR(n), 0);
-
return 0;
-
} else {
-
/* Fall back to the normal assign case. */
-
tmp1=do_docode(CAR(n),DO_LVALUE);
-
#ifdef PIKE_DEBUG
-
if(tmp1 & 1)
-
Pike_fatal("Very internal compiler error.\n");
-
#endif
-
emit1(F_ARRAY_LVALUE, (INT32)(tmp1>>1) );
-
emit0(F_MARK);
-
PUSH_CLEANUP_FRAME(do_pop_mark, 0);
-
do_docode(CDR(n), 0);
-
emit_apply_builtin("aggregate");
-
POP_AND_DONT_CLEANUP;
-
emit0(F_ASSIGN);
-
return 1;
-
}
-
-
case F_ASSIGN_SELF:
-
/* in assign self we know this:
-
*
-
* car(n) = lvalue
-
* cdr(n)= softcast(apply(efun, arglist(car(n),one more arg)))
-
*
-
* The first argument of the arglist is equal to the lvalue.
-
*
-
* We only want to evaluate car(n) once.
-
*/
-
if( CAR(n)->token == F_AUTO_MAP_MARKER )
-
yyerror("[*] is not yet supported here\n");
-
return emit_ltosval_call_and_assign( CAR(n), CAADR(n), CDADR(n) );
-
-
case F_ASSIGN:
-
-
if( CAR(n)->token == F_AUTO_MAP_MARKER )
-
{
-
int depth = 0;
-
node *lval = CAR(n);
-
while( lval->token == F_AUTO_MAP_MARKER )
-
{
-
lval = CAR(lval);
-
depth++;
-
}
-
do_docode(lval,0); /* note: not lvalue */
-
if(do_docode(CDR(n),0)!=1)
-
yyerror("RHS is void!");
-
-
if( CDR(n)->token == F_AUTO_MAP_MARKER ||
-
CDR(n)->token == F_AUTO_MAP ||
-
/* Well, hello there... ;) */
-
/* This is what is generated by a[*] += 10 and such. */
-
(CDR(n)->token == F_SOFT_CAST &&
-
has_automap(CDR(n))))
-
{
-
emit1(F_ASSIGN_INDICES,depth);
-
}
-
else
-
{
-
emit1(F_ASSIGN_ALL_INDICES,depth);
-
}
-
if( flags & DO_POP )
-
emit0( F_POP_VALUE );
-
return !(flags&DO_POP);
-
}
-
-
switch(CDR(n)->token)
-
{
-
case F_RANGE:
-
if(node_is_eq(CAR(n),CADR(n)))
-
{
-
int num_args;
-
/* tmp1=do_docode(CDR(n),DO_LVALUE); */
-
if(match_types(CAR(n)->type, array_type_string) ||
-
match_types(CAR(n)->type, string_type_string) ||
-
match_types(CAR(n)->type, object_type_string) ||
-
match_types(CAR(n)->type, multiset_type_string) ||
-
match_types(CAR(n)->type, mapping_type_string))
-
{
-
do_docode(CAR(n),DO_LVALUE);
-
num_args = do_docode(CDDR(n), 0);
-
switch (num_args)
-
{
-
case 0: emit0(F_LTOSVAL_AND_FREE); break;
-
case 1: emit0(F_LTOSVAL2_AND_FREE); break;
-
case 2: emit0(F_LTOSVAL3_AND_FREE); break;
-
#ifdef PIKE_DEBUG
-
default:
-
Pike_fatal("Arglebargle glop-glyf?\n");
-
#endif
-
}
-
}else{
-
goto do_not_suboptimize_assign;
-
emit0(F_LTOSVAL);
-
num_args = do_docode(CDDR(n), 0);
-
}
-
-
if (CDR (n)->token == F_RANGE)
-
emit_range (CDR (n) DO_IF_DEBUG (COMMA num_args));
-
else
-
emit0(CDR(n)->token);
-
-
emit0(n->token);
-
return n->token==F_ASSIGN; /* So when is this false? /mast */
-
}
-
goto do_not_suboptimize_assign;
-
-
case F_SOFT_CAST:
-
/* a = [type]`oper(a,*) */
-
if( CADR(n)->token == F_APPLY &&
-
is_apply_constant_function_arg0( CADR(n), CAR(n) ))
-
return 1;
-
goto do_not_suboptimize_assign;
-
case F_APPLY:
-
/* a = `oper(a,*) */
-
if (is_apply_constant_function_arg0( CDR(n), CAR(n) ))
-
return 1;
-
/* FALLTHRU */
-
default:
-
do_not_suboptimize_assign:
-
switch(CAR(n)->token)
-
{
-
case F_GLOBAL:
-
if(CAR(n)->u.integer.b) goto normal_assign;
-
code_expression(CDR(n), 0, "RHS");
-
emit_assign_global( CAR(n)->u.integer.a, flags & DO_POP );
-
break;
-
case F_LOCAL:
-
if(CAR(n)->u.integer.a >=
-
find_local_frame(CAR(n)->u.integer.b)->max_number_of_locals)
-
yyerror("Illegal to use local variable here.");
-
-
if(CAR(n)->u.integer.b) goto normal_assign;
-
-
if (CAR(n)->node_info & OPT_ASSIGNMENT) {
-
/* Initialize. */
-
emit0(F_CONST0);
-
emit1(F_ASSIGN_LOCAL_AND_POP, CAR(n)->u.integer.a);
-
}
-
code_expression(CDR(n), 0, "RHS");
-
emit1(flags & DO_POP ? F_ASSIGN_LOCAL_AND_POP:F_ASSIGN_LOCAL,
-
CAR(n)->u.integer.a );
-
break;
-
-
case F_GET_SET:
-
{
-
/* Check for the setter function. */
-
struct program_state *state = Pike_compiler;
-
int program_id = CAR(n)->u.integer.a;
-
int level = 0;
-
while (state && (state->new_program->id != program_id)) {
-
state = state->previous;
-
level++;
-
}
-
if (!state) {
-
yyerror("Lost parent.");
-
} else {
-
struct reference *ref =
-
PTR_FROM_INT(state->new_program, CAR(n)->u.integer.b);
-
struct identifier *id =
-
ID_FROM_PTR(state->new_program, ref);
-
struct inherit *inh =
-
INHERIT_FROM_PTR(state->new_program, ref);
-
int f;
-
#ifdef PIKE_DEBUG
-
if (!IDENTIFIER_IS_VARIABLE(id->identifier_flags) ||
-
(id->run_time_type != PIKE_T_GET_SET)) {
-
Pike_fatal("Not a getter/setter in a F_GET_SET node!\n"
-
" identifier_flags: 0x%08x\n"
-
" run_time_type; %s (%d)\n",
-
id->identifier_flags,
-
get_name_of_type(id->run_time_type),
-
id->run_time_type);
-
}
-
#endif /* PIKE_DEBUG */
-
f = id->func.gs_info.setter;
-
if (f == -1) {
-
yywarning("Variable %S lacks a setter.", id->name);
-
} else if (!level) {
-
f += inh->identifier_level;
-
if (flags & DO_POP) {
-
#ifndef USE_APPLY_N
-
emit0(F_MARK);
-
#endif
-
code_expression(CDR(n), 0, "RHS");
-
} else {
-
code_expression(CAR(n), 0, "RHS");
-
#ifndef USE_APPLY_N
-
emit0(F_MARK);
-
#endif
-
emit0(F_DUP);
-
}
-
#ifdef USE_APPLY_N
-
emit2(F_CALL_LFUN_N, f, 1);
-
#else
-
emit1(F_CALL_LFUN, f);
-
#endif
-
emit0(F_POP_VALUE);
-
return !(flags & DO_POP);
-
}
-
}
-
}
-
/* FALLTHRU */
-
case F_EXTERNAL:
-
/* Check that it is in this context */
-
if(Pike_compiler ->new_program->id == CAR(n)->u.integer.a)
-
{
-
/* Check that it is a variable */
-
if(CAR(n)->u.integer.b != IDREF_MAGIC_THIS &&
-
IDENTIFIER_IS_VARIABLE( ID_FROM_INT(Pike_compiler->new_program, CAR(n)->u.integer.b)->identifier_flags))
-
{
-
code_expression(CDR(n), 0, "RHS");
-
emit_assign_global(CAR(n)->u.integer.b, flags & DO_POP );
-
break;
-
}
-
}
-
/* fall through */
-
-
default:
-
normal_assign:
-
tmp1=do_docode(CAR(n),DO_LVALUE);
-
if(do_docode(CDR(n),0)!=1) yyerror("RHS is void!");
-
emit0(flags & DO_POP ? F_ASSIGN_AND_POP:F_ASSIGN);
-
break;
-
}
-
return flags & DO_POP ? 0 : 1;
-
}
-
-
case F_LAND:
-
case F_LOR:
-
tmp1=alloc_label();
-
if(flags & DO_POP)
-
{
-
do_cond_jump(CAR(n), (INT32)tmp1, n->token == F_LOR, DO_POP);
-
DO_CODE_BLOCK(CDR(n));
-
low_insert_label( (INT32)tmp1 );
-
return 0;
-
}else{
-
do_cond_jump(CAR(n), (INT32)tmp1, n->token == F_LOR, 0);
-
code_expression(CDR(n), flags, n->token == F_LOR ? "||" : "&&");
-
low_insert_label( (INT32)tmp1 );
-
return 1;
-
}
-
-
case F_RANGE:
-
tmp1=do_docode(CAR(n),DO_NOT_COPY_TOPLEVEL);
-
{
-
#ifdef PIKE_DEBUG
-
int num_args =
-
#endif
-
do_docode (CDR (n), DO_NOT_COPY);
-
emit_range (n DO_IF_DEBUG (COMMA num_args));
-
return (INT32)tmp1;
-
}
-
-
/* The special bound type nodes are simply ignored when the
-
* arglist to the range operator is coded. emit_range looks at
-
* them later on instead. */
-
case F_RANGE_FROM_BEG:
-
case F_RANGE_FROM_END:
-
return do_docode (CAR (n), flags);
-
case F_RANGE_OPEN:
-
return 0;
-
-
case F_INC:
-
case F_POST_INC:
-
if(CAR(n)->token == F_AUTO_MAP_MARKER)
-
{
-
int depth=0;
-
int ret=0;
-
node *tmp=CAR(n);
-
while(tmp->token == F_AUTO_MAP_MARKER)
-
{
-
depth++;
-
tmp=CAR(tmp);
-
}
-
-
tmp1=do_docode(tmp,DO_LVALUE);
-
if(n->token == F_POST_INC)
-
{
-
emit0(F_LTOSVAL);
-
emit2(F_REARRANGE,1,2);
-
ret++;
-
flags|=DO_POP;
-
}
-
-
#ifdef PIKE_DEBUG
-
if(tmp1 != 2)
-
Pike_fatal("HELP! FATAL INTERNAL COMPILER ERROR (1)\n");
-
#endif
-
-
emit0(F_MARK);
-
emit0(F_MARK);
-
emit0(F_LTOSVAL);
-
emit1(F_NUMBER, depth);
-
emit_apply_builtin("__builtin.automap_marker");
-
emit_builtin_svalue("`+");
-
emit2(F_REARRANGE,1,1);
-
emit1(F_NUMBER, 1);
-
emit_apply_builtin("__automap__");
-
-
if(flags & DO_POP)
-
{
-
emit0(F_ASSIGN_AND_POP);
-
}else{
-
emit0(F_ASSIGN);
-
ret++;
-
}
-
return ret;
-
}else{
-
tmp1=do_docode(CAR(n),DO_LVALUE);
-
#ifdef PIKE_DEBUG
-
if(tmp1 != 2)
-
Pike_fatal("HELP! FATAL INTERNAL COMPILER ERROR (1)\n");
-
#endif
-
-
if(flags & DO_POP)
-
{
-
emit0(F_INC_AND_POP);
-
return 0;
-
}else{
-
emit0(n->token);
-
return 1;
-
}
-
}
-
-
case F_DEC:
-
case F_POST_DEC:
-
if(CAR(n)->token == F_AUTO_MAP_MARKER)
-
{
-
int depth=0;
-
int ret=0;
-
node *tmp=CAR(n);
-
while(tmp->token == F_AUTO_MAP_MARKER)
-
{
-
depth++;
-
tmp=CAR(tmp);
-
}
-
-
tmp1=do_docode(tmp,DO_LVALUE);
-
if(n->token == F_POST_DEC)
-
{
-
emit0(F_LTOSVAL);
-
emit2(F_REARRANGE,1,2);
-
ret++;
-
flags|=DO_POP;
-
}
-
-
#ifdef PIKE_DEBUG
-
if(tmp1 != 2)
-
Pike_fatal("HELP! FATAL INTERNAL COMPILER ERROR (1)\n");
-
#endif
-
-
emit0(F_MARK);
-
emit0(F_MARK);
-
emit0(F_LTOSVAL);
-
emit1(F_NUMBER, depth);
-
emit_apply_builtin("__builtin.automap_marker");
-
emit_builtin_svalue("`-");
-
emit2(F_REARRANGE,1,1);
-
emit1(F_NUMBER, 1);
-
emit_apply_builtin("__automap__");
-
-
if(flags & DO_POP)
-
{
-
emit0(F_ASSIGN_AND_POP);
-
}else{
-
emit0(F_ASSIGN);
-
ret++;
-
}
-
return ret;
-
}else{
-
tmp1=do_docode(CAR(n),DO_LVALUE);
-
#ifdef PIKE_DEBUG
-
if(tmp1 != 2)
-
Pike_fatal("HELP! FATAL INTERNAL COMPILER ERROR (2)\n");
-
#endif
-
if(flags & DO_POP)
-
{
-
emit0(F_DEC_AND_POP);
-
return 0;
-
}else{
-
emit0(n->token);
-
return 1;
-
}
-
}
-
-
case F_FOR:
-
{
-
INT32 *prev_switch_jumptable = current_switch.jumptable;
-
BLOCK_BEGIN;
-
PUSH_STATEMENT_LABEL;
-
-
current_switch.jumptable=0;
-
current_label->break_label=alloc_label();
-
current_label->continue_label=alloc_label();
-
-
if(CDR(n))
-
{
-
do_jump_when_zero(CAR(n),current_label->break_label);
-
tmp2=ins_label(-1);
-
DO_CODE_BLOCK(CADR(n));
-
ins_label(current_label->continue_label);
-
DO_CODE_BLOCK(CDDR(n));
-
}else{
-
tmp2=ins_label(-1);
-
}
-
do_jump_when_non_zero(CAR(n), (INT32)tmp2);
-
ins_label(current_label->break_label);
-
-
current_switch.jumptable = prev_switch_jumptable;
-
POP_STATEMENT_LABEL;
-
BLOCK_END;
-
return 0;
-
}
-
-
case ' ':
-
/* FIXME: Is this code reached? */
-
ret = do_docode(CAR(n),0);
-
return ret + do_docode(CDR(n),DO_LVALUE);
-
-
case F_FOREACH:
-
{
-
node *arr;
-
INT32 *prev_switch_jumptable = current_switch.jumptable;
-
arr=CAR(n);
-
-
if(CDR(arr) && CDR(arr)->token == ':')
-
{
-
BLOCK_BEGIN;
-
/* New-style */
-
tmp1=do_docode(CAR(arr), DO_NOT_COPY_TOPLEVEL);
-
emit0(F_MAKE_ITERATOR);
-
-
if(CADR(arr))
-
{
-
do_docode(CADR(arr), DO_LVALUE);
-
}else{
-
emit0(F_CONST0);
-
emit0(F_CONST0);
-
modify_stack_depth(2);
-
}
-
-
if(CDDR(arr))
-
{
-
do_docode(CDDR(arr), DO_LVALUE);
-
}else{
-
emit0(F_CONST0);
-
emit0(F_CONST0);
-
modify_stack_depth(2);
-
}
-
-
PUSH_CLEANUP_FRAME(do_pop, 5);
-
-
PUSH_STATEMENT_LABEL;
-
current_switch.jumptable=0;
-
current_label->break_label=alloc_label();
-
current_label->continue_label=alloc_label();
-
-
/* Doubt it's necessary to use a label separate from
-
* current_label->break_label, but I'm playing safe. /mast */
-
tmp3 = alloc_label();
-
do_jump(F_FOREACH_START, (INT32) tmp3);
-
tmp1=ins_label(-1);
-
DO_CODE_BLOCK(CDR(n));
-
ins_label(current_label->continue_label);
-
do_jump(F_FOREACH_LOOP, (INT32)tmp1);
-
ins_label(current_label->break_label);
-
low_insert_label( (INT32)tmp3 );
-
-
current_switch.jumptable = prev_switch_jumptable;
-
POP_STATEMENT_LABEL;
-
POP_AND_DO_CLEANUP;
-
BLOCK_END;
-
return 0;
-
}
-
-
-
BLOCK_BEGIN;
-
-
if(CAR(arr) && CAR(arr)->token==F_RANGE)
-
{
-
node *range = CAR(arr);
-
node *low = CADR(range);
-
node *high = CDDR(range);
-
if(high->token == F_RANGE_OPEN &&
-
low->token == F_RANGE_FROM_BEG &&
-
match_types (low->type, int_type_string))
-
{
-
/* Optimize foreach(x[start..],y). */
-
do_docode (CAR(range), DO_NOT_COPY_TOPLEVEL);
-
do_docode (CDR(arr), DO_NOT_COPY|DO_LVALUE);
-
if ((low->token == F_CONSTANT) && (TYPEOF(low->u.sval) == PIKE_T_INT)) {
-
if (low->u.sval.u.integer < 0) {
-
emit0(F_CONST0);
-
goto foreach_arg_pushed;
-
}
-
do_docode (CAR(low), DO_NOT_COPY);
-
goto foreach_arg_pushed;
-
}
-
do_docode (CAR(low), DO_NOT_COPY);
-
tmp1 = alloc_label();
-
emit0(F_DUP);
-
emit0(F_CONST0);
-
do_jump(F_BRANCH_WHEN_GE, tmp1);
-
/* The value is negative. replace it with zero. */
-
emit0(F_POP_VALUE);
-
emit0(F_CONST0);
-
low_insert_label((INT32)tmp1);
-
goto foreach_arg_pushed;
-
}
-
}
-
do_docode(arr,DO_NOT_COPY);
-
emit0(F_CONST0);
-
modify_stack_depth(1);
-
foreach_arg_pushed:
-
PUSH_CLEANUP_FRAME(do_pop, 4);
-
-
PUSH_STATEMENT_LABEL;
-
current_switch.jumptable=0;
-
current_label->break_label=alloc_label();
-
current_label->continue_label=alloc_label();
-
-
tmp3=do_branch(-1);
-
tmp1=ins_label(-1);
-
DO_CODE_BLOCK(CDR(n));
-
ins_label(current_label->continue_label);
-
low_insert_label( (INT32)tmp3 );
-
do_jump(n->token, (INT32)tmp1);
-
ins_label(current_label->break_label);
-
-
current_switch.jumptable = prev_switch_jumptable;
-
POP_STATEMENT_LABEL;
-
POP_AND_DO_CLEANUP;
-
BLOCK_END;
-
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;
-
BLOCK_BEGIN;
-
-
do_docode(CAR(n),0);
-
PUSH_CLEANUP_FRAME(do_pop, 3);
-
-
PUSH_STATEMENT_LABEL;
-
current_switch.jumptable=0;
-
current_label->break_label=alloc_label();
-
current_label->continue_label=alloc_label();
-
tmp3=do_branch(-1);
-
tmp1=ins_label(-1);
-
-
DO_CODE_BLOCK(CDR(n));
-
ins_label(current_label->continue_label);
-
low_insert_label( (INT32)tmp3 );
-
do_jump(n->token, (INT32)tmp1);
-
ins_label(current_label->break_label);
-
-
current_switch.jumptable = prev_switch_jumptable;
-
POP_STATEMENT_LABEL;
-
POP_AND_DO_CLEANUP;
-
BLOCK_END;
-
return 0;
-
}
-
-
case F_LOOP:
-
{
-
/* FIXME: No support for break or continue. */
-
PUSH_STATEMENT_LABEL;
-
tmp1 = do_docode(CAR(n), 0);
-
if (tmp1 > 0) {
-
do_pop(tmp1-1);
-
tmp2 = do_branch(-1);
-
tmp3 = ins_label(-1);
-
DO_CODE_BLOCK(CDR(n));
-
ins_label(tmp2);
-
emit1(F_LOOP, tmp3);
-
}
-
POP_STATEMENT_LABEL;
-
return 0;
-
}
-
-
case F_DO:
-
{
-
INT32 *prev_switch_jumptable = current_switch.jumptable;
-
BLOCK_BEGIN;
-
PUSH_STATEMENT_LABEL;
-
-
current_switch.jumptable=0;
-
current_label->break_label=alloc_label();
-
current_label->continue_label=alloc_label();
-
-
tmp2=ins_label(-1);
-
DO_CODE_BLOCK(CAR(n));
-
ins_label(current_label->continue_label);
-
do_jump_when_non_zero(CDR(n), (INT32)tmp2);
-
ins_label(current_label->break_label);
-
-
current_switch.jumptable = prev_switch_jumptable;
-
POP_STATEMENT_LABEL;
-
BLOCK_END;
-
return 0;
-
}
-
-
case F_POP_VALUE:
-
{
-
BLOCK_BEGIN;
-
DO_CODE_BLOCK(CAR(n));
-
BLOCK_END;
-
return 0;
-
}
-
-
case F_CAST:
-
switch(n->type->type) {
-
case T_VOID:
-
DO_CODE_BLOCK(CAR(n));
-
return 0;
-
case T_INT:
-
/* FIXME: Integer range? */
-
tmp1 = do_docode(CAR(n), 0);
-
if(!tmp1)
-
emit0(F_CONST0);
-
else {
-
if(tmp1>1)
-
do_pop((INT32)(tmp1-1));
-
emit0(F_CAST_TO_INT);
-
}
-
return 1;
-
case T_STRING:
-
/* FIXME: String width? */
-
tmp1 = do_docode(CAR(n), 0);
-
if(!tmp1)
-
emit0(F_CONST0);
-
else if(tmp1>1)
-
do_pop((INT32)(tmp1-1));
-
emit0(F_CAST_TO_STRING);
-
return 1;
-
default:
-
if (compile_type_to_runtime_type(n->type) == PIKE_T_MIXED) {
-
tmp1 = do_docode(CAR(n), 0);
-
if(!tmp1)
-
emit0(F_CONST0);
-
else if(tmp1>1)
-
do_pop((INT32)(tmp1-1));
-
return 1;
-
}
-
}
-
{
-
struct svalue sv;
-
SET_SVAL(sv, T_TYPE, 0, type, n->type);
-
tmp1 = store_constant(&sv, 0, n->name);
-
emit1(F_CONSTANT, (INT32)tmp1);
-
}
-
-
tmp1=do_docode(CAR(n),0);
-
if(!tmp1) { emit0(F_CONST0); tmp1=1; }
-
if(tmp1>1) do_pop((INT32)(tmp1-1));
-
-
emit0(F_CAST);
-
return 1;
-
-
case F_SOFT_CAST:
-
if (runtime_options & RUNTIME_CHECK_TYPES) {
-
{
-
struct svalue sv;
-
SET_SVAL(sv, T_TYPE, 0, type, n->type);
-
tmp1 = store_constant(&sv, 0, n->name);
-
emit1(F_CONSTANT, (INT32)tmp1);
-
}
-
tmp1 = do_docode(CAR(n), 0);
-
if (!tmp1) { emit0(F_CONST0); tmp1 = 1; }
-
if (tmp1 > 1) do_pop((INT32)(tmp1 - 1));
-
emit0(F_SOFT_CAST);
-
return 1;
-
}
-
tmp1 = do_docode(CAR(n), flags);
-
if (tmp1 > 1) do_pop((INT32)(tmp1 - 1));
-
return !!tmp1;
-
-
case F_APPLY:
-
if(CAR(n)->token == F_CONSTANT)
-
{
-
int args = count_args(CDR(n));
-
if(TYPEOF(CAR(n)->u.sval) == T_FUNCTION)
-
{
-
if(SUBTYPEOF(CAR(n)->u.sval) == FUNCTION_BUILTIN) /* driver fun? */
-
{
-
if(!CAR(n)->u.sval.u.efun->docode ||
-
!CAR(n)->u.sval.u.efun->docode(n))
-
{
-
if(args==1)
-
{
-
do_docode(CDR(n),0);
-
tmp1=store_constant(& CAR(n)->u.sval,
-
!(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND),
-
CAR(n)->name);
-
emit1(F_CALL_BUILTIN1, (INT32)tmp1);
-
#ifdef USE_APPLY_N
-
}else if(args>0){
-
do_docode(CDR(n),0);
-
tmp1=store_constant(& CAR(n)->u.sval,
-
!(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND),
-
CAR(n)->name);
-
emit2(F_CALL_BUILTIN_N, (INT32)tmp1, args);
-
#endif
-
}else{
-
emit0(F_MARK);
-
PUSH_CLEANUP_FRAME(do_pop_mark, 0);
-
do_docode(CDR(n),0);
-
tmp1=store_constant(& CAR(n)->u.sval,
-
!(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND),
-
CAR(n)->name);
-
emit1(F_CALL_BUILTIN, (INT32)tmp1);
-
POP_AND_DONT_CLEANUP;
-
}
-
}
-
if (!n->type) fix_type_field(n);
-
return !pike_types_le(n->type, void_type_string);
-
}else{
-
if(CAR(n)->u.sval.u.object == Pike_compiler->fake_object)
-
return do_lfun_call(SUBTYPEOF(CAR(n)->u.sval), CDR(n));
-
}
-
}
-
#ifdef USE_APPLY_N
-
if( args <= 1 )
-
#endif
-
{
-
emit0(F_MARK);
-
PUSH_CLEANUP_FRAME(do_pop_mark, 0);
-
do_docode(CDR(n),0);
-
tmp1=store_constant(& CAR(n)->u.sval,
-
!(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND),
-
CAR(n)->name);
-
emit1(F_APPLY, (INT32)tmp1);
-
POP_AND_DONT_CLEANUP;
-
}
-
#ifdef USE_APPLY_N
-
else
-
{
-
do_docode(CDR(n),0);
-
tmp1=store_constant(& CAR(n)->u.sval,
-
!(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND),
-
CAR(n)->name);
-
emit2(F_APPLY_N, (INT32)tmp1, args);
-
}
-
#endif
-
return 1;
-
}
-
else if(CAR(n)->token == F_EXTERNAL &&
-
CAR(n)->u.integer.a == Pike_compiler->new_program->id &&
-
CAR(n)->u.integer.b != IDREF_MAGIC_THIS)
-
{
-
return do_lfun_call(CAR(n)->u.integer.b, CDR(n));
-
}
-
else if(CAR(n)->token == F_GET_SET &&
-
CAR(n)->u.integer.a == Pike_compiler->new_program->id &&
-
CAR(n)->u.integer.b != IDREF_MAGIC_THIS)
-
{
-
return do_lfun_call(CAR(n)->u.integer.b, CDR(n));
-
}
-
else if(CAR(n)->token == F_ARROW)
-
{
-
emit0(F_MARK);
-
PUSH_CLEANUP_FRAME(do_pop_mark, 0);
-
do_docode(CAAR(n),0); /* object */
-
do_docode(CDR(n),0); /* args */
-
emit1(F_CALL_OTHER, store_prog_string(CDAR(n)->u.sval.u.string));
-
POP_AND_DONT_CLEANUP;
-
return 1;
-
}
-
else
-
{
-
struct pike_string *tmp;
-
node *foo;
-
-
emit0(F_MARK);
-
PUSH_CLEANUP_FRAME(do_pop_mark, 0);
-
do_docode(CAR(n),0);
-
do_docode(CDR(n),0);
-
-
foo=find_module_identifier(lfun_strings[LFUN_CALL],0);
-
if(!foo || foo->token!=F_CONSTANT)
-
{
-
yyerror("No `() efun.");
-
}else{
-
if(TYPEOF(foo->u.sval) == T_FUNCTION &&
-
SUBTYPEOF(foo->u.sval) == FUNCTION_BUILTIN &&
-
foo->u.sval.u.efun->function == f_call_function)
-
{
-
emit0(F_CALL_FUNCTION);
-
}else{
-
/* We might want to put "predef::"+foo->name here /Hubbe */
-
tmp1=store_constant(& foo->u.sval, 1, foo->name);
-
emit1(F_APPLY, (INT32)tmp1);
-
}
-
}
-
free_node(foo);
-
POP_AND_DONT_CLEANUP;
-
return 1;
-
}
-
-
case F_ARG_LIST:
-
case F_COMMA_EXPR:
-
case ':':
-
{
-
node *root = n;
-
node *parent = n->parent;
-
-
/* Avoid a bit of recursion by traversing the graph... */
-
n->parent = NULL;
-
tmp1 = 0;
-
next_car:
-
while (CAR(n) &&
-
((CAR(n)->token == F_ARG_LIST) ||
-
(CAR(n)->token == F_COMMA_EXPR))) {
-
CAR(n)->parent = n;
-
n = CAR(n);
-
}
-
/* CAR(n) is not F_ARG_LIST or F_COMMA_EXPR */
-
tmp1 += do_docode(CAR(n), flags & ~WANT_LVALUE);
-
-
do {
-
if (CDR(n)) {
-
if ((CDR(n)->token == F_ARG_LIST) ||
-
(CDR(n)->token == F_COMMA_EXPR)) {
-
/* Note: Parent points to the closest preceding CAR node
-
* on the way to the root.
-
*/
-
CDR(n)->parent = n->parent;
-
n = CDR(n);
-
goto next_car;
-
}
-
/* CDR(n) is not F_ARG_LIST or F_COMMA_EXPR */
-
if (n->parent) {
-
tmp1 += do_docode(CDR(n), flags & ~WANT_LVALUE);
-
} else {
-
tmp1 += do_docode(CDR(n), flags);
-
}
-
}
-
/* Retrace */
-
/* Note: n->parent is always a visited CAR node on the
-
* way to the root.
-
*/
-
n = n->parent;
-
} while (n);
-
-
/* Restore root->parent. */
-
root->parent = parent;
-
}
-
return (INT32)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;
-
struct switch_data prev_switch = current_switch;
-
#ifdef PIKE_DEBUG
-
struct svalue *save_sp=Pike_sp;
-
#endif
-
BLOCK_BEGIN;
-
PUSH_STATEMENT_LABEL;
-
-
if(do_docode(CAR(n),0)!=1)
-
Pike_fatal("Internal compiler error, time to panic\n");
-
-
if (!(CAR(n) && (current_switch.type = CAR(n)->type))) {
-
current_switch.type = mixed_type_string;
-
}
-
-
current_label->break_label=alloc_label();
-
-
cases=count_cases(CDR(n));
-
-
tmp1=emit1(F_SWITCH,0);
-
modify_stack_depth(-1);
-
emit1(F_ALIGN,sizeof(INT32));
-
-
current_switch.values_on_stack=0;
-
current_switch.index=2;
-
current_switch.less_label=-1;
-
current_switch.greater_label=-1;
-
current_switch.default_label=-1;
-
current_switch.jumptable=xalloc(sizeof(INT32)*(cases*2+2));
-
jumptable=xalloc(sizeof(INT32)*(cases*2+2));
-
-
for(e=1; e<cases*2+2; e++)
-
{
-
jumptable[e] = (INT32)emit1(F_POINTER, 0);
-
current_switch.jumptable[e]=-1;
-
}
-
emit0(F_NOTREACHED);
-
-
DO_CODE_BLOCK(CDR(n));
-
-
#ifdef PIKE_DEBUG
-
if(Pike_sp-save_sp != cases)
-
Pike_fatal("Count cases is wrong!\n");
-
#endif
-
-
f_aggregate(cases);
-
-
/* FIXME: get_switch_order might possibly be able to
-
* throw errors, add a catch around this! -Hubbe
-
*/
-
order=get_switch_order(Pike_sp[-1].u.array);
-
-
if (!Pike_compiler->num_parse_error) {
-
/* Check for cases inside a range */
-
if (cases &&
-
((current_switch.less_label >= 0 &&
-
current_switch.jumptable[order[0]*2+2] !=
-
current_switch.less_label) ||
-
(current_switch.greater_label >= 0 &&
-
current_switch.jumptable[order[cases-1]*2+2] !=
-
current_switch.greater_label)))
-
yyerror("Case inside range.");
-
for(e=0; e<cases-1; e++)
-
{
-
if(order[e] < cases-1)
-
{
-
int o1=order[e]*2+2;
-
if(current_switch.jumptable[o1]==current_switch.jumptable[o1+1] &&
-
current_switch.jumptable[o1]==current_switch.jumptable[o1+2])
-
{
-
if(order[e]+1 != order[e+1])
-
yyerror("Case inside range.");
-
e++;
-
}
-
}
-
}
-
}
-
-
order_array(Pike_sp[-1].u.array,order);
-
-
reorder((void *)(current_switch.jumptable+2),cases,sizeof(INT32)*2,order);
-
free(order);
-
-
current_switch.jumptable[1] = current_switch.less_label;
-
current_switch.jumptable[current_switch.index - 1] = current_switch.greater_label;
-
-
if(current_switch.default_label < 0)
-
current_switch.default_label = ins_label(-1);
-
-
for(e=1;e<cases*2+2;e++)
-
if(current_switch.jumptable[e]==-1)
-
current_switch.jumptable[e]=current_switch.default_label;
-
-
for(e=1; e<cases*2+2; e++)
-
update_arg(jumptable[e], current_switch.jumptable[e]);
-
-
update_arg((INT32)tmp1, store_constant(Pike_sp-1,1,0));
-
-
pop_stack();
-
free(jumptable);
-
free(current_switch.jumptable);
-
-
current_switch = prev_switch;
-
-
low_insert_label( current_label->break_label);
-
-
POP_STATEMENT_LABEL;
-
BLOCK_END;
-
#ifdef PIKE_DEBUG
-
if(Pike_interpreter.recoveries && Pike_sp-Pike_interpreter.evaluator_stack < Pike_interpreter.recoveries->stack_pointer)
-
Pike_fatal("Stack error after F_SWITCH (underflow)\n");
-
#endif
-
return 0;
-
}
-
-
case F_CASE:
-
case F_CASE_RANGE:
-
{
-
if(!current_switch.jumptable)
-
{
-
yyerror("Case outside switch.");
-
}else{
-
INT32 label = ins_label(-1);
-
int i;
-
-
for (i = 0; i < 2; i++) {
-
node *case_val = i == 0 ? CAR(n) : CDR(n);
-
-
if (case_val) {
-
if(!is_const(case_val))
-
yyerror("Case label isn't constant.");
-
-
if (case_val->type) {
-
if (!pike_types_le(case_val->type, current_switch.type)) {
-
if (!match_types(case_val->type, current_switch.type)) {
-
yytype_error("Type mismatch in case.",
-
current_switch.type, case_val->type, 0);
-
} else if (c->lex.pragmas & ID_STRICT_TYPES) {
-
yytype_error("Type mismatch in case.",
-
current_switch.type, case_val->type, YYTE_IS_WARNING);
-
}
-
}
-
}
-
-
if (!Pike_compiler->num_parse_error) {
-
tmp1=eval_low(case_val,1);
-
if(tmp1<1)
-
{
-
yyerror("Error in case label.");
-
push_int(0);
-
tmp1=1;
-
}
-
pop_n_elems(tmp1-1);
-
current_switch.values_on_stack++;
-
for(tmp1=current_switch.values_on_stack; tmp1 > 1; tmp1--)
-
if(is_equal(Pike_sp-tmp1, Pike_sp-1))
-
yyerror("Duplicate case label.");
-
} else {
-
push_int(0);
-
current_switch.values_on_stack++;
-
}
-
}
-
}
-
-
if (n->token == F_CASE) {
-
current_switch.jumptable[current_switch.index++] = label;
-
current_switch.jumptable[current_switch.index++] = -1;
-
}
-
else {
-
if (!CAR(n)) current_switch.less_label = label;
-
if (!CDR(n)) current_switch.greater_label = label;
-
if (CAR(n) && CDR(n)) {
-
current_switch.jumptable[current_switch.index++] = label;
-
current_switch.jumptable[current_switch.index++] = label;
-
current_switch.jumptable[current_switch.index++] = label;
-
current_switch.jumptable[current_switch.index++] = -1;
-
}
-
else {
-
current_switch.jumptable[current_switch.index++] = label;
-
current_switch.jumptable[current_switch.index++] = -1;
-
}
-
}
-
}
-
return 0;
-
}
-
-
case F_DEFAULT:
-
if(!current_switch.jumptable)
-
{
-
yyerror("Default outside switch.");
-
}else if(current_switch.default_label!=-1){
-
yyerror("Duplicate switch default.");
-
}else{
-
current_switch.default_label = ins_label(-1);
-
}
-
return 0;
-
-
case F_BREAK:
-
case F_CONTINUE: {
-
struct statement_label *label, *p;
-
-
if (CAR(n)) {
-
struct pike_string *name = CAR(n)->u.sval.u.string;
-
struct statement_label_name *lbl_name;
-
for (label = current_label; label; label = label->prev)
-
for (lbl_name = label->name; lbl_name; lbl_name = lbl_name->next)
-
if (lbl_name->str == name) {
-
lbl_name->used = 1;
-
goto label_found_1;
-
}
-
my_yyerror("No surrounding statement labeled %S.", name);
-
return 0;
-
-
label_found_1:
-
if (n->token == F_CONTINUE && label->continue_label < 0) {
-
my_yyerror("Cannot continue the non-loop statement on line %ld.",
-
(long)lbl_name->line_number);
-
return 0;
-
}
-
}
-
-
else {
-
if (n->token == F_BREAK) {
-
for (label = current_label; label; label = label->prev)
-
if (label->break_label >= 0 && !label->emit_break_label)
-
goto label_found_2;
-
yyerror("Break outside loop or switch.");
-
return 0;
-
}
-
else {
-
for (label = current_label; label; label = label->prev)
-
if (label->continue_label >= 0)
-
goto label_found_2;
-
yyerror("Continue outside loop.");
-
return 0;
-
}
-
label_found_2: ;
-
}
-
-
for (p = current_label; 1; p = p->prev) {
-
struct cleanup_frame *q;
-
for (q = p->cleanups; q; q = q->prev) {
-
do_pop(current_stack_depth - q->stack_depth);
-
q->cleanup(q->cleanup_arg);
-
}
-
do_pop(current_stack_depth - p->stack_depth);
-
if (p == label) break;
-
}
-
-
if (n->token == F_BREAK) {
-
if (label->break_label < 0) label->emit_break_label = 1;
-
label->break_label = do_branch(label->break_label);
-
}
-
else
-
do_branch(label->continue_label);
-
-
return 0;
-
}
-
-
case F_NORMAL_STMT_LABEL:
-
case F_CUSTOM_STMT_LABEL: {
-
struct statement_label *label;
-
struct statement_label_name name;
-
BLOCK_BEGIN;
-
PUSH_STATEMENT_LABEL;
-
name.str = CAR(n)->u.sval.u.string;
-
name.line_number = n->line_number;
-
name.file = n->current_file;
-
name.used = 0;
-
-
for (label = current_label; label; label = label->prev) {
-
struct statement_label_name *lbl_name;
-
for (lbl_name = label->name; lbl_name; lbl_name = lbl_name->next)
-
if (lbl_name->str == name.str) {
-
INT_TYPE save_line = c->lex.current_line;
-
struct pike_string *save_file = c->lex.current_file;
-
c->lex.current_line = name.line_number;
-
c->lex.current_file = name.file;
-
my_yyerror("Duplicate nested labels, previous one on line %d.",
-
lbl_name->line_number);
-
c->lex.current_line = save_line;
-
c->lex.current_file = save_file;
-
goto label_check_done;
-
}
-
}
-
label_check_done:
-
-
name.next = current_label->name;
-
current_label->name = &name;
-
-
if (!name.next) {
-
if (n->token == F_CUSTOM_STMT_LABEL)
-
/* The statement we precede has custom label handling; leave
-
* the statement_label "open" so the statement will use it
-
* instead of covering it. */
-
current_label->break_label = -2;
-
else
-
current_label->break_label = -1;
-
}
-
DO_CODE_BLOCK(CDR(n));
-
if (!name.next && current_label->emit_break_label)
-
low_insert_label(current_label->break_label);
-
if (!name.used) {
-
low_yyreport(REPORT_WARNING, n->current_file, n->line_number,
-
parser_system_string, 0,
-
"Label %S not used.", name.str);
-
}
-
POP_STATEMENT_LABEL;
-
BLOCK_END;
-
return 0;
-
}
-
-
case F_RETURN: {
-
struct statement_label *p;
-
int in_catch = 0;
-
do_docode(CAR(n),0);
-
-
/* Insert the appropriate number of F_ESCAPE_CATCH. The rest of
-
* the cleanup is handled wholesale in low_return et al.
-
* Alternatively we could handle this too in low_return and
-
* then allow tail recursion of these kind of returns too. */
-
for (p = current_label; p; p = p->prev) {
-
struct cleanup_frame *q;
-
for (q = p->cleanups; q; q = q->prev) {
-
if (q->cleanup == (cleanup_func) do_escape_catch) {
-
in_catch = 1;
-
do_escape_catch();
-
}
-
#ifdef PIKE_DEBUG
-
/* Have to pop marks from F_SYNCH_MARK too if the debug level
-
* is high enough to get them inserted, otherwise we'll get
-
* false alarms from debug checks in e.g. POP_CATCH_CONTEXT. */
-
else if (d_flag > 2 &&
-
q->cleanup == (cleanup_func) do_cleanup_synch_mark) {
-
/* Use the ordinary pop mark instruction here since we know
-
* the stack isn't in synch and we don't want debug checks
-
* for that. */
-
do_pop_mark (NULL);
-
}
-
#endif
-
}
-
}
-
-
emit0(in_catch ? F_VOLATILE_RETURN : 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);
-
emit1(F_SSCANF, (INT32)(tmp1+tmp2));
-
return 1;
-
-
case F_CATCH: {
-
INT32 *prev_switch_jumptable = current_switch.jumptable;
-
-
tmp1=do_jump(F_CATCH,-1);
-
PUSH_CLEANUP_FRAME(do_escape_catch, 0);
-
-
/* Entry point called via catching_eval_instruction(). */
-
emit0(F_ENTRY);
-
-
PUSH_STATEMENT_LABEL;
-
current_switch.jumptable=0;
-
current_label->break_label=alloc_label();
-
-
DO_CODE_BLOCK(CAR(n));
-
-
ins_label(current_label->break_label);
-
emit0(F_EXIT_CATCH);
-
POP_STATEMENT_LABEL;
-
current_switch.jumptable = prev_switch_jumptable;
-
do_branch (tmp1);
-
-
modify_stack_depth(1);
-
/* Entry point called via catching_eval_instruction() after
-
* catching an error.
-
*
-
* NB: This is reached by subtracting ENTRY_PROLOGUE_SIZE
-
* from the label below.
-
* NB: The label must be after the entry, since it may expand to code
-
* that requires the entry code to have run.
-
*/
-
emit0(F_ENTRY);
-
ins_label((INT32)tmp1);
-
-
POP_AND_DONT_CLEANUP;
-
return 1;
-
}
-
-
case F_LVALUE_LIST:
-
ret = do_docode(CAR(n),DO_LVALUE);
-
return ret + do_docode(CDR(n),DO_LVALUE);
-
-
case F_ARRAY_LVALUE:
-
tmp1=do_docode(CAR(n),DO_LVALUE);
-
#ifdef PIKE_DEBUG
-
if(tmp1 & 1)
-
Pike_fatal("Very internal compiler error.\n");
-
#endif
-
emit1(F_ARRAY_LVALUE, (INT32)(tmp1>>1));
-
return 2;
-
-
case F_ARROW:
-
if(CDR(n)->token != F_CONSTANT || TYPEOF(CDR(n)->u.sval) != T_STRING)
-
Pike_fatal("Bugg in F_ARROW, index not string.\n");
-
if(flags & WANT_LVALUE)
-
{
-
/* FIXME!!!! ??? I wonder what needs fixing... /Hubbe */
-
tmp1=do_docode(CAR(n), 0);
-
emit1(F_ARROW_STRING, store_prog_string(CDR(n)->u.sval.u.string));
-
return 2;
-
}else{
-
tmp1 = do_docode(CAR(n), DO_NOT_COPY);
-
if ((tmp2 = lfun_lookup_id(CDR(n)->u.sval.u.string)) != -1 ) {
-
emit1(F_LOOKUP_LFUN, tmp2);
-
} else {
-
emit1(F_ARROW, store_prog_string(CDR(n)->u.sval.u.string));
-
}
-
if(!(flags & DO_NOT_COPY))
-
{
-
while(n && (n->token==F_INDEX || n->token==F_ARROW)) n=CAR(n);
-
if(n && n->token==F_CONSTANT && !(n->node_info & OPT_EXTERNAL_DEPEND))
-
emit0(F_COPY_VALUE);
-
}
-
}
-
return (INT32)tmp1;
-
-
case F_INDEX:
-
if(flags & WANT_LVALUE)
-
{
-
int mklval=CAR(n) && match_types(CAR(n)->type, string_type_string);
-
tmp1 = do_docode(CAR(n),
-
mklval ? DO_LVALUE_IF_POSSIBLE : 0);
-
if(tmp1==2)
-
{
-
#ifdef PIKE_DEBUG
-
if(!mklval)
-
Pike_fatal("Unwanted lvalue!\n");
-
#endif
-
emit0(F_INDIRECT);
-
}
-
-
if(do_docode(CDR(n),0) != 1)
-
Pike_fatal("Internal compiler error, please report this (1).\n");
-
if(CDR(n)->token != F_CONSTANT &&
-
match_types(CDR(n)->type, string_type_string))
-
emit0(F_CLEAR_STRING_SUBTYPE);
-
return 2;
-
}else{
-
tmp1=do_docode(CAR(n), DO_NOT_COPY);
-
-
code_expression(CDR(n), DO_NOT_COPY, "index");
-
if(CDR(n)->token != F_CONSTANT &&
-
match_types(CDR(n)->type, string_type_string))
-
emit0(F_CLEAR_STRING_SUBTYPE);
-
-
emit0(F_INDEX);
-
-
if(!(flags & DO_NOT_COPY))
-
{
-
while(n && (n->token==F_INDEX || n->token==F_ARROW)) n=CAR(n);
-
if(n && (n->token==F_CONSTANT) && !(n->node_info & OPT_EXTERNAL_DEPEND))
-
emit0(F_COPY_VALUE);
-
}
-
}
-
return (INT32)tmp1;
-
-
case F_CONSTANT:
-
switch(TYPEOF(n->u.sval))
-
{
-
case T_INT:
-
if(!n->u.sval.u.integer && SUBTYPEOF(n->u.sval) == NUMBER_UNDEFINED)
-
{
-
emit0(F_UNDEFINED);
-
}else{
-
#if SIZEOF_INT_TYPE > 4
-
INT_TYPE i=n->u.sval.u.integer;
-
if (i != (INT32)i)
-
{
-
unsigned INT_TYPE ip=(unsigned INT_TYPE)i;
-
INT32 a,b;
-
a=(INT32)(ip>>32);
-
b=(INT32)(ip&0xffffffff);
-
emit2(F_NUMBER64,a,b);
-
}
-
else
-
emit1(F_NUMBER,i);
-
#else
-
emit1(F_NUMBER,n->u.sval.u.integer);
-
#endif
-
}
-
return 1;
-
-
case T_STRING:
-
tmp1=store_prog_string(n->u.sval.u.string);
-
emit1(F_STRING, (INT32)tmp1);
-
return 1;
-
-
case T_FUNCTION:
-
if(SUBTYPEOF(n->u.sval) != FUNCTION_BUILTIN)
-
{
-
if(n->u.sval.u.object == Pike_compiler->fake_object)
-
{
-
/* When does this occur? /mast */
-
emit1(F_GLOBAL, SUBTYPEOF(n->u.sval));
-
return 1;
-
}
-
-
if(n->u.sval.u.object->next == n->u.sval.u.object)
-
{
-
int x=0;
-
#if 0
-
struct object *o;
-
-
for(o=Pike_compiler->fake_object;o!=n->u.sval.u.object;o=o->parent) {
-
state->new_program->flags |=
-
PROGRAM_USES_PARENT | PROGRAM_NEEDS_PARENT;
-
x++;
-
}
-
#else
-
struct program_state *state=Pike_compiler;
-
for(;state->fake_object!=n->u.sval.u.object;state=state->previous) {
-
state->new_program->flags |=
-
PROGRAM_USES_PARENT | PROGRAM_NEEDS_PARENT;
-
x++;
-
}
-
#endif
-
emit2(F_EXTERNAL, SUBTYPEOF(n->u.sval), x);
-
Pike_compiler->new_program->flags |=
-
PROGRAM_USES_PARENT | PROGRAM_NEEDS_PARENT;
-
return 1;
-
}
-
}
-
/* FALLTHRU */
-
default:
-
#ifdef PIKE_DEBUG
-
if((TYPEOF(n->u.sval) == T_OBJECT) &&
-
(n->u.sval.u.object->next == n->u.sval.u.object))
-
Pike_fatal("Internal error: Pointer to parent cannot be a compile time constant!\n");
-
#endif
-
tmp1=store_constant(&(n->u.sval),
-
!(n->tree_info & OPT_EXTERNAL_DEPEND),
-
n->name);
-
emit1(F_CONSTANT, (INT32)tmp1);
-
return 1;
-
-
case T_TYPE:
-
tmp1 = store_constant(&(n->u.sval), 0, n->name);
-
emit1(F_CONSTANT, (INT32)tmp1);
-
return 1;
-
-
case T_ARRAY:
-
case T_MAPPING:
-
case T_MULTISET:
-
tmp1=store_constant(&(n->u.sval),
-
!(n->tree_info & OPT_EXTERNAL_DEPEND),
-
n->name);
-
emit1(F_CONSTANT, (INT32)tmp1);
-
-
/* copy now or later ? */
-
if(!(flags & DO_NOT_COPY) && !(n->tree_info & OPT_EXTERNAL_DEPEND))
-
{
-
if(flags & DO_NOT_COPY_TOPLEVEL)
-
{
-
switch(TYPEOF(n->u.sval))
-
{
-
case T_ARRAY:
-
if(array_fix_type_field(n->u.sval.u.array) & BIT_COMPLEX)
-
emit0(F_COPY_VALUE);
-
break;
-
-
case T_MAPPING:
-
mapping_fix_type_field(n->u.sval.u.mapping);
-
if((n->u.sval.u.mapping->data->ind_types |
-
n->u.sval.u.mapping->data->val_types) & BIT_COMPLEX)
-
emit0(F_COPY_VALUE);
-
break;
-
-
case T_MULTISET:
-
multiset_fix_type_field(n->u.sval.u.multiset);
-
if(multiset_ind_types(n->u.sval.u.multiset) & BIT_COMPLEX)
-
emit0(F_COPY_VALUE);
-
break;
-
}
-
}else{
-
emit0(F_COPY_VALUE);
-
}
-
}
-
return 1;
-
-
}
-
-
case F_LOCAL:
-
if(n->u.integer.a >=
-
find_local_frame(n->u.integer.b)->max_number_of_locals)
-
yyerror("Illegal to use local variable here.");
-
-
if(n->u.integer.b)
-
{
-
if(flags & WANT_LVALUE)
-
{
-
emit2(F_LEXICAL_LOCAL_LVALUE, n->u.integer.a, n->u.integer.b);
-
return 2;
-
}else{
-
emit2(F_LEXICAL_LOCAL, n->u.integer.a, n->u.integer.b);
-
return 1;
-
}
-
}else{
-
if(flags & WANT_LVALUE)
-
{
-
if (n->node_info & OPT_ASSIGNMENT) {
-
/* Initialize the variable. */
-
emit0(F_CONST0);
-
emit1(F_ASSIGN_LOCAL_AND_POP, n->u.integer.a);
-
}
-
emit1(F_LOCAL_LVALUE, n->u.integer.a);
-
return 2;
-
}else{
-
if (n->node_info & OPT_ASSIGNMENT) {
-
/* Initialize the variable. */
-
emit0(F_CONST0);
-
emit1(F_ASSIGN_LOCAL, n->u.integer.a);
-
} else {
-
emit1(F_LOCAL, n->u.integer.a);
-
}
-
return 1;
-
}
-
}
-
-
case F_TRAMPOLINE:
-
{
-
struct compiler_frame *f;
-
int depth=0;
-
for(f=Pike_compiler->compiler_frame;
-
f!=n->u.trampoline.frame;f=f->previous)
-
depth++;
-
-
emit2(F_TRAMPOLINE,n->u.trampoline.ident,depth);
-
return 1;
-
}
-
-
case F_VAL_LVAL:
-
case F_FOREACH_VAL_LVAL:
-
ret = do_docode(CAR(n),flags);
-
return ret + do_docode(CDR(n), flags | DO_LVALUE);
-
-
case F_AUTO_MAP:
-
emit0(F_MARK);
-
code_expression(CAR(n), 0, "automap function");
-
do_encode_automap_arg_list(CDR(n),0);
-
emit_apply_builtin("__automap__");
-
return 1;
-
-
case F_AUTO_MAP_MARKER:
-
if( flags & DO_LVALUE )
-
{
-
do_docode(CAR(n),DO_LVALUE);
-
}
-
else
-
{
-
yyerror("[*] not supported here.\n");
-
emit0(F_CONST0);
-
}
-
return 1;
-
-
case F_TYPEOF:
-
{
-
struct svalue s;
-
/* NB: This should only be reachable via eval_low().
-
* Typically treeopt will get rid of this node.
-
*/
-
SET_SVAL(s, PIKE_T_TYPE, 0, type,
-
CAR(n)->type?CAR(n)->type:mixed_type_string);
-
tmp1 = store_constant(&s, 0, NULL);
-
emit1(F_CONSTANT, (INT32)tmp1);
-
}
-
return 1;
-
-
default:
-
Pike_fatal("Infernal compiler error (unknown parse-tree-token %d).\n", n->token);
-
UNREACHABLE(return 0);
-
}
-
}
-
-
static void emit_save_locals(struct compiler_frame *f)
-
{
-
struct compilation *c = THIS_COMPILATION;
-
unsigned INT16 offset;
-
unsigned INT16 idx;
-
int num_locals = f->max_number_of_locals;
-
-
for (offset = 0; offset < (num_locals >> 4) + 1; offset++) {
-
unsigned int bitmask = 0;
-
for (idx = 0; idx < 16; idx++) {
-
int local_var_idx = offset * 16 + idx;
-
if (local_var_idx >= num_locals) {
-
break;
-
}
-
if (f->variable[local_var_idx].flags & LOCAL_VAR_USED_IN_SCOPE) {
-
bitmask |= 1 << idx;
-
}
-
}
-
if (bitmask) {
-
emit1(F_SAVE_LOCALS, (offset << 16) | bitmask);
-
}
-
}
-
}
-
-
/* Used to generate code for functions. */
-
INT32 do_code_block(node *n, int identifier_flags)
-
{
-
struct compilation *c = THIS_COMPILATION;
-
struct reference *id = NULL;
-
INT32 entry_point;
-
int aggregate_cnum = -1;
-
int save_stack_depth = current_stack_depth;
-
int save_label_no = label_no;
-
current_stack_depth = 0;
-
-
if (Pike_compiler->compiler_frame->current_function_number >= 0) {
-
id = Pike_compiler->new_program->identifier_references +
-
Pike_compiler->compiler_frame->current_function_number;
-
}
-
-
init_bytecode();
-
label_no=1;
-
-
/* NOTE: This is no ordinary label... */
-
low_insert_label(0);
-
emit0(F_ENTRY);
-
emit0(F_START_FUNCTION);
-
-
if (Pike_compiler->compiler_frame->num_args) {
-
emit2(F_FILL_STACK, Pike_compiler->compiler_frame->num_args, 1);
-
}
-
emit1(F_MARK_AT, Pike_compiler->compiler_frame->num_args);
-
if (identifier_flags & IDENTIFIER_VARARGS) {
-
struct svalue *sval =
-
simple_mapping_string_lookup(get_builtin_constants(), "aggregate");
-
if (!sval) {
-
yyerror("predef::aggregate() is missing.\n");
-
Pike_fatal("No aggregate!\n");
-
UNREACHABLE(return 0);
-
}
-
aggregate_cnum = store_constant(sval, 0, NULL);
-
emit1(F_CALL_BUILTIN, aggregate_cnum);
-
if (Pike_compiler->compiler_frame->max_number_of_locals !=
-
Pike_compiler->compiler_frame->num_args+1) {
-
emit2(F_FILL_STACK,
-
Pike_compiler->compiler_frame->max_number_of_locals, 0);
-
}
-
} else {
-
emit0(F_POP_TO_MARK);
-
if (Pike_compiler->compiler_frame->max_number_of_locals !=
-
Pike_compiler->compiler_frame->num_args) {
-
emit2(F_FILL_STACK,
-
Pike_compiler->compiler_frame->max_number_of_locals, 0);
-
}
-
}
-
emit2(F_INIT_FRAME, Pike_compiler->compiler_frame->num_args,
-
Pike_compiler->compiler_frame->max_number_of_locals);
-
if (Pike_compiler->compiler_frame->lexical_scope & SCOPE_SCOPE_USED) {
-
emit_save_locals(Pike_compiler->compiler_frame);
-
}
-
-
if(id && (id->id_flags & ID_INLINE))
-
{
-
Pike_compiler->compiler_frame->recur_label=0;
-
Pike_compiler->compiler_frame->is_inline=1;
-
}
-
-
DO_CODE_BLOCK(n);
-
-
if(Pike_compiler->compiler_frame->recur_label > 0)
-
{
-
#ifdef PIKE_DEBUG
-
if(l_flag)
-
{
-
fprintf(stderr,"Generating inline recursive function.\n");
-
}
-
#endif
-
/* generate code again, but this time it is inline */
-
Pike_compiler->compiler_frame->is_inline=1;
-
-
/* NOTE: This is no ordinary label... */
-
low_insert_label(Pike_compiler->compiler_frame->recur_label);
-
emit0(F_ENTRY);
-
emit0(F_START_FUNCTION);
-
-
if (Pike_compiler->compiler_frame->num_args) {
-
emit2(F_FILL_STACK, Pike_compiler->compiler_frame->num_args, 1);
-
}
-
emit1(F_MARK_AT, Pike_compiler->compiler_frame->num_args);
-
if (identifier_flags & IDENTIFIER_VARARGS) {
-
emit1(F_CALL_BUILTIN, aggregate_cnum);
-
if (Pike_compiler->compiler_frame->max_number_of_locals !=
-
Pike_compiler->compiler_frame->num_args+1) {
-
emit2(F_FILL_STACK,
-
Pike_compiler->compiler_frame->max_number_of_locals, 0);
-
}
-
emit2(F_INIT_FRAME, Pike_compiler->compiler_frame->num_args+1,
-
Pike_compiler->compiler_frame->max_number_of_locals);
-
} else {
-
emit0(F_POP_TO_MARK);
-
if (Pike_compiler->compiler_frame->max_number_of_locals !=
-
Pike_compiler->compiler_frame->num_args) {
-
emit2(F_FILL_STACK,
-
Pike_compiler->compiler_frame->max_number_of_locals, 0);
-
}
-
emit2(F_INIT_FRAME, Pike_compiler->compiler_frame->num_args,
-
Pike_compiler->compiler_frame->max_number_of_locals);
-
}
-
if (Pike_compiler->compiler_frame->lexical_scope & SCOPE_SCOPE_USED) {
-
emit_save_locals(Pike_compiler->compiler_frame);
-
}
-
-
DO_CODE_BLOCK(n);
-
}
-
entry_point = assemble(1);
-
-
current_stack_depth = save_stack_depth;
-
label_no = save_label_no;
-
return entry_point;
-
}
-
-
/* Used by eval_low() to build code for constant expressions. */
-
INT32 docode(node *n)
-
{
-
INT32 entry_point;
-
int label_no_save = label_no;
-
struct byte_buffer instrbuf_save = instrbuf;
-
int stack_depth_save = current_stack_depth;
-
struct statement_label *label_save = current_label;
-
struct cleanup_frame *top_cleanups_save = top_statement_label_dummy.cleanups;
-
-
label_no=1;
-
current_stack_depth = 0;
-
current_label = &top_statement_label_dummy; /* Fix these two to */
-
top_statement_label_dummy.cleanups = 0; /* please F_PUSH_ARRAY. */
-
init_bytecode();
-
-
insert_opcode0(F_ENTRY, n->line_number, n->current_file);
-
/* FIXME: Should we check that do_docode() returns 1? */
-
do_docode(n,0);
-
insert_opcode0(F_DUMB_RETURN, n->line_number, n->current_file);
-
entry_point = assemble(0); /* Don't store linenumbers. */
-
-
instrbuf=instrbuf_save;
-
label_no = label_no_save;
-
current_stack_depth = stack_depth_save;
-
current_label = label_save;
-
top_statement_label_dummy.cleanups = top_cleanups_save;
-
return entry_point;
-
}
+
Newline at end of file removed.