919 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			919 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /*
 | ||
|  |  * Copyright (c) 2006-2018, RT-Thread Development Team | ||
|  |  * | ||
|  |  * SPDX-License-Identifier: Apache-2.0 | ||
|  |  * | ||
|  |  * Change Logs: | ||
|  |  * Date           Author       Notes | ||
|  |  * 2010-03-22     Bernard      first version | ||
|  |  */ | ||
|  | #include <finsh.h>
 | ||
|  | 
 | ||
|  | #include "finsh_node.h"
 | ||
|  | #include "finsh_error.h"
 | ||
|  | #include "finsh_var.h"
 | ||
|  | #include "finsh_ops.h"
 | ||
|  | 
 | ||
|  | union finsh_value*  finsh_compile_sp;       /* stack pointer */ | ||
|  | uint8_t*            finsh_compile_pc;       /* PC */ | ||
|  | 
 | ||
|  | #define finsh_code_byte(x)  do { *finsh_compile_pc = (x); finsh_compile_pc ++; } while(0)
 | ||
|  | #define finsh_code_word(x)  do { FINSH_SET16(finsh_compile_pc, x); finsh_compile_pc +=2; } while(0)
 | ||
|  | #define finsh_code_dword(x) do { FINSH_SET32(finsh_compile_pc, x); finsh_compile_pc +=4; } while(0)
 | ||
|  | 
 | ||
