/* "p2c", a Pascal to C translator.
   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation.
   Author's address: daveg@synaptics.com.

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_FUNCS_C
#include "trans.h"




Static Strlist *enumnames;
Static int enumnamecount;



void setup_funcs()
{
    enumnames = NULL;
    enumnamecount = 0;
}





int isvar(ex, mp)
Expr *ex;
Meaning *mp;
{
    return (ex->kind == EK_VAR && (Meaning *)ex->val.i == mp);
}




char *getstring(ex)
Expr *ex;
{
    ex = makeexpr_stringify(ex);
    if (ex->kind != EK_CONST || ex->val.type->kind != TK_STRING) {
        intwarning("getstring", "Not a string literal [206]");
	return "";
    }
    return ex->val.s;
}




Expr *p_parexpr(target)
Type *target;
{
    Expr *ex;

    if (wneedtok(TOK_LPAR)) {
	ex = p_expr(target);
	if (!wneedtok(TOK_RPAR))
	    skippasttotoken(TOK_RPAR, TOK_SEMI);
    } else
	ex = p_expr(target);
    return ex;
}



Type *argbasetype(ex)
Expr *ex;
{
    if (ex->kind == EK_CAST)
        ex = ex->args[0];
    if (ex->val.type->kind == TK_POINTER)
        return ex->val.type->basetype;
    else
        return ex->val.type;
}



Type *choosetype(t1, t2)
Type *t1, *t2;
{
    if (t1 == tp_void ||
        (type_sizeof(t2, 1) && !type_sizeof(t1, 1)))
        return t2;
    else
        return t1;
}



Expr *convert_offset(type, ex2)
Type *type;
Expr *ex2;
{
    long size;
    int i;
    Value val;
    Expr *ex3;

    if (type->kind == TK_POINTER ||
        type->kind == TK_ARRAY ||
        type->kind == TK_SET ||
        type->kind == TK_STRING)
        type = type->basetype;
    size = type_sizeof(type, 1);
    if (size == 1)
        return ex2;
    val = eval_expr_pasc(ex2);
    if (val.type) {
        if (val.i == 0)
            return ex2;
        if (size && val.i % size == 0) {
            freeexpr(ex2);
            return makeexpr_long(val.i / size);
        }
    } else {     /* look for terms like "n*sizeof(foo)" */
	while (ex2->kind == EK_CAST || ex2->kind == EK_ACTCAST)
	    ex2 = ex2->args[0];
        if (ex2->kind == EK_TIMES) {
	    for (i = 0; i < ex2->nargs; i++) {
		ex3 = convert_offset(type, ex2->args[i]);
		if (ex3) {
		    ex2->args[i] = ex3;
		    return resimplify(ex2);
		}
	    }
            for (i = 0;
                 i < ex2->nargs && ex2->args[i]->kind != EK_SIZEOF;
                 i++) ;
            if (i < ex2->nargs) {
                if (ex2->args[i]->args[0]->val.type == type) {
                    delfreearg(&ex2, i);
                    if (ex2->nargs == 1)
                        return ex2->args[0];
                    else
                        return ex2;
                }
            }
        } else if (ex2->kind == EK_PLUS) {
	    ex3 = copyexpr(ex2);
	    for (i = 0; i < ex2->nargs; i++) {
		ex3->args[i] = convert_offset(type, ex3->args[i]);
		if (!ex3->args[i]) {
		    freeexpr(ex3);
		    return NULL;
		}
	    }
	    freeexpr(ex2);
	    return resimplify(ex3);
        } else if (ex2->kind == EK_SIZEOF) {
            if (ex2->args[0]->val.type == type) {
                freeexpr(ex2);
                return makeexpr_long(1);
            }
        } else if (ex2->kind == EK_NEG) {
	    ex3 = convert_offset(type, ex2->args[0]);
	    if (ex3)
                return makeexpr_neg(ex3);
        }
    }
    return NULL;
}



Expr *convert_size(type, ex, name)
Type *type;
Expr *ex;
char *name;
{
    long size;
    Expr *ex2;
    int i, okay;
    Value val;

    if (debug>2) { fprintf(outf,"convert_size("); dumpexpr(ex); fprintf(outf,")\n"); }
    while (type->kind == TK_ARRAY || type->kind == TK_STRING)
        type = type->basetype;
    if (type == tp_void)
        return ex;
    size = type_sizeof(type, 1);
    if (size == 1)
        return ex;
    while (ex->kind == EK_CAST || ex->kind == EK_ACTCAST)
	ex = ex->args[0];
    switch (ex->kind) {

        case EK_TIMES:
            for (i = 0; i < ex->nargs; i++) {
                ex2 = convert_size(type, ex->args[i], NULL);
                if (ex2) {
                    ex->args[i] = ex2;
                    return resimplify(ex);
                }
            }
            break;

        case EK_PLUS:
            okay = 1;
            for (i = 0; i < ex->nargs; i++) {
                ex2 = convert_size(type, ex->args[i], NULL);
                if (ex2)
                    ex->args[i] = ex2;
                else
                    okay = 0;
            }
            ex = distribute_plus(ex);
            if ((ex->kind != EK_TIMES || !okay) && name)
                note(format_s("Suspicious mixture of sizes in %s [173]", name));
            return ex;

        case EK_SIZEOF:
            return ex;

	default:
	    break;
    }
    val = eval_expr_pasc(ex);
    if (val.type) {
        if (val.i == 0)
            return ex;
        if (size && val.i % size == 0) {
            freeexpr(ex);
            return makeexpr_times(makeexpr_long(val.i / size),
                                  makeexpr_sizeof(makeexpr_type(type), 0));
        }
    }
    if (name) {
        note(format_s("Can't interpret size in %s [174]", name));
        return ex;
    } else
        return NULL;
}












Static Expr *func_abs()
{
    Expr *ex;
    Meaning *tvar;
    int lness;

    ex = p_parexpr(tp_integer);
    if (ex->val.type->kind == TK_REAL)
        return makeexpr_bicall_1("fabs", tp_longreal, ex);
    else {
        lness = exprlongness(ex);
        if (lness < 0)
            return makeexpr_bicall_1("abs", tp_int, ex);
        else if (lness > 0 && *absname) {
            if (ansiC > 0) {
                return makeexpr_bicall_1("labs", tp_integer, ex);
            } else if (*absname == '*' && (exprspeed(ex) >= 5 || !nosideeffects(ex, 0))) {
                tvar = makestmttempvar(tp_integer, name_TEMP);
                return makeexpr_comma(makeexpr_assign(makeexpr_var(tvar),
                                                      ex),
                                      makeexpr_bicall_1(absname, tp_integer,
                                                        makeexpr_var(tvar)));
            } else {
                return makeexpr_bicall_1(absname, tp_integer, ex);
            }
        } else if (exprspeed(ex) < 5 && nosideeffects(ex, 0)) {
            return makeexpr_cond(makeexpr_rel(EK_LT, copyexpr(ex),
                                                     makeexpr_long(0)),
                                 makeexpr_neg(copyexpr(ex)),
                                 ex);
        } else {
            tvar = makestmttempvar(tp_integer, name_TEMP);
            return makeexpr_cond(makeexpr_rel(EK_LT, makeexpr_assign(makeexpr_var(tvar),
                                                                     ex),
                                                     makeexpr_long(0)),
                                 makeexpr_neg(makeexpr_var(tvar)),
                                 makeexpr_var(tvar));
        }
    }
}



Static Expr *func_addr()
{
    Expr *ex, *ex2, *ex3;
    Type *type, *tp2;
    int haspar;

    haspar = wneedtok(TOK_LPAR);
    ex = p_expr(tp_proc);
    if (curtok == TOK_COMMA) {
        gettok();
        ex2 = p_expr(tp_integer);
        ex3 = convert_offset(ex->val.type, ex2);
        if (checkconst(ex3, 0)) {
            ex = makeexpr_addrf(ex);
        } else {
            ex = makeexpr_addrf(ex);
            if (ex3) {
                ex = makeexpr_plus(ex, ex3);
            } else {
                note("Don't know how to reduce offset for ADDR [175]");
                type = makepointertype(tp_abyte);
		tp2 = ex->val.type;
                ex = makeexpr_cast(makeexpr_plus(makeexpr_cast(ex, type), ex2), tp2);
            }
        }
    } else {
	if ((ex->val.type->kind != TK_PROCPTR &&
	     ex->val.type->kind != TK_CPROCPTR) ||
	    (ex->kind == EK_VAR &&
	     ex->val.type == ((Meaning *)ex->val.i)->type))
	    ex = makeexpr_addrf(ex);
    }
    if (haspar) {
	if (!wneedtok(TOK_RPAR))
	    skippasttotoken(TOK_RPAR, TOK_SEMI);
    }
    return ex;
}


Static Expr *func_iaddress()
{
    return makeexpr_cast(func_addr(), tp_integer);
}



Static Expr *func_addtopointer()
{
    Expr *ex, *ex2, *ex3;
    Type *type, *tp2;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_anyptr);
    if (skipcomma()) {
	ex2 = p_expr(tp_integer);
    } else
	ex2 = makeexpr_long(0);
    skipcloseparen();
    ex3 = convert_offset(ex->val.type, ex2);
    if (!checkconst(ex3, 0)) {
	if (ex3) {
	    ex = makeexpr_plus(ex, ex3);
	} else {
	    note("Don't know how to reduce offset for ADDTOPOINTER [175]");
	    type = makepointertype(tp_abyte);
	    tp2 = ex->val.type;
	    ex = makeexpr_cast(makeexpr_plus(makeexpr_cast(ex, type), ex2), tp2);
	}
    }
    return ex;
}



Stmt *proc_assert()
{
    Expr *ex;

    ex = p_expr(tp_boolean);
    return makestmt_call(makeexpr_bicall_1("assert", tp_void, ex));
}



Stmt *wrapopencheck(sp, fex)
Stmt *sp;
Expr *fex;
{
    Stmt *sp2;

    if (FCheck(checkfileisopen) && !is_std_file(fex)) {
        sp2 = makestmt(SK_IF);
        sp2->exp1 = makeexpr_rel(EK_NE, filebasename(fex), makeexpr_nil());
        sp2->stm1 = sp;
        if (iocheck_flag) {
            sp2->stm2 = makestmt_call(makeexpr_bicall_1(name_ESCIO, tp_integer,
							makeexpr_name(filenotopenname, tp_int)));
        } else {
            sp2->stm2 = makestmt_assign(makeexpr_var(mp_ioresult),
					makeexpr_name(filenotopenname, tp_int));
        }
        return sp2;
    } else {
        freeexpr(fex);
        return sp;
    }
}



Static Expr *checkfilename(nex)
Expr *nex;
{
    Expr *ex;

    nex = makeexpr_stringcast(nex);
    if (nex->kind == EK_CONST && nex->val.type->kind == TK_STRING) {
        switch (which_lang) {

            case LANG_HP:
                if (!strncmp(nex->val.s, "#1:", 3) ||
                    !strncmp(nex->val.s, "console:", 8) ||
                    !strncmp(nex->val.s, "CONSOLE:", 8)) {
                    freeexpr(nex);
                    nex = makeexpr_string("/dev/tty");
                } else if (!strncmp(nex->val.s, "#2:", 3) ||
                           !strncmp(nex->val.s, "systerm:", 8) ||
                           !strncmp(nex->val.s, "SYSTERM:", 8)) {
                    freeexpr(nex);
                    nex = makeexpr_string("/dev/tty");     /* should do more? */
                } else if (!strncmp(nex->val.s, "#6:", 3) ||
                           !strncmp(nex->val.s, "printer:", 8) ||
                           !strncmp(nex->val.s, "PRINTER:", 8)) {
                    note("Opening a file named PRINTER: [176]");
                } else if (my_strchr(nex->val.s, ':')) {
                    note("Opening a file whose name contains a ':' [177]");
                }
                break;

            case LANG_TURBO:
                if (checkstring(nex, "con") ||
                    checkstring(nex, "CON") ||
                    checkstring(nex, "")) {
                    freeexpr(nex);
                    nex = makeexpr_string("/dev/tty");
                } else if (checkstring(nex, "nul") ||
                           checkstring(nex, "NUL")) {
                    freeexpr(nex);
                    nex = makeexpr_string("/dev/null");
                } else if (checkstring(nex, "lpt1") ||
                           checkstring(nex, "LPT1") ||
                           checkstring(nex, "lpt2") ||
                           checkstring(nex, "LPT2") ||
                           checkstring(nex, "lpt3") ||
                           checkstring(nex, "LPT3") ||
                           checkstring(nex, "com1") ||
                           checkstring(nex, "COM1") ||
                           checkstring(nex, "com2") ||
                           checkstring(nex, "COM2")) {
                    note("Opening a DOS device file name [178]");
                }
                break;

	    default:
		break;
        }
    } else {
	if (*filenamefilter && strcmp(filenamefilter, "0")) {
	    ex = makeexpr_sizeof(copyexpr(nex), 0);
	    nex = makeexpr_bicall_2(filenamefilter, tp_str255, nex, ex);
	} else
	    nex = makeexpr_stringify(nex);
    }
    return nex;
}



Static Stmt *assignfilename(fex, nex)
Expr *fex, *nex;
{
    Meaning *mp;
    Expr *nvex;

    nvex = filenamepart(fex);
    if (nvex) {
        freeexpr(fex);
        return makestmt_call(makeexpr_assign(nvex, nex));
    } else {
	mp = isfilevar(fex);
        if (mp)
            warning("Don't know how to ASSIGN to a non-explicit file variable [207]");
        else
            note("Encountered an ASSIGN statement [179]");
        return makestmt_call(makeexpr_bicall_2("assign", tp_void, fex, nex));
    }
}



Static Stmt *proc_assign()
{
    Expr *fex, *nex;

    if (!skipopenparen())
	return NULL;
    fex = p_expr(tp_text);
    if (!skipcomma())
	return NULL;
    nex = checkfilename(p_expr(tp_str255));
    skipcloseparen();
    return assignfilename(fex, nex);
}



Static Stmt *handleopen(code)
int code;
{
    Stmt *sp, *sp1, *sp2, *spassign;
    Expr *fex, *tfex, *nex, *ex, *truenex, *nvex;
    Meaning *fmp;
    int needcheckopen = 1;
    char modebuf[5], *cp;

    if (!skipopenparen())
	return NULL;
    fex = p_expr(tp_text);
    tfex = fex;
    fmp = isfilevar(fex);
    nvex = filenamepart(fex);
    truenex = NULL;
    spassign = NULL;
    if (curtok == TOK_COMMA) {
        gettok();
        ex = p_expr(tp_str255);
    } else
        ex = NULL;
    if (ex && (ex->val.type->kind == TK_STRING ||
	       ex->val.type->kind == TK_ARRAY)) {
        nex = checkfilename(ex);
        if (nvex) {
            spassign = assignfilename(copyexpr(fex), nex);
            nex = nvex;
        }
	truenex = nex;
        if (curtok == TOK_COMMA) {
            gettok();
            ex = p_expr(tp_str255);
        } else
            ex = NULL;
    } else if (nvex) {
        nex = nvex;
    } else {
	switch (code) {
	    case 0:
	        if (ex)
		    note("Can't interpret name argument in RESET [180]");
		break;
  	    case 1:
	        note("REWRITE does not specify a name [181]");
		break;
	    case 2:
		note("OPEN does not specify a name [181]");
		break;
	    case 3:
		note("APPEND does not specify a name [181]");
		break;
	}
	nex = NULL;
    }
    if (ex) {
        if (ord_type(ex->val.type)->kind == TK_INTEGER) {
	    if (!checkconst(ex, 1))
		note("Ignoring block size in binary file [182]");
            freeexpr(ex);
        } else {
	    if (ex->kind == EK_CONST && ex->val.type->kind == TK_STRING) {
		cp = getstring(ex);
		if (strcicmp(cp, "SHARED"))
		    note(format_s("Ignoring option string \"%s\" in open [183]", cp));
	    } else
		note("Ignoring option string in open [183]");
        }
    }
    switch (code) {

        case 0:  /* reset */
            strcpy(modebuf, "r");
            break;

        case 1:  /* rewrite */
            strcpy(modebuf, "w");
            break;

        case 2:  /* open */
            strcpy(modebuf, openmode);
            break;

        case 3:  /* append */
            strcpy(modebuf, "a");
            break;

    }
    if (!*modebuf) {
        strcpy(modebuf, "r+");
    }
    if (readwriteopen == 2 ||
	(israndomfile(fex->val.type) && code != 0) ||
	(readwriteopen &&
	 fex->val.type != tp_text &&
	 fex->val.type != tp_bigtext)) {
	if (!my_strchr(modebuf, '+'))
	    strcat(modebuf, "+");
    }
    if (fex->val.type != tp_text &&
	fex->val.type != tp_bigtext &&
	binarymode != 0) {
        if (binarymode == 1)
            strcat(modebuf, "b");
        else
            note("Opening a binary file [184]");
    }
    if (!nex && fmp &&
	!is_std_file(fex) &&
	literalfilesflag > 0 &&
	(literalfilesflag == 1 ||
	 strlist_cifind(literalfiles, fmp->name))) {
	nex = makeexpr_string(fmp->name);
    }
    sp1 = NULL;
    sp2 = NULL;
    if (!nex || (isfiletype(fex->val.type, 1) && !truenex)) {
	if (isvar(fex, mp_output)) {
	    note("RESET/REWRITE ignored for file OUTPUT [319]");
	} else {
	    sp1 = makestmt_call(makeexpr_bicall_1("rewind", tp_void,
						  filebasename(copyexpr(fex))));
	    if (code == 0 || is_std_file(fex)) {
		sp1 = wrapopencheck(sp1, copyexpr(fex));
		needcheckopen = 0;
	    } else
		sp1 = makestmt_if(makeexpr_rel(EK_NE,
					       filebasename(copyexpr(fex)),
					       makeexpr_nil()),
				 sp1,
				 makestmt_assign(filebasename(copyexpr(fex)),
						 makeexpr_bicall_0("tmpfile",
								   tp_text)));
	}
    }
    if (nex || isfiletype(fex->val.type, 1)) {
	needcheckopen = 1;
	if (!strcmp(freopenname, "fclose") ||
	    !strcmp(freopenname, "fopen")) {
	    sp2 = makestmt_assign(filebasename(copyexpr(fex)),
				  makeexpr_bicall_2("fopen", tp_text,
						    copyexpr(nex),
						    makeexpr_string(modebuf)));
	    if (!strcmp(freopenname, "fclose")) {
		sp2 = makestmt_seq(makestmt_if(makeexpr_rel(EK_NE,
							    filebasename(copyexpr(fex)),
							    makeexpr_nil()),
					       makestmt_call(makeexpr_bicall_1("fclose", tp_void,
									       filebasename(copyexpr(fex)))),
					       NULL),
				   sp2);
	    }
	} else {
	    char *frname = freopenname;
	    if (fex->kind == EK_VAR && fex->val.type == tp_text &&
		((Meaning *)fex->val.i == mp_input ||
		 (Meaning *)fex->val.i == mp_output)) {
		tfex = makeexpr_var(makestmttempvar(tp_text, name_TEMP));
		frname = "freopen";
	    }
	    sp2 = makestmt_assign(filebasename(copyexpr(tfex)),
				 makeexpr_bicall_3((*frname) ? frname : "freopen",
						   tp_text,
						   copyexpr(nex),
						   makeexpr_string(modebuf),
						   filebasename(copyexpr(fex))));
	    if (!*frname) {
		sp2 = makestmt_if(makeexpr_rel(EK_NE, filebasename(copyexpr(fex)),
					       makeexpr_nil()),
				  sp2,
				  makestmt_assign(filebasename(copyexpr(fex)),
						  makeexpr_bicall_2("fopen", tp_text,
								    copyexpr(nex),
								    makeexpr_string(modebuf))));
	    }
	}
    }
    if (!sp1)
	sp = sp2;
    else if (!sp2)
	sp = sp1;
    else {
	sp = makestmt_if(makeexpr_rel(EK_NE, copyexpr(nex),
				      makeexpr_string("")),
			 sp2, sp1);
    }
    if (code == 2 && !*openmode && nex) {
        sp = makestmt_seq(sp, makestmt_if(makeexpr_rel(EK_EQ,
						       filebasename(copyexpr(fex)),
						       makeexpr_nil()),
                                          makestmt_assign(filebasename(copyexpr(fex)),
                                                          makeexpr_bicall_2("fopen", tp_text,
                                                                            copyexpr(nex),
                                                                            makeexpr_string("w+"))),
                                          NULL));
    }
    if (FCheck(checkfileopen) && needcheckopen) {
        sp = makestmt_seq(sp, makestmt_call(
				  makeexpr_SETIO(
				      makeexpr_rel(EK_NE,
						   filebasename(copyexpr(tfex)),
						   makeexpr_nil()),
				      filenotfoundname,
				      filenamepart(tfex)
				      ? tfex : nex)));
    }
    sp = makestmt_seq(spassign, sp);
    cp = (code == 0) ? resetbufname : setupbufname;
    if (*cp &&   /* (may be eaten later, if buffering isn't needed) */
	fileisbuffered(fex, 1))
	sp = makestmt_seq(sp,
	         makestmt_call(
                     makeexpr_bicall_2(cp, tp_void, filebasename(fex),
			 makeexpr_type(filebasetype(fex->val.type)))));
    else
	freeexpr(fex);
    skipcloseparen();
    return sp;
}



