Κυριακή, 27 Σεπτεμβρίου 2015

Πρόγραμμα απόδοσης προφοράς Ιταλικών (Μ2000)

Σε αυτή την ανάρτηση θα δούμε τη Μηχανή Απόδοσης Προφοράς Ιταλικών Λέξεων. Είναι ένα παράδειγμα και όχι ό,τι καλύτερο. Έχω κάνει μερικές αλλαγές από την αρχική έκδοση που γράφτηκε πριν έντεκα χρόνια και έτρεχε σε έκδοση 5.6. Τρέχει στην έκδοση 8 αναθεώρηση 56 και πάνω.
Η αναθεώρηση 56 είναι σημερινή, και περιλαμβάνει δυο εντολές την ΣΕΝΑΡΙΟ και την ΕΝΘΕΣΗ ΚΩΔΙΚΑ (η ΕΝΘΕΣΗ υπάρχει αλλά προστέθηκε μια παραλλαγή). Η πρώτη τρέχει στο διερμηνευτή εντολών γραμμής ενώ η δεύτερη στον Εκτελεστή (δες παρακάτω). Και οι δυο κάνουν το ίδιο πράγμα, δηλαδή ζητούν ένα όνομα τμήματος και παίρνουν τον κώδικα και τον τρέχουν απευθείας, σαν να ήταν ο κώδικας γραμμένος στη θέση της εντολής. Το γιατί το ήθελα αυτό θα το δούμε στο παράδειγμα των Ιταλικών!

Επί ευκαιρία να ξεκαθαρίσω ότι η γλώσσα έχει πέντε εσωτερικούς διερμηνευτές:
1. Ο διερμηνευτής γραμμής εντολών (CLI ή command line interpreter)  και εκεί δεν υπάρχουν εντολές όπως ΓΙΑ, ΕΝΩ, ΕΠΑΝΕΛΑΒΕ, ΕΠΙΛΕΞΕ και άλλες που θέλουν πολλές γραμμές και εκτελούν άλματα μπρος ή πίσω. Ο διερμηνευτής αν δεν αναγνωρίζει μια εντολή καλεί τον εκτελεστή. Αν και λέγεται "γραμμής" μπορεί να εκτελέσει πολλές εντολές αν χωρίζονται με : ή με αλλαγή γραμμής.

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

3.Ο διερμηνευτής εντολών, εκτελεί ότι δεν γνωρίζουν τα παραπάνω. Όμως, εδώ είναι το ωραίο, εκτελεί εντολές οι οποίες καλούν πάλι τον εκτελεστή ή και τον διερμηνευτή γραμμής εντολών, αλλά όχι ως μια επικοινωνία του Β προς το Α, το οποίο το είχε καλέσει, αλλά με νέα εκκίνηση. 

και οι τρεις παραπάνω διερμηνευτές καλούν τους άλλους δύο (4ος, 5ος):
4. Ο επεξεργαστής Εκφράσεων με αριθμητικό αποτέλεσμα, που περιλαμβάνει και τις συγκρίσεις με σύμβολα και με χειριστές όπως ΚΑΙ, Η, ΑΠΟ (το ΑΠΟ είναι το XOR). Αυτός λοιπόν αναγνωρίζει τις εκφράσεις και ενδεχομένως μέχρι να βγει το αποτέλεσμα να έχουν κληθεί όλοι οι άλλοι μεταφραστές και ο ίδιος ξανά, αλλά όπως έγραψα παραπάνω όχι  κλήση του προηγούμενου αλλά κλήση κάθε φορά ενός νέου διερμηνευτή ή επεξεργαστή. Αυτός ο επεξεργαστής αναγνωρίζει τις μεταβλητές που έχουμε ορίσει, τις συναρτήσεις που υπάρχουν στη γλώσσα και αυτές που έχουμε ορίσει καθώς και μια σειρά μεταβλητών μόνο ανάγνωσης (αλλάζουν τιμές από το σύστημα, και μόνο διαβάζονται)

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

