File: interp.c

package info (click to toggle)
infocom 4.01pl2-8
  • links: PTS
  • area: non-free
  • in suites: potato
  • size: 464 kB
  • ctags: 990
  • sloc: ansic: 8,232; perl: 961; makefile: 86
file content (338 lines) | stat: -rw-r--r-- 6,869 bytes parent folder | download | duplicates (3)
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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
/*
**	File:	interp.c
**
**	(C)opyright 1987-1992 InfoTaskforce.
*/

#include	"infocom.h"

extern proc_ptr	jmp_op0[] ;
extern proc_ptr	jmp_op1[] ;
extern proc_ptr	jmp_op2[] ;
extern int		operands[] ;

Void
init_interpreter ( init_pc )
boolean		init_pc ;
{
	extern word			pc_page ;
	extern word			pc_offset ;
	extern word			*stack_base ;
	extern word			*stack_var_ptr ;
	extern word			*stack ;
	extern byte_ptr		base_ptr ;
	extern header		data_head ;
	extern int			screen_width ;
	extern int			screen_height ;
	extern boolean		enhanced ;

	register byte_ptr	ptr ;

	if ( init_pc == TRUE )
	{
		stack_var_ptr = stack_base ;
		stack = --stack_var_ptr ;
		pc_page = data_head.start / BLOCK_SIZE ;
		pc_offset = data_head.start % BLOCK_SIZE ;
	}

	fix_pc () ;
	init_print () ;

	/*
	**	Set the "script_status" word in the data file to the
	**	value currently in use by the interpreter.
	*/

	ptr = (byte_ptr) &(((header_ptr)base_ptr) -> script_status) ;
	*ptr++ = MOST_SIGNIFICANT_BYTE ( data_head.script_status ) ;
	*ptr = LEAST_SIGNIFICANT_BYTE ( data_head.script_status ) ;

	if ( data_head.z_code_version <= VERSION_3 )
	{
		if ( enhanced )
		{
			((header_ptr)base_ptr) -> mode_bits |= SCREEN_MODES ;
			data_head.mode_bits |= SCREEN_MODES ;
			USE_WINDOW ( FULL_SCREEN ) ;
		}
	}
	else
	{
		/*
		**	Screen Coordinates:
		**
		**		Horizontal:	From 0 to (screen_width - 1)
		**		Vertical:	From 0 to (screen_height - 2)
		**
		**	Note: One screen line is needed for the "[MORE]" function,
		**	hence (screen_height - 2) instead of (screen_height - 1).
		*/
			
		((header_ptr)base_ptr) -> interpreter_number = INTERPRETER ;
		((header_ptr)base_ptr) -> interpreter_version = (byte)'A' ;
		((header_ptr)base_ptr) -> screen_height = (byte)(screen_height - 1) ;
		((header_ptr)base_ptr) -> screen_width = (byte)screen_width ;
		((header_ptr)base_ptr) -> mode_bits |= MODE_BITS ;
		data_head.mode_bits |= MODE_BITS ;
		USE_WINDOW ( FULL_SCREEN ) ;

		if ( data_head.z_code_version >= VERSION_5 )
		{

			((header_ptr)base_ptr) -> left = 0 ;
			((header_ptr)base_ptr) -> right = (byte)screen_width ;
			((header_ptr)base_ptr) -> top = 0 ;
			((header_ptr)base_ptr) -> bottom = (byte)(screen_height - 1) ;
			((header_ptr)base_ptr) -> unknown1 = 1 ;
			((header_ptr)base_ptr) -> unknown2 = 1 ;
			((header_ptr)base_ptr) -> unknown3 = 9 ;
			((header_ptr)base_ptr) -> unknown4 = 2 ;
		}
	}
}

Void
execute_opcode ()
{
	extern boolean	stop ;
	extern word		pc_page ;
	extern word		pc_offset ;

	register word	opcode ;

#ifdef	DEBUG
	register long	debug_pc ;
#endif	/* DEBUG */

	stop = FALSE ;
	while ( stop == FALSE )
	{

#ifdef	DEBUG
		debug_pc = ( (long)pc_page * BLOCK_SIZE ) + (long)pc_offset ;
#endif	/* DEBUG */
		opcode = next_byte () ;
#ifdef	DEBUG
		display ( "PC: $" ) ;
		hex_display ( (word)(( debug_pc >> 16 ) & 0xFFFF ) ) ;
		hex_display ( (word)( debug_pc & 0xFFFF ) ) ;
		display ( " - opcode: $" ) ;
		hex_display ( opcode ) ;
#endif	/* DEBUG */
		if ( opcode < 0x80 )
			operand2 ( opcode ) ;
		else
		{
			if ( opcode < 0xB0 )
				operand1 ( opcode ) ;
			else
			{
				if ( opcode >= 0xC0 )
					operand3 ( opcode ) ;
				else
				{
					/*
					**	Opcode 0xBE is an ADVANCED series opcode. It is
					**	used to access opcodes 0x40 to 0x4A in the
					**	"jmp_op2[]" table. These call "illegal_opcode ()"
					**	for game files earlier than ADVANCED.
					*/

					if ( opcode == 0xBE )
					{
						opcode = ( next_byte () & 0x3F ) | 0x40 ;
#ifdef	DEBUG
						display ( ":<$" ) ;
						hex_display ( opcode ) ;
						display ( ">" ) ;
#endif	/* DEBUG */
						operand4 ( opcode ) ;
					}
					else
						(*jmp_op0[opcode & 0x0F])() ;
				}
			}
		}
#ifdef	DEBUG
		new_line () ;
#endif	/* DEBUG */
	}
}