Static Stmt *proc_append()
{
    return handleopen(3);
}



Static Expr *func_arccos(ex)
Expr *ex;
{
    return makeexpr_bicall_1("acos", tp_longreal, grabarg(ex, 0));
}


Static Expr *func_arcsin(ex)
Expr *ex;
{
    return makeexpr_bicall_1("asin", tp_longreal, grabarg(ex, 0));
}


Static Expr *func_arctan(ex)
Expr *ex;
{
    ex = grabarg(ex, 0);
    if (atan2flag && ex->kind == EK_DIVIDE)
        return makeexpr_bicall_2("atan2", tp_longreal, 
                                 ex->args[0], ex->args[1]);
    return makeexpr_bicall_1("atan", tp_longreal, ex);
}


Static Expr *func_arctanh(ex)
Expr *ex;
{
    return makeexpr_bicall_1("atanh", tp_longreal, grabarg(ex, 0));
}



Static Stmt *proc_argv()
{
    Expr *ex, *aex, *lex;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_integer);
    if (skipcomma()) {
	aex = p_expr(tp_str255);
    } else
	return NULL;
    skipcloseparen();
    lex = makeexpr_sizeof(copyexpr(aex), 0);
    aex = makeexpr_addrstr(aex);
    return makestmt_call(makeexpr_bicall_3("P_sun_argv", tp_void,
					   aex, lex, makeexpr_arglong(ex, 0)));
}


Static Expr *func_asr()
{
    Expr *ex;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_integer);
    if (skipcomma()) {
        if (signedshift == 0 || signedshift == 2) {
            ex = makeexpr_bicall_2("P_asr", ex->val.type, ex,
				   p_expr(tp_unsigned));
	} else {
	    ex = force_signed(ex);
	    ex = makeexpr_bin(EK_RSH, ex->val.type, ex, p_expr(tp_unsigned));
	    if (signedshift != 1)
		note("Assuming >> is an arithmetic shift [320]");
	}
	skipcloseparen();
    }
    return ex;
}


Static Expr *func_lsl()
{
    Expr *ex;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_integer);
    if (skipcomma()) {
	ex = makeexpr_bin(EK_LSH, ex->val.type, ex, p_expr(tp_unsigned));
	skipcloseparen();
    }
    return ex;
}


Static Expr *func_lsr()
{
    Expr *ex;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_integer);
    if (skipcomma()) {
	ex = force_unsigned(ex);
	ex = makeexpr_bin(EK_RSH, ex->val.type, ex, p_expr(tp_unsigned));
	skipcloseparen();
    }
    return ex;
}



Static Expr *func_bin()
{
    note("Using %b for binary printf format [185]");
    return handle_vax_hex(NULL, "b", 1);
}



Static Expr *func_binary(ex)
Expr *ex;
{
    char *cp;

    ex = grabarg(ex, 0);
    if (ex->kind == EK_CONST) {
        cp = getstring(ex);
        ex = makeexpr_long(my_strtol(cp, NULL, 2));
        insertarg(&ex, 0, makeexpr_name("%#lx", tp_integer));
        return ex;
    } else {
        return makeexpr_bicall_3("strtol", tp_integer, 
                                 ex, makeexpr_nil(), makeexpr_long(2));
    }
}



Static Expr *handle_bitsize(next)
int next;
{
    Expr *ex;
    Type *type;
    int lpar;
    long psize;

    lpar = (curtok == TOK_LPAR);
    if (lpar)
	gettok();
    if (curtok == TOK_IDENT && curtokmeaning &&
	curtokmeaning->kind == MK_TYPE) {
        ex = makeexpr_type(curtokmeaning->type);
        gettok();
    } else
        ex = p_expr(NULL);
    type = ex->val.type;
    if (lpar)
	skipcloseparen();
    psize = 0;
    packedsize(NULL, &type, &psize, 0);
    if (psize > 0 && psize < 32 && next) {
	if (psize > 16)
	    psize = 32;
	else if (psize > 8)
	    psize = 16;
	else if (psize > 4)
	    psize = 8;
	else if (psize > 2)
	    psize = 4;
	else if (psize > 1)
	    psize = 2;
	else
	    psize = 1;
    }
    if (psize)
	return makeexpr_long(psize);
    else
	return makeexpr_times(makeexpr_sizeof(ex, 0),
			      makeexpr_long(sizeof_char ? sizeof_char : 8));
}


Static Expr *func_bitsize()
{
    return handle_bitsize(0);
}


Static Expr *func_bitnext()
{
    return handle_bitsize(1);
}



Static Expr *func_blockread()
{
    Expr *ex, *ex2, *vex, *sex, *fex;
    Type *type;

    if (!skipopenparen())
	return NULL;
    fex = p_expr(tp_text);
    if (!skipcomma())
	return NULL;
    vex = p_expr(NULL);
    if (!skipcomma())
	return NULL;
    ex2 = p_expr(tp_integer);
    if (curtok == TOK_COMMA) {
        gettok();
        sex = p_expr(tp_integer);
	sex = doseek(copyexpr(fex),
		     makeexpr_times(sex, makeexpr_long(512)))->exp1;
    } else
        sex = NULL;
    skipcloseparen();
    type = vex->val.type;
    ex = makeexpr_bicall_4("fread", tp_integer,
			   makeexpr_addr(vex),
			   makeexpr_long(512),
			   convert_size(type, ex2, "BLOCKREAD"),
			   filebasename(copyexpr(fex)));
    return makeexpr_comma(sex, ex);
}



Static Expr *func_blockwrite()
{
    Expr *ex, *ex2, *vex, *sex, *fex;
    Type *type;

    if (!skipopenparen())
	return NULL;
    fex = p_expr(tp_text);
    if (!skipcomma())
	return NULL;
    vex = p_expr(NULL);
    if (!skipcomma())
	return NULL;
    ex2 = p_expr(tp_integer);
    if (curtok == TOK_COMMA) {
        gettok();
        sex = p_expr(tp_integer);
	sex = doseek(copyexpr(fex),
		     makeexpr_times(sex, makeexpr_long(512)))->exp1;
    } else
        sex = NULL;
    skipcloseparen();
    type = vex->val.type;
    ex = makeexpr_bicall_4("fwrite", tp_integer,
			   makeexpr_addr(vex),
			   makeexpr_long(512),
			   convert_size(type, ex2, "BLOCKWRITE"),
			   filebasename(copyexpr(fex)));
    return makeexpr_comma(sex, ex);
}




Static Stmt *proc_blockread()
{
    Expr *ex, *ex2, *vex, *rex, *fex;
    Type *type;

    if (!skipopenparen())
	return NULL;
    fex = p_expr(tp_text);
    if (!skipcomma())
	return NULL;
    vex = p_expr(NULL);
    if (!skipcomma())
	return NULL;
    ex2 = p_expr(tp_integer);
    if (curtok == TOK_COMMA) {
        gettok();
        rex = p_expr(tp_integer);
    } else
        rex = NULL;
    skipcloseparen();
    type = vex->val.type;
    if (rex) {
        ex = makeexpr_bicall_4("fread", tp_integer,
                               makeexpr_addr(vex),
                               makeexpr_long(1),
                               convert_size(type, ex2, "BLOCKREAD"),
                               filebasename(copyexpr(fex)));
        ex = makeexpr_assign(rex, ex);
        if (!iocheck_flag)
            ex = makeexpr_comma(ex,
                                makeexpr_assign(makeexpr_var(mp_ioresult),
                                                makeexpr_long(0)));
    } else {
        ex = makeexpr_bicall_4("fread", tp_integer,
                               makeexpr_addr(vex),
                               convert_size(type, ex2, "BLOCKREAD"),
                               makeexpr_long(1),
                               filebasename(copyexpr(fex)));
        if (checkeof(fex)) {
            ex = makeexpr_SETIO(makeexpr_rel(EK_EQ, ex, makeexpr_long(1)),
				endoffilename, fex);
        }
    }
    return wrapopencheck(makestmt_call(ex), fex);
}




Static Stmt *proc_blockwrite()
{
    Expr *ex, *ex2, *vex, *rex, *fex;
    Type *type;

    if (!skipopenparen())
	return NULL;
    fex = p_expr(tp_text);
    if (!skipcomma())
	return NULL;
    vex = p_expr(NULL);
    if (!skipcomma())
	return NULL;
    ex2 = p_expr(tp_integer);
    if (curtok == TOK_COMMA) {
        gettok();
        rex = p_expr(tp_integer);
    } else
        rex = NULL;
    skipcloseparen();
    type = vex->val.type;
    if (rex) {
        ex = makeexpr_bicall_4("fwrite", tp_integer,
                               makeexpr_addr(vex),
                               makeexpr_long(1),
                               convert_size(type, ex2, "BLOCKWRITE"),
                               filebasename(copyexpr(fex)));
        ex = makeexpr_assign(rex, ex);
        if (!iocheck_flag)
            ex = makeexpr_comma(ex,
                                makeexpr_assign(makeexpr_var(mp_ioresult),
                                                makeexpr_long(0)));
    } else {
        ex = makeexpr_bicall_4("fwrite", tp_integer,
                               makeexpr_addr(vex),
                               convert_size(type, ex2, "BLOCKWRITE"),
                               makeexpr_long(1),
                               filebasename(copyexpr(fex)));
        if (FCheck(checkfilewrite)) {
            ex = makeexpr_SETIO(makeexpr_rel(EK_EQ, ex, makeexpr_long(1)),
				filewriteerrorname, fex);
        }
    }
    return wrapopencheck(makestmt_call(ex), fex);
}



Static Stmt *proc_bclr()
{
    Expr *ex, *ex2;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    ex2 = p_expr(tp_integer);
    skipcloseparen();
    return makestmt_assign(ex,
			   makeexpr_bin(EK_BAND, ex->val.type,
					copyexpr(ex),
					makeexpr_un(EK_BNOT, ex->val.type,
					makeexpr_bin(EK_LSH, tp_integer,
						     makeexpr_arglong(
						         makeexpr_long(1), 1),
						     ex2))));
}



Static Stmt *proc_bset()
{
    Expr *ex, *ex2;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    ex2 = p_expr(tp_integer);
    skipcloseparen();
    return makestmt_assign(ex,
			   makeexpr_bin(EK_BOR, ex->val.type,
					copyexpr(ex),
					makeexpr_bin(EK_LSH, tp_integer,
						     makeexpr_arglong(
						         makeexpr_long(1), 1),
						     ex2)));
}



Static Expr *func_bsl()
{
    Expr *ex, *ex2;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    ex2 = p_expr(tp_integer);
    skipcloseparen();
    return makeexpr_bin(EK_LSH, tp_integer, ex, ex2);
}



Static Expr *func_bsr()
{
    Expr *ex, *ex2;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    ex2 = p_expr(tp_integer);
    skipcloseparen();
    return makeexpr_bin(EK_RSH, tp_integer, force_unsigned(ex), ex2);
}



Static Expr *func_btst()
{
    Expr *ex, *ex2;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    ex2 = p_expr(tp_integer);
    skipcloseparen();
    return makeexpr_rel(EK_NE,
			makeexpr_bin(EK_BAND, tp_integer,
				     ex,
				     makeexpr_bin(EK_LSH, tp_integer,
						  makeexpr_arglong(
						      makeexpr_long(1), 1),
						  ex2)),
			makeexpr_long(0));
}



Static Expr *func_byteread()
{
    Expr *ex, *ex2, *vex, *sex, *fex;
    Type *type;

    if (!skipopenparen())
	return NULL;
    fex = p_expr(tp_text);
    if (!skipcomma())
	return NULL;
    vex = p_expr(NULL);
    if (!skipcomma())
	return NULL;
    ex2 = p_expr(tp_integer);
    if (curtok == TOK_COMMA) {
        gettok();
        sex = p_expr(tp_integer);
	sex = doseek(copyexpr(fex), sex)->exp1;
    } else
        sex = NULL;
    skipcloseparen();
    type = vex->val.type;
    ex = makeexpr_bicall_4("fread", tp_integer,
			   makeexpr_addr(vex),
			   makeexpr_long(1),
			   convert_size(type, ex2, "BYTEREAD"),
			   filebasename(copyexpr(fex)));
    return makeexpr_comma(sex, ex);
}



Static Expr *func_bytewrite()
{
    Expr *ex, *ex2, *vex, *sex, *fex;
    Type *type;

    if (!skipopenparen())
	return NULL;
    fex = p_expr(tp_text);
    if (!skipcomma())
	return NULL;
    vex = p_expr(NULL);
    if (!skipcomma())
	return NULL;
    ex2 = p_expr(tp_integer);
    if (curtok == TOK_COMMA) {
        gettok();
        sex = p_expr(tp_integer);
	sex = doseek(copyexpr(fex), sex)->exp1;
    } else
        sex = NULL;
    skipcloseparen();
    type = vex->val.type;
    ex = makeexpr_bicall_4("fwrite", tp_integer,
			   makeexpr_addr(vex),
			   makeexpr_long(1),
			   convert_size(type, ex2, "BYTEWRITE"),
			   filebasename(copyexpr(fex)));
    return makeexpr_comma(sex, ex);
}



Static Expr *func_byte_offset()
{
    Type *tp;
    Meaning *mp;
    Expr *ex;

    if (!skipopenparen())
	return NULL;
    tp = p_type(NULL);
    if (!skipcomma())
	return NULL;
    if (!wexpecttok(TOK_IDENT))
	return NULL;
    mp = curtoksym->fbase;
    while (mp && mp->rectype != tp)
	mp = mp->snext;
    if (!mp)
	ex = makeexpr_name(curtokcase, tp_integer);
    else
	ex = makeexpr_name(mp->name, tp_integer);
    gettok();
    skipcloseparen();
    return makeexpr_bicall_2("OFFSETOF", (size_t_long) ? tp_integer : tp_int,
			     makeexpr_type(tp), ex);
}



Static Stmt *proc_call()
{
    Expr *ex, *ex2, *ex3;
    Type *type, *tp;
    Meaning *mp;

    if (!skipopenparen())
	return NULL;
    ex2 = p_expr(tp_proc);
    type = ex2->val.type;
    if (type->kind != TK_PROCPTR && type->kind != TK_CPROCPTR) {
        warning("CALL requires a procedure variable [208]");
	type = tp_proc;
    }
    ex = makeexpr(EK_SPCALL, 1);
    ex->val.type = tp_void;
    ex->args[0] = copyexpr(ex2);
    if (type->escale != 0)
	ex->args[0] = makeexpr_cast(makeexpr_dotq(ex2, "proc", tp_anyptr),
				    makepointertype(type->basetype));
    mp = type->basetype->fbase;
    if (mp) {
        if (wneedtok(TOK_COMMA))
	    ex = p_funcarglist(ex, mp, 0, 0);
    }
    skipcloseparen();
    if (type->escale != 1 || hasstaticlinks == 2) {
	freeexpr(ex2);
	return makestmt_call(ex);
    }
    ex2 = makeexpr_dotq(ex2, "link", tp_anyptr),
    ex3 = copyexpr(ex);
    insertarg(&ex3, ex3->nargs, copyexpr(ex2));
    tp = maketype(TK_FUNCTION);
    tp->basetype = type->basetype->basetype;
    tp->fbase = type->basetype->fbase;
    tp->issigned = 1;
    ex3->args[0]->val.type = makepointertype(tp);
    return makestmt_if(makeexpr_rel(EK_NE, ex2, makeexpr_nil()),
                       makestmt_call(ex3),
                       makestmt_call(ex));
}



Static Expr *func_chr()
{
    Expr *ex;

    ex = p_parexpr(tp_integer);
    if ((exprlongness(ex) < 0 || ex->kind == EK_CAST) && ex->kind != EK_ACTCAST)
        ex->val.type = tp_char;
    else
        ex = makeexpr_cast(ex, tp_char);
    return ex;
}



Static Stmt *proc_close()
{
    Stmt *sp, *sp2;
    Expr *fex, *ex;
    char *opt;

    if (!skipopenparen())
	return NULL;
    fex = p_expr(tp_text);
    sp = makestmt_if(makeexpr_rel(EK_NE, filebasename(copyexpr(fex)),
				  makeexpr_nil()),
                     makestmt_call(makeexpr_bicall_1("fclose", tp_void,
                                                     filebasename(copyexpr(fex)))),
                     (FCheck(checkfileisopen))
		         ? makestmt_call(
			     makeexpr_bicall_1(name_ESCIO,
					       tp_integer,
					       makeexpr_name(filenotopenname,
							     tp_int)))
                         : NULL);
    if (curtok == TOK_COMMA) {
        gettok();
	opt = "";
	if (curtok == TOK_IDENT &&
	    (!strcicmp(curtokbuf, "LOCK") ||
	     !strcicmp(curtokbuf, "PURGE") ||
	     !strcicmp(curtokbuf, "NORMAL") ||
	     !strcicmp(curtokbuf, "CRUNCH"))) {
	    opt = stralloc(curtokbuf);
	    gettok();
	} else {
	    ex = p_expr(tp_str255);
	    if (ex->kind == EK_CONST && ex->val.type->kind == TK_STRING)
		opt = ex->val.s;
	}
	if (!strcicmp(opt, "PURGE")) {
	    note("File is being closed with PURGE option [186]");
        }
    }
    sp2 = makestmt_assign(filebasename(fex), makeexpr_nil());
    sp2->quietelim = 1;
    sp = makestmt_seq(sp, sp2);
    skipcloseparen();
    return sp;
}



Static Expr *func_concat()
{
    Expr *ex;

    if (!skipopenparen())
	return makeexpr_string("oops");
    ex = p_expr(tp_str255);
    while (curtok == TOK_COMMA) {
        gettok();
        ex = makeexpr_concat(ex, p_expr(tp_str255), 0);
    }
    skipcloseparen();
    return ex;
}



Static Expr *func_copy(ex)
Expr *ex;
{
    if (isliteralconst(ex->args[3], NULL) == 2 &&
        ex->args[3]->val.i >= stringceiling) {
        return makeexpr_bicall_3("sprintf", ex->val.type,
                                 ex->args[0],
                                 makeexpr_string("%s"),
                                 bumpstring(ex->args[1], 
                                            makeexpr_unlongcast(ex->args[2]), 1));
    }
    if (checkconst(ex->args[2], 1)) {
        return makeexpr_addr(makeexpr_substring(ex->args[0], ex->args[1], 
                                                ex->args[2], ex->args[3]));
    }
    return makeexpr_bicall_4(strsubname, ex->val.type,
                             ex->args[0],
                             ex->args[1],
                             makeexpr_arglong(ex->args[2], 0),
                             makeexpr_arglong(ex->args[3], 0));
}



Static Expr *func_cos(ex)
Expr *ex;
{
    return makeexpr_bicall_1("cos", tp_longreal, grabarg(ex, 0));
}


Static Expr *func_cosh(ex)
Expr *ex;
{
    return makeexpr_bicall_1("cosh", tp_longreal, grabarg(ex, 0));
}



Static Stmt *proc_cycle()
{
    return makestmt(SK_CONTINUE);
}



Static Stmt *proc_date()
{
    Expr *ex;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_str255);
    skipcloseparen();
    return makestmt_call(makeexpr_bicall_1("VAXdate", tp_integer, ex));
}


Static Stmt *proc_dec()
{
    Expr *vex, *ex;

    if (!skipopenparen())
	return NULL;
    vex = p_expr(NULL);
    if (curtok == TOK_COMMA) {
        gettok();
        ex = p_expr(tp_integer);
    } else
        ex = makeexpr_long(1);
    skipcloseparen();
    return makestmt_assign(vex, makeexpr_minus(copyexpr(vex), ex));
}



Static Expr *func_dec()
{
    return handle_vax_hex(NULL, "d", 0);
}



Static Stmt *proc_delete(ex)
Expr *ex;
{
    if (ex->nargs == 1)   /* Kludge for Oregon Software Pascal's delete(f) */
	return makestmt_call(makeexpr_bicall_1(strdeletename, tp_void, ex->args[0]));
    return makestmt_call(makeexpr_bicall_3(strdeletename, tp_void,
                                           ex->args[0], 
                                           makeexpr_arglong(ex->args[1], 0),
                                           makeexpr_arglong(ex->args[2], 0)));
}



void parse_special_variant(tp, buf)
Type *tp;
char *buf;
{
    char *cp;
    Expr *ex;

    if (!tp)
	intwarning("parse_special_variant", "tp == NULL");
    if (!tp || tp->meaning == NULL) {
	*buf = 0;
	if (curtok == TOK_COMMA) {
	    skiptotoken(TOK_RPAR);
	}
	return;
    }
    strcpy(buf, tp->meaning->name);
    while (curtok == TOK_COMMA) {
	gettok();
	cp = buf + strlen(buf);
	*cp++ = '.';
	if (curtok == TOK_MINUS) {
	    *cp++ = '-';
	    gettok();
	}
	if (curtok == TOK_INTLIT ||
	    curtok == TOK_HEXLIT ||
	    curtok == TOK_OCTLIT) {
	    sprintf(cp, "%ld", curtokint);
	    gettok();
	} else if (curtok == TOK_HAT || curtok == TOK_STRLIT) {
	    ex = makeexpr_charcast(accumulate_strlit());
	    if (ex->kind == EK_CONST) {
		if (ex->val.i <= 32 || ex->val.i > 126 ||
		    ex->val.i == '\'' || ex->val.i == '\\' ||
		    ex->val.i == '=' || ex->val.i == '}')
		    sprintf(cp, "%ld", ex->val.i);
		else
		    strcpy(cp, makeCchar(ex->val.i));
	    } else {
		*buf = 0;
		*cp = 0;
	    }
	    freeexpr(ex);
	} else {
	    if (!wexpecttok(TOK_IDENT)) {
		skiptotoken(TOK_RPAR);
		return;
	    }
	    if (curtokmeaning)
		strcpy(cp, curtokmeaning->name);
	    else
		strcpy(cp, curtokbuf);
	    gettok();
	}
    }
}


