view src/daoyu.c @ 12518:2d8fe55c6e65 draft default tip

<int-e> learn The password of the month is release incident pilot.
author HackEso <hackeso@esolangs.org>
date Sun, 03 Nov 2024 00:31:02 +0000
parents 5aac3c341f92
children
line wrap: on
line source

/*
*   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 3 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
*   aint with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
* DaoLanguage / Daoyu Compiler and Interpreter.
* Kaynato - 2016
* See splash() for details.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BITS_IN_BYTE	8
#define BITS_IN_CELL 	(sizeof(unsigned int) * 8)
#define INPUT_DELIMITER '@'

typedef struct PATH
{
	struct PATH*	owner;						/* OWNER      PROGRAM */
	struct PATH*	child;						/* CHILD      PROGRAM */
	unsigned int*	prg_data;					/*		   DATA	      */
	unsigned int	prg_allocbits;				/* OPEN	   DATA   BITS*/
	unsigned int	prg_index;					/* INSTRUCTION POINTER*/
	unsigned char	prg_level;					/* OPERATING   LEVEL  */
	unsigned int	sel_length;					/* LENGTH OF SELECTION*/
	unsigned int	sel_index;					/* INDEX  OF SELECTION*/
	unsigned int    prg_floor;					/* FLOOR  OF PATH     */
	unsigned int   prg_start;					/* START  OF RUNNING  */
} Pathstrx;

typedef Pathstrx* Path;

static void interpret(char*);

static void swaps(Path), later(Path), merge(Path), sifts(Path), delev(Path), equal(Path), halve(Path);
static void uplev(Path), reads(Path), dealc(Path), split(Path), polar(Path), doalc(Path), input(Path), execs(Path, Path);

char 			getInput();
char 			algn(Path);
char 			getChar(unsigned char);
char*			bin(unsigned int);
char*			str_dup(char *s);
char*			l_to_str(unsigned int, unsigned char, unsigned char);
static void		skip();
static void 	write_by_bit_index(Path, unsigned int, unsigned int, unsigned int);
unsigned char 	getNybble(char);
unsigned int 	read_by_bit_index(Path, unsigned int, unsigned int);
unsigned int 	mask(int);
unsigned int	ptwo_round(unsigned int);

static unsigned char command = 0;
static int doloop = 1;

typedef void(*PathFunc)(Path);

static PathFunc functions[16] = \
	{NULL, swaps, later, merge, \
	sifts, NULL , delev, equal, \
	halve, uplev, reads, dealc, \
	split, polar, doalc, input};

const struct PATH NEW_PATH = { NULL, NULL, NULL, 1, 0, 0, 1, 0, 0, 0 };

static Path P_RUNNING = NULL,
			P_WRITTEN = NULL;

static const char* symbols = ".!/)%#>=(<:S[*$;";

static char* inputptr = NULL;

/* Run argv[0] as code. Input separated by '!' and once empty reads the null character. */
int main(int argc, char * argv[])
{
	char* i = argv[1];

	/* No argument(s)? */
	if (argc < 2)
		return 0;

	/* Seek input until it either points to delimiter or NUL */
	while (*i && *i != INPUT_DELIMITER) i++;

	/* If it is the input delimiter then put the inputptr there*/
	if (*i == INPUT_DELIMITER)
		inputptr = ++i;

	interpret(argv[1]);
	return 0;
}

#define rc(r,c) case c: return r;

unsigned char getNybble(char ch)
{
	switch (ch)
	{
		rc(0x0, '.')	rc(0x1, '!')	rc(0x2, '/')	rc(0x3, ']': case ')')
		rc(0x4, '%')	rc(0x5, '#')	rc(0x6, '>')	rc(0x7, '=')
		rc(0x8, '(')	rc(0x9, '<')	rc(0xA, ':')	rc(0xB, 'S')
		rc(0xC, '[')	rc(0xD, '*')	rc(0xE, '$')	rc(0xF, ';')
		default: return 0x0;
	}
}

void interpret(char* input)
{
	unsigned int length = 0;										/* How many bytes in input 							*/

	/* Initialize path */
	struct PATH newpath = NEW_PATH;
	Path dao = &newpath;

	/* Seek end of program input */
	while (input[length] && input[length] != INPUT_DELIMITER) length++;

	/* Terminate empty program */
	if (length == 0) return;

	/* Get necessary byte number from nybbles */
	length = ptwo_round((length+1) / 2);

	/* Set bit length of path */
	(dao->prg_allocbits) = length * 8;

	/* Prevent zero-sized allocation */
	if (length % sizeof(unsigned int) != 0)
		length = sizeof(unsigned int);		

	/* Allocate bytes for data array */
	if (((dao->prg_data) = calloc(length, 1)) == NULL)
	{
		printf("Error allocating %d bytes: ", length);
		perror("");
		abort();
	}

	/* Copy over data */
	for (length = 0; input[length] && input[length] != INPUT_DELIMITER; length++)
	{
		int hex = getNybble(input[length]);
		write_by_bit_index(dao, 4*length, 4, hex);
	}

	P_RUNNING = dao;												/* For the sake of levlim							*/
	
	/***************************************************** EXECUTE ******************************************************/
	execs(dao, NULL);
	free((dao->prg_data));
	(dao -> prg_data) = NULL;
	/********************************************************************************************************************/

}

