/** * * Is a virtual machine for parsing. It has some ideas * drawn from the sed tool. * * @author http://bumble.sf.net */ // good examples // http://www.josuttis.com/libbook/i18n/loc1.cpp.html #include <iostream> #include <vector> #include <stack> #include <string> #include <sstream> #include <ctype.h> #include "Tape.h" using namespace std; class Machine { private: //-------------------------------------------- vector<string> tokenstack; //-------------------------------------------- Tape tape; //-------------------------------------------- /* where the stack and tape are used */ string workarea; //-------------------------------------------- string influx; //-------------------------------------------- string lastOperation; public: //-------------------------------------------- Machine(); //-------------------------------------------- string getWorkspace(); //-------------------------------------------- string workspace(); //-------------------------------------------- string accumulator(); //-------------------------------------------- /** this method may not be necessary, can check with pops */ int stacksize(); //-------------------------------------------- bool matches(string sTest); //-------------------------------------------- /* determines if the workspace is a space character */ bool isSpace(); //-------------------------------------------- /* determines if the workspace is a digit character */ bool isDigit(); //-------------------------------------------- /* determines if the workspace is a letter character */ bool isLetter(); //-------------------------------------------- bool isUnicode(); //-------------------------------------------- /* to allow simple pattern testing for literal values */ bool workspaceInRange(char cStart, char cEnd); //-------------------------------------------- /* to allow simple pattern testing for literal values */ bool matches(char cStart, char cEnd); //-------------------------------------------- /** decrements the pointer to the tape by one */ void decrementTape(); //-------------------------------------------- /** increments the pointer to the tape by one */ void incrementTape(); //-------------------------------------------- /** puts the workspace into the current item of the tape. * The workspace is not changed */ void put(); //-------------------------------------------- /** gets the current item of the tape and adds it to * the end of the workspace */ void get(); //-------------------------------------------- /** inserts the last item of the stack at the front of the workspace, * adding a bar character "|" to separate the token. If the * stack is empty, there is no change to the machine. */ void pop(); //-------------------------------------------- string replaceText(string sOriginal, string sReplace, string sReplacement); //-------------------------------------------- /** pushes the contents of the workspace onto the stack. * The first token on the workspace is deleted. */ void push(); //-------------------------------------------- /* shifts the accumulator into the workspace */ void shift(); //-------------------------------------------- /** prints the workspace to standard out */ void print(); //-------------------------------------------- /** adds a piece of text to the end of the workspace */ void add(string sText); //-------------------------------------------- /** clears the workspace */ void clear(); //-------------------------------------------- /** anyade una nueva linea al espacio */ void newline(); //-------------------------------------------- /** indents each line of the workspace, which may * be useful for print code fragments */ void indent(); //-------------------------------------------- string toString(); //-------------------------------------------- string Machine::printStack(); //-------------------------------------------- /** returns a description of the current state of the machine, displays the * contents of the stack, tape and the workspace. */ string printState(); }; //-- class definition //-------------------------------------------- Machine::Machine() { stack<string> tokenstack; Tape tape; string influx(""); string workarea(""); string lastOperation("NEW MACHINE"); } //-------------------------------------------- string Machine::getWorkspace() { return this->workarea; } //-- //-------------------------------------------- string Machine::workspace() { return this->workarea; } //-- //-------------------------------------------- string Machine::accumulator() { return this->influx; } //-- //-------------------------------------------- /** this method may not be necessary, can check with pops */ int Machine::stacksize() { return this->tokenstack.size(); } //-------------------------------------------- bool Machine::matches(string sTest) { if (this->workarea == sTest) { return true; } return false; } //-------------------------------------------- /* determines if the workspace is a space character */ bool Machine::isSpace() { if (this->workarea.length() != 1) { return false; } if (isspace(this->workarea.at(0))) { return true; } return false; } //-- //-------------------------------------------- /* determines if the workspace is a digit character */ bool Machine::isDigit() { if (this->workarea.length() != 1) { return false; } if (isdigit(this->workarea.at(0))) { return true; } return false; } //-- //-------------------------------------------- /* determines if the workspace is a letter character */ bool Machine::isLetter() { if (this->workarea.length() != 1) { return false; } if (isalpha(this->workarea.at(0))) { return true; } return false; } //-- //-------------------------------------------- /* bool Machine::isUnicode() { if (this->workarea.length() != 1) { return false; } if (Character.isDefined(this->workarea.at(0))) { return true; } return false; } //-- */ //-------------------------------------------- /* to allow simple pattern testing for literal values */ bool Machine::workspaceInRange(char cStart, char cEnd) { if (this->workarea.length() > 1) { return false;} char cCharacter = this->workarea.at(0); if (cCharacter < cStart) { return false; } if (cCharacter > cEnd) { return false; } return true; } //-------------------------------------------- /* to allow simple pattern testing for literal values */ bool Machine::matches(char cStart, char cEnd) { if (this->workarea.length() > 1) { return false;} char cCharacter = this->workarea.at(0); if (cCharacter < cStart) { return false; } if (cCharacter > cEnd) { return false; } return true; } //-- //-------------------------------------------- /** decrements the pointer to the tape by one */ void Machine::decrementTape() { this->tape.decrementPointer(); this->lastOperation.clear(); this->lastOperation.append("decrement-tape"); } //-- //-------------------------------------------- /** increments the pointer to the tape by one */ void Machine::incrementTape() { this->tape.incrementPointer(); this->lastOperation.clear(); this->lastOperation.append("increment-tape"); } //-- //-------------------------------------------- /** puts the workspace into the current item of the tape. * The workspace is not changed */ void Machine::put() { this->tape.put(this->workarea); this->lastOperation.clear(); this->lastOperation.append("put"); } //-- //-------------------------------------------- /** gets the current item of the tape and adds it to * the end of the workspace */ void Machine::get() { this->workarea.append(this->tape.get()); this->lastOperation.clear(); this->lastOperation.append("get"); } //-- //-------------------------------------------- /** inserts the last item of the stack at the front of the workspace, * adding a bar character "|" to separate the token. If the * stack is empty, there is no change to the machine. */ void Machine::pop() { if (this->tokenstack.empty()) { this->lastOperation.clear(); this->lastOperation.append("pop [stack empty]"); return; } string sSymbol(this->tokenstack.at(this->tokenstack.size() - 1)); this->tokenstack.pop_back(); string sText(this->replaceText(sSymbol, "|", "&bar;")); this->workarea.insert(0, sText + "|"); this->tape.decrementPointer(); this->lastOperation.clear(); this->lastOperation.append("pop"); } //-- string Machine::replaceText(string sOriginal, string sReplace, string sReplacement) { string::size_type iFirst = sOriginal.find(sReplace, 0 ); if (iFirst == string::npos) { return sOriginal; } sOriginal.replace(iFirst, sReplace.length(), sReplacement); return sOriginal; } //-- //-------------------------------------------- /** pushes the contents of the workspace onto the stack. * The first token on the workspace is deleted. */ void Machine::push() { if (this->workarea.length() < 1) { this->lastOperation.clear(); this->lastOperation.append("push [workspace empty]"); return; } this->lastOperation.clear(); this->lastOperation.append("push"); string::size_type iFirstBar = this->workarea.find("|", 0 ); if (iFirstBar == string::npos) { string sText(this->replaceText(this->workarea, "&bar;", "|")); this->tokenstack.push_back(sText); this->tape.incrementPointer(); this->workarea.clear(); return; } string sFirstToken(this->workarea.substr(0, iFirstBar)); string sText(this->replaceText(sFirstToken, "&bar;", "|")); this->tokenstack.push_back(sText); this->workarea = this->workarea.substr(iFirstBar + 1); this->tape.incrementPointer(); return; } //-- method: push //-------------------------------------------- /** */ void Machine::shift() { this->workarea.append(this->influx); this->influx.clear(); this->lastOperation.clear(); this->lastOperation.append("shift"); } //-------------------------------------------- /** prints the workspace to standard out */ void Machine::print() { cout << this->workarea; this->lastOperation.clear(); this->lastOperation.append("print"); } //-------------------------------------------- /** adds a piece of text to the end of the workspace */ void Machine::add(string sText) { this->workarea.append(sText); this->lastOperation.clear(); this->lastOperation.append("add"); } //-------------------------------------------- /** clears the workspace */ void Machine::clear() { this->workarea.clear(); this->lastOperation.clear(); this->lastOperation.append("clear"); } //-------------------------------------------- /** anyade una nueva linea al espacio */ void Machine::newline() { this->workarea.append("\n"); this->lastOperation.clear(); this->lastOperation.append("newline"); } //-------------------------------------------- /** indents each line of the workspace, which may * be useful for print code fragments */ void Machine::indent() { string sText(this->workarea); this->workarea.clear(); char cCurrent; this->workarea.append(" "); for (int ii = 0; ii < sText.length(); ii++) { cCurrent = sText[ii]; this->workarea += cCurrent; if (cCurrent == '\n') { this->workarea.append(" "); } } //-- for this->lastOperation.clear(); this->lastOperation.append("indent"); } //-- method: indent //-------------------------------------------- /** */ string Machine::toString() { return ""; } //-- method: //-------------------------------------------- /** returns a description of the current state of the machine, displays the * contents of the tokenstack, tape and the workspace. */ string Machine::printState() { string sMessage(""); sMessage.append("\n"); sMessage.append("last operation:" + this->lastOperation); sMessage.append("\n"); sMessage.append("ACCUMULATOR:["); sMessage.append(this->influx); sMessage.append("]"); sMessage.append("\n"); sMessage.append("WORKSPACE:["); sMessage.append(this->workarea); sMessage.append("]"); sMessage.append("\n"); sMessage.append("STACK :"); sMessage.append(this->printStack()); sMessage.append("\n"); sMessage.append("TAPE :"); sMessage.append("\n"); sMessage.append(this->tape.print()); sMessage.append("\n"); return sMessage; } //-- method: //-------------------------------------------- /* shows the contents of the stack in a concise form */ string Machine::printStack() { string sCurrentItem(""); string sMessage("["); for (int ii = 0; ii < this->tokenstack.size(); ii++) { sMessage.append(this->tokenstack.at(ii)); sMessage.append(", "); } sMessage.append("]"); return sMessage; } //-- method: //-------------------------------------------- /** provides a command loop to test the machine operations and view the machine */ int main() { string sUsageMessage(""); sUsageMessage.append("test usage: java Machine "); sUsageMessage.append("\n"); string sMessage(""); /* if (args.length > 2) { cout << sUsageMessage; System.exit(-1); } */ //string sText = args[0]; //char cChar = args[1].at(0); Machine testMachine; string sCommand(""); char *ccCommand; string sUserMessage(""); sUserMessage.append("Commands;"); sUserMessage.append("\n"); sUserMessage.append(" a - add to the workspace"); sUserMessage.append("\n"); sUserMessage.append(" c - clear the work space [clear, cl]"); sUserMessage.append("\n"); sUserMessage.append(" pr - print the contents of the workspace [print]"); sUserMessage.append("\n"); sUserMessage.append(" i - indents the work space [indent]"); sUserMessage.append("\n"); sUserMessage.append(" n - add newline to the work space [newline, nl]"); sUserMessage.append("\n"); sUserMessage.append(" p - push the workspace onto the stack [push]"); sUserMessage.append("\n"); sUserMessage.append(" s - shift the accumulator to the workspace [shift]"); sUserMessage.append("\n"); sUserMessage.append(" o - pop the stack into the workspace [pop]"); sUserMessage.append("\n"); sUserMessage.append(" u - put the workspace on the tape [put]"); sUserMessage.append("\n"); sUserMessage.append(" g - get the tape item into the workspace "); sUserMessage.append("\n"); sUserMessage.append(" - - decrement the tape pointer"); sUserMessage.append("\n"); sUserMessage.append(" + - increment the tape pointer"); sUserMessage.append("\n"); sUserMessage.append(" h - help, show this message [?]"); sUserMessage.append("\n"); sUserMessage.append(" q - quit"); sUserMessage.append("\n"); cout << sUserMessage; //---------------------------------- //-- the command loop //-- sCommand = "dd"; while (!(sCommand == "q")) { //-------------------------------- // if (sCommand.at(0) == 'a') { testMachine.add(sCommand.substr(1)); } //-------------------------------- // if ((sCommand == "c") || (sCommand == "clear")) { testMachine.clear(); } //-------------------------------- // if ((sCommand == "pr") || (sCommand == "print")) { testMachine.print(); } //-------------------------------- // if ((sCommand == "n") || (sCommand == "newline")) { testMachine.newline(); } //-------------------------------- // if ((sCommand == "i") || (sCommand == "indent")) { testMachine.indent(); } //-------------------------------- // if ((sCommand == "p") || (sCommand == "push")) { testMachine.push(); } //-------------------------------- // if ((sCommand == "s") || (sCommand == "shift")) { testMachine.shift(); } //-------------------------------- // if ((sCommand == "o") || (sCommand == "pop")) { testMachine.pop(); } //-------------------------------- // if ((sCommand == "u") || (sCommand == "put")) { testMachine.put(); } //-------------------------------- // if ((sCommand == "g") || (sCommand == "get")) { testMachine.get(); } //-------------------------------- // if (sCommand == "-") { testMachine.decrementTape(); } //-------------------------------- // if (sCommand == "+") { testMachine.incrementTape(); } //-------------------------------- // if ((sCommand == "?") || (sCommand == "h")) { cout << sUserMessage; } cout << testMachine.printState(); cout << ">"; //cin.getline(ccCommand); sCommand.clear(); //sCommand.append(ccCommand); cin >> sCommand; } //-- while cout << testMachine.printState(); } //-- main()