Ejemplo n.º 1
0
/* Parse and emit initializer code for target variable in statements such as
 * int b[] = {0, 1, 2, 3}. Generate a series of assignment operations on
 * references to target variable.
 */
static struct block *initializer(struct block *block, struct var target)
{
    assert(target.kind == DIRECT);

    /* Do not care about cv-qualifiers here. */
    target.type = unwrapped(target.type);

    if (peek().token == '{') {
        block = object_initializer(block, target);
    } else {
        block = assignment_expression(block);
        if (!target.symbol->depth && block->expr.kind != IMMEDIATE) {
            error("Initializer must be computable at load time.");
            exit(1);
        }
        if (target.kind == DIRECT && !target.type->size) {
            assert(!target.offset);
            assert(is_string(block->expr));
            assert(is_array(block->expr.type));

            /* Complete type based on string literal. Evaluation does not have
             * the required context to do this logic. */
            ((struct symbol *) target.symbol)->type.size =
                block->expr.type->size;
            target.type = block->expr.type;
        }
        eval_assign(block, target, block->expr);
    }

    return block;
}
Ejemplo n.º 2
0
struct block *assignment_expression(struct block *block)
{
    struct var target;

    block = conditional_expression(block);
    target = block->expr;
    switch (peek().token) {
    case '=':
        consume('=');
        block = assignment_expression(block);
        break;
    case MUL_ASSIGN:
        consume(MUL_ASSIGN);
        block = assignment_expression(block);
        block->expr = eval_expr(block, IR_OP_MUL, target, block->expr);
        break;
    case DIV_ASSIGN:
        consume(DIV_ASSIGN);
        block = assignment_expression(block);
        block->expr = eval_expr(block, IR_OP_DIV, target, block->expr);
        break;
    case MOD_ASSIGN:
        consume(MOD_ASSIGN);
        block = assignment_expression(block);
        block->expr = eval_expr(block, IR_OP_MOD, target, block->expr);
        break;
    case PLUS_ASSIGN:
        consume(PLUS_ASSIGN);
        block = assignment_expression(block);
        block->expr = eval_expr(block, IR_OP_ADD, target, block->expr);
        break;
    case MINUS_ASSIGN:
        consume(MINUS_ASSIGN);
        block = assignment_expression(block);
        block->expr = eval_expr(block, IR_OP_SUB, target, block->expr);
        break;
    case AND_ASSIGN:
        consume(AND_ASSIGN);
        block = assignment_expression(block);
        block->expr = eval_expr(block, IR_OP_AND, target, block->expr);
        break;
    case OR_ASSIGN:
        consume(OR_ASSIGN);
        block = assignment_expression(block);
        block->expr = eval_expr(block, IR_OP_OR, target, block->expr);
        break;
    case XOR_ASSIGN:
        consume(XOR_ASSIGN);
        block = assignment_expression(block);
        block->expr = eval_expr(block, IR_OP_XOR, target, block->expr);
        break;
    default:
        return block;
    }

    block->expr = eval_assign(block, target, block->expr);
    return block;
}
Ejemplo n.º 3
0
Archivo: interp.c Proyecto: sbstp/zeta
/**
Evaluate a function call
*/
value_t eval_call(
    clos_t* callee,
    array_t* arg_exprs,
    clos_t* caller,
    value_t* caller_locals
)
{
    ast_fun_t* fptr = callee->fun;
    assert (fptr != NULL);

    if (arg_exprs->len != fptr->param_decls->len)
    {
        printf("argument count mismatch\n");
        exit(-1);
    }

    // Allocate space for the local variables
    value_t* callee_locals = alloca(
        sizeof(value_t) * fptr->local_decls->len
    );

    // Allocate mutable cells for the escaping variables
    for (size_t i = 0; i < fptr->esc_locals->len; ++i)
    {
        ast_decl_t* decl = array_get(fptr->esc_locals, i).word.decl;
        assert (decl->esc);
        assert (decl->idx < fptr->local_decls->len);
        callee_locals[decl->idx] = value_from_obj((heapptr_t)cell_alloc());
    }

    // Evaluate the argument values
    for (size_t i = 0; i < arg_exprs->len; ++i)
    {
        //printf("evaluating arg %ld\n", i);

        heapptr_t param_decl = array_get_ptr(fptr->param_decls, i);

        // Evaluate the parameter value
        value_t arg_val = eval_expr(
            array_get_ptr(arg_exprs, i),
            caller,
            caller_locals
        );

        // Assign the value to the parameter
        eval_assign(
            param_decl,
            arg_val,
            callee,
            callee_locals
        );
    }

    // Evaluate the unit function body in the local frame
    return eval_expr(fptr->body_expr, callee, callee_locals);
}
Ejemplo n.º 4
0
static struct block *unary_expression(struct block *block)
{
    struct var value;

