/* "p2c", a Pascal to C translator.
   Copyright (C) 1989 David Gillespie.
   Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

#define PROTO_PEXPR2_C
#include "trans.h"

Expr *pascaltypecast(type, ex2)
Type *type;
Expr *ex2;
{
    if ((ex2->val.type->kind == TK_INTEGER ||
	 ex2->val.type->kind == TK_CHAR ||
	 ex2->val.type->kind == TK_BOOLEAN ||
	 ex2->val.type->kind == TK_ENUM ||
	 ex2->val.type->kind == TK_SUBR ||
	 ex2->val.type->kind == TK_REAL ||
	 ex2->val.type->kind == TK_POINTER ||
	 ex2->val.type->kind == TK_STRING) &&
	(type->kind == TK_INTEGER ||
	 type->kind == TK_CHAR ||
	 type->kind == TK_BOOLEAN ||
	 type->kind == TK_ENUM ||
	 type->kind == TK_SUBR ||
	 type->kind == TK_REAL ||
	 type->kind == TK_POINTER)) {
	if (type->kind == TK_POINTER || ex2->val.type->kind == TK_POINTER)
	    return makeexpr_un(EK_CAST, type, ex2);
	else
	    return makeexpr_un(EK_ACTCAST, type, ex2);
    } else {
	return makeexpr_hat(makeexpr_cast(makeexpr_addr(ex2),
					  makepointertype(type)), 0);
    }
}




Static Expr *p_factor(target)
Type *target;
{
    Expr *ex, *ex2;
    Type *type;
    Meaning *mp, *mp2;

    switch (curtok) {

        case TOK_INTLIT:
            ex = makeexpr_long(curtokint);
            gettok();
            return ex;

        case TOK_HEXLIT:
            ex = makeexpr_long(curtokint);
            insertarg(&ex, 0, makeexpr_name("%#lx", tp_integer));
            gettok();
            return ex;

        case TOK_OCTLIT:
            ex = makeexpr_long(curtokint);
            insertarg(&ex, 0, makeexpr_name("%#lo", tp_integer));
            gettok();
            return ex;

        case TOK_MININT:
	    strcat(curtokbuf, ".0");

	/* fall through */
        case TOK_REALLIT:
            ex = makeexpr_real(curtokbuf);
            gettok();
            return ex;

        case TOK_HAT:
        case TOK_STRLIT:
            ex = accumulate_strlit();
            return ex;

        case TOK_LPAR:
            gettok();
            ex = p_expr(target);
            skipcloseparen();
            return dots_n_hats(ex, target);

        case TOK_NOT:
	case TOK_TWIDDLE:
            gettok();
            ex = p_factor(tp_integer);
            if (ord_type(ex->val.type)->kind == TK_INTEGER)
                return makeexpr_un(EK_BNOT, tp_integer, ex);
            else
                return makeexpr_not(ex);

        case TOK_ADDR:
            gettok();
	    if (curtok == TOK_ADDR) {
		gettok();
		ex = p_factor(tp_proc);
		if (ex->val.type->kind == TK_PROCPTR && ex->kind == EK_COMMA)
		    return grabarg(grabarg(grabarg(ex, 0), 1), 0);
		if (ex->val.type->kind != TK_CPROCPTR)
		    warning("@@ allowed only for procedure pointers [302]");
		return makeexpr_addrf(ex);
	    }
            if (curtok == TOK_IDENT && 0 &&  /***/
                curtokmeaning && (curtokmeaning->kind == MK_FUNCTION ||
                                  curtokmeaning->kind == MK_SPECIAL)) {
                if (curtokmeaning->ctx == nullctx)
                    warning(format_s("Can't take address of predefined object %s [303]",
                                     curtokmeaning->name));
                ex = makeexpr_name(curtokmeaning->name, tp_anyptr);
                gettok();
            } else {
		ex = p_factor(tp_proc);
		if (ex->val.type->kind == TK_PROCPTR) {
		  /*  ex = makeexpr_dotq(ex, "proc", tp_anyptr);  */
		} else if (ex->val.type->kind == TK_CPROCPTR) {
		    ex = makeexpr_cast(ex, tp_anyptr);
		} else
		    ex = makeexpr_addrf(ex);
            }
            return ex;

        case TOK_LBR:
	case TOK_LBRACE:
            return p_setfactor(NULL);

        case TOK_NIL:
            gettok();
            return makeexpr_nil();

	case TOK_IF:    /* nifty Pascal extension */
	    gettok();
	    ex = p_expr(tp_boolean);
	    wneedtok(TOK_THEN);
	    ex2 = p_expr(tp_integer);
	    if (wneedtok(TOK_ELSE))
		return makeexpr_cond(ex, ex2, p_factor(ex2->val.type));
	    else
		return makeexpr_cond(ex, ex2, makeexpr_long(0));

        case TOK_IDENT:
            mp = curtokmeaning;
            switch ((mp) ? mp->kind : MK_VAR) {

                case MK_TYPE:
                    gettok();
                    type = mp->type;
                    switch (curtok) {

                        case TOK_LPAR:    /* Turbo type cast */
                            gettok();
                            ex2 = p_expr(type);
			    ex = pascaltypecast(type, ex2);
                            skipcloseparen();
                            return dots_n_hats(ex, target);

                        case TOK_LBR:
			case TOK_LBRACE:
                            switch (type->kind) {

                                case TK_SET:
                                case TK_SMALLSET:
                                    return p_setfactor(type->indextype);

                                case TK_RECORD:
                                    return p_constrecord(type, 0);

                                case TK_ARRAY:
                                case TK_SMALLARRAY:
                                    return p_constarray(type, 0);

                                case TK_STRING:
                                    return p_conststring(type, 0);

                                default:
                                    warning("Bad type for constructor [304]");
				    skipparens();
				    return makeexpr_name(mp->name, mp->type);
                            }

			default:
			    wexpected("an expression");
			    return makeexpr_name(mp->name, mp->type);
                    }

                case MK_SPECIAL:
                    if (mp->handler && mp->isfunction &&
			(curtok == TOK_LPAR || !target ||
			 (target->kind != TK_PROCPTR &&
			  target->kind != TK_CPROCPTR))) {
                        gettok();
                        if ((mp->sym->flags & LEAVEALONE) || mp->constdefn) {
                            ex = makeexpr_bicall_0(mp->name, tp_integer);
                            if (curtok == TOK_LPAR) {
                                do {
                                    gettok();
                                    insertarg(&ex, ex->nargs, p_expr(NULL));
                                } while (curtok == TOK_COMMA);
                                skipcloseparen();
                            }
                            tryfuncmacro(&ex, mp);
			    return ex;
                        }
                        ex = (*mp->handler)(mp);
			if (!ex)
			    ex = makeexpr_long(0);
			return ex;
                    } else {
			if (target->kind == TK_PROCPTR ||
			    target->kind == TK_CPROCPTR)
			    note("Using a built-in procedure as a procedure pointer [316]");
                        else
			    symclass(curtoksym);
                        gettok();
                        return makeexpr_name(mp->name, tp_integer);
                    }

                case MK_FUNCTION:
                    mp->refcount++;
                    need_forward_decl(mp);
		    gettok();
                    if (mp->isfunction &&
			(curtok == TOK_LPAR || !target ||
			 (target->kind != TK_PROCPTR &&
			  target->kind != TK_CPROCPTR))) {
                        ex = p_funccall(mp);
                        if (!mp->constdefn) {
                            if (mp->handler && !(mp->sym->flags & LEAVEALONE))
                                ex = (*mp->handler)(ex);
			}
			if (mp->cbase->kind == MK_VARPARAM) {
			    ex = makeexpr_hat(ex, 0);    /* returns pointer to structured result */
                        }
                        return dots_n_hats(ex, target);
                    } else {
			if (mp->handler && !(mp->sym->flags & LEAVEALONE))
			    note("Using a built-in procedure as a procedure pointer [316]");
			if (target && target->kind == TK_CPROCPTR) {
			    type = maketype(TK_CPROCPTR);
			    type->basetype = mp->type;
			    type->escale = 0;
			    mp2 = makestmttempvar(type, name_TEMP);
			    ex = makeexpr_comma(
                                    makeexpr_assign(
                                       makeexpr_var(mp2),
				       makeexpr_name(mp->name, tp_text)),
				    makeexpr_var(mp2));
			    if (mp->ctx->kind == MK_FUNCTION)
				warning("Procedure pointer to nested procedure [305]");
			} else {
			    type = maketype(TK_PROCPTR);
			    type->basetype = mp->type;
			    type->escale = 1;
			    mp2 = makestmttempvar(type, name_TEMP);
			    ex = makeexpr_comma(
                                    makeexpr_comma(
                                       makeexpr_assign(
                                          makeexpr_dotq(makeexpr_var(mp2),
							"proc",
							tp_anyptr),
					  makeexpr_name(mp->name, tp_text)),
                                          /* handy pointer type */
				       makeexpr_assign(
                                          makeexpr_dotq(makeexpr_var(mp2),
							"link",
							tp_anyptr),
				          makeexpr_ctx(mp->ctx))),
				    makeexpr_var(mp2));
			}
                        return ex;
                    }

                default:
                    return p_variable(target);
            }

	default:
	    wexpected("an expression");
	    return makeexpr_long(0);
	    
    }
}

