From: yu.dongliang <18588496441@163.com>
Date: Wed, 2 Oct 2024 04:30:07 +0000 (+0800)
Subject: support "const literal string" in 'case' for 'switch'
X-Git-Url: http://baseworks.info/?a=commitdiff_plain;h=6c90ed24c758e6ba85ebed2f6cdc13c84233bdc5;p=scf.git

support "const literal string" in 'case' for 'switch'
---

diff --git a/core/scf_3ac.c b/core/scf_3ac.c
index 9d82a62..3a13aff 100644
--- a/core/scf_3ac.c
+++ b/core/scf_3ac.c
@@ -450,16 +450,16 @@ static void _3ac_print_node(scf_node_t* node)
 {
 	if (scf_type_is_var(node->type)) {
 		if (node->var->w) {
-			printf("v_%d_%d/%s",
-					node->var->w->line, node->var->w->pos, node->var->w->text->data);
+			printf("v_%d_%d/%s/%#lx",
+					node->var->w->line, node->var->w->pos, node->var->w->text->data, 0xffff & (uintptr_t)node->var);
 		} else {
 			printf("v_%#lx", 0xffff & (uintptr_t)node->var);
 		}
 	} else if (scf_type_is_operator(node->type)) {
 		if (node->result) {
 			if (node->result->w) {
-				printf("v_%d_%d/%s",
-						node->result->w->line, node->result->w->pos, node->result->w->text->data);
+				printf("v_%d_%d/%s/%#lx",
+						node->result->w->line, node->result->w->pos, node->result->w->text->data, 0xffff & (uintptr_t)node->result);
 			} else
 				printf("v/%#lx", 0xffff & (uintptr_t)node->result);
 		}
diff --git a/core/scf_basic_block.c b/core/scf_basic_block.c
index 786e3b8..8e39c9b 100644
--- a/core/scf_basic_block.c
+++ b/core/scf_basic_block.c
@@ -194,10 +194,10 @@ void scf_basic_block_print(scf_basic_block_t* bb, scf_list_t* sentinel)
 	if (bb) {
 #define SCF_BB_PRINT(h) \
 		do { \
-			scf_list_t* l; \
-			for (l = scf_list_head(&bb->h); l != scf_list_sentinel(&bb->h); \
-					l = scf_list_next(l)) { \
-				scf_3ac_code_t* c = scf_list_data(l, scf_3ac_code_t, list); \
+			scf_3ac_code_t* c; \
+			scf_list_t*     l; \
+			for (l = scf_list_head(&bb->h); l != scf_list_sentinel(&bb->h); l = scf_list_next(l)) { \
+				c  = scf_list_data(l, scf_3ac_code_t, list); \
 				scf_3ac_code_print(c, sentinel); \
 			} \
 		} while (0)
@@ -259,7 +259,7 @@ void scf_basic_block_print_list(scf_list_t* h)
 	for (l = scf_list_head(h); l != scf_list_sentinel(h); l = scf_list_next(l)) {
 		bb = scf_list_data(l, scf_basic_block_t, list);
 
-		printf("\033[33mbasic_block: %p, index: %d, dfo: %d, cmp_flag: %d, call_flag: %d, group: %d, loop: %d, dereference_flag: %d, ret_flag: %d\033[0m\n",
+		printf("\033[34mbasic_block: %p, index: %d, dfo: %d, cmp_flag: %d, call_flag: %d, group: %d, loop: %d, dereference_flag: %d, ret_flag: %d\033[0m\n",
 				bb, bb->index, bb->dfo, bb->cmp_flag, bb->call_flag, bb->group_flag, bb->loop_flag, bb->dereference_flag, bb->ret_flag);
 
 		scf_basic_block_print(bb, sentinel);
@@ -280,12 +280,7 @@ void scf_basic_block_print_list(scf_list_t* h)
 				printf("next     : %p, index: %d\n", bb2, bb2->index);
 			}
 		}
-#if 0
-		if (bb->dominators_normal) {
-			for (i = 0; i < bb->dominators_normal->size; i++)
-				printf("dominator: %p\n", bb->dominators_normal->data[i]);
-		}
-#endif
+
 		if (bb->dn_status_initeds) {
 			printf("inited: \n");
 			for (i = 0; i < bb->dn_status_initeds->size; i++) {
@@ -295,7 +290,7 @@ void scf_basic_block_print_list(scf_list_t* h)
 			}
 			printf("\n");
 		}
-#if 1
+
 		if (bb->ds_malloced) {
 			printf("auto gc: \n");
 			for (i = 0; i < bb->ds_malloced->size; i++) {
@@ -307,7 +302,7 @@ void scf_basic_block_print_list(scf_list_t* h)
 			}
 			printf("\n");
 		}
-#endif
+
 		if (bb->entry_dn_actives) {
 			for (i = 0; i < bb->entry_dn_actives->size; i++) {
 				dn =        bb->entry_dn_actives->data[i];
diff --git a/core/scf_expr.c b/core/scf_expr.c
index c3c94ac..b2377c3 100644
--- a/core/scf_expr.c
+++ b/core/scf_expr.c
@@ -3,17 +3,12 @@
 scf_expr_t* scf_expr_alloc()
 {
 	scf_expr_t* e = calloc(1, sizeof(scf_expr_t));
-	if (!e) {
-		scf_loge("expr alloc failed");
+	if (!e)
 		return NULL;
-	}
 
 	e->nodes = calloc(1, sizeof(scf_node_t*));
 	if (!e->nodes) {
-		scf_loge("expr nodes alloc failed");
-
 		free(e);
-		e = NULL;
 		return NULL;
 	}
 
@@ -29,7 +24,6 @@ int scf_expr_copy(scf_node_t* e2, scf_node_t* e)
 	for (i = 0; i < e->nb_nodes; i++) {
 
 		node = scf_node_clone(e->nodes[i]);
-
 		if (!node)
 			return -ENOMEM;
 
@@ -66,7 +60,7 @@ void scf_expr_free(scf_expr_t* e)
 	}
 }
 
-static int _scf_expr_node_add_node(scf_node_t** pparent, scf_node_t* child)
+static int __expr_node_add_node(scf_node_t** pparent, scf_node_t* child)
 {
 	scf_node_t* parent = *pparent;
 	if (!parent) {
@@ -79,10 +73,10 @@ static int _scf_expr_node_add_node(scf_node_t** pparent, scf_node_t* child)
 
 		if (parent->op->nb_operands > parent->nb_nodes)
 			return scf_node_add_child(parent, child);
-		else {
-			assert(parent->nb_nodes >= 1);
-			return _scf_expr_node_add_node(&(parent->nodes[parent->nb_nodes - 1]), child);
-		}
+
+		assert(parent->nb_nodes >= 1);
+		return __expr_node_add_node(&(parent->nodes[parent->nb_nodes - 1]), child);
+
 	} else if (parent->priority < child->priority) {
 		assert(child->op);
 
@@ -90,37 +84,34 @@ static int _scf_expr_node_add_node(scf_node_t** pparent, scf_node_t* child)
 			assert(child->op->nb_operands > child->nb_nodes);
 
 		child->parent = parent->parent;
-		if (scf_node_add_child(child, parent) < 0) {
-			scf_loge("expr nodes alloc failed");
+		if (scf_node_add_child(child, parent) < 0)
 			return -1;
-		}
+
 		*pparent = child;
 		return 0;
-	} else {
-		// parent->priority == child->priority
-		assert(parent->op);
-		assert(child->op);
+	}
 
-		if (SCF_OP_ASSOCIATIVITY_LEFT == child->op->associativity) {
-			if (child->op->nb_operands > 0)
-				assert(child->op->nb_operands > child->nb_nodes);
-
-			child->parent = parent->parent;
-			scf_node_add_child(child, parent); // add parent to child's child node
-			*pparent = child; // child is the new parent node
-			return 0;
-		} else {
-			if (parent->op->nb_operands > parent->nb_nodes)
-				return scf_node_add_child(parent, child);
-			else {
-				assert(parent->nb_nodes >= 1);
-				return _scf_expr_node_add_node(&(parent->nodes[parent->nb_nodes - 1]), child);
-			}
-		}
+	// parent->priority == child->priority
+	assert(parent->op);
+	assert(child->op);
+
+	if (SCF_OP_ASSOCIATIVITY_LEFT == child->op->associativity) {
+		if (child->op->nb_operands > 0)
+			assert(child->op->nb_operands > child->nb_nodes);
+
+		child->parent = parent->parent;
+
+		scf_node_add_child(child, parent); // add parent to child's child node
+
+		*pparent = child; // child is the new parent node
+		return 0;
 	}
 
-	scf_loge("\n");
-	return -1;
+	if (parent->op->nb_operands > parent->nb_nodes)
+		return scf_node_add_child(parent, child);
+
+	assert(parent->nb_nodes >= 1);
+	return __expr_node_add_node(&(parent->nodes[parent->nb_nodes - 1]), child);
 }
 
 int scf_expr_add_node(scf_expr_t* e, scf_node_t* node)
@@ -128,10 +119,10 @@ int scf_expr_add_node(scf_expr_t* e, scf_node_t* node)
 	assert(e);
 	assert(node);
 
-	if (scf_type_is_var(node->type)) {
+	if (scf_type_is_var(node->type))
 		node->priority = -1;
 
-	} else if (scf_type_is_operator(node->type)) {
+	else if (scf_type_is_operator(node->type)) {
 
 		node->op = scf_find_base_operator_by_type(node->type);
 		if (!node->op) {
@@ -144,13 +135,31 @@ int scf_expr_add_node(scf_expr_t* e, scf_node_t* node)
 		return -1;
 	}
 
-	if (_scf_expr_node_add_node(&(e->nodes[0]), node) < 0) {
-		scf_loge("\n");
+	if (__expr_node_add_node(&(e->nodes[0]), node) < 0)
 		return -1;
-	}
 
 	e->nodes[0]->parent = e;
 	e->nb_nodes = 1;
 	return 0;	
 }
 
+void scf_expr_simplify(scf_expr_t** pe)
+{
+	scf_expr_t** pp = pe;
+	scf_expr_t*  e;
+
+	while (SCF_OP_EXPR == (*pp)->type) {
+		e  = *pp;
+		pp = &(e->nodes[0]);
+	}
+
+	if (pp != pe) {
+		e   = *pp;
+		*pp = NULL;
+
+		e->parent = (*pe)->parent;
+
+		scf_expr_free(*pe);
+		*pe = e;
+	}
+}
diff --git a/core/scf_expr.h b/core/scf_expr.h
index 7029b68..de8ca60 100644
--- a/core/scf_expr.h
+++ b/core/scf_expr.h
@@ -3,12 +3,13 @@
 
 #include"scf_node.h"
 
-typedef scf_node_t	scf_expr_t; // expr is a node
+typedef scf_node_t  scf_expr_t; // expr is a node
 
-scf_expr_t*			scf_expr_alloc();
-scf_expr_t*			scf_expr_clone(scf_expr_t* e);
-void				scf_expr_free(scf_expr_t* expr);
-int					scf_expr_add_node(scf_expr_t* expr, scf_node_t* node);
+scf_expr_t*         scf_expr_alloc();
+scf_expr_t*         scf_expr_clone(scf_expr_t* e);
+void                scf_expr_free (scf_expr_t* e);
 
-#endif
+int                 scf_expr_add_node(scf_expr_t*  e, scf_node_t* node);
+void                scf_expr_simplify(scf_expr_t** pe);
 
+#endif
diff --git a/core/scf_node.c b/core/scf_node.c
index dd111da..03de08d 100644
--- a/core/scf_node.c
+++ b/core/scf_node.c
@@ -134,10 +134,8 @@ int scf_node_add_child(scf_node_t* parent, scf_node_t* child)
 		return -EINVAL;
 
 	void* p = realloc(parent->nodes, sizeof(scf_node_t*) * (parent->nb_nodes + 1));
-	if (!p) {
-		scf_loge("realloc failed\n");
+	if (!p)
 		return -ENOMEM;
-	}
 
 	parent->nodes = p;
 	parent->nodes[parent->nb_nodes++] = child;
diff --git a/core/scf_operator_handler_3ac.c b/core/scf_operator_handler_3ac.c
index 5dcd74b..e5c3897 100644
--- a/core/scf_operator_handler_3ac.c
+++ b/core/scf_operator_handler_3ac.c
@@ -1140,12 +1140,17 @@ static int _scf_op_switch(scf_ast_t* ast, scf_node_t** nodes, int nb_nodes, void
 					return -1;
 				}
 
-				scf_node_t* srcs[2] = {e, e2};
+				if (SCF_OP_CALL == e2->type)
+					cmp = scf_3ac_code_NN(SCF_OP_3AC_TEQ, NULL, 0, &e2, 1);
+				else {
+					scf_node_t* srcs[2] = {e, e2};
+
+					cmp = scf_3ac_code_NN(SCF_OP_3AC_CMP, NULL, 0, srcs, 2);
+				}
+				scf_list_add_tail(d->_3ac_list_head, &cmp->list);
 
-				cmp  = scf_3ac_code_NN(SCF_OP_3AC_CMP, NULL, 0, srcs, 2);
 				jnot = scf_3ac_jmp_code(SCF_OP_3AC_JNZ, NULL, NULL);
 
-				scf_list_add_tail(d->_3ac_list_head, &cmp->list);
 				scf_list_add_tail(d->_3ac_list_head, &jnot->list);
 
 				scf_vector_add(up_branch_ops->_breaks, jnot);
diff --git a/core/scf_optimizer.c b/core/scf_optimizer.c
index ad0dbfd..6b89c9f 100644
--- a/core/scf_optimizer.c
+++ b/core/scf_optimizer.c
@@ -161,6 +161,7 @@ int scf_optimize(scf_ast_t* ast, scf_vector_t* functions)
 		if (!f->node.define_flag)
 			continue;
 
+		printf("\n");
 		scf_logi("------- %s() ------\n", f->node.w->text->data);
 
 		scf_basic_block_print_list(&f->basic_block_list_head);
diff --git a/core/scf_type_cast.c b/core/scf_type_cast.c
index be31fb6..15e0c73 100644
--- a/core/scf_type_cast.c
+++ b/core/scf_type_cast.c
@@ -156,11 +156,9 @@ int scf_type_cast_check(scf_ast_t* ast, scf_variable_t* dst, scf_variable_t* src
 
 		if (scf_type_is_integer(dst->type)) {
 
-			if (dst->size < src->size) {
-				scf_logw("type cast %s -> %s discard bits\n",
-						src->w->text->data, dst->w->text->data);
-			}
-
+			if (dst->size < src->size)
+				scf_logw("type cast %s -> %s discard bits, file: %s, line: %d\n",
+						src->w->text->data, dst->w->text->data, src->w->file->data, src->w->line);
 			return 0;
 		}
 	}
@@ -178,9 +176,9 @@ failed:
 	dst_type = scf_variable_type_name(ast, dst);
 	src_type = scf_variable_type_name(ast, src);
 
-	scf_loge("type cast '%s -> %s' with different type: from '%s' to '%s'\n",
+	scf_loge("type cast '%s -> %s' with different type: from '%s' to '%s', file: %s, line: %d\n",
 			src->w->text->data, dst->w->text->data,
-			src_type->data, dst_type->data);
+			src_type->data, dst_type->data, src->w->file->data, src->w->line);
 
 	scf_string_free(dst_type);
 	scf_string_free(src_type);
diff --git a/core/scf_variable.h b/core/scf_variable.h
index 564ab14..7d0360d 100644
--- a/core/scf_variable.h
+++ b/core/scf_variable.h
@@ -128,6 +128,11 @@ static inline int scf_variable_const_string(scf_variable_t* v)
 		&& 0 == v->nb_dimentions;
 }
 
+static inline int scf_variable_string(scf_variable_t* v)
+{
+	return SCF_VAR_CHAR == v->type && 1 == v->nb_pointers + v->nb_dimentions;
+}
+
 static inline int scf_variable_float(scf_variable_t* v)
 {
 	return scf_type_is_float(v->type) && 0 == v->nb_pointers && 0 == v->nb_dimentions;
diff --git a/examples/switch_string.c b/examples/switch_string.c
new file mode 100644
index 0000000..7c5844a
--- /dev/null
+++ b/examples/switch_string.c
@@ -0,0 +1,20 @@
+int printf(const char* fmt, ...);
+int strcmp(const char* s1, const char* s2);
+
+int main()
+{
+	const char* s = "123";
+
+	switch (s) {
+		case "456":
+			printf("0\n");
+		case "123":
+			printf("1\n");
+			break;
+		default:
+			printf("default\n");
+			break;
+	};
+
+	return 0;
+}
diff --git a/native/x64/scf_x64.c b/native/x64/scf_x64.c
index 8ff7f3c..c7d2964 100644
--- a/native/x64/scf_x64.c
+++ b/native/x64/scf_x64.c
@@ -250,7 +250,7 @@ static int _x64_function_finish(scf_function_t* f)
 				local += 8;
 		}
 
-		scf_logw("### local: %#x, local_vars_size: %#x, callee_saved_size: %#x\n",
+		scf_logd("### local: %#x, local_vars_size: %#x, callee_saved_size: %#x\n",
 				local, f->local_vars_size, f->callee_saved_size);
 
 		inst = x64_make_inst_I2E(sub, rsp, (uint8_t*)&local, 4);
@@ -1165,6 +1165,7 @@ int scf_x64_select_inst(scf_native_t* ctx, scf_function_t* f)
 	for (i = 0; i < local_vars->size; i++) {
 		scf_variable_t* v = local_vars->data[i];
 		assert(v->w);
+
 		scf_logd("v: %p, name: %s_%d_%d, size: %d, bp_offset: %d, arg_flag: %d\n",
 				v, v->w->text->data, v->w->line, v->w->pos,
 				scf_variable_size(v), v->bp_offset, v->arg_flag);
@@ -1194,4 +1195,3 @@ scf_native_ops_t	native_ops_x64 = {
 
 	.select_inst     = scf_x64_select_inst,
 };
-
diff --git a/parse/scf_dfa_for.c b/parse/scf_dfa_for.c
index 0258ced..9a7eeb2 100644
--- a/parse/scf_dfa_for.c
+++ b/parse/scf_dfa_for.c
@@ -280,7 +280,7 @@ static int _for_action_end(scf_dfa_t* dfa, scf_vector_t* words, void* data)
 
 	d->current_node = fd->parent_node;
 
-	scf_logi("\033[31m for: %d, fd: %p, s->size: %d\033[0m\n", fd->_for->w->line, fd, s->size);
+	scf_logi("for: %d, fd: %p, s->size: %d\n", fd->_for->w->line, fd, s->size);
 
 	free(fd);
 	fd = NULL;
diff --git a/parse/scf_dfa_if.c b/parse/scf_dfa_if.c
index cd2f75b..ad3666e 100644
--- a/parse/scf_dfa_if.c
+++ b/parse/scf_dfa_if.c
@@ -195,7 +195,7 @@ static int _if_action_end(scf_dfa_t* dfa, scf_vector_t* words, void* data)
 
 	d->current_node = ifd->parent_node;
 
-	scf_logi("\033[31m if: %d, ifd: %p, s->size: %d\033[0m\n", ifd->_if->w->line, ifd, s->size);
+	scf_logi("if: %d, ifd: %p, s->size: %d\n", ifd->_if->w->line, ifd, s->size);
 
 	free(ifd);
 	ifd = NULL;
diff --git a/parse/scf_dfa_switch.c b/parse/scf_dfa_switch.c
index e95de06..fa22c3a 100644
--- a/parse/scf_dfa_switch.c
+++ b/parse/scf_dfa_switch.c
@@ -30,16 +30,12 @@ static int _switch_action_switch(scf_dfa_t* dfa, scf_vector_t* words, void* data
 	scf_stack_t*     s      = d->module_datas[dfa_module_switch.index];
 	scf_node_t*     _switch = scf_node_alloc(w, SCF_OP_SWITCH, NULL);
 
-	if (!_switch) {
-		scf_loge("node alloc failed\n");
-		return SCF_DFA_ERROR;
-	}
+	if (!_switch)
+		return -ENOMEM;
 
 	dfa_switch_data_t* sd = calloc(1, sizeof(dfa_switch_data_t));
-	if (!sd) {
-		scf_loge("module data alloc failed\n");
-		return SCF_DFA_ERROR;
-	}
+	if (!sd)
+		return -ENOMEM;
 
 	if (d->current_node)
 		scf_node_add_child(d->current_node, _switch);
@@ -192,7 +188,7 @@ static int _switch_action_end(scf_dfa_t* dfa, scf_vector_t* words, void* data)
 
 	d->current_node = sd->parent_node;
 
-	scf_logi("\033[31m switch: %d, sd: %p, s->size: %d\033[0m\n", sd->_switch->w->line, sd, s->size);
+	scf_logi("switch: %d, sd: %p, s->size: %d\n", sd->_switch->w->line, sd, s->size);
 
 	free(sd);
 	sd = NULL;
diff --git a/parse/scf_dfa_while.c b/parse/scf_dfa_while.c
index 77aa343..1098618 100644
--- a/parse/scf_dfa_while.c
+++ b/parse/scf_dfa_while.c
@@ -132,7 +132,7 @@ static int _while_action_end(scf_dfa_t* dfa, scf_vector_t* words, void* data)
 
 	d->current_node = wd->parent_node;
 
-	scf_logi("\033[31m while: %d, wd: %p, s->size: %d\033[0m\n", wd->_while->w->line, wd, s->size);
+	scf_logi("while: %d, wd: %p, s->size: %d\n", wd->_while->w->line, wd, s->size);
 
 	free(wd);
 	wd = NULL;
diff --git a/parse/scf_operator_handler_const.c b/parse/scf_operator_handler_const.c
index 7039425..0d53b21 100644
--- a/parse/scf_operator_handler_const.c
+++ b/parse/scf_operator_handler_const.c
@@ -40,13 +40,13 @@ static int _scf_expr_calculate_internal(scf_ast_t* ast, scf_node_t* node, void*
 		return __scf_op_const_call(ast, (scf_function_t*)node, data);
 
 	if (0 == node->nb_nodes) {
+
+		if (scf_type_is_var(node->type) && node->var->w)
+			scf_logd("w: %s\n", node->var->w->text->data);
+
 		assert(scf_type_is_var(node->type)
 				|| SCF_LABEL == node->type
 				|| node->split_flag);
-
-		if (scf_type_is_var(node->type) && node->var->w) {
-			scf_logd("w: %s\n", node->var->w->text->data);
-		}
 		return 0;
 	}
 
@@ -327,30 +327,40 @@ static int _scf_op_const_switch(scf_ast_t* ast, scf_node_t** nodes, int nb_nodes
 	scf_handler_data_t* d = data;
 	scf_variable_t*     r = NULL;
 	scf_expr_t*         e = nodes[0];
+	scf_expr_t*         e2;
+	scf_node_t*         b = nodes[1];
+	scf_node_t*         child;
 
 	assert(SCF_OP_EXPR == e->type);
 
 	if (_scf_expr_calculate_internal(ast, e, &r) < 0)
 		return -1;
 
-	if (_scf_op_const_node(ast, nodes[1], d) < 0)
-		return -1;
+	int i;
+	for (i = 0; i < b->nb_nodes; i++) {
+		child     = b->nodes[i];
+
+		if (SCF_OP_CASE == child->type) {
+			assert(1    == child->nb_nodes);
+
+			e = child->nodes[0];
+
+			assert(SCF_OP_EXPR == e->type);
+
+			if (_scf_expr_calculate_internal(ast, e, &r) < 0)
+				return -1;
+
+		} else {
+			if (_scf_op_const_node(ast, child, d) < 0)
+				return -1;
+		}
+	}
 
 	return 0;
 }
 
 static int _scf_op_const_case(scf_ast_t* ast, scf_node_t** nodes, int nb_nodes, void* data)
 {
-	assert(1 == nb_nodes);
-
-	scf_handler_data_t* d = data;
-	scf_variable_t*     r = NULL;
-	scf_expr_t*         e = nodes[0];
-
-	assert(SCF_OP_EXPR == e->type);
-
-	if (_scf_expr_calculate_internal(ast, e, &r) < 0)
-		return -1;
 	return 0;
 }
 
@@ -453,20 +463,14 @@ static int _scf_op_const_expr(scf_ast_t* ast, scf_node_t** nodes, int nb_nodes,
 {
 	assert(1 == nb_nodes);
 
-	scf_handler_data_t* d = data;
-
-	scf_node_t* n      = nodes[0];
 	scf_node_t* parent = nodes[0]->parent;
+	scf_node_t* node;
 
-	while (SCF_OP_EXPR == n->type)
-		n = n->nodes[0];
+	scf_expr_simplify(&nodes[0]);
 
-	n->parent->nodes[0] = NULL;
-	scf_node_free(nodes[0]);
-	nodes[0]  = n;
-	n->parent = parent;
+	node = nodes[0];
 
-	int ret = _scf_expr_calculate_internal(ast, n, d);
+	int ret = _scf_expr_calculate_internal(ast, node, data);
 	if (ret < 0) {
 		scf_loge("\n");
 		return -1;
@@ -475,8 +479,7 @@ static int _scf_op_const_expr(scf_ast_t* ast, scf_node_t** nodes, int nb_nodes,
 	if (parent->result)
 		scf_variable_free(parent->result);
 
-	scf_variable_t* v = _scf_operand_get(n);
-
+	scf_variable_t* v = _scf_operand_get(node);
 	if (v)
 		parent->result = scf_variable_ref(v);
 	else
diff --git a/parse/scf_operator_handler_semantic.c b/parse/scf_operator_handler_semantic.c
index 856030f..f37493c 100644
--- a/parse/scf_operator_handler_semantic.c
+++ b/parse/scf_operator_handler_semantic.c
@@ -1045,7 +1045,6 @@ static int _scf_op_semantic_block(scf_ast_t* ast, scf_node_t** nodes, int nb_nod
 			ret = _scf_op_semantic_node(ast, node, d);
 
 		if (ret < 0) {
-			scf_loge("\n");
 			ast->current_block = up;
 			return -1;
 		}
@@ -1285,59 +1284,173 @@ static int _scf_op_semantic_while(scf_ast_t* ast, scf_node_t** nodes, int nb_nod
 	return 0;
 }
 
-static int _scf_op_semantic_switch(scf_ast_t* ast, scf_node_t** nodes, int nb_nodes, void* data)
+static int __switch_for_string(scf_ast_t* ast, scf_node_t* parent, scf_node_t* child, scf_expr_t* e, scf_expr_t* e1, scf_handler_data_t* d)
 {
-	assert(2 == nb_nodes);
-
-	scf_handler_data_t* d = data;
-	scf_variable_t*     r = NULL;
-	scf_expr_t*         e = nodes[0];
+	scf_function_t* f = NULL;
+	scf_expr_t*     e2;
+	scf_expr_t*     e3;
+	scf_expr_t*     e4;
 
-	assert(SCF_OP_EXPR == e->type);
+	int ret = scf_ast_find_function(&f, ast, "strcmp");
+	if (ret < 0)
+		return ret;
 
-	if (_scf_expr_calculate(ast, e, &r) < 0) {
-		scf_loge("\n");
+	if (!f) {
+		scf_loge("can't find function 'strcmp()' for compare const string, file: %s, line: %d\n",
+				parent->w->file->data, parent->w->line);
 		return -1;
 	}
 
-	if (!r || !scf_variable_integer(r)) {
-		scf_loge("\n");
-		return -1;
+	e2 = scf_expr_clone(e);
+	if (!e1)
+		return -ENOMEM;
+
+	e3 = scf_expr_alloc();
+	if (!e3) {
+		scf_expr_free(e2);
+		return -ENOMEM;
 	}
-	scf_variable_free(r);
-	r = NULL;
 
-	int ret = _scf_op_semantic_node(ast, nodes[1], d);
+	ret = scf_node_add_child(e3, e2);
 	if (ret < 0) {
-		scf_loge("\n");
-		return -1;
+		scf_expr_free(e2);
+		scf_expr_free(e3);
+		return ret;
 	}
+	e2 = NULL;
 
-	return 0;
+	ret = scf_node_add_child(e3, e1);
+	if (ret < 0) {
+		scf_expr_free(e3);
+		return ret;
+	}
+	child->nodes[0] = NULL;
+
+	e4 = scf_expr_alloc();
+	if (!e4) {
+		scf_expr_free(e3);
+		return -ENOMEM;
+	}
+
+	ret = scf_node_add_child(e4, e3);
+	if (ret < 0) {
+		scf_expr_free(e3);
+		scf_expr_free(e4);
+		return ret;
+	}
+
+	child->nodes[0] = e4;
+	e4->parent      = child;
+
+	d->pret = &e3->result;
+
+	return _semantic_add_call(ast, e3->nodes, e3->nb_nodes, d, f);
 }
 
-static int _scf_op_semantic_case(scf_ast_t* ast, scf_node_t** nodes, int nb_nodes, void* data)
+static int _scf_op_semantic_switch(scf_ast_t* ast, scf_node_t** nodes, int nb_nodes, void* data)
 {
-	assert(1 == nb_nodes);
+	assert(2 == nb_nodes);
 
-	scf_handler_data_t* d = data;
-	scf_variable_t*     r = NULL;
-	scf_expr_t*         e = nodes[0];
+	scf_handler_data_t* d      = data;
+	scf_variable_t**    pret   = d->pret;
+	scf_variable_t*     v0     = NULL;
+	scf_variable_t*     v1     = NULL;
+	scf_block_t*        tmp    = ast->current_block;
+	scf_expr_t*         e      = nodes[0];
+	scf_node_t*         b      = nodes[1];
+	scf_node_t*         parent = nodes[0]->parent;
+	scf_node_t*         child;
+	scf_expr_t*         e1;
 
-	assert(SCF_OP_EXPR == e->type);
+	assert(SCF_OP_EXPR  == e->type);
+	assert(SCF_OP_BLOCK == b->type);
 
-	if (_scf_expr_calculate(ast, e, &r) < 0) {
-		scf_loge("\n");
+	if (_scf_expr_calculate(ast, e, &v0) < 0)
 		return -1;
-	}
 
-	if (!r || !scf_variable_integer(r)) {
-		scf_loge("\n");
+	if (!scf_variable_integer(v0) && !scf_variable_string(v0)) {
+		scf_loge("result of switch expr should be an integer or string, file: %s, line: %d\n", parent->w->file->data, parent->w->line);
+		scf_variable_free(v0);
 		return -1;
 	}
-	scf_variable_free(r);
 
+	ast->current_block = (scf_block_t*)b;
+
+	int ret = -1;
+	int i;
+
+	for (i = 0; i < b->nb_nodes; i++) {
+		child     = b->nodes[i];
+
+		if (SCF_OP_CASE == child->type) {
+			assert(1    == child->nb_nodes);
+
+			e1 = child->nodes[0];
+
+			assert(SCF_OP_EXPR == e1->type);
+
+			ret = _scf_expr_calculate(ast, e1, &v1);
+			if (ret < 0) {
+				scf_variable_free(v0);
+				return ret;
+			}
+
+			if (!scf_variable_const_integer(v1) && !scf_variable_const_string(v1)) {
+				ret = -1;
+				scf_loge("result of case expr should be const integer or const string, file: %s, line: %d\n", child->w->file->data, child->w->line);
+				goto error;
+			}
+
+			if (!scf_variable_type_like(v0, v1)) {
+
+				if (scf_type_cast_check(ast, v0, v1) < 0) {
+					ret = -1;
+					scf_loge("type of switch's expr is NOT same to the case's, file: %s, line: %d\n", child->w->file->data, child->w->line);
+					goto error;
+				}
+
+				ret = _semantic_add_type_cast(ast, &(e1->nodes[0]), v0, e1->nodes[0]);
+				if (ret < 0)
+					goto error;
+			}
+
+			if (scf_variable_const_string(v1)) {
+
+				ret = __switch_for_string(ast, parent, child, e, e1, d);
+				if (ret < 0)
+					goto error;
+			}
+
+			scf_variable_free(v1);
+			v1 = NULL;
+
+		} else {
+			ret = _scf_op_semantic_node(ast, child, d);
+			if (ret < 0) {
+				scf_variable_free(v0);
+				return -1;
+			}
+		}
+	}
+
+	ast->current_block = tmp;
+
+	scf_variable_free(v0);
+
+	d->pret = pret;
 	return 0;
+
+error:
+	scf_variable_free(v0);
+	scf_variable_free(v1);
+	d->pret = pret;
+	return ret;
+}
+
+static int _scf_op_semantic_case(scf_ast_t* ast, scf_node_t** nodes, int nb_nodes, void* data)
+{
+	scf_loge("\n");
+	return -1;
 }
 
 static int _scf_op_semantic_default(scf_ast_t* ast, scf_node_t** nodes, int nb_nodes, void* data)
@@ -1404,10 +1517,8 @@ static int __scf_op_semantic_call(scf_ast_t* ast, scf_function_t* f, void* data)
 	// change the current block
 	ast->current_block = (scf_block_t*)f;
 
-	if (_scf_op_semantic_block(ast, f->node.nodes, f->node.nb_nodes, d) < 0) {
-		scf_loge("\n");
+	if (_scf_op_semantic_block(ast, f->node.nodes, f->node.nb_nodes, d) < 0)
 		return -1;
-	}
 
 	ast->current_block = tmp;
 	return 0;
diff --git a/parse/scf_parse.c b/parse/scf_parse.c
index e0f889d..4fbda8e 100644
--- a/parse/scf_parse.c
+++ b/parse/scf_parse.c
@@ -1860,12 +1860,12 @@ static int _add_debug_sections(scf_parse_t* parse, scf_elf_context_t* elf)
 int scf_parse_compile_functions(scf_parse_t* parse, scf_vector_t* functions)
 {
 	scf_function_t* f;
-
 	int i;
+
 	for (i = 0; i < functions->size; i++) {
 		f  =        functions->data[i];
 
-		scf_logi("i: %d, fname: %s, f->argv->size: %d, f->node.define_flag: %d, inline_flag: %d\n",
+		printf("%d, %s(), argv->size: %d, define_flag: %d, inline_flag: %d\n",
 				i, f->node.w->text->data, f->argv->size, f->node.define_flag, f->inline_flag);
 
 		if (!f->node.define_flag)