Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

ws.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  *
00059  * ws.c
00060  *
00061  * Author: Markku Rossi <mtr@iki.fi>
00062  *
00063  * Copyright (c) 1999-2000 WAPIT OY LTD.
00064  *       All rights reserved.
00065  *
00066  * Public entry points to the WMLScript compiler and the main compile
00067  * function.
00068  *
00069  */
00070 
00071 #include "wsint.h"
00072 #include "ws.h"
00073 #include "wsstree.h"
00074 #include "wsasm.h"
00075 
00076 /********************* Types and definitions ****************************/
00077 
00078 #define WS_CHECK_COMPILE_ERROR()                \
00079     do {                            \
00080         if (compiler->errors != 0) {                        \
00081             if (compiler->errors & WS_ERROR_B_MEMORY)       \
00082                 result = WS_ERROR_OUT_OF_MEMORY;        \
00083             else if (compiler->errors & WS_ERROR_B_SYNTAX)  \
00084                 result = WS_ERROR_SYNTAX;           \
00085             else if (compiler->errors & WS_ERROR_B_SEMANTIC)    \
00086                 result = WS_ERROR_SEMANTIC;         \
00087             else                        \
00088                 /* This shouldn't happen. */            \
00089                 result = WS_ERROR;              \
00090             goto out;                       \
00091         }                           \
00092     } while (0);
00093 
00094 /********************* Static variables *********************************/
00095 
00096 /* Human readable names for the result codes. */
00097 static struct
00098 {
00099     WsResult code;
00100     char *description;
00101 } result_codes[] = {
00102     { WS_OK, "success" },
00103     { WS_ERROR_OUT_OF_MEMORY, "out of memory" },
00104     { WS_ERROR_SYNTAX, "syntax error" },
00105     { WS_ERROR_SEMANTIC, "compile error" },
00106     { WS_ERROR_IO, "IO error" },
00107     { WS_ERROR, "error" },
00108 
00109     { 0, NULL },
00110 };
00111 
00112 /********************* Prototypes for static functions ******************/
00113 
00114 /* Compile the input stream `input' with the compiler `compiler' and
00115    return the byte-code in `output_return' and its length in
00116    `output_len_return'.  The function returns a WsResult error code
00117    describing the success of the compilation. */
00118 static WsResult compile_stream(WsCompilerPtr compiler,
00119                                const char *input_name, WsStream *input,
00120                                unsigned char **output_return,
00121                                size_t *output_len_return);
00122 
00123 /* The default I/O function to send the output to stdout and stderr.
00124    The argument `context' must be a `FILE *' file to which the output
00125    is written. */
00126 static void std_io(const char *data, size_t len, void *context);
00127 
00128 /* A comparison function for functions entries when sorting them by
00129    their usage counts.  The function is stable maintaining their
00130    original order if their usage counts are equal. */
00131 static int sort_functions_cmp(const void *a, const void *b);
00132 
00133 /********************* Global functions *********************************/
00134 
00135 WsCompilerPtr ws_create(WsCompilerParams *params)
00136 {
00137     WsCompilerPtr compiler = ws_calloc(1, sizeof(*compiler));
00138 
00139     if (compiler == NULL)
00140         return NULL;
00141 
00142     /* Store user params if specified. */
00143     if (params)
00144         compiler->params = *params;
00145 
00146     /* Basic initialization. */
00147 
00148     compiler->magic = COMPILER_MAGIC;
00149 
00150     if (compiler->params.stdout_cb == NULL) {
00151         compiler->params.stdout_cb = std_io;
00152         compiler->params.stdout_cb_context = stdout;
00153     }
00154     if (compiler->params.stderr_cb == NULL) {
00155         compiler->params.stderr_cb = std_io;
00156         compiler->params.stderr_cb_context = stderr;
00157     }
00158 
00159     return compiler;
00160 }
00161 
00162 
00163 void ws_destroy(WsCompilerPtr compiler)
00164 {
00165     if (compiler == NULL)
00166         return;
00167 
00168     ws_free(compiler);
00169 
00170 #if WS_MEM_DEBUG
00171     if (ws_has_leaks())
00172         ws_dump_blocks();
00173 #endif /* WS_MEM_DEBUG */
00174 }
00175 
00176 
00177 WsResult ws_compile_file(WsCompilerPtr compiler, const char *input_name,
00178                          FILE *input, FILE *output)
00179 {
00180     WsResult result;
00181     WsStream *stream;
00182     unsigned char *bc;
00183     size_t bc_len;
00184 
00185     /* Initialize the input stream. */
00186     stream = ws_stream_new_file(input, WS_FALSE, WS_FALSE);
00187     if (stream == NULL)
00188         return WS_ERROR_OUT_OF_MEMORY;
00189 
00190     result = compile_stream(compiler, input_name, stream, &bc, &bc_len);
00191 
00192     ws_stream_close(stream);
00193 
00194     if (result == WS_OK) {
00195         /* Store the result to the file. */
00196         if (fwrite(bc, 1, bc_len, output) != bc_len)
00197             result = WS_ERROR_IO;
00198 
00199         ws_bc_data_free(bc);
00200     }
00201 
00202     return result;
00203 }
00204 
00205 
00206 WsResult ws_compile_data(WsCompilerPtr compiler, const char *input_name,
00207                          const unsigned char *input, size_t input_len,
00208                          unsigned char **output_return,
00209                          size_t *output_len_return)
00210 {
00211     WsResult result;
00212     WsStream *stream;
00213 
00214     /* Initialize the input stream. */
00215     stream = ws_stream_new_data_input(input, input_len);
00216     if (stream == NULL)
00217         return WS_ERROR_OUT_OF_MEMORY;
00218 
00219     result = compile_stream(compiler, input_name, stream, output_return,
00220                             output_len_return);
00221 
00222     ws_stream_close(stream);
00223 
00224     return result;
00225 }
00226 
00227 
00228 void ws_free_byte_code(unsigned char *byte_code)
00229 {
00230     ws_bc_data_free(byte_code);
00231 }
00232 
00233 
00234 const char *ws_result_to_string(WsResult result)
00235 {
00236     int i;
00237 
00238     for (i = 0; result_codes[i].description; i++) {
00239         if (result_codes[i].code == result)
00240             return result_codes[i].description;
00241     }
00242 
00243     return "unknown result code";
00244 }
00245 
00246 /********************* Lexer's memory handling helpers ******************/
00247 
00248 WsBool ws_lexer_register_block(WsCompiler *compiler, void *ptr)
00249 {
00250     void **n;
00251 
00252     if (ptr == NULL)
00253         return WS_TRUE;
00254 
00255     n = ws_realloc(compiler->lexer_active_list,
00256                    ((compiler->lexer_active_list_size + 1) * sizeof(void *)));
00257     if (n == NULL)
00258         return WS_FALSE;
00259 
00260     compiler->lexer_active_list = n;
00261     compiler->lexer_active_list[compiler->lexer_active_list_size++] = ptr;
00262 
00263     return WS_TRUE;
00264 }
00265 
00266 
00267 WsBool ws_lexer_register_utf8(WsCompiler *compiler, WsUtf8String *string)
00268 {
00269     if (!ws_lexer_register_block(compiler, string))
00270         return WS_FALSE;
00271 
00272     if (!ws_lexer_register_block(compiler, string->data)) {
00273         compiler->lexer_active_list_size--;
00274         return WS_FALSE;
00275     }
00276 
00277     return WS_TRUE;
00278 }
00279 
00280 
00281 void ws_lexer_free_block(WsCompiler *compiler, void *ptr)
00282 {
00283     int i;
00284 
00285     if (ptr == NULL)
00286         return;
00287 
00288     for (i = compiler->lexer_active_list_size - 1; i >= 0; i--) {
00289         if (compiler->lexer_active_list[i] == ptr) {
00290             memmove(&compiler->lexer_active_list[i],
00291                     &compiler->lexer_active_list[i + 1],
00292                     (compiler->lexer_active_list_size - i - 1) * sizeof(void *));
00293             compiler->lexer_active_list_size--;
00294 
00295             ws_free(ptr);
00296             return;
00297         }
00298     }
00299 
00300     ws_fatal("ws_lexer_free_block(): unknown block 0x%lx",
00301              (unsigned long) ptr);
00302 }
00303 
00304 
00305 void ws_lexer_free_utf8(WsCompiler *compiler, WsUtf8String *string)
00306 {
00307     if (string == NULL)
00308         return;
00309 
00310     ws_lexer_free_block(compiler, string->data);
00311     ws_lexer_free_block(compiler, string);
00312 }
00313 
00314 /********************* Static functions *********************************/
00315 
00316 static WsResult compile_stream(WsCompilerPtr compiler, const char *input_name,
00317                                WsStream *input, unsigned char **output_return,
00318                                size_t *output_len_return)
00319 {
00320     WsResult result = WS_OK;
00321     WsUInt32 i;
00322     WsListItem *li;
00323     WsUInt8 findex;
00324     WsUInt8 num_locals;
00325     WsBcStringEncoding string_encoding = WS_BC_STRING_ENC_UTF8;
00326 
00327     /* Initialize the compiler context. */
00328 
00329     compiler->linenum = 1;
00330     compiler->input_name = input_name;
00331 
00332     compiler->num_errors = 0;
00333     compiler->num_warnings = 0;
00334     compiler->num_extern_functions = 0;
00335     compiler->num_local_functions = 0;
00336     compiler->errors = 0;
00337     compiler->last_syntax_error_line = 0;
00338 
00339     /* Allocate fast-malloc pool for the syntax tree. */
00340 
00341     compiler->pool_stree = ws_f_create(1024 * 1024);
00342     if (compiler->pool_stree == NULL) {
00343         result = WS_ERROR_OUT_OF_MEMORY;
00344         goto out;
00345     }
00346 
00347     /* Allocate hash tables. */
00348 
00349     compiler->pragma_use_hash = ws_pragma_use_hash_create();
00350     if (compiler->pragma_use_hash == NULL) {
00351         result = WS_ERROR_OUT_OF_MEMORY;
00352         goto out;
00353     }
00354 
00355     compiler->functions_hash = ws_function_hash_create();
00356     if (compiler->functions_hash == NULL) {
00357         result = WS_ERROR_OUT_OF_MEMORY;
00358         goto out;
00359     }
00360 
00361     /* Allocate a byte-code module. */
00362 
00363     if (compiler->params.use_latin1_strings)
00364         string_encoding = WS_BC_STRING_ENC_ISO_8859_1;
00365 
00366     compiler->bc = ws_bc_alloc(string_encoding);
00367     if (compiler->bc == NULL) {
00368         result = WS_ERROR_OUT_OF_MEMORY;
00369         goto out;
00370     }
00371 
00372     /* Save the input stream. */
00373     compiler->input = input;
00374 
00375     /* Parse the input. */
00376 #if WS_DEBUG
00377     global_compiler = compiler;
00378 #endif /* WS_DEBUG */
00379 
00380     ws_yy_parse(compiler);
00381 
00382     /* Free all lexer's active not freed blocks.  If we have any blocks
00383        on the used list, our compilation was not successful. */
00384     {
00385         size_t j;
00386 
00387         for (j = 0; j < compiler->lexer_active_list_size; j++)
00388             ws_free(compiler->lexer_active_list[j]);
00389         ws_free(compiler->lexer_active_list);
00390 
00391         compiler->lexer_active_list = NULL;
00392     }
00393 
00394     WS_CHECK_COMPILE_ERROR();
00395 
00396     /* Sort functions if allowed and it helps. */
00397     if (!compiler->params.no_opt_sort_bc_functions
00398         && compiler->num_functions > 7) {
00399         WsUInt32 i;
00400 
00401         ws_info(compiler, "optimize: sorting functions");
00402 
00403         /* Fetch the usage counts from the functions hash. */
00404         for (i = 0; i < compiler->num_functions; i++) {
00405             WsFunctionHash *fh = ws_function_hash(compiler,
00406                                                   compiler->functions[i].name);
00407             compiler->functions[i].usage_count = fh->usage_count;
00408         }
00409 
00410         /* Sort functions.  */
00411         qsort(compiler->functions, compiler->num_functions,
00412               sizeof(compiler->functions[0]), sort_functions_cmp);
00413 
00414         /* Patch the function indexes. */
00415         for (i = 0; i < compiler->num_functions; i++) {
00416             WsFunctionHash *fh = ws_function_hash(compiler,
00417                                                   compiler->functions[i].name);
00418             compiler->functions[i].findex = i;
00419             fh->findex = i;
00420         }
00421     }
00422 
00423     /* Linearize functions */
00424     for (i = 0; i < compiler->num_functions; i++) {
00425         WsFunction *func = &compiler->functions[i];
00426 
00427         ws_info(compiler, "linearizing function `%s'...", func->name);
00428 
00429         compiler->pool_asm = ws_f_create(100 * 1024);
00430         if (compiler->pool_asm == NULL) {
00431             result = WS_ERROR_OUT_OF_MEMORY;
00432             goto out;
00433         }
00434 
00435         compiler->next_label = 0;
00436         compiler->asm_head = compiler->asm_tail = NULL;
00437 
00438         /* Create variables namespace. */
00439         compiler->next_vindex = 0;
00440         compiler->variables_hash = ws_variable_hash_create();
00441         if (compiler->variables_hash == NULL) {
00442             result = WS_ERROR_OUT_OF_MEMORY;
00443             goto out;
00444         }
00445 
00446         /* Define the formal arguments to the namespace. */
00447         for (li = func->params->head; li; li = li->next) {
00448             WsFormalParm *parm = li->data;
00449 
00450             ws_variable_define(compiler, parm->line, WS_FALSE, parm->name);
00451         }
00452 
00453         WS_CHECK_COMPILE_ERROR();
00454 
00455         /* Linearize it. */
00456         for (li = func->block->head; li; li = li->next)
00457             ws_stmt_linearize(compiler, li->data);
00458 
00459         WS_CHECK_COMPILE_ERROR();
00460 
00461         /* Optimize symbolic assembler.  This function does nothing if
00462            no optimizations were requested. */
00463         ws_asm_optimize(compiler);
00464 
00465         /* Print the resulting symbolic assembler if requested. */
00466         if (compiler->params.print_symbolic_assembler)
00467             ws_asm_print(compiler);
00468 
00469         WS_CHECK_COMPILE_ERROR();
00470 
00471         /* Generate byte-code */
00472 
00473         ws_buffer_init(&compiler->byte_code);
00474         ws_asm_linearize(compiler);
00475 
00476         WS_CHECK_COMPILE_ERROR();
00477 
00478         /* Disassemble the output if requested. */
00479         if (compiler->params.print_assembler)
00480             ws_asm_dasm(compiler, ws_buffer_ptr(&compiler->byte_code),
00481                         ws_buffer_len(&compiler->byte_code));
00482 
00483         /* Calculate the number of local variables */
00484         num_locals = compiler->next_vindex - func->params->num_items;
00485 
00486         /* Add the function to the byte-code module. */
00487         if (!ws_bc_add_function(compiler->bc, &findex,
00488                                 func->externp ? func->name : NULL,
00489                                 func->params->num_items,
00490                                 num_locals,
00491                                 ws_buffer_len(&compiler->byte_code),
00492                                 ws_buffer_ptr(&compiler->byte_code))) {
00493             result = WS_ERROR_OUT_OF_MEMORY;
00494             goto out;
00495         }
00496 
00497         /* Cleanup and prepare for the next function. */
00498 
00499         ws_buffer_uninit(&compiler->byte_code);
00500 
00501         ws_hash_destroy(compiler->variables_hash);
00502         compiler->variables_hash = NULL;
00503 
00504         ws_f_destroy(compiler->pool_asm);
00505         compiler->pool_asm = NULL;
00506     }
00507 
00508     /* Linearize the byte-code structure. */
00509     if (!ws_bc_encode(compiler->bc, output_return, output_len_return))
00510         result = WS_ERROR_OUT_OF_MEMORY;
00511 
00512 out:
00513 
00514     /* Cleanup. */
00515 
00516     ws_f_destroy(compiler->pool_stree);
00517     compiler->pool_stree = NULL;
00518 
00519     ws_hash_destroy(compiler->pragma_use_hash);
00520     compiler->pragma_use_hash = NULL;
00521 
00522     /* Free functions. */
00523     for (i = 0; i < compiler->num_functions; i++)
00524         ws_free(compiler->functions[i].name);
00525     ws_free(compiler->functions);
00526 
00527     ws_hash_destroy(compiler->functions_hash);
00528     compiler->functions_hash = NULL;
00529 
00530     ws_bc_free(compiler->bc);
00531     compiler->bc = NULL;
00532 
00533     compiler->input = NULL;
00534 
00535     ws_f_destroy(compiler->pool_asm);
00536     compiler->pool_asm = NULL;
00537 
00538     ws_hash_destroy(compiler->variables_hash);
00539     compiler->variables_hash = NULL;
00540 
00541     ws_buffer_uninit(&compiler->byte_code);
00542 
00543     /* All done. */
00544     return result;
00545 }
00546 
00547 
00548 static void std_io(const char *data, size_t len, void *context)
00549 {
00550     fwrite(data, 1, len, (FILE *) context);
00551 }
00552 
00553 
00554 static int sort_functions_cmp(const void *a, const void *b)
00555 {
00556     WsFunction *fa = (WsFunction *) a;
00557     WsFunction *fb = (WsFunction *) b;
00558 
00559     if (fa->usage_count > fb->usage_count)
00560         return -1;
00561     if (fa->usage_count < fb->usage_count)
00562         return 1;
00563 
00564     if (fa->findex < fb->findex)
00565         return -1;
00566 
00567     return 1;
00568 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.