Πέμπτη, 29 Αυγούστου 2019

Αναθεώρηση 31 Έκδοση 9.8

Μια από τις τελευταίες αναθεωρήσεις για την έκδοση 9.8. Η επόμενη έκδοση 9.9 ετοιμάζεται, αλλά θα πάρει αρκετό καιρό. Στη φάση ετοιμασία της όπου βρίσκω βελτιώσεις για την 9.8 τις βάζω και στις δυο. Η 9.9 θα τρέχει αρκετά ποιο γρήγορα, γιατί θα έχει το κώδικα φτιαγμένο σε μια δομή για εκτέλεση (ένας τύπος AST interpreter).

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

Επίσης ένα άλλο ζήτημα το οποίο ενώ το είχα δει, δεν είχα δώσει λύση, λισως το έβλεπα σαν ειδική περίπτωση. Αυτό λοιπόν έχει να κάνει με τα tuplr ή αλλιώς αυτόματους πίνακες και ειδικότερα όταν δίνονταν άμεσα δηλαδή με παρενθέσεις όπως το ("α", "β"). Μπορούμε να βάζουμε μια σειρά ειδικών συναρτήσεων με το διαχωριστικό #. Δείτε το παράδειγμα. Η τρίτη γραμμή έχει άμεσα το πίνακα και ζητάμε την τιμή από το στοιχείο 1 (το οποίο είναι το δεύτερο)

a=(1,2,3)
print a#val(1)=2
print (1,200,3)#val(1)=200

Το πρόβλημα που λύθηκε ήταν στη περίπτωση που ζητάγαμε την αλφαριθμητική τιμή με Val$() ενός στοιχείου.  Δείτε το παρακάτω που τρέχει στην 31:

