Παρασκευή 29 Οκτωβρίου 2021

Πώς δουλεύει ο διερμηνευτής της Μ2000 (Έκδοση 10) - Ανανέωση!

Σκοπός του διερμηνευτή της Μ2000 δεν είναι η ταχύτητα εκτέλεσης, αλλά η σωστή εκτέλεση όλων αυτών που μπορεί να κάνει η Μ2000.

Από την αρχή επιλέχθηκε ο κώδικας να είναι όσο πιο απλός γίνεται. Ασφαλώς αυτό δεν ισχύει σήμερα. Με τις προσθήκες έχει γίνει τεράστιος! Υπήρξαν στάδια που "ξεχείλωναν" το πρόγραμμα!

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

Το αντικείμενο σωρός είναι στο αρχείο mStiva.cls (το cls σημαίνει κλάση).

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

Ο σωρός αρχικά μπορούσε να πάρει αριθμούς και γράμματα. Όμως μπορεί να πάρει και αντικείμενα. Πχ μπορούμε να βάλουμε ένα πίνακα (είναι αντικείμενο στη Μ2000). Γενικά το γράψιμο στο σωρό είναι με τιμή "πάντα". Από την 5η έκδοση της γλώσσας είχε μπει ο τρόπος να περάσουμε αναφορές.

Οι μεταβλητές απαιτούν δυο δομές: Έναν πίνακα τιμών, και ένα "λεξικό" που στη Μ2000 λέγεται κατάσταση τιμών. Ο πίνακας είναι τύπου Variant (παίρνει οτιδήποτε) και μπορεί να αυξομειώνεται. Το λεξικό δουλεύει με δυο πίνακες, ο ένας έχει για κάθε στοιχείο του μια ομάδα τιμών (UDT ή user defined type, κατά μια έννοια κάτι όπως το struct της C), και ο άλλος είναι πιο απλός, λέγεται πίνακας Κατακερματισμού (Hash Table), λέει πχ στη θέση Κ ότι έχει το στοιχείο Μ του πρώτου πίνακα. 

Ενδιαφέρον παρουσιάζει εδώ να κατανοήσει κανείς πως μεγαλώνουν αυτοί οι πίνακες και πώς χρησιμοποιούνται από τη Μ2000 για να βρίσκει τις μεταβλητές. Οι μεταβλητές διαγράφονται με σειρά ανάποδη από τη σειρά που δημιουργούνται. Ο πίνακας κατακερματισμού "αφαιρεί" πχ τρεις μεταβλητές άμεσα, γιατί ξέρει που είναι στο πίνακα Hash, οπότε "καθαρίζει" και απλά ένας δείκτης μειώνεται κατά 3. Η αναζήτηση στο πίνακα Hash γίνεται άμεσα! Το χρονοβόρο είναι το μέγεθος του ονόματος. Μια συνάρτηση Hash (χρησιμοποιείται εδώ η κλασική του συστήματος των Windows, που είναι πάντα φορτωμένη στη πιο γρήγορη μνήμη του επεξεργαστή), λέγεται HashData. Παλαιότερα είχα δική μου συνάρτηση γιατί τα ονόματα των μεταβλητών "ξεχείλωναν" με το πρόθεμα τους (που σχετίζεται με το που δημιουργήθηκαν), οπότε αντί να διάβαζα όλα τα γράμματα έριχνα το βάρος στο όνομα της μεταβλητής και έπαιρνα λιγότερα στοιχεία από το πρόθεμα. Στις τελευταίες εκδόσεις τα προθέματα έχουν γίνει σαν "συντομεύσεις" με ένα γράμμα και έναν αριθμό, οπότε το κλειδί για τον HashData δεν είναι μεγάλο. Για να δουλέψει ο πίνακας κατακερματισμού πρέπει να έχουν φτιαχτεί δυο κλειδιά. Το πρώτο βγαίνει από το όνομα ως ένας 32bit αριθμός. Το δεύτερο βγαίνει βάσει του μεγέθους του πίνακα κατακερματισμού, και δείχνει τη θέση στο πίνακα. Οπότε στο βοηθητικό πίνακα με τα UDT υπάρχει πεδίο που φυλάσσεται το πρώτο κλειδί για το λόγο ότι αν αλλάξει ο πίνακας HASH μέγεθος  τότε πρέπει να υπολογιστούν τα δεύτερα κλειδιά από τα πρώτα. Αν έχουμε πενήντα μεταβλητές τότε αυτό σημαίνει ότι θα πάρουμε 50 αριθμούς των 32bit, θα βγάλουμε το υπόλοιπο (mod) βάσει του μεγέθους του πίνακα και βρήκαμε τις θέσεις. Ο πίνακας κατακερματισμού είναι μεγαλύτερος από τον πίνακα με τα UDT, αλλά ενδέχεται να έχουμε "σύγκρουση" δηλαδή δύο στοιχεία να έχουν το ίδιο τελικό κλειδί. Αυτό λύνεται ως εξής. Όταν στο δεύτερο διαπιστωθεί ότι υπάρχει ήδη κάποιο στο πίνακα HASH τότε παίρνουμε από εκεί τον δείκτη που δείχνει στο πίνακα των UDT και τον βάζουμε σε πεδίο στο νέο στοιχείο και θα βάλουμε το δικό του "νούμερο" ή θέση στον πίνακα των UDT, στη θέση που δείχνει το κλειδί για τον HASH πίνακα. Άρα αν φτιαχτούν διαδοχικά δυο ας πούμε Γενικές μεταβλητές με όνομα Α, τότε και οι δύο βγάζουν τον ίδιο κωδικό HASH, αλλά στο πίνακα HASH πρώτα εμφανίζεται η τελευταία που μπήκε. Δηλαδή για ίδια ονόματα έχουμε το LIFO, το τελευταίο που μπήκε θα βγεί πρώτο (στην αναζήτηση αλλά και στη διαγραφή). Αυτός είναι και ο μηχανισμός σκίασης!