Static Expr *p_powterm(target)
Type *target;
{
    Expr *ex = p_factor(target);
    Expr *ex2;
    int i, castit;
    long v;

    if (curtok == TOK_STARSTAR) {
	gettok();
	ex2 = p_powterm(target);
	if (ex->val.type->kind == TK_REAL ||
	    ex2->val.type->kind == TK_REAL) {
	    if (checkconst(ex2, 2)) {
		ex = makeexpr_sqr(ex, 0);
	    } else if (checkconst(ex2, 3)) {
		ex = makeexpr_sqr(ex, 1);
	    } else {
		castit = castargs >= 0 ? castargs : (prototypes == 0);
		if (ex->val.type->kind != TK_REAL && castit)
		    ex = makeexpr_cast(ex, tp_longreal);
		if (ex2->val.type->kind != TK_REAL && castit)
		    ex2 = makeexpr_cast(ex2, tp_longreal);
		ex = makeexpr_bicall_2("pow", tp_longreal, ex, ex2);
	    }
	} else if (checkconst(ex, 2)) {
	    freeexpr(ex);
	    ex = makeexpr_bin(EK_LSH, tp_integer,
			      makeexpr_longcast(makeexpr_long(1), 1), ex2);
	} else if (checkconst(ex, 0) ||
		   checkconst(ex, 1) ||
		   checkconst(ex2, 1)) {
	    freeexpr(ex2);
	} else if (checkconst(ex2, 0)) {
	    freeexpr(ex);
	    freeexpr(ex2);
	    ex = makeexpr_long(1);
	} else if (isliteralconst(ex, NULL) == 2 &&
		   isliteralconst(ex2, NULL) == 2 &&
		   ex2->val.i > 0) {
	    v = ex->val.i;
	    i = ex2->val.i;
	    while (--i > 0)
		v *= ex->val.i;
	    freeexpr(ex);
	    freeexpr(ex2);
	    ex = makeexpr_long(v);
	} else if (checkconst(ex2, 2)) {
	    ex = makeexpr_sqr(ex, 0);
	} else if (checkconst(ex2, 3)) {
	    ex = makeexpr_sqr(ex, 1);
	} else {
	    ex = makeexpr_bicall_2("ipow", tp_integer,
				   makeexpr_arglong(ex, 1),
				   makeexpr_arglong(ex2, 1));
	}
    }
    return ex;
}


