Τετάρτη, 20 Φεβρουαρίου 2019

Revision 22 Version 9.7

This is the final revision for 9.7 version.

All updates for GUI elements done. Also minor bugs removed.

The help file update and include the # functions for arrays. The # functions call one another, if result is an array e.g if p is a pointer to array then we can perform a series of  functions like this p#Filter(...)#Map(...)#Fold(...)

When we exit from a module with an error and before we set Nothing to user forms, the forms was not unloaded, and all references to forms (from M2000 variables) lost. Now there is an automatic routine which unload the forms. So we can programming in M2000 editor and call modules without any problem, even if we have errors in program.

Calling a method for com objects prior use only passing by value, now we can pass by reference using & before the name of variable.

An example exist in info.gsb in the updated meditor.

Κυριακή, 17 Φεβρουαρίου 2019

Αναθεώρηση 20 Έκδοση 9.7

Σε αυτήν την αναθεώρηση κοίταξα το σύστημα παραθύρων. Η Μ2000 έχει δικό της σύστημα (βασίζεται στη μηχανή της Visual Basic 6, και δεν χρησιμοποιεί τα στοιχεία της VB6). Μπορούμε να φτιάχνουμε φόρμες με πέντε διαφορετικά στοιχεία, που έχουν παραλλαγές ανάλογα με την ρύθμιση.

Ειδικά στο EditBox ή Κείμενο, προστέθηκε νέο γεγονός. Δεν αναφέρω κάτι περισσότερο, γιατί είναι πολύ τεχνικό. Στο info.gsb που παρέχεται με τον διερμηνευτή υπάρχει το meditor, ο διορθωτής για προγράμματα της Μ2000, σε μορφή παραθύρου, γραμμένος σε Μ2000. Τα επιπρόσθετα σε αυτήν την έκδοση του meditor είναι:
  • η ενσωμάτωση της βοήθειας (με χρήση SQL ερωτημάτων, στην βάση δεδομένων της βοήθειας της Μ2000). Από την ίδια βάση δουλεύει και το Βοήθεια ή Help. 
  • νέο μενού όπου επιλέγουμε αν θα τρέξουμε το πρόγραμμα με επίδειξη του κώδικα καθώς τρέχει (αυτό γίνεται με κλήση του προγράμματος που γράφουμε σε νέα παρουσία του διερμηνευτή, και σε αυτήν ανοίγει ο Έλεγχος, που δείχνει τις εντολές).
Ως προς το σύστημα παραθύρων:
Στις αναδυόμενες λίστες, όπως αυτή των μενού, έχει βγει η μετακίνηση με το ροδελάκι του ποντικιού και έχει αντικατασταθεί με άμεση μετακίνηση του δρομέα (που εμφανίζει την επιλογή) με την κίνηση του δείκτη του ποντικιού. Μπορούμε με κράτημα του αριστερού πλήκτρου του ποντικιού να μετακινούμε τις επιλογές (αν το μενού έχει περισσότερες από ένα αριθμό γραμμών, τότε δεν εμφανίζονται όλες οι επιλογές, αλλά μπορούμε με ολίσθηση των γραμμών να δούμε και τις άλλες εντολές). Η χρήση των μενού προγραμματιστικά δεν είναι δύσκολη, αλλά παρόλα αυτά απαιτεί δουλειά για να προγραμματίσει κανείς ένα καλό μενού. Δείτε πόσα πράγματα χρειάζονται. Για κάθε μενού πρέπει να ορίσουμε ένα αντικείμενο τύπου Combo ή Λίστα.Εισαγωγής. Αυτό το στοιχείο έχει τρεις βασικές παραλλαγές. Και οι τρεις εμφανίζουν ένα όνομα και δίπλα ένα τρίγωνο με την βάση από πάνω, που δηλώνει σαν βελάκι, ότι κάτι βγαίνει από κάτω! Η απλή λίστα εισαγωγής δείχνει μόνο το όνομα αυτό και όταν πατάμε σε αυτήν ανοίγει η λίστα για να επιλέξουμε. Αυτός ο τύπος γίνεται μενού επιλογής. Μπορούμε να καθορίσουμε το πλάτος της αναδυόμενης λίστας, αλλά το ύψος καθορίζεται αυτόματα. Βεβαίως το προς τα που θα ανοίξει η λίστα σχετίζεται με το που είναι το μενού (η επικεφαλίδα) σε σχέση με την οθόνη, ώστε πάντα η λίστα να είναι εντός οθόνης. Μπορεί δηλαδή η λίστα να βγει πάνω από την επικεφαλίδα.  Κατόπιν προγραμματίζουμε τις επιλογές του μενού. Μπορούμε να βάζουμε γραμμές διαχχωρισμού (δεν σταματάει σε αυτές ο δρομέας), να ορίζουμε αν η επιλογή είναι ενεργή ή όχι (βγαίνει με κόκκινο χρώμα η μη επιλογή), και επιπλέον μπορούμε να έχουμε δυο ακόμα ειδών επιλογές, τις λεγόμενες radiobutton, και τις τύπου checkbutton. Οι τύπου radiobutton δουλεύουν ως μια συνεχόμενη ομάδα όπου όμως μια από τα μέλη της μπορεί να "τσεκαριστεί" με ένα τετράγωνο αριστερά. Αντίθετα οι επιλογές τύπου checkbutton, είναι ανεξάρτητες και αυτές εμφανίζουν ένα τετράγωνο.

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

Τώρα ως προς το χειρισμό των μενού. Για να επιλέξουμε κάτι ή θα δώσουμε διπλό κλικ με ένα πλήκτρο του ποντικιού (και το δεξί πιάνει), ή θα σείρουμε την επιλογή στα δεξιά, ως σχεδόν να εξαφανιστεί και αφήνοντας την επιλογή είναι σαν να την επιλέξαμε. Αν δεν την αφήσουμε εκεί και την γυρίσουμε πίσω τότε δεν πιάνει σαν επιλογή μας.
Πριν ανοίξει το μενού και ενώ το έχουμε ζητήσει με πλήκτρο ή με το ποντίκι, στέλνει ένα γεγονός Open. Σε αυτό ρυθμίζουμε το ποια στοιχεία θα είναι ενεργά ή όχι, ή ποια checkbutton θα είναι τσεκαρισμένα ή όχι. Μπορούμε ακόμα και αν αλλάζουμε τα ονόματα! Δείτε όμως κάτι. Το συγκεκριμένο γεγονός δεν δίνει κάτι, πέρα ότι καλεί συγκεκριμένη συνάρτηση με το όνομα του στοιχείου και το επίθεμα .Open, Για να έχουμε πρόσβαση ή έλεγχο στις επιλογές πρέπει να δημιουργήσουμε πίνακες επιλογών, το οποίο είναι εύκολο, με την Με Στοιχείο, "όνομα ιδιότητας" ως Πίνακας1(). Δεν δίνουν όλες οι ιδιότητες πίνακες. Η βασική στα μενού λέγεται "label" και είναι η ετικέτα ή επικεφαλίδα του μενού. Οι πίνακες που μας ενδιαφέρουν (φαίνονται σαν πίνακες αλλά είναι ιδιότητες με μια παράμετρο), είναι των ιδιοτήτων "ListSelected" και "MenuEnabled". Η πρώτη έχει να κάνει με τα checkbutton, και η δεύτερη με όλα τα στοιχεία, όπου με 0 ή false τα απενεργοποιούμε.Κάθε επιλογή έχει ένα νούμερο, με την πρώτη να έχει το 0. Για κάθε στοιχείο μενού (που όπως είδαμε είναι λίστα εισαγωγής αναδυόμενη) έχουμε και το γεγονός dblClick() το οποίο δίνει τον αριθμό της επιλογής.

