Ejemplo n.º 1
0
void ws_stmt_linearize(WsCompiler *compiler, WsStatement *stmt)
{
    WsListItem *li;
    WsAsmIns *ins;

    switch (stmt->type) {
    case WS_STMT_BLOCK:
        for (li = stmt->u.block->head; li; li = li->next)
            ws_stmt_linearize(compiler, li->data);
        break;

    case WS_STMT_VARIABLE:
        linearize_variable_init(compiler, stmt->u.var, stmt->first_line);
        break;

    case WS_STMT_EMPTY:
        /* Nothing here. */
        break;

    case WS_STMT_EXPR:
        ws_expr_linearize(compiler, stmt->u.expr);

        /* Pop the expressions result from the stack.  Otherwise loops
           could eventually cause stack overflows. */
        ws_asm_link(compiler, ws_asm_ins(compiler, stmt->last_line, WS_ASM_POP));
        break;

    case WS_STMT_IF:
        {
            WsAsmIns *l_else = ws_asm_label(compiler,
                                            (stmt->u.s_if.s_else
                                             ? stmt->u.s_if.s_else->first_line
                                             : stmt->last_line));
            WsAsmIns *l_end = ws_asm_label(compiler, stmt->last_line);

            /* Linearize the expression. */
            ws_expr_linearize(compiler, stmt->u.s_if.expr);

            /* If the result is false, jump to the else-branch. */
            ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
                                                WS_ASM_P_TJUMP, l_else));

            /* Else, execute the then-branch and jump to the end. */
            ws_stmt_linearize(compiler, stmt->u.s_if.s_then);
            ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line,
                                                WS_ASM_P_JUMP, l_end));

            /* Then else-branch. */
            ws_asm_link(compiler, l_else);

            /* Linearize the else-branch if it is present. */
            if (stmt->u.s_if.s_else)
                ws_stmt_linearize(compiler, stmt->u.s_if.s_else);

            /* Insert the end label. */
            ws_asm_link(compiler, l_end);
        }
        break;

    case WS_STMT_FOR:
        {
            WsAsmIns *l_loop = ws_asm_label(compiler, stmt->first_line);
            WsAsmIns *l_cont = ws_asm_label(compiler, stmt->first_line);
            WsAsmIns *l_break = ws_asm_label(compiler, stmt->first_line);
            WsContBreak *cb;

            /* Store the labels to the compiler. */

            cb = ws_f_calloc(compiler->pool_stree, 1, sizeof(*cb));
            if (cb == NULL) {
                ws_error_memory(compiler);
                return;
            }

            cb->next = compiler->cont_break;
            compiler->cont_break = cb;

            cb->l_cont = l_cont;
            cb->l_break = l_break;

            /* Linearize the possible init code. */
            if (stmt->u.s_for.init)
                linearize_variable_init(compiler, stmt->u.s_for.init,
                                        stmt->first_line);
            else if (stmt->u.s_for.e1) {
                /* Linearize the init. */
                ws_expr_linearize(compiler, stmt->u.s_for.e1);

                /* Pop the result. */
                ws_asm_link(compiler, ws_asm_ins(compiler, stmt->first_line,
                                                 WS_ASM_POP));
            }

            /* Insert the loop label. */
            ws_asm_link(compiler, l_loop);

            /* Linearize the condition. */
            if (stmt->u.s_for.e2) {
                ws_expr_linearize(compiler, stmt->u.s_for.e2);

                /* If false, jump out. */
                ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
                                                    WS_ASM_P_TJUMP, l_break));
            }

            /* Linearize the body statement. */
            ws_stmt_linearize(compiler, stmt->u.s_for.stmt);

            /* Link the continue label. */
            ws_asm_link(compiler, l_cont);

            /* Linearize the update expression. */
            if (stmt->u.s_for.e3) {
                ws_expr_linearize(compiler, stmt->u.s_for.e3);

                /* Pop the result. */
                ws_asm_link(compiler, ws_asm_ins(compiler, stmt->first_line,
                                                 WS_ASM_POP));
            }

            /* Jump to the loop label to check the condition. */
            ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line,
                                                WS_ASM_P_JUMP, l_loop));

            /* Insert the break label. */
            ws_asm_link(compiler, l_break);

            /* Pop the cont-break block. */
            compiler->cont_break = compiler->cont_break->next;
        }
        break;

    case WS_STMT_WHILE:
        {
            WsAsmIns *l_cont = ws_asm_label(compiler, stmt->first_line);
            WsAsmIns *l_break = ws_asm_label(compiler,
                                             stmt->u.s_while.stmt->last_line);
            WsContBreak *cb;

            /* Store the labels to the compiler. */

            cb = ws_f_calloc(compiler->pool_stree, 1, sizeof(*cb));
            if (cb == NULL) {
                ws_error_memory(compiler);
                return;
            }

            cb->next = compiler->cont_break;
            compiler->cont_break = cb;

            cb->l_cont = l_cont;
            cb->l_break = l_break;

            /* Insert the continue label. */
            ws_asm_link(compiler, l_cont);

            /* Linearize the expression. */
            ws_expr_linearize(compiler, stmt->u.s_while.expr);

            /* If false, jump out. */
            ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
                                                WS_ASM_P_TJUMP, l_break));

            /* Linearize the body statement. */
            ws_stmt_linearize(compiler, stmt->u.s_while.stmt);

            /* And jump to the continue label to check the expression. */
            ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line,
                                                WS_ASM_P_JUMP, l_cont));

            /* Insert the break label. */
            ws_asm_link(compiler, l_break);

            /* Pop the cont-break block. */
            compiler->cont_break = compiler->cont_break->next;
        }
        break;

    case WS_STMT_CONTINUE:
        if (compiler->cont_break == NULL)
            ws_src_error(compiler, stmt->first_line,
                         "continue statement not within a loop");

        ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
                                            WS_ASM_P_JUMP,
                                            compiler->cont_break->l_cont));
        break;

    case WS_STMT_BREAK:
        if (compiler->cont_break == NULL)
            ws_src_error(compiler, stmt->first_line,
                         "break statement not within a loop");

        ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line,
                                            WS_ASM_P_JUMP,
                                            compiler->cont_break->l_break));
        break;

    case WS_STMT_RETURN:
        if (stmt->u.expr) {
            /* Linearize the return value and return it. */
            ws_expr_linearize(compiler, stmt->u.expr);
            ins = ws_asm_ins(compiler, stmt->first_line, WS_ASM_RETURN);
        } else
            /* Return an empty string. */
            ins = ws_asm_ins(compiler, stmt->first_line, WS_ASM_RETURN_ES);

        ws_asm_link(compiler, ins);
        break;
    }
}
Ejemplo n.º 2
0
Archivo: ws.c Proyecto: markjeee/kannel
static WsResult compile_stream(WsCompilerPtr compiler, const char *input_name,
                               WsStream *input, unsigned char **output_return,
                               size_t *output_len_return)
{
    WsResult result = WS_OK;
    WsUInt32 i;
    WsListItem *li;
    WsUInt8 findex;
    WsUInt8 num_locals;
    WsBcStringEncoding string_encoding = WS_BC_STRING_ENC_UTF8;

    /* Initialize the compiler context. */

    compiler->linenum = 1;
    compiler->input_name = input_name;

    compiler->num_errors = 0;
    compiler->num_warnings = 0;
    compiler->num_extern_functions = 0;
    compiler->num_local_functions = 0;
    compiler->errors = 0;
    compiler->last_syntax_error_line = 0;

    /* Allocate fast-malloc pool for the syntax tree. */

    compiler->pool_stree = ws_f_create(1024 * 1024);
    if (compiler->pool_stree == NULL) {
        result = WS_ERROR_OUT_OF_MEMORY;
        goto out;
    }

    /* Allocate hash tables. */

    compiler->pragma_use_hash = ws_pragma_use_hash_create();
    if (compiler->pragma_use_hash == NULL) {
        result = WS_ERROR_OUT_OF_MEMORY;
        goto out;
    }

    compiler->functions_hash = ws_function_hash_create();
    if (compiler->functions_hash == NULL) {
        result = WS_ERROR_OUT_OF_MEMORY;
        goto out;
    }

    /* Allocate a byte-code module. */

    if (compiler->params.use_latin1_strings)
        string_encoding = WS_BC_STRING_ENC_ISO_8859_1;

    compiler->bc = ws_bc_alloc(string_encoding);
    if (compiler->bc == NULL) {
        result = WS_ERROR_OUT_OF_MEMORY;
        goto out;
    }

    /* Save the input stream. */
    compiler->input = input;

    /* Parse the input. */
#if WS_DEBUG
    global_compiler = compiler;
#endif /* WS_DEBUG */

    ws_yy_parse(compiler);

    /* Free all lexer's active not freed blocks.  If we have any blocks
       on the used list, our compilation was not successful. */
    {
        size_t j;

        for (j = 0; j < compiler->lexer_active_list_size; j++)
            ws_free(compiler->lexer_active_list[j]);
        ws_free(compiler->lexer_active_list);

        compiler->lexer_active_list = NULL;
    }

    WS_CHECK_COMPILE_ERROR();

    /* Sort functions if allowed and it helps. */
    if (!compiler->params.no_opt_sort_bc_functions
        && compiler->num_functions > 7) {
        WsUInt32 i;

        ws_info(compiler, "optimize: sorting functions");

        /* Fetch the usage counts from the functions hash. */
        for (i = 0; i < compiler->num_functions; i++) {
            WsFunctionHash *fh = ws_function_hash(compiler,
                                                  compiler->functions[i].name);
            compiler->functions[i].usage_count = fh->usage_count;
        }

        /* Sort functions.  */
        qsort(compiler->functions, compiler->num_functions,
              sizeof(compiler->functions[0]), sort_functions_cmp);

        /* Patch the function indexes. */
        for (i = 0; i < compiler->num_functions; i++) {
            WsFunctionHash *fh = ws_function_hash(compiler,
                                                  compiler->functions[i].name);
            compiler->functions[i].findex = i;
            fh->findex = i;
        }
    }

    /* Linearize functions */
    for (i = 0; i < compiler->num_functions; i++) {
        WsFunction *func = &compiler->functions[i];

        ws_info(compiler, "linearizing function `%s'...", func->name);

        compiler->pool_asm = ws_f_create(100 * 1024);
        if (compiler->pool_asm == NULL) {
            result = WS_ERROR_OUT_OF_MEMORY;
            goto out;
        }

        compiler->next_label = 0;
        compiler->asm_head = compiler->asm_tail = NULL;

        /* Create variables namespace. */
        compiler->next_vindex = 0;
        compiler->variables_hash = ws_variable_hash_create();
        if (compiler->variables_hash == NULL) {
            result = WS_ERROR_OUT_OF_MEMORY;
            goto out;
        }

        /* Define the formal arguments to the namespace. */
        for (li = func->params->head; li; li = li->next) {
            WsFormalParm *parm = li->data;

            ws_variable_define(compiler, parm->line, WS_FALSE, parm->name);
        }

        WS_CHECK_COMPILE_ERROR();

        /* Linearize it. */
        for (li = func->block->head; li; li = li->next)
            ws_stmt_linearize(compiler, li->data);

        WS_CHECK_COMPILE_ERROR();

        /* Optimize symbolic assembler.  This function does nothing if
           no optimizations were requested. */
        ws_asm_optimize(compiler);

        /* Print the resulting symbolic assembler if requested. */
        if (compiler->params.print_symbolic_assembler)
            ws_asm_print(compiler);

        WS_CHECK_COMPILE_ERROR();

        /* Generate byte-code */

        ws_buffer_init(&compiler->byte_code);
        ws_asm_linearize(compiler);

        WS_CHECK_COMPILE_ERROR();

        /* Disassemble the output if requested. */
        if (compiler->params.print_assembler)
            ws_asm_dasm(compiler, ws_buffer_ptr(&compiler->byte_code),
                        ws_buffer_len(&compiler->byte_code));

        /* Calculate the number of local variables */
        num_locals = compiler->next_vindex - func->params->num_items;

        /* Add the function to the byte-code module. */
        if (!ws_bc_add_function(compiler->bc, &findex,
                                func->externp ? func->name : NULL,
                                func->params->num_items,
                                num_locals,
                                ws_buffer_len(&compiler->byte_code),
                                ws_buffer_ptr(&compiler->byte_code))) {
            result = WS_ERROR_OUT_OF_MEMORY;
            goto out;
        }

        /* Cleanup and prepare for the next function. */

        ws_buffer_uninit(&compiler->byte_code);

        ws_hash_destroy(compiler->variables_hash);
        compiler->variables_hash = NULL;

        ws_f_destroy(compiler->pool_asm);
        compiler->pool_asm = NULL;
    }

    /* Linearize the byte-code structure. */
    if (!ws_bc_encode(compiler->bc, output_return, output_len_return))
        result = WS_ERROR_OUT_OF_MEMORY;

out:

    /* Cleanup. */

    ws_f_destroy(compiler->pool_stree);
    compiler->pool_stree = NULL;

    ws_hash_destroy(compiler->pragma_use_hash);
    compiler->pragma_use_hash = NULL;

    /* Free functions. */
    for (i = 0; i < compiler->num_functions; i++)
        ws_free(compiler->functions[i].name);
    ws_free(compiler->functions);

    ws_hash_destroy(compiler->functions_hash);
    compiler->functions_hash = NULL;

    ws_bc_free(compiler->bc);
    compiler->bc = NULL;

    compiler->input = NULL;

    ws_f_destroy(compiler->pool_asm);
    compiler->pool_asm = NULL;

    ws_hash_destroy(compiler->variables_hash);
    compiler->variables_hash = NULL;

    ws_buffer_uninit(&compiler->byte_code);

    /* All done. */
    return result;
}