void test_move_card_from_non_stack_empty_stack_to_stack_empty_stack() { struct stack *origin, *destination; struct card *card[6]; for (int i = 0; i < 6; i++) { card_malloc(&card[i]); card_init(card[i]); card_set(card[i], TWO + i, i % 5, i % 2, 99, 99); } stack_malloc(&origin); stack_malloc(&destination); stack_init(origin); stack_init(destination); for (int i = 0; i < 6; i++) { stack_push(&origin, card[i]); } move_card(&origin, &destination); assert(stack_length(origin) == 5); assert(stack_length(destination) == 1); assert(cards_equal(destination->card, card[5])); move_card(&origin, &destination); assert(stack_length(origin) == 4); assert(stack_length(destination) == 2); assert(cards_equal(destination->card, card[4])); move_card(&origin, &destination); assert(stack_length(origin) == 3); assert(stack_length(destination) == 3); assert(cards_equal(destination->card, card[3])); stack_free(origin); stack_free(destination); }
double _parse(gchar *args, struct global_vars *gvars) { gchar mul_char = '*'; gdouble minus_one = -1.0; gchar null = 0; gint args_len = strlen(args); struct stack *arguments = stack_init(sizeof(gdouble)); struct stack *operators = stack_init(sizeof(gchar)); gint i = 0; gint j = 0; gint local_nest_level = 0; gint8 last_p = 0; /** priority of last parsed operator */ gboolean coef_flag = FALSE; /** set if value might preceed a bracket and thus become a coefficient */ gboolean func_flag = FALSE; /** set if result of next bracket is to be passed as an argument to function <symbol> */ gboolean nest_flag = FALSE; /** indicates characters are being collected and not parsed */ gboolean nest_init_flag = FALSE; /** necessary to skip first character '(' during string collection */ gboolean neg_flag = TRUE; /** set if next '-' will make number signed and not be an operator */ gboolean frac_flag = FALSE; //char nested_term[100] = { 0 }; /** collector string for contents of nested term */ GString *nested_term = g_string_new(&null); //char symbol[100] = { 0 }; /** collector string for symbol name */ GString *symbol = g_string_new(&null); for (i=0; i < args_len; i++) { if (nest_init_flag) {nest_init_flag = FALSE;} /** lock computing by raising nest level, substitute '*' if coefficient exists */ if (args[i] == '(') { if (!nest_flag) /** nested interpreting is just about to be initialized */ { if (coef_flag) {stack_push(operators, &mul_char); last_p = priority(mul_char);} coef_flag = TRUE; nest_flag = TRUE; nest_init_flag = TRUE; gvars->nest_level += 1; nested_term = g_string_new(&null); } else /** nested interpreting is in progress */ { local_nest_level += 1; } } else if (args[i] == ')') { if (nest_flag && local_nest_level == 0) /** nesting has reached end */ { nest_flag = FALSE; gdouble nested_term_result = _parse(nested_term->str, gvars); gvars->nest_level -= 1; g_string_free(nested_term, TRUE); nested_term = g_string_new(&null); if (func_flag) { gdouble compute_function_results = compute_function(symbol->str, nested_term_result, gvars); stack_push(arguments, &compute_function_results); func_flag = FALSE; g_string_free(symbol, TRUE); symbol = g_string_new(&null); } else {stack_push(arguments, &nested_term_result);} } else /** nested interpreting is in progress, passing by uninterpreted ')' */ { local_nest_level -= 1; } } if (!nest_flag) { if (args[i] == '.' || args[i] == ',') { if (g_ascii_isdigit(char_at(args,i+1))) {frac_flag = TRUE;} else {gvars->error_type = 3; return 0;} } else if (g_ascii_isdigit(args[i])) /** parse number */ { if (gvars->debug) {for (j=0;j<gvars->nest_level;j++) {g_printf(" ");} g_printf("args[%d] is digit\n", i);} gint8 dig = to_d(args[i]); stack_push(gvars->digits, &dig); if (frac_flag) {gvars->frac_point -= 1;} /** check if there is more than one digit or fractal part */ if (!(g_ascii_isdigit(char_at(args, i+1)) || char_at(args, i+1) == '.' || char_at(args, i+1) == ',')) { if (coef_flag) {stack_push(operators, &mul_char); last_p = priority(mul_char);} gdouble joined_dig = join_digits(gvars->digits, gvars->frac_point); stack_push(arguments, &joined_dig); neg_flag = FALSE; coef_flag = TRUE; frac_flag = FALSE; gvars->frac_point = 0; } } else if (isoperator(args[i])) /** parse operators */ { if (gvars->debug) {for (j=0;j<gvars->nest_level;j++) {g_printf(" ");} g_printf("args[%d] is operator\n", i);} if (neg_flag && args[i] == '-') /** check if preceeding minus changes sign of next symbol */ { neg_flag = FALSE; stack_push(arguments, &minus_one); stack_push(operators, &mul_char); last_p = priority(mul_char); } else { if (stack_length(arguments) <= stack_length(operators)) {gvars->error_type = 4; break;} /** check beforehand if lower priority operator is encountered */ if (priority(args[i]) < last_p) {compute(arguments, operators, gvars);} last_p = priority(args[i]); stack_push(operators, &args[i]); coef_flag = FALSE; neg_flag = TRUE; } } else if (g_ascii_isalpha(args[i])) /** parse letters */ { if (gvars->debug) {for (j=0;j<gvars->nest_level;j++) {g_printf(" ");} printf("args[%d] is letter\n", i);} if (coef_flag) {coef_flag = FALSE; stack_push(operators, &mul_char); last_p = priority(mul_char);} if (neg_flag) {neg_flag = FALSE;} g_string_append_c(symbol, args[i]); if (char_at(args,i+1) == '(') { compute_function(symbol->str, 1.337, gvars); if (gvars->error_type != 0) { gvars->error_type = 0; gdouble looked_up_c = lookup_constant(symbol->str, gvars); stack_push(arguments, &looked_up_c); //+symbol = ""; g_string_free(symbol, TRUE); symbol = g_string_new(&null); coef_flag = TRUE; } else {func_flag = TRUE;} } else if (!g_ascii_isalpha(char_at(args,i+1))) { gdouble looked_up_c = lookup_constant(symbol->str, gvars); stack_push(arguments, &looked_up_c); g_string_free(symbol, TRUE); symbol = g_string_new(&null); coef_flag = TRUE; } } } else if (!nest_init_flag) /** this collector block needs to be skipped once so the first '(' isn't collected */ { g_string_append_c(nested_term, args[i]); } if (args[i] == ' ') {coef_flag = FALSE;} if (char_at(args,i) == '#') {break;} /** failsafe, in case array bounds are left */ } if (gvars->debug) {printf("<args>\n");stack_dump(arguments, 'd');printf("<ops>\n");stack_dump(operators, 'c');printf("<>\n");} if (local_nest_level != 0 && gvars->error_type == 0) {gvars->error_type = 1;} if (neg_flag && gvars->error_type == 0) {gvars->error_type = 4;} if (gvars->error_type == 0) {compute(arguments, operators, gvars);} if (stack_length(arguments) > 1 && gvars->error_type == 0) {gvars->error_type = 4;printf("no2\n");} gdouble return_value = 0; if (gvars->error_type == 0) {stack_pop(arguments, &return_value);} stack_destroy(arguments); stack_destroy(operators); return return_value; }
void key_path(int graph[][MAX]) { int graph2[MAX][MAX]; int i; for (i = 0; i < MAX; i++) { int j; for (j = 0; j < MAX; j++) graph2[i][j] = graph[i][j]; } stack sve, svl; init_stack(&sve, 100); init_stack(&svl, 100); int ve[MAX]; for (i = 0; i < MAX; i++) ve[i] = 0; int j; for (j = 0; j < MAX; j++) { for (i = 0; i < MAX; i++) { if (graph2[i][j] != 0) break; } if (i == MAX) push(&sve, j); } while (stack_length(&sve)) { int s = pop(&sve); push(&svl, s); int n; for (n = 0; n < MAX; n++) { graph2[s][n] = 0; if (graph[s][n] != 0) { int l; for (l = 0; l < MAX; l++) { if (graph2[l][n] != 0) break; } if (l == MAX) push(&sve, n); } } int m; for (m = 0; m < MAX; m++) { if (graph[s][m] != 0) if (ve[s]+graph[s][m] > ve[m]) ve[m] = ve[s] + graph[s][m]; } } int vl[MAX]; for (i = 0; i < MAX; i++) vl[i] = ve[MAX-1]; int x; while (stack_length(&svl)) { int v = pop(&svl); for (x = 0; x < MAX; x++) if (graph[x][v] != 0) if ((vl[v] - graph[x][v]) < vl[x]) vl[x] = vl[v] - graph[x][v]; } int key[MAX]; i = 0; int y; for (y = 0; y < MAX; y++) { if (ve[y] == vl[y]) { key[i] = y; i++; } } printf("all the key node: "); for (y = 0; y < i; y++) printf ("%d ", key[y]); printf("\n"); printf("keypath: "); int prev = key[0]; int next = key[1]; int length = 0; int ne; while (1) { length += graph[prev][next]; printf("%d ", prev); if (next == key[i-1]) { printf ("%d\n", next); break; } for (y = 0; y < i; y++) { ne = key[y]; if (graph[next][ne] != 0 ) { prev = next; next = ne; break; } } } printf("keypath length: %d\n", length); }
void print_stack(stack *s) { while(stack_length(s) != 0) printf("%c", pop(s)); printf ("\n"); }
Link interpret(Link codeblock_link , Link This, Link Arg){ CallEnv env = callenv_new_root( codeblock_link, This, Arg); LinkStack stack = env->stack; Link b = NULL; Link link = NULL; Link parent = NULL; Link child_key = NULL; Link pusher = NULL; // Anything in this variable gets pushed onto the stack Link trapped = NULL; // This is the last critical caught by the trap operator int delta = 0; // jump delta /* Main interpreter loop */ while(1){ switch( *(env->current++) ){ case INTRO: env->current+=4; break; case ALLOC_MODULE: delta = read_offset(env); env->module->global_vars = linkarray_new(delta); break; case ALLOC_LOCAL: delta = read_offset(env); env->local = linkarray_new(delta); break; case NO_OP: break; case RETURN: // if there is something on the env->stack stack pop it off and return it, if not return null link if ( stack_length(stack) - env->stack_offset ){ pusher = stack_pop(stack); }else{ pusher = object_create(Global->null_type); } goto done; case RAISE: // if there is something on the stack stack pop it off and return it, if not return null link if ( stack_length(stack) - env->stack_offset ){ pusher = create_critical(stack_pop(stack)); }else{ pusher = create_critical(object_create(Global->null_type)); } goto done; case PUSH_LEX: delta = read_offset(env); //fprintf(stderr , "push lex [%i] %p\n", delta,env->function->value.codeblock->lexicals); pusher = link_dup(env->function->value.codeblock->lexicals->vars[delta]); break; case STORE_LEX: delta = read_offset(env); //fprintf(stderr , "storing lex [%i] %p\n", delta,env->function->value.codeblock->lexicals); b = env->function->value.codeblock->lexicals->vars[delta]; if (b){ if ( (b->type == Global->function_type) && (b->value.codeblock->lexicals == env->function->value.codeblock->lexicals) ) b->value.codeblock->lexical_cycles--; link_free(b); } b = link_dup(stack_peek(stack)); if ( (b->type == Global->function_type) && (b->value.codeblock->lexicals == env->function->value.codeblock->lexicals) ) b->value.codeblock->lexical_cycles++; env->function->value.codeblock->lexicals->vars[delta] = b; break; case DEF: if (env->Def) link_free(env->Def); env->Def = stack_pop(env->stack); pusher = link_dup(env->Def); break; case PUSH_DEF: if ( ! env->Def){ pusher = exception("NoDefObject",NULL, NULL); } pusher = link_dup(env->Def); break; case ALLOC_LEXICAL: delta = read_offset(env); lexicals_alloc( env->function, delta); //env->lexical_root = 1; break; case STORE_ARG: delta = read_offset(env); if (env->Arg->value.array->length > delta){ retry_store_arg: env->Arg->value.array->links[delta] = link_dup( stack_peek(stack) ); }else{ array_push(env->Arg, NULL); goto retry_store_arg; } break; case PUSH_ARG: delta = read_offset(env); if (env->Arg->value.array->length > delta){ pusher = link_dup( env->Arg->value.array->links[delta]); }else{ pusher = exception("ArgsIndexOutOfBounds", NULL, NULL); } break; case STORE_GVAR: delta = read_offset(env); if (env->module->global_vars->links[delta]){ link_free(env->module->global_vars->links[delta]); } env->module->global_vars->links[delta] = link_dup( stack_peek(stack) ); break; case STORE_VAR: delta = read_offset(env); if (env->local->links[delta]){ link_free(env->local->links[delta]); } env->local->links[delta] = link_dup( stack_peek(stack) ); break; case STORE_CHILD: link = stack_pop(stack); // value child_key = stack_pop(stack); // key to find the child parent = stack_pop(stack); // parent to look in pusher = object_addChild(parent, link, child_key); goto STORE_COMMON; case STORE_ATTR: link = stack_pop(stack); // value child_key = stack_pop(stack); // key to find the child parent = stack_pop(stack); // parent to look in pusher = addAttr(parent, link,child_key); goto STORE_COMMON; STORE_COMMON: if (! pusher){ pusher = exception("AssignError", NULL, NULL); link_free(link); } link_free(child_key); link_free(parent); break; case LT: delta = compare(env); pusher = create_numberi( (delta < 0) ? 1 : 0 ); break; case GT: delta = compare(env); pusher = create_numberi( (delta > 0) ? 1 : 0 ); break; case EQ: delta = compare(env); pusher = create_numberi( (delta == 0) ? 1 : 0 ); break; case NE: delta = compare(env); pusher = create_numberi( (delta == 0) ? 0 : 1 ); break; case LE: delta = compare(env); pusher = create_numberi( (delta <= 0) ? 1 : 0 ); break; case GE: delta = compare(env); pusher = create_numberi( (delta >= 0) ? 1 : 0 ); break; case CMP: delta = compare(env); pusher = create_numberi( delta ); break; case OR: case AND: break; case SUB: b = stack_pop(env->stack); link = stack_pop(env->stack); if ( (link->type == Global->number_type) && (link->type == b->type)){ pusher = create_number(link->value.number - b->value.number); link_free(link); link_free(b); break; } pusher = object_op_minus(link,b); link_free(link); link_free(b); break; case ADD: b = stack_pop(env->stack); link = stack_pop(env->stack); if ( (link->type == Global->number_type) && (link->type == b->type)){ pusher = create_number(link->value.number + b->value.number); link_free(link); link_free(b); break; } pusher = object_op_plus(link,b); link_free(link); link_free(b); break; case DIV: binary_op(env , object_op_divide); break; case MULT: binary_op(env , object_op_multiply); break; case MOD: binary_op(env , object_op_modulus); break; case POW: binary_op(env , object_op_power); break; case NEG: unary_op(env, object_op_neg); break; case NOT: link = stack_pop(stack); pusher = create_numberi( (object_is_true(link)) ? 0 : 1 ); link_free(link); break; case TEST: case ELSE: break; case DO: delta = read_offset(env); link = codeblock_literal2( env->function->value.codeblock->parent, delta ); if (env->function->value.codeblock->lexicals) { lexicals_attach( env->function->value.codeblock->lexicals, link); } env = callenv_new_doblock(env,link); break; case PUSH_ARRAY: delta = read_offset(env); pusher = array_new_subarray( stack , delta); break; case CALL: link = stack_pop(stack); // the arguments in an array b = stack_pop(stack); // the function that gets called parent = link_dup(env->This); // caller goto CALL_COMMON; case CALL_ATTR: link = stack_pop(stack); // arguments child_key = stack_pop(stack); // name of the function parent = stack_pop(stack); // caller b = getAttr(parent,child_key); // the function that gets called link_free(child_key); // no longer need the attributes key if (! b) { pusher = exception("AttrNotFound", NULL, NULL); break; } goto CALL_COMMON; case CALL_CHILD: link = stack_pop(stack); // ARG child_key = stack_pop(stack); parent = stack_pop(stack); // THIS b = object_getChild(parent,child_key); link_free(child_key); goto CALL_COMMON; CALL_COMMON: /* function type so we can call it inline */ if (b->type == Global->function_type){ env = callenv_new_function(env, b, parent, link); // ce , func,this, arg /* Not a CodeBlock so we have to use its virtual call function */ }else{ pusher = object_call(b, parent, link);// function, caller, args link_free(link); if (parent) link_free(parent); link_free(b); if (! pusher) pusher = object_create(Global->null_type); } break; case DEL_CHILD: child_key = stack_pop(stack); // key to find the child parent = stack_pop(stack); // parent to look in /* delete child from container */ pusher = object_delChild(parent,child_key); if (! pusher) pusher = exception("ChildNotFound", object_getString(child_key), NULL); link_free(child_key); link_free(parent); break; case DEL_ATTR: child_key = stack_pop(stack); // key to find the child parent = stack_pop(stack); // parent to look in /* delete attr from container */ pusher = delAttr(parent,child_key); if (! pusher) pusher = exception("AttrNotFound", object_getString(child_key), NULL); link_free(child_key); link_free(parent); break; case GET_CHILD: child_key = stack_pop(stack); // key to find the child parent = stack_pop(stack); // parent to look in pusher = object_getChild(parent, child_key); if (! pusher) pusher = exception("ChildNotFound", object_getString(child_key), NULL); link_free(parent); link_free(child_key); break; case GET_ATTR: child_key = stack_pop(stack); // key to find the child parent = stack_pop(stack); // parent to look in pusher = getAttr(parent, child_key); if (! pusher) pusher = exception("AttrNotFound", object_getString(child_key), NULL); link_free(parent); link_free(child_key); break; case TRAP: break; case CLEAR: for ( delta = stack_length( stack ) ; delta > env->stack_offset ; delta--){ link_free( stack_pop(stack) ); } break; case STOP: break; done: case END: for ( delta = stack_length( stack ) ; delta > env->stack_offset ; delta--){ link_free( stack_pop(stack) ); } addBacktrace(pusher, env->function, env->linenum); env = callenv_free(env); if (! env) goto end; if (! pusher) pusher = object_create(Global->null_type); break; /* JUMPS */ case JIT: /* Jump if true */ delta = read_offset(env); link = stack_peek(stack); if ( link->type->is_true(link) ) env->current = env->start+delta; break; case JIF: /* Jump if false */ delta = read_offset(env); link = stack_peek(stack); if ( ! link->type->is_true(link) ) env->current = env->start+delta; break; case JIF_POP: /* Pop value then jump if value is false, */ delta = read_offset(env); link = stack_pop(stack); if ( ! link->type->is_true(link) ) env->current = env->start+delta; link_free(link); break; case JUMP: /* Absolute jump */ delta = read_offset(env); env->current = env->start + delta; break; case JINC: /* Jump If Not Critical */ delta = read_offset(env); env->current = env->start+delta; break; jinc_critical: delta = read_offset(env); if (trapped) link_free(trapped); trapped = pusher->value.link; pusher->value.link = NULL; link_free(pusher); pusher = NULL; break; case PUSH_NULL: pusher = create_null(); break; case PUSH_NUM: pusher = create_number( *((number_t *)env->current) ); env->current+= sizeof(number_t); break; case PUSH_STR: delta = read_offset(env); pusher = create_string_literal( env->start + delta ); break; case PUSH_GVAR: delta = read_offset(env); pusher = link_dup(env->module->global_vars->links[delta]); if (! pusher){ pusher = exception("GlobalVariableUsedBeforeSet",NULL,NULL); } break; case PUSH_VAR: delta = read_offset(env); pusher = link_dup(env->local->links[delta]); if (! pusher){ pusher = exception("VariableUsedBeforeSet",NULL,NULL);; } break; case PUSH_BLOCK: delta = read_offset(env); pusher = codeblock_literal2( env->function->value.codeblock->parent, delta ); if (env->function->value.codeblock->lexicals) { lexicals_attach( env->function->value.codeblock->lexicals, pusher); } break; case PUSH_SYS: pusher = link_dup(Global->SYS_MODULE); break; case PUSH_MODULE: pusher = link_dup( env->function->value.codeblock->parent); break; case TYPEOF: link = stack_pop(stack); pusher = link_dup( link->type->type_link); link_free(link); break; case PUSH_THIS: pusher = link_dup(env->This); break; case PUSH_SELF: pusher = link_dup(env->Self); break; case PUSH_ARGS: pusher = link_dup(env->Arg); break; case PUSH_TRAPPED: pusher = trapped ? link_dup(trapped) : object_create(Global->null_type); break; case POP: link_free( stack_pop(stack) ); break; case LINE: env->linenum = read_offset(env); break; default: fprintf(stderr," UNRECOGNIZED OPCODE ERROR %i\n", *(env->current)); fprintf(stderr," near line %i\n", (int)(env->linenum)); exit(1); break; } if (pusher) { if ( is_critical( pusher ) ){ if ( *(env->current) == JINC) goto jinc_critical; goto done; } stack_push(stack , pusher); pusher = NULL; } } end: if (trapped) link_free(trapped); return pusher; }