PLH24_4ERG_ΕΝΔΕΙΚΤΙΚΗ ΑΠΑΝΤΗΣΗ.v.1.0

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 49

ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»

ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

Ενδεικτική απάντηση 4ης εργασίας

ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ 2023-2024

Αναλυτική Αξιολόγηση

Άσκηση Περιγραφή Ποσοστό Βαθμός


1 Υλοποίηση Τμήματος Μεταγλωττιστή
1.Α Λεκτικός Αναλυτής 5
1.Β Συντακτικός Αναλυτής 35
1.Γ Ανάλυση Κώδικα 35
1.Δ Έλεγχος Ορθής Λειτουργίας 10
2. Μετασχηματισμός Γραμματικής για top-down
ανίχνευση με πρόβλεψη
2.Α Μετασχηματισμός γραμματικής 10
3. Συμμόρφωση με τους Κανόνες Συγγραφής 5
Σύνολο 15

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

Άσκηση 1 – Υλοποίηση Τμήματος Μεταγλωττιστή

Γλώσσα SPL (Simple Programming Language)

Σας δίνεται μια απλή γλώσσα προγραμματισμού που θα την ονομάσουμε SPL (Simple Programming
Language) με λεκτικές και συντακτικές προδιαγραφές όπως παρουσιάζονται παρακάτω.

Λεκτικές Προδιαγραφές
Για τη γλώσσα που μας ενδιαφέρει οι λεκτικές προδιαγραφές συνοψίζονται στον παρακάτω πίνακα:
ΛΕΚΤΙΚΕΣ ΠΡΟΔΙΑΓΡΑΦΕΣ της γλώσσας SPL
Μπορεί να είναι ο κενός χαρακτήρας (blank), o χαρακτήρας νέα γραμμή (newline) και o
Whitespaces
χαρακτήρας tab
Ένα σχόλιο ανοίγει με το σύμβολο { και κλείνει με το σύμβολο } και περιορίζεται σε μια
Comments
μόνο γραμμή. ΔΕΝ υποστηρίζονται εμφωλιασμένα σχόλια (σχόλιο μέσα σε σχόλιο).
PROGRAM, INTEGER, BOOLEAN, STRING, ARRAY, OF, READ, WRITE,
Keywords
IF, THEN, ELSE, WHILE, DO, EXIT, VAR, BODY, BEGIN, END, AND,
OR, NOT, TRUE, FALSE
Τα αναγνωριστικά είναι ονόματα που αρχίζουν με γράμμα ή το χαρακτήρα underscore (_)
Identifiers
και στη συνέχεια περιέχουν γράμματα, αριθμούς ή το χαρακτήρα underscore.
Οι σταθερές μπορεί να είναι ακέραιοι αριθμοί (με πιθανό αρνητικό πρόσημο), οι λογικές
τιμές TRUE και FALSE και αλφαριθμητικές σταθερές που περικλείονται σε ζεύγος διπλών
εισαγωγικών ″…″. Διπλά εισαγωγικά ″ μπορούν να περιέχονται εντός μια
Constants
αλφαριθμητικής σταθεράς αρκεί να προηγείται ένα backslash (\″). Το ίδιο ισχύει και για
τη συμμετοχή ενός backslash (\\). Μια αλφαριθμητική σταθερά δεν μπορεί να περιέχει το
χαρακτήρα newline.
Unary-minus1 ‘–’ (π.χ. – 7)
Multiplicative ‘*’, ‘/’, ‘%’ (% = modulo)
Additive ‘+’, ‘–’
Relational ‘=’, ‘<>’, ‘<’, ‘>’, ‘<=’, ‘>=’
Operators
Logical AND, OR, NOT (NOT is a unary operator)
String ‘|’
Concatenation
Assignment ‘:=’
‘(’, ‘)’ Ομαδοποιούν expressions
Χρησιμοποιούνται στον ορισμό ενός πίνακα ή στην αναφορά σ’ ένα
‘[’, ‘]’
στοιχείο του πίνακα
Διαχωρίζει είτε δηλώσεις μεταβλητών στο τμήμα δηλώσεων του
Punctuators ή ‘;’
προγράμματος, είτε εντολές στο σώμα του προγράμματος
Separators
‘:’ Εισαγάγει τον τύπο δεδομένων ενός identifier
Διαχωρίζει τα ονόματα μιας λίστας από identifiers κατά τη δήλωση
‘,’ τύπου δεδομένων ή διαχωρίζει τα μέλη μιας λίστας εκφράσεων στις
εντολές READ και WRITE.

Συντακτικές Προδιαγραφές

1
Ο τελεστής unary-minus θα εφαρμόζεται μόνο σε αριθμητικές σταθερές.

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

Οι συντακτικές προδιαγραφές προσδιορίζουν τους νόμιμους τρόπους κατά τους οποίους τα tokens που
προκύπτουν από τις λεκτικές προδιαγραφές μπορούν να συνδυαστούν ώστε να ορίσουν τα συστατικά
στοιχεία ενός προγράμματος της SPL (δηλώσεις, εντολές, εκφράσεις, κ.ά.). Ένα πρόγραμμα SPL
αποτελείται από τρία βασικά τμήματα:
 Την επικεφαλίδα του προγράμματος (υποχρεωτικό)
 Το τμήμα δηλώσεων του προγράμματος (προαιρετικό)
 Το σώμα του προγράμματος (υποχρεωτικό)

Η επικεφαλίδα του προγράμματος αποτελείται από τη δεσμευμένη λέξη PROGRAM κι ένα όνομα που
ορίζουμε για το πρόγραμμα.

Το τμήμα δηλώσεων του προγράμματος, όταν υπάρχει, εισάγεται με τη δεσμευμένη λέξη VAR και
περιλαμβάνει μια ή περισσότερες εντολές δήλωσης μεταβλητών. Μια εντολή δήλωσης μπορεί να
περιλαμβάνει τα ονόματα πολλών μεταβλητών. Οι εντολές δήλωσης (εκτός της τελευταίας)
διαχωρίζονται με τον διαχωριστή ‘;’. Για κάθε μεταβλητή που δηλώνουμε ορίζουμε το όνομα και τον
τύπο δεδομένων της. Οι βασικοί τύποι δεδομένων είναι INTEGER, BOOLEAN και STRING, ενώ
υποστηρίζεται και η δομή δεδομένων πίνακα. Οι πίνακες είναι μονοδιάστατοι και o τύπος εισάγεται με
τη δεσμευμένη λέξη ARRAY. Στη δήλωση ενός πίνακα ο τύπος του δείκτη πρέπει να είναι αριθμητικός
ενώ ο τύπος των περιεχομένων (ακολουθεί τη δεσμευμένη λέξη OF) είναι κάποιος από τους βασικούς
τύπους δεδομένων. Ένα παράδειγμα τμήματος δήλωσης ακολουθεί:

VAR
i, j: INTEGER;
s1, s2: STRING;
buffer: ARRAY[10] OF INTEGER;
flag: BOOLEAN

Το σώμα του προγράμματος εισάγεται με τη δεσμευμένη λέξη BODY και περιλαμβάνει μια ή
περισσότερες εντολές. Εάν το σώμα περιλαμβάνει περισσότερες της μιας εντολές, τότε αυτές
περικλείονται εντός block που οριοθετείται από τις δεσμευμένες λέξεις BEGIN … END. Τα block
εντολών μπορεί να είναι εμφωλιασμένα. Οι εντολές σ’ ένα block εντολών (εκτός της τελευταίας)
διαχωρίζονται με τον διαχωριστή ‘;’. Ένα παράδειγμα σώματος του προγράμματος ακολουθεί:
BODY
BEGIN
Statement-1;
Statement-2;
BEGIN
Statement-3
END;
Statement-4

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

END

Οι εντολές που υποστηρίζονται από τη γλώσσα δίνονται στον παρακάτω πίνακα:


ΕΝΤΟΛΗ ΣΥΝΤΑΞΗ
Η εντολή εκχώρησης έχει τη μορφή lvalue := expression, όπου lvalue είναι
είτε μια μεταβλητή, είτε ένα στοιχείο ενός πίνακα με δείκτη είτε μια αριθμητική
Assignment σταθερά, είτε μια ακέραια μεταβλητή. Παραδείγματα:
temp := -10;
flag := x < y;
buffer[i] := x-i;
READ H εντολή READ διαβάζει τις τιμές των ορισμάτων της. Τα ορίσματα της READ είναι μια
λίστα μεταβλητών. Π.χ.
READ(size);
READ(username, password);
WRITE H εντολή WRITE τυπώνει στην οθόνη τις τιμές των ορισμάτων της. Τα ορίσματα της
WRITE είναι μια λίστα εκφράσεων. Π.χ.
WRITE(″The result is ″, a%2);
IF-THEN-ELSE H εντολή έχει τη μορφή IF expression THEN statement ELSE
statement, με το ELSE τμήμα να είναι προαιρετικό. Το ELSE τμήμα συνοδεύει το
πλησιέστερο από τα προηγούμενα ασυνόδευτα ΤΗΕΝ. Παράδειγμα:
IF x < y THEN l := m+1
ELSE IF x > y THEN r := m
ELSE BEGIN
WRITE("Answer is ", m);
EXIT
END ;
WHILE-DO H εντολή έχει τη μορφή WHILE expression DO statement. To statement
μπορεί να είναι ένα block εντολών.
ΕΧΙΤ Η εντολή EXIT τερματίζει το πρόγραμμα

Οι εντολές όπως περιγράφηκαν παραπάνω μπορεί να περιλαμβάνουν μια ή περισσότερες εκφράσεις.


Μια έκφραση είναι μια ακολουθία από τελεστές, έντελα και διαχωριστές που προσδιορίζουν συνολικά
έναν υπολογισμό. Οι εκφράσεις μπορεί να περιλαμβάνουν σταθερές, μεταβλητές, αναφορά σε στοιχείο
πίνακα και τελεστές. Οι τελεστές μπορεί να εφαρμόζονται σε υπο-εκφράσεις μιας έκφρασης.
Η προσεταιριστικότητα όλων των τελεστών είναι από αριστερά προς τα δεξιά και η προτεραιότητα
τους ορίζεται βάσει του ακόλουθου πίνακα (η προτεραιότητα μειώνεται από πάνω προς τα κάτω,
τελεστές στην ίδια γραμμή έχουν την ίδια προτεραιότητα):
Operators

– (unary minus) ΝΟΤ ( )

