BSD 4_3 release
[unix-history] / usr / src / ucb / pascal / src / func.c
/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef lint
static char sccsid[] = "@(#)func.c 5.1 (Berkeley) 6/5/85";
#endif not lint
#include "whoami.h"
#ifdef OBJ
/*
* the rest of the file
*/
#include "0.h"
#include "tree.h"
#include "opcode.h"
#include "tree_ty.h"
/*
* Funccod generates code for
* built in function calls and calls
* call to generate calls to user
* defined functions and procedures.
*/
struct nl
*funccod(r)
struct tnode *r;
{
struct nl *p;
register struct nl *p1;
struct nl *tempnlp;
register struct tnode *al;
register op;
int argc;
struct tnode *argv, tr, tr2;
/*
* Verify that the given name
* is defined and the name of
* a function.
*/
p = lookup(r->pcall_node.proc_id);
if (p == NLNIL) {
rvlist(r->pcall_node.arg);
return (NLNIL);
}
if (p->class != FUNC && p->class != FFUNC) {
error("%s is not a function", p->symbol);
rvlist(r->pcall_node.arg);
return (NLNIL);
}
argv = r->pcall_node.arg;
/*
* Call handles user defined
* procedures and functions
*/
if (bn != 0)
return (call(p, argv, FUNC, bn));
/*
* Count the arguments
*/
argc = 0;
for (al = argv; al != TR_NIL; al = al->list_node.next)
argc++;
/*
* Built-in functions have
* their interpreter opcode
* associated with them.
*/
op = p->value[0] &~ NSTAND;
if (opt('s') && (p->value[0] & NSTAND)) {
standard();
error("%s is a nonstandard function", p->symbol);
}
switch (op) {
/*
* Parameterless functions
*/
case O_CLCK:
case O_SCLCK:
case O_WCLCK:
case O_ARGC:
if (argc != 0) {
error("%s takes no arguments", p->symbol);
rvlist(argv);
return (NLNIL);
}
(void) put(1, op);
return (nl+T4INT);
case O_EOF:
case O_EOLN:
if (argc == 0) {
argv = (&tr);
tr.list_node.list = (&tr2);
tr2.tag = T_VAR;
tr2.var_node.cptr = input->symbol;
tr2.var_node.line_no = NIL;
tr2.var_node.qual = TR_NIL;
argc = 1;
} else if (argc != 1) {
error("%s takes either zero or one argument", p->symbol);
rvlist(argv);
return (NLNIL);
}
}
/*
* All other functions take
* exactly one argument.
*/
if (argc != 1) {
error("%s takes exactly one argument", p->symbol);
rvlist(argv);
return (NLNIL);
}
/*
* Evaluate the argmument
*/
if (op == O_EOF || op == O_EOLN)
p1 = stklval(argv->list_node.list, NIL );
else
p1 = stkrval(argv->list_node.list, NLNIL , (long) RREQ );
if (p1 == NLNIL)
return (NLNIL);
switch (op) {
case 0:
error("%s is an unimplemented 6000-3.4 extension", p->symbol);
default:
panic("func1");
case O_EXP:
case O_SIN:
case O_COS:
case O_ATAN:
case O_LN:
case O_SQRT:
case O_RANDOM:
case O_EXPO:
case O_UNDEF:
if (isa(p1, "i"))
convert( nl+T4INT , nl+TDOUBLE);
else if (isnta(p1, "d")) {
error("%s's argument must be integer or real, not %s", p->symbol, nameof(p1));
return (NLNIL);
}
(void) put(1, op);
if (op == O_UNDEF)
return (nl+TBOOL);
else if (op == O_EXPO)
return (nl+T4INT);
else
return (nl+TDOUBLE);
case O_SEED:
if (isnta(p1, "i")) {
error("seed's argument must be an integer, not %s", nameof(p1));
return (NLNIL);
}
(void) put(1, op);
return (nl+T4INT);
case O_ROUND:
case O_TRUNC:
if (isnta(p1, "d")) {
error("%s's argument must be a real, not %s", p->symbol, nameof(p1));
return (NLNIL);
}
(void) put(1, op);
return (nl+T4INT);
case O_ABS2:
case O_SQR2:
if (isa(p1, "d")) {
(void) put(1, op + O_ABS8-O_ABS2);
return (nl+TDOUBLE);
}
if (isa(p1, "i")) {
(void) put(1, op + (width(p1) >> 2));
return (nl+T4INT);
}
error("%s's argument must be an integer or real, not %s", p->symbol, nameof(p1));
return (NLNIL);
case O_ORD2:
if (isa(p1, "bcis")) {
return (nl+T4INT);
}
if (classify(p1) == TPTR) {
if (!opt('s')) {
return (nl+T4INT);
}
standard();
}
error("ord's argument must be of scalar type, not %s",
nameof(p1));
return (NLNIL);
case O_SUCC2:
case O_PRED2:
if (isa(p1, "d")) {
error("%s is forbidden for reals", p->symbol);
return (NLNIL);
}
if ( isnta( p1 , "bcsi" ) ) {
error("%s's argument must be of scalar type, not %s", p->symbol, nameof(p1));
return NIL;
}
tempnlp = p1 -> class == TYPE ? p1 -> type : p1;
if (isa(p1, "i")) {
if (width(p1) <= 2) {
op += O_PRED24 - O_PRED2;
(void) put(3, op, (int)tempnlp->range[0],
(int)tempnlp->range[1]);
} else {
op++;
(void) put(3, op, tempnlp->range[0],
tempnlp->range[1]);
}
return nl + T4INT;
} else {
(void) put(3, op, (int)tempnlp->range[0],
(int)tempnlp->range[1]);
return p1;
}
case O_ODD2:
if (isnta(p1, "i")) {
error("odd's argument must be an integer, not %s", nameof(p1));
return (NLNIL);
}
(void) put(1, op + (width(p1) >> 2));
return (nl+TBOOL);
case O_CHR2:
if (isnta(p1, "i")) {
error("chr's argument must be an integer, not %s", nameof(p1));
return (NLNIL);
}
(void) put(1, op + (width(p1) >> 2));
return (nl+TCHAR);
case O_CARD:
if (isnta(p1, "t")) {
error("Argument to card must be a set, not %s", nameof(p1));
return (NLNIL);
}
(void) put(2, O_CARD, width(p1));
return (nl+T2INT);
case O_EOLN:
if (!text(p1)) {
error("Argument to eoln must be a text file, not %s", nameof(p1));
return (NLNIL);
}
(void) put(1, op);
return (nl+TBOOL);
case O_EOF:
if (p1->class != FILET) {
error("Argument to eof must be file, not %s", nameof(p1));
return (NLNIL);
}
(void) put(1, op);
return (nl+TBOOL);
}
}
#endif OBJ