    switch (peek().token) {
    case '&':
        consume('&');
        block = cast_expression(block);
        block->expr = eval_addr(block, block->expr);
        break;
    case '*':
        consume('*');
        block = cast_expression(block);
        block->expr = eval_deref(block, block->expr);
        break;
    case '!':
        consume('!');
        block = cast_expression(block);
        block->expr = eval_expr(block, IR_OP_EQ, var_int(0), block->expr);
        break;
    case '~':
        consume('~');
        block = cast_expression(block);
        block->expr = eval_expr(block, IR_NOT, block->expr);
        break;
    case '+':
        consume('+');
        block = cast_expression(block);
        block->expr.lvalue = 0;
        break;
    case '-':
        consume('-');
        block = cast_expression(block);
        block->expr = eval_expr(block, IR_OP_SUB, var_int(0), block->expr);
        break;
    case SIZEOF: {
        struct typetree *type;
        struct block *head = cfg_block_init(), *tail;
        consume(SIZEOF);
        if (peek().token == '(') {
            switch (peekn(2).token) {
            case FIRST(type_name):
                consume('(');
                type = declaration_specifiers(NULL);
                if (peek().token != ')') {
                    type = declarator(type, NULL);
                }
                consume(')');
                break;
            default:
                tail = unary_expression(head);
                type = (struct typetree *) tail->expr.type;
                break;
            }
        } else {
            tail = unary_expression(head);
            type = (struct typetree *) tail->expr.type;
        }
        if (is_function(type)) {
            error("Cannot apply 'sizeof' to function type.");
        }
        if (!size_of(type)) {
            error("Cannot apply 'sizeof' to incomplete type.");
        }
        block->expr = var_int(size_of(type));
        break;
    }
    case INCREMENT:
        consume(INCREMENT);
        block = unary_expression(block);
        value = block->expr;
        block->expr = eval_expr(block, IR_OP_ADD, value, var_int(1));
        block->expr = eval_assign(block, value, block->expr);
        break;
    case DECREMENT:
        consume(DECREMENT);
        block = unary_expression(block);
        value = block->expr;
        block->expr = eval_expr(block, IR_OP_SUB, value, var_int(1));
        block->expr = eval_assign(block, value, block->expr);
        break;
    default:
        block = postfix_expression(block);
        break;
    }

    return block;
}
Ejemplo n.º 5
0
static struct block *postfix_expression(struct block *block)
{
    struct var root;

    block = primary_expression(block);
    root = block->expr;

