wsstree.c
资源名称:gateway-1.2.1 [点击查看]
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:43k
源码类别:
手机WAP编程
开发平台:
WINDOWS
- /*
- *
- * wsstree.c
- *
- * Author: Markku Rossi <mtr@iki.fi>
- *
- * Copyright (c) 1999-2000 WAPIT OY LTD.
- * All rights reserved.
- *
- * Syntax tree creation, manipulation and byte-code assembler
- * generation.
- *
- */
- #include "wsint.h"
- #include "wsgram.h"
- /* TODO: Constant folding. */
- /********************* Misc syntax tree structures **********************/
- WsVarDec *ws_variable_declaration(WsCompilerPtr compiler,
- char *name, WsExpression *expr)
- {
- WsVarDec *vardec = ws_f_malloc(compiler->pool_stree, sizeof(*vardec));
- if (vardec == NULL)
- ws_error_memory(compiler);
- else {
- vardec->name = name;
- vardec->expr = expr;
- }
- return vardec;
- }
- WsFormalParm *ws_formal_parameter(WsCompilerPtr compiler,
- WsUInt32 line, char *name)
- {
- WsFormalParm *parm = ws_f_malloc(compiler->pool_stree, sizeof(*parm));
- if (parm == NULL)
- ws_error_memory(compiler);
- else {
- parm->line = line;
- parm->name = name;
- }
- return parm;
- }
- /********************* Linked list **************************************/
- WsList *ws_list_new(WsCompiler *compiler)
- {
- WsList *list = ws_f_calloc(compiler->pool_stree, 1, sizeof(*list));
- if (list == NULL)
- ws_error_memory(compiler);
- return list;
- }
- void ws_list_append(WsCompiler *compiler, WsList *list, void *value)
- {
- WsListItem *item;
- if (list == NULL)
- /* A recovery code for previous memory allocation problems. */
- return;
- item = ws_f_calloc(compiler->pool_stree, 1, sizeof(*item));
- if (item == NULL) {
- ws_error_memory(compiler);
- return;
- }
- item->data = value;
- if (list->tail) {
- list->tail->next = item;
- list->tail = item;
- } else
- list->head = list->tail = item;
- list->num_items++;
- }
- /********************* Namespace for arguments and locals ***************/
- static void variable_hash_destructor(void *item, void *context)
- {
- ws_free(item);
- }
- WsHashPtr ws_variable_hash_create(void)
- {
- return ws_hash_create(variable_hash_destructor, NULL);
- }
- WsNamespace *ws_variable_define(WsCompilerPtr compiler, WsUInt32 line,
- WsBool variablep, char *name)
- {
- WsNamespace *ns;
- /* Is the symbol already defined? */
- ns = ws_hash_get(compiler->variables_hash, name);
- if (ns) {
- ws_src_error(compiler, line, "redeclaration of `%s'", name);
- ws_src_error(compiler, ns->line, "`%s' previously declared here", name);
- return NULL;
- }
- /* Can we still define more variables? */
- if (compiler->next_vindex > 255) {
- /* No we can't. */
- ws_src_error(compiler, line, "too many local variables");
- return NULL;
- }
- ns = ws_calloc(1, sizeof(*ns));
- if (ns == NULL) {
- ws_error_memory(compiler);
- return NULL;
- }
- ns->line = line;
- ns->vindex = compiler->next_vindex++;
- if (!ws_hash_put(compiler->variables_hash, name, ns)) {
- ws_free(ns);
- ws_error_memory(compiler);
- return NULL;
- }
- return ns;
- }
- WsNamespace *ws_variable_lookup(WsCompilerPtr compiler, char *name)
- {
- return ws_hash_get(compiler->variables_hash, name);
- }
- /********************* Top-level declarations ***************************/
- /* External compilation units. */
- static void pragma_use_hash_destructor(void *item, void *context)
- {
- ws_free(item);
- }
- WsHashPtr ws_pragma_use_hash_create(void)
- {
- return ws_hash_create(pragma_use_hash_destructor, NULL);
- }
- void ws_pragma_use(WsCompilerPtr compiler, WsUInt32 line, char *identifier,
- WsUtf8String *url)
- {
- WsPragmaUse *u = ws_calloc(1, sizeof(*u));
- WsPragmaUse *uold;
- /* Do we already know this pragma? */
- uold = ws_hash_get(compiler->pragma_use_hash, identifier);
- if (uold) {
- ws_src_error(compiler, line, "redefinition of pragma `%s'", identifier);
- ws_src_error(compiler, uold->line, "`%s' previously defined here",
- identifier);
- goto error_cleanup;
- }
- if (u == NULL)
- goto error;
- u->line = line;
- /* Insert the URL to the byte-code module. */
- if (!ws_bc_add_const_utf8_string(compiler->bc, &u->urlindex, url->data,
- url->len))
- goto error;
- /* Add it to the use pragma hash. */
- if (!ws_hash_put(compiler->pragma_use_hash, identifier, u))
- goto error;
- /* Cleanup. */
- ws_lexer_free_block(compiler, identifier);
- ws_lexer_free_utf8(compiler, url);
- return;
- /* Error handling. */
- error:
- ws_error_memory(compiler);
- error_cleanup:
- ws_free(u);
- ws_lexer_free_block(compiler, identifier);
- ws_lexer_free_utf8(compiler, url);
- }
- /* MetaBody of the `use meta' pragmas. */
- WsPragmaMetaBody *ws_pragma_meta_body(WsCompilerPtr compiler,
- WsUtf8String *property_name,
- WsUtf8String *content,
- WsUtf8String *scheme)
- {
- WsPragmaMetaBody *mb = ws_calloc(1, sizeof(*mb));
- if (mb == NULL) {
- ws_error_memory(compiler);
- return NULL;
- }
- mb->property_name = property_name;
- mb->content = content;
- mb->scheme = scheme;
- return mb;
- }
- void ws_pragma_meta_body_free(WsCompilerPtr compiler, WsPragmaMetaBody *mb)
- {
- if (mb == NULL)
- return;
- ws_lexer_free_utf8(compiler, mb->property_name);
- ws_lexer_free_utf8(compiler, mb->content);
- ws_lexer_free_utf8(compiler, mb->scheme);
- ws_free(mb);
- }
- /* Functions. */
- static void function_hash_destructor(void *item, void *context)
- {
- ws_free(item);
- }
- WsHashPtr ws_function_hash_create(void)
- {
- return ws_hash_create(function_hash_destructor, NULL);
- }
- WsFunctionHash *ws_function_hash(WsCompilerPtr compiler, char *name)
- {
- WsFunctionHash *i = ws_hash_get(compiler->functions_hash, name);
- if (i)
- return i;
- /* Must create a new mapping. */
- i = ws_calloc(1, sizeof(*i));
- if (i == NULL) {
- ws_error_memory(compiler);
- return NULL;
- }
- if (!ws_hash_put(compiler->functions_hash, name, i)) {
- ws_free(i);
- ws_error_memory(compiler);
- return NULL;
- }
- return i;
- }
- 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;
- }
- /********************* Expressions **************************************/
- 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;
- }
- }
- /* Constructors. */
- static WsExpression *expr_alloc(WsCompiler *compiler,
- WsExpressionType type, WsUInt32 line)
- {
- WsExpression *expr = ws_f_calloc(compiler->pool_stree, 1, sizeof(*expr));
- if (expr == NULL)
- ws_error_memory(compiler);
- else {
- expr->type = type;
- expr->line = line;
- }
- return expr;
- }
- WsExpression *ws_expr_comma(WsCompilerPtr compiler, WsUInt32 line,
- WsExpression *left, WsExpression *right)
- {
- WsExpression *expr = expr_alloc(compiler, WS_EXPR_COMMA, line);
- if (expr) {
- expr->u.comma.left = left;
- expr->u.comma.right = right;
- }
- return expr;
- }
- WsExpression *ws_expr_assign(WsCompilerPtr compiler, WsUInt32 line,
- char *identifier, int op, WsExpression *expr)
- {
- WsExpression *e = expr_alloc(compiler, WS_EXPR_ASSIGN, line);
- if (e) {
- e->u.assign.identifier = ws_f_strdup(compiler->pool_stree, identifier);
- if (e->u.assign.identifier == NULL)
- ws_error_memory(compiler);
- e->u.assign.op = op;
- e->u.assign.expr = expr;
- }
- /* Free the identifier symbol since it allocated from the system
- heap. */
- ws_lexer_free_block(compiler, identifier);
- return e;
- }
- WsExpression *ws_expr_conditional(WsCompilerPtr compiler, WsUInt32 line,
- WsExpression *e_cond, WsExpression *e_then,
- WsExpression *e_else)
- {
- WsExpression *e = expr_alloc(compiler, WS_EXPR_CONDITIONAL, line);
- if (e) {
- e->u.conditional.e_cond = e_cond;
- e->u.conditional.e_then = e_then;
- e->u.conditional.e_else = e_else;
- }
- return e;
- }
- WsExpression *ws_expr_logical(WsCompilerPtr compiler, WsUInt32 line,
- int type, WsExpression *left, WsExpression *right)
- {
- WsExpression *expr = expr_alloc(compiler, WS_EXPR_LOGICAL, line);
- if (expr) {
- expr->u.logical.type = type;
- expr->u.logical.left = left;
- expr->u.logical.right = right;
- }
- return expr;
- }
- WsExpression *ws_expr_binary(WsCompilerPtr compiler, WsUInt32 line,
- int type, WsExpression *left, WsExpression *right)
- {
- WsExpression *expr = expr_alloc(compiler, WS_EXPR_BINARY, line);
- if (expr) {
- expr->u.binary.type = type;
- expr->u.binary.left = left;
- expr->u.binary.right = right;
- }
- return expr;
- }
- WsExpression *ws_expr_unary(WsCompilerPtr compiler, WsUInt32 line, int type,
- WsExpression *expression)
- {
- WsExpression *expr;
- /* Handle negative integers here as a special case of constant folding,
- * in order to get -2147483648 right. */
- if (type == WS_ASM_UMINUS && expression->type == WS_EXPR_CONST_INTEGER) {
- expression->u.integer.sign = - expression->u.integer.sign;
- return expression;
- }
- expr = expr_alloc(compiler, WS_EXPR_UNARY, line);
- if (expr) {
- expr->u.unary.type = type;
- expr->u.unary.expr = expression;
- }
- return expr;
- }
- WsExpression *ws_expr_unary_var(WsCompilerPtr compiler, WsUInt32 line,
- WsBool addp, char *variable)
- {
- WsExpression *expr = expr_alloc(compiler, WS_EXPR_UNARY_VAR, line);
- if (expr) {
- expr->u.unary_var.addp = addp;
- expr->u.unary_var.variable = ws_f_strdup(compiler->pool_stree, variable);
- if (expr->u.unary_var.variable == NULL)
- ws_error_memory(compiler);
- }
- ws_lexer_free_block(compiler, variable);
- return expr;
- }
- WsExpression *ws_expr_postfix_var(WsCompilerPtr compiler, WsUInt32 line,
- WsBool addp, char *variable)
- {
- WsExpression *expr = expr_alloc(compiler, WS_EXPR_POSTFIX_VAR, line);
- if (expr) {
- expr->u.postfix_var.addp = addp;
- expr->u.postfix_var.variable = ws_f_strdup(compiler->pool_stree,
- variable);
- if (expr->u.postfix_var.variable == NULL)
- ws_error_memory(compiler);
- }
- ws_lexer_free_block(compiler, variable);
- return expr;
- }
- WsExpression *ws_expr_call(WsCompiler *compiler, WsUInt32 line,
- int type, char *base, char *name, WsList *arguments)
- {
- WsExpression *expr = expr_alloc(compiler, WS_EXPR_CALL, line);
- if (expr) {
- expr->u.call.type = type;
- expr->u.call.base = ws_f_strdup(compiler->pool_stree, base);
- expr->u.call.name = ws_f_strdup(compiler->pool_stree, name);
- expr->u.call.arguments = arguments;
- if ((base && expr->u.call.base == NULL)
- || (name && expr->u.call.name == NULL))
- ws_error_memory(compiler);
- }
- ws_lexer_free_block(compiler, base);
- ws_lexer_free_block(compiler, name);
- return expr;
- }
- WsExpression *ws_expr_symbol(WsCompiler *compiler, WsUInt32 line,
- char *identifier)
- {
- WsExpression *expr = expr_alloc(compiler, WS_EXPR_SYMBOL, line);
- if (expr) {
- expr->u.symbol = ws_f_strdup(compiler->pool_stree, identifier);
- if (expr->u.symbol == NULL)
- ws_error_memory(compiler);
- }
- ws_lexer_free_block(compiler, identifier);
- return expr;
- }
- WsExpression *ws_expr_const_invalid(WsCompiler *compiler, WsUInt32 line)
- {
- return expr_alloc(compiler, WS_EXPR_CONST_INVALID, line);
- }
- WsExpression *ws_expr_const_true(WsCompiler *compiler, WsUInt32 line)
- {
- return expr_alloc(compiler, WS_EXPR_CONST_TRUE, line);
- }
- WsExpression *ws_expr_const_false(WsCompiler *compiler, WsUInt32 line)
- {
- return expr_alloc(compiler, WS_EXPR_CONST_FALSE, line);
- }
- WsExpression *ws_expr_const_integer(WsCompiler *compiler, WsUInt32 line,
- WsUInt32 ival)
- {
- WsExpression *expr = expr_alloc(compiler, WS_EXPR_CONST_INTEGER, line);
- if (expr) {
- expr->u.integer.sign = 1;
- expr->u.integer.ival = ival;
- }
- return expr;
- }
- WsExpression *ws_expr_const_float(WsCompiler *compiler, WsUInt32 line,
- WsFloat fval)
- {
- WsExpression *expr = expr_alloc(compiler, WS_EXPR_CONST_FLOAT, line);
- if (expr)
- expr->u.fval = fval;
- return expr;
- }
- WsExpression *ws_expr_const_string(WsCompiler *compiler, WsUInt32 line,
- WsUtf8String *string)
- {
- WsExpression *expr = expr_alloc(compiler, WS_EXPR_CONST_STRING, line);
- if (expr) {
- expr->u.string.len = string->len;
- expr->u.string.data = ws_f_memdup(compiler->pool_stree,
- string->data, string->len);
- if (expr->u.string.data == NULL)
- ws_error_memory(compiler);
- }
- ws_lexer_free_utf8(compiler, string);
- return expr;
- }
- /********************* Statements ***************************************/
- /* Linearize the variable declaration list `list'. */
- static void linearize_variable_init(WsCompiler *compiler, WsList *list,
- WsUInt32 line)
- {
- WsNamespace *ns;
- WsListItem *li;
- /* For each variable, declared with this list. */
- for (li = list->head; li; li = li->next) {
- WsVarDec *vardec = li->data;
- ns = ws_variable_define(compiler, line, WS_TRUE, vardec->name);
- if (ns && vardec->expr) {
- ws_expr_linearize(compiler, vardec->expr);
- /* Emit an instruction to store the initialization
- value to the variable. */
- ws_asm_link(compiler,
- ws_asm_variable(compiler, line, WS_ASM_P_STORE_VAR,
- ns->vindex));
- }
- }
- }
- 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;
- }
- }
- /* Constructors. */
- static WsStatement *stmt_alloc(WsCompiler *compiler, WsStatementType type,
- WsUInt32 first_line, WsUInt32 last_line)
- {
- WsStatement *stmt = ws_f_calloc(compiler->pool_stree, 1, sizeof(*stmt));
- if (stmt == NULL)
- ws_error_memory(compiler);
- else {
- stmt->type = type;
- stmt->first_line = first_line;
- stmt->last_line = last_line;
- }
- return stmt;
- }
- WsStatement *ws_stmt_block(WsCompiler *compiler, WsUInt32 fline,
- WsUInt32 lline, WsList *block)
- {
- WsStatement *stmt = stmt_alloc(compiler, WS_STMT_BLOCK, fline, lline);
- if (stmt)
- stmt->u.block = block;
- return stmt;
- }
- WsStatement *ws_stmt_variable(WsCompilerPtr compiler, WsUInt32 line,
- WsList *variables)
- {
- WsStatement *stmt = stmt_alloc(compiler, WS_STMT_VARIABLE, line, line);
- if (stmt)
- stmt->u.var = variables;
- return stmt;
- }
- WsStatement *ws_stmt_empty(WsCompiler *compiler, WsUInt32 line)
- {
- return stmt_alloc(compiler, WS_STMT_EMPTY, line, line);
- }
- WsStatement *ws_stmt_expr(WsCompiler *compiler, WsUInt32 line,
- WsExpression *expr)
- {
- WsStatement *stmt = stmt_alloc(compiler, WS_STMT_EXPR, line, line);
- if (stmt)
- stmt->u.expr = expr;
- return stmt;
- }
- WsStatement *ws_stmt_if(WsCompiler *compiler, WsUInt32 line,
- WsExpression *expr, WsStatement *s_then,
- WsStatement *s_else)
- {
- WsStatement *stmt = stmt_alloc(compiler, WS_STMT_IF, line, line);
- if (stmt) {
- stmt->u.s_if.expr = expr;
- stmt->u.s_if.s_then = s_then;
- stmt->u.s_if.s_else = s_else;
- }
- return stmt;
- }
- WsStatement *ws_stmt_for(WsCompilerPtr compiler, WsUInt32 line, WsList *init,
- WsExpression *e1, WsExpression *e2, WsExpression *e3,
- WsStatement *stmt_body)
- {
- WsStatement *stmt = stmt_alloc(compiler, WS_STMT_FOR, line, line);
- if (stmt) {
- stmt->u.s_for.init = init;
- stmt->u.s_for.e1 = e1;
- stmt->u.s_for.e2 = e2;
- stmt->u.s_for.e3 = e3;
- stmt->u.s_for.stmt = stmt_body;
- }
- return stmt;
- }
- WsStatement *ws_stmt_while(WsCompiler *compiler, WsUInt32 line,
- WsExpression *expr, WsStatement *stmt_arg)
- {
- WsStatement *stmt = stmt_alloc(compiler, WS_STMT_WHILE, line, line);
- if (stmt) {
- stmt->u.s_while.expr = expr;
- stmt->u.s_while.stmt = stmt_arg;
- }
- return stmt;
- }
- WsStatement *ws_stmt_continue(WsCompiler *compiler, WsUInt32 line)
- {
- return stmt_alloc(compiler, WS_STMT_CONTINUE, line, line);
- }
- WsStatement *ws_stmt_break(WsCompiler *compiler, WsUInt32 line)
- {
- return stmt_alloc(compiler, WS_STMT_BREAK, line, line);
- }
- WsStatement *ws_stmt_return(WsCompilerPtr compiler, WsUInt32 line,
- WsExpression *expr)
- {
- WsStatement *stmt = stmt_alloc(compiler, WS_STMT_RETURN, line, line);
- if (stmt)
- stmt->u.expr = expr;
- return stmt;
- }