Static Expr *p_term(target)
Type *target;
{
    Expr *ex = p_powterm(target);
    Expr *ex2;
    Type *type;
    Meaning *tvar;
    int useshort;

    for (;;) {
	checkkeyword(TOK_SHL);
	checkkeyword(TOK_SHR);
	checkkeyword(TOK_REM);
        switch (curtok) {

            case TOK_STAR:
                gettok();
                if (ex->val.type->kind == TK_SET ||
                    ex->val.type->kind == TK_SMALLSET) {
                    ex2 = p_powterm(ex->val.type);
                    type = mixsets(&ex, &ex2);
                    if (type->kind == TK_SMALLSET) {
                        ex = makeexpr_bin(EK_BAND, type, ex, ex2);
                    } else {
                        tvar = makestmttempvar(type, name_SET);
                        ex = makeexpr_bicall_3(setintname, type,
                                               makeexpr_var(tvar),
                                               ex, ex2);
                    }
                } else
                    ex = makeexpr_times(ex, p_powterm(tp_integer));
                break;

            case TOK_SLASH:
                gettok();
                if (ex->val.type->kind == TK_SET ||
                    ex->val.type->kind == TK_SMALLSET) {
                    ex2 = p_powterm(ex->val.type);
                    type = mixsets(&ex, &ex2);
                    if (type->kind == TK_SMALLSET) {
                        ex = makeexpr_bin(EK_BXOR, type, ex, ex2);
                    } else {
                        tvar = makestmttempvar(type, name_SET);
                        ex = makeexpr_bicall_3(setxorname, type,
                                               makeexpr_var(tvar),
                                               ex, ex2);
                    }
		} else
		    ex = makeexpr_divide(ex, p_powterm(tp_integer));
                break;

            case TOK_DIV:
                gettok();
                ex = makeexpr_div(ex, p_powterm(tp_integer));
                break;

            case TOK_REM:
                gettok();
                ex = makeexpr_rem(ex, p_powterm(tp_integer));
                break;

            case TOK_MOD:
                gettok();
                ex = makeexpr_mod(ex, p_powterm(tp_integer));
                break;

            case TOK_AND:
	    case TOK_AMP:
		useshort = (curtok == TOK_AMP);
                gettok();
                ex2 = p_powterm(tp_integer);
                if (ord_type(ex->val.type)->kind == TK_INTEGER)
                    ex = makeexpr_bin(EK_BAND, ex->val.type, ex, ex2);
                else if (partial_eval_flag || useshort ||
                         (shortopt && nosideeffects(ex2, 1)))
                    ex = makeexpr_and(ex, ex2);
                else
                    ex = makeexpr_bin(EK_BAND, tp_boolean, ex, ex2);
                break;

            case TOK_SHL:
                gettok();
                ex = makeexpr_bin(EK_LSH, ex->val.type, ex, p_powterm(tp_integer));
                break;

            case TOK_SHR:
                gettok();
                ex = force_unsigned(ex);
                ex = makeexpr_bin(EK_RSH, ex->val.type, ex, p_powterm(tp_integer));
                break;

            default:
                return ex;
        }
    }
}