print ("a","b")#val$(1)="b", ("a","b")#val$(1)>="b"
print (("a","b")#val$(1)="b"), (("a","b")#val$(1)>="b")
print (1,"b")#val$(1)="b", (1,"b")#val$(1)>="b"
print ((1,"b")#val$(1)="b"), ((1,"b")#val$(1)>="b")
print "b"=("a","b")#val$(1), "b">=("a","b")#val$(1)
print "b"=(1,"b")#val$(1), "b">=(1,"b")#val$(1)

Τα tuple ή αυτόματοι πίνακες μπορούν να έχουν ότι στοιχείο θέλουμε (ακόμα και άλλα tuple), και εδώ φαίνονται περιπτώσεις με πρώτο στοιχείο πότε με αριθμό και πότε με αλφαριθμητικό.





Η πολυπλοκότητα του ζητήματος έχει να κάνει με το ότι γίνεται άμεση μετάφραση του κώδικα, με μια ανίχνευση του τύπου της έκφρασης (ή παράστασης). Όταν κάτι ξεκινάει με παρένθεση τότε "λογικά" δεν είναι αλφαριθμητική συνάρτηση. Όμως αν ένα tuple έχει συνοδευτική συνάρτηση μια Val$() ή Τιμή#() τότε έχουμε επιστροφή αλφαριθμητικής τιμής. Αν ακολουθεί τελεστής σύγκρισης τότε η παράσταση είναι αριθμητική! Έτσι το σύστημα την εκτελεί στο μέρος του επεξεργαστή παραστάσεων για αριθμητικές παραστάσεις. Επειδή και μια έκφραση "α"<"β" είναι όντως μια αριθμητική παράσταση, το μέρος της επεξεργασίας των αριθμητικών παραστάσεων διαβάζει και αλφαριθμητικές συναρτήσεις. Πριν μπουν στη γλώσσα οι συναρτήσεις για τα tuple, αυτά γύρναγαν πάντα μια αριθμητική τιμή 0 και ένα αντικείμενο (ένα δείκτη σε αντικείμενο). Αν λοιπόν το tuple πρέπει να γυρίσει αλφαριθμητικό τότε η μετάφραση σε αριθμό πρέπει να αποτύχει για την  αριθμητική συνάρτηση, αλλά και να γίνει, γιατί μόνο σε αυτό το σημείο διαβάζουμε το touple. Το ενδιαφέρον με τον κώδικα της Μ2000 είναι ότι βασίζεται σε συναρτήσεις που "φέρουν" ένα αντικείμενο, το λεγόμενο και ως αντικείμενο εκτέλεσης. Έτσι κάνουμε τη μετάφραση του tuple και βγάζουμε το αλφαριθμητικό αποτέλεσμα και κάνουμε το μαγικό: Σώνουμε το αποτέλεσμα στο σωρό τιμών (με απλή αλλαγή δυο δεικτών, περνάμε το αλφαριθμητικό στο σωρό τιμών) και δημιουργούμε μια κατάσταση "τσόντας" ή patch στο αντίγραφο του κώδικα που εκτελείται. Η τσόντα αυτή κάνει το μεταφραστή να διαβάσει μια νέα έκφραση που τώρα έχει το αλφαριθμητικό (είναι η εντολή letter$ με το @ μπροστά για να χρησιμοποιηθεί η γνήσια letter$, η οποία σηκώνει ένα αλφαριθμητικό από το σωρό τιμών). Η τσόντα είναι μια "πατέντα" βελτίωσης γενικώς στο κώδικα του διερμηνευτή. Αρχικά ο διερμηνευτής φτιάχτηκε για να καταναλώνει κώδικα. Δηλαδή αντί να υπάρχει ένας μετρητής που να δείχνει το κώδικα ως μετρητής προγράμματος (program counter) υπάρχει το αλφαριθμητικό που "Τρώγεται" καθώς μεταφράζεται. Ορισμένες φορές ο διερμηνευτής διαβάζει κάτι και το αλλάζει και το προσθέτει στην αρχή του αλφαριθμητικού για να το εκτελέσει ξανά.(σε άλλο σημείο του). Για την βελτίωση όλων αυτών των κοψιμάτων και ενώσεων υπάρχουν δυο συστήματα. Το ένα αντιγράφει ένα κομμάτι από το κώδικα και κάνει το κόψιμο και το ράψιμο σε αυτό. Αν κατά τη μετάφραση ζητηθούν όλοι οι χαρακτήρες του αντιγράφου τότε σημαίνει ότι απέτυχε το αντίγραφο και αλλάζει το σύστημα στο βασικό (άμεσα στο μεγάλο κομμάτι). Όμως αυτό πρακτικά δεν γίνεται, εκτός αν έχουμε τεράστια ονόματα μεταβλητών). Το ράψιμο, δηλαδή η εισαγωγή αλφαριθμητικού γίνεται με χρήση του αντικειμένου εκτέλεσης όπου μπαίνει σε μια ιδιότητα (μεταβλητή του αντικειμένου) το κομμάτι που θέλουμε να ράψουμε συν ένας χαρακτήρας (αν υπάρχει) από το αλφαριθμητικό και στο αλφαριθμητικό μπαίνει στην θέση του χαρακτήρα (ή απλά από άδειο γίνεται ένας χαρακτήρας)  ο χαρακτήρας με το νούμερο 8. Στην αναζήτηση ονομάτων το 8 δηλώνει " υπάρχει τσόντα στο αντικείμενο εκτέλεσης" (τσόντα ή επίθεμα). Όλες οι βασικές συναρτήσεις του μεταφραστή φέρουν ως πρώτη παράμετρο το δείκτη στο αντικείμενο εκτέλεσης. Με τη χρήση της τσόντας και του σωρού τιμών (ο δείκτης του είναι στο αντικείμενο εκτέλεσης) κάνουμε την εκτέλεση για το tuple σε συνάρτηση που γυρνάει αριθμητικό αποτέλεσμα και "ακυρώνουμε" τη συνάρτηση (αυτή έχει επιστροφή μια boolean τιμή η οποία επικυρώνει αν μια παράμετρος που περάσαμε με αναφορά είναι έγκυρη ή όχι, δηλαδή εδώ αν έχει το αριθμητικό αποτέλεσμα ή όχι). Ενώ λοιπόν έχουμε μεταφράσει το tuple (έχουμε φτιάξει το πίνακα, και για κάθε στοιχείο έχουμε πιθανόν ξανακαλέσει την ίδια συνάρτηση( και έχουμε επίσης εφαρμόσει το #Val$()  η τιμή επειδή είναι αλφαριθμητική έχει τοποθετηθεί στη κορυφή του σωρού τιμών.και έχει περαστεί ως τσόντα η ανάγνωσή της. Οπότε στην επιστροφή ο διερμηνευτής βλέπει ότι έχει αλφαριθμητικό και το εκτελεί και κρατάει το αποτέλεσμα.  (αφού το έχει πάρει από τον σωρό τιμών). Η μετακίνηση στο σωρό τιμών έλυσε το πρόβλημα του πώς θα γυρίσει η τιμή του αλφαριθμητικού από μια συνάρτηση που με επικύρωση έπρεπε να γυρίσει αριθμό ή χωρίς να αγνοηθεί ο αριθμός. Αν δεν υπήρχε το αντικείμενο εκτέλεσης δεν θα είχαμε πώς να κάνουμε τη μεταφορά "ιδιωτικά", και θα έπρεπε να βασιστούμε σε κάποια γενική μεταβλητή. Όμως επειδή ο διερμηνευτής δύναται να εκτελεί νήματα,  το κάθε νήμα έχει το δικό του αντικείμενο εκτέλεσης, και έτσι κρατάει σε ιδιωτικό χώρο όλα αυτά τα "μικροπράγματα" για να γίνονται τα μαγικά.

Στην έκδοση 9.9 θα υπάρχει program counter, επειδή το πρόγραμμα θα γράφεται σε δομή εκτέλεσης. Εδώ θα αλλάξει ο σχεδιασμός, επειδή δεν θα υπάρχει κόψιμο και ράψιμο, επειδή ο μετρητής προγράμματος θα δείχνει πράγματα όπως αριθμούς και αλφαριθμητικά καθώς και σύμβολα έτοιμα με πεδίο χαρακτηρισμού.
Ο κώδικας και το αποτέλεσμα του Συντακτικού Αναλυτή.
Το πρώτο νούμερο λέει για τη θέση στη δομή εκτέλεσης, το δεύτερο λέει  για τη θέση στο  πηγαίο κώδικα, μετά ακολουθεί ο τύπος με νούμερο, στην εμφάνιση βγαίνει το Identifier: PRINT, αλλά στη δομή μόνο το PRINT υπάρχει. Στο δεύτερο στοιχείο της δομής έχουμε ένα ακόμα μέλος που καταγράφει μια παράκαμψη, εδώ στο στοιχείο 6 δηλαδή αμέσως μετά το τέλος της παρένθεσης. Και στο στοιχείο 19 έχουμε την παράκαμψη, στο 22 δηλαδή αμέσως μετά από το τέλος της συνάρτησης που ξεκινάει από το 19 και τερματίζει στο 22-1, ή 21.

Στην θέση 8 έχουμε αριθμό, και έχει καταχωρηθεί με το τύπο που έχουμε δώσει (εξ ορισμού είναι ο Double)

Η δομή αυτή έχει τέσσερα νούμερα και ένα τύπου Variant, όπου μπορεί να μπει δείκτης σε αλφαριθμητικό και οποιοσδήποτε αριθμητικός τύπος (decimal, currency, double, float, long, integer, boolean)  δηλαδή ότι διαχειρίζεται η Μ2000 σε σταθερές.
Στο τέλος μας λέει πόσες αριθμητικές σταθερές έχει, πόσα σταθερά αλφαριθμητικά, και πόσα αναγνωριστικά. Δείτε ότι έβγαλε μόνο δύο αναγνωριστικά, γιατί τα καταχωρεί σε ξεχωριστό πίνακα αναζήτησης με hash function μια φορά. Στα αλφαριθμητικά δεν κάνει το ίδιο, βάζει το καθένα στη δομή.

Βλέπουμε στο πίνακα ότι δεν υπάρχουν κενά (white space)

print ("a","b")#val$(1)="b", ("a","b")#val$(1)>="b"
 0 1 171 Identifier:PRINT
 1 7 21 TUPLE ( skip to 6
 2 8 15 "a"
 3 11 8 ,
 4 12 15 "b"
 5 15 19 )
 6 16 14 #
 7 17 176 Identifier:VAL$( skip to 10
 8 22 100  1 Double
 9 23 19 )
 10 24 14 =
 11 25 15 "b"
 12 28 8 ,
 13 30 21 TUPLE ( skip to 18
 14 31 15 "a"
 15 34 8 ,
 16 35 15 "b"
 17 38 19 )
 18 39 14 #
 19 40 176 Identifier:VAL$( skip to 22
 20 45 100  1 Double
 21 46 19 )
 22 47 14 >
 23 48 14 =
 24 49 15 "b"
Number Literals: 2
String Literals: 6
Identifiers: 2

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

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