char *find_special_variant(buf, spname, splist, need)
char *buf, *spname;
Strlist *splist;
int need;
{
    Strlist *best = NULL;
    int len, bestlen = -1;
    char *cp, *cp2;

    if (!*buf)
	return NULL;
    while (splist) {
	cp = splist->s;
	cp2 = buf;
	while (*cp && toupper(*cp) == toupper(*cp2))
	    cp++, cp2++;
	len = cp2 - buf;
	if (!*cp && (!*cp2 || *cp2 == '.') && len > bestlen) {
	    best = splist;
	    bestlen = len;
	}
	splist = splist->next;
    }
    if (bestlen != strlen(buf) && my_strchr(buf, '.')) {
	if ((need & 1) || bestlen >= 0) {
	    if (need & 2)
		return NULL;
	    if (spname)
		note(format_ss("No %s form known for %s [187]",
			       spname, strupper(buf)));
	}
    }
    if (bestlen >= 0)
	return (char *)best->value;
    else
	return NULL;
}


Static Expr *parse_constructor(type, var)
Type *type;
Expr *var;
{
    Meaning *mp;
    Expr *expr = NULL;
    int savewith = withlevel;

    if (curtok == TOK_COMMA) {
	curtokmeaning = mp;
	withrecordtype(type, makeexpr_hat(copyexpr(var), 0));
	gettok();
	if (wexpecttok(TOK_IDENT)) {
	    mp = curtokmeaning;
	    if (mp && mp->kind == MK_FUNCTION && curtokint >= savewith) {
		expr = p_expr(tp_void);
	    } else
		warning(format_s("No constructor/destructor named %s [334]",
				 curtokbuf));
	}
	withlevel = savewith;
	freeexpr(withexprs[withlevel]);
    }
    return expr;
}


Static char *choose_free_func(ex)
Expr *ex;
{
    if (!*freename) {
	if (!*freervaluename)
	    return "free";
	else
	    return freervaluename;
    }
    if (!*freervaluename)
	return freervaluename;
    if (expr_is_lvalue(ex))
	return freename;
    else
	return freervaluename;
}


Static int usenewdelete(tp)
Type *tp;
{
    if (newdelete)
	return 1;
    if (tp->kind == TK_POINTER && tp->basetype->kind == TK_RECORD &&
	tp->basetype->issigned)
	return 1;   /* Always use new/delete for object types */
    return 0;
}


Static Stmt *proc_dispose()
{
    Expr *ex, *destr = NULL;
    Type *type;
    Stmt *sp;
    char *name, vbuf[1000];

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_anyptr);
    type = ex->val.type->basetype;
    if (type->kind == TK_RECORD && type->issigned)
	destr = parse_constructor(type, ex);
    else
	parse_special_variant(type, vbuf);
    skipcloseparen();
    name = find_special_variant(vbuf, "SpecialFree", specialfrees, 0);
    if (!name && usenewdelete(ex->val.type)) {
	if (type->kind == TK_ARRAY || type->kind == TK_SET ||
	    type->kind == TK_STRING)
	    sp = makestmt_call(makeexpr_bin(EK_DELETE, tp_void, ex,
					    makeexpr_name("", tp_integer)));
	else
	    sp = makestmt_call(makeexpr_un(EK_DELETE, tp_void, ex));
    } else {
	if (!name)
	    name = choose_free_func(ex);
	sp = makestmt_call(makeexpr_bicall_1(name, tp_void, ex));
    }
    if (destr)
	sp = makestmt_seq(makestmt_call(destr), sp);
    return sp;
}



Static Expr *func_exp(ex)
Expr *ex;
{
    return makeexpr_bicall_1("exp", tp_longreal, grabarg(ex, 0));
}



Static Expr *func_expo(ex)
Expr *ex;
{
    Meaning *tvar;

    tvar = makestmttempvar(tp_int, name_TEMP);
    return makeexpr_comma(makeexpr_bicall_2("frexp", tp_longreal,
					    grabarg(ex, 0),
					    makeexpr_addr(makeexpr_var(tvar))),
			  makeexpr_var(tvar));
}



int is_std_file(ex)
Expr *ex;
{
    return isvar(ex, mp_input) || isvar(ex, mp_output) ||
           isvar(ex, mp_stderr);
}



Static Expr *iofunc(ex, code)
Expr *ex;
int code;
{
    Expr *ex2 = NULL, *ex3 = NULL;
    Meaning *tvar = NULL;

    if (FCheck(checkfileisopen) && !is_std_file(ex)) {
        if (isfiletype(ex->val.type, 1) ||
	    (exprspeed(ex) < 5 && nosideeffects(ex, 0))) {
            ex2 = filebasename(copyexpr(ex));
	} else {
            ex3 = ex;
            tvar = makestmttempvar(ex->val.type, name_TEMP);
            ex2 = makeexpr_var(tvar);
            ex = makeexpr_var(tvar);
        }
    }
    ex = filebasename(ex);
    switch (code) {

        case 0:  /* eof */
            if (fileisbuffered(ex, 0) && *eofbufname)
		ex = makeexpr_bicall_1(eofbufname, tp_boolean, ex);
	    else if (*eofname)
		ex = makeexpr_bicall_1(eofname, tp_boolean, ex);
	    else
		ex = makeexpr_rel(EK_NE, makeexpr_bicall_1("feof", tp_int, ex),
				         makeexpr_long(0));
            break;

        case 1:  /* eoln */
            ex = makeexpr_bicall_1(eolnname, tp_boolean, ex);
            break;

        case 2:  /* position or filepos */
            if (fileisbuffered(ex, 0) && *fileposbufname)
		ex = makeexpr_bicall_1(fileposbufname, tp_integer, ex);
	    else
		ex = makeexpr_bicall_1(fileposname, tp_integer, ex);
            break;

        case 3:  /* maxpos or filesize */
            ex = makeexpr_bicall_1(maxposname, tp_integer, ex);
            break;

    }
    if (ex2) {
        ex = makeexpr_bicall_4((iocheck_flag) ? "~~CHKIO" : name_CHKIO,
                               (code == 0 || code == 1) ? tp_boolean : tp_integer,
                               makeexpr_rel(EK_NE, ex2, makeexpr_nil()),
			       makeexpr_name("FileNotOpen", tp_int),
                               ex, makeexpr_long(0));
    }
    if (ex3)
        ex = makeexpr_comma(makeexpr_assign(makeexpr_var(tvar), ex3), ex);
    return ex;
}



Static Expr *func_eof()
{
    Expr *ex;

    if (curtok == TOK_LPAR)
        ex = p_parexpr(tp_text);
    else
        ex = makeexpr_var(mp_input);
    return iofunc(ex, 0);
}



Static Expr *func_eoln()
{
    Expr *ex;

    if (curtok == TOK_LPAR)
        ex = p_parexpr(tp_text);
    else
        ex = makeexpr_var(mp_input);
    return iofunc(ex, 1);
}



Static Stmt *proc_escape()
{
    Stmt *sp;
    Expr *ex;

    if (which_lang == LANG_TIP) {
	if (!wexpecttok(TOK_IDENT))
	    return NULL;
	if (curtokmeaning && curtokmeaning->kind == MK_LABEL) {
	    sp = makestmt(SK_GOTO);
	    sp->exp1 = makeexpr_name(format_s(name_LABEL,
					      curtokmeaning->name),
				     tp_integer);
	    gettok();
	    return sp;
	} else if (curtokmeaning && curtokmeaning == curctx &&
		   curctx->kind == MK_FUNCTION) {
	    sp = makestmt(SK_RETURN);
	    if (curctx->kind == MK_FUNCTION && curctx->isfunction) {
		sp->exp1 = makeexpr_var(curctx->cbase);
		curctx->cbase->refcount++;
	    }
	    gettok();
	    return sp;
	} else if (curtokmeaning && curtokmeaning->kind == MK_MODULE) {
	    gettok();
	    return makestmt_call(makeexpr_bicall_1("exit", tp_void,
						   makeexpr_name("EXIT_SUCCESS",
								 tp_integer)));
	} else {
	    note("Attempting to ESCAPE beyond this function [188]");
	    ex = makeexpr_name(curtokbuf, tp_integer);
	    gettok();
	    return makestmt_call(makeexpr_bicall_1("ESCAPE", tp_void, ex));
	}
    }
    if (curtok == TOK_LPAR)
        ex = p_parexpr(tp_integer);
    else
        ex = makeexpr_long(0);
    return makestmt_call(makeexpr_bicall_1(name_ESCAPE, tp_int, 
                                           makeexpr_arglong(ex, 0)));
}



Static Stmt *proc_excl()
{
    Expr *vex, *ex;

    if (!skipopenparen())
	return NULL;
    vex = p_expr(NULL);
    if (!skipcomma())
	return NULL;
    ex = p_expr(vex->val.type->indextype);
    skipcloseparen();
    if (vex->val.type->kind == TK_SMALLSET)
	return makestmt_assign(vex, makeexpr_bin(EK_BAND, vex->val.type,
						 copyexpr(vex),
						 makeexpr_un(EK_BNOT, vex->val.type,
							     makeexpr_bin(EK_LSH, vex->val.type,
									  makeexpr_longcast(makeexpr_long(1), 1),
									  ex))));
    else
	return makestmt_call(makeexpr_bicall_2(setremname, tp_void, vex,
					       makeexpr_arglong(enum_to_int(ex), 0)));
}



Stmt *proc_exit()
{
    Stmt *sp;

    if (curtok == TOK_IF) {
	gettok();
	return makestmt_if(p_expr(tp_boolean), makestmt(SK_BREAK), NULL);
    }
    if (modula2) {
	return makestmt(SK_BREAK);
    }
    if (curtok == TOK_LPAR) {
        gettok();
	if (curtok == TOK_PROGRAM ||
	    (curtok == TOK_IDENT && curtokmeaning &&
	     curtokmeaning->kind == MK_MODULE)) {
	    gettok();
	    skipcloseparen();
	    return makestmt_call(makeexpr_bicall_1("exit", tp_void,
						   makeexpr_name("EXIT_SUCCESS",
								 tp_integer)));
	}
        if (curtok != TOK_IDENT || !curtokmeaning || curtokmeaning != curctx)
            note("Attempting to EXIT beyond this function [188]");
        gettok();
	skipcloseparen();
    }
    sp = makestmt(SK_RETURN);
    if (curctx->kind == MK_FUNCTION && curctx->isfunction) {
        sp->exp1 = makeexpr_var(curctx->cbase);
        curctx->cbase->refcount++;
    }
    return sp;
}



Static Expr *file_iofunc(code, base)
int code;
long base;
{
    Expr *ex;
    Type *basetype;

    if (curtok == TOK_LPAR)
	ex = p_parexpr(tp_text);
    else
	ex = makeexpr_var(mp_input);
    if (!ex->val.type || !ex->val.type->basetype ||
	!filebasetype(ex->val.type))
	basetype = tp_char;
    else
	basetype = filebasetype(ex->val.type);
    return makeexpr_plus(makeexpr_div(iofunc(ex, code),
                                      makeexpr_sizeof(makeexpr_type(basetype), 0)),
                         makeexpr_long(base));
}



Static Expr *func_fcall()
{
    Expr *ex, *ex2, *ex3;
    Type *type, *tp;
    Meaning *mp, *tvar = NULL;
    int firstarg = 0;

    if (!skipopenparen())
	return NULL;
    ex2 = p_expr(tp_proc);
    type = ex2->val.type;
    if (type->kind != TK_PROCPTR && type->kind != TK_CPROCPTR) {
        warning("FCALL requires a function variable [209]");
	type = tp_proc;
    }
    ex = makeexpr(EK_SPCALL, 1);
    ex->val.type = type->basetype->basetype;
    ex->args[0] = copyexpr(ex2);
    if (type->escale != 0)
	ex->args[0] = makeexpr_cast(makeexpr_dotq(ex2, "proc", tp_anyptr),
				    makepointertype(type->basetype));
    mp = type->basetype->fbase;
    if (mp && mp->isreturn) {    /* pointer to buffer for return value */
        tvar = makestmttempvar(ex->val.type->basetype,
            (ex->val.type->basetype->kind == TK_STRING) ? name_STRING : name_TEMP);
        insertarg(&ex, 1, makeexpr_addr(makeexpr_var(tvar)));
        mp = mp->xnext;
	firstarg++;
    }
    if (mp) {
        if (wneedtok(TOK_COMMA))
	    ex = p_funcarglist(ex, mp, 0, 0);
    }
    if (tvar)
	ex = makeexpr_hat(ex, 0);    /* returns pointer to structured result */
    skipcloseparen();
    if (type->escale != 1 || hasstaticlinks == 2) {
	freeexpr(ex2);
	return ex;
    }
    ex2 = makeexpr_dotq(ex2, "link", tp_anyptr),
    ex3 = copyexpr(ex);
    insertarg(&ex3, ex3->nargs, copyexpr(ex2));
    tp = maketype(TK_FUNCTION);
    tp->basetype = type->basetype->basetype;
    tp->fbase = type->basetype->fbase;
    tp->issigned = 1;
    ex3->args[0]->val.type = makepointertype(tp);
    return makeexpr_cond(makeexpr_rel(EK_NE, ex2, makeexpr_nil()),
			 ex3, ex);
}



Static Expr *func_filepos()
{
    return file_iofunc(2, seek_base);
}



Static Expr *func_filesize()
{
    return file_iofunc(3, 0L);
}



Static Stmt *proc_fillchar()
{
    Expr *vex, *ex, *cex;

    if (!skipopenparen())
	return NULL;
    vex = gentle_cast(makeexpr_addr(p_expr(NULL)), tp_anyptr);
    if (!skipcomma())
	return NULL;
    ex = convert_size(argbasetype(vex), p_expr(tp_integer), "FILLCHAR");
    if (!skipcomma())
	return NULL;
    cex = makeexpr_charcast(p_expr(tp_integer));
    skipcloseparen();
    return makestmt_call(makeexpr_bicall_3("memset", tp_void,
                                           vex,
                                           makeexpr_arglong(cex, 0),
                                           makeexpr_arglong(ex, (size_t_long != 0))));
}



Static Expr *func_sngl()
{
    Expr *ex;

    ex = p_parexpr(tp_real);
    return makeexpr_cast(ex, tp_real);
}



Static Expr *func_float()
{
    Expr *ex;

    ex = p_parexpr(tp_longreal);
    return makeexpr_cast(ex, tp_longreal);
}



Static Stmt *proc_flush()
{
    Expr *ex;
    Stmt *sp;

    ex = p_parexpr(tp_text);
    sp = makestmt_call(makeexpr_bicall_1("fflush", tp_void, filebasename(ex)));
    if (iocheck_flag)
        sp = makestmt_seq(sp, makestmt_assign(makeexpr_var(mp_ioresult), 
                                              makeexpr_long(0)));
    return sp;
}



Static Expr *func_frac(ex)
Expr *ex;
{
    Meaning *tvar;

    tvar = makestmttempvar(tp_longreal, name_DUMMY);
    return makeexpr_bicall_2("modf", tp_longreal, 
                             grabarg(ex, 0),
                             makeexpr_addr(makeexpr_var(tvar)));
}



Static Stmt *proc_freemem(ex)
Expr *ex;
{
    Stmt *sp;
    Expr *vex;

    vex = makeexpr_hat(eatcasts(ex->args[0]), 0);
    if (newdelete) {
	sp = makestmt_call(makeexpr_bin(EK_DELETE, tp_void, copyexpr(vex),
					makeexpr_name("", tp_integer)));
    } else {
	sp = makestmt_call(makeexpr_bicall_1(choose_free_func(vex),
					     tp_void, copyexpr(vex)));
    }
    if (alloczeronil) {
        sp = makestmt_if(makeexpr_rel(EK_NE, vex, makeexpr_nil()),
                         sp, NULL);
    } else
        freeexpr(vex);
    return sp;
}



Static Stmt *proc_get()
{
    Expr *ex;
    Type *type;

    if (curtok == TOK_LPAR)
	ex = p_parexpr(tp_text);
    else
	ex = makeexpr_var(mp_input);
    requirefilebuffer(ex);
    type = ex->val.type;
    if (isfiletype(type, -1) && *chargetname &&
	filebasetype(type)->kind == TK_CHAR)
	return makestmt_call(makeexpr_bicall_1(chargetname, tp_void,
					       filebasename(ex)));
    else if (isfiletype(type, -1) && *arraygetname &&
	     filebasetype(type)->kind == TK_ARRAY)
	return makestmt_call(makeexpr_bicall_2(arraygetname, tp_void,
					       filebasename(ex),
					       makeexpr_type(filebasetype(type))));
    else
	return makestmt_call(makeexpr_bicall_2(getname, tp_void,
					       filebasename(ex),
					       makeexpr_type(filebasetype(type))));
}



Static Stmt *proc_getmem(ex)
Expr *ex;
{
    Type *type;
    Expr *vex, *ex2, *sz = NULL;
    Stmt *sp;

    type = ex->args[0]->val.type;
    vex = makeexpr_hat(eatcasts(ex->args[0]), 0);
    ex2 = ex->args[1];
    if (vex->val.type->kind == TK_POINTER)
        ex2 = convert_size(vex->val.type->basetype, ex2, "GETMEM");
    if (alloczeronil)
        sz = copyexpr(ex2);
    if (newdelete) {
	ex2 = makeexpr_cast(makeexpr_bin(EK_NEW, tp_anyptr,
					 makeexpr_type(tp_abyte),
					 ex2),
			    type);
    } else
	ex2 = makeexpr_bicall_1(mallocname, tp_anyptr, ex2);
    sp = makestmt_assign(copyexpr(vex), ex2);
    if (malloccheck) {
        sp = makestmt_seq(sp, makestmt_if(makeexpr_rel(EK_EQ, copyexpr(vex), makeexpr_nil()),
                                          makestmt_call(makeexpr_bicall_0(name_OUTMEM, tp_int)),
                                          NULL));
    }
    if (sz && !isconstantexpr(sz)) {
        if (alloczeronil == 2)
            note("Called GETMEM with variable argument [189]");
        sp = makestmt_if(makeexpr_rel(EK_NE, sz, makeexpr_long(0)),
                         sp,
                         makestmt_assign(vex, makeexpr_nil()));
    } else
        freeexpr(vex);
    return sp;
}



Static Stmt *proc_gotoxy(ex)
Expr *ex;
{
    return makestmt_call(makeexpr_bicall_2("gotoxy", tp_void,
                                           makeexpr_arglong(ex->args[0], 0),
                                           makeexpr_arglong(ex->args[1], 0)));
}



Static Stmt *proc_halt()
{
    if (which_lang == LANG_TIP) {
	return makestmt_call(makeexpr_bicall_1("exit", tp_void,
					       makeexpr_name("EXIT_FAILURE",
							     tp_integer)));
    } else
	return proc_escape();
}



Static Expr *handle_vax_hex(ex, fmt, scale)
Expr *ex;
char *fmt;
int scale;
{
    Expr *lex, *dex, *vex;
    Meaning *tvar;
    Type *tp;
    long smin, smax;
    int bits;

    if (!ex) {
	if (!skipopenparen())
	    return NULL;
	ex = p_expr(tp_integer);
    }
    tp = true_type(ex);
    if (ord_range(tp, &smin, &smax))
	bits = typebits(smin, smax);
    else
	bits = 32;
    if (curtok == TOK_COMMA) {
	gettok();
	if (curtok != TOK_COMMA)
	    lex = makeexpr_arglong(p_expr(tp_integer), 0);
	else
	    lex = NULL;
    } else
	lex = NULL;
    if (!lex) {
	if (!scale)
	    lex = makeexpr_long(11);
	else
	    lex = makeexpr_long((bits+scale-1) / scale + 1);
    }
    if (curtok == TOK_COMMA) {
	gettok();
	dex = makeexpr_arglong(p_expr(tp_integer), 0);
    } else {
	if (!scale)
	    dex = makeexpr_long(10);
	else
	    dex = makeexpr_long((bits+scale-1) / scale);
    }
    if (lex->kind == EK_CONST && dex->kind == EK_CONST &&
	lex->val.i < dex->val.i)
	lex = NULL;
    skipcloseparen();
    tvar = makestmttempvar(tp_str255, name_STRING);
    vex = makeexpr_var(tvar);
    ex = makeexpr_forcelongness(ex);
    if (exprlongness(ex) > 0)
	fmt = format_s("l%s", fmt);
    if (checkconst(lex, 0) || checkconst(lex, 1))
	lex = NULL;
    if (checkconst(dex, 0) || checkconst(dex, 1))
	dex = NULL;
    if (lex) {
	if (dex)
	    ex = makeexpr_bicall_5("sprintf", tp_str255, vex,
				   makeexpr_string(format_s("%%*.*%s", fmt)),
				   lex, dex, ex);
	else
	    ex = makeexpr_bicall_4("sprintf", tp_str255, vex,
				   makeexpr_string(format_s("%%*%s", fmt)),
				   lex, ex);
    } else {
	if (dex)
	    ex = makeexpr_bicall_4("sprintf", tp_str255, vex,
				   makeexpr_string(format_s("%%.*%s", fmt)),
				   dex, ex);
	else
	    ex = makeexpr_bicall_3("sprintf", tp_str255, vex,
				   makeexpr_string(format_s("%%%s", fmt)),
				   ex);
    }
    return ex;
}