Static Expr *p_sexpr(target)
Type *target;
{
    Expr *ex, *ex2;
    Type *type;
    Meaning *tvar;
    int useshort;

    switch (curtok) {
        case TOK_MINUS:
            gettok();
            if (curtok == TOK_MININT) {
                gettok();
                ex = makeexpr_long(MININT);
		break;
            }
            ex = makeexpr_neg(p_term(target));
            break;
        case TOK_PLUS:
            gettok();
        /* fall through */
        default:
            ex = p_term(target);
            break;
    }
    if (curtok == TOK_PLUS &&
        (ex->val.type->kind == TK_STRING ||
         ord_type(ex->val.type)->kind == TK_CHAR ||
         ex->val.type->kind == TK_ARRAY)) {
        while (curtok == TOK_PLUS) {
            gettok();
            ex = makeexpr_concat(ex, p_term(NULL), 0);
        }
        return ex;
    } else {
        for (;;) {
	    checkkeyword(TOK_XOR);
            switch (curtok) {

                case TOK_PLUS:
                    gettok();
                    if (ex->val.type->kind == TK_SET ||
                        ex->val.type->kind == TK_SMALLSET) {
                        ex2 = p_term(ex->val.type);
                        type = mixsets(&ex, &ex2);
                        if (type->kind == TK_SMALLSET) {
                            ex = makeexpr_bin(EK_BOR, type, ex, ex2);
                        } else {
                            tvar = makestmttempvar(type, name_SET);
                            ex = makeexpr_bicall_3(setunionname, type,
                                                   makeexpr_var(tvar),
                                                   ex, ex2);
                        }
                    } else
                        ex = makeexpr_plus(ex, p_term(tp_integer));
                    break;

                case TOK_MINUS:
                    gettok();
                    if (ex->val.type->kind == TK_SET ||
                        ex->val.type->kind == TK_SMALLSET) {
                        ex2 = p_term(tp_integer);
                        type = mixsets(&ex, &ex2);
                        if (type->kind == TK_SMALLSET) {
                            ex = makeexpr_bin(EK_BAND, type, ex,
                                              makeexpr_un(EK_BNOT, type, ex2));
                        } else {
                            tvar = makestmttempvar(type, name_SET);
                            ex = makeexpr_bicall_3(setdiffname, type,
                                                   makeexpr_var(tvar), ex, ex2);
                        }
                    } else
                        ex = makeexpr_minus(ex, p_term(tp_integer));
                    break;

		case TOK_VBAR:
		    if (modula2)
			return ex;
		    /* fall through */

                case TOK_OR:
		    useshort = (curtok == TOK_VBAR);
                    gettok();
                    ex2 = p_term(tp_integer);
                    if (ord_type(ex->val.type)->kind == TK_INTEGER)
                        ex = makeexpr_bin(EK_BOR, ex->val.type, ex, ex2);
                    else if (partial_eval_flag || useshort ||
                             (shortopt && nosideeffects(ex2, 1)))
                        ex = makeexpr_or(ex, ex2);
                    else
                        ex = makeexpr_bin(EK_BOR, tp_boolean, ex, ex2);
                    break;

                case TOK_XOR:
                    gettok();
                    ex2 = p_term(tp_integer);
                    ex = makeexpr_bin(EK_BXOR, ex->val.type, ex, ex2);
                    break;

                default:
                    return ex;
            }
        }
    }
}



Expr *p_expr(target)
Type *target;
{
    Expr *ex = p_sexpr(target);
    Expr *ex2, *ex3, *ex4;
    Type *type;
    Meaning *tvar;
    long mask, smin, smax;
    int i, j;

    switch (curtok) {

        case TOK_EQ:
            gettok();
            return makeexpr_rel(EK_EQ, ex, p_sexpr(ex->val.type));

        case TOK_NE:
            gettok();
            return makeexpr_rel(EK_NE, ex, p_sexpr(ex->val.type));

        case TOK_LT:
            gettok();
            return makeexpr_rel(EK_LT, ex, p_sexpr(ex->val.type));

        case TOK_GT:
            gettok();
            return makeexpr_rel(EK_GT, ex, p_sexpr(ex->val.type));

        case TOK_LE:
            gettok();
            return makeexpr_rel(EK_LE, ex, p_sexpr(ex->val.type));

        case TOK_GE:
            gettok();
            return makeexpr_rel(EK_GE, ex, p_sexpr(ex->val.type));

        case TOK_IN:
            gettok();
            ex2 = p_sexpr(tp_smallset);
            ex = gentle_cast(ex, ex2->val.type->indextype);
            if (ex2->val.type->kind == TK_SMALLSET) {
                if (!ord_range(ex->val.type, &smin, &smax)) {
                    smin = -1;
                    smax = setbits;
                }
                if (!nosideeffects(ex, 0)) {
                    tvar = makestmttempvar(ex->val.type, name_TEMP);
                    ex3 = makeexpr_assign(makeexpr_var(tvar), ex);
                    ex = makeexpr_var(tvar);
                } else
                    ex3 = NULL;
                ex4 = copyexpr(ex);
                if (ex->kind == EK_CONST && smallsetconst)
                    ex = makesmallsetconst(1<<ex->val.i, ex2->val.type);
                else
                    ex = makeexpr_bin(EK_LSH, ex2->val.type,
                                      makeexpr_longcast(makeexpr_long(1), 1),
                                      enum_to_int(ex));
                ex = makeexpr_rel(EK_NE, makeexpr_bin(EK_BAND, tp_integer, ex, ex2),
                                         makeexpr_long(0));
                if (*name_SETBITS ||
                    ((ex4->kind == EK_CONST) ? ((unsigned long)ex4->val.i >= setbits)
                                             : !(0 <= smin && smax < setbits))) {
                    ex = makeexpr_and(makeexpr_range(enum_to_int(ex4),
                                                     makeexpr_long(0),
                                                     makeexpr_setbits(), 0),
                                      ex);
                } else
                    freeexpr(ex4);
                ex = makeexpr_comma(ex3, ex);
                return ex;
            } else {
                ex3 = ex2;
                while (ex3->kind == EK_BICALL &&
                       (!strcmp(ex3->val.s, setaddname) ||
                        !strcmp(ex3->val.s, setaddrangename)))
                    ex3 = ex3->args[0];
                if (ex3->kind == EK_BICALL && !strcmp(ex3->val.s, setexpandname) &&
                    (tvar = istempvar(ex3->args[0])) != NULL && 
                    isconstexpr(ex3->args[1], &mask)) {
                    canceltempvar(tvar);
                    if (!nosideeffects(ex, 0)) {
                        tvar = makestmttempvar(ex->val.type, name_TEMP);
                        ex3 = makeexpr_assign(makeexpr_var(tvar), ex);
                        ex = makeexpr_var(tvar);
                    } else
                        ex3 = NULL;
                    type = ord_type(ex2->val.type->indextype);
                    ex4 = NULL;
                    i = 0;
                    while (i < setbits) {
                        if (mask & (1<<i++)) {
                            if (i+1 < setbits && (mask & (2<<i))) {
                                for (j = i; j < setbits && (mask & (1<<j)); j++) ;
                                ex4 = makeexpr_or(ex4,
                                        makeexpr_range(copyexpr(ex),
                                                       makeexpr_val(make_ord(type, i-1)),
                                                       makeexpr_val(make_ord(type, j-1)), 1));
                                i = j;
                            } else {
                                ex4 = makeexpr_or(ex4,
                                        makeexpr_rel(EK_EQ, copyexpr(ex),
                                                            makeexpr_val(make_ord(type, i-1))));
                            }
                        }
                    }
                    mask = 0;
                    for (;;) {
                        if (!strcmp(ex2->val.s, setaddrangename)) {
                            if (checkconst(ex2->args[1], 'a') &&
                                checkconst(ex2->args[2], 'z')) {
                                mask |= 0x1;
                            } else if (checkconst(ex2->args[1], 'A') &&
                                       checkconst(ex2->args[2], 'Z')) {
                                mask |= 0x2;
                            } else if (checkconst(ex2->args[1], '0') &&
                                       checkconst(ex2->args[2], '9')) {
                                mask |= 0x4;
                            } else {
                                ex4 = makeexpr_or(ex4,
                                        makeexpr_range(copyexpr(ex), ex2->args[1], ex2->args[2], 1));
                            }
                        } else if (!strcmp(ex2->val.s, setaddname)) {
                            ex4 = makeexpr_or(ex4,
                                    makeexpr_rel(EK_EQ, copyexpr(ex), ex2->args[1]));
                        } else
                            break;
                        ex2 = ex2->args[0];
                    }
                    /* do these now so that EK_OR optimizations will work: */
                    if (mask & 0x1)
                        ex4 = makeexpr_or(ex4, makeexpr_range(copyexpr(ex),
                                                              makeexpr_char('a'),
                                                              makeexpr_char('z'), 1));
                    if (mask & 0x2)
                        ex4 = makeexpr_or(ex4, makeexpr_range(copyexpr(ex),
                                                              makeexpr_char('A'),
                                                              makeexpr_char('Z'), 1));
                    if (mask & 0x4)
                        ex4 = makeexpr_or(ex4, makeexpr_range(copyexpr(ex),
                                                              makeexpr_char('0'),
                                                              makeexpr_char('9'), 1));
                    freeexpr(ex);
                    return makeexpr_comma(ex3, ex4);
                }
                return makeexpr_bicall_2(setinname, tp_boolean,
                                         makeexpr_arglong(ex, 0), ex2);
            }

	default:
	    return ex;
    }
}







