Alien-TinyCC

 view release on metacpan or  search on metacpan

src/tccgen.c  view on Meta::CPAN

    case '+':
        next();
        /* in order to force cast, we add zero */
        unary();
        if ((vtop->type.t & VT_BTYPE) == VT_PTR)
            tcc_error("pointer not accepted for unary plus");
        vpushi(0);
        gen_op('+');
        break;
    case TOK_SIZEOF:
    case TOK_ALIGNOF1:
    case TOK_ALIGNOF2:
        t = tok;
        next();
        in_sizeof++;
        unary_type(&type); // Perform a in_sizeof = 0;
        size = type_size(&type, &align);
        if (t == TOK_SIZEOF) {
            if (!(type.t & VT_VLA)) {
                if (size < 0)
                    tcc_error("sizeof applied to an incomplete type");
                vpushs(size);
            } else {
                vla_runtime_type_size(&type, &align);
            }
        } else {
            vpushs(align);
        }
        vtop->type.t |= VT_UNSIGNED;
        break;

    case TOK_builtin_types_compatible_p:
        {
            CType type1, type2;
            next();
            skip('(');
            parse_type(&type1);
            skip(',');
            parse_type(&type2);
            skip(')');
            type1.t &= ~(VT_CONSTANT | VT_VOLATILE);
            type2.t &= ~(VT_CONSTANT | VT_VOLATILE);
            vpushi(is_compatible_types(&type1, &type2));
        }
        break;
    case TOK_builtin_constant_p:
        {
            int saved_nocode_wanted, res;
            next();
            skip('(');
            saved_nocode_wanted = nocode_wanted;
            nocode_wanted = 1;
            gexpr();
            res = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
            vpop();
            nocode_wanted = saved_nocode_wanted;
            skip(')');
            vpushi(res);
        }
        break;
    case TOK_builtin_frame_address:
        {
            int level;
            CType type;
            next();
            skip('(');
            if (tok != TOK_CINT || tokc.i < 0) {
                tcc_error("__builtin_frame_address only takes positive integers");
            }
            level = tokc.i;
            next();
            skip(')');
            type.t = VT_VOID;
            mk_pointer(&type);
            vset(&type, VT_LOCAL, 0);       /* local frame */
            while (level--) {
                mk_pointer(&vtop->type);
                indir();                    /* -> parent frame */
            }
        }
        break;
#ifdef TCC_TARGET_X86_64
#ifdef TCC_TARGET_PE
    case TOK_builtin_va_start:
        {
            next();
            skip('(');
            expr_eq();
            skip(',');
            expr_eq();
            skip(')');
            if ((vtop->r & VT_VALMASK) != VT_LOCAL)
                tcc_error("__builtin_va_start expects a local variable");
            vtop->r &= ~(VT_LVAL | VT_REF);
            vtop->type = char_pointer_type;
            vstore();
        }
        break;
#else
    case TOK_builtin_va_arg_types:
        {
            CType type;
            next();
            skip('(');
            parse_type(&type);
            skip(')');
            vpushi(classify_x86_64_va_arg(&type));
        }
        break;
#endif
#endif
    case TOK_INC:
    case TOK_DEC:
        t = tok;
        next();
        unary();
        inc(0, t);
        break;
    case '-':
        next();
        vpushi(0);
        unary();
        gen_op('-');
        break;
    case TOK_LAND:
        if (!gnu_ext)
            goto tok_identifier;
        next();
        /* allow to take the address of a label */
        if (tok < TOK_UIDENT)
            expect("label identifier");
        s = label_find(tok);
        if (!s) {
            s = label_push(&global_label_stack, tok, LABEL_FORWARD);
        } else {
            if (s->r == LABEL_DECLARED)
                s->r = LABEL_FORWARD;
        }

src/tccgen.c  view on Meta::CPAN

    expr_cond();
    const_wanted = a;
}

/* parse an integer constant and return its value. */
ST_FUNC int expr_const(void)
{
    int c;
    expr_const1();
    if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
        expect("constant expression");
    c = vtop->c.i;
    vpop();
    return c;
}

/* return the label token if current token is a label, otherwise
   return zero */
