diff options
author | Gavin Howard <gavin@yzena.com> | 2022-10-23 14:35:27 -0600 |
---|---|---|
committer | Gavin Howard <gavin@yzena.com> | 2022-10-23 14:35:53 -0600 |
commit | 92eff1f500c9b1e4845849bfc929d798318f84a7 (patch) | |
tree | 5c7d63124c0138471dba0c2c03680fa7298240e6 | |
parent | 1610acd5dbf5b9653aa23d5043525ea95771da68 (diff) | |
download | bc-92eff1f500c9b1e4845849bfc929d798318f84a7.tar.gz |
Add the ability for bc to turn full arrays into strings
This will simplify the handling of strings for users, I think.
Signed-off-by: Gavin Howard <gavin@yzena.com>
-rw-r--r-- | src/bc_parse.c | 6 | ||||
-rw-r--r-- | src/program.c | 100 | ||||
-rw-r--r-- | tests/bc/all.txt | 1 | ||||
-rw-r--r-- | tests/bc/asciify_array.txt | 17 | ||||
-rw-r--r-- | tests/bc/asciify_array_results.txt | 3 |
5 files changed, 104 insertions, 23 deletions
diff --git a/src/bc_parse.c b/src/bc_parse.c index aacdb73f..9048a377 100644 --- a/src/bc_parse.c +++ b/src/bc_parse.c @@ -530,7 +530,11 @@ bc_parse_builtin(BcParse* p, BcLexType type, uint8_t flags, BcInst* prev) flags |= BC_PARSE_NEEDVAL; // Since length can take arrays, we need to specially add that flag. - if (type == BC_LEX_KW_LENGTH) flags |= BC_PARSE_ARRAY; + if (type == BC_LEX_KW_LENGTH || type == BC_LEX_KW_ASCIIFY) + { + flags |= BC_PARSE_ARRAY; + } + // Otherwise, we need to clear it because it could be set. else flags &= ~(BC_PARSE_ARRAY); diff --git a/src/program.c b/src/program.c index 8b984904..38ad0fec 100644 --- a/src/program.c +++ b/src/program.c @@ -2070,6 +2070,9 @@ bc_program_builtin(BcProgram* p, uchar inst) // bc_program_num() to a vector. BcVec* v = (BcVec*) num; + // XXX: If this is changed, you should also change the similar + // code in bc_program_asciify(). + #if BC_ENABLED // Dereference the array, if necessary. if (BC_IS_BC && v->size == sizeof(uchar)) @@ -2239,19 +2242,18 @@ bc_program_asciifyNum(BcProgram* p, BcNum* n) } /** - * Executes the "asciify" command in dc. - * @param p The program. - * @param fidx The index of the current function. + * Executes the "asciify" command in bc and dc. + * @param p The program. */ static void -bc_program_asciify(BcProgram* p, size_t fidx) +bc_program_asciify(BcProgram* p) { BcResult *r, res; BcNum* n; - char str[2]; - char* str2; uchar c; size_t idx; + // This is in the outer scope because it has to be freed after a jump. + char* temp_str; // Check the stack. if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK); @@ -2262,35 +2264,89 @@ bc_program_asciify(BcProgram* p, size_t fidx) bc_program_operand(p, &r, &n, 0); assert(n != NULL); - assert(r->t != BC_RESULT_ARRAY); + assert(BC_IS_BC || r->t != BC_RESULT_ARRAY); - // Asciify. - if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n); - else +#if BC_ENABLED + // Handle arrays in bc specially. + if (r->t == BC_RESULT_ARRAY) { - // Get the string itself, then the first character. - str2 = bc_program_string(p, n); - c = (uchar) str2[0]; + // Yes, this is one place where we need to cast the number from + // bc_program_num() to a vector. + BcVec* v = (BcVec*) n; + size_t i; + + // XXX: If this is changed, you should also change the similar code in + // bc_program_builtin(). + + // Dereference the array, if necessary. + if (v->size == sizeof(uchar)) + { + v = bc_program_dereference(p, v); + } + + assert(v->size == sizeof(BcNum)); + + // Allocate the string and set the jump for it. + BC_SIG_LOCK; + BC_SETJMP_LOCKED(vm, exit); + temp_str = bc_vm_malloc(v->len + 1); + BC_SIG_UNLOCK; + + // Convert the array. + for (i = 0; i < v->len; ++i) + { + BcNum* num = (BcNum*) bc_vec_item(v, i); + temp_str[i] = (char) bc_program_asciifyNum(p, num); + } + + temp_str[v->len] = '\0'; + + // Store the string in the slab and map, and free the temp string. + BC_SIG_LOCK; + idx = bc_program_addString(p, temp_str); + free(temp_str); + BC_UNSETJMP(vm); + BC_SIG_UNLOCK; } + else +#endif // BC_ENABLED + { + char str[2]; + char* str2; - // Fill the resulting string. - str[0] = (char) c; - str[1] = '\0'; + // Asciify. + if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n); + else + { + // Get the string itself, then the first character. + str2 = bc_program_string(p, n); + c = (uchar) str2[0]; + } - // Add the string to the data structures. - BC_SIG_LOCK; - idx = bc_program_addString(p, str); - BC_SIG_UNLOCK; + // Fill the resulting string. + str[0] = (char) c; + str[1] = '\0'; + + // Add the string to the data structures. + BC_SIG_LOCK; + idx = bc_program_addString(p, str); + BC_SIG_UNLOCK; + } // Set the result res.t = BC_RESULT_STR; bc_num_clear(&res.d.n); - res.d.n.rdx = fidx; res.d.n.scale = idx; // Pop and push. bc_vec_pop(&p->results); bc_vec_push(&p->results, &res); + + return; + +exit: + + free(temp_str); } /** @@ -3222,7 +3278,7 @@ bc_program_exec(BcProgram* p) BC_PROG_LBL(BC_INST_ASCIIFY): // clang-format on { - bc_program_asciify(p, ip->func); + bc_program_asciify(p); // Because we changed the execution stack and where we are // executing, we have to update all of this. diff --git a/tests/bc/all.txt b/tests/bc/all.txt index 775b274d..af5eaaa4 100644 --- a/tests/bc/all.txt +++ b/tests/bc/all.txt @@ -53,6 +53,7 @@ bitfuncs leadingzero is_number is_string +asciify_array line_by_line1 line_by_line2 line_loop_quit1 diff --git a/tests/bc/asciify_array.txt b/tests/bc/asciify_array.txt new file mode 100644 index 00000000..4efae1d1 --- /dev/null +++ b/tests/bc/asciify_array.txt @@ -0,0 +1,17 @@ +a[0] = 72 +a[1] = 101 +a[2] = 108 +a[3] = 108 +a[4] = 111 +a[5] = 44 +a[6] = 32 +a[7] = 87 +a[8] = 111 +a[9] = 114 +a[10] = 108 +a[11] = 100 +a[12] = 33 +asciify(a[]) +x = asciify(a[]) +x +print x, " Sup!\n" diff --git a/tests/bc/asciify_array_results.txt b/tests/bc/asciify_array_results.txt new file mode 100644 index 00000000..d0dc2bc3 --- /dev/null +++ b/tests/bc/asciify_array_results.txt @@ -0,0 +1,3 @@ +Hello, World! +Hello, World! +Hello, World! Sup! |