Τρίτη 20 Ιουνίου 2017

Αναθεώρηση 10 (Έκδοση 8.8) και json δημιουργία δομής

Σε αυτήν την αναθεώρηση έφτιαξα διάφορα, διόρθωσα κάποια bug, και ξαναδιάβασα τη λειτουργία, γιατί χρειάστηκε να κάνω διάφορα για να μπορεί να παίξει άψογα το παρακάτω παράδειγμα,. όπου φτιάχνουμε δομές τύπου Json και διαβάβαζουμε στοιχεία από αυτές.
Το πρόγραμμα είναι στα αγγλικά. Αν θέλουμε να εξάγουμε στο πρόχειρο αντί της Print ή της Report δίνουμε την Clipboard any_string$ και το αλφαριθμητικό πάει στο πρόχειρο.

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

Το πρόγραμμα είναι κάπως μεγάλο. Δημιουργούμε κλάσεις για κάθε τύπο στοιχείου της δομής. Τα αντικείμενα json είναι στην ουσία inventories (καταστάσεις), ενώ οι πίνακες είναι κανονικοί πίνακες. Και στις δυο δομές δεν βάζουμε απευθείας στοιχεία αλλά μέσω αντικειμένων όπου έχουμε βάλει μερικά πράγματα όπως για παράδειγμα το type$ για να γυρίζει τον τύπο.
Υπάρχουν δυο αντικείμενα "εργασίας". Το ένα παίρνει την δομή (την αρχική κατάσταση) και την μετατρέπει σε φορμαρισμένο json  (έχει ελεγχεθεί στο https://jsonformatter.curiousconcept.com/):
{
      "name" : "this is a name",
      "number" : 100,
      "null1" : null,
      "boolean" : true,
      "array1" : [
          100,
          [
              2,
              2.5
          ],
          3,
          4,
          5
      ],
      "object" : {
          "name" : "name2",
          "array1" : [
              "A",
              "B",
              "C"
          ]
      },
      "array2" : [
          101,
          "A"
      ],
      "string" : "Hello There\r\nSecond Line\r\n"
}

Και ένα δεύτερο το μετατρέπει σε μια παράγραφο:
{"first" : {"name" : "name2", "array1" : ["A", "B", "C"]}, "second" : {"name_2" : "name2_NAME", "array1001" : ["A1", "B2", "C3"]}, "third" : [{"byte" : 200, "bytename" : "String Alfa", "my array" : [1, 2, 3]}, 10, 5]}

Το δεύτερο αντικείμενο "εργασίας" κάνει διάβασμα σε ότι θέλουμε (χρησιμοποιεί μια κόπια του πρώτου)

Εδώ είναι η έξοδος στην οθόνη:

Flush
Form 80, 50
Inventory alfa, alfa1, alfa2, alfa3, alfa4
Class Arr {
Private:
      Dim MyValue()
Public:
      Property Type$ {Value} ="Array"
      Value {
            =.MyValue()
      }
Class:
      Module Arr (.MyValue()) {}
}
Class Null {
     Property Type$ {Value} ="Null"
     Property Str$ {Value}="null"
     Value { =0}
}
Class JString$ {
Private:
      MyValue$=""
Public:
      Property Type$ {Value} ="String"
      Property Str$ {
            Value{
                  Link parent MyValue$ to MyValue$
                  value$=quote$(string$(MyValue$ as json))
            }
      }
      Value {
            =.MyValue$
      }
Class:
      Module JString (.MyValue$) {}
}
Class Numeric {
Private:
      MyValue=0
Public:
      Property Type$ {Value} ="Number"
      Property Str$ {
            Value{
                  Link parent MyValue to MyValue
                  value$=trim$(str$(MyValue))
            }
      }
      Value {
            =.MyValue
      }
Class:
      Module Numeric (.MyValue) {}
}
Class Boolean {
Private:
      MyValue=false
Public:
      Property Type$ {Value} ="Boolean"
      Property Str$ {
            Value{
                  Link parent MyValue to MyValue
                  If MyValue Then {
                        value$="true"
                  } else value$="false"
            }
      }
      Value {
            =.MyValue
      }
Class:
      Module Boolean (.MyValue) {}
}
Class Object {
Private:
      Inventory MyValue
Public:
      Property Type$ {Value} ="Object"
      Value {
            =.MyValue
      }
Class:
      Module Object (.MyValue) {}
}
Append alfa, "name":=JString$("this is a name"), "number":=Numeric(100)
Append alfa, "null1":=Null(),  "boolean":=Boolean(True)
Append alfa, "array1":=Arr((Numeric(100),arr((Numeric(2), Numeric(2.5))),Numeric(3),Numeric(4),Numeric(5)))
Append alfa1, "name":=JString$("name2"), "array1":=Arr((JString$("A"),JString$("B"),JString$("C")))
Append alfa2, "name_2":=JString$("name2_NAME"), "array1001":=Arr((JString$("A1"),JString$("B2"),JString$("C3")))
Append alfa, "object":=Object(alfa1)
Append alfa, "array2":=Arr((Numeric(101), JString$("A") )) ', Object(alfa2,)
A$={Hello There
      Second Line
      }
Append alfa, "string":=JString$(A$)
Append alfa4, "byte":=numeric(200), "bytename":=Jstring$("String Alfa"), "my array":=Arr((Numeric(1),Numeric(2), Numeric(3)))
Append alfa3, "first":=object(alfa1), "second":=object(alfa2), "third":=Arr((object(alfa4), Numeric(10),Numeric(5)))
\\ using an object to call recuirsive in object's namespace
Class CreatSerialize$ {
      space=6
      nl1$={
      }
      Function Jarray$ (json1, n){
            \\ json1 is group type Array
                     A=json1
                  \\ A is mArray (pointer to Array)
                  nl$=.nl1$
                  if n>0 then {
                        if n<.space then n=.space
                        nl$=nl$+string$(" ", n)
                  }
                  document a$
                  a$="["
                  if n>0 then a$=nl$
                   k=each(A)
                   M=len(A)-1
                   while k {
                        For This {
                              \\ temporary group
                              temp=array(k)
                              select case temp.type$
                              case "Number", "Null","Boolean", "String"
                              a$=temp.str$
                              case "Array"
                              {
                                    nn=0
                                    if n>0 then {
                                          nn=n +.space
                                    }
                                    a$=.Jarray$(temp, nn, "")
                              }
                              case "Object"
                              {
                                   nn=0
                                    if n>0 then {
                                          nn=n +.space
                                    }
                                    a$=.Jobject$(temp, nn,"")
                              }
                              else
                                    a$=" "+temp.type$
                              end select
                               If k^<M then {
                                   a$=", "
                                    if n>0 then a$=nl$
                              } else {
                                    if n>0 then a$=.nl1$
                                    if n-.space*2>0 then a$=string$(" ", n-.space)
                              }
                        }     
                  }
            a$="]"
               =a$+letter$
      }
      Function Jobject$ (json1, n){
                        json=json1
                        \\ json has to be an object inventory
                        nl$=.nl1$
                        if n>0 then {
                              if n<.space then n=.space
                              nl$=nl$+string$(" ", n)
                        }
                        document a$
                        a$="{"
                        if n>0 then a$=nl$
                         k=each(json)
                         M=len(json)-1
                         while k {
                              a$=quote$(eval$(json, k^)) +" : "
                              select case json(k^!).type$
                              case "Array"
                              {
                                    nn=0
                                    if n>0 then {
                                          nn=n +.space
                                    }
                                    a$=.Jarray$(eval(k), nn, "")
                              }
                              case  "Boolean", "Null", "Number", "String"
                                    a$=json(k^!).str$
                              case "Object"
                              {
                                    nn=0
                                    if n>0 then {
                                          nn=n +.space
                                    }
                                    a$=.Jobject$(eval(k), nn, "")
                              }
                              else
                                    a$=" "+json( k^!).type$
                              end select
                               If k^<M then {
                                   a$=", "
                                    if n>0 then a$=nl$
                              } else {
                                    if n>0 then a$=.nl1$
                                    if n-.space*2>0 then a$=string$(" ", n-.space)
                              }
                        }
                  a$="}"
                  =a$+letter$
      }
      Class Object {
      Private:
            Inventory MyValue
      Public:
            Property Type$ {Value} ="Object"
            Value {
                  =.MyValue
            }
      Class:
            Module Object (.MyValue) {}
      }
      Value (json, n) {
                  a$=.nl1$
                  if n=0 then a$=""
                  if type$(json)<>"Group" then {
                        =.Jobject$(.Object(json), n, a$)
                  } else {
                        =.Jobject$(json, n,a$)
                  }
      }
}
Global Serialize=CreatSerialize$()
Serialize.space<=4
Group alfabeta {
Private:
      Ser$=CreatSerialize$()
      Module ReadArrayItem (temp){
             Select Case temp.type$
                  Case "String","Boolean","Number", "Null"
                  {
                        Push temp.str$
                  }
                  Case "Object"
                  {
                        if not empty then {
                           call .ReadObject temp, letter$
                        } else {
                              Push .ser.Jobject$(group(temp),0,"")
                        }
                  }
                  Case "Array"
                  {
                        if not empty then {
                              ' recursion only with Call statement for modules
                              Call .ReadArrayItem, Array(temp, number)
                        } else {
                              Push .ser.JArray$(group(temp),0,"")
                        }
                  }
                  End Select
      }
      Module ReadObject (json, id$){
      \\ take two or more parameters
            If exist(json, id$) then {
                  temp=eval(json)
                  Select Case temp.type$
                  Case "String","Boolean","Number", "Null"
                  {
                        Push temp.str$
                  }
                  Case "Object"
                  {
                        if not empty then {
                              Call .ReadObject temp, letter$
                        } else {
                              Push .ser.Jobject$(group(temp),0,"")
                        }
                  }
                  Case "Array"
                  {
                        if not empty then {
                           call .ReadArrayItem array(temp, number)
                        } else {
  
                              Push .ser.JArray$(group(temp),0,"")
                        }
                  }
                  End Select
                 } else {
                 push "none"
            }
      }
Public:
      Function UseDecimalPoint$ {
            ' use this to change standard decimal point to local decimal point character
            =str$(val(letter$),"")
      }
      Function ReadNumber$ {
                  \\ read an inventory
                  .ReadObject
                  =.UseDecimalPoint$(Letter$)
      }           
      Function ReadAnyString$ {
                  \\ read an inventory
                  .ReadObject
                  =Letter$
      }
}
Pen 11 {
     Report Serialize$(alfa, 6)
}
For alfabeta {
      Print "Read alfa"
      Report  {(alfa, "name")=}+ .ReadAnyString$(alfa, "name")
      Report  {(alfa, "array1")=} + .ReadAnyString$(alfa, "array1")
      Report  {(alfa, "array1", 0)=} + .ReadAnyString$(alfa, "array1", 0)
      Report  {(alfa, "array1", 1, 1)=} + .ReadNumber$(alfa, "array1", 1, 1)
      Report  {(alfa, "array1", 3)=} + .ReadAnyString$(alfa, "array1", 3)
      Report  {(alfa, "object")=} + .ReadAnyString$(alfa, "object")
      Report  {(alfa, "object","name")=} + .ReadAnyString$(alfa, "object","name")
      Report  {(alfa, "object", "array1")=} + .ReadAnyString$(alfa, "object", "array1")
      Report  {(alfa, "object", "array1", 2)=} + .ReadNumber$(alfa, "object", "array1", 2)
      \\ Param$() throw first and last ""
      n=row
      report {(alfa,"string")=}
      Cursor tab(1), row-1
      Pen 10 {
           Report format$(Param$(.ReadAnyString$(alfa,"string")))
      }
      Print @(0,n+2)
      Pen 11 {
            Report Serialize$(alfa3, 0)
      }
      Print "Read alfa3"
      Report  {(alfa3, "third", 0,"byte")=} + .ReadNumber$(alfa3, "third", 0,"byte")
      Report  {(alfa3, "third", 0,"my array")=} + .ReadAnyString$(alfa3, "third", 0,"my array")
      Report  {(alfa3, "third", 0,"my array",0)=} + .ReadNumber$(alfa3, "third", 0,"my array",0)
}


Document json$=Serialize$(alfa, 6)
Save.Doc json$, "alfa.json"
Wait 100
If exist("alfa.json") then {
      report "File Saved to "+Dir$+"alfa.json"
}
' by default document saved in utf8 format
' Display to notepad
Win "notepad", dir$+"alfa.json"









Πέμπτη 8 Ιουνίου 2017

Δομές Δεδομένων στην Μ2000


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

Υπολογισμός Μέσου Όρου

Γράφουμε σε ένα τμήμα Α με το Σ Α ανοίγει ο διορθωτής, κάνουμε επικόλληση  και πατάμε το Esc για να βγούμε. Καλούμε το τμήμα με Α και enter

Εισαγωγή "Χ, Υ =", Χ, Υ
Τύπωσε "Μέσος όρος=", (Χ+Υ)/2
Λίστα      'εμφάνιση μεταβλητών
Τμήματα ? ' εμφάνιση τμημάτων



Καλούμε το τμήμα Α και εμφανίζεται το:
Χ,Υ=_
Τώρα γράφουμε το 10 πατάμε το κόμμα ή το Εnter κα βάζουμε το 3 και πατάμε Enter. Η Τύπωσε μας επιστρέφει τιμή το μέσο όρο, με εμφάνιση μηνύματος. Δείτε ότι το νούμερο "απέχει" κάπως από το = γιατί έχουμε βάλει το κόμμα (σημαίνει αλλαγή στήλης) και ίσως το σταθερό αλφαριθμητικό "Μέσος όρος=" να καλύπτει περισσότερες από μια στήλες. Οι αριθμοί στοιχίζονται με δεξιά στοίχιση, ενώ τ3α αλφαριθμητικά με αριστερή στις στήλες.
Γενικά όταν γράφουμε προγράμματα δεν στεκόμαστε μόνο στο ότι "κάπως" θα εισάγει στοιχεία και στο ότι "κάπως" θα εξάγει στοιχεία, αλλά μας ενδιαφέρει το πώς θα εισάγει και πώς θα εξάγει στοιχεία.
Τώρα θα επεκτείνουμε το πρόγραμμα ώστε αντί να διαβάσει από τη κονσόλα τιμές θα τις διαβάσει από το σωρό τιμών. Θα εξασφαλίσουμε πρώτα ότι ο σωρός είναι καθαρός με την εντολή Άδειασε
>Άδειασε
Τώρα με Σ Α ανοίγουμε το διορθωτή και γράφουμε:
Σειρά 10, 3
Διάβασε
Χ, Υ
Τύπωσε Μορφή$(
"Μέσος_όρος({0},{1})={2}",Χ, Υ, (Χ+Υ)/2
)


Έχουμε αλλάξει την Τύπωσε για να μας δείχνει σε ένα αλφαριθμητικό το αποτέλεσμα. Η εντολή Σειρά βάζει τα 10,3 στο τέλος του σωρού, άρα το 3 θα είναι τελευταίο. Αφού ο σωρός είναι άδειος το 10 θα είναι στην κορυφή και θα διαβαστεί στην Χ, και το 3 θα γίνει η επόμενη κορυφή και θα διαβαστεί στην Υ.
Τώρα θα βάλουμε περισσότερα νούμερα και θα σκεφτούμε έναν τρόπο ώστε αφενός να μην μας νοιάζει τι είχε ο σωρός πριν τα βάλουμε και επιπλέον να μπορούμε να σταματήσουμε πριν αδειάσει ο σωρός, διαφορετικά θα βγει λάθος.

Α=Σωρός:=10,3,5,2,11,7,45,23
Σωρός Α {
      Διάβασε Χ, Υ
      Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}",Χ, Υ, (Χ+Υ)/2)
      Αν οχι κενό τότε κυκλικά
}


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