Void
operand1 ( opcode )
register word	opcode ;
{
	register word	param1 ;

	param1 = load ((int)(( opcode >> 4 ) & 0x03 )) ;
#ifdef	DEBUG
	display ( "\t$0001 Parameter: $" ) ;
	hex_display ( param1 ) ;
#endif	/* DEBUG */
	(*jmp_op1[opcode & 0x0F])( param1 ) ;
}

Void
operand2 ( opcode )
register word	opcode ;
{
	extern word		param_stack[] ;

	register word	*param_ptr ;
	register word	param1 ;
	register word	param2 ;
	register int	mode ;

	mode = 1 ;
	if ( opcode & 0x40 )
		++mode ;
	param1 = load ( mode ) ;
	mode = 1 ;
	if ( opcode & 0x20 )
		++mode ;
	param2 = load ( mode ) ;
#ifdef	DEBUG
	display ( "\t$0002 Parameters: $" ) ;
	hex_display ( param1 ) ;
	display ( " $" ) ;
	hex_display ( param2 ) ;
#endif	/* DEBUG */
	opcode &= 0x1F ;
	if ( operands[opcode] )
		(*jmp_op2[opcode])( param1,param2 ) ;
	else
	{
		param_ptr = &param_stack[0] ;
		*param_ptr++ = 2 ;
		*param_ptr++ = param1 ;
		*param_ptr++ = param2 ;
		(*jmp_op2[opcode])() ;
	}
}

word
*push_params ( modes,param_ptr,count )
register word	modes ;
register word	*param_ptr ;
register int	count ;
{
	extern word		param_stack[] ;

	if ( count )
	{
		param_ptr = push_params ( ( modes >> 2 ),param_ptr,--count ) ;
		if ( param_ptr != (word *)0 )
		{
			modes &= 0x03 ;
			if ( modes != 0x03 )
			{
				*param_ptr++ = load ( (int)modes ) ;
				++param_stack[0] ;
				return ( param_ptr ) ;
			}
		}
		return ( (word *)0 ) ;
	}
	return ( param_ptr ) ;
}

Void
operand3 ( opcode )
register word	opcode ;
{
	extern word		param_stack[] ;

	register word	*param_ptr ;

	/*
	**	Reset the Parameter Count.
	*/

	param_stack[0] = 0 ;

	/*
	**	Fetch the Parameters.
	**
	**	Opcode 0xFA is an ADVANCED series opcode. It is used to
	**	access opcode 0x3A in the "jmp_op2[]" table. This calls
	**	"illegal_opcode ()" for game files earlier than ADVANCED.
	*/

	if (( opcode == 0xEC ) || ( opcode == 0xFA ))
		param_ptr = push_params ( (word) next_word (),&param_stack[1],8 ) ;
	else
		param_ptr = push_params ( (word) next_byte (),&param_stack[1],4 ) ;

	opcode &= 0x3F ;
	call_function ( opcode ) ;
}

Void
call_function ( opcode )
register word	opcode ;
{
	extern word			param_stack[] ;

	register proc_ptr	func ;

#ifdef	DEBUG
	display ( "\t$" ) ;
	hex_display ( param_stack[0] ) ;
	display ( " Parameters: $" ) ;
	hex_display ( param_stack[1] ) ;
	display ( " $" ) ;
	hex_display ( param_stack[2] ) ;
	display ( " $" ) ;
	hex_display ( param_stack[3] ) ;
#endif	/* DEBUG */

	func = jmp_op2[opcode] ;
	switch ( operands[opcode] )
	{
		case 0 :
				(*func)() ;
				break ;
		case 1 :
				(*func)( param_stack[1] ) ;
				break ;
		case 2 :
				(*func)( param_stack[1],param_stack[2] ) ;
				break ;
		case 3 :
				(*func)( param_stack[1],param_stack[2],param_stack[3] ) ;
				break ;
	}
}

Void
illegal_opcode ()
{
#ifdef	DEBUG
	new_line () ;
#endif	/* DEBUG */
	error ( ERR_OPCODE ) ;
}

Void
operand4 ( opcode )
register word	opcode ;
{
	extern word		param_stack[] ;

	register word	*param_ptr ;

	/*
	**	Reset the Parameter Count.
	*/

	param_stack[0] = 0 ;

	/*
	**	Fetch the Parameters.
	*/

	param_ptr = push_params ( (word) next_byte (),&param_stack[1],4 ) ;
	call_function ( opcode ) ;
}