#include <vector>
#include <queue>
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <regex>
namespace ov {
using namespace std;
struct NotImplemented : public exception {
const char * what () const throw () {
return "Not implemented.";
}
} NotImplemented;
struct NotAvailable : public exception {
const char * what () const throw () {
return "I/O is currently not available. You can try again.";
}
} NotAvailable;
struct BufferingRequired : public exception {
const char * what () const throw () {
return "I/O buffering must be enabled for this function, but it's not.";
}
} BufferingRequired;
struct NotAligned : public exception {
const char * what () const throw () {
return "Byte count can't be deserialized without remainder.";
}
} NotAligned;
struct AssemblerFatal : public exception {
const char * what () const throw () {
return "Fatal error in assembler.";
}
} AssemblerFatal;
struct SyntaxError : AssemblerFatal {
const char * what () const throw () {
return "Fatal syntax error in assembler.";
}
} SyntaxError;
struct EndlessArgument : public SyntaxError {
const char * what () const throw () {
return "Some builtin preprocessor command does not have enough arguments.";
}
} EndlessArgument;
struct EndlessBlock : public SyntaxError {
const char * what () const throw () {
return "Some builtin preprocessor block %* is not terminated with %end*.";
}
} EndlessBlock;
enum opts { // opts are pas-1 bits aftr last ram ptr (2**ras)-1 and can be w/r from prg
DEFAULT,
BUFOUT, // output from program in VM is always possible and no blocks
BUFIN, // input to program in VM is always possible and no blocks
BUFINCLR, // clears whatever is in the input buffer
BUFOUTCLR, // clears whatever is in the output buffer
OPTSLEN
}; // read those last bits with the COPY instruction with source/dest on last pointer
enum iobits {
INA, // input available, clear when read
IN, // input bit
OUTA, // output available, set when have output, cleared by VM when wrote
OUT, // output bit
IOLEN
};
enum instrs {
COPY,
NAND
};
struct instr { // deserializirana inštrukcija
unsigned int s = 0; // source
unsigned int d = 0; // destination
bool i = 0; // instruction
bool p = 0; // enobitni padding, lahko za metainštrukcije, pri COPY je že
}; // privzeto inicializiran na NOOP inštrukcijo
struct def {
vector<string> args;
string body;
};
class Ov;
template<typename value_type, typename index_type> class Ram {
private:
public:
vector<value_type> storage;
Ov * ov;
value_type peek (index_type);
void poke(index_type, value_type);
Ram (Ov *);
};
/* v Program (memory) bi lahko uporabili metainštrukcije (tisti padding bit) v
* vsaki inštrukciji in v metainštrukcijah reprezentirali assembly org (lokacijo).
* s tem bi lahko imeli npr. 128 biten program counter in s tem zelo preproste jumpe,
* ne bi pa bilo treba narediti 2^128 vektorja in posledično binarne datoteke.
* Tak način bi bilo verjetno težko implementirati na dejanski strojni opremi,
* tukaj pa bi v enem passu čez cel deserializan program memory zaznali te org
* metainštrukcije in naredili neko tabelo oziroma prevajalnik program counterja
* v lokacijo v vektorju. problem je, da bi se morala prevajalska tabela vsakič znova
* regenerirati, ko spreminjamo program memory.
* */
template<typename value_type, typename index_type> class Program {
private:
public:
index_type hiaddr;
vector<value_type> storage;
const struct instr empty;
Ov * ov;
value_type & peek (index_type addr) {
if (addr > hiaddr) {
hiaddr = addr;
storage.resize(hiaddr+1, empty);
}
return storage[addr];
}
void poke (index_type addr, value_type val) {
if (addr > hiaddr) {
hiaddr = addr;
storage.resize(hiaddr+1, empty /* avoid leaking memory */);
}
storage[addr] = val;
}
index_type length () {
return hiaddr+1;
}
Program (Ov * ov) : ov(ov) {
hiaddr = 0;
storage.push_back(empty); // we don't want to leak memory contents
}
};
class Ov {
private:
public:
queue<bool> inbuf;
queue<bool> outbuf;
unsigned int ras (void) {
return (is*8-2)/2;
}
unsigned int rs (void) {
return 1 << ras();
}
unsigned int ps (void) {
return 1 << pas;
}
unsigned short int is;
unsigned short int pas;
bool io[IOLEN];
bool opts[OPTSLEN];
unsigned int pc = 0; /* where the program starts --- at zero or where? */
Ram<bool, unsigned int> r{this};
Program<struct instr, unsigned int> p{this};
Ov (unsigned short int is = 2, unsigned short int pas = 16) :
is(is), pas(pas) { // TODO: check
for (int i = 0; i < OPTSLEN; i++)
opts[i] = 0;
for (int i = 0; i < IOLEN; i++) {
io[i] = 0;
}
}
void step (void);
bool out (void);
char outc (void);
void in (bool);
void inc (char);
struct instr deserialize (const char [sizeof(struct instr)]);
void deserialize (istream &, unsigned int);
void deserialize (string, unsigned int);
string serialize (struct instr *, unsigned int);
string serialize (struct instr);
void pd (ostream &);
};
vector<struct instr> assembler (string);
}