ΜέσοςΌρος(10,3,5,2,11,7,45,23,0)
ΜέσοςΌρος(10,3,0)

Ρουτίνα ΜέσοςΌρος()
            Τοπικές Χ, Υ
            {
                  Διάβασε Χ
                  Αν Χ=0 τότε Έξοδος
                  Διάβασε Υ
                  Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}",Χ, Υ, (Χ+Υ)/2)
                  Κυκλικά
            }
Τέλος Ρουτίνας


Οι ρουτίνες δεν έχουν μπλοκ κώδικα αλλά μπορούμε να βάλουμε ένα όπου θέλουμε! Το πρόγραμμα θα τερματίσει αν δώσουμε το μηδέν. Αν κάνουμε λάθος και δεν δώσουμε το μηδέν τότε θα τραβήξει ότι βρει στο σωρό τιμών, και αν δεν βρει το μηδέν, θα πάει να διαβάσει από κενό σωρό και θα βγει λάθος! Ορίζουμε τις Χ και Υ ως τοπικές γιατί η ρουτίνα βλέπει οτιδήποτε βλέπουμε και στο τμήμα που καλούμε την ρουτίνα. Αν λοιπόν τα Χ και Υ υπήρχαν ήδη στο τμήμα, τότε θα άλλαζαν τιμή στην ρουτίνα, χωρίς την χρήση της εντολής Τοπικές (ή Τοπική)!
Ορισμένες φορές οι Πίνακες δίνουν μικρότερο κώδικα. Εδώ δεν θα χρησιμοποιήσουμε φύλακα, ούτε θα χρησιμοποιήσουμε αντικείμενο Σωρό, αλλά Πίνακα. Μάλιστα θα τροφοδοτήσουμε το πίνακα με "αυτόματο πίνακα", δηλαδή τιμές μέσα σε παρενθέσεις. Εδώ το (2) δεν είναι πίνακας, ενώ το (2,) είναι πίνακας ενός στοιχείου, και το (,) είναι πίνακας μηδενικών στοιχείων.