unsigned int ptwo_round(unsigned int x)
{
	unsigned int rounded = x;										/* Initialize bytes_alloc with the file_size value. */
	unsigned int	shift = 0;										/* Shift for first one of file size for rounding    */

	while ((rounded >> 1) != 0)										/* Determine leftmost '1' bit of file size.		 	*/
	{																/*													*/
		rounded >>= 1;												/* Shift right until the next shift zeroes it.		*/
		shift++;													/* Keep track of shifts.							*/
	}																/*													*/
	rounded <<= shift; 												/* Unshift. 										*/
	if (x != rounded)												/* If not a power of two, round up.					*/
		rounded <<= 1;

	return rounded;
}

char getInput()
{
	/* if null return zero */
	if (!inputptr)
		return 0;

	/* If not zero then return-advance */
	if (*inputptr)
		return *inputptr++;
	
	inputptr = NULL;
	return 0;
}

/***
 *    oooooooooooo ooooooooooooo   .oooooo.   
 *    `888'     `8 8'   888   `8  d8P'  `Y8b  
 *     888              888      888          
 *     888oooo8         888      888          
 *     888    "         888      888          
 *     888       o      888      `88b    ooo  
 *    o888ooooood8     o888o      `Y8bood8P'  
 *                                            
 */

#define roc(o,v,c) case o:c=v; return &c;

char *str_dup (char *s) {
    char *d = malloc (strlen (s) + 1);   /*Allocate memory			*/
    if (d != NULL) strcpy (d,s);         /*Copy string if okay		*/
    return d;                            /*Return new memory		*/
}

char* bin(unsigned int val) { return l_to_str(val, 32, 2); }

char getChar(unsigned char ch)
{
	if (ch > 0xF) return '?';
	return symbols[ch];
}

char* l_to_str(unsigned int val, unsigned char len, unsigned char radix)
{
	static char buf[32] = { '0' };
	int i = 33;
	for (; val && i; --i, val /= radix)
		buf[i] = "0123456789ABCDEFGHIJKLMNOPQRSTUV"[val % radix];
	for (; i; i--)
		buf[i] = '0';
	return &buf[2 + (32 - len)];
}

/***
 *     .oooooo..o oooooo   oooo ooo        ooooo oooooooooo.    .oooooo.   ooooo         .oooooo..o 
 *    d8P'    `Y8  `888.   .8'  `88.       .888' `888'   `Y8b  d8P'  `Y8b  `888'        d8P'    `Y8 
 *    Y88bo.        `888. .8'    888b     d'888   888     888 888      888  888         Y88bo.      
 *     `"Y8888o.     `888.8'     8 Y88. .P  888   888oooo888' 888      888  888          `"Y8888o.  
 *         `"Y88b     `888'      8  `888'   888   888    `88b 888      888  888              `"Y88b 
 *    oo     .d8P      888       8    Y     888   888    .88P `88b    d88'  888       o oo     .d8P 
 *    8""88888P'      o888o     o8o        o888o o888bood8P'   `Y8bood8P'  o888ooooood8 8""88888P'  
 *                                                                                                  
 */

#define levlim(l)		if (PR_LEV >= l) return;
#define P_LEN 			(path -> sel_length)
#define P_IND 			(path -> sel_index)
#define P_ALC 			(path -> prg_allocbits)
#define P_LEV 			(path -> prg_level)
#define P_PIND			(path -> prg_index)
#define P_DATA 			(path -> prg_data)
#define P_OWNER			(path -> owner)
#define P_CHILD			(path -> child)
#define PR_START  		(P_RUNNING -> prg_start)
#define PR_LEV 			(P_RUNNING -> prg_level)

static void swaps(Path path)
{
	unsigned int i = 0;
	unsigned int report = 0;
	levlim(1)
	if (P_LEN == 1)	return;
	if (P_LEN <= BITS_IN_CELL)
	{
		unsigned int half_len = P_LEN / 2;
		write_by_bit_index(path, P_IND, P_LEN, read_by_bit_index(path, P_IND, half_len) | (read_by_bit_index(path, P_IND + half_len, half_len) << half_len));
		return;
	}
	while (i < ((P_LEN / BITS_IN_CELL) / 2))
	{
		report = P_DATA[(P_IND / BITS_IN_CELL) + i];
		P_DATA[(P_IND / BITS_IN_CELL) + i] = P_DATA[(P_IND / BITS_IN_CELL) + ((P_LEN / BITS_IN_CELL) / 2) + i];
		P_DATA[(P_IND / BITS_IN_CELL) + ((P_LEN / BITS_IN_CELL) / 2) + i++] = report;
	}
}