Εδώ πρέπει να ξεκαθαρίσω στον αναγνώστη ότι ενώ οι συναρτήσεις και τα τμήματα εξ ορισμού δεν βλέπουν τίποτα έξω από αυτές, εκτός των όποιων γενικών μεταβλητών και τμημάτων, οι συναρτήσεις γεγονότων είναι "ψεύτικες". Αφενός δεν μπαίνουν σε εκφράσεις (πράξεις). και αφετέρου το όνομα τους δεν είναι αυτό που βλέπουμε αλλά το όνομα του τμήματος ή της συνάρτησης όπου δημιουργήθηκαν. Με αυτόν τον τρόπο έχουμε πρόσβαση σε όλες τις μεταβλητές του τμήματος, καθώς και σε άλλες συναρτήσεις γεγονότων.  Ο τρόπος κλήσης διαφέρει, και για τα γεγονότα γίνεται με την Κάλεσε Τοπικά. Η λέξη τοπικά κάνει την παραλλαγή της κλήσης. Ότι ορίσουμε σε μια συνάρτηση εξυπηρέτησης γεγονότος, θα διαγραφεί. Επίσης όταν καλείται η συνάρτηση από το "παράθυρο" ξεκινάει με νέο σωρό τιμών. Η Κάλεσε εξ ορισμού μεταβιβάζει τον τρέχον σωρό τιμών του  καλούντος. Στη πρώτη  κλήση αυτό δεν έχει κέρδος, δηλαδή αν αφήσουμε δυο τιμές στο σωρό, αυτές θα διαγραφούν με την επιστροφή από την κλήση. Αν όμως καλέσουμε από άλλη συνάρτηση τη συγκεκριμένη, τότε θα μεταβιβαστεί και ο σωρός τιμών. Αυτό βολεύει όταν καλέσουμε μια άλλη συνάρτηση "τοπικά" και αφήσουμε τιμές στο σωρό τιμών (είναι ένας τρόπος να αποφύγουμε να δημιουργήσουμε μεταβλητή που θα πάρει την τιμή και μετά θα την περάσουμε ως έχει στην επόμενη κλήση).
Εδώ καλό είναι επίσης να ξεκαθαρίσουμε ότι η γλώσσα τρέχει πάνω σε ένα περιβάλλον γραμμένο σε Visual Basic 6, και ότι τα γεγονότα έχουν σχέση με αυτή, αν και είναι νέα δηλαδή δεν υπήρχαν τα στοιχεία ελέγχου και γράφτηκαν σε αυτήν. Τα ονόματα των γεγονότων είναι στα αγγλικά από επιλογή, γιατί δεν θα μπορούσαν να ήταν σε δυο γλώσσες (όπως είναι όλα τα αναγνωριστικά στα λεξιλόγια της Μ2000). Κάθε γεγονός πυροδοτεί μια συνάρτηση εξυπηρέτησης. Μπορούμε βέβαια τη μεταβλητή που δηλώνει το μενού να την έχουμε στα ελληνικά, αλλά στη συνάρτηση το όνομα θα είναι το ελληνικό του στοιχείου, μετά μια τελεία και όνομα του γεγονότος στα αγγλικά. Επιπλέον ως προς το πότε εκτελούνται έχει σημασία εδώ να πούμε ότι ενώ η γλώσσα είναι ενός νήματος εκτέλεσης, δηλαδή πάντα εκτελείται μόνο μια εντολή, η σειρά εκτέλεσης αλλάζει λόγω των γεγονότων. Μπορεί ένα γεγονός να έχει κολλήσει κάπου, πχ τραβάει ένα αρχείο από το δίσκο, αλλά αυτό δεν σημαίνει ότι άλλο γεγονός δεν θα εκτελεστεί. Στον meditor, έχει γραφτεί έτσι το πρόγραμμα ώστε να δίνει μήνυμα του πότε ξεκινάει το διάβασμα αρχείου και το πότε τελειώνει. Αν δε κλείσουμε την φόρμα, γίνεται σταμάτημα της φόρτωσης. Όσο δε φορτώνει το έγγραφο μπορούμε να μετακινούμε ή να αλλάζουμε το μέγεθος της φόρμας, που σημαίνει το τελευταίο ότι θα τρέξει κώδικας της Μ2000 για να ρυθμίσει το πώς θα εμφανίζονται τα στοιχεία ελέγχου. Αυτό μας κάνει να νομίζουμε ότι γίνονται παράλληλα εργασίες,αλλά στην ουσία κάθε γεγονός θα πάρει το χρόνο του για να εκτελεστεί. Επειδή ένα μενού που έχει σταλία μπορεί να ανοίξει και να καλέσουμε άλλη ή την ίδια εντολή, οι παράμετροι δεν διαβάζονται με την απλή Διάβασε αλλά με την Διάβασε Νέο, ώστε να φτιαχτούν σίγουρα νέες μεταβλητές. Πάντα το σύστημα τερματίζει το νεότερο προς το αρχαιότερο. Έτσι πάντα "καθαρίζουν" οι πιο πρόσφατες μεταβλητές.  Το σύστημα της Μ2000 έχει τις μεταβλητές σε μια γραμμή "χρόνου". Οι νεότερες διαγράφονται πρώτα. Σε άλλες γλώσσες αυτό γίνεται με το σωρό επιστροφής, return stack, αλλά εδώ ο σωρός επιστροφής είναι για το περιβάλλον της Μ2000, έτσι οι μεταβλητές που φτιάχνουμε πάνε σε μια ιδιόμορφη λίστα, που απλώνει στη λεγόμενη heap, σε όλη δηλαδή τη μνήμη. Αυτή η ιδιόμορφη λίστα κρατάει ονόματα και τιμές μαζί. Τα δε ονόματα έχουν προθέματα που τα διαφοροποιούν ως προς την θέαση. Ο αριθμός ονομάτων δεν ταυτίζεται πάντα με τον αριθμό τιμών/ Αυτό συμβαίνει γιατί κάποια ονόματα είναι "αναφορές" οπότε αναφέρονται σε τιμές που ήδη υπάρχουν άλλα ονόματα γι' αυτές. Τα γεγονότα του συστήματος παραθύρων χωρίζονται σε δυο ήδη, αυτά προς αναμονή, τα οποία δίνουν τιμές, και σε αυτά της άμεσης εξυπηρέτησης, τα οποία δίνουν με αναφορά τιμές. Πχ το γεγονός unload της φόρμας ζητάει να δώσουμε μηδέν ή μη μηδενική τιμή, με την τελευταία να σημαίνει, ακύρωση "αποφόρτωσης". Μπορούμε αν θέλουμε να μην "σηκώσουμε" τη αναφορά. Το σύστημα δεν το ενδιαφέρει το τι θα κάνουμε, η αλλαγή ή όχι της τιμής "εμάς" πονάει! Πχ αν έχουμε κάνει αλλαγές στο κείμενο στον διορθωτή meditor, και πατήσουμε το τετράγωνο που κλείνει τη φόρμα (θέλει διπλό κλικ, με ένα δεν πιάνει), τότε θα μας ρωτήσει αν θέλουμε να σώσουμε τις αλλαγές. Το κλείσιμο της φόρμας μπορεί να γίνει με alt+f4, από τη λίστα ελέγχου της φόρμας (δίπλα στο εικονίδιο, ένα μόνιμο μενού για χρήση και με το πληκτρολόγιο), με το τετράγωνο πάνω στην επικεφαλίδα της φόρμας (αντίθετα από το εικονίδιο), και μέσω του μενού File, με την επιλογή Quit. Όλες οι περιπτώσεις οδηγούν στον ίδιο κώδικα, που βλέπει αν πρέπει να ρωτήσει για να σώσει.