ΜέσοςΌρος((10,3,5,2,11,7,45,23))

Ρουτίνα ΜέσοςΌρος(Π())
      Τοπική Ν
      Για Ν = 0 έως Μήκος(Π())-1 ανά 2 {
            Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}", Π(Ν), Π(Ν+1), (Π(Ν)+Π(Ν+1))/2)
      }
Τέλος Ρουτίνας



Και χωρίς την χρήση ρουτίνας:

Πίνακας Π()
Π()=(10,3,5,2,11,7,45,23)
Για Ν = 0 έως Μήκος(Π())-1 ανά 2 {
      Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}",Π(Ν), Π(Ν+1), (Π(Ν)+Π(Ν+1))/2)
}



Και στα δυο παραδείγματα χρησιμοποιούμε απαριθμητή. Στο παρακάτω παράδειγμα έχουμε δυο πίνακες (κενούς στην αρχή). Ο Π() γεμίζει με τέσσερις πίνακες των δυο στοιχείων). Δεν γίνεται δυο διαστάσεων, αλλά πίνακας με στοιχεία πίνακες. Κάθε φορά διαβάζουμε έναν πίνακα στο Α(), στην ουσία ο Α() γεμίζει με στοιχεία από το Π(Ν).

Πίνακας Π(), Α()
Π()=((10, 3),(5,2),(11,7),(45,23))
Για Ν = 0 έως Μήκος(Π())-1 {
      Α()=Π(Ν)
      Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}",Α(0),Α(1), (Α(0)+Α(1))/2)
}