Το ότι κάθε μεταφραστής δύναται να κληθεί πολλές φορές, είναι με την έννοια ότι το Α καλεί το Β μετά το Β το Γ μετά το Γ το Α μετά το Α το Δ μετά το Δ το Γ μετά το Γ το Α και κάποια στιγμή όλα επιστρέφουν στην αρχική κλήση. Η δυνατότητα αυτή λέγεται Reentrancy γιατί αν το δούμε αλλιώς, όταν το  Α καλεί το Β δεν έχει τερματίσει, και κάπου στο βάθος των κλήσεων μια άλλη ρουτίνα ή συνάρτηση καλεί την Α κάνει την δουλειά του και  με τις επιστροφές φτάνουμε στην Α και αυτή συνεχίζει. Αυτά συμβαίνουν στο κώδικα της Μ2000 που είναι γραμμένος σε Visual Basic 6

Τα τμήματα στην Μ2000 δεν μπορούν ως έχουν να καλέσουν τον εαυτό τους (οι συναρτήσεις μπορούν). Η κλήση στον εαυτό λέγεται αναδρομή. Για να πετύχουμε το Reentrancy εκεί που δεν υπάρχει αναδρομή, πρέπει να καλέσουμε ένα τμήμα ξανά μέσω ενός άλλου τμήματος. Δείτε όμως το θέμα στο παρακάτω πρόγραμμα. Αν βγάλουμε το προσδιοριστικό "γενικό" σε κάθε τμήμα τότε έχουμε λάθος! Δηλαδή στην μπες_ξανά κάνουμε να καλέσουμε την μπες_από_εδώ  αλλά αυτή δεν υπάρχει για την μπες_ξανά  υπάρχει για την α. Αν ορίσουμε ότι αυτά τα δυο εσωτερικά τμήματα είναι γενικά τότε θα τρέξει το πρόγραμμα μέχρι το κ να γίνει μικρότερο του 0. Έτσι καταλαβαίνουμε ότι στην Visual Basic 6 οι συναρτήσεις και οι διαδικασίες (subroutines) βρίσκονται σε μια γενική οριοθέτηση, δηλαδή μεταξύ τους είναι "γνωστά", ή όπως λέμε είναι γενικού σκοπού. Όπως βλέπουμε στη Μ2000 ο σκοπός περιορίζεται σε ότι υπάρχει στο τρέχον τμήμα ή έχει ονομαστεί πρωτύτερα ως γενικό. 

Τμήμα α {
      τμήμα γενικο μπες_ξανά {
            διαβασε κ
            τύπωσε τμήμα$, κ \\τυπώνει το αναγνωριστικό του τμήματος
            αν κ>0 τότε μπες_από_εδώ κ-1
      }
      Τμήμα γενικο μπες_από_εδώ {
            διαβασε κ
            τύπωσε τμήμα$, κ
            μπες_ξανά κ-1
      }      
      μπες_ξανά 10
}
α   

