aboutsummaryrefslogtreecommitdiff
path: root/pkg/vocl/compile.c
blob: 87615d196ab5f12ff08bbefc5b8004dd8f30d17d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
 */

#define import_spp
#define import_libc
#define import_stdio
#define import_stdarg
#include <iraf.h>

#include "config.h"
#include "operand.h"
#include "opcodes.h"
#include "mem.h"
#include "errs.h"
#include "task.h"
#include "proto.h"


/*
 * COMPILE -- compile instructions at compile time, compile constants,
 * params and misc at runtime on stacks or dictionary.
 */

memel *dictionary;		/* base of dictionary			*/
XINT   pc;			/* program-counter			*/
XINT   topd, maxd;		/* current top and highest d. indices	*/

extern	int	cldebug, cltrace;

/* compile opcode and optional arguments into stack.
 * interpret "args" according to what is being compiled.
 * if (all goes well during compilation)
 *	{advance pc, return base addr of new codeentry}
 * else
 *	{leave pc unchanged, return (ERR)}
 * TODO: be more sophisticated in guarding against compiling past topcs.
 */

/*VARARGS1*/
int 
compile (int opcode, ... )
{
	register struct codeentry *cep;
	register int status = OK;
	va_list argp;


	if (pc > topcs - 20) {
	    eprintf ("INTERNAL ERROR: pc/topcs collision: %d/%d\n", pc, topcs);
	    return (ERR);
	}

	va_start (argp, opcode);

	cep = coderef (pc);
	cep->c_opcode = opcode;
	cep->c_scriptln = currentask->t_scriptln;
	cep->c_length = 3;	/* initial length is opcode+scriptln+length
				 * The order of this is important so the access
				 * to the c_args is handled properly.
				 */


	switch (opcode) {
	
	/* all these opcodes have one string argument, at args */
	case ABSARGSET:
	case ADDASSIGN:
	case ASSIGN:
	case CALL:
	case CATASSIGN:
	case DIVASSIGN:
	case GETPIPE:
	case GSREDIR:
	case INDIRABSSET:
	case INSPECT:
	case INTRINSIC:
	case OSESC:
	case MULASSIGN:
	case PUSHPARAM:
	case SUBASSIGN:
	case SWOFF:
 	case SWON: {
                char *sp = va_arg (argp, char *);
		status = comstr (sp, &cep->c_args);
		if (status != ERR)
		    cep->c_length += status;
		}
		break;

	/* these opcodes use c_args as a pointer to an operand.
	 * it is copied in-line following the new instruction in the stack.
	 * further, if type is OT_STRING, compile the string in-line following
	 * the operand and change o_val.v_s to point to it.
	 */
	case PUSHCONST: {
		register memel *argsaddr;
		struct operand *op, *dp;

                op = va_arg (argp, struct operand *);
		argsaddr = (memel *) &cep->c_args;
		dp = (struct operand *) argsaddr;
		*dp = *op;
		argsaddr += OPSIZ;
		cep->c_length += OPSIZ;
		if ((op->o_type & OT_BASIC) == OT_STRING) {
		    status = comstr (op->o_val.v_s, argsaddr);
		    if (status != ERR) {
			dp->o_val.v_s = (char *) argsaddr;
			cep->c_length += status;
		    }
		}
		} /* end of case PUSHCONST */
		break;

	/* these opcodes use no arguments */
	case ADD:
	case ALLAPPEND:
	case ALLREDIR:
	case AND:
	case APPENDOUT:
	case CHSIGN:
	case CONCAT:
	case DEFAULT:
	case DIV:
	case END:
	case EQ:
	case EXEC:
	case FSCAN:
	case FSCANF:
	case GE:
	case GT:
	case IMMED:
	case LE:
	case LT:
	case MUL:
	case NE:
	case NOT:
	case OR:
	case POW:
	case PRINT:
	case REDIR:
	case REDIRIN:
	case RETURN:
	case SCAN:
	case SCANF:
	case SUB:
	case FIXLANGUAGE:
		break;

	/* these opcodes have one simple integer argument;
	 * rather than put it after the instruction and point c_args there,
	 * just use c_args itself.
	 */
	case ADDPIPE:
	case BIFF:
	case GOTO:
	case INDIRPOSSET:
	case PUSHINDEX:
	case POSARGSET:
	case RMPIPES:
		cep->c_args = va_arg (argp, int);
		cep->c_length++;
		break;

	/* SWITCH has one argument which will be supplied after the
	 * entire switch block has been compiled.
	 */
	case SWITCH:
		cep->c_length++;
		break;


	/* The CASE statement has a variable number of arguments
	 * depending on how many different values are set for
	 * this case block.  Just allocate the block and let
	 * the parser fill in the argument list.
	 */
	case CASE:
		cep->c_length += va_arg (argp, int);
		cep->c_args = INDEFI;	    /* sentinel be filled in later */
		break;

	/* The INDXINCR statment has two integer args. */
	case INDXINCR: {
		memel *pargs;

		cep->c_length += 2;
		pargs = (memel *) &(cep->c_args);
		*pargs++ = va_arg (argp, int);
		*pargs = va_arg (argp, int);
		break;
		}

	default:
		cl_error (E_IERR, e_badsw, opcode, "compile()");
		status = ERR;
	}

	if (cltrace >= 3)
    	    d_instr (stderr, "\t", pc);

	if (status != ERR) {
	    XINT oldpc = pc;
	    pc += cep->c_length;
	    return (oldpc);
	}
	return (ERR);
}


/* COMSTR -- compile string s into an arbitrary core address loc, which must be
 * on an int boundry.  Allow for trailing '\0'.  Return number of whole ints 
 * taken up by string else ERR if no room.  
 * (comdstr() should be used to copy a string into the dictionary)
 */
int 
comstr (register char *s, memel *loc)
{
	register char *to, *from;

	from = to = (char *)loc;
	while ( (*to++ = *s++) )
	    ;
	return (btoi((memel)to - (memel)from));
}

/* copy string s into the dictionary at topd, returning pointer to its
 *   beginning and incrementing topd properly.
 * allow for trailing '\0'.
 */
char *
comdstr (char *s)
{
	char *start;

	start = memneed (btoi (strlen (s) + 1));
	strcpy (start, s);
	return (start);
}

/* concat new string, ns, after existing string, es, in dictionary.
 * only works, of course, if memneed() was not called since es was compiled
 * originally.
 */
void 
catdstr (char *es, char *ns)
{
	int eslen = strlen (es) + 1;

	memneed (btoi (eslen + strlen (ns)) - btoi (eslen));
	strcat (es, ns);
}