Error Throwing not working to how I wanted it - c++

#include <cstring>
#include <string>
#include <cstdlib>
#include <ctype.h>
using namespace std;
const int MAX = 100;
class SampleEx{
public:
SampleEx(int, char);
void setNum(int);
int getNum();
void setCh(char);
char getCh();
private:
int number;
char c;
};
SampleEx :: SampleEx (int n, char c)
{
this->number =n;
this->c = c;
}
void SampleEx::setNum(int n){number = n;}
int SampleEx::getNum(){return number;}
void SampleEx::setCh(char n){c = n;}
char SampleEx::getCh(){return c;}
char Read (char[]);
void analyze(char[], int char_loc, int & size);
void DigitProcess(char[], int char_loc, int & size);
void AlphaProcess(char[], int char_loc, int & size);
void printStatus(int status);
int nextSpace(char[], int char_loc, int & size);
int main() {
int status = 0, char_loc = 0, size = 0;
char cont = ' ';
char lexeme[MAX];
char next = ' ';
do
{
try
{
do
{
next = Read(lexeme);
cout << lexeme;
analyze(lexeme, char_loc, size);
} while (next !='\n');
}
catch (SampleEx &e)
{
// cout << "Exception Number: " << e.getNum() << " Char: " << e.getCh() << '\n';
switch(e.getNum())
{
case 1:
cout << "[Invalid Integer: " << e.getCh() << " Found.] ";
break;
case 2:
cout << "[Invalid Decimal: " << e.getCh() << " Found.] ";
break;
case 3:
cout << "[Invalid Decimal: " << "Too Many . Found.] ";
break;
case 4:
cout << "[Invalid ID: " << e.getCh() << " Found.] ";
break;
}
}
cout << endl << "Continue? Y] Yes N] No" << endl;
cin.ignore(size);
cin >> cont;
while (cont != 'Y' && cont != 'N')
{
cout << "Invalid Input. Try Again." << endl;
cin >> cont;
}
if (cont == 'Y')
{
cin.ignore();
}
} while(cont != 'N');
cout << "Program Ended." << endl;
return 0;
}
void analyze(char item[], int char_loc, int & size)
{
SampleEx s1(0, ' ');
if (isdigit(item[0]))
{
DigitProcess(item, char_loc, size);
}
else if (isalpha(item[0]))
{
AlphaProcess(item, char_loc, size);
}
else if (item[0] == '.')
{
s1.setCh(item[0]);
s1.setNum(2);
throw s1;
}
else
{
s1.setCh(item[0]);
s1.setNum(4);
throw s1;
}
}
char Read(char temp[])
{
char extra;
int size = 0;
cin.get(extra);
while (size < MAX && extra != ' ' && extra != '\n')
{
temp[size] = extra;
cin.get(extra);
size++;
}
temp[size] = '\0';
return extra;
}
void DigitProcess(char item[], int char_loc, int & size)
{
SampleEx error(0, ' ');
size = strlen(item);
bool decimalMax = false, alphaUsed = false;
for (char_loc = 1; char_loc < size; char_loc++)
{
if (isdigit(item[char_loc]))
{
continue;
}
else if (isalpha(item[char_loc]))
{
error.setCh(item[char_loc]);
error.setNum(1);
throw error;
alphaUsed = true;
break;
}
else if (item[char_loc] == '.')
{
if (decimalMax == true)
{
error.setCh(item[char_loc]);
error.setNum(3);
throw error;
}
decimalMax = true; // stops anymore decimals from being entered
}
else
{
error.setCh(item[char_loc]);
error.setNum(4);
throw error;
}
}
if (decimalMax == true && alphaUsed == false)
{
printStatus(1);
}
else if (decimalMax == false && alphaUsed == false)
{
printStatus(2);
}
}
void AlphaProcess(char item[], int char_loc, int & size)
{
SampleEx error(0, ' ');
size = strlen(item);
bool digitUsed = false, deciUsed = false;
for (char_loc = 1; char_loc < size; char_loc++)
{
if (isalpha(item[char_loc]))
{
continue;
}
else if (isdigit(item[char_loc]))
{
digitUsed = true;
error.setCh(item[char_loc]);
error.setNum(4);
throw error;
for (int i = char_loc; i < size; i++)
{
if (isspace(item[i]))
{
char_loc = i - 1;
break;
}
}
}
else if (item[char_loc] == '.')
{
deciUsed = true;
error.setCh(item[char_loc]);
error.setNum(4);
throw error;
break;
}
else
{
error.setCh(item[char_loc]);
error.setNum(4);
throw error;
}
}
if (digitUsed == false && deciUsed == false)
{
printStatus(3);
}
}
void printStatus(int status)
{
switch(status)
{
case 1:
cout << "Decimal ";
break;
case 2:
cout << "Integer ";
break;
case 3:
cout << "ID ";
}
}
The above code will give "ID" if I were to say something like x or mike, "Decimal" if I were to say something like 4.4424, "Integer" if I were to say like 444.
However, it will print an error if anything is invalid, like if I put .333, it should print an error. The issue is that the program refuses to print multiple errors at a time.
For example: if I were to put "taco taco taco", it should print ID ID ID.
but if I were to put taco taco taco1, it would print ID ID [Invalid ID: 1 found]
The problem is that if I were to put taco taco1 taco1, it would NOT print the following:
ID [Invalid ID: 1 found] [Invalid ID: 1 found]
which that is the goal.

