static void unparse_stmt_catch(Stream * str, struct Stmt_Catch catchstmt, int indent) { Except_Arm *ex; stream_add_string(str, "try"); output(str); unparse_stmt(catchstmt.body, indent + 2); for (ex = catchstmt.excepts; ex; ex = ex->next) { indent_stmt(str, indent); stream_add_string(str, "except "); if (ex->id >= 0) stream_printf(str, "%s ", prog->var_names[ex->id]); stream_add_char(str, '('); if (ex->codes) unparse_arglist(str, ex->codes); else stream_add_string(str, "ANY"); stream_add_char(str, ')'); output(str); unparse_stmt(ex->stmt, indent + 2); } indent_stmt(str, indent); stream_add_string(str, "endtry"); output(str); }
static void unparse_stmt_cond(Stream * str, struct Stmt_Cond cond, int indent) { Cond_Arm *elseifs; stream_add_string(str, "if ("); unparse_expr(str, cond.arms->condition); stream_add_char(str, ')'); output(str); unparse_stmt(cond.arms->stmt, indent + 2); for (elseifs = cond.arms->next; elseifs; elseifs = elseifs->next) { indent_stmt(str, indent); stream_add_string(str, "elseif ("); unparse_expr(str, elseifs->condition); stream_add_char(str, ')'); output(str); unparse_stmt(elseifs->stmt, indent + 2); } if (cond.otherwise) { indent_stmt(str, indent); stream_add_string(str, "else"); output(str); unparse_stmt(cond.otherwise, indent + 2); } indent_stmt(str, indent); stream_add_string(str, "endif"); output(str); }
static void bracket_le(Stream * str, enum Expr_Kind parent, Expr * child) { if ((fully_parenthesize && expr_prec[child->kind] < expr_prec[EXPR_PROP]) || expr_prec[parent] >= expr_prec[child->kind]) { stream_add_char(str, '('); unparse_expr(str, child); stream_add_char(str, ')'); } else { unparse_expr(str, child); } }
static void indent_stmt(Stream * str, int indent) { int i; if (indent_code) for (i = 0; i < indent; i++) stream_add_char(str, ' '); }
static void unparse_name_expr(Stream * str, Expr * expr) { /* * Handle the right-hand expression in EXPR_PROP and EXPR_VERB. * If it's a simple string literal with the syntax of an identifier, * just print the name. Otherwise, use parens and unparse the * expression normally. */ if (expr->kind == EXPR_VAR && expr->e.var.type == TYPE_STR && ok_identifier(expr->e.var.v.str)) { stream_add_string(str, expr->e.var.v.str); return; } /* We need to use the full unparser */ stream_add_char(str, '('); unparse_expr(str, expr); stream_add_char(str, ')'); }
static void unparse_stmt_list(Stream * str, struct Stmt_List list, int indent) { stream_printf(str, "for %s in (", prog->var_names[list.id]); unparse_expr(str, list.expr); stream_add_char(str, ')'); output(str); unparse_stmt(list.body, indent + 2); indent_stmt(str, indent); stream_add_string(str, "endfor"); output(str); }
static void unparse_arglist(Stream * str, Arg_List * args) { while (args) { if (args->kind == ARG_SPLICE) stream_add_char(str, '@'); unparse_expr(str, args->expr); if (args->next) stream_add_string(str, ", "); args = args->next; } }
static void unparse_stmt_range(Stream * str, struct Stmt_Range range, int indent) { stream_printf(str, "for %s in [", prog->var_names[range.id]); unparse_expr(str, range.from); stream_add_string(str, ".."); unparse_expr(str, range.to); stream_add_char(str, ']'); output(str); unparse_stmt(range.body, indent + 2); indent_stmt(str, indent); stream_add_string(str, "endfor"); output(str); }
static void unparse_stmt_fork(Stream * str, struct Stmt_Fork fork_stmt, int indent) { if (fork_stmt.id >= 0) stream_printf(str, "fork %s (", prog->var_names[fork_stmt.id]); else stream_add_string(str, "fork ("); unparse_expr(str, fork_stmt.time); stream_add_char(str, ')'); output(str); unparse_stmt(fork_stmt.body, indent + 2); indent_stmt(str, indent); stream_add_string(str, "endfork"); output(str); }
static void unparse_scatter(Stream * str, Scatter * sc) { while (sc) { switch (sc->kind) { case SCAT_REST: stream_add_char(str, '@'); /* fall thru to ... */ case SCAT_REQUIRED: stream_add_string(str, prog->var_names[sc->id]); break; case SCAT_OPTIONAL: stream_printf(str, "?%s", prog->var_names[sc->id]); if (sc->expr) { stream_add_string(str, " = "); unparse_expr(str, sc->expr); } } if (sc->next) stream_add_string(str, ", "); sc = sc->next; } }
static void disassemble(Program * prog, Printer p, void *data) { Stream *s = new_stream(100); Stream *insn = new_stream(50); int i, l; unsigned pc; Bytecodes bc; const char *ptr; const char **names = prog->var_names; unsigned tmp, num_names = prog->num_var_names; # define NAMES(i) (tmp = i, \ tmp < num_names ? names[tmp] \ : "*** Unknown variable ***") Var *literals = prog->literals; initialize_tables(); print = p; print_data = data; stream_printf(s, "Language version number: %d", (int) prog->version); output(s); stream_printf(s, "First line number: %d", prog->first_lineno); output(s); for (i = -1; i < 0 || i < prog->fork_vectors_size; i++) { output(s); if (i == -1) { stream_printf(s, "Main code vector:"); output(s); stream_printf(s, "================="); output(s); bc = prog->main_vector; } else { stream_printf(s, "Forked code vector %d:", i); l = stream_length(s); output(s); while (l--) stream_add_char(s, '='); output(s); bc = prog->fork_vectors[i]; } stream_printf(s, "[Bytes for labels = %d, literals = %d, ", bc.numbytes_label, bc.numbytes_literal); stream_printf(s, "forks = %d, variables = %d, stack refs = %d]", bc.numbytes_fork, bc.numbytes_var_name, bc.numbytes_stack); output(s); stream_printf(s, "[Maximum stack size = %d]", bc.max_stack); output(s); max_bytes_width = 5; for (pc = 0; pc < bc.size;) { Byte b; unsigned arg; # define ADD_BYTES(n) (arg = add_bytes(s, bc.vector, pc, n), \ pc += n, \ arg) unsigned a1, a2; new_insn(s, pc); b = add_bytes(s, bc.vector, pc++, 1); if (b != OP_EXTENDED) stream_add_string(insn, COUNT_TICK(b) ? " * " : " "); if (IS_OPTIM_NUM_OPCODE(b)) stream_printf(insn, "NUM %d", OPCODE_TO_OPTIM_NUM(b)); #ifdef BYTECODE_REDUCE_REF else if (IS_PUSH_CLEAR_n(b)) stream_printf(insn, "PUSH_CLEAR %s", NAMES(PUSH_CLEAR_n_INDEX(b))); #endif /* BYTECODE_REDUCE_REF */ else if (IS_PUSH_n(b)) stream_printf(insn, "PUSH %s", NAMES(PUSH_n_INDEX(b))); else if (IS_PUT_n(b)) stream_printf(insn, "PUT %s", NAMES(PUT_n_INDEX(b))); else if (b == OP_EXTENDED) { b = ADD_BYTES(1); stream_add_string(insn, COUNT_EOP_TICK(b) ? " * " : " "); stream_add_string(insn, ext_mnemonics[b]); switch ((Extended_Opcode) b) { case EOP_WHILE_ID: a1 = ADD_BYTES(bc.numbytes_var_name); a2 = ADD_BYTES(bc.numbytes_label); stream_printf(insn, " %s %d", NAMES(a1), a2); break; case EOP_EXIT_ID: stream_printf(insn, " %s", NAMES(ADD_BYTES(bc.numbytes_var_name))); /* fall thru */ case EOP_EXIT: a1 = ADD_BYTES(bc.numbytes_stack); a2 = ADD_BYTES(bc.numbytes_label); stream_printf(insn, " %d %d", a1, a2); break; case EOP_PUSH_LABEL: case EOP_END_CATCH: case EOP_END_EXCEPT: case EOP_TRY_FINALLY: stream_printf(insn, " %d", ADD_BYTES(bc.numbytes_label)); break; case EOP_TRY_EXCEPT: stream_printf(insn, " %d", ADD_BYTES(1)); break; case EOP_LENGTH: stream_printf(insn, " %d", ADD_BYTES(bc.numbytes_stack)); break; case EOP_SCATTER: { int i, nargs = ADD_BYTES(1); a1 = ADD_BYTES(1); a2 = ADD_BYTES(1); stream_printf(insn, " %d/%d/%d:", nargs, a1, a2); for (i = 0; i < nargs; i++) { a1 = ADD_BYTES(bc.numbytes_var_name); a2 = ADD_BYTES(bc.numbytes_label); stream_printf(insn, " %s/%d", NAMES(a1), a2); } stream_printf(insn, " %d", ADD_BYTES(bc.numbytes_label)); } break; default: break; } } else { stream_add_string(insn, mnemonics[b]); switch ((Opcode) b) { case OP_IF: case OP_IF_QUES: case OP_EIF: case OP_AND: case OP_OR: case OP_JUMP: case OP_WHILE: stream_printf(insn, " %d", ADD_BYTES(bc.numbytes_label)); break; case OP_FORK: stream_printf(insn, " %d", ADD_BYTES(bc.numbytes_fork)); break; case OP_FORK_WITH_ID: a1 = ADD_BYTES(bc.numbytes_fork); a2 = ADD_BYTES(bc.numbytes_var_name); stream_printf(insn, " %d %s", a1, NAMES(a2)); break; case OP_FOR_LIST: case OP_FOR_RANGE: a1 = ADD_BYTES(bc.numbytes_var_name); a2 = ADD_BYTES(bc.numbytes_label); stream_printf(insn, " %s %d", NAMES(a1), a2); break; case OP_G_PUSH: #ifdef BYTECODE_REDUCE_REF case OP_G_PUSH_CLEAR: #endif /* BYTECODE_REDUCE_REF */ case OP_G_PUT: stream_printf(insn, " %s", NAMES(ADD_BYTES(bc.numbytes_var_name))); break; case OP_IMM: { Var v; v = literals[ADD_BYTES(bc.numbytes_literal)]; switch (v.type) { case TYPE_OBJ: stream_printf(insn, " #%d", v.v.obj); break; case TYPE_INT: stream_printf(insn, " %d", v.v.num); break; case TYPE_STR: stream_add_string(insn, " \""); for (ptr = v.v.str; *ptr; ptr++) { if (*ptr == '"' || *ptr == '\\') stream_add_char(insn, '\\'); stream_add_char(insn, *ptr); } stream_add_char(insn, '"'); break; case TYPE_ERR: stream_printf(insn, " %s", error_name(v.v.err)); break; default: stream_printf(insn, " <literal type = %d>", v.type); break; } } break; case OP_BI_FUNC_CALL: stream_printf(insn, " %s", name_func_by_num(ADD_BYTES(1))); default: break; } } finish_insn(s, insn); } } free_stream(s); free_stream(insn); }
static const char * translate_pattern(const char *pattern, int *tpatlen) { /* Translate a MOO pattern into a more standard syntax. Effectively, this * just involves converting from `%' escapes into `\' escapes. */ static Stream *s = 0; const char *p = pattern; char c; if (!s) s = new_stream(100); while (*p) { switch (c = *p++) { case '%': c = *p++; if (!c) goto fail; else if (strchr(".*+?[^$|()123456789bB<>wW", c)) stream_add_char(s, '\\'); stream_add_char(s, c); break; case '\\': stream_add_string(s, "\\\\"); break; case '[': /* Any '%' or '\' characters inside a charset should be copied * over without translation. */ stream_add_char(s, c); c = *p++; if (c == '^') { stream_add_char(s, c); c = *p++; } /* This is the only place a ']' can appear and not be the end of * the charset. */ if (c == ']') { stream_add_char(s, c); c = *p++; } while (c && c != ']') { stream_add_char(s, c); c = *p++; } if (!c) goto fail; else stream_add_char(s, c); break; default: stream_add_char(s, c); break; } } *tpatlen = stream_length(s); return reset_stream(s); fail: reset_stream(s); return 0; }
int network_process_io(int timeout) { network_handle nh; static server_handle sh; static Stream *s = 0; char buffer[1024]; int count; char *ptr, *end; int got_some = 0; if (s == 0) { int flags; s = new_stream(1000); if ((flags = fcntl(0, F_GETFL)) < 0 || fcntl(0, F_SETFL, flags | NONBLOCK_FLAG) < 0) { log_perror("Setting standard input non-blocking"); return 0; } } switch (state) { case STATE_CLOSED: if (listening) { sh = server_new_connection(slistener, nh, 0); state = STATE_OPEN; got_some = 1; } else if (timeout != 0) sleep(timeout); break; case STATE_OPEN: for (;;) { while (!input_suspended && (count = read(0, buffer, sizeof(buffer))) > 0) { got_some = 1; if (binary) { stream_add_string(s, raw_bytes_to_binary(buffer, count)); server_receive_line(sh, reset_stream(s)); } else for (ptr = buffer, end = buffer + count; ptr < end; ptr++) { unsigned char c = *ptr; if (isgraph(c) || c == ' ' || c == '\t') stream_add_char(s, c); else if (c == '\n') server_receive_line(sh, reset_stream(s)); } } if (got_some || timeout == 0) goto done; sleep(1); timeout--; } } done: return got_some; }
static void unparse_expr(Stream * str, Expr * expr) { switch (expr->kind) { case EXPR_PROP: if (expr->e.bin.lhs->kind == EXPR_VAR && expr->e.bin.lhs->e.var.type == TYPE_OBJ && expr->e.bin.lhs->e.var.v.obj == 0 && expr->e.bin.rhs->kind == EXPR_VAR && expr->e.bin.rhs->e.var.type == TYPE_STR && ok_identifier(expr->e.bin.rhs->e.var.v.str)) { stream_add_char(str, '$'); stream_add_string(str, expr->e.bin.rhs->e.var.v.str); } else { bracket_lt(str, EXPR_PROP, expr->e.bin.lhs); if (expr->e.bin.lhs->kind == EXPR_VAR && expr->e.bin.lhs->e.var.type == TYPE_INT) /* avoid parsing digits followed by dot as floating-point */ stream_add_char(str, ' '); stream_add_char(str, '.'); unparse_name_expr(str, expr->e.bin.rhs); } break; case EXPR_VERB: if (expr->e.verb.obj->kind == EXPR_VAR && expr->e.verb.obj->e.var.type == TYPE_OBJ && expr->e.verb.obj->e.var.v.obj == 0 && expr->e.verb.verb->kind == EXPR_VAR && expr->e.verb.verb->e.var.type == TYPE_STR && ok_identifier(expr->e.verb.verb->e.var.v.str)) { stream_add_char(str, '$'); stream_add_string(str, expr->e.verb.verb->e.var.v.str); } else { bracket_lt(str, EXPR_VERB, expr->e.verb.obj); stream_add_char(str, ':'); unparse_name_expr(str, expr->e.verb.verb); } stream_add_char(str, '('); unparse_arglist(str, expr->e.verb.args); stream_add_char(str, ')'); break; case EXPR_INDEX: bracket_lt(str, EXPR_INDEX, expr->e.bin.lhs); stream_add_char(str, '['); unparse_expr(str, expr->e.bin.rhs); stream_add_char(str, ']'); break; case EXPR_RANGE: bracket_lt(str, EXPR_RANGE, expr->e.range.base); stream_add_char(str, '['); unparse_expr(str, expr->e.range.from); stream_add_string(str, ".."); unparse_expr(str, expr->e.range.to); stream_add_char(str, ']'); break; /* left-associative binary operators */ case EXPR_PLUS: case EXPR_MINUS: case EXPR_TIMES: case EXPR_DIVIDE: case EXPR_MOD: case EXPR_AND: case EXPR_OR: case EXPR_EQ: case EXPR_NE: case EXPR_LT: case EXPR_GT: case EXPR_LE: case EXPR_GE: case EXPR_IN: bracket_lt(str, expr->kind, expr->e.bin.lhs); stream_add_string(str, binop_string[expr->kind]); bracket_le(str, expr->kind, expr->e.bin.rhs); break; /* right-associative binary operators */ case EXPR_EXP: bracket_le(str, expr->kind, expr->e.bin.lhs); stream_add_string(str, binop_string[expr->kind]); bracket_lt(str, expr->kind, expr->e.bin.rhs); break; case EXPR_COND: bracket_le(str, EXPR_COND, expr->e.cond.condition); stream_add_string(str, " ? "); unparse_expr(str, expr->e.cond.consequent); stream_add_string(str, " | "); bracket_le(str, EXPR_COND, expr->e.cond.alternate); break; case EXPR_NEGATE: stream_add_char(str, '-'); bracket_lt(str, EXPR_NEGATE, expr->e.expr); break; case EXPR_NOT: stream_add_char(str, '!'); bracket_lt(str, EXPR_NOT, expr->e.expr); break; case EXPR_VAR: stream_add_string(str, value_to_literal(expr->e.var)); break; case EXPR_ASGN: unparse_expr(str, expr->e.bin.lhs); stream_add_string(str, " = "); unparse_expr(str, expr->e.bin.rhs); break; case EXPR_CALL: stream_add_string(str, name_func_by_num(expr->e.call.func)); stream_add_char(str, '('); unparse_arglist(str, expr->e.call.args); stream_add_char(str, ')'); break; case EXPR_ID: stream_add_string(str, prog->var_names[expr->e.id]); break; case EXPR_LIST: stream_add_char(str, '{'); unparse_arglist(str, expr->e.list); stream_add_char(str, '}'); break; case EXPR_SCATTER: stream_add_char(str, '{'); unparse_scatter(str, expr->e.scatter); stream_add_char(str, '}'); break; case EXPR_CATCH: stream_add_string(str, "`"); unparse_expr(str, expr->e.catchexp.tryexp); stream_add_string(str, " ! "); if (expr->e.catchexp.codes) unparse_arglist(str, expr->e.catchexp.codes); else stream_add_string(str, "ANY"); if (expr->e.catchexp.except) { stream_add_string(str, " => "); unparse_expr(str, expr->e.catchexp.except); } stream_add_string(str, "'"); break; case EXPR_LENGTH: stream_add_string(str, "$"); break; default: errlog("UNPARSE_EXPR: Unknown Expr_Kind: %d\n", expr->kind); stream_add_string(str, "(?!?!?!?!?)"); break; } }
static void unparse_stmt(Stmt * stmt, int indent) { Stream *str = new_stream(100); while (stmt) { indent_stmt(str, indent); switch (stmt->kind) { case STMT_COND: unparse_stmt_cond(str, stmt->s.cond, indent); break; case STMT_LIST: unparse_stmt_list(str, stmt->s.list, indent); break; case STMT_RANGE: unparse_stmt_range(str, stmt->s.range, indent); break; case STMT_FORK: unparse_stmt_fork(str, stmt->s.fork, indent); break; case STMT_EXPR: unparse_expr(str, stmt->s.expr); stream_add_char(str, ';'); output(str); break; case STMT_WHILE: if (stmt->s.loop.id == -1) stream_add_string(str, "while ("); else stream_printf(str, "while %s (", prog->var_names[stmt->s.loop.id]); unparse_expr(str, stmt->s.loop.condition); stream_add_char(str, ')'); output(str); unparse_stmt(stmt->s.loop.body, indent + 2); indent_stmt(str, indent); stream_add_string(str, "endwhile"); output(str); break; case STMT_RETURN: if (stmt->s.expr) { stream_add_string(str, "return "); unparse_expr(str, stmt->s.expr); } else stream_add_string(str, "return"); stream_add_char(str, ';'); output(str); break; case STMT_TRY_EXCEPT: unparse_stmt_catch(str, stmt->s.catchexp, indent); break; case STMT_TRY_FINALLY: stream_add_string(str, "try"); output(str); unparse_stmt(stmt->s.finally.body, indent + 2); indent_stmt(str, indent); stream_add_string(str, "finally"); output(str); unparse_stmt(stmt->s.finally.handler, indent + 2); indent_stmt(str, indent); stream_add_string(str, "endtry"); output(str); break; case STMT_BREAK: case STMT_CONTINUE: { const char *kwd = (stmt->kind == STMT_BREAK ? "break" : "continue"); if (stmt->s.exit == -1) stream_printf(str, "%s;", kwd); else stream_printf(str, "%s %s;", kwd, prog->var_names[stmt->s.exit]); output(str); } break; default: errlog("UNPARSE_STMT: Unknown Stmt_Kind: %d\n", stmt->kind); stream_add_string(str, "?!?!?!?;"); output(str); break; } stmt = stmt->next; } free_stream(str); }
void stream_printf(Stream * s, const char *fmt,...) { char buffer[40]; va_list args; va_start(args, fmt); while (*fmt) { char c = *fmt; if (c == '%') { char pad = ' '; int width = 0, base; const char *string = ""; /* initialized to silence warning */ while ((c = *(++fmt)) != '\0') { switch (c) { case 's': string = va_arg(args, char *); break; case 'x': base = 16; goto finish_number; case 'o': base = 8; goto finish_number; case 'd': base = 10; finish_number: string = itoa(va_arg(args, int), base); break; case 'g': sprintf(buffer, dbl_fmt(), va_arg(args, double)); if (!strchr(buffer, '.') && !strchr(buffer, 'e')) strcat(buffer, ".0"); /* make it look floating */ string = buffer; break; case '0': if (width == 0) { pad = '0'; continue; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': width = width * 10 + c - '0'; continue; default: errlog("STREAM_PRINTF: Unknown format directive: %%%c\n", c); goto abort; } break; } if (width && (width -= strlen(string)) > 0) while (width--) stream_add_char(s, pad); stream_add_string(s, string); } else