Τρίτη 19 Μαΐου 2026

Test Enumeration - Δοκιμές Απαρίθμησης

 English Version:



locale 1033  ' we get True and False - using 1032 we get the Greek words
Module TestEnumNumericValue {
print "Test Enumeration Type of Numeric Value"
enum alfa {
kappa
delta
}
var m as alfa
print m=1, eval$(m)="kappa", m=kappa, type$(m)="alfa", m^=0
m++
print m=2, eval$(m)="delta", m=delta, type$(m)="alfa", m^=1
m=1
print m=1, eval$(m)="kappa", m=kappa, type$(m)="alfa", m^=0
try ok {
m=100
}
if error or not ok then print error$ 'we get error message Expected Enumaration Type
print m=1, eval$(m)="kappa", m=kappa, type$(m)="alfa", m^=0

clear
' clear all local variables
' make alfa start from 0 (by default is 1), also make the error value active
enum alfa {
kappa=0 ' we can use 0& for long type or 0&& for long long etc..
delta
error:
novalue=-1
}
var m as alfa
print m=0, eval$(m)="kappa", m=kappa, type$(m)="alfa", m^=0
m++
print m=1, eval$(m)="delta", m=delta, type$(m)="alfa", m^=1
m=0
print m=0, eval$(m)="kappa", m=kappa, type$(m)="alfa", m^=0
' this is bad value (not exist in values list of enumaration)
m=100
' then m turn to error vaue
print m=-1, eval$(m)="novalue", m=novalue, type$(m)="alfa", m^=2
m=kappa
do
print m^, type$(m^)="Long", eval$(m)
if m^=alfa^ then exit
m++
always
' we may have members of an enumaration with same value
clear
enum alfa {
kappa=0 ' we can use 0& for long type or 0&& for long long etc..
delta
epsilon=0
omega
error:
novalue=-1
}
var m as alfa
zeta=each(alfa)
oldtab=tab
// $(6,6) means center propotional print at 6 character's place column
print $(6, 6),"value", "name", "type","index", "same"
while zeta
m=eval(zeta) '  an object at index zeta^
? m, eval$(m), type$(m), m^, m^=zeta^
end while
print $(0, oldtab)
// we don't get the error value. Error value has index 4 now, but is out of the normal range.

}
module TestEnumStringValue {
print "Test Enumeration Type of String Value"
enum alfa {
kappa="North"
delta="East"
}
var m as alfa
print m="North", eval$(m)="kappa", m=kappa, type$(m)="alfa", m^=0
m++
print m="East", eval$(m)="delta", m=delta, type$(m)="alfa", m^=1
m="North"
print m="North", eval$(m)="kappa", m=kappa, type$(m)="alfa", m^=0
try ok {
m="Beep"
}
if error or not ok then print error$ 'we get error message Expected Enumaration Type
print m="North", eval$(m)="kappa", m=kappa, type$(m)="alfa", m^=0
clear
' clear all local variables
' make the error value active
enum alfa {
kappa="True"
delta="False"
error:
novalue="?"
}
var m as alfa
print m="True", eval$(m)="kappa", m=kappa, type$(m)="alfa", m^=0
m++
print m="False", eval$(m)="delta", m=delta, type$(m)="alfa", m^=1
m="True"
print m="True", eval$(m)="kappa", m=kappa, type$(m)="alfa", m^=0
' this is bad value (not exist in values list of enumaration)
m="Beep"
' then m turn to error vaue
print m="?", eval$(m)="novalue", m=novalue, type$(m)="alfa", m^=2
m=kappa
do
print m^, type$(m^)="Long", eval$(m)
if m^=alfa^ then exit
m++
always
' we may have members of an enumaration with same value
clear
enum alfa {
kappa="True"
delta="False"
epsilon="True"
omega="False"
error:
novalue="?"
}
var m as alfa
zeta=each(alfa)
oldtab=tab
// $(6,6) means center propotional print at 6 character's place column
print $(6, 6),"value", "name", "type","index", "same"
while zeta ' this is a variation of while using an iterator object
m=eval(zeta) '  an object at index zeta^
print m, eval$(m), type$(m), m^, m^=zeta^
end while
print $(0, oldtab)
// we don't get the error value. Error value has index 4 now, but is out of the normal range.
}
TestEnumNumericValue
TestEnumStringValue


Greek Version:



Τοπικό 1032 'θα έχουμε στα ελληνικά το Αληθές Ψευδές
Τμήμα ΔοκιμήΑπαρίθμησηςΑριθμητικήςΤιμής {
τύπωσε "Δοκιμή Απαρίθμησης με Αριθμητική Τιμή"
απαρ άλφα {
κάππα
δέλτα
}
μεταβλητή μ ως άλφα
τύπωσε μ=1, εκφρ$(μ)="κάππα", μ=κάππα, τύπος$(μ)="άλφα", μ^=0
μ++
τύπωσε μ=2, εκφρ$(μ)="δέλτα", μ=δέλτα, τύπος$(μ)="άλφα", μ^=1
μ=1
τύπωσε μ=1, εκφρ$(μ)="κάππα", μ=κάππα, τύπος$(μ)="άλφα", μ^=0
δες οκ {
μ=100
}
αν λάθος ή όχι οκ τότε τύπωσε λάθος$ 'θα πάρουμε το μήνυμα Λάθους Περίμενα τύπο απαρίθμησης
τύπωσε μ=1, εκφρ$(μ)="κάππα", μ=κάππα, τύπος$(μ)="άλφα", μ^=0

καθαρό
' καθαρίζουμε όλες τις τοπικές του τμήματος
' κάνουμε το άλφα να ξεκινάει από το 0 (εξ ορισμού είναι το 1), επίσης ενεργοποιούμε τη λάθος τιμή.
απαρ άλφα {
κάππα=0 ' με 0& για Μακρύς ή 0&& για Μακρύς Μακρύς κ.ο.κ.
δέλτα
λάθος:
μη_τιμή=-1
}
μεταβλητή μ ως άλφα
τύπωσε μ=0, εκφρ$(μ)="κάππα", μ=κάππα, τύπος$(μ)="άλφα", μ^=0
μ++
τύπωσε μ=1, εκφρ$(μ)="δέλτα", μ=δέλτα, τύπος$(μ)="άλφα", μ^=1
μ=0
τύπωσε μ=0, εκφρ$(μ)="κάππα", μ=κάππα, τύπος$(μ)="άλφα", μ^=0
' δίνουμε μια τιμή που δεν υπάρχει στη λίστα τιμών της απαρίθμησης
μ=100
' το μ θα πάρει την τιμή λάθους
τύπωσε μ=-1, εκφρ$(μ)="μη_τιμή", μ=μη_τιμή, τύπος$(μ)="άλφα", μ^=2
μ=κάππα
επανέλαβε
τύπωσε μ^, τύπος$(μ^)="Long", εκφρ$(μ)
αν μ^=άλφα^ τότε έξοδος
μ++
πάντα
' μπορούμε να έχουμε μέλη απαρίθμησης με ίδια τιμή
καθαρό
απαρ άλφα {
κάππα=0 ' με 0& για Μακρύς ή 0&& για Μακρύς Μακρύς κ.ο.κ.
δέλτα
έψιλον=0
ωμέγα
λάθος:
μη_τιμή=-1
}
μεταβλητή μ ως άλφα
ζήτα=κάθε(άλφα) ' το ζήτα είναι ένα αντικείμενο επαναλήπτης με το άλφα εντός
παλιά_στήλη=στήλη
// $(6,6) σημαίνει αναλογική γραφή με κεντράρισμα στη στήλη και στήλη 6 χαρακτήρων (μη αναλογικών)
τύπωσε $(6, 6),"τιμή", "όνομα", "τύπος","δείκτης", "όμοιος"
ενώ ζήτα ' η ενώ εδώ είναι παραλλαγή της ενώ και δουλεύει με επαναλήπτη
μ=εκφρ(ζήτα) '  μας δίνει ένα αντικειμενο του άλφα με δείκτη ζήτα^
τύπωσε μ, εκφρ$(μ), τύπος$(μ), μ^, μ^=ζήτα^
τέλος ενώ
τύπωσε $(0, παλιά_στήλη)
// δεν θα δούμε την τιμή του λάθους εδώ γιατί είναι εκτός λίστας (πάντα είναι στο δείκτη άλφα^+1, ακριβώς μετά το τελευταίο)
}
Τμήμα ΔοκιμηΑπαρίθμησηςΑλφαριθμητικήςΤιμής {
τύπωσε "Δοκιμή Απαρίθμησης με Αλφαριθμητική Τιμή"
απαρ άλφα {
κάππα="North"
δέλτα="East"
}
μεταβλητή μ ως άλφα
τύπωσε μ="North", εκφρ$(μ)="κάππα", μ=κάππα, τύπος$(μ)="άλφα", μ^=0
μ++
τύπωσε μ="East", εκφρ$(μ)="δέλτα", μ=δέλτα, τύπος$(μ)="άλφα", μ^=1
μ="North"
τύπωσε μ="North", εκφρ$(μ)="κάππα", μ=κάππα, τύπος$(μ)="άλφα", μ^=0
δες οκ {
μ="Beep"
}
αν λάθος ή όχι οκ τότε τύπωσε λάθος$ 'θα πάρουμε το μήνυμα Λάθους Περίμενα τύπο απαρίθμησης
τύπωσε μ="North", εκφρ$(μ)="κάππα", μ=κάππα, τύπος$(μ)="άλφα", μ^=0
καθαρό
' καθαρίζουμε όλες τις τοπικές του τμήματος
' ενεργοποιούμε τη λάθος τιμή.
απαρ άλφα {
κάππα="Αληθές"
δέλτα="Ψευδές"
λάθος:
μη_τιμή="?"
}
μεταβλητή μ ως άλφα
τύπωσε μ="Αληθές", εκφρ$(μ)="κάππα", μ=κάππα, τύπος$(μ)="άλφα", μ^=0
μ++
τύπωσε μ="Ψευδές", εκφρ$(μ)="δέλτα", μ=δέλτα, τύπος$(μ)="άλφα", μ^=1
μ="Αληθές"
τύπωσε μ="Αληθές", εκφρ$(μ)="κάππα", μ=κάππα, τύπος$(μ)="άλφα", μ^=0
' δίνουμε μια τιμή που δεν υπάρχει στη λίστα τιμών της απαρίθμησης
μ="Beep"
' το μ θα πάρει την τιμή λάθους
τύπωσε μ="?", εκφρ$(μ)="μη_τιμή", μ=μη_τιμή, τύπος$(μ)="άλφα", μ^=2
μ=κάππα
' το άλφα εξ ορισμού έχει δείκτη στο τελευταίο κανονικό στοιχείο (όχι στο λάθος)
επανέλαβε
τύπωσε μ^, τύπος$(μ^)="Long", εκφρ$(μ)
αν μ^=άλφα^ τότε έξοδος
μ++ ' αλλάζουμε τιμή με αλλαγή του δείκτη αλλά δεν αλλάζει στο τέρμα.
πάντα
' μπορούμε να έχουμε μέλη απαρίθμησης με ίδια τιμή
καθαρό
απαρ άλφα {
κάππα="Αληθές"
δέλτα="Ψευδές"
έψιλον="Αληθές"
ωμέγα="Ψευδές"
λάθος:
μη_τιμή="?"
}
μεταβλητή μ ως άλφα
ζήτα=κάθε(άλφα) ' το ζήτα είναι ένα αντικείμενο επαναλήπτης με το άλφα εντός
παλιά_στήλη=στήλη
// $(6,6) σημαίνει αναλογική γραφή με κεντράρισμα στη στήλη και στήλη 6 χαρακτήρων (μη αναλογικών)
τύπωσε $(6, 6),"τιμή", "όνομα", "τύπος","δείκτης", "όμοιος"
ενώ ζήτα ' η ενώ εδώ είναι παραλλαγή της ενώ και δουλεύει με επαναλήπτη
μ=εκφρ(ζήτα) '  μας δίνει ένα αντικειμενο του άλφα με δείκτη ζήτα^
τύπωσε μ, εκφρ$(μ), τύπος$(μ), μ^, μ^=ζήτα^
τέλος ενώ
τύπωσε $(0, παλιά_στήλη)
// δεν θα δούμε την τιμή του λάθους εδώ γιατί είναι εκτός λίστας (πάντα είναι στο δείκτη άλφα^+1, ακριβώς μετά το τελευταίο)
}
ΔοκιμήΑπαρίθμησηςΑριθμητικήςΤιμής
ΔοκιμηΑπαρίθμησηςΑλφαριθμητικήςΤιμής



Δευτέρα 18 Μαΐου 2026

Ταξινόμηση τύπου Κύκλου

 Η τακινόμηση τύπου κύκλου είναι ένας αλγόριθμος ταξινόμησης με τα παρακάτω χαρακτηριστικά:

- In Place  (Στο τόπο) : Η ταξινόμηση γίνεται στον ίδιο πίνακα όχι σε βοηθητικό ή πρόχειρο.

- Unstable (Ασταθής): Μια ασταθή ταξινόμηση είναι αυτή που τα όμοια "κλειδιά" χάνουν την σειρά τους. Αν είχαμε για κάθε κλειδί μια τιμή δεδομένων τότε θα βλέπαμε τα δεδομένα να χάνουν την σειρά τους από αυτήν που είχαν στην αρχική τοποθέτηση στο πίνακα. Εδώ δεν έχουμε τιμές και κλειδιά, αλλά θα μπορούσαμε να είχαμε και έναν  δεύτερο πίνακα με τιμές και να κάναμε τις αλλαγές όπως στα κλειδιά.

- Comparison Sort (Ταξινόμηση βάσει Σύγκρισης). Στη ταξινόμηση βάσει σύγκρισης γίνονται μεταφορές στοιχείων όταν υπολογιστεί η θέση του στοιχείου.

Tο πρόγραμμα που ακολουθεί είναι η ελληνική εκδοχή του προγράμματος σε Μ2000 με αγγλικές εντολές

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

Η συνάρτηση ΤαξινόμησηΚύκλου() είναι απλή συνάρτηση της Μ2000. Οι απλές συνάρτησης είναι μέρος του τμήματος που της καλεί. Παλαιότερα για να καλέσουμε μια απλή συνάρτηση βάζαμε το @ μπροστά από το όνομα (ισχύει ακόμα) αλλά μπορούμε να μην το βάλουμε και βρίσκει ο διερμηνευτής τη πρώτη φορά ότι εννοούμε την απλή συνάρτηση και το απομνημονεύει για μελλοντική κλήση. Η χρήση του @ κάνει ελαφρά πιο γρήγορη τη κλήση.

Ο πίνακας π() παιρνάει με αναφορά στην ΤαξινόμησηΚύκλου. Για αυτό το πρόγραμμα το πέρασμα με αναφορά είναι πλεοονασμός, αφού η απλή συνάρτηση βλέπει τον π() και την χρησιμοποιούμε μόνο για τον π(). Εδώ είναι  μια άσκηση να αλλάξει κάποιος το πρόγραμμα και να δουλεύει χωρίς να περάσουμε με αναφορά τον π(). Δείτε ότι όταν περνάμε με αναφορά έναν πίνακα το & πρέπει να το έχουμε και στις δυο πλευρές, στην πλευρά του καλούντα και  στη πλευτά του καλούμενου. Δείτε επίσης ότι παρενθέσεις έχουν και οι πίνακας και οι συναρτήσεις στη Μ2000. Αν έχουμε πίνακα με ίδιο όνομα με συνάρτηση τότε η Μ2000 διαλέγει τον πίνακα εκτός αν βάλουμε το * αμέσως μετά το όνομα και την ανοικτή παρένθεση στη κλήση για να του πούμε ότι θέλουμε τη συνάρτηση ΤαξινόμησηΚύκλου(*&π())  (αυτό αν έχουμε ήδη ένα πίνακα ΤαξινόμησηΚύκλου() (που δεν υπάρχει περίπτωση να έχουμε...αλλά λέμε τώρα σε περίπτωση που θα υπήρχε τι θα έκανε ο διερμηνευτής).

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

Επίσης η Για όπως υλοποιείται στην Μ2000 πάντα εκτελεί μια φορά τουλάχιστον το σώμα της. Εκτός αν δώσουμε στην αρχή του τμήματος το BASIC οπότε μόνο για το τμήμα η Για δουλεύει όπως η Basic (αλλά και η ΠΙΝΑΚΑΣ φτιάχνει ν+1 στοιχεία από ν, πχ Πίνακας Α(10) φτιάχνει από 0 έως και 10, συνολικά 11 στοιχεία, και επίσης η εντολή Διάβασε δουλεύει όπως το read της Basic, με τα Data (Σειρά) και Restore (Επαναφορά) όπως της Basic (BBC BASIC)).

Μας ενδιαφέρει λοιπόν να δούμε τι γίνεται στην Για ι = Αρχή_Κύκλου+1 Έως Άνω_Όριο, αν υπάρχει περίπτωση να έχουμε Αρχή_Κύκλου+1>Άνω_Όριο γιατί σε αυτήν την περίπτωση θα πρέπει να βάλουμε μια Αν  Αρχή_Κύκλου+1<=Άνω_Όριο Τότε / Βάζουμε τη Για ανάμεσα/ Τέλος Αν, αν δεν έχουμε το τρόπο της BASIC όπου το βήμα είναι θετικό και αν ΑρχικήΤιμή>ΤελικήΤιμή τότε παρακάμπτει το Για. Στην Μ2000 το βήμα δεν έχει πρόσημο, και η κατεύθυνση ορίζεται από τις τιμές Αρχική και Τελική. Με μηδενικό βήμα εκτελείται μια φορά το Για.

Το παρακάτω πρόγραμμα θα εκτελεστεί μια φορά και θα δώσει 1 (αυτό ισχύει και σε επιλογή BASIC)

για ι=1 εως 10 ανά 0
? ι
επόμενο ι

Ενώ αυτό χωρίς τη BASIC εντολή θα δώσει τα 10 έως 0, ενώ με την εντολή BASIC δεν θα δώσει τίποτα γιατί το βήμα είναι μη μηδενικό και αφού δεν το δώσαμε είναι το 1:

//	BASIC
για ι=10 εως 0
? ι
επόμενο ι

Τα παραπάνω παραδείγματα τα γράφουμε σε ένα τμήμα. Δείτε τις οδηγίες για το τμήμα Α παρακάτω (αντί να βάλουμε με επικόλληση το πρόγραμμα Ταξινόμηση τύπου Κύκλου, γράφουμε το πρόγραμμά μας).

Σώνουμε όλα τα  φορτωμένα/διορθωμένα τμήματα με το Σώσε Όνομα123 και με το Νεο τα καθαρίζουμε. Καμιά φορά μπορεί να χρειαστεί και το Καθαρό που σβήνει τυχόν μεταβλητές γενικές που φτιάξαμε στην κονσόλα - όχι σε τμήμα, και το Άδειασε που αδειάζει το σωρό τιμών.  Μπορούμε να δούμε αν έχουμε μεταβλητές με την εντολή Λίστα (και μέσα σε τμήμα) και να δούμε τις τιμές στο σωρό τιμών με την Σωρός (και μέσα σε τμήματα). Επίσης μπορούμε να δούμε τα τμήματα με την Τμήματα και Τμήματα ? (με το ερωτηματικό μόνο τα φορτωμένα, ενώ χωρίς τα δείχνει όλα, και τα φορτωμένα και τα προγράμματα που μπορούν να έχουν πολλά τμήματα). Σημειώστε ότι ένα τμήμα μπορεί να έχει πολλά τμήματα αλλά με την Τμήματα βλέπουμε όσα τμήματα είναι ενεργά δηλαδή έχουν δηλωθεί. Τα τμήματα μέσα σε τμήμα δεν θα δηλωθούν όσο το τμήμα δεν εκτελείται

Η απλή συνάρτηση ΤαξινόμησηΚύκλου() λέγεται απλή γιατί δεν είναι όπως το τμήμα, με δήλωση στην αρχή, αλλά στατική συνάρτηση του τμήματος. Στατική σημαίνει ότι δεν είναι δυναμική, δεν μπορεί να αλλάξει κώδικα. Μια κανονική συνάρτηση δηλώνεται με το Συνάρτηση Όνομα { } ή Συνάρτηση Όνομα(χ, ψ) { } και κάθε φορά που δηλώνεται στο ίδιο τμήμα, αλλάζει κώδικα! Επίσης μια κανονική συνάρτηση έχει δικά της τμήματα και συναρτήσεις και απλές συναρτήσεις καθώς και ρουτίνες επειδή έχει Όνομα Χώρου (δίνει το πρόθεμα που δεν βλέπουμε στα νέα αναγνωριστκά). Ετσι μια απλή συνάρτηση: Δεν έχει δικό της όνομα χώρου, δεν έχει δικά της τμήματα/συναρτήσεις, και πρέπει να χρησιμοποιεί την Τοπικό/Τοπική/Τοπικές για να δημιουργεί τοπικές μεταβλητές (που σκιάζουν τυχόν μεταβλητές με το ίδιο όνομα) γιατί εντός της απλής συνάρτησης είναι θεατό οτιδήποτε έχει φτιαχτεί στο τμήμα. Επίσης μια απλή συνάρτηση έχει πρόσβαση στον σωρό τιμών του τμήματος/συνάρτησης από όπου τη καλούμε ενώ μια κανονική συνάρτηση όταν καλείται σε έκφραση έχω πάντα δικό της σωρό τιμών. Μια απλή συνάρτηση μπορεί να κληθεί μόνο σε έκφραση, ενώ μια κανονική συνάρτηση μπορεί να κληθεί με τη Κάλεσε σαν τμήμα (με σωρό τον σωρό του καλούντα). Μια κανονική συνάρτηση μπορεί να περαστεί με αναφορά ενώ μια απλή όχι.

Σε άλλες γλώσσες υπάρχει μια και μόνο συνάρτηση. Συνήθως όμως σε αυτές τις γλώσσες δεν υπάρχει συνάρτηση στη συνάρτηση. Μια βασική διαφορά στη Μ2000 είναι η θέαση άλλων αναγνωριστικών σε σχέση με τους δυο τύπους συναρτήσεων. Στην κανονική συνάρτηση είναι θεατά μόνο τα τοπικά που  δεν δηλώνονται τοπικά γιατί εξ ορισμού ότι φτιάχνουμε είναι τοπικά, και τα γενικά. Στην απλή συνάρτηση είναι θεατό οτιδήποτε είναι θεατό σε αυτό που τη κάλεσε. Αυτή είναι μια ουσιαστική διαφορά. Στη C σε μια συνάρτηση είναι θεατό οτιδήποτε έχει δηλωθεί στο αρχείο που είναι γραμμένη, η δε συνάρτηση αν δηλωθεί static δεν θα είναι θεατή έξω από το αρχείο (εξ ορισμού οι συναρτήσεις είναι extern δηλαδή αν το αρχείο γίνει import σε άλλο αρχείο τότε όλες οι extern συναρτήσεις θα είναι θεατές σε αυτό). Η C επεξεργάζεται το πρόγραμμα πριν το εκτελέσει (compiler). Η Μ2000 εκτελεί άμεσα το πρόγραμμα και βασίζεται στο τρόπο που ορίζουμε κάτι για να γγνωρίζει τι να κάνει με αυτό. Η Συνάρτηση ΤαξινόμησηΚύκλος δεν δηλώνεται σαν κανονική συνάρτηση (θα μπορούσε να δηλωθεί), οπότε όταν ζητηθεί με @ΤαξινόμνησηΚύκλου() θα αναζητηθεί στη λίστα στατικών και αν δεν βρεθεί θα αναζητηθεί στο κώδικα, και αν βρεθεί θα γραφτεί στη λίστα στατικών και θα εκτελεστεί. Στην επόμενη κλήση ήδη θα υπάρχει στη λίστα και έτσι δεν θα γίνει αναζήτηση. Αν δεν χρησιμοποιήσουμε το @ και δώσουμε τη πρώτη φορά το ΤαξινόμησηΚύκλου() πρώτα θα αναζητηθεί αν είναι πίνακας, αν δεν βρεθεί θα αναζητηθεί στη λίστα κανονικών συναρτήσεων, αν δεν βρεθεί θα υποθέσει ο διερμηνευτής ότι ζηταμε στατική και θα βάλει έναν μεσολαβητή. Ο μεσολαβητής λέει ότι το όνομα ΤαξινόμησηΚύκλου() είναι στατική. Αν δεν βρεθεί η στατική τότε βγαίνει λάθος και πετάει τον μεσολαβητή το σύστημα. Αν βρεθεί γίνεται κανονικά η εγγραφή στη λίστα στατικών και εκτελείται. Τη δευτερη φορά αν χρησιμοποιήσουμε το @ θα βρεί αμέσως ο διερμηνευτής τη συνάρτηση στη λιστα στατικών ενώ αν δεν το χρησιμοποιήσουμε τότε εκεί που ψάχνουμε για κανονική συνάρτηση θα βγει ο μεσολαβητής και θα δηλώσει ότι είναι στατική και έτσι θα εκτρέψει τη ροή στην εκτέλεση της στατικής (εύρεση από τη λίστα στατικών και εκτέλεση). Η "πατέντα" με τον μεσολαβητή έκανε τον διερμηνευτή να εκτελεί τις απλές συναρτήσεις χωρίς τη χρήση του @ (όπως είδατε το ζήτημα δεν ήταν απλά να δούμε πως θα εκτελεστεί η απλή συνάρτηση αλλά τι θα γίνει αν δώσουμε όνομα που δεν υπάρχει). Γενικά στο προγραμματισμό πρέπει να σκεφτόμαστε για κάτι διπλά, μια φορά αν αυτό που έχουμε είναι πραγματικό και μια αν δεν είναι, και αυτό ισχύει και με τα νούμερα, μια φορά αν τα νούμερα είναι αποδεκτά και μια φορά αν δεν είναι. Και αυτό το σκεφτόμαστε και στις επαναλήψεις, πότε μια επανάληωη θα γίνει και πότε όχι.  Επίσης πρέπει να σκεφτόμαστε και πώς θα τερματίσει μια επανάληψη και πώς δεν θα τερματίσει σε εύλογο διάστημα (άρα να έχουμε υπολογίσει πόσο χρόνο χρειάζεται περίπου για το σκοπό της χρήσης).

Στην ταξινόμηση κύκλου  ο χρόνος έχει σχέση με το πόσα στοιχεία έχουμε. Δείτε ότι η Αρχή_κύκλου ξεκινάει από το κάτω όριο του πίνακα (εδώ είναι το 0) και πάει στο πάνω όριο μειον ένα. Αν ο πίνακας έχει λιγότερα από 2 στοιχεία δεν έχουμε ταξινόμηση. Αν έχουμε 2 τότε το πάνω όριο είναι το 1 άρα η Αρχή_κύκλου θα πάει από το 0 μέχρι το 1-1 = 0, άρα θα έχουμε μια μόνο επανάληψη (δεν θα έχουμε πρακτικά καμία επανάληψη, απλά θα εκτελεστεί ο κώδικας της επανάληψης μια φορά). Μετά κοιτάμε από την Αρχή_κύκλου+1 μέχρι το Άνω όριο, δηλαδή από το 0+1=1 μέχρι το 1 (τόσο είναι το άνω όριο) οπότε θα έχουμε εδώ μια φορά την επανάληψη (από 1 μέχρι 1) και σε αυτήν θα κάνουμε έλεγχο α(ι)<Στοιχείο και αν ναι τότε προσθέτουμε ένα στη Θέση_στοιχείου. Αφού τελειώσει η επανάληψη κοιτάμε αν η Θέση_στοιχείου μεγάλωσε από την αρχική. Αν δεν μεγάλωσε τότε πάμε στην επομενη Αρχή_κύκλου (σημαίνει ότι το στοιχείο είναι στη θέση του). Ας υποθέσουμε εδώ ότι πράγματι μεγάλωσε η Θέση_στοιχείου. Κοιτάμε αν στο στοιχείο που θελουμε να βάλουμε στοιχείο είναι ήδη κάποιο στοιχείο με ίδια τιμή και αν είναι αυξάνουμε τη Θέση_στοιχείου. Τώρα αν προσέξουμε θα δούμε ότι αυξάνουμε τη Θέση_στοιχείου χωρίς να κοιτάμε αν φτάσαμε στο τέλος! Πράγματι δεν μας νοιάζει εδώ γιατί ξέρουμε κάτι σίγουρο, ότι υπάρχει ένα α(ι) που είναι μικρότερο από το Στοιχείο, άρα ξέρουμε ότι το Θέση_στοιχείου δεν θα περάσει το ι. Όταν τελειώσει και αυτή η επανάληψη θα κάνουμε την αλλαγή με την Άλλαξε α(Θέση_στοιχείου), Στοιχείο. Τώρα το Στοιχείο θα πρέπει να μπεί κάπου μεταξύ της αρχή_κύκλου έως Θέση_στοιχείου-1. Επίσης επειδή μας ενδιαφέρει να γράφουμε τον αριθμό μεταφορών αυξάνουμε τη μεταβλητή Μεταφορές κατά ένα. Ξεκινάμε για τη τελική επανάληψη που γίνεται όσο η Θέση_Στοιχείου δεν συμπίμπτει με την Αρχή_Κύκλου. Πράγματι στην αρχή δεν συμπίπτει γιατί είναι η Θέση_Στοιχείου που βρέθηκε το α(ι)<Στοιχείο και ξεκίνησε από το Αρχή_Κύκλου+1. Το πρώτο πράγμα που κάνουμε εντός της επανάληψης είναι να πάμε τη Θέση_Στοιχείου στην Αρχή_Κύκλου, φτιάχνοντας δηλαδή τη τιμή που η συνθηκη της επανάληψης ΔΕΝ ικανοποιείται, δηλαδή που τερματίζει την επανάληψη. Μετά πάμε σε μια Για ι = Αρχή_Κύκλου + 1 Έως Άνω_Όριο. Σκεφτήτε εδώ ότι από τηνΑρχή_Κύκλου πήραμε το στοιχείο στο 0 και βρήκαμε ότι στο 1 το α(1)<Στοιχείο, και μετά αλλάξαμε το Στοιχείο με το α(1), και τώρα έχουμε στο α(0) το προηγούμενο στοιχείο που είναι και στο α(1), και το Στοιχείο που είναι το παλιό α(1) και δεν είναι αυτή τη στιγμή στο πίνακα!  Όταν πάμε λοιπόν στο Για θα πάμε στο α(1) που είναι το αντίγραφο του α(0), κα θα το συγκρίνουμε με το Στοιχείο, το παλιό α(1), όμως το Στοιχείο είναι μικρότερο από το α(1) (που είναι το α(0) αντίγραφο) άρα το α(ι)<Στοιχείο δεν ισχύει. Τερματίζει η Για και πάμε στην Ενώ για τα όμοια. Δεν υπάρχει όμοιο στη πρώτη θέση, στη θέση_στοιχείου, δεν ικανοποιείται η συνθήκη Στοιχείο=α(Θέση_στοιχείου), φεύγουμε από το Ενώ και πάμε στην αλλαγή, με την Άλλαξε α(Θέση_στοιχείου), Στοιχείο και έτσι το Στοιχείο που είναι το παλιό α(1) γίνεται α(0). Τώρα όλα τα στοιχεία είναι στον πίνακα. Και αυξάνουμε τον αριθμό μεταφορών κατά ένα. Επειδή δεν άλλαξε τιμή η Θέση_στοιχείου και δείχνει στη τιμή του Αρχή_κύκλου τερματίζει η Ενώ. Τερματίζει και η Για με επόμενο το Αρχή_κύκλου. Επιστρέφουμε τη τιμή μεταφορές και τερματίζει η συνάρτηση.


Ο χρόνος που θα χρειστεί η συνάρτηση εξατιέται από τα στοιχεία που έχει ο πίνακας και αν είναι n θα έχουμε n*n ή n^2 συνολικές ενέργειες  ή διακριτές επαναλήψεις. 

Η εντολή Τύπωσε π()#ταξινόμηση()#γραφή$(", ")  κάνει άμεσα ταξινόμηση με QuickSort (Γρήγορη Ταξινόμηση) σε γλώσσα μηχανής (όχι σε Μ2000) και για το λόγο αυτό το παράδειγμα με τη Ταξινόμηση τύπου κύκλου δεν έχει πρακτική αξία, πέρα από την εκπαιδευτική σκοπιά. Βέβαια η ταξινόμηση κύκλου κάνει τις λιγότερες εγγραφές, και πρακτικά κάνει τόσες εγγραφές όσα και τα στοιχεία του πίνακα. Όταν η εγγραφή είναι κοστοβόρα τότε η Ταξινόμηση τύπου  κύκλου έχει πρακτική αξία! Στα αλφαριθμητικά στους πίνακες η Μ2000 κάνει αλλαγή στους δείκτες στα αλφαριθμητικά και όχι στα ίδια τα αλφαριθμητικά! Έτσι η αλλαγή δεν έχει να κάνει με το πόσα γράμματα έχει το αλφαριθμητικό αλλά μόνο με ένα δείκτη που έχει μέγεθος 32bit, ή 4bytes, όσο δηλαδή ένας Μακρύς (long) αριθμός. Αν αντί για το Αλλαξε α(ι), Στοιχείο χρησιμοποιούσαμε μια τρίτη μεταβλητή τότε θα δουλεύαμε με αντίγραφα, άρα θα μέτραγε το μήκος του αλφαριθμητικού. Αυτό συμβαίνει με οποιαδήποτε γλώσσα. Εξ ορισμού τα αλφαριθμητικά είναι "απρόσβλητα" από αλλαγές, και όταν προσθέτουμε ένα χαρακτήρα γίνεται το τελικό αποτέλεσμα σε νέο αλφαριθμητικό. Η Άλλαξε μας βοηθάει με το να μην δουλεύουμε με τα αλφαριθμητικά ως έχουν αλλά με τους δείκτες σε αυτά. Στην πράξη ένα αλφαριθμητικό είναι ένας δείκτης που αν εχει το 0 σημαίνει κενός αλφαριθμητικό ενώ αν έχει οτιδήποτε άλλο σημαίνει ότι εκεί που δείχνει θα έχει το πρώτο χαρακτήρα (μας λέει πόσους χαρακτήρες έχει ακριβώς 4 θέσεις πιο πίσω που γράφεται το μήκος του αλφαριθμητικού σε bytes, και ένα Unicode Utf16Le γράφεται σε μοναδες Word, δυο bytes, άρα το μήκος θα βγαίνει ζυγό). Για λόγους συμβατότητας, η VB6, με την οποία είναι γραμμένος ο διερμηνευτής της Μ2000, για  ένα κενό αλφαριθμητικό μπορεί να έχει δείκτη και στο πρώτο χαρακτήρα να έχει το μηδέν (δηλώνει και τέρμα σε ορισμένες γλώσσες), ενώ το μήκος δηλώνεται 0. Έτσι 'ενα κενό αλφαριθμητικό μπορεί να έχει δείκτη ή όχι! Στη VB6 το "" είναι κενό αλφαριθμητικό με δείκτη, ενώ το vbnullstring είναι μηδενικός δείκτης.




Πρόγραμμα Ταξινόμηση τύπου Κύκλου.

  • Ξεκινάμε το m2000.exe
  • Γράφουμε Σ Α πατάμε enter
  • Κάνουμε επικόλληση και πατάμε esc
  • Γράφουμε Α και πατάμε enter και έχουμε την εκτέλεση.
  • Αν θέλουμε να καθαρίσουμε την οθόνη (και να φύγουν και οι γραμμές πάνω που λέει στοιχεία για τον διερμηνευτή και το σύστημα) τότε γράφουμε Οθόνη , 0 και πατάμε enter. Η πρώτη παράμετρος της Οθόνη είναι το χρώμα φόντου και εδώ δεν το δίνουμε, το αφήνουμε ως έχει.
  • Με το Βοήθεια Οθόνη βλέπουμε πληροφορίες για την εντολή. Με το Βοήθεια όλα μας δίνει μια λίστα ονομάτων για επιλογή (κάνουμε κλικ σε όποιο όνομα θέλουμε).


Πίνακας π()
π()=(0, 1, 2, 2, 2, 2, 1, 9, 3.5, 5, 8, 4, 7, 0, 6)
Τύπωσε π()#γραφή$(", ")
ποσό=ΤαξινόμησηΚύκλου(&π())
Τύπωσε "Μετεγγραφές:";ποσό ' 10
Τύπωσε π()#γραφή$(", ")
π()=(38, 119, 38, 33, 33, 28, 24, 101, 108, 120, 99, 59, 69, 24, 117, 22, 90, 94, 78, 75)
Τύπωσε π()#γραφή$(", ")
ποσό=ΤαξινόμησηΚύκλου(&π())
Τύπωσε "Μετεγγραφές:";ποσό '  19
Τύπωσε π()#γραφή$(", ")
π()=("Greygill Hole", "Ogof Draenen", "Ogof Ffynnon Ddu", "Malham Tarn Pot")
Τύπωσε π()#γραφή$(", ")
ποσό=ΤαξινόμησηΚύκλου(&π())
Τύπωσε "Μετεγγραφές:";ποσό '  3
Τύπωσε π()#γραφή$(", ")


Συνάρτηση ΤαξινόμησηΚύκλου(&α())
Αν Διάσταση(α())<>1 Τότε Λάθος "Ταξινόμηση μόνο για μιας διάστασης πίνακα"
Αν Μήκος(α())<2 Τότε =0:Έξοδος Συνάρτησης
Τοπική Μακρύς Θέση_Στοιχείου, Μεταφορές, Αρχή_Κύκλου, ι
Τοπική Μακρύς Άνω_Όριο=Διάσταση(α(), 1, 1)
Τοπική Άτυπος Στοιχείο
Για Αρχή_Κύκλου=Διάσταση(α(), 1, 0) Έως Άνω_Όριο-1
Στοιχείο = α(Αρχή_Κύκλου)
Θέση_Στοιχείου = Αρχή_Κύκλου
Για ι = Αρχή_Κύκλου+1 Έως Άνω_Όριο
Αν α(ι)<Στοιχείο Τότε Θέση_Στοιχείου++
Επόμενο
Αν Θέση_Στοιχείου = Αρχή_Κύκλου Τότε Συνέχισε Για
Ενώ Στοιχείο = α(Θέση_Στοιχείου)
Θέση_Στοιχείου++
Τέλος Ενώ
Άλλαξε α(Θέση_Στοιχείου), Στοιχείο
Μεταφορές++
Ενώ Θέση_Στοιχείου <> Αρχή_Κύκλου
Θέση_Στοιχείου = Αρχή_Κύκλου
Για ι = Αρχή_Κύκλου + 1 Έως Άνω_Όριο
Αν α(ι) < Στοιχείο Τότε Θέση_Στοιχείου++
Επόμενο ι
Ενώ Στοιχείο = α(Θέση_Στοιχείου)
Θέση_Στοιχείου++
Τέλος Ενώ
Άλλαξε α(Θέση_Στοιχείου), Στοιχείο
Μεταφορές++
Τέλος Ενώ
Επόμενο Αρχή_Κύκλου
=Μεταφορές
Τέλος Συνάρτησης

Κυριακή 17 Μαΐου 2026

Χρήση γραμματοσειράς Roboto

 Με το παρακάτω πρόγραμμα φορτώνουμε ένα αρχείο zip από το Drive το οποίο έχει το αρχείο πειρ1.gsb. Αυτό το πρόγραμμα το φορτώνουμε και το εκτελούμε. Κατά την εκτέλεση αν δεν υπάρχει στον τρέχοντα φάκελο το αρχείο ttf για τη γραμματοσειρά Roboto θα σωθεί από το αρχείο που είναι περασμένο ήδη στο πειρ1.gsb (στο τμήμα β έχει 10 χιλιάδες γραμμές σε Base64, 487.768 bytes).

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

Στη κονσόλα της Μ2000 γράφουμε Σ "roboto.gsb" και αντιγράφουμε το πρόγραμμα που ακολουθεί. Πατάμε Esc και δίνουμε αυτό: Φόρτωσε roboto   και μας ανοίγει ο επιλογέας γραμματοσειράς. Για να κάνουμε επιλογή πρέπει να κάνουμε επιλογή στο κάτω μέρος και το σέρνουμε δεξιά ή πατάμε enter! (είναι ένα πλαίσιο για να γράφουμε και να βλέπουμε τι γράμματα γράφει και όχι για να επιλέγουμε με όνομα τη γραμματοσειρά). Η φόρμα έχει τρια στοιχεία, την επιλογή γραμματοσειράς, την αλλαγή χαρακτηρισικών και το πεδίο δοκιμής. Αυτά αλλάζουν με Tab. Όταν βλέπει το σύστημα ότι μια γραμματοσειρά είναι ήδη Bold μας εμφανίζει το εντονη. Αν δεν είναι μπορούμε να δηλώσουμε να γίνει έντονη (φαρδιά γράμματα). Η αλλαγή γίνεται με το διάστημα. Πάμε με tab στο δεύτερο στοιχείο και σε αυτό με βελάκια επιλέγουμε πεδίο για αλλαγή. Στα Εντονη και Πλάγια πατάμε το διάστημα ή κάνουμε κλικ στο τετραγωνάκι στα αριστερά. 





Τμήμα ΦόρτωσηΑπόDrive {
Συνάρτηση Γενική Κατέβασε(αρχείο$, κωδ_drive$){
σταθερή BINDF_GETNEWESTVERSION = 0x10&
σταθερή πρόθεμα$="http://drive.google.com/uc?export=download&id="
αν διαδίκτυο τότε
αν υπάρχει(αρχείο$) τότε δες {κονσόλα "del "+παράθεση$(κατ$+αρχείο$);} : αναμονή 200
όρισε URLDownloadToFile από "urlmon.URLDownloadToFileW" {μακρύς pCaller, szUrl$, sxFilename$, μακρύς dwReserved, μακρύς callback}
αν URLDownloadToFile(0,πρόθεμα$+κωδ_drive$, κατ$+αρχείο$,BINDF_GETNEWESTVERSION+0x20000&,0)==0 τότε
= Εντάξει
αλλιώς
= ΔεςΞανά
τέλος αν
αλλιώς
= ΧωρίςΣύνδεση
τέλος αν
}
Γενική Απαρίθμηση Κατάσταση_Κατεβάσματος {
Εντάξει="Εντάξει"
ΔεςΞανά="Δομίμασε ξανά"
ΧωρίςΣύνδεση="Δεν υπάρχει διαδίκτυο, Δοκίμασε ξανά"
}
Τμήμα ΚάνεΔοκιμή {
αν δεν υπάρχει("πειρ1.gsb") τότε
ορισε zip συμπιεστης
μεθοδος zip, "openzip", κατ$+"robotom2000.zip"
μεθοδος zip, "extracttopath", κατ$
τέλος αν
φορτωσε πειρ1
κάλεσε α
}
ΑρχείοΣτοDrive="1MSX7kMbb_TcwqFBGYqgwOtJjF5Q-HrPO"
ΑρχείοΣτοΔίσκο="robotoM2000.zip"
αν Υπάρχει(ΑρχείοΣτοΔίσκο) τότε
ΚάνεΔοκιμή
Αλλιώς
απάντηση=Κατέβασε(ΑρχείοΣτοΔίσκο, ΑρχείοΣτοDrive)
αν απάντηση=Εντάξει τότε
ΚάνεΔοκιμή
αλλιώς
τύπωσε εκφρ$(απάντηση)
τέλος αν
τέλος αν
}
ΦόρτωσηΑπόDrive



Προγραμματισμός με Αντικείμενα (2η έκδοση)

 Έχω ανεβάσει εδώ τη νέα έκδοση του Προγραμματισμού με Αντικείμενα με τον διερμηνευτή Μ2000.

Από το drive μπορεί κανείς να το δει στο browser. Δεξιά υπάρχει και σύνδεσμος στο Github.

Περιλαμβάνει μια εισαγωγή στη Μ2000 και όλα τα μοτίβα του προγραμματισμού με αντικείμενα.



Το αρχείο είναι pdf αλλά ανοίγει και σε LibreOffice (έχει και το odt μέσα στο pdf). Από το libreoffice μπορεί κάποιος να αντιγράψει τα προγράμματα για να τα τρέξει.

Γ.Κ.




Σάββατο 25 Απριλίου 2026

New major revision (22) for Version 14.

 Hello, dear M2000 Users,

The latest revision of M2000 make the interpreter faster, of about 17% (less time to compute), so we can say we have a speedup of  x1.2 times,(1/0.83=1.204) so we can say the new revision make the Interpreter 20% faster.

How this done?

M2000 Interpeter always execute the source as is. Which means there is no conversion to a tokenized form. Also there is no AST construct. That is no very bad, for a language which are made for expansion as we go, for the last 26 years). The purpose for using the M2000 Interpreter surely is not for \time critical programs. Much of the time consuming work done from objects and internal code which can do things like rotation of bitmaps. So all the Interpreter is a function with a series of helping functions. The code run consuming the string which hold it. Some time maybe I change this, but for now when we do this Print 12+10 first the Print statement removed from string, then the Expression evaluation stage get the first number 12 then get the plus sign and looking for another number or another sign before the number (you can do this 12+-+-12 and is ok)) or an open parenthesis and so on.

A numeric expression may have strings on it: "aaa" is a string expression, but "aaa">"bbb" is a Boolean one (a numeric for M2000). So before this revision and before the 11th version, there was strictly two kind of expressions, the string and the numeric. When we start the numeric evaluator, there was a looking ahead mechanism to find if there is a logic operator, when strings find in front at the expression, so at this point conclude that in front exist a numeric expression or a string one. So if it is a string return without exclude any value (literal) or name (variable or constant). For versions lower than 11, the string variables and functions was all with a $ as suffix, so alfa$ was treated as string, and this was the same with a alfa$(), where the "things" inside parenthesis skipped from the look ahead system as irrelevant for determinate the type of expression. So from version 11 we may have an alfa variable as a string one. That was a difficult situation for holding the IsExp() function for numeric (and now string results) and the string only IsStrExp() function. Each of these functions knows all the internal functions, the numeric for IsExp() and string fot IsStrExp(). So there was a logical() function which find looking ahead if there is a string expression and and a logic operator. If not return false without removing anything. Now for the Revision 20 of version 14, this function drop the look ahead part and also the internal string comparison part. The logical() function called from the IsExpA() function inside IsExp() function, for each value which we want to process. So now we don't have the look ahead part because now the process done for strings too inside IsExpA(). The IsStrExp()  works because some time we want to get a parameter only as string. This IsStrExp() call the IsString() and get the value and then see if there is the plus operator to get another string, to concatenate them, and repeat this until no other operation exist. IsExpA() which work for a number of different types, work nice for strings too. If we place a value an operator and a value and then an operator plus and a string then we get error. I do that because this can be a mistake, So 10+10+"ok" give an error, but 10+"ok"+10 give a string 10ok10, and also "ok"+10+10 give a string ok1010. IsExp() the shell of the numeric/object expressions, works for all numeric types plus the complex numbers (1,-2i) or (a,b i) are complex notation for making complex numbers, also works for dates, bytes, long long and biginteger (which are objects), plus with Group type of objects which have operators as functions so a A+A can be a sum of two numeric types including complex and biginteger, a  concatenation of two string values or a produce of an object from object A which knows the operator "+" as a function (which call the evaluator) and pass the value of expression at part after the "plus" operator.