|  | static int finsh_compile(struct finsh_node* node) | ||
|  | { | ||
|  |     if (node != NULL) | ||
|  |     { | ||
|  |         /* compile child node */ | ||
|  |         if (finsh_node_child(node) != NULL) | ||
|  |             finsh_compile(finsh_node_child(node)); | ||
|  | 
 | ||
|  |         /* compile current node */ | ||
|  |         switch (node->node_type) | ||
|  |         { | ||
|  |         case FINSH_NODE_ID: | ||
|  |             { | ||
|  |                 /* identifier::syscall */ | ||
|  |                 if (node->idtype & FINSH_IDTYPE_SYSCALL) | ||
|  |                 { | ||
|  |                     /* load address */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                     finsh_code_dword((long)node->id.syscall->func); | ||
|  |                 } | ||
|  |                 /* identifier::sysvar */ | ||
|  |                 else if (node->idtype & FINSH_IDTYPE_SYSVAR) | ||
|  |                 { | ||
|  |                     struct finsh_sysvar* sysvar; | ||
|  | 
 | ||
|  |                     sysvar = node->id.sysvar; | ||
|  |                     if (sysvar != NULL) | ||
|  |                     { | ||
|  |                         switch (sysvar->type) | ||
|  |                         { | ||
|  |                         case finsh_type_char: | ||
|  |                         case finsh_type_uchar: | ||
|  |                             if (node->idtype & FINSH_IDTYPE_ADDRESS) | ||
|  |                             { | ||
|  |                                 /* load address */ | ||
|  |                                 finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                             } | ||
|  |                             else | ||
|  |                             { | ||
|  |                                 /* load value */ | ||
|  |                                 finsh_code_byte(FINSH_OP_LD_VALUE_BYTE); | ||
|  |                             } | ||
|  | 
 | ||
|  |                             finsh_code_dword((long)(sysvar->var)); | ||
|  |                             break; | ||
|  | 
 | ||
|  |                         case finsh_type_short: | ||
|  |                         case finsh_type_ushort: | ||
|  |                             if (node->idtype & FINSH_IDTYPE_ADDRESS) | ||
|  |                             { | ||
|  |                                 /* load address */ | ||
|  |                                 finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                             } | ||
|  |                             else | ||
|  |                             { | ||
|  |                                 /* load value */ | ||
|  |                                 finsh_code_byte(FINSH_OP_LD_VALUE_WORD); | ||
|  |                             } | ||
|  | 
 | ||
|  |                             finsh_code_dword((long)(sysvar->var)); | ||
|  |                             break; | ||
|  | 
 | ||
|  |                         case finsh_type_int: | ||
|  |                         case finsh_type_uint: | ||
|  |                         case finsh_type_long: | ||
|  |                         case finsh_type_ulong: | ||
|  |                         case finsh_type_charp: | ||
|  |                         case finsh_type_shortp: | ||
|  |                         case finsh_type_intp: | ||
|  |                         case finsh_type_longp: | ||
|  |                             if (node->idtype & FINSH_IDTYPE_ADDRESS) | ||
|  |                             { | ||
|  |                                 /* load address */ | ||
|  |                                 finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                             } | ||
|  |                             else | ||
|  |                             { | ||
|  |                                 /* load value */ | ||
|  |                                 finsh_code_byte(FINSH_OP_LD_VALUE_DWORD); | ||
|  |                             } | ||
|  | 
 | ||
|  |                             finsh_code_dword((long)(sysvar->var)); | ||
|  |                             break; | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |                 /* identifier::var */ | ||
|  |                 else | ||
|  |                 { | ||
|  |                     struct finsh_var* var; | ||
|  | 
 | ||
|  |                     var = node->id.var; | ||
|  |                     if (var != NULL) | ||
|  |                     { | ||
|  |                         switch (var->type) | ||
|  |                         { | ||
|  |                         case finsh_type_char: | ||
|  |                         case finsh_type_uchar: | ||
|  |                             if (node->idtype & FINSH_IDTYPE_ADDRESS) | ||
|  |                             { | ||
|  |                                 /* load address */ | ||
|  |                                 finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                             } | ||
|  |                             else | ||
|  |                             { | ||
|  |                                 /* load value */ | ||
|  |                                 finsh_code_byte(FINSH_OP_LD_VALUE_BYTE); | ||
|  |                             } | ||
|  | 
 | ||
|  |                             finsh_code_dword((long)&(var->value.char_value)); | ||
|  |                             break; | ||
|  | 
 | ||
|  |                         case finsh_type_short: | ||
|  |                         case finsh_type_ushort: | ||
|  |                             if (node->idtype & FINSH_IDTYPE_ADDRESS) | ||
|  |                             { | ||
|  |                                 /* load address */ | ||
|  |                                 finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                             } | ||
|  |                             else | ||
|  |                             { | ||
|  |                                 /* load value */ | ||
|  |                                 finsh_code_byte(FINSH_OP_LD_VALUE_WORD); | ||
|  |                             } | ||
|  | 
 | ||
|  |                             finsh_code_dword((long)&(var->value.short_value)); | ||
|  |                             break; | ||
|  | 
 | ||
|  |                         case finsh_type_int: | ||
|  |                         case finsh_type_uint: | ||
|  |                         case finsh_type_long: | ||
|  |                         case finsh_type_ulong: | ||
|  |                         case finsh_type_charp: | ||
|  |                         case finsh_type_shortp: | ||
|  |                         case finsh_type_intp: | ||
|  |                         case finsh_type_longp: | ||
|  |                             if (node->idtype & FINSH_IDTYPE_ADDRESS) | ||
|  |                             { | ||
|  |                                 /* load address */ | ||
|  |                                 finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                             } | ||
|  |                             else | ||
|  |                             { | ||
|  |                                 /* load value */ | ||
|  |                                 finsh_code_byte(FINSH_OP_LD_VALUE_DWORD); | ||
|  |                             } | ||
|  | 
 | ||
|  |                             finsh_code_dword((long)&(var->value.long_value)); | ||
|  |                             break; | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |             break; | ||
|  | 
 | ||
|  |         /* load const */ | ||
|  |         case FINSH_NODE_VALUE_CHAR: | ||
|  |             finsh_code_byte(FINSH_OP_LD_BYTE); | ||
|  |             finsh_code_byte(node->value.char_value); | ||
|  |             break; | ||
|  | 
 | ||
|  |         case FINSH_NODE_VALUE_INT: | ||
|  |         case FINSH_NODE_VALUE_LONG: | ||
|  |             finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |             finsh_code_dword(node->value.long_value); | ||
|  |             break; | ||
|  | 
 | ||
|  |         case FINSH_NODE_VALUE_NULL: | ||
|  |         case FINSH_NODE_VALUE_STRING: | ||
|  |             finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |             finsh_code_dword((uint32_t)node->value.ptr); | ||
|  |             break; | ||
|  | 
 | ||
|  |         /* arithmetic operation */ | ||
|  |         case FINSH_NODE_SYS_ADD: | ||
|  |             if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_ADD_BYTE); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_ADD_WORD); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_ADD_DWORD); | ||
|  |             break; | ||
|  | 
 | ||
|  |         case FINSH_NODE_SYS_SUB: | ||
|  |             if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_SUB_BYTE); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_SUB_WORD); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_SUB_DWORD); | ||
|  |             break; | ||
|  | 
 | ||
|  |         case FINSH_NODE_SYS_MUL: | ||
|  |             if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_MUL_BYTE); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_MUL_WORD); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_MUL_DWORD); | ||
|  |             break; | ||
|  | 
 | ||
|  |         case FINSH_NODE_SYS_DIV: | ||
|  |             if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_DIV_BYTE); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_DIV_WORD); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_DIV_DWORD); | ||
|  |             break; | ||
|  | 
 | ||