    while (1) {
        const struct member *field;
        const struct typetree *type;
        struct var expr, copy, *arg;
        struct token tok;
        int i, j;

        switch ((tok = peek()).token) {
        case '[':
            do {
                /* Evaluate a[b] = *(a + b). The semantics of pointer arithmetic
                 * takes care of multiplying b with the correct width. */
                consume('[');
                block = expression(block);
                root = eval_expr(block, IR_OP_ADD, root, block->expr);
                root = eval_deref(block, root);
                consume(']');
            } while (peek().token == '[');
            break;
        case '(':
            type = root.type;
            if (is_pointer(root.type) && is_function(root.type->next))
                type = type_deref(root.type);
            else if (!is_function(root.type)) {
                error("Expression must have type pointer to function, was %t.",
                    root.type);
                exit(1);
            }
            consume('(');
            arg = calloc(nmembers(type), sizeof(*arg));
            for (i = 0; i < nmembers(type); ++i) {
                if (peek().token == ')') {
                    error("Too few arguments, expected %d but got %d.",
                        nmembers(type), i);
                    exit(1);
                }
                block = assignment_expression(block);
                arg[i] = block->expr;
                /* todo: type check here. */
                if (i < nmembers(type) - 1) {
                    consume(',');
                }
            }
            while (is_vararg(type) && peek().token != ')') {
                consume(',');
                arg = realloc(arg, (i + 1) * sizeof(*arg));
                block = assignment_expression(block);
                arg[i] = block->expr;
                i++;
            }
            consume(')');
            for (j = 0; j < i; ++j)
                param(block, arg[j]);
            free(arg);
            root = eval_call(block, root);
            break;
        case '.':
            consume('.');
            tok = consume(IDENTIFIER);
            field = find_type_member(root.type, tok.strval);
            if (!field) {
                error("Invalid field access, no member named '%s'.",
                    tok.strval);
                exit(1);
            }
            root.type = field->type;
            root.offset += field->offset;
            break;
        case ARROW:
            consume(ARROW);
            tok = consume(IDENTIFIER);
            if (is_pointer(root.type) && is_struct_or_union(root.type->next)) {
                field = find_type_member(type_deref(root.type), tok.strval);
                if (!field) {
                    error("Invalid field access, no member named '%s'.",
                        tok.strval);
                    exit(1);
                }

                /* Make it look like a pointer to the field type, then perform
                 * normal dereferencing. */
                root.type = type_init(T_POINTER, field->type);
                root = eval_deref(block, root);
                root.offset = field->offset;
            } else {
                error("Invalid field access.");
                exit(1);
            }
            break;
        case INCREMENT:
            consume(INCREMENT);
            copy = create_var(root.type);
            eval_assign(block, copy, root);
            expr = eval_expr(block, IR_OP_ADD, root, var_int(1));
            eval_assign(block, root, expr);
            root = copy;
            break;
        case DECREMENT:
            consume(DECREMENT);
            copy = create_var(root.type);
            eval_assign(block, copy, root);
            expr = eval_expr(block, IR_OP_SUB, root, var_int(1));
            eval_assign(block, root, expr);
            root = copy;
            break;
        default:
            block->expr = root;
            return block;
        }
    }
}
Ejemplo n.º 6
0
Archivo: interp.c Proyecto: sbstp/zeta
/**
Evaluate an expression in a given frame
*/
value_t eval_expr(
    heapptr_t expr, 
    clos_t* clos,
    value_t* locals
)
{
    //printf("eval_expr\n");

    // Get the shape of the AST node
    // Note: AST nodes must match the shapes defined in init_parser,
    // otherwise this interpreter can't handle it
    shapeidx_t shape = get_shape(expr);

    // Variable or constant declaration (let/var)
    if (shape == SHAPE_AST_DECL)
    {
        ast_decl_t* decl = (ast_decl_t*)expr;

        // Let declarations should be initialized
        assert (decl->cst == false);

        return VAL_FALSE;
    }

    // Variable reference (read)
    if (shape == SHAPE_AST_REF)
    {
        ast_ref_t* ref = (ast_ref_t*)expr;
        assert (ref->decl != NULL);

        //printf("evaluating ref to %s\n", string_cstr(ref->name));

        // If this is a variable from an outer function
        if (ref->decl->fun != clos->fun)
        {
            //printf("ref from outer fun\n");

            assert (ref->idx < clos->fun->free_vars->len);
            cell_t* cell = clos->cells[ref->idx];
            assert (cell != NULL);

            value_t value;
            value.word = cell->word;
            value.tag = cell->tag;

            return value;
        }

        // Check that the ref index is valid
        if (ref->idx > clos->fun->local_decls->len)
        {
            printf("invalid variable reference\n");
            printf("ref->name=%s\n", string_cstr(ref->name));
            printf("ref->idx=%d\n", ref->idx);
            printf("local_decls->len=%d\n", clos->fun->local_decls->len);
            exit(-1);
        }

        // If this an escaping variable (captured by a closure)
        if (ref->decl->esc)
        {
            // Free variables are stored in mutable cells
            // Pointers to the cells are found on the closure object
            cell_t* cell = locals[ref->idx].word.cell;
            value_t value;
            value.word = cell->word;
            value.tag = cell->tag;

            //printf("read value from cell\n");

            return value;
        }

        /*
        printf("reading normal local\n");
        string_print(ref->name);
        printf("\n");
        */

        // Read directly from the stack frame
        return locals[ref->idx];
    }

    if (shape == SHAPE_AST_CONST)
    {
        //printf("constant\n");

        ast_const_t* cst = (ast_const_t*)expr;
        return cst->val;
    }

    if (shape == SHAPE_STRING)
    {
        return value_from_heapptr(expr, TAG_STRING);
    }

    // Array literal expression
    if (shape == SHAPE_ARRAY)
    {
        array_t* array_expr = (array_t*)expr;

        // Array of values to be produced
        array_t* val_array = array_alloc(array_expr->len);

        for (size_t i = 0; i < array_expr->len; ++i)
        {
            heapptr_t expr = array_get(array_expr, i).word.heapptr;
            value_t value = eval_expr(expr, clos, locals);
            array_set(val_array, i, value);
        }

        return value_from_heapptr((heapptr_t)val_array, TAG_ARRAY);
    }

    // Object literal expression
    if (shape == SHAPE_AST_OBJ)
    {
        //printf("obj literal expr\n");

        ast_obj_t* obj_expr = (ast_obj_t*)expr;

        object_t* obj = object_alloc(OBJ_MIN_CAP);

        // TODO: set prototype
        // Do this in object_alloc?

        for (size_t i = 0; i < obj_expr->name_strs->len; ++i)
        {
            string_t* prop_name = array_get(obj_expr->name_strs, i).word.string;
            heapptr_t val_expr = array_get(obj_expr->val_exprs, i).word.heapptr;

            value_t value = eval_expr(val_expr, clos, locals);

            object_set_prop(
                obj,
                prop_name,
                value,
                ATTR_DEFAULT
            );
        }

        return value_from_obj((heapptr_t)obj);
    }

    // Binary operator (e.g. a + b)
    if (shape == SHAPE_AST_BINOP)
    {
        //printf("binop\n");

        ast_binop_t* binop = (ast_binop_t*)expr;

        // Assignment
        if (binop->op == &OP_ASSIGN)
        {
            value_t val = eval_expr(binop->right_expr, clos, locals);

            return eval_assign(
                binop->left_expr, 
                val, 
                clos,
                locals
            );
        }

        value_t v0 = eval_expr(binop->left_expr, clos, locals);
        value_t v1 = eval_expr(binop->right_expr, clos, locals);
        int64_t i0 = v0.word.int64;
        int64_t i1 = v1.word.int64;
        string_t* s0 = v0.word.string;
        string_t* s1 = v1.word.string;

        if (binop->op == &OP_MEMBER)
            return eval_get_prop(v0, v1);

        if (binop->op == &OP_INDEX)
            return eval_get_index(v0, v1);

        if (binop->op == &OP_ADD)
            return value_from_int64(i0 + i1);
        if (binop->op == &OP_SUB)
            return value_from_int64(i0 - i1);
        if (binop->op == &OP_MUL)
            return value_from_int64(i0 * i1);
        if (binop->op == &OP_DIV)
            return value_from_int64(i0 / i1);
        if (binop->op == &OP_MOD)
            return value_from_int64(i0 % i1);

        if (binop->op == &OP_LT)
            return (i0 < i1)? VAL_TRUE:VAL_FALSE;

        if (binop->op == &OP_LE)
        {
            if (v0.tag == TAG_STRING && v1.tag == TAG_STRING)
                return (strcmp(string_cstr(s0), string_cstr(s1)) <= 0)? VAL_TRUE:VAL_FALSE;
            if (v0.tag == TAG_INT64 && v1.tag == TAG_INT64)
                return (i0 <= i1)? VAL_TRUE:VAL_FALSE;
            assert (false);
        }

        if (binop->op == &OP_GT)
            return (i0 > i1)? VAL_TRUE:VAL_FALSE;

        if (binop->op == &OP_GE)
        {
            if (v0.tag == TAG_STRING && v1.tag == TAG_STRING)
                return (strcmp(string_cstr(s0), string_cstr(s1)) >= 0)? VAL_TRUE:VAL_FALSE;
            if (v0.tag == TAG_INT64 && v1.tag == TAG_INT64)
                return (i0 >= i1)? VAL_TRUE:VAL_FALSE;
            assert (false);
        }

        if (binop->op == &OP_EQ)
            return value_equals(v0, v1)? VAL_TRUE:VAL_FALSE;
        if (binop->op == &OP_NE)
            return value_equals(v0, v1)? VAL_FALSE:VAL_TRUE;

        printf("unimplemented binary operator: %s\n", binop->op->str);
        return VAL_FALSE;
    }

    // Unary operator (e.g.: -x, not a)
    if (shape == SHAPE_AST_UNOP)
    {
        ast_unop_t* unop = (ast_unop_t*)expr;

        value_t v0 = eval_expr(unop->expr, clos, locals);

        if (unop->op == &OP_NEG)
            return value_from_int64(-v0.word.int64);

        if (unop->op == &OP_NOT)
            return eval_truth(v0)? VAL_FALSE:VAL_TRUE;

        printf("unimplemented unary operator: %s\n", unop->op->str);
        return VAL_FALSE;
    }

    // Sequence/block expression
    if (shape == SHAPE_AST_SEQ)
    {
        ast_seq_t* seqexpr = (ast_seq_t*)expr;
        array_t* expr_list = seqexpr->expr_list;

        value_t value = VAL_TRUE;

        for (size_t i = 0; i < expr_list->len; ++i)
        {
            heapptr_t expr = array_get(expr_list, i).word.heapptr;
            value = eval_expr(expr, clos, locals);
        }

        // Return the value of the last expression
        return value;
    }

    // If expression
    if (shape == SHAPE_AST_IF)
    {
        ast_if_t* ifexpr = (ast_if_t*)expr;

        value_t t = eval_expr(ifexpr->test_expr, clos, locals);

        if (eval_truth(t))
            return eval_expr(ifexpr->then_expr, clos, locals);
        else
            return eval_expr(ifexpr->else_expr, clos, locals);
    }

    // Function/closure expression
    if (shape == SHAPE_AST_FUN)
    {
        //printf("creating closure\n");

        ast_fun_t* nested = (ast_fun_t*)expr;

        // Allocate a closure of the nested function
        clos_t* new_clos = clos_alloc(nested);

        // For each free (closure) variable of the nested function
        for (size_t i = 0; i < nested->free_vars->len; ++i)
        {
            ast_decl_t* decl = array_get(nested->free_vars, i).word.decl;

            // If the variable is from this function
            if (decl->fun == clos->fun)
            {
                new_clos->cells[i] = locals[decl->idx].word.cell;
            }
            else
            {
                uint32_t free_idx = array_indexof_ptr(clos->fun->free_vars, (heapptr_t)decl);
                assert (free_idx < clos->fun->free_vars->len);
                new_clos->cells[i] = clos->cells[free_idx];
            }
        }

        assert (new_clos->fun == nested);

        return value_from_heapptr((heapptr_t)new_clos, TAG_CLOS);
    }

    // Call expression
    if (shape == SHAPE_AST_CALL)
    {
        //printf("evaluating call\n");

        ast_call_t* callexpr = (ast_call_t*)expr;

        // Evaluate the closure expression
        value_t callee_clos = eval_expr(callexpr->fun_expr, clos, locals);

        if (callee_clos.tag == TAG_CLOS)
        {
            return eval_call(
                callee_clos.word.clos,
                callexpr->arg_exprs,
                clos,
                locals
            );
        }

        if (callee_clos.tag == TAG_HOSTFN)
        {
            return eval_host_call(
                callee_clos.word.hostfn,
                callexpr->arg_exprs,
                clos,
                locals
            );
        }

        printf("invalid callee in function call\n");
        exit(-1);
    }

    printf("eval error, unknown expression type, shapeidx=%d\n", get_shape(expr));
    exit(-1);
}
Ejemplo n.º 7
0
static void member_declaration_list(struct typetree *type)
{
    struct namespace ns = {0};
    struct typetree *decl_base, *decl_type;
    const char *name;

    push_scope(&ns);

    do {
        decl_base = declaration_specifiers(NULL);

        do {
            name = NULL;
            decl_type = declarator(decl_base, &name);

            if (!name) {
                error("Missing name in member declarator.");
                exit(1);
            } else if (!size_of(decl_type)) {
                error("Field '%s' has incomplete type '%t'.", name, decl_type);
                exit(1);
            } else {
                sym_add(&ns, name, decl_type, SYM_DECLARATION, LINK_NONE);
                type_add_member(type, name, decl_type);
            }

            if (peek().token == ',') {
                consume(',');
                continue;
            }
        } while (peek().token != ';');

        consume(';');
    } while (peek().token != '}');

    pop_scope(&ns);
}

