Σάββατο 31 Αυγούστου 2019

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

1. Διορθώθηκε ένα λάθος που μόνο στο εκτελέσιμο εμφανίζονταν, ενώ μέσα από το περιβάλλον της VB6 δεν είχε θέμα, όπως επίσης δεν γύρναγε σφάλμα κατά την δημιουργία του εκτελέσιμου. Σε μια συνάρτηση δεν είχα δώσει τύπο μεταβλητής οπότε την είχε βάλει ως τύπου Variant. Ενώ την έδινα ως τύπου μακρύς (long), και με πέρασμα με αναφορά περίμενα να πάρω μια τιμή αλλά έπαιρνα την αρχική τιμή -1, δεν άλλαζε δηλαδή. Αυτό φαινόταν στην Image.Υ(A) όπου το A είναι ένα δείκτης σε Διάρθρωση μνήμης και περιέχει μια εικόνα (ως αρχείο στη μνήμη), για χρήση από το GDI σύστημα.  Επειδή στη αντίστοιχη για Χ είχα το long, δεν είχα πρόβλημα.
2. Έβαλα ένα νέο τμήμα στο Info.gsb με χρήση εικόνας η οποία περιέχεται στο κώδικα ως Resource μπλοκ, το οποίο περιέχει bytes σε μορφή base64 κωδικοποίηση. Μπορούμε από τον διορθωτή της Μ2000 να επιλέξουμε εισαγωγή αρχείου και μας ρωτάει αφού ανοίξει το αρχείο αν θέλουμε την μεταβλητή ελέγχου να την έχουμε ως αλφαριθμητικό με όνομα πχ Α$ ή ως διάρθρωση μνήμης πχ με Α.
3. Έκανα την επιλογή χρωμάτων στην πρώτη εγκατάσταση του διερμηνευτή να έχει τα χρώματα ματζέντα για φόντο  και κίτρινο για γράμματα. (παλιά ήταν μπλε και άσπρο). Μπορούμε με την εντολή Ρυθμίσεις να το αλλάξουμε. Δεν αλλάζει κάτι σε ήδη εγκατεστημένους διερμηνευτές.

Στο registry των Windows γράφεται το κλειδί HKEY_CURRENT_USER\Software\m2000v το οποίο αν το σβήσουμε στην επόμενη εκτέλεση της Μ2000 θα γραφτεί ξανά. Αυτοί είναι οι διακόπτες που φαίνονται με την εντολή Monitor (μαζί με τοπικούς διακόπτες, που αλλάζουν μόνο για την τρέχουσα εκτέλεση), και αλλάζουνε με την εντολή switches.
Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\m2000v5]
"FONT"="Verdana"
"NEWSECURENAMES"=dword:ffffffff
"SIZE"=dword:0000000e
"BOLD"=dword:00000001
"PEN"=dword:0000000e
"PAPER"=dword:00000005
"COMMAND"="LATIN"
"HTML"="DARK"
"TEXTCOMPARE"=dword:00000000
"DEC"=dword:ffffffff
"CASESENSITIVE"="NO"
"FOR-LIKE-BASIC"=dword:00000000
"PRIORITY-OR"=dword:00000000

New setup file.

I found a problem with Inno Setup 6.0.2. The new version make an exe file not combatible with XP os. So I change to Inno Setyp 5.6 (my previous version) to eliminate this issue.

Πέμπτη 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), και εδώ φαίνονται περιπτώσεις με πρώτο στοιχείο πότε με αριθμό και πότε με αλφαριθμητικό.


Τετάρτη 28 Αυγούστου 2019

Χρήση του Info.GSB

Χρήση του Info.GSB

Όταν πρώτη φορά εγκαταστήσουμε τη Μ2000 ή όταν την αναβαθμίσουμε με νεότερη έκδοση ή όταν θέλουμε να επαναφέρουμε το ήδη σωσμένο στο τρέχον κατάλογο το Info.gsb κάνουμε το παρακάτω:

Από την γραμμή εντολών της Μ2000 γράφουμε:
ΚΑΤΑΛΟΓΟΣ ΕΦΑΡΜΟΓΗ.ΚΑΤ$
ΦΟΡΤΩΣΕ info.gsb

Με το που φορτώνει τρέχει αυτόματα, γυρίζει ο τρέχον φάκελος στο φάκελο χρήστη και εμφανίζει επιλογές:
Πατάμε το F1
Και αυτόματα σώνεται στο τρέχον κατάλογο χρήστη (κάνει αυτόματα την αλλαγή)

Στο αρχείο info.gsb χρησιμοποιήθηκε μια έκδοση της FORM με το ! και τα νούμερα που θέλουμε για πλάτος και ύψος σε χαρακτήρες η οποία βάζει μεγαλύτερο περιθώριο. Επίσης χρωματίσαμε το περιθώριο. Αυτό έγινε γιατί μπορεί η οθόνη προβολής να είναι τηλεόραση και εκεί μερικές γραμμές δεν φαίνονται.

