Bjarne Stroustrup programming practices and principles chapter 7 - c++

I have a question about logic flow:
I'm trying to create a calculator functionality that:
1.lets you assign a declare a variable (eg, let x = 5;)
2. that will also let you reassign a value (eg, x = 10;)
3. will let you use values in expressions (eg, x + 5; returns 15)
The bottom function statement() is supposed to decide if Token Token_stream::get()
returns a declaration, reassignment, or expression then run the appropriate code.
In making it so that Token_stream::get() returns name to statement()
and calls the reassignment. I lost the functionality to
have an expression() start with a name. Eg. If I write
x + 5;
It will throw an error from assignment because it reads the x and looks for a =
instead of calling expression.
I want to create special token for assignment to use in statement() if Token Token_stream::get() reads a string followed by a '=', but then put the name back into the input stream so I can grab if for the assignment. Does any have any suggestions?
//------------------------------------------------------------------------------
Token Token_stream::get()
{
if (full) { full=false; return buffer; }
char ch;
cin >> ch;
switch (ch) {
case '(':
case ')':
case '+':
case '-':
case '*':
case '/':
case '%':
case ';':
case '=':
case ',':
return Token(ch);
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{ cin.unget();
double val;
cin >> val;
return Token(number,val);
}
default:
if (isalpha(ch)) {
string s;
s += ch;
while(cin.get(ch) && (isalpha(ch) || isdigit(ch))|| ch =='_' ) s+=ch;
cin.unget();
if (s == "let") return Token(let);
if (s == "const") return Token(constant);
if (s == "q") return Token(quit);
if (s == "sqrt") return Token(square_root);
if (s == "pow") return Token(exponent);
return Token(name,s);
}
error("Bad token");
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
double statement()
{
Token t = ts.get();
switch(t.kind)
{
case let:
return declaration();
case name:
ts.unget(t);
return assigment();
case constant:
return declare_constant();
default:
ts.unget(t);
return expression();
}
}
//----

I wouldn't put error handling logic inside a tokenizer class - it's supposed to be a pretty dumb text muncher that just splits it on whitespaces and returns tokens to the caller.
So lets say you start parsing a statement and your tokeninizer returns let. Now you know that what follows is supposed to be a declaration. The next token should be a unique name of a variable that doesn't exists yet. So you call Token_stream::get() again and see what you get. On success, you get the next token and see if you get a =. Etc.
Similarly - you get a name of a variable as a first token of a statement. You check whether it has been declared yet and report an error if it hasn't. You check another token. It's supposed be an operator of some sort (that probably includes =). If you get it, you start looking for a valid term (a value, another variable, an expression...). Etc.

Related

C++ PPP Chapter 8 Exercise 1

Modify the calculator program from Chapter 7 to make the input stream an explicit parameter (as shown in §8.5.8), rather than simply
using cin. Also give the Token_stream constructor (§7.8.2) an istream&
parameter so that when we figure out how to make our own istreams
(e.g., attached to files), we can use the calculator for those. Hint:
Don’t try to copy an istream.
I'd say this is the code that might relate to what I have to do here?
class Token_stream {
public:
Token get(); // get a Token
void putback(Token t); // put a token back
void ignore(char c); // discard characters up to and including a c
private:
bool full{ false }; // is there a Token in the buffer?
Token buffer{ '0' };
// here is where putback() stores a Token
};
Token Token_stream::get()
{
if (full) { // do we already have a Token?
full = false; // remove Token from buffer
return buffer;
}
char ch;
cin.get(ch); // look for any char including whitespace
while (isspace(ch) && ch != '\n') cin.get(ch);
switch (ch) {
case '\n':
return Token{ print };
case print:
case quit:
case help:
case '(':
case ')':
case '{':
case '}':
case '!':
case '+':
case '-':
case '*':
case '/':
case '%':
case '=':
case ',':
return Token{ ch }; // let each character represent itself
case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
cin.putback(ch); // put digit back into input stream
double val;
cin >> val; // read floating-point number
return Token{ number, val };
}
default:
if (isalpha(ch)) {
string s;
s += ch;
while (cin.get(ch) &&
((isalpha(ch) || isdigit(ch) || ch == '_')))
s += ch;
cin.putback(ch);
if (s == declkey) return Token{ let }; // declaration keyword
else if (s == sqrtkey) return Token{ square_root };
else if (s == expkey) return Token{ exponent };
else if (s == sinkey) return Token{ c_sin };
else if (s == coskey) return Token{ c_cos };
else if (s == quitkey) return Token{ quit };
else if (s == helpkey) return Token{ help };
else return Token{ name, s };
}
error("Bad token");
}
};
But I'm still not really sure what I have to do here? Like I just don't understand what I need to do and how.. Can anybody maybe help me out? I did some research on what istream is but I still am not really sure what to do here..
He means to give token to function as an argument rather than using a std::cin statement inside a function.
void Token_stream::putback(Token t) //like this one
{
if (full) error("putback() into full buffer");
buffer = t;
full = true;
}
// ignore Tokens up to specific kind
void Token_stream::ignore(char c) // and this one
{
// first look in buffer:
if (full && c==buffer.kind) {
full = false;
return;
}
full = false;
char ch = 0;
while (cin>>ch)
if (ch==c) return;
}

the difference between for(char& c : s) and for(char c : s)?

This is a problem on leetcode
Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not.
And this is a solution:
class Solution {
public:
bool isValid(string s) {
stack<char> paren;
for (char& c : s) {
switch (c) {
case '(':
case '{':
case '[': paren.push(c); break;
case ')': if (paren.empty() || paren.top()!='(') return false; else paren.pop(); break;
case '}': if (paren.empty() || paren.top()!='{') return false; else paren.pop(); break;
case ']': if (paren.empty() || paren.top()!='[') return false; else paren.pop(); break;
default: ; // pass
}
}
return paren.empty() ;
}
};
This is another solution:
class Solution {
public:
bool isValid(string s) {
stack<char> paren;
for (char c : s) {
switch (c) {
case '(':
case '{':
case '[': paren.push(c); break;
case ')': if (paren.empty() || paren.top()!='(') return false; else paren.pop(); break;
case '}': if (paren.empty() || paren.top()!='{') return false; else paren.pop(); break;
case ']': if (paren.empty() || paren.top()!='[') return false; else paren.pop(); break;
default: ; // pass
}
}
return paren.empty() ;
}
};
The only difference between two solution is
for (char& c : s)
in the first solution and
for (char c : s)
in the second solution.
However, the first solution only take 3ms and the second takes 6ms.
So why the first solution is faster than the second solution?
for (char c : s)
This creates a copy of each element in s and stores it in c. This means that modifying c does not modify s.
for (char& c : s)
This does NOT create a copy of each element in s but instead directly references and stores it in c as an alias. This means that modifying c does modify s.
Since copying can be an expensive operation, the peformance of it is slower versus referencing (even with built in types when optimizations are not present), which avoids a copy.
If you want to prevent from unknowingly modifying the string, then you can use a const reference, i.e:
for (const char& c : s)

Programming and Principles chapter 6 Tokens and Calculator

This is the code set-up:
class Token {
public:
char kind; // what kind of token
double value; // for numbers: a value
Token(char ch) // make a Token from a char
:kind(ch), value(0) { }
Token(char ch, double val) // make a Token from a char and a double
:kind(ch), value(val) { }
};
//------------------------------------------------------------------------------
class Token_stream {
public:
Token_stream(); // make a Token_stream that reads from cin
Token get(); // get a Token (get() is defined elsewhere)
void putback(Token t); // put a Token back
private:
bool full; // is there a Token in the buffer?
Token buffer; // here is where we keep a Token put back using putback()
};
//------------------------------------------------------------------------------
// The constructor just sets full to indicate that the buffer is empty:
Token_stream::Token_stream()
:full(false), buffer(0) // no Token in buffer
{
}
//------------------------------------------------------------------------------
// The putback() member function puts its argument back into the Token_stream's buffer:
void Token_stream::putback(Token t)
{
if (full) error("putback() into a full buffer");
buffer = t; // copy t to buffer
full = true; // buffer is now full
}
//------------------------------------------------------------------------------
Token get()
{
if (full) { // do we already have a Token ready? //Syntax error "full" and "buffer" not declared
// remove token from buffer
full=false;
return buffer;
}
char ch;
cin >> ch; // note that >> skips whitespace (space, newline, tab, etc.)
switch (ch) {
case ';': // for "print"
case 'q': // for "quit"
case '(': case ')': case '+': case '-': case '*': case '/':
return Token(ch); // let each character represent itself
case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '9':
{
cin.putback(ch); // put digit back into the input stream
double val;
cin >> val; // read a floating-point number
return Token('8',val); // let '8' represent "a number"
}
default:
error("Bad token");
}
}
//------------------------------------------------------------------------------
Token_stream ts; // provides get() and putback()
//------------------------------------------------------------------------------
double expression(); // declaration so that primary() can call expression()
//------------------------------------------------------------------------------
// deal with numbers and parentheses
double primary()
{
Token t = ts.get();
switch (t.kind) {
case '(': // handle '(' expression ')'
{
double d = expression();
t = ts.get();
if (t.kind != ')') error("')' expected)");
return d;
}
case '8': // we use '8' to represent a number
return t.value; // return the number's value
default:
error("primary expected");
}
}
//------------------------------------------------------------------------------
// deal with *, /, and %
double term()
{
double left = primary();
Token t = ts.get(); // get the next token from token stream
while(true) {
switch (t.kind) {
case '*':
left *= primary();
t = ts.get();
case '/':
{
double d = primary();
if (d == 0) error("divide by zero");
left /= d;
t = ts.get();
break;
}
default:
ts.putback(t); // put t back into the token stream
return left;
}
}
}
//------------------------------------------------------------------------------
// deal with + and -
double expression()
{
double left = term(); // read and evaluate a Term
Token t = ts.get(); // get the next token from token stream
while(true) {
switch(t.kind) {
case '+':
left += term(); // evaluate Term and add
t = ts.get();
break;
case '-':
left += term(); // evaluate Term and subtract
t = ts.get();
break;
default:
ts.putback(t); // put t back into the token stream
return left; // finally: no more + or -: return the answer
}
}
}
I'm having difficulty understanding expression(), term(), and primary(). Expression() says that once it reads the token in, if the token is a number, it'll return left, which is term(), which then ALSO returns left, which is primary(), which finally returns the value of the number itself. However, what I don't understand are the switch cases. Expression() states that left = left +/- term() but left already exists as term() in this case? Wouldn't the code just repeat multiplying, dividing, adding, and subtracting by itself over and over? The switch cases also never seem to return anything, instead just getting the next token, and finally breaking, after acknowledging that it found an operator and moved on with the calculations, so I'm confused as to how this would present any indication of calculations without something like cout or return?
About the switches: they all return a double in the appropriate case and continue consuming and processing in the other (non-error) cases.
About endless loops: expression() calls term(), term() calls primary(), primary() calls expression() only when it reads an '(' and they all call get() to consume the input, so everything is input driven and with valid input (ending with 'q' or ';'), should end with a value after consuming all the input, which is returned by expression().
About left += term(): left is the result of term() and after this statement, left is the result of whatever was in left + the result of term(), so left is still a number.
One error in the code: Token get() should be Token Token_stream::get()

c++ An interesting result [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
This code somehow always adds to the conclusion 12142.
For example insert 12; the output is 1212142, insert 1 + 2; get 312142
#include "stdafx.h"
#include <iostream>
using namespace std;
class Token
{
public:
char kind;
double value;
};
class Token_stream
{
public:
Token get();
void putback(Token t);
private:
bool full{ false };
Token buffer;
};
void Token_stream::putback(Token t)
{
buffer = t;
full = true;
}
Token Token_stream::get()
{
if (full)
{
full = false;
return buffer;
}
char ch;
cin >> ch;
switch (ch)
{
case ';':
case 'q':
case '(': case ')': case '+':
case '-': case '*': case '/':
return Token{ ch };
case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
cin.putback(ch);
double val;
cin >> val;
return Token{ '8',val };
}
default:
throw runtime_error("dont true token");
break;
}
}
Token_stream ts;
double expres();
double prim()
{
Token t = ts.get();
switch (t.kind)
{
case '(':
{
double d = expres();
t = ts.get();
if (t.kind != ')')
{
throw runtime_error("))))");
}
return d;
}
case '8':
return t.value;
default:
throw runtime_error("perm");
}
}
double term()
{
double left = prim();
Token t = ts.get();
while (true)
{
switch (t.kind)
{
case '*':
left *= prim();
t = ts.get();
break;
case '/':
{
double d = prim();
if (d == 0)
{
throw runtime_error("/0");
}
left /= d;
t = ts.get();
break;
}
default:
ts.putback(t);
return left;
}
}
}
double expres()
{
{
double left = term();
Token t = ts.get();
while (true)
{
switch (t.kind)
{
case '+':
left += term();
t = ts.get();
break;
case '-':
left -= term();
t = ts.get();
break;
default:
ts.putback(t);
return left;
}
}
}
}
int main()
{
double val = 0;
while (cin)
{
Token t = ts.get();
if (t.kind == 'q') break;
if (t.kind == ';')
cout << "=" << val << '/n';
else
ts.putback(t);
val = expres();
}
return 0;
}
This code is taken from the book Programming - Principles and Practice Using C ++
Look here:
if (t.kind == ';')
cout << "=" << val << '/n';
'/n' is the character / followed by the character n, squeezed into what's known as a "multi-character literal". These are actually ints with implementation-defined values; on your system, apparently that's the number 12142.
You meant the single character '\n'.
In future, locate and solve problems like this by constructing a minimal testcase. In doing so, you would eventually have ended up with a test program that simply said cout << '/n' and output 12142; at that point, if you still didn't spot the typo, you'd have a very simple thing to look up and/or ask about.

A recursive parser help

I'm supposed to write this c++ that take in 01 and on. for example: 01010101 but not 0,1,10,011,110. Can someone help me figure out what I need to do to fix the problem. Sorry guys the code isn't working right.I pushed ctrl+k and posted the code but everything wasn't in place.
What I was trying to do is that when some enter 1 than it prints invalid. if they enter 0 it prints invalid, if the enter 10 it prints invalid, if they enter 01 it prints valid, if the enter 0101 it prints valid. So 0 always have to come first and always follow by 1. another example: 0101010101 prints valid
Thanks Seth :). I removed the links
[From seth.arnold: I removed commented-out code and indented the code to follow some kind of logical pattern. Feel free to replace this with your code if you wish, indent each line by four spaces to properly format it.]
#include <iostream>
#include<stdlib.h> // for the exit(1) function
using namespace std;
char text[300];
char ToBeChecked;
char lexical(); //identify the characters
void SProd();
void BProd();
int main(){
cout<<"Enter some strings only 1 and 0 (max. 300 characters"<<endl;
cin>>text;
ToBeChecked = lexical(); //identify the character; find the first letter and give it to ToBeChecked
SProd();
if(ToBeChecked == '\0')
cout<<"Valid"<<endl;
else
cout<<"Invalid"<<endl;
cin.get();
return 0;
}
char lexical(){
static int index = -1; //a memory box named index with a value of -1; is static so it won't change.
//is -1 because -1 to 1 is 0; everything move on to next one
index++; //update index
return text[index]; //return the value of index
}
void SProd(){
if(ToBeChecked != '0' ) {
cout<<"Invalid"<<endl;
exit(1);
}
else{
BProd();
ToBeChecked = lexical();
}
}
void BProd(){
if(ToBeChecked != '1')
{
cout<<"Invalid"<<endl;
exit(1);
}
else
SProd();
ToBeChecked = lexical();
}
Have a look in Bjorn Stroustroup's book Programming Principles and Practice using c++ chapter 6-7.
You will have to write the grammar, you need to know how to:
Distinguish a rule from a token
Put one rule after another (sequencing)
Express alternative patterns (alternation)
Express a repeating pattern
(repetition)
Recognize the grammar rule to start
with
For example - you will have to have a token class:
class Token {
public:
char kind; // what kind of token
double value; // for numbers: a value
Token(char ch) // make a Token from a char
:kind(ch), value(0) { }
Token(char ch, double val) // make a Token from a char and a double
:kind(ch), value(val) { }
};
Then Token stream class:
class Token_stream {
public:
Token_stream(); // make a Token_stream that reads from cin
Token get(); // get a Token (get() is defined elsewhere)
void putback(Token t); // put a Token back
private:
bool full; // is there a Token in the buffer?
Token buffer; // here is where we keep a Token put back using putback()
};
Identify default constructor for Token stream:
Token_stream::Token_stream()
:full(false), buffer(0) // no Token in buffer
{
}
Then create a putback() function, you will need that to put back the character you read from the iostream if it is of interest to you, and function who specializes in extraction of that particular character will be called:
void Token_stream::putback(Token t)
{
if (full) throw std::runtime_error("putback() into a full buffer");
buffer = t; // copy t to buffer
full = true; // buffer is now full
}
Then in Token::get() you will have to make the rules what is important to you and what you want to include, omit or throw error:
Token Token_stream::get()
{
if (full) { // do we already have a Token ready?
// remove token from buffer
full=false;
return buffer;
}
char ch;
cin >> ch; // note that >> skips whitespace (space, newline, tab, etc.)
switch (ch) {
case '=': // for "print"
case 'x': // for "quit"
case '(': case ')': case '{': case '}': case '+': case '-': case '*': case '/': case '!':
return Token(ch); // let each character represent itself
break;
case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '9':
{
cin.putback(ch); // put digit back into the input stream
double val;
cin >> val; // read a floating-point number
return Token('8',val); // let '8' represent "a number"
}
break;
default:
throw std::runtime_error("Bad token");
}
}
In this version of Token_stream::get() we are interested in numbers, mathematical operators and brackets. So you will have to change that case statement to get either '1' or '0', and ignore everything else, or throw, it is up to you, I don't know what is exactly you need to do.
Then create a grammar function, you will have to establish hierarchy of functions that call one another if you want or example 1 character to be processed in front of the other. But if you only need to read sequentially, you can have only 1 function. anyway, I include 3 functions that are using calculator example where you have +,-,*,/,(,),{,}. As you see this example need to identify what it is in order to call the right function before the other one, eg - multiplication before subscription.
primary() function deals with numbers and parentheses:
// deal with numbers and parentheses
double primary()
{
Token t = ts.get();
switch (t.kind) {
case '(': // handle '(' expression ')'
{
double d = expression();
t = ts.get();
if (t.kind != ')') throw std::runtime_error("')' expected");
return d;
break;
}
case '{':
{
double d = expression();
t=ts.get();
if (t.kind != '}') throw std::runtime_error("'}' expected");
return d;
break;
}
case '8': // we use '8' to represent a number
return t.value; // return the number's value
break;
default:
throw std::runtime_error("primary expected");
}
}
term() function deals with multiplication and division:
// deal with *, /, and %
double term()
{
double left = primary();
Token t = ts.get(); // get the next token from token stream
while(true) {
switch (t.kind) {
case '*':
left *= primary();
t = ts.get();
break;
case '/':
{
double d = primary();
if (d == 0) throw std::runtime_error("divide by zero");
left /= d;
t = ts.get();
break;
}
default:
ts.putback(t); // put t back into the token stream
return left;
}
}
}
expression() deals with addition and subtraction:
double expression()
{
double left = term(); // read and evaluate a Term
Token t = ts.get(); // get the next token from token stream
while(true) {
switch(t.kind) {
case '+':
left += term(); // evaluate Term and add
t = ts.get();
break;
case '-':
left -= term(); // evaluate Term and subtract
t = ts.get();
break;
default:
ts.putback(t); // put t back into the token stream
return left; // finally: no more + or -: return the answer
}
}
}
And finally our calling function:
int callDrill_01(void)
try
{
std::cout << "Welcome to simple calculator." << std::endl;
std::cout << "Please enter expressions using floating-point numbers." << std::endl;
std::cout << "The arithmetic operators available are: + - * / ( ) { } = e(x)it." << std::endl;
double val = 0;
while (cin) {
Token t = ts.get();
if (t.kind == 'x') break; // 'q' for quit
if (t.kind == '=') { // ';' for "print now"
cout << "=" << val << '\n';
}else{
ts.putback(t);
}
val = expression();
}
keep_window_open();
}
catch (exception& e) {
cerr << "error: " << e.what() << '\n';
keep_window_open();
return 1;
}
catch (...) {
cerr << "Oops: unknown exception!\n";
keep_window_open();
return 2;
}
This should give you an idea of how recursive parser are created. Your head is probably spinning. I suggest you to find that book that I mentioned and read those chapters. It will help you in the future.
#include <iostream>
//#include<stdlib.h> // for the exit(1) function
using namespace std;
char text[300];
char ToBeChecked;
char lexical(); //identify the characters
void SProd();
void BProd();
int main(){
cout<<"Enter some strings (max. 300 characters"<<endl;
cin>>text;
ToBeChecked = lexical(); //identify the character; find the first letter and give it to ToBeChecked
SProd();
if(ToBeChecked == '\0')
cout<<"Valid"<<endl;
else
cout<<"Invalid"<<endl;
cin.get();
return 0;
}
char lexical(){
static int index = -1; //a memory box named index with a value of -1; is static so it won't change.
//is -1 because -1 to 1 is 0; everything move on to next one
index++; //update index
return text[index]; //return the value of index
}
void SProd(){
if(ToBeChecked != 'a' ) {
BProd();
ToBeChecked = lexical();
}
}
void BProd(){
if(ToBeChecked == 'b'){
ToBeChecked = lexical();
SProd();
}
}