static struct typetree *struct_or_union_declaration(void)
{
    struct symbol *sym = NULL;
    struct typetree *type = NULL;
    enum type kind =
        (next().token == STRUCT) ? T_STRUCT : T_UNION;

    if (peek().token == IDENTIFIER) {
        const char *name = consume(IDENTIFIER).strval;
        sym = sym_lookup(&ns_tag, name);
        if (!sym) {
            type = type_init(kind);
            sym = sym_add(&ns_tag, name, type, SYM_TYPEDEF, LINK_NONE);
        } else if (is_integer(&sym->type)) {
            error("Tag '%s' was previously declared as enum.", sym->name);
            exit(1);
        } else if (sym->type.type != kind) {
            error("Tag '%s' was previously declared as %s.",
                sym->name, (sym->type.type == T_STRUCT) ? "struct" : "union");
            exit(1);
        }

        /* Retrieve type from existing symbol, possibly providing a complete
         * definition that will be available for later declarations. Overwrites
         * existing type information from symbol table. */
        type = &sym->type;
        if (peek().token == '{' && type->size) {
            error("Redefiniton of '%s'.", sym->name);
            exit(1);
        }
    }

    if (peek().token == '{') {
        if (!type) {
            /* Anonymous structure; allocate a new standalone type,
             * not part of any symbol. */
            type = type_init(kind);
        }

        consume('{');
        member_declaration_list(type);
        assert(type->size);
        consume('}');
    }