Ακόμα πιο απλός κώδικας με πίνακα δυο διαστάσεων. Μπορούμε να γεμίσουμε τιμές τον πίνακα δίνοντας ένα αρχικό στοιχείο (εδώ το 0,0) και δίνοντας τις σειρές τη μία μετά την άλλη.

Πίνακας Π(4,2)
Π(0,0)=10,3,5,2,11,7,45,23
Για Ν = 0 έως 3 {
      Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}",Π(Ν,0),Π(Ν,1), (Π(Ν,0)+Π(Ν,1))/2)
}



Αν δεν μας αρέσει το 0,0 δηλαδή η βάση πίνακα να είναι το 0 μπορούμε να ορίσουμε βάση το 1 (ή 0 ή 1 δέχεται η Μ2000)

Πίνακας Βάση 1, Π(4,2)
Π(1,1)=10, 3,5,2,11,7,45,23
Για Ν = 1 έως 4 {
      Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}",Π(Ν,1),Π(Ν,2), (Π(Ν,1)+Π(Ν,2))/2)
}



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

Α=Σωρός:=10,3,5,2,11,7,45,23
Σωρός Α {
      Για ι=1 έως Μέγεθος.Σωρού ανά 2 {
            Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}",ΤιμήΣωρού(ι), ΤιμήΣωρού(ι+1), (ΤιμήΣωρού(ι)+ΤιμήΣωρού(ι+1))/2)
      }
}
Τύπωσε Μήκος(Α)
Σωρός Α {Αδειασε}
Τύπωσε Μήκος(Α)


