Jump to content

SUBIECTE NOI
« 1 / 5 »
RSS
ajutor

Whisky for Mac

Xiaomi 14 Gpay

Izolare zid exterior de scandura
 Dezinstalare drivere W11 23H3

Recomandare masina de spalat fiab...

BSOD din cauza Intel Audio DSP dr...

De ce sunt oamenii nostalgici
 Cum vand casa fara factura Hidroe...

Scor FICO minim

Tonometru compensat CAS?

polita RCA ONLINE
 Termostat frigider - verificare

Mai au PC-urile vreun viitor?

Centrala termica immergas

Amenda in Lipsa ?
 

[C++] Proiect - Calculator

- - - - -
  • Please log in to reply
12 replies to this topic

#1
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016
Salut!

Acesta este un proiect pe care cred ca l-am cam terminat. Mai exact, este un calculator care se descurca cu adunari, scaderi, inmultiri, impartiri, impartiri cu rest, ridicare la putere, extragerea radicalului (de ordin 2), crearea si editarea, de catre utilizator, a unor variabile si crearea, de catre utilizator, a unor constante.

Zic ca este "cam" terminat, deoarece nu imi mai vin idei noi. Totusi, doresc sa imbunatatesc codul existent, deoarece sunt 100% sigur ca exista loc de mai bine, mai ales pentru ca sunt incepator. Asadar, va rog sa veniti cu sfaturi si recomandari!

Codul este destul de lung, sper ca nu este o problema ca l-am postat direct aici si nu l-am urcat pe undeva sau n-am folosit Github.

Multumesc!

Stiu ca un prim sfat ar fi modificarea numelor acelor functii (expression(), term(), primary(), statement() etc.), deoarece nu spun in mod direct ceea ce fac, comentariul fiind necesar. Nu prea stiu cum sa schimb acei identificatori, deoarece acest proiect a fost creat cu sprijinul cartii "Programming: Principles and Practice using C++", unde schema si ideile sunt expuse cu aceste denumiri.

/*
# CALCULATOR PROGRAM
#
# This calculator program handles addition (+), substraction (-), multiplication (*), division (/), modulo (%), exponentiation (pow(base, exponent)),
# square root (sqrt(expression)), creating user-defined variables or constants and editing those user-defined variables.
#
# Type "help" for help regarding other commands.
#
#
# The general grammar of the program:
#
# Expression:
# Term
# Expression + Term
# Expression - Term
#
# Term:
# Primary
# Term() * Primary
# term() / Primary
# Term % Primary
#
# Primary:
# Number
# ( Expression )
# sqrt(Expression)
# pow(base, exponent)
# - Primary -> negative number
# name -> of either a variable or a constant
# }
*/

#include "pch.h"
#include "D:\Programming\Additionals\std_lib_facilities.h"