    /* Return to the caller a copy of the root node, which can be overwritten
     * with new type qualifiers without altering the tag registration. */
    return (sym) ? type_tagged_copy(&sym->type, sym->name) : type;
}

static void enumerator_list(void)
{
    struct var val;
    struct symbol *sym;
    int enum_value = 0;

    consume('{');
    do {
        const char *name = consume(IDENTIFIER).strval;

        if (peek().token == '=') {
            consume('=');
            val = constant_expression();
            if (!is_integer(val.type)) {
                error("Implicit conversion from non-integer type in enum.");
            }
            enum_value = val.imm.i;
        }

        sym = sym_add(
            &ns_ident,
            name,
            &basic_type__int,
            SYM_ENUM_VALUE,
            LINK_NONE);
        sym->enum_value = enum_value++;

        if (peek().token != ',')
            break;
        consume(',');
    } while (peek().token != '}');
    consume('}');
}

static struct typetree *enum_declaration(void)
{
    struct typetree *type = type_init(T_SIGNED, 4);

    consume(ENUM);
    if (peek().token == IDENTIFIER) {
        struct symbol *tag = NULL;
        const char *name = consume(IDENTIFIER).strval;

        tag = sym_lookup(&ns_tag, name);
        if (!tag || tag->depth < ns_tag.current_depth) {
            tag = sym_add(&ns_tag, name, type, SYM_TYPEDEF, LINK_NONE);
        } else if (!is_integer(&tag->type)) {
            error("Tag '%s' was previously defined as aggregate type.",
                tag->name);
            exit(1);
        }

        /* Use enum_value as a sentinel to represent definition, checked on 
         * lookup to detect duplicate definitions. */
        if (peek().token == '{') {
            if (tag->enum_value) {
                error("Redefiniton of enum '%s'.", tag->name);
            }
            enumerator_list();
            tag->enum_value = 1;
        }
    } else {
        enumerator_list();
    }

    /* Result is always integer. Do not care about the actual enum definition,
     * all enums are ints and no type checking is done. */
    return type;
}

static struct typetree get_basic_type_from_specifier(unsigned short spec)
{
    switch (spec) {
    case 0x0001: /* void */
        return basic_type__void;
    case 0x0002: /* char */
    case 0x0012: /* signed char */
        return basic_type__char;
    case 0x0022: /* unsigned char */
        return basic_type__unsigned_char;
    case 0x0004: /* short */
    case 0x0014: /* signed short */
    case 0x000C: /* short int */
    case 0x001C: /* signed short int */
        return basic_type__short;
    case 0x0024: /* unsigned short */
    case 0x002C: /* unsigned short int */
        return basic_type__unsigned_short;
    case 0x0008: /* int */
    case 0x0010: /* signed */
    case 0x0018: /* signed int */
        return basic_type__int;
    case 0x0020: /* unsigned */
    case 0x0028: /* unsigned int */
        return basic_type__unsigned_int;
    case 0x0040: /* long */
    case 0x0050: /* signed long */
    case 0x0048: /* long int */
    case 0x0058: /* signed long int */
    case 0x00C0: /* long long */
    case 0x00D0: /* signed long long */
    case 0x00D8: /* signed long long int */
        return basic_type__long;
    case 0x0060: /* unsigned long */
    case 0x0068: /* unsigned long int */
    case 0x00E0: /* unsigned long long */
    case 0x00E8: /* unsigned long long int */
        return basic_type__unsigned_long;
    case 0x0100: /* float */
        return basic_type__float;
    case 0x0200: /* double */
    case 0x0240: /* long double */
        return basic_type__double;
    default:
        error("Invalid type specification.");
        exit(1); 
    }
}

