Nested looping for simple logic parser - c++

I am writing a parser for a simple programming language consisting of possibly an axis number, a two letter command, and possibly an input value. All commands are separated by a comma. I have a parser that splits the input by the delineator and runs each valid command one at a time. I'm having issues programming the looping function RP.
I could have a command like this
MD1,TP,RP5,TT,RP10
in which I would want it to run as
for (int i = 0; i < 10; i++) {
TT();
for (int j = 0; j < 5; j++) {
TP();
}
}
So far the main parser that I have will see the first RP command and run that then see the second RP command and run it. The RP command is set to loop from the end of the last RP command giving something more like this.
for (int j = 0; j < 5; j++) {
TP();
}
for (int i = 0; i < 10; i++) {
TT();
}
I've tried a few different approaches, but so far no luck. Any and all help is appreciated.

Actually, I considered the question a little bit too broad. On the other hand, I couldn't resist to "try out".
Preface
First, I want to criticize (a little bit) the question title. simple logic parser sounds for me like an interpreter of boolean expressions. However, I remember that my engineering colleagues are often talking about "program logic" (and I've not yet achieved that they get rid of this). Hence, my recommendation: If you (the questioner) are talking with computer scientists, use the term "logic" sensible (or they might look confused sometimes...)
The sample code MD1,TP,RP5,TT,RP10 looks somehow familiar to me. A short google/wikipedia research cleared my mind: The Wikipedia article Numerical control is about CNC machines. Close to the end of the article, the programming is mentioned. (The German "sibling" article provides even more.) IMHO, the code really looks similar a bit but seems to be even simpler. (No offense – I consider it as good to keep things as simple as possible.)
The program notation which seems to be intended is somehow like Reverse Polish notation. I wanted at least mention that term as googling for "rpn interpreter" throws a lot of sufficient hits including github sites. Actually, the description of the intended language is a little bit too short to decide certainly which existing S/W project could be appropriate.
Having said this, I want to show what I got...
Parser
I started first with a parser (as the questioner didn't dare to expose his). This is the code of mci1.cc:
#include <iostream>
#include <sstream>
using namespace std;
typedef unsigned char uchar;
enum Token {
TkMD = 'M' | 'D' << 8,
TkRP = 'R' | 'P' << 8,
TkTP = 'T' | 'P' << 8,
TkTT = 'T' | 'T' << 8
};
inline Token tokenize(uchar c0, uchar c1) { return (Token)(c0 | c1 << 8); }
bool parse(istream &in)
{
for (;;) {
// read command (2 chars)
char cmd[2];
if (in >> cmd[0] >> cmd[1]) {
//cout << "DEBUG: token: " << hex << tokenize(cmd[0], cmd[1]) << endl;
switch (tokenize(cmd[0], cmd[1])) {
case TkMD: { // MD<num>
int num;
if (in >> num) {
cout << "Received 'MD" << dec << num << "'." << endl;
} else {
cerr << "ERROR: Number expected after 'MD'!" << endl;
return false;
}
} break;
case TkRP: { // RP<num>
int num;
if (in >> num) {
cout << "Received 'RP" << dec << num << "'." << endl;
} else {
cerr << "ERROR: Number expected after 'RP'!" << endl;
return false;
}
} break;
case TkTP: // TP
cout << "Received 'TP'." << endl;
break;
case TkTT: // TT
cout << "Received 'TT'." << endl;
break;
default:
cerr << "ERROR: Wrong command '" << cmd[0] << cmd[1] << "'!" << endl;
return false;
}
} else {
cerr << "ERROR: Command expected!" << endl;
return false;
}
// try to read separator
char sep;
if (!(in >> sep)) break; // probably EOF (further checks possible)
if (sep != ',') {
cerr << "ERROR: ',' expected!" << endl;
return false;
}
}
return true;
}
int main()
{
// test string
string sample("MD1,TP,RP5,TT,RP10");
// read test string
istringstream in(sample);
if (parse(in)) cout << "Done." << endl;
else cerr << "Interpreting aborted!" << endl;
// done
return 0;
}
I compiled and tested with g++ and bash in Cygwin on Windows 10:
$ g++ --version
g++ (GCC) 6.4.0
$ g++ -std=c++11 -o mci mci1.cc
$ ./mci
Received 'MD1'.
Received 'TP'.
Received 'RP5'.
Received 'TT'.
Received 'RP10'.
Done.
$
Uploaded for life demo on ideone.
I introduced the function tokenize() as part of an update. (I got the idea when I was tooth brushing and poring how to get rid of the ugly nested switches of the previous version.) Tokenizing is a common technique in parsing – however, the implementation is usually a little bit different.
Thus, the parser seems to work. Not yet the next big thing but sufficient for the next step...
Interpreter
To interprete the parsed commands, I started to make a resp. back-end – a set of classes which may store and execute the required operations.
The parse() function of the first step became the compile() function where simple standard output was replaced by code building and nesting the operations. mci2.cc:
#include <cassert>
#include <iostream>
#include <stack>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
// super class of all operations
class Op {
protected:
Op() = default;
public:
virtual ~Op() = default;
virtual void exec() const = 0;
// disabled: (to prevent accidental usage)
Op(const Op&) = delete;
Op& operator=(const Op&) = delete;
};
// super class of grouping operations
class Grp: public Op {
protected:
vector<Op*> _pOps; // nested operations
protected:
Grp() = default;
virtual ~Grp()
{
for (Op *pOp : _pOps) delete pOp;
}
public:
void add(Op *pOp) { _pOps.push_back(pOp); }
// disabled: (to prevent accidental usage)
Grp(const Grp&) = delete;
Grp& operator=(const Grp&) = delete;
};
// class for repeat op.
class RP: public Grp {
private:
unsigned _n; // repeat count
public:
RP(unsigned n): Grp(), _n(n) { }
virtual ~RP() = default;
virtual void exec() const
{
cout << "Exec. RP" << _n << endl;
for (unsigned i = 0; i < _n; ++i) {
for (const Op *pOp : _pOps) pOp->exec();
}
}
// disabled: (to prevent accidental usage)
RP(const RP&) = delete;
RP& operator=(const RP&) = delete;
};
// class for TP op.
class TP: public Op {
public:
TP() = default;
virtual ~TP() = default;
virtual void exec() const
{
cout << "Exec. TP" << endl;
}
};
// class for TT op.
class TT: public Op {
public:
TT() = default;
virtual ~TT() = default;
virtual void exec() const
{
cout << "Exec. TT" << endl;
}
};
// class for MD sequence
class MD: public Grp {
private:
unsigned _axis;
public:
MD(unsigned axis): Grp(), _axis(axis) { }
virtual ~MD() = default;
virtual void exec() const
{
cout << "Exec. MD" << _axis << endl;
for (const Op *pOp : _pOps) pOp->exec();
}
};
typedef unsigned char uchar;
enum Token {
TkMD = 'M' | 'D' << 8,
TkRP = 'R' | 'P' << 8,
TkTP = 'T' | 'P' << 8,
TkTT = 'T' | 'T' << 8
};
inline Token tokenize(uchar c0, uchar c1) { return (Token)(c0 | c1 << 8); }
MD* compile(istream &in)
{
MD *pMD = nullptr;
stack<Op*> pOpsNested;
#define ERROR \
delete pMD; \
while (pOpsNested.size()) { delete pOpsNested.top(); pOpsNested.pop(); } \
return nullptr
for (;;) {
// read command (2 chars)
char cmd[2];
if (in >> cmd[0] >> cmd[1]) {
//cout << "DEBUG: token: " << hex << tokenize(cmd[0], cmd[1]) << dec << endl;
switch (tokenize(cmd[0], cmd[1])) {
case TkMD: { // MD<num>
int num;
if (in >> num) {
if (pMD) {
cerr << "ERROR: Unexpected command 'MD" << num << "'!" << endl;
ERROR;
}
pMD = new MD(num);
} else {
cerr << "ERROR: Number expected after 'MD'!" << endl;
ERROR;
}
} break;
case TkRP: { // RP<num>
int num;
if (in >> num) {
if (!pMD) {
cerr << "ERROR: Unexpected command 'RP" << num << "'!" << endl;
ERROR;
}
RP *pRP = new RP(num);
while (pOpsNested.size()) {
pRP->add(pOpsNested.top());
pOpsNested.pop();
}
pOpsNested.push(pRP);
} else {
cerr << "ERROR: Number expected after 'RP'!" << endl;
ERROR;
}
} break;
case TkTP: { // TP
if (!pMD) {
cerr << "ERROR: Unexpected command 'TP'!" << endl;
ERROR;
}
pOpsNested.push(new TP());
} break;
case TkTT: { // TT
if (pOpsNested.empty()) {
cerr << "ERROR: Unexpected command 'TT'!" << endl;
ERROR;
}
pOpsNested.push(new TT());
} break;
default:
cerr << "ERROR: Wrong command '" << cmd[0] << cmd[1] << "'!" << endl;
ERROR;
}
} else {
cerr << "ERROR: Command expected!" << endl;
ERROR;
}
// try to read separator
char sep;
if (!(in >> sep)) break; // probably EOF (further checks possible)
if (sep != ',') {
cerr << "ERROR: ',' expected!" << endl;
ERROR;
}
}
#undef ERROR
assert(pMD != nullptr);
while (pOpsNested.size()) {
pMD->add(pOpsNested.top());
pOpsNested.pop();
}
return pMD;
}
int main()
{
// test string
string sample("MD1,TP,RP3,TT,RP2");
// read test string
istringstream in(sample);
MD *pMD = compile(in);
if (!pMD) {
cerr << "Interpreting aborted!" << endl;
return 1;
}
// execute sequence
pMD->exec();
delete pMD;
// done
return 0;
}
Again, I compiled and tested with g++ and bash in Cygwin on Windows 10:
$ g++ -std=c++11 -o mci mci2.cc
$ ./mci
Exec. MD1
Exec. RP2
Exec. TT
Exec. RP3
Exec. TP
Exec. TP
Exec. TP
Exec. TT
Exec. RP3
Exec. TP
Exec. TP
Exec. TP
$
Uploaded for life demo on ideone.
The trick with the nesting is rather simple done in the compile() function:
commands TP and TT are added to a temporary stack pOpsNested
for command RP, all collected operations are added to the RP instance popping the pOpsNested stack (and thus reversing their order),
afterwards, the RP instance itself is pushed into pOpsNested stack instead
finally the contents of buffer pOpsNested is added to sequence MD (as these are the top-level ops).

Related

operator _surrogate_func: no matching overload found and 2 other errors

I've written a code which creates a list of buses that you can modify and manage. The whole managing process is proceed by writing strings in console. After running code I'm receiving 3 errors, none of which I understand therefore can fix. Code is planned this way:
NEW_BUS - Adds new bus in list by taking it's number, amount of stops and stop list.
ALL_BUSES - Display all buses in lexicographical order (by their name)
STOPS_FOR_BUS - Display all stops specific bus follows.
BUSES_FOR_STOP - Diplay all buses that go though the specific stop.
Here are error list:
1. operator _surrogate_func: no matching overload found
2. Failed to specialize function template 'unknown-type std::less::operator ()(_Ty 1 &&,_Ty2 &&)
3. illegal expression
All errors come from line 617 from xutility file.
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <tuple>
#include <iterator>
using namespace std;
class Bus {
public:
int StopsAmount;
string BusNumber;
vector<string> Stops;
Bus(tuple<string, int, vector<string>> BusParams) {
BusNumber = get<0>(BusParams);
StopsAmount = get<1>(BusParams);
Stops = get<2>(BusParams);
}
void ShowStops() {
cout << BusNumber << ": ";
for (int i = 0; i < StopsAmount; i++) cout << Stops[i] << " ";
cout << "\n";
}
bool FindStop(string Stop) {
for (int i = 0; i < StopsAmount; i++) {
if (Stops[i] == Stop) {
return true;
}
}
return false;
}
};
class BusTraffic {
public:
BusTraffic() {
while (true) {
string Request;
cin >> Request;
switch (Request[0]) {
case 'N': NEW_BUS(Request.substr(8, Request.length() - 8)) ;
break;
case 'B': BUSES_FOR_STOP(Request.substr(15, Request.length() - 15));
break;
case 'S': STOPS_FOR_BUS(Request.substr(14, Request.length() - 14));
break;
case 'A': ALL_BUSES();
break;
}
}
}
private:
list<Bus> BusList;
void NEW_BUS(string Request) {
BusList.push_back(Bus::Bus(SplitString(Request)));
}
void BUSES_FOR_STOP(string Stop) {
cout << Stop << ": ";
for (list<Bus>::iterator It = BusList.begin(); It != BusList.end(); It++) {
if (It->FindStop(Stop)) {
cout << It->BusNumber << " ";
}
}
cout << endl;
}
void STOPS_FOR_BUS(string Name) {
cout << Name << ": ";
for (list<Bus>::iterator It = BusList.begin(); It != BusList.end(); It++) {
if (It->BusNumber == Name) {
It->ShowStops();
}
}
}
void ALL_BUSES() {
if (BusList.size() > 0) {
BusList.sort();
for (list<Bus>::iterator It = BusList.begin(); It != BusList.end(); It++) {
cout << It->BusNumber << ": ";
It->ShowStops();
}
}
else {
cout << "No buses" << endl;
}
}
// Converting string to information about bus
tuple<string, int, vector<string>> &SplitString(string str) {
tuple<string, int, vector<string>> BusParams;
string Word = "";
int WordNum = 0;
for (auto Letter : str) {
if (Letter == ' ') {
if (WordNum == 0) get<0>(BusParams) = Word;
if (WordNum == 1) get<1>(BusParams) = stoi(Word);
if (WordNum == 2) get<2>(BusParams).push_back(Word);
Word = "";
WordNum++;
}
else {
Word = Word + Letter;
}
}
get<2>(BusParams).push_back(Word);
return BusParams;
}
};
int main() {
BusTraffic TestTraffic;
return 0;
}
Unfortunately, you are absolutely correct. the error message here is just terrible. It's just from experience that you learn to interpret that as a missing less-than-operator.
So something in the lines of:
bool operator< (const Bus& lhs, const Bus& rhs) {
// however you want to sort them...
return (lhs.BusNumber < rhs.BusNumber);
}
The other small bug is within NEW_BUS: In C++ you don't need to specify the constructor name. So it's not Bus::Bus it's just Bus
Last but not least your SplitString is returning a reference to a local variable. In general that's a bad idea as that memory might simply not be accessible anymore when you try to. Just remove "&" from the return type. Further explanations.
You're trying to sort a list of buses. By the sounds of it there is no overload for the less than operator. This means C++ doesn't know how to compare objects of type bus. Add this to your Bus class and it should work. This overload of the less than operator returns true if the other bus is less than the current bus.
bool operator < (const Bus& otherBus) const {
if(otherBus.StopsAmount < this.StopsAmount) {
return true;
}
return false;
}
Useful links with more details:
http://fusharblog.com/3-ways-to-define-comparison-functions-in-cpp/
https://www.tutorialspoint.com/cplusplus/relational_operators_overloading.htm

"cast with the appropriate bitmask" while using alternative cout

So I decided to make a console class as an alternative to std::cout << stream << std::endl routine.
Here's my code:
class Console {
public:
Console() {
this->console = GetStdHandle(STD_OUTPUT_HANDLE);
this->current_color = 7;
}
void color(int k) {
this->current_color = k;
SetConsoleTextAttribute(this->console, this->current_color);
}
void remove() {
FreeConsole();
}
void print(std::string s) {
std::cout << s;
}
void log(std::string s) {
this->color(7);
std::cout << s << std::endl;
this->color(this->current_color);
}
void error(std::string s) {
this->color(12);
std::cout << s << std::endl;
this->color(this->current_color);
}
private:
HANDLE console;
int current_color;
};
Initializing console as Console console;, I use console.log("String " + n), where n is an unsigned short, for example. The code compiles fine, however this thing shows up:
What is it and how do I fix it?
Your program contains undefined behavior.
console.log("String " + n) (where n is an integral type) is interpreted as follows:
const char* tmp_ptr1 = "String ";
const char* tmp_ptr2 = tmp_ptr1 + n;
console.log(std::string(tmp_ptr2));
If n > 7 or n < 0 the code above performs out-of-bounds access. In your case this access happens to pick up some other (sub)string from the string literals linked into your program's data section and you see it on your screen. In theory anything else could happen.

Function must return a value

I am trying to make a text based RPG and i'm fairly new to c++. I understand that I need to return a value, but when I try and return CharacterName or CharacterRace it comes up with unresolved externals errors. I'd really appreciate the help guys, thanks :)
CharacterCreation.h
#include <string>
#include <iostream>
void petc(), ConsoleClear(), petc(), EnterClear();
std::string CharacterName, CharacterRace;
Main.cpp
#include <iostream>
#include <limits>
#include <string>
#include <string.h>
#include "CharacterCreation.h"
std::string CharacterCreation();
int main()
{
CharacterCreation();
}
std::string CharacterCreation(int RaceChoice, int RaceChoiceLoop)
{
RaceChoiceLoop = 0;
std::cout << "Welcome to the character creation V 1.0.0" << std::endl;
EnterClear();
std::cout << "Choose a name: ";
std::cin >> CharacterName;
std::cout << CharacterName << std::endl;
EnterClear();
while (RaceChoiceLoop == 0)
{
std::cout << "(1) Human - Human's race perks: + 5 to Magic | + 1 to Sword Skill" << std::endl;
std::cout << "(2) Elf - Elve's race perks: + 5 to Archery | + 1 to Magic" << std::endl;
std::cout << "(3) Dwarf - Dwarven race perks: + 5 to Strength | + 1 to Archery" << std::endl;
std::cout << "Choose a race, " << CharacterName << ": ";
std::cin >> RaceChoice;
if (RaceChoice == 1)
{
RaceChoiceLoop = 1;
CharacterRace = "Human";
}
else if (RaceChoice == 2)
{
RaceChoiceLoop = 1;
CharacterRace = "Elf";
}
else if (RaceChoice == 3)
{
RaceChoiceLoop = 1;
CharacterRace = "Dwarf";
}
else
{
std::cout << "Invalid Option";
EnterClear();
RaceChoiceLoop = 0;
}
}
}
void petc()
{
std::cout << "Press Enter To Continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
void EnterClear()
{
std::cout << "Press Enter To Continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
system("cls");
}
void ConsoleClear()
{
system("cls");
}
A declared std::string function should return a string and this is not the same as printing it on the screen, use return "something" inside the function otherwise declare it void.
The "unresolved externals" message isn't directly caused by your returning a value.
It's a linker error, and only occurs because compilation succeeded.
The cause is that you're declaring, and calling, this parameter-less function:
std::string CharacterCreation();
but you're defining this function with two parameters:
std::string CharacterCreation(int RaceChoice, int RaceChoiceLoop)
The declaration and the definition must match.
From the looks of it, you don't actually want the parameters and should use local variables instead:
std::string CharacterCreation()
{
int RaceChoice = 0;
int RaceChoiceLoop = 0;
// ...
Problem is that the function CharacterCreation() (taking no arguments) is never defined, and thus the linker cannot find it.
Try substituting in the following:
std::string CharacterCreation(int, int);
int main()
{
CharacterCreation(1,1);
}
This will call the CharacterCreation function you have implemented below the main function. Doing this I can compile (and link) your code :)
As I have pointed in my comment before, your CharacterCreation method does not return any value, although you have defined a string as an expected one.
What you most likely want to do is either change CharacterCreation signature to:
void CharacterCreation(int RaceChoice, int RaceChoiceLoop)
and keep the current implementation
or pack all your console output in a string and return it at the end of the method.
Then in main()
string result = CharacterCreation();
can retrieve this value and you can print it in main

How to add a time limit for user to input something or else it goes on?

Since very long time, I am trying to put a timer in C++ which actually gives a limited time to input anything like for example :-
if I type
cout<<"Enter the name :-
cin>>name;
cout<<"Enter Phonenoe :- ";
cin>>phoneno;
So in this How can I add time say for 5 secs to input name, and if user don't input anything in 5 secs, programs should go to input phonenoe.
Give the full code, I am a beginner.
Fine, I am overruled.
The best google I found for this is here. In a nutshell, this is very difficult to do in C++ and I believe impossible to do in a portable way. In assembler, I would poll the lowest level keyboard interrupt (9h I think) to see what is coming in, but that was in DOS days and I'm not sure if that works anymore.
just for fun. only works in windows.
#include <windows.h>
#include <iostream>
#include <string>
bool wait_for_key(int timeout_milliseconds, char& ch) {
HANDLE tui_handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD tui_evtc = 0;
DWORD deadline = GetTickCount() + timeout_milliseconds;
INPUT_RECORD tui_inrec = { 0 };
DWORD tui_numread = 0;
while (GetTickCount() < deadline) {
if (tui_evtc > 0) {
ReadConsoleInput(tui_handle, &tui_inrec, 1, &tui_numread);
if (tui_inrec.EventType == KEY_EVENT) {
if (tui_inrec.Event.KeyEvent.bKeyDown) {
ch = tui_inrec.Event.KeyEvent.uChar.AsciiChar;
return true;
}
}
}
YieldProcessor();
GetNumberOfConsoleInputEvents(tui_handle, &tui_evtc);
}
return false;
}
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE tui_handle = GetStdHandle(STD_INPUT_HANDLE);
std::string name;
std::string other;
std::cout << "name: ";
char ch;
if (wait_for_key(5000, ch)) {
std::cout << ch;
std::getline(std::cin, name);
name = ch + name;
std::cout << "name is '" << name.c_str() << "'" << std::endl;
} else {
std::cout << std::endl << "other: ";
std::getline(std::cin, other);
std::cout << "other is '" << other.c_str() << "'" << std::endl;
}
return 0;
}

Performance difference between accessing local and class member variables

I have the following code in a class member function:
int state = 0;
int code = static_cast<int>(letter_[i]);
if (isalnum(code)) {
state = testTable[state][0];
} else if (isspace(code)) {
state = testTable[state][2];
} else if (code == OPEN_TAG) {
state = testTable[state][3];
} else if (code == CLOSE_TAG) {
state = testTable[state][4];
} else {
state = testTable[state][1];
}
switch (state) {
case 1: // alphanumeric symbol was read
buffer[j] = letter_[i];
++j;
break;
case 2: // delimeter was read
j = 0;
// buffer.clear();
break;
}
However, if state is a class member variable rather than local, the performance drops considerably (~ 5 times). I was reading about differences in accessing local variables and class members, but texts usually say that it affects performance very slightly.
If it helps: I am using MinGW GCC compiler with -O3 option.
I could not reproduce your observation, testing on x86_64 with both, VS10 and g++. The local variant is slightly faster, probably due to what Alan Stokes described in his comment, but at most ~10%. You should check your timing, try to rule out any other problems and best would be the reduce all your code to a very simple test-cast which still shows this behavior.
I think my test-case resembles your scenario quite good, at least like you described it:
#include <iostream>
#include <boost/timer.hpp>
const int max_iter = 1<<31;
const int start_value = 65535;
struct UseMember
{
int member;
void foo()
{
for(int i=0; i<max_iter; ++i)
{
if(member%2)
member = 3*member+1;
else
member = member>>1;
}
std::cout << "Value=" << member << std::endl;
}
};
struct UseLocal
{
void foo()
{
int local = start_value;
for(int i=0; i<max_iter; ++i)
{
if((local%2)!=0) /* odd */
local = 3*local+1;
else /* even */
local = local>>1;
}
std::cout << "Value=" << local << std::endl;
}
};
int main(int argc, char* argv[])
{
/* First, test using member */
std::cout << "** Member Access" << std::endl;
{
UseMember bar;
bar.member = start_value;
boost::timer T;
bar.foo();
double e = T.elapsed();
std::cout << "Time taken: " << e << "s" << std::endl;
}
/* Then, test using local */
std::cout << "** Local Access" << std::endl;
{
UseLocal bar;
boost::timer T;
bar.foo();
double e = T.elapsed();
std::cout << "Time taken: " << e << "s" << std::endl;
}
return 0;
}