View Full Version : reading a concatenated string

01-11-2008, 12:35 AM
Hello, I am a new propeller user transitioning from Basic Stamp experience.

I am trying to access a data table (stored in a DAT format) and I have named each entry in the DAT table with a name:

scrn1 byte {list of comma delimited datas}
scrn2 byte {}
scrn3 byte {}

Within the body of the program I have a variable (crntscrn) that is an integer corresponding to the number after scrn.
I have the following code to concatenate two strings to make the name tag in the DAT table.

ascii := NUM.ToStr(crntscrn, NUM#DEC) 'string representation of crntscrn
ascii2 := string("scrn") 'zero terminated string
bytemove(@ascii2+strsize(@ascii2),@ascii,strsize(@ ascii)) 'hopefully the concatenated string (e.g., scrn2)

I now need a way to read the string into a variable (e.g. dattag) that I can reference to get data from the correct line of the DAT table.


dattag = ??????????
value of interest := dattag 'where dattag is the 6th entry in the DAT table on line corresponding to scrnX

if scrn is zero terminated it might make more sense to replace the bytemove line with:
bytemove(@ascii2+strsize(@ascii2)-1,@ascii,strsize(@ascii)) { -1 added to attach the number(ascii) right after the scrn eliminating the 0? but accessing the
concatenated string as a variable is my primary concern }
I am brand new to spin so if this is giberish I appologize.
Thank you

01-11-2008, 01:07 AM
It is more difficult with SPIN. There are no string variables, but only pointers to allocated memory where a string starts. So you have to care that all needed memory is allocated so that nothing will be overwritten. E.g. all your BYTEMOVES will overwrite some data. There is no "space" after the end of a string allocated with STRING("ABC"), so you must not copy there.

It is best to allocate ample space in the DAT section for string maniputalation, e.g.

stringSpace BYTE 0[200]

or such

01-11-2008, 01:19 AM
Perhaps my jargon is incorrect. I don't really need a string variable. I want to be able to reference the name tags in the DAT table. The name tags I have used are scrn#. I understand that SPIN uses pointers to memory locations, I think.

What I am trying to do is simply build up the name tag from a string (scrn) and a number (turned into a string). Being that the scrn is static I can count on the memory size used to be constant. The attached "number" is also going to be a fixed size (in memory).

I will allocate sufficient memory for a stringspace as deSilva recommends; however, I still need a way to reference the concatenated name tag. I was thinking of building the tag up byte by byte with a loop but I am unsure how to do this.

much thanks

Peter Verkaik
01-11-2008, 01:25 AM
The Format object can do it in one line:

· byte buf 0[200] 'reserve space
· fmt: "Format"
· fmt.sprintf(@buf,string("scrn%1.1d"),crntscrn)

If crntscrn is 1, 2 or 3 then buf will hold null terminated strings
"scrn1", "scrn2" or "scrn3"

The Format object is in the Object Exchange under Tools.

regards peter

01-11-2008, 01:38 AM
Format object. Fantastic. Thanks Peter, I will give it a shot. I found the object on the exchange and it appears you wrote it :), double thanks.

My propeller and an LCD screen arrive today, this stuff is code I am developing without the chip so it will be a few days until I can test things.

01-12-2008, 04:26 AM
I have implemented the Format object and it created the desired concatenated string. Problem is I can't seem to use it to reference my DAT table?

Code snipet:

fmt : "Format"

PUB gui | crntscrn, temp
crntscrn := 1
temp := @buf
updated := temp

buf word 0[200] 'reserve space
scrn1 word 2, 2, 2, 10, 100, 2
scrn2 word 2, 1, 2, 10, 100, 3, 50, 100, 1
scrn3 word 3, 1, 3, 10, 100, 2, 50, 100, 1, 100, 100, 3

The above code does not set updated to 10 as expected/desired? @buf does hold scrn1 as desired and putting in a line:
updated := scrn1 does generate 10

It would appear I am missing something...

Do I need to use the sscanf command in format (it so, how do I use that?)

much thanks

Peter Verkaik
01-12-2008, 06:06 AM
You wanted to contatenate a fixed string "crtnscrn" with a digit
and Format did that for you.
You then assign the address of buf to temp.
And then you assign temp to updated.
So updated holds the address of buf but you could do that with just updated := @buf.

Why do you expect updated to hold 10?
Where does this 10 come from, or is supposed to come from?

regards peter

01-12-2008, 06:28 AM
whoops, the line in my post:
updated := scrn1
should have been:
updated := scrn1 thereby referencing the third word in the DAT line starting with scrn1

perhaps I am completely misunderstanding the uses of the DAT structure?

