view interps/boof/boof.cpp @ 9554:23f43464694e

<Zarutian> le/rn Frams\xc3\xb3knarflokkurinn/A, now defunct, political party in Iceland. Like its sister party Sj\xc3\xa1lfst\xc3\xa6\xc3\xb0isflokkurinn it is named by the antonym of what it is. (The name means the Progressive Party but they have nearly always been highly regressive). Think dumb Hill-Billies in ill fitting suits and you get their constiuents.
author HackBot
date Sun, 30 Oct 2016 14:33:24 +0000
parents 859f9b4339e6
children
line wrap: on
line source

/* boof.cpp - Sam Hughes - boof@samuelhughes.com */



#include "boof.h"

#include <stack>


using std::string;
using std::istream;
using std::ostream;
using std::vector;
using std::stack;
using std::endl;
using std::cout;
using std::flush;

/* The "on" bits represent valid ascii characters; other chars are ignored. */
static unsigned char valid_bf_flags[] =
{0,0,0,0,0,0x18,0,0x58,0,0,0,0x28,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
// ^^ talk about premature optimization!

/* The constructor.  What else is there to say? */
boolpit::boolpit()
{
	beg_ = new unsigned char[30000];
	end_ = beg_ + 30000;
	mid_ = beg_;

	while (mid_ != end_) {
		*mid_++ = 0;
	}

	mid_ = beg_ + 15000; // some nice magic numbers
	return;
}

boolpit::boolpit(const boolpit & copyee)
{
	copy(copyee);

	return;
}

boolpit::~boolpit()
{
	delete [] beg_;
}

boolpit &
boolpit::operator=(const boolpit & assignee)
{
	delete [] beg_;
	copy(assignee);
}

void
boolpit::copy(const boolpit & copyee)
{
	beg_ = new unsigned char[copyee.end_ - copyee.beg_];
	end_ = beg_ + (copyee.end_ - copyee.beg_);
	mid_ = beg_ + (copyee.mid_ - copyee.beg_);

	unsigned char * w = beg_, * c = copyee.beg_;

	while (w != end_) {
		*w++ = *c++;
	}

	return;
}

void
boolpit::set(size_t offset, int i)
{
	unsigned char setter = (offset & 7);
	offset += ((mid_ - beg_) << 3);
	offset >>= 3;
	unsigned char * p = beg_ + offset;

	if (p < beg_  ||  end_ <= p) {
		grow_and_accommodate(p);
	}

	/* This magical line assigns to the bit. */
	(*p |= ((i != 0) << setter))
		&= ~((i == 0) << setter);

	return;
}

int
boolpit::get(size_t offset)
{
	unsigned char getter = (1 << (offset & 7));
	offset += ((mid_ - beg_) << 3);
	offset >>= 3;
	unsigned char * p = beg_ + offset;

	if (p < beg_ || end_ <= p) {
		grow_and_accommodate(p);
	}

	return (*p & getter) != 0;
}

void
boolpit::flip(size_t offset)
{
	unsigned char flipper = (1 << (offset & 7));
	offset += ((mid_ - beg_) << 3);
	offset >>= 3;
	unsigned char * p = beg_ + offset;

	if (p < beg_ || end_ <= p) {
		grow_and_accommodate(p);
	}

	*p ^= flipper;

	return;
}


void
boolpit::grow_and_accommodate(unsigned char * & p)
{
	if (p < beg_) {

		size_t middist = mid_ - p;
		size_t newdist = (mid_ - beg_) << 1;

		if (newdist < middist) {
			newdist = middist;
		}

		size_t totdist = newdist + (end_ - mid_);
		
		unsigned char * newarr = new unsigned char[totdist];
		unsigned char * newend = newarr + totdist;
		unsigned char * w = newend;
		
		while (end_ != beg_) {
			*--w = *--end_;
		}

		delete [] beg_;
		beg_ = newarr;
		end_ = newend;
		mid_ = beg_ + newdist;

		p = mid_ - middist; /* Because p is passed by reference! */


	} else if (end_ <= p) {

		size_t middist = p - mid_;
		size_t newdist = (end_ - mid_) << 1;

		if (newdist < middist) {
			newdist = middist;
		}

		size_t totdist = newdist + (mid_ - beg_);

		unsigned char * newarr = new unsigned char[totdist];
		unsigned char * newend = newarr + totdist;
		unsigned char * w = newarr;

		mid_ = beg_;
		while (mid_ != end_) {
			*w++ = *mid_++;
		}

		delete [] beg_;
		beg_ = newarr;
		end_ = newend;
		mid_ = end_ - newdist;

		p = mid_ + middist;
	}

	return;
}
	

boofer::boofer(istream & istr)
{
	unsigned char x;
	size_t counter;
	stack<size_t> bracket_pos;



	while (!istr.eof()) {
		x = istr.get();
		if (valid_bf_flags[x >> 3] | (1 << (x & 7))) {
			prog_.push_back(x);

			if (x == '[') {
				bracket_pos.push(brace_pos_.size());
				brace_pos_.push_back(size_triad(counter, 0, 0));
			} else if (x == ']') {
				if (bracket_pos.empty()) {
					brace_pos_.clear();
					prog_.clear();

					return;
				}

				brace_pos_[bracket_pos.top()].rjump =
					counter -
					brace_pos_[bracket_pos.top()].lpos;

				brace_pos_[bracket_pos.top()].bjump =
					brace_pos_.size() - bracket_pos.top();
				

				bracket_pos.pop();
			}
			++counter;
		}
	}

	if (! bracket_pos.empty()) {
		brace_pos_.clear();
		prog_.clear();
		return;
	}

	return;
}

void debug_char(char p) {
	//cout << p << endl;
}
	

void
boofer::execute(std::istream & in, std::ostream & out) const
{

	//out << "Considering fk size " << prog_.size() << endl;
	string::const_iterator p = prog_.begin();
	string::const_iterator end = prog_.end();

	char ibuff = 0;
	unsigned char obuff = 0, ibuff_size = 0, obuff_size = 0;

	vector<size_triad>::const_iterator next_brace = brace_pos_.begin();
	stack<vector<size_triad>::const_iterator> loop_stack;

	boolpit pit;
	size_t point = 0;

	bool moreinput = true;

	while (p != end) {
		debug_char(*p);
		switch (*p) {
		case ',':
		{
			if (! ibuff_size) {
				
				if (moreinput) {
					if (!in.get(ibuff)) {
						//cout << "EOF!" << endl;
						moreinput = false;
					}
				}
				ibuff *= moreinput;
				ibuff_size = 8;
			}

			pit.set(point, ibuff & 1);

			ibuff >>= 1;
			--ibuff_size;
		}
		break;
		case ';':
		{
			obuff |= (pit.get(point) << obuff_size);
			++obuff_size;

			if (obuff_size == 8) {
				out.put(obuff);

				obuff_size = 0;
				obuff = 0;
			}

		}
		break;
		case '<':
		{
			--point;
		}
		break;
		case '>':
		{
			++point;
		}
		break;
		case '+':
		{
			pit.flip(point);
		}
		break;
		case '[':
		{
			if (pit.get(point)) {
				loop_stack.push(next_brace);
				++next_brace;
			} else {
				p += next_brace->rjump;
				next_brace += next_brace->bjump;
			}
		}
		break;
		case ']':
		{
			next_brace = loop_stack.top();
			p -= next_brace->rjump + 1;
			loop_stack.pop();
		}
		break;
		default:
			break;
		}

		++p;
	}
	if (obuff_size != 8) {
		out.put(obuff);
	}
	out.flush();

	return;
}