Όταν φορτώνεται το Info.gsb ρυθμίζονται τα πλήκτρα λειτουργιών (Function Keys). Στην εικόνα παραπάνω εμφανίζεται η λίστα πλήκτρων και το περιεχόμενό τους. Επίσης εμφανίζεται η λίστα τμημάτων όπως φορτώθηκε με το info.gsb (έχει 14073 γραμμές στην έκδοση 5.2, οι οποίες μοιράζονται σε όλα αυτά τα φορτωμένα τμήματα). Κάθε τμήμα που βλέπουμε είναι γενικό, και αυτό σημαίνει ότι έχει επεκταθεί η γλώσσα με εντολές τα ονόματα των τμημάτων.

Με το F3 εμφανίζεται πάλι η παραπάνω εικόνα.  Με F2 ανοίγει ο διορθωτής για το τμήμα που τρέχει αυτόματα και δείχνει την παραπάνω εικόνα.

Με το F8 ανοίγουμε τον παραθυρικό διορθωτή της Μ2000

Εδώ βλέπουμε το παράθυρο σε maximize μορφή, με φορτωμένο το info.gsb και το δρομέα στην τρίτη γραμμή από το τέλος. Η τελευταία εντολή του Info.gsb είναι η κλήση του τμήματος Info. Η κονσόλα έχει γίνει minimized.

Για να φορτώσουμε το αρχείο info.gsb (αφού το έχουμε σώσει με το F1 από τη κονσόλα), πατάμε το F8 να τρέξει το πρόγραμμα του παραθυρικού διορθωτή και αμέσως εμφανίζεται το παράθυρο με ένα μικρό κείμενο. Πατάμε στις τρεις οριζόντιες γραμμές πάνω αριστερά (δίπλα από εικονίδιο της Μ2000) και ανοίγει το control menu, και σε αυτό πατάμε το maximized ή πατάμε το μεσαίο εικονίδιο από τα εικονίδια πάνω δεξιά. Το control menu χρησιμοποιείται και με το πληκτρολόγιο, πατάμε το TAB και μόλις αλλάξει το χρώμα των τριών παράλληλων γραμμών σε άσπρο πατάμε το κάτω βελάκι και επιλέγουμε εντολή.

Το στοιχείο ΚΕΙΜΕΝΟ λειτουργεί όπως ο διορθωτής, με την διαφορά ότι τα TAB και SHIFT+TAB λειτουργούν για αλλαγή εστίασης σε γραφικό στοιχείο. Για να το χρησιμοποιήσουμε όπως στο διορθωτή πρέπει να χρησιμοποιήσουμε και το CTRL μαζί. Επίσης δεν υπάρχει ο αυτοματισμός του διορθωτή για χρήση και tab χαρακτήρα και διαστήματος, αλλά πρέπει να οριστεί με κώδικα.


Περί του διορθωτή της Μ2000

Περί του διορθωτή της Μ2000

Ο διερμηνευτής περιλαμβάνει δικό του διορθωτή προγράμματος. Αυτός ανοίγει με την εντολή Συγγραφή ή Σ ή Edit και κλείνει με το Esc ή το Shift+F12 αν δεν θέλουμε να περάσουν οι αλλαγές). Ο διορθωτής χρησιμοποιεί δικό του στοιχείο πάνω στην κονσόλα και δεν αλλάζει το περιεχόμενο της κονσόλας.

Σχέση με τη Λειτουργία της Χωριστή Οθόνης (Split Screen Function)
Επειδή η κονσόλα έχει λειτουργία χωριστής οθόνης (split screen) ο διορθωτής πάντα πιάνει το κάτω μισό (αυτό που στην κονσόλα ολισθαίνει). Αν ορίσουμε φόρμα με τη ΦΟΡΜΑ ή αλλάξουμε το παράθυρο της κονσόλας με το ΠΑΡΑΘΥΡΟ ή αλλάξουμε το τύπο της κονσόλας με την εντολή ΤΥΠΟΣ τότε παύει η λειτουργία της χωριστής οθόνης. Με την εντολή Οθόνη ορίζουμε χρώμα φόντου και γραμμή χωριστής οθόνης οπότε με ΟΘΟΝΗ ,0 δίνουμε χρώμα φόντου το τρέχον και παύει η λειτουργία χωριστής οθόνης.  Με ΟΘΟΝΗ, -10 ορίζουμε τις κάτω δέκα γραμμές ως γραμμές τις χωριστής οθόνης. Η εντολή Οθόνη χωρίς παραμέτρους καθαρίζει την οθόνη (το κάτω μέρος αν έχουμε χωριστή οθόνη).
Μπορούμε να αλλάζουμε τη γραμμή χωριστής οθόνης με την ΚΥΛΙΣΗ (SCROLL).
Αγγλικές εντολές FORM, WINDOW, MODE, CLS, SCROLL
Λειτουργία Διορθωτή

