xref: /csrg-svn/usr.bin/pascal/src/pcfunc.c (revision 1197)
1764Speter /* Copyright (c) 1979 Regents of the University of California */
2764Speter 
3*1197Speter static	char sccsid[] = "@(#)pcfunc.c 1.2 10/03/80";
4764Speter 
5764Speter #include "whoami.h"
6764Speter #ifdef PC
7764Speter     /*
8764Speter      *	and to the end of the file
9764Speter      */
10764Speter #include "0.h"
11764Speter #include "tree.h"
12764Speter #include "opcode.h"
13764Speter #include	"pc.h"
14764Speter #include	"pcops.h"
15764Speter 
16764Speter bool cardempty = FALSE;
17764Speter 
18764Speter /*
19764Speter  * Funccod generates code for
20764Speter  * built in function calls and calls
21764Speter  * call to generate calls to user
22764Speter  * defined functions and procedures.
23764Speter  */
24764Speter pcfunccod( r )
25764Speter 	int	 *r;
26764Speter {
27764Speter 	struct nl *p;
28764Speter 	register struct nl *p1;
29764Speter 	register int *al;
30764Speter 	register op;
31764Speter 	int argc, *argv;
32764Speter 	int tr[2], tr2[4];
33764Speter 	char		*funcname;
34764Speter 	long		tempoff;
35764Speter 	long		temptype;
36764Speter 	struct nl	*rettype;
37764Speter 
38764Speter 	/*
39764Speter 	 * Verify that the given name
40764Speter 	 * is defined and the name of
41764Speter 	 * a function.
42764Speter 	 */
43764Speter 	p = lookup(r[2]);
44764Speter 	if (p == NIL) {
45764Speter 		rvlist(r[3]);
46764Speter 		return (NIL);
47764Speter 	}
48*1197Speter 	if (p->class != FUNC && p->class != FFUNC) {
49764Speter 		error("%s is not a function", p->symbol);
50764Speter 		rvlist(r[3]);
51764Speter 		return (NIL);
52764Speter 	}
53764Speter 	argv = r[3];
54764Speter 	/*
55764Speter 	 * Call handles user defined
56764Speter 	 * procedures and functions
57764Speter 	 */
58764Speter 	if (bn != 0)
59764Speter 		return (call(p, argv, FUNC, bn));
60764Speter 	/*
61764Speter 	 * Count the arguments
62764Speter 	 */
63764Speter 	argc = 0;
64764Speter 	for (al = argv; al != NIL; al = al[2])
65764Speter 		argc++;
66764Speter 	/*
67764Speter 	 * Built-in functions have
68764Speter 	 * their interpreter opcode
69764Speter 	 * associated with them.
70764Speter 	 */
71764Speter 	op = p->value[0] &~ NSTAND;
72764Speter 	if (opt('s') && (p->value[0] & NSTAND)) {
73764Speter 		standard();
74764Speter 		error("%s is a nonstandard function", p->symbol);
75764Speter 	}
76764Speter 	if ( op == O_ARGC ) {
77764Speter 	    putleaf( P2NAME , 0 , 0 , P2INT , "__argc" );
78764Speter 	    return nl + T4INT;
79764Speter 	}
80764Speter 	switch (op) {
81764Speter 		/*
82764Speter 		 * Parameterless functions
83764Speter 		 */
84764Speter 		case O_CLCK:
85764Speter 			funcname = "_CLCK";
86764Speter 			goto noargs;
87764Speter 		case O_SCLCK:
88764Speter 			funcname = "_SCLCK";
89764Speter 			goto noargs;
90764Speter noargs:
91764Speter 			if (argc != 0) {
92764Speter 				error("%s takes no arguments", p->symbol);
93764Speter 				rvlist(argv);
94764Speter 				return (NIL);
95764Speter 			}
96764Speter 			putleaf( P2ICON , 0 , 0
97764Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
98764Speter 				, funcname );
99764Speter 			putop( P2UNARY P2CALL , P2INT );
100764Speter 			return (nl+T4INT);
101764Speter 		case O_WCLCK:
102764Speter 			if (argc != 0) {
103764Speter 				error("%s takes no arguments", p->symbol);
104764Speter 				rvlist(argv);
105764Speter 				return (NIL);
106764Speter 			}
107764Speter 			putleaf( P2ICON , 0 , 0
108764Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
109764Speter 				, "_time" );
110764Speter 			putleaf( P2ICON , 0 , 0 , P2INT , 0 );
111764Speter 			putop( P2CALL , P2INT );
112764Speter 			return (nl+T4INT);
113764Speter 		case O_EOF:
114764Speter 		case O_EOLN:
115764Speter 			if (argc == 0) {
116764Speter 				argv = tr;
117764Speter 				tr[1] = tr2;
118764Speter 				tr2[0] = T_VAR;
119764Speter 				tr2[2] = input->symbol;
120764Speter 				tr2[1] = tr2[3] = NIL;
121764Speter 				argc = 1;
122764Speter 			} else if (argc != 1) {
123764Speter 				error("%s takes either zero or one argument", p->symbol);
124764Speter 				rvlist(argv);
125764Speter 				return (NIL);
126764Speter 			}
127764Speter 		}
128764Speter 	/*
129764Speter 	 * All other functions take
130764Speter 	 * exactly one argument.
131764Speter 	 */
132764Speter 	if (argc != 1) {
133764Speter 		error("%s takes exactly one argument", p->symbol);
134764Speter 		rvlist(argv);
135764Speter 		return (NIL);
136764Speter 	}
137764Speter 	/*
138764Speter 	 * find out the type of the argument
139764Speter 	 */
140764Speter 	codeoff();
141764Speter 	p1 = stkrval((int *) argv[1], NLNIL , RREQ );
142764Speter 	codeon();
143764Speter 	if (p1 == NIL)
144764Speter 		return (NIL);
145764Speter 	/*
146764Speter 	 * figure out the return type and the funtion name
147764Speter 	 */
148764Speter 	switch (op) {
149764Speter 	    case O_EXP:
150764Speter 		    funcname = "_exp";
151764Speter 		    goto mathfunc;
152764Speter 	    case O_SIN:
153764Speter 		    funcname = "_sin";
154764Speter 		    goto mathfunc;
155764Speter 	    case O_COS:
156764Speter 		    funcname = "_cos";
157764Speter 		    goto mathfunc;
158764Speter 	    case O_ATAN:
159764Speter 		    funcname = "_atan";
160764Speter 		    goto mathfunc;
161764Speter 	    case O_LN:
162764Speter 		    funcname = opt('t') ? "_LN" : "_log";
163764Speter 		    goto mathfunc;
164764Speter 	    case O_SQRT:
165764Speter 		    funcname = opt('t') ? "_SQRT" : "_sqrt";
166764Speter 		    goto mathfunc;
167764Speter 	    case O_RANDOM:
168764Speter 		    funcname = "_RANDOM";
169764Speter 		    goto mathfunc;
170764Speter mathfunc:
171764Speter 		    if (isnta(p1, "id")) {
172764Speter 			    error("%s's argument must be integer or real, not %s", p->symbol, nameof(p1));
173764Speter 			    return (NIL);
174764Speter 		    }
175764Speter 		    putleaf( P2ICON , 0 , 0
176764Speter 			    , ADDTYPE( P2FTN | P2DOUBLE , P2PTR ) , funcname );
177764Speter 		    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
178764Speter 		    if ( isa( p1 , "i" ) ) {
179764Speter 			putop( P2SCONV , P2DOUBLE );
180764Speter 		    }
181764Speter 		    putop( P2CALL , P2DOUBLE );
182764Speter 		    return nl + TDOUBLE;
183764Speter 	    case O_EXPO:
184764Speter 		    if (isnta( p1 , "id" ) ) {
185764Speter 			    error("%s's argument must be integer or real, not %s", p->symbol, nameof(p1));
186764Speter 			    return NIL;
187764Speter 		    }
188764Speter 		    putleaf( P2ICON , 0 , 0
189764Speter 			    , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_EXPO" );
190764Speter 		    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
191764Speter 		    if ( isa( p1 , "i" ) ) {
192764Speter 			putop( P2SCONV , P2DOUBLE );
193764Speter 		    }
194764Speter 		    putop( P2CALL , P2INT );
195764Speter 		    return ( nl + T4INT );
196764Speter 	    case O_UNDEF:
197764Speter 		    if ( isnta( p1 , "id" ) ) {
198764Speter 			    error("%s's argument must be integer or real, not %s", p->symbol, nameof(p1));
199764Speter 			    return NIL;
200764Speter 		    }
201764Speter 		    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
202764Speter 		    putleaf( P2ICON , 0 , 0 , P2INT , 0 );
203764Speter 		    putop( P2COMOP , P2INT );
204764Speter 		    return ( nl + TBOOL );
205764Speter 	    case O_SEED:
206764Speter 		    if (isnta(p1, "i")) {
207764Speter 			    error("seed's argument must be an integer, not %s", nameof(p1));
208764Speter 			    return (NIL);
209764Speter 		    }
210764Speter 		    putleaf( P2ICON , 0 , 0
211764Speter 			    , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_SEED" );
212764Speter 		    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
213764Speter 		    putop( P2CALL , P2INT );
214764Speter 		    return nl + T4INT;
215764Speter 	    case O_ROUND:
216764Speter 	    case O_TRUNC:
217764Speter 		    if ( isnta( p1 , "d" ) ) {
218764Speter 			    error("%s's argument must be a real, not %s", p->symbol, nameof(p1));
219764Speter 			    return (NIL);
220764Speter 		    }
221764Speter 		    putleaf( P2ICON , 0 , 0
222764Speter 			    , ADDTYPE( P2FTN | P2INT , P2PTR )
223764Speter 			    , op == O_ROUND ? "_ROUND" : "_TRUNC" );
224764Speter 		    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
225764Speter 		    putop( P2CALL , P2INT );
226764Speter 		    return nl + T4INT;
227764Speter 	    case O_ABS2:
228764Speter 			if ( isa( p1 , "d" ) ) {
229764Speter 			    putleaf( P2ICON , 0 , 0
230764Speter 				, ADDTYPE( P2FTN | P2DOUBLE , P2PTR )
231764Speter 				, "_fabs" );
232764Speter 			    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
233764Speter 			    putop( P2CALL , P2DOUBLE );
234764Speter 			    return nl + TDOUBLE;
235764Speter 			}
236764Speter 			if ( isa( p1 , "i" ) ) {
237764Speter 			    putleaf( P2ICON , 0 , 0
238764Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR ) , "_abs" );
239764Speter 			    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
240764Speter 			    putop( P2CALL , P2INT );
241764Speter 			    return nl + T4INT;
242764Speter 			}
243764Speter 			error("%s's argument must be an integer or real, not %s", p->symbol, nameof(p1));
244764Speter 			return NIL;
245764Speter 	    case O_SQR2:
246764Speter 			if ( isa( p1 , "d" ) ) {
247764Speter 			    temptype = P2DOUBLE;
248764Speter 			    rettype = nl + TDOUBLE;
249764Speter 			    sizes[ cbn ].om_off -= sizeof( double );
250764Speter 			} else if ( isa( p1 , "i" ) ) {
251764Speter 			    temptype = P2INT;
252764Speter 			    rettype = nl + T4INT;
253764Speter 			    sizes[ cbn ].om_off -= sizeof( long );
254764Speter 			} else {
255764Speter 			    error("%s's argument must be an integer or real, not %s", p->symbol, nameof(p1));
256764Speter 			    return NIL;
257764Speter 			}
258764Speter 			tempoff = sizes[ cbn ].om_off;
259764Speter 			if ( tempoff < sizes[ cbn ].om_max ) {
260764Speter 			    sizes[ cbn ].om_max = tempoff;
261764Speter 			}
262764Speter 			putlbracket( ftnno , -tempoff );
263764Speter 			putRV( 0 , cbn , tempoff , temptype , 0 );
264764Speter 			p1 = rvalue( (int *) argv[1] , NLNIL , RREQ );
265764Speter 			putop( P2ASSIGN , temptype );
266764Speter 			putRV( 0 , cbn , tempoff , temptype , 0 );
267764Speter 			putRV( 0 , cbn , tempoff , temptype , 0 );
268764Speter 			putop( P2MUL , temptype );
269764Speter 			putop( P2COMOP , temptype );
270764Speter 			return rettype;
271764Speter 	    case O_ORD2:
272764Speter 			p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
273764Speter 			if (isa(p1, "bcis") || classify(p1) == TPTR) {
274764Speter 				return (nl+T4INT);
275764Speter 			}
276764Speter 			error("ord's argument must be of scalar type or a pointer, not %s", nameof(p1));
277764Speter 			return (NIL);
278764Speter 	    case O_SUCC2:
279764Speter 	    case O_PRED2:
280764Speter 			if (isa(p1, "d")) {
281764Speter 				error("%s is forbidden for reals", p->symbol);
282764Speter 				return (NIL);
283764Speter 			}
284764Speter 			if ( isnta( p1 , "bcsi" ) ) {
285764Speter 			    error("%s's argument must be of scalar type, not %s", p->symbol, nameof(p1));
286764Speter 			    return NIL;
287764Speter 			}
288764Speter 			if ( opt( 't' ) ) {
289764Speter 			    putleaf( P2ICON , 0 , 0
290764Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
291764Speter 				    , op == O_SUCC2 ? "_SUCC" : "_PRED" );
292764Speter 			    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
293764Speter 			    putleaf( P2ICON , p1 -> range[0] , 0 , P2INT , 0 );
294764Speter 			    putop( P2LISTOP , P2INT );
295764Speter 			    putleaf( P2ICON , p1 -> range[1] , 0 , P2INT , 0 );
296764Speter 			    putop( P2LISTOP , P2INT );
297764Speter 			    putop( P2CALL , P2INT );
298764Speter 			} else {
299764Speter 			    p1 = rvalue( argv[1] , NIL , RREQ );
300764Speter 			    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
301764Speter 			    putop( op == O_SUCC2 ? P2PLUS : P2MINUS , P2INT );
302764Speter 			}
303764Speter 			if ( isa( p1 , "bcs" ) ) {
304764Speter 			    return p1;
305764Speter 			} else {
306764Speter 			    return nl + T4INT;
307764Speter 			}
308764Speter 	    case O_ODD2:
309764Speter 			if (isnta(p1, "i")) {
310764Speter 				error("odd's argument must be an integer, not %s", nameof(p1));
311764Speter 				return (NIL);
312764Speter 			}
313764Speter 			p1 = rvalue( (int *) argv[1] , NLNIL , RREQ );
314764Speter 			putleaf( P2ICON , 1 , 0 , P2INT , 0 );
315764Speter 			putop( P2AND , P2INT );
316764Speter 			return nl + TBOOL;
317764Speter 	    case O_CHR2:
318764Speter 			if (isnta(p1, "i")) {
319764Speter 				error("chr's argument must be an integer, not %s", nameof(p1));
320764Speter 				return (NIL);
321764Speter 			}
322764Speter 			if (opt('t')) {
323764Speter 			    putleaf( P2ICON , 0 , 0
324764Speter 				, ADDTYPE( P2FTN | P2CHAR , P2PTR ) , "_CHR" );
325764Speter 			    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
326764Speter 			    putop( P2CALL , P2CHAR );
327764Speter 			} else {
328764Speter 			    p1 = stkrval( (int *) argv[1] , NLNIL , RREQ );
329764Speter 			}
330764Speter 			return nl + TCHAR;
331764Speter 	    case O_CARD:
332764Speter 			if ( p1 != nl + TSET ) {
333764Speter 			    if (isnta(p1, "t")) {
334764Speter 				error("Argument to card must be a set, not %s", nameof(p1));
335764Speter 				return (NIL);
336764Speter 			    }
337764Speter 			    putleaf( P2ICON , 0 , 0
338764Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR ) , "_CARD" );
339764Speter 			    p1 = stkrval( (int *) argv[1] , NLNIL , LREQ );
340764Speter 			    putleaf( P2ICON , lwidth( p1 ) , 0 , P2INT , 0 );
341764Speter 			    putop( P2LISTOP , P2INT );
342764Speter 			    putop( P2CALL , P2INT );
343764Speter 			} else {
344764Speter 			    if ( !cardempty ) {
345764Speter 				warning();
346764Speter 				error("Cardinality of the empty set is 0." );
347764Speter 				cardempty = TRUE;
348764Speter 			    }
349764Speter 			    putleaf( P2ICON , 0 , 0 , P2INT , 0 );
350764Speter 			}
351764Speter 			return nl + T2INT;
352764Speter 	    case O_EOLN:
353764Speter 			if (!text(p1)) {
354764Speter 				error("Argument to eoln must be a text file, not %s", nameof(p1));
355764Speter 				return (NIL);
356764Speter 			}
357764Speter 			putleaf( P2ICON , 0 , 0
358764Speter 			    , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_TEOLN" );
359764Speter 			p1 = stklval( (int *) argv[1] , NOFLAGS );
360764Speter 			putop( P2CALL , P2INT );
361764Speter 			return nl + TBOOL;
362764Speter 	    case O_EOF:
363764Speter 			if (p1->class != FILET) {
364764Speter 				error("Argument to eof must be file, not %s", nameof(p1));
365764Speter 				return (NIL);
366764Speter 			}
367764Speter 			putleaf( P2ICON , 0 , 0
368764Speter 			    , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_TEOF" );
369764Speter 			p1 = stklval( (int *) argv[1] , NOFLAGS );
370764Speter 			putop( P2CALL , P2INT );
371764Speter 			return nl + TBOOL;
372764Speter 	    case 0:
373764Speter 			error("%s is an unimplemented 6000-3.4 extension", p->symbol);
374764Speter 	    default:
375764Speter 			panic("func1");
376764Speter 	}
377764Speter }
378764Speter #endif PC
379