diff -N -c ../MOO-1.8.1/SCATTERED_FOR.txt ./SCATTERED_FOR.txt *** ../MOO-1.8.1/SCATTERED_FOR.txt Thu Jan 1 01:00:00 1970 --- ./SCATTERED_FOR.txt Sat May 6 14:03:21 2000 *************** *** 0 **** --- 1,74 ---- + Scattered FOR statement patch + (c) Bert Huijben - March 2000 - bert@vmoo.com + + ------------------------------------------------------------------------------ + ****** Usage of this code is AT YOUR OWN RISK ****** + (As is all my non commercial code) + ------------------------------------------------------------------------------ + For the latest updates, please visit + http://www.vmoo.com/~bert/moo/server-patches/ + ------------------------------------------------------------------------------ + (Fixed a traceback bug, 6 may 2000) + + I have only tested this patch with LambdaMOO 1.8.1 but I assume it can + be used with other versions of the server code with minor modifications. + (These files haven't changed much in the last versions) + + + For adding the scattered FOR I needed to make changes to the following files: + * parser.y Add syntax + * ast.c Add statement type + * ast.h + * opcode.h Added a new (Extended) opcode + (Extended -> No upwards incompatibilities with previous server versions) + + * code_gen.c Generate code for this statement + * unparse.c + * decompile.c + * execute.c + + * disassemble.c Add update for EOP_FOR_SCATTER to bf_disassemble() + + * version.h Updated database format number (Incompatible statements) + + ------------------------------------------------------ + The scattered for behaves just like an for with an ordinary scatter inside + + for {a, b} in (list) + endfor + + Represented as: + for current_member in (list) + {a,b} = current_member; + endfor + + Raises + * E_TYPE when typeof(list) != list + * E_TYPE when typeof(current_member) != list + * E_ARGS when current_member doesn't 'fit' {a, b} + + + Just like oridinary scatters the scatter may contain imtems with the ? and @ + operators. + + ?a a is filled in when there is an item available and isn't accessed when + there is no fitting item + ( + An verb: + for {a, ?b} in ({{1}}) + player:Tell(b); + endfor + will raise E_VARNF if b isn't defined before the loop. + + (The verb;{a,?b}={1};player:tell(b); has the same problem) + ) + ?a=expr a is filled in when an item is available. When this isn't the case, + expr is evaluated and assigned to a. (expr isn't evaluated in the other + case (just like the ordinary scatter) + + @rest This type eats all elements which are left over after the other + variables are filled. (Only one @ is allowed per scatter) + + -------- + Bert Huijben, + Eemnes, The Netherlands, 16-3-2000 diff -N -c ../MOO-1.8.1/ast.c ./ast.c *** ../MOO-1.8.1/ast.c Mon Dec 14 14:17:26 1998 --- ./ast.c Sat May 6 13:58:37 2000 *************** *** 367,372 **** --- 367,382 ---- free_stmt(stmt->s.range.body); break; + /* Scattered FOR */ + case STMT_SCATFOR: + if (stmt->s.scatfor.scat) + /* = NULL when arglist couldn't be converted to scatter */ + free_scatter(stmt->s.scatfor.scat); + free_expr(stmt->s.scatfor.expr); + free_stmt(stmt->s.scatfor.body); + break; + /* /Scattered FOR */ + case STMT_WHILE: free_expr(stmt->s.loop.condition); free_stmt(stmt->s.loop.body); diff -N -c ../MOO-1.8.1/ast.h ./ast.h *** ../MOO-1.8.1/ast.h Mon Dec 14 14:17:28 1998 --- ./ast.h Sat May 6 13:58:37 2000 *************** *** 146,151 **** --- 146,159 ---- Stmt *body; }; + /* Scattered FOR */ + struct Stmt_ScatFor { + Scatter *scat; + Expr *expr; + Stmt *body; + }; + /* /Scattered FOR */ + struct Stmt_Loop { int id; Expr *condition; *************** *** 170,176 **** enum Stmt_Kind { STMT_COND, STMT_LIST, STMT_RANGE, STMT_WHILE, STMT_FORK, STMT_EXPR, ! STMT_RETURN, STMT_TRY_EXCEPT, STMT_TRY_FINALLY, STMT_BREAK, STMT_CONTINUE }; union Stmt_Data { --- 178,187 ---- enum Stmt_Kind { STMT_COND, STMT_LIST, STMT_RANGE, STMT_WHILE, STMT_FORK, STMT_EXPR, ! STMT_RETURN, STMT_TRY_EXCEPT, STMT_TRY_FINALLY, STMT_BREAK, STMT_CONTINUE, ! /* Scattered FOR */ ! STMT_SCATFOR ! /* /Scattered FOR */ }; union Stmt_Data { *************** *** 181,186 **** --- 192,198 ---- struct Stmt_Fork fork; struct Stmt_Catch catch; struct Stmt_Finally finally; + struct Stmt_ScatFor scatfor; Expr *expr; int exit; }; diff -N -c ../MOO-1.8.1/code_gen.c ./code_gen.c *** ../MOO-1.8.1/code_gen.c Sat Aug 14 21:44:15 1999 --- ./code_gen.c Sat May 6 13:58:37 2000 *************** *** 586,591 **** --- 586,634 ---- } } + /* Scattered FOR */ + static void + generate_scatter_data(Scatter * scat, State * state) + { + int nargs = 0, nreq = 0, rest = -1; + unsigned done; + Scatter *sc; + + for (sc = scat; sc; sc = sc->next) { + nargs++; + if (sc->kind == SCAT_REQUIRED) + nreq++; + else if (sc->kind == SCAT_REST) + rest = nargs; + } + + if (rest == -1) + rest = nargs + 1; + emit_byte(nargs, state); + emit_byte(nreq, state); + emit_byte(rest, state); + for (sc = scat; sc; sc = sc->next) { + add_var_ref(sc->id, state); + if (sc->kind != SCAT_OPTIONAL) + add_pseudo_label(0, state); + else if (!sc->expr) + add_pseudo_label(1, state); + else + sc->label = add_label(state); + } + done = add_label(state); + for (sc = scat; sc; sc = sc->next) + if (sc->kind == SCAT_OPTIONAL && sc->expr) { + define_label(sc->label, state); + generate_expr(sc->expr, state); + emit_var_op(OP_PUT, sc->id, state); + emit_byte(OP_POP, state); + pop_stack(1, state); + } + define_label(done, state); + } + /* /Scattered FOR */ + static void generate_expr(Expr * expr, State * state) { *************** *** 943,948 **** --- 986,1019 ---- pop_stack(2, state); } break; + /* Scattered FOR */ + case STMT_SCATFOR: + { + Fixup loop_top; + int end_label; + + generate_expr(stmt->s.scatfor.expr, state); + emit_byte(OPTIM_NUM_TO_OPCODE(1), state); /* loop list index */ + push_stack(1, state); + loop_top = capture_label(state); + + emit_extended_byte(EOP_FOR_SCATTER, state); + + end_label = add_label(state); + enter_loop(stmt->s.scatfor.scat->id, 0, loop_top, + state->cur_stack, end_label, + state->cur_stack - 2, state); + generate_scatter_data(stmt->s.scatfor.scat, state); + + generate_stmt(stmt->s.scatfor.body, state); + end_label = exit_loop(state); + emit_byte(OP_JUMP, state); + add_known_label(loop_top, state); + define_label(end_label, state); + pop_stack(2, state); + } + break; + /* /Scattered FOR */ case STMT_RANGE: { Fixup loop_top; diff -N -c ../MOO-1.8.1/decompile.c ./decompile.c *** ../MOO-1.8.1/decompile.c Wed Aug 11 10:23:40 1999 --- ./decompile.c Sat May 6 13:59:14 2000 *************** *** 784,789 **** --- 784,880 ---- s = alloc_stmt(STMT_WHILE); s->s.loop.id = READ_ID(); goto finish_while; + /* Scattered FOR */ + case EOP_FOR_SCATTER: + { + unsigned top = (ptr - 2) - bc.vector; /* 2 for EOP, 1 for OP */ + unsigned done = READ_LABEL(); + Expr *one = pop_expr(); + Expr *list = pop_expr(); + int jump_hot; + + if (one->kind != EXPR_VAR + || one->e.var.type != TYPE_INT + || one->e.var.v.num != 1) + panic("Not a literal one in DECOMPILE!"); + else + dealloc_node(one); + + { /* +- From scatter code (Some minor changes) */ + Scatter **scp, *sc; + int nargs = *ptr++; + int rest = (ptr++, *ptr++); /* skip nreq */ + int *next_label = 0; + int i, done, is_hot = op_hot; + + for (i = 1, scp = ≻ i <= nargs; + i++, scp = &((*scp)->next)) { + int id = READ_ID(); + int label = READ_LABEL(); + + *scp = + alloc_scatter(i == + rest ? SCAT_REST : label + == + 0 ? SCAT_REQUIRED : + SCAT_OPTIONAL, id, 0); + if (label > 1) { + (*scp)->label = label; + if (next_label) + *next_label = label; + next_label = &((*scp)->next_label); + } else + (*scp)->label = 0; + } + done = READ_LABEL(); + if (next_label) + *next_label = done; + + s = alloc_stmt(STMT_SCATFOR); + s->s.scatfor.expr = list; + s->s.scatfor.scat = sc; + + for ( /*sc = s->s.scatfor.scat */ ; sc; + sc = sc->next) if (sc->label) { + Expr *defallt; + + if (ptr != bc.vector + sc->label) + panic + ("Misplaced default in DECOMPILE!"); + DECOMPILE(bc, ptr, + bc.vector + sc->next_label - + 1, 0, 0); + defallt = pop_expr(); + HOT1(is_hot, defallt, 0 /* was e */ ); + if (defallt->kind != EXPR_ASGN + || defallt->e.bin.lhs->kind != + EXPR_ID + || defallt->e.bin.lhs->e.id != + sc-> + id) + panic + ("Wrong variable in DECOMPILE!"); + sc->expr = defallt->e.bin.rhs; + dealloc_node(defallt->e.bin.lhs); + dealloc_node(defallt); + is_hot = (is_hot || ptr == hot_byte); + if (*ptr++ != OP_POP) + panic + ("Missing default POP in DECOMPILE!"); + } + } + + DECOMPILE(bc, ptr, bc.vector + done - jump_len, + &(s->s.scatfor.body), 0); + if (top != READ_JUMP(jump_hot)) + panic + ("EOP_FOR_SCATTER jumps to wrong place in DECOMPILE!"); + + HOT_BOTTOM(jump_hot, s); + ADD_STMT(HOT_OP2(one, list, s)); + } + break; + /* /Scattered FOR */ case EOP_EXIT: case EOP_EXIT_ID: s = alloc_stmt(STMT_BREAK); *************** *** 952,957 **** --- 1043,1053 ---- return 1; lineno++; /* Skip `finally' line */ if (find_hot_node(stmt->s.finally.handler)) + return 1; + break; + case STMT_SCATFOR: + lineno++; /* Skip (scattered) `for' line */ + if (find_hot_node(stmt->s.scatfor.body)) return 1; break; default: diff -N -c ../MOO-1.8.1/disassemble.c ./disassemble.c *** ../MOO-1.8.1/disassemble.c Mon Dec 14 14:17:42 1998 --- ./disassemble.c Sat May 6 13:58:37 2000 *************** *** 107,113 **** {EOP_CONTINUE, "CONTINUE"}, {EOP_WHILE_ID, "WHILE_ID"}, {EOP_EXIT, "EXIT"}, ! {EOP_EXIT_ID, "EXIT_ID"}}; static void initialize_tables(void) --- 107,116 ---- {EOP_CONTINUE, "CONTINUE"}, {EOP_WHILE_ID, "WHILE_ID"}, {EOP_EXIT, "EXIT"}, ! {EOP_EXIT_ID, "EXIT_ID"}, ! /* Scattered FOR */ ! {EOP_FOR_SCATTER, "FOR_SCATTER"}}; ! /* /Scattered FOR */ static void initialize_tables(void) *************** *** 285,290 **** --- 288,300 ---- case EOP_LENGTH: stream_printf(insn, " %d", ADD_BYTES(bc.numbytes_stack)); break; + /* Scattered FOR */ + case EOP_FOR_SCATTER: + a2 = ADD_BYTES(bc.numbytes_label); + stream_printf(insn, " %d ", a2); + + /* Fall thru */ + /* /Scattered FOR */ case EOP_SCATTER: { int i, nargs = ADD_BYTES(1); diff -N -c ../MOO-1.8.1/execute.c ./execute.c *** ../MOO-1.8.1/execute.c Mon Dec 14 14:17:50 1998 --- ./execute.c Sat May 6 13:58:37 2000 *************** *** 1708,1714 **** --- 1708,1810 ---- PUSH(ans); } break; + /* Scattered FOR */ + case EOP_FOR_SCATTER: + { + unsigned lab = READ_BYTES(bv, bc.numbytes_label); + Var count, list; + count = TOP_RT_VALUE; /* will be a integer */ + list = NEXT_TOP_RT_VALUE; /* should be a list */ + if (list.type != TYPE_LIST) { + RAISE_ERROR(E_TYPE); + free_var(POP()); + free_var(POP()); + JUMP(lab); + break; + } else if (count.v.num > + list.v.list[0].v.num /* size */ ) { + free_var(POP()); + free_var(POP()); + JUMP(lab); + break; + } + { + int nargs = READ_BYTES(bv, 1); + int nreq = READ_BYTES(bv, 1); + int rest = READ_BYTES(bv, 1); + int have_rest = (rest > nargs ? 0 : 1); + Var list; + int len = 0, nopt_avail, nrest, i, offset; + int done, where = 0; + enum error e = E_NONE; + + /* Get list item AND increment index */ + + list = + NEXT_TOP_RT_VALUE.v.list[TOP_RT_VALUE.v. + num++]; + + if (list.type != TYPE_LIST) + e = E_TYPE; + else if ((len = list.v.list[0].v.num) < nreq + || (!have_rest && len > nargs)) + e = E_ARGS; + + if (e != E_NONE) { /* skip rest of operands */ + free_var(POP()); /* replace list with error code */ + PUSH_ERROR(e); + for (i = 1; i <= nargs; i++) { + READ_BYTES(bv, bc.numbytes_var_name); + READ_BYTES(bv, bc.numbytes_label); + } + } else { + nopt_avail = len - nreq; + nrest = (have_rest + && len >= + nargs ? len - nargs + 1 : 0); + for (offset = 0, i = 1; i <= nargs; i++) { + int id = READ_BYTES(bv, + bc.numbytes_var_name); + int label = + READ_BYTES(bv, bc.numbytes_label); + + if (i == rest) { /* rest */ + free_var(RUN_ACTIV.rt_env[id]); + RUN_ACTIV.rt_env[id] = + sublist(var_ref(list), i, + i + nrest - 1); + offset += nrest - 1; + } else if (label == 0) { /* required */ + free_var(RUN_ACTIV.rt_env[id]); + RUN_ACTIV.rt_env[id] = + var_ref(list.v. + list[i + offset]); + } else { /* optional */ + if (nopt_avail > 0) { + nopt_avail--; + free_var(RUN_ACTIV.rt_env[id]); + RUN_ACTIV.rt_env[id] = + var_ref(list.v.list[i + + offset]); + } else { + offset--; + if (where == 0 && label != 1) + where = label; + } + } + } + } + + done = READ_BYTES(bv, bc.numbytes_label); + if (where == 0) + JUMP(done); + else + JUMP(where); + } + } + break; + /* /Scattered FOR */ case EOP_SCATTER: { int nargs = READ_BYTES(bv, 1); diff -N -c ../MOO-1.8.1/opcode.h ./opcode.h *** ../MOO-1.8.1/opcode.h Mon Dec 14 14:18:40 1998 --- ./opcode.h Sat May 6 13:58:37 2000 *************** *** 32,37 **** --- 32,41 ---- EOP_WHILE_ID, EOP_EXIT, EOP_EXIT_ID, EOP_SCATTER, EOP_EXP, + /* Scatter Assignment */ + EOP_FOR_SCATTER, + /* /Scatter Assignment */ + Last_Extended_Opcode = 255 }; diff -N -c ../MOO-1.8.1/parser.y ./parser.y *** ../MOO-1.8.1/parser.y Mon Dec 14 14:18:45 1998 --- ./parser.y Sat May 6 13:58:37 2000 *************** *** 51,56 **** --- 51,59 ---- static void error(const char *, const char *); static void warning(const char *, const char *); static int find_id(char *name); + /* Scattered FOR */ + static const char* get_name_from_id(int); + /* /Scattered FOR */ static void yyerror(const char *s); static int yylex(void); static Scatter *scatter_from_arglist(Arg_List *); *************** *** 152,157 **** --- 155,199 ---- $$->s.list.body = $8; pop_loop_name(); } + /* Scattered FOR */ + | tFOR '{' scatter '}' tIN '(' expr ')' + { + vet_scatter($3); + push_loop_name(get_name_from_id($3->id)); + } + statements tENDFOR + { + $$ = alloc_stmt(STMT_SCATFOR); + $$->s.scatfor.scat = $3; + $$->s.scatfor.expr = $7; + $$->s.scatfor.body = $10; + + pop_loop_name(); + } + | tFOR '{' arglist '}' tIN '(' expr ')' + { + if (!$3) { + yyerror("Empty list in scattering assignment."); + break; + } else { + Scatter* sc = scatter_from_arglist($3); + if(sc) { + vet_scatter(sc); + push_loop_name(get_name_from_id(sc->id)); + } + else + push_loop_name(0); + + $$ = sc; + } + } + statements tENDFOR + { + $$ = alloc_stmt(STMT_SCATFOR); + $$->s.scatfor.scat = $9; + $$->s.scatfor.expr = $7; + $$->s.scatfor.body = $10; + + pop_loop_name(); + } + /* /Scattered FOR */ + | tFOR tID tIN '[' expr tTO expr ']' { push_loop_name($2); *************** *** 694,699 **** --- 736,751 ---- dealloc_string(name); return slot; } + + /* Scattered FOR */ + + /* Get name of variable for setting loopname (Loopname could be optimized as id instead) */ + static const char* + get_name_from_id(int id) + { + return local_names->names[id]; + } + /* /Scattered FOR */ static void yyerror(const char *s) Common subdirectories: ../MOO-1.8.1/pgperf and ./pgperf diff -N -c ../MOO-1.8.1/unparse.c ./unparse.c *** ../MOO-1.8.1/unparse.c Mon Dec 14 14:19:12 1998 --- ./unparse.c Sat May 6 13:58:37 2000 *************** *** 315,320 **** --- 315,340 ---- output(str); } + /* Scattered FOR */ + static void + unparse_stmt_scatfor(Stream * str, struct Stmt_ScatFor sfor, int indent) + { + stream_add_string(str, "for {"); + unparse_scatter(str, sfor.scat); + stream_add_string(str, "} in ("); + unparse_expr(str, sfor.expr); + stream_add_char(str, ')'); + + output(str); + + unparse_stmt(sfor.body, indent + 2); + indent_stmt(str, indent); + stream_add_string(str, "endfor"); + output(str); + } + + /* /Scattered FOR */ + static void unparse_stmt_range(Stream * str, struct Stmt_Range range, int indent) { *************** *** 390,395 **** --- 410,420 ---- case STMT_RANGE: unparse_stmt_range(str, stmt->s.range, indent); break; + /* Scattered FOR */ + case STMT_SCATFOR: + unparse_stmt_scatfor(str, stmt->s.scatfor, indent); + break; + /* /Scattered FOR */ case STMT_FORK: unparse_stmt_fork(str, stmt->s.fork, indent); break;