Author Topic: Stubborn deer  (Read 1119 times)

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Stubborn deer
« Reply #30 on: November 28, 2012, 03:15:33 am »


               

Lightfoot8 wrote...

The truth is that  =  does not evalulate.    The uses that do work are examples of side effect  programing that take advantage of a value that  is not yet removed from the top of the stack.


I would have thought that this were an issue with order of operation.  (x = y)  = 0; would try to assign an integer (0)  to an integer ((x=y) which is not a variable), hence causing an error.  However, this case in NW compiler comes up with a different error than x = y = 0;

Lightfoot, do you know of any language that would compile x = y = 0; as being the same as x = (y = 0); and not (x = y) = 0;? From what I am seeing, there is nothing to be gained by evaluating an assignment without another operation being performed on it, as those cases where the evaluation would matter would always result in errors.
               
               

               


                     Modifié par WhiZard, 28 novembre 2012 - 03:43 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Stubborn deer
« Reply #31 on: November 28, 2012, 04:12:28 am »


               

WhiZard wrote...

I would have thought that this were an issue with order of operation.  (x = y)  = 0; would try to assign an integer (0)  to an integer ((x=y) which is not a variable), hence causing an error.  However, this case in NW compiler comes up with a different error than x = y = 0;



Yes I can see that.  

x and y are Lables  for memory locations on the VM stack,   They get replaced with Offsets from the Top of the Stack in the compiled VM code. 

  (x=y)  basicly moves the offset where  y is stored to the top of the stack and then copies the Top of the Stack to the offset where x is stored. 

 = 0;   then runs into problems,   It pushes the constant 0 onto the top of the stack  but has no labled offset to then copy the top of the stack down to. {( x=y) is not a Lable, it is now at offset -8 from the top of the stack, but the NWNComplier has no lable to tell it that.  }   


example of standard NWN VM assignment. 

int  x = 5;  
  • int      -- Reserver storage for an intenger on the VM stack.   At this point the Top of Stack pointer points to the first memory location after the reserved storage.

     

  • (x       -- The compiler at this point adds x as a lable to an internal list that will keep track of of far it is from the top of the stack during compiling) It is currently at -4 from Top of Stack.  



  • 5       -- Push the Constant 5 onto the top of the VM stack.  



  • =     -- Copy the Top Of the VM Stack to Offset -8.  This is where x is currently stored having only the one constant  above it. 



  •  ;      --  Move Top Of Stack pointer down 4,    This basicly removes the constant 5 from the top of the stack. 



       
  

    
               
               

               


                     Modifié par Lightfoot8, 28 novembre 2012 - 04:13 .
                     
                  


            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Stubborn deer
« Reply #32 on: November 29, 2012, 03:38:55 pm »


               

Lightfoot8 wrote...

not 100% true with the default nwn compiler.   If it was True, your x = y = 0;   statment would compile in nwn script.  It however does not compile with the default compiler.    x = ( y = 0);  will compile though.    The fact that  x = y = 0;  does not compile implies that y = 0 does not evalulate to anything.   The fact that x = ( y = 0);  works implies that that it does evalulte to an intenger.     confused yet? 

The truth is that  =  does not evalulate.    The uses that do work are examples of side effect  programing that take advantage of a value that  is not yet removed from the top of the stack.


My bad. I forget that nwscript is not a real language sometimes '<img'>

Actually, I'm surprised that x=y=0; does not work when the orignal form does. I think that's a compiler bug.

Assignment really should be evaluating the value assigned for the orignal example to work. It's not a side
effect of the VM runtime stack. it has to be a compile time thing.  

