BSD 3 development
[unix-history] / usr / src / cmd / pi / func.c
CommitLineData
d27a781b
CH
1/* Copyright (c) 1979 Regents of the University of California */
2#
3/*
4 * pi - Pascal interpreter code translator
5 *
6 * Charles Haley, Bill Joy UCB
7 * Version 1.2 November 1978
8 */
9
10#include "whoami"
11#include "0.h"
12#include "tree.h"
13#include "opcode.h"
14
15/*
16 * Funccod generates code for
17 * built in function calls and calls
18 * call to generate calls to user
19 * defined functions and procedures.
20 */
21funccod(r)
22 int *r;
23{
24 struct nl *p;
25 register struct nl *p1;
26 register int *al;
27 register op;
28 int argc, *argv;
29 int tr[2], tr2[4];
30
31 /*
32 * Verify that the given name
33 * is defined and the name of
34 * a function.
35 */
36 p = lookup(r[2]);
37 if (p == NIL) {
38 rvlist(r[3]);
39 return (NIL);
40 }
41 if (p->class != FUNC) {
42 error("%s is not a function", p->symbol);
43 rvlist(r[3]);
44 return (NIL);
45 }
46 argv = r[3];
47 /*
48 * Call handles user defined
49 * procedures and functions
50 */
51 if (bn != 0)
52 return (call(p, argv, FUNC, bn));
53 /*
54 * Count the arguments
55 */
56 argc = 0;
57 for (al = argv; al != NIL; al = al[2])
58 argc++;
59 /*
60 * Built-in functions have
61 * their interpreter opcode
62 * associated with them.
63 */
64 op = p->value[0] &~ NSTAND;
65 if (opt('s') && (p->value[0] & NSTAND)) {
66 standard();
67 error("%s is a nonstandard function", p->symbol);
68 }
69 switch (op) {
70 /*
71 * Parameterless functions
72 */
73 case O_CLCK:
74 case O_SCLCK:
75 case O_WCLCK:
76 case O_ARGC:
77 if (argc != 0) {
78 error("%s takes no arguments", p->symbol);
79 rvlist(argv);
80 return (NIL);
81 }
82 put1(op);
83 return (nl+T4INT);
84 case O_EOF:
85 case O_EOLN:
86 if (argc == 0) {
87 argv = tr;
88 tr[1] = tr2;
89 tr2[0] = T_VAR;
90 tr2[2] = input->symbol;
91 tr2[1] = tr2[3] = NIL;
92 argc = 1;
93 } else if (argc != 1) {
94 error("%s takes either zero or one argument", p->symbol);
95 rvlist(argv);
96 return (NIL);
97 }
98 }
99 /*
100 * All other functions take
101 * exactly one argument.
102 */
103 if (argc != 1) {
104 error("%s takes exactly one argument", p->symbol);
105 rvlist(argv);
106 return (NIL);
107 }
108 /*
109 * Evaluate the argmument
110 */
111 p1 = rvalue((int *) argv[1], NLNIL);
112 if (p1 == NIL)
113 return (NIL);
114 switch (op) {
115 case O_EXP:
116 case O_SIN:
117 case O_COS:
118 case O_ATAN:
119 case O_LN:
120 case O_SQRT:
121 case O_RANDOM:
122 case O_EXPO:
123 case O_UNDEF:
124 if (isa(p1, "i"))
125 convert(p1, nl+TDOUBLE);
126 else if (isnta(p1, "d")) {
127 error("%s's argument must be integer or real, not %s", p->symbol, nameof(p1));
128 return (NIL);
129 }
130 put1(op);
131 if (op == O_UNDEF)
132 return (nl+TBOOL);
133 else if (op == O_EXPO)
134 return (nl+T4INT);
135 else
136 return (nl+TDOUBLE);
137 case O_SEED:
138 if (isnta(p1, "i")) {
139 error("seed's argument must be an integer, not %s", nameof(p1));
140 return (NIL);
141 }
142 convert(p1, nl+T4INT);
143 put1(op);
144 return (nl+T4INT);
145 case O_ROUND:
146 case O_TRUNC:
147 if (isnta(p1, "d")) {
148 error("%s's argument must be a real, not %s", p->symbol, nameof(p1));
149 return (NIL);
150 }
151 put1(op);
152 return (nl+T4INT);
153 case O_ABS2:
154 case O_SQR2:
155 if (isa(p1, "d")) {
156 put1(op + O_ABS8-O_ABS2);
157 return (nl+TDOUBLE);
158 }
159 if (isa(p1, "i")) {
160 put1(op + (width(p1) >> 2));
161 return (nl+T4INT);
162 }
163 error("%s's argument must be an integer or real, not %s", p->symbol, nameof(p1));
164 return (NIL);
165 case O_ORD2:
166 if (isa(p1, "bcis") || classify(p1) == TPTR)
167 switch (width(p1)) {
168 case 1:
169 return (nl+T1INT);
170 case 2:
171 return (nl+T2INT);
172 case 4:
173 return (nl+T4INT);
174 }
175 error("ord's argument must be of scalar type or a pointer, not %s", nameof(p1));
176 return (NIL);
177 case O_SUCC2:
178 case O_PRED2:
179 if (isa(p1, "bcs")) {
180 put1(op);
181 return (p1);
182 }
183 if (isa(p1, "i")) {
184 if (width(p1) <= 2)
185 op += O_PRED24-O_PRED2;
186 else
187 op++;
188 put1(op);
189 return (nl+T4INT);
190 }
191 if (isa(p1, "id")) {
192 error("%s is forbidden for reals", p->symbol);
193 return (NIL);
194 }
195 error("%s's argument must be of scalar type, not %s", p->symbol, nameof(p1));
196 return (NIL);
197 case O_ODD2:
198 if (isnta(p1, "i")) {
199 error("odd's argument must be an integer, not %s", nameof(p1));
200 return (NIL);
201 }
202 put1(op + (width(p1) >> 2));
203 return (nl+TBOOL);
204 case O_CHR2:
205 if (isnta(p1, "i")) {
206 error("chr's argument must be an integer, not %s", nameof(p1));
207 return (NIL);
208 }
209 put1(op + (width(p1) >> 2));
210 return (nl+TCHAR);
211 case O_CARD:
212 if (isnta(p1, "t")) {
213 error("Argument to card must be a set, not %s", nameof(p1));
214 return (NIL);
215 }
216 put2(O_CARD, width(p1));
217 return (nl+T2INT);
218 case O_EOLN:
219 if (!text(p1)) {
220 error("Argument to eoln must be a text file, not %s", nameof(p1));
221 return (NIL);
222 }
223 put1(op);
224 return (nl+TBOOL);
225 case O_EOF:
226 if (p1->class != FILET) {
227 error("Argument to eof must be file, not %s", nameof(p1));
228 return (NIL);
229 }
230 put1(op);
231 return (nl+TBOOL);
232 case 0:
233 error("%s is an unimplemented 6000-3.4 extension", p->symbol);
234 default:
235 panic("func1");
236 }
237}