|  |         case FINSH_NODE_SYS_MOD: | ||
|  |             if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_MOD_BYTE); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_MOD_WORD); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_MOD_DWORD); | ||
|  |             break; | ||
|  | 
 | ||
|  |         /* bit operation */ | ||
|  |         case FINSH_NODE_SYS_AND: | ||
|  |             if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_AND_BYTE); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_AND_WORD); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_AND_DWORD); | ||
|  |             break; | ||
|  | 
 | ||
|  |         case FINSH_NODE_SYS_OR: | ||
|  |             if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_OR_BYTE); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_OR_WORD); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_OR_DWORD); | ||
|  |             break; | ||
|  | 
 | ||
|  |         case FINSH_NODE_SYS_XOR: | ||
|  |             if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_XOR_BYTE); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_XOR_WORD); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_XOR_DWORD); | ||
|  |             break; | ||
|  | 
 | ||
|  |         case FINSH_NODE_SYS_BITWISE: | ||
|  |             if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_BITWISE_BYTE); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_BITWISE_WORD); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_BITWISE_DWORD); | ||
|  |             break; | ||
|  | 
 | ||
|  |         case FINSH_NODE_SYS_SHL: | ||
|  |             if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_SHL_BYTE); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_SHL_WORD); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_SHL_DWORD); | ||
|  |             break; | ||
|  | 
 | ||
|  |         case FINSH_NODE_SYS_SHR: | ||
|  |             if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_SHR_BYTE); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_SHR_WORD); | ||
|  |             else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_SHR_DWORD); | ||
|  |             break; | ||
|  | 
 | ||
|  |         /* syscall */ | ||
|  |         case FINSH_NODE_SYS_FUNC: | ||
|  |             { | ||
|  |                 int parameters; | ||
|  |                 struct finsh_node* sibling; | ||
|  | 
 | ||
|  |                 parameters = 0; | ||
|  |                 if (finsh_node_child(node) != NULL) | ||
|  |                 { | ||
|  |                     sibling = finsh_node_sibling(finsh_node_child(node)); | ||
|  |                     while (sibling != NULL) | ||
|  |                     { | ||
|  |                         parameters ++; | ||
|  |                         sibling = finsh_node_sibling(sibling); | ||
|  |                     } | ||
|  | 
 | ||
|  |                     /* load address of function */ | ||
|  |                     // finsh_code_dword((long)&(node->var->value.ptr));
 | ||
|  | 
 | ||
|  |                     /* syscall parameters */ | ||
|  |                     finsh_code_byte(FINSH_OP_SYSCALL); | ||
|  |                     finsh_code_byte(parameters); | ||
|  |                 } | ||
|  |             } | ||
|  |             break; | ||
|  | 
 | ||
|  |         /* assign expression */ | ||
|  |         case FINSH_NODE_SYS_ASSIGN: | ||
|  |             if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID) | ||
|  |             { | ||
|  |                 switch (finsh_node_child(node)->data_type) | ||
|  |                 { | ||
|  |                 case FINSH_DATA_TYPE_BYTE: | ||
|  |                     finsh_code_byte(FINSH_OP_ST_BYTE); | ||
|  | 
 | ||
|  |                     /* load value again */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_BYTE_STACK); | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case FINSH_DATA_TYPE_WORD: | ||
|  |                     finsh_code_byte(FINSH_OP_ST_WORD); | ||
|  | 
 | ||
|  |                     /* load value again */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_WORD_STACK); | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case FINSH_DATA_TYPE_DWORD: | ||
|  |                     finsh_code_byte(FINSH_OP_ST_DWORD); | ||
|  | 
 | ||
|  |                     /* load value again */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 default: | ||
|  |                     finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE); | ||
|  |                 } | ||
|  |             } | ||
|  |             else if (finsh_node_child(node)->node_type == FINSH_NODE_SYS_GETVALUE) | ||
|  |             { | ||
|  |                 switch ((finsh_node_child(node)->data_type) & 0x0F) | ||
|  |                 { | ||
|  |                 case FINSH_DATA_TYPE_BYTE: | ||
|  |                     finsh_code_byte(FINSH_OP_ST_BYTE); | ||
|  | 
 | ||
|  |                     /* load value again */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_BYTE_STACK); | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case FINSH_DATA_TYPE_WORD: | ||
|  |                     finsh_code_byte(FINSH_OP_ST_WORD); | ||
|  | 
 | ||
|  |                     /* load value again */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_WORD_STACK); | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case FINSH_DATA_TYPE_DWORD: | ||
|  |                     finsh_code_byte(FINSH_OP_ST_DWORD); | ||
|  | 
 | ||