/* Parse a C expression; used by VarMacro, etc. */

Type *nametotype(name)
char *name;
{
    if (!strcicmp(name, "malloc") ||
	!strcicmp(name, mallocname)) {
	return tp_anyptr;
    }
    return tp_integer;
}


int istypespec()
{
    switch (curtok) {

        case TOK_CONST:
            return 1;

        case TOK_IDENT:
            return !strcmp(curtokcase, "volatile") ||
                   !strcmp(curtokcase, "void") ||
                   !strcmp(curtokcase, "char") ||
                   !strcmp(curtokcase, "short") ||
                   !strcmp(curtokcase, "int") ||
                   !strcmp(curtokcase, "long") ||
                   !strcmp(curtokcase, "float") ||
                   !strcmp(curtokcase, "double") ||
                   !strcmp(curtokcase, "signed") ||
                   !strcmp(curtokcase, "unsigned") ||
                   !strcmp(curtokcase, "struct") ||
                   !strcmp(curtokcase, "union") ||
                   !strcmp(curtokcase, "class") ||
                   !strcmp(curtokcase, "enum") ||
                   !strcmp(curtokcase, "typedef") ||
                   (curtokmeaning &&
                    curtokmeaning->kind == MK_TYPE);

        default:
            return 0;
    }
}



Expr *pc_parentype(cp)
char *cp;
{
    Expr *ex;

    if (curtok == TOK_IDENT &&
         curtokmeaning &&
         curtokmeaning->kind == MK_TYPE) {
        ex = makeexpr_type(curtokmeaning->type);
        gettok();
        skipcloseparen();
    } else if (curtok == TOK_IDENT && !strcmp(curtokcase, "typedef")) {
        ex = makeexpr_name(getparenstr(inbufptr), tp_integer);
        gettok();
    } else {
        ex = makeexpr_name(getparenstr(cp), tp_integer);
        gettok();
    }
    return ex;
}




Expr *pc_expr2();