/* Parse type, qualifiers and storage class. Do not assume int by default, but
 * require at least one type specifier. Storage class is returned as token
 * value, unless the provided pointer is NULL, in which case the input is parsed
 * as specifier-qualifier-list.
 */
struct typetree *declaration_specifiers(int *stc)
{
    struct typetree *type = NULL;
    struct token tok;
    int done = 0;

    /* Use a compact bit representation to hold state about declaration 
     * specifiers. Initialize storage class to sentinel value. */
    unsigned short spec = 0x0000;
    enum qualifier qual = Q_NONE;
    if (stc)       *stc =    '$';

    #define set_specifier(d) \
        if (spec & d) error("Duplicate type specifier '%s'.", tok.strval); \
        next(); spec |= d;

    #define set_qualifier(d) \
        if (qual & d) error("Duplicate type qualifier '%s'.", tok.strval); \
        next(); qual |= d;

    #define set_storage_class(t) \
        if (!stc) error("Unexpected storage class in qualifier list."); \
        else if (*stc != '$') error("Multiple storage class specifiers."); \
        next(); *stc = t;

    do {
        switch ((tok = peek()).token) {
        case VOID:      set_specifier(0x001); break;
        case CHAR:      set_specifier(0x002); break;
        case SHORT:     set_specifier(0x004); break;
        case INT:       set_specifier(0x008); break;
        case SIGNED:    set_specifier(0x010); break;
        case UNSIGNED:  set_specifier(0x020); break;
        case LONG:
            if (spec & 0x040) {
                set_specifier(0x080);
            } else {
                set_specifier(0x040);   
            }
            break;
        case FLOAT:     set_specifier(0x100); break;
        case DOUBLE:    set_specifier(0x200); break;
        case CONST:     set_qualifier(Q_CONST); break;
        case VOLATILE:  set_qualifier(Q_VOLATILE); break;
        case IDENTIFIER: {
            struct symbol *tag = sym_lookup(&ns_ident, tok.strval);
            if (tag && tag->symtype == SYM_TYPEDEF && !type) {
                consume(IDENTIFIER);
                type = type_init(T_STRUCT);
                *type = tag->type;
            } else {
                done = 1;
            }
            break;
        }
        case UNION:
        case STRUCT:
            if (!type) {
                type = struct_or_union_declaration();
            } else {
                done = 1;
            }
            break;
        case ENUM:
            if (!type) {
                type = enum_declaration();
            } else {
                done = 1;
            }
            break;
        case AUTO:
        case REGISTER:
        case STATIC:
        case EXTERN:
        case TYPEDEF:
            set_storage_class(tok.token);
            break;
        default:
            done = 1;
            break;
        }

        if (type && spec) {
            error("Invalid combination of declaration specifiers.");
            exit(1);
        }
    } while (!done);