|  |                     /* load value again */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 default: | ||
|  |                     finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE); | ||
|  |                 } | ||
|  |             } | ||
|  |             break; | ||
|  | 
 | ||
|  |         /* pre-increase */ | ||
|  |         case FINSH_NODE_SYS_PREINC: | ||
|  |             if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID) | ||
|  |             { | ||
|  |                 struct finsh_var* var; | ||
|  |                 var = finsh_node_child(node)->id.var; | ||
|  | 
 | ||
|  |                 /* ld_dword &id */ | ||
|  |                 // finsh_code_byte(FINSH_OP_LD_DWORD);
 | ||
|  | 
 | ||
|  |                 switch (node->data_type) | ||
|  |                 { | ||
|  |                 case FINSH_DATA_TYPE_BYTE: | ||
|  |                     /* address */ | ||
|  |                     // finsh_code_dword((long)&(var->value.char_value));
 | ||
|  | 
 | ||
|  |                     /* ld_value_byte &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_BYTE); | ||
|  |                     finsh_code_dword((long)&(var->value.char_value)); | ||
|  | 
 | ||
|  |                     /* ld_byte 1 */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_BYTE); | ||
|  |                     finsh_code_byte(1); | ||
|  | 
 | ||
|  |                     /* add_byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_ADD_BYTE); | ||
|  |                     /* st_byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_ST_BYTE); | ||
|  | 
 | ||
|  |                     /* load value again */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); | ||
|  | 
 | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case FINSH_DATA_TYPE_WORD: | ||
|  |                     /* address */ | ||
|  |                     // finsh_code_dword((long)&(var->value.short_value));
 | ||
|  | 
 | ||
|  |                     /* ld_value_word &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_WORD); | ||
|  |                     finsh_code_dword((long)&(var->value.short_value)); | ||
|  | 
 | ||
|  |                     /* ld_word 1 */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_WORD); | ||
|  |                     finsh_code_word(1); | ||
|  | 
 | ||
|  |                     /* add_word */ | ||
|  |                     finsh_code_byte(FINSH_OP_ADD_WORD); | ||
|  |                     /* st_word */ | ||
|  |                     finsh_code_byte(FINSH_OP_ST_WORD); | ||
|  | 
 | ||
|  |                     /* load value again */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); | ||
|  | 
 | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case FINSH_DATA_TYPE_DWORD: | ||
|  |                     /* address */ | ||
|  |                     // finsh_code_dword((long)&(var->value.long_value));
 | ||
|  | 
 | ||
|  |                     /* ld_dword &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_DWORD); | ||
|  |                     finsh_code_dword((long)&(var->value.long_value)); | ||
|  | 
 | ||
|  |                     /* ld_dword 1 */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                     finsh_code_dword(1); | ||
|  | 
 | ||
|  |                     /* add_dword */ | ||
|  |                     finsh_code_byte(FINSH_OP_ADD_DWORD); | ||
|  |                     /* st_dword */ | ||
|  |                     finsh_code_byte(FINSH_OP_ST_DWORD); | ||
|  | 
 | ||
|  |                     /* load value again */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); | ||
|  | 
 | ||
|  |                     break; | ||
|  |                 } | ||
|  |             } | ||
|  |             break; | ||
|  | 
 | ||
|  |         /* pre-decrease */ | ||
|  |         case FINSH_NODE_SYS_PREDEC: | ||
|  |             if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID) | ||
|  |             { | ||
|  |                 struct finsh_var* var; | ||
|  |                 var = finsh_node_child(node)->id.var; | ||
|  | 
 | ||
|  |                 /* ld_dword &id */ | ||
|  |                 // finsh_code_byte(FINSH_OP_LD_DWORD);
 | ||
|  | 
 | ||
|  |                 switch (node->data_type) | ||
|  |                 { | ||
|  |                 case FINSH_DATA_TYPE_BYTE: | ||
|  |                     /* address */ | ||
|  |                     // finsh_code_dword((long)&(var->value.char_value));
 | ||
|  | 
 | ||
|  |                     /* ld_value_byte &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_BYTE); | ||
|  |                     finsh_code_dword((long)&(var->value.char_value)); | ||
|  | 
 | ||
|  |                     /* ld_byte 1 */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_BYTE); | ||
|  |                     finsh_code_byte(1); | ||
|  | 
 | ||
|  |                     /* add_byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_SUB_BYTE); | ||
|  |                     /* st_byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_ST_BYTE); | ||
|  | 
 | ||
|  |                     /* load value again */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); | ||
|  | 
 | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case FINSH_DATA_TYPE_WORD: | ||
