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()
Related
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;
}
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.
I'm learning C++ using B. Stroustrup's PPP, 1st edition. I was testing this simple calculator after completing Q9. from the Ch.7 exercises by giving random inputs to the calculator.
I'm using Visual Studio 2013 and this is the complete code of the calculator I'm using -
// This program is an simple calculator
/*
----------------------------------------------------------------------------------------
>>> Grammar used in this program to handle expressions and features <<<
Calculator:
Statement
Quit
Print
Help
Calculator Statement
Print:
";"
Quit:
"q"
Statement:
Declaration
Assignment
Expression
Declaration:
"let" Name "=" Expression
"const" Name "=" Expression
Assignment:
"set" Name "=" Expression
Name:
string-literal-starting-with-alphabet-or-underscore-and-contains-only-alphabets-underscores-&-numbers
Expression:
Term
Expression "+" Term
Expression "-" Term
Term:
Primary
Term "*" Primary
Term "/" Primary
Term "%" Primary
Primary:
Number
Name
"(" Expression ")"
"+" Primary
"-" Primary
"pow(" Primary "," Primary ")"
"sqrt(" Primary ")"
Number:
floating-point-literal
Input comes from cin through Token_stream called ts, in the form of Tokens.
*/
#include "std_lib_facilities.h"
struct Token {
char kind; // kind of Token
double value; // for numbers: value of Token
string name; // for variables: name of variables
Token(char ch) :kind(ch), value(0) { }
Token(char ch, double val) :kind(ch), value(val) { }
Token(char ch, string var) :kind(ch), name(var) { }
};
class Token_stream {
public:
Token_stream() :full(0), buffer(0) { }
Token get(); // get Tokens from Token_stream
void unget(Token t) { buffer = t; full = true; } // putback Token into Token_stream
void ignore(char c); // ignore characters till c is found, including c
private:
bool full; // buffer status
Token buffer; // buffer to store single Token
};
// Token.kind symbolic constants
const char let = '#'; // for variale-declaration
const char set = '#'; // for assignment
const char constant = '!'; // for constant-declaration
const char quit = 'Q'; // quit application
const char print = ';'; // print expression-output
const char number = '8'; // for number
const char name = 'a'; // for variable-name
const char sqroot = 'R'; // square root
const char power = 'P'; // power/order
//const char variabletype = 'v'; // variable type in Variable
//const char constanttype = 'c'; // constant type in Variable
const char help = 'h'; // help - instructions/examples/features
const string declkey = "let"; // declaration keyword, like let x = 2; to declare a new variable x
const string assignkey = "set"; // assignment keyword, like set x = 3; where x is a declared variable
const string quit1key = "quit"; // quit keyword 1
const string quit2key = "exit"; // quit keyword 2
const string quit3key = "q"; // quit keyword 3
const string powerkey = "pow"; // for using power function
const string sqrtkey = "sqrt"; // for using square root function
const string constkey = "const";// for declaring a symbolic constant, not a variable
const string help1key = "H"; // help keyword 1
const string help2key = "h"; // help keyword 2
const string help3key = "help"; // help keyword 3
const string help4key = "HELP"; // help keyword 4
const string help5key = "Help"; // help keyword 5
Token Token_stream::get()
{
if (full) { full = false; return buffer; }
char ch;
cin.get(ch);
switch (ch) {
case '(':
case ')':
case '+':
case '-':
case '*':
case '/':
case '%':
case print:
//case quit:
//case let:
case '=': // during variable/constant-initialization, assignment
case ',': // pow(x , i);
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) || ch == '_') { // check for alphabet
string s;
s += ch;
while (cin.get(ch) && (isalpha(ch) || isdigit(ch) || ch == '_')) s += ch; // store only alphabets, numbers & underscores
cin.unget();
if (s == declkey) return Token(let); // is current statement a variable-declaration?
if (s == constkey) return Token(constant); // is current statement a constant-declaration?
if (s == assignkey) return Token(set); // is current statement an assignment?
if (s == quit1key || s == quit2key || s == quit3key) return Token(quit); // user wants to quit?
if (s == help1key || s == help2key || s == help3key || s == help4key || s == help5key) return Token(help); // user needs help?
if (s == sqrtkey) return Token(sqroot); // square root of expression
if (s == powerkey) return Token(power); // pow(x,i) = x^i = x*x*...*x (i times)
return Token(name, s); // it's a variable name then
}
else if (isspace(ch)){
if (ch == '\n')
return Token(print);
else
return get();
}
error("Bad token");
}
}
void Token_stream::ignore(char c) // ignore all characters till & including c
{
if (full && c == buffer.kind) {
full = false;
return;
}
full = false;
char ch;
while (cin.get(ch))
if (ch == c) return;
}
struct Variable {
string name;
double value;
char type;
Variable(string n, double v, char c) :name(n), value(v), type(c) { }
};
class Table {
public:
double get(string s);
void set(string s, double d);
double declare(string s, double val, char type);
bool is_declared(string s);
private:
vector<Variable> var_table;
};
Table symbol_table;
double Table::get(string s) // get value of declared variable with name s
{
for (int i = 0; i < var_table.size(); ++i)
if (var_table[i].name == s) return var_table[i].value;
error("get: undefined name ", s);
}
void Table::set(string s, double d) // set value of declared variable with name s to d
{
for (int i = 0; i <= var_table.size(); ++i)
if (var_table[i].name == s) {
if (var_table[i].type == constant)
error("set: can't change the value of a constant");
var_table[i].value = d;
return;
}
error("set: undefined name ", s);
}
bool Table::is_declared(string s) // check if a variable with name s is declared
{
for (int i = 0; i < var_table.size(); ++i)
if (var_table[i].name == s) return true;
return false;
}
double Table::declare(string s, double d, char type)
{
if (is_declared(s))
error("declare: variable already exists ", s);
var_table.push_back(Variable(s, d, type));
return d;
}
Token_stream ts;
double expression();
double primary() // Primary:
{
Token t = ts.get();
switch (t.kind) {
case '(': // "(" Expression ")"
{
double d = expression();
t = ts.get();
if (t.kind != ')') error("primary: '(' expected");
return d;
}
case '-': // "-" Primary
return -primary();
case '+': // "+" Primary
return primary();
case number: // floating-point-number
return t.value;
case name: // value of variable with name t.name
return symbol_table.get(t.name);
case sqroot: // sqrt(x) or "sqrt" Primary
{
double d = primary();
if (d < 0) error("negative square root");
return sqrt(d);
}
case power:
{
t = ts.get(); // check for '('
if (t.kind != '(')
error("power_primary: '(' expected");
double d1 = expression();
t = ts.get();
if (t.kind != ',')
error("power_primary: ',' expected");
double d2 = expression();
t = ts.get();
if (t.kind != ')')
error("power_primary: ')' expected");
int i = narrow_cast<int>(d2);
//if (d2 - int(d2) > 0)
// error("power_primary: 2nd argument invalid, must be an integer");
//if (d1 == 0 && d2 == 0)
// error("power_primary: pow(0,0) is undefined");
return pow(d1, i);
}
default:
error("primary expected");
}
}
double term() // Term:
{
double left = primary(); // Primary
while (true) {
Token t = ts.get();
switch (t.kind) {
case '*': // Term "*" Primary
left *= primary();
break;
case '/': // Term "/" Primary
{
double d = primary();
if (d == 0) error("divide by zero");
left /= d;
break;
}
case '%': // Term "%" Primary
{
double d = primary();
int i1 = narrow_cast<int>(left);
int i2 = narrow_cast<int>(d);
if (i2 == 0)
error("term: modulo by zero");
left = i1%i2;
break;
}
default: // return term-value
ts.unget(t);
return left;
}
}
}
double expression() // Expression:
{
double left = term(); // Term
while (true) {
Token t = ts.get();
switch (t.kind) {
case '+': // Expression "+" Term
left += term();
break;
case '-': // Expression "-" Term
left -= term();
break;
default: // return expression-value
ts.unget(t);
return left;
}
}
}
double declaration() // assuming "let" has been found
{
Token t = ts.get();
char type;
type = t.kind;
t = ts.get();
if (t.kind != name) error("declaration: name expected in declaration"); // check if the Token read is a name
string name = t.name;
Token t2 = ts.get();
if (t2.kind != '=') error("declaration: '=' missing in declaration of ", name); // expecting a '=' after variable name
double d = expression(); // everything right so far, get the initial value of the variable
return symbol_table.declare(name, d, type); // store new variable/constant in vector names
}
double assignment() // assuming "set" has been found
{
Token t = ts.get();
if (t.kind != name) // check if the Token read is a name
error("assignment: name expected in declaration");
string var = t.name;
if (!symbol_table.is_declared(var)) // check if the variable is declared or not
error("assignment: can't assign value to an undeclared variable");
t = ts.get(); // check for '='
if (t.kind != '=')
error("assignment: '=' expected in declaration of ", var);
double newval = expression(); // get new value of variable var
symbol_table.set(var, newval); // set new value
return newval;
}
double statement()
{
Token t = ts.get();
switch (t.kind) {
case let: // is it a variable-declaration?
case constant: // is it a constant-declaration?
ts.unget(t);
return declaration();
case set: // or an assignment?
return assignment();
default: // or an expression?
ts.unget(t);
return expression();
}
}
void clean_up_mess()
{
ts.ignore(print); // ignore characters till and including 'print' character
}
const string prompt_str = "> ";
const string result_str = "= ";
void calculate()
{
// Welcome message
cout << " This program is a basic calculator\n"
<< " To know more use - 'help'\n"
<< " To quit use - 'quit' or 'exit'\n\n";
while (true)
try {
cout << prompt_str;
Token t = ts.get(); // get a token
while (t.kind == print) t = ts.get(); // eat all 'print' tokens
if (t.kind == quit) return; // 'quit' token?
else if (t.kind == help){
// Instructions to use calculator
cout << "\n INSTRUCTIONS TO USE -\n"
<< "\t1. Operations supported: +, -, *, /, % (last one for integers only), sqrt(x), pow(x,y) (y is an integer).\n"
<< "\t2. Use expressions like 1+2/3*4-5, followed by " << print << " to terminate expression.\n"
<< "\t3. Use square brackets or parenthesis or both in expressions as usual, for example, (1-2)*{(3-4)/2}.\n";
// Features
cout << "\n FEATURES -\n"
<< "\t1. Evaluate multiple expressions at once. Enter more than one expressions in a line and see them get evaluated at once.\n"
<< "\t2. Use variables for easy calculation. Declare them like this, \"let x = 6;\" or write any expression in place of '6'.\n"
<< "\t3. Assign new values to already declared variables like this, \"set x = 3;\"\n"
<< "\t4. Use constants like 'pi' & 'e' in statements instead of remembering their values.\n"
<< "\t5. Declare your own constants like this, \"const pi = 3.1415\"\n"
<< "\t6. Ask for help anytime, use \"Help\" or \"help\" or \"HELP\" or \"h\" or \"H\"\n"
<< "\t7. Want to quit, just type \"quit\" or \"exit\"\n"
<< "\n";
//continue;
}
else{
ts.unget(t); // some other token was read, so unread it, put it back in Token_stream
cout << result_str << statement() << endl; // read 'statement' from the input stream, and evaluate it, and print its result
}
}
catch (runtime_error& e) {
cerr << e.what() << endl;
clean_up_mess();
}
catch (...){
cerr << "Oops, unknown exception" << endl;
clean_up_mess();
}
}
int main()
{
try {
// pre-defined symbolic constants
symbol_table.declare("k", 1000, constant); // k = 1000 like pi = 3.1415926535(not defined here)
calculate();
char c;
while (cin.get(c) && c != print && c != '\n');
cout << "\n\n You've now exited the program.\n"
<< " Enter x to close this window.\n\n ";
while (cin >> c && c == 'x')
break;
return 0;
}
catch (exception& e) {
cerr << "exception: " << e.what() << endl;
char c;
while (cin >> c && c != print);
return 1;
}
catch (...) {
cerr << "Oops: Unknown exception\n";
char c;
while (cin >> c && c != print);
return 2;
}
}
But I've found that the program gives this error
whenever I provide it input of the form "some_real_number_here e string_starting_with_alphabet", without any whitespace, with last string being optional and it happens with e only and not with any other alphabet (hopefully because I haven't tried each & every combination of numbers & alphabets).
What is this error? How to resolve this?
Here is the library std_lib_facilities.h .
If you're testing the program too, then at the end of every input/expression to the program, have ; for letting the program clean_up_mess() easily.
Hopefully, this is the file mentioned in the error window, isctype.c.
For example -
Input: 2e; or 4easdf123; Output: The above mentioned error
Other weird outputs -
Input: 2e12; Output: 2e+12
Input: 3e1; Output: 30
Edit: It might be the case (discussed in comments) that Token_stream::get() function when trying to read a floating-point number like 2e+11, gives error because of expecting a number whenever >> sees something like this - "number e anything" (without whitespace) and when it finds an alphabet in anything instead of an integer, it throws an exception.
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.
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();
}
}