const char let = 'L';
const char quit = 'Q';
const char print = ';';
const char number = '8';
const char name = 'a';
const char squareroot = 's';
const char power = 'p';
const char con = 'C';
const char help = 'h';
const string helpkey = "help";
const string declkey = "#";
const string quitkey = "exit";
const string constkey = "const";
class Token {
public:
char kind;
double value;
string name;
Token(char ch)
	 : kind{ ch }
	 , value{ 0 }
{
}
Token(char ch, double val)
	 : kind{ ch }
	 , value{ val }
{
}
Token(char ch, string str)
	 : kind{ ch }
	 , name{ str }
{
}
};
class Token_stream {
public:
Token_stream()
	 : full{ 0 }
	 , buffer{ 0 }
{
}
Token get();
void unget(Token t)
{
	 buffer = t;
	 full = true;
} // puts a Token back
void ignore(char c); // discards Tokens up to and including c
private:
bool full;
Token buffer;
};
Token Token_stream::get() // reads characters from cin and composes Tokens
{
if (full) {
	 full = false;
	 return buffer;
}
char ch;
cin.get(ch);
if (isspace(ch))
	 if (ch == '\n')
		 return Token(print);
cin.unget();
cin >> ch;
switch (ch) {
case '(':
case ')':
case '+':
case '-':
case '*':
case '/':
case '%':
case '=':
case ',':
case print:
	 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 == '#') {
		 string s;
		 s += ch;
		 while (cin.get(ch) && (isalpha(ch) || isdigit(ch) || ch == '_'))
			 s += ch;
		 cin.unget();
		 if (s == helpkey)
			 return Token(help);
		 if (s == declkey)
			 return Token(let);
		 if (s == quitkey)
			 return Token(quit);
		 if (s == "sqrt")
			 return Token(squareroot);
		 if (s == "pow")
			 return Token(power);
		 if (s == constkey)
			 return Token(con);
		 return Token(name, s);
	 }
	 error("Bad token");
}
}
void Token_stream::ignore(char c)
{
if (full && c == buffer.kind) {
	 full = false;
	 return;
}
full = false;
char ch;
while (cin >> ch)
	 if (ch == c)
		 return;
}
class Symbol_table {
public:
string name;
double value;
bool var;
Symbol_table(string n, double v, bool va)
	 : name(n)
	 , value(v)
	 , var(va)
{
}
};
vector<Symbol_table> names;
double get_value(string s)
{
for (unsigned i = 0; i < names.size(); ++i)
	 if (names[i].name == s)
		 return names[i].value;
error("get: undefined name ", s);
}
void set_value(string s, double d)
{
for (unsigned i = 0; i <= names.size(); ++i)
	 if (names[i].name == s) {
		 names[i].value = d;
		 return;
	 }
error("set: undefined name ", s);
}
bool is_declared(string s)
{
for (unsigned i = 0; i < names.size(); ++i)
	 if (names[i].name == s)
		 return true;
return false;
}
Token_stream ts;
double expression(); // analyzes input such as addition layout and substraction layout
double primary() // analyzes input such as positive or negative numbers, expressions between parantheses, square root layout, exponentiation layout, names of variables / constants
{
Token t = ts.get();
switch (t.kind) {
case '(': {
	 double d = expression();
	 t = ts.get();
	 if (t.kind != ')')
		 error("')' expected");
	 break;
}
case squareroot: // layout: 's' + '(' + expression + ')'
{
	 t = ts.get();
	 if (t.kind != '(')
		 error("'(' expected");
	 double d = expression();
	 if (d < 0)
		 error("sqrt: the number must be positive");
	 t = ts.get();
	 if (t.kind != ')')
		 error("')' expected");
	 return sqrt(d);
}
case power: // layout: 'p' + '(' + base + ',' + exponent + ')'
{
	 t = ts.get();
	 if (t.kind != '(')
		 error("'(' expected");
	 double base = expression();
	 t = ts.get();
	 if (t.kind != ',')
		 error("',' expected");
	 int exponent = narrow_cast<int>(expression());
	 t = ts.get();
	 if (t.kind != ')')
		 error("')' expected");
	 return pow(base, exponent);
}
case '-':
	 return -primary();
case number:
	 return t.value;
case name: {
	 Token t_next = ts.get();
	 if (t_next.kind == '=') // handles name = expression
	 {
		 for (Symbol_table& x : names)
			 if (x.name == t.name)
				 if (x.var) {
					 double new_value = expression();
					 set_value(t.name, new_value);
					 return new_value;
				 }
				 else
					 error("can't change the value of a const");
	 }
	 ts.unget(t_next);
	 return get_value(t.name);
}
default:
	 error("primary expected");
}
}
double term() // analyzes input such as multiplication layout, division layout, modulo layout
{
double left = primary();
while (true) {
	 Token t = ts.get();
	 switch (t.kind) {
	 case '*':
		 left *= primary();
		 break;
	 case '/': {
		 double d = primary();
		 if (d == 0)
			 error("divide by zero");
		 left /= d;
		 break;
	 }
	 case '%': {
		 int i1 = narrow_cast<int>(left);
		 int i2 = narrow_cast<int>(primary());
		 if (i2 == 0)
			 error("%: divide by zero");
		 left = i1 % i2;
		 break;
	 }
	 default:
		 ts.unget(t);
		 return left;
	 }
}
}
double expression() // analyzes input such as addition layout and substraction layout
{
double left = term();
while (true) {
	 Token t = ts.get();
	 switch (t.kind) {
	 case '+':
		 left += term();
		 break;
	 case '-':
		 left -= term();
		 break;
	 default:
		 ts.unget(t);
		 return left;
	 }
}
}
double declaration()
{
Token t = ts.get();
if (t.kind != name)
	 error("name expected in declaration");
string new_name = t.name;
if (is_declared(new_name))
	 error(new_name, " declared twice");
Token t2 = ts.get();
if (t2.kind != '=')
	 error("= missing in declaration of ", new_name);
double d = expression(); // calls expression() for parsing the value of the new variable
names.push_back(Symbol_table(new_name, d, true));
return d;
}
double const_declaration()
{
Token t = ts.get();
if (t.kind != name)
	 error("name expected in declaration");
string new_name = t.name;
if (is_declared(new_name))
	 error(new_name, " declared twice");
Token t2 = ts.get();
if (t2.kind != '=')
	 error("= missing in declaration of ", new_name);
double d = expression(); // calls expression() for parsing the value of the new constant
names.push_back(Symbol_table(new_name, d, false));
return d;
}
void predefine_name(string name, double value, bool var)
{
if (is_declared(name))
	 error(name, " declared twice");
names.push_back(Symbol_table(name, value, var));
}
double statement() // analyzes input such as variable / constant declaration keyword ('#' or "const") - resulting in calling appropriate functions
{
Token t = ts.get();
switch (t.kind) {
case let:
	 return declaration();
case con:
	 return const_declaration();
default:
	 ts.unget(t);
	 return expression();
}
}
void clean_up_mess()
{
ts.ignore(print); // discards Tokens up to and including the print character
}
void display_info()
{
cout << " This calculator program handles addition (+), substraction (-), multiplication (*), division (/), modulo (%), " << endl
		 << " exponentiation (pow(base, exponent)), square root(sqrt(expression)), creating user - defined variables or" << endl
		 << " constants and editing those user - defined variables." << endl
		 << endl
		 << " Other commands:" << endl
		 << "\t 'exit' for exiting the program" << endl
		 << "\t '#' keyword for user-defined variable declaration" << endl
		 << "\t 'const' keyword for user-defined constant declaration" << endl;
}
const string prompt = "> ";
const string result = "= ";
void calculate()
{
while (true)
	 try {
		 cout << prompt;
		 Token t = ts.get();
		 while (t.kind == print)
			 t = ts.get();
		 if (t.kind == quit)
			 return;
		 if (t.kind == help)
			 display_info();
		 else {
			 ts.unget(t);
			 cout << result << statement() << endl;
		 }
	 }
	 catch (runtime_error& e) {
		 cerr << e.what() << endl;
		 clean_up_mess();
	 }
}
int main()
try {
predefine_name("pi", 3.14159265, false);
predefine_name("e", 2.71828182, false);
display_info();
calculate();
return 0;
}
catch (exception& e) {
cerr << "exception: " << e.what() << endl;
char c;
while (cin >> c && c != ';')
	 ;
return 1;
}
catch (...) {
cerr << "exception\n";
char c;
while (cin >> c && c != ';')
	 ;
return 2;
}