Ο διορθωτής λειτουργεί με παραγράφους. Κάθε γραμμή εντολής ουσιαστικά είναι μια παράγραφος. Εξ ορισμού ο διορθωτής κάνει αναδίπλωση γραμμής όταν αυτή είναι μεγαλύτερη από το πλάτος της οθόνης. Με το F1 αλλάζουμε την κατάσταση αναδίπλωσης. Υπάρχει ένα μενού επιλογών που ανοίγει με δεξί κλικ στο ποντίκι, με αριστερό κλικ στην γραμμή κατάστασης του διορθωτή (η γραμμή πάνω από κείμενο) ή με SHIFT+F10.  Το μενού μπορεί να μεταφερθεί αλλού αν κρατήσουμε με πατημένο το αριστερό κουμπί του ποντικιού στην επικεφαλίδα του μενού ή να αλλάξουμε το μέγεθός του από την κάτω δεξιά γωνία. Το μενού έχει περισσότερες επιλογές απ΄όσες φαίνονται και τις βρίσκουμε με κράτημα του αριστερού πλήκτρου του ποντικιού και κατέβασμα προς τα κάτω ή με την μπάρα ολίσθησης που εμφανίζεται στη δεξιά πλευρά όταν ο δείκτης του ποντικιού εισέρχεται στην περιοχή του (ομοίως και ο διορθωτής έχει μπάρα ολίσθηση κρυφή, και εμφανίζεται με τον ίδιο τρόπο).

Μεταφορά σε αριθμό γραμμής διορθωτή
Από το μενού μπορούμε με την πρώτη επιλογή να δώσουμε αριθμό γραμμής για μεταφορά του δρομέα.  Για παράδειγμα αν έχουμε ένα πρόγραμμα με 10 γραμμές τότε μπορούμε να δώσουμε το SHIFT+F10 να ανοίξουμε το μενού και αμέσως να γράψουμε 8 και να πατήσουμε enter. Το μενού κλείνει αν επιλέξουμε το κείμενο με κλικ με το ποντίκι ή αν πατήσουμε το Esc. Έτσι μπορούμε να δίνουμε άλλα νούμερα και να πατάμε enter και να βλέπουμε άμεσα τη γραμμή που μας ενδιαφέρει. Εδώ οι γραμμές έχουν να κάνουν με τις γραμμές που βλέπουμε και όχι με τις παραγράφους. Αν έχουμε επιλέξει την μη αναδίπλωση, με το F1, τότε οι γραμμές ταυτίζονται με τις παραγράφους.

Περί της χρήσης του TAB

Στην έκδοση 9 το TAB, δηλαδή το πλήκτρο TAB εξ ορισμού προσθέτει ένα γνήσιο χαρακτήρα TAB, το ASCII 9. Ο διορθωτής χειρίζεται το χαρακτήρα όπως και ένας επεξεργαστής κειμένου. Επιπλέον όταν θέλουμε να εισάγουμε διαστήματα δεξιά του κώδικα σε μια ή πολλές συνεχόμενες γραμμές τότε επιλέγουμε την γραμμή ή τις συνεχόμενες γραμμές και με το TAB προωθούνται δεξιά βάζοντας ένα χαρακτήρα TAB (αν έχουμε αναδίπλωση γραμμής το TAB θα μπει μόνο στην αρχή της παραγράφου). Με SHFIT TAB κάνουμε την ανάποδη ενέργεια. Με το F10 αλλάζει η κατάσταση προβολής. Υπάρχουν δυο καταστάσεις, η κανονική προβολή και η προβολή κρυφών χαρακτήρων. Με την εμφάνιση κρυφών χαρακτήρων εμφανίζεται και το σύμβολο του TAB όπως και της παραγράφου. Έτσι μπορούμε να δούμε πώς είναι πράγματι το κείμενο βάσει χαρακτήρων.

Επειδή σε παλιά προγράμματα γίνονταν αφαίρεση του χαρακτήρα TAB και αντικατάσταση με χαρακτήρες διαστήματος, ο διορθωτής κάνει το εξής. Όταν υπάρχει διάστημα στην αρχή της γραμμής τότε αντί να βάλει τον χαρακτήρα TAB βάζει διαστήματα. Αν θέλουμε μπορούμε να απενεργοποιήσουμε την χρήση του χαρακτήρα TAB με την εντολή ΔΙΑΚΟΠΤΕΣ "-TAB" ή SWITCHES "-TAB" και έτσι η χρήση του TAB γίνεται όπως στις παλιές εκδόσεις, με διαστήματα.
Μπορούμε να αλλάξουμε σε κώδικα το χαρακτήρα TAB με διαστήματα βάζοντας το πρόγραμμα στο πρόχειρο και εκτελώντας από την γραμμή εντολών (παίρνει το πρόχειρο και το αλλάζει):
ΠΡΟΧΕΙΡΟ ΑΛΛΑΓΗ$(ΧΑΡ$(9),ΕΠΑΝ$(" ",6),ΠΡΟΧΕΙΡΟ$)
Το πλάτος του TAB μπορεί να ορισθεί με την Σ ή Edit, για παράδειγμα η Σ ! 4 κάνει το TAB 4 χαρακτήρες πλάτος.