Related

Why isn't my program doing anything at all?

I'm sorry for the vague title, but I don't know what else to say.
Here is my program:
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
int
main (int argc, char **argv)
{
//string fin;
string ttl, dscp, ext;
string west = "w";
string east = "e";
string north = "n";
string south = "s";
int numRooms;
//string argv[1] = filename;
class Room
{
public:string title;
string description;
string exits;
int exitWest = -1;
int exitNorth = -1;
int exitEast = -1;
int exitSouth = -1;
int numExits;
};
ifstream fin;
fin.open (argv[1]);
//cin.ignore();
int t = 0;
while (fin)
{
string tilde;
string tester;
tester = "~";
cin >> tilde;
if (tilde == tester)
{
t = t + 1;
}
(numRooms = t / 3);
}
Room *roomArrayPtr = new Room[numRooms];
fin.clear ();
while (fin)
{
for (int l = 0; l < numRooms; l++)
{
getline (fin, ttl, '~');
roomArrayPtr[l].title = ttl;
getline (fin, dscp, '~');
roomArrayPtr[l].description = dscp;
getline (fin, ext, '~');
stringstream sin;
sin << ext;
string x;
int y;
while (sin >> x >> y)
{
if (x == west)
{
roomArrayPtr[l].exitWest = y;
}
if (x == south)
{
roomArrayPtr[l].exitSouth = y;
}
if (x == north)
{
roomArrayPtr[l].exitNorth = y;
}
if (x == east)
{
roomArrayPtr[l].exitEast = y;
}
}
sin.clear ();
int numext;
numext = (ext.size ()) / 3;
roomArrayPtr[l].numExits = numext;
}}
//(read in file again populate roomarrayptr w while loop and getline)
//roomArrayPtr[index].title = line;
//roomArrayPtr[index].description=line;
//close files, while loop that reads in user input from stdin, delete pointers w (delete[] roomArrayPtr;)
//if (exitsarray[i].size() > 2){
char command;
char newcommand;
cout << ">";
cin >> command;
int currentroom = 0;
int newroom;
bool keepgoing = true;
//string dir1;
while (keepgoing)
switch (command)
{
// stringstream ss;
case 'l':
cout << roomArrayPtr[currentroom].title << endl;
cout << roomArrayPtr[currentroom].description << endl;
cout << endl;
//if (roomArrayPtr[currentroom].numExits < 2) {
cout << "Exits: ";
if (roomArrayPtr[currentroom].exitWest > -1)
{
cout << "w";
}
if (roomArrayPtr[currentroom].exitNorth > -1)
{
cout << "n";
}
if (roomArrayPtr[currentroom].exitSouth > -1)
{
cout << "s";
}
if (roomArrayPtr[currentroom].exitEast > -1)
{
cout << "e";
}
/*else {
cout << "Exits: " ;
for (int k = 0; k < numExits; k++){
cout << exitdirection << " ";
}
}*/
//string newcommand;
cin >> newcommand;
//int newroom;
switch (newcommand)
{
case 'w':
if (roomArrayPtr[currentroom].exitWest == -1)
{
cout << "You can't go WEST!" << endl;
}
else
{
newroom = roomArrayPtr[currentroom].exitWest;
cout << "You moved WEST." << endl;
}
break;
case 'e':
if (roomArrayPtr[currentroom].exitEast == -1)
{
cout << "You can't go EAST!" << endl;
}
else
{
newroom = roomArrayPtr[currentroom].exitEast;
cout << "You moved EAST." << endl;
}
break;
case 'n':
if (roomArrayPtr[currentroom].exitNorth == -1)
{
cout << "You can't go NORTH!" << endl;
}
else
{
newroom = roomArrayPtr[currentroom].exitNorth;
cout << "You moved NORTH." << endl;
}
break;
case 's':
if (roomArrayPtr[currentroom].exitSouth == -1)
{
cout << "You can't go SOUTH!" << endl;
}
else
{
newroom = roomArrayPtr[currentroom].exitSouth;
cout << "You moved SOUTH." << endl;
}
break;
}
break;
case 'q':
keepgoing = false;
return 0;
break;
currentroom = newroom;
}
}
Whenever I run it, it compiles, but nothing happens. I tried putting in some random cout << "testing1" "testing2" scattered throughout, but none of those even showed up. I put it immediately after the { after int main and it still didn't show up. What's going on?
I tried putting in some random cout << "testing1" "testing2" scattered throughout, but none of those even showed up. I put it immediately after the { after int main and it still didn't show up.
you are reading the wrong file
int t = 0;
while (fin)
{
string tilde;
string tester;
tester = "~";
cin >> tilde; <<<<===== i assume you mean fin
if (tilde == tester)
{
t = t + 1;
}
(numRooms = t / 3);
}

C++ with menu system: How to eliminate input buffers when pressing arrow keys

I was able to make a program that has a menu on it. At first, the program is running smoothly. The problem starts to appear when, at a certain point in the program, the user starts inputting something and then navigating the menus again.
Sometimes it will print out integers/characters that were previously entered by the user when pressing the ENTER key in the menu.
I managed to block the inputs with cin.ignore(). But how can I eliminate the display of the (I don't know if its excess or garbage) inside the input buffer whenever the user presses the LEFT and RIGHT arrow keys? Or I think there's even one for UP and DOWN arrow key?
int main()
{
color(FG_WHITE);
bool progFinished = false;
while (!progFinished) {
cout << "[ACTIVITY FOR 26 FEBRUARY 2018]\n";
vector<string> menu = { "Currency Converter","Student Information System" };
int choice = menu_std(menu, FG_YELLOW, false);
bool currencyFinished = false;
bool studentFinished = false;
switch (choice) {
case 0:
while (!currencyFinished) {
cout << "\n\n[CURRENCY CONVERT]\n";
vector<string> curr_menu = { "PHP TO OTHERS","USD TO PHP","YEN TO PHP","EUR TO PHP","BHD TO PHP" };
int currency = menu_std(curr_menu, FG_YELLOW, false);
double value = validation("\nEnter the value", 0, false);
CurrencyConverter convert(currency, value);
cout << "\n\nConvert again? ";
currencyFinished = !menu_yn(FG_YELLOW);
}
system("cls");
break;
case 1:
Studentv2 stud;
stud.LoadFile();
while (!studentFinished) {
cout << "\n\n[STUDENT INFO SYSTEM]\n";
vector<string> stud_menu = { "Add Student","View All Students" };
int stud_choice = menu_std(stud_menu, FG_YELLOW, false);
switch (stud_choice) {
case 0:
stud.AddStudent();
cout << "\n\nDo you want to continue with the Student Info System? ";
stud.SaveFile();
studentFinished = !menu_yn(FG_YELLOW);
break;
case 1:
stud.DisplayStudentInformation();
cout << "\n\nDo you want to continue with the Student Info System? ";
studentFinished = !menu_yn(FG_YELLOW);
break;
}
}
system("cls");
break;
}
cout << "\nContinue using the program? ";
progFinished = !menu_yn(FG_YELLOW);
system("cls");
}
cout << "Press any key to exit.\n";
cin.get();
return 0;
}
Code snippets for some of the functions I used inside my program.
Function menu_std():
int menu_std(std::vector<std::string> &menu, WORD atrribute, bool argument)
{
sleep_for(milliseconds(150));
int elements = menu.size();
int elements_max_size = menu.size() - 1;
int menu_position = 0;
COORD position = getcoordinates();
while (true) {
for (int i = 0; i < elements; i++) {
move(position.X, position.Y + i);
if (i == menu_position) {
color(atrribute);
std::cout << menu[i];
color(FG_WHITE);
}
else {
std::cout << menu[i];
}
}
while (true) {
if (GetAsyncKeyState(VK_UP) < 0 && menu_position != 0) {
menu_position--;
break;
}
if (GetAsyncKeyState(VK_DOWN) < 0 && menu_position != elements_max_size) {
menu_position++;
break;
}
if (GetAsyncKeyState(VK_RETURN) < 0) {
std::cin.ignore(10000, '\n');
if (argument == true) {
sleep_for(milliseconds(100));
COORD previous = getcoordinates();
std::cout << "\n\nAre you sure? ";
bool sure = menu_yn(atrribute);
if (sure) {
clear_output(previous);
return menu_position;
}
else {
clear_output(previous);
break;
}
}
else {
return menu_position;
}
}
sleep_for(milliseconds(50));
}
sleep_for(milliseconds(175));
}
}
Function menu_yn():
bool menu_yn(WORD attribute)
{
sleep_for(milliseconds(150));
COORD currentpos = getcoordinates();
int pos = 0;
while (true) {
move(currentpos);
switch (pos) {
case 0:
color(attribute);
std::cout << "YES";
color(FG_WHITE);
std::cout << " NO";
break;
case 1:
std::cout << "YES";
color(attribute);
std::cout << " NO";
color(FG_WHITE);
break;
}
while (true) {
if (GetAsyncKeyState(VK_RIGHT) < 0 && pos != 1) {
pos++;
break;
}
if (GetAsyncKeyState(VK_LEFT) < 0 && pos != 0) {
pos--;
break;
}
if (GetAsyncKeyState(VK_RETURN) < 0) {
std::cin.ignore(10000, '\n');
if (pos == 0) {
return true;
}
else if (pos == 1) {
return false;
}
}
}
sleep_for(milliseconds(175));
}
}
Function validation()
double validation(std::string question, double limit, bool argument)
{
double userInput;
while (true) {
std::cout << question << " >> ";
while (!(std::cin >> userInput)) {
std::cout << "Error: Non-integer input. " << question << " >> ";;
std::cin.clear();
std::cin.ignore(256, '\n');
}
std::cin.ignore(10000, '\n');
while (userInput > limit && limit != 0) {
std::cout << "Error: Input out-of-bounds. " << question << " >> ";
std::cin >> userInput;
std::cin.ignore(10000, '\n');
}
if (argument) {
return (userInput <= 0) ? 1 : userInput;
}
else {
return userInput;
}
}
}
Screenshot of the problem:
There are numbers appearing whenever I press enter on the menu. I suspect that it comes whenever the user presses the arrow keys before entering the enter.

Check space in a string in two loops

In the proccess of creating a user register, I see a double do {} while loop with a same condition. The condition is if detected a space in the strings, the reading will not become available.
void createAccount()
{
unsigned short int i = 0;
bool space = false;
cin.ignore();
cout << "FIRST NAME: ";
getline(cin, fullName[0]);
do {
cout << "MIDDLE NAME: ";
getline(cin, fullName[1]);
for (i = 0; i < fullName[1].size(); i++)
{
if (fullName[i][1] == 32) {
space = true;
break;
}
else {
space = false;
break;
}
}
} while(space);
/*Reset values for the same loop again (I would not like to write 2 times all of this)
i is reseted at loop-for, which helps.*/
space = false;
do {
cout << "MIDDLE NAME: ";
getline(cin, fullName[1]);
for (i = 0; i < fullName[1].size(); i++)
{
if (fullName[i][1] == 32) {
space = true;
break;
}
else {
space = false;
break;
}
}
} while(space);
fullName[3] = fullName[0] + string(" ") + fullName[1] + string(" ") + fullName[2];
}
I really don't know how can I put this together in a same loop. I'm mind broken.
#edit: I'm roger that the right thing is to put fullName[1][i] and that the breaks conditions are wrong.
#edit²: The result:
class BankAccount
{
private:
string fullName[5];
char accountAddress[10];
unsigned short int cards;
float money;
bool visa, mastercard, americanExpress;
void checkName(string name, string typeName, bool exception)
{
unsigned short int errorVar, i;
errorVar = i = 0;
bool space = false;
do {
if (errorVar > 0)
cout << "Enter only the name purposed." << endl << endl;
if (exception)
cout << typeName << " NAME (type no if you haven't): ";
else
cout << typeName << " NAME: ";
getline(cin, name);
for (i = 0; i < name.size(); i++)
{
if (name[i] == ' ')
{
space = true;
break;
}
else
space = false;
}
errorVar++;
} while (space);
if (name.compare("no") == 0)
name = "NULL";
}
public:
void createAccount()
{
cout << endl << "FIRST NAME: "; /* First name has no checks (it can be a compound name) */
getline(cin, this->fullName[0]);
checkName(this->fullName[1], "SECOND", false);
checkName(this->fullName[2], "THIRD", true);
checkName(this->fullName[3], "LAST", false);
if (this->fullName[2].compare("NULL") == 0)
{
this->fullName[4] = this->fullName[0] + string(" ") + this->fullName[1] + string(" ") + this->fullName[3]; //NOT FULL NAME
cout << this->fullName[4];
}
else
{
this->fullName[4] = this->fullName[0] + string(" ") + this->fullName[1] + string(" ") + this->fullName[2] + string(" ") + this->fullName[3]; //NOT FULL NAME
cout << this->fullName[4];
}
}
BankAccount() {/* Constructor */}
~BankAccount() {/* Deconstructor */}
};
Logically it's a simple stuff. Thanks for helping and improve the code also in other areas.
The obvious and clean solution is to put the do-loop in a function (or method), and call it twice, once with fullname[1] and then again with fullname[2].

error C2664 char [80] to char [duplicate]

This question already has an answer here:
invalid conversion from 'int' to 'char *'
(1 answer)
Closed 8 years ago.
Hi I am suppose to create a program to read a .txt file and save the information in the txt to a struct and enum (have to use enum. as it compulsory) then prints out the information after rearranging the words. eg
Sarah
Wonderland
Libra 2 - 10 - 1993
3
I want to...
I hope to...
............
TO
My name is sarah
my nationality is wonderland
my bday is 2 october 1993
I am a libra
I have 3 wishes
1. I want to...
2. I hope to...
3. ............
I have encountered similar error C2664 for getHoroNum and checkHoro stating that it cant convert parameter 1 from 'char [80]' to 'char'. Please help! Thanks a lot in advance!
#include <iomanip>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cctype>
#include <fstream>
#include <string>
using namespace std;
const int MAX = 80;
const int MAXNO = 10;
enum Zodiac
{
Aquarius, Pisces, Aries, Taurus,
Gemini, Cancer, Leo, Virgo,
Libra, Scorpio, Sagittarius, Capricorn
};
struct Date
{
Zodiac sign;
int day;
int month;
int year;
};
struct Student
{
char name [MAX];
char nationality [MAX];
Date birthDate;
int no; // no of other messages
char wishMessage [MAXNO][MAX];
};
void myInfo (fstream&, char [], Student&);
// The above function reads information from the text file
// and store the information in a structure reference parameter
void printOut(Student , char[], char[]);
void getHoroNum(char , Student&);
void checkHoro (char , Student);
void getMth (int, char []) ;
int main()
{
fstream infile;
char fName[MAX];
char horo [MAX];
char fHoro[MAX];
char mth[MAX];
int month;
Student info;
cout << "Enter your info file name: ";
cin >> fName;
cout << endl;
month = info.birthDate.month;
myInfo(infile, fName, info);
getHoroNum(horo, info);
checkHoro(fHoro, info);
getMth(month, mth);
printOut(info, );
}
void myInfo (fstream& infile, char fName[], Student& info)
{
infile.open(fName, ios::in);
char temp[MAX];
char horo[MAX];
if(!infile)
{
cout << "Error file not found!" << endl;
exit(0);
}
infile.getline(info.name, MAX);
infile.getline(info.nationality,MAX);
infile >> horo
>> info.birthDate.day
>> temp
>> info.birthDate.month
>> temp
>> info.birthDate.year;
infile >> info.no;
for(int i=0; i < info.no ;i++)
{
infile.getline(info.wishMessage[i], MAX);
}
infile.close();
cout << "Successfully readed!" << endl;
}
void getHoroNum(char horo[], Student& info)
{
if (strcmp (horo,"Aquarius"))
{
info.birthDate.sign = Aquarius;
}
else if (strcmp(horo,"Pisces"))
{
info.birthDate.sign = Pisces;
}
else if (strcmp(horo,"Aries"))
{
info.birthDate.sign = Aries;
}
else if (strcmp(horo,"Taurus"))
{
info.birthDate.sign = Taurus;
}
else if (strcmp(horo,"Gemini"))
{
info.birthDate.sign = Gemini;
}
else if (strcmp(horo,"Cancer"))
{
info.birthDate.sign = Cancer;
}
else if (strcmp(horo,"Leo"))
{
info.birthDate.sign = Leo;
}
else if (strcmp(horo,"Virgo"))
{
info.birthDate.sign = Virgo;
}
else if (strcmp(horo,"Libra"))
{
info.birthDate.sign = Libra;
}
else if (strcmp(horo,"Scorpio"))
{
info.birthDate.sign = Scorpio;
}
else if (strcmp(horo,"Sagittarius"))
{
info.birthDate.sign = Sagittarius;
}
else if (strcmp(horo,"Capricorn"))
{
info.birthDate.sign = Capricorn;
}
}
void checkHoro (char fHoro[], Student info)
{
if (info.birthDate.sign == Aquarius)
{
fHoro = "Aquarius";
}
else if (info.birthDate.sign == Pisces)
{
fHoro = "Pisces";
}
else if (info.birthDate.sign == Aries)
{
fHoro = "Aries";
}
else if (info.birthDate.sign == Taurus)
{
fHoro = "Taurus";
}
else if (info.birthDate.sign == Gemini)
{
fHoro = "Gemini";
}
else if (info.birthDate.sign == Cancer)
{
fHoro = "Cancer";
}
else if (info.birthDate.sign == Leo)
{
fHoro = "Leo";
}
else if (info.birthDate.sign == Virgo)
{
fHoro = "Virgo";
}
else if (info.birthDate.sign == Libra)
{
fHoro = "Libra";
}
else if (info.birthDate.sign == Scorpio)
{
fHoro = "Scorpio";
}
else if (info.birthDate.sign == Sagittarius)
{
fHoro = "Sagittarius";
}
else if (info.birthDate.sign == Capricorn)
{
fHoro = "Capricorn";
}
}
void getMth (int month, char mth[] )
{
switch (month)
{
case 1:
{
mth = "January";
break;
}
case 2:
{
mth = "February";
break;
}
case 3:
{
mth = "March";
break;
}
case 4:
{
mth = "April";
break;
}
case 5:
{
mth = "May";
break;
}
case 6:
{
mth = "June";
break;
}
case 7:
{
mth = "July";
break;
}
case 8:
{
mth = "August";
break;
}
case 9:
{
mth = "September";
break;
}
case 10:
{
mth = "October";
break;
}
case 11:
{
mth = "November";
break;
}
case 12:
{
mth = "December";
break;
}
}
}
void printOut(Student info, char mth[], char fHoro[])
{
cout << "My name is " << info.name << endl;
cout << "My nationality is " << info.nationality << endl;
cout << "My date of birth is " << info.birthDate.day
<< " " << mth << " "
<< info.birthDate.year << endl;
cout << "I am a" << fHoro << endl;
cout << "\nI have " << info.no << " wishes:" << endl;
for(int i=0; i < info.no ;i++)
{
cout << i << ". " << info.wishMessage[i];
}
}
You have this function definition:
void getHoroNum(char horo[], Student& info)
and before you have this declaration:
void getHoroNum(char , Student&);
latter should be replaced by:
void getHoroNum(char* , Student&);

_block_type_is_valid phead- nblockuse on delete command

So I know this is a pretty common error, but I'm very new to C++, we are using it for a programing languages class, and this error has me stuck. The delete parser; line is the line that causes this error, and I cannot figure out why.
Turtle2.cpp
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include "scanner.h"
#include "parser.h"
using namespace std;
int main(int argc, char* argv[]) {
//string line;
if (argc != 2) {
cout << "Usage: turtle filename" << endl;
return 0;
}
char* filename = argv[1];
cout << "filename is " << filename << endl;
ifstream in(filename);
Parser * parser = new Parser(&in);
AST* tree = parser->parse();
tree->evaluate();
delete tree;
delete parser; //This is the line that causes the error!
return 0;
}
parser.cpp
#include "parser.h"
#include "calcex.h"
#include <string>
#include <sstream>
Parser::Parser(istream* in) {
scan = new Scanner(in);
}
Parser::~Parser() {
try {
delete scan;
} catch (...) {
}
}
AST* Parser::parse() {
AST* returnValue = Prog();
cout << "We are still ok1" << endl;
return returnValue;
}
AST* Parser::Prog() {
AST* result = StmtList();
Token* t = scan->getToken();
if (t->getType() != eof) {
cout << "Syntax Error: Expected EOF, found token at column " << t->getCol() << endl;
throw ParseError;
}
cout << "We are still ok2" << endl;
return result;
}
AST* Parser::StmtList() {
AST* result = Statement();
Token* t = scan->getToken();
scan->putBackToken();
if (t->getType() != eof) {
AST* result = StmtList();
return result;
}
return result;
}
AST* Parser::Statement() {
float num1;
float num2;
stmtNode* node;
Token* t = scan->getToken();
/*if (turtle->getType() != keyword || turtle->getLex() != "turtle"){
cerr <<"expected turtle" << endl; //print to standard error stream
throw ParseError;
}*/
if (t->getType() == keyword && t->getLex() == "turtle"){
t = scan->getToken();
if (t->getType() == dot){
t = scan->getToken();
if (t->getType() == keyword && t->getLex() == "goto"){
t = scan->getToken();
if (t->getType() == lparen){
t = scan->getToken();
if (t->getType() == number){
istringstream in(t->getLex());
in >> num1;
t = scan->getToken();
if (t->getType() == comma){
t = scan->getToken();
if (t->getType() == number){
istringstream in(t->getLex());
in >> num2;
t = scan->getToken();
if (t->getType() == rparen){
cout << "Good" << endl;
node = new stmtNode(num1,num2);
cout << "X is " << node->getX() << endl;
cout << "Y is " << node->getY() << endl;
}
}
}
}
}
}
}
}
else{
cout << "bad" << endl;
}
return node;
}
scanner.cpp
#include "scanner.h"
#include "calcex.h"
#include <iostream>
#include <string>
using namespace std;
//Uncomment this to get debug information
//#define debug
const int numberOfKeywords = 2;
const string keywd[numberOfKeywords] = { //defining the keywords
string("turtle"), string("goto")
};
int isLetter(char c) { //c is bigger or equal to 'a' and small or equal to 'z'. same for captial versions
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
}
int isDigit(char c) { //c is bigger or equal to '0' or smaller or equal to '9'
return (c >= '0' && c <= '9');
}
int isWhiteSpace(char c) { //c is a space, tab or newline
return (c == ' ' || c == '\t' || c == '\n');
}
Scanner::Scanner(istream* in): //scanner constructor
inStream(in),
lineCount(1),
colCount(0),
needToken(true),
lastToken(0)
{}
Scanner::~Scanner() { //scanner de-constructor
try {
delete inStream;
} catch (...) {}
}
void Scanner::putBackToken() { //method?
needToken = false;
}
Token* Scanner::getToken() { //method?
if (!needToken) {
needToken=true;
return lastToken;
}
Token* t;
int state=0;
bool foundOne=false;
char c;
string lex;
TokenType type;
int k;
int column, line;
c = inStream->get();
while (!foundOne) {
colCount++;
switch (state) {
case 0 :
lex = "";
column=colCount;
line = lineCount;
if (isLetter(c)) state=1;
else if (isDigit(c)) state=2;
else if (c=='.') state=3;
else if (c==',') state=4;
else if (c=='(') state=5;
else if (c==')') state=6;
else if (c=='\n') {
colCount=0;
lineCount++;
}
else if (isWhiteSpace(c));
else if (inStream->eof()) {
foundOne=true;
type=eof;
}
else {
cout << "Unrecognized Token found at line " << line <<
" and column " << column << endl;
throw UnrecognizedToken;
}
break;
case 1 :
if (isLetter(c) || isDigit(c)) state=1;
else {
for (k=0;k<numberOfKeywords;k++)
if (lex == keywd[k]) {
foundOne = true;
type = keyword;
}
if (!foundOne) {
type = identifier;
foundOne = true;
}
}
break;
case 2 :
if (isDigit(c)) state=2;
else {
type = number;
foundOne=true;
}
break;
case 3 :
type = dot;
foundOne = true;
break;
case 4 :
type = comma;
foundOne = true;
break;
case 5 :
type = lparen;
foundOne=true;
break;
case 6 :
type = rparen;
foundOne=true;
break;
}
if (!foundOne) {
lex = lex + c;
c = inStream->get();
}
}
inStream->putback(c);
colCount--;
if (type == number || type == identifier || type == keyword) {
t = new Token(type,new string(lex),line, column);
}
else {
t = new Token(type,new string(lex),line,column);
}
#ifdef debug
cout << "just found " << lex << " with type " << type << endl;
#endif
lastToken = t;
return t;
}
I don't know if that is enough code to help you guys out or not, if you need anything more just ask, its not a secret or anything :) I know its the de-constructor for parser, but I have no idea how to fix it, or really why this is happening... I've added scanner.cpp, because some ponited out that the problem could be in its deconstructor, so I hope that helps.
The reason why this is failing is that you are using delete on something that was allocated on the stack.
Note the combination of ifstream in(filename);, creating an ifstream on the stack and the delete inStream; in the destructor of Scanner.
The easiest suggestion would be to allocate in on the heap, whish ifstream *in = new ifstream(filename) or whatnot.
A better solution would probably be to have the other classes(Scanner, Parser, etc) take the ifstream by reference, and avoid pointers unless they are needed.
You are trying to delete a stack variable, in the destructor of Scanner.
Parser * parser = new Parser(&in);
Parser::Parser(istream* in) {
scan = new Scanner(in);
}
Parser::Parser(istream* in) {
scan = new Scanner(in);
}
Parser::~Parser() {
try {
delete scan;
} catch (...) {
}
}
Scanner::~Scanner() { //scanner de-constructor
try {
delete inStream;
} catch (...) {}
}