Skip to content

Commit 676f9f2

Browse files
Convert some EVALUATE statements to switch statement (#504)
1 parent 04f66a9 commit 676f9f2

File tree

8 files changed

+1263
-3
lines changed

8 files changed

+1263
-3
lines changed

cobj/codegen.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3549,6 +3549,47 @@ static void joutput_ferror_stmt(struct cb_statement *p, int code) {
35493549
// joutput_line("// %s:%d: %s", p->file, p->line, p->comment);
35503550
// }
35513551

3552+
static void joutput_switch(struct cb_switch *sw,
3553+
enum joutput_stmt_type output_type) {
3554+
joutput_prefix();
3555+
joutput("switch(");
3556+
joutput_param(sw->test, -1);
3557+
joutput(".getInt()) {");
3558+
joutput_newline();
3559+
joutput_indent_level += 2;
3560+
cb_tree case_tree;
3561+
for (case_tree = sw->case_list; case_tree; case_tree = CB_CHAIN(case_tree)) {
3562+
cb_tree whens = CB_VALUE(case_tree);
3563+
cb_tree stmt = CB_VALUE(whens);
3564+
int flag_other_exists = 1;
3565+
for (; whens; whens = CB_CHAIN(whens)) {
3566+
cb_tree objs = CB_VALUE(whens);
3567+
for (; objs; objs = CB_CHAIN(objs)) {
3568+
cb_tree obj = CB_VALUE(objs);
3569+
if (obj && CB_LIST_P(obj)) {
3570+
flag_other_exists = 0;
3571+
}
3572+
if (obj && CB_PAIR_P(obj)) {
3573+
cb_tree when_target = CB_PAIR_Y(obj);
3574+
struct cb_literal *primary_target =
3575+
CB_LITERAL(CB_PAIR_X(when_target));
3576+
int dummy;
3577+
int label =
3578+
cb_literal_to_int_for_switch_label(primary_target, &dummy);
3579+
joutput_line("case %d:", label);
3580+
}
3581+
}
3582+
}
3583+
if (flag_other_exists) {
3584+
joutput_line("default:");
3585+
}
3586+
joutput_stmt(stmt, output_type);
3587+
joutput_line("break;");
3588+
}
3589+
joutput_indent_level -= 2;
3590+
joutput_line("}");
3591+
}
3592+
35523593
static void joutput_stmt(cb_tree x, enum joutput_stmt_type output_type) {
35533594
struct cb_statement *p;
35543595
struct cb_label *lp;
@@ -3948,6 +3989,9 @@ static void joutput_stmt(cb_tree x, enum joutput_stmt_type output_type) {
39483989
joutput_prefix();
39493990
joutput(";\n");
39503991
break;
3992+
case CB_TAG_SWITCH:
3993+
joutput_switch(CB_SWITCH(x), output_type);
3994+
break;
39513995
case CB_TAG_LIST:
39523996
if (x && CB_TREE_TAG(CB_VALUE(x)) == CB_TAG_PERFORM) {
39533997
putParen = 0;

cobj/tree.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2511,6 +2511,19 @@ cb_tree cb_build_continue(void) {
25112511
return CB_TREE(p);
25122512
}
25132513

2514+
/*
2515+
* SWITCH
2516+
*/
2517+
2518+
cb_tree cb_build_switch(cb_tree test, cb_tree case_list) {
2519+
struct cb_switch *p;
2520+
2521+
p = make_tree(CB_TAG_SWITCH, CB_CATEGORY_UNKNOWN, sizeof(struct cb_switch));
2522+
p->test = test;
2523+
p->case_list = case_list;
2524+
return CB_TREE(p);
2525+
}
2526+
25142527
/*
25152528
* FUNCTION
25162529
*/

cobj/tree.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ enum cb_tag {
8585

8686
CB_TAG_JAVA_CONTINUE,
8787
CB_TAG_JAVA_BREAK,
88+
89+
CB_TAG_SWITCH,
8890
};
8991

9092
enum cb_alphabet_name_type {
@@ -1118,6 +1120,24 @@ extern cb_tree cb_build_perform(int type);
11181120
extern cb_tree cb_build_perform_varying(cb_tree name, cb_tree from,
11191121
cb_tree step, cb_tree until);
11201122

1123+
/*
1124+
* switch (evaluate)
1125+
*/
1126+
1127+
struct cb_switch {
1128+
struct cb_tree_common common;
1129+
cb_tree test;
1130+
cb_tree case_list;
1131+
};
1132+
1133+
#define CB_SWITCH(x) (CB_TREE_CAST(CB_TAG_SWITCH, struct cb_switch, x))
1134+
#define CB_SWITCH_P(x) (CB_TREE_TAG(x) == CB_TAG_SWITCH)
1135+
1136+
extern cb_tree cb_build_switch(cb_tree test, cb_tree case_tree);
1137+
1138+
extern int cb_literal_to_int_for_switch_label(struct cb_literal *lit,
1139+
int *result);
1140+
11211141
/*
11221142
* SORT
11231143
*/

cobj/typeck.c

Lines changed: 147 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3673,8 +3673,154 @@ static cb_tree build_evaluate(cb_tree subject_list, cb_tree case_list) {
36733673
}
36743674
}
36753675

3676+
int cb_literal_to_int_for_switch_label(struct cb_literal *lit, int *result) {
3677+
const char *min_num_abs =
3678+
"2147483648"; // -1 * (the minimum value of int of Java)
3679+
const char *max_num = "2147483647"; // the maximum value of int of Java
3680+
const int len_boundary =
3681+
10; // string length of min_num_abs (== string length of max_num)
3682+
if (lit->size > len_boundary) {
3683+
// the value of the literal is out of range
3684+
*result = 0;
3685+
return 0;
3686+
}
3687+
3688+
size_t i;
3689+
const char *boundary = lit->sign < 0 ? min_num_abs : max_num;
3690+
if (lit->size == len_boundary) {
3691+
for (i = 0; i < len_boundary; ++i) {
3692+
if (boundary[i] < lit->data[i]) {
3693+
// the value of the literal is out of range
3694+
*result = 0;
3695+
return 0;
3696+
}
3697+
}
3698+
}
3699+
3700+
int ret = 0;
3701+
for (i = 0; i < lit->size; ++i) {
3702+
ret = ret * 10 + lit->data[i] - '0';
3703+
}
3704+
*result = 1;
3705+
return lit->sign < 0 ? -ret : ret;
3706+
}
3707+
3708+
// Determine a given label exists in the list of existing labels
3709+
// If a given label exists in the list, return 1. Otherwise return 0;
3710+
static int is_switch_label_duplicate(int label, const int *existing_label_list,
3711+
int list_len) {
3712+
int i = 0;
3713+
for (; i < list_len; ++i) {
3714+
if (existing_label_list[i] == label) {
3715+
return 1;
3716+
}
3717+
}
3718+
return 0;
3719+
}
3720+
3721+
static cb_tree convert_evaluate_stmt_to_switch_stmt(cb_tree subject_list,
3722+
cb_tree case_list) {
3723+
cb_tree subjs;
3724+
cb_tree whens;
3725+
cb_tree objs;
3726+
3727+
cb_tree case_tree = case_list;
3728+
int when_count = 0;
3729+
int other_exists = 0;
3730+
3731+
// The length of subject_list must be 1
3732+
if (subject_list == NULL || CB_CHAIN(subject_list)) {
3733+
return NULL;
3734+
}
3735+
3736+
// Determine if a given evaluate statement can be converted to a switch
3737+
// statement
3738+
int case_count = 0;
3739+
for (; case_tree; case_tree = CB_CHAIN(case_tree), ++case_count) {
3740+
whens = CB_VALUE(case_tree);
3741+
/* for each WHEN sequence */
3742+
int flag_other_exists = 1;
3743+
for (; whens; whens = CB_CHAIN(whens)) {
3744+
for (subjs = subject_list, objs = CB_VALUE(whens); subjs && objs;
3745+
subjs = CB_CHAIN(subjs), objs = CB_CHAIN(objs)) {
3746+
cb_tree subj = CB_VALUE(subjs);
3747+
cb_tree obj = CB_VALUE(objs);
3748+
if (!subj || CB_TREE_CATEGORY(subj) != CB_CATEGORY_NUMERIC) {
3749+
return NULL;
3750+
}
3751+
if (obj) {
3752+
if (CB_LIST_P(obj)) {
3753+
flag_other_exists = 0;
3754+
}
3755+
if (CB_STATEMENT_P(obj)) {
3756+
continue;
3757+
}
3758+
if (CB_PAIR_P(obj)) {
3759+
// WHEN NOT
3760+
if (CB_PURPOSE_INT(obj)) {
3761+
return NULL;
3762+
}
3763+
cb_tree when_target = CB_PAIR_Y(obj);
3764+
if (CB_PAIR_P(when_target)) {
3765+
cb_tree primary_target = CB_PAIR_X(when_target);
3766+
cb_tree thru_target = CB_PAIR_Y(when_target);
3767+
if (!CB_LITERAL_P(primary_target) || thru_target) {
3768+
return NULL;
3769+
}
3770+
struct cb_literal *lit = CB_LITERAL(primary_target);
3771+
if (lit->data == NULL || lit->scale != 0) {
3772+
return NULL;
3773+
}
3774+
++when_count;
3775+
}
3776+
}
3777+
}
3778+
}
3779+
}
3780+
other_exists |= flag_other_exists;
3781+
}
3782+
// Build Switch statement
3783+
int *cases = malloc(when_count * sizeof(int));
3784+
int case_index = 0;
3785+
for (case_tree = case_list; case_tree; case_tree = CB_CHAIN(case_tree)) {
3786+
whens = CB_VALUE(case_tree);
3787+
/* for each WHEN sequence */
3788+
for (; whens; whens = CB_CHAIN(whens)) {
3789+
for (objs = CB_VALUE(whens); objs; objs = CB_CHAIN(objs)) {
3790+
cb_tree obj = CB_VALUE(objs);
3791+
if (obj && CB_PAIR_P(obj)) {
3792+
cb_tree when_target = CB_PAIR_Y(obj);
3793+
struct cb_literal *primary_target =
3794+
CB_LITERAL(CB_PAIR_X(when_target));
3795+
int result;
3796+
int label =
3797+
cb_literal_to_int_for_switch_label(primary_target, &result);
3798+
// If calculating a switch label fails, the evaluate statement cannot
3799+
// be converted to switch statement
3800+
if (!result) {
3801+
return NULL;
3802+
}
3803+
// If a duplicate label is found, the evaluate statement cannot be
3804+
// converted to switch statement
3805+
if (is_switch_label_duplicate(label, cases, case_index)) {
3806+
return NULL;
3807+
}
3808+
cases[case_index++] = label;
3809+
}
3810+
}
3811+
}
3812+
}
3813+
return cb_build_switch(CB_VALUE(subject_list), case_list);
3814+
}
3815+
36763816
void cb_emit_evaluate(cb_tree subject_list, cb_tree case_list) {
3677-
cb_emit(build_evaluate(subject_list, case_list));
3817+
cb_tree switch_stmt =
3818+
convert_evaluate_stmt_to_switch_stmt(subject_list, case_list);
3819+
if (switch_stmt) {
3820+
cb_emit(switch_stmt);
3821+
} else {
3822+
cb_emit(build_evaluate(subject_list, case_list));
3823+
}
36783824
}
36793825

36803826
/*

tests/Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ misc_DEPENDENCIES = \
217217
misc.src/record-key-duplicates-error.at \
218218
misc.src/copy-comments.at \
219219
misc.src/read_prev_after_start.at \
220-
misc.src/japanese-char-section-var.at
220+
misc.src/japanese-char-section-var.at \
221+
misc.src/evaluate-switch.at
221222

222223
EXTRA_DIST = $(srcdir)/package.m4 \
223224
$(TESTS) \

tests/Makefile.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,8 @@ misc_DEPENDENCIES = \
758758
misc.src/record-key-duplicates-error.at \
759759
misc.src/copy-comments.at \
760760
misc.src/read_prev_after_start.at \
761-
misc.src/japanese-char-section-var.at
761+
misc.src/japanese-char-section-var.at \
762+
misc.src/evaluate-switch.at
762763

763764
EXTRA_DIST = $(srcdir)/package.m4 \
764765
$(TESTS) \

tests/misc.at

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,4 @@ m4_include([record-key-duplicates-error.at])
4747
#m4_include([copy-comments.at])
4848
m4_include([read_prev_after_start.at])
4949
m4_include([japanese-char-section-var.at])
50+
m4_include([evaluate-switch.at])

0 commit comments

Comments
 (0)