Ή χωρίς την χρήση Σωρός Αντικείμενο {} που βάζει προσωρινά το Α για τον σωρό τιμών, και απευθείας χρήση του αντικειμένου με την Μήκος(Α) αντί του Μέγεθος.Σωρού. Η ΤιμήΣωρού() μπορεί να πάρει πρώτο στοιχείο το αντικείμενο και δεύτερο τον αριθμό της τιμής στο σωρό).

Α=Σωρός:=10,3,5,2,11,7,45,23
Για ι=1 έως Μήκος(Α) ανά 2 {
      Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}",ΤιμήΣωρού(Α,ι), ΤιμήΣωρού(Α,ι+1), (ΤιμήΣωρού(Α,ι)+ΤιμήΣωρού(Α,ι+1))/2)
}
Η μεταβλητή Α είναι δείκτης σε Σωρό. Η Μ2000 ποτέ δεν μας δίνει το δείκτη, τον χρησιμοποιεί όμως. Θα μπορούσαμε να καθαρίσουμε το σωρό μόνο με μια εντολή: Α=Σωρός όπου η Α θα έπαιρνε έναν άδειο σωρό, και ο προηγούμενος επειδή θα έχανε το δείκτη που τον κρατούσε "σε ύπαρξη", θα καταστρέφονταν αυτόματα.
Η Τύπωσε εκτός από το να τυπώνει αλφαριθμητικά και αριθμούς, τυπώνει σε στήλες πίνακες, καταστάσεις, και σωρούς. Πχ. η Τύπωσε Α πριν αδειάσουμε το σωρό θα έδειχνε τα στοιχεία του σε στήλες.
Δείτε επίσης ότι στο αντικείμενο σωρός η βάση είναι το 1, δηλαδή το πρώτο στοιχείο είναι το 1.
Μπορούμε σε ένα σωρό να έχουμε άλλους σωρούς μέσα (όπως κάναμε και με τους αυτόματους πίνακες πιο πριν). Εδώ θα χρησιμοποιήσουμε ένα σωρό με δυο σωρούς, και θα διαβάζουμε απευθείας σε δείκτη Α το σωρό (δεν υπάρχουν αντιγραφές πινάκων όπως γίνονταν στα παραδείγματα με τους πίνακες).

Α1=Σωρός:=(Σωρός:=10,3,5,2), (Σωρός:=11,7,45,23)
Για Ν=1 έως Μήκος(Α1) {
      Α=ΤιμήΣωρού(Α1,Ν)
      Για ι=1 έως Μήκος(Α) ανά 2 {
            Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}",ΤιμήΣωρού(Α,ι), ΤιμήΣωρού(Α,ι+1), (ΤιμήΣωρού(Α,ι)+ΤιμήΣωρού(Α,ι+1))/2)
      }
}


Υπάρχει τρόπος να μην χρησιμοποιήσουμε την Για, και αντί αυτής να χρησιμοποιήσουμε επαναλήπτη με την Κάθε(). Ο επαναλήπτης λειτουργεί από το 0 (οπότε εμείς θέλουμε το +1, γιατί έχουμε βάση το ένα στο αντικείμενο). Η τιμή του μπορεί να διαβαστεί στο Ν^ για τον Ν και στο Ν1^ για το Ν1 (τα Ν και Ν1 είναι αντικείμενα επαναλήπτες). Η αλλαγή βήματος γίνεται με τον αναπρογραμματισμό του επαναλήπτη μέσα στην Ενώ { }, αλλιώς το βήμα παραμένει ένα.

