Δευτέρα 1 Φεβρουαρίου 2016

Περί της 8.1 έκδοσης και πώς λειτουργεί!


Εδώ είναι  ο κώδικας της ανεπίσημης 8.1 (θα πάρει νούμερο όταν θα έχει ελεγχθεί διεξοδικά)
Αναθεώρηση 151 (έχει ανέβει η 152 και μπορεί κανείς να την πάρει από το Κώδικας Γλώσσας


Η παρούσα έκδοση, 8, είναι στην αναθεώρηση 147 και το πολύ να πάρει άλλες δύο (χλωμό το βλέπω). Έτσι θα προχωρώ την 151 μέχρι να αποφασίσω ότι ολοκληρώθηκε! Αυτή θα είναι η 8.1.

Το διαφορετικό αυτής της έκδοσης είναι ότι οι μεταβλητές, οι πίνακες και τα τμήματα αναζητούνται με πίνακα κατακερματισμού και όχι σειριακά. Δείτε όμως μια ιδιαιτερότητα: Μπορούν να υπάρχουν ίδια κλειδιά! Σε αυτή την περίπτωση διαβάζουμε το τελευταίο που μπήκε. Επιπλέον πρέπει να σβήνουμε τις Χ τελευταίες μεταβλητές, άρα να κάνουμε νέο κατακερματισμό. Αυτό χρειάζεται όταν τερματίζει κάτι που δημιουργεί προσωρινές-ιδιωτικές μεταβλητές/πίνακες/τμήματα. Αυτό πετυχαίνεται με το να κρατάμε μερικά αποτελέσματα της συνάρτησης κατακερματισμού. Η συνάρτηση έχει δυο στάδια, και το δεύτερο έχει να κάνει με το μέγεθος του πίνακα.
Η υλοποίηση γίνεται με ένα αντικείμενο hash  για μεταβλητές και πίνακες, και ένα sbhash για τα τμήματα και τις ρουτίνες. Επιλέχθηκε αυτός ο τρόπος γιατί σε κάθε αντικείμενο δίνουμε το πίνακα των καταχωρήσεων για να τις σβήνει όταν χρειάζεται. Οπότε επειδή έχουμε δυο διαφορετικούς πίνακες, θα έχουμε και δυο διαφορετικά αντικείμενα!

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

Μια μεταβλητή (ως όνομα)  στην ουσία είναι αναφορά σε μια τιμή (στον πρώτο πίνακα).  Στη Μ2000 μπορούμε να έχουμε πολλές αναφορές σε μια τιμή. Αυτό που δεν γίνεται εύκολα είναι να αλλάζουμε αναφορά σε ένα όνομα! Άρα ο πρώτος πίνακας μπορεί να έχει Ν τιμές αλλά να υπάρχουν Ν+Μ ονόματα όπου τα Μ θα είναι οι αναφορές που δείχνουν κάπου στις Ν τιμές. 
Ο πίνακας κατακερματισμού έχει για καλή λειτουργία παραπάνω τιμές από όσες οι Ν+Μ. Ουσιαστικά το αντικείμενο δίνει σε μια ιδιότητα count τον αριθμό των ονομάτων, ενώ έχει δική του μια μεταβλητή με το μέγεθος του πίνακα κατακερματισμού. Αν κάποιο όνομα πέσει πάνω σε άλλο τότε πιάνει αυτό την θέση του, και το άλλο βγαίνει από τον πίνακα. Δεν χάνεται όμως, γιατί μπαίνει σε μια λίστα που σχηματίζεται από αυτό που μπήκε και προς τα πίσω..σε αυτά που βγήκαν. Έτσι ουσιαστικά ο πίνακας κατακερματισμού ακόμα και να ήταν ένα στοιχείο θα δούλευε ως μια λίστα συνδεδεμένων "ονομάτων" (μάλλον δεικτών σε ονόματα, γιατί ο πίνακας αυτός είναι μόνο Long, δηλαδή κρατάει μόνο το νούμερο του στοιχείου, εκείνου που έχει το όνομα).


Μέσα λοιπόν στο αντικείμενο του πίνακα κατακερματισμού, υπάρχει μια δομή σε πίνακα όπου κάθε στοιχείο έχει κλειδί (όχι μόνο το όνομα, αλλά όλο το μονοπάτι, το name space, ή όνομα χώρου), θέση τιμής στον πίνακα τιμών, αν είναι αναφορά (το χρειάζεται για να ξέρει αν θα σβήσει την τιμή στην θέση τιμής ή όχι. όταν χρειαστεί), μια υπολογισμένη τιμή Hash1 (που έχει να κάνει με το κλειδί και οχι με το μέγεθος του πίνακα), και η τελευταία θέση στο πίνακα. Δηλαδή κάθε όνομα, έχει και ένα δείκτη πρός τη τελευταία θέση (μπορεί όπως είδαμε ένα όνομα να μην είναι στο πίνακα κατακερματισμού αλλά να είναι στην ουρά κάποιου άλλου, απλά και μόνο επειδή η συνάρτηση δίνει την ίδια θέση στον πίνακα). Ας λέμε το πίνακα με τα ονόματα PriveName() και τον πίνακα κατακερματισμού hash()

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

Στους πίνακες γράφονται ότι έχει διαβαστεί στο κώδικα. Δηλαδή ο κώδικας που δεν έχει εκτελεστεί μπορεί να γράψει τμήματα, συναρτήσεις, μεταβλητές. Η Μ2000 μπορεί να φορτώνει κατ' απαίτηση κώδικα. Δηλαδή μπορούμε να χρησιμοποιούμε βιβλιοθήκες, οι οποίες φορτώνονται και τερματίζουν όταν το τμήμα που τις φόρτωσε τερματίσει. Έτσι αν θέλουμε κάτι πιο μόνιμο μπορούμε να το δώσουμε σε εντολές κατά την φόρτωση του αρχικού προγράμματος, πριν από την εκτέλεση κάποιου τμήματος (για το σκοπό αυτό η εντολή συγγραφή ή σ με παράμετρο σε εισαγωγικά και κατάλξη gsb  ανοίγει για διόρθωση απ΄ευθείας από το δίσκο, και προσθέτουμε εντολές, π.χ. Πίνακας Α(100) για δημιουργία  γενικού πίνακα, που θα σβήσει μόνο στο τερματισμό ή με εντολή "καθαρό", ή άλλες όπως τη Φόρτωσε/Load και Σενάριο/Script)

Η Μ2000 στις στατικές μεταβλητές (δεν έχει πίνακες εδώ) χρησιμοποιεί άλλο τρόπο αποθήκευσης, που δεν έχει να κάνει με τους πίνακες παραπάνω, αλλά με συλλογή μεταβλητών σε ένα αντικείμενο "συλλογή" το οποίο εκτός από τιμές μαζεύει και πακέτα από άλλα τμήματα και συναρτήσεις, με "συλλογές" και άλλα πακέτα. Όταν δηλαδή επιστρέφουμε στην γραμμή εντολών το πακέτο μπορεί να πέριεχει δυο τρία άλλα, που θα περιέχουν επίσης άλλα...Όλα τα πακέτα σχετίζονται με το αντικείμενο εκτέλεσης. Αν ένα τμήμα, όπως αυτά που φτιάχνουμε με την Σ ή Συγγραφή, που είναι γενικά και μπορούν να κληθούν από παντού, έχουμε στατικές μεταβλητές τότε κάθε άλλο τμήμα που καλεί το τμήμα αυτο θα δημιουργεί δικό του πακέτο στατικών μεταβλητών. Τα αντικείμενα στις συναρτήσεις-τμήματα δεν επιτρέπουν στατικές μεταβλητές, αφού στατικές έχουν κατά ένα τρόπο τις μεταβλητές του αντικειμένου (είναι σχεδόν το ίδιο ενώ οι στατικές κρατάνε τη πληροφορία και αφού τερματίσει το τμήμα ή συνάρτηση, το ίδιο συμβαίνει με τα τμήματα/συναρτήσεις ενός αντικειμένου, όπου αλλάζουν τις τιμές του. Η διαφορά είναι ότι το αντικείμενο θα διαγραφεί όταν ο δημιουργός του τερματίσει - σώνεται αν το δώσουμε ως επιστροφή, δεν θα επεκταθώ εδώ - ενώ οι στατικές θα σβήσουν μόνο με εντολή Καθαρό / Clear από την γραμμή εισαγωγής, ή μέσα από το τμήμα)

Όταν καλούμε ένα τμήμα γίνεται το εξής: Μια φορά αναζητείται σαν να είναι τοπικό (1). Αν δεν βρεθεί αναζητείται χωρίς όνομα χώρου (2). Δείτε εδώ όμως τι συμβαίνει. Αν το τμήμα είναι μέσα σε αντικείμενο, τότε οι μεταβλητές με τελεία αναφέρονται στις μεταβλητές του αντικειμένου, διότι έχει άλλο όνομα χώρου. Αν το αντικείμενο είναι γενικό ή τοπικό, σημαίνει ότι θα έχουμε μια από τις 1 ή 2 περιπτώσεις και στο όνομα θα έχουυμε το όνομα του αντικειμένου.
Το όνομα του αντικειμένου είναι και αυτό μια μεταβλητή και τα επιμέρους στοιχεία του είναι και αυτά στο πίνακα κατακερματισμού, εκτός από την περίπτωση που το αντικείμενο είναι κλειστό, ή ανώνυμο, ή πτητικό (επειδή μπορεί να φύγει από το τμήμα ή τη συνάρτηση που βρίσκεται). Το κλειστό αντικείμενο πρέπει να ανοίξει (παίρνει εσωτερικά ένα όνομα αυτόματα) για να το χειριστούμε. Όταν ανοίγει τότε έχει θέση στους πίνακες, μεταβλητών, πινάκων και τμημάτων/συναρτήσεων!

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

Το μόνο θέμα που δεν έχει επιλυθεί ακόμα είναι να τρέχουν νήματα σε διαφορετικά ονόματα χώρου, και να θέλουμε να δημιουργήσουμε μεταβλητές. Η Μ2000 θα το κάνει. Αλλά αν τερματίσει το ένα τμήμα πριν τερματίσει το άλλο, τότε θα καθαρίσει και τις μεταβλητές που έκανε το πρώτο (μέσα από νήμα). Δεν έχω βάλει επιπλέον λογική γι΄αυτό για να μην επιβαρύνω το σύστημα (ακόμα και αν δεν θες να γίνει κάτι, χρειάζεται κάτι για να το πετύχεις). Μια άλλη προσέγγιση είναι η χρήση στατικών μεταβλητών. Αυτές οι στατικές (σε νήμα) καθαρίζουν όταν το νήμα τερματίζει. Το νήμα είναι ένα αντικείμενο εκτέλεσης που δανείζεται ένα όνομα χώρου, βλέπει τις μεταβλητές του, και τρέχει όταν το επιτρέπουν συνθήκες (που δεν θα περιγράψω εδώ).

Συνοψίζοντας: Η Μ2000 έχει το μοντέλο των αντικειμένων εκτέλεσης, που καταναλώνουν κώδικα, έχουν ένα πακέτο στατικών μεταβλητών, έχουν ένα σωρό τιμών  (ως FIFO και LIFO),  μια στοίβα επιστροφών για ρουτίνες, και παράλληλα υπάρχουν δυο μεγάλοι πίνακες κατακερματισμού, ο πίνακας τμημάτων/συναρτήσεων και ο πίνακας μεταβλητών/πινάκων.

Από κώδικα που είναι γραμμένος σε αρχείο κειμένου UTF ...φτιάχνονται μια σειρά τμημάτων/συναρτήσεων στο επίπεδο 0 (γενικό, το βλέπουν παντού). Η εκτέλεση ενός τμήματος ή συνάρτησης δημιουργεί νέο αντικείμενο εκτέλεσης. Το αρχικό αντικείμενο εκτέλεσης, είναι αυτό της γραμμής εντολών, το οποίο δεν μπορεί να φτιάξει στατικές (αλλά ακριβώς αυτό είναι ότι κάνει, δηλαδή μια Α=4 θα παραμείνει ως γενική, μια Α=5 σε ένα τμήμα θα φτιάξει τοπική ενώ η Α<=5 θα αλλάξει τιμή στη γενική. Οι πίνακες δεν θέλουν το <= γιατί δεν ορίζονται όπως οι μεταβλητές).

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

Αυτά για την ώρα!
ΓΚ

Υ.Γ.
Μέχρι να ανεβάσω την αναθεώρηση 150...να και ένα ωραίο γραφικό:

move 6000,6000
b=1 \\ 1 .. -1
every 30 {
      for n=1 to 2 step .05 {all()}
      if keypress(32) then exit
      for n=2-.05 to 1+.05 step .05 {all()}
      if keypress(32) then exit
}


sub all()
      local c=1000, c1=c*n, c2=c1/2
      refresh 5000
      cls
      for i=4000 to 1000 step 300 {
            width 3 { circle fill 8-4*b,i,800/c }
            step c2*b,c1*b : b-! : if b>0 then c-=150
      }
end sub




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

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

You can feel free to write any suggestion, or idea on the subject.