Static Expr *func_hex()
{
    Expr *ex;
    char *cp;

    if (!skipopenparen())
	return NULL;
    ex = makeexpr_stringcast(p_expr(tp_integer));
    if ((ex->val.type->kind == TK_STRING ||
	 ex->val.type == tp_strptr) &&
	curtok != TOK_COMMA) {
	skipcloseparen();
	if (ex->kind == EK_CONST) {    /* HP Pascal */
	    cp = getstring(ex);
	    ex = makeexpr_long(my_strtol(cp, NULL, 16));
	    insertarg(&ex, 0, makeexpr_name("%#lx", tp_integer));
	    return ex;
	} else {
	    return makeexpr_bicall_3("strtol", tp_integer, 
				     ex, makeexpr_nil(), makeexpr_long(16));
	}
    } else {    /* VAX Pascal */
	return handle_vax_hex(ex, "x", 4);
    }
}



Static Expr *func_hi()
{
    Expr *ex;

    ex = force_unsigned(p_parexpr(tp_integer));
    return makeexpr_bin(EK_RSH, tp_ubyte,
                        ex, makeexpr_long(8));
}



Static Expr *func_high()
{
    Expr *ex;
    Type *type;

    ex = p_parexpr(tp_integer);
    type = ex->val.type;
    if (type->kind == TK_POINTER)
	type = type->basetype;
    if (type->kind == TK_ARRAY ||
	type->kind == TK_SMALLARRAY) {
	ex = makeexpr_minus(copyexpr(type->indextype->smax),
			    copyexpr(type->indextype->smin));
    } else {
	warning("HIGH requires an array name parameter [210]");
	ex = makeexpr_bicall_1("HIGH", tp_int, ex);
    }
    return ex;
}



Static Expr *func_hiword()
{
    Expr *ex;

    ex = force_unsigned(p_parexpr(tp_unsigned));
    return makeexpr_bin(EK_RSH, tp_unsigned,
                        ex, makeexpr_long(16));
}



Static Stmt *proc_inc()
{
    Expr *vex, *ex;

    if (!skipopenparen())
	return NULL;
    vex = p_expr(NULL);
    if (curtok == TOK_COMMA) {
        gettok();
        ex = p_expr(tp_integer);
    } else
        ex = makeexpr_long(1);
    skipcloseparen();
    return makestmt_assign(vex, makeexpr_plus(copyexpr(vex), ex));
}



Static Stmt *proc_incl()
{
    Expr *vex, *ex;

    if (!skipopenparen())
	return NULL;
    vex = p_expr(NULL);
    if (!skipcomma())
	return NULL;
    ex = p_expr(vex->val.type->indextype);
    skipcloseparen();
    if (vex->val.type->kind == TK_SMALLSET)
	return makestmt_assign(vex, makeexpr_bin(EK_BOR, vex->val.type,
						 copyexpr(vex),
						 makeexpr_bin(EK_LSH, vex->val.type,
							      makeexpr_longcast(makeexpr_long(1), 1),
							      ex)));
    else
	return makestmt_call(makeexpr_bicall_2(setaddname, tp_void, vex,
					       makeexpr_arglong(enum_to_int(ex), 0)));
}



Static Stmt *proc_insert(ex)
Expr *ex;
{
    return makestmt_call(makeexpr_bicall_3(strinsertname, tp_void,
                                           ex->args[0], 
                                           ex->args[1],
                                           makeexpr_arglong(ex->args[2], 0)));
}



Static Expr *func_int()
{
    Expr *ex;
    Meaning *tvar;

    ex = p_parexpr(tp_integer);
    if (ex->val.type->kind == TK_REAL) {    /* Turbo Pascal INT */
	tvar = makestmttempvar(tp_longreal, name_TEMP);
	return makeexpr_comma(makeexpr_bicall_2("modf", tp_longreal,
						grabarg(ex, 0),
						makeexpr_addr(makeexpr_var(tvar))),
			      makeexpr_var(tvar));
    } else {     /* VAX Pascal INT */
	return makeexpr_ord(ex);
    }
}


Static Expr *func_uint()
{
    Expr *ex;

    ex = p_parexpr(tp_integer);
    return makeexpr_cast(ex, tp_unsigned);
}



Static Stmt *proc_leave()
{
    return makestmt(SK_BREAK);
}



Static Expr *func_lint()
{
    Expr *ex;

    ex = p_parexpr(tp_integer);
    return pascaltypecast(tp_integer, ex);
}



Static Expr *func_lo()
{
    Expr *ex;

    ex = gentle_cast(p_parexpr(tp_integer), tp_ushort);
    return makeexpr_bin(EK_BAND, tp_ubyte,
                        ex, makeexpr_long(255));
}


Static Expr *func_loophole()
{
    Type *type;
    Expr *ex;

    if (!skipopenparen())
	return NULL;
    type = p_type(NULL);
    if (!skipcomma())
	return NULL;
    ex = p_expr(tp_integer);
    skipcloseparen();
    return pascaltypecast(type, ex);
}



Static Expr *func_lower()
{
    Expr *ex;
    Value val;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_integer);
    if (curtok == TOK_COMMA) {
	gettok();
	val = p_constant(tp_integer);
	if (!val.type || val.i != 1)
	    note("LOWER(v,n) not supported for n>1 [190]");
    }
    skipcloseparen();
    return copyexpr(ex->val.type->indextype->smin);
}



Static Expr *func_loword()
{
    Expr *ex;

    ex = p_parexpr(tp_integer);
    return makeexpr_bin(EK_BAND, tp_ushort,
                        ex, makeexpr_long(65535));
}



Static Expr *func_ln(ex)
Expr *ex;
{
    return makeexpr_bicall_1("log", tp_longreal, grabarg(ex, 0));
}



Static Expr *func_log(ex)
Expr *ex;
{
    return makeexpr_bicall_1("log10", tp_longreal, grabarg(ex, 0));
}



Static Expr *func_max()
{
    Type *tp;
    Expr *ex, *ex2;

    if (!skipopenparen())
	return NULL;
    if (curtok == TOK_IDENT && curtokmeaning &&
	curtokmeaning->kind == MK_TYPE) {
	tp = curtokmeaning->type;
	gettok();
	skipcloseparen();
	return copyexpr(tp->smax);
    }
    ex = p_expr(tp_integer);
    while (curtok == TOK_COMMA) {
	gettok();
	ex2 = p_expr(ex->val.type);
	if (ex->val.type->kind == TK_REAL) {
	    tp = ex->val.type;
	    if (ex2->val.type->kind != TK_REAL)
		ex2 = makeexpr_cast(ex2, tp);
	} else {
	    tp = ex2->val.type;
	    if (ex->val.type->kind != TK_REAL)
		ex = makeexpr_cast(ex, tp);
	}
	ex = makeexpr_bicall_2((tp->kind == TK_REAL) ? "P_rmax" : "P_imax",
			       tp, ex, ex2);
    }				
    skipcloseparen();
    return ex;
}



Static Expr *func_maxavail(ex)
Expr *ex;
{
    freeexpr(ex);
    return makeexpr_bicall_0("maxavail", tp_integer);
}



Static Expr *func_maxpos()
{
    return file_iofunc(3, seek_base);
}



Static Expr *func_memavail(ex)
Expr *ex;
{
    freeexpr(ex);
    return makeexpr_bicall_0("memavail", tp_integer);
}



Static Expr *var_mem()
{
    Expr *ex, *ex2;

    if (!wneedtok(TOK_LBR))
	return makeexpr_name("MEM", tp_integer);
    ex = p_expr(tp_integer);
    if (curtok == TOK_COLON) {
	gettok();
	ex2 = p_expr(tp_integer);
	ex = makeexpr_bicall_2("MEM", tp_ubyte, ex, ex2);
    } else {
	ex = makeexpr_bicall_1("MEM", tp_ubyte, ex);
    }
    if (!wneedtok(TOK_RBR))
	skippasttotoken(TOK_RBR, TOK_SEMI);
    note("Reference to MEM [191]");
    return ex;
}



Static Expr *var_memw()
{
    Expr *ex, *ex2;

    if (!wneedtok(TOK_LBR))
	return makeexpr_name("MEMW", tp_integer);
    ex = p_expr(tp_integer);
    if (curtok == TOK_COLON) {
	gettok();
	ex2 = p_expr(tp_integer);
	ex = makeexpr_bicall_2("MEMW", tp_ushort, ex, ex2);
    } else {
	ex = makeexpr_bicall_1("MEMW", tp_ushort, ex);
    }
    if (!wneedtok(TOK_RBR))
	skippasttotoken(TOK_RBR, TOK_SEMI);
    note("Reference to MEMW [191]");
    return ex;
}



Static Expr *var_meml()
{
    Expr *ex, *ex2;

    if (!wneedtok(TOK_LBR))
	return makeexpr_name("MEML", tp_integer);
    ex = p_expr(tp_integer);
    if (curtok == TOK_COLON) {
	gettok();
	ex2 = p_expr(tp_integer);
	ex = makeexpr_bicall_2("MEML", tp_integer, ex, ex2);
    } else {
	ex = makeexpr_bicall_1("MEML", tp_integer, ex);
    }
    if (!wneedtok(TOK_RBR))
	skippasttotoken(TOK_RBR, TOK_SEMI);
    note("Reference to MEML [191]");
    return ex;
}



Static Expr *func_min()
{
    Type *tp;
    Expr *ex, *ex2;

    if (!skipopenparen())
	return NULL;
    if (curtok == TOK_IDENT && curtokmeaning &&
	curtokmeaning->kind == MK_TYPE) {
	tp = curtokmeaning->type;
	gettok();
	skipcloseparen();
	return copyexpr(tp->smin);
    }
    ex = p_expr(tp_integer);
    while (curtok == TOK_COMMA) {
	gettok();
	ex2 = p_expr(ex->val.type);
	if (ex->val.type->kind == TK_REAL) {
	    tp = ex->val.type;
	    if (ex2->val.type->kind != TK_REAL)
		ex2 = makeexpr_cast(ex2, tp);
	} else {
	    tp = ex2->val.type;
	    if (ex->val.type->kind != TK_REAL)
		ex = makeexpr_cast(ex, tp);
	}
	ex = makeexpr_bicall_2((tp->kind == TK_REAL) ? "P_rmin" : "P_imin",
			       tp, ex, ex2);
    }				
    skipcloseparen();
    return ex;
}



Static Stmt *proc_move(ex)
Expr *ex;
{
    ex->args[0] = gentle_cast(ex->args[0], tp_anyptr);    /* source */
    ex->args[1] = gentle_cast(ex->args[1], tp_anyptr);    /* dest */
    ex->args[2] = convert_size(choosetype(argbasetype(ex->args[0]),
                                          argbasetype(ex->args[1])), ex->args[2], "MOVE");
    return makestmt_call(makeexpr_bicall_3("memmove", tp_void,
                                           ex->args[1],
                                           ex->args[0],
                                           makeexpr_arglong(ex->args[2], (size_t_long != 0))));
}



Static Stmt *proc_move_fast()
{
    Expr *ex, *ex2, *ex3, *ex4;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    ex2 = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    ord_range_expr(ex2->val.type->indextype, &ex4, NULL);
    ex2 = makeexpr_index(ex2, p_expr(tp_integer), copyexpr(ex4));
    if (!skipcomma())
	return NULL;
    ex3 = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    ord_range_expr(ex3->val.type->indextype, &ex4, NULL);
    ex3 = makeexpr_index(ex3, p_expr(tp_integer), copyexpr(ex4));
    skipcloseparen();
    ex = convert_size(choosetype(argbasetype(ex2),
				 argbasetype(ex3)), ex, "MOVE_FAST");
    return makestmt_call(makeexpr_bicall_3("memmove", tp_void,
					   makeexpr_addr(ex3),
					   makeexpr_addr(ex2),
					   makeexpr_arglong(ex, (size_t_long != 0))));
}



Static Stmt *proc_new()
{
    Expr *ex;
    Stmt *sp, **spp;
    Type *type;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_anyptr);
    type = ex->val.type;
    if (type->kind == TK_POINTER)
	type = type->basetype;
    sp = makestmt_call(handle_new(ex));
    spp = &sp->next;
    if (type->kind == TK_RECORD)
	initfilevars(type->fbase, &spp, makeexpr_hat(ex, 0));
    else if (isfiletype(type, -1))
	sp = makestmt_seq(sp, makestmt_call(initfilevar(makeexpr_hat(ex, 0))));
    else
	freeexpr(ex);
    return sp;
}


Static Expr *func_new_turbo()
{
    Meaning *tvar;
    Expr *ex;

    if (!skipopenparen())
	return NULL;
    if (!wexpecttok(TOK_IDENT))
	return NULL;
    if (!curtokmeaning || curtokmeaning->kind != MK_TYPE)
	wexpected("a type name");
    tvar = makestmttempvar(curtokmeaning->type, name_TEMP);
    ex = makeexpr_var(tvar);
    gettok();
    ex = handle_new(ex);
    if (ex->kind == EK_ASSIGN && ex->args[0]->kind == EK_VAR)
	return ex->args[1];
    else
	return makeexpr_comma(ex, makeexpr_var(tvar));
}


Static Expr *handle_new(ex)
Expr *ex;
{
    Expr *ex2, *init = NULL;
    Type *type;
    char *name, *name2 = NULL, vbuf[1000];

    type = ex->val.type;
    if (type->kind == TK_POINTER)
	type = type->basetype;
    if (type->kind == TK_RECORD && type->issigned)
	init = parse_constructor(type, ex);
    else
	parse_special_variant(type, vbuf);
    skipcloseparen();
    name = find_special_variant(vbuf, NULL, specialmallocs, 3);
    if (!name) {
        name2 = find_special_variant(vbuf, NULL, specialsizeofs, 3);
	if (!name2) {
	    name = find_special_variant(vbuf, NULL, specialmallocs, 1);
	    name2 = find_special_variant(vbuf, NULL, specialsizeofs, 1);
	    if (name || !name2)
		name = find_special_variant(vbuf, "SpecialMalloc", specialmallocs, 1);
	    else
		name2 = find_special_variant(vbuf, "SpecialSizeOf", specialsizeofs, 1);
	}
    }
    if (name) {
	ex2 = makeexpr_bicall_0(name, ex->val.type);
    } else if (name2) {
	ex2 = makeexpr_bicall_1(mallocname, tp_anyptr, pc_expr_str(name2));
    } else if (usenewdelete(ex->val.type)) {
	if (type->kind == TK_ARRAY || type->kind == TK_SET ||
	    type->kind == TK_STRING)
	    ex2 = makeexpr_bin(EK_NEW, makepointertype(type),
			       makeexpr_type(type->basetype),
			       arraysize(type, 1));
	else
	    ex2 = makeexpr_un(EK_NEW, makepointertype(type),
			      makeexpr_type(type));
    } else {
	ex2 = makeexpr_bicall_1(mallocname, tp_anyptr,
				makeexpr_sizeof(makeexpr_type(type), 1));
    }
    ex2 = makeexpr_assign(copyexpr(ex), ex2);
    if (malloccheck) {
        ex2 = makeexpr_comma(ex2, makeexpr_cond(makeexpr_rel(EK_EQ,
							     copyexpr(ex),
							     makeexpr_nil()),
						makeexpr_bicall_0(name_OUTMEM, tp_int),
						makeexpr_long(0)));
    }
    if (init)
	ex2 = makeexpr_comma(ex2, init);
    return ex2;
}



Static Expr *func_oct()
{
    return handle_vax_hex(NULL, "o", 3);
}

 

Static Expr *func_octal(ex)
Expr *ex;
{
    char *cp;

    ex = grabarg(ex, 0);
    if (ex->kind == EK_CONST) {
        cp = getstring(ex);
        ex = makeexpr_long(my_strtol(cp, NULL, 8));
        insertarg(&ex, 0, makeexpr_name("0%lo", tp_integer));
        return ex;
    } else {
        return makeexpr_bicall_3("strtol", tp_integer, 
                                 ex, makeexpr_nil(), makeexpr_long(8));
    }
}



Static Expr *func_odd(ex)
Expr *ex;
{
    ex = makeexpr_unlongcast(grabarg(ex, 0));
    if (*oddname)
        return makeexpr_bicall_1(oddname, tp_boolean, ex);
    else
        return makeexpr_bin(EK_BAND, tp_boolean, ex, makeexpr_long(1));
}



Static Expr *func_ofs()
{
    Expr *ex;

    ex = p_parexpr(tp_cproc);
    if (ex->val.type->kind == TK_CPROCPTR) {
	ex = makeexpr_cast(ex, tp_anyptr);
    } else
	ex = makeexpr_addrf(ex);
    return makeexpr_bicall_1(OFSname, tp_ushort, ex);
}


Static Expr *func_seg()
{
    Expr *ex;

    ex = p_parexpr(tp_cproc);
    if (ex->val.type->kind == TK_CPROCPTR) {
	ex = makeexpr_cast(ex, tp_anyptr);
    } else
	ex = makeexpr_addrf(ex);
    return makeexpr_bicall_1(SEGname, tp_ushort, ex);
}



Static Stmt *proc_open()
{
    return handleopen(2);
}



Static Expr *func_ord()
{
    Expr *ex;

    if (wneedtok(TOK_LPAR)) {
	ex = p_ord_expr();
	skipcloseparen();
    } else
	ex = p_ord_expr();
    return makeexpr_ord(ex);
}



Static Expr *func_ord4()
{
    Expr *ex;

    if (wneedtok(TOK_LPAR)) {
	ex = p_ord_expr();
	skipcloseparen();
    } else
	ex = p_ord_expr();
    return makeexpr_longcast(makeexpr_ord(ex), 1);
}



Static Stmt *proc_pack()
{
    Expr *exs, *exd, *exi, *mind;
    Meaning *tvar;
    Stmt *sp;

    if (!skipopenparen())
	return NULL;
    exs = p_expr(NULL);
    if (!skipcomma())
	return NULL;
    exi = p_ord_expr();
    if (!skipcomma())
	return NULL;
    exd = p_expr(NULL);
    skipcloseparen();
    if (exs->val.type->kind != TK_ARRAY ||
	(exd->val.type->kind != TK_ARRAY &&
	 exd->val.type->kind != TK_SMALLARRAY)) {
	warning("Bad argument types for PACK/UNPACK [325]");
	return makestmt_call(makeexpr_bicall_3("pack", tp_void,
					       exs, exi, exd));
    }
    if (exs->val.type->smax || exd->val.type->smax) {
	tvar = makestmttempvar(exd->val.type->indextype, name_TEMP);
	sp = makestmt(SK_FOR);
	if (exd->val.type->smin)
	    mind = exd->val.type->smin;
	else
	    mind = exd->val.type->indextype->smin;
	sp->exp1 = makeexpr_assign(makeexpr_var(tvar),
				   copyexpr(mind));
	sp->exp2 = makeexpr_rel(EK_LE, makeexpr_var(tvar),
				copyexpr(exd->val.type->indextype->smax));
	sp->exp3 = makeexpr_assign(makeexpr_var(tvar),
				   makeexpr_plus(makeexpr_var(tvar),
						 makeexpr_long(1)));
	exi = makeexpr_minus(exi, copyexpr(mind));
	sp->stm1 = makestmt_assign(p_index(exd, makeexpr_var(tvar)),
				   p_index(exs,
					   makeexpr_plus(makeexpr_var(tvar),
							 exi)));
	return sp;
    } else {
	exi = gentle_cast(exi, exs->val.type->indextype);
	return makestmt_call(makeexpr_bicall_3("memcpy", exd->val.type,
					       exd,
					       makeexpr_addr(p_index(exs, exi)),
					       makeexpr_sizeof(copyexpr(exd), 0)));
    }
}



Static Expr *func_pad(ex)
Expr *ex;
{
    if (checkconst(ex->args[1], 0) ||    /* "s" is null string */
	checkconst(ex->args[2], ' ')) {
        return makeexpr_bicall_4("sprintf", tp_strptr, ex->args[0],
                                 makeexpr_string("%*s"),
                                 makeexpr_longcast(ex->args[3], 0),
                                 makeexpr_string(""));
    }
    return makeexpr_bicall_4(strpadname, tp_strptr,
			     ex->args[0], ex->args[1], ex->args[2],
			     makeexpr_arglong(ex->args[3], 0));
}



