diff --git a/src/capitulo_06/CMakeLists.txt b/src/capitulo_06/CMakeLists.txt index 206746b..f643f92 100644 --- a/src/capitulo_06/CMakeLists.txt +++ b/src/capitulo_06/CMakeLists.txt @@ -5,4 +5,14 @@ project(capitulo_06) add_subdirectory(tente_isto/t02) add_subdirectory(tente_isto/t03) -add_subdirectory(pratica/p01) \ No newline at end of file +add_subdirectory(pratica/p01) + +add_subdirectory(exercicios/e02) +add_subdirectory(exercicios/e03) +add_subdirectory(exercicios/e04) +add_subdirectory(exercicios/e05) +add_subdirectory(exercicios/e06) +add_subdirectory(exercicios/e07) +add_subdirectory(exercicios/e08) +add_subdirectory(exercicios/e09) +add_subdirectory(exercicios/e10) \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e02/CMakeLists.txt b/src/capitulo_06/exercicios/e02/CMakeLists.txt new file mode 100644 index 0000000..11c65d4 --- /dev/null +++ b/src/capitulo_06/exercicios/e02/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.12.0) + +set(thisProject c06e02) + +project(${thisProject}) + +add_executable(${thisProject}) + +target_include_directories(${thisProject} PRIVATE + ${lib_path}) + +target_sources(${thisProject} PRIVATE + ${thisProject}.cpp + ${lib_file}) \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e02/README.md b/src/capitulo_06/exercicios/e02/README.md new file mode 100644 index 0000000..4dc2e7b --- /dev/null +++ b/src/capitulo_06/exercicios/e02/README.md @@ -0,0 +1,3 @@ +# Exercícios 2 + +Acrescente a capacidade de usar **{ }** e **( )** no programa, de modo que **{(4+5)\*6} / (3+4)** seja uma expressão válida. diff --git a/src/capitulo_06/exercicios/e02/c06e02.cpp b/src/capitulo_06/exercicios/e02/c06e02.cpp new file mode 100644 index 0000000..af6f08b --- /dev/null +++ b/src/capitulo_06/exercicios/e02/c06e02.cpp @@ -0,0 +1,203 @@ +#include "std_lib_facilities.h" + +//------------------------------------------------------------------------------ + +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 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 '}': + 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 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 '{': + { + 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(); + break; + 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 + } + } +} + +//------------------------------------------------------------------------------ + +int main() +try +{ + double val = 0; + + cout << "Welcome to our simple calculator." << endl + << "Please, enter an expression with point float numbers." << endl; + + cout << "Available operators: '+', '-', '*' and '/'" << endl; + cout << "To see the result, type '='. To exit, type 'x'" << endl; + + while (cin) { + Token t = ts.get(); + + if (t.kind == 'x') break; // 'x' 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; +} + +//------------------------------------------------------------------------------ diff --git a/src/capitulo_06/exercicios/e03/CMakeLists.txt b/src/capitulo_06/exercicios/e03/CMakeLists.txt new file mode 100644 index 0000000..7f1efa8 --- /dev/null +++ b/src/capitulo_06/exercicios/e03/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.12.0) + +set(thisProject c06e03) + +project(${thisProject}) + +add_executable(${thisProject}) + +target_include_directories(${thisProject} PRIVATE + ${lib_path}) + +target_sources(${thisProject} PRIVATE + ${thisProject}.cpp + ${lib_file}) \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e03/README.md b/src/capitulo_06/exercicios/e03/README.md new file mode 100644 index 0000000..1873feb --- /dev/null +++ b/src/capitulo_06/exercicios/e03/README.md @@ -0,0 +1,3 @@ +# Exercícios 3 + +Acrescente um operador de fatorial: use um operador de sufixo ! para representar "fatorial". Por exemplo, a expressão **7!** significa **7\*6\*5\*4\*3\*2\*1**. Faça com que ! tenha prioridade maior que * e /; isto é **7\*8!** significa **7\*(8!)**, em vez de **(7\*8)!**. Inicie pela modificação da gramática para considerar um operador de mais alto nível. Para concordar com a definição matemática padrão de fatorial, o **0!** é avaliado como **1**. Dica: As funções de calculadora lidam com **doubles**, mas o fatorial é definido somente para **int**s, então somente para **x !** atribua o **x** para um **int** e calcule o fatorial desse **int**. diff --git a/src/capitulo_06/exercicios/e03/c06e03.cpp b/src/capitulo_06/exercicios/e03/c06e03.cpp new file mode 100644 index 0000000..4a2a122 --- /dev/null +++ b/src/capitulo_06/exercicios/e03/c06e03.cpp @@ -0,0 +1,239 @@ +#include "std_lib_facilities.h" + +//------------------------------------------------------------------------------ + +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 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" + // Acrescente um operador de fatorial: use um operador de sufixo ! para representar "fatorial". + // Por exemplo, a expressão **7!** significa **7\*6\*5\*4\*3\*2\*1**. + 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 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() + +//------------------------------------------------------------------------------ +double factorialCalc(double n) +{ + // Para concordar com a definição matemática padrão de fatorial, o **0!** é avaliado como **1**. + if (n == 1 || n == 0) return 1; + + return n * factorialCalc(n - 1); +} + +// 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 '{': + { + 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"); + } +} + +//------------------------------------------------------------------------------ + +// Inicie pela modificação da gramática para considerar um operador de mais alto nível. +double factorial() +{ + int x = 0; + double left = primary(); + Token t = ts.get(); // get the next token from token stream + + while (true) + { + switch (t.kind) + { + case '!': + // Dica: As funções de calculadora lidam com **doubles**, mas o fatorial é definido somente para **int**s, + // então somente para **x !** atribua o **x** para um **int** e calcule o fatorial desse **int**. + x = left; + left = factorialCalc(x); + t = ts.get(); + break; + default: + ts.putback(t); // put t back into the token stream + return left; + } + } +} + +//------------------------------------------------------------------------------ + +// deal with *, /, and % +double term() +{ + double left = factorial(); + Token t = ts.get(); // get the next token from token stream + + while (true) { + switch (t.kind) { + case '*': + left *= factorial(); + t = ts.get(); + break; + case '/': + { + double d = factorial(); + 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 + } + } +} + +//------------------------------------------------------------------------------ + +int main() +try +{ + double val = 0; + + cout << "Welcome to our simple calculator." << endl + << "Please, enter an expression with point float numbers." << endl; + + cout << "Available operators: '+', '-', '*' and '/'" << endl; + cout << "To see the result, type '='. To exit, type 'x'" << endl; + + while (cin) { + Token t = ts.get(); + + if (t.kind == 'x') break; // 'x' 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; +} + +//------------------------------------------------------------------------------ diff --git a/src/capitulo_06/exercicios/e04/CMakeLists.txt b/src/capitulo_06/exercicios/e04/CMakeLists.txt new file mode 100644 index 0000000..dd06a76 --- /dev/null +++ b/src/capitulo_06/exercicios/e04/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.12.0) + +set(thisProject c06e04) + +project(${thisProject}) + +add_executable(${thisProject}) + +target_include_directories(${thisProject} PRIVATE + ${lib_path}) + +target_sources(${thisProject} PRIVATE + ${thisProject}.cpp + ${lib_file}) \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e04/README.md b/src/capitulo_06/exercicios/e04/README.md new file mode 100644 index 0000000..f170bb7 --- /dev/null +++ b/src/capitulo_06/exercicios/e04/README.md @@ -0,0 +1,3 @@ +# Exercícios 4 + +Defina uma classe **Nome_valor** que armazena uma cadeia de caracteres e um valor. Coloque um construtor (algo parecido com o de **Token**). Refaça o exercício 19 do Capítulo 4 para usar um **vector** em vez de dois **vector**. diff --git a/src/capitulo_06/exercicios/e04/c06e04.cpp b/src/capitulo_06/exercicios/e04/c06e04.cpp new file mode 100644 index 0000000..2e7091e --- /dev/null +++ b/src/capitulo_06/exercicios/e04/c06e04.cpp @@ -0,0 +1,71 @@ +#include "std_lib_facilities.h" + +// Defina uma classe **Nome_valor** que armazena uma cadeia de caracteres e um valor. +class ScoreBoard +{ +public: + string name; + int point; + + // Coloque um construtor (algo parecido com o de **Token**). + ScoreBoard(string str, int n) + :name(str), point(n) + { + } +}; + +bool checkIfNameExists(vector vec, string searchedName) +{ + for (int i = 0; i < vec.size(); i++) + { + if (vec[i].name == searchedName) return true; + } + + return false; +} + +// Escreva um programa em que você primeiro entra com um conjunto de pares de nome e valor, tais como Joe 17 e Barbara 22. +int main() +{ + string name = ""; + int point = 0; + bool keepInTheLoop = true; + bool nameExists = true; + vector scoreBoard; // Refaça o exercício 19 do Capítulo 4 para usar um **vector** em vez de dois **vector**. + + cout << "To stop loop type 'No longer'." << endl; + + while (keepInTheLoop) + { + cout << "Enter the name followed by the points: " << endl; + cin >> name >> point; + + // Encerre a entrada com a linha “Não mais” (“mais” irá provocar um erro na tentativa de ler outro inteiro). + if (point == 0) + { + keepInTheLoop = false; + continue; + } + + // Verifique se cada nome é único e termine com uma mensagem de erro se um nome for fornecido duas vezes. + nameExists = checkIfNameExists(scoreBoard, name); + + // Para cada par, coloque o nome em um vector chamado nomes e o número em um vector chamado pontos (em posições correspondentes, de modo que se nomes[7]==”Joe” então pontos[7]==17). + if (nameExists) + { + cout << "This name already exists." << endl; + continue; + } + + ScoreBoard t = ScoreBoard(name, point); + scoreBoard.push_back(t); + } + + // Escreva todos os pares (nome, pontos), um por linha. + for (int i = 0; i < scoreBoard.size(); i++) + { + cout << scoreBoard[i].name << " " << scoreBoard[i].point << endl; + } + + return 0; +} \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e05/CMakeLists.txt b/src/capitulo_06/exercicios/e05/CMakeLists.txt new file mode 100644 index 0000000..124b9d9 --- /dev/null +++ b/src/capitulo_06/exercicios/e05/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.12.0) + +set(thisProject c06e05) + +project(${thisProject}) + +add_executable(${thisProject}) + +target_include_directories(${thisProject} PRIVATE + ${lib_path}) + +target_sources(${thisProject} PRIVATE + ${thisProject}.cpp + ${lib_file}) \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e05/README.md b/src/capitulo_06/exercicios/e05/README.md new file mode 100644 index 0000000..9fdc24b --- /dev/null +++ b/src/capitulo_06/exercicios/e05/README.md @@ -0,0 +1,3 @@ +# Exercícios 5 + +Acrescente o artigo os na gramática do §6.4.1, de modo que possa descrever frases tais como "Os pássaros voam mas os peixes nadam". diff --git a/src/capitulo_06/exercicios/e05/c06e05.cpp b/src/capitulo_06/exercicios/e05/c06e05.cpp new file mode 100644 index 0000000..dfed6d5 --- /dev/null +++ b/src/capitulo_06/exercicios/e05/c06e05.cpp @@ -0,0 +1,41 @@ +#include "std_lib_facilities.h" + +void article(); +void subject(); +void verb(); +void conjunction(); +void sentence(); + +int main() +{ + cout << "Nothing to see here." << endl; + + return 0; +} + +// Acrescente o artigo os na gramática do §6.4.1, de modo que possa descrever frases tais como "Os pássaros voam mas os peixes nadam". +void article() +{ + vector articles{ "the" }; +} + +void subject() +{ + vector subjects{ "birds", "fish", "C++" }; +} + +void verb() +{ + vector verbs{ "predominates", "fly", "swim" }; +} + +void conjunction() +{ + vector conjunctions{ "and", "or", "but" }; +} + +void sentence() +{ + //article() + subject() + verb(); + //sentence() + conjunction() + sentence(); +} \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e06/CMakeLists.txt b/src/capitulo_06/exercicios/e06/CMakeLists.txt new file mode 100644 index 0000000..fbd4bbe --- /dev/null +++ b/src/capitulo_06/exercicios/e06/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.12.0) + +set(thisProject c06e06) + +project(${thisProject}) + +add_executable(${thisProject}) + +target_include_directories(${thisProject} PRIVATE + ${lib_path}) + +target_sources(${thisProject} PRIVATE + ${thisProject}.cpp + ${lib_file}) \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e06/README.md b/src/capitulo_06/exercicios/e06/README.md new file mode 100644 index 0000000..7f112c1 --- /dev/null +++ b/src/capitulo_06/exercicios/e06/README.md @@ -0,0 +1,3 @@ +# Exercícios 6 + +Escreva um programa que verifique se uma frase está correta de acordo com a gramática no §6.4.1. Suponha que cada frase é terminada por ponto (.) cercado de espaço em branco. Por exemplo, pássaros voam mas os peixes nadam . é uma frase , mas pássaros voam mas os peixes nadam. (sem espaço antes do ponto) não são. Para cada frase fornecida, o programa deve responder simplesmente "O.K" ou "NÃO O.K". Dica: não se incomode com tokens; apenas leia para um string usando >>. diff --git a/src/capitulo_06/exercicios/e06/c06e06.cpp b/src/capitulo_06/exercicios/e06/c06e06.cpp new file mode 100644 index 0000000..f90dc4f --- /dev/null +++ b/src/capitulo_06/exercicios/e06/c06e06.cpp @@ -0,0 +1,168 @@ +#include "std_lib_facilities.h" + +class String_stream +{ +public: + String_stream(); + string get(); + void putback(string str); +private: + bool full; + string buffer; +}; + +String_stream::String_stream() + :full(false), buffer("") +{ +} + +String_stream ss; + +void String_stream::putback(string str) +{ + if (full) error("putback() into a full buffer"); + buffer = str; + full = true; +} + +string String_stream::get() +{ + if (full) + { + full = false; + return buffer; + } + + // Dica: não se incomode com tokens; apenas leia para um string usando >>. + string str; + cin >> str; + + return str; +} + +// Escreva um programa que verifique se uma frase está correta de acordo com a gramática no §6.4.1. +bool article(); +bool subject(); +bool verb(); +bool conjunction(); +bool sentence(); +void isAPeriod(string); + +int main() +try +{ + bool result = false; + + while (cin) + { + vector results{ "Not O.K.", "O.K." }; + string str = ss.get(); + + if (str == "x") break; + if (str == ".") + // Suponha que cada frase é terminada por ponto (.) cercado de espaço em branco. + // Por exemplo, pássaros voam mas os peixes nadam . é uma frase , mas pássaros voam mas os peixes nadam. (sem espaço antes do ponto) não são. + // Para cada frase fornecida, o programa deve responder simplesmente "O.K" ou "NÃO O.K". + cout << "=" << results[result] << '\n'; + else + ss.putback(str); + result = sentence(); + } + 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; +} + +bool article() +{ + vector articles{ "the" }; + string str = ss.get(); + isAPeriod(str); + + auto pos = find(articles.begin(), articles.end(), str); + + if (pos < articles.end()) return true; + + return false; +} + +bool subject() +{ + vector subjects{ "birds", "fish", "C++" }; + string str = ss.get(); + isAPeriod(str); + + auto pos = find(subjects.begin(), subjects.end(), str); + + if (pos < subjects.end()) return true; + + return false; +} + +bool verb() +{ + vector verbs{ "predominates", "fly", "swim" }; + string str = ss.get(); + isAPeriod(str); + + auto pos = find(verbs.begin(), verbs.end(), str); + + if (pos < verbs.end()) return true; + + return false; +} + +bool conjunction() +{ + vector conjunctions{ "and", "or", "but" }; + string str = ss.get(); + isAPeriod(str); + + auto pos = find(conjunctions.begin(), conjunctions.end(), str); + + if (pos < conjunctions.end()) return true; + + return false; +} + +bool sentence() +{ + bool result = article() && subject() && verb(); + + if (result) + { + string str = ss.get(); + + if (str == "." || str == "x") + { + isAPeriod(str); + return result; + } + + ss.putback(str); + + if (::conjunction()) return sentence(); + + return false; + } + + return result; +} + +void isAPeriod(string str) +{ + if (str == "." || str == "x") + { + ss.putback(str); + } +} \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e07/CMakeLists.txt b/src/capitulo_06/exercicios/e07/CMakeLists.txt new file mode 100644 index 0000000..17e5da5 --- /dev/null +++ b/src/capitulo_06/exercicios/e07/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.12.0) + +set(thisProject c06e07) + +project(${thisProject}) + +add_executable(${thisProject}) + +target_include_directories(${thisProject} PRIVATE + ${lib_path}) + +target_sources(${thisProject} PRIVATE + ${thisProject}.cpp + ${lib_file}) \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e07/README.md b/src/capitulo_06/exercicios/e07/README.md new file mode 100644 index 0000000..257d311 --- /dev/null +++ b/src/capitulo_06/exercicios/e07/README.md @@ -0,0 +1,3 @@ +# Exercícios 7 + +Escreva uma gramática para expressões lógicas. Uma expressão lógica é bem parecida com uma expressão aritmética, exceto que os operadores são ! (negação), ~ (complemento), & (e), | (ou) e ^ (ou exclusivo). Os ! e ~ são operadores unários de prefixo. Um ^ se une a | (assim como * se une a +), de modo que x|y^z significa x|(y^z) em vez de (x|y)^z. O operador & tem precedência sobre ^, de modo que x^y&z significa x^(y&z). diff --git a/src/capitulo_06/exercicios/e07/c06e07.cpp b/src/capitulo_06/exercicios/e07/c06e07.cpp new file mode 100644 index 0000000..a9069f1 --- /dev/null +++ b/src/capitulo_06/exercicios/e07/c06e07.cpp @@ -0,0 +1,236 @@ +#include "std_lib_facilities.h" + +class Token +{ +public: + char kind; + double value; + Token(char ch) + :kind(ch), value(0) + { + } + Token(char ch, double val) + :kind(ch), value(val) + { + } +}; + +class Token_stream +{ +public: + Token_stream(); + Token get(); + void putback(Token t); +private: + bool full; + Token buffer; +}; + +Token_stream::Token_stream() + :full(false), buffer(0) +{ +} + +void Token_stream::putback(Token t) +{ + if (full) error("putback() into a full buffer"); + buffer = t; + full = true; +} + +Token Token_stream::get() +{ + if (full) + { + full = false; + return buffer; + } + + char ch; + cin >> ch; + + switch (ch) + { + case '=': + case 'x': + 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.putback(ch); + double val; + cin >> val; + return Token('8', val); + } + default: + error("Bad token"); + } +} + +Token_stream ts; + +// Escreva uma gramática para expressões lógicas. +// Uma expressão lógica é bem parecida com uma expressão aritmética, exceto que os operadores são ! (negação), ~ (complemento), & (e), | (ou) e ^ (ou exclusivo). +// Os ! e ~ são operadores unários de prefixo. +// Um ^ se une a | (assim como * se une a +), de modo que x|y^z significa x|(y^z) em vez de (x|y)^z. +// O operador & tem precedência sobre ^, de modo que x^y&z significa x^(y&z). + +double unary(char op, int n); +double expression(); + +double primary() +{ + Token t = ts.get(); + switch (t.kind) + { + case '(': + { + double d = expression(); + t = ts.get(); + if (t.kind != ')') error("')' expected"); + return d; + } + case '{': + { + double d = expression(); + t = ts.get(); + if (t.kind != '}') error("'}' expected"); + return d; + } + case '!': case '~': + { + char op = t.kind; + t = ts.get(); + double d = unary(op, t.value); + return d; + } + case '8': + return t.value; + default: + error("primary expected"); + } +} + +double unary(char op, int n) +{ + int result = 0; + + // '!' and '~' + switch (op) + { + case '!': + result = !n; + case '~': + result = ~n; + default: + break; + } + + return result; +} + +double expressionL2() +{ + // & + int x = 0; + double left = primary(); + Token t = ts.get(); + + while (true) + { + switch (t.kind) + { + case '&': + x = left; + left = x & int(primary()); + t = ts.get(); + break; + default: + ts.putback(t); + return left; + } + } +} + +double expressionL1() +{ + // ^ + int x = 0; + double left = expressionL2(); + Token t = ts.get(); + + while (true) + { + switch (t.kind) + { + case '^': + x = left; + left = x ^ int(expressionL2()); + t = ts.get(); + break; + default: + ts.putback(t); + return left; + } + } +} + +double expression() +{ + // | + int x = 0; + double left = expressionL1(); + Token t = ts.get(); + + while (true) + { + switch (t.kind) + { + case '|': + x = left; + left = x | int(expressionL1()); + t = ts.get(); + break; + default: + ts.putback(t); + return left; + } + } +} + +int main() +{ + try + { + double val = 0; + + while (cin) + { + Token t = ts.get(); + + if (t.kind == 'x') break; // 'x' 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; + } + + return 0; +} diff --git a/src/capitulo_06/exercicios/e08/CMakeLists.txt b/src/capitulo_06/exercicios/e08/CMakeLists.txt new file mode 100644 index 0000000..f4e6157 --- /dev/null +++ b/src/capitulo_06/exercicios/e08/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.12.0) + +set(thisProject c06e08) + +project(${thisProject}) + +add_executable(${thisProject}) + +target_include_directories(${thisProject} PRIVATE + ${lib_path}) + +target_sources(${thisProject} PRIVATE + ${thisProject}.cpp + ${lib_file}) \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e08/README.md b/src/capitulo_06/exercicios/e08/README.md new file mode 100644 index 0000000..cab14cc --- /dev/null +++ b/src/capitulo_06/exercicios/e08/README.md @@ -0,0 +1,3 @@ +# Exercícios 8 + +Refaça o jogo "Touros e vacas" do exercício 12 do Capítulo 5, para usar quatro letras em vez de quatro dígitos. diff --git a/src/capitulo_06/exercicios/e08/c06e08.cpp b/src/capitulo_06/exercicios/e08/c06e08.cpp new file mode 100644 index 0000000..5f6ca91 --- /dev/null +++ b/src/capitulo_06/exercicios/e08/c06e08.cpp @@ -0,0 +1,56 @@ +#include "std_lib_facilities.h" + +// Refaça o jogo "Touros e vacas" do exercício 12 do Capítulo 5, para usar quatro letras em vez de quatro dígitos. +int main() +{ + char c = ' '; + int bull = 0; + int cow = 0; + bool win = false; + vector letters; + vector guess; + + srand(time(0)); + while (letters.size() < 4) + { + char randomC = ' '; + // 'A' == 65; 'Z' == 90 + while (randomC < 65) + { + randomC = rand() % 90; + } + + auto posC = find(letters.begin(), letters.end(), randomC); + if (posC < letters.end()) continue; + letters.push_back(randomC); + } + + while (!win) + { + bull = 0; + cow = 0; + guess.clear(); + + cout << "Make your guess: " << endl; + for (int i = 0; i < letters.size(); i++) + { + cin >> c; + guess.push_back(c); + } + + for (int i = 0; i < letters.size(); i++) + { + auto pos = find(letters.begin(), letters.end(), guess[i]); + + if (guess[i] == letters[i]) bull++; + else if (pos < letters.end()) cow++; + } + cout << bull << " bull and " << cow << " cow." << endl; + + if (bull == 4) win = true; + } + + cout << "WINNER!" << endl; + + return 0; +} \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e09/CMakeLists.txt b/src/capitulo_06/exercicios/e09/CMakeLists.txt new file mode 100644 index 0000000..ca46e5e --- /dev/null +++ b/src/capitulo_06/exercicios/e09/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.12.0) + +set(thisProject c06e09) + +project(${thisProject}) + +add_executable(${thisProject}) + +target_include_directories(${thisProject} PRIVATE + ${lib_path}) + +target_sources(${thisProject} PRIVATE + ${thisProject}.cpp + ${lib_file}) \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e09/README.md b/src/capitulo_06/exercicios/e09/README.md new file mode 100644 index 0000000..8bbf424 --- /dev/null +++ b/src/capitulo_06/exercicios/e09/README.md @@ -0,0 +1,3 @@ +# Exercícios 9 + +Escreva um programa que leia dígitos e componha números inteiros. Por exemplo, 123 é lido como os caracteres 1, 2 e 3. O programa deve ter fornecido como saída "123 é 1 cento e 2 dezenas e 3 unidades". O número deve ser escrito como um valor int. Trate com números de um, dois, três e quatro dígitos. Dica: para obter o valor inteiro 5 a partir do caracter '5' subtraia '0', isto é, '5'-'0'==5. diff --git a/src/capitulo_06/exercicios/e09/c06e09.cpp b/src/capitulo_06/exercicios/e09/c06e09.cpp new file mode 100644 index 0000000..44f2387 --- /dev/null +++ b/src/capitulo_06/exercicios/e09/c06e09.cpp @@ -0,0 +1,89 @@ +#include "std_lib_facilities.h" + +void decomposesNumber(string); +string returnsUnitsSentence(string); +string returnTensSentence(string); +string returnHundredsSentence(string); +string returnThousandsSentence(string); +int getInt(string, int); + +// Escreva um programa que leia dígitos e componha números inteiros. +// Por exemplo, 123 é lido como os caracteres 1, 2 e 3. +int main() +{ + string n = ""; + + cout << "Type a number: \n"; + cin >> n; + + decomposesNumber(n); + + return 0; +} + +// O programa deve ter fornecido como saída "123 é 1 cento e 2 dezenas e 3 unidades". +// O número deve ser escrito como um valor int. +void decomposesNumber(string n) + { + switch (n.size()) + { + case 1: + cout << n << " is " << returnsUnitsSentence(n) << "."; + break; + case 2: + cout << n << " is " << returnTensSentence(n) << " and " << returnsUnitsSentence(n) << "."; + break; + case 3: + cout << n << " is " << returnHundredsSentence(n) << " and " << returnTensSentence(n) << " and " << returnsUnitsSentence(n) << "."; + break; + case 4: + cout << n << " is " << returnThousandsSentence(n) << " and " << returnHundredsSentence(n) << " and " << returnTensSentence(n) << " and " << returnsUnitsSentence(n) << "."; + break; + default: + cout << "Cannot decompose the number " << n; + break; + } +} + +// Trate com números de um, dois, três e quatro dígitos. +string returnsUnitsSentence(string fullNumber) +{ + int nAsInt = getInt(fullNumber, fullNumber.size() - 1); + string nAsStr = to_string(nAsInt); + + if (nAsInt > 1) return nAsStr + " units"; + return nAsStr + " unit"; +} + +string returnTensSentence(string fullNumber) +{ + int nAsInt = getInt(fullNumber, fullNumber.size() - 2); + string nAsStr = to_string(nAsInt); + + if (nAsInt > 1) return nAsStr + " tens"; + return nAsStr + " ten"; +} + +string returnHundredsSentence(string fullNumber) +{ + int nAsInt = getInt(fullNumber, fullNumber.size() - 3); + string nAsStr = to_string(nAsInt); + + if (nAsInt > 1) return nAsStr + " hundreds"; + return nAsStr + " hundred"; +} + +string returnThousandsSentence(string fullNumber) +{ + int nAsInt = getInt(fullNumber, fullNumber.size() - 4); + string nAsStr = to_string(nAsInt); + + if (nAsInt > 1) return nAsStr + " thousands"; + return nAsStr + " thousand"; +} + +// Dica: para obter o valor inteiro 5 a partir do caracter '5' subtraia '0', isto é, '5'-'0'==5. +int getInt(string fullN, int pos) +{ + return fullN[pos] - '0'; +} \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e10/CMakeLists.txt b/src/capitulo_06/exercicios/e10/CMakeLists.txt new file mode 100644 index 0000000..d1bbad9 --- /dev/null +++ b/src/capitulo_06/exercicios/e10/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.12.0) + +set(thisProject c06e10) + +project(${thisProject}) + +add_executable(${thisProject}) + +target_include_directories(${thisProject} PRIVATE + ${lib_path}) + +target_sources(${thisProject} PRIVATE + ${thisProject}.cpp + ${lib_file}) \ No newline at end of file diff --git a/src/capitulo_06/exercicios/e10/README.md b/src/capitulo_06/exercicios/e10/README.md new file mode 100644 index 0000000..2f0c2c3 --- /dev/null +++ b/src/capitulo_06/exercicios/e10/README.md @@ -0,0 +1,21 @@ +# Exercícios 10 + +Uma permutação é um subconjunto ordenado de um conjunto. Por exemplo, digamos que você quer selecionar uma combinação para um cofre. Existem 60 números possíveis, e você necessita de três números diferentes para a combinação. Existem *P(60,3)* permutações para a combinação, onde *P* é definido pela fórmula + +```cpp +P(a,b) = a! + _______ + (a-b)!' +``` + +onde ! é usado como operador de sufixo para fatorial. Por exemplo, 4! é 4\*3\*2\*1. Combinações são similares a permutações, exceto que a ordem dos objetos não importa. Por exemplo, se você estiver fazendo uma *banana split* e quiser colocar três sabores diferentes de sorvete, dentre os cinco que estão disponíveis, você não se importaria de colocar uma colher de sorvete de baunilha no início ou no fim; você ainda estaria pondo sabor baunilha. A fórmula para combinações é: + +```cpp +C(a,b) = P(a,b) + _________ + b! +``` + +Projete um programa que peça ao usuário dois números, pergunte se ele quer calcular permutações ou combinações e imprima o resultado. Ele terá várias partes. Faça uma análise dos requisitos anteriores. + +Escreva exatamente o que o programa terá que fazer. Depois, vá para a fase do projeto. Escreva pseudocógico para o programa e o divida em subcomponentes. Esse programa deve ter verificação de erros. Assegure-se de que todos os dados de entrada incorretos irão gerar boas mensagens de erro. diff --git a/src/capitulo_06/exercicios/e10/c06e10.cpp b/src/capitulo_06/exercicios/e10/c06e10.cpp new file mode 100644 index 0000000..d531324 --- /dev/null +++ b/src/capitulo_06/exercicios/e10/c06e10.cpp @@ -0,0 +1,102 @@ +#include "std_lib_facilities.h" + +int permutation(int, int); +int combination(int, int); +int factorial(int); + +int main() +{ + // Esse programa deve ter verificação de erros. + // Assegure-se de que todos os dados de entrada incorretos irão gerar boas mensagens de erro. + try + { + int n1 = 0, n2 = 0, result = 0; + char opt = ' '; + + cout << "Type two numbers:\n"; + + //Projete um programa que peça ao usuário dois números, + cin >> n1 >> n2; + + if(!cin) error("Invalid input."); + if (n1 == 0 || n2 == 0) error("Numbers cannot be zero."); + + // pergunte se ele quer calcular permutações ou combinações + cout << "Choose an option, 'p' for Permutation or 'c' for Combination:\n"; + cin >> opt; + + switch (opt) + { + case 'p': + result = permutation(n1, n2); + // e imprima o resultado. + cout << "There are " << result << " permutations.\n"; + break; + case 'c': + result = combination(n1, n2); + cout << "There are " << result << " combinations.\n"; + break; + default: + error("Invalid option, aborting..."); + } + + return 0; + } + catch (exception& e) + { + cerr << "error: " << e.what() << '\n'; + keep_window_open(); + return 1; + } + catch (...) + { + cerr << "Oops: unknown exception!\n"; + keep_window_open(); + return 2; + } +} + +int permutation(int a, int b) +{ + //Uma permutação é um subconjunto ordenado de um conjunto. + // Por exemplo, digamos que você quer selecionar uma combinação para um cofre. + // Existem 60 números possíveis, e você necessita de três números diferentes para a combinação. + // Existem *P(60,3)* permutações para a combinação, onde *P* é definido pela fórmula + // + //```cpp + //P(a,b) = a! + // _______ + // (a-b)!' + //``` + // + //onde ! é usado como operador de sufixo para fatorial. + // Por exemplo, 4! é 4\*3\*2\*1. + int p = factorial(a) / factorial((a - b)); + + return p; +} + +int combination(int a, int b) +{ + // Combinações são similares a permutações, exceto que a ordem dos objetos não importa. + // Por exemplo, se você estiver fazendo uma *banana split* e quiser colocar três sabores diferentes de sorvete, + // dentre os cinco que estão disponíveis, você não se importaria de colocar uma colher de sorvete de baunilha no início ou no fim; + // você ainda estaria pondo sabor baunilha. + // A fórmula para combinações é: + // + //```cpp + //C(a,b) = P(a,b) + // _________ + // b! + //``` + int c = permutation(a, b) / factorial(b); + + return c; +} + +int factorial(int n) +{ + if (n == 1 || n == 0) return 1; + + return n * factorial(n - 1); +}