Παρακάτω είναι μια εικόνα από το σύστημα linux με τις δυο οθόνες, η δεύτερη είναι 32άρα τηλεόραση! Τρέχουν ταυτόχρονα τέσσερις παρουσίες του διερμηνευτή. Οι δυο δεξιά τρέχουν το info, από το οποίο ξεκίνησε το meditor, και αυτά έκλεισαν την κονσόλα (την ανοίγουν λίγο πλην τερματίσουν). Οι δυο αριστερά είναι τα προγράμματα που εκ κινήσαμε από τους διορθωτές. Το ένα από αυτά έχει ανοίξει ένα παράθυρο και περιστρέφει ένα 3D γραφικό. Δείτε επίσης στους διορθωτές. είναι ανοικτή η βοήθεια.




εδώ έχω ανοίξει ένα αρχείο 13.5Mbyte, με 575120 γραμμές (το πρόγραμμα ήταν ο παλιός meditor, δεν έχει το μενού Run!


Με το shift F2 ανοίγει φόρμα εισαγωγής για αναζήτηση προς τα πάνω (με shift F3 προς τα κάτω). Αν έχουμε επιλέξει μια λέξη τότε με τα F2 και F3 αναζητούμε χωρίς να βγει η φόρμα. Η λέξη καιρός είναι στην 240317 γραμμή (φαίνεται δίπλα στο μενού)


Παρακάτω είναι κώδικας της Μ2000, χρωματισμένος! Μπορούμε να ορίσουμε η εσοχή να είναι με tab ή με διαστήματα. Με F1 αλλάζουμε την εμφάνιση αναδίπλωση παραγράφου (με ή χωρίς).


Δείτε το νέο πρόγραμμα κατά την εγκατάσταση, ή απευθείας στο Github:
https://github.com/M2000Interpreter/Version9  στο info.gsb

Παρασκευή, 15 Φεβρουαρίου 2019

Revision 19, Version 97 Update (Gui Controls)

New from this revision:
1. Shift F9 in editor and in Editbox control toggle the editor mode from free line to center line (by default is the center line, which means we type in the center line, if there are enough  lines before the current one)
2. The directory/file dialog form now can take keys as we type and automatic find the file. If we move cursor then letters erased, also backspace erase letters too (we didn't saw letters but we saw the result, what we find)
3. Popup menu and the list of Combo control now move the cursor as we hover over it. Menus may have more lines, so we can hold the left mouse button to automatic scroll up or down (also there is a hidden vertical scroll bar, which get visible, at some state, so we can scroll using it, or we can use keys, like page up, page down, home and end).
4. Color, Font, File dialogs now use better the mouse wheel.


Δευτέρα, 11 Φεβρουαρίου 2019

Revision 16, Version 9.7

1. Refactoring for more speed.
2. Addition: Functions in Math object (hyperbolic trigonometric functions)
3. Identifiers from M2000 vocabulary can be used variables/functions, temporary in modules and functions.
4. Addition of modules (M2000 programs) in info.gsb file.
When we install the language, the info.gsb saved in program directory. We have to do this:

dir appdir$
load info

so now we can press F1 to save the file in M2000 user directory (we can open this directory in explorer using Win Dir$  where Dir$ is the current directory as string and Win is the shell statement of M2000)

This is the screen of m2000 console when we load info.gsb (there are commands which run automatic). Info.gsb has 7749 lines. The modules have names as the statement Modules ? return. Also in editor we can use F12 to display a list in a form, and we can click in any name and we get the code in that form.

We can open for edit the info.gsb without loading the modules, using the name in quotation marks (we press Esc to return and save the text, or Shift+F12 to abandon any change):
Edit "info.gsb"

The cyan border help for TV, so we have a safety area to display.





New modules are:


kb, a keyboard for playing music (run on Linux through Wine but with no sound, because utilize the Midi, and Wine has no sound banks to reproduce sound)



FL, a demonstration of rotating flowers. Moving the mouse they separate more, but pressing left mouse button all flowers follow the mouse. Right mouse for exit, with a nice effect of rotating zooming text.

tr

SH, demonstration: moving the console, and how we can get the desktop as an image.




TR, Three oscilloscopes, we can accelerate in any direction.



Σάββατο, 9 Φεβρουαρίου 2019

Revision 15 Version 9.7

Some last minute corrections. Also info.gsb has some added modules: Demo1 for simple 3d graphics in a user form (window), Json (using Lib3 module as library), BJ a black jack simulator, for 4 players.

Corrections:
Wine: From revision 15 was a fault in Esc key, so now is ok (this not happen when the same program, the M2000 interpreter run on a Windows OS).

Fix for For object {} so now old programs can run as expected.

To understand the next fix: When I change the Case in Select Case from executing one statement or a block of statements, to including many statements in one line (but not in block of statements), I gave to the method execution on group objects more than one statement. This was not bad, except for some special statements like restart and continue, which have to interpret at the level from we wish to get the effect of the statement. So the group method executed in a deeper level, and return without
allowing the execution of other statements, onto the deep level, but instead   (inside the functions of interpreter - interpreter is one top function calling other inside, and some of them may call interpreter again, and that is the meaning of the level).

Syntax color: Now anything is after Then and Else are as in a first line, so we get the proper color for operator =, which is white when we use it to assign a value, or yellow when used for comparisons.




Παρασκευή, 8 Φεβρουαρίου 2019

Αναθεώρηση 14, Έκδοση 9.7 Βελτιώσεις!

Σε αυτήν την αναθεώρηση βελτίωσα τη χρήση των Break και Ctrl+C. Επιπλέον το Esc σε ένα μπλοκ Δες {} ή Try {}  τώρα το σταματάει, μαζί με το κώδικα. Υπάρχει η εντολή ΔΙΑΦΥΓΗ ΟΧΙ ή ESCAPE OFF η οποία βγάζει εκτός το ESC.  Όταν τρέχουμε τον διερμηνευτή στην πιο γρήγορη ταχύτητα (ΓΡΗΓΟΡΑ ! ή FAST !, στη κονσόλα ή ΘΕΣΕ ΓΡΗΓΟΡΑ! ή SET FAST! σε πρόγραμμα), τότε δεν γίνονται αυτόματα ανανεώσεις της οθόνης. Παλαιότερα είχα συνδέσει την χρήση των CTRL+C και BREAK με την ανανέωση της οθόνης, αλλά τώρα το άλλαξα ώστε κάθε δευτερόλεπτο ο διερμηνευτής ελέγχει αν αυτά τα πλήκτρα είναι πατημένα, εκτός από την περίπτωση που εκτελεί κάποιο γεγονός (οπότε δεν το διακόπτουμε, αλλά αυτά είναι σύντομα) ή αν έχουμε φόρμες χρήστη. Επειδή στις φόρμες ισχύει το Alt F4 που κλείνει την φόρμα, δεν χρειάζεται άλλο τρόπο "κράτησης".

Μικρές βελτιώσεις στα νήματα, και επιπλέον βρήκα και ένα λάθος, στις λάμδα συναρτήσεις, όπου μια τιμή σε μια συνάρτηση της VB6 πέρναγε με αναφορά, ενώ ήταν από πίνακα, με συνέπεια σε αυτήν την συνάρτηση ο πίνακας να μην μπορούσε να αλλάξει μέγεθος (τον είχε κλειδώσει). Δεν το ήξερα και το βρήκα μέσω ενός παραδείγματος που έκανα με χρήση αναδρομής σε λάμδα συνάρτηση. Το παράδειγμα δεν ήταν σωστό και λογικά θα περίμενα να βγάλει Full Stack, δηλαδή ότι γέμισε ο σωρός επιστροφής Έχω φτιάξει το πρόγραμμα έτσι ώστε να μην πέφτει όταν γεμίζει ο σωρός επιστροφής, δηλαδή τον έχει μετρήσει στην αρχή της εκτέλεσης, και μετά ελέγχει το μέγεθός του, κάθε φορά που καλούμε ένα τμήμα ή μια συνάρτηση (επειδή αυτά είναι που τρώνε περισσότερο από το σωρό επιστροφής). Τελικά ως προς το πρόβλημα, λόγω του λάθους, αυτό που έπρεπε να βγει, ως ένδειξη λάθους δεν βγήκε! Αυτό σήμαινε ότι άλλο λάθος είχε προκύψει. Έτρεξα τον διερμηνευτή στο περιβάλλον της VB6, και το βρήκα! Το μεγαλύτερο πρόβλημα στο θέμα του λάθους, δεν είναι το πώς θα το λύσεις, αλλά το πότε μαθαίνεις για την ύπαρξή του. Άμα μάθεις λοιπόν για το λάθος, δεν αργείς να το διορθώσεις. Το πρόβλημα ήταν ότι όταν πέρναγα με αναφορά στοιχείο ενός πίνακα, δεν μπορούσα σε αυτόν τον πίνακα να αλλάξω μέγεθος. Στη Μ2000 μπορούμε να περνάμε με αναφορά στοιχείο πίνακα. Δείτε όμως πώς. Πρώτα η γλώσσα φτιάχνει μια πρόσκαιρη μεταβλητή, δίνει σε αυτήν την τιμή του στοιχείου του πίνακα, και μετά αυτή μεταφέρεται στο τμήμα που καλούμε. Στην επιστροφή από το τμήμα γίνεται η αντιγραφή από αυτή τη μεταβλητή στο στοιχείο του πίνακα...και εκεί μπορεί να βρεθεί λάθος αν ο πίνακας έχει λιγότερα στοιχεία, και δεν έχει θέση για αυτό που αρχικά πήραμε. H VB6 δίνει κατευθείαν την διεύθυνση του στοιχείου και κλειδώνει το πίνακα! Στην επιστροφή, τον ξεκλειδώνει!  Η λύση ήταν να αλλαχθεί ο τρόπος που πέρναγε η τιμή (αφού δεν με ενδιέφερε η αλλαγή της, δεν γίνονταν αλλαγή στη συνάρτηση που καλούσα), σε By Value, δηλαδή αντέγραφα τον αριθμό (από τον πίνακα) και έτσι η VB6 δεν τον κλείδωνε!

Τετάρτη, 6 Φεβρουαρίου 2019

Αναθεώρηση 13 Έκδοση 9.7

Διαγράφηκε κώδικας που εμφάνιζε λάθος ενώ δεν υπήρχε. Δηλαδή κάπου έγινα υπερβολικός πιστεύοντας ότι το κομμάτι των τεσσάρων γραμμών θα εμφάνιζε μήνυμα λάθους για μια κατάσταση, η οποία όμως δεν ήταν ανεπιθύμητη, και αφορούσε το κενό μεταξύ του χειριστή "=>" και ότι ακολουθεί.
Παρακάτω είναι κώδικας που δείχνει ό,τι επιλύθηκε το πρόβλημα (με αγγλικές εντολές):
Το πρόβλημα που έδινε η προηγούμενη έκδοση ήταν για το κενό μεταξύ του => και του SAY "OK", πράγμα που δεν μας ενδιαφέρει αφού γίνεται η δουλειά μας με και χωρίς κενό!

GROUP ALFA {
 GROUP BETA
 MODULE TEST_BETA {
  .BETA  =>  SAY "OK"
 }
}
CLASS BEING {
 MODULE SAY (A$) {
  PRINT A$
 }
}
Z=BEING()
\\ pointer show the names group (is a weak reference inside)
ALFA.BETA->Z
ALFA.TEST_BETA
\\ pointer show the float group (is a real pointer)
ALFA.BETA->(Z)
ALFA.TEST_BETA

Εκτός όμως από τα προβλήματα, σήμερα θα δείξω κάτι για την Λάμδα συνάρτηση:

Παρακάτω είναι ένα πρόγραμμα που δείχνει πώς η λάμδα συνάρτηση είναι τύπου τιμής και όχι αναφοράς, αλλά ως μέλος ομάδας (group) για την ομάδα είναι εσωτερικά τύπου αναφοράς (δηλαδή με δείκτη), που σημαίνει ότι αν αντιγράψουμε την Α στη Β και η Α έχει μια λάμδα συνάρτηση αυτή θα αντιγραφεί στο Β ως δείκτης, και έτσι τα οποιαδήποτε κλεισίματα (closures) θα είναι κοινά. Τα κλεισίματα (closures) στις λάμδα της Μ2000 είναι αντίγραφα την ώρα που δημιουργείται η λάμδα και παραμένουν εκεί και για τον κώδικα της λάμδα όταν τον καλούμε άμεσα αλλά και για την περίπτωση της αναδρομικής κλήσης, δηλαδή η λάμδα να καλέσει τον εαυτό της. Επειδή δεν μπορούμε να γνωρίζουμε το όνομα της συνάρτησης λάμδα (οι λάμδα είναι ανώνυμες ουσιαστικά), χρησιμοποιούμε το Λάμδα() ή το Λάμδα$() (lambda(), lambda$()) ως ονόματα για την κλήση αυτή. Τα ίδια ονόματα μπορούν να χρησιμοποιηθούν και σε απλές συναρτήσεις (επειδή και οι απλές έχουν τρόπο να μεταβιβαστούν με αναφορά, και έτσι πάλι χάνεται το αρχικό όνομα της συνάρτησης).


Μια μικρή εξήγηση του κώδικα. Πρώτα ορίζουμε την α ως την τιμή της lambda... (η λάμδα είναι ανώνυμη συνάρτηση και έτσι αυτό που πάει στην a είναι ένας δείκτης στην συνάρτηση, αυτό το λέμε αλλιώς ότι η a είναι αντικείμενο τύπου lambda.

Η λάμδα κατασκευάζεται με τέσσερα μέρη. Πρώτο μέρος είναι το αναγνωριστικό lambda (λάμδα) ή lambda$ (λάμδα$). Αυτό το μέρος λέει στον διερμηνευτή τι γυρίζει η λάμδα, από τα δυο: αριθμό ή αλφαριθμητικό. Μπορεί όμως να γυρίζει αντικείμενο, αλλά σημασία έχει το τι μπορεί να σταθεί αριστερά του ίσον. Εδώ έχουμε για αριθμούς και η μεταβλητή a μπορεί να δεχτεί αριθμούς άρα είμαστε εντάξει. Το δεύτερο μέρος είναι μια λίστα κλεισιμάτων. Η λίστα δεν έχει παρενθέσεις, και τα κλεισίματα μπορούν να έχουν ή να μην έχουν κάποια αρχική τιμή. Όταν δεν βάζουμε αρχική τιμή τότε πρώτα κοιτάει ο διερμηνευτής αν αυτό που έχουμε για κλείσιμο υπάρχει, αν ναι τότε το αντιγράφει, αν όχι το δημιουργεί με αρχικές τιμές. Δεν μπορούμε να περάσουμε πχ ένα πίνακα Α() χωρίς αυτός ήδη να υπάρχει. Μπορούμε όμως να περάσουμε αυτόματο πίνακα, πχ b=(1,2,3,4,5) θα κάνει το b ως κλείσιμο με δείκτη σε πίνακα πέντε στοιχείων. Μετά τα κλεισίματα  ακολουθεί μια λίστα παραμέτρων σε παρενθέσεις. Αυτό είναι προαιρετικό. Τόσο όσον αφορά το αν θέλουμε εισαγωγή παραμέτρων ως και σε όσον αφορά το πώς θα διαβάσουμε τις παραμέτρους.  Όταν έχουμε τη λίστα παραμέτρων τότε ο διερμηνευτής βάζει μια πρώτη γραμμή στο κώδικα ως Διάβασε και ότι ακολουθεί στη λίστα. Θα μπορούσαμε δηλαδή αντί να βάλουμε την λίστα με τις παραμέτρους πριν το βελάκι ->, να βάλουμε μια ή περισσότερες Διάβασε εντός του κώδικας. Ο κώδικας πάει μετά το βελάκι, ή ως μια παράσταση ή ως ένα μπλοκ με πολλές εντολές. Γενικά αν βάλουμε μια παράσταση ο διερμηνευτής φτιάχνει το μπλοκ και βάζει ένα = πριν την παράσταση. Οι συναρτήσεις στην Μ2000 επιστρέφουν τιμή με ένα = ως εντολή. Εδώ έχουμε μπλοκ και το = γυρνάει το χ. Μετά ακολουθεί η άνω και κάτω τελεία που δηλώνει ότι θα ακολουθήσει νέα εντολή και εκεί αυξάνουμε το χ κατά 2. Τα κλεισίματα στις Λάμδα στην Μ2000 μπορούν να αλλάξουν στις λάμδα, απλά η λάμδα δεν τα προσφέρει ως μέλη όπως κάνουν οι ομάδες. Τρίτο μέρος θεωρείται η λίστα παραμέτρων και τέταρτο μέρος ο κώδικας της συνάρτησης. Αν έχουμε ως παραμέτρους διαδοχικά πολλές λάμδα, τότε εκτός από την τελευταία τις άλλες τις βάζουμε σε παρενθέσεις (εκτός και όλα τα τέταρτα μέρη είναι μπλοκ). Αυτό συμβαίνει γιατί σε αυτήν την υλοποίηση της Μ2000 πριν την εκτέλεση μιας παράστασης ο διερμηνευτής με έναν γρήγορο τρόπο βγάζει συμπέρασμα αν είναι αλφαριθμητική ή αριθμητική η παράσταση που ακολουθεί για να καλέσει τις αντίστοιχες εσωτερικές δικές του συναρτήσεις.

Μετά ακολουθεί η δημιουργία ενός αντικειμένου χρήστη, η λεγόμενη ομάδα (Group). Εδώ  η ομάδα έχει όνομα G, και θα υπάρχει όσο το τμήμα που φτιάχτηκε συνεχίζει να εκτελείται. Σε αυτήν ορίζουμε μια ομάδα k με ένα μόνο αποτέλεσμα το 0 (δεν βάζουμε το =, θα το βάλει ο διερμηνευτής).
Μέλη στην ομάδα λέμε τις μεταβλητές και τους πίνακας. Η  λάμδα αφού έχει μεταβλητή είναι μέλος. Ουσιαστικά μέλη είναι και τα τμήματα (modules) και οι συναρτήσεις (functions) αλλά δεν τα λέμε μέλη, τα λέμε μεθόδους. Η λέξη ιδιότητα δηλώνει ένα είδος μέλους που λέγεται ιδιότητα, και είναι ουσιαστικά μια ομάδα που γυρνάει τιμή ή παίρνει τιμή ή κάνει και τα δύο, και μπορούμε να ελέγχουμε τι παίρνουμε και τι δίνουμε (σε άλλες γλώσσες αυτό θα ήταν ένα αντικείμενο με getters και setters).

Οπότε ξεκινάμε να δείξουμε ότι κάθε φορά που καλούμε την a() αυτή δίνει την τιμή του x και τον αυξάνει κατά 1. Μετά εισάγουμε στην G.k που είναι λάμδα την a. Ο διερμηνευτής βλέπει τις λάμδα ως πρώτους πολίτες (first citizen), που σημαίνει ότι λειτουργούν όπως οι μεταβλητές, παίρνουν και δίνουν αντίγραφο της τιμής τους. Εδώ το αντίγραφο θα είναι μαζί με τα αντίγραφα των κλεισιμάτων.

Επίσης φτιάχνουμε την ομάδα G1 ως αντίγραφο της G. Θα δούμε μετά γιατί το κάνουμε αυτό.

Για να δείξουμε ότι όντως έχουμε αντιγραφή του κλεισίματος x, αρκεί να τρέξουμε πρώτα την a() δυο φορές, ώστε να έχουμε τα 3 και 4 ως αποτέλεσμα και μετά να καλέσουμε στο G το τμήμα test_me το οποίο συγκρίνει μια τιμή που δίνουμε, τα 3 και 4 και αν συμπίπτει με την τιμή της λάμδα συνάρτησης k() (δείτε τη τελεία πριν το k στο κώδικα, λέει ότι το k είναι μέλος της ομάδας).

Μετά θέλουμε να δείξουνε ότι στην αντιγραφή ομάδας σε νέα ομάδα, η λάμδα ως μέλος θα αντιγραφεί ως δείκτης και όχι ως τιμή. Αρκεί να καλέσουμε την ίδια μέθοδο στο δεύτερο αντικείμενο, στο G1. Αν ήταν περασμένη με τιμή θα έπρεπε να ξεκινήσει η αρίθμηση από το 3 (αφού τότε εκεί ήταν η k του G. Όμως βλέπουμε ότι θα πάρουμε τιμές 4 και 5, άρα έχουμε αντιγραφή με δείκτη που δείχνει την ίδια λάμδα. Ο δείκτης είναι ένα αντικείμενο φορέας που περιέχει ένα δείκτη στην λάμδα. Αυτός ο φορέας είναι θεατός μόνο από τον διερμηνευτή. Αν τώρα βάλουμε πάλι στο k του G την τιμή του a, τότε θα δείξουμε ότι τα G και G1 δεν έχουν πια κοινή λάμδα! Αυτό πάλι είναι εύκολα κατανοητό εφόσον τρέξουμε την k του G που θα μας δώσει το 5 (αλλιώς θα μας έδινε το 7), και όντως η k του G1 δίνει 7. Επίσης βλέπουμε ότι η a δεν έχει αλλάξει και ότι αν καλέσουμε την συνάρτηση a() δυο φορές θα πάρουμε τα 5 και 4.



a=lambda x=1 ->{
 =x : x++
}
Group G {
 k=lambda ->0
 module test_me (n) {
  Print .k()=n
 }
}
Print a()=1, a()=2
\\ G.k get a copy of a
G.k=a
\\ G1.K get a reference of G.K
G1=G
Print a()=3, a()=4
G.test_me 3
G.test_me 4
\\ this shows that G1 get G.k by reference
G1.test_me 5
G1.test_me 6
\\ reloading G.k as a copy of a, so now G.k has a new pointer to a new copy of a
G.k=a
G.test_me 5
G1.test_me 7
Print a()=5, a()=6

Τρίτη, 5 Φεβρουαρίου 2019

Αναθεώρηση 12 (Τελική οπωσδήποτε)

Μια μικρή προσθήκη για τα windows XP και την εντολή Αναφορά ή Report. Η αρχικοποίηση του μεγέθους του στηλοθέτη (tab) δεν δίνονταν για την κονσόλα της Μ2000, για την συγκεκριμένη εντολή, και αυτό είχε ως αποτέλεσμα να έχει τιμή 0 που για τα Windows 7 η εντολή του λειτουργικού DrawTextEx (που χρησιμοποιείται από την Report ή Αναφορά) δίνει το εξ ορισμού μέγεθος 8, ενώ στα Xp η ίδια εντολή θέλει κάποιο αριθμό, το μηδέν το παίρνει ως μη χρήση του tab (χαρακτήρας με κωδικό 9).

Αναθεώρηση 11, Έκδοση 9.7 (Τελική)


Σε αυτήν την αναθεώρηση διορθώθηκε ο χρωματιστής εντολών (επαναφορά μιας λειτουργίας που "χάλασε" λόγω αλλαγής συμπεριφοράς μιας συνάρτησης, η λύση ήταν να βγεί μια άλλη τοπική ώστε να δουλεύει όπως είχε σχεδιαστεί)
πχ στο παρακάτω πρόγραμμα (Y Combinator) οι δυο πρώτες γιραμμές με την Print δεν εμφανίζονταν σωστά στον διοθρωτή. Υπάρχει το F11 για αυτές τις περιπτώσεις όπου αφαιρεί άμεσα το χρώμα, και η εμφάνιση επανέρχεται σωστά. Αλλά τώρα που έχει διορθωθεί, δεν υπάρχει θέμα χρήσης "αποχρωματισμού". Ο διορθωτής δεν φυλάει το χρώμα, δηλαδή όποτε ανοίγουμε ένα τμήμα να το διορθώσουμε το χρωματίζει άμεσα. Επίσης δουλεύει καθώς πληκτρολογούμε. Από την έκδοση 9.8 (είναι ακόμα στις αρχές της), ο χρωματιστής θα παίξει το ρόλο του lexical analyzer. Σκοπεύω να αλλάξω τον τρόπο εκτέλεσης. Τώρα ο μεταφραστής είναι ένα σύνολο συναρτήσεεων που καλούν η μια την άλλη, και παρέχουν τον κώδικα που η κάθε μια θα εκτελέσει σε μορφή αλφαριθμητικού. Κάθε φορά πχ που υπάρχει ένας αριθμός στο κώδικα, πχ το 10 θα πρέπει να κληθεί η συνάρτηση που από το κώδικα θα επιστρέψει το 10.  Με βόλεψε αυτή η κατάσταση για να φτιάξω το πρότυπο της γλώσσας. Τώρα έχει ολοκληρωθεί και έτσι το επόμενο βήμα θα είναι η σύσταση του λεγόμενου AST ώστε να έχουμε έναν AST Interpreter, όπου θα έχει ολοκληρωθεί το lexical analyzer και το syntax analyzer.

Το Abstract syntax tree (AST),  περιλαμβάνει κόμβους (Nodes) εκ των οποίων κάποιοι θα είναι τελικοί (leaf), πχ ένα αλφαριθμητικό, ή ένας αριθμός.

Ο χρωματιστής δίνει τις συναρτήσεις του για να φτιαχτεί το lexical analyzer. Στο τέλος το συντακτικό δένδρο, θα είναι αυτό που θα εκετελείται. Το δένδρο αυτό σου λέει ποια θα είναι η επόμενη εντολή και έχει όλες τις λφαριθμητικές παραστάσεις σε μορφή άμεσης εκτέλεσης χωρίς παρένθεση, δηλαδή το 2+3 θα είναι ως 2 3 +, ή βάλε 2, βάλε 3, Πρόσθεσε.
Δεν θα είναι εύκολη η υπόθεση γιατί πρέπει να υλοποιηθούν όλες οι ιδιαιτερότητες της Μ2000, όπως τα άλματα (GOTO) τα οποία σημαίνουν συνδέσεις μεταξύ των κόμβων του δένδρου. Ήδη υπάρχει προεργασία, πχ και τώρα όταν καλεί ο διερμηνευτής πχ την Print βρίσκει από ένα πίνακα κατακερματισμού σε χρόνο Ο(1) την διεύθυνση της συνάρτησης και την καλεί. Με αυτόν τον τρόπο καταργήθηκε ένα αρχικό μεγάλο Select Case, όπου σήμαινε ότι η τελευταία στη λίστα θα εκτελούνταν αφού πρώτα γίνονταν συγκρισεις σε κάθε άλλο μέλος της λίστας. Ο πίνακας κατακερματισμού δίνει με έναν τύπο (τη συνάρτηση κατακερματισμού) τη θέση του κλειδιού που ψάχνουμε, εδώ το αναγνωριστικό. Στην νέα έκδοση 9.αυτός ο πίνακας θα χρησιμοποιείται πάλι, αλλά τώρα δεν θα έχει το όνομα να ψάχνει αλλά έναν ακέραιο αριθμό (ακόμα πιο γρήγορα). Ο πίνακας των εντολών έχει δυνατότητα να αυξομειώνεται, ώστε εντολές όπως η Print ή Τύπωσε να μπορούν να αναπρογραμματιστούν, κατά την εκτέλεση. Έτσι το AST θα περιέχει τον κωδικό της Print, αλλά αν δεν έρθει η ώρα της εκτέλεσης δεν θα ξέρει  επακριβώς τι πρέπει να καλέσει, Αυτό θα συμβαίνει συνεχώς και για άλλους τύπους, όπως πχ μια λάμδα συνάρτηση, η οποία δεν ξέρει ποια είναι (επειδή οι λάμδα συναρτήσεις ειναι σαν μεταβλητές, μπορούν να δώσουν τον εαυτό τους ως τιμή και να πάρουν ως τιμή μια άλλη λάμδα, σημαίνει ότι κάπου στις μεταβλητές θα υπάρχει ένας δείκτης σε ένα Ast δένδρο, με όλες τις αναφορές έμμεσε, ώστε το ίδιο δένδρο να δουλεύει ταυτόχρονα για πολλές συναρτήσεις. Πχ μια τέτοια περίπτωση είναι η Y combinator. Αυτός λοιπόν παίρνει μια συνάρτηση και αποδίδει μια άλλη συνάρτηση ενώ έχει κάνει την αρχική ως τύπου αναδρομής. Ενώ δηλαδή η συνάρτηση δεν καλεί τον εαυτό της, εντέλει καλεί συναρτήσεις που είναι όπως ο εαυτός της, επειδή ο combinator την παρέχει. Υπάρχουν δυο τρόποι υλοποίησης. Ο πρώτος εμφανίζεται στις δυο πρώτες Τύπωσε ή Print. έχουμε μια δυο παραμέτρους g και x και εκτελείται το g(g,x), δείτε ότι η πρώτη παράμετρος είναι με τιμή πέρασμα της g (στην Μ2000 το πέρασμα με αναφορά γίνεται με το &, ενώ σε μεταβλητές που είναι δείκτες σε αντικείμενα, ακόμα και το πέρασμα με τιμή είναι εν μέρη πέρασμα με αναφορά, απλά δεν μπορεί να αλλάξει δείκτη προς το αντικείμενο από την πλευρά της κλήσης). Οι λάμδα συναρτήσεις αν περαστούν με τιμή, τότε δίνουν αντίγραφο του εαυτού τους, που σημαίνει ότι τα τυχόν κλεισίματα (closures) θα αντιγραφούν, θα περαστούν με τιμή δηλαδή.

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

Ο δεύτερο τρόπος παράγει μια λάμδα που κρατάει μια δεύτερη τον Y combinator. Η πρώτη δηλαδή απλά παίρνει έναν αριθμό, και περιέχει ως κλείσιμο τον Y combinator, και έτσι δεν χρειάζεται να το παρέχουμε σε κάθε κλήση.

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



Module Ycombinator {
      \\ factorial
      Print lambda (gx)->{=g(gx)}(lambda (gn)->if(n=0->1, n*g(gn-1)),10)
       \\ fibonacci
      Print lambda (gx)->{=g(gx)}(lambda (gn)->if(n<=1->n,g(gn-1)+g(gn-2)), 10)

      \\ Using closure in y, y() return function
      y=lambda (g)->lambda (x-> g(gx)
   
      fact=y((lambda (gn)-> if(n=0->1, n*g(gn-1))))
      Print fact(6)fact(24)
   
      fib=y(lambda (gn)->if(n<=1->n,g(gn-1)+g(gn-2)))
      Print fib(10)
}
Ycombinator

Σάββατο, 2 Φεβρουαρίου 2019

Τελική Αναθεώρηση 10 για Έκδοση 9.7.

Σε αυτή την αναθεώρηση διορθώθηκαν όλα τα προβλήματα των προηγούμενων αναθεωρήσεων. Επιπλέον μπήκε στο αρχείο M2000language.exe το αρχείο info.gsb το οποίο σώνεται στο φάκελο του προγράμματος
Μόλις εγκαταστήσουμε τη γλώσσα (αν έχουμε ήδη εγκαταστήσει προηγούμενη έκδοση κάνουμε απεγκατάσταση πρώτα), θα ανοίξει ο μεταφραστής και τότε δίνουμε τα παρακάτω:
dir appdir$
load info
Η πρώτη εντολή κάνειει το τρέχον κατάλογο να είναι ο κατάλογος της εφαρμογής (όπου βρίσκεται το m2000.exe). Από εκεί φορτώνουμε το info  (info.gsb) το οποίο εκτελεί άμεσα ένα τμήμα και μας δείχνει βασικές πληροφορίες. Αμέσως πατάμε το F1 (έχει προγραμματιστεί από το πρόγραμμα που φορτώσαμε) και σώνεται το πρόγραμμα στο φάκελο του χρήστη (πάμε σε αυτόν με dir user, αλλά ήδη έχει γίνει ). Οποιαδήποτε άλλη φορά θα γράφουμε απλά load info και θα φορτώνει.

Στο πρόγραμμα info.gsb υπάρχουν αρκετά τμήματα (είναι όλα στα αγγλικά), τα οποία μπορούμε να τρέξουμε. Το meditor είναι ένας διορθωτής προγραμμάτων Μ2000 σε παραθυρικό περιβάλλον. (δεν δείχνει όμως τη βοήθεια όπως το κάνει ο διορθωτής της κονσόλας-ίσως αναβαθμίσω το meditor, γιατί γίνεται και αυτός να δείχνει την βοήθεια)

Το δεύτερο μενού (Edit) παρέχει την δυνατότητα να αλλάζουμε από tab σε διαστήματα τον τρόπο που θα βάζει εσοχές. Επιπλέον όταν πατάμε το F10 και γίνεται αλλαγή προβολής από κανονική σε προβολή με μη φανερούς χαρακτήρες, και το ανάποδο, τότε παίρνουμε μήνυμα στην φόρμα και όταν ανοίξουμε το Edit τότε και αυτό ενημερώνεται.

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

Παρακάτω είναι το πρόγραμμα.

\\ notepad for M2000 programs (gsb files)
Show
Clear \\ Clear all variables/objects
Flush \\ Empty the stack
Title$="M2000 Pad"
Dir User
Title Title$, 0
Declare NotePad Form
Declare Pad EditBox Form NotePad
Declare File1 Combobox Form NotePad
Declare Edit1 Combobox Form NotePad
Declare Help1 Combobox Form NotePad
Declare Inform1 Button Form NotePad
Method Inform1, "Colors", 15, #FFA000
With Inform1, "Locked", true
Method Pad, "FontAttr", "Tahoma", 12, true   '  size=12, bold=true
With Pad, "NoWrap", True, "SetM2000", True, "SelLength" as SelLength
With File1,"label","File", "listtext" As list$, "list" As list$() '
With Edit1,"label","Edit",  "Mark", Color(255,100,0)
With Help1,"label","Help",  "Mark", Color(255,100,0)
With NotePad,"UseIcon", True, "UseReverse", True
With NotePad, "Title" As Caption$, "Visible" As Visible, "TitleHeight" As tHeight, "Sizable", True
\\ Call MakeStandardInfo, after setting Sizable to true to enable contol box's maximize button.
Method NotePad,"MakeStandardInfo", 1
With Pad, "Text" As Pad.Text$, "NoColor", False, "ShowAlways", True, "UseTab", True, "tabwidth", 6
Def TitleStr$(a$)=ucase$(left$(a$,1))+mid$(a$,2)
Filename$=Dir$+"Untitled.gsb"
Caption$=TitleStr$(File.Name$(Filename$)) +" - M2000 Pad"
Method NotePad,"move", 2000, 4000, 8000, 4000
Layer NotePad {Cls #FFA000}
With File1,"MenuStyle", True, "MenuWidth", 4000 
With Edit1,"MenuStyle", True, "MenuWidth", 4000 
With Help1,"MenuStyle", True, "MenuWidth", 4000 
With File1, "MenuEnabled" As mEnable()
For This {
 mi$="MenuItem"  \\ is a temporary variable only for For This Block
 Method File1, mi$,"Open",True
 Method File1, mi$,"Save",True
 Method File1, mi$,""    \\  only  a line here
 Method File1, mi$,"Close",True
 Method File1, mi$,"Quit",True
Rem Method File1, "Transparent"
 
 With File1, "MenuGroup","This"
 
 Method Edit1, mi$,"Cut",True
 Method Edit1, mi$,"Copy",True
 Method Edit1, mi$,"Paste",True
 Method Edit1, mi$,""
 Method Edit1, mi$,"Less Indent",True
 Method Edit1, mi$,"More Indent",True
 Method Edit1, mi$,""
 Method Edit1,"MenuRadio","Tabs for Indent",True,True
 Method Edit1,"MenuRadio","Spaces for Indent",True,false
 Method Edit1, mi$,""
 Method Edit1, mi$,"Show Hidden Characters", True, True
 
Rem Method Edit1, "Transparent"
 
 With Edit1, "MenuGroup","This"
 Method Help1, mi$,"About",True
Rem Method Help1, "Transparent"
 With Help1, "MenuGroup","This"
}
Def par_Status as boolean=false, old_status
old_status=par_Status
With Edit1,"ListSelected" as Edit1.Selected(), "MenuEnabled" As Edit1.Enabled()
With Pad, "showparagraph" as par_Status
Document BackUp$="\\Write something..."
Def ok as boolean
Pad.Text$=BackUp$
Function Notepad.Resize {
 Layer NotePad { Cls Color(255, 160, 0) ,0}
 With NotePad, "Width" As NP.Width, "Height" As NP.Height, "TitleHeight" As tHeight
 tHeight1=theight*2
 Method File1,"move", twipsX*2, tHeight,  twipsX*80, tHeight
 Method Edit1,"move", twipsX*2+twipsX*80, tHeight,  twipsX*80, tHeight
 Method Help1,"move", twipsX*2+twipsX*160, tHeight,  twipsX*80, tHeight
       Method Inform1,"move", twipsX*2+twipsX*240, tHeight,  twipsX*160, tHeight
 If NP.height>2000 Then {
  Method Pad,"move", twipsX*2, tHeight1,  NP.Width-twipsX*5, NP.Height-tHeight1-twipsx*3
  With Pad, "NoWrap" As NoWrap
  If Not NoWrap Then Method Pad,"Resize"
 }
}
Function Pad.Inform {
 Read New L, P
 if old_status<>par_status then
 With Inform1, "Caption",if$(par_status->"Hidden", "No Hidden")
 old_status=par_status
 else
 With Inform1, "Caption", format$("{0}-{1}", L,P)
 end if
 Method Pad,"Show"
}
Function SetTabs { With Pad, "UseTab", True,"tabwidth",6 With Inform1, "Caption","Set Tabs" Method Pad,"Show" } Function SetSpaces { With Pad, "SpaceIndent", 6 With Inform1, "Caption","Set Spaces" Method Pad,"Show" } Function ChangeHidden { Edit1.Selected(10)=not par_Status Method Pad,"PressKey", 121, 0 ' 121=vbkeyF10 old_status=par_status With Inform1, "Caption",if$(Edit1.Selected(10)->"Hidden", "No Hidden") Method Pad,"Show"       } Function Edit1.OpenMenu { Local X X=SelLength>0 Edit1.Enabled(0)=X Edit1.Enabled(1)=X Edit1.Selected(10)=par_Status With Inform1, "Caption",if$(Edit1.Selected(10)->"Hidden", "No Hidden") } Function Edit1.MenuChecked { Read New RadioIndex If RadioIndex=7 then Call Local SetTabs() else.If RadioIndex=8 then Call Local SetSpaces() else.If RadioIndex=10 then Call Local ChangeHidden() else With Inform1, "Caption","??" Method Pad,"Show" end if } Function Edit1.DblClick { Read New Edit1index Select Case Edit1index Case 0 Method Pad,"mn1sub" : Method Pad,"Resize" Case 1 Method Pad,"mn2sub" Case 2 Method Pad, "mn3sub" : Method Pad,"GetFocus" : Method Pad,"Resize" Case 4 Method Pad,"PressKey", 9, 1 Case 5 Method Pad,"PressKey", 9, 0 Case 7 Call Local SetTabs() Case 8 Call Local SetSpaces() Case 10 Call Local ChangeHidden() End Select } Function Pad.PopUp {       Read Local X, Y       Method Pad,"PopUpMenu", "",X , Y } Function File1.DblClick { Read New File1index Local cont, cont2, f$, NL$={ } File1index++ \\ Because we want some jumps..we use  On Goto \\ on Goto need here a block { On File1index Goto Open1, Save1, ExitNow, Save2, Unload Exitnow: Exit Open1: If Pad.Text$<>BackUp$ Then { If ask("Save Changes first?",Title$)=1 Then Goto Save1 } Layer NotePad { \\Using "**" we can go up to drives. Try ok { Open.file filename$,"**","Load M2000 (Gsb) File","gsb" } if not ok then push "" : Dir User } Method Pad,"GetFocus" Read f$ If f$<>"" Then Filename$=f$ If exist(F$) then { Clear BackUp$ Load.Doc BackUp$, f$ Caption$=TitleStr$(File.Name$(Filename$)) +" - M2000 Pad" \\ set the current directory dir file.path$(Filename$) Pad.Text$=BackUp$ } else Pad.text$="": Clear BackUp$ Method Pad, "Resize" End If Exit Save1: Layer NotePad { try ok { Save.As Filename$,"**","Save M2000 File","gsb" } if not ok then Push "" : Dir User } if not cont2 then Method Pad,"GetFocus" Read f$ If f$="" Then Exit If lcase$(file.type$(f$))<>"gsb" then f$=f$+".gsb" If Exist(f$) Then If Ask(NL$+"Overwrite"+NL$+f$,Title$)<>1 Then Exit Try ok { Clear BackUp$ BackUp$=Pad.Text$ Save.Doc BackUp$, f$ filename$=f$ Caption$=TitleStr$(File.Name$(Filename$)) +" - M2000 Pad" } If ok else beep If not cont then Exit Save2: cont=True If Pad.Text$<>BackUp$ Then { If ask("Save Changes?",Title$)=1 Then Goto Save1 } Clear BackUp$ Pad.Text$="" If Cont2 then Method NotePad, "CloseNow" Else FileName$=Dir$+"Untitled.gsb" Caption$=TitleStr$(File.Name$(Filename$)) +" - M2000 Pad" Method Pad, "Resize" End If Exit Unload: Cont2=True : Goto Save2 } } Function Help1.DblClick { Local A, info$ Info$={ This is an example of a notepad for M2000 Programs written in M2000 and run in M2000 Environment } A=Ask(info$,Title$,"","") } Function Notepad.InfoClick { Read New X If X=0 then Call Local Help1.DblClick() } Call Local Notepad.Resize() \\ make this as the default control (get focus) With Pad,"Default",True \\ open As modal Method NotePad,"Show", 1 Declare Pad Nothing Declare NotePad Nothing Print "Done"