Willsy Posted October 24, 2012 Share Posted October 24, 2012 Since Forth doesn't have arrays, the answer is no! In Forth, when we make an array, all we're really doing is: Using CREATE to create a word that returns a memory address when executed Using ALLOT to reserve some space Example: CREATE MyArray 10 CHARS ALLOT Reserves 10 bytes. The word MyArray, when executed, returns the address of the start of the ALLOTted block of memory. As with C et al, there are no bounds checking - Forth is *very* low-level, as you have no doubt learned by now! We then access our "array" by using MyArray and adding an offset - exactly the way we would do it in machine code. So, to access the 5th byte (byte 4): MyArray 4 + C@ Reads the byte at address MyArray+4 So, as you can see, it's just a block of memory, and ALLOT just changes the memory pointer. It doesn't zero anything. You can use FILL to do that for you. I would use CONSTANTs to specify the array size, then you can update your arrays and any associated code by simply changing the constant: 100 CHARS CONSTANT ArraySize CREATE MyArray ArraySize ALLOT \ reserve ArraySize bytes MyArray ArraySize 0 FILL \ fill ArraySize bytes Sometimes, you'll want to reserve 16-bit words, rather than bytes. That's when you use CELLS, as follows: 100 CELLS CONSTANT ArraySize CREATE MyArray ArraySize ALLOT \ reserve ArraySize cells MyArray ArraySize 0 FILL \ fill ArraySize cells A cell is 2 bytes. So, all CELLS does is multiply the value on the stack by 2. ALLOT, FILL take their arguments in *bytes*. In the above ArraySize gets intialised to 200 (100 cells==200 bytes). That's probably as clear as mud! It seems to tie a lot of people up in knots initially. Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted October 25, 2012 Share Posted October 25, 2012 (edited) Thanks Willsy. I'm actually quite familiar with arrays in Forth now because of my current graphics experimentations. I'm still using TIF however given that TF has no bitmap support currently... The reason for my question was that TIF requires a zero on the stack when declaring arrays, and I was wondering if it was somehow initializing them. With variable declarations, the number on top of the stack gets stored in the variable automatically. Edited October 25, 2012 by Vorticon Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 25, 2012 Share Posted October 25, 2012 (edited) Thanks Willsy. I'm actually quite familiar with arrays in Forth now because of my current graphics experimentations. I'm still using TIF however given that TF has no bitmap support currently... The reason for my question was that TIF requires a zero on the stack when declaring arrays, and I was wondering if it was somehow initializing them. With variable declarations, the number on top of the stack gets stored in the variable automatically. In TIF, the 0 only initializes the variable that is declared---actually, you can initialize it to whatever 16-bit value you want. That is only one cell, however. The rest of the array is only ALLOTted. 10 VARIABLE XX 30 ALLOT initializes the variable XX to 10 and reserves 30 additional bytes in the dictionary immediately following XX for a total of 32 bytes (16 cells) that can be referenced through XX and an offset. The additional 30 bytes (15 cells) beyond the first one, initialized to 10, contain whatever was in memory when they were ALLOTted. The only difference between TF and TIF in this regard is that the initializing number is not used in TF, but must be used in TIF. TF initializes the variable to 0 with VARIABLE XX and TIF, as already stated, initializes to whatever number you put in front of VARIABLE as in 0 VARIABLE XX . You can use a variable name as the name of an array in TF the same way you do in TIF by following its definition with an ALLOTment of bytes to accommodate it. The usual way to create an array in TF, I suppose, is to use CREATE to create the header for the array and ALLOT to reserve all the bytes or cells in the array as @Willsy explained earlier. I am pretty sure that you can do the same thing in TIF with CREATE , though I have not yet tried it. The word CELLS does not exist in TIF, but is easily created with : CELLS ( n --- n*2 ) 2 * ; Anyway, as you can see, there are a couple of ways to create arrays and they do need to be initialized by the programmer if s/he cares. Well, I guess that dead horse has had a sufficient beating! ...lee Edited October 25, 2012 by Lee Stewart Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 25, 2012 Share Posted October 25, 2012 Well, I guess that dead horse has had a sufficient beating! LOL! Hey! It's all grit for the mill, as we say! Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 25, 2012 Share Posted October 25, 2012 Just a comment regarding VARIABLE... As you've realised, in TIF, VARIABLE takes an initial value. That was the de-facto standard for FIG Forth (TI Forth is a FIG Forth system IIRC). I think it's a nice feature. However, for some reason, the initial value was removed from the Forth 83 standard, and it was mandated that variables shall be initialised to 0. TurboForth conforms to the Forth 83 standard. However, the cool thing about Forth is, if it doesn't behave the way you want, you can just change it So, if you want TurboForth to take an initial value for variables, just re-define VARIABLE: : VARIABLE ( n -- ) CREATE LATEST @ >CFA >BODY ! ; 99 VARIABLE FRED FRED @ . 99 ok:0 Now, the question is, can you see how it works? Quote Link to comment Share on other sites More sharing options...
JonnyBritish Posted October 26, 2012 Share Posted October 26, 2012 well here is the help : VARIABLE ( n -- ) CREATE LATEST @ >CFA >BODY ! ; CREATE - Reads forward in the terminal input buffer and creates a word in the dictionary whose run-time behaviour is to return the body address of the newly created word LATEST - Pushes the address of the latest dictionary entry variable. @ - Pushes the value read from address to the stack. >CFA - Converts dictionary address da to code field address cfa. >BODY - Given a CFA on the stack, >BODY returns the address of the body of the word. The “body” contains the “payload” of the word. Only applies to words created with <a href="http://www.turboforth.net/language_reference.html#create">CREATE (i.e. VARIABLE, CONSTANT, VALUE). It is not meaningful to apply >BODY to words that are not children of CREATE. >BODY may also be applied to words that utilise DOES> to carry out their work. ! - Writes value to the cell at address. Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 26, 2012 Share Posted October 26, 2012 He he! perfect! Bravo! Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted October 27, 2012 Share Posted October 27, 2012 Since TIF does not have an I', how can one access the outermost loop counter in a 3 nested loop structure? I suppose I could always pull I and J off of the return stack onto the data stack, read the 3rd value off of the return stack (I'), then push back the I and J onto the return stack, but is there a better and less cumbersome way? Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 27, 2012 Share Posted October 27, 2012 Just push I in your outer-most loop into a variable and access the variable in the inner most loop. Or see if you can pass it via the stack. Mark Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 27, 2012 Share Posted October 27, 2012 Since TIF does not have an I', how can one access the outermost loop counter in a 3 nested loop structure? I suppose I could always pull I and J off of the return stack onto the data stack, read the 3rd value off of the return stack (I'), then push back the I and J onto the return stack, but is there a better and less cumbersome way? Actually, I' is the 2nd value on the return stack, at least, that's the way it is for TI Forth. I haven't looked for how @Willsy keeps track of the loop index and limit for TurboForth. I' is the loop limit for the innermost loop. If you have 3 loops and want to reference the outermost loop index from the innermost loop, TIF would have it as the 5th value down on the return stack! If TF does loops the same way, we could write a TF assembler word for the 3rd loop index by directly reading the 5th value down on the return stack---perhaps, with a check that the return stack actually has at least 5 values! ...lee Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted October 27, 2012 Share Posted October 27, 2012 (edited) Actually, I' is the 2nd value on the return stack, at least, that's the way it is for TI Forth. I haven't looked for how @Willsy keeps track of the loop index and limit for TurboForth. I' is the loop limit for the innermost loop. If you have 3 loops and want to reference the outermost loop index from the innermost loop, TIF would have it as the 5th value down on the return stack! If TF does loops the same way, we could write a TF assembler word for the 3rd loop index by directly reading the 5th value down on the return stack---perhaps, with a check that the return stack actually has at least 5 values! ...lee Yes, you're right, it is the 5th value on the stack. I don't recall seeing I' mentioned in the TIF manual. I might be able to come up with a workaround to avoid having 3 nested loops, but it won't be as neat. Alternatively, I could create a word like this: : INDEX3 R> R> R> R> R> J' ! >R >R >R >R >R ; where J' is defined as a simple variable. I'm not sure what kind of performance hit using this scheme repeatedly will result in, but it's worth experimenting with. It's becoming clear to me that I will have to eventually learn to use the TIF assembler at some point... Edited October 27, 2012 by Vorticon Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 27, 2012 Share Posted October 27, 2012 (edited) Yes, you're right, it is the 5th value on the stack. I don't recall seeing I' mentioned in the TIF manual. I might be able to come up with a workaround to avoid having 3 nested loops, but it won't be as neat. Alternatively, I could create a word like this: : INDEX3 R> R> R> R> R> J' ! >R >R >R >R >R ; where J' is defined as a simple variable. I'm not sure what kind of performance hit using this scheme repeatedly will result in, but it's worth experimenting with. It's becoming clear to me that I will have to eventually learn to use the TIF assembler at some point... A few things: You used up one of the values taken from the return stack with R> J' ! , so your code will cause a stack underflow and corrupt the return stack. J' as a variable will likely not be up to date when you check it. It is better to define it as a word that gets the current value every time it is executed. To keep the loop metaphor consistent, you should use a different letter for the third loop, something like K . J' implies the 2nd loop's limit, not the 3rd loop's index. You will want to leave a value on the stack when you execute INDEX3 or K if you define it as suggested in (2). Perhaps (The following code does not work and will also corrupt the return stack! This is explained in later posts.) : INDEX3 R> R> R> R> R >R >R >R >R ; or : K R> R> R> R> R >R >R >R >R ; Also, I' is not defined in TI Forth, it is mentioned (and defined) in "Appendix C" of the TI Forth Instruction Manual because the first edition of Brodie's Starting Forth explains it on pages 110 and 123. ...lee Edited October 28, 2012 by Lee Stewart Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted October 27, 2012 Share Posted October 27, 2012 Ah yes, I missed that one The stack monster strikes again! I'm currently tackling 3D matrix transformations in floating point math, and I shudder at the thought of how many stack oversights I have made so far. I still have 2-3 functions to write then I'll be able to test everything. I was not planning on using J' without an INDEX3 first, so it would have remained up to date. But of course, your suggestion of defining it as a word itself makes a lot of sense and now that you mentioned it so obvious! I think I'm still hampered by my old programming habits with classic languages, and Forth has so many ways to skin a cat it's not even funny. The good news is that I'm starting to get fairly comfortable with it, too late unfortunately to write any decent application by Faire time... Quote Link to comment Share on other sites More sharing options...
+Gemintronic Posted October 27, 2012 Share Posted October 27, 2012 Ah yes, I missed that one The stack monster strikes again! I'm currently tackling 3D matrix transformations in floating point math, and I shudder at the thought of how many stack oversights I have made so far. I still have 2-3 functions to write then I'll be able to test everything. I was not planning on using J' without an INDEX3 first, so it would have remained up to date. But of course, your suggestion of defining it as a word itself makes a lot of sense and now that you mentioned it so obvious! I think I'm still hampered by my old programming habits with classic languages, and Forth has so many ways to skin a cat it's not even funny. The good news is that I'm starting to get fairly comfortable with it, too late unfortunately to write any decent application by Faire time... 3D? You should try entering a contest with this 4k Forth http://neoscientists.org/~plex/win4k/index.html Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted October 27, 2012 Share Posted October 27, 2012 3D? You should try entering a contest with this 4k Forth http://neoscientists...in4k/index.html This looks strange and unfamiliar to me. I think I'd better stick with TIF for now Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 27, 2012 Share Posted October 27, 2012 Well, hang on guys... If you know which CPU register points to the return stack, and you know where TIF's workspace is, then you can peek the return stack pointer directly, apply an offset, do a fetch and voila, there is your value. Alternatively, TIF may have a word which returns the *address* of the top of the return stack? In TF it's called RP@. Again, apply an offset, do a fetch, and there's your value... Quote Link to comment Share on other sites More sharing options...
+Gemintronic Posted October 27, 2012 Share Posted October 27, 2012 Sorry to interject, again. I noticed people say Forth was fragmented by slightly different variations. Has anyone ever tried making a standard library based off of features common to most dialects of Forth? Something everyone can count on? Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted October 27, 2012 Share Posted October 27, 2012 Well, hang on guys... If you know which CPU register points to the return stack, and you know where TIF's workspace is, then you can peek the return stack pointer directly, apply an offset, do a fetch and voila, there is your value. Alternatively, TIF may have a word which returns the *address* of the top of the return stack? In TF it's called RP@. Again, apply an offset, do a fetch, and there's your value... When is TF's manual coming again? Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 27, 2012 Share Posted October 27, 2012 Well, hang on guys... If you know which CPU register points to the return stack, and you know where TIF's workspace is, then you can peek the return stack pointer directly, apply an offset, do a fetch and voila, there is your value. Alternatively, TIF may have a word which returns the *address* of the top of the return stack? In TF it's called RP@. Again, apply an offset, do a fetch, and there's your value... TIF does not have a pointer to the top of the return stack, just the bottom ( R0 ). I wrote one in assembler awhile back. I'll have to dig it up for y'all. It was actually very simple, as you said. ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 27, 2012 Share Posted October 27, 2012 In TurboForth, here is how you do K: Assembly: asm: K ( -- k) sp dect, 14 r5 () *sp mov, 12 r5 () *sp a, ;asm Or, in Forth: : K ( -- k ) RP@ 14 + DUP @ SWAP 2+ @ + ; RP@ returns the address of the top of the return stack pointer. Here's a test: : test 10 0 do 1 0 do 1 0 do k . loop loop loop ; In TIF it will be simpler. Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 27, 2012 Share Posted October 27, 2012 TIF does not have a pointer to the top of the return stack, just the bottom ( R0 ). I wrote one in assembler awhile back. I'll have to dig it up for y'all. It was actually very simple, as you said. ...lee It must be tracked in a register? If it is, then you can get it just by reading the register direct (see my TF example above). A rather nice feature of our processor architecture! Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 27, 2012 Share Posted October 27, 2012 (edited) In TurboForth, here is how you do K: ... In TIF it will be simpler. Yeah. Much simpler in TIF! RP is the TIF ALC alias for R14, the return stack pointer. TIF workspace also starts at 8300h: TI Forth assembler--- CODE K ( -- k) SP DECT, 8 @(RP) *SP MOV, NEXT, High level TI Forth ( This code does not work!! )--- HEX : K ( -- k) 831C @ 8 + @ ; I haven't tried it yet. I will later---gotta go fix a gutter before the hurricane hits! ...lee Edited October 28, 2012 by Lee Stewart Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 28, 2012 Share Posted October 28, 2012 Yeah. Much simpler in TIF! RP is the TIF ALC alias for R14, the return stack pointer. TIF workspace also starts at 8300h: ... ...lee TI Forth hex machine code--- HEX CODE K ( -- k) 0649 , C66E , 0008 , 045F , ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 28, 2012 Share Posted October 28, 2012 The above TI Forth assembler coded K and the compiled machine coded K work just fine. The words have identical dictionary entries. I am not sure why the high-level TI Forth code above, which grabs the 5th number down the return stack, does not work. The only idea I have is that the return stack must be involved in the high-level definition of K so that the position on the return stack of the loop variables is either indeterminate or not safe to guess. The only place in the ALC source I can find that the return stack is used in a high-level definition is the code for : and ; . At the moment, I'm stymied! ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 28, 2012 Share Posted October 28, 2012 (edited) OK, it looks like this code will work: HEX : K 831C @ A + @ ; DECIMAL It goes one notch lower on the return stack, which must mean that executing the word pushes a number onto the return stack (probably : ) at the beginning, necessitating going one deeper to get the right number! This took way too much time and space here---sorry. ...lee Edited October 28, 2012 by Lee Stewart Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.