Expr *pc_factor()
{
    Expr *ex;
    char *cp;
    Strlist *sl;
    int i;

    switch (curtok) {

        case TOK_BANG:
            gettok();
            return makeexpr_not(pc_expr2(14));

        case TOK_TWIDDLE:
            gettok();
            return makeexpr_un(EK_BNOT, tp_integer, pc_expr2(14));

        case TOK_PLPL:
            gettok();
            ex = pc_expr2(14);
            return makeexpr_assign(ex, makeexpr_plus(copyexpr(ex), makeexpr_long(1)));

        case TOK_MIMI:
            gettok();
            ex = pc_expr2(14);
            return makeexpr_assign(ex, makeexpr_minus(copyexpr(ex), makeexpr_long(1)));

        case TOK_STAR:
            gettok();
            ex = pc_expr2(14);
            if (ex->val.type->kind != TK_POINTER)
                ex->val.type = makepointertype(ex->val.type);
            return makeexpr_hat(ex, 0);

        case TOK_AMP:
            gettok();
            return makeexpr_addr(pc_expr2(14));

        case TOK_PLUS:
            gettok();
            return pc_expr2(14);

        case TOK_MINUS:
            gettok();
            return makeexpr_neg(pc_expr2(14));

        case TOK_LPAR:
            cp = inbufptr;
            gettok();
            if (istypespec()) {
                ex = pc_parentype(cp);
                return makeexpr_bin(EK_LITCAST, tp_integer, ex, pc_expr2(14));
            }
            ex = pc_expr();
            skipcloseparen();
            return ex;

        case TOK_IDENT:
            if (!strcmp(curtokcase, "sizeof")) {
                gettok();
                if (curtok != TOK_LPAR)
                    return makeexpr_sizeof(pc_expr2(14), 1);
                cp = inbufptr;
                gettok();
                if (istypespec()) {
                    ex = makeexpr_sizeof(pc_parentype(cp), 1);
                } else {
                    ex = makeexpr_sizeof(pc_expr(), 1);
                    skipcloseparen();
                }
                return ex;
            }
            if (curtoksym->flags & FMACREC) {
                ex = makeexpr(EK_MACARG, 0);
                ex->val.type = tp_integer;
                ex->val.i = 0;
                for (sl = funcmacroargs, i = 1; sl; sl = sl->next, i++) {
                    if (sl->value == (long)curtoksym) {
                        ex->val.i = i;
                        break;
                    }
                }
            } else
                ex = makeexpr_name(curtokcase, nametotype(curtokcase));
            gettok();
            return ex;

        case TOK_INTLIT:
            ex = makeexpr_long(curtokint);
            if (curtokbuf[strlen(curtokbuf)-1] == 'L')
                ex = makeexpr_longcast(ex, 1);
            gettok();
            return ex;

        case TOK_HEXLIT:
            ex = makeexpr_long(curtokint);
            insertarg(&ex, 0, makeexpr_name("%#lx", tp_integer));
            if (curtokbuf[strlen(curtokbuf)-1] == 'L')
                ex = makeexpr_longcast(ex, 1);
            gettok();
            return ex;

        case TOK_OCTLIT:
            ex = makeexpr_long(curtokint);
            insertarg(&ex, 0, makeexpr_name("%#lo", tp_integer));
            if (curtokbuf[strlen(curtokbuf)-1] == 'L')
                ex = makeexpr_longcast(ex, 1);
            gettok();
            return ex;

        case TOK_REALLIT:
            ex = makeexpr_real(curtokbuf);
            gettok();
            return ex;

        case TOK_STRLIT:
            ex = makeexpr_lstring(curtokbuf, curtokint);
            gettok();
            return ex;

        case TOK_CHARLIT:
            ex = makeexpr_char(curtokint);
            gettok();
            return ex;

        default:
	    wexpected("a C expression");
	    return makeexpr_long(0);
    }
}




#define pc_prec(pr)  if (prec > (pr)) return ex; gettok();