Μπορούμε να εισάγουμε ΤΑΒ με χαρακτήρες διαστήματος σε μια γραμμή αν υπάρχουν διαστήματα στην αρχή, όπως και αν υπάρχει διάστημα σε μια ομάδα γραμμών. Μπορούμε να εισάγουμε ΤΑΒ με χαρακτήρες διαστήματος σε μια γραμμή, που ξεκινάει χωρίς διάστημα με το SHIFT+TAB (το οποίο σε πολλές γραμμές βγάζει διαστήματα ή TAB, αλλά εδώ κάνει το αντίστροφό, βάζει διαστήματα, ως ειδική περίπτωση)

Χρήση σελιδοδεικτών.
Αν και τους λέμε σελιδοδείκτες δεν έχουν σχέση με σελίδες αλλά με παραγράφους. Υπάρχουν τρεις που γράφονται με τα F6, F7 και F8 Αν προσθέσουμε παραγράφους οι σελιδοδείκτες δεν χαλάνε, γιατί συνδέονται με το μοναδικό αριθμό μιας παραγράφου. Οι σελιδοδείκτες φυλάσσονται σε διαδοχικές χρήσεις του διορθωτή εφόσον διορθώνουμε το ίδιο τμήμα ή συνάρτηση.

Επιλογή/επικόλληση κώδικα από άλλο τμήμα/συνάρτηση ή από την βοήθεια
Αν θέλουμε από το διορθωτή να δούμε κώδικα άλλου τμήματος τότε αυτό γίνεται με το F12 όπου ανοίγει η βοήθεια με τα ονόματα που έχουν ήδη καταχωρηθεί και μπορεί να περιλαμβάνει και το τρέχον ήδη έχουμε ανοίξει μια φορά πριν την τρέχουσα. Με κλικ στο όνομα, στη φόρμα της βοήθειας, εμφανίζεται ο κώδικας - χωρίς χρωματισμό. Μπορούμε με κλικ σε μια κενή γραμμή στο διορθωτή να εμφανίσουμε το δρομέα και να επιλέξουμε το κείμενο που θέλουμε για να το αντιγράψουμε ή με χρήση Ctrl+C και μετά στο διορθωτή με Ctrl+V ή με σύρε και άφησε (drag and drop). Ομοίως με Shift+F1 ανοίγουμε την βοήθεια ή αν έχουμε επιλέξει μια εντολή τότε θα ανοίξει η βοήθεια για την εντολή αυτή.

Ο διορθωτής έχει πολλαπλά UNDO και REDO με τους συνδυασμούς πλήκτρων CTRL+Z και CTRL+Y.

Αυτόματο κλείσιμο εισαγωγικών "", παρενθέσεων () και αγκυλών {} και []. Όταν πατάμε το πρώτο πλήκτρο από τις δυάδες χαρακτήρων εμφανίζεται αυτόματα και ο δεύτερος και ο δρομέας εμφανίζεται ανάμεσα. Αν επιλέξουμε  κείμενο και πατήσουμε ένα από αυτά τα πλήκτρα (τα πρώτα στις δυάδες) τότε το κείμενο εμφανίζεται ανάμεσα και ο δρομέας στην αρχή του κειμένου.

Ειδικά για το {} μπορούμε να το δώσουμε με SHIFT+ENTER το οποίο βάζει το {} σε τρεις γραμμές με προώθηση κατά ένα TAB (οι χαρακτήρες διαστήματος αν έχουμε αλλάξει το σύστημα με την ΔΙΑΚΟΠΤΕΣ)

Αναζήτηση

Μπορούμε να κάνουμε αναζήτηση με SHIFT+F2 προς τα πάνω ή SHIFT+F3 προς τα κάτω με άνοιγμα διαλόγου εισαγωγής κειμένου προς εύρεση. Αν έχουμε επιλέξει λέξη τότε με F2 πάμε στην προηγούμενη ίδια λέξη ή με F3 στην επόμενη, αν υπάρχουν.

Αλλαγή λέξης, με χρήση UNDO

Με επιλογή λέξης και πάτημα του F5 ανοίγει διάλογος που ζητάει την λέξη που θα βάλουμε στη θέση της λέξης επιλογής σε όλο το κείμενο. Οι αλλαγές δείχνονται καθώς γίνονται, και στο τέλος μπορούμε να κάνουμε UNDO με χρήση του CTRL+Z, για κάθε αλλαγή χωριστά.

Αλλαγή λέξης με ίδια γράμματα κεφαλαία ή πεζά

Με επιλογή λέξης και πάτημα του F4 αλλάζουμε όλες τις λέξεις που έχουν τα ίδια γράμματα αλλά διαφέρουν σε πεζά-κεφαλαία με αυτήν της επιλογής. Αυτή η αλλαγή δεν έχει Undo και γίνεται ακαριαία.

Ελεύθερη Γραμμή Διόρθωσης

Με το SHIFT+F9 εναλλάσσουμε τη κατάσταση λειτουργίας σε ελεύθερη γραμμή διόρθωσης ή κεντρική γραμμή διόρθωσης. Στη κεντρική γραμμή διόρθωσης κάθε φορά που αλλάζουμε κάτι στο κείμενο, η γραμμή που αλλάζει αν γίνεται πάει στο κεντρική γραμμή της οθόνης του διορθωτή. Στην ελεύθερη γραμμή διόρθωσης η γραμμή δεν μεταφέρεται (σε κάποιες περιπτώσεις μεταφέρεται, όπως στην επιλογή από το μενού).

Μέτρηση λέξεων στο διορθωτή

Με F9 εμφανίζεται ο αριθμός λέξεων στο κείμενο. Είναι πολύ γρήγορος, για παράδειγμα στο αρχείο Info.gsb που έχει 14073 παραγράφους, βρίσκει 51968 λέξεις άμεσα (σε χρόνο μηδέν), στην έκδοση 5.2 του Info.gsb. (Στην έκδοση 34, έχουμε 166383 λέξεις σε 35183 γραμμές)
Οι λειτουργίες του διορθωτή γίνονται και στο στοιχείο Κείμενο του συστήματος παραθύρων της Μ2000. Πχ αν ανοίξουμε το Info.gsb και πατήσουμε το F8, θα τρέξει ο παραθυρικός διορθωτής της Μ2000 (είναι πρόγραμμα σε Μ2000) και αν εκεί ανοίξουμε το info.gsb θα ανοίξουν οι 14073 γραμμές και πατώντας το F9 θα πάρουμε το 51968 - γράφεται σε μια γραμμή που εμφανίζεται πρόσκαιρα στο διορθωτή σαν πρώτη γραμμή με πράσινο φόντο). Το στοιχείο ΚΕΙΜΕΝΟ έχει την επικεφαλίδα όπως ο διορθωτής αλλά είναι κρυφή και ανοίγει όταν χρειάζεται αυτόματα, και φεύγει αν ξεκινήσουμε διόρθωση του κειμένου.




Ένας γρήγορος τρόπος να μετρήσουμε το μέγεθος του info σε λέξεις, είναι να φορτώσουμε το info, να πατήσουμε το F8 για να ανοίξει ο παραθυρικός διορθωτής της Μ2000 (υπάρχει στο info ως M2000Editor), μετά επιλέγουμε από το μενού file to Open (επιλέγεται και με το Ctrl+O), και ανοίγει η φόρμα διαλόγου για επιλογή αρχείου, πατάμε τα πλήκτρα i n f o μέχρι να γίνει αυτόματα επιλογή του info.gsb και το ανοίγουμε, τέλος μόλις δούμε το κείμενο (πολύ γρήγορα) πατάμε το F9 και μας δίνει άμεσα απάντηση! Επίσης αν πατήσουμε το Ctrl+End πάμε στη τελευταία γραμμή και βλέπουμε δίπλα στο μενού τον αριθμό γραμμής και τη θέση του δρομέα με νούμερα.

Δευτέρα 26 Αυγούστου 2019

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

Προστέθηκαν δυο πράγματα;
1. Συνάρτηση HSL() ήΧΚΦ() χροιά, κορεσμός και φωτεινότητα. Τιμές βάζουμε στη χροιά μοίρες, στο κορεσμό από 0 έως 100 και στη φωτεινότητα από 0 έως 100. Το κόκκινο βγαίνει με HSL(0,100,50), αλλά και HSL(360,100,50). Η συνάρτηση γυρίζει έναν αρνητικό αριθμό. Στα χρώματα οι θετικοί από 1 έως 15, και μαζί με το 0 είναι τα στάνταρ χρώματα των windows (Default Colors), ενώ από το 0x80000000 (είναι double, και έχει τιμή σαν unsign 32 bit) είναι τα χρώματα των στοιχείων γραφικής διεπαφής των Windows (System Colors).

2. Font Load & Font Remove (Γραμματοσειρά Φόρτωσε & Γραμματοσειρά Διαγραφή) για όσο αυτός τρέχει. Αν τρέξουμε και δεύτερο διερμηνευτή τότε ο δεύτερος θα πρέπει να φορτώσει και αυτός τη γραμματοσειρά που θέλει. Η φόρτωση δεν σημαίνει και επιλογή. Η επιλογή γίνεται με την Font "όνομα γραμματοσειράς". Η choose.font ή επίλεξε.γραμματοσειρά μας ανοίγει ένα πλαίσιο διαλόγου για να επιλέξουμε γραμματοσειρά, και το αποτέλεσμα το γράφει στο σωρό τιμών. Πριν διαλέξουμε τη γραμματοσειρά, αν αυτή είναι μόνο ελληνική (δηλαδή δεν είναι unicode) πρέπει να ενημερώσουμε το επίπεδο (η εντολή Γραμματοσειρά "όνομα γραμματοσειράς" αλλάζει γραμματοσειρά στο επιλεγμένο επίπεδο). Η ενημέρωση γίνεται με την charset ή Χαρακτήρες και το νούμερο 161 (είναι τα ελληνικά για τις γραμματοσειρές που είναι μόνο ελληνικές). Πολλές γραμματοσειρές όπως αυτές οι δωρεάν στο http://www.aka-acid.com θέλουν το charset 161, αλλιώς δεν φορτώνουν!

Οι διακοπές τελείωσαν!
Καλό Χειμώνα!

Κυριακή 18 Αυγούστου 2019

Html Colors



A simple example just open M2000 interpreter, then write Edit A, paste this code, then press Esc, and write A and you get the results.

About program.
1. Module ShowColors is a module in module A. Function Title$() exist as string funcion, but here we make a user function (which hide the M2000 function, for this module). We can delete this function, because Title$() exist and have same behavior. Also we can change a M2000 function adding more parameters, or change the signature as we wish. Each inner module/function can be called only from code inside module. We can't call a sibling module/function, but we can make some modules or functions as global (module Global Inner { ... })

We can make two type of functions. The simple functions, and the lambda functions (see 2)

We call the Module ShowColors after we declare it, using its name. At calling M2000 pass the current stack of values in a process object, among the code of chosen Module. So the next statement after the call is a READ, which read from stack of values. A read statement can make variables. If a global variable exist with same name then a new local variable created. If a local variable exist then first the READ check the type of that variable and the type of the top value on stack and then if its ok do the read else raise an error. To read a global variable we have to use a line to line interpreter using Set, so a Set Read Alfa  read Alfa as a global variable (if exist assign value on it)

Module ShowColors has some parts. First is the function declaration of Tittles$(), then a Pen and a Cls (clear screen) set pen and background color. The next part make an Inventory, an object with keys and values. keys maybe numbers or strings (internal is always strings), and value can be anything (except simple functions and  modules, but we can create Groups which have functions and modules).

Before using Module ShowColors we have to delete all values from stack of values, or we can do this using a temporary stack STACK NEW { ShowColors :  ..... } and at the exit from the block we get the old stack, which preserve the Stack New { } block.

Here we use Flush to empty the stack. So the next part of Module ShowColors include some Data statements which place values to end of stack, so the first we place we read it first (FIFO). So to use the stack (which is a LIFO) as a FIFO we have to use Data  (using Push we use stack as LIFO). For this example we can change the DATA with PUSH, and we get the list in reverse order, but this isn't a problem.

The next part has two For loops. The first append 16 pairs to inventory list. The second print a list of list keys and use the value to change the color using a Pen color_value {} block which preserve at the exit the pen color before the use of Pen. We use the For Next and not For  { } block. We can use Next i or Next without variable name. A For always execute at least one (even with a zero step), at default behavior. We can change behavior using a  proper switch, where we get the For like this on Basic language). At default behavior we use absolute value of step, so a For I=16 to 1 step 1 { } call the block 16 times and i get value 0 at the end of the loop. In alternate behavior the sign used so we get no execution of block, and the I get 16 as value. From a module we can use Set Switches "+FOR" to set the BASIC type For (or "-FOR" to set the M2000 type of For).

2. The final part has two statements. We make a lambda function as css_c and we push the value of it on stack of values.