I want to have a list of numbers associated with tags (scrn#) and refer to certain values in the table by using:

I was trying to assign the actual information at the address of buf (i.e., scrn1 or scrn2 etc.) to temp so I could access a value with scrn1(for example and get 10)

perhaps this is not possible in spin? I may have to just implement a lookup table approach (not as pleasing as using the labels DAT appears to afford but....)

thanks again

Peter Verkaik
01-12-2008, 06:34 AM
You don't need format for that, just a simple routine

PUB getValue(scrn,index):value | buf
· case scrn
··· 1: buf := @scrn1
··· 2: buf := @scrn2
··· 3: buf := @scrn3
· return word[buf+index]

and to write a value
PUB putValue(scrn,index,value) | buf
· case scrn
··· 1: buf := @scrn1
··· 2: buf := @scrn2
··· 3: buf := @scrn3
··word[buf+index] := value

regards peter

Phil Pilgrim (PhiPi)
01-12-2008, 06:37 AM

When you post code fragments with numbers in brackets [], leave a space between the left bracket and the number so the forum software doesn't mistake it for a font size tag.


01-12-2008, 07:22 AM
Thanks for the heads-up on the brackets, I was curious why the font looked odd. Is it all brackets? or just square?

Peter, thanks for the code snipet, I will give it a try.


Phil Pilgrim (PhiPi)
01-12-2008, 07:35 AM
I thought all brackets were square! http://forums.parallax.com/images/smilies/smile.gif

() = parentheses
[] = brackets
{} = braces
<> = ? ... oh, right: "angle" brackets

Yeah, just the square ones. You can also use &#091; in place of a left bracket, but if you reedit your post, you have to keep replacing the [ again and again.


01-12-2008, 08:13 AM
The reason you can't refer to labels at runtime is that they don't exist anymore - once your Spin and assembly code is prepared for downloading, the text labels are all removed and replaced with memory addresses.

I sometimes have a similar requirement in my own code - what I generally do is to create a small index array at runtime, which I can refer to when needed. An initialisation routine in Spin places the addresses of various blocks of data into the array. I can then pass the base address of the array to a new cog, which can then locate any block of data it needs.

Please note that this code is written completely off the top of my head and is almost certainly syntactically incorrect, it's just to look at to get a better idea of what I'm trying to explain.

addresses[A_scrn1] := @scrn1
addresses[A_scrn2] := @scrn2
addresses[A_out_buffer] := @scrn1
addresses[A_in_buffer] := @scrn2

cognew(@codeblock, @addresses)

addresses long 0 [16]

scrn0 ...
scrn1 ...
out_buffer ...
in_buffer ...

org 0
codeblock ...

01-12-2008, 10:05 AM
Ziggy252 said...
The reason you can't refer to labels at runtime is that they don't exist anymore - once your Spin and assembly code is prepared for downloading, the text labels are all removed and replaced with memory addresses.

Ziggy, the code you posted is valid and makes sense under certain circumstances; however there are more techniques to accomplish what you do...

What I do not understand is what you want to say with your first sentence I quoted here, and how it relates to your program (or to the OP's problem)?

01-12-2008, 12:27 PM

As far as I could tell from the OP, he (she? - sorry if I'm making an incorrect assumption)·wanted to access a memory location by name, but he wanted to determine the name at runtime. He was attempting to·construct a string and pass it·as a parameter to bytemove. I was explaining why it wasn't giving the result he wanted.

I am aware that there are many ways to solve the problem. Peter solved it with a case statement, I solved it with an array of pointers. I'm sure there are more, each of which has·advantages and shortcomings. We offer suggestions, and it's up to the OP to determine which is best suited to his application.

01-12-2008, 07:22 PM
I have to admit that I did not understand the objective of the OP before your recent posting here http://forums.parallax.com/images/smilies/smile.gif
I had not recognized the true root for the confusion!

Long live TCL and Perl!

01-15-2008, 12:40 AM
Thank you all for taking the time to answer this ludite's likely inane questions. The case statement approach seems to work although I am intrigued by the array of pointers idea. The pointer idea looks like it has some assembly (org) so I will leave that alone for the time being.

Regarding Peter's code...

PUB getValue(scrn,index):value | buf
case scrn
1: buf := @scrn1
2: buf := @scrn2
3: buf := @scrn3
return word[ buf+index]

My understanding is that the getValue method is passed two variables: scrn and index from the main routine and returns a variable named value. In addition it locally declares a variable buf. The case statement evaluates the variable scrn and matches it to 1, 2 or 3. buf is then assigned the pointer to an address.

The form of the return statement puzzles me? I would have thought it would look like:
return word buf[ index]

This does not work and of course Peter's code does...
I read the whole spin manual (not the assembly section) and this obviously did not stick, what is going on?
Would return word[ buf] give the word at the start of the address? I.e., is it the same as return word[ buf+0] ????

As I am writing this the light is starting to turn on regarding the idea of pointers to addresses and the inability to reference them by name....
the light is dim, bear with me and thanks again

01-15-2008, 12:48 AM
Woops spoke too soon. The case approach does work (sort of). At least with my implementation it will return the word in the appropriate row of the dat table but the indexing (finding the column) is not working. No matter what I use for index the word returned is the zeroith value in the appropriate row. So the row referencing is working (i.e., the scrn1 or scrn2 or scrn3) but the column indexing is not? I am always returned the zeroith data in whatever row I reference?


01-15-2008, 01:00 AM
There is no assembly involved in Ziggy's code; you will benefit from understand his given example.
Your interpretation of "GetValue" is quite correct.

When reading through the manual, don't overlook chapter 4! Look for LONG, WORD and BYTE: There are three (or four) different meanings and situations described how to use them.

Peter's code however can be a little bit confusing to you, as index in not what you might think; his last line should better look like this

value := WORD[ buf+2*index]

which is functonally equivalent to

value := WORD[ buf][index]

01-15-2008, 01:22 AM
Thank you, the code mod:
value := WORD[ buf+2*index]
works but I am in the dark as to how?

I did read chapter 4 but reading and doing are vastly different. I will try and implement Ziggy's suggestion for the purposes of learning the pointer stuff better.

Nick Mueller
01-15-2008, 01:33 AM
> The case approach does work (sort of).

Then you could use "lookup" too?


Never use force, just go for a bigger hammer!

The DIY Digital-Readout for mills, lathes etc.:
YADRO (http://www.yadro.de)

01-15-2008, 01:35 AM
The things I was referring to are described on pp. 333 to 334..