Static Stmt *proc_page()
{
    Expr *fex, *ex;

    if (curtok == TOK_LPAR) {
        fex = p_parexpr(tp_text);
        ex = makeexpr_bicall_2("fprintf", tp_int,
                               filebasename(copyexpr(fex)),
                               makeexpr_string("\f"));
    } else {
        fex = makeexpr_var(mp_output);
        ex = makeexpr_bicall_1("printf", tp_int,
                               makeexpr_string("\f"));
    }
    if (FCheck(checkfilewrite)) {
        ex = makeexpr_SETIO(makeexpr_rel(EK_GE, ex, makeexpr_long(0)),
			    filewriteerrorname, fex);
    }
    return wrapopencheck(makestmt_call(ex), fex);
}



Static Expr *func_paramcount(ex)
Expr *ex;
{
    freeexpr(ex);
    return makeexpr_minus(makeexpr_name(name_ARGC, tp_int),
                          makeexpr_long(1));
}



Static Expr *func_paramstr(ex)
Expr *ex;
{
    Expr *ex2;

    ex2 = makeexpr_index(makeexpr_name(name_ARGV,
				       makepointertype(tp_strptr)),
			 makeexpr_unlongcast(ex->args[1]),
			 makeexpr_long(0));
    ex2->val.type = tp_str255;
    return makeexpr_bicall_3("sprintf", tp_strptr,
			     ex->args[0],
			     makeexpr_string("%s"),
			     ex2);
}



Static Expr *func_pi()
{
    return makeexpr_name("M_PI", tp_longreal);
}



Static Expr *var_port()
{
    Expr *ex;

    if (!wneedtok(TOK_LBR))
	return makeexpr_name("PORT", tp_integer);
    ex = p_expr(tp_integer);
    if (!wneedtok(TOK_RBR))
	skippasttotoken(TOK_RBR, TOK_SEMI);
    note("Reference to PORT [191]");
    return makeexpr_bicall_1("PORT", tp_ubyte, ex);
}



Static Expr *var_portw()
{
    Expr *ex;

    if (!wneedtok(TOK_LBR))
	return makeexpr_name("PORTW", tp_integer);
    ex = p_expr(tp_integer);
    if (!wneedtok(TOK_RBR))
	skippasttotoken(TOK_RBR, TOK_SEMI);
    note("Reference to PORTW [191]");
    return makeexpr_bicall_1("PORTW", tp_ushort, ex);
}



Static Expr *func_pos(ex)
Expr *ex;
{
    char *cp;

    cp = strposname;
    if (!*cp) {
        note("POS function used [192]");
        cp = "POS";
    } 
    return makeexpr_bicall_3(cp, tp_int,
                             ex->args[1], 
                             ex->args[0],
                             makeexpr_long(1));
}



Static Expr *func_ptr(ex)
Expr *ex;
{
    note("PTR function was used [193]");
    return ex;
}



Static Expr *func_position()
{
    return file_iofunc(2, seek_base);
}



Static Expr *func_pred()
{
    Expr *ex;

    if (wneedtok(TOK_LPAR)) {
	ex = p_ord_expr();
	skipcloseparen();
    } else
	ex = p_ord_expr();
#if 1
    ex = makeexpr_inc(ex, makeexpr_long(-1));
#else
    ex = makeexpr_cast(makeexpr_plus(ex, makeexpr_long(-1)), ex->val.type);
#endif
    return ex;
}



Static Stmt *proc_put()
{
    Expr *ex;
    Type *type;

    if (curtok == TOK_LPAR)
	ex = p_parexpr(tp_text);
    else
	ex = makeexpr_var(mp_output);
    requirefilebuffer(ex);
    type = ex->val.type;
    if (isfiletype(type, -1) && *charputname &&
	filebasetype(type)->kind == TK_CHAR)
	return makestmt_call(makeexpr_bicall_1(charputname, tp_void,
					       filebasename(ex)));
    else if (isfiletype(type, -1) && *arrayputname &&
	     filebasetype(type)->kind == TK_ARRAY)
	return makestmt_call(makeexpr_bicall_2(arrayputname, tp_void,
					       filebasename(ex),
					       makeexpr_type(filebasetype(type))));
    else
	return makestmt_call(makeexpr_bicall_2(putname, tp_void,
					       filebasename(ex),
					       makeexpr_type(filebasetype(type))));
}



Static Expr *func_pwroften(ex)
Expr *ex;
{
    return makeexpr_bicall_2("pow", tp_longreal,
			     makeexpr_real("10.0"), grabarg(ex, 0));
}



Static Stmt *proc_reset()
{
    return handleopen(0);
}



Static Stmt *proc_rewrite()
{
    return handleopen(1);
}




Stmt *doseek(fex, ex)
Expr *fex, *ex;
{
    Expr *ex2;
    Type *basetype = filebasetype(fex->val.type);

    if (ansiC == 1)
        ex2 = makeexpr_name("SEEK_SET", tp_int);
    else
        ex2 = makeexpr_long(0);
    ex = makeexpr_bicall_3("fseek", tp_int,
                           filebasename(copyexpr(fex)),
                           makeexpr_arglong(
                               makeexpr_times(makeexpr_minus(ex,
                                                             makeexpr_long(seek_base)),
                                              makeexpr_sizeof(makeexpr_type(basetype), 0)),
                               1),
                           ex2);
    if (FCheck(checkfileseek)) {
        ex = makeexpr_SETIO(makeexpr_rel(EK_EQ, ex, makeexpr_long(0)),
			    endoffilename, fex);
    }
    return makestmt_call(ex);
}




Static Expr *makegetchar(fex)
Expr *fex;
{
    if (isvar(fex, mp_input))
        return makeexpr_bicall_0("getchar", tp_char);
    else
        return makeexpr_bicall_1("getc", tp_char, filebasename(copyexpr(fex)));
}



Static Stmt *fixscanf(sp, fex)
Stmt *sp;
Expr *fex;
{
    int nargs, i, isstrread;
    char *cp;
    Expr *ex;
    Stmt *sp2;

    isstrread = (fex->val.type->kind == TK_STRING);
    if (sp->kind == SK_ASSIGN && sp->exp1->kind == EK_BICALL &&
        !strcmp(sp->exp1->val.s, "scanf")) {
        if (sp->exp1->args[0]->kind == EK_CONST &&
            !(sp->exp1->args[0]->val.i&1) && !isstrread) {
            cp = sp->exp1->args[0]->val.s;    /* scanf("%c%c") -> getchar;getchar */
            for (i = 0; cp[i] == '%' && cp[i+1] == 'c'; ) {
                i += 2;
                if (i == sp->exp1->args[0]->val.i) {
                    sp2 = NULL;
                    for (i = 1; i < sp->exp1->nargs; i++) {
                        ex = makeexpr_hat(sp->exp1->args[i], 0);
                        sp2 = makestmt_seq(sp2,
                                           makestmt_assign(copyexpr(ex),
                                                           makegetchar(fex)));
                        if (checkeof(fex)) {
                            sp2 = makestmt_seq(sp2,
                                makestmt_call(makeexpr_SETIO(makeexpr_rel(EK_NE,
									  ex,
									  makeexpr_name("EOF", tp_char)),
							     endoffilename,
							     fex)));
                        } else
                            freeexpr(ex);
                    }
                    return sp2;
                }
            }
        }
        nargs = sp->exp1->nargs - 1;
        if (isstrread) {
            strchange(&sp->exp1->val.s, "sscanf");
            insertarg(&sp->exp1, 0, copyexpr(fex));
        } else if (!isvar(fex, mp_input)) {
            strchange(&sp->exp1->val.s, "fscanf");
            insertarg(&sp->exp1, 0, filebasename(copyexpr(fex)));
        }
        if (FCheck(checkreadformat)) {
            if (checkeof(fex) && !isstrread)
                ex = makeexpr_cond(makeexpr_rel(EK_NE,
                                                makeexpr_bicall_1("feof",
								  tp_int,
								  filebasename(copyexpr(fex))),
                                                makeexpr_long(0)),
				   makeexpr_name(endoffilename, tp_int),
				   makeexpr_name(badinputformatname, tp_int));
            else
		ex = makeexpr_name(badinputformatname, tp_int);
            sp->exp1 = makeexpr_SETIO(makeexpr_rel(EK_EQ,
						   sp->exp1,
						   makeexpr_long(nargs)),
				      NULL, makeexpr_bicall_2("Z", tp_int,
							      ex, fex));
        } else if (checkeof(fex) && !isstrread) {
            sp->exp1 = makeexpr_SETIO(makeexpr_rel(EK_NE,
						   sp->exp1,
						   makeexpr_name("EOF", tp_int)),
				      endoffilename, fex);
        }
    }
    return sp;
}



Static Expr *makefgets(vex, lex, fex)
Expr *vex, *lex, *fex;
{
    Expr *ex;

    ex = makeexpr_bicall_3("fgets", tp_strptr,
                           vex,
                           lex,
                           filebasename(copyexpr(fex)));
    if (checkeof(fex)) {
        ex = makeexpr_SETIO(makeexpr_rel(EK_NE, ex, makeexpr_nil()),
			    endoffilename, fex);
    }
    return ex;
}



Static Stmt *skipeoln(fex)
Expr *fex;
{
    Meaning *tvar;
    Expr *ex;

    if (!strcmp(readlnname, "fgets")) {
        tvar = makestmttempvar(tp_str255, name_STRING);
        return makestmt_call(makefgets(makeexpr_var(tvar),
                                       makeexpr_long(stringceiling+1),
                                       filebasename(fex)));
    } else if (!strcmp(readlnname, "scanf") || !*readlnname) {
        if (checkeof(fex))
            ex = makeexpr_SETIO(makeexpr_rel(EK_NE,
					     makegetchar(fex),
					     makeexpr_name("EOF", tp_char)),
				endoffilename, fex);
        else
            ex = makegetchar(fex);
        return makestmt_seq(fixscanf(
                    makestmt_call(makeexpr_bicall_1("scanf", tp_int,
                                                    makeexpr_string("%*[^\n]"))), fex),
                    makestmt_call(ex));
    } else {
        return makestmt_call(makeexpr_bicall_1(readlnname, tp_void,
                                               filebasename(copyexpr(fex))));
    }
}



Static Stmt *handleread_text(fex, var, isreadln)
Expr *fex, *var;
int isreadln;
{
    Stmt *spbase, *spafter, *sp;
    Expr *ex = NULL, *exj = NULL;
    Type *type;
    Meaning *tvar, *tempcp, *mp;
    int i, isstrread, scanfmode, readlnflag, varstring, maxstring;
    int longstrsize = (longstringsize > 0) ? longstringsize : stringceiling;
    long rmin, rmax;
    char *fmt;

    spbase = NULL;
    spafter = NULL;
    sp = NULL;
    tempcp = NULL;
    if (fex->val.type->kind == TK_ARRAY)
	fex = makeexpr_sprintfify(fex);
    isstrread = (fex->val.type->kind == TK_STRING);
    if (isstrread) {
        exj = var;
        var = p_expr(NULL);
    }
    scanfmode = !strcmp(readlnname, "scanf") || !*readlnname || isstrread;
    for (;;) {
        readlnflag = isreadln && curtok == TOK_RPAR;
        if (var->val.type->kind == TK_STRING && !isstrread) {
            if (sp)
                spbase = makestmt_seq(spbase, fixscanf(sp, fex));
            spbase = makestmt_seq(spbase, spafter);
            varstring = (varstrings && var->kind == EK_VAR &&
                         (mp = (Meaning *)var->val.i)->kind == MK_VARPARAM &&
                         mp->type == tp_strptr);
            maxstring = (strmax(var) >= longstrsize && !varstring);
            if (isvar(fex, mp_input) && maxstring && usegets && readlnflag) {
                spbase = makestmt_seq(spbase,
                                      makestmt_call(makeexpr_bicall_1("gets", tp_str255,
                                                                      makeexpr_addr(var))));
                isreadln = 0;
            } else if (scanfmode && !varstring &&
                       (*readlnname || !isreadln)) {
                spbase = makestmt_seq(spbase, makestmt_assign(makeexpr_hat(copyexpr(var), 0),
                                                              makeexpr_char(0)));
                if (maxstring && usegets)
                    ex = makeexpr_string("%[^\n]");
                else
                    ex = makeexpr_string(format_d("%%%d[^\n]", strmax(var)));
                ex = makeexpr_bicall_2("scanf", tp_int, ex, makeexpr_addr(var));
                spbase = makestmt_seq(spbase, fixscanf(makestmt_call(ex), fex));
                if (readlnflag && maxstring && usegets) {
                    spbase = makestmt_seq(spbase, makestmt_call(makegetchar(fex)));
                    isreadln = 0;
                }
            } else {
                ex = makeexpr_plus(strmax_func(var), makeexpr_long(1));
                spbase = makestmt_seq(spbase,
                                      makestmt_call(makefgets(makeexpr_addr(copyexpr(var)),
                                                              ex,
                                                              fex)));
                if (!tempcp)
                    tempcp = makestmttempvar(tp_charptr, name_TEMP);
                spbase = makestmt_seq(spbase,
                                      makestmt_assign(makeexpr_var(tempcp),
                                                      makeexpr_bicall_2("strchr", tp_charptr,
                                                                        makeexpr_addr(copyexpr(var)),
                                                                        makeexpr_char('\n'))));
                sp = makestmt_assign(makeexpr_hat(makeexpr_var(tempcp), 0),
                                     makeexpr_long(0));
                if (readlnflag)
                    isreadln = 0;
                else
                    sp = makestmt_seq(sp,
                                      makestmt_call(makeexpr_bicall_2("ungetc", tp_void,
                                                                      makeexpr_char('\n'),
                                                                      filebasename(copyexpr(fex)))));
                spbase = makestmt_seq(spbase, makestmt_if(makeexpr_rel(EK_NE,
                                                                       makeexpr_var(tempcp),
                                                                       makeexpr_nil()),
                                                          sp,
                                                          NULL));
            }
            sp = NULL;
            spafter = NULL;
        } else if (var->val.type->kind == TK_ARRAY && !isstrread) {
            if (sp)
                spbase = makestmt_seq(spbase, fixscanf(sp, fex));
            spbase = makestmt_seq(spbase, spafter);
	    ex = makeexpr_sizeof(copyexpr(var), 0);
	    if (readlnflag) {
		spbase = makestmt_seq(spbase,
		     makestmt_call(
			 makeexpr_bicall_3("P_readlnpaoc", tp_void,
					   filebasename(copyexpr(fex)),
					   makeexpr_addr(var),
					   makeexpr_arglong(ex, 0))));
		isreadln = 0;
	    } else {
		spbase = makestmt_seq(spbase,
		     makestmt_call(
			 makeexpr_bicall_3("P_readpaoc", tp_void,
					   filebasename(copyexpr(fex)),
					   makeexpr_addr(var),
					   makeexpr_arglong(ex, 0))));
	    }
            sp = NULL;
            spafter = NULL;
        } else {
            switch (ord_type(var->val.type)->kind) {

                case TK_INTEGER:
		    fmt = "d";
		    if (curtok == TOK_COLON) {
			gettok();
		    }
		    if (curtok == TOK_IDENT &&
			!strcicmp(curtokbuf, "HEX")) {
			fmt = "x";
			gettok();
		    } else if (curtok == TOK_IDENT &&
			       !strcicmp(curtokbuf, "OCT")) {
			fmt = "o";
			gettok();
		    } else if (curtok == TOK_IDENT &&
			       !strcicmp(curtokbuf, "BIN")) {
			fmt = "b";
			note("Using %b for binary format in scanf [194]");
			gettok();
		    }
                    type = findbasetype(var->val.type, ODECL_NOPRES);
                    if (exprlongness(var) > 0)
                        ex = makeexpr_string(format_s("%%l%s", fmt));
                    else if (type == tp_integer || type == tp_int ||
                             type == tp_uint || type == tp_sint)
                        ex = makeexpr_string(format_s("%%%s", fmt));
                    else if (type == tp_sshort || type == tp_ushort)
                        ex = makeexpr_string(format_s("%%h%s", fmt));
                    else {
                        tvar = makestmttempvar(tp_int, name_TEMP);
                        spafter = makestmt_seq(spafter,
                                               makestmt_assign(var,
                                                               makeexpr_var(tvar)));
                        var = makeexpr_var(tvar);
                        ex = makeexpr_string(format_s("%%%s", fmt));
                    }
                    break;

                case TK_CHAR:
                    ex = makeexpr_string("%c");
                    if (newlinespace && !isstrread) {
                        spafter = makestmt_seq(spafter,
                                               makestmt_if(makeexpr_rel(EK_EQ,
                                                                        copyexpr(var),
                                                                        makeexpr_char('\n')),
                                                           makestmt_assign(copyexpr(var),
                                                                           makeexpr_char(' ')),
                                                           NULL));
                    }
                    break;

                case TK_BOOLEAN:
                    tvar = makestmttempvar(tp_str255, name_STRING);
                    spafter = makestmt_seq(spafter,
                        makestmt_assign(var,
                                        makeexpr_or(makeexpr_rel(EK_EQ,
                                                                 makeexpr_hat(makeexpr_var(tvar), 0),
                                                                 makeexpr_char('T')),
                                                    makeexpr_rel(EK_EQ,
                                                                 makeexpr_hat(makeexpr_var(tvar), 0),
                                                                 makeexpr_char('t')))));
                    var = makeexpr_var(tvar);
                    ex = makeexpr_string(" %[a-zA-Z]");
                    break;

                case TK_ENUM:
                    warning("READ on enumerated types not yet supported [213]");
                    if (useenum)
                        ex = makeexpr_string("%d");
                    else
                        ex = makeexpr_string("%hd");
                    break;

                case TK_REAL:
		    if (!*floatscanfcode)
			strcpy(floatscanfcode, "%g");
		    if (var->val.type == tp_longreal &&
			(strlen(floatscanfcode) == 2)) {
			char buf[4];
			strcpy(buf, ".l.");
			buf[0] = floatscanfcode[0];
			buf[2] = floatscanfcode[1];
			ex = makeexpr_string(buf);
		    } else
			ex = makeexpr_string(floatscanfcode);
                    break;

                case TK_STRING:     /* strread only */
                    ex = makeexpr_string(format_d("%%%lds", strmax(fex)));
                    break;

                case TK_ARRAY:      /* strread only */
                    if (!ord_range(ex->val.type->indextype, &rmin, &rmax)) {
                        rmin = 1;
                        rmax = 1;
                        note("Can't determine length of packed array of chars [195]");
                    }
                    ex = makeexpr_string(format_d("%%%ldc", rmax-rmin+1));
                    break;

                default:
                    note("Element has wrong type for WRITE statement [196]");
                    ex = NULL;
                    break;

            }
            if (ex) {
                var = makeexpr_addr(var);
                if (sp) {
                    sp->exp1->args[0] = makeexpr_concat(sp->exp1->args[0], ex, 0);
                    insertarg(&sp->exp1, sp->exp1->nargs, var);
                } else {
                    sp = makestmt_call(makeexpr_bicall_2("scanf", tp_int, ex, var));
                }
            }
        }
        if (curtok == TOK_COMMA) {
            gettok();
            var = p_expr(NULL);
        } else
            break;
    }
    if (sp) {
        if (isstrread && !FCheck(checkreadformat) &&
            ((i=0, checkstring(sp->exp1->args[0], "%d")) ||
             (i++, checkstring(sp->exp1->args[0], "%ld")) ||
             (i++, checkstring(sp->exp1->args[0], "%hd")) ||
             (i++, checkstring(sp->exp1->args[0], "%lg")))) {
            if (fullstrread != 0 && exj) {
                tvar = makestmttempvar(tp_strptr, name_STRING);
                sp->exp1 = makeexpr_assign(makeexpr_hat(sp->exp1->args[1], 0),
                                           (i == 3) ? makeexpr_bicall_2("strtod", tp_longreal,
                                                                        copyexpr(fex),
                                                                        makeexpr_addr(makeexpr_var(tvar)))
                                                    : makeexpr_bicall_3("strtol", tp_integer,
                                                                        copyexpr(fex),
                                                                        makeexpr_addr(makeexpr_var(tvar)),
                                                                        makeexpr_long(10)));
		spafter = makestmt_seq(spafter,
				       makestmt_assign(copyexpr(exj),
						       makeexpr_minus(makeexpr_var(tvar),
								      makeexpr_addr(copyexpr(fex)))));
            } else {
                sp->exp1 = makeexpr_assign(makeexpr_hat(sp->exp1->args[1], 0),
                                           makeexpr_bicall_1((i == 1) ? "atol" : (i == 3) ? "atof" : "atoi",
                                                             (i == 1) ? tp_integer : (i == 3) ? tp_longreal : tp_int,
                                                             copyexpr(fex)));
            }
        } else if (isstrread && fullstrread != 0 && exj) {
            sp->exp1->args[0] = makeexpr_concat(sp->exp1->args[0],
                                                makeexpr_string(sizeof_int >= 32 ? "%n" : "%ln"), 0);
            insertarg(&sp->exp1, sp->exp1->nargs, makeexpr_addr(copyexpr(exj)));
        } else if (isreadln && scanfmode && !FCheck(checkreadformat)) {
            isreadln = 0;
            sp->exp1->args[0] = makeexpr_concat(sp->exp1->args[0],
                                                makeexpr_string("%*[^\n]"), 0);
            spafter = makestmt_seq(makestmt_call(makegetchar(fex)), spafter);
        }
        spbase = makestmt_seq(spbase, fixscanf(sp, fex));
    }
    spbase = makestmt_seq(spbase, spafter);
    if (isreadln)
        spbase = makestmt_seq(spbase, skipeoln(fex));
    return spbase;
}



