xref: /csrg-svn/usr.bin/pascal/src/pcfunc.c (revision 764)
1*764Speter /* Copyright (c) 1979 Regents of the University of California */
2*764Speter 
3*764Speter static	char sccsid[] = "@(#)pcfunc.c 1.1 08/27/80";
4*764Speter 
5*764Speter #include "whoami.h"
6*764Speter #ifdef PC
7*764Speter     /*
8*764Speter      *	and to the end of the file
9*764Speter      */
10*764Speter #include "0.h"
11*764Speter #include "tree.h"
12*764Speter #include "opcode.h"
13*764Speter #include	"pc.h"
14*764Speter #include	"pcops.h"
15*764Speter 
16*764Speter bool cardempty = FALSE;
17*764Speter 
18*764Speter /*
19*764Speter  * Funccod generates code for
20*764Speter  * built in function calls and calls
21*764Speter  * call to generate calls to user
22*764Speter  * defined functions and procedures.
23*764Speter  */
24*764Speter pcfunccod( r )
25*764Speter 	int	 *r;
26*764Speter {
27*764Speter 	struct nl *p;
28*764Speter 	register struct nl *p1;
29*764Speter 	register int *al;
30*764Speter 	register op;
31*764Speter 	int argc, *argv;
32*764Speter 	int tr[2], tr2[4];
33*764Speter 	char		*funcname;
34*764Speter 	long		tempoff;
35*764Speter 	long		temptype;
36*764Speter 	struct nl	*rettype;
37*764Speter 
38*764Speter 	/*
39*764Speter 	 * Verify that the given name
40*764Speter 	 * is defined and the name of
41*764Speter 	 * a function.
42*764Speter 	 */
43*764Speter 	p = lookup(r[2]);
44*764Speter 	if (p == NIL) {
45*764Speter 		rvlist(r[3]);
46*764Speter 		return (NIL);
47*764Speter 	}
48*764Speter 	if (p->class != FUNC) {
49*764Speter 		error("%s is not a function", p->symbol);
50*764Speter 		rvlist(r[3]);
51*764Speter 		return (NIL);
52*764Speter 	}
53*764Speter 	argv = r[3];
54*764Speter 	/*
55*764Speter 	 * Call handles user defined
56*764Speter 	 * procedures and functions
57*764Speter 	 */
58*764Speter 	if (bn != 0)
59*764Speter 		return (call(p, argv, FUNC, bn));
60*764Speter 	/*
61*764Speter 	 * Count the arguments
62*764Speter 	 */
63*764Speter 	argc = 0;
64*764Speter 	for (al = argv; al != NIL; al = al[2])
65*764Speter 		argc++;
66*764Speter 	/*
67*764Speter 	 * Built-in functions have
68*764Speter 	 * their interpreter opcode
69*764Speter 	 * associated with them.
70*764Speter 	 */
71*764Speter 	op = p->value[0] &~ NSTAND;
72*764Speter 	if (opt('s') && (p->value[0] & NSTAND)) {
73*764Speter 		standard();
74*764Speter 		error("%s is a nonstandard function", p->symbol);
75*764Speter 	}
76*764Speter 	if ( op == O_ARGC ) {
77*764Speter 	    putleaf( P2NAME , 0 , 0 , P2INT , "__argc" );
78*764Speter 	    return nl + T4INT;
79*764Speter 	}
80*764Speter 	switch (op) {
81*764Speter 		/*
82*764Speter 		 * Parameterless functions
83*764Speter 		 */
84*764Speter 		case O_CLCK:
85*764Speter 			funcname = "_CLCK";
86*764Speter 			goto noargs;
87*764Speter 		case O_SCLCK:
88*764Speter 			funcname = "_SCLCK";
89*764Speter 			goto noargs;
90*764Speter noargs:
91*764Speter 			if (argc != 0) {
92*764Speter 				error("%s takes no arguments", p->symbol);
93*764Speter 				rvlist(argv);
94*764Speter 				return (NIL);
95*764Speter 			}
96*764Speter 			putleaf( P2ICON , 0 , 0
97*764Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
98*764Speter 				, funcname );
99*764Speter 			putop( P2UNARY P2CALL , P2INT );
100*764Speter 			return (nl+T4INT);
101*764Speter 		case O_WCLCK:
102*764Speter 			if (argc != 0) {
103*764Speter 				error("%s takes no arguments", p->symbol);
104*764Speter 				rvlist(argv);
105*764Speter 				return (NIL);
106*764Speter 			}
107*764Speter 			putleaf( P2ICON , 0 , 0
108*764Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
109*764Speter 				, "_time" );
110*764Speter 			putleaf( P2ICON , 0 , 0 , P2INT , 0 );
111*764Speter 			putop( P2CALL , P2INT );
112*764Speter 			return (nl+T4INT);
113*764Speter 		case O_EOF:
114*764Speter 		case O_EOLN:
115*764Speter 			if (argc == 0) {
116*764Speter 				argv = tr;
117*764Speter 				tr[1] = tr2;
118*764Speter 				tr2[0] = T_VAR;
119*764Speter 				tr2[2] = input->symbol;
120*764Speter 				tr2[1] = tr2[3] = NIL;
121*764Speter 				argc = 1;
122*764Speter 			} else if (argc != 1) {
123*764Speter 				error("%s takes either zero or one argument", p->symbol);
124*764Speter 				rvlist(argv);
125*764Speter 				return (NIL);
126*764Speter 			}
127*764Speter 		}
128*764Speter 	/*
129*764Speter 	 * All other functions take
130*764Speter 	 * exactly one argument.
131*764Speter 	 */
132*764Speter 	if (argc != 1) {
133*764Speter 		error("%s takes exactly one argument", p->symbol);
134*764Speter 		rvlist(argv);
135*764Speter 		return (NIL);
136*764Speter 	}
137*764Speter 	/*
138*764Speter 	 * find out the type of the argument
139*764Speter 	 */
140*764Speter 	codeoff();
141*764Speter 	p1 = stkrval((int *) argv[1], NLNIL , RREQ );
142*764Speter 	codeon();
143*764Speter 	if (p1 == NIL)
144*764Speter 		return (NIL);
145*764Speter 	/*
146*764Speter 	 * figure out the return type and the funtion name
147*764Speter 	 */
148*764Speter 	switch (op) {
149*764Speter 	    case O_EXP:
150*764Speter 		    funcname = "_exp";
151*764Speter 		    goto mathfunc;
152*764Speter 	    case O_SIN:
153*764Speter 		    funcname = "_sin";
154*764Speter 		    goto mathfunc;
155*764Speter 	    case O_COS:
156*764Speter 		    funcname = "_cos";
157*764Speter 		    goto mathfunc;
158*764Speter 	    case O_ATAN:
159*764Speter 		    funcname = "_atan";
160*764Speter 		    goto mathfunc;
161*764Speter 	    case O_LN:
162*764Speter 		    funcname = opt('t') ? "_LN" : "_log";
163*764Speter 		    goto mathfunc;
164*764Speter 	    case O_SQRT:
165*764Speter 		    funcname = opt('t') ? "_SQRT" : "_sqrt";
166*764Speter 		    goto mathfunc;
167*764Speter 	    case O_RANDOM:
168*764Speter 		    funcname = "_RANDOM";
169*764Speter 		    goto mathfunc;
170*764Speter mathfunc:
171*764Speter 		    if (isnta(p1, "id")) {
172*764Speter 			    error("%s's argument must be integer or real, not %s", p->symbol, nameof(p1));
173*764Speter 			    return (NIL);
174*764Speter 		    }
175*764Speter 		    putleaf( P2ICON , 0 , 0
176*764Speter 			    , ADDTYPE( P2FTN | P2DOUBLE , P2PTR ) , funcname );
177*764Speter 		    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
178*764Speter 		    if ( isa( p1 , "i" ) ) {
179*764Speter 			putop( P2SCONV , P2DOUBLE );
180*764Speter 		    }
181*764Speter 		    putop( P2CALL , P2DOUBLE );
182*764Speter 		    return nl + TDOUBLE;
183*764Speter 	    case O_EXPO:
184*764Speter 		    if (isnta( p1 , "id" ) ) {
185*764Speter 			    error("%s's argument must be integer or real, not %s", p->symbol, nameof(p1));
186*764Speter 			    return NIL;
187*764Speter 		    }
188*764Speter 		    putleaf( P2ICON , 0 , 0
189*764Speter 			    , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_EXPO" );
190*764Speter 		    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
191*764Speter 		    if ( isa( p1 , "i" ) ) {
192*764Speter 			putop( P2SCONV , P2DOUBLE );
193*764Speter 		    }
194*764Speter 		    putop( P2CALL , P2INT );
195*764Speter 		    return ( nl + T4INT );
196*764Speter 	    case O_UNDEF:
197*764Speter 		    if ( isnta( p1 , "id" ) ) {
198*764Speter 			    error("%s's argument must be integer or real, not %s", p->symbol, nameof(p1));
199*764Speter 			    return NIL;
200*764Speter 		    }
201*764Speter 		    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
202*764Speter 		    putleaf( P2ICON , 0 , 0 , P2INT , 0 );
203*764Speter 		    putop( P2COMOP , P2INT );
204*764Speter 		    return ( nl + TBOOL );
205*764Speter 	    case O_SEED:
206*764Speter 		    if (isnta(p1, "i")) {
207*764Speter 			    error("seed's argument must be an integer, not %s", nameof(p1));
208*764Speter 			    return (NIL);
209*764Speter 		    }
210*764Speter 		    putleaf( P2ICON , 0 , 0
211*764Speter 			    , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_SEED" );
212*764Speter 		    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
213*764Speter 		    putop( P2CALL , P2INT );
214*764Speter 		    return nl + T4INT;
215*764Speter 	    case O_ROUND:
216*764Speter 	    case O_TRUNC:
217*764Speter 		    if ( isnta( p1 , "d" ) ) {
218*764Speter 			    error("%s's argument must be a real, not %s", p->symbol, nameof(p1));
219*764Speter 			    return (NIL);
220*764Speter 		    }
221*764Speter 		    putleaf( P2ICON , 0 , 0
222*764Speter 			    , ADDTYPE( P2FTN | P2INT , P2PTR )
223*764Speter 			    , op == O_ROUND ? "_ROUND" : "_TRUNC" );
224*764Speter 		    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
225*764Speter 		    putop( P2CALL , P2INT );
226*764Speter 		    return nl + T4INT;
227*764Speter 	    case O_ABS2:
228*764Speter 			if ( isa( p1 , "d" ) ) {
229*764Speter 			    putleaf( P2ICON , 0 , 0
230*764Speter 				, ADDTYPE( P2FTN | P2DOUBLE , P2PTR )
231*764Speter 				, "_fabs" );
232*764Speter 			    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
233*764Speter 			    putop( P2CALL , P2DOUBLE );
234*764Speter 			    return nl + TDOUBLE;
235*764Speter 			}
236*764Speter 			if ( isa( p1 , "i" ) ) {
237*764Speter 			    putleaf( P2ICON , 0 , 0
238*764Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR ) , "_abs" );
239*764Speter 			    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
240*764Speter 			    putop( P2CALL , P2INT );
241*764Speter 			    return nl + T4INT;
242*764Speter 			}
243*764Speter 			error("%s's argument must be an integer or real, not %s", p->symbol, nameof(p1));
244*764Speter 			return NIL;
245*764Speter 	    case O_SQR2:
246*764Speter 			if ( isa( p1 , "d" ) ) {
247*764Speter 			    temptype = P2DOUBLE;
248*764Speter 			    rettype = nl + TDOUBLE;
249*764Speter 			    sizes[ cbn ].om_off -= sizeof( double );
250*764Speter 			} else if ( isa( p1 , "i" ) ) {
251*764Speter 			    temptype = P2INT;
252*764Speter 			    rettype = nl + T4INT;
253*764Speter 			    sizes[ cbn ].om_off -= sizeof( long );
254*764Speter 			} else {
255*764Speter 			    error("%s's argument must be an integer or real, not %s", p->symbol, nameof(p1));
256*764Speter 			    return NIL;
257*764Speter 			}
258*764Speter 			tempoff = sizes[ cbn ].om_off;
259*764Speter 			if ( tempoff < sizes[ cbn ].om_max ) {
260*764Speter 			    sizes[ cbn ].om_max = tempoff;
261*764Speter 			}
262*764Speter 			putlbracket( ftnno , -tempoff );
263*764Speter 			putRV( 0 , cbn , tempoff , temptype , 0 );
264*764Speter 			p1 = rvalue( (int *) argv[1] , NLNIL , RREQ );
265*764Speter 			putop( P2ASSIGN , temptype );
266*764Speter 			putRV( 0 , cbn , tempoff , temptype , 0 );
267*764Speter 			putRV( 0 , cbn , tempoff , temptype , 0 );
268*764Speter 			putop( P2MUL , temptype );
269*764Speter 			putop( P2COMOP , temptype );
270*764Speter 			return rettype;
271*764Speter 	    case O_ORD2:
272*764Speter 			p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
273*764Speter 			if (isa(p1, "bcis") || classify(p1) == TPTR) {
274*764Speter 				return (nl+T4INT);
275*764Speter 			}
276*764Speter 			error("ord's argument must be of scalar type or a pointer, not %s", nameof(p1));
277*764Speter 			return (NIL);
278*764Speter 	    case O_SUCC2:
279*764Speter 	    case O_PRED2:
280*764Speter 			if (isa(p1, "d")) {
281*764Speter 				error("%s is forbidden for reals", p->symbol);
282*764Speter 				return (NIL);
283*764Speter 			}
284*764Speter 			if ( isnta( p1 , "bcsi" ) ) {
285*764Speter 			    error("%s's argument must be of scalar type, not %s", p->symbol, nameof(p1));
286*764Speter 			    return NIL;
287*764Speter 			}
288*764Speter 			if ( opt( 't' ) ) {
289*764Speter 			    putleaf( P2ICON , 0 , 0
290*764Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
291*764Speter 				    , op == O_SUCC2 ? "_SUCC" : "_PRED" );
292*764Speter 			    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
293*764Speter 			    putleaf( P2ICON , p1 -> range[0] , 0 , P2INT , 0 );
294*764Speter 			    putop( P2LISTOP , P2INT );
295*764Speter 			    putleaf( P2ICON , p1 -> range[1] , 0 , P2INT , 0 );
296*764Speter 			    putop( P2LISTOP , P2INT );
297*764Speter 			    putop( P2CALL , P2INT );
298*764Speter 			} else {
299*764Speter 			    p1 = rvalue( argv[1] , NIL , RREQ );
300*764Speter 			    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
301*764Speter 			    putop( op == O_SUCC2 ? P2PLUS : P2MINUS , P2INT );
302*764Speter 			}
303*764Speter 			if ( isa( p1 , "bcs" ) ) {
304*764Speter 			    return p1;
305*764Speter 			} else {
306*764Speter 			    return nl + T4INT;
307*764Speter 			}
308*764Speter 	    case O_ODD2:
309*764Speter 			if (isnta(p1, "i")) {
310*764Speter 				error("odd's argument must be an integer, not %s", nameof(p1));
311*764Speter 				return (NIL);
312*764Speter 			}
313*764Speter 			p1 = rvalue( (int *) argv[1] , NLNIL , RREQ );
314*764Speter 			putleaf( P2ICON , 1 , 0 , P2INT , 0 );
315*764Speter 			putop( P2AND , P2INT );
316*764Speter 			return nl + TBOOL;
317*764Speter 	    case O_CHR2:
318*764Speter 			if (isnta(p1, "i")) {
319*764Speter 				error("chr's argument must be an integer, not %s", nameof(p1));
320*764Speter 				return (NIL);
321*764Speter 			}
322*764Speter 			if (opt('t')) {
323*764Speter 			    putleaf( P2ICON , 0 , 0
324*764Speter 				, ADDTYPE( P2FTN | P2CHAR , P2PTR ) , "_CHR" );
325*764Speter 			    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
326*764Speter 			    putop( P2CALL , P2CHAR );
327*764Speter 			} else {
328*764Speter 			    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
329*764Speter 			}
330*764Speter 			return nl + TCHAR;
331*764Speter 	    case O_CARD:
332*764Speter 			if ( p1 != nl + TSET ) {
333*764Speter 			    if (isnta(p1, "t")) {
334*764Speter 				error("Argument to card must be a set, not %s", nameof(p1));
335*764Speter 				return (NIL);
336*764Speter 			    }
337*764Speter 			    putleaf( P2ICON , 0 , 0
338*764Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR ) , "_CARD" );
339*764Speter 			    p1 = stkrval( (int *) argv[1] , NLNIL , LREQ );
340*764Speter 			    putleaf( P2ICON , lwidth( p1 ) , 0 , P2INT , 0 );
341*764Speter 			    putop( P2LISTOP , P2INT );
342*764Speter 			    putop( P2CALL , P2INT );
343*764Speter 			} else {
344*764Speter 			    if ( !cardempty ) {
345*764Speter 				warning();
346*764Speter 				error("Cardinality of the empty set is 0." );
347*764Speter 				cardempty = TRUE;
348*764Speter 			    }
349*764Speter 			    putleaf( P2ICON , 0 , 0 , P2INT , 0 );
350*764Speter 			}
351*764Speter 			return nl + T2INT;
352*764Speter 	    case O_EOLN:
353*764Speter 			if (!text(p1)) {
354*764Speter 				error("Argument to eoln must be a text file, not %s", nameof(p1));
355*764Speter 				return (NIL);
356*764Speter 			}
357*764Speter 			putleaf( P2ICON , 0 , 0
358*764Speter 			    , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_TEOLN" );
359*764Speter 			p1 = stklval( (int *) argv[1] , NOFLAGS );
360*764Speter 			putop( P2CALL , P2INT );
361*764Speter 			return nl + TBOOL;
362*764Speter 	    case O_EOF:
363*764Speter 			if (p1->class != FILET) {
364*764Speter 				error("Argument to eof must be file, not %s", nameof(p1));
365*764Speter 				return (NIL);
366*764Speter 			}
367*764Speter 			putleaf( P2ICON , 0 , 0
368*764Speter 			    , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_TEOF" );
369*764Speter 			p1 = stklval( (int *) argv[1] , NOFLAGS );
370*764Speter 			putop( P2CALL , P2INT );
371*764Speter 			return nl + TBOOL;
372*764Speter 	    case 0:
373*764Speter 			error("%s is an unimplemented 6000-3.4 extension", p->symbol);
374*764Speter 	    default:
375*764Speter 			panic("func1");
376*764Speter 	}
377*764Speter }
378*764Speter #endif PC
379