-
Notifications
You must be signed in to change notification settings - Fork 0
Sitaras/Java-Calculator-and-Parser
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Δημήτριος Σιταράς | 1115201800178 | ———————————————————— ► Οργάνωση Κώδικα: . ├── README.txt ├── part1 │ ├── Calculator.java │ ├── Main.java │ ├── Makefile │ └── ParseError.java └── part2 ├── Main.java ├── Makefile ├── parser.cup └── scanner.flex ---------------------------------------------------------------------------------------- ► Γενικά: → Ο κώδικας είναι σχολιασμένος. → Πληρούνται όλες οι προϋποθέσεις/απαιτήσεις που αναγράφονται στην εκφώνηση της άσκησης. → Η υλοποιήσεις μου βασίζονται στα παραδείγματα του φροντιστηρίου. → Και τα 2 προγράμματα του part1 και του part2 έχουν το δικό τους Makefile, επομένως μεταγλωττίζονται και εκτελούνται με όμοιο τρόπο: ► Eντολή μεταγλώττισης: make ► Eντολή εκτέλεσης: make execute (make clean, για την διαγράφη των παραγόμενων από την μεταγλώττιση αρχείων) ▪ Part 1 ——————————————— Για το μέρος πρώτο κατασκέυασα την παρακάτω LL1 γραμματική, με την κατάλληλη προτεραιότητα τελεστών, αφαιρώντας βέβαια την αριστερή αναδρομή: #1 expr -> term expr2 #2 expr2 -> + term expr2 #3 | - term expr2 #4 | ε #5 term -> factor term2 #6 term2 -> ** factor term2 #7 | ε #8 factor -> number #9 | ( expr ) #10 number -> 1...9 number_tail #11 | 0 #12 number_tail -> 0...9 #13 | ε Για να επαληθεύσω οτι η γραμματική μου ειναι LL1 υπολόγισα τα FIRST+ sets και με βάση αυτά για να διευκολυνθώ στην ανάπτυξη του προγράμματος εκάνα το παρακάτω πινακά ( για λόγους εξοικονόμησης χώρου στον πίνακα "θεώρησα" ότι το number είναι τερματικό και δεν το ανέλυσα περαιτέρω): number | + | - | ** | ( | ) | EOF expr #1 | | | | #1 | | expr2 | #2 | #3 | | | #4 | #4 term #5 | | | | #5 | | term2 | #7 | #7 | #6 | | #7 | #7 factor #8 | | | | #9 | | ► Διευκρινήσεις και παρατηρήσεις : → Κάθε μη τερματικό αντιστοιχεί σε μια συνάρτηση (τα μη τερματικα number και number_tail έχουν ουσιαστίκα "συγχωνευτεί" σε μια συνάρτηση για λόγους κομψότητας, φυσικά η γραμματική μου παραμένει LL1). → To πρόγραμμα διαβάζει ένα προς ένα τα σύμβολα από το standard input (μέσω της συνάρτησης consume()) → Για την πράξη της ύψωσης σε δύναμη χρησιμοποιήθηκε η συνάρτηση που δώθηκε στο piazza. → Αν υπάρχουν συντακτικά λάθη στην έκφραση που δίνει ο χρήστης (προκύπτει σφάλμα ανάλυσης) εκτυπώνω "parse error" (στο standard error). → Η υπολογισμένη τιμή της έκρασης που δίνει ο χρήστης (αν δεν έχει συντακτικά λάθη) εκτυπώνεται στο standard output. → Η έκφραση που δίνει ως είσοδο ο χρήστης δεν πρεπει να έχει κενά, καθώς δεν αναγνωρίζονται και αποτιμούνται σε σφάλμα ανάλυσης. → Η έκφραση που δίνει ως είσοδο ο χρήστης τερμάτιζεται με \n (Εnter) ή EOF. ▪ Part 2 ——————————————— ► Στο αρχείο scanner.flex: Έχω κατασκευάσει τις λεκτικές προδιαγραφές, ορίζοντας στην "ενότητα" των Macro Declarations τα : LineTerminator, WhiteSpace και Identifier (χρησιμοποιείται για τα ονόματα των συναρτήσεων και των παραμέτρων στις δηλώσεις αυτών αλλά και για το σώμα τους) Επίσης, στην "ενότητα" των λεκτικών κανόνων έχω ορίσει τους τελεστές και τα σύμβολα που χρησιμοποιούνται στην γραμματική της γλώσσας. Συγκεκριμένα, έχω ορίσει τα παρακάτω: → "+" → "if" → "else" → "suffix" → "prefix" → "(" και ")" → "{" και "}" → "," Επιπλέον, έχω καθορίσει στην ίδια ενότητα την κατάσταση <STRING> που χρησιμοποιείται για την ανάλυση των συμβολοσειρών. ► Στο αρχείο parser.cup: Έχω ορίσει την γραμματική της γλώσσας. Στην αρχή, γίνεται η σύνδεση του scanner με τον parser.cup και στην συνέχεια δηλώνω τα τερματικα και μη τερματικά σύμβολα που χρησιμοποιούνται στην γραμματική. Επίσης, ορίζω αριστερή προτεραιότητα για την λέξη "if" και τον τελεστή "+". Έπειτα, ακολουθεί η γραμματική. Ουσιαστικά, αποτελείται απο δύο τμήματα, ένα τμήμα που περιλαμβάνει τις δηλώσεις των συναρτήσεων της γλώσσα που θα παραχθέι και ένα δεύτερο τμήμα που περιλαμβάνει κλήσεις συναρτήσεων και γενικότερα εκφράσεις που περιλαμβάνουν συμβολοσειρές, το τμήμα αυτό είναι το σώμα της public static void main(String[] args). H χρήση του αναγνωριστικου (identifier) στο τμήμα που θα αποτελέσει το σώμα της public static void main(String[] args) "κρίνεται απαγορευτική", επομένως αν δωθει λανθασμένη είσοδος θα προκληθεί "syntax error". Όπως ανέφερα και προηγουμένως identifier χρησιμοποιείται μόνο για τα ονόματα των συναρτήσεων και των παραμέτρων στις δηλώσεις αυτών αλλά και για το σώμα τους. Έτσι, έχω κατασκευάσει στην γραμματική διαφορετικές εκφράσεις για κάθε τμήμα ώστε να γίνεται "αποδεκτό" μόνο ότι πραγματικά επιτρέπεται. ► Διευκρινήσεις και παρατηρήσεις : → Κάθε "if έκφραση" αποτιμάται σε μια ανάλογη έκφραση όπου χρησιμοποιείται ο ternary operator. → Οι λογικοί τελεστές suffix και prefix αποτιμούνται στις συναρτήσεις endsWith() και startsWith() αντίστοιχα. → Η είσοδος του χρήστη τερμάτιζεται με EOF. → Το τελικό προγραμμα εξόδου .java εκτυπώνεται στο standard output. → Τα αρχεία με κατάληξη .jar που ειναι απαραίτητα για την μεταγλώττιση του προγράμματος πρέπει να βρίσκονται στον ίδιο φάκελο με το README.txt (στο MakeFile έχω τα εξής: ../java-cup-11b-runtime.jar, ../java-cup-11b-runtime.jar). Δηλαδή, η τελική οργάνωση του κώδικα για την μεταγλώττιση του προγράμματος είναι η παρακάτω: . ├── README.txt ├── java-cup-11b-runtime.jar ├── java-cup-11b.jar ├── part1 │ ├── Calculator.java │ ├── Main.java │ ├── Makefile │ └── ParseError.java └── part2 ├── Main.java ├── Makefile ├── parser.cup └── scanner.flex
About
No description or website provided.
Topics
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published