The fact that if (GetIsObjectValid(target = GetObjectByTag("foo"))  works implies nwscript does evaluate
assignment statements (or in different words: assignment "returns" a typed value) . Otherwise this would
be a compile time error. 

In order for that to compile "target = GetObjectByTag("foo")" has to be evaluated as an object, no?


Cheers,

Meaglyn
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Stubborn deer
« Reply #33 on: November 29, 2012, 05:32:10 pm »


               

meaglyn wrote...
My bad. I forget that nwscript is not a real language sometimes '<img'>

Actually, I'm surprised that x=y=0; does not work when the orignal form does. I think that's a compiler bug.

Assignment really should be evaluating the value assigned for the orignal example to work. It's not a side
effect of the VM runtime stack. it has to be a compile time thing.  


You realize that if x=y=0; were evaluated, it still would not compile, as it would be (x=y)=0; not x=(y=0);

Edit: I have looked up the C++ implementation of double assignment, and it processes x=y=0; as assigning zero to y and then 0 to x (as opposed to x=(y=0) which assigns 0 to y then evaluates and assigns that to x).  So double assignment is itself processed in a unique way when it is able to compile.
               
               

               


                     Modifié par WhiZard, 29 novembre 2012 - 05:55 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Stubborn deer
« Reply #34 on: November 29, 2012, 11:06:28 pm »


               

meaglyn wrote...


Actually, I'm surprised that x=y=0; does not work when the orignal form does. I think that's a compiler bug.

Assignment really should be evaluating the value assigned for the orignal example to work. It's not a side
effect of the VM runtime stack. it has to be a compile time thing.

 
The only thing  stating something as a "SideEffect"  Means is that it is undocumented.
But with that argument I guess all of NWNScript would be a side effect since nothing is documented.  At least not officially.   

It is definitely a compiler thing that we are talking about.  After all it is a compiler error we are getting.    

 

...The fact that if (GetIsObjectValid(target = GetObjectByTag("foo"))  works implies nwscript does evaluate
assignment statements (or in different words: assignment "returns" a typed value) . Otherwise this would
be a compile time error. 

Well all Return values are left on the top of the VM_Stack in NWScript.   So I guess that you could make a case that it is evalulated.   And for the record at RunTime everything on the VM_Stack is Type Casted. The VM_Stack is really two Array, an array of dWords and an array of Bytes.   The Byte Array hold the type of the entrys in the dword array.   so the type of the 5th dword on the VM_Stack would be of the  type stored in the 5th byte in the byte array.  My guess is that  The compiler is only looking at the last Type it that it has pushed to the stack.  And is the reason I call the versions that work a Side Effect since it is not standard programing and not documented as a way to write code. At least not that I know of.    So really the compiler only has to recognize that the last thing placed on the stack was the correct type. 

Lets assume I give the the argument of side effect vs evalulated to type.   You then have the problem of precedence.   x=y=0;   equal has the same precedence, I mean they are not two different operators.   So x=y will happen first,   then  0 will try to be assigned to the constant on the top of the stack(the x=Y operation that just took place) .     the assignment operator has the lowest priority.   So that things like x= 5 + y = 7;  Will not work since the  y var is no longer  the object of the assignment operator after 5+ y operation takes place.  Hence x= 5 + (y= 7); will work.   (  Note This applies to NWScript and not compilers like c++)      




...In order for that to compile "target = GetObjectByTag("foo")" has to be evaluated as an object, no?

 
Yes the compiler has to requnize that an Object is left on the top of the stack.    Another think of interest is that the compiler evaluates nothing.   It does not even know how to add.   If you place x =5+ 6; into your script.  well the compiler will not change that to x = 11; for you the way a full blown compiler would.   It will  multiply 5 and 6 then move the result into x every time the statment is called at run time.    This is the main reason that you can not assign  an equation to a constant.    const int MyConst =  5+5:   Does not work,  The compiler simply does not know how to add then together to make an immediate constant to place into the compiled code.

So if you do not buy the side effect argument,  Your  reason would be that the compiler does not know how to evaluate anyhing.   If  5 + 5 is to hard.  x = y = 5 is out of the question, it takes special rules to evaluate.  
               
               

               


                     Modifié par Lightfoot8, 29 novembre 2012 - 11:10 .
                     
                  


            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Stubborn deer
« Reply #35 on: November 30, 2012, 12:36:25 am »


               

WhiZard wrote...


You realize that if x=y=0; were evaluated, it still would not compile, as it would be (x=y)=0; not x=(y=0);

Edit: I have looked up the C++ implementation of double assignment, and it processes x=y=0; as assigning zero to y and then 0 to x (as opposed to x=(y=0) which assigns 0 to y then evaluates and assigns that to x).  So double assignment is itself processed in a unique way when it is able to compile.


That's not quite accurate.  It's called chained assignment and in C and derivative languages it works exactly
because assignement evaluates to the assigned value. As does the original snippet which is more to the point
of what we were talking about.

I'm not claiming it compiles in nwscript with the default compiler.  I still think that's a bug. 

By your reasoning this c program would produce  
           x = 1, y = 6

#include <stdio.h>
int main () {
        int x;        int y = 5;
        x = y += 1;
        printf("x = %d, y = %d\\n", x,y);
}
But what it does produce is 

      x = 6 , y = 6

The only way to get there is to evaulate y +=1 to 6 and then assign that to x.


Cheers,
Meaglyn
               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Stubborn deer
« Reply #36 on: November 30, 2012, 12:52:27 am »


               
Quote
Lightfoot8 wrote...


The only thing  stating something as a "SideEffect"  Means is that it is undocumented.
But with that argument I guess all of NWNScript would be a side effect since nothing is documented.  At least not officially.   
 
It is definitely a compiler thing that we are talking about.  After all it is a compiler error we are getting.    



A side effect doesn't really matter if its documented or not.  

By refering back to the compiler I meant the syntactic part not the code generation part.


Quote
...The fact that if (GetIsObjectValid(target = GetObjectByTag("foo"))  works implies nwscript does evaluate
assignment statements (or in different words: assignment "returns" a typed value) . Otherwise this would
be a compile time error. 


Well all Return values are left on the top of the VM_Stack in NWScript.   So I guess that you could make a case that it is evalulated.   And for the record at RunTime everything on the VM_Stack is Type Casted. The VM_Stack is really two Array, an array of dWords and an array of Bytes.   The Byte Array hold the type of the entrys in the dword array.   so the type of the 5th dword on the VM_Stack would be of the  type stored in the 5th byte in the byte array.  My guess is that  The compiler is only looking at the last Type it that it has pushed to the stack.  And is the reason I call the versions that work a Side Effect since it is not standard programing and not documented as a way to write code. At least not that I know of.    So really the compiler only has to recognize that the last thing placed on the stack was the correct type. 
 [/quote]

At the time it's checking the types of the functions and arguments there is no stack.  NWNScript compiler
makes at least two passes. 

Quote


Lets assume I give the the argument of side effect vs evalulated to type.   You then have the problem of precedence.   x=y=0;   equal has the same precedence, I mean they are not two different operators.   So x=y will happen first,   then  0 will try to be assigned to the constant on the top of the stack(the x=Y operation that just took place) .     the assignment operator has the lowest priority.   So that things like x= 5 + y = 7;  Will not work since the  y var is no longer  the object of the assignment operator after 5+ y operation takes place.  Hence x= 5 + (y= 7); will work.   (  Note This applies to NWScript and not compilers like c++)      




Quote
...In order for that to compile "target = GetObjectByTag("foo")" has to be evaluated as an object, no?

 
Yes the compiler has to requnize that an Object is left on the top of the stack.    Another think of interest is that the compiler evaluates nothing.   It does not even know how to add.   If you place x =5+ 6; into your script.  well the compiler will not change that to x = 11; for you the way a full blown compiler would.   It will  multiply 5 and 6 then move the result into x every time the statment is called at run time.    This is the main reason that you can not assign  an equation to a constant.    const int MyConst =  5+5:   Does not work,  The compiler simply does not know how to add then together to make an immediate constant to place into the compiled code.

So if you do not buy the side effect argument,  Your  reason would be that the compiler does not know how to evaluate anyhing.   If  5 + 5 is to hard.  x = y = 5 is out of the question, it takes special rules to evaluate.  


That's a nice example of reductio ad absurdum '<img'>

These are two different things.  Optimizing the evaluation of constant expressions is not what we where talking about.

In C and derivative, assignment _IS_ covered by special rules in the grammar.

And again, at the point it's discovering the argument to GetIsObjectValid is a object or not there is no stack.
There is no last value left on the stack, there is no generated code yet.

Anyway, this is getting academic. With the default NWN compiler you get the evaluation of assignemt as
the assigned value as illustrated by the original code and not chained assignment.  Another quirk '<img'>

Cheers,

Meaglyn
               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Stubborn deer
« Reply #37 on: November 30, 2012, 01:47:54 am »


               

Lightfoot8 wrote...

WhiZard wrote...

I would have thought that this were an issue with order of operation.  (x = y)  = 0; would try to assign an integer (0)  to an integer ((x=y) which is not a variable), hence causing an error.  However, this case in NW compiler comes up with a different error than x = y = 0;



Yes I can see that.  

x and y are Lables  for memory locations on the VM stack,   They get replaced with Offsets from the Top of the Stack in the compiled VM code. 

  (x=y)  basicly moves the offset where  y is stored to the top of the stack and then copies the Top of the Stack to the offset where x is stored. 

 = 0;   then runs into problems,   It pushes the constant 0 onto the top of the stack  but has no labled offset to then copy the top of the stack down to. {( x=y) is not a Lable, it is now at offset -8 from the top of the stack, but the NWNComplier has no lable to tell it that.  }   


 


That's not how compilers work though.   If it was an interpreted script it could do something more or less like
what you describe.

You're mixing up the runtime execution of the generated code with the compilation of said code.
The compiler generates code that uses these offsets and pushes values onto the stack. But to get to that point
is has already checked the syntax and the types, made sure the provided code is legal in the rules of the language. It does not just read the code in order and convert each token to a VM instruction.

Anyway, this wikipedia page gives a good overview of the assignment returning value part
of this discussion: en.wikipedia.org/wiki/Assignment_(computer_science)


 Cheers,
Meaglyn
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Stubborn deer
« Reply #38 on: November 30, 2012, 02:27:03 am »


               

meaglyn wrote...




That's not how compilers work though.   If it was an interpreted script it could do something more or less like
what you describe.

You're mixing up the runtime execution of the generated code with the compilation of said code.
The compiler generates code that uses these offsets and pushes values onto the stack. But to get to that point
is has already checked the syntax and the types, made sure the provided code is legal in the rules of the language. It does not just read the code in order and convert each token to a VM instruction.

Anyway, this wikipedia page gives a good overview of the assignment returning value part
of this discussion: en.wikipedia.org/wiki/Assignment_(computer_science)


 Cheers,
Meaglyn



Sorry for getting you riled up and sorry if you dissagree.    But I am not talking about compilers, I am talking about only one compiler and that is the compiler that shipped with NWN.  That is how the nwn compiler works.  Agreed it has been a long time since I have gone through the machine code for the compiler.   I can guarantee that that I am not mixing up run time with compile time.   The example given above to Whiz was how the compiler would try to compile the script.  For what it is worth the nwn compiler compiles line for line like the example I  gave to whiz.  and yes I know it makes more then one pass.     


    

  
               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Stubborn deer
« Reply #39 on: November 30, 2012, 03:30:40 pm »


               

Lightfoot8 wrote...


Sorry for getting you riled up and sorry if you dissagree.    But I am not talking about compilers, I am talking about only one compiler and that is the compiler that shipped with NWN.  That is how the nwn compiler works.  Agreed it has been a long time since I have gone through the machine code for the compiler.   I can guarantee that that I am not mixing up run time with compile time.   The example given above to Whiz was how the compiler would try to compile the script.  For what it is worth the nwn compiler compiles line for line like the example I  gave to whiz.  and yes I know it makes more then one pass.     


I am not riled up, darn it '<img'>

My last statement came out not exactly as I meant it, sorry.  Was not trying to sound that critical.

I agree that the compiler generates its code more or less line by line. I say more or less because it
does get muddy when it has to first evaluate arguments before putting them on the stack and those could
be on seperate lines. But that's after the syntax check. It probably does include the type checking.

My points were simply that the first example  "while(GetIsObjectValid(target = GetNearestObject(oSource, i++)))"
does not rely on an implementation accident of the code generator. It has to first pass syntactic muster. And
to do that is must be in the grammar of the languange that an assignment operation returns a value. The
fact that it is easy to implement in the generated code because the needed value is left on top of the stack
and all it needs to do is not remove it, is a bonus.

And second WhiZard's example,  (x=y) = 0; also does not pass the syntax checking. It is simply not a valid
assignment statement because (x=y) is an expression not a variable and won't parse correctly. So in this case I believe it will fail to compile _before_ it starts the code generation.

This very dated page mentions the actual grammar, although the three issues he mentions seem to
have all been fixed...

http://www2.gamma.uk...?questionID=275


But enough of this flogging a stubborn deer on poor Rolo's dime  '<img'>

Cheers,
Meaglyn
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Stubborn deer
« Reply #40 on: December 02, 2012, 03:15:54 pm »


               <wondering where he can hire...>

Hey! Flog that deer :-) Thanks to discussions like this I can now evaluate assignments without fear and write slightly more elegant code ;-)

Not precisely *kosher*, but slightly more elegant.

Thanks!

<...a mule deer-skinner>