Static Stmt *handleread_bin(fex, var)
Expr *fex, *var;
{
    Type *basetype;
    Stmt *sp;
    Expr *ex, *tvardef = NULL;

    sp = NULL;
    basetype = filebasetype(fex->val.type);
    for (;;) {
        ex = makeexpr_bicall_4("fread", tp_integer, makeexpr_addr(var),
                                                    makeexpr_sizeof(makeexpr_type(basetype), 0),
                                                    makeexpr_long(1),
                                                    filebasename(copyexpr(fex)));
        if (checkeof(fex)) {
            ex = makeexpr_SETIO(makeexpr_rel(EK_EQ, ex, makeexpr_long(1)),
				endoffilename, fex);
        }
        sp = makestmt_seq(sp, makestmt_call(ex));
        if (curtok == TOK_COMMA) {
            gettok();
            var = p_expr(NULL);
        } else
            break;
    }
    freeexpr(tvardef);
    return sp;
}



Static Stmt *proc_read()
{
    Expr *fex, *ex;
    Stmt *sp;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(NULL);
    sp = NULL;
    if (isfiletype(ex->val.type, -1) && wneedtok(TOK_COMMA)) {
        fex = ex;
	if (israndomfile(fex->val.type)) {
	    ex = p_expr(tp_integer);
	    sp = doseek(fex, ex);
	    if (!skipcomma())
		return sp;
	}
        ex = p_expr(NULL);
    } else {
        fex = makeexpr_var(mp_input);
    }
    if (fex->val.type == tp_text || fex->val.type == tp_bigtext)
        sp = makestmt_seq(sp, handleread_text(fex, ex, 0));
    else
        sp = makestmt_seq(sp, handleread_bin(fex, ex));
    skipcloseparen();
    return wrapopencheck(sp, fex);
}



Static Stmt *proc_readdir()
{
    Expr *fex, *ex;
    Stmt *sp;

    if (!skipopenparen())
	return NULL;
    fex = p_expr(tp_text);
    if (!skipcomma())
	return NULL;
    ex = p_expr(tp_integer);
    sp = doseek(fex, ex);
    if (!skipcomma())
	return sp;
    sp = makestmt_seq(sp, handleread_bin(fex, p_expr(NULL)));
    skipcloseparen();
    return wrapopencheck(sp, fex);
}



Static Stmt *proc_readln()
{
    Expr *fex, *ex;
    Stmt *sp;

    if (curtok != TOK_LPAR) {
        fex = makeexpr_var(mp_input);
        return wrapopencheck(skipeoln(copyexpr(fex)), fex);
    } else {
        gettok();
        ex = p_expr(NULL);
        if (isfiletype(ex->val.type, -1)) {
            fex = ex;
            if (curtok == TOK_RPAR || !wneedtok(TOK_COMMA)) {
                skippasttotoken(TOK_RPAR, TOK_SEMI);
                return wrapopencheck(skipeoln(copyexpr(fex)), fex);
            } else {
                ex = p_expr(NULL);
            }
        } else {
            fex = makeexpr_var(mp_input);
        }
        sp = handleread_text(fex, ex, 1);
        skipcloseparen();
    }
    return wrapopencheck(sp, fex);
}



Static Stmt *proc_readv()
{
    Expr *vex;
    Stmt *sp;

    if (!skipopenparen())
	return NULL;
    vex = p_expr(tp_str255);
    if (!skipcomma())
	return NULL;
    sp = handleread_text(vex, NULL, 0);
    skipcloseparen();
    return sp;
}



Static Stmt *proc_strread()
{
    Expr *vex, *exi, *exj, *exjj, *ex;
    Stmt *sp, *sp2;
    Meaning *tvar, *jvar;

    if (!skipopenparen())
	return NULL;
    vex = p_expr(tp_str255);
    if (vex->kind != EK_VAR) {
        tvar = makestmttempvar(tp_str255, name_STRING);
        sp = makestmt_assign(makeexpr_var(tvar), vex);
        vex = makeexpr_var(tvar);
    } else
        sp = NULL;
    if (!skipcomma())
	return NULL;
    exi = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    exj = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    if (exprspeed(exi) >= 5 || !nosideeffects(exi, 0)) {
        sp = makestmt_seq(sp, makestmt_assign(copyexpr(exj), exi));
        exi = copyexpr(exj);
    }
    if (fullstrread != 0 &&
        ((ex = singlevar(exj)) == NULL || exproccurs(exi, ex))) {
        jvar = makestmttempvar(exj->val.type, name_TEMP);
        exjj = makeexpr_var(jvar);
    } else {
        exjj = copyexpr(exj);
        jvar = (exj->kind == EK_VAR) ? (Meaning *)exj->val.i : NULL;
    }
    sp2 = handleread_text(bumpstring(copyexpr(vex),
                                     copyexpr(exi), 1),
                          exjj, 0);
    sp = makestmt_seq(sp, sp2);
    skipcloseparen();
    if (fullstrread == 0) {
        sp = makestmt_seq(sp, makestmt_assign(exj,
                                              makeexpr_plus(makeexpr_bicall_1("strlen", tp_int,
                                                                              vex),
                                                            makeexpr_long(1))));
        freeexpr(exjj);
        freeexpr(exi);
    } else {
        sp = makestmt_seq(sp, makestmt_assign(exj,
                                              makeexpr_plus(exjj, exi)));
        if (fullstrread == 2)
            note("STRREAD was used [197]");
        freeexpr(vex);
    }
    return mixassignments(sp, jvar);
}




Static Expr *func_random()
{
    Expr *ex;

    if (curtok == TOK_LPAR) {
        gettok();
        ex = p_expr(tp_integer);
        skipcloseparen();
        return makeexpr_bicall_1(randintname, tp_integer, makeexpr_arglong(ex, 1));
    } else {
        return makeexpr_bicall_0(randrealname, tp_longreal);
    }
}



Static Stmt *proc_randomize()
{
    if (*randomizename)
        return makestmt_call(makeexpr_bicall_0(randomizename, tp_void));
    else
        return NULL;
}



Static Expr *func_round(ex)
Expr *ex;
{
    Meaning *tvar;

    ex = grabarg(ex, 0);
    if (ex->val.type->kind != TK_REAL)
	return ex;
    if (*roundname) {
        if (*roundname != '*' || (exprspeed(ex) < 5 && nosideeffects(ex, 0))) {
            return makeexpr_bicall_1(roundname, tp_integer, ex);
        } else {
            tvar = makestmttempvar(tp_longreal, name_TEMP);
            return makeexpr_comma(makeexpr_assign(makeexpr_var(tvar), ex),
                                  makeexpr_bicall_1(roundname, tp_integer, makeexpr_var(tvar)));
        }
    } else {
        return makeexpr_actcast(makeexpr_bicall_1("floor", tp_longreal,
						  makeexpr_plus(ex, makeexpr_real("0.5"))),
                                tp_integer);
    }
}



Static Stmt *proc_unpack()
{
    Expr *exs, *exd, *exi, *mins;
    Meaning *tvar;
    Stmt *sp;

    if (!skipopenparen())
	return NULL;
    exs = p_expr(NULL);
    if (!skipcomma())
	return NULL;
    exd = p_expr(NULL);
    if (!skipcomma())
	return NULL;
    exi = p_ord_expr();
    skipcloseparen();
    if (exd->val.type->kind != TK_ARRAY ||
	(exs->val.type->kind != TK_ARRAY &&
	 exs->val.type->kind != TK_SMALLARRAY)) {
	warning("Bad argument types for PACK/UNPACK [325]");
	return makestmt_call(makeexpr_bicall_3("unpack", tp_void,
					       exs, exd, exi));
    }
    if (exs->val.type->smax || exd->val.type->smax) {
	tvar = makestmttempvar(exs->val.type->indextype, name_TEMP);
	sp = makestmt(SK_FOR);
	if (exs->val.type->smin)
	    mins = exs->val.type->smin;
	else
	    mins = exs->val.type->indextype->smin;
	sp->exp1 = makeexpr_assign(makeexpr_var(tvar),
				   copyexpr(mins));
	sp->exp2 = makeexpr_rel(EK_LE, makeexpr_var(tvar),
				copyexpr(exs->val.type->indextype->smax));
	sp->exp3 = makeexpr_assign(makeexpr_var(tvar),
				   makeexpr_plus(makeexpr_var(tvar),
						 makeexpr_long(1)));
	exi = makeexpr_minus(exi, copyexpr(mins));
	sp->stm1 = makestmt_assign(p_index(exd,
					   makeexpr_plus(makeexpr_var(tvar),
							 exi)),
				   p_index(exs, makeexpr_var(tvar)));
	return sp;
    } else {
	exi = gentle_cast(exi, exs->val.type->indextype);
	return makestmt_call(makeexpr_bicall_3("memcpy", exd->val.type,
					       exd,
					       makeexpr_addr(p_index(exs, exi)),
					       makeexpr_sizeof(copyexpr(exd), 0)));
    }
}



Static Expr *func_uround(ex)
Expr *ex;
{
    ex = grabarg(ex, 0);
    if (ex->val.type->kind != TK_REAL)
	return ex;
    return makeexpr_actcast(makeexpr_bicall_1("floor", tp_longreal,
					      makeexpr_plus(ex, makeexpr_real("0.5"))),
			    tp_unsigned);
}



Static Expr *func_scan()
{
    Expr *ex, *ex2, *ex3;
    char *name;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    if (curtok == TOK_EQ)
	name = "P_scaneq";
    else 
	name = "P_scanne";
    gettok();
    ex2 = p_expr(tp_char);
    if (!skipcomma())
	return NULL;
    ex3 = p_expr(tp_str255);
    skipcloseparen();
    return makeexpr_bicall_3(name, tp_int,
			     makeexpr_arglong(ex, 0),
			     makeexpr_charcast(ex2), ex3);
}



Static Expr *func_scaneq(ex)
Expr *ex;
{
    return makeexpr_bicall_3("P_scaneq", tp_int,
			     makeexpr_arglong(ex->args[0], 0),
			     makeexpr_charcast(ex->args[1]),
			     ex->args[2]);
}


Static Expr *func_scanne(ex)
Expr *ex;
{
    return makeexpr_bicall_3("P_scanne", tp_int,
			     makeexpr_arglong(ex->args[0], 0),
			     makeexpr_charcast(ex->args[1]),
			     ex->args[2]);
}



Static Stmt *proc_seek()
{
    Expr *fex, *ex;
    Stmt *sp;

    if (!skipopenparen())
	return NULL;
    fex = p_expr(tp_text);
    if (!skipcomma())
	return NULL;
    ex = p_expr(tp_integer);
    skipcloseparen();
    sp = wrapopencheck(doseek(fex, ex), copyexpr(fex));
    if (*setupbufname && fileisbuffered(fex, 1))
	sp = makestmt_seq(sp,
		 makestmt_call(
		     makeexpr_bicall_2(setupbufname, tp_void,
				       filebasename(fex),
				       makeexpr_type(filebasetype(fex->val.type)))));
    else
	freeexpr(fex);
    return sp;
}



Static Expr *func_seekeof()
{
    Expr *ex;

    if (curtok == TOK_LPAR)
        ex = p_parexpr(tp_text);
    else
        ex = makeexpr_var(mp_input);
    if (*skipnlspacename)
        ex = makeexpr_bicall_1(skipnlspacename, tp_text, filebasename(ex));
    else
        note("SEEKEOF was used [198]");
    return iofunc(ex, 0);
}



Static Expr *func_seekeoln()
{
    Expr *ex;

    if (curtok == TOK_LPAR)
        ex = p_parexpr(tp_text);
    else
        ex = makeexpr_var(mp_input);
    if (*skipspacename)
        ex = makeexpr_bicall_1(skipspacename, tp_text, filebasename(ex));
    else
        note("SEEKEOLN was used [199]");
    return iofunc(ex, 1);
}



Static Expr *func_self()
{
    Expr *ex;
    Type *type;

    if (curctx && curctx->kind == MK_FUNCTION && curctx->rectype) {
	type = curctx->rectype;
    } else {
	type = tp_integer;
	warning("Reference to SELF outside of member function [330]");
    }
    ex = makeexpr_name("this", makepointertype(type));
    if (turboobjects)
	ex = makeexpr_hat(ex, 0);
    return ex;
}


Static Stmt *proc_setstrlen()
{
    Expr *ex, *ex2;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_str255);
    if (!skipcomma())
	return NULL;
    ex2 = p_expr(tp_integer);
    skipcloseparen();
    return makestmt_assign(makeexpr_bicall_1("strlen", tp_int, ex),
                           ex2);
}



Static Stmt *proc_settextbuf()
{
    Expr *fex, *bex, *sex;

    if (!skipopenparen())
	return NULL;
    fex = p_expr(tp_text);
    if (!skipcomma())
	return NULL;
    bex = p_expr(NULL);
    if (curtok == TOK_COMMA) {
        gettok();
        sex = p_expr(tp_integer);
    } else
        sex = makeexpr_sizeof(copyexpr(bex), 0);
    skipcloseparen();
    note("Make sure setvbuf() call occurs when file is open [200]");
    return makestmt_call(makeexpr_bicall_4("setvbuf", tp_void,
                                           filebasename(fex),
                                           makeexpr_addr(bex),
                                           makeexpr_name("_IOFBF", tp_integer),
                                           sex));
}



Static Expr *func_sin(ex)
Expr *ex;
{
    return makeexpr_bicall_1("sin", tp_longreal, grabarg(ex, 0));
}


Static Expr *func_sinh(ex)
Expr *ex;
{
    return makeexpr_bicall_1("sinh", tp_longreal, grabarg(ex, 0));
}



Static Expr *func_sizeof()
{
    Expr *ex;
    Type *type;
    char *name, vbuf[1000];
    int lpar;

    lpar = (curtok == TOK_LPAR);
    if (lpar)
	gettok();
    if (curtok == TOK_IDENT && curtokmeaning && curtokmeaning->kind == MK_TYPE) {
        ex = makeexpr_type(curtokmeaning->type);
        gettok();
    } else {
        ex = p_expr(NULL);
	if (ex->val.type->kind == TK_RECORD && ex->val.type->issigned &&
	    ex->kind != EK_VAR) {
	    Type *tp = ex->val.type;
	    while (tp) {
		Meaning *mp = ex->val.type->fbase;
		while (mp && (mp->kind != MK_FUNCTION || !mp->bufferedfile))
		    mp = mp->cnext;
		if (mp)
		    break;
		tp = tp->basetype;
	    }
	    if (tp)
		warning("SIZEOF called on virtual object type [335]");
	}
    }
    type = ex->val.type;
    parse_special_variant(type, vbuf);
    if (lpar)
	skipcloseparen();
    name = find_special_variant(vbuf, "SpecialSizeOf", specialsizeofs, 1);
    if (name) {
	freeexpr(ex);
	return pc_expr_str(name);
    } else
	return makeexpr_sizeof(ex, 0);
}



Static Expr *func_statusv()
{
    return makeexpr_name(name_IORESULT, tp_integer);
}



Static Expr *func_str_hp(ex)
Expr *ex;
{
    return makeexpr_addr(makeexpr_substring(ex->args[0], ex->args[1], 
                                            ex->args[2], ex->args[3]));
}



Static Stmt *proc_strappend()
{
    Expr *ex, *ex2;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_str255);
    if (!skipcomma())
	return NULL;
    ex2 = p_expr(tp_str255);
    skipcloseparen();
    return makestmt_assign(ex, makeexpr_concat(copyexpr(ex), ex2, 0));
}



Static Stmt *proc_strdelete()
{
    Meaning *tvar = NULL, *tvari;
    Expr *ex, *ex2, *ex3, *ex4, *exi, *exn;
    Stmt *sp;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_str255);
    if (!skipcomma())
	return NULL;
    exi = p_expr(tp_integer);
    if (curtok == TOK_COMMA) {
	gettok();
	exn = p_expr(tp_integer);
    } else
	exn = makeexpr_long(1);
    skipcloseparen();
    if (exprspeed(exi) < 5 && nosideeffects(exi, 0))
        sp = NULL;
    else {
        tvari = makestmttempvar(tp_int, name_TEMP);
        sp = makestmt_assign(makeexpr_var(tvari), exi);
        exi = makeexpr_var(tvari);
    }
    ex3 = bumpstring(copyexpr(ex), copyexpr(exi), 1);
    ex4 = bumpstring(copyexpr(ex), makeexpr_plus(exi, exn), 1);
    if (strcpyleft) {
        ex2 = ex3;
    } else {
        tvar = makestmttempvar(tp_str255, name_STRING);
        ex2 = makeexpr_var(tvar);
    }
    sp = makestmt_seq(sp, makestmt_assign(ex2, ex4));
    if (!strcpyleft)
        sp = makestmt_seq(sp, makestmt_assign(ex3, makeexpr_var(tvar)));
    return sp;
}



Static Stmt *proc_strinsert()
{
    Meaning *tvari;
    Expr *exs, *exd, *exi;
    Stmt *sp;

    if (!skipopenparen())
	return NULL;
    exs = p_expr(tp_str255);
    if (!skipcomma())
	return NULL;
    exd = p_expr(tp_str255);
    if (!skipcomma())
	return NULL;
    exi = p_expr(tp_integer);
    skipcloseparen();
#if 0
    if (checkconst(exi, 1)) {
        freeexpr(exi);
        return makestmt_assign(exd,
                               makeexpr_concat(exs, copyexpr(exd)));
    }
#endif
    if (exprspeed(exi) < 5 && nosideeffects(exi, 0))
        sp = NULL;
    else {
        tvari = makestmttempvar(tp_int, name_TEMP);
        sp = makestmt_assign(makeexpr_var(tvari), exi);
        exi = makeexpr_var(tvari);
    }
    exd = bumpstring(exd, exi, 1);
    sp = makestmt_seq(sp, makestmt_assign(exd,
                                          makeexpr_concat(exs, copyexpr(exd), 0)));
    return sp;
}



Static Stmt *proc_strmove()
{
    Expr *exlen, *exs, *exsi, *exd, *exdi;

    if (!skipopenparen())
	return NULL;
    exlen = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    exs = p_expr(tp_str255);
    if (!skipcomma())
	return NULL;
    exsi = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    exd = p_expr(tp_str255);
    if (!skipcomma())
	return NULL;
    exdi = p_expr(tp_integer);
    skipcloseparen();
    exsi = makeexpr_arglong(exsi, 0);
    exdi = makeexpr_arglong(exdi, 0);
    return makestmt_call(makeexpr_bicall_5(strmovename, tp_str255,
					   exlen, exs, exsi, exd, exdi));
}



Static Expr *func_strlen(ex)
Expr *ex;
{
    return makeexpr_bicall_1("strlen", tp_int, grabarg(ex, 0));
}



Static Expr *func_strltrim(ex)
Expr *ex;
{
    return makeexpr_assign(makeexpr_hat(ex->args[0], 0),
                           makeexpr_bicall_1(strltrimname, tp_str255, ex->args[1]));
}



Static Expr *func_strmax(ex)
Expr *ex;
{
    return strmax_func(grabarg(ex, 0));
}



Static Expr *func_strpos(ex)
Expr *ex;
{
    char *cp;

    if (!switch_strpos)
        swapexprs(ex->args[0], ex->args[1]);
    cp = strposname;
    if (!*cp) {
        note("STRPOS function used [201]");
        cp = "STRPOS";
    } 
    return makeexpr_bicall_3(cp, tp_int,
                             ex->args[0], 
                             ex->args[1],
                             makeexpr_long(1));
}



Static Expr *func_strrpt(ex)
Expr *ex;
{
    if (ex->args[1]->kind == EK_CONST &&
        ex->args[1]->val.i == 1 && ex->args[1]->val.s[0] == ' ') {
        return makeexpr_bicall_4("sprintf", tp_strptr, ex->args[0],
                                 makeexpr_string("%*s"),
                                 makeexpr_longcast(ex->args[2], 0),
                                 makeexpr_string(""));
    } else
        return makeexpr_bicall_3(strrptname, tp_strptr, ex->args[0], ex->args[1],
                                 makeexpr_arglong(ex->args[2], 0));
}



Static Expr *func_strrtrim(ex)
Expr *ex;
{
    return makeexpr_bicall_1(strrtrimname, tp_strptr,
                             makeexpr_assign(makeexpr_hat(ex->args[0], 0),
                                             ex->args[1]));
}



Static Expr *func_succ()
{
    Expr *ex;

    if (wneedtok(TOK_LPAR)) {
	ex = p_ord_expr();
	skipcloseparen();
    } else
	ex = p_ord_expr();
#if 1
    ex = makeexpr_inc(ex, makeexpr_long(1));
#else
    ex = makeexpr_cast(makeexpr_plus(ex, makeexpr_long(1)), ex->val.type);
#endif
    return ex;
}



Static Expr *func_sqr()
{
    return makeexpr_sqr(p_parexpr(tp_integer), 0);
}



Static Expr *func_sqrt(ex)
Expr *ex;
{
    return makeexpr_bicall_1("sqrt", tp_longreal, grabarg(ex, 0));
}



Static Expr *func_swap(ex)
Expr *ex;
{
    char *cp;

    ex = grabarg(ex, 0);
    cp = swapname;
    if (!*cp) {
        note("SWAP function was used [202]");
        cp = "SWAP";
    }
    return makeexpr_bicall_1(swapname, tp_int, ex);
}