*/%

+ –|

= <> < > <= >=

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

AND

OR

Ερώτημα Α – Λεκτικός Αναλυτής

Ο λεκτικός αναλυτής (ΛΑ) είναι ένα τμήμα ενός μεταγλωττιστή, το οποίο αποσυνθέτει ένα πρόγραμμα
στις λεκτικές μονάδες από τις οποίες αποτελείται. Στην περίπτωση που αναγνωρίσει κάποιο σφάλμα
(για παράδειγμα έναν χαρακτήρα που δεν ανήκει στο αλφάβητο της γλώσσας) βγάζει ένα κατάλληλο
μήνυμα λάθους και τερματίζει τη λειτουργία του μεταγλωττιστή.
Για να υλοποιήσουμε τον ΛΑ θα χρησιμοποιήσουμε κανονικές εκφράσεις, ώστε να περιγράψουμε τις
λεκτικές μονάδες που επιθυμούμε να αναγνωρίζονται. Οι λεκτικές μονάδες έχουν αυστηρή σύνταξη,
χρησιμοποιούνται για να περιγράψουν συμβολοσειρές ή σύνολα από συμβολοσειρές και είναι πολύ
χρήσιμες στην λεκτική ανάλυση. Πιο συγκεκριμένα, η υλοποίηση του ΛΑ βασίζεται στο πακέτο
java.util.regex της Java.
Η υλοποίηση του ΛΑ σας δίνεται κατά το μεγαλύτερο μέρος έτοιμη στις κλάσεις Lex, Token και
TokenType. Χρησιμοποιούμε την κλάση Token η οποία υλοποιεί μία δομή στην οποία αποθηκεύουμε
τις λεκτικές μονάδες που αναγνωρίζουμε. Η κλάση αυτή έχει τρία πεδία. Το πρώτο πεδίο είναι το type
το οποίο είναι τύπου TokenType και αποθηκεύει τον τύπο της λεκτικής μονάδας. Το δεύτερο πεδίο το
ονομάζουμε data, είναι τύπου String και αποθηκεύει τη λεκτική μονάδα (π.χ. το όνομα μιας
μεταβλητής) και το τρίτο πεδίο, το line, είναι ακέραιος και αποθηκεύει τη γραμμή στην οποία
εμφανίστηκε η λεκτική μονάδα.
Για τη σύνταξη των κανονικών εκφράσεων, αλλά και τη βιβλιοθήκη γενικότερα java.util.regex,
μπορείτε να συμβουλευτείτε τον ακόλουθο σύνδεσμο:
https://www.tutorialspoint.com/java/java_regular_expressions.htm
Επίσης, μπορείτε να συμβουλευτείτε την Ενότητα 4.2 του Εγχειριδίου «Μεταγλωττιστές: Επιλεγμένες
Λύσεις Θεμάτων και Αναφορά στη Σχετική Θεωρία» που είναι διαθέσιμο στην ενότητα
«Συμπληρωματικό Υλικό» στο Study.
Στην κλάση TokenType της εργασίας χρειάζεται να συμπληρώσετε τις Κανονικές Εκφράσεις για τις
ακόλουθες περιπτώσεις:
- commentTK()
- numericTK()
- stringConstTK()
- identifierTK()
Οι λεκτικές μονάδες αξιοποιούνται από τον Συντακτικό Αναλυτή όπως περιγράφεται στην επόμενη
ενότητα. Η λεκτική μονάδα που αναπαριστά ένα σχόλιο που θα χρησιμοποιηθεί;
Μαθησιακά Αποτελέσματα

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

Στην άσκηση 1.Α. θα σας δοθεί η δυνατότητα να κατανοήσετε:


 την περιγραφή λεκτικών μονάδων με κανονικές εκφράσεις
 την έννοια της λεκτικής ανάλυσης
 τη λειτουργία ενός λεκτικού αναλυτή

Απάντηση
Να συμπληρώσετε τις κανονικές εκφράσεις που λείπουν.
Εάν δεν έχετε δώσει απάντηση, γράψτε με κεφαλαία γράμματα: ΔΕΝ ΑΠΑΝΤΗΘΗΚΕ.
Εάν εν γνώση σας δίνετε ελλιπή απάντηση, γράψτε με κεφαλαία γράμματα: ΕΛΛΙΠΗΣ ΑΠΑΝΤΗΣΗ. Εξηγείστε σε
ποιο σημείο θεωρείτε την απάντησή σας ελλιπή και γιατί.

Οι Κανονικές Εκφράσεις που συμπληρώνονται στο enumeration TokenType είναι οι εξής:

commentTK("\\{[^{}\\n]*\\}")

Σύμφωνα με τις λεκτικές προδιαγραφές:


Ένα σχόλιο ανοίγει με το σύμβολο { και κλείνει με το σύμβολο } και περιορίζεται σε μια μόνο γραμμή.
ΔΕΝ υποστηρίζονται εμφωλιασμένα σχόλια (σχόλιο μέσα σε σχόλιο).

Ανάλυση ΚΕ:
\\{
Αντιστοιχεί στο άνοιγμα του σχολίου με το σύμβολο {. Οι δύο χαρακτήρες διαφυγής (\\)2
χρησιμοποιούνται για την αποφυγή της ειδικής ερμηνείας του χαρακτήρα { στις κανονικές εκφράσεις.

[^{}\\n]*
Προσδιορίζει ένα σετ χαρακτήρων που αποκλείει τους χαρακτήρες { } και \n (νέα γραμμή). Το
[^...] χρησιμοποιείται για να δηλώσει μια ομάδα χαρακτήρων που ΔΕΝ πρέπει να εμφανίζονται. Το
* σημαίνει ότι μπορεί να υπάρχουν μηδέν ή περισσότεροι χαρακτήρες.

\\}
Αυτό το μέρος αντιστοιχεί στο κλείσιμο του σχολίου με το σύμβολο }. Όπως και με το άνοιγμα, οι δύο
χαρακτήρες διαφυγής χρησιμοποιούνται για την αποφυγή της ειδικής ερμηνείας του χαρακτήρα }.

numericTK("(0|[1-9]\\d*)")

Σύμφωνα με τις λεκτικές προδιαγραφές:


Οι σταθερές μπορεί να είναι ακέραιοι αριθμοί (με πιθανό αρνητικό πρόσημο).

Ανάλυση ΚΕ:

2
Στην Java, όταν χρησιμοποιούμε κανονικές εκφράσεις μέσα σε συμβολοσειρές, πρέπει να "διαφύγουμε"
(escape) δύο φορές τους ειδικούς χαρακτήρες: μία για την Java, λόγω συμβολοσειράς, και μία για την κανονική
έκφραση.

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

0
Αντιστοιχεί ακριβώς στον αριθμό 0.

[1-9]\\d*
Αντιστοιχεί σε οποιονδήποτε ακέραιο που ξεκινά με έναν από τους αριθμούς 1-9 και ακολουθείται από
οποιονδήποτε αριθμό (ή καθόλου) ψηφίων (0-9).

Οι αρνητικοί ακέραιοι αναγνωρίζονται σε επίπεδο ΣΑ χρησιμοποιώντας τον τελεστή unary minus της
γλώσσας.

stringConstTK("\"(?:\\\\[\"\\\\]|[^\"\\\n])*\"")

Σύμφωνα με τις λεκτικές προδιαγραφές:


Οι αλφαριθμητικές σταθερές περικλείονται σε ζεύγος διπλών εισαγωγικών ″…″. Διπλά εισαγωγικά ″
μπορούν να περιέχονται εντός μια αλφαριθμητικής σταθεράς αρκεί να προηγείται ένα backslash (\″).
Το ίδιο ισχύει και για τη συμμετοχή ενός backslash (\\). Μια αλφαριθμητική σταθερά δεν μπορεί να
περιέχει το χαρακτήρα newline.

Ανάλυση ΚΕ:
\"
Η κανονική έκφραση αρχίζει και τελειώνει με διπλά εισαγωγικά.

(?: ... )
Αυτή είναι μια non-capturing ομάδα. Χρησιμοποιείται για να ομαδοποιήσει τμήματα της κανονικής
έκφρασης χωρίς να αποθηκεύει τα αποτελέσματα για μετέπειτα χρήση.

