So I have this recursive descent parser that works fine recognizing and using values through command line arguments but I am not sure how to port this to reading from a .dat file, using the proper char pointer, printing the string, and working for multiple strings.
Parser using command line args:
#include <iostream>
#include <fstream>
using namespace std;
bool A(void);
bool E(void);
bool T(void);
bool F(void);
bool P(void);
bool I(void);
bool L(void);
char *c;
int main(int argc, char *argv[]){
c = argc == 2 ? argv[1] : (char *)"";
if (A() && *c == '\0') {
cout << "The string \"" << argv[1] << "\" is in the language." << endl;
}
else {
cout << "The string \"" << argv[1] << "\" is not in the language." << endl;
}
return 0;
}
bool A(void){
if( I() )
{
if ( *c == '=' ){
++c;
if ( E() )
return true;
}
}
return false;
}
bool E(void){
if( T() ){
if ( *c == '+' || *c == '-' ){
++c;
return E();
}
return true;
}
return false;
}
bool F(void){
if( P() ){
if( *c == '^'){
++c;
return F();
}
return true;
}
return false;
}
bool I(void){
if ( *c >= 'a' && *c <= 'z'){
++c;
return true;
}
return false;
}
bool L(void){
if ( *c >= '0' && *c <= '9' ){
++c;
return true;
}
return false;
}
bool P(void){
if ( I() ){
return true;
}
else
if ( L() ){
return true;
}
else
if ( *c == '(' ){
++c;
if ( E() ){
if ( *c == ')' ){
++c;
return true;
}
}
}
return false;
}
bool T(void){
if( F() ){
if ( *c == '*' || *c == '/' ){
++c;
return T();
}
return true;
}
return false;
}
I don't know what I can replace argv[1] with to print the string.
To get the proper char pointer could I just do this?
ifstream fin("input.dat");
while (fin >> *c)
when I try that I get segmentation fault.
You are asking the stream to store a value into what is represented by the value that c points to. Instead of that, consider:
char ch;
char *c = &ch;
ifstream fin("input.dat");
while (fin >> ch) {
// whatever
}
This would not segfault immediately. However, bad things would happen on the "next" iteration, as you change the value of c inside the parsing functions.
You need to restructure the program and abstract the intention of reading the next character from the method of reading the next character (by incrementing a pointer, or reading from a stream, or whatever).
Or you could also read the file into one big memory buffer and then proceed as if that buffer was a string passed from the command line.
Assuming your file is a text file with one entry to parse per line you could do this:
ifstream fin("input.dat")
if (fin.is_open())
{
std::string line;
while (fin.good())
{
getline(fin, line);
c = line.c_str();
... go and parse c
}
}
Update: apparently c is non-const, so using c_str() won't work just like that. You have two options:
Change your parser to work with std::string (use an index to point at the current character).
Allocate some memory and copy the c_str() in there.
Number 1 is probably the better way.
Related
I am solving a question in which I have to check if the input string of parentheses are balanced or not,
and if not, code is expected to return the 1-based index of unmatched closing parenthesis, and if not found, return the 1-based index of the opening parenthesis. My code runs fine if I implement only the parenthesis checking part, but as I try to implement the returning index part, the code starts giving 'success' output for all the input.
Here is the code:
#include<iostream>
#include<string>
#include<algorithm>
#include<stack>
using namespace std;
int process_input( string value );
bool closing_bracket_match(char opening_bracket, char closing_bracket);
bool closing_bracket_match(char opening_bracket , char closing_bracket){
if( (opening_bracket == '{' && closing_bracket == '}') || (opening_bracket == '(' && closing_bracket == ')') || (opening_bracket == '[' &&
closing_bracket == ']') ){
return true;
}
else{
return false;
}
}
int process_input( string value ){
stack<char> processed_input{};
int unmatched_index{};
for( size_t i{}; i< value.size() ; ++i ){
if( value.at(i) == '{' || value.at(i) == '(' || value.at(i) == '[' ){ // check for opening brackets
processed_input.push(value.at(i)); // Appending opening bracket into the stack
}
else if( (value.at(i) == '}' || value.at(i) == ')' || value.at(i) == ']') && (processed_input.empty() == false) &&
closing_bracket_match(processed_input.top(),value.at(i)) ){ // the bracket in stack would be popped
processed_input.pop(); // matching brackets ar removed
}
}
if( processed_input.empty()==true ){
return 0;
}//This part is causing the bug
if(processed_input.empty() == false){
auto it = find( value.begin(), value.end(), processed_input.top() );
if( it!= value.end() ){
unmatched_index = distance(value.begin() , it)+1; //returning the 1 -based index of unmatched bracket
}
return unmatched_index;
}
}
int main(){
string input{};
cout<<"Please enter the code here: "; // debug line
cin>> input;
int result{};
result = process_input(input);
if( result == 0 ){
cout<<"Success";
}
else{
cout<<result;
}
}
If you want to return a position of the last (innermost) unmatched paren, you need to store it together with its position on the stack. Seeking for it leads to errors.
Which of potentially several items equal to the one you seek will find() find?
For example, in "(((" there are three unmatched opening parentheses, and all of them are equal to '('. Which one do you want to return as a result? Which one do you actually return?
And how about this input: "()("...?
Added
Here is a possible solution. Please note how it does not find() anything, but it stores on a stack all information necessary to produce the desired output.
#include<iostream>
#include<string>
#include<stack>
using std::string;
using std::stack;
bool is_opening(char c) {
return c == '(' || c == '[' || c == '{';
}
bool is_closing(char c) {
return c == ')' || c == ']' || c == '}';
}
bool is_matching(char opn, char cls) {
switch(opn) {
case '(': return cls == ')';
case '[': return cls == ']';
case '{': return cls == '}';
}
return false;
}
int process_input( string value )
{
stack<char> opn_parens{};
stack<size_t> positions{};
for( size_t i{}; i < value.size() ; ++i )
{
const char ch = value.at(i);
if( is_opening(ch) )
{
opn_parens.push(ch);
positions.push(i);
}
else if( is_closing(ch) )
{
if( opn_parens.empty() ) // a closing paren with no unmatched opening one
return i + 1;
const char opn_ch = opn_parens.top();
const size_t opn_pos = positions.top();
if( ! is_matching(opn_ch, ch) ) // unmatched closing paren
return opn_pos + 1;
opn_parens.pop(); // remove a matched paren
positions.pop();
}
}
if( ! positions.empty() ) // some unmatched parens remain
return positions.top() + 1;
return 0;
}
int main(){
std::cout << process_input("hello(mum[]{(dad()[bro!])})") << std::endl;
std::cout << process_input("))") << std::endl;
std::cout << process_input("([") << std::endl;
std::cout << process_input("([)") << std::endl;
std::cout << process_input("([{") << std::endl;
}
You can see it working at https://godbolt.org/z/e8fYW5fKz
So writing a palindrome with pointers and boolean. I have it working with a single word but then I began building it to work with a sentence. The problem is I am unsure how to keep the new modified sentence after making it lowercase and getting rid of the spaces for it to return whether it is or isn't a palindrome. It keeps returning the palindrome as false and when I went to check why I see that the program ignores the modification and kept the original string. I can't use "&" on the parameter as I tested it out. Any hints or takes on what I can do to keep the new modified string?
int main()
{
userInput();
return 0;
}
void userInput()
{
char str[90];
std::cout<<"Please enter a string to check if it is a palindrome: ";
std::cin.getline(str, 90);
modifyString(str);
}
void modifyString(char *string)
{
int count = 0;
for (int i=0; i<strlen(string); i++)
{
putchar(tolower(string[i]));
}
for (int i = 0; string[i]; i++)
{
if (string[i] != ' ')
{
string[count++] = string[i];
}
}
string[count] = '\0';
std::cout<<string<<std::endl;
results(string);
}
bool checkPalindrome(char *string)
{
char *begin;
char *end;
begin = string;
end = (string + strlen(string)-1);
while(begin != end)
{
if ((*begin) == (*end))
{
begin ++;
end--;
}
else
{
return false;
}
}
return true;
}
void results(char *string)
{
bool isItPalindrome;
isItPalindrome = checkPalindrome(string);
if( isItPalindrome == true)
{
std::cout<<"\nCongrats, the string is a palindrome!";
}
else
{
std::cout<<"\nThis string is not a palindrome.";
}
}
For starters this definition of main
int main()
{
userInput();
return 0;
}
does not make a sense. According to the function name main the function should perform the main task that is to output whether the entered sentence is a palindrome or not.
This for loop
for (int i=0; i<strlen(string); i++)
{
putchar(tolower(string[i]));
}
does nothing useful. It just outputs the string in the lower case.
This statement
end = (string + strlen(string)-1);
can invoke undefined behavior if an empty string was passed.
This while loop
while(begin != end)
{
if ((*begin) == (*end))
{
begin ++;
end--;
}
else
{
return false;
}
}
also can invoke undefined behavior for a string containing an even number ofo characters because after this if statement
if ((*begin) == (*end))
{
begin ++;
end--;
}
if the two adjacent characters are equal then begin after incrementing will be greater than end after its decrementing. And as a result the loop will continue its iteration.
In general the approach when the original string is changed is just a bad approach.
Your program has too many functions. It is enough to write one function that will determine whether the passed string is a palindrome or not.
Here is a demonstrative program.
#include <iostream>
#include <cstring>
#include <cctype>
bool checkPalindrome( const char *s )
{
const char *t = s + std::strlen( s );
do
{
while ( s != t && std::isspace( ( unsigned char )*s ) ) ++ s;
while ( s != t && std::isspace( ( unsigned char )*--t ) );
} while ( s != t &&
std::tolower( ( unsigned char )*s ) == tolower( ( unsigned char ) *t ) &&
++s != t );
return s == t;
}
int main()
{
const size_t N = 100;
char s[N] = "";
std::cout << "Please enter a string to check if it is a palindrome: ";
std::cin.getline( s, N );
std::cout << '\n';
if ( checkPalindrome( s ) )
{
std::cout << "Congrats, the string is a palindrome!\n";
}
else
{
std::cout << "This string is not a palindrome.\n";
}
return 0;
}
Its output might look like
Please enter a string to check if it is a palindrome: 1 23 456 6 54 321
Congrats, the string is a palindrome!
Okay, I solved it!
As one of the users on here brought up a point that my lowercase did not modify the string and only prints it out. I try my best to solve the problem and I think I found the solution and everything works perfectly fine. comment back to debug it if you like to see how it looks but what I did was create a for loop again for the lower case but made another pointer with it. here how it looks.
for (char *pt = string; *pt != '\0'; ++pt)
{
*pt = std::tolower(*pt);
++pt;
}
Now that definitely changes the string into a lower case and keeps it as a lower case.
so now the modified function looks like this and ready to take any sentence palindrome you give it. Example: A nUt fOr a jAr of tUNa. We make this all lowercase and take out space and boom palindrome and return true.
void modifyString(char *string)
{
int count = 0;
for (char *pt = string; *pt != '\0'; ++pt)
{
*pt = std::tolower(*pt);
++pt;
}
for (int i = 0; string[i]; i++)
{
if (string[i] != ' ')
{
string[count++] = string[i];
}
}
string[count] = '\0';
//take out the forward slash below to see how it looks after being modified
// std::cout<<std::endl<<string<<std::endl;
results(string);
}
So, the goal is to check to see if the C style string ends with a period or exclamation mark. However, for some reason, i keep getting false.
bool isItSentence(const char* s)
{
int x = strlen(s);
for (int c = 0; s[c] != '\0'; c++)
{
if (!isupper(s[0])) return false;
if (isupper(s[c]) && c > 0) return false;
if (s[x-1] != '.') return false;
if (s[x-1] != '!') return false;
}
return true;
}
int main()
{
std::string str = "Smelly.";
reverse(str.c_str());
std::cout << isItSentence(str.c_str()) << std::endl;
std::cout << strlen(str.c_str()) << std::endl;
system("pause");
Heres what I have so far. But when I add the last if statement to handle exclamation marks, it returns zero. Any suggestions?
First, note s[x-1] is a loop invariant, so you'd rather move it out of the for loop
if (s[x-1] != '.') return false;
if (s[x-1] != '!') return false;
this is always false (a char cannot be both a dot and an explanation mark).
the test should rather be
if (s[x-1] != '.' && s[x-1] != '!') return false;
I need to write a program that uses a stack to verify if a string expression is balanced, in regards to the parenthesis, brackets, and curly braces contained in it. The string's are to be inputted by the user, and all errors (i.e. mismatched parenthesis, brackets, and curly braces) need to be pointed out by a caret on the next line, directly under it, like this:
(a bit hard to show here...)
(()
^
In my "balanced" function, I am taking the current index of the loop, and assigning it to either "unmatchedRightPosition" or "unmatchedLeftPosition," whichever one is needed, at the time. I think that a lot of my program works already, but I'm having problems with placing the carets under the errors. My professor suggested that I may choose to use a stack class that holds structs, where each struct contains both a char and the char's position, but I am a bit puzzled by that.
Thanks for looking
#include <iostream>
#include <string>
#include <stdlib.h>
#include <sstream>
using namespace std;
struct Stack{
static const unsigned MAX_SIZE = 5;
char data[ MAX_SIZE ];
unsigned size;
};
struct Stack2{
unsigned unmatchedLeftPos, unmatchedRightPos;
};
void initialize( Stack & stack );
void show( const Stack & stack );
unsigned getSize( const Stack & stack );
void push( Stack & stack, char c );
char pop( Stack & stack );
char top( const Stack & stack );
bool die( const string & msg );
bool balanced (unsigned & unmatchedLeftPos, unsigned & unmatchedRightPos, const string & expr);
int main(){
Stack2 s2;
cout << "\nPlease enter your expression - enter a blank line to quit. \n";
for(;;){
string line;
getline(cin, line);
if( line.size() == 0 ) break;
if (balanced(s2.unmatchedLeftPos, s2.unmatchedRightPos, line) == 1){
cout << "OK\n";
}
else if (balanced(s2.unmatchedLeftPos, s2.unmatchedRightPos, line) == 0){
cout << string(s2.unmatchedLeftPos, ' ') << '^';
cout << string(s2.unmatchedRightPos, ' ') << '^';
}
}
return 0;
}
void initialize( Stack & stack ){
stack.size = 0;
}
void show( const Stack & stack ){
cout <<"[" << stack.size <<"]:";
for( unsigned i = 0; i < stack.size; i++ )
cout <<stack.data[i];
cout <<endl;
} // show
unsigned getSize( const Stack & stack ) {return stack.size;}
void push( Stack & stack, char c ){
if( stack.size == Stack::MAX_SIZE ) die( "push: overflow" );
stack.data[stack.size++] = c;
} // push
char pop( Stack & stack ){
if( stack.size == 0 ) die( "pop: underflow" );
return stack.data[--stack.size];
} // pop
char top( const Stack & stack ){
if( stack.size == 0 ) die( "top: underflow" );
return stack.data[stack.size-1];
} // pop
bool die( const string & msg ){
cerr <<endl <<"Fatal error: " << msg <<endl;
exit( EXIT_FAILURE );
}
bool balanced (unsigned & unmatchedLeftPos, unsigned & unmatchedRightPos, const string & expr){
Stack s;
initialize(s);
unsigned i;
for (i = 0; i < expr.size(); i++){
char c = expr[i];
if( expr.size() == Stack::MAX_SIZE) {
die( "push: overflow" );
}
if (c == '(')
{
push(s, c);
}
else if (c == '['){
push(s, c);
}
else if (c == '{'){
push(s, c);
}
if (s.size == 0 && (c == ')' || c == ']' || c == '}'))
{
unmatchedRightPos = i;
return false;
}
else if (c == ')' && top(s) == '('){
pop(s);
}
else if (c == ']' && top(s) == '['){
pop(s);
}
else if (c == '}' && top(s) == '{'){
pop(s);
}
}
if (s.size == 0){
return true;
}
else if (top(s) == '(' || top(s) == '[' || top(s) == '{'){
unmatchedLeftPos = i;
return false;
}
}
You are currently using stack, with an array of characters:
char data[ MAX_SIZE ];
Instead, you would go for a struct, that holds both character and position in the input string
struct info {
char data;
int pos;
};
info data[ MAX_SIZE ];
So at the end, you just check your stack, and in addition to invalid characters, you also have the position in the input string.
Hope that helps.
You can move your main to the bottom to avoid forward function declarations. You also don't need to use another stack for the errors (actually I think it's easier if you don't). You just need to hold both the bracket and its position on a single stack, i.e.
struct Item
{
char bracket;
size_t position;
}
std::stack<Item> st;
As well as either an array or, better a string initialized to the same length as the input string with all spaces which you change to '^' upon encountering an error, i.e.
std::string errorString(input.size(), ' ');
if ( /* brackets don't match */ )
{
errorString[st.top().position] = '^';
}
In case you cannot use STL stack, you need to modify your own to hold Item objects instead of char (i.e. Item data[ MAX_SIZE ];). Your code looks very much like C thought and it would be better if you made use of std::string and std::stack instead.
I'm trying to make sure all arguments passed to main are valid integers, and if not, I'll print an error. For example, if I have an executable named total, I would enter total 1 2 3 4.
I want to print an error if there's an invalid integer, so if I enter total 1 2 3zy it will print an error message. My code is as follows.
#include <iostream>
#include<stdlib.h>
using namespace std;
bool legal_int(char *str);
int main(int argc, char *argv[])
{
//int total = 0;
for(int i = 1; i < argc; i++)
{
if( (legal_int(argv[i]) == true) )
{
cout << "Good to go" << endl;
}
else
{
cerr << "Error: illegal integer." << endl;
return 1;
}
}
// int value = atoi(argv[i]);
//cout << value << endl;
}
bool legal_int(char *str)
{
while(str != 0) // need to
if( (isdigit(str)) )// do something here
{
return true;
}
else
{
return false;
}
}
What I need to know is how can I index through all the characters in the string and make sure they are digits with the legal_int function?
When comparing every character, the logic should be if it's not legal, return false, otherwise continue:
bool legal_int(char *str)
{
while (str != 0)
{
if (!isdigit(*str))
{
return false;
}
str++;
}
return true;
}
What about:
bool legal_int(char *str) {
while (*str)
if (!isdigit(*str++))
return false;
return true;
}
It is not the best function but it should serve the purpose. The isdigit function needs a character to look at so pass in *str. The other key point is that you need to advance the pointer inside of the loop.
bool legal_int(char *str)
{
while(str != 0) // need to
if( (isdigit(str)) )// do something here
{
return true;
}
else
{
return false;
}
}
You have three mistakes:
while (str != 0) should be while (*str != 0). You want to continue until you encounter a zero in the string, not until the string itself goes away.
if( (isdigit(str)) ) should be if( (isdigit(*str++)) ). You want to look at what str points to and see if that's a digit, and you need to point to the next digit.
return true; That should not be there. You don't want to return just because you found a single digit.