Παρακάτω είναι ένα πρόγραμμα με μια ιδιαιτερότητα ως προς τον σχεδιασμό. Η Μ2000 έχει έναν πίνακα που βάζει σε κάθε θέση ένα τμήμα ή μια συνάρτηση. Για να τρέξει ένα τμήμα ή μια συνάρτηση πρέπει να βρίσκεται στον πίνακα αυτό. Όταν σε ένα τμήμα έχουμε ορισμούς άλλων τμημάτων, όταν το τρέξουμε αυτά τα τμήματα θα μετεγγραφούν στον πίνακα, θα εκτελεστούν αν τα καλέσουμε (η εκτέλεση γίνεται με αντιγραφή από τον πίνακα του κώδικα σε μια παράμετρο του εκτελεστή (δες το 2)), και στο πέρας της εκτέλεσης ότι ορίστηκε θα σβηστεί και θα μείνει η λίστα τμημάτων΄/συναρτήσεων ως είχε πριν εκτελέσουμε το τμήμα.
Όταν εκτελούμε την σ α, δηλαδή συγγραφή α, τότε αν υπάρχει το τμήμα στη λίστα μας το δίνει για διόρθωση/συμπλήρωση, αν δεν υπάρχει τότε δημιουργεί μια θέση επιπλέον και βάζει ένα κενό τμήμα με το όνομα που δίνουμε και μας ανοίγει το διορθωτή για να γράψουμε το τμήμα μας!
Θα μπορούσαμε λοιπόν να δούμε ένα πρόγραμμα ως μια συλλογή τμημάτων που καλούμε από την γραμμή εντολών. Δηλαδή εδώ αλλάζουμε την εντύπωση που ίσως είχαμε ότι ένα πρόγραμμα είναι κάτι "δεμένο" σε ένα σύνολο, αλλά μπορεί να απαρτίζεται από τμήματα χωριστά. Και εδώ στο παράδειγμα είναι σε τμήματα στην κυριολεξία. Και αντί να έχουμε ένα μενού επιλογών, γράφουμε απευθείας το τμήμα που θέλουμε με τις παραμέτρους του και παίρνουμε την απάντηση. Την ώρα που τρέχει ένα τμήμα, τα άλλα τμήματα βρίσκονται στο λεγόμενο επίπεδο μηδέν, όπου όλα είναι γενικά (να γιατί η ανάλυση της VB6 πριν). Το πρόγραμμα που θα βάλω εδώ δεν θα είναι γραμμένο σε ένα τμήμα αλλά σε ένα αρχείο με κατάληξη gsb και θα το φορτώσω στον μεταφραστή γραμμής ο οποίος θα τρέξει εντολές, θα φτιάξει τίτλους, θα χωρίσει την οθόνη, όπου το κάτω τμήμα της θα μπορεί να ολισθαίνει και θα περιμένει να δώσουμε εντολές ενώ δεν θα έχουμε βγει από την γραμμή εντολών!
Μάλιστα καθορίζει και το ctrl+F1 για να έχουμε βοήθεια, η οποία μας λέει ποιες εντολές έχουμε επιπλέον, σαν να προστέθηκαν στην γλώσσα, και ποια πλήκτρα λειτουργίας (κλειδιά) μπορούμε να χρησιμοποιήσουμε (F1 F2 F3).

Για να γράψουμε το αρχείο κάνουμε αυτό (ανοίγουμε τον διορθωτή για κείμενο στο δίσκο και όχι στη λίστα τμημάτων/συναρτήσεων)

σ "ιταλικα.gsb"
τώρα αντιγράφουμε το παρακάτω (ενημερώθηκε, γράφει έκδοση 2.1)


