static void transform_CEIL(struct radeon_compiler* c, struct rc_instruction* inst) { /* Assuming: * ceil(x) = -floor(-x) * * After inlining floor: * ceil(x) = -(-x-frac(-x)) * * After simplification: * ceil(x) = x+frac(-x) */ struct rc_dst_register dst = try_to_reuse_dst(c, inst); emit1(c, inst->Prev, RC_OPCODE_FRC, 0, dst, negate(inst->U.I.SrcReg[0])); emit2(c, inst->Prev, RC_OPCODE_ADD, inst->U.I.SaturateMode, inst->U.I.DstReg, inst->U.I.SrcReg[0], srcreg(RC_FILE_TEMPORARY, dst.Index)); rc_remove_instruction(inst); }
ssize_t process_unicorn_data( context_t *ctx, size_t ready ) { unicorn_config_t *cf = ctx->data; x_printf(ctx, "Entering process_unicorn_data()\n"); if( ready >= cf->msgHdr.length ) { char *data_buffer = alloca( cf->msgHdr.length ); u_ringbuf_read( &cf->input, data_buffer, cf->msgHdr.length ); driver_data_t notification = { TYPE_DATA, ctx, {} }; notification.event_data.bytes = cf->msgHdr.length; notification.event_data.data = data_buffer; emit2( ctx, EVENT_DATA_INCOMING, ¬ification ); cf->flags &= ~(unsigned int)UNICORN_EXPECTING_DATA; return 0; } x_printf(ctx, "Leaving process_unicorn_data()\n"); return -1; }
/** * Approximate sin(x), where x is clamped to (-pi/2, pi/2). * * MUL tmp.xy, src, { 4/PI, -4/(PI^2) } * MAD tmp.x, tmp.y, |src|, tmp.x * MAD tmp.y, tmp.x, |tmp.x|, -tmp.x * MAD dest, tmp.y, weight, tmp.x */ static void sin_approx( struct radeon_compiler* c, struct rc_instruction * inst, struct rc_dst_register dst, struct rc_src_register src, const unsigned int* constants) { unsigned int tempreg = rc_find_free_temporary(c); emit2(c, inst->Prev, RC_OPCODE_MUL, 0, dstregtmpmask(tempreg, RC_MASK_XY), swizzle_xxxx(src), srcreg(RC_FILE_CONSTANT, constants[0])); emit3(c, inst->Prev, RC_OPCODE_MAD, 0, dstregtmpmask(tempreg, RC_MASK_X), swizzle_yyyy(srcreg(RC_FILE_TEMPORARY, tempreg)), absolute(swizzle_xxxx(src)), swizzle_xxxx(srcreg(RC_FILE_TEMPORARY, tempreg))); emit3(c, inst->Prev, RC_OPCODE_MAD, 0, dstregtmpmask(tempreg, RC_MASK_Y), swizzle_xxxx(srcreg(RC_FILE_TEMPORARY, tempreg)), absolute(swizzle_xxxx(srcreg(RC_FILE_TEMPORARY, tempreg))), negate(swizzle_xxxx(srcreg(RC_FILE_TEMPORARY, tempreg)))); emit3(c, inst->Prev, RC_OPCODE_MAD, 0, dst, swizzle_yyyy(srcreg(RC_FILE_TEMPORARY, tempreg)), swizzle_wwww(srcreg(RC_FILE_CONSTANT, constants[0])), swizzle_xxxx(srcreg(RC_FILE_TEMPORARY, tempreg))); }
static void transform_r300_vertex_fix_LIT(struct radeon_compiler* c, struct rc_instruction* inst) { struct rc_dst_register dst = try_to_reuse_dst(c, inst); unsigned constant_swizzle; int constant = rc_constants_add_immediate_scalar(&c->Program.Constants, 0.0000000000000000001, &constant_swizzle); /* MOV dst, src */ dst.WriteMask = RC_MASK_XYZW; emit1(c, inst->Prev, RC_OPCODE_MOV, 0, dst, inst->U.I.SrcReg[0]); /* MAX dst.y, src, 0.00...001 */ emit2(c, inst->Prev, RC_OPCODE_MAX, 0, dstregtmpmask(dst.Index, RC_MASK_Y), srcreg(RC_FILE_TEMPORARY, dst.Index), srcregswz(RC_FILE_CONSTANT, constant, constant_swizzle)); inst->U.I.SrcReg[0] = srcreg(RC_FILE_TEMPORARY, dst.Index); }
static void transform_SSG(struct radeon_compiler* c, struct rc_instruction* inst) { /* result = sign(x) * * CMP tmp0, -x, 1, 0 * CMP tmp1, x, 1, 0 * ADD result, tmp0, -tmp1; */ struct rc_dst_register dst0; unsigned tmp1; /* 0 < x */ dst0 = try_to_reuse_dst(c, inst); emit3(c, inst->Prev, RC_OPCODE_CMP, 0, dst0, negate(inst->U.I.SrcReg[0]), builtin_one, builtin_zero); /* x < 0 */ tmp1 = rc_find_free_temporary(c); emit3(c, inst->Prev, RC_OPCODE_CMP, 0, dstregtmpmask(tmp1, inst->U.I.DstReg.WriteMask), inst->U.I.SrcReg[0], builtin_one, builtin_zero); /* Either both are zero, or one of them is one and the other is zero. */ /* result = tmp0 - tmp1 */ emit2(c, inst->Prev, RC_OPCODE_ADD, 0, inst->U.I.DstReg, srcreg(RC_FILE_TEMPORARY, dst0.Index), negate(srcreg(RC_FILE_TEMPORARY, tmp1))); rc_remove_instruction(inst); }
ssize_t unicorn_handler(context_t *ctx, event_t event, driver_data_t *event_data) { event_data_t *data = 0L; event_child_t *child = 0L; unicorn_config_t *cf = (unicorn_config_t *) ctx->data; //x_printf(ctx, "<%s> Event = \"%s\" (%d)\n", ctx->name, event_map[event], event); if (event_data->type == TYPE_DATA) data = &event_data->event_data; else if( event_data->type == TYPE_CHILD ) child = & event_data->event_child; switch (event) { case EVENT_INIT: { x_printf(ctx,"calling event add SIGQUIT\n"); event_add( ctx, SIGQUIT, EH_SIGNAL ); x_printf(ctx,"calling event add SIGTERM\n"); event_add( ctx, SIGTERM, EH_SIGNAL ); x_printf(ctx,"calling event 1000 EH_WANT_TICK\n"); event_add( ctx, 1000, EH_WANT_TICK ); cf->driver = config_get_item( ctx->config, "endpoint" ); if( ! config_get_timeval( ctx->config, "retry", &cf->retry_time ) ) cf->retry_time = 120*1000; if( cf->driver ) start_service( &cf->modem, cf->driver, ctx->config, ctx, 0L ); if( !cf->modem ) { logger( ctx, "Unable to launch modem driver. Exiting\n" ); cf->state = UNICORN_STATE_ERROR; context_terminate( ctx ); return -1; } cf->state = UNICORN_STATE_IDLE; } break; case EVENT_TERMINATE: { cf->pending_action_timeout = rel_time(0L); cf->flags |= UNICORN_TERMINATING; // In process of terminating the modem driver cf->state = UNICORN_STATE_STOPPING; // In process of terminating self // Ensure 'exec' driver known not to restart when the modem driver terminates. // If the modem driver is something other than 'exec', this should be ignored. uint8_t flag = 0; driver_data_t notification = { TYPE_CUSTOM, ctx, {} }; notification.event_custom = &flag; emit(cf->modem, EXEC_SET_RESPAWN, ¬ification); if( cf->driver_state == CMD_ST_ONLINE ) { x_printf(ctx,"Driver is online - sending disconnect\n"); send_unicorn_command( ctx, CMD_DISCONNECT, CMD_ST_OFFLINE, 0, 0L ); } else { x_printf(ctx,"Driver is offline - sending shutdown\n"); send_unicorn_command( ctx, CMD_STATE, CMD_ST_OFFLINE, 0, 0L ); } } break; case EVENT_RESTART: // This event is used to signal that the modem driver needs to resync. // set the 'reconnecting' flag and send a disconnect x_printf(ctx,"EVENT_RESTART: - sending disconnect to modem\n"); //logger(ctx, "Sending disconnect command to modem driver"); if( event_data->source == ctx->owner ) { cf->pending_action_timeout = rel_time(0L); cf->flags |= UNICORN_WAITING_FOR_CONNECT; if( cf->modem ) { x_printf(ctx, "Sending CMD_DISCONNECT to modem driver (%s)\n",cf->modem->name); if( (event_data->type == TYPE_CUSTOM) && event_data->event_custom ) { logger(ctx, "Sending abort command to modem driver due to unexpected disconnect"); send_unicorn_command( ctx, CMD_ABORT, CMD_ST_OFFLINE, 0, 0L ); } else { logger(ctx, "Sending disconnect command to modem driver"); send_unicorn_command( ctx, CMD_DISCONNECT, CMD_ST_OFFLINE, 0, 0L ); } } else { x_printf(ctx, "Modem driver not running.. doing nothing.\n"); } } else { x_printf(ctx,"Forwarding EVENT_RESTART to owner (%s)\n",ctx->name); emit2( ctx, EVENT_RESTART, event_data); } break; case EVENT_CHILD: x_printf(ctx,"Got a message from a child (%s:%d).. probably starting\n", child->ctx->name, child->action); if ( child->ctx == cf->modem ) { if( child->action == CHILD_STARTING ) { cf->state = UNICORN_STATE_RUNNING; cf->flags &= ~(unsigned int) UNICORN_RESTARTING; // Assume ensure the first time the modem driver starts it skips the connection delay cf->flags |= UNICORN_FIRST_START; } if ( child->action == CHILD_STOPPED ) { x_printf(ctx,"Modem driver terminated - restart or terminate\n"); // modem driver terminated. Restart or exit. cf->state = UNICORN_STATE_IDLE; if ( cf->flags & UNICORN_TERMINATING ) { x_printf(ctx,"Terminating immediately\n"); context_terminate( ctx ); } else { x_printf(ctx,"Need to restart modem driver\n"); cf->flags |= UNICORN_RESTARTING; cf->pending_action_timeout = rel_time(0L); // Reset the driver state, and notify the parent that we are offline cf->driver_state = CMD_ST_UNKNOWN; context_owner_notify( ctx, CHILD_EVENT, UNICORN_MODE_OFFLINE ); } } } break; case EVENT_DATA_INCOMING: case EVENT_DATA_OUTGOING: if( event_data->source == cf->modem ) { size_t bytes = data->bytes; size_t offset = 0; while( bytes ) { size_t to_read = u_ringbuf_avail( &cf->input ); if( to_read > bytes ) to_read = bytes; u_ringbuf_write( &cf->input, &((char *)data->data)[offset], to_read ); bytes -= to_read; offset += to_read; while(process_unicorn_packet(ctx) >= 0); } return (ssize_t) offset; } else { send_unicorn_command( ctx, CMD_DATA, CMD_ST_ONLINE, data->bytes,data->data); return (ssize_t) data->bytes; } break; case EVENT_READ: break; case EVENT_EXCEPTION: break; case EVENT_SIGNAL: x_printf(ctx,"Woa! Got a sign from the gods... %d\n", event_data->event_signal); if( event_data->event_signal == SIGQUIT || event_data->event_signal == SIGTERM ) emit( ctx, EVENT_TERMINATE, 0L ); break; case EVENT_TICK: { time_t now = rel_time(0L); // Handle case where a massive time shift due to NTP resync causes all timeouts to fire simultaneously // This is technically deprecated due to the use of rel_time() if( (now - cf->last_message) > MAXIMUM_SAFE_TIMEDELTA ) { logger(ctx, "WARNING: Resetting timeout due to RTC time change"); cf->last_message = now; } if( ((now - cf->last_message) > UNICORN_KEEPALIVE_TIMEOUT ) && ( cf->driver_state != CMD_ST_UNKNOWN )) { if( ~ cf->flags & UNICORN_LAGGED ) { // Its been a couple of minutes since the last keepalive, reset the driver_state // to unknown and prompt for one. logger(ctx,"Forcing connection state request due to communications timeout.\n"); cf->flags |= UNICORN_LAGGED; cf->retry_count = UNICORN_KEEPALIVE_RETRY_MAX; } if( cf->retry_count ) { send_unicorn_command( ctx, CMD_STATE, CMD_ST_OFFLINE, 0, 0L ); cf->retry_count --; } else { // Its been a long time since the last message, despite prompting for one // restart the modem driver logger(ctx, "Communications timeout. Restarting modem driver."); uint8_t sig = SIGHUP; driver_data_t notification = { TYPE_CUSTOM, ctx, {} }; notification.event_custom = &sig; emit( cf->modem, EVENT_RESTART, ¬ification ); } cf->last_message = now; } if( (cf->flags & UNICORN_RESTARTING) && ((now - cf->pending_action_timeout) > UNICORN_RESTART_DELAY )) { x_printf(ctx,"Restart delay expired - restarting modem driver\n"); cf->pending_action_timeout = rel_time(0L); if( cf->driver ) start_service( &cf->modem, cf->driver, ctx->config, ctx, 0L ); } else if( (cf->flags & UNICORN_RECONNECTING) && ((now - cf->pending_action_timeout) > cf->retry_time )) { x_printf(ctx,"Reconnect delay expired - attempting reconnect\n"); cf->pending_action_timeout = rel_time(0L); cf->flags &= ~(unsigned int)UNICORN_RECONNECTING; if( cf->modem ) send_unicorn_command(ctx, CMD_CONNECT, CMD_ST_ONLINE, 0, 0 ); } else if( (cf->flags & UNICORN_WAITING_FOR_CONNECT) && ((now - cf->pending_action_timeout) > UNICORN_CONNECT_TIMEOUT )) { x_printf(ctx,"Timeout during connect - terminating modem driver\n"); cf->flags &= ~(unsigned int) UNICORN_WAITING_FOR_CONNECT; cf->state = UNICORN_STATE_IDLE; if( cf->modem ) emit( cf->modem, EVENT_TERMINATE, 0L ); } if( (cf->flags & UNICORN_TERMINATING) && ((now - cf->pending_action_timeout) > UNICORN_PROCESS_TERMINATION_TIMEOUT)) { x_printf(ctx,"termination timeout - killing the modem driver with prejudice\n"); cf->state = UNICORN_STATE_IDLE; if( cf->modem ) context_terminate( cf->modem ); context_terminate( ctx ); } // Special case.. If I am expecting a data frame, and it takes too long to arrive, // reset state. if( (cf->flags & UNICORN_EXPECTING_DATA) && ((now - cf->last_message) > FRAME_TIMEOUT)) { x_printf(ctx,"FRAME TIMEOUT - resetting input buffer\n"); u_ringbuf_init( &cf->input ); cf->flags &= ~(unsigned int)UNICORN_EXPECTING_DATA; } #ifndef NDEBUG size_t bytes = u_ringbuf_ready( &cf->input ); if( bytes ) x_printf(ctx,"Un-processed data in ring buffer... %d bytes\n",(int)bytes); #endif } break; default: x_printf(ctx,"\n *\n *\n * Emitted some kind of event \"%s\" (%d)\n *\n *\n", event_map[event], event); } return 0; }
/** * Definition of LIT (from ARB_fragment_program): * * tmp = VectorLoad(op0); * if (tmp.x < 0) tmp.x = 0; * if (tmp.y < 0) tmp.y = 0; * if (tmp.w < -(128.0-epsilon)) tmp.w = -(128.0-epsilon); * else if (tmp.w > 128-epsilon) tmp.w = 128-epsilon; * result.x = 1.0; * result.y = tmp.x; * result.z = (tmp.x > 0) ? RoughApproxPower(tmp.y, tmp.w) : 0.0; * result.w = 1.0; * * The longest path of computation is the one leading to result.z, * consisting of 5 operations. This implementation of LIT takes * 5 slots, if the subsequent optimization passes are clever enough * to pair instructions correctly. */ static void transform_LIT(struct radeon_compiler* c, struct rc_instruction* inst) { unsigned int constant; unsigned int constant_swizzle; unsigned int temp; struct rc_src_register srctemp; constant = rc_constants_add_immediate_scalar(&c->Program.Constants, -127.999999, &constant_swizzle); if (inst->U.I.DstReg.WriteMask != RC_MASK_XYZW || inst->U.I.DstReg.File != RC_FILE_TEMPORARY) { struct rc_instruction * inst_mov; inst_mov = emit1(c, inst, RC_OPCODE_MOV, 0, inst->U.I.DstReg, srcreg(RC_FILE_TEMPORARY, rc_find_free_temporary(c))); inst->U.I.DstReg.File = RC_FILE_TEMPORARY; inst->U.I.DstReg.Index = inst_mov->U.I.SrcReg[0].Index; inst->U.I.DstReg.WriteMask = RC_MASK_XYZW; } temp = inst->U.I.DstReg.Index; srctemp = srcreg(RC_FILE_TEMPORARY, temp); /* tmp.x = max(0.0, Src.x); */ /* tmp.y = max(0.0, Src.y); */ /* tmp.w = clamp(Src.z, -128+eps, 128-eps); */ emit2(c, inst->Prev, RC_OPCODE_MAX, 0, dstregtmpmask(temp, RC_MASK_XYW), inst->U.I.SrcReg[0], swizzle(srcreg(RC_FILE_CONSTANT, constant), RC_SWIZZLE_ZERO, RC_SWIZZLE_ZERO, RC_SWIZZLE_ZERO, constant_swizzle&3)); emit2(c, inst->Prev, RC_OPCODE_MIN, 0, dstregtmpmask(temp, RC_MASK_Z), swizzle_wwww(srctemp), negate(srcregswz(RC_FILE_CONSTANT, constant, constant_swizzle))); /* tmp.w = Pow(tmp.y, tmp.w) */ emit1(c, inst->Prev, RC_OPCODE_LG2, 0, dstregtmpmask(temp, RC_MASK_W), swizzle_yyyy(srctemp)); emit2(c, inst->Prev, RC_OPCODE_MUL, 0, dstregtmpmask(temp, RC_MASK_W), swizzle_wwww(srctemp), swizzle_zzzz(srctemp)); emit1(c, inst->Prev, RC_OPCODE_EX2, 0, dstregtmpmask(temp, RC_MASK_W), swizzle_wwww(srctemp)); /* tmp.z = (tmp.x > 0) ? tmp.w : 0.0 */ emit3(c, inst->Prev, RC_OPCODE_CMP, inst->U.I.SaturateMode, dstregtmpmask(temp, RC_MASK_Z), negate(swizzle_xxxx(srctemp)), swizzle_wwww(srctemp), builtin_zero); /* tmp.x, tmp.y, tmp.w = 1.0, tmp.x, 1.0 */ emit1(c, inst->Prev, RC_OPCODE_MOV, inst->U.I.SaturateMode, dstregtmpmask(temp, RC_MASK_XYW), swizzle(srctemp, RC_SWIZZLE_ONE, RC_SWIZZLE_X, RC_SWIZZLE_ONE, RC_SWIZZLE_ONE)); rc_remove_instruction(inst); }
void processOperator(SymbolTable *table, Node *ptr) { int stIndex; switch(ptr->token.tokenNumber) { case ASSIGN_OP: { Node *lhs = ptr->son, *rhs = ptr->son->next; if (lhs->noderep == NONTERM) { lvalue = 1; processOperator(table, lhs); lvalue = 0; } if (rhs->noderep == NONTERM) { processOperator(table, rhs); } else { rv_emit(table, rhs); } if (lhs->noderep == TERMINAL) { stIndex = lookup(table, lhs->token.tokenValue); if (stIndex == -1) { fprintf(stderr, "undefined variable: %s\n", lhs->token.tokenValue); return; } emit2("str", table->rows[stIndex].base, table->rows[stIndex].offset); } else { emit0("sti"); } break; } case ADD_ASSIGN: case SUB_ASSIGN: case MUL_ASSIGN: case DIV_ASSIGN: case MOD_ASSIGN: { Node *lhs = ptr->son, *rhs = ptr->son->next; int nodeNumber = ptr->token.tokenNumber; ptr->token.tokenNumber = ASSIGN_OP; if (lhs->noderep == NONTERM) { lvalue = 1; processOperator(table, lhs); lvalue = 0; } ptr->token.tokenNumber = nodeNumber; if (lhs->noderep == NONTERM) { processOperator(table, lhs); } else { rv_emit(table, lhs); } if (rhs->noderep == NONTERM) { processOperator(table, rhs); } else { rv_emit(table, rhs); } switch(ptr->token.tokenNumber) { case ADD_ASSIGN: emit0("add"); break; case SUB_ASSIGN: emit0("sub"); break; case MUL_ASSIGN: emit0("mult"); break; case DIV_ASSIGN: emit0("div"); break; case MOD_ASSIGN: emit0("mod"); break; } if (lhs->noderep == TERMINAL) { stIndex = lookup(table, lhs->token.tokenValue); if (stIndex == -1) { fprintf(file, "undefined variable: %s\n", lhs->son->token.tokenValue); return; } emit2("str", table->rows[stIndex].base, table->rows[stIndex].offset); } else { emit0("sti"); } break; } case ADD: case SUB: case MUL: case DIV: case MOD: case EQ: case NE: case GT: case LT: case GE: case LE: case LOGICAL_AND: case LOGICAL_OR: { Node *lhs = ptr->son, *rhs = ptr->son->next; if (lhs->noderep == NONTERM) { processOperator(table, lhs); } else { rv_emit(table, lhs); } if (rhs->noderep == NONTERM) { processOperator(table, rhs); } else { rv_emit(table, rhs); } switch(ptr->token.tokenNumber) { case ADD: emit0("add"); break; case SUB: emit0("sub"); break; case MUL: emit0("mult"); break; case DIV: emit0("div"); break; case MOD: emit0("mod"); break; case EQ: emit0("eq"); break; case NE: emit0("ne"); break; case GT: emit0("gt"); break; case LT: emit0("lt"); break; case GE: emit0("ge"); break; case LE: emit0("le"); break; case LOGICAL_AND: emit0("and"); break; case LOGICAL_OR: emit0("or"); break; } break; } case UNARY_MINUS: case LOGICAL_NOT: { Node *p = ptr->son; if (p->noderep == NONTERM) { processOperator(table, p); } else { rv_emit(table, p); } switch(ptr->token.tokenNumber) { case UNARY_MINUS: emit0("neg"); break; case LOGICAL_NOT: emit0("not"); break; } break; } case INDEX: { Node *indexExp = ptr->son->next; if (indexExp->noderep == NONTERM) processOperator(table, indexExp); else rv_emit(table, indexExp); stIndex = lookup(table, ptr->son->token.tokenValue); if (stIndex == -1) { fprintf(file, "undefined variable: %s\n", ptr->son->token.tokenValue); return; } emit2("lda", table->rows[stIndex].base, table->rows[stIndex].offset); emit0("add"); if (!lvalue) { emit0("ldi"); } break; } case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: { Node *p = ptr->son; Node *q; int stIndex; int amount = 1; if (p->noderep == NONTERM) { processOperator(table, p); } else { rv_emit(table, p); } q = p; while (q->noderep != TERMINAL) { q = q->son; } if (!q || (q->token.tokenNumber != IDENT)) { fprintf(file, "increment/decrement operators can not be applied in expression\n"); return; } stIndex = lookup(table, q->token.tokenValue); if (stIndex == -1) { return; } switch(ptr->token.tokenNumber) { case PRE_INC: emit0("inc"); break; case PRE_DEC: emit0("dec"); break; case POST_INC: emit0("inc"); break; case POST_DEC: emit0("dec"); break; } if (p->noderep == TERMINAL) { stIndex = lookup(table, p->token.tokenValue); if (stIndex == -1) { return; } emit2("str", table->rows[stIndex].base, table->rows[stIndex].offset); } else if (p->token.tokenNumber == INDEX) { lvalue = 1; processOperator(table, p); lvalue = 0; emit0("swp"); emit0("sti"); } else fprintf(file, "error in increment/decrement operators\n"); break; } case CALL: { Node *p = ptr->son; char *functionName; int stIndex; int noArguments; if (checkPredefined(table, p)) { break; } functionName = p->token.tokenValue; stIndex = lookup(rootTable, functionName); if (stIndex == -1) { fprintf(file, "%s: undefined function\n", functionName); break; } noArguments = rootTable->rows[stIndex].width; emit0("ldp"); p = p->next->son; while (p) { if (p->noderep == NONTERM) { processOperator(table, p); } else { rv_emit(table, p); } noArguments--; p = p->next; } if (noArguments > 0) { fprintf(file, "%s: too few actual arguments\n", functionName); } if (noArguments < 0) { fprintf(file, "%s: too many actual arguments\n", functionName); } emitJump("call", ptr->son->token.tokenValue); break; } } }
int checkPredefined(SymbolTable *table, Node *ptr) { Node *p=ptr; char *functionName; int noArguments; int stIndex; functionName = p->token.tokenValue; if (strcmp(functionName, "read") == 0) { noArguments = 1; emit0("ldp"); p = p->next->son; while (p) { if (p->noderep == NONTERM) { processOperator(table, p); } else { stIndex = lookup(table, p->token.tokenValue); if (stIndex == -1) { return 0; } emit2("lda", table->rows[stIndex].base, table->rows[stIndex].offset); } noArguments--; p = p->next; } if (noArguments > 0) { fprintf(file, "%s: too few actual arguments\n", functionName); } if (noArguments < 0) { fprintf(file, "%s: too many actual arguments\n", functionName); } emitJump("call", functionName); return 1; } else if (strcmp(functionName, "write") == 0) { noArguments = 1; emit0("ldp"); p = p->next->son; while (p) { if (p->noderep == NONTERM) { processOperator(table, p); } else { stIndex = lookup(table, p->token.tokenValue); if (stIndex == -1) return 0; emit2("lod", table->rows[stIndex].base, table->rows[stIndex].offset); } noArguments--; p=p->next; } if (noArguments > 0) { fprintf(file, "%s: too few actual arguments\n", functionName); } if (noArguments < 0) { fprintf(file, "%s: too many actual arguments\n", functionName); } emitJump("call", functionName); return 1; } else if (strcmp(functionName, "lf") == 0) { emitJump("call", functionName); return 1; } return 0; }
static int compile_operator(compiletime c) { int operand_count = 0; const char *op = pop_operator(c, &operand_count); if (!strcmp(op, "*")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, multiply_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "**")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, power_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "/")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, divide_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "%")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, modulo_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "=")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, assign_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, ";")) { } else if (!strcmp(op, "if")) { const char *val1 = pop_operand(c); emit2(c, if_tc, val1); DEBUG printf("emit '%s' %s\n", val1, op); c->level++; } else if (!strcmp(op, "else")) { c->level--; emit1(c, else_tc); c->level++; DEBUG printf("emit %s\n", op); } else if (!strcmp(op, "fi")) { c->level--; emit1(c, fi_tc); DEBUG printf("emit %s\n", op); } else if (!strcmp(op, "!")) { const char *val1 = pop_operand(c); emit2(c, not_tc, val1); DEBUG printf("emit '%s' %s\n", val1, op); } else if (!strcmp(op, "+")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, add_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "-")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, subtract_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, ">")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, gt_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, ">=")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, geq_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "<=")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, leq_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "<")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, lt_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "&&")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, and_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "||")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, or_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "^^")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, xor_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "&")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, bit_and_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "|")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, bit_or_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "^")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, bit_xor_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "~")) { const char *val1 = pop_operand(c); emit2(c, bit_negate_tc, val1); DEBUG printf("emit %s %s\n", val1, op); } else if (!strcmp(op, "<<")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, shift_left_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, ">>")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, shift_right_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, ">>>")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, logical_shift_right_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "==")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, eq_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "!=")) { const char *val2 = pop_operand(c); const char *val1 = pop_operand(c); emit3(c, neq_tc, val1, val2); DEBUG printf("emit %s %s %s\n", val1, op, val2); } else if (!strcmp(op, "fold-case")) { const char *val1 = pop_operand(c); emit2(c, func_fold_case_tc, val1); DEBUG printf("emit %s %s\n", op, val1); } else if (!strcmp(op, "size")) { const char *val1 = pop_operand(c); emit2(c, func_size_tc, val1); DEBUG printf("emit %s %s\n", op, val1); } else if (!strcmp(op, "print")) { const char *val1 = pop_operand(c); emit2(c, func_print_tc, val1); DEBUG printf("emit %s %s\n", op, val1); } else if (!strcmp(op, "jday")) { const char *val1 = pop_operand(c); emit2(c, func_jday_tc, val1); DEBUG printf("emit %s %s\n", op, val1); } else if (!strcmp(op, "dow")) { const char *val1 = pop_operand(c); emit2(c, func_dow_tc, val1); DEBUG printf("emit %s %s\n", op, val1); } else if (!strcmp(op, "equals")) { emit_code(c, func_eq_tc, operand_count); while (operand_count--) { const char *val1 = pop_operand(c); emit_value(c, val1); DEBUG printf("emit %s '%s'\n", op, val1); } } else if (!strcmp(op, "contains")) { emit_code(c, func_contains_tc, operand_count); while (operand_count--) { const char *val1 = pop_operand(c); emit_value(c, val1); DEBUG printf("emit %s '%s'\n", op, val1); } } else if (!strcmp(op, "begins-with")) { emit_code(c, func_begins_with_tc, operand_count); while (operand_count--) { const char *val1 = pop_operand(c); emit_value(c, val1); DEBUG printf("emit %s '%s'\n", op, val1); } } else if (!strcmp(op, "ends-with")) { emit_code(c, func_ends_with_tc, operand_count); while (operand_count--) { const char *val1 = pop_operand(c); emit_value(c, val1); DEBUG printf("emit %s '%s'\n", op, val1); } } else if (!strcmp(op, "int")) { const char *val1 = pop_operand(c); emit2(c, func_is_int_tc, val1); DEBUG printf("emit %s '%s'\n", op, val1); } else if (!strcmp(op, "real")) { const char *val1 = pop_operand(c); emit2(c, func_is_real_tc, val1); DEBUG printf("emit %s '%s'\n", op, val1); } else if (!strcmp(op, "nan")) { const char *val1 = pop_operand(c); emit2(c, func_is_nan_tc, val1); DEBUG printf("emit %s '%s'\n", op, val1); } else if (!strcmp(op, "string")) { const char *val1 = pop_operand(c); emit2(c, func_is_string_tc, val1); DEBUG printf("emit %s '%s'\n", op, val1); } else if (!strcmp(op, "(")) { return 1; } else if (!strcmp(op, ")")) { return 1; } else { DEBUG printf("bad operator '%s'\n", op); return 0; } push_operand(c, "_STACK"); return 1; }