|  |                     /* address */ | ||
|  |                     // finsh_code_dword((long)&(var->value.short_value));
 | ||
|  | 
 | ||
|  |                     /* ld_value_word &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_WORD); | ||
|  |                     finsh_code_dword((long)&(var->value.short_value)); | ||
|  | 
 | ||
|  |                     /* ld_word 1 */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_WORD); | ||
|  |                     finsh_code_word(1); | ||
|  | 
 | ||
|  |                     /* add_word */ | ||
|  |                     finsh_code_byte(FINSH_OP_SUB_WORD); | ||
|  |                     /* st_word */ | ||
|  |                     finsh_code_byte(FINSH_OP_ST_WORD); | ||
|  | 
 | ||
|  |                     /* load value again */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); | ||
|  | 
 | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case FINSH_DATA_TYPE_DWORD: | ||
|  |                     /* address */ | ||
|  |                     // finsh_code_dword((long)&(var->value.long_value));
 | ||
|  | 
 | ||
|  |                     /* ld_dword &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_DWORD); | ||
|  |                     finsh_code_dword((long)&(var->value.long_value)); | ||
|  | 
 | ||
|  |                     /* ld_dword 1 */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                     finsh_code_dword(1); | ||
|  | 
 | ||
|  |                     /* add_dword */ | ||
|  |                     finsh_code_byte(FINSH_OP_SUB_DWORD); | ||
|  |                     /* st_dword */ | ||
|  |                     finsh_code_byte(FINSH_OP_ST_DWORD); | ||
|  | 
 | ||
|  |                     /* load value again */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); | ||
|  | 
 | ||
|  |                     break; | ||
|  |                 } | ||
|  |             } | ||
|  |             break; | ||
|  | 
 | ||
|  |         /* increase */ | ||
|  |         case FINSH_NODE_SYS_INC: | ||
|  |             if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID) | ||
|  |             { | ||
|  |                 struct finsh_var* var; | ||
|  |                 var = finsh_node_child(node)->id.var; | ||
|  | 
 | ||
|  |                 switch (node->data_type) | ||
|  |                 { | ||
|  |                 case FINSH_DATA_TYPE_BYTE: | ||
|  |                     /* ld_value_byte &id */ | ||
|  |                     // finsh_code_byte(FINSH_OP_LD_VALUE_BYTE);
 | ||
|  |                     // finsh_code_dword((long)&(var->value.char_value));
 | ||
|  | 
 | ||
|  |                     /* ld_dword &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                     finsh_code_dword((long)&(var->value.char_value)); | ||
|  | 
 | ||
|  |                     /* ld_value_byte &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_BYTE); | ||
|  |                     finsh_code_dword((long)&(var->value.char_value)); | ||
|  | 
 | ||
|  |                     /* ld_byte 1 */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_BYTE); | ||
|  |                     finsh_code_byte(1); | ||
|  | 
 | ||
|  |                     /* add_byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_ADD_BYTE); | ||
|  |                     /* get byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_ST_BYTE); | ||
|  | 
 | ||
|  |                     /* pop */ | ||
|  |                     finsh_code_byte(FINSH_OP_POP); | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case FINSH_DATA_TYPE_WORD: | ||
|  |                     /* ld_value_word &id */ | ||
|  |                     // finsh_code_byte(FINSH_OP_LD_VALUE_WORD);
 | ||
|  |                     // finsh_code_dword((long)&(var->value.short_value));
 | ||
|  | 
 | ||
|  |                     /* ld_dword &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                     finsh_code_dword((long)&(var->value.short_value)); | ||
|  | 
 | ||
|  |                     /* ld_value_word &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_WORD); | ||
|  |                     finsh_code_dword((long)&(var->value.short_value)); | ||
|  | 
 | ||
|  |                     /* ld_word 1 */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_WORD); | ||
|  |                     finsh_code_word(1); | ||
|  | 
 | ||
|  |                     /* add_byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_ADD_WORD); | ||
|  |                     /* get byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_ST_WORD); | ||
|  | 
 | ||
|  |                     /* pop */ | ||
|  |                     finsh_code_byte(FINSH_OP_POP); | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case FINSH_DATA_TYPE_DWORD: | ||
|  |                     /* ld_value_dword &id */ | ||
|  |                     // finsh_code_byte(FINSH_OP_LD_VALUE_DWORD);
 | ||
|  |                     // finsh_code_dword((long)&(var->value.long_value));
 | ||
|  | 
 | ||