τμημα ΠΡΟΦΟΡΑ {
      διάβασε ΛΕΞΗ$
      αν ΛΕΞΗ$="" τότε έξοδος
      πενα 7
      τυπωσε "η λέξη: ";
      πενα χρώμα(255,128,40) {
            πλαγια
            τυπωσε ΛΕΞΗ$;
            πλάγια
      }
      τυπωσε " έχει προφορά: ";
      Ν = 1 : Μ = 1
      ΛΕΞΗ$=ΛΕΞΗ$+" "
      βαλε 0 ' σκοπός  - αν το βρούμε σημαίνει τέλος
      Ι=0
      {
            Ι++
            αν Ι> ΜΗΚΟΣ(ΛΕΞΗ$) τότε ΕΞΟΔΟΣ
            Σ=0
            ΑΣΦΑΛΕΙΑ=0
            Ν = 1
            {
                  Μ=Ν
                  επιλεξε με κεφ$(μεσ$(ΛΕΞΗ$, Ι, Ν))
                  με "A"
                        {Ν=2 :Ι++: βαλε "α"}
                  με "B"
                        βαλε "μπ"
                  με "C"
                        Ν = 2
                  με "CI","CE"
                  {
                        αν Σ=1 τότε {
                              διάβασε ΚΚΚ$
                              βαλε "σσ"
                        }αλλιώς βαλε "τσ"
                  }
                  με "CO","CA","CU", "CQ"
                        βαλε "κ"
                  με "C "
                        βαλε "τσι"
                  με "G "
                        βαλε "τζ"
                  με "SS"
                        {Ι++
                        βαλε "σ"}
                  με "GL"
                        Ν=3
                  με "GLI"
                        {βαλε "λι"
                         ι+=2
                        }
                  με "GH"
                        Ν=3
                  με "GHI", "GHE"
                        {Ι++
                         βαλε "γκχ"
                        }
                  με "CH"
                        Ν=3
                  με "CHI", "CHE"
                        {Ι++
                        βαλε "κχ"
                        }
                  με "D"
                        βαλε "ντ"
                  με "E"
                        {Ν=2:Ι++:βαλε "ε"}
                  με "F"
                        βαλε "φ"
                  με "G"
                        Ν=2
                  με "GN"
                        {Ι++
                        βαλε "νι"}
                  με "GI","GE"
                        βαλε "τζ"
                  με "GO","GA","GU"
                         βαλε "γκ"
                  με "H"
                         βαλε "" 'αηχο
                  με "I"
                         {Ν=2 :Ι++: βαλε "ι"}
                  με "L"
                         βαλε "λ"
                  με "M"
                         βαλε "μ"
                  με "N"
                         βαλε "ν"
                  με "O"
                         {Ν=2 :Ι++: βαλε "ο"}
                  με "P"
                         βαλε "π"
                  με "Q"
                         βαλε "κ"
                  με "R"
                         βαλε "ρ"
                  με "S"
                        {
                              Ι++
                              Μ=0
                              Σ=1
                              βαλε "σ"
                        }
                  με "SA","SO","SI","SU","SE"
                        βαλε "ζ"
                  με "T"
                         βαλε "τ"
                  με "U"
                        {Ν=2 :Ι++: βαλε "ου"}
                  με "V"
                        βαλε "β"
                  με "Z"
                        {
                              αν Ι=1 τότε {
                              βαλε "τζζ"
                              } αλλιώς βαλε "τσσ"
                        }
                  με "GG"
                        {Ι++
                        Ν=1}
                  με "CC"
                        {Ι++
                        Ν=1}
                  με "GB" ΕΩΣ "GZ"
                        {Ι++
                        βαλε "γκ"
                        Ν=1}
                  με "CB" ΕΩΣ "CZ"
                        {Ι++
                        βαλε "κ"
                        Ν=1}
                  με " "
                        Ν=Μ
                  αλλιώς
                  {
                        Ν=1 : Σ=0
                        ΑΣΦΑΛΕΙΑ++
                        αν ΑΣΦΑΛΕΙΑ>2 τότε Ν=Μ
                  }
                  τελος επιλογης
                  αν Ν<>Μ τότε ΚΥΚΛΙΚΑ
            }
            κυκλικα
      }
      'τωρα μαζεύουμε την λέξη
      Κ$=""
      Λ$=""
      αν εινγρ τότε { \\ η εινγρ λέει αληθλης αν είναι γράμματα (αλφαριθμητικό) στη κορυφή του σωρού
            ενω οχι ειναρ { \\ η ειναρ λέει αληθής αν είναι αριθμός στη κορυφή του σωρού
                  διάβασε Γ$ \\ διαβάζει από το σωρό
                  αν (Λ$ <> Γ$) Η ΜΗΚΟΣ(Γ$)=1 τότε {Κ$=Γ$+Κ$}
                  Λ$=Γ$
            }
            διάβασε ΣΚΟΠΟΣ
            πενα ΧΡΩΜΑ(100,200,100)
            φαρδια
            τυπωσε ΠΕΖ$(κεφ$(Κ$))
            φαρδια
      } αλλιώς {
            πενα 4
            τυπωσε "ΛΕΞΗ ?"
      }
      πενα 15
}
τμημα P { \\ p "λέξη"
      διαβασε α$
      ΠΡΟΦΟΡΑ α$
}
τμημα ΛΕΞΕΙΣ {
      για Ι=1 εως 4 {
            αλλαξε Α$(τυχαιος(0,14)), Α$(15)
            ΠΡΟΦΟΡΑ Α$(Ι)
      }
}
τμημα PA { ΠΡΟΤΑΣΗ γραμμα$ \\ pa "λέξη"
}
τμημα ΠΡΟΤΑΣΗ {
      διαβασε Π$
      Π$=αποκ$(Π$)+" "
      ενω Π$<>" " {
            Ι=θεση(Π$," ")
            Λ$=αρισ$(Π$,Ι-1)
            Π$=αποκ$(μεσ$(Π$,Ι))+" "
            αν Λ$<>"" τότε ΠΡΟΦΟΡΑ Λ$
      }
}
τμημα ΟΔΗΓΙΕΣ {
            περι ! "ΧΡΗΣΗ ΠΡΟΓΡΑΜΜΑΤΟΣ", 8000, 5000 , { p "giorgio"
                        Τυπώνει την προφορά της λέξης
                        pa "gli zii"
                        Τυπώνει την προφορά των λέξεων!
                        F1 - ΛΕΞΕΙΣ, F2 - ΚΑΘΑΡΗ οθονη, F3 - τελος
                        }
\\ βάζουμε εδώ τις σημειώσεις γιατί στα σενάρια δεν μπορούμε να τις βάλουμε
\\ θα το καλέσουμε σαν σενάριο εντολών.
\\ ένα σενάριο εντολών έχει εντολές που καταλαβαίνει η γραμμή εντολών
\\ δεν υπάρχει αλλαγή ροής προς προηγούμενη ή μεθεπόμενη γραμμή
\\ πάντα θα τρέχει η επόμενη
}
τμημα ΜΑΠΙΛ {
      οθονη 5,0
      πινακας Α$(16)
      Α$(0)="famiglia","chiamo", "casa", "gelato", "ghiaccio", "canzone", "ciao","pizza", "zio", "pesce", "rosso", "luce", "bagno", "pachetto","gonna", "anno"
      κλειδι 1,"ΛΕΞΕΙΣ"
      κλειδι 2,"ΟΘΟΝΗ"
      κλειδι 3,"τελος"
      ΟΔΗΓΙΕΣ
      πενα 13
      φαρδια
      τυπωσε "Μ.Α.Π.Ι.Λ εκδ 2.1"
      τυπωσε "ΜΗΧΑΝΗ ΑΠΟΔΟΣΗΣ ΠΡΟΦΟΡΑΣ ΙΤΑΛΙΚΩΝ ΛΕΞΕΩΝ"
      φαρδια
      τυπωσε
      οθονη ,γραμμη
      πενα 11
      τυπωσε "Παράδειγμα:"
      πενα 15
      τυπωσε "p "+Παραθεση$("giorgio")
      P "giorgio"
      τυπωσε "Ctrl+F1 για Βοήθεια"
      πενα 15
      αναψε
}
Σεναριο ΜΑΠΙΛ

