ws.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:14k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  *
  3.  * ws.c
  4.  *
  5.  * Author: Markku Rossi <mtr@iki.fi>
  6.  *
  7.  * Copyright (c) 1999-2000 WAPIT OY LTD.
  8.  *  All rights reserved.
  9.  *
  10.  * Public entry points to the WMLScript compiler and the main compile
  11.  * function.
  12.  *
  13.  */
  14. #include "wsint.h"
  15. #include "ws.h"
  16. #include "wsstree.h"
  17. #include "wsasm.h"
  18. /********************* Types and definitions ****************************/
  19. #define WS_CHECK_COMPILE_ERROR()
  20.     do {
  21.         if (compiler->errors != 0) {                    
  22.             if (compiler->errors & WS_ERROR_B_MEMORY)
  23.                 result = WS_ERROR_OUT_OF_MEMORY;
  24.             else if (compiler->errors & WS_ERROR_B_SYNTAX)
  25.                 result = WS_ERROR_SYNTAX;
  26.             else if (compiler->errors & WS_ERROR_B_SEMANTIC)
  27.                 result = WS_ERROR_SEMANTIC;
  28.             else
  29.                 /* This shouldn't happen. */
  30.                 result = WS_ERROR;
  31.             goto out;
  32.         }
  33.     } while (0);
  34. /********************* Static variables *********************************/
  35. /* Human readable names for the result codes. */
  36. static struct
  37. {
  38.     WsResult code;
  39.     char *description;
  40. } result_codes[] = {
  41.     { WS_OK, "success" },
  42.     { WS_ERROR_OUT_OF_MEMORY, "out of memory" },
  43.     { WS_ERROR_SYNTAX, "syntax error" },
  44.     { WS_ERROR_SEMANTIC, "compile error" },
  45.     { WS_ERROR_IO, "IO error" },
  46.     { WS_ERROR, "error" },
  47.     { 0, NULL },
  48. };
  49. /********************* Prototypes for static functions ******************/
  50. /* Compile the input stream `input' with the compiler `compiler' and
  51.    return the byte-code in `output_return' and its length in
  52.    `output_len_return'.  The function returns a WsResult error code
  53.    describing the success of the compilation. */
  54. static WsResult compile_stream(WsCompilerPtr compiler,
  55.                                const char *input_name, WsStream *input,
  56.                                unsigned char **output_return,
  57.                                size_t *output_len_return);
  58. /* The default I/O function to send the output to stdout and stderr.
  59.    The argument `context' must be a `FILE *' file to which the output
  60.    is written. */
  61. static void std_io(const char *data, size_t len, void *context);
  62. /* A comparison function for functions entries when sorting them by
  63.    their usage counts.  The function is stable maintaining their
  64.    original order if their usage counts are equal. */
  65. static int sort_functions_cmp(const void *a, const void *b);
  66. /********************* Global functions *********************************/
  67. WsCompilerPtr ws_create(const WsCompilerParams *params)
  68. {
  69.     WsCompilerPtr compiler = ws_calloc(1, sizeof(*compiler));
  70.     if (compiler == NULL)
  71.         return NULL;
  72.     /* Store user params if specified. */
  73.     if (params)
  74.         compiler->params = *params;
  75.     /* Basic initialization. */
  76.     compiler->magic = COMPILER_MAGIC;
  77.     if (compiler->params.stdout_cb == NULL) {
  78.         compiler->params.stdout_cb = std_io;
  79.         compiler->params.stdout_cb_context = stdout;
  80.     }
  81.     if (compiler->params.stderr_cb == NULL) {
  82.         compiler->params.stderr_cb = std_io;
  83.         compiler->params.stderr_cb_context = stderr;
  84.     }
  85.     return compiler;
  86. }
  87. void ws_destroy(WsCompilerPtr compiler)
  88. {
  89.     if (compiler == NULL)
  90.         return;
  91.     ws_free(compiler);
  92. #if WS_MEM_DEBUG
  93.     if (ws_has_leaks())
  94.         ws_dump_blocks();
  95. #endif /* WS_MEM_DEBUG */
  96. }
  97. WsResult ws_compile_file(WsCompilerPtr compiler, const char *input_name,
  98.                          FILE *input, FILE *output)
  99. {
  100.     WsResult result;
  101.     WsStream *stream;
  102.     unsigned char *bc;
  103.     size_t bc_len;
  104.     /* Initialize the input stream. */
  105.     stream = ws_stream_new_file(input, WS_FALSE, WS_FALSE);
  106.     if (stream == NULL)
  107.         return WS_ERROR_OUT_OF_MEMORY;
  108.     result = compile_stream(compiler, input_name, stream, &bc, &bc_len);
  109.     ws_stream_close(stream);
  110.     if (result == WS_OK) {
  111.         /* Store the result to the file. */
  112.         if (fwrite(bc, 1, bc_len, output) != bc_len)
  113.             result = WS_ERROR_IO;
  114.         ws_bc_data_free(bc);
  115.     }
  116.     return result;
  117. }
  118. WsResult ws_compile_data(WsCompilerPtr compiler, const char *input_name,
  119.                          const unsigned char *input, size_t input_len,
  120.                          unsigned char **output_return,
  121.                          size_t *output_len_return)
  122. {
  123.     WsResult result;
  124.     WsStream *stream;
  125.     /* Initialize the input stream. */
  126.     stream = ws_stream_new_data_input(input, input_len);
  127.     if (stream == NULL)
  128.         return WS_ERROR_OUT_OF_MEMORY;
  129.     result = compile_stream(compiler, input_name, stream, output_return,
  130.                             output_len_return);
  131.     ws_stream_close(stream);
  132.     return result;
  133. }
  134. void ws_free_byte_code(unsigned char *byte_code)
  135. {
  136.     ws_bc_data_free(byte_code);
  137. }
  138. const char *ws_result_to_string(WsResult result)
  139. {
  140.     int i;
  141.     for (i = 0; result_codes[i].description; i++) {
  142.         if (result_codes[i].code == result)
  143.             return result_codes[i].description;
  144.     }
  145.     return "unknown result code";
  146. }
  147. /********************* Lexer's memory handling helpers ******************/
  148. WsBool ws_lexer_register_block(WsCompiler *compiler, void *ptr)
  149. {
  150.     void **n;
  151.     if (ptr == NULL)
  152.         return WS_TRUE;
  153.     n = ws_realloc(compiler->lexer_active_list,
  154.                    ((compiler->lexer_active_list_size + 1) * sizeof(void *)));
  155.     if (n == NULL)
  156.         return WS_FALSE;
  157.     compiler->lexer_active_list = n;
  158.     compiler->lexer_active_list[compiler->lexer_active_list_size++] = ptr;
  159.     return WS_TRUE;
  160. }
  161. WsBool ws_lexer_register_utf8(WsCompiler *compiler, WsUtf8String *string)
  162. {
  163.     if (!ws_lexer_register_block(compiler, string))
  164.         return WS_FALSE;
  165.     if (!ws_lexer_register_block(compiler, string->data)) {
  166.         compiler->lexer_active_list_size--;
  167.         return WS_FALSE;
  168.     }
  169.     return WS_TRUE;
  170. }
  171. void ws_lexer_free_block(WsCompiler *compiler, void *ptr)
  172. {
  173.     int i;
  174.     if (ptr == NULL)
  175.         return;
  176.     for (i = compiler->lexer_active_list_size - 1; i >= 0; i--) {
  177.         if (compiler->lexer_active_list[i] == ptr) {
  178.             memmove(&compiler->lexer_active_list[i],
  179.                     &compiler->lexer_active_list[i + 1],
  180.                     (compiler->lexer_active_list_size - i - 1) * sizeof(void *));
  181.             compiler->lexer_active_list_size--;
  182.             ws_free(ptr);
  183.             return;
  184.         }
  185.     }
  186.     ws_fatal("ws_lexer_free_block(): unknown block 0x%lx",
  187.              (unsigned long) ptr);
  188. }
  189. void ws_lexer_free_utf8(WsCompiler *compiler, WsUtf8String *string)
  190. {
  191.     if (string == NULL)
  192.         return;
  193.     ws_lexer_free_block(compiler, string->data);
  194.     ws_lexer_free_block(compiler, string);
  195. }
  196. /********************* Static functions *********************************/
  197. static WsResult compile_stream(WsCompilerPtr compiler, const char *input_name,
  198.                                WsStream *input, unsigned char **output_return,
  199.                                size_t *output_len_return)
  200. {
  201.     WsResult result = WS_OK;
  202.     WsUInt32 i;
  203.     WsListItem *li;
  204.     WsUInt8 findex;
  205.     WsUInt8 num_locals;
  206.     WsBcStringEncoding string_encoding = WS_BC_STRING_ENC_UTF8;
  207.     /* Initialize the compiler context. */
  208.     compiler->linenum = 1;
  209.     compiler->input_name = input_name;
  210.     compiler->num_errors = 0;
  211.     compiler->num_warnings = 0;
  212.     compiler->num_extern_functions = 0;
  213.     compiler->num_local_functions = 0;
  214.     compiler->errors = 0;
  215.     compiler->last_syntax_error_line = 0;
  216.     /* Allocate fast-malloc pool for the syntax tree. */
  217.     compiler->pool_stree = ws_f_create(1024 * 1024);
  218.     if (compiler->pool_stree == NULL) {
  219.         result = WS_ERROR_OUT_OF_MEMORY;
  220.         goto out;
  221.     }
  222.     /* Allocate hash tables. */
  223.     compiler->pragma_use_hash = ws_pragma_use_hash_create();
  224.     if (compiler->pragma_use_hash == NULL) {
  225.         result = WS_ERROR_OUT_OF_MEMORY;
  226.         goto out;
  227.     }
  228.     compiler->functions_hash = ws_function_hash_create();
  229.     if (compiler->functions_hash == NULL) {
  230.         result = WS_ERROR_OUT_OF_MEMORY;
  231.         goto out;
  232.     }
  233.     /* Allocate a byte-code module. */
  234.     if (compiler->params.use_latin1_strings)
  235.         string_encoding = WS_BC_STRING_ENC_ISO_8859_1;
  236.     compiler->bc = ws_bc_alloc(string_encoding);
  237.     if (compiler->bc == NULL) {
  238.         result = WS_ERROR_OUT_OF_MEMORY;
  239.         goto out;
  240.     }
  241.     /* Save the input stream. */
  242.     compiler->input = input;
  243.     /* Parse the input. */
  244. #if WS_DEBUG
  245.     global_compiler = compiler;
  246. #endif /* WS_DEBUG */
  247.     ws_yy_parse(compiler);
  248.     /* Free all lexer's active not freed blocks.  If we have any blocks
  249.        on the used list, our compilation was not successful. */
  250.     {
  251.         size_t j;
  252.         for (j = 0; j < compiler->lexer_active_list_size; j++)
  253.             ws_free(compiler->lexer_active_list[j]);
  254.         ws_free(compiler->lexer_active_list);
  255.         compiler->lexer_active_list = NULL;
  256.     }
  257.     WS_CHECK_COMPILE_ERROR();
  258.     /* Sort functions if allowed and it helps. */
  259.     if (!compiler->params.no_opt_sort_bc_functions
  260.         && compiler->num_functions > 7) {
  261.         WsUInt32 i;
  262.         ws_info(compiler, "optimize: sorting functions");
  263.         /* Fetch the usage counts from the functions hash. */
  264.         for (i = 0; i < compiler->num_functions; i++) {
  265.             WsFunctionHash *fh = ws_function_hash(compiler,
  266.                                                   compiler->functions[i].name);
  267.             compiler->functions[i].usage_count = fh->usage_count;
  268.         }
  269.         /* Sort functions.  */
  270.         qsort(compiler->functions, compiler->num_functions,
  271.               sizeof(compiler->functions[0]), sort_functions_cmp);
  272.         /* Patch the function indexes. */
  273.         for (i = 0; i < compiler->num_functions; i++) {
  274.             WsFunctionHash *fh = ws_function_hash(compiler,
  275.                                                   compiler->functions[i].name);
  276.             compiler->functions[i].findex = i;
  277.             fh->findex = i;
  278.         }
  279.     }
  280.     /* Linearize functions */
  281.     for (i = 0; i < compiler->num_functions; i++) {
  282.         WsFunction *func = &compiler->functions[i];
  283.         ws_info(compiler, "linearizing function `%s'...", func->name);
  284.         compiler->pool_asm = ws_f_create(100 * 1024);
  285.         if (compiler->pool_asm == NULL) {
  286.             result = WS_ERROR_OUT_OF_MEMORY;
  287.             goto out;
  288.         }
  289.         compiler->next_label = 0;
  290.         compiler->asm_head = compiler->asm_tail = NULL;
  291.         /* Create variables namespace. */
  292.         compiler->next_vindex = 0;
  293.         compiler->variables_hash = ws_variable_hash_create();
  294.         if (compiler->variables_hash == NULL) {
  295.             result = WS_ERROR_OUT_OF_MEMORY;
  296.             goto out;
  297.         }
  298.         /* Define the formal arguments to the namespace. */
  299.         for (li = func->params->head; li; li = li->next) {
  300.             WsFormalParm *parm = li->data;
  301.             ws_variable_define(compiler, parm->line, WS_FALSE, parm->name);
  302.         }
  303.         WS_CHECK_COMPILE_ERROR();
  304.         /* Linearize it. */
  305.         for (li = func->block->head; li; li = li->next)
  306.             ws_stmt_linearize(compiler, li->data);
  307.         WS_CHECK_COMPILE_ERROR();
  308.         /* Optimize symbolic assembler.  This function does nothing if
  309.            no optimizations were requested. */
  310.         ws_asm_optimize(compiler);
  311.         /* Print the resulting symbolic assembler if requested. */
  312.         if (compiler->params.print_symbolic_assembler)
  313.             ws_asm_print(compiler);
  314.         WS_CHECK_COMPILE_ERROR();
  315.         /* Generate byte-code */
  316.         ws_buffer_init(&compiler->byte_code);
  317.         ws_asm_linearize(compiler);
  318.         WS_CHECK_COMPILE_ERROR();
  319.         /* Disassemble the output if requested. */
  320.         if (compiler->params.print_assembler)
  321.             ws_asm_dasm(compiler, ws_buffer_ptr(&compiler->byte_code),
  322.                         ws_buffer_len(&compiler->byte_code));
  323.         /* Calculate the number of local variables */
  324.         num_locals = compiler->next_vindex - func->params->num_items;
  325.         /* Add the function to the byte-code module. */
  326.         if (!ws_bc_add_function(compiler->bc, &findex,
  327.                                 func->externp ? func->name : NULL,
  328.                                 func->params->num_items,
  329.                                 num_locals,
  330.                                 ws_buffer_len(&compiler->byte_code),
  331.                                 ws_buffer_ptr(&compiler->byte_code))) {
  332.             result = WS_ERROR_OUT_OF_MEMORY;
  333.             goto out;
  334.         }
  335.         /* Cleanup and prepare for the next function. */
  336.         ws_buffer_uninit(&compiler->byte_code);
  337.         ws_hash_destroy(compiler->variables_hash);
  338.         compiler->variables_hash = NULL;
  339.         ws_f_destroy(compiler->pool_asm);
  340.         compiler->pool_asm = NULL;
  341.     }
  342.     /* Linearize the byte-code structure. */
  343.     if (!ws_bc_encode(compiler->bc, output_return, output_len_return))
  344.         result = WS_ERROR_OUT_OF_MEMORY;
  345. out:
  346.     /* Cleanup. */
  347.     ws_f_destroy(compiler->pool_stree);
  348.     compiler->pool_stree = NULL;
  349.     ws_hash_destroy(compiler->pragma_use_hash);
  350.     compiler->pragma_use_hash = NULL;
  351.     /* Free functions. */
  352.     for (i = 0; i < compiler->num_functions; i++)
  353.         ws_free(compiler->functions[i].name);
  354.     ws_free(compiler->functions);
  355.     ws_hash_destroy(compiler->functions_hash);
  356.     compiler->functions_hash = NULL;
  357.     ws_bc_free(compiler->bc);
  358.     compiler->bc = NULL;
  359.     compiler->input = NULL;
  360.     ws_f_destroy(compiler->pool_asm);
  361.     compiler->pool_asm = NULL;
  362.     ws_hash_destroy(compiler->variables_hash);
  363.     compiler->variables_hash = NULL;
  364.     ws_buffer_uninit(&compiler->byte_code);
  365.     /* All done. */
  366.     return result;
  367. }
  368. static void std_io(const char *data, size_t len, void *context)
  369. {
  370.     fwrite(data, 1, len, (FILE *) context);
  371. }
  372. static int sort_functions_cmp(const void *a, const void *b)
  373. {
  374.     WsFunction *fa = (WsFunction *) a;
  375.     WsFunction *fb = (WsFunction *) b;
  376.     if (fa->usage_count > fb->usage_count)
  377.         return -1;
  378.     if (fa->usage_count < fb->usage_count)
  379.         return 1;
  380.     if (fa->findex < fb->findex)
  381.         return -1;
  382.     return 1;
  383. }