|  |                     /* ld_dword &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                     finsh_code_dword((long)&(var->value.long_value)); | ||
|  | 
 | ||
|  |                     /* ld_value_dword &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_DWORD); | ||
|  |                     finsh_code_dword((long)&(var->value.long_value)); | ||
|  | 
 | ||
|  |                     /* ld_dword 1 */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                     finsh_code_dword(1); | ||
|  | 
 | ||
|  |                     /* add_byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_ADD_DWORD); | ||
|  |                     /* get byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_ST_DWORD); | ||
|  | 
 | ||
|  |                     /* pop */ | ||
|  |                     finsh_code_byte(FINSH_OP_POP); | ||
|  |                     break; | ||
|  |                 } | ||
|  |             } | ||
|  |             break; | ||
|  | 
 | ||
|  |         /* decrease */ | ||
|  |         case FINSH_NODE_SYS_DEC: | ||
|  |             if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID) | ||
|  |             { | ||
|  |                 struct finsh_var* var; | ||
|  |                 var = finsh_node_child(node)->id.var; | ||
|  | 
 | ||
|  |                 switch (node->data_type) | ||
|  |                 { | ||
|  |                 case FINSH_DATA_TYPE_BYTE: | ||
|  |                     /* ld_value_byte &id */ | ||
|  |                     // finsh_code_byte(FINSH_OP_LD_VALUE_BYTE);
 | ||
|  |                     // finsh_code_dword((long)&(var->value.char_value));
 | ||
|  | 
 | ||
|  |                     /* ld_dword &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                     finsh_code_dword((long)&(var->value.char_value)); | ||
|  | 
 | ||
|  |                     /* ld_value_byte &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_BYTE); | ||
|  |                     finsh_code_dword((long)&(var->value.char_value)); | ||
|  | 
 | ||
|  |                     /* ld_byte 1 */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_BYTE); | ||
|  |                     finsh_code_byte(1); | ||
|  | 
 | ||
|  |                     /* add_byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_SUB_BYTE); | ||
|  |                     /* get byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_ST_BYTE); | ||
|  | 
 | ||
|  |                     /* pop */ | ||
|  |                     finsh_code_byte(FINSH_OP_POP); | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case FINSH_DATA_TYPE_WORD: | ||
|  |                     /* ld_value_word &id */ | ||
|  |                     // finsh_code_byte(FINSH_OP_LD_VALUE_WORD);
 | ||
|  |                     // finsh_code_dword((long)&(var->value.short_value));
 | ||
|  | 
 | ||
|  |                     /* ld_dword &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                     finsh_code_dword((long)&(var->value.short_value)); | ||
|  | 
 | ||
|  |                     /* ld_value_word &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_WORD); | ||
|  |                     finsh_code_dword((long)&(var->value.short_value)); | ||
|  | 
 | ||
|  |                     /* ld_word 1 */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_WORD); | ||
|  |                     finsh_code_word(1); | ||
|  | 
 | ||
|  |                     /* add_byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_SUB_WORD); | ||
|  |                     /* get byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_ST_WORD); | ||
|  | 
 | ||
|  |                     /* pop */ | ||
|  |                     finsh_code_byte(FINSH_OP_POP); | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case FINSH_DATA_TYPE_DWORD: | ||
|  |                     /* ld_value_dword &id */ | ||
|  |                     // finsh_code_byte(FINSH_OP_LD_VALUE_DWORD);
 | ||
|  |                     // finsh_code_dword((long)&(var->value.long_value));
 | ||
|  | 
 | ||
|  |                     /* ld_dword &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                     finsh_code_dword((long)&(var->value.long_value)); | ||
|  | 
 | ||
|  |                     /* ld_value_dword &id */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_DWORD); | ||
|  |                     finsh_code_dword((long)&(var->value.long_value)); | ||
|  | 
 | ||
|  |                     /* ld_dword 1 */ | ||
|  |                     finsh_code_byte(FINSH_OP_LD_DWORD); | ||
|  |                     finsh_code_dword(1); | ||
|  | 
 | ||
|  |                     /* add_byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_SUB_DWORD); | ||
|  |                     /* get byte */ | ||
|  |                     finsh_code_byte(FINSH_OP_ST_DWORD); | ||
|  | 
 | ||
|  |                     /* pop */ | ||
|  |                     finsh_code_byte(FINSH_OP_POP); | ||
|  |                     break; | ||
|  |                 } | ||
|  |             } | ||
|  |             break; | ||
|  | 
 | ||
|  |         case FINSH_NODE_SYS_NULL: | ||
|  |             finsh_code_dword(0); | ||
|  |             break; | ||
|  | 
 | ||
