diff options
| author | bernard.xiong <[email protected]> | 2009-07-02 22:48:23 +0000 |
|---|---|---|
| committer | bernard.xiong <[email protected]> | 2009-07-02 22:48:23 +0000 |
| commit | bda4730a9482c23083006abea939ee8d95d6ecff (patch) | |
| tree | 83005121824bd50ac74e63688c0d5eac148665f8 /finsh | |
| parent | 80c72e66de0b00b1a6de3e3508366a4c3eee458d (diff) | |
import RT-Thread RTOS 0.3.x to Google SVN
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@2 bbd45198-f89e-11dd-88c7-29a3b14d5316
Diffstat (limited to 'finsh')
| -rw-r--r-- | finsh/cmd.c | 375 | ||||
| -rw-r--r-- | finsh/finsh.h | 303 | ||||
| -rw-r--r-- | finsh/finsh_compiler.c | 906 | ||||
| -rw-r--r-- | finsh/finsh_error.c | 46 | ||||
| -rw-r--r-- | finsh/finsh_error.h | 14 | ||||
| -rw-r--r-- | finsh/finsh_heap.c | 269 | ||||
| -rw-r--r-- | finsh/finsh_heap.h | 10 | ||||
| -rw-r--r-- | finsh/finsh_init.c | 48 | ||||
| -rw-r--r-- | finsh/finsh_node.c | 174 | ||||
| -rw-r--r-- | finsh/finsh_node.h | 60 | ||||
| -rw-r--r-- | finsh/finsh_ops.c | 594 | ||||
| -rw-r--r-- | finsh/finsh_ops.h | 107 | ||||
| -rw-r--r-- | finsh/finsh_parser.c | 965 | ||||
| -rw-r--r-- | finsh/finsh_parser.h | 9 | ||||
| -rw-r--r-- | finsh/finsh_token.c | 562 | ||||
| -rw-r--r-- | finsh/finsh_token.h | 53 | ||||
| -rw-r--r-- | finsh/finsh_var.c | 130 | ||||
| -rw-r--r-- | finsh/finsh_var.h | 32 | ||||
| -rw-r--r-- | finsh/finsh_vm.c | 356 | ||||
| -rw-r--r-- | finsh/finsh_vm.h | 26 | ||||
| -rw-r--r-- | finsh/shell.c | 270 | ||||
| -rw-r--r-- | finsh/symbol.c | 56 |
22 files changed, 5365 insertions, 0 deletions
diff --git a/finsh/cmd.c b/finsh/cmd.c new file mode 100644 index 0000000000..ef2b02d135 --- /dev/null +++ b/finsh/cmd.c @@ -0,0 +1,375 @@ +/* + * File : cmd.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-04-30 Bernard first implementation + * 2006-05-04 Bernard add list_thread, + * list_sem, + * list_timer + * 2006-05-20 Bernard add list_mutex, + * list_mailbox, + * list_msgqueue, + * list_event, + * list_fevent, + * list_mempool + * 2006-06-03 Bernard display stack information in list_thread + * 2006-08-10 Bernard change version to invoke rt_show_version + * 2008-09-10 Bernard update the list function for finsh syscall + * list and sysvar list + * 2009-05-30 Bernard add list_device + */ + +#include <rtthread.h> +#include "finsh.h" + +long hello() +{ + rt_kprintf("Hello RT-Thread!\n"); + + return 0; +} +FINSH_FUNCTION_EXPORT(hello, say hello world) + +extern void rt_show_version(void); +long version() +{ + rt_show_version(); + + return 0; +} +FINSH_FUNCTION_EXPORT(version, show RT-Thread version information) + +#define rt_list_entry(node, type, member) \ + ((type *)((char *)(node) - (unsigned long)(&((type *)0)->member))) +extern struct rt_object_information rt_object_container[]; + +int list_thread() +{ + struct rt_thread *thread; + struct rt_list_node *list, *node; + rt_uint8_t* ptr; + + list = &rt_object_container[RT_Object_Class_Thread].object_list; + + rt_kprintf(" thread pri status sp stack size max used left tick error\n"); + rt_kprintf("-------- ---- ------- ---------- ---------- ---------- ---------- ---\n"); + for (node = list->next; node != list; node = node->next) + { + thread = rt_list_entry(node, struct rt_thread, list); + rt_kprintf("%-8s 0x%02x", thread->name, thread->current_priority); + + if (thread->stat == RT_THREAD_READY) rt_kprintf(" ready "); + else if (thread->stat == RT_THREAD_SUSPEND) rt_kprintf(" suspend"); + else if (thread->stat == RT_THREAD_INIT) rt_kprintf(" init "); + + ptr = (rt_uint8_t*)thread->stack_addr; + while (*ptr == '#')ptr ++; + + rt_kprintf(" 0x%08x 0x%08x 0x%08x 0x%08x %03d\n", + thread->stack_size + ((rt_uint32_t)thread->stack_addr - (rt_uint32_t)thread->sp), + thread->stack_size, + thread->stack_size - ((rt_uint32_t) ptr - (rt_uint32_t)thread->stack_addr), + thread->remaining_tick, + thread->error); + + } + return 0; +} +FINSH_FUNCTION_EXPORT(list_thread, list thread) + +static void show_wait_queue(struct rt_list_node* list) +{ + struct rt_thread *thread; + struct rt_list_node *node; + + for (node = list->next; node != list; node = node->next) + { + thread = rt_list_entry(node, struct rt_thread, tlist); + rt_kprintf("%s", thread->name); + if (node->next != list) rt_kprintf("/"); + } +} + +#ifdef RT_USING_SEMAPHORE +int list_sem() +{ + struct rt_semaphore *sem; + struct rt_list_node *list, *node; + + list = &rt_object_container[RT_Object_Class_Semaphore].object_list; + + rt_kprintf("semaphore v suspend thread\n"); + rt_kprintf("-------- --- --------------\n"); + for (node = list->next; node != list; node = node->next) + { + sem = (struct rt_semaphore*)(rt_list_entry(node, struct rt_object, list)); + if (sem->parent.suspend_thread_count != 0) + { + rt_kprintf("%-8s %03d %d:", sem->parent.parent.name, sem->value, sem->parent.suspend_thread_count); + show_wait_queue(&(sem->parent.suspend_thread)); + rt_kprintf("\n"); + } + else + { + rt_kprintf("%-8s %03d %d\n", sem->parent.parent.name, sem->value, sem->parent.suspend_thread_count); + } + } + + return 0; +} +FINSH_FUNCTION_EXPORT(list_sem, list semaphone in system) +#endif + +#ifdef RT_USING_FASTEVENT +int list_fevent() +{ + struct rt_fast_event *e; + struct rt_list_node *list, *node; + + list = &rt_object_container[RT_Object_Class_FastEvent].object_list; + + rt_kprintf("fevent set \n"); + rt_kprintf("-------- ----------\n"); + for (node = list->next; node != list; node = node->next) + { + e = (struct rt_fast_event*)(rt_list_entry(node, struct rt_object, list)); + rt_kprintf("%-8s 0x%08x\n", e->parent.name, e->set); + } + + return 0; +} +FINSH_FUNCTION_EXPORT(list_fevent, list fast event in system) +#endif + +#ifdef RT_USING_EVENT +int list_event() +{ + struct rt_event *e; + struct rt_list_node *list, *node; + + list = &rt_object_container[RT_Object_Class_Event].object_list; + + rt_kprintf("event set suspend thread\n"); + rt_kprintf("-------- ---------- --------------\n"); + for (node = list->next; node != list; node = node->next) + { + e = (struct rt_event*)(rt_list_entry(node, struct rt_object, list)); + rt_kprintf("%-8s 0x%08x %03d\n", e->parent.parent.name, e->set, e->parent.suspend_thread_count); + } + + return 0; +} +FINSH_FUNCTION_EXPORT(list_event, list event in system) +#endif + +#ifdef RT_USING_MUTEX +int list_mutex() +{ + struct rt_mutex *m; + struct rt_list_node *list, *node; + + list = &rt_object_container[RT_Object_Class_Mutex].object_list; + + rt_kprintf("mutex owner hold suspend thread\n"); + rt_kprintf("-------- -------- ---- --------------\n"); + for (node = list->next; node != list; node = node->next) + { + m = (struct rt_mutex*)(rt_list_entry(node, struct rt_object, list)); + rt_kprintf("%-8s %-8s %04d %d\n", m->parent.parent.name, m->owner->name, m->hold, m->parent.suspend_thread_count); + } + + return 0; +} +FINSH_FUNCTION_EXPORT(list_mutex, list mutex in system) +#endif + +#ifdef RT_USING_MAILBOX +int list_mailbox() +{ + struct rt_mailbox *m; + struct rt_list_node *list, *node; + + list = &rt_object_container[RT_Object_Class_MailBox].object_list; + + rt_kprintf("mailbox entry size suspend thread\n"); + rt_kprintf("-------- ---- ---- --------------\n"); + for (node = list->next; node != list; node = node->next) + { + m = (struct rt_mailbox*)(rt_list_entry(node, struct rt_object, list)); + if (m->parent.suspend_thread_count != 0) + { + rt_kprintf("%-8s %04d %04d %d:", m->parent.parent.name, m->entry, m->size, m->parent.suspend_thread_count); + show_wait_queue(&(m->parent.suspend_thread)); + rt_kprintf("\n"); + } + else + { + rt_kprintf("%-8s %04d %04d %d\n", m->parent.parent.name, m->entry, m->size, m->parent.suspend_thread_count); + } + } + + return 0; +} +FINSH_FUNCTION_EXPORT(list_mailbox, list mail box in system) +#endif + +#ifdef RT_USING_MESSAGEQUEUE +int list_msgqueue() +{ + struct rt_messagequeue *m; + struct rt_list_node *list, *node; + + list = &rt_object_container[RT_Object_Class_MessageQueue].object_list; + + rt_kprintf("msgqueue entry suspend thread\n"); + rt_kprintf("-------- ---- --------------\n"); + for (node = list->next; node != list; node = node->next) + { + m = (struct rt_messagequeue*)(rt_list_entry(node, struct rt_object, list)); + rt_kprintf("%-8s %04d %d\n", m->parent.parent.name, m->entry, m->parent.suspend_thread_count); + } + + return 0; +} +FINSH_FUNCTION_EXPORT(list_msgqueue, list message queue in system) +#endif + +#ifdef RT_USING_MEMPOOL +int list_mempool() +{ + struct rt_mempool *mp; + + struct rt_list_node *list, *node; + + list = &rt_object_container[RT_Object_Class_MemPool].object_list; + + rt_kprintf("mempool block total free suspend thread\n"); + rt_kprintf("-------- ---- ---- ---- --------------\n"); + for (node = list->next; node != list; node = node->next) + { + mp = (struct rt_mempool*)rt_list_entry(node, struct rt_object, list); + rt_kprintf("%-8s %04d %04d %04d %d\n", mp->parent.name, + mp->block_size, mp->block_total_count, mp->block_free_count, + mp->suspend_thread_count); + } + + return 0; +} +FINSH_FUNCTION_EXPORT(list_mempool, list memory pool in system) +#endif + +int list_timer() +{ + struct rt_timer *timer; + struct rt_list_node *list, *node; + + list = &rt_object_container[RT_Object_Class_Timer].object_list; + + rt_kprintf("timer periodic timeout flag\n"); + rt_kprintf("-------- ---------- ---------- -----------\n"); + for (node = list->next; node != list; node = node->next) + { + timer = (struct rt_timer*)(rt_list_entry(node, struct rt_object, list)); + rt_kprintf("%-8s 0x%08x 0x%08x ", timer->parent.name, timer->init_tick, timer->timeout_tick); + if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) rt_kprintf("activated\n"); + else rt_kprintf("deactivated\n"); + } + + rt_kprintf("current tick:0x%08x\n", rt_tick_get()); + + return 0; +} +FINSH_FUNCTION_EXPORT(list_timer, list timer in system) + +#ifdef RT_USING_DEVICE +int list_device() +{ + struct rt_device *device; + struct rt_list_node *list, *node; + const char *device_type_str[] = + { + "Character Device", + "Block Device", + "Network Interface", + "MTD Device", + "CAN", + "RTC", + "Unknown" + }; + + list = &rt_object_container[RT_Object_Class_Device].object_list; + + rt_kprintf("device type \n"); + rt_kprintf("-------- ---------- \n"); + for (node = list->next; node != list; node = node->next) + { + device = (struct rt_device*)(rt_list_entry(node, struct rt_object, list)); + rt_kprintf("%-8s %-8s \n", device->parent.name, device_type_str[device->type]); + } + + return 0; +} +FINSH_FUNCTION_EXPORT(list_device, list device in system) +#endif + +int list() +{ + struct finsh_syscall_item* syscall_item; + struct finsh_sysvar_item* sysvar_item; + + rt_kprintf("--Function List:\n"); + { + struct finsh_syscall* index; + for (index = _syscall_table_begin; index < _syscall_table_end; index ++) + { +#ifdef FINSH_USING_DESCRIPTION + rt_kprintf("%-16s -- %s\n", index->name, index->desc); +#else + rt_kprintf("%s\n", index->name); +#endif + } + } + + /* list syscall list */ + syscall_item = global_syscall_list; + while (syscall_item != NULL) + { + rt_kprintf("[l] %s\n", syscall_item->syscall.name); + syscall_item = syscall_item->next; + } + + rt_kprintf("--Variable List:\n"); + { + struct finsh_sysvar* index; + for (index = _sysvar_table_begin; index < _sysvar_table_end; index ++) + { +#ifdef FINSH_USING_DESCRIPTION + rt_kprintf("%-16s -- %s\n", index->name, index->desc); +#else + rt_kprintf("%s\n", index->name); +#endif + } + } + + sysvar_item = global_sysvar_list; + while (sysvar_item != NULL) + { + rt_kprintf("[l] %s\n", sysvar_item->sysvar.name); + sysvar_item = sysvar_item->next; + } + + return 0; +} +FINSH_FUNCTION_EXPORT(list, list all symbol in system) + +#ifdef FINSH_USING_SYMTAB +static int dummy = 0; +FINSH_VAR_EXPORT(dummy, finsh_type_int, dummy variable for finsh) +#endif diff --git a/finsh/finsh.h b/finsh/finsh.h new file mode 100644 index 0000000000..a913588d48 --- /dev/null +++ b/finsh/finsh.h @@ -0,0 +1,303 @@ +#ifndef __FINSH_H__ +#define __FINSH_H__ + +#include <rtthread.h> + +/* -- the beginning of option -- */ +#define FINSH_NAME_MAX 16 /* max length of identifier */ +#define FINSH_NODE_MAX 16 /* max number of node */ + +#define FINSH_HEAP_MAX 128 /* max length of heap */ +#define FINSH_STRING_MAX 128 /* max length of string */ +#define FINSH_VARIABLE_MAX 8 /* max number of variable */ + +#define FINSH_STACK_MAX 128 /* max stack size */ +#define FINSH_TEXT_MAX 128 /* max text segment size */ + +#define HEAP_ALIGNMENT 4 /* heap alignment */ + +#define FINSH_GET16(x) (*(x)) | (*((x)+1) << 8) +#define FINSH_GET32(x) (*(x)) | (*((x)+1) << 8) | (*((x)+2) << 16) | (*((x)+3) << 24) + +#define FINSH_SET16(x, v) \ + do \ + { \ + *(x) = (v) & 0x00ff; \ + (*((x)+1)) = (v) >> 8; \ + } while ( 0 ) + +#define FINSH_SET32(x, v) \ + do \ + { \ + *(x) = (v) & 0x000000ff; \ + (*((x)+1)) = ((v) >> 8) & 0x000000ff; \ + (*((x)+2)) = ((v) >> 16) & 0x000000ff; \ + (*((x)+3)) = ((v) >> 24); \ + } while ( 0 ) + +/* -- the end of option -- */ + + /** + * @defgroup finsh finsh shell + * + * finsh is a C-expression shell which gives user access to some symbols present in RT-Thread. + */ +/*@{*/ + +#if defined(RT_USING_NEWLIB) || defined (RT_USING_MINILIBC) +#include <string.h> +#else +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned long u_long; +typedef unsigned int size_t;
+ +#ifndef NULL +#define NULL RT_NULL +#endif
+ +#define memset rt_memset +#define strlen rt_strlen +#define strncpy rt_strncpy +#define strncmp rt_strncmp + +int strcmp (const char *s1, const char *s2); +char *strdup(const char *s); + +int isalpha( int ch ); +int atoi(const char* s); +#endif + +#define FINSH_VERSION_MAJOR 0 +#define FINSH_VERSION_MINOR 5 + +/* error code */ +#define FINSH_ERROR_OK 0 /** No error */ +#define FINSH_ERROR_INVALID_TOKEN 1 /** Invalid token */ +#define FINSH_ERROR_EXPECT_TYPE 2 /** Expect a type */ +#define FINSH_ERROR_UNKNOWN_TYPE 3 /** Unknown type */ +#define FINSH_ERROR_VARIABLE_EXIST 4 /** Variable exist */ +#define FINSH_ERROR_EXPECT_OPERATOR 5 /** Expect a operater */ +#define FINSH_ERROR_MEMORY_FULL 6 /** Memory full */ +#define FINSH_ERROR_UNKNOWN_OP 7 /** Unknown operator */ +#define FINSH_ERROR_UNKNOWN_NODE 8 /** Unknown node */ +#define FINSH_ERROR_EXPECT_CHAR 9 /** Expect a character */ +#define FINSH_ERROR_UNEXPECT_END 10 /** Unexpect end */ +#define FINSH_ERROR_UNKNOWN_TOKEN 11 /** Unknown token */ +#define FINSH_ERROR_NO_FLOAT 12 /** Float not supported */ +#define FINSH_ERROR_UNKNOWN_SYMBOL 13 /** Unknown symbol */ +#define FINSH_ERROR_NULL_NODE 14 /** Null node */ + +typedef long (*syscall_func)(); + +/* system call table */ +struct finsh_syscall +{ + const char* name; /* the name of system call */ +#if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB) + const char* desc; /* description of system call */ +#endif + syscall_func func; /* the function address of system call */ +}; +/* system call item */ +struct finsh_syscall_item +{ + struct finsh_syscall_item* next; /* next item */ + struct finsh_syscall syscall; /* syscall */ +}; +extern struct finsh_syscall *_syscall_table_begin, *_syscall_table_end; +extern struct finsh_syscall_item *global_syscall_list; + +/* find out system call, which should be implemented in user program */ +struct finsh_syscall* finsh_syscall_lookup(const char* name); + +/* system variable table */ +struct finsh_sysvar +{ + const char* name; /* the name of variable */ +#if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB) + const char* desc; /* description of system variable */ +#endif + u_char type; /* the type of variable */ + void* var ; /* the address of variable */ +}; +/* system variable item */ +struct finsh_sysvar_item +{ + struct finsh_sysvar_item *next; /* next item */ + struct finsh_sysvar sysvar; /* system variable */ +}; +extern struct finsh_sysvar *_sysvar_table_begin, *_sysvar_table_end; +extern struct finsh_sysvar_item* global_sysvar_list; + +/* find out system variable, which should be implemented in user program */ +struct finsh_sysvar* finsh_sysvar_lookup(const char* name); + +#ifdef FINSH_USING_SYMTAB + #ifdef FINSH_USING_DESCRIPTION + #define FINSH_FUNCTION_EXPORT(name, desc) \ + const char __fsym_##name##_name[] = #name; \ + const char __fsym_##name##_desc[] = #desc; \ + const struct finsh_syscall __fsym_##name SECTION("FSymTab")= \ + { \ + __fsym_##name##_name, \ + __fsym_##name##_desc, \ + (syscall_func)&name \ + }; + + #define FINSH_VAR_EXPORT(name, type, desc) \ + const char __vsym_##name##_name[] = #name; \ + const char __vsym_##name##_desc[] = #desc; \ + const struct finsh_sysvar __vsym_##name SECTION("VSymTab")= \ + { \ + __vsym_##name##_name, \ + __vsym_##name##_desc, \ + type, \ + (void*)&name \ + }; + #else + #define FINSH_FUNCTION_EXPORT(name, desc) \ + const char __fsym_##name##_name[] = #name; \ + const struct finsh_syscall __fsym_##name SECTION("FSymTab")= \ + { \ + __fsym_##name##_name, \ + (syscall_func)&name \ + }; + + #define FINSH_VAR_EXPORT(name, type, desc) \ + const char __vsym_##name##_name[] = #name; \ + const struct finsh_sysvar __vsym_##name SECTION("VSymTab")= \ + { \ + __vsym_##name##_name, \ + type, \ + (void*)&name \ + }; + #endif +#else + #define FINSH_FUNCTION_EXPORT(name, desc) + #define FINSH_VAR_EXPORT(name, type, desc) +#endif + +struct finsh_token +{ + char eof; + char replay; + + int position; + u_char current_token; + + union { + char char_value; + int int_value; + long long_value; + } value; + u_char string[128]; + + u_char* line; +}; + +#define FINSH_IDTYPE_VAR 0x01 +#define FINSH_IDTYPE_SYSVAR 0x02 +#define FINSH_IDTYPE_SYSCALL 0x04 +#define FINSH_IDTYPE_ADDRESS 0x08 +struct finsh_node +{ + u_char node_type; /* node node_type */ + u_char data_type; /* node data node_type */ + u_char idtype; /* id node information */ + + union { /* value node */ + char char_value; + short short_value; + int int_value; + long long_value; + void* ptr; + } value; + union + { + /* point to variable identifier or function identifier */ + struct finsh_var *var; + struct finsh_sysvar *sysvar; + struct finsh_syscall*syscall; + }id; + + /* sibling and child node */ + struct finsh_node *sibling, *child; +}; + +struct finsh_parser +{ + u_char* parser_string; + + struct finsh_token token; + struct finsh_node* root; +}; + +/** + * finsh basic data type + */ +enum finsh_type { + finsh_type_unknown = 0, + finsh_type_void, /** void */ + finsh_type_voidp, /** void pointer */ + finsh_type_char, /** char */ + finsh_type_uchar, /** unsigned char */ + finsh_type_charp, /** char pointer */ + finsh_type_short, /** short */ + finsh_type_ushort, /** unsigned short */ + finsh_type_shortp, /** short pointer */ + finsh_type_int, /** int */ + finsh_type_uint, /** unsigned int */ + finsh_type_intp, /** int pointer */ + finsh_type_long, /** long */ + finsh_type_ulong, /** unsigned long */ + finsh_type_longp /** long pointer */ +}; + +/* init finsh environment */ +int finsh_init(struct finsh_parser* parser); +/* flush finsh node, text segment */ +int finsh_flush(struct finsh_parser* parser); +/* reset all of finsh */ +int finsh_reset(struct finsh_parser* parser); +#ifdef RT_USING_DEVICE
+/* set finsh device */
+void finsh_set_device(char* device_name);
+#endif
+ +/* run finsh parser to generate abstract synatx tree */ +void finsh_parser_run (struct finsh_parser* parser, const unsigned char* string); +/* run compiler to compile abstract syntax tree */ +int finsh_compiler_run(struct finsh_node* node); +/* run finsh virtual machine */ +void finsh_vm_run(void); + +/* get variable value */ +struct finsh_var* finsh_var_lookup(const char* name); +/* get bottom value of stack */ +long finsh_stack_bottom(void); + +/* get error number of finsh */ +u_char finsh_errno(void); +/* get error string */ +const char* finsh_error_string(u_char type); + +#ifdef RT_USING_HEAP +/** + * append a system call to finsh runtime environment + * @param name the name of system call + * @param func the function pointer of system call + */ +void finsh_syscall_append(const char* name, syscall_func func); +/** + * append a system variable to finsh runtime environment + * @param name the name of system variable + * @param type the data type of system variable + * @param addr the address of system variable + */ +void finsh_sysvar_append(const char* name, u_char type, void* addr); +#endif + +/*@}*/ + +#endif diff --git a/finsh/finsh_compiler.c b/finsh/finsh_compiler.c new file mode 100644 index 0000000000..b440f0fa4e --- /dev/null +++ b/finsh/finsh_compiler.c @@ -0,0 +1,906 @@ +#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 */ +u_char* 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((u_long)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; + 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)->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)->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)->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)->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)->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, u_char 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; +} diff --git a/finsh/finsh_error.c b/finsh/finsh_error.c new file mode 100644 index 0000000000..e28223c732 --- /dev/null +++ b/finsh/finsh_error.c @@ -0,0 +1,46 @@ +#include "finsh_error.h" + +u_char global_errno; + +const char* finsh_error_string_table[] = +{ + "No error", + "Invalid token", + "Expect a type", + "Unknown type", + "Variable exist", + "Expect a operater", + "Memory full", + "Unknown operator", + "Unknown node", + "Expect a character", + "Unexpect end", + "Unknown token", + "Float not supported", + "Unknown symbol", + "Null node" +}; + +int finsh_error_init() +{ + global_errno = FINSH_ERROR_OK; + + return 0; +} + +int finsh_error_set(u_char type) +{ + global_errno = type; + + return 0; +} + +u_char finsh_errno() +{ + return global_errno; +} + +const char* finsh_error_string(u_char type) +{ + return finsh_error_string_table[type]; +} diff --git a/finsh/finsh_error.h b/finsh/finsh_error.h new file mode 100644 index 0000000000..725da02a9e --- /dev/null +++ b/finsh/finsh_error.h @@ -0,0 +1,14 @@ +#ifndef __FINSH_ERROR_H__ +#define __FINSH_ERROR_H__ + +#include <finsh.h> + +int finsh_error_init(void); + +/* get error number */ +u_char finsh_errno(void); + +int finsh_error_set(u_char type); +const char* finsh_error_string(u_char type); + +#endif diff --git a/finsh/finsh_heap.c b/finsh/finsh_heap.c new file mode 100644 index 0000000000..2fc027896f --- /dev/null +++ b/finsh/finsh_heap.c @@ -0,0 +1,269 @@ +#include <finsh.h> + +#include "finsh_var.h" + +u_char finsh_heap[FINSH_HEAP_MAX]; +struct finsh_block_header +{ + u_long length; + struct finsh_block_header* next; +}; +#define BLOCK_HEADER(x) (struct finsh_block_header*)(x) +#define finsh_block_get_header(data) (struct finsh_block_header*)((u_char*)data - sizeof(struct finsh_block_header)) +#define finsh_block_get_data(header) (u_char*)((struct finsh_block_header*)header + 1) +#define HEAP_ALIGN_SIZE(size) (((size) + HEAP_ALIGNMENT - 1) & ~(HEAP_ALIGNMENT-1)) + +static struct finsh_block_header* free_list; +static struct finsh_block_header* allocate_list; + +static void finsh_heap_gc(void); + +static void finsh_block_insert(struct finsh_block_header** list, struct finsh_block_header* header); +static void finsh_block_remove(struct finsh_block_header** list, struct finsh_block_header* header); +static void finsh_block_split(struct finsh_block_header* header, size_t size); +static void finsh_block_merge(struct finsh_block_header** list, struct finsh_block_header* header); + +int finsh_heap_init() +{ + /* clear heap to zero */ + memset(&finsh_heap[0], 0, sizeof(finsh_heap)); + + /* init free and alloc list */ + free_list = BLOCK_HEADER(&finsh_heap[0]); + free_list->length = FINSH_HEAP_MAX - sizeof(struct finsh_block_header); + free_list->next = NULL; + + allocate_list = NULL; + + return 0; +} + +/** + * allocate a block from heap + */ +void* finsh_heap_allocate(size_t size) +{ + struct finsh_block_header* header; + + size = HEAP_ALIGN_SIZE(size); + + /* find the first fit block */ + for (header = free_list; + ((header != NULL) && (header->length <= size + sizeof(struct finsh_block_header))); + header = header->next) ; + + if (header == NULL) + { + finsh_heap_gc(); + + /* find the first fit block */ + for (header = free_list; + ((header != NULL) && (header->length < size + sizeof(struct finsh_block_header))); + header = header->next) ; + + /* there is no memory */ + if (header == NULL) return NULL; + } + + /* split block */ + finsh_block_split(header, size); + + /* remove from free list */ + finsh_block_remove(&free_list, header); + header->next = NULL; + + /* insert to allocate list */ + finsh_block_insert(&allocate_list, header); + + memset(finsh_block_get_data(header), 0, size); + + return finsh_block_get_data(header); +} + +/** + * release the allocated block + */ +void finsh_heap_free(void*ptr) +{ + struct finsh_block_header* header; + + /* get block header */ + header = finsh_block_get_header(ptr); + + /* remove from allocate list */ + finsh_block_remove(&allocate_list, header); + + /* insert to free list */ + finsh_block_insert(&free_list, header); + finsh_block_merge(&free_list, header); +} + +/** + * garbage collector + */ +static void finsh_heap_gc(void) +{ + int i; + struct finsh_block_header *header, *temp; + + temp = NULL; + + /* find the first fit block */ + for (header = allocate_list; header != NULL; ) + { + for (i = 0; i < FINSH_VARIABLE_MAX; i ++) + { + if (global_variable[i].type != finsh_type_unknown) + { + if (global_variable[i].value.ptr == finsh_block_get_data(header)) + break; + } + } + + temp = header; + header = header->next; + + /* this block is an unused block, release it */ + if (i == FINSH_VARIABLE_MAX) + { + finsh_heap_free(finsh_block_get_data(temp)); + } + } +} + +/** + * insert a block to list + */ +void finsh_block_insert(struct finsh_block_header** list, struct finsh_block_header* header) +{ + struct finsh_block_header* node; + + if (*list == NULL) + { + *list = header; + return; + } + + /* find out insert point */ + node = *list; + + if (node > header) + { + /* insert node in the header of list */ + header->next = node; + *list = header; + + return; + } + else + { + for (node = *list; node; node = node->next) + { + if (node->next > header) break; + + if (node->next == NULL) break; + } + } + + /* insert node */ + if (node->next != NULL) header->next = node->next; + node->next = header; +} + +/** + * remove block from list + */ +void finsh_block_remove(struct finsh_block_header** list, struct finsh_block_header* header) +{ + struct finsh_block_header* node; + + node = *list; + if (node == header) + { + /* remove list header */ + *list = header->next; + header->next = NULL; + + return; + } + + for (node = *list; node != NULL; node = node->next) + { + if (node->next == header) + { + node->next = header->next; + break; + } + } +} + +/** + * split block + */ +void finsh_block_split(struct finsh_block_header* header, size_t size) +{ + struct finsh_block_header* next; + + /* + * split header into two node: + * header->next->... + */ + next = BLOCK_HEADER((u_char*)header + sizeof(struct finsh_block_header) + size); + next->length = header->length - sizeof(struct finsh_block_header) - size; + header->length = size; + next->next = header->next; + + header->next = next; +} + +void finsh_block_merge(struct finsh_block_header** list, struct finsh_block_header* header) +{ + struct finsh_block_header* prev_node; + struct finsh_block_header* next_node; + + next_node = header->next; + + if (*list == header) prev_node = NULL; + else + { + /* find out the previous header */ + for (prev_node = *list; prev_node; prev_node =prev_node->next) + { + if (prev_node->next == header) + break; + } + } + + /* try merge node */ + + /* merge to previous node */ + if (prev_node != NULL && + ((u_char*)prev_node + prev_node->length + sizeof(struct finsh_block_header) + == (u_char*)header)) + { + /* is it close to next node? */ + if ((next_node != NULL) && + ((u_char*)header + header->length + sizeof(struct finsh_block_header) + == (u_char*)next_node)) + { + /* merge three node */ + prev_node->length += header->length + next_node->length + + 2 * sizeof(struct finsh_block_header); + + prev_node->next = next_node->next; + } + else + { + prev_node->length += header->length + sizeof(struct finsh_block_header); + prev_node->next = header->next; + } + } + else /* merge to last node */ + if ( (next_node != NULL) && + ((u_char*)header + header->length + sizeof(struct finsh_block_header) + == (u_char*)next_node)) + { + header->length += next_node->length + sizeof(struct finsh_block_header); + header->next = next_node->next; + } +} diff --git a/finsh/finsh_heap.h b/finsh/finsh_heap.h new file mode 100644 index 0000000000..ac9df4f91a --- /dev/null +++ b/finsh/finsh_heap.h @@ -0,0 +1,10 @@ +#include <finsh.h> + +#ifndef __FINSH_HEAP_H__ +#define __FINSH_HEAP_H__ + +int finsh_heap_init(void); +void* finsh_heap_allocate(size_t size); +void finsh_heap_free(void*ptr); + +#endif diff --git a/finsh/finsh_init.c b/finsh/finsh_init.c new file mode 100644 index 0000000000..e0dce342d3 --- /dev/null +++ b/finsh/finsh_init.c @@ -0,0 +1,48 @@ +#include <finsh.h> + +#include "finsh_node.h" +#include "finsh_vm.h" +#include "finsh_parser.h" +#include "finsh_var.h" +#include "finsh_error.h" +#include "finsh_heap.h" + +int finsh_init(struct finsh_parser* parser) +{ + finsh_parser_init(parser); + + /* finsh init */ + finsh_node_init(); + finsh_var_init(); + finsh_error_init(); + finsh_heap_init(); + + return 0; +} + +long finsh_stack_bottom() +{ + return finsh_vm_stack[0].long_value; +} + +int finsh_flush(struct finsh_parser* parser) +{ + finsh_parser_init(parser); + + /* finsh init */ + finsh_node_init(); + finsh_error_init(); + + return 0; +} + +int finsh_reset(struct finsh_parser* parser) +{ + /* finsh init */ + finsh_node_init(); + finsh_var_init(); + finsh_error_init(); + finsh_heap_init(); + + return 0; +} diff --git a/finsh/finsh_node.c b/finsh/finsh_node.c new file mode 100644 index 0000000000..b5d7461adc --- /dev/null +++ b/finsh/finsh_node.c @@ -0,0 +1,174 @@ +#include <finsh.h> + +#include "finsh_node.h" +#include "finsh_error.h" +#include "finsh_var.h" +#include "finsh_heap.h" + +struct finsh_node global_node_table[FINSH_NODE_MAX]; + +int finsh_node_init() +{ + memset(global_node_table, 0, sizeof(global_node_table)); + + return 0; +} + +struct finsh_node* finsh_node_allocate(u_char type) +{ + int i; + + /* find an empty entry */ + for (i = 0; i < FINSH_NODE_MAX; i ++) + { + if (global_node_table[i].node_type == FINSH_NODE_UNKNOWN) break; + } + + if (i == FINSH_NODE_MAX) return NULL; + + /* fill type field */ + global_node_table[i].node_type = type; + + /* return this allocated node */ + return &global_node_table[i]; +} + +struct finsh_node* finsh_node_new_id(char* id) +{ + struct finsh_node* node; + void* symbol; + unsigned char type; + + symbol = NULL; + type = 0; + node = NULL; + + /* lookup variable firstly */ + symbol = (void*)finsh_var_lookup(id); + if (symbol == NULL) + { + /* then lookup system variable */ + symbol = (void*)finsh_sysvar_lookup(id); + if (symbol == NULL) + { + /* then lookup system call */ + symbol = (void*)finsh_syscall_lookup(id); + if (symbol != NULL) type = FINSH_IDTYPE_SYSCALL; + } + else type = FINSH_IDTYPE_SYSVAR; + } + else type = FINSH_IDTYPE_VAR; + + if (symbol != NULL) + { + /* allocate a new node */ + node = finsh_node_allocate(FINSH_NODE_ID); + + /* allocate node error */ + if (node == NULL) + { + finsh_error_set(FINSH_ERROR_MEMORY_FULL); + return NULL; + } + + /* fill node value according type */ + switch (type) + { + case FINSH_IDTYPE_VAR: + node->id.var = (struct finsh_var*)symbol; + break; + + case FINSH_IDTYPE_SYSVAR: + node->id.sysvar = (struct finsh_sysvar*)symbol; + break; + + case FINSH_IDTYPE_SYSCALL: + node->id.syscall = (struct finsh_syscall*)symbol; + break; + } + /* fill identifier type */ + node->idtype = type; + } + else finsh_error_set(FINSH_ERROR_UNKNOWN_SYMBOL); + + return node; +} + +struct finsh_node* finsh_node_new_char(char c) +{ + struct finsh_node* node; + + node = finsh_node_allocate(FINSH_NODE_VALUE_CHAR); + if (node == NULL) + { + finsh_error_set(FINSH_ERROR_MEMORY_FULL); + return NULL; + } + + node->value.char_value = c; + return node; +} + +struct finsh_node* finsh_node_new_int(int i) +{ + struct finsh_node* node; + + node = finsh_node_allocate(FINSH_NODE_VALUE_INT); + if (node == NULL) + { + finsh_error_set(FINSH_ERROR_MEMORY_FULL); + return NULL; + } + + node->value.int_value = i; + return node; +} + +struct finsh_node* finsh_node_new_long(long l) +{ + struct finsh_node* node; + + node = finsh_node_allocate(FINSH_NODE_VALUE_LONG); + if (node == NULL) + { + finsh_error_set(FINSH_ERROR_MEMORY_FULL); + return NULL; + } + + node->value.long_value = l; + return node; +} + +struct finsh_node* finsh_node_new_string(char* s) +{ + struct finsh_node* node; + + node = finsh_node_allocate(FINSH_NODE_VALUE_STRING); + if (node == NULL) + { + finsh_error_set(FINSH_ERROR_MEMORY_FULL); + return NULL; + } + + /* make string */ + node->value.ptr = finsh_heap_allocate(strlen(s) + 1); + strncpy(node->value.ptr, s, strlen(s)); + ((u_char*)node->value.ptr)[strlen(s)] = '\0'; + + return node; +} + +struct finsh_node* finsh_node_new_ptr(void* ptr) +{ + struct finsh_node* node; + + node = finsh_node_allocate(FINSH_NODE_VALUE_NULL); + if (node == NULL) + { + finsh_error_set(FINSH_ERROR_MEMORY_FULL); + return NULL; + } + + node->value.ptr = ptr; + return node; +} diff --git a/finsh/finsh_node.h b/finsh/finsh_node.h new file mode 100644 index 0000000000..c26fdea8de --- /dev/null +++ b/finsh/finsh_node.h @@ -0,0 +1,60 @@ +#ifndef __FINSH_NODE_H__ +#define __FINSH_NODE_H__ + +#include <finsh.h> + +#define FINSH_NODE_UNKNOWN 0 +#define FINSH_NODE_ID 1 + +#define FINSH_NODE_VALUE_CHAR 2 +#define FINSH_NODE_VALUE_INT 3 +#define FINSH_NODE_VALUE_LONG 4 +#define FINSH_NODE_VALUE_STRING 5 +#define FINSH_NODE_VALUE_NULL 6 + +#define FINSH_NODE_SYS_ADD 7 +#define FINSH_NODE_SYS_SUB 8 +#define FINSH_NODE_SYS_MUL 9 +#define FINSH_NODE_SYS_DIV 10 +#define FINSH_NODE_SYS_MOD 11 +#define FINSH_NODE_SYS_AND 12 +#define FINSH_NODE_SYS_OR 13 +#define FINSH_NODE_SYS_XOR 14 +#define FINSH_NODE_SYS_BITWISE 15 +#define FINSH_NODE_SYS_SHL 16 +#define FINSH_NODE_SYS_SHR 17 +#define FINSH_NODE_SYS_FUNC 18 +#define FINSH_NODE_SYS_ASSIGN 19 +#define FINSH_NODE_SYS_CAST 20 +#define FINSH_NODE_SYS_PREINC 21 +#define FINSH_NODE_SYS_PREDEC 22 +#define FINSH_NODE_SYS_INC 23 +#define FINSH_NODE_SYS_DEC 24 +#define FINSH_NODE_SYS_GETVALUE 25 +#define FINSH_NODE_SYS_GETADDR 26 +#define FINSH_NODE_SYS_NULL 27 + +#define FINSH_DATA_TYPE_VOID 0x00 +#define FINSH_DATA_TYPE_BYTE 0x01 +#define FINSH_DATA_TYPE_WORD 0x02 +#define FINSH_DATA_TYPE_DWORD 0x03 +#define FINSH_DATA_TYPE_PTR 0x10 + +#define FINSH_NODE_VALUE 0 +#define FINSH_NODE_ADDRESS 1 +#define FINSH_NODE_FUNCTION 2 + +int finsh_node_init(void); + +struct finsh_node* finsh_node_allocate(u_char type); +struct finsh_node* finsh_node_new_id(char* id); +struct finsh_node* finsh_node_new_char(char c); +struct finsh_node* finsh_node_new_int(int i); +struct finsh_node* finsh_node_new_long(long l); +struct finsh_node* finsh_node_new_string(char* s); +struct finsh_node* finsh_node_new_ptr(void* ptr); + +#define finsh_node_sibling(node) ((node)->sibling) +#define finsh_node_child(node) ((node)->child) + +#endif diff --git a/finsh/finsh_ops.c b/finsh/finsh_ops.c new file mode 100644 index 0000000000..d201397083 --- /dev/null +++ b/finsh/finsh_ops.c @@ -0,0 +1,594 @@ +#include "finsh_ops.h" +#include "finsh_vm.h" + +#define OP_BIN_BYTE(x) do {\ + (finsh_sp - 2)->char_value = (finsh_sp - 2)->char_value x (finsh_sp - 1)->char_value; \ + finsh_sp--; \ + }while (0) + +#define OP_BIN_WORD(x) do {\ + (finsh_sp - 2)->short_value = (finsh_sp - 2)->short_value x (finsh_sp - 1)->short_value; \ + finsh_sp--; \ + }while (0) + +#define OP_BIN_DWORD(x) do {\ + (finsh_sp - 2)->long_value = (finsh_sp - 2)->long_value x (finsh_sp - 1)->long_value; \ + finsh_sp--; \ + }while (0) + +/* --- noop --- */ +void OP_no_op() +{ + /* none */ + return ; +} + +/* --- add --- */ +void OP_add_byte() +{ + OP_BIN_BYTE(+); + + return ; +} + +void OP_add_word() +{ + OP_BIN_WORD(+); + + return ; +} + +void OP_add_dword() +{ + OP_BIN_DWORD(+); + + return ; +} + +/* --- sub --- */ +void OP_sub_byte() +{ + OP_BIN_BYTE(-); + + return ; +} + +void OP_sub_word() +{ + OP_BIN_WORD(-); + + return ; +} + +void OP_sub_dword() +{ + OP_BIN_DWORD(-); + + return ; +} + +/* --- div --- */ +void OP_div_byte() +{ + OP_BIN_BYTE(/); + + return ; +} + +void OP_div_word() +{ + OP_BIN_WORD(/); + + return ; +} + +void OP_div_dword() +{ + OP_BIN_DWORD(/); + + return ; +} + +/* --- mod --- */ +void OP_mod_byte() +{ + OP_BIN_BYTE(%); + + return ; +} + +void OP_mod_word() +{ + OP_BIN_WORD(%); + + return ; +} + +void OP_mod_dword() +{ + OP_BIN_DWORD(%); + + return ; +} + +/* --- mul --- */ +void OP_mul_byte() +{ + OP_BIN_BYTE(*); + + return ; +} + +void OP_mul_word() +{ + OP_BIN_WORD(*); + + return ; +} + +void OP_mul_dword() +{ + OP_BIN_DWORD(*); + + return ; +} + +/* --- and --- */ +void OP_and_byte() +{ + OP_BIN_BYTE(&); + + return ; +} + +void OP_and_word() +{ + OP_BIN_WORD(&); + + return ; +} + +void OP_and_dword() +{ + OP_BIN_DWORD(&); + + return ; +} + +/* --- or --- */ +void OP_or_byte() +{ + OP_BIN_BYTE(|); + + return ; +} + +void OP_or_word() +{ + OP_BIN_WORD(|); + + return ; +} + +void OP_or_dword() +{ + OP_BIN_DWORD(|); + + return ; +} + +/* --- xor --- */ +void OP_xor_byte() +{ + OP_BIN_BYTE(^); + + return ; +} + +void OP_xor_word() +{ + OP_BIN_WORD(^); + + return ; +} + +void OP_xor_dword() +{ + OP_BIN_DWORD(^); + + return ; +} + +/* --- bw --- */ +void OP_bw_byte() +{ + (finsh_sp - 1)->char_value = ~ ((finsh_sp - 1)->char_value); + + return ; +} + +void OP_bw_word() +{ + (finsh_sp - 1)->short_value = ~ ((finsh_sp - 1)->short_value); + + return ; +} + +void OP_bw_dword() +{ + (finsh_sp - 1)->long_value = ~ ((finsh_sp - 1)->long_value); + + return ; +} + +/* --- shl --- */ +void OP_shl_byte() +{ + OP_BIN_BYTE(<<); + + return ; +} + +void OP_shl_word() +{ + OP_BIN_WORD(<<); + + return ; +} + +void OP_shl_dword() +{ + OP_BIN_DWORD(<<); + + return ; +} + +/* --- shr --- */ +void OP_shr_byte() +{ + OP_BIN_BYTE(>>); + + return ; +} + +void OP_shr_word() +{ + OP_BIN_WORD(>>); + + return ; +} + +void OP_shr_dword() +{ + OP_BIN_DWORD(>>); + + return ; +} + +/* --- ld --- */ +void OP_ld_byte() +{ + finsh_sp->char_value = *finsh_pc; + + finsh_sp++; + finsh_pc++; + + return ; +} + +void OP_ld_word() +{ + finsh_sp->short_value = FINSH_GET16(finsh_pc); + + finsh_sp ++; + finsh_pc += 2; + + return ; +} + +void OP_ld_dword() +{ + finsh_sp->long_value = FINSH_GET32(finsh_pc); + + finsh_sp ++; + finsh_pc += 4; + + return ; +} + +void OP_ld_value_byte() +{ + char* c; + + c = (char*) (FINSH_GET32(finsh_pc)); + + finsh_sp->char_value = *c; + + finsh_sp ++; + finsh_pc += 4; + + return; +} + +void OP_ld_value_byte_stack() +{ + char* c; + + c = (char *)(finsh_sp - 1)->long_value; + (finsh_sp - 1)->char_value = *c; + + return; +} + +void OP_ld_value_word() +{ + short* s; + + s = (short*) (FINSH_GET32(finsh_pc)); + + finsh_sp->short_value = *s; + + finsh_sp ++; + finsh_pc += 4; + + return; +} + +void OP_ld_value_word_stack() +{ + short* s; + + s = (short *)(finsh_sp - 1)->long_value; + (finsh_sp - 1)->short_value = *s; + + return; +} + +void OP_ld_value_dword() +{ + long* l; + + l = (long*) (FINSH_GET32(finsh_pc)); + + finsh_sp->long_value = *l; + + finsh_sp ++; + finsh_pc += 4; + + return; +} + +void OP_ld_value_dword_stack() +{ + long* l; + + l = (long *)(finsh_sp - 1)->long_value; + (finsh_sp - 1)->long_value = *l; + + return; +} + +/* --- st --- */ +/* + * 2006-4-16 bernard + * fixed the sp move bug + */ +void OP_st_byte() +{ + *(char*)((finsh_sp - 2)->long_value) = (finsh_sp - 1)->char_value; + finsh_sp --; + + return ; +} + +/* + * 2006-4-16 bernard + * fixed the sp move bug + */ +void OP_st_word() +{ + *(short*)((finsh_sp - 2)->long_value) = (finsh_sp - 1)->short_value; + finsh_sp --; + + return ; +} + +/* + * 2006-4-16 bernard + * fixed the sp move bug + */ +void OP_st_dword() +{ + *(long*)((finsh_sp - 2)->long_value) = (finsh_sp - 1)->long_value; + finsh_sp --; + + return ; +} + +/* --- pop --- */ +void OP_pop() +{ + finsh_sp --; + return ; +} + +/* --- call --- */ +void OP_call() +{ + /* the max number of arg*/ + unsigned long parameterv[16]; + unsigned int parameters, i; + + typedef unsigned long var_t; + typedef var_t (*op_func)(); + op_func f; + var_t r; + + parameters = *finsh_pc ++; + + i = 0; finsh_sp --; + while (i < parameters) + { + parameterv[parameters - 1 - i] = finsh_sp->long_value; + finsh_sp --; + i++; + } + + f = (op_func)(finsh_sp->long_value); + switch (parameters) + { + case 0: + r = f(); + break; + + case 1: + r = f(parameterv[0]); + break; + + case 2: + r = f(parameterv[0], parameterv[1]); + break; + + case 3: + r = f(parameterv[0], parameterv[1], parameterv[2]); + break; + + case 4: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3]); + break; + + case 5: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4]); + break; + + case 6: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5]); + break; + + case 7: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6]); + break; + + case 8: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7]); + break; + + case 9: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8]); + break; + + case 10: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8], parameterv[9]); + break; + + case 11: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8], parameterv[9], parameterv[10]); + break; + + case 12: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8], parameterv[9], parameterv[10], parameterv[11]); + break; + + case 13: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8], parameterv[9], parameterv[10], parameterv[11], + parameterv[12]); + break; + + case 14: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8], parameterv[9], parameterv[10], parameterv[11], + parameterv[12], parameterv[13]); + break; + + case 15: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8], parameterv[9], parameterv[10], parameterv[11], + parameterv[12], parameterv[13], parameterv[14]); + break; + + case 16: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8], parameterv[9], parameterv[10], parameterv[11], + parameterv[12], parameterv[13], parameterv[14], parameterv[15]); + break; + + default: + r = 0; + break; + } + + finsh_sp->long_value = r; + finsh_sp ++; + + return ; +} + +op_func op_table[] = +{ + /* 00 */ OP_no_op, + /* 01 */ OP_add_byte, + /* 02 */ OP_add_word, + /* 03 */ OP_add_dword, + /* 04 */ OP_sub_byte, + /* 05 */ OP_sub_word, + /* 06 */ OP_sub_dword, + /* 07 */ OP_div_byte, + /* 08 */ OP_div_word, + /* 09 */ OP_div_dword, + /* 10 */ OP_mod_byte, + /* 11 */ OP_mod_word, + /* 12 */ OP_mod_dword, + /* 13 */ OP_mul_byte, + /* 14 */ OP_mul_word, + /* 15 */ OP_mul_dword, + /* 16 */ OP_and_byte, + /* 17 */ OP_and_word, + /* 18 */ OP_and_dword, + /* 19 */ OP_or_byte, + /* 20 */ OP_or_word, + /* 21 */ OP_or_dword, + /* 22 */ OP_xor_byte, + /* 23 */ OP_xor_word, + /* 24 */ OP_xor_dword, + /* 25 */ OP_bw_byte, + /* 26 */ OP_bw_word, + /* 27 */ OP_bw_dword, + /* 28 */ OP_shl_byte, + /* 29 */ OP_shl_word, + /* 30 */ OP_shl_dword, + /* 31 */ OP_shr_byte, + /* 32 */ OP_shr_word, + /* 33 */ OP_shr_dword, + /* 34 */ OP_ld_byte, + /* 35 */ OP_ld_word, + /* 36 */ OP_ld_dword, + /* 37 */ OP_ld_value_byte, + /* 38 */ OP_ld_value_word, + /* 39 */ OP_ld_value_dword, + /* 40 */ OP_st_byte, + /* 41 */ OP_st_word, + /* 42 */ OP_st_dword, + /* 43 */ OP_pop, + /* 44 */ OP_call, + /* 45 */ OP_ld_value_byte_stack, + /* 46 */ OP_ld_value_word_stack, + /* 47 */ OP_ld_value_dword_stack, + NULL +}; diff --git a/finsh/finsh_ops.h b/finsh/finsh_ops.h new file mode 100644 index 0000000000..1db5869518 --- /dev/null +++ b/finsh/finsh_ops.h @@ -0,0 +1,107 @@ +#ifndef __FINSH_OP_H__ +#define __FINSH_OP_H__ + +#include "finsh_vm.h" + +/* + * FinC VM specification + * Memory + * .VAR + * + * .STACK + * + * .HEAP + * + * .TEXT + * OP [op1] + */ + +#define FINSH_OP_NOOP 0x00 + +/* add @ r1 = r2 + r3 */ +#define FINSH_OP_ADD_BYTE 0x01 +#define FINSH_OP_ADD_WORD 0x02 +#define FINSH_OP_ADD_DWORD 0x03 + +/* sub @ r1 = r2 - r3 */ +#define FINSH_OP_SUB_BYTE 0x04 +#define FINSH_OP_SUB_WORD 0x05 +#define FINSH_OP_SUB_DWORD 0x06 + +/* div @ r1 = r2 / r3 */ +#define FINSH_OP_DIV_BYTE 0x07 +#define FINSH_OP_DIV_WORD 0x08 +#define FINSH_OP_DIV_DWORD 0x09 + +/* mod @ r1 = r2 % r3 */ +#define FINSH_OP_MOD_BYTE 0x0A +#define FINSH_OP_MOD_WORD 0x0B +#define FINSH_OP_MOD_DWORD 0x0C + +/* mul @ r1 = r2 * r3 */ +#define FINSH_OP_MUL_BYTE 0x0D +#define FINSH_OP_MUL_WORD 0x0E +#define FINSH_OP_MUL_DWORD 0x0F + +/* and @ r1 = r2 & r3 */ +#define FINSH_OP_AND_BYTE 0x10 +#define FINSH_OP_AND_WORD 0x11 +#define FINSH_OP_AND_DWORD 0x12 + +/* or @ r1 = r2 | r3 */ +#define FINSH_OP_OR_BYTE 0x13 +#define FINSH_OP_OR_WORD 0x14 +#define FINSH_OP_OR_DWORD 0x15 + +/* xor @ r1 = r2 ^ r3 */ +#define FINSH_OP_XOR_BYTE 0x16 +#define FINSH_OP_XOR_WORD 0x17 +#define FINSH_OP_XOR_DWORD 0x18 + +/* bw @ r1 = ~r2 */ +#define FINSH_OP_BITWISE_BYTE 0x19 +#define FINSH_OP_BITWISE_WORD 0x1A +#define FINSH_OP_BITWISE_DWORD 0x1B + +/* shl @ r1 = r2 << r3 */ +#define FINSH_OP_SHL_BYTE 0x1C +#define FINSH_OP_SHL_WORD 0x1D +#define FINSH_OP_SHL_DWORD 0x1E + +/* shr @ r1 = r2 >> r3 */ +#define FINSH_OP_SHR_BYTE 0x1F +#define FINSH_OP_SHR_WORD 0x20 +#define FINSH_OP_SHR_DWORD 0x21 + +/* ld @ r1 = [r2] */ +#define FINSH_OP_LD_BYTE 0x22 +#define FINSH_OP_LD_WORD 0x23 +#define FINSH_OP_LD_DWORD 0x24 + +#define FINSH_OP_LD_VALUE_BYTE 0x25 +#define FINSH_OP_LD_VALUE_WORD 0x26 +#define FINSH_OP_LD_VALUE_DWORD 0x27 + +/* st @ [r2] = r1 */ +#define FINSH_OP_ST_BYTE 0x28 +#define FINSH_OP_ST_WORD 0x29 +#define FINSH_OP_ST_DWORD 0x2A + +/* pop */ +#define FINSH_OP_POP 0x2B + +/* call r1 @ [r1](stack) */ +#define FINSH_OP_SYSCALL 0x2C + +/* load value from stack */ +#define FINSH_OP_LD_VALUE_BYTE_STACK 0x2D +#define FINSH_OP_LD_VALUE_WORD_STACK 0x2E +#define FINSH_OP_LD_VALUE_DWORD_STACK 0x2F + +/* halt */ +#define FINSH_OP_HALT 0xFF + +typedef void (*op_func)(); +extern op_func op_table[]; + +#endif diff --git a/finsh/finsh_parser.c b/finsh/finsh_parser.c new file mode 100644 index 0000000000..b308e6d8f5 --- /dev/null +++ b/finsh/finsh_parser.c @@ -0,0 +1,965 @@ +#include <finsh.h> + +#include "finsh_token.h" +#include "finsh_node.h" +#include "finsh_error.h" +#include "finsh_parser.h" +#include "finsh_var.h" + +/* + * the structure of abstract syntax tree: + * root____________ + * | \ + * child__ sibling__ + * | \ | \ + * child sibling child sibling + * ... + */ +static enum finsh_type proc_type(struct finsh_parser* self); +static int proc_identifier(struct finsh_parser* self, char* id); +static struct finsh_node* proc_variable_decl(struct finsh_parser* self); +static struct finsh_node* proc_expr(struct finsh_parser* self); +static struct finsh_node* proc_assign_expr(struct finsh_parser* self); +static struct finsh_node* proc_inclusive_or_expr(struct finsh_parser* self); +static struct finsh_node* proc_exclusive_or_expr(struct finsh_parser* self); +static struct finsh_node* proc_and_expr(struct finsh_parser* self); +static struct finsh_node* proc_shift_expr(struct finsh_parser* self); +static struct finsh_node* proc_additive_expr(struct finsh_parser* self); +static struct finsh_node* proc_multiplicative_expr(struct finsh_parser* self); +static struct finsh_node* proc_cast_expr(struct finsh_parser* self); +static struct finsh_node* proc_unary_expr(struct finsh_parser* self); +static struct finsh_node* proc_postfix_expr(struct finsh_parser* self); +static struct finsh_node* proc_primary_expr(struct finsh_parser* self); +static struct finsh_node* proc_param_list(struct finsh_parser* self); +static struct finsh_node* proc_expr_statement(struct finsh_parser* self); +static struct finsh_node* make_sys_node(u_char type, struct finsh_node* node1, + struct finsh_node* node2); + +/* check token */ +#define check_token(token, lex, type) if ( (token) != (type) ) \ + { \ + finsh_error_set(FINSH_ERROR_INVALID_TOKEN); \ + finsh_token_replay(lex); \ + } + +/* is the token a data type? */ +#define is_base_type(token) ((token) == finsh_token_type_void \ + || (token) == finsh_token_type_char \ + || (token) == finsh_token_type_short \ + || (token) == finsh_token_type_int \ + || (token) == finsh_token_type_long) + +/* get the next token */ +#define next_token(token, lex) (token) = finsh_token_token(lex) + +/* match a specified token */ +#define match_token(token, lex, type) next_token(token, lex); \ + check_token(token, lex, type) + +/* +process for function and variable declaration. +decl_variable -> type declaration_list ';' +declarator_list -> declarator_list ',' declarator + | declarator +declarator -> identifier + | identifier ASSIGN expr_assign +*/ +static struct finsh_node* proc_variable_decl(struct finsh_parser* self) +{ + enum finsh_token_type token; + enum finsh_type type; + char id[FINSH_NAME_MAX + 1]; + + struct finsh_node *node; + struct finsh_node *end; + struct finsh_node *assign; + + node = NULL; + end = NULL; + + /* get type */ + type = proc_type(self); + + /*process id.*/ + if (proc_identifier(self, id) == 0) + { + /* if add variable failed */ + if (finsh_var_insert(id, type) < 0) + { + finsh_error_set(FINSH_ERROR_VARIABLE_EXIST); + } + } + + next_token(token, &(self->token)); + switch ( token ) + { + case finsh_token_type_comma:/*',', it's a variable_list declaration.*/ + if (proc_identifier(self, id) == 0) + { + /* if add variable failed */ + if (finsh_var_insert(id, type) < 0) + { + finsh_error_set(FINSH_ERROR_VARIABLE_EXIST); + } + } + + next_token(token, &(self->token)); + if ( token == finsh_token_type_assign ) + { + /* get the right side of assign expression */ + assign = proc_assign_expr(self); + + if (assign != NULL) + { + struct finsh_node* idnode; + + idnode = finsh_node_new_id(id); + end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign); + node = end; + + next_token(token, &(self->token)); + } + } + + while ( token == finsh_token_type_comma ) + { + if (proc_identifier(self, id) == 0) + { + /* if add variable failed */ + if (finsh_var_insert(id, type) < 0) + { + finsh_error_set(FINSH_ERROR_VARIABLE_EXIST); + } + } + + next_token(token, &(self->token)); + if ( token == finsh_token_type_assign ) + { + /* get the right side of assign expression */ + assign = proc_assign_expr(self); + + if (assign != NULL) + { + struct finsh_node* idnode; + + idnode = finsh_node_new_id(id); + + /* make assign expression node */ + if (node != NULL) + { + finsh_node_sibling(end) = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign); + end = finsh_node_sibling(end); + } + else + { + end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign); + node = end; + } + + next_token(token, &(self->token)); + } + } + } + + check_token(token, &(self->token), finsh_token_type_semicolon); + return node; + + case finsh_token_type_assign:/*'=', it's a variable with assign declaration.*/ + { + struct finsh_node *idnode; + + assign = proc_assign_expr(self); + if (assign != NULL) + { + idnode = finsh_node_new_id(id); + + /* make assign expression node */ + end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign); + node = end; + + next_token(token, &(self->token)); + } + + while ( token == finsh_token_type_comma ) + { + if (proc_identifier(self, id) == 0) + { + /* if add variable failed */ + if (finsh_var_insert(id, type) < 0) + { + finsh_error_set(FINSH_ERROR_VARIABLE_EXIST); + } + } + + next_token(token, &(self->token)); + if (token == finsh_token_type_assign) + { + /* get the right side of assign expression */ + assign = proc_assign_expr(self); + + if (assign != NULL) + { + idnode = finsh_node_new_id(id); + + /* make assign expression node */ + if (node != NULL) + { + finsh_node_sibling(end) = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign); + end = finsh_node_sibling(end); + } + else + { + end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign); + node = end; + } + + next_token(token, &(self->token)); + } + } + } + + check_token(token, &(self->token), finsh_token_type_semicolon); + return node; + } + + case finsh_token_type_semicolon:/*';', it's a variable declaration.*/ + return node; + + default: + finsh_error_set(FINSH_ERROR_EXPECT_TYPE); + + return NULL; + } +} + +/* +type -> type_prefix type_basic | type_basic +type_prefix -> UNSIGNED +type_basic -> VOID + | CHAR + | SHORT + | INT + | STRING +*/ +static enum finsh_type proc_type(struct finsh_parser* self) +{ + enum finsh_type type; + enum finsh_token_type token; + + /* set init type */ + type = finsh_type_unknown; + + next_token(token, &(self->token)); + if ( is_base_type(token) ) /* base_type */ + { + switch (token) + { + case finsh_token_type_void: + type = finsh_type_void; + break; + + case finsh_token_type_char: + type = finsh_type_char; + break; + + case finsh_token_type_short: + type = finsh_type_short; + break; + + case finsh_token_type_int: + type = finsh_type_int; + break; + + case finsh_token_type_long: + type = finsh_type_long; + break; + + default: + goto __return; + } + } + else if ( token == finsh_token_type_unsigned ) /* unsigned base_type */ + { + next_token(token, &(self->token)); + if ( is_base_type(token) ) + { + switch (token) + { + case finsh_token_type_char: + type = finsh_type_uchar; + break; + + case finsh_token_type_short: + type = finsh_type_ushort; + break; + + case finsh_token_type_int: + type = finsh_type_uint; + break; + + case finsh_token_type_long: + type = finsh_type_ulong; + break; + + default: + goto __return; + } + } + else + { + finsh_token_replay(&(self->token)); + finsh_error_set(FINSH_ERROR_EXPECT_TYPE); + } + } + else + { + goto __return; + } + + /* parse for pointer */ + next_token(token, &(self->token)); + if (token == finsh_token_type_mul) + { + switch (type) + { + case finsh_type_void: + type = finsh_type_voidp; + break; + + case finsh_type_char: + case finsh_type_uchar: + type = finsh_type_charp; + break; + + case finsh_type_short: + case finsh_type_ushort: + type = finsh_type_shortp; + break; + + case finsh_type_int: + case finsh_type_uint: + type = finsh_type_intp; + break; + + case finsh_type_long: + case finsh_type_ulong: + type = finsh_type_longp; + break; + + default: + type = finsh_type_voidp; + break; + } + } + else finsh_token_replay(&(self->token)); + + return type; + +__return: + finsh_token_replay(&(self->token)); + finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE); + + return type; +} + +/* +identifier -> IDENTIFIER +*/ +static int proc_identifier(struct finsh_parser* self, char* id) +{ + enum finsh_token_type token; + + match_token(token, &(self->token), finsh_token_type_identifier); + + strncpy(id, (char*)self->token.string, FINSH_NAME_MAX); + + return 0; +} + +/* +statement_expr -> ';' + | expr ';' +*/ +static struct finsh_node* proc_expr_statement(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* expr; + + expr = NULL; + next_token(token, &(self->token)); + if ( token != finsh_token_type_semicolon ) + { + finsh_token_replay(&(self->token)); + expr = proc_expr(self); + + match_token(token, &(self->token), finsh_token_type_semicolon); + } + + return expr; +} + +/* +expr -> expr_assign +*/ +static struct finsh_node* proc_expr(struct finsh_parser* self) +{ + return proc_assign_expr(self); +} + +/* +expr_assign -> expr_inclusive_or + | expr_unary ASSIGN expr_assign +*/ +static struct finsh_node* proc_assign_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* or; + struct finsh_node* assign; + + or = proc_inclusive_or_expr(self); + + next_token(token, &(self->token)); + + if (token == finsh_token_type_assign) + { + assign = proc_assign_expr(self); + + return make_sys_node(FINSH_NODE_SYS_ASSIGN, or, assign); + } + else finsh_token_replay(&(self->token)); + + return or; +} + +/* +expr_inclusive_or -> expr_exclusive_or + | expr_inclusive_or '|' expr_exclusive_or +*/ +static struct finsh_node* proc_inclusive_or_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* xor; + struct finsh_node* xor_new; + + xor = proc_exclusive_or_expr(self); + + next_token(token, &(self->token)); + while ( token == finsh_token_type_or ) + { + xor_new = proc_exclusive_or_expr(self); + + if (xor_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + else xor = make_sys_node(FINSH_NODE_SYS_OR, xor, xor_new); + + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + return xor; +} + +/* +expr_exclusive_or -> expr_and + | expr_exclusive '^' expr_and +*/ +static struct finsh_node* proc_exclusive_or_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* and; + struct finsh_node* and_new; + + and = proc_and_expr(self); + next_token(token, &(self->token)); + while ( token == finsh_token_type_xor ) + { + and_new = proc_and_expr(self); + if (and_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + else and = make_sys_node(FINSH_NODE_SYS_XOR, and, and_new); + + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + return and; +} + +/* +expr_and -> expr_shift + | expr_and '&' expr_shift +*/ +static struct finsh_node* proc_and_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* shift; + struct finsh_node* shift_new; + + shift = proc_shift_expr(self); + + next_token(token, &(self->token)); + while ( token == finsh_token_type_and ) + { + shift_new = proc_shift_expr(self); + + if (shift_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + else shift = make_sys_node(FINSH_NODE_SYS_AND, shift, shift_new); + + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + return shift; +} + +/* +expr_shift -> expr_additive + | expr_shift '<<' expr_additive + | expr_shift '>>' expr_additive +*/ +static struct finsh_node* proc_shift_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* add; + struct finsh_node* add_new; + + add = proc_additive_expr(self); + + next_token(token, &(self->token)); + while ( token == finsh_token_type_shl || token == finsh_token_type_shr) + { + add_new = proc_additive_expr(self); + if (add_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + else + { + switch (token) + { + case finsh_token_type_shl: + add = make_sys_node(FINSH_NODE_SYS_SHL, add, add_new); + break; + case finsh_token_type_shr: + add = make_sys_node(FINSH_NODE_SYS_SHR, add, add_new); + break; + default: + finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + break; + } + } + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + return add; +} + +/* +expr_additive -> expr_multiplicative + | expr_additive SUB expr_multiplicative + | expr_additive ADD expr_multiplicative +*/ +static struct finsh_node* proc_additive_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* mul; + struct finsh_node* mul_new; + + mul = proc_multiplicative_expr(self); + + next_token(token, &(self->token)); + while ( token == finsh_token_type_sub || token == finsh_token_type_add ) + { + mul_new = proc_multiplicative_expr(self); + if (mul_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + else + { + switch (token) + { + case finsh_token_type_sub: + mul = make_sys_node(FINSH_NODE_SYS_SUB, mul, mul_new); + break; + case finsh_token_type_add: + mul = make_sys_node(FINSH_NODE_SYS_ADD, mul, mul_new); + break; + default: + finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + break; + } + } + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + return mul; +} + +/* +expr_multiplicative -> expr_cast + | expr_multiplicative '*' expr_cast + | expr_multiplicative '/' expr_cast + | expr_multiplicative '%' expr_cast +*/ +static struct finsh_node* proc_multiplicative_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* cast; + struct finsh_node* cast_new; + + cast = proc_cast_expr(self); + next_token(token, &(self->token)); + while (token == finsh_token_type_mul || + token == finsh_token_type_div || + token == finsh_token_type_mod ) + { + cast_new = proc_cast_expr(self); + if (cast_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + else + { + switch (token) + { + case finsh_token_type_mul: + cast = make_sys_node(FINSH_NODE_SYS_MUL, cast, cast_new); + break; + + case finsh_token_type_div: + cast = make_sys_node(FINSH_NODE_SYS_DIV, cast, cast_new); + break; + + case finsh_token_type_mod: + cast = make_sys_node(FINSH_NODE_SYS_MOD, cast, cast_new); + break; + + default: + finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + break; + } + } + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + return cast; +} + +/* +20060313, add recast parse +expr_cast -> expr_unary + | '(' type ')' expr_cast +*/ +static struct finsh_node* proc_cast_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + enum finsh_type type; + struct finsh_node* cast; + + next_token(token, &(self->token)); + if (token == finsh_token_type_left_paren) + { + type = proc_type(self); + match_token(token, &(self->token), finsh_token_type_right_paren); + + cast = proc_cast_expr(self); + cast->data_type = type; + return cast; + } + + finsh_token_replay(&(self->token)); + return proc_unary_expr(self); +} + +/* +20050921, add '*' and '&' +expr_unary -> expr_postfix + | ADD expr_cast + | INC expr_cast + | SUB expr_cast + | DEC expr_cast + | '~' expr_cast + | '*' expr_cast + | '&' expr_cast +*/ +static struct finsh_node* proc_unary_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node *cast; + + next_token(token, &(self->token)); + switch (token) + { + case finsh_token_type_add: /* + */ + cast = proc_cast_expr(self); + return cast; + + case finsh_token_type_inc: /* ++ */ + cast = proc_cast_expr(self); + return make_sys_node(FINSH_NODE_SYS_PREINC, cast, NULL); + + case finsh_token_type_sub: /* - */ + cast = proc_cast_expr(self); + return make_sys_node(FINSH_NODE_SYS_SUB, finsh_node_new_long(0), cast); + + case finsh_token_type_dec: /* -- */ + cast = proc_cast_expr(self); + return make_sys_node(FINSH_NODE_SYS_PREDEC, cast, NULL); + + case finsh_token_type_bitwise: /* ~ */ + cast = proc_cast_expr(self); + return make_sys_node(FINSH_NODE_SYS_BITWISE, cast, NULL); + + case finsh_token_type_mul: /* * */ + cast = proc_cast_expr(self); + return make_sys_node(FINSH_NODE_SYS_GETVALUE, cast, NULL); + + case finsh_token_type_and: /* & */ + cast = proc_cast_expr(self); + return make_sys_node(FINSH_NODE_SYS_GETADDR, cast, NULL); + + default: + finsh_token_replay(&(self->token)); + return proc_postfix_expr(self); + } +} + +/* +expr_postfix -> expr_primary + | expr_postfix INC + | expr_postfix DEC + | expr_postfix '(' param_list ')' +*/ +static struct finsh_node* proc_postfix_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* postfix; + + postfix = proc_primary_expr(self); + + next_token(token, &(self->token)); + while ( token == finsh_token_type_inc || + token == finsh_token_type_dec || + token == finsh_token_type_left_paren ) + { + switch (token) + { + case finsh_token_type_inc :/* '++' */ + postfix = make_sys_node(FINSH_NODE_SYS_INC, postfix, NULL); + break; + + case finsh_token_type_dec :/* '--' */ + postfix = make_sys_node(FINSH_NODE_SYS_DEC, postfix, NULL); + break; + + case finsh_token_type_left_paren :/* '(' */ + { + struct finsh_node* param_list; + + param_list = NULL; + next_token(token, &(self->token)); + if (token != finsh_token_type_right_paren) + { + finsh_token_replay(&(self->token)); + param_list = proc_param_list(self); + + match_token(token, &(self->token), finsh_token_type_right_paren); + } + + postfix = make_sys_node(FINSH_NODE_SYS_FUNC, postfix, param_list); + } + break; + + default: + break; + } + + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + return postfix; +} + +/* +expr_primary -> literal + | '(' expr ')' + | identifier +*/ +static struct finsh_node* proc_primary_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* expr; + + next_token(token, &(self->token)); + switch ( token ) + { + case finsh_token_type_identifier: + { + char id[FINSH_NAME_MAX + 1]; + + finsh_token_replay(&(self->token)); + proc_identifier(self, id); + return finsh_node_new_id(id); + } + + case finsh_token_type_left_paren: + expr = proc_expr(self); + match_token(token, &(self->token), finsh_token_type_right_paren); + return expr; + + case finsh_token_type_value_int: + return finsh_node_new_int(self->token.value.int_value); + + case finsh_token_type_value_long: + return finsh_node_new_long(self->token.value.long_value); + + case finsh_token_type_value_char: + return finsh_node_new_char(self->token.value.char_value); + + case finsh_token_type_value_string: + return finsh_node_new_string((char*)self->token.string); + + case finsh_token_type_value_null: + return finsh_node_new_ptr(NULL); + + default: + finsh_error_set(FINSH_ERROR_INVALID_TOKEN); + break; + } + + return NULL; +} + +/* +param_list -> empty + | expr_assign + | param_list ',' expr_assign +*/ +static struct finsh_node* proc_param_list(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node *node, *assign; + + assign = proc_assign_expr(self); + node = assign; + + next_token(token, &(self->token)); + while (token == finsh_token_type_comma ) + { + finsh_node_sibling(assign) = proc_assign_expr(self); + + if (finsh_node_sibling(assign) != NULL) assign = finsh_node_sibling(assign); + else finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + + return node; +} + +/* +make a new node as following tree: +new_node +| +node1__ + \ + node2 +*/ +static struct finsh_node* make_sys_node(u_char type, struct finsh_node* node1, struct finsh_node* node2) +{ + struct finsh_node* node; + + node = finsh_node_allocate(type); + + finsh_node_child(node) = node1; + if (node1 != NULL) finsh_node_sibling(node1) = node2; + else finsh_error_set(FINSH_ERROR_NULL_NODE); + + return node; +} + +/* +start -> statement_expr | decl_variable +*/ +void finsh_parser_run(struct finsh_parser* self, const u_char* string) +{ + enum finsh_token_type token; + struct finsh_node *node; + + node = NULL; + + /* init parser */ + self->parser_string = (u_char*)string; + + /* init token */ + finsh_token_init(&(self->token), self->parser_string); + + /* get next token */ + next_token(token, &(self->token)); + while (token != finsh_token_type_eof && token != finsh_token_type_bad) + { + switch (token) + { + case finsh_token_type_identifier: + /* process expr_statement */ + finsh_token_replay(&(self->token)); + + if (self->root != NULL) + { + finsh_node_sibling(node) = proc_expr_statement(self); + if (finsh_node_sibling(node) != NULL) + node = finsh_node_sibling(node); + } + else + { + node = proc_expr_statement(self); + self->root = node; + } + break; + + default: + if (is_base_type(token) || token == finsh_token_type_unsigned) + { + /* variable decl */ + finsh_token_replay(&(self->token)); + + if (self->root != NULL) + { + finsh_node_sibling(node) = proc_variable_decl(self); + if (finsh_node_sibling(node) != NULL) + node = finsh_node_sibling(node); + } + else + { + node = proc_variable_decl(self); + self->root = node; + } + } + else + { + /* process expr_statement */ + finsh_token_replay(&(self->token)); + + if (self->root != NULL) + { + finsh_node_sibling(node) = proc_expr_statement(self); + if (finsh_node_sibling(node) != NULL) + node = finsh_node_sibling(node); + else next_token(token, &(self->token)); + } + else + { + node = proc_expr_statement(self); + self->root = node; + } + } + + break; + } + /* get next token */ + next_token(token, &(self->token)); + } +} + +int finsh_parser_init(struct finsh_parser* self) +{ + memset(self, 0, sizeof(struct finsh_parser)); + + return 0; +} diff --git a/finsh/finsh_parser.h b/finsh/finsh_parser.h new file mode 100644 index 0000000000..a8339062e7 --- /dev/null +++ b/finsh/finsh_parser.h @@ -0,0 +1,9 @@ +#ifndef __FINSH_PARSER_H__ +#define __FINSH_PARSER_H__ + +#include <finsh.h> + +int finsh_parser_init(struct finsh_parser* self); +void finsh_parser_run(struct finsh_parser* self, const u_char* string); + +#endif diff --git a/finsh/finsh_token.c b/finsh/finsh_token.c new file mode 100644 index 0000000000..7002ca27f4 --- /dev/null +++ b/finsh/finsh_token.c @@ -0,0 +1,562 @@ +#include <finsh.h> + +#include "finsh_token.h" +#include "finsh_error.h" + +#define is_digit(ch) ((ch) >= '0' && (ch) <= '9') +#define is_separator(ch) !(((ch) >= 'a' && (ch) <= 'z') \ + || ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= '0' && (ch) <= '9') || ((ch) == '_')) +#define is_eof(self) (self)->eof + +struct name_table +{ + char* name; + enum finsh_token_type type; +}; + +/* keyword */ +static struct name_table finsh_name_table[] = +{ + {"void", finsh_token_type_void}, + {"char", finsh_token_type_char}, + {"short", finsh_token_type_short}, + {"int", finsh_token_type_int}, + {"long", finsh_token_type_long}, + {"unsigned", finsh_token_type_unsigned}, + + {"NULL", finsh_token_type_value_null}, + {"null", finsh_token_type_value_null} +}; + +static char token_next_char(struct finsh_token* self); +static void token_prev_char(struct finsh_token* self); +static long token_spec_number(char* string, int length, int b); +static void token_run(struct finsh_token* self); +static int token_match_name(struct finsh_token* self, const char* str); +static void token_proc_number(struct finsh_token* self); +static u_char* token_proc_string(struct finsh_token* self); +static void token_trim_space(struct finsh_token* self); +static char token_proc_char(struct finsh_token* self); +static int token_proc_escape(struct finsh_token* self); + +void finsh_token_init(struct finsh_token* self, u_char* line) +{ + memset(self, 0, sizeof(struct finsh_token)); + + self->line = line; +} + +enum finsh_token_type finsh_token_token(struct finsh_token* self) +{ + if ( self->replay ) self->replay = 0; + else token_run(self); + + return (enum finsh_token_type)self->current_token; +} + +void finsh_token_get_token(struct finsh_token* self, u_char* token) +{ + strncpy((char*)token, (char*)self->string, FINSH_NAME_MAX); +} + +int token_get_string(struct finsh_token* self, u_char* str) +{ + unsigned char *p=str; + char ch; + + ch = token_next_char(self); + if (is_eof(self)) return -1; + + str[0] = '\0'; + + if ( is_digit(ch) )/*the first character of identifier is not a digit.*/ + { + token_prev_char(self); + return -1; + } + + while (!is_separator(ch) && !is_eof(self)) + { + *p++ = ch; + + ch = token_next_char(self); + } + self->eof = 0; + + token_prev_char(self); + *p = '\0'; + + return 0; +} + +/* +get next character. +*/ +static char token_next_char(struct finsh_token* self) +{ + if (self->eof) return '\0'; + + if (self->position == (int)strlen((char*)self->line) || self->line[self->position] =='\n') + { + self->eof = 1; + self->position = 0; + return '\0'; + } + + return self->line[self->position++]; +} + +static void token_prev_char(struct finsh_token* self) +{ + if ( self->eof ) return; + + if ( self->position == 0 ) return; + else self->position--; +} + +static void token_run(struct finsh_token* self) +{ + char ch; + + token_trim_space(self); /* first trim space and tab. */ + token_get_string(self, &(self->string[0])); + + if ( is_eof(self) ) /*if it is eof, break;*/ + { + self->current_token = finsh_token_type_eof; + return ; + } + + if (self->string[0] != '\0') /*It is a key word or a identifier.*/ + { + if ( !token_match_name(self, (char*)self->string) ) + { + self->current_token = finsh_token_type_identifier; + } + return; + } + else/*It is a operator character.*/ + { + ch = token_next_char(self); + + switch ( ch ) + { + case '(': + self->current_token = finsh_token_type_left_paren; + break; + + case ')': + self->current_token = finsh_token_type_right_paren; + break; + + case ',': + self->current_token = finsh_token_type_comma; + break; + + case ';': + self->current_token = finsh_token_type_semicolon; + break; + + case '&': + self->current_token = finsh_token_type_and; + break; + + case '*': + self->current_token = finsh_token_type_mul; + break; + + case '+': + ch = token_next_char(self); + + if ( ch == '+' ) + { + self->current_token = finsh_token_type_inc; + } + else + { + token_prev_char(self); + self->current_token = finsh_token_type_add; + } + break; + + case '-': + ch = token_next_char(self); + + if ( ch == '-' ) + { + self->current_token = finsh_token_type_dec; + } + else + { + token_prev_char(self); + self->current_token = finsh_token_type_sub; + } + break; + + case '/': + self->current_token = finsh_token_type_div; + break; + + case '<': + ch = token_next_char(self); + + if ( ch == '<' ) + { + self->current_token = finsh_token_type_shl; + } + else + { + token_prev_char(self); + self->current_token = finsh_token_type_bad; + } + break; + + case '>': + ch = token_next_char(self); + + if ( ch == '>' ) + { + self->current_token = finsh_token_type_shr; + } + else + { + token_prev_char(self); + self->current_token = finsh_token_type_bad; + } + break; + + case '|': + self->current_token = finsh_token_type_or; + break; + + case '%': + self->current_token = finsh_token_type_mod; + break; + + case '~': + self->current_token = finsh_token_type_bitwise; + break; + + case '^': + self->current_token = finsh_token_type_xor; + break; + + case '=': + self->current_token = finsh_token_type_assign; + break; + + case '\'': + self->value.char_value = token_proc_char(self); + self->current_token = finsh_token_type_value_char; + break; + + case '"': + token_proc_string(self); + self->current_token = finsh_token_type_value_string; + break; + + default: + if ( is_digit(ch) ) + { + token_prev_char(self); + token_proc_number(self); + break; + } + + finsh_error_set(FINSH_ERROR_UNKNOWN_TOKEN); + self->current_token = finsh_token_type_bad; + + break; + } + } +} + +static int token_match_name(struct finsh_token* self, const char* str) +{ + int i; + + for (i = 0; i < sizeof(finsh_name_table)/sizeof(struct name_table); i++) + { + if ( strcmp(finsh_name_table[i].name, str)==0 ) + { + self->current_token = finsh_name_table[i].type; + return 1; + } + } + + return 0; +} + +static void token_trim_space(struct finsh_token* self) +{ + char ch; + while ( (ch = token_next_char(self)) ==' ' || ch == '\t'); + + token_prev_char(self); +} + +static char token_proc_char(struct finsh_token* self) +{ + char ch; + char buf[4], *p; + + p = buf; + ch = token_next_char(self); + + if ( ch == '\\' ) + { + ch = token_next_char(self); + switch ( ch ) + { + case 'n': ch = '\n'; break; + case 't': ch = '\t'; break; + case 'v': ch = '\v'; break; + case 'b': ch = '\b'; break; + case 'r': ch = '\r'; break; + case '\\': ch = '\\'; break; + case '\'': ch = '\''; break; + default : + while ( is_digit(ch) )/*for '\113' char*/ + { + ch = token_next_char(self); + *p++ = ch; + } + + token_prev_char(self); + *p = '\0'; + ch = atoi(p); + break; + } + } + + if ( token_next_char(self) != '\'' ) + { + token_prev_char(self); + finsh_error_set(FINSH_ERROR_EXPECT_CHAR); + return ch; + } + + return ch; +} + +static u_char* token_proc_string(struct finsh_token* self) +{ + u_char* p; + + for ( p = &self->string[0]; p - &(self->string[0]) < FINSH_STRING_MAX; ) + { + char ch = token_next_char(self); + + if ( is_eof(self) ) + { + finsh_error_set(FINSH_ERROR_UNEXPECT_END); + return NULL;; + } + if ( ch == '\\' ) + { + ch = token_proc_escape(self); + } + else if ( ch == '"' )/*end of string.*/ + { + *p = '\0'; + return self->string; + } + + *p++ = ch; + } + + return NULL; +} + +static int token_proc_escape(struct finsh_token* self) +{ + char ch; + int result=0; + + ch = token_next_char(self); + switch (ch) + { + case 'n': + result = '\n'; + break; + case 't': + result = '\t'; + break; + case 'v': + result = '\v'; + break; + case 'b': + result = '\b'; + break; + case 'r': + result = '\r'; + break; + case 'f': + result = '\f'; + break; + case 'a': + result = '\007'; + break; + case 'x': + result = 0; + ch = token_next_char(self); + while ( (ch - '0')<16u ) + { + result = result*16 + ch - '0'; + ch = token_next_char(self); + } + token_prev_char(self); + break; + default: + if ( (ch - '0') < 8u) + { + result = 0; + while ( (ch - '0') < 8u ) + { + result = result*8 + ch - '0'; + ch = token_next_char(self); + } + + token_prev_char(self); + } + break; + } + + return result; +} + +/* +(0|0x|0X|0b|0B)number+(l|L) +*/ +static void token_proc_number(struct finsh_token* self) +{ + char ch; + int b; + char *p, buf[128]; + long value; + + value = 0; + p = buf; + b = 10; + + ch = token_next_char(self); + if ( ch == '0' ) + { + ch = token_next_char(self); + if ( ch == 'x' || ch == 'X' )/*it's a hex number*/ + { + b = 16; + ch = token_next_char(self); + while ( is_digit(ch) || isalpha(ch) ) + { + *p++ = ch; + ch = token_next_char(self); + } + + *p = '\0'; + } + else if ( ch == 'b' || ch == 'B' ) + { + b = 2; + ch = token_next_char(self); + while ( (ch=='0')||(ch=='1') ) + { + *p++ = ch; + ch = token_next_char(self); + } + + *p = '\0'; + } + else + { + b = 8; + while ( is_digit(ch) ) + { + *p++ = ch; + ch = token_next_char(self); + } + + *p = '\0'; + } + + self->value.int_value = token_spec_number(buf, strlen(buf), b); + self->current_token = finsh_token_type_value_int; + } + else + { + while ( is_digit(ch) ) + { + value = value*10 + ( ch - '0' ); + ch = token_next_char(self); + } + + self->value.int_value = value; + self->current_token = finsh_token_type_value_int; + } + + switch ( ch ) + { + case 'l': + case 'L': + self->current_token = finsh_token_type_value_long; + break; + + default: + token_prev_char(self); + break; + } +} + +/*use 64 bit number*/ +#define BN_SIZE 2 + +static long token_spec_number(char* string, int length, int b) +{ + char* p; + int t; + int i, j, shift=1; + unsigned int bn[BN_SIZE], v; + long d; + + p = string; + i = 0; + + switch ( b ) + { + case 16: shift = 4; + break; + case 8: shift = 3; + break; + case 2: shift = 1; + break; + default: break; + } + + for ( j=0; j<BN_SIZE ; j++) bn[j] = 0; + + while ( i<length ) + { + t = *p++; + if ( t>='a' && t <='f' ) + { + t = t - 'a' +10; + } + else if ( t >='A' && t <='F' ) + { + t = t - 'A' +10; + } + else t = t - '0'; + + for ( j=0; j<BN_SIZE ; j++) + { + v = bn[j]; + bn[j] = (v<<shift) | t; + t = v >> (32 - shift); + } + i++; + } + + d = (long)bn[0]; + + return d; +} diff --git a/finsh/finsh_token.h b/finsh/finsh_token.h new file mode 100644 index 0000000000..2224f003a1 --- /dev/null +++ b/finsh/finsh_token.h @@ -0,0 +1,53 @@ +#ifndef __FINSH_TOKEN_H__ +#define __FINSH_TOKEN_H__ + +#include <finsh.h> + +enum finsh_token_type +{ + finsh_token_type_left_paren = 1, /* ( */ + finsh_token_type_right_paren , /* ) */ + finsh_token_type_comma , /* , */ + finsh_token_type_semicolon , /* ; */ + finsh_token_type_mul , /* * */ + finsh_token_type_add , /* + */ + finsh_token_type_inc , /* ++ */ + finsh_token_type_sub , /* - */ + finsh_token_type_dec , /* -- */ + finsh_token_type_div , /* / */ + finsh_token_type_mod , /* % */ + finsh_token_type_assign , /* = */ + finsh_token_type_and, /* & */ + finsh_token_type_or, /* | */ + finsh_token_type_xor, /* ^ */ + finsh_token_type_bitwise, /* ~ */ + finsh_token_type_shl, /* << */ + finsh_token_type_shr, /* >> */ + /*-- data type --*/ + finsh_token_type_void, /* void */ + finsh_token_type_char, /* char */ + finsh_token_type_short, /* short */ + finsh_token_type_int, /* int */ + finsh_token_type_long, /* long */ + finsh_token_type_unsigned, /* unsigned */ + /* data value type */ + finsh_token_type_value_char, /* v:char */ + finsh_token_type_value_int, /* v:int */ + finsh_token_type_value_long, /* v:long */ + finsh_token_type_value_string, /* v:string */ + finsh_token_type_value_null, /* NULL */ + /*-- others --*/ + finsh_token_type_identifier, /* ID */ + finsh_token_type_bad, /* bad token */ + finsh_token_type_eof +}; + +#define finsh_token_position(self) (self)->position +#define finsh_token_replay(self) (self)->replay = 1 + +void finsh_token_init(struct finsh_token* self, u_char* script); + +enum finsh_token_type finsh_token_token(struct finsh_token* self); +void finsh_token_get_token(struct finsh_token* self, u_char* token); + +#endif diff --git a/finsh/finsh_var.c b/finsh/finsh_var.c new file mode 100644 index 0000000000..5b6d6ac3ea --- /dev/null +++ b/finsh/finsh_var.c @@ -0,0 +1,130 @@ +#include <finsh.h> +#include "finsh_var.h" + +struct finsh_var global_variable[FINSH_VARIABLE_MAX]; +struct finsh_sysvar_item* global_sysvar_list; + +int finsh_var_init() +{ + memset(global_variable, 0, sizeof(global_variable)); + + return 0; +} + +int finsh_var_insert(const char* name, int type) +{ + int i, empty; + + empty = -1; + for (i = 0; i < FINSH_VARIABLE_MAX; i ++) + { + /* there is a same name variable exist. */ + if (strncmp(global_variable[i].name, name, FINSH_NAME_MAX) == 0) + return -1; + + if (global_variable[i].type == finsh_type_unknown && empty == -1) + { + empty = i; + } + } + + /* there is no empty entry */ + if (empty == -1) return -1; + + /* insert entry */ + strncpy(global_variable[empty].name, name, FINSH_NAME_MAX); + global_variable[empty].type = type; + + /* return the offset */ + return empty; +} + +int finsh_var_delete(const char* name) +{ + int i; + + for (i = 0; i < FINSH_VARIABLE_MAX; i ++) + { + if (strncpy(global_variable[i].name, name, FINSH_NAME_MAX) == 0) + break; + } + + /* can't find variable */ + if (i == FINSH_VARIABLE_MAX) return -1; + + memset(&global_variable[i], 0, sizeof(struct finsh_var)); + + return 0; +} + +struct finsh_var* finsh_var_lookup(const char* name) +{ + int i; + + for (i = 0; i < FINSH_VARIABLE_MAX; i ++) + { + if (strncmp(global_variable[i].name, name, FINSH_NAME_MAX) == 0) + break; + } + + /* can't find variable */ + if (i == FINSH_VARIABLE_MAX) return NULL; + + return &global_variable[i]; +} + +#ifdef RT_USING_HEAP +extern char *strdup(const char *s); +void finsh_sysvar_append(const char* name, u_char type, void* var_addr) +{ + /* create a sysvar */ + struct finsh_sysvar_item* item; + + item = (struct finsh_sysvar_item*) rt_malloc (sizeof(struct finsh_sysvar_item)); + if (item != NULL) + { + item->next = NULL; + item->sysvar.name = strdup(name); + item->sysvar.type = type; + item->sysvar.var = var_addr; + + if (global_sysvar_list == NULL) + { + global_sysvar_list = item; + } + else + { + item->next = global_sysvar_list; + global_sysvar_list->next = item; + } + } +} +#endif + +struct finsh_sysvar* finsh_sysvar_lookup(const char* name) +{ + struct finsh_sysvar* index; + struct finsh_sysvar_item* item; + + for (index = _sysvar_table_begin; index < _sysvar_table_end; index ++) + { + if (strcmp(index->name, name) == 0) + return index; + } + + /* find in sysvar list */ + item = global_sysvar_list; + while (item != NULL) + { + if (strncmp(item->sysvar.name, name, strlen(name)) == 0) + { + return &(item->sysvar); + } + + /* move to next item */ + item = item->next; + } + + /* can't find variable */ + return NULL; +} diff --git a/finsh/finsh_var.h b/finsh/finsh_var.h new file mode 100644 index 0000000000..fa7df0ff1f --- /dev/null +++ b/finsh/finsh_var.h @@ -0,0 +1,32 @@ +#ifndef __FINSH_VAR_H__ +#define __FINSH_VAR_H__ + +#include <finsh.h> + +/* + * The variable in finsh is put in data segment as a global variable. + * The 'finsh_var' structure presents the structure of variable in data segment. + */ +struct finsh_var +{ + char name[FINSH_NAME_MAX + 1]; /* the name of variable */ + + u_char type; /* the type of variable */ + + /* variable value */ + union { + char char_value; + short short_value; + int int_value; + long long_value; + void* ptr; + }value; +}; +extern struct finsh_var global_variable[]; + +int finsh_var_init(void); +int finsh_var_insert(const char* name, int type); +int finsh_var_delete(const char* name); +struct finsh_var* finsh_var_lookup(const char* name); + +#endif diff --git a/finsh/finsh_vm.c b/finsh/finsh_vm.c new file mode 100644 index 0000000000..e51e4de022 --- /dev/null +++ b/finsh/finsh_vm.c @@ -0,0 +1,356 @@ +#include <finsh.h> + +#include "finsh_vm.h" +#include "finsh_ops.h" +#include "finsh_var.h" + +/* stack */ +union finsh_value finsh_vm_stack[FINSH_STACK_MAX]; +/* text segment */ +u_char text_segment[FINSH_TEXT_MAX]; + +union finsh_value* finsh_sp; /* stack pointer */ +u_char* finsh_pc; /* PC */ + +/* syscall list, for dynamic system call register */ +struct finsh_syscall_item* global_syscall_list = NULL; + +// #define VM_DISASSEMBLE +void finsh_vm_run() +{ + u_char op; + + /* if want to disassemble the bytecode, please define VM_DISASSEMBLE */ +#ifdef VM_DISASSEMBLE + void finsh_disassemble(); + finsh_disassemble(); +#endif + + /* set sp(stack pointer) to the beginning of stack */ + finsh_sp = &finsh_vm_stack[0]; + + /* set pc to the beginning of text segment */ + finsh_pc = &text_segment[0]; + + while ((finsh_pc - &text_segment[0] >= 0) && + (finsh_pc - &text_segment[0] < FINSH_TEXT_MAX)) + { + /* get op */ + op = *finsh_pc++; + + /* call op function */ + op_table[op](); + } +} + +#ifdef RT_USING_HEAP +extern char *strdup(const char *s); +void finsh_syscall_append(const char* name, syscall_func func) +{ + /* create the syscall */ + struct finsh_syscall_item* item; + + item = (struct finsh_syscall_item*)rt_malloc(sizeof(struct finsh_syscall_item)); + if (item != RT_NULL) + { + item->next = NULL; + item->syscall.name = strdup(name); + item->syscall.func = func; + + if (global_syscall_list == NULL) + { + global_syscall_list = item; + } + else + { + item->next = global_syscall_list; + global_syscall_list = item; + } + } +} +#endif + +struct finsh_syscall* finsh_syscall_lookup(const char* name) +{ + struct finsh_syscall* index; + struct finsh_syscall_item* item; + + for (index = _syscall_table_begin; index < _syscall_table_end; index ++) + { + if (strcmp(index->name, name) == 0) + return index; + } + + /* find on syscall list */ + item = global_syscall_list; + while (item != NULL) + { + if (strncmp(item->syscall.name, name, strlen(name)) == 0) + { + return &(item->syscall); + } + + item = item->next; + } + + return NULL; +} + +#ifdef VM_DISASSEMBLE +#include <stdio.h> +void finsh_disassemble() +{ + u_char *pc, op; + + pc = &text_segment[0]; + while (*pc != 0) + { + op = *pc; + switch (op) + { + case FINSH_OP_ADD_BYTE: + pc ++; + printf("addb\n"); + break; + + case FINSH_OP_SUB_BYTE: + pc ++; + printf("subb\n"); + break; + + case FINSH_OP_DIV_BYTE: + pc ++; + printf("divb\n"); + break; + + case FINSH_OP_MOD_BYTE: + pc ++; + printf("modb\n"); + break; + + case FINSH_OP_MUL_BYTE: + pc ++; + printf("mulb\n"); + break; + + case FINSH_OP_AND_BYTE: + pc ++; + printf("andb\n"); + break; + + case FINSH_OP_OR_BYTE: + pc ++; + printf("orb\n"); + break; + + case FINSH_OP_XOR_BYTE: + pc ++; + printf("xorb\n"); + break; + + case FINSH_OP_BITWISE_BYTE: + pc ++; + printf("bwb\n"); + break; + + case FINSH_OP_SHL_BYTE: + pc ++; + printf("shlb\n"); + break; + + case FINSH_OP_SHR_BYTE: + pc ++; + printf("shrb\n"); + break; + + case FINSH_OP_LD_BYTE: + pc ++; + printf("ldb %d\n", *pc++); + break; + + case FINSH_OP_LD_VALUE_BYTE: + pc ++; + printf("ldb [0x%x]\n", FINSH_GET32(pc)); + pc += 4; + break; + + case FINSH_OP_ST_BYTE: + pc ++; + printf("stb\n"); + break; + + case FINSH_OP_ADD_WORD: + pc ++; + printf("addw\n"); + break; + + case FINSH_OP_SUB_WORD: + pc ++; + printf("subw\n"); + break; + + case FINSH_OP_DIV_WORD: + pc ++; + printf("divw\n"); + break; + + case FINSH_OP_MOD_WORD: + pc ++; + printf("modw\n"); + break; + + case FINSH_OP_MUL_WORD: + pc ++; + printf("mulw\n"); + break; + + case FINSH_OP_AND_WORD: + pc ++; + printf("andw\n"); + break; + + case FINSH_OP_OR_WORD: + pc ++; + printf("orw\n"); + break; + + case FINSH_OP_XOR_WORD: + pc ++; + printf("xorw\n"); + break; + + case FINSH_OP_BITWISE_WORD: + pc ++; + printf("bww\n"); + break; + + case FINSH_OP_SHL_WORD: + pc ++; + printf("shlw\n"); + break; + + case FINSH_OP_SHR_WORD: + pc ++; + printf("shrw\n"); + break; + + case FINSH_OP_LD_WORD: + pc ++; + printf("ldw %d\n", FINSH_GET16(pc)); + pc += 2; + break; + + case FINSH_OP_LD_VALUE_WORD: + pc ++; + printf("ldw [0x%x]\n", FINSH_GET32(pc)); + pc += 4; + break; + + case FINSH_OP_ST_WORD: + pc ++; + printf("stw\n"); + break; + + case FINSH_OP_ADD_DWORD: + pc ++; + printf("addd\n"); + break; + + case FINSH_OP_SUB_DWORD: + pc ++; + printf("subd\n"); + break; + + case FINSH_OP_DIV_DWORD: + pc ++; + printf("divd\n"); + break; + + case FINSH_OP_MOD_DWORD: + pc ++; + printf("modd\n"); + break; + + case FINSH_OP_MUL_DWORD: + pc ++; + printf("muld\n"); + break; + + case FINSH_OP_AND_DWORD: + pc ++; + printf("andd\n"); + break; + + case FINSH_OP_OR_DWORD: + pc ++; + printf("ord\n"); + break; + + case FINSH_OP_XOR_DWORD: + pc ++; + printf("xord\n"); + break; + + case FINSH_OP_BITWISE_DWORD: + pc ++; + printf("bwd\n"); + break; + + case FINSH_OP_SHL_DWORD: + pc ++; + printf("shld\n"); + break; + + case FINSH_OP_SHR_DWORD: + pc ++; + printf("shrd\n"); + break; + + case FINSH_OP_LD_DWORD: + pc ++; + printf("ldd 0x%x\n", FINSH_GET32(pc)); + pc += 4; + break; + + case FINSH_OP_LD_VALUE_DWORD: + pc ++; + printf("ldd [0x%x]\n", FINSH_GET32(pc)); + pc += 4; + break; + + case FINSH_OP_ST_DWORD: + pc ++; + printf("std\n"); + break; + + case FINSH_OP_POP: + printf("pop\n"); + pc ++; + break; + + case FINSH_OP_SYSCALL: + pc ++; + printf("syscall %d\n", *pc++); + break; + + case FINSH_OP_LD_VALUE_BYTE_STACK: + pc ++; + printf("ldb [sp]\n"); + break; + + case FINSH_OP_LD_VALUE_WORD_STACK: + pc ++; + printf("ldw [sp]\n"); + break; + + case FINSH_OP_LD_VALUE_DWORD_STACK: + pc ++; + printf("ldd [sp]\n"); + break; + + default: + return; + } + } +} +#endif diff --git a/finsh/finsh_vm.h b/finsh/finsh_vm.h new file mode 100644 index 0000000000..1e453776ed --- /dev/null +++ b/finsh/finsh_vm.h @@ -0,0 +1,26 @@ +#ifndef __FINSH_VM_H__ +#define __FINSH_VM_H__ + +#include <finsh.h> + +#include "finsh_var.h" + +union finsh_value { + char char_value; + short short_value; + long long_value; + void* ptr; +}; + +extern union finsh_value* finsh_sp; /* stack pointer */ +extern u_char* finsh_pc; /* PC */ + +/* stack */ +extern union finsh_value finsh_vm_stack[FINSH_STACK_MAX]; +/* text segment */ +extern u_char text_segment[FINSH_TEXT_MAX]; + +void finsh_vm_run(void); +//void finsh_disassemble(void); + +#endif diff --git a/finsh/shell.c b/finsh/shell.c new file mode 100644 index 0000000000..f38d745a9c --- /dev/null +++ b/finsh/shell.c @@ -0,0 +1,270 @@ +/* + * File : shell.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-04-30 Bernard the first verion for FinSH + * 2006-05-08 Bernard change finsh thread stack to 2048 + * 2006-06-03 Bernard add support for skyeye + * 2006-09-24 Bernard remove the code related with hardware + */ + +#include <rtthread.h> +#include <rthw.h> + +#include "finsh.h" + +#if defined(__CC_ARM) /* ARMCC compiler */ + #ifdef FINSH_USING_SYMTAB + extern int FSymTab$$Base; + extern int FSymTab$$Limit; + extern int VSymTab$$Base; + extern int VSymTab$$Limit; + #endif +#elif defined(__ICCARM__) /* for IAR compiler */
+ #ifdef FINSH_USING_SYMTAB + #pragma section="FSymTab" + #pragma section="VSymTab"
+ #endif +#endif
+ +/* finsh thread */ +struct rt_thread finsh_thread; +char finsh_thread_stack[2048]; +struct rt_semaphore uart_sem; +#ifdef RT_USING_DEVICE +rt_device_t finsh_device; +#endif + +#if !defined (RT_USING_NEWLIB) && !defined (RT_USING_MINILIBC) +void *memccpy(void *dst, const void *src, int c, size_t count) +{ + char *a = dst; + const char *b = src; + while (count--) + { + *a++ = *b; + if (*b==c) + { + return (void *)a; + } + + b++; + } + return 0; +}
+ +int strcmp (const char *s1, const char *s2) +{ + while (*s1 && *s1 == *s2) s1++, s2++; + + return (*s1 - *s2); +} + +#ifdef RT_USING_HEAP +char *strdup(const char *s) +{ + size_t len = strlen(s) + 1; + char *tmp = (char *)rt_malloc(len); + + if(!tmp) return NULL; + + rt_memcpy(tmp, s, len); + return tmp; +} +#endif + +int isalpha( int ch ) +{ + return (unsigned int)((ch | 0x20) - 'a') < 26u; +} + +int atoi(const char* s) +{ + long int v=0; + int sign=1; + while ( *s == ' ' || (unsigned int)(*s - 9) < 5u) s++; + + switch (*s) + { + case '-': sign=-1; + case '+': ++s; + } + + while ((unsigned int) (*s - '0') < 10u) + { + v=v*10+*s-'0'; ++s; + } + + return sign==-1?-v:v; +} + +int isprint(unsigned char ch) +{ + return (unsigned int)(ch - ' ') < 127u - ' '; +} +#endif + +#ifdef RT_USING_DEVICE +static rt_err_t finsh_rx_ind(rt_device_t dev, rt_size_t size) +{ + /* release semaphore to let finsh thread rx data */ + rt_sem_release(&uart_sem); + + return RT_EOK; +} + +void finsh_set_device(char* device_name) +{ + rt_device_t dev = RT_NULL; + + dev = rt_device_find(device_name); + if (dev != RT_NULL && rt_device_open(dev, RT_DEVICE_OFLAG_RDWR) == RT_EOK) + { + if (finsh_device != RT_NULL) + { + /* close old finsh device */ + rt_device_close(finsh_device); + } + + finsh_device = dev;
+ rt_device_set_rx_indicate(dev, finsh_rx_ind); + } + else + { + rt_kprintf("finsh: can not find device:%s\n", device_name); + } +} +#else +void finsh_notify() +{ + rt_sem_release(&uart_sem); +} +#endif + +void finsh_thread_entry(void* parameter) +{ + struct finsh_parser parser; + char line[256]; + int pos ; + + finsh_init(&parser); + + while (1) + { + rt_kprintf("finsh>>"); + + memset(line, 0, sizeof(line)); + pos = 0; + while (1) + { + if (rt_sem_take(&uart_sem, -1) == RT_EOK) + { + /* read one character from serial */ + char ch; + +#ifndef RT_USING_DEVICE + ch = rt_serial_getc(); + if (ch != 0) +#else + rt_err_t rx_result; + rx_result = rt_device_read(finsh_device, 0, &ch, 1); + if (ch != 0 && rx_result == 1) +#endif + { + line[pos] = ch; + + rt_kprintf("%c", line[pos]); + + /* if it's the end of line, break */ + if (line[pos] == 0xd || line[pos] == 0xa) + { + /* change to ';' and break */ + line[pos] = ';'; + break; + } + pos ++; + } + } + } + + rt_kprintf("\n"); + finsh_parser_run(&parser, (unsigned char*)&line[0]); + + /* compile node root */ + if (finsh_errno() == 0) + { + finsh_compiler_run(parser.root); + } + else + { + rt_kprintf("%s\n", finsh_error_string(finsh_errno())); + } + + /* run virtual machine */ + if (finsh_errno() == 0) + { + finsh_vm_run(); + + if (isprint((unsigned char)finsh_stack_bottom())) + { + rt_kprintf("\t'%c', %d, 0x%08x\n", + (unsigned char)finsh_stack_bottom(), + (unsigned int)finsh_stack_bottom(), + (unsigned int)finsh_stack_bottom()); + } + else + { + rt_kprintf("\t%d, 0x%04x\n", + (unsigned int)finsh_stack_bottom(), + (unsigned int)finsh_stack_bottom()); + } + } + + finsh_flush(&parser); + } +} + +void finsh_system_function_init(void* begin, void* end) +{ + _syscall_table_begin = (struct finsh_syscall*) begin; + _syscall_table_end = (struct finsh_syscall*) end; +} + +void finsh_system_var_init(void* begin, void* end) +{ + _sysvar_table_begin = (struct finsh_sysvar*) begin; + _sysvar_table_end = (struct finsh_sysvar*) end; +} + +/* init finsh */ +void finsh_system_init() +{ + rt_sem_init(&uart_sem, "uart", 0, 0); + +#ifdef FINSH_USING_SYMTAB +#ifdef __CC_ARM /* ARM C Compiler */ + finsh_system_function_init(&FSymTab$$Base, &FSymTab$$Limit); + finsh_system_var_init(&VSymTab$$Base, &VSymTab$$Limit); +#elif defined (__ICCARM__) /* for IAR Compiler */ + finsh_system_function_init(__section_begin("FSymTab"), + __section_end("FSymTab")); + finsh_system_var_init(__section_begin("VSymTab"), + __section_end("VSymTab")); +#elif defined (__GNUC__) /* GNU GCC Compiler */ +#endif +#endif + + rt_thread_init(&finsh_thread, + "tshell", + finsh_thread_entry, RT_NULL, + &finsh_thread_stack[0], sizeof(finsh_thread_stack), + 20, 100); + rt_thread_startup(&finsh_thread); +} diff --git a/finsh/symbol.c b/finsh/symbol.c new file mode 100644 index 0000000000..a94ec64009 --- /dev/null +++ b/finsh/symbol.c @@ -0,0 +1,56 @@ +#include "finsh.h" + +long hello(void); +long version(void); +long list(void); +long list_thread(void); +long list_sem(void); +long list_mutex(void); +long list_fevent(void); +long list_event(void); +long list_mailbox(void); +long list_msgqueue(void); +long list_mempool(void); +long list_timer(void); + +#ifdef FINSH_USING_SYMTAB +struct finsh_syscall *_syscall_table_begin = NULL; +struct finsh_syscall *_syscall_table_end = NULL; +struct finsh_sysvar *_sysvar_table_begin = NULL; +struct finsh_sysvar *_sysvar_table_end = NULL; +#else +struct finsh_syscall _syscall_table[] = +{ + {"hello", hello}, + {"version", version}, + {"list", list}, + {"list_thread", list_thread}, +#ifdef RT_USING_SEMAPHORE + {"list_sem", list_sem}, +#endif +#ifdef RT_USING_MUTEX + {"list_mutex", list_mutex}, +#endif +#ifdef RT_USING_FEVENT + {"list_fevent", list_fevent}, +#endif +#ifdef RT_USING_EVENT + {"list_event", list_event}, +#endif +#ifdef RT_USING_MAILBOX + {"list_mb", list_mailbox}, +#endif +#ifdef RT_USING_MESSAGEQUEUE + {"list_mq", list_msgqueue}, +#endif +#ifdef RT_USING_MEMPOOL + {"list_memp", list_mempool}, +#endif + {"list_timer", list_timer}, +}; +struct finsh_syscall *_syscall_table_begin = &_syscall_table[0]; +struct finsh_syscall *_syscall_table_end = &_syscall_table[sizeof(_syscall_table) / sizeof(struct finsh_syscall)]; + +struct finsh_sysvar *_sysvar_table_begin = NULL; +struct finsh_sysvar *_sysvar_table_end = NULL; +#endif |
