view interps/c-intercal/etc/IFFI/IFFI.c @ 11293:a7899ef2d7b6

<wob_jonas> learn Aristotle said that every illness can be cured by balancing the four vitreous humors, and everyone believed him for two thousand years, even though people still died of illnesses. It wasn\'t until the 20th century that Szent-Gy\xc3\xb6rgyi Albert realized that Aristotle didn\'t find fifth kind of vitreous humor, vitamin C, because the Greek alphabet
author HackBot
date Mon, 01 Jan 2018 17:57:43 +0000
parents 859f9b4339e6
children
line wrap: on
line source

/* -*- mode: C; coding: utf-8; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-

    cfunge - a conformant Befunge93/98/08 interpreter in C.
    Copyright (C) 2008 Arvid Norlander <anmaster AT tele2 DOT se>
    Copyright (C) 2008 Alex Smith

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    Note that this code is designed to be linked against a GPLv3 library
    (producing a GPLv3 output), and therefore it is recommended that
    modifications to this code are compatible with GPLv3, although this
    is not a legal requirement.
 */

#include "IFFI.h"
#include "../../stack.h"
#include "../../settings.h"
#include "../../interpreter.h"

#ifdef HAVE_clock_gettime
#  include <time.h>
#else
#  include <sys/time.h>
#endif

static instructionPointer *iffiIP = NULL;

static bool firstload = true;

// Communication functions with the ecto_b98 expansion library
void ick_save_ip_pos_delta(struct ick_ipposdeltatype* ippd)
{
	ippd->ix = iffiIP->position.x;
	ippd->iy = iffiIP->position.y;
	ippd->dx = iffiIP->delta.x;
	ippd->dy = iffiIP->delta.y;
}

void ick_restore_ip_pos_delta(const struct ick_ipposdeltatype* ippd)
{
	iffiIP->position.x = ippd->ix;
	iffiIP->position.y = ippd->iy;
	iffiIP->delta.x = ippd->dx;
	iffiIP->delta.y = ippd->dy;
}

void ick_interpreter_run(void)
{
	if (!fungespace_create()) {
		perror("Couldn't create funge space!?");
		exit(EXIT_FAILURE);
	}
	fungespace_load_string(ick_iffi_befungeString);
	iffiIP = ip_create();
	if (iffiIP == NULL) {
		perror("Couldn't create instruction pointer!?");
		exit(EXIT_FAILURE);
	}
	{
#ifdef HAVE_clock_gettime
		struct timespec tv;
		if (clock_gettime(CLOCK_REALTIME, &tv)) {
			perror("Couldn't get time of day?!");
			exit(EXIT_FAILURE);
		}
		// Set up randomness
		srandom(tv.tv_nsec);
#else
		struct timeval tv;
		if (gettimeofday(&tv, NULL)) {
			perror("Couldn't get time of day?!");
			exit(EXIT_FAILURE);
		}
		// Set up randomness
		srandom(tv.tv_usec);
#endif
	}
	if(ick_printflow) setting_trace_level=9;
	ick_interpreter_main_loop();
}

void ick_iffi_interpreter_one_iteration(void)
{
	funge_cell opcode;
	opcode = fungespace_get(&iffiIP->position);

	if (setting_trace_level > 8) {
		fprintf(stderr, "x=%" FUNGECELLPRI " y=%" FUNGECELLPRI
				": %c (%" FUNGECELLPRI ")\n",
				iffiIP->position.x, iffiIP->position.y, (char)opcode, opcode);
		stack_print_top(iffiIP->stack);
	} else if (setting_trace_level > 3) {
		fprintf(stderr, "x=%" FUNGECELLPRI " y=%" FUNGECELLPRI
				": %c (%" FUNGECELLPRI ")\n",
				iffiIP->position.x, iffiIP->position.y, (char)opcode, opcode);
	} else if (setting_trace_level > 2)
		fprintf(stderr, "%c", (char)opcode);

	execute_instruction(opcode, iffiIP);
	if (iffiIP->needMove)
		ip_forward(iffiIP);
	else
		iffiIP->needMove = true;
}

// A - CREATE a new INTERCAL instruction
static void finger_IFFI_create(instructionPointer * ip)
{
    // arguments: line number on TOS, signature as 0gnirts beneath it
	funge_cell l = stack_pop(ip->stack);
	unsigned char * restrict str = stack_pop_string(ip->stack, NULL);
	ick_create((const char*)str, l);
}

// C - In markmode COME FROM the top of stack
static void finger_IFFI_come_from(instructionPointer * ip)
{
	funge_cell l;

	l = stack_pop(ip->stack);

	if (ick_iffi_inmarkmode) {
		ick_iffi_breakloop = 1;
		ick_iffi_linelabel = l;
		ick_iffi_comingfrom = 1;
	}
}

// D - Push information about a CREATED instruction argument
static void finger_IFFI_create_data(instructionPointer * ip)
{
	// Arguments: argument's index (0-based) on TOS
	// Return: the following values (from bottom to top):
	// The argument's data type, in bits
	// Whether the argument is an array variable
	// 0 if the argument is not a variable, or its number if it is
	// The argument's value at the time the CREATED instruction was called
	// The argument's value now (same as previous if -a was not used)
	funge_cell i;

	if (firstload) {
		ip_reverse(ip);
		return;
	}

	i = stack_pop(ip->stack);

	stack_push(ip->stack, ick_c_i_width(i));
	stack_push(ip->stack, ick_c_i_isarray(i));
	stack_push(ip->stack, ick_c_i_varnumber(i));
	stack_push(ip->stack, ick_c_i_value(i));
	stack_push(ip->stack, ick_c_i_getvalue(i));
}

// F - FORGET NEXT stack entries equal to top of stack
static void finger_IFFI_forget(instructionPointer * ip)
{
	funge_cell f;

	if (firstload) {
		ip_reverse(ip);
		return;
	}

	if (ick_iffi_inmarkmode) { /* this is an error in the user's code */
		ip_reverse(ip);
		return;
	}

	f = stack_pop(ip->stack);

	if (f > 81 || f < 0) f = 81;

	ick_iffi_forgetcount = f;
}

// G - Get the value of an INTERCAL scalar variable
static void finger_IFFI_var_get(instructionPointer * ip)
{
	// arguments: var number on TOS
	// var numbers are positive for onespot, negative for twospot
	// return: the value of the variable

	funge_cell v;

	if (firstload) {
		ip_reverse(ip);
		return;
	}

	v = stack_pop(ip->stack);

	if (v == 0) {
		ip_reverse(ip);
	} else if (v > 0) {
		stack_push(ip->stack, ick_getonespot(v));
	} else {
		stack_push(ip->stack, ick_gettwospot(-v));
	}
}

// L - Use top of stack as a line label for this point
static void finger_IFFI_label(instructionPointer * ip)
{
	funge_cell l;

	if (firstload) {
		ip_reverse(ip);
		return;
	}

	l = stack_pop(ip->stack);

	ick_iffi_breakloop = 1;
	ick_iffi_linelabel = l;
	ick_iffi_sucking = 1;
}

// M - Marks points where the code can be entered from outside
static void finger_IFFI_marker(instructionPointer * ip)
{
	(void) ip;
	ick_iffi_breakloop = ick_iffi_inmarkmode;
}

// N - Try to NEXT to the line labelled with the top of stack
static void finger_IFFI_next(instructionPointer * ip)
{
	funge_cell l;

	if (firstload) {
		ip_reverse(ip);
		return;
	}

	if (ick_iffi_inmarkmode) { /* this is an error in the user's code */
		ip_reverse(ip);
		return;
	}

	l = stack_pop(ip->stack);

	ick_iffi_breakloop = 1;
	ick_iffi_linelabel = l;
	ick_iffi_nexting = 1;
}

// R - RESUME to the top-of-stackth NEXT stack entry
static void finger_IFFI_resume(instructionPointer * ip)
{
	funge_cell f;

	if (firstload) {
		ip_reverse(ip);
		return;
	}

	if (ick_iffi_inmarkmode) { /* this is an error in the user's code */
		ip_reverse(ip);
		return;
	}

	f = stack_pop(ip->stack);

	if (f > 81 || f < 0) f = 81;

	ick_iffi_forgetcount = f;

	ick_iffi_resuming = 1;

	ick_iffi_breakloop = 1;
}

// S - Set the value of an INTERCAL scalar variable
static void finger_IFFI_var_set(instructionPointer * ip)
{
	// arguments: var number on TOS, new value beneath it
	// var numbers are positive for onespot, negative for twospot
	// return: the value of the variable

	funge_cell v, d;

	if (firstload) {
		ip_reverse(ip);
		return;
	}

	v = stack_pop(ip->stack);
	d = stack_pop(ip->stack);

	if (v == 0) {
		ip_reverse(ip);
	} else if (v > 0) {
		ick_setonespot(v, d);
	} else {
		ick_settwospot(-v, d);
	}
}

// V - Assign to a CREATEd instruction argument
static void finger_IFFI_arg_set(instructionPointer * ip)
{
	// arguments: 0-based argument index on TOS, new value beneath it
	// note that this is a NOP unless -a was used when compiling
	funge_cell i, d;

	if (firstload) {
		ip_reverse(ip);
		return;
	}

	i = stack_pop(ip->stack);
	d = stack_pop(ip->stack);

	ick_c_i_setvalue(i, d);
}

// X - In markmode NEXT FROM the top of stack
static void finger_IFFI_next_from(instructionPointer * ip)
{
	funge_cell l;

	l = stack_pop(ip->stack);

	if (ick_iffi_inmarkmode) {
		ick_iffi_breakloop = 1;
		ick_iffi_linelabel = l;
		ick_iffi_nextingfrom = 1;
	}
}

// Y - Marks the end of initialisation
static void finger_IFFI_yield(instructionPointer * ip)
{
	ick_iffi_breakloop = firstload;
	if (! firstload)
		ip_reverse(ip);
	firstload = false;
}

bool finger_IFFI_load(instructionPointer * ip)
{
	manager_add_opcode(IFFI,  'A', create)
	manager_add_opcode(IFFI,  'C', come_from)
	manager_add_opcode(IFFI,  'D', create_data)
	manager_add_opcode(IFFI,  'F', forget)
	manager_add_opcode(IFFI,  'G', var_get)
	manager_add_opcode(IFFI,  'L', label)
	manager_add_opcode(IFFI,  'M', marker)
	manager_add_opcode(IFFI,  'N', next)
	manager_add_opcode(IFFI,  'R', resume)
	manager_add_opcode(IFFI,  'S', var_set)
	manager_add_opcode(IFFI,  'V', arg_set)
	manager_add_opcode(IFFI,  'X', next_from)
	manager_add_opcode(IFFI,  'Y', yield)
	return true;
}