Στο σημείο αυτό ας δούμε και κάτι ακόμα για τις μεταβλητές. Είδαμε ότι οι δυο πίνακες του Λεξικού (ή Κατάσταση) δεν είναι ίδιες σε αριθμό στοιχείων. Ακριβώς το ίδιο συμβαίνει και με το πίνακα μεταβλητών (που κρατάμε τις τιμές τους) και τον πίνακα UDT. Όμως ο λόγος που συμβαίνει είναι διαφορετικός.  Μπορούμε να έχουμε πχ τρεις τιμές στο 0, 1 και 2 του πίνακα τιμών και τέσσερα ονόματα Α, Β, Γ, Δ όπου δυο από αυτά να δείχνουν σε μια τιμή, έστω στην 2. Υπάρχει ένα πεδίο στο UDT που λέει ότι το όνομα είναι "αναφορά". Κανονικά όταν διαγράφουμε όνομα από το λεξικό μηδενίζουμε και τη τιμή του. Αν όμως έχουμε "σήμα" ότι το όνομα είναι αναφορά θα αφήσουμε την τιμή ως έχει. Εξ ορισμού μια μεταβλητή που είναι αναφορά δεν παίρνει άλλη αναφορά, έτσι πάντα η αρχική μεταβλητή βρίσκεται σε "παλαιότερη" θέση. Αν αλλάζαμε τιμές θα γίνονταν "χαμός", δεν θα μπορούσε να λειτουργήσει σωστά το σύστημα! Θα δούμε αργότερα ότι υπάρχουν μεταβλητές που λέγονται δείκτες και αλλάζουν αυτό που δείχνουν. Όμως αυτά που δείχνουν δεν βρίσκονται στο χώρο των μεταβλητών!

Με απλά λόγια ο χώρος των μεταβλητών είναι αυτός που σχετίζεται με τα ονόματα. Οι τιμές είτε μένουν σε αυτόν το χώρο είτε αντί τιμής να υπάρχει δείκτης σε αντικείμενο, όπου το αντικείμενο έχει δικό του χώρο. Κατά μια έννοια, αλλά χωρίς να είναι αντικείμενο, συμβαίνει και στα αλφαριθμητικά να έχουμε ένα δείκτη στο χώρο μεταβλητών και ο χώρος που γράφονται τα γράμματα να είναι αλλού. Εδώ αξίζει να σημειωθεί ότι τα αλφαριθμητικά είναι μιας εγγραφής. Δηλαδή, όταν θέλουμε να προσθέσουμε δυο αλφαριθμητικά Α$ και Β$ (δείτε το $ είναι απαραίτητο για τον διερμηνευτή της Μ2000), δηλαδή να τα συνδέσουμε σε ένα, και να τα βάλουμε στο Α$ τότε η Μ2000 φτιάχνει ένα νέο αλφαριθμητικό, από την έκφραση A$+B$ και μετά πάει σε αυτό που έχει το Α$ και κάνει αλλαγή των δεικτών, ώστε εκείνο που φτιάχτηκε να μην διαγραφεί αλλά να διαγραφεί στη θέση του το παλιό του A$. Παλαιότερα έβγαινε ένα αντίγραφο του A$+B$ ως νέο αλφαριθμητικό για το A$ και μετά διαγράφονταν αυτό της έκφρασης, δηλαδή κάποια στιγμή υπήρχαν δυο αλφαριθμητικά A$+B$. Με την βελτιστοποίηση να γίνεται αλλαγή δεικτών (swap), κέρδισε σε ταχύτητα ο διερμηνευτής!

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

  1. Τα τμήματα δεν έχουν αναδρομή, ενώ οι συναρτήσεις έχουν.
  2. Τα τμήματα δεν ξεκινούν με δικό τους σωρό τιμών αλλά δέχονται τον "γονικό". Αυτό σημαίνει ότι στη κορυφή του σωρού (ειδική στοίβα, μπορεί κανείς να τη λέει και στοίβα), θα υπάρχουν οι τιμές που περάσαμε και μετά θα ακολουθεί ότι ήδη υπάρχει. Άρα μπορούμε να αφήσουμε κάτι. Τα τμήματα μπορούν να γυρίσουν τιμές στο σωρό τιμών. 
  3. Οι συναρτήσεις μπορούν να περαστούν με αναφορά
  4. Τα τμήματα έχουν μια ειδική λειτουργία που μπορούν κατά τη κλήση να αλλάξουν εσωτερικά τμήματα πρόσκαιρα (για τη κλήση αυτή)
Μερικές ομοιότητες:
  1. Και τα τμήματα και οι κανονικές συναρτήσεις (λέγονται κανονικές γιατί υπάρχουν και άλλες), έχουν δικό τους όνομα χώρου. Δηλαδή όταν δημιουργούμε μια μεταβλητή, πχ την Α τότε θα δώσει ο διερμηνευτής ένα πρόθεμα σχετικό με το χώρο που δημιουργήθηκε, και τη σειρά δημιουργίας του χώρου.
  2. Ότι όνομα (αναγνωριστικό) δημιουργούμε θα διαγραφεί στο τέλος εκτέλεσης.
  3. Κάθε "μονάδα" είτε είναι τμήμα είτε κανονική συνάρτηση, έχει δικό του ένα αντικείμενο τύπου Basetask. Επειδή ο διερμηνευτής είναι ένα σύνολο συναρτήσεων όπου καλούνται η μία μεσα στην άλλη, μεταφέρεται μαζί με βασικές παραμέτρους και το αντικείμενο τύπου Basetask. Σε αυτό υπάρχει ο δείκτης προς τον "τωρινό" σωρό τιμών, καθώς επίσης και ο δείκτης για το αντικείμενο εξόδου (πχ η κοσνόλα, ή ένα επίπεδο πάνω στη κονσόλα, ή μια φόρμα του γραφικού περιβάλλοντος που μπορούμε να δημιουργήσουμε, ή ο εκτυπωτής που έχουμε επιλέξει). Οι εντολές εξόδου είναι ίδιες για οποιοδήποτε αντικείμενο εξόδου (εκτός από κάποιες εντολές που δεν υποστηρίζονται, όπως πχ μια εντολή να καθαρίσουμε το αντικείμενο εξόδου όταν αυτό είναι ο εκτυπωτής - απλά δεν γίνεται, απαιτείται εντολή αλλαγής σελίδας και επιλογή προσανατολισμού, οριζόντιου ή κάθετου).
  4. Και τα τμήματα και οι συναρτήσεις μπορούν να έχουν στατικές μεταβλητές. Δηλαδή μεταβλητές που μετά την αρχικοποίησή τους, θα έχουν τιμές που θα τις ξαναβρούμε σε επόμενες κλήσεις.