Expr *pc_expr2(prec)
int prec;
{
    Expr *ex, *ex2;
    int i;

    ex = pc_factor();
    for (;;) {
        switch (curtok) {

            case TOK_COMMA:
                pc_prec(1);
                ex = makeexpr_comma(ex, pc_expr2(2));
                break;

            case TOK_EQ:
                pc_prec(2);
                ex = makeexpr_assign(ex, pc_expr2(2));
                break;

            case TOK_QM:
                pc_prec(3);
                ex2 = pc_expr();
                if (wneedtok(TOK_COLON))
		    ex = makeexpr_cond(ex, ex2, pc_expr2(3));
		else
		    ex = makeexpr_cond(ex, ex2, makeexpr_long(0));
                break;

            case TOK_OROR:
                pc_prec(4);
                ex = makeexpr_or(ex, pc_expr2(5));
                break;

            case TOK_ANDAND:
                pc_prec(5);
                ex = makeexpr_and(ex, pc_expr2(6));
                break;

            case TOK_VBAR:
                pc_prec(6);
                ex = makeexpr_bin(EK_BOR, tp_integer, ex, pc_expr2(7));
                break;

            case TOK_HAT:
                pc_prec(7);
                ex = makeexpr_bin(EK_BXOR, tp_integer, ex, pc_expr2(8));
                break;

            case TOK_AMP:
                pc_prec(8);
                ex = makeexpr_bin(EK_BAND, tp_integer, ex, pc_expr2(9));
                break;

            case TOK_EQEQ:
                pc_prec(9);
                ex = makeexpr_rel(EK_EQ, ex, pc_expr2(10));
                break;

            case TOK_BANGEQ:
                pc_prec(9);
                ex = makeexpr_rel(EK_NE, ex, pc_expr2(10));
                break;

            case TOK_LT:
                pc_prec(10);
                ex = makeexpr_rel(EK_LT, ex, pc_expr2(11));
                break;

            case TOK_LE:
                pc_prec(10);
                ex = makeexpr_rel(EK_LE, ex, pc_expr2(11));
                break;

            case TOK_GT:
                pc_prec(10);
                ex = makeexpr_rel(EK_GT, ex, pc_expr2(11));
                break;

            case TOK_GE:
                pc_prec(10);
                ex = makeexpr_rel(EK_GE, ex, pc_expr2(11));
                break;

            case TOK_LTLT:
                pc_prec(11);
                ex = makeexpr_bin(EK_LSH, tp_integer, ex, pc_expr2(12));
                break;

            case TOK_GTGT:
                pc_prec(11);
                ex = makeexpr_bin(EK_RSH, tp_integer, ex, pc_expr2(12));
                break;

            case TOK_PLUS:
                pc_prec(12);
                ex = makeexpr_plus(ex, pc_expr2(13));
                break;

            case TOK_MINUS:
                pc_prec(12);
                ex = makeexpr_minus(ex, pc_expr2(13));
                break;

            case TOK_STAR:
                pc_prec(13);
                ex = makeexpr_times(ex, pc_expr2(14));
                break;

            case TOK_SLASH:
                pc_prec(13);
                ex = makeexpr_div(ex, pc_expr2(14));
                break;

            case TOK_PERC:
                pc_prec(13);
                ex = makeexpr_mod(ex, pc_expr2(14));
                break;

            case TOK_PLPL:
                pc_prec(15);
                ex = makeexpr_un(EK_POSTINC, tp_integer, ex);
                break;

            case TOK_MIMI:
                pc_prec(15);
                ex = makeexpr_un(EK_POSTDEC, tp_integer, ex);
                break;

            case TOK_LPAR:
                pc_prec(16);
                if (ex->kind == EK_NAME) {
                    ex->kind = EK_BICALL;
                } else {
                    ex = makeexpr_un(EK_SPCALL, tp_integer, ex);
                }
                while (curtok != TOK_RPAR) {
                    insertarg(&ex, ex->nargs, pc_expr2(2));
                    if (curtok != TOK_RPAR)
                        if (!wneedtok(TOK_COMMA))
			    skiptotoken2(TOK_RPAR, TOK_SEMI);
                }
                gettok();
                break;

            case TOK_LBR:
                pc_prec(16);
                ex = makeexpr_index(ex, pc_expr(), NULL);
                if (!wneedtok(TOK_RBR))
		    skippasttoken(TOK_RBR);
                break;

            case TOK_ARROW:
                pc_prec(16);
                if (!wexpecttok(TOK_IDENT))
		    break;
                if (ex->val.type->kind != TK_POINTER)
                    ex->val.type = makepointertype(ex->val.type);
                ex = makeexpr_dotq(makeexpr_hat(ex, 0),
                                   curtokcase, tp_integer);
                gettok();
                break;

            case TOK_DOT:
                pc_prec(16);
                if (!wexpecttok(TOK_IDENT))
		    break;
                ex = makeexpr_dotq(ex, curtokcase, tp_integer);
                gettok();
                break;

	    case TOK_COLONCOLON:
		if (prec > 16)
		    return ex;
		i = C_lex;
		C_lex = 0;
		gettok();
		if (curtok == TOK_IDENT &&
		    curtokmeaning && curtokmeaning->kind == MK_TYPE) {
		    ex->val.type = curtokmeaning->type;
		} else if (curtok == TOK_LPAR) {
		    gettok();
		    ex->val.type = p_type(NULL);
		    if (!wexpecttok(TOK_RPAR))
			skiptotoken(TOK_RPAR);
		} else
		    wexpected("a type name");
		C_lex = i;
		gettok();
		break;

            default:
                return ex;
        }
    }
}