static int is_label(void)
{
    int last_tok;

    /* fast test first */
    if (tok < TOK_UIDENT)
        return 0;
    /* no need to save tokc because tok is an identifier */
    last_tok = tok;
    next();
    if (tok == ':') {
        next();
        return last_tok;
    } else {
        unget_tok(last_tok);
        return 0;
    }
}

static void label_or_decl(int l)
{
    int last_tok;

    /* fast test first */
    if (tok >= TOK_UIDENT)
      {
	/* no need to save tokc because tok is an identifier */
	last_tok = tok;
	next();
	if (tok == ':') {
	    unget_tok(last_tok);
	    return;
	}
	unget_tok(last_tok);
      }
    decl(l);
}

static void block(int *bsym, int *csym, int *case_sym, int *def_sym, 
                  int case_reg, int is_expr)
{
    int a, b, c, d;
    Sym *s, *frame_bottom;

    /* generate line number info */
    if (tcc_state->do_debug &&
        (last_line_num != file->line_num || last_ind != ind)) {
        put_stabn(N_SLINE, 0, file->line_num, ind - func_ind);
        last_ind = ind;
        last_line_num = file->line_num;
    }

    if (is_expr) {
        /* default return value is (void) */
        vpushi(0);
        vtop->type.t = VT_VOID;
    }

    if (tok == TOK_IF) {
        /* if test */
        next();
        skip('(');
        gexpr();
        skip(')');
        a = gtst(1, 0);
        block(bsym, csym, case_sym, def_sym, case_reg, 0);
        c = tok;
        if (c == TOK_ELSE) {
            next();
            d = gjmp(0);
            gsym(a);
            block(bsym, csym, case_sym, def_sym, case_reg, 0);
            gsym(d); /* patch else jmp */
        } else
            gsym(a);
    } else if (tok == TOK_WHILE) {
        next();
        d = ind;
        skip('(');
        gexpr();
        skip(')');
        a = gtst(1, 0);
        b = 0;
        block(&a, &b, case_sym, def_sym, case_reg, 0);
        gjmp_addr(d);
        gsym(a);
        gsym_addr(b, d);
    } else if (tok == '{') {
        Sym *llabel;
        int block_vla_sp_loc, *saved_vla_sp_loc, saved_vla_flags;

        next();
        /* record local declaration stack position */
        s = local_stack;
        frame_bottom = sym_push2(&local_stack, SYM_FIELD, 0, 0);
        frame_bottom->next = scope_stack_bottom;
        scope_stack_bottom = frame_bottom;
        llabel = local_label_stack;
        
        /* save VLA state */
        block_vla_sp_loc = *(saved_vla_sp_loc = vla_sp_loc);
        if (saved_vla_sp_loc != &vla_sp_root_loc)
          vla_sp_loc = &block_vla_sp_loc;

        saved_vla_flags = vla_flags;
        vla_flags |= VLA_NEED_NEW_FRAME;
        
        /* handle local labels declarations */
        if (tok == TOK_LABEL) {
            next();
            for(;;) {
                if (tok < TOK_UIDENT)
                    expect("label identifier");
                label_push(&local_label_stack, tok, LABEL_DECLARED);
                next();
                if (tok == ',') {
                    next();
                } else {
                    skip(';');
                    break;
                }
            }
        }
        while (tok != '}') {
            label_or_decl(VT_LOCAL);
            if (tok != '}') {
                if (is_expr)
                    vpop();
                block(bsym, csym, case_sym, def_sym, case_reg, is_expr);
            }
        }
        /* pop locally defined labels */
        label_pop(&local_label_stack, llabel);
        if(is_expr) {
            /* XXX: this solution makes only valgrind happy...
               triggered by gcc.c-torture/execute/20000917-1.c */
            Sym *p;
            switch(vtop->type.t & VT_BTYPE) {
            case VT_PTR:
            case VT_STRUCT:
            case VT_ENUM:
            case VT_FUNC:
                for(p=vtop->type.ref;p;p=p->prev)
                    if(p->prev==s)
                        tcc_error("unsupported expression type");
            }
        }
        /* pop locally defined symbols */
        scope_stack_bottom = scope_stack_bottom->next;
        sym_pop(&local_stack, s);
        
        /* Pop VLA frames and restore stack pointer if required */
        if (saved_vla_sp_loc != &vla_sp_root_loc)
            *saved_vla_sp_loc = block_vla_sp_loc;
        if (vla_sp_loc != (saved_vla_sp_loc == &vla_sp_root_loc ? &vla_sp_root_loc : &block_vla_sp_loc)) {
            vla_sp_loc = saved_vla_sp_loc;
            gen_vla_sp_restore(*vla_sp_loc);
        }
        vla_flags = (vla_flags & ~VLA_SCOPE_FLAGS) | (saved_vla_flags & VLA_SCOPE_FLAGS);
        
        next();
    } else if (tok == TOK_RETURN) {
        next();
        if (tok != ';') {
            gexpr();
            gen_assign_cast(&func_vt);
            if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
                CType type, ret_type;
                int ret_align;
                if (gfunc_sret(&func_vt, &ret_type, &ret_align)) {
                    /* if returning structure, must copy it to implicit
                       first pointer arg location */
                    type = func_vt;
                    mk_pointer(&type);
                    vset(&type, VT_LOCAL | VT_LVAL, func_vc);
                    indir();
                    vswap();
                    /* copy structure value to pointer */
                    vstore();
                } else {
                    /* returning structure packed into registers */
                    int size, addr, align;
                    size = type_size(&func_vt,&align);
                    if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
                        && (align & (ret_align-1))) {
                        loc = (loc - size) & -align;
                        addr = loc;
                        type = func_vt;
                        vset(&type, VT_LOCAL | VT_LVAL, addr);
                        vswap();
                        vstore();
                        vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
                    }
                    vtop->type = ret_type;
                    if (is_float(ret_type.t))
                        gv(rc_fret(ret_type.t));
                    else
                        gv(RC_IRET);
                }
            } else if (is_float(func_vt.t)) {
                gv(rc_fret(func_vt.t));
            } else {
                gv(RC_IRET);
            }
            vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
        }
        skip(';');
        rsym = gjmp(rsym); /* jmp */
    } else if (tok == TOK_BREAK) {
        /* compute jump */
        if (!bsym)
            tcc_error("cannot break");
        *bsym = gjmp(*bsym);
        next();
        skip(';');
    } else if (tok == TOK_CONTINUE) {
        /* compute jump */
        if (!csym)
            tcc_error("cannot continue");
        *csym = gjmp(*csym);
        next();
        skip(';');
    } else if (tok == TOK_FOR) {
        int e;
        next();
        skip('(');
        s = local_stack;
        frame_bottom = sym_push2(&local_stack, SYM_FIELD, 0, 0);
        frame_bottom->next = scope_stack_bottom;
        scope_stack_bottom = frame_bottom;
        if (tok != ';') {
            /* c99 for-loop init decl? */
            if (!decl0(VT_LOCAL, 1)) {
                /* no, regular for-loop init expr */
                gexpr();
                vpop();
            }
        }
        skip(';');
        d = ind;
        c = ind;
        a = 0;
        b = 0;
        if (tok != ';') {
            gexpr();
            a = gtst(1, 0);
        }
        skip(';');
        if (tok != ')') {
            e = gjmp(0);
            c = ind;
            gexpr();
            vpop();
            gjmp_addr(d);
            gsym(e);
        }
        skip(')');
        block(&a, &b, case_sym, def_sym, case_reg, 0);
        gjmp_addr(c);
        gsym(a);
        gsym_addr(b, c);
        scope_stack_bottom = scope_stack_bottom->next;
        sym_pop(&local_stack, s);
    } else 
    if (tok == TOK_DO) {
        next();
        a = 0;
        b = 0;
        d = ind;
        block(&a, &b, case_sym, def_sym, case_reg, 0);
        skip(TOK_WHILE);
        skip('(');
        gsym(b);
        gexpr();
        c = gtst(0, 0);
        gsym_addr(c, d);
        skip(')');
        gsym(a);
        skip(';');
    } else
    if (tok == TOK_SWITCH) {
        next();
        skip('(');
        gexpr();
        /* XXX: other types than integer */
        case_reg = gv(RC_INT);
        vpop();
        skip(')');
        a = 0;
        b = gjmp(0); /* jump to first case */



( run in 0.961 second using v1.01-cache-2.11-cpan-df04353d9ac )