Α1=Σωρός:=(Σωρός:=10,3,5,2), (Σωρός:=11,7,45,23)
Ν=Κάθε(Α1)
Ενώ Ν {
      Α=ΤιμήΣωρού(Α1,Ν^+1)
      Ν1=Κάθε(Α)
      Ενώ Ν1 {
            Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}",ΤιμήΣωρού(Α,Ν1^+1), ΤιμήΣωρού(Α,Ν1^+2), (ΤιμήΣωρού(Α,Ν1^+1)+ΤιμήΣωρού(Α,Ν1^+2))/2)
            ' Αλλαγή βήματος
            Ν1=Κάθε(Α, Ν1^+2)
      }
}


Εδώ έχουμε ένα πίνακα (δείκτη σε πίνακα) που κρατάει έναν αυτόματο πίνακα, με δυο στοιχεία, δυο αντικείμενα σωρούς. 

Π=((Σωρός:=10,3,5,2), (Σωρός:=11,7,45,23))
Ν=Κάθε(Π)
Ενώ Ν {
      Α=Πίνακας(Ν)
      Για ι=1 έως Μήκος(Α) ανά 2 {
            Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}",ΤιμήΣωρού(Α,ι), ΤιμήΣωρού(Α,ι+1), (ΤιμήΣωρού(Α,ι)+ΤιμήΣωρού(Α,ι+1))/2)
      }
}



Με μια προσεκτική μελέτη των παραπάνω, βλέπουμε ότι όλα τα δεδομένα μας είναι ζευγάρια τιμών, από τα οποία εξάγουμε τον μέσο όρο. Θα μπορούσαμε να φτιάξουμε ομάδες με δυο τιμές Χ και Υ με κατασκευαστή μια κλάση με όνομα Ζεύγος.

Κλάση Ζεύγος {
      
Χ, Υ
Κλάση:
      
Τμήμα Ζεύγος (.Χ, .Υ) {}
}

Π=((Σωρός:=Ζεύγος(10,3), Ζεύγος(5,2)), (Σωρός:=Ζεύγος(11,7), Ζεύγος(45,23)))
Ν=Κάθε(Π)
Ενώ Ν {
      Α=Πίνακας(Ν)
      Α1=Κάθε(Α)
      Ενώ Α1 {
            ΔείξεΜέσοΌρο(ΤιμήΣωρού(Α1))
      }
}

Ρουτίνα ΔείξεΜέσοΌρο(Ζεύγος)
      Για Ζεύγος {
            Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}",.Χ, .Υ, (.Χ+.Υ)/2)
      }
Τέλος Ρουτίνας






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

Κλάση Ζεύγος {
      Χ, Υ
Κλάση:
      Τμήμα Ζεύγος (.Χ, .Υ) {}
}

Π=((Σωρός:=Ζεύγος(10,3), Ζεύγος(5,2)), (Σωρός:=Ζεύγος(11,7), Ζεύγος(45,23)))
Ν=Κάθε(Π)
Ενώ Ν {
      Α=Πίνακας(Ν)
      Α1=Κάθε(Α)
      Ενώ Α1 {
            ΔείξεΜέσοΌρο(ΤιμήΣωρού(Α1), Αληθές)
            Επιστροφή Α, Α1^+1:=Ομάδα
      }
}
\\ Δεύτερη ανάγνωση - επεξεργασία
Ν=Κάθε(Π)
Ενώ Ν {
      Α=Πίνακας(Ν)
      Α1=Κάθε(Α)
      Ενώ Α1 {
            ΔείξεΜέσοΌρο(ΤιμήΣωρού(Α1), Ψευδές)
      }
}
Ρουτίνα ΔείξεΜέσοΌρο(Ζεύγος, Οκ)
      Για Ζεύγος {
            Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}",.Χ, .Υ, (.Χ+.Υ)/2)
            Αν Οκ Τότε {
                  Ζεύγος.Χ+=10
                  Βάλε Ζεύγος
            }
      }
Τέλος Ρουτίνας



