コード例 #1
0
void ws_function(WsCompiler *compiler, WsBool externp, char *name,
                 WsUInt32 line, WsList *params, WsList *block)
{
    WsFunctionHash *hash;
    WsFunction *f = ws_realloc(compiler->functions,
                               ((compiler->num_functions + 1)
                                * sizeof(WsFunction)));

    if (f == NULL) {
        ws_free(name);
        ws_error_memory(compiler);
        return;
    }

    if (externp)
        compiler->num_extern_functions++;
    else
        compiler->num_local_functions++;

    compiler->functions = f;
    f = &compiler->functions[compiler->num_functions];

    f->findex = compiler->num_functions++;

    f->externp = externp;
    f->name = name;
    f->line = line;
    f->params = params;
    f->block = block;

    /* Update the function name hash. */

    hash = ws_function_hash(compiler, name);
    if (hash == NULL) {
        ws_error_memory(compiler);
        return;
    }

    if (hash->defined) {
        ws_src_error(compiler, line, "redefinition of `%s'", name);
        ws_src_error(compiler,
                     compiler->functions[hash->findex].line,
                     "`%s' previously defined here", name);
        return;
    }

    hash->defined = WS_TRUE;
    hash->findex = f->findex;
}
コード例 #2
0
void ws_expr_linearize(WsCompiler *compiler, WsExpression *expr)
{
    WsListItem *li;
    WsAsmIns *ins;

    switch (expr->type) {
    case WS_EXPR_COMMA:
        /* Linearize left. */
        ws_expr_linearize(compiler, expr->u.comma.left);

        /* Pop its result. */
        ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, WS_ASM_POP));

        /* Linearize right */
        ws_expr_linearize(compiler, expr->u.comma.right);
        break;

    case WS_EXPR_ASSIGN:
        {
            WsNamespace *ns = ws_variable_lookup(compiler,
                                                 expr->u.assign.identifier);

            if (ns == NULL) {
                /* Unknown identifier. */
                ws_src_error(compiler, expr->line, "unknown variable `%s'",
                             expr->u.symbol);
                return;
            }

            if (expr->u.assign.op == '=') {
                /* Evaluate the expression. */
                ws_expr_linearize(compiler, expr->u.assign.expr);

                /* Store the value to the variable. */
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line,
                                            WS_ASM_P_STORE_VAR, ns->vindex));
            } else if (expr->u.assign.op == tADDA) {
                /* Linearize the expression. */
                ws_expr_linearize(compiler, expr->u.assign.expr);

                /* Add it to the variable. */
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line,
                                            WS_ASM_ADD_ASG, ns->vindex));
            } else if (expr->u.assign.op == tSUBA) {
                /* Linearize the expression. */
                ws_expr_linearize(compiler, expr->u.assign.expr);

                /* Substract it from the variable. */
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line,
                                            WS_ASM_SUB_ASG, ns->vindex));
            } else {
                /* Load the old value from the variable. */
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line,
                                            WS_ASM_P_LOAD_VAR, ns->vindex));

                /* Evaluate the expression. */
                ws_expr_linearize(compiler, expr->u.assign.expr);

                /* Perform the operand. */
                ins = NULL;
                switch (expr->u.assign.op) {
                case tMULA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_MUL);
                    break;

                case tDIVA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_DIV);
                    break;

                case tREMA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_REM);
                    break;

                case tADDA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_ADD);
                    break;

                case tSUBA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_SUB);
                    break;

                case tLSHIFTA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_LSHIFT);
                    break;

                case tRSSHIFTA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_RSSHIFT);
                    break;

                case tRSZSHIFTA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_RSZSHIFT);
                    break;

                case tANDA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_AND);
                    break;

                case tXORA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_XOR);
                    break;

                case tORA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_OR);
                    break;

                case tIDIVA:
                    ins = ws_asm_ins(compiler, expr->line, WS_ASM_IDIV);
                    break;

                default:
                    ws_fatal("ws_expr_linearize(): unknown assignment operand %x",
                             expr->u.assign.op);
                    break;
                }
                ws_asm_link(compiler, ins);

                /* Store the value to the variable. */
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line,
                                            WS_ASM_P_STORE_VAR, ns->vindex));
            }
            /* The value of the assignment expression is the value
               assigned.  So, we must load the value from the variable.
               This would also be a good place for the `dup' operand but
               we lose since we don't have it. */
            ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
                                                  WS_ASM_P_LOAD_VAR, ns->vindex));
        }
        break;

    case WS_EXPR_CONDITIONAL:
        {
            WsAsmIns *l_else = ws_asm_label(compiler, expr->line);
            WsAsmIns *l_end = ws_asm_label(compiler, expr->line);

            /* Linearize condition. */
            ws_expr_linearize(compiler, expr->u.conditional.e_cond);

            /* If the result if false, jump to the else-branch. */
            ws_asm_link(compiler, ws_asm_branch(compiler, expr->line,
                                                WS_ASM_P_TJUMP, l_else));

            /* Linearize the then-expression and jump out. */
            ws_expr_linearize(compiler, expr->u.conditional.e_then);
            ws_asm_link(compiler, ws_asm_branch(compiler, expr->line,
                                                WS_ASM_P_JUMP, l_end));

            /* The else-branch. */
            ws_asm_link(compiler, l_else);
            ws_expr_linearize(compiler, expr->u.conditional.e_else);

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

    case WS_EXPR_LOGICAL:
        {
            WsAsmIns *l_out = ws_asm_label(compiler, expr->line);

            /* Linearize the left-hand size expression. */
            ws_expr_linearize(compiler, expr->u.logical.left);

            /* Short-circuit check.  The type of the logical expression is
                      the short-circuit byte-code operand. */
            ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
                                             expr->u.logical.type));
            ws_asm_link(compiler, ws_asm_branch(compiler, expr->line,
                                                WS_ASM_P_TJUMP, l_out));

            /* Linearize the right-hand size expression. */
            ws_expr_linearize(compiler, expr->u.logical.right);

            /* The result of a logical expression should be boolean.
             * Control statements do automatic conversion, but typeof()
	     * does not. */
            ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
                                         WS_ASM_TOBOOL));

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

    case WS_EXPR_BINARY:
        /* Linearize left and right. */
        ws_expr_linearize(compiler, expr->u.binary.left);
        ws_expr_linearize(compiler, expr->u.binary.right);

        /* The type of the binary expression is the byte-code opcode. */
        ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
                                         expr->u.binary.type));
        break;

    case WS_EXPR_UNARY:
        /* Linearize the expression. */
        ws_expr_linearize(compiler, expr->u.unary.expr);

        /* The type of the unary expression is the byte-code opcode. */
        ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
                                         expr->u.unary.type));
        break;

    case WS_EXPR_UNARY_VAR:
        {
            WsNamespace *ns = ws_variable_lookup(compiler,
                                                 expr->u.unary_var.variable);
            if (ns == NULL) {
                /* An unknown identifier. */
                ws_src_error(compiler, expr->line, "unknown variable `%s'",
                             expr->u.unary_var.variable);
                return;
            }

            /* First, do the operation. */
            if (expr->u.unary_var.addp)
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line, WS_ASM_P_INCR_VAR,
                                            ns->vindex));
            else
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line, WS_ASM_DECR_VAR,
                                            ns->vindex));

            /* Second, load the new value of the variable. */
            ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
                                                  WS_ASM_P_LOAD_VAR, ns->vindex));
        }
        break;

    case WS_EXPR_POSTFIX_VAR:
        {
            WsNamespace *ns = ws_variable_lookup(compiler,
                                                 expr->u.postfix_var.variable);
            if (ns == NULL) {
                /* An unknown identifier. */
                ws_src_error(compiler, expr->line, "unknown variable `%s'",
                             expr->u.postfix_var.variable);
                return;
            }

            /* First, load the old value of the variable. */
            ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
                                                  WS_ASM_P_LOAD_VAR, ns->vindex));

            /* Second, do the operation. */
            if (expr->u.unary_var.addp)
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line, WS_ASM_P_INCR_VAR,
                                            ns->vindex));
            else
                ws_asm_link(compiler,
                            ws_asm_variable(compiler, expr->line, WS_ASM_DECR_VAR,
                                            ns->vindex));
        }
        break;

    case WS_EXPR_CALL:
        /* First, evaluate the arguments. */
        for (li = expr->u.call.arguments->head; li; li = li->next)
            ws_expr_linearize(compiler, li->data);

        /* Second, emit the call instruction. */
        switch (expr->u.call.type) {
        case ' ': 		/* LocalScriptFunctionCall */
            {
                WsFunctionHash *f = ws_function_hash(compiler, expr->u.call.name);

                if (f == NULL || !f->defined)
                {
                    ws_src_error(compiler, expr->line,
                                 "unknown local function `%s'",
                                 expr->u.call.name);
                    return;
                }

                /* Check that the function is called with correct amount
                          of arguments. */
                if (expr->u.call.arguments->num_items
                    != compiler->functions[f->findex].params->num_items)
                {
                    ws_src_error(compiler, expr->line,
                                 "invalid amount of arguments for `%s': "
                                 "expected %u, got %u",
                                 expr->u.call.name,
                                 compiler->functions[f->findex].params->num_items,
                                 expr->u.call.arguments->num_items);
                    return;
                }

                /* Emit assembler. */
                ws_asm_link(compiler, ws_asm_call(compiler, expr->line,
                                                  f->findex));
            }
            break;

        case '#': 		/* ExternalScriptFunctionCall */
            {
                WsPragmaUse *use = ws_hash_get(compiler->pragma_use_hash,
                                               expr->u.call.base);
                WsUInt16 findex;

                if (use == NULL)
                {
                    ws_src_error(compiler, expr->line,
                                 "unknown external compilation unit `%s'",
                                 expr->u.call.base);
                    return;
                }

                /* Insert the function name to the byte-code pool. */
                if (!ws_bc_add_const_utf8_string(
                        compiler->bc, &findex,
                        (unsigned char *) expr->u.call.name,
                        strlen(expr->u.call.name)))
                {
                    ws_error_memory(compiler);
                    return;
                }

                /* Emit assembler. */
                ws_asm_link(compiler,
                            ws_asm_call_url(compiler, expr->line,
                                            findex, use->urlindex,
                                            expr->u.call.arguments->num_items));
            }
            break;

        case '.': 		/* LibraryFunctionCall */
            {
                WsUInt16 lindex;
                WsUInt8 findex;
                WsUInt8 num_args;
                WsBool lindex_found;
                WsBool findex_found;

                if (!ws_stdlib_function(expr->u.call.base, expr->u.call.name,
                                        &lindex, &findex, &num_args,
                                        &lindex_found, &findex_found))
                {
                    if (!lindex_found)
                        ws_src_error(compiler, expr->line,
                                     "unknown system library `%s'",
                                     expr->u.call.base);
                    else
                        ws_src_error(compiler, expr->line,
                                     "unknown library function `%s.%s'",
                                     expr->u.call.base, expr->u.call.name);

                    return;
                }
                /* Check the argument count. */
                if (expr->u.call.arguments->num_items != num_args)
                {
                    ws_src_error(compiler, expr->line,
                                 "invalid amount of arguments for `%s.%s': "
                                 "expected %u, got %u",
                                 expr->u.call.base, expr->u.call.name,
                                 num_args, expr->u.call.arguments->num_items);
                    return;
                }

                /* Emit assembler. */
                ws_asm_link(compiler, ws_asm_call_lib(compiler, expr->line, findex,
                                                      lindex));
            }
            break;

        default:
            ws_fatal("ws_expr_linearize(): unknown call expression type %x",
                     expr->u.call.type);
            break;
        }
        break;

    case WS_EXPR_SYMBOL:
        {
            WsNamespace *ns = ws_variable_lookup(compiler, expr->u.symbol);

            if (ns == NULL) {
                /* An unknown identifier. */
                ws_src_error(compiler, expr->line, "unknown variable `%s'",
                             expr->u.symbol);
                return;
            }

            /* Create a load instruction for the variable. */
            ws_asm_link(compiler, ws_asm_variable(compiler, expr->line,
                                                  WS_ASM_P_LOAD_VAR, ns->vindex));
        }
        break;

    case WS_EXPR_CONST_INVALID:
        ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
                                         WS_ASM_CONST_INVALID));
        break;

    case WS_EXPR_CONST_TRUE:
        ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
                                         WS_ASM_CONST_TRUE));
        break;

    case WS_EXPR_CONST_FALSE:
        ws_asm_link(compiler, ws_asm_ins(compiler, expr->line,
                                         WS_ASM_CONST_FALSE));
        break;


    case WS_EXPR_CONST_INTEGER:
        if (expr->u.integer.ival == 0)
            ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_0);
        else if (expr->u.integer.ival == 1 && expr->u.integer.sign == 1)
            ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_1);
        else {
            WsUInt16 cindex;
	    WsInt32 ival;

            if (expr->u.integer.sign >= 0) {
		if (expr->u.integer.ival > (WsUInt32) WS_INT32_MAX)
		    ws_src_error(compiler, expr->line,
                                 "integer literal too large");
                ival = expr->u.integer.ival;
	    } else {
                if (expr->u.integer.ival > (WsUInt32) WS_INT32_MAX + 1)
		    ws_src_error(compiler, expr->line, "integer too small");
                ival = - (WsInt32) expr->u.integer.ival;
	    }

            if (!ws_bc_add_const_int(compiler->bc, &cindex, ival)) {
                ws_error_memory(compiler);
                return;
            }
            ins = ws_asm_load_const(compiler, expr->line, cindex);
        }

        ws_asm_link(compiler, ins);
        break;

    case WS_EXPR_CONST_FLOAT:
        {
            WsUInt16 cindex;

            if (!ws_bc_add_const_float(compiler->bc, &cindex, expr->u.fval)) {
                ws_error_memory(compiler);
                return;
            }

            ws_asm_link(compiler, ws_asm_load_const(compiler, expr->line, cindex));
        }
        break;

    case WS_EXPR_CONST_STRING:
        if (expr->u.string.len == 0)
            ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_ES);
        else {
            WsUInt16 cindex;

            if (!ws_bc_add_const_utf8_string(compiler->bc, &cindex,
                                             expr->u.string.data,
                                             expr->u.string.len)) {
                ws_error_memory(compiler);
                return;
            }
            ins = ws_asm_load_const(compiler, expr->line, cindex);
        }

        ws_asm_link(compiler, ins);
        break;
    }
}
コード例 #3
0
ファイル: ws.c プロジェクト: 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;
}