#2
pexCom

pexCom

    Senior Member

  • Grup: Senior Members
  • Posts: 2,242
  • Înscris: 15.01.2014
Foarte bine că ai făcut chestii avansate în liceu, probabil că și la orele de limba română programai din pasiune.

Inițiatorul cere păreri/sfaturi, nu se laudă. E cam singurul din începătorii de pe aria asta care chiar pare că se chinuie, așa că hai să nu-l descurajăm din start.

@AnduIX: ca să contribui cât de cât, îți recomand pentru început să pui denumiri mai descriptive la variablie/funcții (așa cum ai zis și tu) - substantive pentru variablie, verbe sau expresii ce conțin verbe pentru funcții.
Și aș pune codul în 2-3 fișiere separate, fiecare cu funcționalitatea lui.

#3
OriginalCopy

OriginalCopy

    I'm harmful, fear me please! :))

  • Grup: Senior Members
  • Posts: 27,268
  • Înscris: 10.08.2006
posteaza codul formatat pe gist.github.com nu aici, ca forumul macelareste codul nu alta.

#4
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016

View PostCrocodiluMereuVesel, on 20 septembrie 2018 - 18:43, said:

eu cand eram in liceu am facut un calculator bazat pe analizor sintactic de polinoame si scriei ecuatia polinomului si furnia toate radacinile (real si /sau complexe) ale acestuia si nu m-am laudat nimanui si era si un sfert din codul pe care l-ai scris tu.
Pa, pa.