|  |         case FINSH_NODE_SYS_GETVALUE: | ||
|  |             if (node->idtype & FINSH_IDTYPE_ADDRESS) | ||
|  |             { | ||
|  |                 /* nothing will be generated */ | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 switch (node->data_type) | ||
|  |                 { | ||
|  |                 case FINSH_DATA_TYPE_BYTE: | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_BYTE_STACK); | ||
|  |                     break; | ||
|  |                 case FINSH_DATA_TYPE_WORD: | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_WORD_STACK); | ||
|  |                     break; | ||
|  |                 case FINSH_DATA_TYPE_DWORD: | ||
|  |                     finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); | ||
|  |                     break; | ||
|  |                 default: | ||
|  |                     break; | ||
|  |                 } | ||
|  |             } | ||
|  |             break; | ||
|  | 
 | ||
|  |         case FINSH_NODE_SYS_GETADDR: | ||
|  |             /* nothing will be generated */ | ||
|  |             break; | ||
|  | 
 | ||
|  |         default: | ||
|  |             finsh_error_set(FINSH_ERROR_UNKNOWN_NODE); | ||
|  |             break; | ||
|  |         } | ||
|  | 
 | ||
|  |         /* compile sibling node */ | ||
|  |         if (finsh_node_sibling(node) != NULL) | ||
|  |             finsh_compile(finsh_node_sibling(node)); | ||
|  |     } | ||
|  | 
 | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int finsh_type_check(struct finsh_node* node, uint8_t is_addr) | ||