Creating the lambda function is easy. We have to use lambda clause (if the returned value isn't a string, or something which return a string, like another lambda function), After the lambda we can place any closure. The closure is a copy of  variable. but here the css_colors is an object pointer so we copy the pointer only. After the list of closures we can put a list of arguments (although this is a sugar code,  and the list of arguments is a Read statement as first statement in lambda function body. In M2000 all user functions except Event functions  have no signature for arguments, so we can pass anything and the Read statement can be raise the error, or we can read the types of stack and make whatever we want. In event functions because of multicast behavior (calling an event, which may have a list of functions, so multicasting means to passing to each function the same signature of parameters, as copies (including by reference parameters), so the signature checked before calling)

Inside lambda css_c we have a Try ok {} block. If we give a not exist key we get 0. Without the = statement (as first char) the function has the default Empty value. But we place a =0 before the try so we get the 0 as a double (or we can use =0& to return a long type, or 0%, for integer 16bit or 0@ dor decimal or 0# for currency or 0! for single float)
Look this example. k is a lambda but has no = statement. So the returned value is Empty. Variable N get the value Empty.

k=lambda -> {
}
N=k()
Print 1, 2, 3, 4
Print N, 0, k(), 1
Print N+1, N*1, Type$(N)="Empty"
we get  an empty column when we pass an Empty value, but Empty value is a 0 for calculations.

      1       2       3       4
               0                1
      1       0    True

3. So after the return from Module, all entities from Module deleted except the lambda function and inside this the inventory which kept as closure. We check this using some Print statements inside Pen {} statements.

4. Now we make another lambda function, which return a string, so we use lambda$. A lambda which return a string, if we don't provide a = statement we get an empty string (not empty value).

Here we pass a closure of another lambda. When this lambda execute the function body make three local variables, a$, clr and clr$. The two last have different names, the second one has a $ which also means that is a string.


5. One last thing
 For i=1 to 16
 Print i, :Pen css_colors(i-1!) {Print Title$(eval$(css_colors, i-1))}
 Next
An inventory has unique keys (except of the type of queue). If we delete a key then we loose the order of keys. We can sort the keys using the Sort statement. We can read a value using the name of inventory as a function. We can use the name of the inventory as a string function (using the $). So css_colors$("GRAY") return the number value as a string.
We can use the order of the key, using the ! after a number expression, where 0 is the first element. So we give css_color(ii-1!) to get values from 0 to 15. We can get the name of key using the ordinal number, using Eval$(css_color, i-1)

To find the ordinal number of a key we can use this (4th-1=3):
 If exist(css_colors,"WHITE") Then Print eval(css_colors, !)=3

The inventory deleted when the last pointer for it also deleted. The closure css_c is a copy, but has a copy of the pointer of the inventory. M2000 Interpreter delete the variables from the last, so first delete the ExportCssColor$() which delete it closure css_c which delete it closure css_colors (because there is another pointer to inventory, the inventory still exist). After that delete the css_c which delete the css_color closure, which release the inventory because it is the last pointer.



6. The code (put it in a Module)

Flush ' Empty the stack of values
Module ShowColors {
 Function Title$(a$) {
  =Ucase$(left$(a$,1))+Lcase$(mid$(a$,2))
 }
 Pen 14
 Cls #A0A022
 Print "CSS COLORS"
 \\ CSS colors
 inventory css_colors
 Data "BLACK", #000000, "SILVER", #C0C0C0
 Data "GRAY", #808080, "WHITE",  #FFFFFF
 Data "MAROON", #800000, "RED", #FF0000
 Data "PURPLE", #800080, "FUCHSIA", #FF00FF
 Data "GREEN", #008800, "LIME", #00FF00
 Data "OLIVE", #808080, "YELLOW", #FFFF00
 Data "NAVY", #000080, "BLUE", #0000FF
 Data "TEAL", #008080, "AQUA", #00FFFF
 For i=1 to 16: Append css_colors, letter$:=number: Next
 For i=1 to 16
 Print i, :Pen css_colors(i-1!) {Print Title$(eval$(css_colors, i-1))}
 Next
 
 css_c=lambda css_colors (a$) -> {
  =0
  Try ok {
   =css_colors(Ucase$(a$))
  }
 }
 Push css_c 
}
ShowColors
Read css_c
Pen css_c("Navy") {Print "Navy";string$("-", width-4);}
Pen css_c("Lime") {Print "Export html color from name"}
ExportCssColor$= lambda$ css_c (a$) -> {
 clr=css_c(a$)
 clr$=hex$(clr, 3)
 =Right$(clr$, 2)+Mid$(clr$, 3,2)+left$(clr$,2)
}
Print "Aqua = #"+ExportCssColor$("Aqua")
Print "Red = #"+ExportCssColor$("Red")
Print "Gray = #"+ExportCssColor$("Gray")

Κυριακή 11 Αυγούστου 2019

New certificate for binaries

Binaries updated with new certificate. Also info.gsb updated with the new Banker algorithm.

When the installation of M2000.exe  and M2000.dll done, you can insert the M2000.cer as a trust root certificate. All binaries have another certificate which chain to the root certificate.


New Banker Algorithm

I fixed the banker algorithm. Now includes two more examples, to display a safe and an unsafe state.



\\ No2
\\ First publish in Rosetta.org
\\ http://www.rosettacode.org/wiki/Banker%27s_algorithm#M2000_Interpreter
Module BankerAlgo {
      Form 80, 44
      Cls 5
      Pen 14
      Function Request(FromWhere as Inventory, What$, Many as long)  {
            =FromWhere(What$)-FromWhere(What$+"_Request")-Many>=0
      }
      Function RequestPreset(FromWhere as Inventory, What$, Many as long)  {
            =FromWhere(What$+"_Request")-Many>=0
      }
      Function Need(FromWhere as Inventory, What$, Many) { 
            =FromWhere(What$ + "_max")-FromWhere(What$)-Many>=0
      }
      \\ code for sub can be found from parent module/function (here parent as in code, not as in call)
      Function NewProcess {
            Inventory Process
            ApplyResources(Process)   ' sub need more arguments and read from current stack
            =Process
      }
      Inventory System, Processes 
      \\ Recource, Max, Available
      ApplyResources(System, "A", 6, 3,"B", 5,1,"C", 7, 1, "D", 6, 2)
      \\ Recource, Max, Available
      Append Processes, "P1":=NewProcess("A", 3, 1, "B", 3, 2, "C", 2, 2, "D", 2,1)
      Append Processes, "P2":=NewProcess("A", 1, 1, "B", 2, 0, "C", 3, 3, "D", 4,3)
      Append Processes, "P3":=NewProcess("A", 1, 1, "B", 3, 2, "C", 5, 1, "D", 0,0)
      Status(True) ' show all process, available resource and max
      SafeState=True
      Print "Current Status"
      RequestResource() ' display Safe State
      RequestResource("P2", "D", 1) ' display Safe State
      RequestResource("P1", "A", 1, "D", 1) ' display Safe State
      RequestResource("P1", "C", 1, "D", 1) ' display Too many resources ...
      RequestResource("P2", "B", 1) ' display Unsafe State
      RequestResource("P3", "C", 1)  ' display Safe State
      Status()
      \\ Second Example
      Clear System, Processes
      ApplyResources(System, "A", 10, 3)
      Append Processes, "P1":=NewProcess("A", 9, 3)
      Append Processes, "P2":=NewProcess("A", 4, 2)
      Append Processes, "P3":=NewProcess("A", 7, 2)
      Status(True) ' show all process, available resource and max    
      Print "Current Status"
      RequestResource() ' display Safe State
      \ Third Example
      Clear System
      ApplyResources(System, "A", 10, 2)
      Return  Processes,"P1":=NewProcess("A", 9,4)
      Status(True) ' show all process, available resource and max    
      Print "Current Status"
      RequestResource() ' display UnSafe State       
      Sub Respond()
            If SafeState Then {
                  Pen 15 {Print "Safe State"}
            } Else Pen 13 {Print "Unsafe State"}
      End Sub
      Sub WaitForKey()
            Pen 11 {Print "Press a key"}
            local a$=key$
      End Sub
      Sub RequestResource(ProcessName$="" )
            SafeState=True
            If ProcessName$="" Then CheckNewState(&SafeState) : Respond() : Print : WaitForKey():Exit Sub
            Local pro=Processes(ProcessName$), ResourceName$, many as long
            ClearAllRequest(pro)
            Local skip=False
            While Match("SN") {
                  Read ResourceName$, many
                  Print  Format$("Claim {1} for type {0} resource ",ResourceName$, many)
                  If skip Then Continue
                  If Request(System, ResourceName$, many) Then {
                        If Need(pro, ResourceName$, many) Then { 
                              Return pro, ResourceName$+"_Request":=many
                              Return System, ResourceName$+"_Request":=-many
                        } Else {
                              Print "Too many Recources "+ResourceName$+" for Process "+ProcessName$  : Skip=True
                        }
                  } Else Print "Too many Recources for System" : Skip=True
                  If Skip Then exit
            } 
            If skip Else  CheckNewState(&SafeState) : Respond()
            Print  ' just a new line
            WaitForKey()
      End Sub
      Sub ApplyResources(Where as Inventory, What$, MaxValue, InitialValue)
            Repeat {
                  If Not Exist(Where, What$) Then {
                        Append Where, What$:=InitialValue, What$+"_max":=MaxValue, What$+"_Request":=0
                  }
                  If not Match("SNN") Then Exit
                  Read What$, MaxValue, InitialValue
            }  Always
      End Sub
      Sub ClearAllRequest(Where  as Inventory)
            Local M=Each(Where)
            While M {
                  If Instr(Eval$(M, M^),"_")=0 Then {
                        Return Where, Eval$(M,M^)+"_Request":=0
                  }
            }
      End Sub
      Sub PrintResources(Where  as Inventory)
            Local M=Each(Where)
            While M {
                  If Instr(Eval$(M, M^),"_")=0 Then Print Eval$(M, M^)+"="+Eval$(M),
            }
            Print
      Exit Sub
      Sub PrintMax(Where  as Inventory)
            Local M=Each(Where)
            While M {
                  If Instr(Eval$(M, M^),"_max")>0 Then Print LeftPart$(Eval$(M, M^), "_")+"="+Eval$(M),
            }
            Print
      Exit Sub
      Sub Status(Ok as boolean=False)
            Print "Total System Resources"
            PrintMax(System)
            Print "Available Resources in System"
            PrintResources(System)
            If Not Ok Then WaitForKey(): Exit Sub
            Local  M=Each(Processes)
            While M {
                  Print "Process "+Eval$(M, M^)
                  PrintResources(Processes(M^!))  ' give index M^ as Key index number (using !)
                  Print "Maximum Resources for "+Eval$(M, M^)
                  PrintMax(Processes(M^!))
            }
      End Sub
      Sub CheckNewState(&Ok)
            local M=Each(Processes), M1, count=len(Processes), alive(0 to count-1)=1
            Local Z, Recource$, safe as boolean=false
            While count {
                  safe=false
                  While M {
                        If alive(M^) Then {
                              Z=Processes(M^!)
                              M1=Each(Z) 
                              safe=True 
                              While M1 {
                                    Recource$=Eval$(M1, M1^)
                                    If Instr(Recource$,"_")=0 Then {
                                         safe=System(Recource$)+System(Recource$+"_Request") >= Z(Recource$ + "_max") - Z(Recource$)-Z(Recource$ + "_Request")
                 }
                                    If not safe Then exit
                              }
                              If safe Then {
                                    print format$("Process {0} is executing", M^+1)
                                    alive(M^)=0
                                    count--
                                    M1=Each(Z) 
                                    While M1 {
                                          Recource$=Eval$(M1, M1^)
                                          If Instr(Recource$,"_")=0 Then {
                                                Return System, Recource$+"_Request":= System(Recource$+"_Request") + Z(Recource$) + Z(Recource$+"_Request")
                                                Return Z, Recource$+"_Request":=0
                                          }
                                    }
                              }
                        }
                  }
                  If safe Else exit
            }
            Ok=safe
            ClearAllRequest(System)
      End Sub
}
BankerAlgo