    #undef set_specifier
    #undef set_qualifier
    #undef set_storage_class

    if (type) {
        if (qual & type->qualifier) {
            error("Duplicate type qualifier:%s%s.",
                (qual & Q_CONST) ? " const" : "",
                (qual & Q_VOLATILE) ? " volatile" : "");
        }
    } else if (spec) {
        type = type_init(T_STRUCT);
        *type = get_basic_type_from_specifier(spec);
    } else {
        error("Missing type specifier.");
        exit(1);
    }

    type->qualifier |= qual;
    return type;
}

/* Set var = 0, using simple assignment on members for composite types. This
 * rule does not consume any input, but generates a series of assignments on the
 * given variable. Point is to be able to zero initialize using normal simple
 * assignment rules, although IR can become verbose for large structures.
 */
static void zero_initialize(struct block *block, struct var target)
{
    int i;
    struct var var;
    assert(target.kind == DIRECT);

    switch (target.type->type) {
    case T_STRUCT:
    case T_UNION:
        target.type = unwrapped(target.type);
        var = target;
        for (i = 0; i < nmembers(var.type); ++i) {
            target.type = get_member(var.type, i)->type;
            target.offset = var.offset + get_member(var.type, i)->offset;
            zero_initialize(block, target);
        }
        break;
    case T_ARRAY:
        assert(target.type->size);
        var = target;
        target.type = target.type->next;
        assert(is_struct(target.type) || !target.type->next);
        for (i = 0; i < var.type->size / var.type->next->size; ++i) {
            target.offset = var.offset + i * var.type->next->size;
            zero_initialize(block, target);
        }
        break;
    case T_POINTER:
        var = var_zero(8);
        var.type = type_init(T_POINTER, &basic_type__void);
        eval_assign(block, target, var);
        break;
    case T_UNSIGNED:
    case T_SIGNED:
        var = var_zero(target.type->size);
        eval_assign(block, target, var);
        break;
    default:
        error("Invalid type to zero-initialize, was '%t'.", target.type);
        exit(1);
    }
}
Ejemplo n.º 8
0
Archivo: eval.c Proyecto: crab2313/m1
static void
eval_expr(m1_expression *e) {
    if (e == NULL) 
        return;
        
    switch (e->type) {
        case EXPR_NUMBER:
            eval_number(e->expr.l->value.fval);
            break;
        case EXPR_INT:
            eval_int(e->expr.l->value.ival);
            break;
        case EXPR_BINARY:
            eval_binary(e->expr.b);
            break;
        case EXPR_UNARY:
            eval_unary(e->expr.u);
            break;
        case EXPR_FUNCALL:
            eval_funcall(e->expr.f);
            break;
        case EXPR_ASSIGN:
            eval_assign(e->expr.a);
            break;
        case EXPR_IF:   
            eval_if(e->expr.i);
            break;
        case EXPR_WHILE:
            eval_while(e->expr.w);
            break;
        case EXPR_DOWHILE:
            eval_dowhile(e->expr.w);
            break;
        case EXPR_FOR:
            eval_for(e->expr.o);
            break;
        case EXPR_RETURN:
            eval_return(e->expr.e);
            break;
        case EXPR_NULL:
            eval_null();
            break;
        case EXPR_DEREF:
            eval_deref(e->expr.t);
            break;
        case EXPR_ADDRESS:
            eval_address(e->expr.t);
            break;
        case EXPR_OBJECT:
            eval_obj(e->expr.t);
            break;
        case EXPR_BREAK:
            eval_break();
            break;            
        case EXPR_CONTINUE:
            eval_continue();
            break;
        case EXPR_CONSTDECL:
        case EXPR_VARDECL:
            break;
        default:
            fprintf(stderr, "unknown expr type");   
            exit(EXIT_FAILURE);
    }   

}