Skip to content

Instantly share code, notes, and snippets.

Created December 7, 2013 08:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/7838706 to your computer and use it in GitHub Desktop.
Save anonymous/7838706 to your computer and use it in GitHub Desktop.
Tiny assembler v0.04a, latest heavy code cleanup. Fully command line operable, will compile, and run TINY instruction files.
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>
#include <map>
#include <unordered_map>
#include <vector>
#include <ctime>
#include <climits>
#include <cstdlib>
using namespace std;
// Tiny Assembler
// v0.04alpha
// Heavy code cleanup
namespace tiny {
// mostly incorporated this throughout
struct tiny_error {
tiny_error(string m) : msg(m) {}
string msg;
}; // struct tiny_error
// helper functions for parser
bool IsLabel(const string &_str) {
// returns true if label format met
// anything_before_colon: used with ex. "jmp anything_before_colon"
if(_str.find_first_of(':') != std::string::npos) // found label delim
return true;
else
return false;
}
bool IsIndex(const string &_str) {
if(_str.find_first_of("[]") != std::string::npos) { // Found brackets
if(_str.substr(1,_str.size()-2).find_first_of("[]") == std::string::npos) { // No internal brackets
if(_str.at(0) == '[') { // Found opening bracket
if(_str.at(_str.size()-1) == ']') // Found closing bracket
return true; // Proper Index(mostly)
else
throw tiny_error("Missing closing bracket.");
}
else if(_str.at(_str.size()-1) == ']') // Found closing bracket
throw tiny_error("Missing opening bracket.");
else // catches bracket reversal ]x[
throw tiny_error("Misplaced bracket(s).");
}
else // brackets mid string
throw tiny_error("Misplaced bracket(s).");
}
else // no brackets
return false; // not indexed(mostly)
} // tiny::IsIndex(string)
void StripIndex(string &_str) {
_str = _str.substr(1,_str.size()-2);
}
// Mingw gcc 4.7.7 to_string workaround
// some more for stoull, stof, stod would be nice also
template<typename T> std::string to_string(const T& _str) {
std::stringstream oss;
oss << _str;
return oss.str();
}
// really filling in for stoull
// lazy hacks .. but meh
template<typename T, typename N> uint64_t stoi(const T& _str, const N& _sz) {
std::stringstream oss(_str);
uint64_t _tmp = 0;
if(_sz == 8) // octal
oss >> oct >> _tmp;
else if(_sz == 10) // decimal
oss >> dec >> _tmp;
else if(_sz == 16) // hexadecimal
oss >> hex >> _tmp;
else
oss >> _tmp; // Let it sort itself
return _tmp;
}
enum MNEM : uint64_t {
AND = 0x00, OR = 0x02, XOR = 0x04, NOT = 0x06,
MOV = 0x07, RANDOM = 0x09, ADD = 0x0A, SUB = 0x0C,
JMP = 0x0E, JZ = 0x10, JEQ = 0x14, JLS = 0x18,
JGT = 0x1C, APRINT = 0x20, DPRINT = 0x22, HALT = 0xFF,
INVALID = 0x100,
};
// bitshiftable for usage
enum SIG : uint64_t {
N = 0, M = 0x1, L = 0x2,
MM = 0x11, ML = 0x12,
LM = 0x21, LL = 0x22,
MMM = 0x111, LMM = 0x211,
MML = 0x112, LML = 0x212,
};
map<string, MNEM> MnemonicMap {
{"AND", AND}, {"OR", OR}, {"XOR", XOR}, {"NOT", NOT}, {"MOV", MOV},
{"RANDOM", RANDOM}, {"ADD", ADD}, {"SUB", SUB}, {"JMP", JMP}, {"JZ", JZ},
{"JEQ", JEQ}, {"JLS", JLS}, {"JGT", JGT}, {"HALT", HALT},
{"APRINT", APRINT}, {"DPRINT", DPRINT},
};
// Opcode lookup table
pair<MNEM, pair<SIG, uint64_t>> InstructionData [] = {
{AND, {MM, 0x00}}, {AND, {ML, 0x01}},
{OR, {MM, 0x02}}, {OR, {ML, 0x03}},
{XOR, {MM, 0x04}}, {XOR, {ML, 0x05}},
{NOT, {M, 0x06}}, {MOV, {MM, 0x07}},
{MOV, {ML, 0x08}}, {RANDOM,{M, 0x09}},
{ADD, {MM, 0x0a}}, {ADD, {ML, 0x0b}},
{SUB, {MM, 0x0c}}, {SUB, {ML, 0x0d}},
{JMP, {M, 0x0e}}, {JMP, {L, 0x0f}},
{JZ, {MM, 0x10}}, {JZ, {ML, 0x11}},
{JZ, {LM, 0x12}}, {JZ, {LL, 0x13}},
{JEQ, {MMM, 0x14}}, {JEQ, {LMM, 0x15}},
{JEQ, {MML, 0x16}}, {JEQ, {LML, 0x17}},
{JLS, {MMM, 0x18}}, {JLS, {LMM, 0x19}},
{JLS, {MML, 0x1a}}, {JLS, {LML, 0x1b}},
{JGT, {MMM, 0x1c}}, {JGT, {LMM, 0x1d}},
{JGT, {MML, 0x1e}}, {JGT, {LML, 0x1f}},
{APRINT, {M, 0x20}}, {APRINT, {L, 0x21}},
{DPRINT, {M, 0x22}}, {DPRINT, {L, 0x23}},
{HALT, {N, 0xff}},
};
unordered_multimap<MNEM, pair<SIG, uint64_t>, hash<uint64_t>>
InstructionMap(InstructionData, InstructionData + (sizeof(InstructionData) / sizeof(InstructionData[0])));
// used by the parser during initial pass
class Mnemonic_Instruction {
public:
Mnemonic_Instruction() : mnem(INVALID), sig(N) {}
Mnemonic_Instruction(string s) : mnem(INVALID), sig(N) { // one parser uses
stringstream ss(s);
string mnem_str;
ss >> mnem_str; // get mnemonic instrucion
for(auto &c : mnem_str)
c = toupper(c); // mnemonic touppercase
auto mnem_iter = MnemonicMap.find(mnem_str);
if(mnem_iter != MnemonicMap.end()) { // valid mnemonic
this->mnem = MnemonicMap[mnem_str]; // set mnemonic
string op_str;
uint64_t op_cnt = 0;
while(ss >> op_str) {
op_cnt++;
this->sig <<= 4;
if(IsIndex(op_str)) { //
StripIndex(op_str); // remove brackets
this->sig |= 1;
}
else
this->sig |= 2;
if(op_cnt == 1 && this->mnem >= 0x0e && this->mnem <=0x1f) {
// do nothing, lets jump instruction label targets get through
}
else if(op_str.find_first_not_of("1234567890") != std::string::npos) { // found a non-digit
throw tiny_error("Parser - Expected base 10 data: "+op_str);
}
this->ops.push_back(op_str); // load op vector
}
// validation of MNEM + SIG combo
auto match = InstructionMap.equal_range(this->mnem);
bool found = false;
for(auto it = match.first; it != match.second; it++) {
if(it->second.first == (SIG)this->sig) { // Found match
found = true;
}
}
if(!found) // No match for signature
throw tiny_error("Parser - Invalid instruction signature: "+tiny::to_string(this->sig));
}
else // invalid mnemonic
throw tiny_error("Parser - Invalid Mnemonic instruction: "+mnem_str);
}
// Nice easy lazy way ..
operator MNEM() { return mnem; }
operator SIG() { return (SIG)sig; }
operator string() const {
string _tmp = "";
for(auto &op : ops)
_tmp += " " + op;
return _tmp;
}
uint64_t size() { return ops.size()+1; }
private:
MNEM mnem;
uint64_t sig;
vector<string> ops;
};
// used by the parser for final pass output,
// and the machine when loading
class Translated_Instruction {
public:
Translated_Instruction() {}
// Convienance members
uint64_t Opcode() { return ops.at(0); }
uint64_t Op(uint64_t i) {
if(i < this->size()) {
return ops.at(i);
}
else
throw tiny_error("Parser::TI - out of range.");
}
uint64_t Op1() {
if(ops.size() >= 2)
return ops.at(1);
}
uint64_t Op2() {
if(ops.size() >= 3)
return ops.at(2);
}
uint64_t Op3() {
if(ops.size() > 3)
return ops.at(3);
}
void Push(uint64_t op) {
ops.push_back(op);
}
uint64_t size() { return ops.size(); }
operator string() const {
string _tmp = "";
for(uint64_t i = 1; i < ops.size(); i++) {
_tmp += tiny::to_string(ops.at(i)) + " ";
}
return _tmp;
}
private:
vector<uint64_t> ops;
};
class Parser {
public:
Parser() : _ready(false), _offset(0) {}
bool Push(string &s) {
bool valid = false;
if(!s.empty()) { // Something to push ..
s.erase(0,s.find_first_not_of(" \t")); // clear leading whitespace
auto comment = s.find(';'); // comment delim in line?
if(comment != std::string::npos) { // found a comment delim
s.erase(comment,s.size()); // erase from comment on
s = s.substr(0,s.find_last_not_of(" \t")+1); // erase trailing whitespace
cout << " ; trimmed";
}
if(IsLabel(s)) { // We have a label
string label_str = s.substr(0,s.find_first_of(':'));
if(_labelmap.find(label_str) == _labelmap.end()) {
_labelmap.insert(make_pair(label_str, _offset));
cout << " Added label: " << label_str;
valid = true;
}
else { // duplicate label
throw tiny_error("Parser::Push() - Duplicate Label: "+label_str);
}
}
else { // Not a label, parse for instruction
// start parsing instructions
if(!s.empty()) {
Mnemonic_Instruction mi(s);
if((MNEM)mi != INVALID) {
valid = true;
_mnemmap.insert(make_pair(_offset,mi));
_offset += mi.size();
}
else
throw tiny_error("Parser::Push() - Invalid mnemonic instruction.");
}
else
return valid;
}
}
else // empty line
return valid;
return valid;
}
void Resolve() {
for(auto &raw : _mnemmap) {
Translated_Instruction ti;
bool found = false;
auto range = InstructionMap.equal_range((MNEM)raw.second);
for(auto it = range.first; it != range.second; it++) {
if(it->second.first == (SIG)raw.second) {
found = true; // found the opcode
ti.Push(it->second.second); // push it in
}
}
if(found) { // Continue translating mnemonic instruction
if(ti.Opcode() >= 0x0e && ti.Opcode() <= 0x1f) { // jump instruction range
stringstream ss((string)raw.second);
string label;
ss >> label;
auto lit = _labelmap.find(label);
if(lit != _labelmap.end()) // matched the label
ti.Push(lit->second);
else
throw tiny_error("Parser::Resolve() - Invalid label target: "+label);
// fill any remaining ops
while(ss >> label) {
ti.Push(tiny::stoi(label,10));
}
}
else { // regular non-jump opcodes
stringstream ss((string)raw.second);
string tmp;
while(ss >> tmp) {
ti.Push(tiny::stoi(tmp,10));
}
}
}
else // should never see this
throw tiny_error("Parser::Resolve() - Invalid mnemonic instruction.");
_transmap.insert(make_pair(raw.first,ti));
}
return;
} // Parser::Resolve()
void Debug() {
// Debugging member function
cout << "\nParser debugging beginning.\n\n"
<< "Constructed label map: [name,target offset]" << endl;
for(auto &lab : _labelmap) {
cout << lab.first << ", " << lab.second << endl;
}
cout << "\nConstructed Mnemonic Instruction map: [Offset, Mnemonic, sig, ops]" << endl;
for(auto &m : _mnemmap) {
cout << setw(4) << m.first << ", Mnemonic: " << setw(3) << (MNEM)m.second << ", SIG: "
<< setw(3) << (SIG)m.second; // << (m.second.size() > 1 ? ", Ops:" : "");
if(m.second.size() > 1) { // ops to show
cout << ", Ops:" << (string)m.second;
}
cout << endl;
}
cout << "\nConstructed Translated Instruction map: [offset, opcode, ops]" << endl;
for(auto &t : _transmap) {
cout << setw(4) << t.first << ", Opcode: " << setw(3) << t.second.Opcode();
if(t.second.size() > 1) {
cout << ", Ops: " << (string)t.second;
}
cout << endl;
}
}
bool Load(const string &file) {
bool valid = false;
if(this->_ready) // File previously loaded
this->Unload(); // Unload
ifstream in(file,ios::in);
if(!in.is_open()) // file not opened
throw tiny_error("Parser::Load() - Could not load: "+file);
else {
string line = "";
uint64_t errors = 0;
uint64_t linenum = 0;
while(getline(in,line)) {
linenum++;
try { // catch tiny_errors in this feed loop to
// validate the instructions read in
// and provide valuable feedback on errors
// to the user.
cout << setw(4) << linenum;
if(!line.empty()) { // something to push..
if(this->Push(line))
cout << " Valid";
else if(line.empty())
cout << " Empty";
else
cout << " Invalid";
}
else
cout << " Empty";
cout << endl;
} catch(tiny::tiny_error err) {
errors++;
cout << " Error: " << err.msg << endl;
}
}
if(errors == 0) { // no errors
valid = true;
this->_ready = true; // file loaded, flip ready flag
}
in.close();
}
return valid;
}
bool Write(const string &file) {
bool valid = false;
if(!this->_ready) // No file loaded to write
throw tiny_error("Parser::Write() - Must load a file first.");
ofstream out(file,ios::trunc); // open outputfile, overwrite existing
if(!out.is_open()) { // file not open/doesn't exist
throw tiny_error("Parser::Write() - Could not write: "+file);
}
else { // file open, begin writing it
for(auto &t : _transmap) {
out << showbase <<hex << t.second.Opcode();
for(uint64_t i = 1; i < t.second.size(); i++) {
out << " " << showbase << hex << t.second.Op(i);
}
out << endl;
}
valid = true;
}
out.close();
return valid;
}
private:
void Unload() {
if(this->_ready) {
this->_ready = false; // no longer ready
this->_offset = 0; // reset offset marker
this->_mnemmap.clear(); // clear the data
this->_transmap.clear();
this->_labelmap.clear();
}
}
bool _ready;
uint64_t _offset;
map<uint64_t, Mnemonic_Instruction> _mnemmap;
map<uint64_t, Translated_Instruction> _transmap;
map<string, uint64_t> _labelmap;
};
class Machine {
public:
Machine() : _ready(false), _offset(0) {}
void Push(const string &s) {
stringstream ss(s);
uint64_t op = 0;
Translated_Instruction ti;
while(ss >> hex >> op)
ti.Push(op);
_transmap.insert(make_pair(_offset,ti));
_offset += ti.size();
}
bool Load(const string &file) {
bool valid = false;
if(this->_ready) // file previously loaded
this->Unload(); // unload
ifstream in(file,ios::in);
if(!in.is_open())
throw tiny_error("Machine::Load() - Could not load: "+file);
else { // open file, good to load
string line = "";
while(getline(in,line)) {
if(!line.empty())
this->Push(line);
}
valid = true;
}
this->_ready = valid;
return valid;
}
void Run() { // runs the loaded file
if(!this->_ready)
throw tiny_error("Machine::Run() - Must load a *.tny file first.");
else {
cout << "\nProgram Running." << endl;
auto current = _transmap.begin();
auto next = _transmap.end();
uint64_t mem[256] = {0};
uint64_t stop = 0;
bool running = true;
srand(time(NULL)); // prep for random
while(running && (current != _transmap.end())) {
if(stop >= ULLONG_MAX-1)
running = false; // thats a lot of instructions
switch(current->second.Opcode()) { // switch on opcode
case 0x00:
mem[current->second.Op(1)] &= mem[current->second.Op(2)];
break;
case 0x01:
mem[current->second.Op(1)] &= current->second.Op(2);
break;
case 0x02:
mem[current->second.Op(1)] |= mem[current->second.Op(2)];
break;
case 0x03:
mem[current->second.Op(1)] |= current->second.Op(2);
break;
case 0x04:
mem[current->second.Op(1)] ^= mem[current->second.Op(2)];
break;
case 0x05:
mem[current->second.Op(1)] ^= current->second.Op(2);
break;
case 0x06: //Not [a] bitwise not ~
mem[current->second.Op(1)] = ~mem[current->second.Op(1)];
break;
case 0x07:
mem[current->second.Op(1)] = mem[current->second.Op(2)];
break;
case 0x08:
mem[current->second.Op(1)] = current->second.Op(2);
break;
case 0x09:
mem[current->second.Op(1)] = rand() % 25+1;
break;
case 0x0a:
mem[current->second.Op(1)] += mem[current->second.Op(2)];
break;
case 0x0b:
mem[current->second.Op(1)] += current->second.Op(2);
break;
case 0x0c:
mem[current->second.Op(1)] -= mem[current->second.Op(2)];
break;
case 0x0d:
mem[current->second.Op(1)] -= current->second.Op(2);
break;
case 0x0e: // Jmp [x]
next = _transmap.find(mem[current->second.Op(1)]);
break;
case 0x0f: // jmp x
next = _transmap.find(current->second.Op(1));
break;
case 0x10: // jz [x] [a]
if(mem[current->second.Op(2)] == 0)
next = _transmap.find(mem[current->second.Op(1)]);
break;
case 0x11: // jz x [a]
if(current->second.Op(2) == 0)
next = _transmap.find(mem[current->second.Op(1)]);
break;
case 0x12: // jz [x] a
if(mem[current->second.Op(2)] == 0)
next = _transmap.find(current->second.Op(1));
break;
case 0x13: // jz x a
if(current->second.Op(2) == 0)
next = _transmap.find(current->second.Op(1));
break;
case 0x14: // jeq [x] [a] [b]
if(mem[current->second.Op(2)] == mem[current->second.Op(3)])
next = _transmap.find(mem[current->second.Op(1)]);
break;
case 0x15:
if(mem[current->second.Op(2)] == mem[current->second.Op(3)])
next = _transmap.find(current->second.Op(1));
break;
case 0x16:
if(mem[current->second.Op(2)] == current->second.Op(3))
next = _transmap.find(mem[current->second.Op(1)]);
break;
case 0x17:
if(mem[current->second.Op(2)] == current->second.Op(3))
next = _transmap.find(current->second.Op(1));
break;
case 0x18: // jls [x] [a] [b]
if(mem[current->second.Op(2)] < mem[current->second.Op(3)])
next = _transmap.find(mem[current->second.Op(1)]);
break;
case 0x19:
if(mem[current->second.Op(2)] < mem[current->second.Op(3)])
next = _transmap.find(current->second.Op(1));
break;
case 0x1a:
if(mem[current->second.Op(2)] < current->second.Op(3))
next = _transmap.find(mem[current->second.Op(1)]);
break;
case 0x1b: // jls x [a] b
if(mem[current->second.Op(2)] < current->second.Op(3))
next = _transmap.find(current->second.Op(1));
break;
case 0x1c: // jgt [x] [a] [b]
if(mem[current->second.Op(2)] > mem[current->second.Op(3)])
next = _transmap.find(mem[current->second.Op(1)]);
break;
case 0x1d:
if(mem[current->second.Op(2)] > mem[current->second.Op(3)])
next = _transmap.find(current->second.Op(1));
break;
case 0x1e:
if(mem[current->second.Op(2)] > current->second.Op(3))
next = _transmap.find(mem[current->second.Op(1)]);
break;
case 0x1f: // jgt x [a] b
if(mem[current->second.Op(2)] > current->second.Op(3))
next = _transmap.find(current->second.Op(1));
break;
case 0x20: // aprint [a]
cout << (char)mem[current->second.Op(1)];
break;
case 0x21: // aprint a
cout << (char)current->second.Op(1);
break;
case 0x22: // dprint [a]
cout << dec << mem[current->second.Op(1)];
break;
case 0x23: // dprint a
cout << dec << current->second.Op(1);
break;
case 0xff: // halt
running = false;
break;
default:
cout << "Illegal instruction. Exiting." << endl;
running = false;
break;
} // massive switch
stop++; // increment executed instruction count.
if(next != _transmap.end()) { // jmp instruction called
current = next; // set current ptr to jmp target
next = _transmap.end(); // reset next sentinal
}
else {
current++; // increment instruction ptr
if(current == _transmap.end()) // at the end for some reason
running = false; // stop running
}
} // while()
cout << "Executed: " << stop << " Instructions." << endl;
}
return;
}
void Debug() {
cout << "\nMachine debugging starting." << endl;
cout << "\nLoaded Runfile. [offset,opcode,ops...]" << endl;
for(auto &t : _transmap) {
cout << setw(4) << showbase << hex << t.first;
for(uint64_t i = 0; i < t.second.size(); i++) {
cout << " " << setw(4) << showbase << hex << t.second.Op(i);
}
cout << endl;
}
}
private:
void Unload() {
if(this->_ready) {
this->_ready = false;
this->_offset = 0;
this->_transmap.clear();
}
}
bool _ready;
uint64_t _offset;
map<uint64_t, Translated_Instruction> _transmap;
};
} // namespace tiny
struct Options {
bool help = false; // -h
bool debug = false; // -d
bool compile = false; // -c
bool output = false; // -o
bool run = false; // -r
string sourcefile = ""; // -c <sourcefile>
string outputfile = ""; // -o <outputfile>
string runfile = ""; // -r <runfile>
operator string() { // debugging string operator
string _tmp = "Help: "; _tmp += (help ? "Yes" : "No");
_tmp += "\nDebug: "; _tmp += (debug ? "Yes" : "No");
_tmp += "\nCompile: "; _tmp += (compile ? "Yes" : "No");
_tmp += "\nOutput: "; _tmp += (output ? "Yes" : "No");
_tmp += "\nRuncode: "; _tmp += (run ? "Yes" : "No");
_tmp += "\nSourcefile: "; _tmp += (sourcefile.empty() ? "None" : sourcefile);
_tmp += "\nOutputfile: "; _tmp += (outputfile.empty() ? "None" : outputfile);
_tmp += "\nRunfile: "; _tmp += (runfile.empty() ? "None" : runfile);
_tmp += "\n";
return _tmp;
}
};
void Usage() { // prints program usage/ -h
cout << "Usage: tinyasm -d ; Runs internal tests\n"
<< " : tinyasm -h ; Prints this helpfile\n"
<< " : tinyasm -c <source.txt> ; Sets tiny sourcefile to compile\n"
<< " : tinyasm -o <output.tny> ; Sets outputfile, defaults to source.tny\n"
<< " : tinyasm -r <file.tny> ; runs file.tny, defaults to output.tny\n\n"
<< "EX: tinyasm -c <src> -o <out> -r ; Compiles src->out then runs <out> if valid\n"
<< "EX: tinyasm -c <src> -r ; Compiles then runs src.tny if valid\n"
<< "EX: tinyasm -c <src> -o -r <foo> ; Compiles src to src.tny then runs foo"
<< endl;
}
bool ParseCommandLine(Options &opts, vector<string> &args) {
// Still a little buggy, needs a better parsing pattern as this just seems
// clunky to me. Further it will blindly take the next arg when dealing with -c, -o, -r
// Need to fine tune
// EX: prog -c -d -r, will try to compile '-d' and then try to run '-d.tny', with no debugging
// Mostly a minor problem, as they will be caught later, but should be done here
if(args.empty()) // no args
return false;
while(!args.empty()) { // command line arguments to parse!
if(args.at(0) == "-h") { // help called for
opts.help = true;
args.erase(args.begin());
return false; // break out of parse loop, help doesn't care about other switches
}
else if(args.at(0) == "-d") { // debug called
opts.debug = true;
args.erase(args.begin());
}
else if(args.at(0) == "-c") { // compile called
opts.compile = true;
if(args.size() > 1) { // requires sourcefile argument
opts.sourcefile = args.at(1);
args.erase(args.begin(), args.begin()+1);
}
else {
args.erase(args.begin());
cout << "-c requires a filename argument. EX: -c source.txt" << endl;
return false; // switch requirement not met,
}
}
else if(args.at(0) == "-o") { // outputfile called
opts.output = true;
if(args.size() > 1) {
opts.outputfile = args.at(1);
args.erase(args.begin(), args.begin()+1);
}
else
args.erase(args.begin());
}
else if(args.at(0) == "-r") { // runfile called
opts.run = true;
if(args.size() > 1) {
opts.runfile = args.at(1);
args.erase(args.begin(), args.begin()+1);
}
else
args.erase(args.begin());
}
else // Invalid command line switch
args.erase(args.begin());
} // no more args
// work out the filenames as needed
bool compile = opts.compile;
bool output = opts.output;
bool run = opts.run;
if(!compile && output) { // -o called w/o -c, error
cout << "-o must be called with -c <source>" << endl;
return false;
}
if(compile && !output) { // -c called w/o -o, default
opts.output = true; // activate output, outputfile caught next
output = true;
}
if(output && opts.outputfile.empty()) // -o called w/o argument, default
opts.outputfile = opts.sourcefile + ".tny"; // to sourcefile.tny
if(run && opts.runfile.empty()) {// -r called w/o argument,
if(compile) // -c called as well, default
opts.runfile = opts.outputfile; // to outputfile name
else { // -c NOT called, error
cout << "-r requires a runfile if not called with -c" << endl;
return false;
}
}
if(opts.debug) // debug invoked, this included
cout << "Options As Follows\n" << (string)opts << endl;
return true;
}
int main(int argc, char** argv) {
cout << "Tiny Assembler v0.04a" << endl;
// Begin startup
Options opts; // command line option structure
vector<string> args; // vector to fill command line arguments with
for(int i = 1; i < argc; i++) // start at argv[1] to skip program pathname
args.push_back(argv[i]); // load the arg vector
bool startup = ParseCommandLine(opts,args);
if(!startup) { // Not ready to startup
Usage(); // Print help
return -1; // exit
}
using namespace tiny;
// Begin
uint64_t errors = 0;
if(opts.compile) { // -c called. Do our work
Parser p; // Fire up the parser
try {
if(p.Load(opts.sourcefile)) // -c <sourcefile>
cout << opts.sourcefile << " Loaded." << endl;
p.Resolve();
if(p.Write(opts.outputfile)) // -o inferred with -c
cout << opts.outputfile << " Written." << endl;
} catch(tiny::tiny_error err) {
errors++;
cout << "Error: " << err.msg << endl;
}
if(opts.debug)
p.Debug();
}
if(opts.run) { // -r
Machine m; // Start the machine
try {
if(m.Load(opts.runfile))
cout << opts.runfile << " Loaded." << endl;
m.Run();
} catch(tiny::tiny_error err) {
errors++;
cout << "Error: " << err.msg << endl;
}
if(opts.debug)
m.Debug();
}
cout << setw(2) << errors << " Errors." << endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment