Scripting 101, lesson #2 - Variables #2, and Functions.

C Scripting questions and answers
Post Reply
User avatar
ArtF
Global Moderator
Global Moderator
Posts: 4586
Joined: Sun Sep 05, 2010 6:14 am
Contact:

Scripting 101, lesson #2 - Variables #2, and Functions.

Post by ArtF »

 
  OK, so weve discussed what a variable is, and what things it can hold. As
I mentioned then, even a function is a variable. Look to the way we declare a
function and youll see only a small difference between a normal variable and
a function.

  variable:

  a = "a string";

  function:

  a = function( x) { b= 9; };


  Both stick a "thing" in the variable a. If you ask Monkey the question
"Whats in your wallet" now with a print statement..

print(a);

  it will in the first case print

  9

  and in the second case print

  a(unknown)

  All the print is really doing is showing the value in the variable, in this case
its tell you its a function named a() with unknown value. Makes sense as no function
can have a known value generally.


    In fact, In Monkey, all variables have several boxes in them, one for each type it can hold,
the system simply uses the type it has deduced the variable to be, to decide which box to open
to show you the contents.

  So when we declare a funciton we have to tell it its a function with that keyword,
and we must then include enough of a script to consider it a function. Just as a
integer or string can be global or local , so too can a function.

      myfunc = function( x, y, z) { return x+y+z; }; 
or
global myfunc = function( x, y, z) { return x+y+z; };

  One sticks around, and other scripts can use it, the other doesnt. Once your script
ends, the non-global is destroyed, just like all variables. Most users will use globals
written by myself, or others who are at that level, to include in their own scripts.
Everyone will in the end likely write scripts or at least modify them. Its quite
possible as of the writing of this, to turn on spindles ( in various ways) and other output
to mimic most things in a conventional controller. More global functions will always be
in the works, and you store these in the libraries. Well talk much more about those
in the future.


    So when declaring a function, you'll notice all your really doing is setting a variable name
such as "myfunc" in the above example. Following the variable name is the word function to tell the
system the variable type. Its very much like declaring a table variable. The real difference
is that following the word function will be a script in braces and ending with a ";". In the
example above we have "{ return x+y+z; };"

  Lets make that less efficient as an example. Lets make it

global myfunc = function( x, y, z)
{
    sum = x + y+ z;
    return sum;

};

  Ive now made it two lines to make a point, and reformatted to make another.
Firstly, the function can be as long as you want it to be, second, its smart
to maintain a format thats the same as the other scripts, not only as a convention
but to aid others reading your code. When I started programming in 1978, if a language
used braces, they were used as above, these days its more common to see a braced section
written as

global myfunc = function( x, y, z){

    sum = x + y+ z;
    return sum;
};

  But as a guy who's programming spots were indelibly etched many eons ago, I find
it hard to get used to that, so I stuck with braces under braces as my personal
choice. I will eventually add auto indent to the current auto completion and syntax
colouring, so you might want to follow my lead and keep braces under each other.
You "could" lobby me to be more cosmopolitan and use the end line braces...but Id
just laugh at you and do as I want anyway.. but either way WILL work.. :)


  I think you get the idea that the function above is adding up the x-z above and
sending back an answer. You dont need to send anything back... the function

global myfunc = function( x, y, z)
{

    sum = x + y+ z;
   
};

  is perfectly legal, though it doesnt do anything, it could though,just by calling other functions..
as in ..

global myfunc = function( x, y, z)
{

    sum = x + y+ z;
    SendSumToMyOtherCode( sum );
};

  Making this function usefull one would assume. Just as Game Monkey autotypes a variable
when you do a f = 6; , it autotypes from a function as well, so a

myvar = myfunc( 6,7,8 );

        would type the variable as a integer when we return one, a string
if we should return a string, or NULL is we return nothing.. you may even get an error
if you try to stick the result of a function in a variable when there is no return,
depending on circumstances.

  The point here is that functions do not need to "return" anything, but if they do,
any variable they send back will be used to type the variable that receives it. As you
see in the example with "SendSumToMyOtherCode(sum);" in it, you can see that a function
can call other functions. Auggies really just a huge collection of such functions, some
of which you can call yourself in your scripts. Now I said a few lines back, that
after the word "function", what follows is "in braces" a valid script. Lets look to that..

{

    sum = x + y+ z;
    SendSumToMyOtherCode( sum );
};

  Auggie considers braces and brace counts in all things it does.The above few lines
are also legal in Gcode files, BECAUSE of the brace count. As augie reads a file it counts
braces. When it see's a "{" it adds 1. When it sees a "}", it subtracts one from the
brace count. This is important to know. When brace count is zero, anything it reads
is GCODE and will be acted on and give errors just like Gcode.. BUT, when the brace count
is above zero, all text read is added together to make one big string, and when
bracecount again hits zero, this triggers a script run of that line.. Let me show you an example,
and show you the hidden accumulation variable which is a string..

Imagine this file is running in a gcode file window.. 

G0X10Y10   
               
{ print(""File starts"); }
G1X5Y5
{
  print("Hello there");
&nbsp; for ( x = 0; x < 10; x+= 1)
&nbsp; {
&nbsp; &nbsp; print( x);
&nbsp; &nbsp; FeedTo( x );
&nbsp; };
}
G1X0Y0
...
...


&nbsp; Silly program, but all quite legal..Heres what happens internally..

G0X10Y10&nbsp; &nbsp; //program send line 10,10 to the planner, it will start soon as planned.&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //spaces or empty lines are ignored.
&nbsp; &nbsp;
{ print(""File starts"); }

as the above line loads, bracecnt goes to 1, print call is put in accumulator and
bracecnt goes to zero on last character, so, since it hit zero, the entire line is sent
( less the first and last brace ) to the scripter for processing, the next line will
not be exectuted until this script ends. So the scripter only see's
"print(""File starts");" just as your type it in the scripter or script mdi, and executes
it.



G1X5Y5&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // feed line to 5,5 sent to planner,
{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //bracecnt goes to 1
&nbsp; print("Hello there");&nbsp; &nbsp; //accumlator = " print("Hello there");"
&nbsp; for ( x = 0; x < 10; x+= 1) //accumlator = " print("Hello there"); for... "
&nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //bracecnt goes to 2, accumlator = " print("Hello there"); for... {"
&nbsp; &nbsp; print( x);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //accumlator = " print("Hello there");.....);"
&nbsp; &nbsp; FeedTo( x );&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //accumlator = " print("He.. FeedTo( x );"
&nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //bracecnt goes to 1; //accumlator = " print("He.. FeedTo( x ); };"
}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //bracecnt goes to 0; Triggers execution of script in accumulator
G1X0Y0&nbsp; //planner gets rapid to (0,0); ...
...
...


&nbsp; So as you can see, the way a function works is similar to the way Gcode and script mix.
after the word function must follow a legal script that if placed in Gcode would also
work just as well. So when in Gcode, any text inbetween "{" and "}" will be
considered a function with no name to be called immediately. It may, as all functions,
contain as many {'s and }' as you need, but they must always cancel each other out.

&nbsp; Functions can do work, and in that work call other functions. Those functions called
may call other functions. In fact , Auggie, like any program boils down to one
function called Main() that runs everything else. Your functions will do the same,
essentially boiling down a large job into many small ones, and when you set out
to start scripting, your well advised to ponder all the things your intended function will
do, break them into the smallest parts possible, and write the smallest fastest ones first,
that basically is how all programming works. Mach3 is a very tall building built with
very small toothpicks. My job, as Auggies author, is to give you an ever increasing array
of toothpicks with which to build your personal tower.

&nbsp; Now there are times, when you want to call a function and wait for an answer, other times
its only necessary to start a fucntion that runs a process or monitors something in hardware
so there are a couple of ways a function can call another.

&nbsp; In a function you could call a function normally, as in

DoMyLaudry();

&nbsp; this implies however, that you wish to wait for your laundry, and sometimes your
script may be leading a busy life.. wife to pick up, kids to kill, important things
that mean you dont have time to waste waiting around, so you can tell a function to
run on its own without you supervising..&nbsp; you can call

thread( DoMyLaundry);

&nbsp; This tells the function to start running as it can, and you immediatley continue
doing what your doing. The internals of DoMyLandry may look something like this

global DoMyLaundry = function()
{

&nbsp; while( kidsarenthome )
&nbsp; {
&nbsp; &nbsp; &nbsp; WatchTV();
&nbsp; }
&nbsp; MakeKidsDoLaudry();

}

&nbsp; &nbsp; Now a function as above would continuously call WatchTV until the
global variable kidsarenthome is set to true by some other thread watching the
front door. But as we said earlier, the Gcode following this call , or function
that follows whatever called this will be blocked from running forward
until the kids get home AND the laudry is done, unless you call it with

thread( DoMyLaundry);

&nbsp; Then it runs on its own.. BUT. we still have a problem.. consider whats happening here..

&nbsp; while( kidsarenthome )
&nbsp; {
&nbsp; &nbsp; &nbsp; WatchTV();
&nbsp; }
&nbsp; MakeKidsDoLaudry();


&nbsp; If, for whatever reason, the kids DONT come home, or they take any time at all,
Auggie will be locked up. Your not running a preemptive operating system, when a
thread locks, which is the term for the above, the program locks up. Auggie, during
a program run is preemptive, it ill interrupt a thread that takes too long, but thats
not a desirable thing, it should'nt happen as the interruption may not have been anticipated
by the author.. so best to plan for such things. We have a couple of ways..

while( kidsarenthome )
&nbsp; {
&nbsp; &nbsp; &nbsp; WatchTV();
&nbsp; &nbsp; &nbsp; yield();
&nbsp; }
&nbsp; MakeKidsDoLaudry();

&nbsp; The above fixes the trouble. A "yield();" means to pass control to other waiting
threads. There is no such things as parallel programming on your cpu, ( in your GPU yes..
but thats another story..), in a cpu all things are linear and one at a time.

&nbsp; Auggie can run hundreds of scripts at once.. but really, they all run every 100ms or so,
and one at a time in sequence..this means as a designer of your machine, you must manage time.
Auggie doesnt hold your hand and plead for mercy, it does as you ask,no matter what you ask.
So, while running all these scripts, every one should be designed to be short..and sweet, or
if its a complex task, must yiled often to ensure you dont hog the systems power. I
suspect we'll see many calls, that if you post for comment, can be made much more efficient.

&nbsp; In fact, youll find programmer types take great pride in how efficient they can be,
logical prowess is our arm flexing to the babes.. programmer types never get babes.

&nbsp; &nbsp; So posting your code examples or scripts, will usually get one nerd or another to
comment on a better way to do that... "The Geek shall inherit the world.". My point
is , feel free to post anything in the this forum, Im happy to help as I read, and other
nerds would love to outbid me on the efficency scale. Some programmers have been programming
for 40 years, others have programmed one year 40 times, I fall somewhere in the middle,
but I dont charge so youll get great value most of the time.. :)

&nbsp; I see my blood sugar must be getting low from re-reading my last few paragraphs so Ill
end this one here before angry wives or children start to throw interrupts my way..
I think now Ive given a lot to think about for new scripters, and maybe even pointed out a few
secrets experienced scripters can use. My advice now at this point is to run Auggie, turn on its
scripter, and experiment. Confused? Post a question, we have nerds standing by...

&nbsp; Scripting, like playing music is a developed talent, the more you play the more complex
and beautiful the music, and I can ensure you that scripting is FAR easier than playing music,
I know, Ive tried. Ive come to accept the only keyboard I will ever play with any grace
has 101 keys. Scripting an elegant solution to your problem though is as addictive and as
peacefull a place as youll find, so dig in as you wish. :-)

( By the way, if you lock up Auggie with a while(1){} type of loop :), use the three-finger salute,
which kills all running scripts.. ctrl-shift-alt

Art


&nbsp;
&nbsp;
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest