Skip to content

Commit 3fc80ca

Browse files
committed
Added substring(s, ind, len). Should fix GitHub issue #656.
1 parent b85101b commit 3fc80ca

File tree

7 files changed

+132
-9
lines changed

7 files changed

+132
-9
lines changed

CHANGELOG

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
1... WLA GB-Z80/Z80/Z80N/6502/65C02/65CE02/65816/68000/6800/6801/6809/8008/8080/HUC6280/SPC-700/SuperFX History
44
---------------------------------------------------------------------------------------------------------------
55

6-
v10.7 (28-Feb-2025) [ALL] Prefixed by a hashtag didn't propagate though nested .MACRO
6+
v10.7 (12-Mar-2025) [ALL] Prefixed by a hashtag didn't propagate though nested .MACRO
77
calls.
88
[ALL] Listfile creation for library files should now work.
99
[ALL] If an object file contained only .SECTIONs in ROM
@@ -18,7 +18,8 @@ v10.7 (28-Feb-2025) [ALL] Prefixed by a hashtag didn't propagate though nested .
1818
long it has been defined earlier lexically.
1919
[ALL] Added parameterless versions of bankbyte(), base(), slot()
2020
and bank(). bankbyte(label) and bank(label) can be used in .IFs.
21-
[ALL] Added built-in functions is(), get(), org() and orga().
21+
[ALL] Added built-in functions is(), get(), org(), orga() and
22+
substring().
2223
[ALL] Added LATESTDIR and RELATIVEDIR to .INCLUDE and .INCBIN.
2324
[68k] Added alias SP for register a7.
2425
[68k] BCLR, BSET and BTST used wrong range [1, 8] / [1, 32] for

doc/functions.rst

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ sin(exp) The same as ANSI C90 sin()
5656
sinh(exp) The same as ANSI C90 sinh()
5757
slot() Returns the current slot (*)
5858
sqrt(exp) Returns the square root of the supplied value
59+
substring(s, ind, len) Returns a substring of ``s``, starting at index ``ind``, consisting of ``len`` characters
5960
tan(exp) The same as ANSI C90 tan()
6061
tanh(exp) The same as ANSI C90 tanh()
6162
====================== ================================================================================

main.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ FILE *g_file_out_ptr = NULL;
3434
__near long __stack = 200000;
3535
#endif
3636

37-
char s_version_string[] = "$VER: wla-" WLA_NAME " 10.7a (28.2.2025)";
37+
char s_version_string[] = "$VER: wla-" WLA_NAME " 10.7a (12.3.2025)";
3838
char s_wla_version[] = "10.7";
3939

4040
extern struct incbin_file_data *g_incbin_file_data_first, *g_ifd_tmp;

parse.c

+11-2
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,16 @@ int input_number(void) {
781781
break;
782782
else if (ee == ' ')
783783
spaces++;
784+
else if (ee == '"' && g_buffer[p-2] != '\\') {
785+
/* skip quoted strings */
786+
while (ee != 0x0A) {
787+
ee = g_buffer[p++];
788+
if (ee == '"' && g_buffer[p-2] != '\\')
789+
break;
790+
}
791+
if (ee == 0x0A)
792+
break;
793+
}
784794
else if (curly_braces <= 0 && (ee == '-' || ee == '+' || ee == '*' || ee == '/' || ee == '&' || ee == '|' || ee == '^' || ee == '(' ||
785795
ee == '<' || ee == '>' || ee == '#' || ee == '~' || ee == ':' || ee == '!' || (ee == '=' && g_buffer[p] == '='))) {
786796
if (ee == ':' && spaces > 0)
@@ -798,8 +808,7 @@ int input_number(void) {
798808
else
799809
return p;
800810
}
801-
ee = g_buffer[p];
802-
p++;
811+
ee = g_buffer[p++];
803812
}
804813
}
805814

phase_1.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -7994,7 +7994,8 @@ int directive_function(void) {
79947994
strcmp("is", g_label) == 0 ||
79957995
strcmp("get", g_label) == 0 ||
79967996
strcmp("org", g_label) == 0 ||
7997-
strcmp("orga", g_label) == 0 ||
7997+
strcmp("orga", g_label) == 0 ||
7998+
strcmp("substring", g_label) == 0 ||
79987999
strcmp("abs", g_label) == 0) {
79998000
print_error(ERROR_DIR, "You cannot redefine a built-in .FUNCTION \"%s\"!\n", g_label);
80008001
return FAILED;

stack.c

+104-3
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,81 @@ static int _parse_function_exists(char *in, int *result, int *parsed_chars) {
10361036
}
10371037

10381038

1039+
static int _parse_function_substring(char *in, struct stack_item *si, int *parsed_chars) {
1040+
1041+
int i, j, res, old_expect = g_expect_calculations, source_index_original = g_source_index, source_index_backup, index, length;
1042+
char tmp[MAX_NAME_LENGTH + 1];
1043+
1044+
/* NOTE! we assume that 'in' is actually '&g_buffer[xyz]', so
1045+
let's update g_source_index for input_number() */
1046+
1047+
g_source_index = (int)(in - g_buffer);
1048+
source_index_backup = g_source_index;
1049+
1050+
/* string */
1051+
g_expect_calculations = NO;
1052+
res = input_number();
1053+
1054+
if (res != INPUT_NUMBER_ADDRESS_LABEL && res != INPUT_NUMBER_STRING) {
1055+
print_error(ERROR_NUM, "substring() requires a string to operate on.\n");
1056+
return FAILED;
1057+
}
1058+
1059+
strcpy(tmp, g_label);
1060+
1061+
/* index */
1062+
g_expect_calculations = YES;
1063+
res = input_number();
1064+
1065+
if (res != SUCCEEDED) {
1066+
print_error(ERROR_NUM, "substring() requires index that can be solved right here.\n");
1067+
return FAILED;
1068+
}
1069+
1070+
index = g_parsed_int;
1071+
1072+
/* length */
1073+
res = input_number();
1074+
g_expect_calculations = old_expect;
1075+
1076+
if (res != SUCCEEDED) {
1077+
print_error(ERROR_NUM, "substring() requires length that can be solved right here.\n");
1078+
return FAILED;
1079+
}
1080+
1081+
length = g_parsed_int;
1082+
1083+
if (g_buffer[g_source_index] != ')') {
1084+
print_error(ERROR_NUM, "Malformed \"substring(?)\" detected!\n");
1085+
return FAILED;
1086+
}
1087+
1088+
/* skip ')' */
1089+
g_source_index++;
1090+
1091+
/* count the parsed chars */
1092+
*parsed_chars = (int)(g_source_index - source_index_backup);
1093+
1094+
/* return g_source_index */
1095+
g_source_index = source_index_original;
1096+
1097+
/* perform substring() */
1098+
si->sign = SI_SIGN_POSITIVE;
1099+
si->type = STACK_ITEM_TYPE_STRING;
1100+
1101+
for (j = 0, i = index; j < length; i++, j++) {
1102+
if (i < 0 || i >= (int)strlen(tmp)) {
1103+
print_error(ERROR_NUM, "Index %d is outside string \"%s\"!\n", i, tmp);
1104+
return FAILED;
1105+
}
1106+
si->string[j] = tmp[i];
1107+
}
1108+
si->string[j] = 0;
1109+
1110+
return SUCCEEDED;
1111+
}
1112+
1113+
10391114
static int _parse_function_math1(char *in, int *type, double *value, char *string, int *parsed_chars, char *name) {
10401115

10411116
int res, source_index_original = g_source_index, source_index_backup, input_float_mode = g_input_float_mode;
@@ -1826,7 +1901,7 @@ static int _stack_calculate(char *in, int *value, int *bytes_parsed, unsigned ch
18261901
can_skip_newline = YES;
18271902
/* was previous token ')'? */
18281903
if (q > 0 && si[q-1].type == STACK_ITEM_TYPE_OPERATOR && si[q-1].value == SI_OP_RIGHT)
1829-
break;
1904+
break;
18301905
q++;
18311906
b++;
18321907
in++;
@@ -2567,10 +2642,20 @@ static int _stack_calculate(char *in, int *value, int *bytes_parsed, unsigned ch
25672642
if (_parse_function_exists(in, &d, &parsed_chars) == FAILED)
25682643
return FAILED;
25692644
in += parsed_chars;
2570-
is_label = NO;
2645+
is_label = NO;
25712646
break;
25722647
}
2648+
else if (k == 9 && strcaselesscmpn(si[q].string, "substring(", 10) == 0) {
2649+
int parsed_chars = 0;
25732650

2651+
if (_parse_function_substring(in, &si[q], &parsed_chars) == FAILED)
2652+
return FAILED;
2653+
in += parsed_chars;
2654+
is_label = NO;
2655+
is_already_processed_function = YES;
2656+
break;
2657+
}
2658+
25742659
if (e == '(') {
25752660
/* are we calling a user created function? */
25762661
int found_function = NO, res, parsed_chars = 0;
@@ -2739,6 +2824,7 @@ static int _stack_calculate(char *in, int *value, int *bytes_parsed, unsigned ch
27392824

27402825
return SUCCEEDED;
27412826
}
2827+
27422828
if (from_substitutor == NO) {
27432829
if (si[0].type == STACK_ITEM_TYPE_STACK) {
27442830
/* update the source pointer */
@@ -2749,14 +2835,29 @@ static int _stack_calculate(char *in, int *value, int *bytes_parsed, unsigned ch
27492835
return INPUT_NUMBER_STACK;
27502836
}
27512837
else if (got_get_label == YES && si[0].type == STACK_ITEM_TYPE_LABEL && si[0].sign == SI_SIGN_POSITIVE) {
2838+
/* update the source pointer */
27522839
*bytes_parsed += (int)(in - in_original) - 1;
27532840

27542841
strcpy(g_label, si[0].string);
27552842
process_special_labels(g_label);
2843+
g_string_size = (int)strlen(g_label);
27562844

27572845
return STACK_RETURN_LABEL;
27582846
}
2847+
else if (si[0].type == STACK_ITEM_TYPE_STRING && si[0].sign == SI_SIGN_POSITIVE) {
2848+
/* update the source pointer */
2849+
*bytes_parsed += (int)(in - in_original) - 1;
27592850

2851+
strcpy(g_label, si[0].string);
2852+
process_special_labels(g_label);
2853+
g_string_size = (int)strlen(g_label);
2854+
2855+
#if defined(WLA_DEBUG)
2856+
print_text(NO, "RETURN STRING %s\n", g_label);
2857+
#endif
2858+
return STACK_RETURN_STRING;
2859+
}
2860+
27602861
return STACK_CALCULATE_DELAY;
27612862
}
27622863
}
@@ -2984,7 +3085,7 @@ static int _stack_calculate(char *in, int *value, int *bytes_parsed, unsigned ch
29843085
}
29853086
}
29863087
}
2987-
3088+
29883089
#if defined(WLA_DEBUG)
29893090
print_text(NO, "INFIX:\n");
29903091
_debug_print_stack(g_active_file_info_last->line_current, -1, si, q, 0, NULL);

tests/65816/function_test/main.s

+10
Original file line numberDiff line numberDiff line change
@@ -684,3 +684,13 @@ addd2: .db 2 ; @BT 02
684684
.dl (base() << 16) | orga() ; @BT 18 80 C0
685685
.db "<32" ; @BT END
686686
687+
.db "33>" ; @BT TEST-33 33 START
688+
.db substring("ABCDEFG", 2, 3) ; @BT 43 44 45
689+
.db substring("ABCDEFG", 0+2, 4-1) ; @BT 43 44 45
690+
.define STRING_ABCDEFG "ABCDEFG"
691+
.define STRING_BCD substring(STRING_ABCDEFG, 1, 3)
692+
.db substring(STRING_ABCDEFG, 2, 3) ; @BT 43 44 45
693+
.db substring(STRING_ABCDEFG, 0+1*2, 4-1-1) ; @BT 43 44
694+
.db substring(STRING_BCD, 1, 1) ; @BT 43
695+
.db "<33" ; @BT END
696+

0 commit comments

Comments
 (0)