Η εντολή Σεναριο τρέχει τις εντολές στο τμήμα σαν να τις γράφαμε μια προς μια. 
Ακολουθήστε τις οδηγίες
Με Ctrl+N βλέπουμε τα τμήματα/συναρτήσεις που είναι φορτωμένα.

Προσθήκη: Δεν έγραψα το "γιατί". Γιατί χρησιμοποίησα τη Σενάριο;
Ο λόγος είναι ότι ήθελα ο πίνακας που βρίσκεται μέσα στο τμήμα ΜΑΠΙΛ να μείνει μετά τη κλήση και να είναι γενικός, αφού σκοπό είχα να καλέσω το ΜΑΠΙΛ και να γυρίσω στην γραμμή εντολών. Αν δώσουμε την εντολη ΛΙΣΤΑ θα δούμε ότι υπάρχει ο πίνακας Α(). Αν ήθελα να φορτώσω το πίνακα από ένα αρχείο τότε θα καλούσα μια συνάρτηση που θα έκανε όλη τη δουλειά και θα γύρναγε το πίνακα
>_
>Σ π$(
γράφω
Πίνακας Α$(10)="οκ"
=Α$()
βγαίνω με esc και γράφω
>Πίνακας Β$()
>Β$()=π$()
>Τύπωσε Β$(1)
οκ


Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου