Κυριακή 29 Ιανουαρίου 2017

An example showing stream operator in M2000

Operator << used here to add to a function a generator, another function to supply a stream of values. Also we see the use of Event object.

Stream operator used for arrays to feed each element, but mainly used for what we see here.

We can make some minor changes and we get a simpler version, without TankControl Group (an object in M2000), and with no Event too. Just delete Line "Group TankControl".., line "Event Probe ..", line "Call Event .Probe...", we have to delete the closing curly bracket (for deleted Group definition) before line "Class SpecificClass...", then line "Event TankControl.Probe....", and we have to change the line "For TankControl" with "For This" (so dot before alfa has a meaning This, or we through For  { } , but keeping inside all the code, because by default a single dot interpreted as This. Keep in mind that a For { } not only tag what is a dot but also make all definitions inside block for temporary use, but here we don't have that issue)

\\ we have a function to simulate a tank quantity change
\\ alfa arguments are:
\\ current tank quantity, optionally quantity (30 by default) to remove if valve is open,
\\ a flag for printing messages (false by default)
\\ and optionally we can pass  as many as we want valve states, true for open, false for closed
\\ we can use the << operator (stream operator) to send valve state
\\ we make a class and a group from that class, named Specific
\\ We can feed Specific with a pattern of valve states (a batch of patterns)
\\ We have 4 options. We can send one pattern as a batch, one time or many (2 options),
\\ or we can send one state at a time for one batch or form many.
\\ We can expand this logic, if we move function's alfa definiton in a group where we put an Event object.
\\ so we can use Event through alfa to stop Specific at some level of tank quantity
LowLevelSet=500
Read ? LowLevelSet \\ read optionally
Group TankControl {
      Event Probe { Read tank_quantity, &exitvalue }
      Function alfa {
            Read tank
            Let quantity=30, messages=false
            Read ? quantity, messages
            exitnow=false
            {
                  Try Stream
                  If empty or tank=0 Then exit
                  Call Event .Probe, tank, &exitnow
                  if exitnow then exit
                  If number Then tank-=quantity : If messages Then Print "Valve open"
                  If tank<0 Then tank=0
                  If messages Then Print format$("Tank quantity={0}", tank)
               
                  Loop
            }
            =tank
      }
}
Class SpecificClass {
Private:
      Dim A()
      myCursor=-1
      many=10
      once, counter, step_cursor
      stepcounter
Public:
      Module SpecificClass {
            .ReSet
      }
      Module ReSet {
            Read ? .many
            Dim .A(.many)=False
            .myCursor<=-1
      }
      Function Feed {
            =True
            .myCursor++
            While .myCursor<.many {
                  If Empty Then Exit
                  Read .A(.myCursor)
                  .myCursor++
               
            }
            If Not Empty Then =False : .myCursor<=.many-1
            .once<=True
      }
      Function ReadAllonce {
            If not .once Then exit
            .once<=False
            If .myCursor>0 Then
            For i=0 to .myCursor { Data .A(i) }
            .counter++
      }
      Function ReadAllmany {
            If .myCursor>0 Then
            For i=0 to .myCursor { Data .A(i) }
            .counter++
      }
      Function ReadOneAtime_once {
            If not .once Then exit
            If .myCursor>0 Then {
                If .step_cursor>.myCursor Then {
                 .once<=False
                 } Else {
                        Data .A(.step_cursor)
                        .stepcounter++
                        .step_cursor++
                 }
            } Else .once<=False
      }
      Function ReadOneAtime_many {
            If .myCursor>0 Then {
                  If .step_cursor>.myCursor Then .ResetStep
                  Data .A(.step_cursor)
                  .stepcounter++
                  .step_cursor++
            }
      }
      Module ResetStep {.step_cursor<=0}
      Module UnlockOnce {.once<=True : .step_cursor<=0}
      Module PrintStepCounter { Print .stepcounter }
}
Specific=SpecificClass()
Function LowLevel {
      \\ need same signature for event
      Read New TankLevel, &exitvalue
      exitvalue=TankLevel<LowLevelSet
}
\\ using Lazy(&LowLevel()) and not LowLevel(), we make the call like the code was in module, so we read LowLevelSet.
\\ and of cource we can tweak the Specific object
Event TankControl.Probe New lazy$(&LowLevel())


Print "Start"
For TankControl {
      If Specific.Feed(True, False, False, True,False,False, True,True) Then {
            Last=.alfa(1000, 35, True)<<Specific.ReadAllonce()
            \\ here we pass manual values
            Last=.alfa(Last, 100, True, True, False, False, True)
            Specific.UnlockOnce
            Last=.alfa(Last, 35, True)<<Specific.ReadAllonce()
            Last=.alfa(Last, 35, True)<<Specific.ReadOneAtime_once()
            Specific.ResetStep
            If Last>0 Then {
                  If Ask("try to empty tank?", "Tank")=1 Then {
                        \\ Last=.alfa(last, 35, True)<<Specific.ReadAllmany()
                        Last=.alfa(last, 35, True)<<Specific.ReadOneAtime_many()
                        Specific.PrintStepCounter
                  }
            }  
      }
}



Σάββατο 28 Ιανουαρίου 2017

Αναθεώρηση 14 (έκδοση 8.2)

1. Μικρές προσθήκες/διορθώσεις. Προστέθηκε στη βοήθεια το Inventory/Κατάσταση, το Buffer/Διάρθρωση, το Λάμδα/Lambda, το Event/Γεγονός.
Γράφουμε Βοήθεια Κατάσταση και μας δίνει η Μ2000 παραδείγματα για να καταλάβουμε πως τα χρησιμοποιούμε.

2. Διορθώθηκε η εντολή:
Εκτυπωτής ?
Τώρα γίνεται επιλογή απευθείας από τη λίστα.

3. Μπήκε εμφάνιση λάθους αν έχουμε υπερχείλιση μακρύ (Long).

4. Μπήκε έλεγχος (εμφάνιση λάθους) αν πάμε σε ένα αντικείμενο να βάλουμε ένα αντικείμενο άλλου τύπου (στις λάμδα συναρτήσεις και στις ομάδες).




Κυριακή 22 Ιανουαρίου 2017

Αναθεώρηση 13 (έκδοση 8.2)

Revision 13, for version 8.2

\\ This is an advanced example of using events, and references
\\ M2000 never expose actual references.
\\ All items are searched by a hash function internal,
\\ using name of item and module name
\\ (maybe that name changed internal from interpreter)
\\ function weak$() return the internal name of any item included array item.
\\
\\ To run this write in M2000 CLI> edit a <enter> and then copy this
\\ press Esc and write a <enter> to run
\\ use Save pr1 <enter> to save it

\\ Nothing is static in M2000, except for "running" code.
\\ so Module deep1 isn't exist until first we make it a module to call
\\ and then when we call it, make anything as it runs
\\ Three steps: part of a source - source with a name - call that name
\\ M2000 interpreter use always source, never made any code of it.
\\ Using the source M2000 makes real objects and execute command on those.
\\
\\ Groups are static objects as list of items (we can reference specific item)
\\ ... like variables, modules, functions, events, lambdas, etc
\\ Here the task is to raise an event from an object (Call Event)
\\ and sending a value to this and to another object, calling functions
\\ and each function read a property y (a variable in the group)
\\ We test the raise of event when we pass the object (group)
\\ by value, by referenec, by weak reference
\\ and then we put copies of these groups in an array, and return it
\\ Then we fix the references, in the new copied array, and test again
\\ the raise of event from stored group (in array) and from passing
\\ with weak reference to another module.

Module deep1 {
      Group aa {
            y=123
            Event b { Read x }
            Function aa { Read x : Print x+.y }
            Module callme {
                  Call Event .b, number
            }
      }
      Group bb {
            y=456
            Function bb { Read x : Print x+.y}
      }
      Event aa.b New aa.aa(), bb.bb()
      Print "From Module a"
      aa.callme 5
      Module testme {
            Read c
            Print "From testme inside Module Deep1"
            c.callme
      }
      \\ Here we copy aa Group to c
      testme aa, 5
      \\  133
      \\ 466
      \\ 128
      \\ 461  (here is the fix, old versions print 128)
      \\ passing by reference was ok
      Module testme2 {
            Read &c
            Print "From testme2 inside Module Deep1"
            c.callme
      }
      testme2 &aa, 5
      \\ using weak reference was ok too
      \\ no copy or reference for each element in Group aa
      \\ just Call it like it is a global Module (using c$ as prefix value)
      Module testme3 {
            Read c$
            Print "From testme3 inside Module Deep1"
            c$.callme
      }
      testme3 &aa, 5
     
      \\ we can put copies of static objects in arrays items
      Print "Test Event from object in item in array"
      Dim A(10)
      A(0)=aa
      A(0).y=1000
      A(0).callme 5
      testme3 weak$(A(0)), 5
      \\ if array returned from this Module then event find error
      \\ because group bb deleted.
      A(1)=bb
      push A()
}
Deep1
\\ now all modules and variables in Deep1 are destroyed
\\ except stack values. And in stack we have an array
Print StackType$(1) \\ print mArray - the inside object for arrays in M2000
Print Match("A") \\ Print -1 (True), is Array
Dim A()
\\ first we create the array and then we put the object on it
Read A()
Print "From exported array"
\\ need to restore weak reference
For A(0) {
      \\ this block make A(0) static with a hidden name
      \\ and this name used every time
      Event .b Clear \\ clear all functions in event chain
      \\ here we don't need to give a lazy$() function.
      Event .b New .aa()
      \\ function lazy$() return an anonymus function with lazy evaluation
      \\ when this anonymus function run, set the module name to A
      \\ so A(1) can be found, also we have to write the parameters to pass
      Event .b New lazy$(A(1).bb(number))
     \\ this happen because we can't get reference from array items.
    
}
\\ Now we Call a non static group
Print "From Module a"
A(0).callme 15
Module testme3 {
      Read c$
      Print "From testme3 inside Module a"
      c$.callme
}
\\ Now we send it to module testme3 (module's deep1 modules are erased)
testme3 Weak$(A(0)), 15
\\ so now we have two objects, non static, but for this momemt they have
\\ one point static...the name of the array (A() is inside the module a)
\\ event b is calling from A(0) and opens A(1) reading variabe (property) y.
\\ Events may have by reference values as parameters and this works with multicast

Σάββατο 21 Ιανουαρίου 2017

Αναθεώρηση 12 (έκδοση 8,2)

Προσθήκη στη γλώσσα για τους πίνακες ακεραίων και αλφαριθμητικών:
Μπορούμε να βάλουμε πίνακα στη θέση στοιχείου:


Dim a$(10)="No"
Dim b$(5)="Yes"
a$(0)=b$()
Print a$(0)(0) \\ Yes
a$(0)(1)="Hello"
Print a$(0)(1), a$(1) \\ Hello No

Dim a%(10)
a%(0)=function({{=10,11,12,13,14,15,16}})
Print a%(0)(3) \\13
a%(0)(3)+=1000
Print a%(0)(3) \\1013

Για πραγματικούς λειτουργούσε και στην αναθεώρηση 11

Dim a(10)
a(0)=function({{=10,11,12,13,14,15,16}})
Print a(0)(3) \\13
a(0)(3)+=1000
Print a(0)(3) \\1013
 

Στη Μ2000 όταν επιστρέφουμε δυο ή περισσότερες τιμές σε συνάρτηση τότε αυτές γράφονται σε πίνακα και επιστρέφει ο πίνακας. Η συνάρτηση function() δέχεται σαν όρισμα όνομα συνάρτησης και χωριστά τις παραμέτρους, ή ανώνυμη συνάρτηση. Μια ανώνυμη συνάρτηση είναι ένα αλφαριθμητικό με πρώτο χαρακτήρα μια αγκύλη. Τα αλφαριθμητικά στη Μ2000 μπαίνουν ή με διπλό εισαγωγικό αρχή και τέλος ή με αγκύλες { }. Εδώ η πρώτη αγκύλη δηλώνει ότι ακολουθεί αλφαριθμητικό, και η δεύτερη δηλώνει ότι έχει συνάρτηση (αυτό το καταλαβαίνει η function() ή συνάρτηση()). Μέσα στις διπλές αγκύλες έχουμε μόνο το = στην αρχή της εντολής (σημαίνει επιστροφή τιμής) και ακολουθούν εκφράσεις -εδώ αριθμοί- χωρισμένοι με κόμματα. Υπάρχει και η function$() για να επιστρέφει αλφαριθμητικά.

Έχει ενημερωθεί το git και το dropbox.

 

Πέμπτη 19 Ιανουαρίου 2017

Ύψωση σε δύναμη και πρόσημο!


Στο παράδειγμα έχουμε τρεις μεταβλητές και τυπώνουμε το περιεχόμενό τους, όπως το έχουμε διαμορφώσει από ισάριθμες εντολές καταχώρησης του τύπου μεταβλητή = έκφραση.
a=-9**2
? a \\ 81
b
=0+-9**2
? b \\ 81
c
=0-9**2
? c \\ -81
Το -9 στη δευτέρα (-9 ** 2) είναι το -9 * -9 άρα το 81 (θετικό πρόσημο), στην a φαίνεται ξεκάθαρα. Στην b έχουμε δυο πρόσημα, το + και το -. Το πρώτο πρόσημο λέει να προσθέσουμε το επόμενο και το επόμενο είναι το -9**2 άρα το 81. Στο c έχουμε το – που σημαίνει “Αφαίρεσε” το 9**2 από το 0. άρα δίνει το 0-81 ή -81.
b1=0+(-9**2)
? b1
Εδώ στο b1 φαίνεται πως ο εκτιμητής παραστάσεων ενεργεί με παρενθέσεις, και είναι το ίδιο με το 0+-9**2, όπου το + επειδή είναι μετά το 0 λέει απλά “πρόσθεσε το παρακάτω -9**2”
Στη Μ2000 η ύψωση σε δύναμη γίνεται και με τον χαρακτήρα ^ (shift 6)
a=-9^2
? a \\ 81
b=0+-9^2
? b \\ 81
b1=0+(-9^2)
? b1
c=0-9^2
? c \\ -81

Μπορούμε στο μέρος της δύναμης να βάλουμε παρενθέσεις αλλά όχι πρόσημο πριν την παρένθεση θα χαθεί! Μέσα στην παρένθεση βάζουμε όποια έκφραση θέλουμε, ακόμα και αρνητικό (με μηδέν μας δίνει 1, ότι υψώσουμε σε 0 θα δώσει 1)
? 2-3**(2), 2-3**(-4)
Το ? 0^0 δίνει 1
Άλλα παραδείγματα:
? 2**-2,3*2**-2, 3/2**2 \\ .25, .75, .75
? (3/2)**2 , 3**2/2**2 \\ 2.25, 2.25
? 3**2-2**2+1 \\6
? (3**2)-(2**2)+1 \\6

Δευτέρα 16 Ιανουαρίου 2017

Προγραμματισμός για αρχάριους!

θα δούμε πως με τρεις αριθμούς μπορούμε με απλό τρόπο να τους βάλουμε σε μια σειρά από τον μικρότερο στον μεγαλύτερο!

Ξεκινάμε τη γλώσσα (κλικ στο m2000.exe) και γράφουμε μετά το >
>edit A 
και ανοίγει ο διορθωτής και αντιγράφουμε το παρακάτω:


Read a, b, c
Local mx, md, mn
If a>b Then {
      If a>c Then {
            mx=a : If b>c Then { md=b : mn=c } Else { md=c : mn=b }
      } Else {mx=c : md=a : mn=b}
} Else.if a>c Then {
      mx=b : md=a : mn=c
} Else.if b>c Then {
      mx=b : md=c : mn=a
} Else {
      mx=c : md=b : mn=a
}
Print "min", mn
Print "middle", md
Print "max", mx


με πλήκτρο Esc γυρνάμε στη γραμμή εντολών
δοκιμάζουμε με το A και τρια νούμερα (χωρίζοντάς τα με κόμμα ",")
>A 1,4,3


Παραλαγή χωρίς τη χρήση τοπικών μεταβλητών, αλλά με τη χρήση του σωρού. Η εντολή Push (Βάλε) βάζει πάντα στην κορυφή, οπότε Push 1,2 θα έχει το 2 στην κορυφή (τελευταίο που μπαίνει θα βγαίνει πρώτο LIFO)

>edit b
Read a, b, c
If a>b Then {
      If a>c Then {
            Push a : If b>c Then { Push b,c } Else Push c,b
      } Else Push c, a, b
} Else.if a>c Then {
      Push b, a, c
} Else.if b>c Then {
      Push b, c, a
} Else Push c, b, a
Print "min", Number
Print "middle", Number
Print "max", Number


με πλήκτρο Esc γυρνάμε στη γραμμή εντολών
>B 4,100,24

Παρατηρούμε ότι και στα δυο προγράμματα οι λύσεις είναι έξι, και αν προσέξουμε το κάθε πρόγραμμα θα τις δούμε. Παρακάτω με πλάγια γράμματα. (το πρώτο Push a θα μπορούσε να πάει στα άλλα δύο ως Push a,b,c  και Push a,c,b)
Πράγματι δεν μπορούμε να έχουμε περισσότερους συνδυασμούς (λύσεις) για τρια νούμερα.

Read a, b, c
If a>b Then {
      If a>c Then {
            If b>c Then { Push α,b,c } Else Push α,c,b
      } Else Push c, a, b
} Else.if a>c Then {
      Push b, a, c
} Else.if b>c Then {
      Push b, c, a
} Else Push c, b, a
Print "min", Number
Print "middle", Number
Print "max", Number


Ο Σωρός τιμών κρατάει τις τιμές μέχρι να τις πάρουμε ή να τον αδειάσουμε. Εδώ δίνουμε εντολές στη γραμμή εντολών της Μ2000: (μετά το σήμα > )
>Push 1,2,3
>Stack
   3   2   1
>Read A
>Print A
  3
>Stack
   2  1
>Flush
>Stack

δεν μας δείχνει τίποτα (κενή γραμμή), οι τιμές 2 και 1 χάθηκαν πια.
Παρατηρούμε ότι τα προγράμματα Α και Β διαφέρουν ουσιαστικά στην χρήση ή μη τριών μεταβλητών, των mx, md, mn. Δηλώνονται τοπικές στη Β  με έναν απλό τρόπο με την εντολή local. Ουσιαστικά το Α έχει τρεις τοπικές, τις a,b,c ενώ το B έχει έξι (a,b,c,mx,md,mn).


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


Ο Σωρός τιμών στην Μ2000 παίρνει διάφορα είδη εκτός από αριθμούς και δεν λέγεται στοίβα που φαίνεται να είναι καταλληλότερη ονομασία ως LIFO, γιατί είναι πιο σύνθετος, για τέσσερις λόγους: Πρώτον έχει FIFO λειτουργία άμεσα, δεύτερον έχει ανάγνωση από θέση, τρίτον έχει μετακίνηση από και προς την κορυφή οποιουδήποτε στοιχείου, ή ομάδα στοιχείων, και τέλος τέταρτον τα στοιχεία μποορεί να μην είναι ίδιου είδους. Στοιχείο μπορεί να είναι αριθμός, αλφαριθμητικό, έγγραφο (είδος αντικειμένου), ομάδα (το βασικό αντικείμενο της Μ2000), λάμδα συνάρτηση, γεγονός (άλλο αντικείμενο), πίνακας, κατάσταση (είδος λίστας), διάρθρωση (είδος λίστας). Για το λόγο αυτό λέμε ότι έχουμε Σωρό τιμών και όχι στοίβα. Παρόλα αυτά στα αγγλικά χρησιμοποιώ την εντολή Σωρός ως Stack (στοίβα). Αυτό δεν είναι απαραίτητα λάθος. Στα αναγνωριστικά των εντολών δεν παίζει άμεσο ρόλο η ερμηνεία ενός λεξικού αλλά η ερμηνεία του εγχειριδίου της γλώσσας.

>Flush
>Push 1,2,3
Μπορούμε να χρησιμοποιούμε το ? για Print ή Τύπωσε
>? stackitem(1), stackitem(2)
      3       2
Διαβάσαμε με δείκτη (η κορυφή είναι πάντα στο 1), αλλά δεν σηκώσαμε κάτι
>Drop
>? stackitem(1), stackitem(2)
     2       1
Τώρα πετάξαμε τη κορυφή 3 και έχουμε νέα κορυφή το 2 και ακολουθεί το 1
>Data 0, -1
>Stack
2 1 0 -1
Η εντολή Data βάζει πάντα στο τέλος! Οπότε το τελευταίο που βάζει θα είναι τελευταίο στο σωρό (ή στοίβα αν θέλετε)

Τώρα το Α θα το αλλάξουμε έτσι:

Local mx, md, mn
If stackitem(1)>stackitem(2) Then {
      If stackitem(1)>stackitem(3) Then {
            read mx : If stackitem(1)>stackitem(2) Then { read md, mn } Else { read mn, md }
      } Else { read md, mn, mx}
} Else.if stackitem(1)>stackitem(3) Then {
      read md, mx, mn
} Else.if stackitem(2)>stackitem(3) Then {
      read mn, mx, md
} Else {
      read mn, md,mx
}
Print "min", mn
Print "middle", md
Print "max", mx

Βλέπουμε ότι δεν διαβάζουμε τα a,b,c και τα αφήνουμε όπως έχουν για να τα διαβάσουμε στις τελικές μεταβλητές mn, md, mx

Μπορούμε όμως να μην χρησιμοποιήσουμε ούτε τις τρεις μεταβλητές, παρά μόνο το σωρό τιμών! Την κορυφή την σηκώνουμε με την Number αλλά την διαβάζουμε με την stacitem(1), και μπορούμε με την shift να την μεταθέσουμε στην Ν θέση, και με την shiftback να φέρουμε ως κορυφή το στοιχείο στη Ν θέση (δεύτερη παράμετρος σημαίνει πόσες φορές θέλουμε να γίνει)

Μπορούμε να γράψουμε το τμήμα c

>edit c
If stackitem(1)>stackitem(2) Then {
      If stackitem(1)>stackitem(3) Then {
            shiftback 3 : If stackitem(1)>stackitem(2) then shiftback 2
      } Else { shiftback 2}
} Else.if stackitem(1)>stackitem(3) Then {
      shiftback 2,2
} Else.if stackitem(2)>stackitem(3) Then {
      shift 3
      shiftback 2
}
Print "min", Number
Print "middle", Number
Print "max", Number

με Esc βγαίνουμε από τον διορθωτή
΄Φαίνεται πιο μαζεμένος ο κώδικας, αλλά σίγουρα πιο δυσνόητος. Αφαιρέσαμε πολλά ονόματα και αντικαταστήσαμε με ονόματα με δείκτες.
βάλτε εντολές Stack να δείτε τις μετακινήσεις μετά από τις Shift και ShiftBack.

Μπορείτε να σώσεται ότι έχετε γράψει, να το σβήσετε στον μεταφραστή, να αδειάσετε τον σωρό και να το ξαναφορτώσετε. (με Ctrl + A ξανασώνουμε ό,τι έχουμε φορτώσει με την Load)
>Save example1
>New
>Flush
>Load example1
>Modules ?

Επίσης κάθε τμήμα που τρέχουμε μπορεί να τρέξει με την Test  (έστω  ονομάσαμε c το τελευταίο τμήμα)
>Test c 1,4,2

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




(Μπορούμε να αλλάζουμε τη φόρμα του τερματικού της Μ2000 σε αριθμό γραμμών και χαρακτήρων με την εντολή  Form. Πχ Form 80,60 θα δώσει φόρμα με 80 χαρακτήρες με 60 γραμμές)