Felicitari! Eu nu am dorit nicidecum sa ma laud. Am facut acest subiect numai pentru a cere sfaturi, caci stiu ca am multe greseli. Prin acel "lung" folosit de mine, am vrut sa zic ca eu cred ca tot codul programului meu este cam mare pentru a il posta direct pe forum. Stiu ca nu este un cod lung. Nu se pune problema. Posted Image


View PostpexCom, on 20 septembrie 2018 - 19:00, said:

Foarte bine că ai făcut chestii avansate în liceu, probabil că și la orele de limba română programai din pasiune.

Inițiatorul cere păreri/sfaturi, nu se laudă. E cam singurul din începătorii de pe aria asta care chiar pare că se chinuie, așa că hai să nu-l descurajăm din start.

@AnduIX: ca să contribui cât de cât, îți recomand pentru început să pui denumiri mai descriptive la variablie/funcții (așa cum ai zis și tu) - substantive pentru variablie, verbe sau expresii ce conțin verbe pentru funcții.
Și aș pune codul în 2-3 fișiere separate, fiecare cu funcționalitatea lui.

Multumesc frumos pentru sfaturi! Voi tine cont de ele si ma voi stradui sa modific denumirile astfel incat sa fie mai ok. Am incercat sa ma pun in pielea voastra, spre exemplu, deoarece voi vedeti cod despre care nu stiti prea multe. Asadar, eu trebuie sa va arat cod care sa spuna cat mai mult si sa nu ma folosesc cu una, cu doua de comentarii.

View PostOriginalCopy, on 20 septembrie 2018 - 19:29, said:

posteaza codul formatat pe gist.github.com nu aici, ca forumul macelareste codul nu alta.

S-a facut! Posted Image

https://gist.github....69e89de970a1cb5

#5
Buleandra94

Buleandra94

    Member

  • Grup: Members
  • Posts: 644
  • Înscris: 19.08.2007
Fiind incepator, nu prea avem ce feedback sa iti dam, acest "proiect" este doar un exercitiu. In mare, daca merge cum trebuie e ok. Ca feedback general, calitatea codului este foarte proasta, insa e de inteles pentru un incepator. Ar trebui sa ai codul separat in mai multe fisiere, sa nu ai switch-uri asa complexe, sa folosesti clase si programarea orientata pe obiect (pentru ca C++ exceleaza la asta), sa incerci sa faci functii cat mai mici si specializate in loc sa faci o functie gigantica de zeci sau sute de linii, sa folosesti enumerari (enum) in loc de variabile de tip char/string cat mai mult posibil.

Nu iti recomand sa continui sa lucrezi la acest proiect, incepe altul pe o alta idee si invata din greselile din proiectul acesta. Cu cate lucrezi la mai multe proiecte diferite o sa te lovesti de probleme diferite si o sa incepi usor-usor sa inveti cum trebuie organizat codul astfel incat sa fie usor de citit, modificat si depanat.

Edited by Buleandra94, 20 September 2018 - 20:11.


#6
OriginalCopy

OriginalCopy

    I'm harmful, fear me please! :))

  • Grup: Senior Members
  • Posts: 27,268
  • Înscris: 10.08.2006
Variabila globala https://gist.github....ulator-cpp-L176 nu e ok.

#7
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016

View PostBuleandra94, on 20 septembrie 2018 - 20:10, said:

Fiind incepator, nu prea avem ce feedback sa iti dam, acest "proiect" este doar un exercitiu. In mare, daca merge cum trebuie e ok. Ca feedback general, calitatea codului este foarte proasta, insa e de inteles pentru un incepator. Ar trebui sa ai codul separat in mai multe fisiere, sa nu ai switch-uri asa complexe, sa folosesti clase si programarea orientata pe obiect (pentru ca C++ exceleaza la asta), sa incerci sa faci functii cat mai mici si specializate in loc sa faci o functie gigantica de zeci sau sute de linii, sa folosesti enumerari (enum) in loc de variabile de tip char/string cat mai mult posibil.

Nu iti recomand sa continui sa lucrezi la acest proiect, incepe altul pe o alta idee si invata din greselile din proiectul acesta. Cu cate lucrezi la mai multe proiecte diferite o sa te lovesti de probleme diferite si o sa incepi usor-usor sa inveti cum trebuie organizat codul astfel incat sa fie usor de citit, modificat si depanat.

