Υποστηρίζει όμως 15 πράξεις και λειτουργεί με τη λογική των κανονικών calculators, ότι δηλαδή παίρνει μόνο έναν τελεστή κι ένα αριθμό στη κάθε γραμμή, και εφαρμόζει τη πράξη στο αποτέλεσμα της προηγούμενης. Μερικοί τελεστές (όπως π.χ της τετραγωνικής ρίζας) είναι μοναδιαίοι (unary) οπότε εφαρμόζονται απευθείας στο προηγούμενο αποτέλεσμα αγνοώντας πλήρως τυχόν νούμερα που υπάρχουν μετά από τον τελεστή, στη γραμμή.
Το prompt δείχνει ανά πάσα στιγμή το αποτέλεσμα της αμέσως προηγούμενης πράξης. Οπότε αν είναι π.χ.
- Κώδικας: Επιλογή όλων
10.6:
και του πληκτρολογήσετε +10...
- Κώδικας: Επιλογή όλων
10.6: +10
το αποτέλεσμα θα βγει στο επόμενο prompt και θα περιμένει την επόμενη πράξη:
- Κώδικας: Επιλογή όλων
10.6: +10
20.6:
Μπορείτε επίσης να δώσετε x για να τερματίσετε το πρόγραμμα, c για να καθαρίσετε το τρέχον αποτέλεσμα και h για να δείτε τη βοηθητική οθόνη με λίστα όλων των υποστηριζόμενων πράξεων και τους τελεστές τους.
Όλο το "παιχνίδι" γίνεται από έναν πίνακα pf που αποτελείται από δείκτες που δείχνουν στις συναρτήσεις των πράξεων...
- Κώδικας: Επιλογή όλων
double (*pf[MAX_OPERATORS])(const double, const double) = {
&add, &sub, &mul, &over, &modulus, &pwr, &expo, &sqroot, &cbroot,
&neg, &fact, &loge, &logten, &truncate, &frac
};
Οι θέσεις αυτού του πίνακα αντιστοιχούν πλήρως με τον πρόσθετο τύπο απαρίθμησης OpCode:
- Κώδικας: Επιλογή όλων
typedef enum { // operator codes
ADD, SUB, MUL, DIV, MOD, POW, EXPO, SQRT, CBRT, NEG,
FACT, LOGE, LOGTEN, TRUNC, FRAC
} OpCode;
Οπότε για παράδειγμα, μια γραμμή σαν αυτήν...
- Κώδικας: Επιλογή όλων
res = (*pf[MUL])(3, 100);
καλεί τη συνάρτηση mul(3, 100) που πολλαπλασιάζει το 3 με το 100 και το αποτέλεσμά που επιστρέφει το βάζουμε στη μεταβλητή res.
Τέλος χρησιμοποιώ κι ένα struct που περιέχει το σύμβολο, το OpCode και το αν είναι unary ένας τελεστής, και φτιάχνω έναν πίνακα tabops από τέτοια struct, ένα για κάθε τελεστή, και τα αρχικοποιώ στην αρχή της main (το πεδίο .unary το ορίζω στο struct και το αρχικοποιώ κι αυτό στον πίνακα με FALSE ή TRUE, αλλά βασικά δεν το χρησιμοποιώ καθόλου στο πρόγραμμα... το έβαλα γιατί μπορεί να μου χρειαστεί αργότερα, αν αναβαθμίσω το πρόγραμμα).
- Κώδικας: Επιλογή όλων
const OperStruct tabops[MAX_OPERATORS] = { // table of operator structures
{'+', ADD, FALSE}, {'-', SUB, FALSE}, {'*', MUL, FALSE},
{'/', DIV, FALSE}, {'%', MOD, FALSE}, {'^', POW, FALSE},
{'e', EXPO, TRUE}, {'@', SQRT, TRUE}, {'#', CBRT, TRUE},
{'~', NEG, TRUE }, {'!', FACT, TRUE}, {'\'', LOGE, TRUE},
{'\"', LOGTEN, TRUE}, {'_', TRUNC, TRUE}, {'.', FRAC, TRUE}
};
Αυτόν τον πίνακα τον χρησιμοποιώ κυρίως για να μετατρέψω τον χαρακτήρα του κάθε τελεστή (το σύμβολό του δηλαδή) στο αντίστοιχο opcode, ώστε να μπορώ μετά να κάνω index με αυτό το opcode τον πίνακα με τους δείκτες των συναρτήσεων.
Οπότε η γενική λογική το προγράμματος είναι, να διαβάζει με την get_input() την κύρια είσοδο και να κρατάει τις μεταβλητές που χρειάζεται (βασικά, τον τελεστή και το νούμερο). Μετατρέπει το σύμβολο του τελεστή από char στο αντίστοιχο opcode (μέσω της sym2opcode()) το οποίο opcode το χρησιμοποιεί μετά στην main για να καλέσει από τον πίνακα των συναρτήσεων την αντίστοιχη συνάρτηση. Για ορίσματα περνάει πάντα το προηγούμενο αποτέλεσμα (res) και το νούμερο που διάβασε (χ).
Οι συναρτήσεις είναι φτιαγμένες έτσι ώστε να αγνοούν το 2ο όρισμά τους αν δεν το χρειάζονται. Απλά για να δουλέψει η φάση με τον πίνακα συναρτήσεων πρέπει όλες οι συναρτήσεις να έχουν το ίδιο πλήθος και τύπο ορισμάτων και να επιστρέφουν όλες τον ίδιο τύπο.
Αυτά!
Ο κώδικας είναι ανεβασμένος στο ideone.com: https://ideone.com/f87ub