Ειδικά για το (4) παραπάνω, αλλά και σε σχέση με το (3): Στην κονσόλα όταν ξεκινάμε τη Μ2000 υπάρχει ο αρχικός Basetask τύπος αντικειμένου. Η εκτέλεση από το σημείο αυτό γίνεται με κλήση στο εσωτερικό Interpreter. Αυτό το μέρος δεν εκτελεί επαναλήψεις, αλλά μπορεί να ξεκινήσει τμήματα ή συναρτήσεις που έχουμε γράψει (του χρήστη δηλαδή) και αυτές θα εκτελεστούν στο εσωτερικό Execute. Το execute αναγνωρίζει τα Statements, τις εντολές κατά μια έννοια (ομοίως και ο Interpreter αλλά σε υποσύνολο, και με μερικές δικές του εντολές). Σε αυτά μπορούν να συμβαίνουν τα παρακάτω:

Πίνακας Αναγνώρισης Εντολών του Execute

  1. Σημείωση (πχ REM η ΣΗΜ η ' ή // ή \\)
  2. Όνομα χωρίς να ακολουθεί τελεστής και χωρίς παρενθέσεις
  3. Όνομα χωρίς να ακολουθεί τελεστής με παρενθέσεις
  4. Γνωστό όνομα δομής (είτε για ορισμούς είτε για αλλαγή ροής εκτέλεσης)
  5. Όνομα (με $ ή με % στο τέλος ή χωρίς κάτι από αυτά) με τελεστή
  6. Όνομα (με $ ή με % στο τέλος ή χωρίς κάτι από αυτά) με παρενθέσεις και με τελεστή
  7. Κενή γραμμή
  8. Όνομα με το : στο τέλος χωρίς να ακολουθεί άλλο εκτός από  κενό, αλλαγή γραμμής ή σημείωση.
  9. Αριθμός μέχρι πέντε ψηφία το 01 και το 00001 είναι το ίδιο το 1
  10. Αγκύλη {  ή  }
  11. Σύμβολο : (σημαίνει αλλαγή εντολής οριζόντια)
  12. Αλλαγή γραμμής (σημαίνει αλλαγή εντολής κάθετα).

Το (2) μπορεί να είναι εντολή πχ Τύπωσε 10 ή ένα όνομα τμήματος. Για το λόγο αυτό αν δώσουμε κάτι άγνωστο, πχ ΑΦΧΨ μας επιστρέφει μήνυμα ο διερμηνευτής ότι δεν υπάρχει τέτοιο τμήμα. 
Το (3) είναι κλήση ρουτίνας. Αν δεν την βρει τότε έχουμε λάθος. Οι ρουτίνες είναι στατικά επώνυμα μέρη κώδικα. Βρίσκονται στο τέλος του τμήματος ή της συνάρτησης. Με την πρωτη κλήση ο διερμηνευτής καταγράφει τη θέση της στο αντικείμενο τύπου Basetask. 
Διαφορές Ρουτινών και Τμημάτων:
  1. Οι ρουτίνες δεν έχουν όνομα χώρου. Οπότε αν θέλουμε να ορίσουμε νέα μεταβλητή πρέπει να τη δηλώσουμε ως τοπική
  2. Οι ρουτίνες έχουν υποχρεωτικά παρενθέσεις ακόμα και αν δεν δηλωθούν παράμετροι. Εκτελούνται με τη Διαμέσου ή χωρίς. Αν υπάρχει πίνακας με ίδιο όνομα τότε ο διερμηνευτής θα "πιστέψει" ότι είναι πίνακας και θα βγάλει λάθος επειδή λείπει τελεστής! 
  3. Η έξοδος από τη ρουτίνα γίνεται με το Τέλος Ρουτίνας ή το Έξοδος Ρουτίνας. Η έξοδος από ένα τμήμα γίνεται στο τέλος του κώδικά του, ή με την έξοδος. Ομοίως για τη Συνάρτηση, η έξοδος γίνεται όπως και στο τμήμα, και όχι με την επιστροφή τιμής.
  4. Οι ρουτίνες επειδή βλέπουν ό,τι έχει το τμήμα ή η συνάρτηση που βρίσκονται μπορούν να τα χρησιμοποιήσουν. Έτσι μπορούν να καλέσουν τον εαυτό τους. Οι ρουτίνες έχουν αναδρομή.
  5. Οι ρουτίνες δεν έχουν δικό τους σωρό τιμών αλλά μπορούμε να δηλώσουμε Σωρός Νέος { } και μέσα στο μπλοκ να έχουμε ένα καθαρό σωρό.
  6. Στο σωρό τιμών μπορούν να περαστούν μεταβλητές με τιμή ή με αναφορά. Γενικά με αναφορά δεν βολεύει αφού υπάρχει θέαση σε όλο το τμήμα, εκτός και αν έρχεται από κάπου αλλού!
  7. Ενώ ένα τμήμα είναι δυναμικό, δηλαδή μπορεί να αλλάξει κώδικα με νέο ορισμό, οι ρουτίνες δεν είναι δυναμικές, αλλά στατικές στο τμήμα ή τη συνάρτηση που βρίσκονται. 
  8. Στα τμήματα και τις κανονικές συναρτήσεις οι ορισμοί βρίσκονται πριν την χρήση τους, ενώ στις ρουτίνες και τις απλές συναρτήσεις οι ορισμοί βρίσκονται στο τέλος του τμήματος ή της συνάρτησης που φτιάχνονται.
  9. Μια ρουτίνα μπορεί να καλέσει μια "αδελφή" ρουτίνα (έχουν και οι δύο τον ίδιο γονέα, το τμήμα ή τη συνάρτηση που ανήκουν), ενώ ένα τμήμα δεν αναγνωρίζει "αδέλφια" αλλά μόνο αυτό (υο παιδί) στο οποίο είναι απευθείας γονικό, και σε ότι είναι γενικό. Ένα τμήμα Α αν ορίζει ένα τμήμα Β και το Β ένα τμήμα Γ τότε το Α δεν βλέπει ο Γ. Αν καλέσουμε από το Α το Β και τερματίσει το Β τότε δεν θα υπάρχει Γ στο σύστημα, επειδή ο ορισμός του έγινε στο Β στην επιστροφή από το Β θα διαγραφεί. Υπάρχει μηχανισμός που κρατάει σε πακέτα τις στατικές μεταβλητές και τις φορτώνει στην επόμενη κλήση της Β. Έτσι οι στατικές μεταβλητές σχετίζονται με το γονέα βάσει κλήσης. Ένα τοπικό τμήμα καλείται από ένα μόνο τμήμα. Αν γενικό τμήμα μπορεί να κληθεί από άλλα όσο δεν τερματίζει το τμήμα που το δημιούργησε. Σε κάθε περίπτωση κλήσης του γενικού τμήματος, οι τυχόν στατικές μεταβλητές θα διαφέρουν βάσει του ποιου τμήματος έγινε η κλήση. Έτσι αν το ΑΑ είναι γενικό και έχει στατικές μεταβλητές και για τα τοπικά Β, Δ ενός τμήματος Ζ, το ΑΑ θα έχει δυο σετ στατικών, ένα για τη  σειρά κλήσεων Ζ μετά Β μετά ΑΑ και ένα για τη σειρά Ζ μετά Δ μετά ΑΑ. Στις κανονικές συναρτήσεις οι στατικές στην αναδρομή είναι ίδιες για όλο το βάθος αναδρομής. Οι στατικές στην έξοδο γίνονται πακέτο και μπαίνουν στη συλλογή στατικών του προηγούμενου Basetask. Στην αναδρομή σε συναρτήσεις βγαίνει νέο αντικείμενο τύπου Basetask και σε αυτό απλά γράφεται ο δείκτης στην ίδια συλλογή στατικών με αυτό που έχει το πρώτο Basetask, στη πρώτη κλήση της συνάρτησης. 
  10. Μια ρουτίνα δεν μπορεί να ορίσει ρουτίνες ή απλές συναρτήσεις. Ένα τμήμα και μια κανονική συνάρτηση μπορούν να ορίζουν άλλα τμήμα και συναρτήσεις καθώς και ρουτίνες και απλές συναρτήσεις. Σε μια ρουτίνα μπορούμε να ορίσουμε τμήματα και συναρτήσεις, και θα είναι ορατά μέχρι να τερματίσει η ρουτίνα. Αν όμως έχουμε ίδια ονόματα με τμήματα και συναρτήσεις που είναι ήδη ορισμένα και δεν είναι "τελικά", τότε θα αλλάξουμε το κώδικά τους!
  11. Μια ρουτίνα (όπως και οι απλές συναρτήσεις) δεν έχουν δικό τους αντικείμενο τύπου Basetask, άρα δεν έχουν και δικές τους στατικές. Αν υπάρχουν τις δημιουργούν. Οι στατικές δεν μπορούν να περαστούν με αναφορά σε ρουτίνες ή απλές συναρτήσεις. Μπορούν να περαστούν με αναφορά σε κλήσεις συναρτήσεων και τμημάτων
Γενική Απαρίθμηση Καθαρισμός {Νέες_Στατικές, Ως_Έχουν_Στατικές}
Τμήμα Γενικό χρήσηΣτατικής (ΝαΚαθαρίσω){
      Αν ΝαΚαθαρίσω = Νέες_Στατικές τότε Καθαρό
      Τύπωσε Γράμμα$
      Στατική Κ=100
      Συνάρτηση Κάππα(&Μ) {
            =Μ^2
            Μ++
      }
      Τύπωσε Κάππα(&Κ)
      Τύπωσε Κάππα(&Κ)
      Τύπωσε Κάππα(&Κ)
}
Τμήμα Αλφα {
      Στατική Επιγραφή$="Από το τμήμα Άλφα"
      χρήσηΣτατικής Νέες_Στατικές, Επιγραφή$
      χρήσηΣτατικής Ως_Έχουν_Στατικές, Επιγραφή$ + " συνέχεια"
}
Τμήμα Βήτα {
      Στατική Επιγραφή$="Από το τμήμα Βήτα"
      χρήσηΣτατικής Νέες_Στατικές, Επιγραφή$
      χρήσηΣτατικής Νέες_Στατικές, Επιγραφή$
}
Άλφα
Βήτα

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

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

Τύπωσε @όνομα(3)#Αθρ()=36, @όνομα(3)#Τιμη(1)=27

(κ, λ)=@όνομα(3)
Τύπωσε κ=9, λ=27

Συνάρτηση όνομα(χ
      =χ**2, χ^3
Τέλος Συνάρτησης


Έξοδο με την Έξοδο Συνάρτησης και κλήση με το @όνομα(). Το σύμβολο @ λέει ότι έχουμε απλή συνάρτηση. Επίσης και εδώ θέλει προσοχή, δεν έχουμε νέο σωρό τιμών. Η συνάρτηση δηλαδή έχει πρόσβαση στο σωρό τιμών του τμήματος ή της συναρτησης που ανήκει. Μπορούμε να γυρίσουμε περισσότερες από δυο τιμές. 

Ο Διερμηνευτής ελέγχει το τύπο επιστροφής μόνο ως προς τον βασικό: Αριθμός ή Γράμματα. Μια αριθμητική συνάρτηση γυρνάει αριθμό ή αντικείμενο (όπως εδώ). Μια αλφαριθμητική μπορεί να γυρίσει γράμματα ή αντικείμενο που γυρνάει αλφαριθμητικά. Αν θέλαμε να δώσουμε στην όνομα() μια πρώτη τιμή γράμματα (αλφαριθμητικό) τότε θα τα βάζαμε όλα μέσα σε ένα ζευγάρι παρενθέσεων μετά το ίσον: ("γράμματα", χ**2, χ^3). Το ** και τι ^ είναι η ύψωση σε δύναμη.


Το αντικείμενο τύπου Basestack έχει λίστα με τις θέσεις των απλών συναρτήσεων και των ρουτινών, καθώς και των απλών ρουτινών. 

Οι απλές ρουτίνες λειτουργούν με την Διαμέσου και δεν έχουν παραμέτρους. Δίνουμε ετικέτα ή αριθμό γραμμής (που έχουμε ήδη βάλει). Στο τέλος της απλής ρουτίνας υπάρχει η εντολή Επιστροφή. Μπορούμε να έχουμε και αλλού την εντολή Επιστροφή, δηλαδή δεν χρειάζεται έξοδος με την εντολή Έξοδος. Ο σκοπός των απλών ρουτινών είναι να χρησιμοποιούμε κώδικα πολλές φορές σαν να ήταν στη θέση της κλήσης. Αν φτιάξουμε κάτι σε απλή ρουτίνα θα μείνει και μετά την επιστροφή της. Δηλαδή δεν έχουμε διαγραφή νέων ορισμών όπως στην ρουτίνα με παρενθέσεις. Δοκιμάστε να βγάλετε το Λ=0 (πχ μπορείται να το σκιάσεται με ένα ' ή ένα / ή ένα \ στην αρχή, ή με το Σημ ή REM στην αρχή). Θα βγει λάθος γιατί η ΔεςΑυτόΛ θα φτιάξει νέα Λ και θα την σβήσει, οπότε στο Αν Λ<10 το Λ δεν θα υπάρχει! Για να τρέξετε το πρόγραμμα ανοίξτε τη Μ2000, γράψτε σ α και πατήστε το πλήκτρο Enter, ανοίγει ο διορθωτής και εκεί κάντε επικόλληση το κώδικα. Πατήστε το πλήκτρο Esc και γράψτε α και πατήστε το πλήκτρο Enter. Τρέξτε το κώδικα και με Δοκιμή α. Επίσης βάλτε πριν την εντολή Τέλος την εντολή Λίστα (δείχνει τι μεταβλητές έχει εκείνη τη στιγμή ο διερμηνευτής και τις τιμές τους). Για να παρεμβάλουμε νέα γραμμή στον διορθωτή πατάμε Enter στην αρχή ή στο τέλος μιας γραμμής ανάλογα που θέλουμε να γίνει η παρεμβολή γραμμής. Με Ctrl+Enter ανοίγουμε μπλοκ { } και μπαίνει αυτόματα εσοχή στην πρώτη γραμμή ανάμεσα στο μπλοκ. Δοκιμάστε και τα Ctrl+Z (undo) και Ctrl+U (redo). Επίσης δείτε και το σχετιζόμενο μενού, βγαίνει με δεξί κλικ στο ποντίκι καθώς και με το shift F10, όπως και με αριστερό κλικ στην επικεφαλίδα του διορθωτή. Το σχετιζόμενο μενού έχει εντολές που δεν φαίνονται αρχικά αλλά βγαίνουν με ολίσθηση. Επίσης μπορούμε όταν είναι ανοιχτό το μενού να πατήσουμε αριθμούς γραμμών και να μας πάει στη γραμμή που θέλουμε! Το μενού αυτό μπορεί να μετακινηθεί και παραμένει ανοικτό όσο δίνουμε αριθμούς γραμμών και enter. Επίσης δοκιμάστε να κάνετε κλικ πάνω στην ετικέτα και με F3 θα σας πάει στο επόμενο ίδιο, ενώ με F2 στο προηγούμενο ίδιο. Με F5 αλλάζεται το όνομα παντού (υπάρχει UNDO), ενώ με F4 κάνετε το όνομα να έχει ίδια πεζά και κεφαλαία παντού στο κείμενο (σε αυτό δεν υπάρχει UNDO). Το σχετιζόμενο μενού είναι είτε με αγγλικά είτε με ελληνικά. Αν γράψουμε Ελληνικά ή Λατινικά (αλλάζει τη γλώσσα μηνυμάτων λαθών και επιγραφών στο μενού). Η εντολή Λατινικά δεν έγινε Αγγλικά λόγω συμβατότητας με την αρική Μ2000, η οποία δεν δούλευε σε Unicode, και έβαζε το λατινικό σύνολο χαρακτήρων (οπότε τα ελληνικά τα χάναμε...στον τότε διορθωτή, που δεν είχε χρωματισμό κώδικα και ήταν ένα απλό textbox της VB6).

Λ=0
για ι=1 έως 30
      διαμέσου ετικέτα
επόμενο
Τέλος


ετικέτα:
      κ=20
200αν κ<10 τότε 400
      τύπωσε κ
      κ--
      διαμέσου ΔεςΑυτότοΛ()
      αν Λ>100 τότε προς ετικέτα
      προς 200
400τύπωσε "ΟΚ - Επιστροφή από:"; ι
      Επιστροφή


Ρουτίνα ΔεςΑυτότοΛ()
      Λ=Τυχαίος(95, 103)
Τέλος Ρουτίνας


Η ετικέτα είναι όπως στη περιγραφή (8) στο πίνακα παραπάνω με την άνω και κάτω τελεία.
Αν έχουμε ένα τμήμα Αλφα τότε το Αλφα: Τύπωσε 10 θα καλέσει το Αλφα και μετα στην επιστροφή θα εκτελέσει την Τύπωσε. Ξέρει ο διερμηνευτής ότι αφού ακολουθεί κάτι μετά την άνω και κάτω τελεία και δεν είναι η αλλαγή γραμμής ή μια σημείωση ότι το Άλφα δεν είναι ετικέτα.

Ο Execute πρώτα πρέπει να ανανγνωρίσει τι έχει όπως ο πίνακας παραπάνω γράφει. Αν έχουμε εντολή τότε κοιτάει αν είναι γνωστή εντολή. Αυτό γίνεται πολύ γρήγορα με πίνακα κατακερματισμού. Αυτή η αναζήτηση μπορεί να γυρίσει ένα από πέντε πράγματα:
  1. Το όνομα έχει παρένθεση, θα είναι πίνακας ή ρουτίνα, παράκαμψη...Α
  2. Υπάρχει εντολή του Execute, στη λίστα εντολών, δίνει έναν αριθμό και αυτός πάει σε μια On X Goto....και άμεσα γίνεται άλμα στο σημείο του Execute που είναι ο κώδικας της εντολής. Οι εκτέλεση εντολών εδώ γίνεται χωρίς άλμα έξω από το Execute.
  3. Υπάρχει εντολή και μαζί μας δίνεται και μια διεύθυνση που θα καλέσουμε το πρόγραμμα για να εκτελεστεί η εντολή και να επιστρέψουμε στο Execute.
  4. Κοιτάμε αν έχουμε τελεστή εκχώρησης ή αλλαγής τιμή, αν ναι τότε έχουμε μεταβλητή
  5. Κοιτάμε αν έχουμε τμήμα, αν ναι καλούμε το τμήμα
Το ερώτημα εδώ που προκύπτει είναι: Που καλούμε συναρτήσεις; Η απάντηση:
  1. Συναρτήσεις γράφονται σε δεξιές ή αριστερές εκφράσεις
  2. Ότι έχουμε δεξιά από ένα σύμβολο εκχώρησης ή αλλαγής τιμής είναι δεξιά έκφραση.
  3. Αριστερή έκφραση είναι ο δείκτης ενός πίνακα: πχ Α(δεξιάΈκφραση1)=δεξιάΈκφραση2, αριστερή έκφραση είναι το Α(δεξιάΈκφραση1), εδώ θα εκτελεστεί πρώτα η αριστερή και μετά η δεξιά έκφραση. Όμως στην εντολή Στη (Let) θα γίνει το ανάποδο θα εκτελεστεί η δεξιά έκφραση, και μετά η αριστερήΈκφραση.
  4. Δεξιά έκφραση είναι και οι εκφράσεις εντός ρουτίνας: πχ Α(δεξιάΈκφραση)
  5. Δεξιά έκφραση είναι και οι εκφράσεις σε ένα τμήμα: πχ Α δεξιάΈκφραση, ΆλληΈκφραση... και σε μια συνάρτηση ή απλή συνάρτηση.
Υπάρχουν λοιπόν συναρτήσεις, δυο, για εκφράσεις δεξιές, που μπορεί να είναι για επιστροφή αλφαριθμητικού ή αριθμού (αντικειμένου). Η IsStrExp() και η IsExp(). Η δεύτερη βρίσκει επιπλέον αν έχουμε λογική έκφραση, ή αν έχουμε αυτόματο πίνακα: (1,2,3). Σε κάθε περίπτωση υπάρχει μια μέθοδος AheadStatusFast που βρίσκει μπροστά αν έχει έκφραση αλφαριθμητική ή αριθμητική. Αυτή η μέθοδος είναι πολλή γρήγορη γιατί κοιτάει τα $ στα ονόματα, και τους τελεστές ενώ αποφεύγει ότι είναι μέσα σε παρενθέσεις. Έτσι το $ βοηθάει να βρίσκει τι έχει μπροστά του χωρίς να κάνει επικύρωση αν τα ονόματα υπάρχουν.

Η IsExp έχει ορισμένες δικές της συναρτήσεις (η VB6 είναι flat, δηλαδή όλα σε ένα αρχείο BAS είναι θεατά, και δεν υπάρχουν συναρτήσεις μέσα σε συναρτήσεις, είναι όλα Γενικά, εκτός από τις τοπικές μεταβλητές). Έτσι όταν λέμε εδώ "δικές της" συναρτήσεις λέμε για συναρτήσεις που γράφτηκαν για να εξυπηρετηθεί η IsExp. Η πιο εσωτερική είναι η IsNumberNew. Σε αυτήν γίνεται χρήση λίστας ονομάτων αριθμητικών συναρτήσεων για να βρεθεί αν το όνομα είναι συνάρτηση της Μ2000, συνάρτηση του χρήστη, συνάρτηση απλή του χρήστη, σε άλλη λίστα  αριθμητική μεταβλητή μόνο για ανάγνωση, πίνακες, μεταβλητές. Πριν κληθεί η IsNumberNew, έχει κληθεί η IsNumber η οποία κοιτάει αν έχουμε αριθμό με νούμερα πχ 12345, επίσης κοιτάει αν έχουμε σύμβολο τύπου πχ το & είναι για 32bit ακέραιο, ενώ το @ είναι για 27 ψηφία αριθμό (Decimal), και υπάρχουν και άλλα. Επίσης κοιτάει και το πρόσημο στην αρχή, πχ το ---27 θα δώσει το -27. Επίσης αναγνωρίζει και αριθμούς με επιστημονική γραφή πχ 1.242ε-19, μπορούμε να έχουμε το e ή το ε για εκθέτη. Το διαχωριστικό δεκαδικών στον κώδικα είναι πάντα η τελεία. Στην κονσόλα εμφανίζεται με βάσει κάποιες ρυθμίσεις της Μ2000.

H IsExp συνάρτηση έχει και μια προαιρετική παράμετρο που λέμε ότι θέλουμε αριθμητική τιμή οπωσδήποτε. Αυτό σημαίνει ότι αν έχουμε αποτέλεσμα αντικείμενο θα πάρουμε την τιμή 0, και το αντικείμενο θα χαθεί. Στην  IsExp καλούμε άμεσα την IsExpA. Η δεύτερη μπορεί να βγει μετά την  ανάγνωση της πρώτης έκφραση γιατί μπορεί να βρήκε παρένθεση και μετά το κόμμα που σημαίνει ότι είναι αυτόματος πίνακας. Στους αυτόματους πίνακες (tuple) το (,) σημαίνει κενός πίνακας (είναι και αυτό μια έκφραση που βρίσκει το IsExp) ενώ το (1,) ή το ("α",) είναι αυτόματος πίνακας ενός στοιχείου. Δείτε ότι το "α" δεν είναι μέρος του IsExp. Όμως είναι του IsExpA γιατί αυτό κοιτάει αν έχουμε τελεστή  λογικό οπότε το "α">" " θα δώσει true (τιμή αριθμητική τύπου boolean, ισοδύναμη με το -1). Οι σταθερές true και false δεν είναι boolean, είναι αριθμητικές double. Οι λογικοί τελεστές (συγκρίσεων και πύλες όπως KAI, H, ΑΠΟ, ΌΧΙ) δίνουν boolean τύπο. Αν λοιπόν βρει αλφαριθμητικό και μετά το κόμμα σημαίνει ότι ανήκει σε αυτόματο πίνακα και κάνει έξοδο προς το IsExp. To IsExpA έχει όλους τους τελεστές και όποτε χρειάζεται έκφραση καλεί την IsExp, ή την logical(). Η logical() καλείται πρώτη γιατί αυτή καλεί την Number, αλλά και την IsStrExp (έχει δυο σετ για συγκρίσεις αλφαριθμητικών, ένα με κανονική σύγκριση βάσει δυαδικών ψηφίων, και ένα με σειρά γραμμάτων βάσει γλώσσας ελέγχοντας μια μεταβλητή mTextCompare (η Διακόπτες "+txt" αλλάζει σε σύγκριση βάσει γλώσσας.

Στο παράδειγμα που ακολουθεί, καλούμε το τμήμα ΔοκιμήΑ. Εκεί αδειάζουμε τον τρέχον σωρό, γιατί θέλουμε να είναι καθαρός εδώ. Φτιάχνουμε ένα τμήμα ΜΜ, και μετά δίνουμε εντολές ΜΜ με παραμέτρους. Δείτε ότι ο Διερμηνευτής δεν νοιάζεται για το τι θα στείλουμε. Θα στείλει ότι του ζητήσουμε. Στο τμήμα ΜΜ έχουμε μια εντολή που μας δείχνει το τρέχον σωρό τιμών, και μετά τον καθαρίζει.

Όταν αναγνωρίζεται ότι το ΜΜ είναι τμήμα, στο Execute καλείται η ProcModuleEntry. Αυτή το πρώτο πράγμα που κοιτάει είναι αν έχει ελεύθερο χώρο στη στοίβα επιστροφής. Αν δεν έχει θα τερματίσει με λάθος. Κατά την εκκίνηση του Διερμηνευτή γίνεται έλεγχος μεγέθους της στοίβας επιστροφής και αποφασίζει πόσες κλήσεις μπορεί να κάνει! Η στοίβα επιστροφής είναι διαφορετική από το σωρό τιμών της Μ2000, και είναι η βασική στοίβα που χρησιμοποιεί ο επεξεργαστής στη συγκεκριμένη υλοποίηση εκτέλεσης! Ο m2000.exe κατά την εκκίνηση έχει ζητήσει ένα μεγάλο μέγεθος στοίβας, και μετά συνδέει το m2000.dll. Μπορεί κάποιος να ανοίξει στο IDE της VB6 to m2000.vbp να τρέχει το dll, μέσα από το IDE και να εκτελέσει απλά το m2000.exe (που το φτιάχνουμε με το mexe.vbp). Αν στο IDE κατεβάσει στο αυστηρότερο το όριο σταματήματος σε λάθη Break On All Errors, τότε το πρώτο λάθος που θα βρει είναι η ανάγνωση του μεγέθους του Stack (πραγματικά η Μ2000 προκαλεί εσκεμμένο λάθος για να μετρήσει το μέγεθος, απλά έχει μια On Error για να το αποφύγει, το οποίο δεν λειτουργεί αν έχουμε το Break On All Errors (context menu, sub menu tongle).

Τμήμα ΔοκιμήΑ {
      Αδειασε
      Τμήμα ΜΜ {
            Σωρός
            Αδειασε
      }
      ΜΜ 100, "α"+"β"="αβ"
      ΜΜ "α"+"β"="αβ", 100
      ΜΜ 100,"αβ""α"+"β"
      ΜΜ "αβ"="α"+"β", 100
}
ΔοκιμήΑ


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

Συνάρτηση ΑφαίρεσεΑστέρια$(α$, &πόσα) {
      πόσα=μήκος(α$)
      α$=φίλτρο$(α$,"*")
      =α$
      πόσα-=μήκος(α$)
}
Τόσα=0
Τύπωσε ΑφαίρεσεΑστέρια$("***ΑΒ***ΓΔΕ***Ζ", &Τόσα), Τόσα

Δείτε ότι βάλαμε το &Τόσα
Στη συνάρτηση ο διερμηνευτής έβαλε τη γραμμή Διάβασε α$, &πόσα Μπορούμε να το κάνουμε και εμείς! Θα βάλουμε τη γραμμή αυτή αμέσως μετά από μια εντολή Σωρός για να δούμε τι θα δείξει. Μάλιστα αντί να τυπώσουμε άμεσα το αποτέλσμα το βάζουμε στη κορυφή του τρεχοντα σωρού (είναι διαφορετικός από αυτόν της συνάρτησης). Διαβάζουμε το αποτέλεσμα με το Γράμμα$ (σηκώνει αλφαριθμητικό από τη κορυφή αλλιώς βγάζει λάθος).

Αν το τμήμα στο οποίο βρίσκεται ο κώδικας είναι το Β τότε το &Τόσα θα είναι ένα αλφαριθμητικό με τιμή "Β.ΤΟΣΑ"  (θα έχουν φύγει οι τόνοι και θα έχουν γίνει κεφαλαία, επειδή έτσι δουλεύει τα ονόματα ο διερμηνευτής). Αυτό που μπήκε στο σωρό τιμών είναι η Ισχνή Αναφορά στο ΤΟΣΑ του Β.

Η Διάβασε ευθύνεται να πάρει μια ισχνή αναφορά και να την κάνει κανονική αναφορά. Πρώτα θα δεί το &πόσα που του λέει πάρε αναφορά για το πόσα. Αν η πόσα υπήρχε στο τμήμα θα έβγαινε λάθος, επειδή δεν επιτρέπεται δεύτερη αναφορά, ή αλλαγή αναφοράς.  Η εσωτερική συνάρτηση ReadMe δουλεύει για το Διάβασε. Μπορεί να ορίσει μεταβλητές, μπορεί να κάνει έλεγχο τύπου για αντικείμενα ή να δημιουργήσει νέες μεταβλητές με μετατροπή της τιμής στην επιθυμητή.


Συνάρτηση ΑφαίρεσεΑστέρια$ {
         Σωρός
      Διάβασε α$, &πόσα
      πόσα=μήκος(α$)
      α$=φίλτρο$(α$,"*")
      =α$
      πόσα-=μήκος(α$)
}
Τόσα=0
Βάλε ΑφαίρεσεΑστέρια$("***ΑΒ***ΓΔΕ***Ζ", &Τόσα)
Τύπωσε Γράμμα$, Τόσα


Αυτά για σήμερα!
Γιώργος Καρράς

Γράψτε κάποιο σχόλιο!

ΥΓ. Τεχνικά θέματα:
  1. Ο κώδικας είναι εδώ χρωματισμένος από τον διορθωτή της Μ2000.
  2. Όταν αντιγράφουμε κώδικα από το διορθωτή της Μ2000 φτιάχνονται δυο αντικείμενα στο πρόχειρο, ένα απλού Unicode κειμένου (UTF16), και ένα HTML κειμένου (UTF8). Στο δεύτερο έχουν μπει και οδηγίες (tags) για το χρώμα. Η επικόλληση στο blogger δίνει το HTML κείμενο, άρα αυτό με το χρώμα. Αν επιλέξουμε το απλό κείμενο θα πάρει το απλό κείμενο.
  3. Επειδή στο διορθωτή χρησιμοποιούμε είτε το TAB (εξορισμού το TAB) είτε το Διάστημα για να βάζουμε εσοχές, κατά την αντιγραφή σε HTML αν δει ο διερμηνευτής τον χαρακτήρα TAB τότε εισάγει οδηγίες για κείμενο Monospace (με ίδιο πλάτος γράμματος για κάθε γράμμα). Αυτό όμως στο Blogger δεν κάνει αναδίπλωση λέξεων, οπότε δεν βγαίνει μαζεμένο σε περίπτωση που έχουμε μικρό πλάτος σελίδας. Οπότε υπάρχει η οδηγία στη κονσόλα Διακόπτες "-nbs" όπου το nbs σημαίνει (non break space), και αλλάζονται όλα τα TAB (στην αρχή των παραγράφων με διαστήματα. Στην HTML το NBS το θέλουμε γιατί αλλιώς χάνουμε τις εσοχές εκτός και αν έχουμε ανοίξει το κείμενο για Monospace κείμενο!
  4. Το πλάτος του TAB το καθορίζουμε με τη εντολή Σ ή Συγγραφή ή Edit αλλά αντί για όνομα (που θα άνοιγε τον διορθωτή, δίνουμε θαυμαστικό και νούμερο. Έτσι το Σ ! 2 κάνει το TAB να εμφανίζεται με δυο χαρακτήρες (μόνο στον διορθωτή και στην εξαγωγή HTML όταν αλλάζουμε τα TAB εσοχής με NBS, δείτε στο παράδειγμα κάτω ότι έχουμε δυο διαστήματα στην εσοχή!).
  5. Αν δεν θέλουμε να χρησιμοποιούμε TAB τότε δίνουμε το διακόπτες "-tab" (η εντολή παίρνει πολλούς μαζί γι' αυτό είναι στον πληθυντικό. Πχ διακόπτες "-tab -nbs".
  6. Ακόμα και αν χρησιμοποιούμε TAB, μπορούμε με το shift TAB να βάλουμε εσοχή με διάστημα. Αν σε ένα μπλοκ δεν υπάρχει εσοχή με TAB αλλά υπάρχει έστω και μια εσοχή με διάστημα τότε αν μαρκάρουμε πολλές γραμμές το πλήκτρο TAB βάζει εσοχές με διαστήματα.
  7. Με το F10 στο διορθωτή αλλάζουμε την εμφάνιση, μια φορά δείχνει χαρακτήρες που δεν φαίνονται, όπως διαστήματα (μια ειδική τελεία) και TAB (βελάκι), NBS (παραμένει ως διάστημα), το διάστημα αριθμών, καθώς και το τέλος παραγράφου, ενώ μια άλλη φορά το κανονικό κείμενο. Και στις δυο εμφανίσεις μπορούμε να διορθώνουμε κείμενο!
Α$= "  "+χαρκωδ$(160)
Για ι=1 έως 3 {
  Τύπωσε Χαρκωδ(Μεσ$(Α$, ι)),
}
Τύπωσε  ' αλλαγή γραμμής


Μας δίνει:  32     8199   160
Κανονικά μπορούμε να βάλουμε το 160 με το shift+ctrl+space, και το διάστημα αριθμών με το alt+ctrl+space. Όμως αν βάλουμε το 160 (NBS) κατά την αντιγραφή από το blogger στον διορθωτή το 160 γίνεται 32. Οπότε εδώ το έφτιαξα με την χαρκωδ$() που γυρίζει τον Unicode χαρακτήρα που δίνουμε.






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

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

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