static void later(Path path)
{
	if (algn(path) || (PR_LEV >= 4))
		P_IND += P_LEN;
	else
		merge(path);
}

static void merge(Path path)
{
	levlim(7)
	if (P_LEN < P_ALC)
	{
		if (!algn(path))
			P_IND -= P_LEN;
		P_LEN <<= 1;
		return;
	}
	if (P_OWNER == NULL)
		return;
	P_WRITTEN = P_OWNER;
	(P_WRITTEN->sel_length) = 1;
	(P_WRITTEN->sel_index) = 1;
}

static void sifts(Path path)
{
	unsigned int write = P_IND;
	unsigned int read = 0;
	levlim(5)
	while(write<P_ALC)
	{
		if (write+read<P_ALC)
			while(!read_by_bit_index(path, write+read, 4))
				read += 4;
		if(read)
			write_by_bit_index(path, write, 4, (write+read<P_ALC)?read_by_bit_index(path, write+read, 4):0);
		write += 4;
		read += 4;
	}
}

static void execs(Path path, Path caller)
{
	unsigned int tempNum1 = 0;																/* Expedite calculation								*/
	levlim(8)																				/* Level operation checking							*/
	P_RUNNING = path;																		/* Set running 										*/

	if (P_CHILD == NULL)																	/* If there is no child 							*/
	{
		if ((P_CHILD = (calloc(1, sizeof(struct PATH)))) == NULL)							/* Allocate memory space 							*/
		{																					/* Cover error case							 		*/
			printf("FATAL ERROR: Unable to allocate memory.");
			return;
		}
		memcpy(P_CHILD, &NEW_PATH, sizeof(struct PATH));									/* Copy over initialization data			 		*/
		path->child->owner = path;															/* Set owner of this new Path 						*/
		path->child->prg_floor = (path->prg_floor) + 1;										/* Set floor of this new Path 						*/
		path->child->prg_data = calloc(1, sizeof(unsigned int));							/* Set data  of this new Path 						*/
	}

	P_WRITTEN = P_CHILD;																	/* Set this as written on 							*/
	P_PIND = (P_IND / 4);																	/* Set program pointer. Rounds down.x				*/
	PR_START = P_PIND;																		/* Track start position 							*/

	for (; doloop && P_PIND < (P_ALC / 4) && path != NULL && P_WRITTEN != NULL ; P_PIND++)	/* Execution Loop 									*/
	{
		tempNum1 = (P_RUNNING->prg_index);
		command = ((P_RUNNING->prg_data)[(tempNum1 * 4) / BITS_IN_CELL] >> (BITS_IN_CELL - ((tempNum1 * 4) % BITS_IN_CELL) - 4)) & mask(4);	/* Calculate command			*/

		if (command == 5)
			execs(P_WRITTEN, path);
		else if (command != 0)
			functions[command](P_WRITTEN);
	}
	if (caller == NULL)
	{
		free(P_CHILD);
		P_CHILD = NULL;
		return;
	}
	if (!doloop)
	{
		free(P_CHILD);
		P_CHILD = NULL;
		doloop = 1;
	}
	P_RUNNING = caller;
	P_WRITTEN = caller->child;
	return;
}

static void delev(Path path)
{
	if (PR_LEV > 0) PR_LEV--;
}

static void equal(Path path)
{
	levlim(5)
	if (read_by_bit_index(path, P_IND, 1) ^ read_by_bit_index(path, P_IND + P_LEN - 1, 1))
		skip();
}

static void halve(Path path)
{
	levlim(7)
	if (P_LEN > 1)
	{
		P_LEN /= 2;
		return;
	}
	if (P_CHILD == NULL)
		return;
	P_WRITTEN = P_CHILD;
	(P_WRITTEN->sel_length) = (P_WRITTEN->prg_allocbits);
}

static void uplev(Path path)
{
	levlim(9)
	PR_LEV++;
	(P_RUNNING->prg_index) = PR_START - 1;
}

static void reads(Path path)
{
	int pos = P_IND;
	levlim(6)
	if (P_LEN < 8)
	{
		char* out = bin(read_by_bit_index(path, pos, P_LEN));
		printf("%s", &out[strlen(out) - P_LEN]);
		return;
	}
	for (; pos < (P_IND + P_LEN); pos += 8)
		putchar(read_by_bit_index(path, pos, 8));
}