\\\\[\"\\\\]
Αυτό το τμήμα καλύπτει τις περιπτώσεις εμφάνισης διπλών εισαγωγικών ή backslashes των οποίων
προηγείται ένα backslash. Τα διπλά backslashes (\\\\) αναπαριστούν ένα κυριολεκτικό backslash στη
Java, επειδή το πρώτο backslash διαφεύγει το δεύτερο. Το [\"\\\\] δηλώνει ότι μπορεί να
ακολουθεί είτε ένα διπλό εισαγωγικό είτε ένα backslash.

[^\"\\\n]
Αυτό το τμήμα δέχεται οποιοδήποτε χαρακτήρα εκτός από διπλό εισαγωγικό (\"), backslash (\\) και
τον χαρακτήρα νέας γραμμής (\n).
Το διπλό εισαγωγικό (\") εξαιρείται γιατί ένα απλό διπλό εισαγωγικό θα ολοκλήρωνε την
αλφαριθμητική σταθερά. Μόνο όταν προηγείται ένα backslash (\\") μπορεί να αποτελέσει μέρος της
σταθεράς ως escaped διπλό εισαγωγικό.
Τo backslash (\\) εξαιρείται επίσης, εκτός εάν ακολουθείται από ένα άλλο backslash ή διπλό
εισαγωγικό. Ένα μοναχικό backslash δεν είναι επιτρεπτό γιατί θα σήμαινε μια ελλιπή διαφυγή.
Ο χαρακτήρας νέας γραμμής (\n) εξαιρείται αυτόματα από την αλφαριθμητική σταθερά για να
διασφαλιστεί ότι το αλφαριθμητικό περιορίζεται σε μία μόνο γραμμή, όπως απαιτούν οι
προδιαγραφές.

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

Ο αστερίσκος που ακολουθεί τη non-capturing ομάδα επιτρέπει την επανάληψη του περιεχομένου της
ομάδας 0 ή περισσότερες φορές. Αυτό σημαίνει ότι η αλφαριθμητική σταθερά μπορεί να είναι κενή ή
να περιέχει πολλαπλά εισαγωγικά ή backslashes, καθώς και άλλους χαρακτήρες εκτός από το διπλό
εισαγωγικό και τον χαρακτήρα νέας γραμμής.

identifierTK("[a-zA-Z_][a-zA-Z_0-9]*")

Σύμφωνα με τις λεκτικές προδιαγραφές:


Τα αναγνωριστικά είναι ονόματα που αρχίζουν με γράμμα ή το χαρακτήρα underscore (_) και στη
συνέχεια περιέχουν γράμματα, αριθμούς ή το χαρακτήρα underscore.

Ανάλυση ΚΕ:
[a-zA-Z_]
Αυτό το τμήμα δηλώνει ότι ο πρώτος χαρακτήρας ενός αναγνωριστικού πρέπει να είναι είτε γράμμα
(από το 'a' μέχρι το 'z' ή από το 'A' μέχρι το 'Z') είτε ο χαρακτήρας underscore (_).

[a-zA-Z_0-9]*
Αυτό το τμήμα χρησιμοποιεί τον τελεστή *, που δηλώνει επανάληψη του προηγούμενου στοιχείου
μηδέν ή περισσότερες φορές. Αυτό σημαίνει ότι στα επόμενα στοιχεία του αναγνωριστικού μπορούν να
συμπεριληφθούν γράμματα (ανεξαρτήτως πεζά ή κεφαλαία), αριθμοί (0-9), ή underscore.

Σημείωση 1:
Στην ανάπτυξη ΛΑ, είναι σημαντική η σειρά των κανονικών εκφράσεων, κυρίως λόγω της αρχής της
«μεγαλύτερης δυνατής λεκτικής μονάδας». Αυτή η αρχή διασφαλίζει ότι ο ΛΑ επιλέγει το μεγαλύτερο
δυνατό τμήμα του κώδικα πηγής που ταιριάζει με μια δεδομένη κανονική έκφραση, πριν προχωρήσει
σε επόμενες αναζητήσεις.

Για παράδειγμα, ο ΛΑ για τη γλώσσα SPL, η οποία περιλαμβάνει τόσο σύνθετους τελεστές (όπως <=,
>=) όσο και απλούς τελεστές (όπως <, >), θα πρέπει πρώτα να χειριστεί τις κανονικές εκφράσεις για
τους σύνθετους τελεστές και μετά αυτές των απλών τελεστών. Αυτό σημαίνει ότι στην TokenType θα
πρέπει να τοποθετήσουμε τα regular expressions των σύνθετων τελεστών (<=, >=) πάνω από τους
απλούς τελεστές (<, >). Αυτό εξασφαλίζει ότι συμβολοσειρές όπως <= και >= δεν θα ερμηνευτούν
λανθασμένα ως δύο διακριτά σύμβολα.

Σημείωση 2:
Η λεκτική μονάδα που αναπαριστά ένα σχόλιο δεν θα χρησιμοποιηθεί από τον ΣΑ και ως εκ τούτου στη
μέθοδο Lex() που παράγει τη λίστα με τις λεκτικές μονάδες και τις αποθηκεύει στη δομή τύπου
ArrayList με όνομα tokens, θα πρέπει να αγνοηθεί, όπως συμβαίνει και με τους λευκούς
χαρακτήρες.


case "whitespaceTK":
case "commentTK":
;
break;

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

Ερώτημα Β – Συντακτικός Αναλυτής

Ο συντακτικός αναλυτής (ΣΑ) υλοποιείται με βάση τη γραμματική της γλώσσας. H γραμματική δίνεται
στην κλάση που υλοποιεί τον ΣΑ (Parser_ex4) στον κώδικα που σας έχει δοθεί. Η γραμματική είναι
μορφής LL(1). Αυτό σημαίνει ότι αναγνωρίζει από αριστερά προς στα δεξιά, την αριστερότερη δυνατή
παραγωγή και όταν βρίσκεται σε δίλλημα ως προς το ποιον κανόνα να ακολουθήσει, της αρκεί να
κοιτάξει το αμέσως επόμενο σύμβολο στην συμβολοσειρά εισόδου (lookahead token). Αυτό το
τελευταίο στοιχείο μας ενδιαφέρει ιδιαίτερα στην κατασκευή του ΣΑ.
Ο ΣΑ φτιάχνεται από την γραμματική με συστηματικό τρόπο, σχεδόν αυτόματο. Για κάθε έναν από τους
κανόνες της γραμματικής, ορίζουμε και ένα αντίστοιχο υποπρόγραμμα (τυπικά μια μέθοδο στην
υλοποίηση της ΓΕ4). Όταν συναντάμε στον κανόνα ένα μη-τερματικό σύμβολο, καλούμε το αντίστοιχο
υποπρόγραμμα. Όταν συναντάμε ένα τερματικό σύμβολο, τότε εάν και ο ΛΑ επιστρέφει λεκτική
μονάδα που αντιστοιχεί στο τερματικό αυτό σύμβολο, τότε έχουμε αναγνωρίσει επιτυχώς τη λεκτική
μονάδα και ο ΣΑ προχωρά στο επόμενο σύμβολο του κανόνα, αν υπάρχει. Αντίθετα εάν ο ΛΑ δεν
επιστρέψει τη λεκτική μονάδα που περιμένει ο ΣΑ, τότε έχουμε λάθος και καλείται ο διαχειριστής
σφαλμάτων (χρήση της μεθόδου error() στον κώδικα που δόθηκε). Όταν αναγνωριστεί και η
τελευταία λέξη του πηγαίου προγράμματος, τότε η συντακτική ανάλυση έχει στεφτεί με επιτυχία.
Παρακάτω δίνεται, ως παράδειγμα, ο κώδικας της μεθόδου που αναφέρεται στην υλοποίηση ενός
κανόνα. Στον κώδικα αυτό χρησιμοποιείται και η μέθοδος next(), η οποία διαχειρίζεται τη δομή που
αποθηκεύει τις λεκτικές μονάδες και κάθε φορά που καλείται, αφαιρείται μία λεκτική μονάδα από τη
δομή και επιστρέφεται σαν αποτέλεσμα. Ο κανόνας της γραμματικής δίνεται ως σχόλιο στην αρχή της
αντίστοιχης μεθόδου.
//-------------------------------------------------------------------
// decl = idList COLON type
//-------------------------------------------------------------------
public static void decl() {
idList();
if (token.type.name().equals("colonTK")) {
token = next();
type();
} else {
error("COLON seperator expected in variable type declaration");
}

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

Ας παρακολουθήσουμε τον τρόπο υλοποίησης. Ξεκινώντας από τον κανόνα decl, ορίζουμε σαν void
την μέθοδο decl(). Στη αρχή του δεξιού μέρους του κανόνα συναντάμε το μη-τερματικό σύμβολο
idlist. Άρα στον κώδικα καλούμε την μέθοδο idList(). Μετά αναμένουμε το τερματικό σύμβολο
COLON. Ελέγχουμε αν το COLON αποτελεί το επόμενο σύμβολο εισόδου. Αν όχι, βγάζουμε μήνυμα
λάθους. Αν ναι, καλούμε την next() για να γίνει διαθέσιμη στον ΣΑ η επόμενη λεκτική μονάδα. Στη
συνέχεια στον κανόνα συναντάμε το μη-τερματικό σύμβολο type. Άρα καλούμε την αντίστοιχη μέθοδο
type().
Αντίστοιχα, δίνεται ως ένα επιπλέον παράδειγμα, ο κώδικας για τον κανόνα exprList:
//-------------------------------------------------------------------
// exprList = expr (COMMA expr)*
//-------------------------------------------------------------------
public static void exprList() {
expr();
while (token.type.name().equals("commaTK")) {
token = next();
expr();
}
}

Εδώ θα πρέπει να σημειωθεί ότι στους κανόνες της γραμματικής χρησιμοποιούνται και οι μετα-
χαρακτήρες (…)* και (…)? που χρησιμεύουν στην εκφραστική διατύπωση των κανόνων. Η πρώτη
ακολουθία επαναλαμβάνει τα σύμβολα που περικλείονται εντός των παρενθέσεων 0 ή περισσότερες
φορές, ενώ η δεύτερη ακολουθία επαναλαμβάνει τα σύμβολα 1 ή καμία φορά. Αυτοί οι μετα-
χαρακτήρες παρέχουν ευελιξία στην οριοθέτηση των κανόνων αλλά δεν αποτελούν μέρος της
γραμματικής της γλώσσας προγραμματισμού που αναλύεται.
Στην exprList, ενδιαφέρον έχει ότι δεν γνωρίζουμε πόσες φορές θα χρειαστεί να περάσουμε από την
δεύτερη expr. Μπορεί να περάσουμε καμία, μία ή περισσότερες φορές. Αφού καλέσουμε για πρώτη
φορά την expr, ο οδηγός μας είναι το τερματικό σύμβολο COMMA. Το σημείο αυτό αποτελεί ένα καλό
παράδειγμα για το τι εννοούμε ότι όταν έχουμε δίλημμα για το τι δρόμο θα ακολουθήσουμε μέσα στη
γραμματική, αυτό θα μας το δείξει το επόμενο σύμβολο στην είσοδο (το lookahead token). Αν λοιπόν,
και για όσο, το επόμενο σύμβολο στην είσοδο είναι το COMMA, τότε θα το αναγνωρίζουμε και θα
απαιτούμε μετά από αυτό να υπάρχει ένα expr. Αυτό υλοποιείται με την while, όπως φαίνεται στον
κώδικα παραπάνω.
Μέρος του κώδικα του ΣΑ σας δίνεται έτοιμο στην κλάση Parser_ex4, την οποία θα πρέπει να
μελετήσετε για να κατανοήσετε και άλλες τεχνικές υλοποίησης των κανόνων μιας γραμματικής, όπως
για παράδειγμα την περίπτωση κανόνα με εναλλακτικό δεξιό μέρος την κενή συμβολοσειρά (ε) ή

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

κανόνα με πολλά εναλλακτικά δεξιά μέρη. Για την υλοποίηση του ΣΑ θα πρέπει να συμπληρώσετε τον
κώδικα των μεθόδων για τους κανόνες της γραμματικής που είναι κενός. Οι κανόνες της γραμματικής
σας δίνονται ως σχόλιο πριν από κάθε μέθοδο. Ωστόσο συγκεκριμένους κανόνες της γραμματικής θα
πρέπει να τους ορίσετε εσείς κατάλληλα. Πιο συγκεκριμένα, θα πρέπει να ορίσετε τη δόμηση της
γραμματικής για τη συντακτική δομή expr (περιλαμβάνει τους κανόνες expr, logicAND,
relationExpr, additiveExpr, factor, term) έτσι ώστε να τηρούνται στον υπολογισμό των
εκφράσεων οι προτεραιότητες των τελεστών σύμφωνα με τις δοθείσες προδιαγραφές (δείτε τον
σχετικό πίνακα με τις προτεραιότητες των τελεστών στην εισαγωγή). Χωρίς αυτή τη δόμηση η
γραμματική θα είναι διφορούμενη ως προς τον υπολογισμό των εκφράσεων.
Για την υλοποίηση του ΣΑ με την παραπάνω μεθοδολογία μπορείτε επίσης να συμβουλευτείτε την
Ενότητα 4.3 του Εγχειριδίου «Μεταγλωττιστές: Επιλεγμένες Λύσεις Θεμάτων και Αναφορά στη Σχετική
Θεωρία» που είναι διαθέσιμο στην ενότητα «Συμπληρωματικό Υλικό» στο Study.
Για τον έλεγχο του ΣΑ που θα υλοποιήσετε σας δίνονται εντός του NetBeans project ενδεικτικά
προγράμματα που είναι σύμφωνα με τη γραμματική της γλώσσας SPL.

Μαθησιακά Αποτελέσματα
Στην άσκηση 1.Β. θα σας δοθεί η δυνατότητα να κατανοήσετε:
 την περιγραφή μίας γλώσσας μέσα από μία γραμματική
 την έννοια της συντακτικής ανάλυσης
 την κύρια ιδιότητα μιας γραμματικής LL(1)
 την υλοποίηση ενός συντακτικού αναλυτή με τη μέθοδο της αναδρομικής κατάβασης
 τη λειτουργία ενός συντακτικού αναλυτή
 τα σφάλματα μεταγλώττισης που μπορούν να προκύψουν κατά τη φάση της συντακτικής ανάλυσης
και τη διαχείρισή τους

Απάντηση
1) Να δώσετε τον κώδικα που υλοποιεί τον συντακτικό αναλυτή, επαρκώς σχολιασμένο. Αυτό
σημαίνει ότι πρέπει να συμπληρώσετε τον κώδικα που λείπει, τις μεθόδους που σημειώνονται με
τρεις τελείες. Να εμφανίζονται τα κατάλληλα μηνύματα λάθους στα οποία να φαίνεται και ο
αριθμός γραμμής του προγράμματος στην οποία έγινε το λάθος.
2) Εάν δεν έχετε δώσει απάντηση στο ερώτημα αυτό, γράψτε με κεφαλαία γράμματα: ΔΕΝ
ΑΠΑΝΤΗΘΗΚΕ.
3) Εάν εν γνώση σας δίνετε ελλιπή απάντηση, γράψτε με κεφαλαία γράμματα: ΕΛΛΙΠΗΣ
ΑΠΑΝΤΗΣΗ. Εξηγήστε σε ποιο σημείο θεωρείτε την απάντησή σας ελλιπή και γιατί.

Η υλοποίηση του ΣΑ ακολουθεί τη μεθοδολογία που περιγράφει η εκφώνηση η οποία βασίζεται στην
αντιστοίχιση κάθε κανόνα της γραμματικής με μια μέθοδο της κλάσης Parser_ex4. Αυτή η
προσέγγιση είναι σύμφωνη με το πλαίσιο υλοποίησης ΣΑ με προβλέπουσα αναδρομική κατάβαση
(recursive descent).

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

Αρχικά, όμως, θα πρέπει να συμπληρωθεί το μέρος τη γραμματικής για τη συντακτική δομή expr
(περιλαμβάνει τους κανόνες expr, logicAND, relationExpr, additiveExpr, factor,
term) έτσι ώστε να τηρούνται στον υπολογισμό των εκφράσεων οι προτεραιότητες των τελεστών
σύμφωνα με τις δοθείσες προδιαγραφές. H γραμματική πρέπει να λαμβάνει υπόψη τις σχετικές
προτεραιότητες των τελεστών, αλλά και την προσεταιριστικότητα του κάθε τελεστή, όπως δόθηκαν
στην εκφώνηση και συνοψίζονται στον ακόλουθο πίνακα.

Τελεστής Προτεραιότητα Προσεταιριστικότητα


– (unary minus) ΝΟΤ ( ) υψηλότερη αριστερή
*/% αριστερή
+ –| αριστερή
= <> < > <= >= αριστερή
AND αριστερή
OR χαμηλότερη αριστερή

Για να διαχειριστούμε την προτεραιότητα των τελεστών σε επίπεδο γραμματικής χρειαζόμαστε ένα μη
τερματικό σύμβολο για κάθε επίπεδο προτεραιότητας. Η διαμόρφωση της γραμματικής θα πρέπει να
είναι τέτοια που να αναγκάζει τον ΣΑ να κτίζει το δένδρο ανίχνευσης βάζοντας τους τελεστές
μικρότερης προτεραιότητας πιο ψηλά και αντίστοιχα τους τελεστές μεγαλύτερης προτεραιότητας πιο
χαμηλά στο δένδρο. Κάτι τέτοιο επιτυγχάνεται με τη δόμηση των κανόνων όπως φαίνεται στο
ακόλουθο απόσπασμα της γραμματικής. Παρατηρήστε ότι ο τελεστής με την χαμηλότερη
προτεραιότητα συνδέεται απευθείας με το μη-τερματικό σύμβολο αφετηρία των εκφράσεων (expr),
ενώ όσο ανεβαίνουμε επίπεδο προτεραιότητας με την εισαγωγή νέου μη-τερματικού συμβόλου και την
εισαγωγή στη γραμματική των σχετικών τελεστών, απομακρυνόμαστε από το σύμβολο αφετηρία.

expr = expr OR logicAND


| logicAND
logicAND = logicAND AND relationExpr
| relationExpr
relationExpr = relationExpr relationOperator additiveExpr
| additiveExpr
additiveExpr = additiveExpr addingOperator factor
| factor
factor = factor multiplyOperator term
| term
term = lvalue
| constant
| LPAREN expr RPAREN
| NOT term

Ωστόσο η παραπάνω γραμματική δεν είναι κατάλληλη για top-down ανίχνευση, όπως η υλοποίηση που
ζητείται, και γι’ αυτό απαιτείται απαλοιφή αριστερής αναδρομής στους κανόνες: expr, logicAND,
relationExpr, additiveExpr, factor. Η γραμματική μετά την εφαρμογή του μετασχηματισμού
απαλοιφής της αριστερής αναδρομής διαμορφώνεται ως ακολούθως:

expr = logicAND expr’


expr’ = OR logicAND expr’

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

| ε
logicAND = relationExpr logicAND’
logicAND’ = AND relationExpr logicAND’
| ε
relationExpr = additiveExpr relationExpr’
relationExpr’ = relationOperator additiveExpr relationExpr’
| ε
additiveExpr = factor additiveExpr’
additiveExpr’ = addingOperator factor dditiveExpr’
| ε
factor = term factor’
factor’ = multiplyOperator term factor’
| ε
term = lvalue
| constant
| LPAREN expr RPAREN
| NOT term

H μεθοδολογία υλοποίησης που έχει δοθεί διευκολύνεται όταν οι κανόνες της γραμματικής
εκφράζονται σε EBNF μορφή. Έτσι, μια επανάληψη σε μορφή BNF:

A=aNC
N = B1 B2 … Bn N | ε

Μπορεί να μετατραπεί στην ακόλουθη μορφή EBNF (με κόκκινο χρώμα δείχνουμε τους μετα-
χαρακτήρες της γραμματικής):

Α = a ( B1 B2 … Bn )* C

Εφαρμόζοντας τον παραπάνω μετασχηματισμό στον κανόνα expr

expr = logicAND expr’


expr’ = OR logicAND expr’
| ε
Θα έχουμε:

expr = logicAND (OR logicAND)*

Με την ίδια λογική το παραπάνω απόσπασμα της γραμματικής για την αναγνώριση των εκφράσεων με
ενσωματωμένη την προτεραιότητα και προσεταιριστικότητα των τελεστών γίνεται:

expr = logicAND (OR logicAND)*


logicAND = relationExpr (AND relationExpr)*
relationExpr = additiveExpr (relationOperator additiveExpr)*
additiveExpr = factor (addingOperator factor)*
factor = term (multiplyOperator term)*
term = lvalue
| constant
| LPAREN expr RPAREN

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

| NOT term

Η συνολική γραμματική που περιγράφει το συντακτικό της γλώσσας SPL σε EBNF μορφή και θα πρέπει
να υλοποιηθεί με προβλέπουσα αναδρομική κατάβαση ακολουθεί:

program = PROGRAM ID declarations BODY statement EOF


declarations3 = (VAR decl (SEMICOLON decl)*)?
decl = idList COLON type
idList = ID (COMMA ID)*
type = basicType
| arrayType
basicType = INTEGER
| BOOLEAN
| STRING
arrayType = ARRAY LBRACK NUMERIC RBRACK OF basicType
statement = BEGIN block END
| lvalue ASSIGN expr
| READ LPAREN idList RPAREN
| WRITE LPAREN exprList RPAREN
| IF expr THEN statement (ELSE statement)?
| WHILE expr DO statement
| EXIT
block4 = (statement (SEMICOLON statement)*)?
lvalue = ID args
args5 = (LBRACK index RBRACK)?
index = ID
| NUMERIC
exprList = expr (COMMA expr)*
expr = logicAND (OR logicAND)*
logicAND = relationExpr (AND relationExpr)*
relationExpr = additiveExpr (relationOperator additiveExpr)*
additiveExpr = factor (addingOperator factor)*
factor = term (multiplyOperator term)*
term = lvalue
| constant
| LPAREN expr RPAREN
| NOT term
constant = NUMERIC
| STRING
| TRUE
| FALSE
| MINUS NUMERIC
relationOperator = EQUAL
| NOT_EQUAL
| LT
| GT
| LTE
| GTE
addingOperator = PLUS
3
declarations = VAR decl (SEMICOLON decl)* | ε
4
block = statement (SEMICOLON statement)* | ε
5
args = LBRACK index RBRACK | ε

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

| MINUS
| CONCAT
multiplyOperator = TIMES
| DIVISION
| MODULO

Οι μέθοδοι και οι αντίστοιχοι κανόνες των οποίων η υλοποίηση ζητείται στην κλάση Parser_ex4
είναι οι παρακάτω:

public static void program()

public static void declarations()

public static void idList()

public static void type()

public static void statement()

public static void block()

public static void index()

public static void expr()

public static void logicAND()

public static void relationExpr()

public static void additiveExpr()

public static void factor()

public static void term()

public static void constant()

public static void relationOperator()

public static void addingOperator()

public static void multiplyOperator()

Ακολουθεί ο κώδικας των ζητούμενων μεθόδων:

//-------------------------------------------------------------------

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

// program = PROGRAM ID declarations BODY statement EOF


//-------------------------------------------------------------------
public static void program() {
if (token.type.name().equals("programTK")) {
token = next();
if (token.type.name().equals("identifierTK")) {
token = next();
declarations();
if (token.type.name().equals("bodyTK")) {
token = next();
statement();
if (token.type.name().equals("eofTK")) {
System.out.println("syntactically correct program");
} else {
error("EOF expected at the end of the program");
}
} else {
error("BODY keyword expected");
}
} else {
error("name of program expected after PROGRAM keyword");
}
} else {
error("programs start with keyword PROGRAM");
}
}

//-------------------------------------------------------------------
// declarations = VAR decl (SEMICOLON decl)* | ε
//-------------------------------------------------------------------
public static void declarations() {
if (token.type.name().equals("varTK")) {
token = next();
decl();
while (token.type.name().equals("semicolonTK")) {
token = next();
decl();
}
}
}

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

//-------------------------------------------------------------------
// idList = ID (COMMA ID)*
//-------------------------------------------------------------------
public static void idList() {
if (token.type.name().equals("identifierTK")) {
token = next();
while (token.type.name().equals("commaTK")) {
token = next();
if (token.type.name().equals("identifierTK")) {
token = next();
} else {
error("name of variable expected after COMMA separator");
}
}
} else {
error("name of variable expected");
}
}

//-------------------------------------------------------------------
// type = basicType | arrayType
//-------------------------------------------------------------------
public static void type() {
if (token.type.name().equals("arrayTK")) {
arrayType();
} else {
basicType();
}
}

//-------------------------------------------------------------------
// statement = BEGIN block END
// | lvalue ASSIGN expr
// | READ LPAREN idList RPAREN
// | WRITE LPAREN exprList RPAREN
// | IF expr THEN statement (ELSE statement)?
// | WHILE expr DO statement
// | EXIT
//-------------------------------------------------------------------
public static void statement() {
switch (token.type.name()) {
case "beginTK": {
token = next();
block();
if (token.type.name().equals("endTK")) {
token = next();
} else {
error("END keyword expected to mark a block of state-
ments");
}
break;

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

}
case "readTK": {
token = next();
if (token.type.name().equals("lparenTK")) {
token = next();
idList();
if (token.type.name().equals("rparenTK")) {
token = next();
} else {
error("RPAREN expected in READ statement");
}
} else {
error("LPAREN expected in READ statement");
}
break;
}
case "writeTK": {
token = next();
if (token.type.name().equals("lparenTK")) {
token = next();
exprList();
if (token.type.name().equals("rparenTK")) {
token = next();
} else {
error("RPAREN expected in WRITE statement");
}
} else {
error("LPAREN expected in WRITE statement");
}
break;
}
case "ifTK": {
token = next();
expr();
if (token.type.name().equals("thenTK")) {
token = next();
statement();
if (token.type.name().equals("elseTK")) {
token = next();
statement();
}
} else {
error("THEN keyword expected in IF statement");
}
break;
}
case "whileTK": {
token = next();
expr();
if (token.type.name().equals("doTK")) {
token = next();
statement();
} else {

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

error("DO keyword expected in WHILE statement");


}
break;
}
case "exitTK": {
token = next();
break;
}
default: {
lvalue();
if (token.type.name().equals("assignTK")) {
token = next();
expr();
} else {
error("ASSIGN operator expected in assignment statement");
}
break;
}
}
}

//-------------------------------------------------------------------
// block = statement (SEMICOLON statement)* | ε
//-------------------------------------------------------------------
public static void block() {
switch (token.type.name()) {
case "beginTK":
case "readTK":
case "writeTK":
case "ifTK":
case "whileTK":
case "exitTK":
case "identifierTK": {
statement();
while (token.type.name().equals("semicolonTK")) {
token = next();
statement();
}
break;
}
default: {
break; // ε
}
}
}

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

//-------------------------------------------------------------------
// index = ID | NUMERIC
//-------------------------------------------------------------------
public static void index() {
switch (token.type.name()) {
case "identifierTK": {
token = next();
break;
}
case "numericTK": {
token = next();
break;
}
default: {
error("Unknown index");
break;
}
}
}

//-------------------------------------------------------------------
// expr = logicAND (OR logicAND)*
//-------------------------------------------------------------------
public static void expr() {
logicAND();
while (token.type.name().equals("orTK")) {
token = next();
logicAND();
}
}

//-------------------------------------------------------------------
// logicAND = relationExpr (AND relationExpr)*
//-------------------------------------------------------------------
public static void logicAND() {
relationExpr();
while (token.type.name().equals("andTK")) {
token = next();
relationExpr();
}
}

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

//-------------------------------------------------------------------
// relationExpr = additiveExpr (relationOperator additiveExpr)*
//-------------------------------------------------------------------
public static void relationExpr() {
additiveExpr();
while (token.type.name().equals("equalTK")
|| token.type.name().equals("notEqualTK")
|| token.type.name().equals("ltTK")
|| token.type.name().equals("gtTK")
|| token.type.name().equals("lteTK")
|| token.type.name().equals("gteTK")) {
relationOperator();
additiveExpr();
}
}

//-------------------------------------------------------------------
// additiveExpr = factor (addingOperator factor)*
//-------------------------------------------------------------------
public static void additiveExpr() {
factor();
while (token.type.name().equals("plusTK")
|| token.type.name().equals("minusTK")
|| token.type.name().equals("concatTK")) {
addingOperator();
factor();
}
}

//-------------------------------------------------------------------
// factor = term (multiplyOperator term)*
//-------------------------------------------------------------------
public static void factor() {
term();
while (token.type.name().equals("timesTK")
|| token.type.name().equals("divisionTK")
|| token.type.name().equals("moduloTK")) {
multiplyOperator();
term();
}
}

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

//-------------------------------------------------------------------
// term = lvalue
// | constant
// | LPAREN expr RPAREN
// | NOT term
//-------------------------------------------------------------------
public static void term() {
switch (token.type.name()) {
case "numericTK":
case "stringConstTK":
case "trueTK":
case "falseTK":
case "minusTK": {
constant();
break;
}
case "lparenTK": {
token = next();
expr();
if (token.type.name().equals("rparenTK")) {
token = next();
} else {
error("RPAREN expected in expression");
}
break;
}
case "notTK": {
token = next();
term();
break;
}
default: {
lvalue();
break;
}
}
}

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

//-------------------------------------------------------------------
// constant = NUMERIC
// | STRING
// | TRUE
// | FALSE
// | MINUS NUMERIC
//-------------------------------------------------------------------
public static void constant() {
switch (token.type.name()) {
case "numericTK": {
token = next();
break;
}
case "stringConstTK": {
token = next();
break;
}
case "trueTK": {
token = next();
break;
}
case "falseTK": {
token = next();
break;
}
case "minusTK": {
token = next();
if (token.type.name().equals("numericTK")) {
token = next();
} else {
error("NUMERIC constant expected");
}
break;
}
default: {
error("Invalid constant");
break;
}
}
}

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

//-------------------------------------------------------------------
// relationOperator = EQUAL
// | NOT_EQUAL
// | LT
// | GT
// | LTE
// | GTE
//-------------------------------------------------------------------
public static void relationOperator() {
switch (token.type.name()) {
case "equalTK": {
token = next();
break;
}
case "notEqualTK": {
token = next();
break;
}
case "ltTK": {
token = next();
break;
}
case "gtTK": {
token = next();
break;
}
case "lteTK": {
token = next();
break;
}
case "gteTK": {
token = next();
break;
}
default: {
error("Invalid relational operator");
break;
}
}
}

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

//-------------------------------------------------------------------
// addingOperator = PLUS
// | MINUS
// | CONCAT
//-------------------------------------------------------------------
public static void addingOperator() {
switch (token.type.name()) {
case "plusTK": {
token = next();
break;
}
case "minusTK": {
token = next();
break;
}
case "concatTK": {
token = next();
break;
}
default: {
error("Invalid additive operator");
break;
}
}
}

//-------------------------------------------------------------------
// multiplyOperator = TIMES
// | DIVISION
// | MODULO
//-------------------------------------------------------------------
public static void multiplyOperator() {
switch (token.type.name()) {
case "timesTK": {
token = next();
break;
}
case "divisionTK": {
token = next();
break;
}
case "moduloTK": {
token = next();
break;
}
default: {
error("Invalid additive operator");
break;
}
}
}

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

Ερώτημα Γ – Ανάλυση Κώδικα

Προσθέστε επιπλέον κώδικα στον ΣΑ, ώστε στο τέλος της συντακτικής ανάλυσης να εμφανίζονται στην
οθόνη οι εξής πληροφορίες για το πρόγραμμα που αναλύθηκε:
1. Ο αριθμός των μεταβλητών που έχουν δηλωθεί.
2. Ο αριθμός των μεταβλητών για κάθε τύπο δεδομένων (INTEGER, STRING, BOOLEAN).
3. Ποιες μεταβλητές (αν υπάρχουν) έχουν χρησιμοποιηθεί στο πρόγραμμα και σε ποια γραμμή
του, χωρίς όμως να έχουν δηλωθεί στο τμήμα δηλώσεων του προγράμματος.
4. Ο αριθμός των εντολών (statements) που έχουν ορισθεί.
5. Ο αριθμός των εντολών ανά κατηγορία, για τις παρακάτω κατηγορίες:
- ASSIGNMENT
- BEGIN-END
- EXIT
- IF-THEN
- IF-THEN-ELSE
- READ
- WHILE-DO
- WRITE
6. Ο αριθμός των εκφράσεων που έχουν ορισθεί.
7. Ο αριθμός των εκφράσεων ανά κατηγορία, για τις παρακάτω κατηγορίες:
- ADDITIVE
- CONSTANT
- LOGICAL
- MULTIPLICATIVE
- RELATIONAL
Υποδείξεις:
- Μπορείτε να ορίσετε έναν απλό πίνακα συμβόλων για να αποθηκεύσετε πληροφορία
σχετική με τις μεταβλητές του προγράμματος και τον τύπο τους.
- Μπορείτε να τροποποιήσετε μεθόδους που υλοποιούν κανόνες της γραμματικής ώστε
να επιστρέφουν πληροφορία στις καλούσες μεθόδους ή να δέχονται ορίσματα κατά
την κλήση τους, για τις ανάγκες της ανάλυσης του κώδικα.

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

- Μπορείτε να ορίσετε μια ξεχωριστή κλάση Statistics στην οποία θα χειριστείτε την
συλλογή και επεξεργασία της πληροφορίας που ζητείται.
- Για τα στατιστικά των εκφράσεων ζητείται το πλήθος ανά είδος έκφρασης και όχι ανά
τύπο δεδομένων μιας έκφρασης

Μαθησιακά Αποτελέσματα
Στην άσκηση 1.Γ. θα σας δοθεί η δυνατότητα να κατανοήσετε:
 το πώς μπορούμε να αναλύσουμε πηγαίο κώδικα
 πως μπορούμε να εντοπίσουμε σφάλματα πέρα από αυτά που εντοπίζονται μέσα από τη γραμματική
της γλώσσας.
 στοιχεία από τη διαχείριση των μεταβλητών που γίνεται από έναν μεταγλωττιστή
 πως θα ελέγξουμε αν ο πηγαίος κώδικας ικανοποιεί κάποιες δεδομένες απαιτήσεις

Απάντηση

1) Να δώσετε τον κώδικα που απαιτείται ώστε να υλοποιηθούν οι παραπάνω απαιτήσεις. Να


παραθέσετε ολόκληρο τον κώδικα του συντακτικού αναλυτή (όχι του λεκτικού), όπως προέκυψε
με τις προσθήκες που κάνατε. Οι προσθήκες οι οποίες απαντούν στα παραπάνω ερωτήματα να
σημειωθούν με πράσινο χρώμα.
2) Εάν δεν έχετε δώσει απάντηση στο ερώτημα αυτό, γράψτε με κεφαλαία γράμματα: ΔΕΝ
ΑΠΑΝΤΗΘΗΚΕ.
3) Εάν εν γνώση σας δίνετε ελλιπή απάντηση, γράψτε με κεφαλαία γράμματα: ΕΛΛΙΠΗΣ ΑΠΑΝΤΗΣΗ.
Εξηγήστε σε ποιο σημείο θεωρείτε την απάντησή σας ελλιπή και γιατί.

Η λύση που δίνεται για να καλυφθούν οι απαιτήσεις του ερωτήματος βασίζεται στα ακόλουθα βασικά
στοιχεία:

 Διαχείριση μεταβλητών και τύπων δεδομένων: Χρησιμοποιείται ένας πίνακας συμβόλων (sym-
bolTable ως δομή τύπου HashMap), όπου κάθε μεταβλητή καταχωρείται με τον αντίστοιχο τύπο
δεδομένων της. Αυτό επιτρέπει την εύκολη πρόσβαση και επεξεργασία των τύπων δεδομένων κατά
τη διάρκεια της ανάλυσης και την εκτύπωση των στατιστικών.
 Συλλογή στατιστικών στοιχείων: Η κλάση ProgramStatistics αποθηκεύει τα στατιστικά
στοιχεία όπως το πλήθος των μεταβλητών ανά τύπο, το πλήθος των εντολών και των εκφράσεων
ανά κατηγορία, καθώς και άλλες πληροφορίες όπως οι μεταβλητές που χρησιμοποιήθηκαν χωρίς
να έχουν δηλωθεί.
 Χειρισμός μη δηλωμένων μεταβλητών: Προστίθεται λειτουργικότητα (μέθοδος
checkVariableUsage(String variable, int line)) για τον εντοπισμό και καταγραφή μη
δηλωμένων μεταβλητών που χρησιμοποιούνται στο πρόγραμμα, με αναφορά στη γραμμή όπου
χρησιμοποιήθηκαν.

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

 Ολοκλήρωση της ProgramStatistics με τον ΣΑ: Η κλάση Parser_ex4 συνεργάζεται με την


κλάση ProgramStatistics για να παρέχει λεπτομερή ανάλυση και παρακολούθηση των δομών
του κώδικα κατά την συντακτική ανάλυση.
 Εκτύπωση στατιστικών: Η διαδικασία εκτύπωσης των στατιστικών στοιχείων στο τέλος της
ανάλυσης του κώδικα μέσω της μεθόδου displayStatistics(Map<String, String> sym-
bolTable) στην κλάση ProgramStatistics.

Ειδικότερα, η ενημέρωση του πίνακα συμβόλων ακολουθεί την οδηγία της εκφώνησης για
τροποποίηση μεθόδων του ΣΑ που υλοποιούν κανόνες της γραμματικής ώστε να επιστρέφουν
πληροφορία στις καλούσες μεθόδους ή να δέχονται ορίσματα κατά την κλήση τους, για τις ανάγκες της
ανάλυσης του κώδικα. Οι μέθοδοι που εμπλέκονται είναι οι εξής:

public static void decl()

Η μέθοδος decl() χρησιμοποιεί τις μεθόδους idList() και type() για να λάβει τη λίστα των
μεταβλητών και τον τύπο τους αντίστοιχα. Στη συνέχεια, αναθέτει τον παραληφθέντα τύπο σε κάθε
μεταβλητή από τη λίστα και ενημερώνει το symbolTable κατάλληλα.

public static List<String> idList()

Η μέθοδος idList() διαβάζει και συλλέγει έναν κατάλογο αναγνωριστικών (ids). Αυτό γίνεται
επαναληπτικά μέχρι να μην βρεθούν άλλα ID που διαχωρίζονται με κόμμα. Η μέθοδος επιστρέφει μια
λίστα από συμβολοσειρές, που αντιστοιχούν στα αναγνωριστικά των μεταβλητών που έχουν διαβαστεί.

public static String type()

Η μέθοδος type() καθορίζει τον τύπο μιας μεταβλητής. Αναγνωρίζει αν η δήλωση αφορά απλό τύπο
(με τη βοήθεια της basicType()) ή πίνακα (με τη βοήθεια της arrayType()). Επιστρέφει μια
συμβολοσειρά που περιγράφει τον τύπο της μεταβλητής.

public static String basicType()

Η μέθοδος basicType() επιστρέφει τον τύπο δεδομένων αν αναφέρεται σε βασικό τύπο: INTEGER,
BOOLEAN, STRING.

public static String arrayType()

Η μέθοδος arrayType() επιστρέφει μια συμβολοσειρά που περιγράφει τον τύπο ενός πίνακα,
μορφοποιημένη ως "ARRAY OF" ακολουθούμενο από τον βασικό τύπο των στοιχείων του πίνακα.

/**

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

* This class collects and displays statistics about SPL program structures
such as
* variables, statements, and expressions.
*/

public class ProgramStatistics {


private Map<String, Integer> variablesByType = new HashMap<>();
private Set<String> undeclaredVariablesUsed = new HashSet<>();
private Map<String, Integer> statementsByType = new HashMap<>();
private Map<String, Integer> expressionsByType = new HashMap<>();

/**
* Updates the set of undeclared variables that have been used, noting the
line number.
* @param variable the variable name used
* @param line the line number where the variable is used
*/

public void updateUndeclaredVariableUsage(String variable, int line) {


undeclaredVariablesUsed.add(variable + " at line " + line);
}

/**
* Increments the count of statements of a specific type.
* @param type the type of the statement (e.g., IF-THEN, WHILE-DO)
*/

public void incrementStatementDefined(String type) {


statementsByType.put(type, statementsByType.getOrDefault(type, 0) +
1);
}

/**
* Increments the count of expressions of a specific type.
* @param type the type of the expression (e.g., ADDITIVE, LOGICAL)
*/

public void incrementExprDefined(String type) {


expressionsByType.put(type, expressionsByType.getOrDefault(type, 0) +
1);
}

/**
* Calculates the total number of statements defined in the program.
* @return the total number of statements
*/

public int calculateTotalStatements() {


int total = 0;
for (Integer count : statementsByType.values()) {
total += count;
}
return total;

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

/**
* Calculates the total number of expressions defined in the program.
* @return the total number of expressions
*/

public int calculateTotalExpressions() {


int total = 0;
for (Integer count : expressionsByType.values()) {
total += count;
}
return total;
}

/**
* Displays the collected statistics about the analyzed program, including
details of
* variables, statements, and expressions.
*
* @param symbolTable the symbol table containing variables and their
types
*/

public void displayStatistics(Map<String, String> symbolTable) {


if (symbolTable != null) {
for (String var : symbolTable.keySet()) {
String type = symbolTable.get(var);
variablesByType.put(type, variablesByType.getOrDefault(type,
0) + 1);
}
}
System.out.println("Program Statistics:");
System.out.println("Total Variables Declared: " + (symbolTable != null
? symbolTable.size() : 0));
System.out.println("Variables by Type: " + variablesByType);
System.out.println("Undeclared Variables Used: " + undeclaredVariable-
sUsed);
System.out.println("Total Statements Defined: " + calculateTotalState-
ments());
System.out.println("Statements by Type: " + statementsByType);
System.out.println("Total Expressions Defined: " + calculateTotalEx-
pressions());
System.out.println("Expressions by Type: " + expressionsByType);
}

----------------------------------------------------------------------------------------------------------------------------------------------

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

/*
* This class implements the recursive descent parser for the SPL grammar,
* systematically analyzing the syntax structure of SPL programs.
* It integrates with the ProgramStatistics class to track and quantify vari-
ous
* aspects of the code being analyzed. This includes counting the types and
instances
* of variables, categorizing statements and expressions, and identifying un-
declared
* variables used within the code. This parser not only parses the SPL code
but also
* provides detailed analysis and insights into the code's structure for edu-
cational purposes.
*/

public class Parser_ex4 {

static ArrayList<Token> tokens;


static Token token;
static ProgramStatistics stats = new ProgramStatistics();
// Global symbol table, key is the variable name and the value is its data
type
static Map<String, String> symbolTable = new HashMap<>();

private static Token next() {


token = tokens.remove(0);
//System.out.format("%s %s %d\n",token.data,token.type,token.line);
return token;
}

public static void error(String s) {


System.out.format("error in line %d: %s\n", token.line, s);
System.exit(0);
}

//-------------------------------------------------------------------
// program = PROGRAM ID declarations BODY statement EOF
//-------------------------------------------------------------------
public static void program() {
if (token.type.name().equals("programTK")) {
token = next();
if (token.type.name().equals("identifierTK")) {
token = next();
declarations();
if (token.type.name().equals("bodyTK")) {
token = next();
statement();
if (token.type.name().equals("eofTK")) {
System.out.println("syntactically correct program");
} else {
error("EOF expected at the end of the program");
}
} else {

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

error("BODY keyword expected");


}
} else {
error("name of program expected after PROGRAM keyword");
}
} else {
error("programs start with keyword PROGRAM");
}
}

//-------------------------------------------------------------------
// declarations = VAR decl (SEMICOLON decl)* | ε
//-------------------------------------------------------------------
public static void declarations() {
if (token.type.name().equals("varTK")) {
token = next();
decl();
while (token.type.name().equals("semicolonTK")) {
token = next();
decl();
}
}
}

//-------------------------------------------------------------------
// decl = idList COLON type
//-------------------------------------------------------------------
public static void decl() {
List<String> ids = idList();
if (token.type.name().equals("colonTK")) {
token = next();
String type = type();
for (String id : ids) {
symbolTable.put(id, type);
}
} else {
error("COLON seperator expected in variable type declaration");
}
}

//-------------------------------------------------------------------
// idList = ID (COMMA ID)*
//-------------------------------------------------------------------
public static List<String> idList() {
List<String> ids = new ArrayList<>();
if (token.type.name().equals("identifierTK")) {
ids.add(token.data);
token = next();
while (token.type.name().equals("commaTK")) {
token = next();
if (token.type.name().equals("identifierTK")) {
ids.add(token.data);
token = next();

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

} else {
error("name of variable expected after COMMA separator");
}
}
} else {
error("name of variable expected");
}
return ids;
}

//-------------------------------------------------------------------
// type = basicType | arrayType
//-------------------------------------------------------------------
public static String type() {
if (token.type.name().equals("arrayTK")) {
return arrayType();
} else {
return basicType();
}
}

//-------------------------------------------------------------------
// basicType = INTEGER | BOOLEAN |STRING
//-------------------------------------------------------------------
public static String basicType() {
switch (token.type.name()) {
case "integerTK": {
token = next();
return "INTEGER";
}
case "booleanTK": {
token = next();
return "BOOLEAN";
}
case "stringTK": {
token = next();
return "STRING";
}
default: {
error("Unknown data type");
return "UNKNOWN";
}
}
}

//-------------------------------------------------------------------
// arrayType = ARRAY LBRACK NUMERIC RBRACK OF basicType
//-------------------------------------------------------------------
public static String arrayType() {
if (token.type.name().equals("arrayTK")) {
token = next();
if (token.type.name().equals("lbrackTK")) {
token = next();

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

if (token.type.name().equals("numericTK")) {
token = next();
if (token.type.name().equals("rbrackTK")) {
token = next();
if (token.type.name().equals("ofTK")) {
token = next();
return "ARRAY OF " + basicType();
} else {
error("OF keyword expected in array variable dec-
laration");
}
} else {
error("RBRACK expected in array variable declara-
tion");
}
} else {
error("Numeric constant expected in array variable decla-
ration");
}
} else {
error("LBRACK expected in array variable declaration");
}
} else {
error("ARRAY keyword expected in array variable declaration");
}
return "UNKNOWN";
}

//-------------------------------------------------------------------
// statement = BEGIN block END
// | lvalue ASSIGN expr
// | READ LPAREN idList RPAREN
// | WRITE LPAREN exprList RPAREN
// | IF expr THEN statement (ELSE statement)?
// | WHILE expr DO statement
// | EXIT
//-------------------------------------------------------------------
public static void statement() {
switch (token.type.name()) {
case "beginTK": {
stats.incrementStatementDefined("BEGIN-END");
token = next();
block();
if (token.type.name().equals("endTK")) {
token = next();
} else {
error("END keyword expected to mark a block of state-
ments");
}
break;
}
case "readTK": {
stats.incrementStatementDefined("READ");

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

token = next();
if (token.type.name().equals("lparenTK")) {
token = next();
idList();
if (token.type.name().equals("rparenTK")) {
token = next();
} else {
error("RPAREN expected in READ statement");
}
} else {
error("LPAREN expected in READ statement");
}
break;
}
case "writeTK": {
stats.incrementStatementDefined("WRITE");
token = next();
if (token.type.name().equals("lparenTK")) {
token = next();
exprList();
if (token.type.name().equals("rparenTK")) {
token = next();
} else {
error("RPAREN expected in WRITE statement");
}
} else {
error("LPAREN expected in WRITE statement");
}
break;
}
case "ifTK": {
token = next();
expr();
if (token.type.name().equals("thenTK")) {
token = next();
statement();
if (token.type.name().equals("elseTK")) {
stats.incrementStatementDefined("IF-THEN-ELSE");
token = next();
statement();
} else {
stats.incrementStatementDefined("IF-THEN");
}
} else {
error("THEN keyword expected in IF statement");
}
break;
}
case "whileTK": {
stats.incrementStatementDefined("WHILE-DO");
token = next();
expr();
if (token.type.name().equals("doTK")) {

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

token = next();
statement();
} else {
error("DO keyword expected in WHILE statement");
}
break;
}
case "exitTK": {
stats.incrementStatementDefined("EXIT");
token = next();
break;
}
default: {
lvalue();
if (token.type.name().equals("assignTK")) {
stats.incrementStatementDefined("ASSIGNMENT");
token = next();
expr();
} else {
error("ASSIGN operator expected in assignment statement");
}
break;
}
}
}

//-------------------------------------------------------------------
// block = statement (SEMICOLON statement)* | ε
//-------------------------------------------------------------------
public static void block() {
switch (token.type.name()) {
case "beginTK":
case "readTK":
case "writeTK":
case "ifTK":
case "whileTK":
case "exitTK":
case "identifierTK": {
statement();
while (token.type.name().equals("semicolonTK")) {
token = next();
statement();
}
break;
}
default: {
break; // ε
}
}
}

//-------------------------------------------------------------------

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

// lvalue = ID args
//-------------------------------------------------------------------
public static void lvalue() {
if (token.type.name().equals("identifierTK")) {
checkVariableUsage(token.data, token.line);
token = next();
args();
} else {
error("variable name expected");
}
}

//-------------------------------------------------------------------
// args = LBRACK index RBRACK | ε
//-------------------------------------------------------------------
public static void args() {
if (token.type.name().equals("lbrackTK")) {
token = next();
index();
if (token.type.name().equals("rbrackTK")) {
token = next();
} else {
error("RBRACK expected in array variable reference");
}
}
}

//-------------------------------------------------------------------
// index = ID | NUMERIC
//-------------------------------------------------------------------
public static void index() {
switch (token.type.name()) {
case "identifierTK": {
checkVariableUsage(token.data, token.line);
token = next();
break;
}
case "numericTK": {
token = next();
break;
}
default: {
error("Unknown index");
break;
}
}
}

//-------------------------------------------------------------------

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

// exprList = expr (COMMA expr)*


//-------------------------------------------------------------------
public static void exprList() {
expr();
while (token.type.name().equals("commaTK")) {
token = next();
expr();
}
}

//-------------------------------------------------------------------
// expr = logicAND (OR logicAND)*
//-------------------------------------------------------------------
public static void expr() {
logicAND();
while (token.type.name().equals("orTK")) {
stats.incrementExprDefined("LOGICAL");
token = next();
logicAND();
}
}

//-------------------------------------------------------------------
// logicAND = relationExpr (AND relationExpr)*
//-------------------------------------------------------------------
public static void logicAND() {
relationExpr();
while (token.type.name().equals("andTK")) {
stats.incrementExprDefined("LOGICAL");
token = next();
relationExpr();
}
}

//-------------------------------------------------------------------
// relationExpr = additiveExpr (relationOperator additiveExpr)*
//-------------------------------------------------------------------
public static void relationExpr() {
additiveExpr();
while (token.type.name().equals("equalTK")
|| token.type.name().equals("notEqualTK")
|| token.type.name().equals("ltTK")
|| token.type.name().equals("gtTK")
|| token.type.name().equals("lteTK")
|| token.type.name().equals("gteTK")) {
relationOperator();
additiveExpr();
}
}

//-------------------------------------------------------------------

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

// additiveExpr = factor (addingOperator factor)*


//-------------------------------------------------------------------
public static void additiveExpr() {
factor();
while (token.type.name().equals("plusTK")
|| token.type.name().equals("minusTK")
|| token.type.name().equals("concatTK")) {
addingOperator();
factor();
}
}

//-------------------------------------------------------------------
// factor = term (multiplyOperator term)*
//-------------------------------------------------------------------
public static void factor() {
term();
while (token.type.name().equals("timesTK")
|| token.type.name().equals("divisionTK")
|| token.type.name().equals("moduloTK")) {
multiplyOperator();
term();
}
}

//-------------------------------------------------------------------
// term = lvalue
// | constant
// | LPAREN expr RPAREN
// | NOT term
//-------------------------------------------------------------------
public static void term() {
switch (token.type.name()) {
case "numericTK":
case "stringConstTK":
case "trueTK":
case "falseTK":
case "minusTK": {
constant();
break;
}
case "lparenTK": {
token = next();
expr();
if (token.type.name().equals("rparenTK")) {
token = next();
} else {
error("RPAREN expected in expression");
}
break;
}
case "notTK": {
stats.incrementExprDefined("LOGICAL");

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

token = next();
term();
break;
}
default: {
lvalue();
break;
}
}
}

//-------------------------------------------------------------------
// constant = NUMERIC
// | STRING
// | TRUE
// | FALSE
// | MINUS NUMERIC
//-------------------------------------------------------------------
public static void constant() {
switch (token.type.name()) {
case "numericTK": {
stats.incrementExprDefined("CONSTANT");
token = next();
break;
}
case "stringConstTK": {
stats.incrementExprDefined("CONSTANT");
token = next();
break;
}
case "trueTK": {
stats.incrementExprDefined("CONSTANT");
token = next();
break;
}
case "falseTK": {
stats.incrementExprDefined("CONSTANT");
token = next();
break;
}
case "minusTK": {
stats.incrementExprDefined("CONSTANT");
token = next();
if (token.type.name().equals("numericTK")) {
token = next();
} else {
error("NUMERIC constant expected");
}
break;
}
default: {
error("Invalid constant");
break;

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

}
}
}

//-------------------------------------------------------------------
// relationOperator = EQUAL
// | NOT_EQUAL
// | LT
// | GT
// | LTE
// | GTE
//-------------------------------------------------------------------
public static void relationOperator() {
switch (token.type.name()) {
case "equalTK": {
stats.incrementExprDefined("RELATIONAL");
token = next();
break;
}
case "notEqualTK": {
stats.incrementExprDefined("RELATIONAL");
token = next();
break;
}
case "ltTK": {
stats.incrementExprDefined("RELATIONAL");
token = next();
break;
}
case "gtTK": {
stats.incrementExprDefined("RELATIONAL");
token = next();
break;
}
case "lteTK": {
stats.incrementExprDefined("RELATIONAL");
token = next();
break;
}
case "gteTK": {
stats.incrementExprDefined("RELATIONAL");
token = next();
break;
}
default: {
error("Invalid relational operator");
break;
}
}
}

//-------------------------------------------------------------------

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

// addingOperator = PLUS
// | MINUS
// | CONCAT
//-------------------------------------------------------------------
public static void addingOperator() {
switch (token.type.name()) {
case "plusTK": {
stats.incrementExprDefined("ADDITIVE");
token = next();
break;
}
case "minusTK": {
stats.incrementExprDefined("ADDITIVE");
token = next();
break;
}
case "concatTK": {
stats.incrementExprDefined("ADDITIVE");
token = next();
break;
}
default: {
error("Invalid additive operator");
break;
}
}
}

//-------------------------------------------------------------------
// multiplyOperator = TIMES
// | DIVISION
// | MODULO
//-------------------------------------------------------------------
public static void multiplyOperator() {
switch (token.type.name()) {
case "timesTK": {
stats.incrementExprDefined("MULTIPLICATIVE");
token = next();
break;
}
case "divisionTK": {
stats.incrementExprDefined("MULTIPLICATIVE");
token = next();
break;
}
case "moduloTK": {
stats.incrementExprDefined("MULTIPLICATIVE");
token = next();
break;
}
default: {
error("Invalid additive operator");
break;

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

}
}
}

public static void checkVariableUsage(String variable, int line) {


if (symbolTable != null && !symbolTable.containsKey(variable)) {
stats.updateUndeclaredVariableUsage(variable, line);
}
}

public static void main(String args[]) {

// path to the input file


Lex lex = new Lex("./test/sample5.spl");
tokens = lex.getTokens();

token = next();
program();
stats.displayStatistics(symbolTable);
}
}

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

Ερώτημα Δ – Έλεγχος Ορθής Λειτουργίας

Να ελέγξετε την ορθή λειτουργία του τελικού μεταγλωττιστή με τα προγράμματα που σας δόθηκαν.
Μια ενδεικτική έξοδος του μεταγλωττιστή για το PROGRAM Sample5 είναι η παρακάτω:

Syntactically correct program


Program Statistics:
Total Variables Declared: 7
Variables by Type: {INTEGER=7}
Undeclared Variables Used: [b at line 10, b at line 9, n at line 35, n at line 37, n
at line 39, s1 at line 11, a at line 39, s2 at line 11, n at line 40]
Total Statements Defined: 32
Statements by Type: {READ=2, WHILE-DO=2, BEGIN-END=7, IF-THEN=1, ASSIGNMENT=9, IF-
THEN-ELSE=2, EXIT=2, WRITE=7}
Total Expressions Defined: 24
Expressions by Type: {RELATIONAL=6, MULTIPLICATIVE=2, ADDITIVE=4, CONSTANT=11,
LOGICAL=1}

Απάντηση

Να ελέγξετε την ορθή λειτουργία της ανάλυσης κώδικα χρησιμοποιώντας τα προγράμματα που σας
δόθηκαν.
Τα πέντε αυτά προγράμματα βρίσκονται στο φάκελο test του project
Παραδώστε τον κώδικα και screenshots των αποτελεσμάτων.
Εάν δεν έχετε δώσει απάντηση, γράψτε με κεφαλαία γράμματα: ΔΕΝ ΑΠΑΝΤΗΘΗΚΕ.
Εάν εν γνώση σας δίνετε ελλιπή απάντηση, γράψτε με κεφαλαία γράμματα: ΕΛΛΙΠΗΣ ΑΠΑΝΤΗΣΗ.
Εξηγείστε σε ποιο σημείο θεωρείτε την απάντησή σας ελλιπή και γιατί.

sample1.spl
syntactically correct program

Program Statistics:

Total Variables Declared: 0

Variables by Type: {}

Undeclared Variables Used: []

Total Statements Defined: 1

Statements by Type: {WRITE=1}

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

Total Expressions Defined: 1

Expressions by Type: {CONSTANT=1}

sample2.spl
syntactically correct program

Program Statistics:

Total Variables Declared: 6

Variables by Type: {STRING=2, ARRAY OF INTEGER=1, BOOLEAN=1, INTEGER=2}

Undeclared Variables Used: []

Total Statements Defined: 9

Statements by Type: {BEGIN-END=1, ASSIGNMENT=8}

Total Expressions Defined: 10

Expressions by Type: {ADDITIVE=3, CONSTANT=7}

sample3.spl
syntactically correct program

Program Statistics:

Total Variables Declared: 3

Variables by Type: {INTEGER=3}

Undeclared Variables Used: []

Total Statements Defined: 10

Statements by Type: {WHILE-DO=2, BEGIN-END=2, IF-THEN=1, ASSIGNMENT=4, WRITE=1}

Total Expressions Defined: 12

Expressions by Type: {RELATIONAL=2, MULTIPLICATIVE=1, ADDITIVE=2, CONSTANT=7}

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

sample4.spl
syntactically correct program

Program Statistics:

Total Variables Declared: 2

Variables by Type: {INTEGER=2}

Undeclared Variables Used: []

Total Statements Defined: 8

Statements by Type: {READ=1, WHILE-DO=1, BEGIN-END=2, ASSIGNMENT=3, WRITE=1}

Total Expressions Defined: 6

Expressions by Type: {RELATIONAL=1, MULTIPLICATIVE=1, ADDITIVE=1, CONSTANT=3}

sample5.spl
syntactically correct program

Program Statistics:

Total Variables Declared: 7

Variables by Type: {INTEGER=7}

Undeclared Variables Used: [b at line 10, b at line 9, n at line 35, n at line 37, n at line 39, s1 at line 11, a at line 39,
s2 at line 11, n at line 40]

Total Statements Defined: 32

Statements by Type: {READ=2, WHILE-DO=2, BEGIN-END=7, IF-THEN=1, ASSIGNMENT=9, IF-THEN-ELSE=2, EXIT=2,


WRITE=7}

Total Expressions Defined: 24

Expressions by Type: {RELATIONAL=6, MULTIPLICATIVE=2, ADDITIVE=4, CONSTANT=11, LOGICAL=1}

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

Άσκηση 2 – Μετασχηματισμός Γραμματικής για top-down ανίχνευση με πρόβλεψη


Έστω η ακόλουθη γραμματική χωρίς συμφραζόμενα με αρχικό σύμβολο το S. Μη-τερματικά σύμβολα
είναι τα S, A, B, C και τερματικά σύμβολα τα k, p, q, r, t, u, w, x, y, z, [, ].

(1) S  S x A

(2) | A

(3) Α  B y z

(4) | w A

(5) | w A t A

(6) | r z q A

(7) | p

(8) Β  u

(9) | u [ C ]

(10) C  k B

Να μετασχηματίσετε την γραμματική ώστε να είναι κατάλληλη για top-down ανίχνευση με πρόβλεψη.
Να εξηγήσετε τους μετασχηματισμούς και να κάνετε τις κατάλληλες αντικαταστάσεις ώστε να προκύψει
ως τελική γραμματική αυτή με τους λιγότερους κανόνες.

Μαθησιακά Αποτελέσματα
Στην άσκηση 3. θα σας δοθεί η δυνατότητα να κατανοήσετε:
 τις γραμματικές που χρησιμοποιούμε για την υλοποίηση συντακτικών αναλυτών αναδρομικής κατάβασης
 τον τρόπο που μετασχηματίζουμε γραμματικές ώστε να είναι κατάλληλες για αναδρομική κατάβαση

Απάντηση

Εάν δεν έχετε δώσει απάντηση, γράψτε με κεφαλαία γράμματα: ΔΕΝ ΑΠΑΝΤΗΘΗΚΕ.
Εάν εν γνώση σας δίνετε ελλιπή απάντηση, γράψτε με κεφαλαία γράμματα: ΕΛΛΙΠΗΣ ΑΠΑΝΤΗΣΗ. Εξηγείστε σε
ποιο σημείο θεωρείτε την απάντησή σας ελλιπή και γιατί.
Για να είναι κατάλληλη η γραμματική για recursive-descent ανίχνευση θα πρέπει να εξαλείψουμε την
αριστερή αναδρομή στον κανόνα S και τις παραγωγές που έχουν κοινά προθέματα, όπως συμβαίνει με

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

τα εναλλακτικά μέρη του κανόνα A (σε ότι αφορά το πρόθεμα w A) και του κανόνα B (σε ότι αφορά το
πρόθεμα u).
Η νέα γραμματική διαμορφώνεται ως εξής:

(1) S  A S’

(2) S’  x A S’

(3) | 

(4) A  B y z

(5) | w A A’

(6) | r z q A

(7) | p

(8) A’  t A

(9) | 

(10) B  u B’

(11) B’  [ C ]

(12) | 

(13) C  k B

O κανόνας (13) μπορεί να απαλειφθεί αντικαθιστώντας το σύμβολο C στον κανόνα (11). Η τελική
γραμματική είναι:

(1) S  A S’

(2) S’  x A S’

(3) | 

(4) A  B y z

(5) | w A A’

(6) | r z q A

(7) | p

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας


ΘΕΜΑΤΙΚΗ ΕΝΟΤΗΤΑ ΠΛΗ24 «ΣΧΕΔΙΑΣΜΟΣ ΛΟΓΙΣΜΙΚΟΥ»
ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ: 2023-2024

(8) A’  t A

(9) | 

(10) B  u B’

(11) B’  [ k B ]

(12) | 

ΠΛΗ24 - Ενδεικτική απάντηση 4ης εργασίας

You might also like