/* Modular design, functions that are as small as they can reasonably be, each with just one well defined task to perform. With virtually no effort, we could extend the caculator to cover all sorts of complexities, like CuSO4.5H2O Copper sulphate pentahydrate Ba(NO3)2 Barium nitrate C6H2(NO2)3CH3 TNT even brackets inside the brackets */ #include #include #include const bool debug = false; using namespace std; struct element { int atno; string symbol; string name; double atwt; }; struct ouristream { string formula; int pos; }; void initialise(ouristream & i) { while (true) { getline(cin, i.formula); if (i.formula != "") break; } if (debug) cout << "input is '" << i.formula << "'\n"; i.formula += "\n"; i.pos = 0; } char readchar(ouristream & i) { char result = i.formula[i.pos]; if (debug) { if (result == '\n') cout << " readchar at end of line\n"; else cout << " readchar read '" << result << "'\n"; } if (result != '\n') i.pos += 1; return result; } char lookahead(ouristream i) { char result = i.formula[i.pos]; if (debug) { if (result == '\n') cout << " lookahead at end of line\n"; else cout << " lookahead read '" << result << "'\n"; } return result; } bool islittle(char c) { if (c>='a' && c<='z') return true; return false; } bool iscapital(char c) { if (c>='A' && c<='Z') return true; return false; } bool isdigit(char c) { if (c>='0' && c<='9') return true; return false; } string readsymbol(ouristream & i) { // function only called when we know a capital letter is coming string sym = ""; sym += readchar(i); while (islittle(lookahead(i))) sym += readchar(i); if (debug) cout << "readsymbol got '" << sym << "'\n"; return sym; } int char_to_digit(char c) { return c - '0'; } int readnumber(ouristream & i) { // only used when digit definitely next int value = 0; while (isdigit(lookahead(i))) value = value * 10 + char_to_digit(readchar(i)); if (debug) cout << "readnumber got " << value << "\n"; return value; } struct periodic_table { element table[110]; int num, capacity; }; void read_file(periodic_table & pt) // returns actual number read. { pt.capacity = 110; ifstream f("/home/www/class/een118/atwt.txt"); if (f.fail()) { cout << "Failed to open atwt.txt file\n"; exit(1); } int i = 1; while (i < pt.capacity) { string sym, name; double wt; f >> sym >> name >> wt; if (f.fail()) break; pt.table[i].atno = i; pt.table[i].symbol = sym; pt.table[i].name = name; pt.table[i].atwt = wt; i += 1; } if (! f.fail()) cout << "Warning!!!! too many elements\n"; f.close(); pt.num = i - 1; } int lookup(string sym, periodic_table PT) // returns position in array // or -1 for "not found" { for (int i=1; i<=PT.num; i+=1) { if (PT.table[i].symbol == sym) return i; } cout << sym << " not found\n"; return -1; } double process_simple_formula(periodic_table PT, ouristream & in); void process_formula(periodic_table PT) { ouristream in; cout << "formula: "; initialise(in); double total = 0.0; while (true) { double wt = process_simple_formula(PT, in); total += wt; char c = readchar(in); if (c == '\n') break; if (c == '.') continue; cout << "Error symbol '" << c << "'\n"; } cout << "Total molecular weight = " << total << "\n\n"; } double process_simple_formula(periodic_table PT, ouristream & in) { double total = 0.0; double prev; char c = lookahead(in); int multiplier = 1; if (isdigit(c)) multiplier = readnumber(in); while (true) { char c = lookahead(in); if (iscapital(c)) { string symbol = readsymbol(in); double wt = 0.0; int atno = lookup(symbol, PT); if (atno == -1) cout << "Error '" << symbol << "' not known\n"; else { double wt = PT.table[atno].atwt; string nm = PT.table[atno].name; cout << " " << symbol << ", " << nm << ", atomic weight " << wt << "\n"; total += wt; prev = wt; } } else if (isdigit(c)) { int num = readnumber(in); cout << " x " << num << "\n"; total += prev * (num-1); } else if (c == '(') { c = readchar(in); // eliminate the ( double partwt = process_simple_formula(PT, in); total += partwt; prev = partwt; c = readchar(in); if (c != ')') cout << "error in brackets\n"; } else if (c == ' ') { } else { if (multiplier != 1) cout << " x " << multiplier << "\n"; cout << " subtotal = " << total * multiplier << "\n"; return total * multiplier; } } } int main() { periodic_table PT; read_file(PT); cout << "read " << PT.num << " elements\n"; while (true) process_formula(PT); }