Στο παράδειγμα, κάνουμε δυο περάσματα στα Ζεύγη. Στο πρώτο μέσω μιας σημαίας (ΟΚ) όταν είναι Αληθές, αυξάνουμε την .Χ του ζεύγους κατά 10 και τοποθετούμε το ζεύγος στο σωρό. Η μεταβλητή Ομάδα διαβάζει από τη κορυφή του σωρού μια ομάδα (αν δεν υπάρχει ομάδα στη κορυφή σωρού βγαίνει λάθος). Για να επιστρέψουμε τιμή στο αντικείμενο Σωρός Α θα πρέπει να χρησιμοποιήσουμε την Επιστροφή (επιστρέφει πολλές τιμές αν θέλουμε), και αυτή δέχεται ένα κλειδί και μια τιμή. Εδώ το κλειδί είναι το Α1^ (με βάση το 0) συν ένα για να γυρίσει σε βάση το 1, όπου δουλεύει το αντικείμενο σωρός, άρα Α^+1. Προσοχή ο τελεστής ^ σε μεταβλητές αριθμητικές είναι η ύψωση σε δύναμη (όπως και το **) αλλά εδώ το Α1 δεν είναι αριθμός αλλά αντικείμενο, ενώ το Α1^ είναι η επιστροφή τιμής του επαναλήπτη. Επίσης βλέπουμε ότι αντί της ΤιμήΣωρού(Α, Α1^+1) χρησιμοποιούμε την ΤιμήΣωρού(Α1) για να διαβάσουμε την ομάδα. Η εντολή Επιστροφή Αντικείμενο, κλειδί:=τιμή [, κλειδίΝ:=τιμήΝ] δουλεύει για αντικείμενα όπως Αντικείμενο Πίνακας, Αντικείμενο Σωρός, Κατάσταση.
Την Κατάσταση δεν την έχουμε δει ακόμα γιατί αυτή σχετίζεται με κλειδιά αριθμητικά ή αλφαριθμητικά (εσωτερικά είναι αλφαριθμητικά). Οι αλλαγές φαίνονται με κίτρινο χρώμα. Οι καταστάσεις δουλεύουν με πίνακα κατακερματισμού, και έτσι έχουν αναζήτηση άμεση ανεξάρτητη από τον αριθμό κλειδιών.
Στις καταστάσεις δεν είναι σίγουρη η σειρά των στοιχείων. Αν κάνουμε διαγραφή θα γίνει αλλαγή θέσης, θα πάει στο χώρο του διαγραμμένου το τελευταίο της σειράς (ο δείκτης του). Υπάρχει η Κατάσταση Ουρά η οποία δεν δέχεται διαγραφή αλλά με την Χρήση της Πέτα, διαγράφουμε από το τέλος όσα στοιχεία θέλουμε. Η Κατάσταση Ουρά επιπλέον δεν επιδέχεται ταξινόμηση, αλλά μπορεί να πάρει όμοια κλειδιά, κάτι που δεν γίνεται στην κανονική Κατάσταση. Ο λόγος ύπαρξης της Κατάστασης Ουράς είναι να συγκεντρώνει σε ένα χώρο (σε ένα δείκτη) πολλαπλές εγγραφές που έρχονται χρονικά, και διαγράφονται με την ανάποδη σειρά, δηλαδή το τελευταιο που μπαίνει βγαίνει πρώτο (LIFO). Όταν υπαρχουν όμοια κλειδιά η αναζήτηση βρίσκει πάντα το τελευταίο. Μπορούμε να κινηθούμε σε όλα, με τον επαναλήπτη, και είναι σίγουρο ότι θα έχουν την θέση "χρονικά" εισαγωγής.

Κλάση Ζεύγος {
      Χ, Υ
Κλάση:
      Τμήμα Ζεύγος (.Χ, .Υ) {}
}

Κατάσταση Κ="Πρώτος Σωρός":=(Σωρός:=Ζεύγος(10,3), Ζεύγος(5,2)), "Δεύτερος Σωρός":=(Σωρός:=Ζεύγος(11,7), Ζεύγος(45,23))
Ν=Κάθε(Κ)
Ενώ Ν {
      Α=Έκφραση(Ν)
      Α1=Κάθε(Α)
      Ενώ Α1 {
            ΔείξεΜέσοΌρο(ΤιμήΣωρού(Α1), Αληθές)
            Επιστροφή Α, Α1^+1:=Ομάδα
      }
}
\\ Δεύτερη ανάγνωση - επεξεργασία
Ν=Κάθε(Κ)
Ενώ Ν {
      Α=Έκφραση(Ν)
      Α1=Κάθε(Α)
      Ενώ Α1 {
            ΔείξεΜέσοΌρο(ΤιμήΣωρού(Α1), Ψευδές)
      }
}
Ρουτίνα ΔείξεΜέσοΌρο(Ζεύγος, Οκ)
      Για Ζεύγος {
            Τύπωσε Μορφή$("Μέσος_όρος({0},{1})={2}",.Χ, .Υ, (.Χ+.Υ)/2)
            Αν Οκ Τότε {
                  Ζεύγος.Χ+=10
                  Βάλε Ζεύγος
            }
      }
Τέλος Ρουτίνας





Τρίτη 6 Ιουνίου 2017

Αναθεώρηση 9 (Έκδοση 8.8)