static void dealc(Path path)
{
	levlim(2)
	if (P_ALC == 1)
	{
		int report = read_by_bit_index(path, 0, 1);
		if ((P_RUNNING->owner) != NULL)
		{
			unsigned int ownind = ((P_RUNNING->owner)->prg_index);
			write_by_bit_index(P_RUNNING->owner, (ownind) * 4, 4, report);
		}
		free(P_DATA);
		P_DATA = NULL;
		doloop = 0;
		return;
	}
	P_ALC >>= 1;
	if (P_ALC <= 8)
		realloc(P_DATA, 1);
	else
		realloc(P_DATA, P_ALC / 8);
	if (P_LEN > 1)
		halve(path);
	if ((P_IND + P_LEN) > P_ALC)
		P_IND -= P_ALC;
}

static void split(Path path)
{
	if (PR_LEV < 1)
	{
		unsigned int len = P_LEN;
		if (len == 1)
		{
			if (P_CHILD == NULL)
				return;
			P_WRITTEN = P_CHILD;
			(P_WRITTEN->sel_length) = (P_WRITTEN->prg_allocbits);
			split(P_WRITTEN);
			halve(P_WRITTEN);
			return;
		}
		if (len <= BITS_IN_CELL)
		{
			write_by_bit_index(path, P_IND, len >> 1, mask(len));
			write_by_bit_index(path, P_IND + (len >> 1), len >> 1, ~mask(len));
		}
		else
		{
			unsigned int leftIndex = (P_IND / BITS_IN_CELL);
			unsigned int rightIndex = leftIndex + (len / BITS_IN_CELL) - 1;
			while (leftIndex < rightIndex)
			{
				P_DATA[leftIndex++] = 0xFFFFFFFF;
				P_DATA[rightIndex--] = 0;
			}
		}
	}
	halve(path);
}

static void polar(Path path)
{
	levlim(3)
	if (!(read_by_bit_index(path, P_IND, 1) && !read_by_bit_index(path, P_IND + P_LEN - 1, 1)))
		skip();
}

static void doalc(Path path)
{
	unsigned int new_cell_count = 0;
	unsigned int* new_data_pointer = NULL;
	levlim(1)
		P_ALC <<= 1;

	if (P_ALC <= BITS_IN_CELL)
		new_cell_count = BITS_IN_CELL / BITS_IN_BYTE;
	else
		new_cell_count = P_ALC / BITS_IN_BYTE;

	new_cell_count /= sizeof(unsigned int);

	if ((new_data_pointer = calloc(new_cell_count, sizeof(unsigned int))) == NULL)
	{
		printf("Error allocating %d bytes: ", new_cell_count * sizeof(unsigned int));
		perror("");
		abort();
	}

	if (new_cell_count > 1)
		memcpy(new_data_pointer, P_DATA, new_cell_count * sizeof(unsigned int) / 2);
	else
		memcpy(new_data_pointer, P_DATA, sizeof(unsigned int));

	P_DATA = new_data_pointer;

	merge(path);
}

static void input(Path path)
{
	int i = P_IND;
	levlim(6)
	if (P_LEN < 8)
	{
		write_by_bit_index(path, P_IND, P_LEN, getInput());
		return;
	}
	for (; i < (P_IND + P_LEN); i += 8)
		write_by_bit_index(path, i, 8, getInput());
}

/***
 *    oooooooooooo ooooooooooooo   .oooooo.   
 *    `888'     `8 8'   888   `8  d8P'  `Y8b  
 *     888              888      888          
 *     888oooo8         888      888          
 *     888    "         888      888          
 *     888       o      888      `88b    ooo  
 *    o888ooooood8     o888o      `Y8bood8P'  
 */

char algn(Path path)
{
	return P_IND % (P_LEN << 1) == 0;
}

unsigned int mask(int length)
{
	if (length < BITS_IN_CELL)	return ((int)1 << length) - 1;
	else			 			return 0xFFFFFFFF;
}

unsigned int read_by_bit_index(Path path, unsigned int i, unsigned int len)
{
	return (P_DATA[i / BITS_IN_CELL] >> (BITS_IN_CELL - (i % BITS_IN_CELL) - len)) & mask(len);
}

static void write_by_bit_index(Path path, unsigned int i, unsigned int len, unsigned int write)
{
	int shift = BITS_IN_CELL - (i % BITS_IN_CELL) - len;
	if (len > BITS_IN_CELL) abort();
	P_DATA[i / BITS_IN_CELL] &= ~(mask(len) << shift);
	P_DATA[i / BITS_IN_CELL] |= ((write & mask(len)) << shift);
}

static void skip()
{
	if (P_RUNNING == NULL) return;
	(P_RUNNING->prg_index)++;
}