Multumesc frumos pentru sfaturi! Sunt complet de acord si ma asteptam la acest feedback! :D Inca nu am ajuns la capitolul in care mi se explica cum sa impart codul in mai multe fisiere sau la capitolul care imi explica enum, insa asta nu inseamna ca nu trebuie sa caut pe Google, sa vad cum functioneaza. :)


View PostOriginalCopy, on 20 septembrie 2018 - 20:21, said:

Variabila globala https://gist.github....ulator-cpp-L176 nu e ok.

Nu este ok in sensul ca este globala, ca nu este pozitionata prea bine in cod sau ca identificatorul este prost ales? Sau toate la un loc? :)

#8
OriginalCopy

OriginalCopy

    I'm harmful, fear me please! :))

  • Grup: Senior Members
  • Posts: 27,268
  • Înscris: 10.08.2006

View PostAnduIX, on 20 septembrie 2018 - 20:33, said:

Nu este ok in sensul ca este globala, ca nu este pozitionata prea bine in cod sau ca identificatorul este prost ales? Sau toate la un loc? Posted Image
Toate, dar faptul ca e globala eclipseaza orice.

Niciodata nu folosi variabile globale. Cazurile alea valide in care global e ok sunt prea greu de decis pentru tine, deci nu te atinge de global.

Muta variabila in main, si paseaz-o ca parametru pe unde e nevoie.

#9
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016

View PostOriginalCopy, on 20 septembrie 2018 - 20:40, said:


Toate, dar faptul ca e globala eclipseaza orice.

Niciodata nu folosi variabile globale. Cazurile alea valide in care global e ok sunt prea greu de decis pentru tine, deci nu te atinge de global.

Muta variabila in main, si paseaz-o ca parametru pe unde e nevoie.

Am înțeles. Mulțumesc!

Ar trebui sa fac așa și pentru vectorul names, care stochează variabilele și constantele definite de utilizator? Dar pentru toate constantele de la începutul fișierului?

#10
OriginalCopy

OriginalCopy

    I'm harmful, fear me please! :))

  • Grup: Senior Members
  • Posts: 27,268
  • Înscris: 10.08.2006

View PostAnduIX, on 20 septembrie 2018 - 21:24, said:

Ar trebui sa fac așa și pentru vectorul names, care stochează variabilele și constantele definite de utilizator?
Da.

View PostAnduIX, on 20 septembrie 2018 - 21:24, said:

Dar pentru toate constantele de la începutul fișierului?
Nu.


Problema cea mai mare e strict cu variabile globale, pentru ca orice functie le poate schimba, si asa introduci buguri in cod.

#11
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016

View PostOriginalCopy, on 20 septembrie 2018 - 21:28, said:

Problema cea mai mare e strict cu variabile globale, pentru ca orice functie le poate schimba, si asa introduci buguri in cod.

Înțeleg. Mulțumesc!

#12
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,232
  • Înscris: 24.02.2007
D:\Programming\Additionals\std_lib_facilities.h - nu avem asa ceva

#13
AnduIX

AnduIX

    Junior Member

  • Grup: Members
  • Posts: 159
  • Înscris: 07.08.2016

View Postdani.user, on 21 septembrie 2018 - 09:10, said:

D:\Programming\Additionals\std_lib_facilities.h - nu avem asa ceva
http://www.stroustru...ib_facilities.h
Este un header cu diferite functii si alte headere incluse. Conform celor spuse in carte si la inceputul acestui header, nu voi "avea nevoie" de el pentru mult timp. De fapt, versiunea care se poate gasi pe site-ul domnului Stroustrup (link mai sus), nu este de actualitate. L-am contactat pe domnul Stroustrup si am reusit sa fac rost de toate fisierele folosite de-a lungul cartii, actualizate.

Deci ar trebui sa inteleg ca mai bine nu l-as folosi? Pana sa primesc varianta actualizata, luam diferitele functii de care aveam nevoie si le puneam in codul meu sursa, cea mai folosita functie fiind cea error() care nu face nimic mai special decat throw runtime_error(string s).

Anunturi

Bun venit pe Forumul Softpedia!

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

Forumul Softpedia foloseste "cookies" pentru a imbunatati experienta utilizatorilor Accept
Pentru detalii si optiuni legate de cookies si datele personale, consultati Politica de utilizare cookies si Politica de confidentialitate