To do this functionality I have to make some changes in the code, to work as expected. Maybe I am not 100% for all situation, but at the long run I will find any mistake or not prepared code to this level of functionality.

Another two new things about this revision:

- We can use Ctrl /  (also Ctrl 4 works the same) to apply comment or uncomment lines of code (one or more). Because / may change to other keys (other virtual keys), I improve the code to find this for the specific keyboard language  in use. Also Keypress() function now have a ! switch to address the same situation we want a character code to be pressed but we didn't know the scan code, but the system know it and we just supply the parameter as character Unicode code.

Also we can use Ctrl 2 for lower case (no selected text, or convert also for selected text), and Ctrl 1 for upper case (no selected text, or convert also for selected text). So if you want fast capital key you press Ctrl 1 and we get the caps lock to ON for sure without looking the keyboard.

- The last thing do magic or something like this. We want to open a second m2000 program in front of our program, through our program. Before this magic, the new program open, but if our own program got the focus the other program go to background, and our program hide it. That is not bad, because all programs do that. But what if we want the new program which we start from our program want to stay in front of our program? To do that we pass the hWnd (the window handler) of the BACK (the real form of M2000 console) to the new program and that program has to run the Show statement using this number as a parameter (this is new, the Show get optional a parameter). You can see how this work with the Clock module (which run the Clock1, in another M2000.exe). So when we open the clock the form of the clock get a parent form, our console form, so Windows manager always show the clock in front of the parent (our console form). It is the same as the Help form, or the Control form, or the user forms which we make as children of the console form. If we start the Form44 module which make three windows we can put the Clock (which run on own M2000.exe) between the user forms because these have the same parent, the console form. If out form terminate, the other program just do nothing about it, like there is no parent for it; We don't have family problems here;

Another example is the Compiler. When we compile one of the examples we ask to use M2000 Transpiler (compile to M2000 starements) or Virtual Machine (byte code for a virtual machine - now running as a M2000 program also). If we choose Transpiler we Asked if we want the execution done in the console or not (by default is not) so if we press enter a new M2000.exe start and run as child window in front of our console (with transparency also). I am thinking to make a way to make forks and these can be used to form a parent child connection. I am thinking about the way the forked code to access global variables of the parent code.