Μερικές διορθώσεις:
1. Όταν βάζαμε αριθμό κινητής υποδιαστολής σε Κατάσταση (Inventory) στην ανάγνωση χάνονταν τα δεκαδικά αν το κόμα ήταν η υποδιαστολή. Διορθώθηκε.
2. Προστέθηκε ένα πεδίο ακόμα στην εντολή Σύστημα ή Win, για να δώσουμε παραμέτρους. Πχ αν έχουμε το αρχείο alfa.bmp στο φάκελο χρήστη τότε το Win "alfa.bmp", "/p" θα ανοίξει το mspaint για άμεση εκτύπωση της εικόνας. Υπάρχει η εντολή Bitmaps ή Εικόνες που εμφανίζει τις εικόνες (το όνομά τους στο τρέχον φάκελο).
3. Με την εντολή Σύστημα Κατ$ ανοίγει ο κατάλογος του χρήστη (ή όποιος είναι ο τρέχον) και εκεί βάζουμε μερικές φωτογραφίες (bmp, ico, jpg, wmf, emf)




Οθόνη 5, 0
Πενα 14
Άνοιγμα.Εικόνας
Διάβασε α$
Αν α$<>"" τότε {
      Θέση 0,0
      Εικόνα α$, χ.σημεία
}
κ$=κομ$
Οθόνη
β$=""""
Αν α$<>"" τότε {
      Θέση 0,0
Σημ 1:
      Εικόνα α$ στο β$ ' το β$ περιέχει εικόνα
Σημ 2: Εικόνα α$ στο β$, 100,50 ' 100% στο πλάτος και 50% στο μήκος
      \\ τώρα βάζουμε την εικόνα  εντός πλαισίου
      Εικόνα Πλαίσιο β$, χ.σημεία, υ.σημεία
}
κ$=κομ$
Αν α$<>"" τότε {
      Θέση χ.σημεία/2, υ.σημεία/2
      ' κεντράρισμα με χρήση του αρχείου
      ' Σκέτο Διάφανο α$ είναι το ίδιο με το παρακάτω
      ' αλλά δεν επιστρέφει στο διαφάνεια το τμήμα που "πατάει"
      ' η δεύτερη παράμετρος είναι για το χρώμα με 100% διαφάνεια
      ' εδώ δεν το χρησιμοποιούμε!
      Διάφανο α$,,0
      α1$=διαφάνεια$
      κ$=κομ$
      Διάφανο α$,,45,200, 50
      α2$=διαφάνεια$
      Αντέγραψε "ολοκληρη_οθονη"
      κ$=κομ$
      Διάφανο α2$
      κ$=κομ$
      Διάφανο α1$
}
κ$=κομ$


Οθόνη
Θέση 0,0
Εικόνα "ολοκληρη_οθονη" , χ.σημεια
Εικόνα "ολοκληρη_οθονη"  στο β$
\\ βάζουμε την εικόνα στο πρόχειρο
Προχειρο β$
β$=""
\\ τώρα τη διαβάζουμε
β$=Πρόχειρο.Εικόνα$
\\ αντιγράφει με το πάνω αριστερό σημείο, διαγράφοντας το πλαίσιο
\\ βάζοντας δηλαδή "επάνω" μόνο την εικόνα
Αντέγραψε 5000,5000 Επάνω β$, 30,20
\\ ομοίως αλλά δεν διαγράφει το πλαίσιο
\\ βάζει την εικόνα με το πλαίσιο μαζί
Αντέγραψε 10000,5000 Με β$, 30,20







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

Αναθεώρηση 8 (Έκδοση 8.8)

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

Επίσης η εντολή  LoadDoc ή Φόρτωσε.Έγγραφο μπορεί να πάρει ένα αρχείο κειμένου (δοκιμάστηκε με 42k παραγράφους από αρχείο bas το οποίο χρωματίστηκε όταν περάστηκε σε EditBox της Μ2000), και είτε να το σταματήσουμε είτε να λειτουργούν τα γεγονότα στην φόρμα, ενώ πριν ο έλεγχος γύρναγε μετά  τη φόρτωση/αναδίπλωση παραγράφων/χρωματισμό.

Επίσης μικρές διορθώσεις, όπως για τα αρχεία gsb, με τμήματα και συναρτήσεις, που σώνουμε κωδικοποιημένα, και τα φορτώνουμε επίσης με δικό μας ή τον στανταρ κωδικό.

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

Στο http://alkisg.mysch.gr/steki/index.php?topic=7138.msg80626#msg80626 έχει γίνει μια συζήτηση για τη ΓΛΩΣΣΑ του σχολείου, όπου το βήμα 0 κάνει την "Για" να μπαίνει σε βρόχο ατέρμων.
Η Μ2000 πάντα εκτελεί μια φορά το μπλοκ της Για ακόμα και με μηδενικό βήμα. Πριν ξεκινήσει η εκτέλεση ο δειρμηνευτής ξέρει πόσες επαναλήψεις θα κάνει. Η μεταβλητή ελέγχου δεν είναι θεατή στο προγραμματιστή. Είναι όμως μια μεταβλητή που έχει επιλέξει ο προγραμματιστής και η οποία ενημερώνεται σε κάθε επανάληψη από την πραγματική μεταβλητή ελέχου. Ετσι δεν μπορούμε να αλλάξουμε την μεταβλητή ελέγχου (αλλάζουμε μόνο τη μεταβλητή για την τρέχουσα επανάληψη)