Static Expr *func_tan(ex)
Expr *ex;
{
    return makeexpr_bicall_1("tan", tp_longreal, grabarg(ex, 0));
}


Static Expr *func_tanh(ex)
Expr *ex;
{
    return makeexpr_bicall_1("tanh", tp_longreal, grabarg(ex, 0));
}



Static Expr *func_trunc(ex)
Expr *ex;
{
    return makeexpr_actcast(grabarg(ex, 0), tp_integer);
}



Static Expr *func_typeof()
{
    Expr *ex;
    int lpar;

    lpar = (curtok == TOK_LPAR);
    if (lpar)
	gettok();
    if (curtok == TOK_IDENT && curtokmeaning && curtokmeaning->kind == MK_TYPE) {
        ex = makeexpr_bicall_1("typeOfType", tp_anyptr,
			       makeexpr_type(curtokmeaning->type));
        gettok();
    } else {
        ex = makeexpr_bicall_1("typeOf", tp_anyptr, p_expr(NULL));
    }
    if (lpar)
	skipcloseparen();
    return ex;
}



Static Expr *func_utrunc(ex)
Expr *ex;
{
    return makeexpr_actcast(grabarg(ex, 0), tp_unsigned);
}



Static Expr *func_uand()
{
    Expr *ex;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_unsigned);
    if (skipcomma()) {
	ex = makeexpr_bin(EK_BAND, ex->val.type, ex, p_expr(tp_unsigned));
	skipcloseparen();
    }
    return ex;
}



Static Expr *func_ub()
{
    Expr *ex, *ex2;
    Type *type;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_integer);
    if (curtok == TOK_COMMA && skipcomma()) {
	ex2 = p_ord_expr();
	/* ignored for now */
    }
    skipcloseparen();
    type = ex->val.type;
    if (type->kind == TK_POINTER)
	type = type->basetype;
    if (type->kind == TK_ARRAY ||
	type->kind == TK_SMALLARRAY) {
	ex = copyexpr(type->indextype->smax);
    } else if (type->kind == TK_STRING) {
	ex = strmax_func(ex);
	/* ex = makeexpr_minus(makeexpr_bicall_1("sizeof", tp_integer, ex),
			       makeexpr_long(1)); */
    } else {
	warning("UB requires an array name parameter [210]");
	ex = makeexpr_bicall_1("UB", tp_int, ex);
    }
    expr_reference(ex);
    return ex;
}



Static Expr *func_udec()
{
    return handle_vax_hex(NULL, "u", 0);
}



Static Expr *func_unot()
{
    Expr *ex;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_unsigned);
    ex = makeexpr_un(EK_BNOT, ex->val.type, ex);
    skipcloseparen();
    return ex;
}



Static Expr *func_uor()
{
    Expr *ex;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_unsigned);
    if (skipcomma()) {
	ex = makeexpr_bin(EK_BOR, ex->val.type, ex, p_expr(tp_unsigned));
	skipcloseparen();
    }
    return ex;
}



Static Expr *func_upcase(ex)
Expr *ex;
{
    return makeexpr_bicall_1("toupper", tp_char, grabarg(ex, 0));
}



Static Expr *func_upper()
{
    Expr *ex;
    Value val;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_integer);
    if (curtok == TOK_COMMA) {
	gettok();
	val = p_constant(tp_integer);
	if (!val.type || val.i != 1)
	    note("UPPER(v,n) not supported for n>1 [190]");
    }
    skipcloseparen();
    return copyexpr(ex->val.type->indextype->smax);
}



Static Expr *func_uxor()
{
    Expr *ex;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_unsigned);
    if (skipcomma()) {
	ex = makeexpr_bin(EK_BXOR, ex->val.type, ex, p_expr(tp_unsigned));
	skipcloseparen();
    }
    return ex;
}



Static Expr *func_val_modula()
{
    Expr *ex;
    Type *tp;

    if (!skipopenparen())
	return NULL;
    tp = p_type(NULL);
    if (!skipcomma())
	return NULL;
    ex = p_expr(tp);
    skipcloseparen();
    return pascaltypecast(tp, ex);
}



Static Stmt *proc_val_turbo()
{
    Expr *ex, *vex, *code, *fmt;

    if (!skipopenparen())
	return NULL;
    ex = gentle_cast(p_expr(tp_str255), tp_str255);
    if (!skipcomma())
	return NULL;
    vex = p_expr(NULL);
    if (curtok == TOK_COMMA) {
	gettok();
	code = gentle_cast(p_expr(tp_integer), tp_integer);
    } else
	code = NULL;
    skipcloseparen();
    if (vex->val.type->kind == TK_REAL)
        fmt = makeexpr_string("%lg");
    else if (exprlongness(vex) > 0)
        fmt = makeexpr_string("%ld");
    else
        fmt = makeexpr_string("%d");
    ex = makeexpr_bicall_3("sscanf", tp_int,
                           ex, fmt, makeexpr_addr(vex));
    if (code) {
	ex = makeexpr_rel(EK_EQ, ex, makeexpr_long(0));
	return makestmt_assign(code, makeexpr_ord(ex));
    } else
	return makestmt_call(ex);
}







Static Expr *writestrelement(ex, wid, vex, code, needboth)
Expr *ex, *wid, *vex;
int code, needboth;
{
    if (formatstrings && needboth) {
        return makeexpr_bicall_5("sprintf", tp_str255, vex,
                                 makeexpr_string(format_d("%%*.*%c", code)),
                                 copyexpr(wid),
                                 wid,
                                 ex);
    } else {
        return makeexpr_bicall_4("sprintf", tp_str255, vex,
                                 makeexpr_string(format_d("%%*%c", code)),
                                 wid,
                                 ex);
    }
}



Static char *makeenumnames(tp)
Type *tp;
{
    Strlist *sp;
    char *name;
    Meaning *mp;
    int saveindent;

    tp = ord_type(tp);
    for (sp = enumnames; sp && sp->value != (long)tp; sp = sp->next) ;
    if (!sp) {
        if (tp->meaning)
            name = format_s(name_ENUM, tp->meaning->name);
        else
            name = format_s(name_ENUM, format_d("_%d", ++enumnamecount));
        sp = strlist_insert(&enumnames, name);
        sp->value = (long)tp;
        outsection(2);
        output(format_s("static %s *", charname));
        output(sp->s);
        output("[] = {\n");
	saveindent = outindent;
	moreindent(tabsize);
	moreindent(structinitindent);
        for (mp = tp->fbase; mp; mp = mp->xnext) {
            output(makeCstring(mp->sym->name, strlen(mp->sym->name)));
            if (mp->xnext)
                output(",\002 ");
        }
        outindent = saveindent;
        output("\n} ;\n");
        outsection(2);
    }
    return sp->s;
}





/* This function must return a "tempsprintf" */

Expr *writeelement(ex, wid, prec, base)
Expr *ex, *wid, *prec;
int base;
{
    Expr *vex, *ex1, *ex2;
    Meaning *tvar;
    char *fmtcode;
    Type *type;

    ex = makeexpr_charcast(ex);
    if (ex->val.type->kind == TK_POINTER &&
	ex->val.type->basetype &&
	ex->val.type->basetype->kind == TK_STRING) {
        ex = makeexpr_hat(ex, 0);   /* convert char *'s to strings */
        intwarning("writeelement", "got a char * instead of a string [214]");
    }
    if ((ex->val.type->kind == TK_STRING && !wid) ||
        (ord_type(ex->val.type)->kind == TK_CHAR && (!wid || checkconst(wid, 1)))) {
        return makeexpr_sprintfify(ex);
    }
    tvar = makestmttempvar(tp_str255, name_STRING);
    vex = makeexpr_var(tvar);
    if (wid)
        wid = makeexpr_longcast(wid, 0);
    if (prec)
        prec = makeexpr_longcast(prec, 0);
#if 0
    if (wid && (wid->kind == EK_CONST && wid->val.i < 0 ||
                checkconst(wid, -1))) {
        freeexpr(wid);     /* P-system uses write(x:-1) to mean write(x) */
        wid = NULL;
    }
    if (prec && (prec->kind == EK_CONST && prec->val.i < 0 ||
                 checkconst(prec, -1))) {
        freeexpr(prec);
        prec = NULL;
    }
#endif
    switch (ord_type(ex->val.type)->kind) {

        case TK_INTEGER:
            if (!wid) {
		if (integerwidth < 0)
		    integerwidth = (which_lang == LANG_TURBO) ? 1 : 12;
		wid = makeexpr_long(integerwidth);
	    }
	    type = findbasetype(ex->val.type, ODECL_NOPRES);
	    if (base == 16)
		fmtcode = "x";
	    else if (base == 8)
		fmtcode = "o";
	    else if ((possiblesigns(wid) & (1|4)) == 1) {
		wid = makeexpr_neg(wid);
		fmtcode = "x";
	    } else if (type == tp_unsigned ||
		       type == tp_uint ||
		       (type == tp_ushort && sizeof_int < 32))
		fmtcode = "u";
	    else
		fmtcode = "d";
            ex = makeexpr_forcelongness(ex);
            if (checkconst(wid, 0) || checkconst(wid, 1)) {
                ex = makeexpr_bicall_3("sprintf", tp_str255, vex,
                                       makeexpr_string(format_ss("%%%s%s",
								 (exprlongness(ex) > 0) ? "l" : "",
								 fmtcode)),
                                       ex);
            } else {
                ex = makeexpr_bicall_4("sprintf", tp_str255, vex,
                                       makeexpr_string(format_ss("%%*%s%s",
								 (exprlongness(ex) > 0) ? "l" : "",
								 fmtcode)),
                                       wid,
                                       ex);
            }
            break;

        case TK_CHAR:
            ex = writestrelement(ex, wid, vex, 'c',
                                     (wid->kind != EK_CONST || wid->val.i < 1));
            break;

        case TK_BOOLEAN:
            if (!wid) {
                ex = makeexpr_bicall_3("sprintf", tp_str255, vex,
                                       makeexpr_string("%s"),
                                       makeexpr_cond(ex,
                                                     makeexpr_string(" TRUE"),
                                                     makeexpr_string("FALSE")));
            } else if (checkconst(wid, 1)) {
                ex = makeexpr_bicall_3("sprintf", tp_str255, vex,
                                       makeexpr_string("%c"),
                                       makeexpr_cond(ex,
                                                     makeexpr_char('T'),
                                                     makeexpr_char('F')));
            } else {
                ex = writestrelement(makeexpr_cond(ex,
                                                   makeexpr_string("TRUE"),
                                                   makeexpr_string("FALSE")),
                                     wid, vex, 's',
                                     (wid->kind != EK_CONST || wid->val.i < 5));
            }
            break;

        case TK_ENUM:
            ex = makeexpr_bicall_3("sprintf", tp_str255, vex,
                                   makeexpr_string("%s"),
                                   makeexpr_index(makeexpr_name(makeenumnames(ex->val.type),
                                                                tp_strptr),
                                                  ex, NULL));
            break;

        case TK_REAL:
            if (!wid)
                wid = makeexpr_long(realwidth);
            if (prec && (possiblesigns(prec) & (1|4)) != 1) {
                ex = makeexpr_bicall_5("sprintf", tp_str255, vex,
                                       makeexpr_string("%*.*f"),
                                       wid,
                                       prec,
                                       ex);
            } else {
		if (prec)
		    prec = makeexpr_neg(prec);
		else
		    prec = makeexpr_minus(copyexpr(wid),
					  makeexpr_long(7));
		if (prec->kind == EK_CONST) {
		    if (prec->val.i <= 0)
			prec = makeexpr_long(1);
		} else {
		    prec = makeexpr_bicall_2("P_max", tp_integer, prec,
					     makeexpr_long(1));
		}
                if (wid->kind == EK_CONST && wid->val.i > 21) {
                    ex = makeexpr_bicall_5("sprintf", tp_str255, vex,
                                           makeexpr_string("%*.*E"),
                                           wid,
					   prec,
                                           ex);
#if 0
                } else if (checkconst(wid, 7)) {
                    ex = makeexpr_bicall_3("sprintf", tp_str255, vex,
                                           makeexpr_string("%E"),
                                           ex);
#endif
                } else {
                    ex = makeexpr_bicall_4("sprintf", tp_str255, vex,
                                           makeexpr_string("% .*E"),
					   prec,
                                           ex);
                }
            }
            break;

        case TK_STRING:
            ex = writestrelement(ex, wid, vex, 's', 1);
            break;

        case TK_ARRAY:     /* assume packed array of char */
	    ord_range_expr(ex->val.type->indextype, &ex1, &ex2);
	    ex1 = makeexpr_plus(makeexpr_minus(copyexpr(ex2),
					       copyexpr(ex1)),
				makeexpr_long(1));
	    ex1 = makeexpr_longcast(ex1, 0);
	    fmtcode = "%.*s";
            if (!wid) {
		wid = ex1;
            } else {
		if (isliteralconst(wid, NULL) == 2 &&
		    isliteralconst(ex1, NULL) == 2) {
		    if (wid->val.i > ex1->val.i) {
			fmtcode = format_ds("%*s%%.*s",
					    wid->val.i - ex1->val.i, "");
			wid = ex1;
		    }
		} else
		    note("Format for packed-array-of-char will work only if width < length [321]");
	    }
            ex = makeexpr_bicall_4("sprintf", tp_str255, vex,
                                   makeexpr_string(fmtcode),
                                   wid,
                                   makeexpr_addr(ex));
            break;

	case TK_POINTER:
	    ex = makeexpr_bicall_3("sprintf", tp_str255, vex,
				   makeexpr_string(format_s("0x%%.8%sx",
							    (sizeof_int < 32)
							    ? "l" : "")),
				   makeexpr_cast(ex, tp_integer));
	    break;

        default:
            note("Element has wrong type for WRITE statement [196]");
            ex = makeexpr_bicall_2("sprintf", tp_str255, vex, makeexpr_string("<meef>"));
            break;

    }
    return ex;
}



Static Stmt *handlewrite_text(fex, ex, iswriteln)
Expr *fex, *ex;
int iswriteln;
{
    Expr *print, *wid, *prec;
    unsigned char *ucp;
    int i, done, base;

    print = NULL;
    for (;;) {
        wid = NULL;
        prec = NULL;
	base = 10;
	if (curtok == TOK_COLON && iswriteln >= 0) {
	    gettok();
	    wid = p_expr(tp_integer);
	    if (curtok == TOK_COLON) {
		gettok();
		prec = p_expr(tp_integer);
	    }
	}
	if (curtok == TOK_IDENT &&
	    !strcicmp(curtokbuf, "OCT")) {
	    base = 8;
	    gettok();
	} else if (curtok == TOK_IDENT &&
		   !strcicmp(curtokbuf, "HEX")) {
	    base = 16;
	    gettok();
	}
        ex = writeelement(ex, wid, prec, base);
        print = makeexpr_concat(print, cleansprintf(ex), 1);
        if (curtok == TOK_COMMA && iswriteln >= 0) {
            gettok();
            ex = p_expr(NULL);
        } else
            break;
    }
    if (fex->val.type->kind != TK_STRING) {      /* not strwrite */
        switch (iswriteln) {
            case 1:
            case -1:
                print = makeexpr_concat(print, makeexpr_string("\n"), 1);
                break;
            case 2:
            case -2:
                print = makeexpr_concat(print, makeexpr_string("\r"), 1);
                break;
        }
        if (isvar(fex, mp_output)) {
            ucp = (unsigned char *)print->args[1]->val.s;
            for (i = 0; i < print->args[1]->val.i; i++) {
                if (ucp[i] >= 128 && ucp[i] < 144) {
                    note("WRITE statement contains color/attribute characters [203]");
		    break;
		}
            }
        }
        if ((i = sprintflength(print, 0)) > 0 && print->nargs == 2 && printfonly != 1) {
            print = makeexpr_unsprintfify(print);
            done = 1;
            if (isvar(fex, mp_output)) {
                if (i == 1) {
                    print = makeexpr_bicall_1("putchar", tp_int,
                                              makeexpr_charcast(print));
                } else {
                    if (printfonly == 0) {
                        if (print->val.s[print->val.i-1] == '\n') {
			    print->val.s[--(print->val.i)] = 0;
                            print = makeexpr_bicall_1("puts", tp_int, print);
                        } else {
                            print = makeexpr_bicall_2("fputs", tp_int,
                                                      print,
                                                      copyexpr(fex));
                        }
                    } else {
                        print = makeexpr_sprintfify(print);
                        done = 0;
                    }
                }
            } else {
                if (i == 1) {
                    print = makeexpr_bicall_2("putc", tp_int,
                                              makeexpr_charcast(print),
                                              filebasename(copyexpr(fex)));
                } else if (printfonly == 0) {
                    print = makeexpr_bicall_2("fputs", tp_int,
                                              print,
                                              filebasename(copyexpr(fex)));
                } else {
                    print = makeexpr_sprintfify(print);
                    done = 0;
                }
            }
        } else
            done = 0;
        if (!done) {
            canceltempvar(istempvar(print->args[0]));
            if (checkstring(print->args[1], "%s") && printfonly != 1) {
                print = makeexpr_bicall_2("fputs", tp_int,
                                          grabarg(print, 2),
                                          filebasename(copyexpr(fex)));
            } else if (checkstring(print->args[1], "%c") && printfonly != 1 &&
                       !nosideeffects(print->args[2], 0)) {
                print = makeexpr_bicall_2("fputc", tp_int,
                                          grabarg(print, 2),
                                          filebasename(copyexpr(fex)));
            } else if (isvar(fex, mp_output)) {
                if (checkstring(print->args[1], "%s\n") && printfonly != 1) {
                    print = makeexpr_bicall_1("puts", tp_int, grabarg(print, 2));
                } else if (checkstring(print->args[1], "%c") && printfonly != 1) {
                    print = makeexpr_bicall_1("putchar", tp_int, grabarg(print, 2));
                } else {
                    strchange(&print->val.s, "printf");
                    delfreearg(&print, 0);
                    print->val.type = tp_int;
                }
            } else {
                if (checkstring(print->args[1], "%c") && printfonly != 1) {
                    print = makeexpr_bicall_2("putc", tp_int,
                                              grabarg(print, 2),
                                              filebasename(copyexpr(fex)));
                } else {
                    strchange(&print->val.s, "fprintf");
                    freeexpr(print->args[0]);
                    print->args[0] = filebasename(copyexpr(fex));
                    print->val.type = tp_int;
                }
            }
        }
        if (FCheck(checkfilewrite)) {
            print = makeexpr_SETIO(makeexpr_rel(EK_GE, print, makeexpr_long(0)),
				   filewriteerrorname, fex);
        }
    }
    return makestmt_call(print);
}



Static Stmt *handlewrite_bin(fex, ex)
Expr *fex, *ex;
{
    Type *basetype;
    Stmt *sp;
    Expr *tvardef = NULL;
    Meaning *tvar = NULL;

    sp = NULL;
    basetype = filebasetype(fex->val.type);
    for (;;) {
        if (!expr_has_address(ex) || ex->val.type != basetype) {
            if (!tvar)
                tvar = makestmttempvar(basetype, name_TEMP);
            if (!tvardef || !exprsame(tvardef, ex, 1)) {
                freeexpr(tvardef);
                tvardef = copyexpr(ex);
                sp = makestmt_seq(sp, makestmt_assign(makeexpr_var(tvar),
                                                      ex));
            } else
                freeexpr(ex);
            ex = makeexpr_var(tvar);
        }
        ex = makeexpr_bicall_4("fwrite", tp_integer, makeexpr_addr(ex),
                                                     makeexpr_sizeof(makeexpr_type(basetype), 0),
                                                     makeexpr_long(1),
			                             filebasename(copyexpr(fex)));
        if (FCheck(checkfilewrite)) {
            ex = makeexpr_SETIO(makeexpr_rel(EK_EQ, ex, makeexpr_long(1)),
				filewriteerrorname, fex);
        }
        sp = makestmt_seq(sp, makestmt_call(ex));
        if (curtok == TOK_COMMA) {
            gettok();
            ex = p_expr(NULL);
        } else
            break;
    }
    freeexpr(tvardef);
    return sp;
}



Static Stmt *proc_write()
{
    Expr *fex, *ex;
    Stmt *sp;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(NULL);
    sp = NULL;
    if (isfiletype(ex->val.type, -1) && wneedtok(TOK_COMMA)) {
        fex = ex;
	if (israndomfile(fex->val.type)) {
	    ex = p_expr(tp_integer);
	    sp = doseek(fex, ex);
	    if (!skipcomma())
		return sp;
	}
        ex = p_expr(NULL);
    } else {
        fex = makeexpr_var(mp_output);
    }
    if (fex->val.type == tp_text || fex->val.type == tp_bigtext)
        sp = makestmt_seq(sp, handlewrite_text(fex, ex, 0));
    else
        sp = makestmt_seq(sp, handlewrite_bin(fex, ex));
    skipcloseparen();
    return wrapopencheck(sp, fex);
}