|  | { | ||
|  |     if (node != NULL) | ||
|  |     { | ||
|  |         /* address & value */ | ||
|  |         if (node->node_type == FINSH_NODE_SYS_ASSIGN || | ||
|  |             node->node_type == FINSH_NODE_SYS_PREINC || | ||
|  |             node->node_type == FINSH_NODE_SYS_PREDEC || | ||
|  |             node->node_type == FINSH_NODE_SYS_GETADDR) | ||
|  |         { | ||
|  |             /* address */ | ||
|  |             finsh_type_check(finsh_node_child(node), FINSH_IDTYPE_ADDRESS); | ||
|  |         } | ||
|  |         else if (node->node_type == FINSH_NODE_SYS_GETVALUE && is_addr) | ||
|  |         { | ||
|  |             /* change the attribute of getvalue in left expr */ | ||
|  |             finsh_type_check(finsh_node_child(node), 0); | ||
|  |         } | ||
|  |         else | ||
|  |         { | ||
|  |             /* transfer 'av' to child node */ | ||
|  |             finsh_type_check(finsh_node_child(node), is_addr); | ||
|  |         } | ||
|  | 
 | ||
|  |         /* always does not load address in sibling */ | ||
|  |         finsh_type_check(finsh_node_sibling(node), FINSH_NODE_VALUE); | ||
|  | 
 | ||
|  |         /** set attribute of current node */ | ||
|  | 
 | ||
|  |         /* make sure the current node is address or value */ | ||
|  |         if (node->idtype != FINSH_IDTYPE_SYSCALL) node->idtype |= is_addr; | ||
|  | 
 | ||
|  |         if (finsh_node_child(node) != NULL) | ||
|  |         { | ||
|  |             node->data_type = finsh_node_child(node)->data_type; | ||
|  |             return 0; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (node->node_type == FINSH_NODE_ID) | ||
|  |         { | ||
|  |             if (node->idtype & FINSH_IDTYPE_VAR) | ||
|  |             { | ||
|  |                 struct finsh_var* var; | ||
|  | 
 | ||
|  |                 var = node->id.var; | ||
|  |                 if (var != NULL) | ||
|  |                 { | ||
|  |                     switch (var->type) | ||
|  |                     { | ||
|  |                     case finsh_type_void: | ||
|  |                         node->data_type = FINSH_DATA_TYPE_VOID; | ||
|  |                         break; | ||
|  | 
 | ||
|  |                     case finsh_type_char: | ||
|  |                     case finsh_type_uchar: | ||
|  |                         node->data_type = FINSH_DATA_TYPE_BYTE; | ||
|  |                         break; | ||
|  | 
 | ||
|  |                     case finsh_type_short: | ||
|  |                     case finsh_type_ushort: | ||
|  |                         node->data_type = FINSH_DATA_TYPE_WORD; | ||
|  |                         break; | ||
|  | 
 | ||
|  |                     case finsh_type_int: | ||
|  |                     case finsh_type_uint: | ||
|  |                     case finsh_type_long: | ||
|  |                     case finsh_type_ulong: | ||
|  |                         node->data_type = FINSH_DATA_TYPE_DWORD; | ||
|  |                         break; | ||
|  | 
 | ||
|  |                     case finsh_type_charp: | ||
|  |                     case finsh_type_voidp: | ||
|  |                     case finsh_type_shortp: | ||
|  |                     case finsh_type_intp: | ||
|  |                     case finsh_type_longp: | ||
|  |                         node->data_type = FINSH_DATA_TYPE_DWORD; | ||
|  |                         break; | ||
|  | 
 | ||
|  |                     default: | ||
|  |                         finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE); | ||
|  |                         break; | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |             else if (node->idtype & FINSH_IDTYPE_SYSVAR) | ||
|  |             { | ||
|  |                 struct finsh_sysvar *sysvar; | ||
|  | 
 | ||
|  |                 sysvar = node->id.sysvar; | ||
|  |                 if (sysvar != NULL) | ||
|  |                 { | ||
|  |                     switch (sysvar->type) | ||
|  |                     { | ||
|  |                     case finsh_type_void: | ||
|  |                         node->data_type = FINSH_DATA_TYPE_VOID; | ||
|  |                         break; | ||
|  | 
 | ||
|  |                     case finsh_type_char: | ||
|  |                     case finsh_type_uchar: | ||
|  |                         node->data_type = FINSH_DATA_TYPE_BYTE; | ||
|  |                         break; | ||
|  | 
 | ||
|  |                     case finsh_type_short: | ||
|  |                     case finsh_type_ushort: | ||
|  |                         node->data_type = FINSH_DATA_TYPE_WORD; | ||
|  |                         break; | ||
|  | 
 | ||
|  |                     case finsh_type_int: | ||
|  |                     case finsh_type_uint: | ||
|  |                     case finsh_type_long: | ||
|  |                     case finsh_type_ulong: | ||
|  |                         node->data_type = FINSH_DATA_TYPE_DWORD; | ||
|  |                         break; | ||
|  | 
 | ||
|  |                     case finsh_type_charp: | ||
|  |                     case finsh_type_voidp: | ||
|  |                     case finsh_type_shortp: | ||
|  |                     case finsh_type_intp: | ||
|  |                     case finsh_type_longp: | ||
|  |                         node->data_type = FINSH_DATA_TYPE_DWORD; | ||
|  |                         break; | ||
|  | 
 | ||
|  |                     default: | ||
|  |                         finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE); | ||
|  |                         break; | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |         else if (node->node_type == FINSH_NODE_VALUE_CHAR) | ||
|  |         { | ||
|  |             node->data_type = FINSH_DATA_TYPE_BYTE; | ||
|  |         } | ||
|  |         else if (node->node_type == FINSH_NODE_VALUE_INT || | ||
|  |             node->node_type == FINSH_NODE_VALUE_LONG    || | ||
|  |             node->node_type == FINSH_NODE_VALUE_STRING  || | ||
|  |             node->node_type == FINSH_NODE_VALUE_NULL) | ||
|  |         { | ||
|  |             node->data_type = FINSH_DATA_TYPE_DWORD; | ||
|  |         } | ||
|  |     } | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | int finsh_compiler_run(struct finsh_node* node) | ||
|  | { | ||
|  |     struct finsh_node* sibling; | ||
|  | 
 | ||
|  |     /* type check */ | ||
|  |     finsh_type_check(node, FINSH_NODE_VALUE); | ||
|  | 
 | ||
|  |     /* clean text segment and vm stack */ | ||
|  |     memset(&text_segment[0], 0, sizeof(text_segment)); | ||
|  |     memset(&finsh_vm_stack[0], 0, sizeof(finsh_vm_stack[0])); | ||
|  | 
 | ||
|  |     /* reset compile stack pointer and pc */ | ||
|  |     finsh_compile_sp = &finsh_vm_stack[0]; | ||
|  |     finsh_compile_pc = &text_segment[0]; | ||
|  | 
 | ||
|  |     /* compile node */ | ||
|  |     sibling = node; | ||
|  |     while (sibling != NULL) | ||
|  |     { | ||
|  |         struct finsh_node* current_node; | ||
|  |         current_node = sibling; | ||
|  | 
 | ||
|  |         /* get sibling node */ | ||
|  |         sibling = current_node->sibling; | ||
|  | 
 | ||
|  |         /* clean sibling node */ | ||
|  |         current_node->sibling = NULL; | ||
|  |         finsh_compile(current_node); | ||
|  | 
 | ||
|  |         /* pop current value */ | ||
|  |         if (sibling != NULL) finsh_code_byte(FINSH_OP_POP); | ||
|  |     } | ||
|  | 
 | ||
|  |     return 0; | ||
|  | } |