Static Stmt *handle_modula_write(fmt)
char *fmt;
{
    Expr *ex, *wid;

    if (!skipopenparen())
	return NULL;
    ex = makeexpr_forcelongness(p_expr(NULL));
    if (skipcomma())
	wid = p_expr(tp_integer);
    else
	wid = makeexpr_long(1);
    if (checkconst(wid, 0) || checkconst(wid, 1))
	ex = makeexpr_bicall_2("printf", tp_str255,
			       makeexpr_string(format_ss("%%%s%s",
							 (exprlongness(ex) > 0) ? "l" : "",
							 fmt)),
			       ex);
    else
	ex = makeexpr_bicall_3("printf", tp_str255,
			       makeexpr_string(format_ss("%%*%s%s",
							 (exprlongness(ex) > 0) ? "l" : "",
							 fmt)),
			       makeexpr_arglong(wid, 0),
			       ex);
    skipcloseparen();
    return makestmt_call(ex);
}


Static Stmt *proc_writecard()
{
    return handle_modula_write("u");
}


Static Stmt *proc_writeint()
{
    return handle_modula_write("d");
}


Static Stmt *proc_writehex()
{
    return handle_modula_write("x");
}


Static Stmt *proc_writeoct()
{
    return handle_modula_write("o");
}


Static Stmt *proc_writereal()
{
    return handle_modula_write("f");
}



Static Stmt *proc_writedir()
{
    Expr *fex, *ex;
    Stmt *sp;

    if (!skipopenparen())
	return NULL;
    fex = p_expr(tp_text);
    if (!skipcomma())
	return NULL;
    ex = p_expr(tp_integer);
    sp = doseek(fex, ex);
    if (!skipcomma())
	return sp;
    sp = makestmt_seq(sp, handlewrite_bin(fex, p_expr(NULL)));
    skipcloseparen();
    return wrapopencheck(sp, fex);
}



Static Stmt *handlewriteln(iswriteln)
int iswriteln;
{
    Expr *fex, *ex;
    Stmt *sp;
    Meaning *deffile = mp_output;

    sp = NULL;
    if (iswriteln == 3) {
	iswriteln = 1;
	if (messagestderr)
	    deffile = mp_stderr;
    }
    if (curtok != TOK_LPAR) {
        fex = makeexpr_var(deffile);
        if (iswriteln)
            sp = handlewrite_text(fex, makeexpr_string(""), -iswriteln);
    } else {
        gettok();
        ex = p_expr(NULL);
        if (isfiletype(ex->val.type, -1)) {
            fex = ex;
            if (curtok == TOK_RPAR || !wneedtok(TOK_COMMA)) {
                if (iswriteln)
                    ex = makeexpr_string("");
                else
                    ex = NULL;
            } else {
                ex = p_expr(NULL);
            }
        } else {
            fex = makeexpr_var(deffile);
        }
        if (ex)
            sp = handlewrite_text(fex, ex, iswriteln);
        skipcloseparen();
    }
    if (iswriteln == 0) {
        sp = makestmt_seq(sp, makestmt_call(makeexpr_bicall_1("fflush", tp_void,
                                                              filebasename(copyexpr(fex)))));
    }
    return wrapopencheck(sp, fex);
}



Static Stmt *proc_overprint()
{
    return handlewriteln(2);
}



Static Stmt *proc_prompt()
{
    return handlewriteln(0);
}



Static Stmt *proc_writeln()
{
    return handlewriteln(1);
}


Static Stmt *proc_message()
{
    return handlewriteln(3);
}



Static Stmt *proc_writev()
{
    Expr *vex, *ex;
    Stmt *sp;
    Meaning *mp;

    if (!skipopenparen())
	return NULL;
    vex = p_expr(tp_str255);
    if (curtok == TOK_RPAR) {
	gettok();
	return makestmt_assign(vex, makeexpr_string(""));
    }
    if (!skipcomma())
	return NULL;
    sp = handlewrite_text(vex, p_expr(NULL), 0);
    skipcloseparen();
    ex = sp->exp1;
    if (ex->kind == EK_BICALL && !strcmp(ex->val.s, "sprintf") &&
        (mp = istempvar(ex->args[0])) != NULL) {
        canceltempvar(mp);
        ex->args[0] = vex;
    } else
        sp->exp1 = makeexpr_assign(vex, ex);
    return sp;
}


Static Stmt *proc_strwrite(mp_x, spbase)
Meaning *mp_x;
Stmt *spbase;
{
    Expr *vex, *exi, *exj, *ex;
    Stmt *sp;
    Meaning *mp;

    if (!skipopenparen())
	return NULL;
    vex = p_expr(tp_str255);
    if (!skipcomma())
	return NULL;
    exi = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    exj = p_expr(tp_integer);
    if (!skipcomma())
	return NULL;
    sp = handlewrite_text(vex, p_expr(NULL), 0);
    skipcloseparen();
    ex = sp->exp1;
    FREE(sp);
    if (checkconst(exi, 1)) {
        sp = spbase;
        while (sp && sp->next)
            sp = sp->next;
        if (sp && sp->kind == SK_ASSIGN && sp->exp1->kind == EK_ASSIGN &&
             (sp->exp1->args[0]->kind == EK_HAT ||
              sp->exp1->args[0]->kind == EK_INDEX) &&
             exprsame(sp->exp1->args[0]->args[0], vex, 1) &&
             checkconst(sp->exp1->args[1], 0)) {
            nukestmt(sp);     /* remove preceding bogus setstrlen */
        }
    }
    if (ex->kind == EK_BICALL && !strcmp(ex->val.s, "sprintf") &&
        (mp = istempvar(ex->args[0])) != NULL) {
        canceltempvar(mp);
        ex->args[0] = bumpstring(copyexpr(vex), exi, 1);
        sp = makestmt_call(ex);
    } else
        sp = makestmt_assign(bumpstring(copyexpr(vex), exi, 1), ex);
    if (fullstrwrite != 0) {
        sp = makestmt_seq(sp, makestmt_assign(exj,
                                              makeexpr_plus(makeexpr_bicall_1("strlen", tp_int, vex),
                                                            makeexpr_long(1))));
        if (fullstrwrite == 1)
            note("FullStrWrite=1 not yet supported [204]");
        if (fullstrwrite == 2)
            note("STRWRITE was used [205]");
    } else {
        freeexpr(vex);
    }
    return mixassignments(sp, NULL);
}



Static Stmt *proc_str_turbo()
{
    Expr *ex, *wid, *prec;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(NULL);
    wid = NULL;
    prec = NULL;
    if (curtok == TOK_COLON) {
        gettok();
        wid = p_expr(tp_integer);
        if (curtok == TOK_COLON) {
            gettok();
            prec = p_expr(tp_integer);
        }
    }
    ex = writeelement(ex, wid, prec, 10);
    if (!skipcomma())
	return NULL;
    wid = p_expr(tp_str255);
    skipcloseparen();
    return makestmt_assign(wid, ex);
}



Static Stmt *proc_time()
{
    Expr *ex;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(tp_str255);
    skipcloseparen();
    return makestmt_call(makeexpr_bicall_1("VAXtime", tp_integer, ex));
}


Static Expr *func_xor()
{
    Expr *ex, *ex2;
    Type *type;
    Meaning *tvar;

    if (!skipopenparen())
	return NULL;
    ex = p_expr(NULL);
    if (!skipcomma())
	return ex;
    ex2 = p_expr(ex->val.type);
    skipcloseparen();
    if (ex->val.type->kind != TK_SET &&
	ex->val.type->kind != TK_SMALLSET) {
	ex = makeexpr_bin(EK_BXOR, ex->val.type, ex, ex2);
    } else {
	type = mixsets(&ex, &ex2);
	tvar = makestmttempvar(type, name_SET);
	ex = makeexpr_bicall_3(setxorname, type,
			       makeexpr_var(tvar),
			       ex, ex2);
    }
    return ex;
}







void decl_builtins()
{
    makespecialfunc( "ABS",           func_abs);
    makespecialfunc( "ADDR",          func_addr);
    if (!modula2)
	makespecialfunc( "ADDRESS",   func_addr);
    makespecialfunc( "ADDTOPOINTER",  func_addtopointer);
    makespecialfunc( "ADR",           func_addr);
    makespecialfunc( "ASL",	      func_lsl);
    makespecialfunc( "ASR",	      func_asr);
    makespecialfunc( "BADDRESS",      func_iaddress);
    makespecialfunc( "BAND",	      func_uand);
    makespecialfunc( "BIN",           func_bin);
    makespecialfunc( "BITNEXT",	      func_bitnext);
    makespecialfunc( "BITSIZE",	      func_bitsize);
    makespecialfunc( "BITSIZEOF",     func_bitsize);
mp_blockread_ucsd =
    makespecialfunc( "BLOCKREAD",     func_blockread);
mp_blockwrite_ucsd =
    makespecialfunc( "BLOCKWRITE",    func_blockwrite);
    makespecialfunc( "BNOT",	      func_unot);
    makespecialfunc( "BOR",	      func_uor);
    makespecialfunc( "BSL",	      func_bsl);
    makespecialfunc( "BSR",	      func_bsr);
    makespecialfunc( "BTST",	      func_btst);
    makespecialfunc( "BXOR",	      func_uxor);
    makespecialfunc( "BYTEREAD",      func_byteread);
    makespecialfunc( "BYTEWRITE",     func_bytewrite);
    makespecialfunc( "BYTE_OFFSET",   func_byte_offset);
    makespecialfunc( "CHR",           func_chr);         
    makespecialfunc( "CONCAT",        func_concat);
    makespecialfunc( "DBLE",          func_float);
mp_dec_dec =
    makespecialfunc( "DEC",           func_dec);
    makespecialfunc( "EOF",           func_eof);
    makespecialfunc( "EOLN",          func_eoln);
    makespecialfunc( "FCALL",         func_fcall);
    makespecialfunc( "FILEPOS",       func_filepos);
    makespecialfunc( "FILESIZE",      func_filesize);
    makespecialfunc( "FLOAT",	      func_float);
    makespecialfunc( "HEX",           func_hex);         
    makespecialfunc( "HI",            func_hi);
    makespecialfunc( "HIWORD",        func_hiword);
    makespecialfunc( "HIWRD",         func_hiword);
    makespecialfunc( "HIGH",          func_high);
    makespecialfunc( "IADDRESS",      func_iaddress);
    makespecialfunc( "INT",           func_int);         
    makespecialfunc( "LAND",	      func_uand);
    makespecialfunc( "LINT",	      func_lint);
    makespecialfunc( "LNOT",	      func_unot);
    makespecialfunc( "LO",            func_lo);
    makespecialfunc( "LOCATION",      func_addr);
    makespecialfunc( "LOOPHOLE",      func_loophole);
    makespecialfunc( "LOR",	      func_uor);
    makespecialfunc( "LOWER",	      func_lower);
    makespecialfunc( "LOWORD",        func_loword);
    makespecialfunc( "LOWRD",         func_loword);
    makespecialfunc( "LSL",	      func_lsl);
    makespecialfunc( "LSR",	      func_lsr);
    makespecialfunc( "MAX",	      func_max);
    makespecialfunc( "MAXPOS",        func_maxpos);
    makespecialfunc( "MIN",	      func_min);
mp_new_turbo =
    makespecialfunc( "NEW_TURBO",     func_new_turbo);
    makespecialfunc( "NEXT",          func_sizeof);
    makespecialfunc( "OCT",           func_oct);
    makespecialfunc( "OFS",           func_ofs);
    makespecialfunc( "ORD",           func_ord);
    makespecialfunc( "ORD4",          func_ord4);
    makespecialfunc( "PI",	      func_pi);
    makespecialfunc( "POSITION",      func_position);
    makespecialfunc( "PRED",          func_pred);
    makespecialfunc( "QUAD",          func_float);
    makespecialfunc( "RANDOM",        func_random);
    makespecialfunc( "REF",	      func_addr);
    makespecialfunc( "SCAN",	      func_scan);
    makespecialfunc( "SEEKEOF",       func_seekeof);
    makespecialfunc( "SEEKEOLN",      func_seekeoln);
    makespecialfunc( "SEG",           func_seg);
mp_self_func =
    makespecialfunc( "SELF",          func_self);
    makespecialfunc( "SIZE",          func_sizeof);
    makespecialfunc( "SIZEOF",        func_sizeof);
    makespecialfunc( "SNGL",          func_sngl);
    makespecialfunc( "SQR",           func_sqr);
    makespecialfunc( "STATUSV",	      func_statusv);
    makespecialfunc( "SUCC",          func_succ);
    makespecialfunc( "TSIZE",         func_sizeof);
    makespecialfunc( "TYPEOF",        func_typeof);
    makespecialfunc( "UAND",	      func_uand);
    makespecialfunc( "UB",            func_ub);
    makespecialfunc( "UDEC",          func_udec);
    makespecialfunc( "UINT",          func_uint);         
    makespecialfunc( "UNOT",	      func_unot);
    makespecialfunc( "UOR",	      func_uor);
    makespecialfunc( "UPPER",	      func_upper);
    makespecialfunc( "UXOR",	      func_uxor);
mp_val_modula =
    makespecialfunc( "VAL",	      func_val_modula);
    makespecialfunc( "WADDRESS",      func_iaddress);
    makespecialfunc( "XOR",	      func_xor);

    makestandardfunc("ARCTAN",        func_arctan);
    makestandardfunc("ARCTANH",       func_arctanh);
    makestandardfunc("BINARY",        func_binary);      
    makestandardfunc("CAP",           func_upcase);
    makestandardfunc("COPY",          func_copy);        
    makestandardfunc("COS",           func_cos);         
    makestandardfunc("COSH",          func_cosh);         
    makestandardfunc("EXP",           func_exp);         
    makestandardfunc("EXP10",         func_pwroften);
    makestandardfunc("EXPO",          func_expo);         
    makestandardfunc("FRAC",          func_frac);        
    makestandardfunc("INDEX",         func_strpos);      
    makestandardfunc("LASTPOS",       NULL);             
    makestandardfunc("LINEPOS",       NULL);             
    makestandardfunc("LENGTH",        func_strlen);      
    makestandardfunc("LN",            func_ln);          
    makestandardfunc("LOG",           func_log);
    makestandardfunc("LOG10",         func_log);
    makestandardfunc("LROUND",        func_round);       
    makestandardfunc("LTRUNC",        func_trunc);       
    makestandardfunc("MAXAVAIL",      func_maxavail);
    makestandardfunc("MEMAVAIL",      func_memavail);
    makestandardfunc("OCTAL",         func_octal);       
    makestandardfunc("ODD",           func_odd);         
    makestandardfunc("PAD",           func_pad);
    makestandardfunc("PARAMCOUNT",    func_paramcount);
    makestandardfunc("PARAMSTR",      func_paramstr);    
    makestandardfunc("POS",           func_pos);         
    makestandardfunc("PTR",           func_ptr);
    makestandardfunc("PWROFTEN",      func_pwroften);
    makestandardfunc("ROUND",         func_round);       
    makestandardfunc("SCANEQ",        func_scaneq);
    makestandardfunc("SCANNE",        func_scanne);
    makestandardfunc("SIN",           func_sin);         
    makestandardfunc("SINH",          func_sinh);         
    makestandardfunc("SQRT",          func_sqrt);        
mp_str_hp =
    makestandardfunc("STR",           func_str_hp);
    makestandardfunc("STRLEN",        func_strlen);      
    makestandardfunc("STRLTRIM",      func_strltrim);    
    makestandardfunc("STRMAX",        func_strmax);      
    makestandardfunc("STRPOS",        func_strpos);      
    makestandardfunc("STRRPT",        func_strrpt);      
    makestandardfunc("STRRTRIM",      func_strrtrim);    
    makestandardfunc("SUBSTR",        func_str_hp);
    makestandardfunc("SWAP",          func_swap);        
    makestandardfunc("TAN",           func_tan);       
    makestandardfunc("TANH",          func_tanh);       
    makestandardfunc("TRUNC",         func_trunc);       
    makestandardfunc("UPCASE",        func_upcase);      
    makestandardfunc("UROUND",        func_uround);
    makestandardfunc("UTRUNC",        func_utrunc);

    makespecialproc( "APPEND",        proc_append);
    makespecialproc( "ARGV",	      proc_argv);
    makespecialproc( "ASSERT",        proc_assert);
    makespecialproc( "ASSIGN",        proc_assign);
    makespecialproc( "BCLR",	      proc_bclr);
mp_blockread_turbo =
    makespecialproc( "BLOCKREAD_TURBO", proc_blockread);
mp_blockwrite_turbo =
    makespecialproc( "BLOCKWRITE_TURBO", proc_blockwrite);
    makespecialproc( "BREAK",         proc_flush);
    makespecialproc( "BSET",	      proc_bset);
    makespecialproc( "CALL",          proc_call);
    makespecialproc( "CLOSE",         proc_close);
    makespecialproc( "CONNECT",       proc_assign);
    makespecialproc( "CYCLE",	      proc_cycle);
    makespecialproc( "DATE",	      proc_date);
mp_dec_turbo =
    makespecialproc( "DEC_TURBO",     proc_dec);
    makespecialproc( "DISPOSE",       proc_dispose);
    makespecialproc( "ESCAPE",        proc_escape);
    makespecialproc( "EXCL",          proc_excl);
    makespecialproc( "EXIT",          proc_exit);
    makespecialproc( "EXTEND",        proc_append);
    makespecialproc( "FILLCHAR",      proc_fillchar);
    makespecialproc( "FLUSH",         proc_flush);
    makespecialproc( "GET",           proc_get);
    makespecialproc( "HALT",          proc_halt);
    makespecialproc( "INC",           proc_inc);
    makespecialproc( "INCL",          proc_incl);
    makespecialproc( "LEAVE",	      proc_leave);
    makespecialproc( "LOCATE",        proc_seek);
    makespecialproc( "MESSAGE",       proc_message);
    makespecialproc( "MOVE_FAST",     proc_move_fast);        
    makespecialproc( "MOVE_L_TO_R",   proc_move_fast);        
    makespecialproc( "MOVE_R_TO_L",   proc_move_fast);        
mp_new_normal =
    makespecialproc( "NEW",           proc_new);
    if (which_lang != LANG_VAX)
	makespecialproc( "OPEN",      proc_open);
    makespecialproc( "OVERPRINT",     proc_overprint);
    makespecialproc( "PACK",          proc_pack);
    makespecialproc( "PAGE",          proc_page);
    makespecialproc( "PUT",           proc_put);
    makespecialproc( "PROMPT",        proc_prompt);
    makespecialproc( "RANDOMIZE",     proc_randomize);
    makespecialproc( "READ",          proc_read);
    makespecialproc( "READDIR",       proc_readdir);
    makespecialproc( "READLN",        proc_readln);
    makespecialproc( "READV",         proc_readv);
    makespecialproc( "RESET",         proc_reset);
    makespecialproc( "REWRITE",       proc_rewrite);
    makespecialproc( "SEEK",          proc_seek);
    makespecialproc( "SETNAME",       proc_assign);
    makespecialproc( "SETSTRLEN",     proc_setstrlen);
    makespecialproc( "SETTEXTBUF",    proc_settextbuf);
mp_str_turbo =
    makespecialproc( "STR_TURBO",     proc_str_turbo);
    makespecialproc( "STRAPPEND",     proc_strappend);
    makespecialproc( "STRDELETE",     proc_strdelete);
    makespecialproc( "STRINSERT",     proc_strinsert);
    makespecialproc( "STRMOVE",       proc_strmove);
    makespecialproc( "STRREAD",       proc_strread);
    makespecialproc( "STRWRITE",      proc_strwrite);
    makespecialproc( "TIME",	      proc_time);
    makespecialproc( "UNPACK",        proc_unpack);
    makespecialproc( "WRITE",         proc_write);
    makespecialproc( "WRITEDIR",      proc_writedir);
    makespecialproc( "WRITELN",       proc_writeln);
    makespecialproc( "WRITEV",        proc_writev);
mp_val_turbo =
    makespecialproc( "VAL_TURBO",     proc_val_turbo);

    if (which_lang != LANG_VAX)
	makestandardproc("DELETE",        proc_delete);      
    makestandardproc("FREEMEM",       proc_freemem);     
    makestandardproc("GETMEM",        proc_getmem);
    makestandardproc("GOTOXY",        proc_gotoxy);      
    makestandardproc("INSERT",        proc_insert);      
    makestandardproc("MARK",          NULL);             
    makestandardproc("MOVE",          proc_move);        
    makestandardproc("MOVELEFT",      proc_move);        
    makestandardproc("MOVERIGHT",     proc_move);        
    makestandardproc("RELEASE",       NULL);             

    makespecialvar(  "MEM",           var_mem);
    makespecialvar(  "MEMW",          var_memw);
    makespecialvar(  "MEML",          var_meml);
    makespecialvar(  "PORT",          var_port);
    makespecialvar(  "PORTW",         var_portw);

    /* Modula-2 standard I/O procedures (case-sensitive!) */
    makespecialproc( "Read",          proc_read);
    makespecialproc( "ReadCard",      proc_read);
    makespecialproc( "ReadInt",       proc_read);
    makespecialproc( "ReadReal",      proc_read);
    makespecialproc( "ReadString",    proc_read);
    makespecialproc( "Write",         proc_write);
    makespecialproc( "WriteCard",     proc_writecard);
    makespecialproc( "WriteHex",      proc_writehex);
    makespecialproc( "WriteInt",      proc_writeint);
    makespecialproc( "WriteOct",      proc_writeoct);
    makespecialproc( "WriteLn",       proc_writeln);
    makespecialproc( "WriteReal",     proc_writereal);
    makespecialproc( "WriteString",   proc_write);
}




/* End. */



