BUG with local variables inside PRI/PUB function?
in Propeller 2
Is this a bug in my code or something else? I am not able to find out what would be wrong.
If I use a local variable inside for PUB getnumber function the index (i) variable jumps after the third character (from 0, 1, 2, to 50!).
If I use a global VAR instead, the behavior is as expected.
(I have tried so many things! changing to PRI instead of PUB, using different variable names, without ALINGNL, use four spaces as tabulator instead of two spaces, both Flexprop and PNUT works the same ... I am not able to find the issue on my code )
CON
_clkfreq = 160_000_000
baud = 115_200
STRING_SIZE = 8
OBJ
ser: "jm_fullduplexserial"
fmt: "ers_fmt"
VAR
BYTE number_str[STRING_SIZE]
BYTE i ' UNCOMMENT THIS LINE !!!!!
PUB main()
ser.start(63, 62, %0000, baud)
send := @ser.tx
waitms(2000)
send("Please write a number (max 8 characters) : ")
getnumber(number_str)
ser.fstr1(string("Your number is : "),number_str)
'PUB getnumber(str) | ALIGNL c, i ' COMMENT THIS LINE !!!!!
PUB getnumber(str) | ALIGNL c ' UNCOMMENT THIS LINE !!!!!
i := 0
repeat
c := ser.rx()
if (c == 8) or (c==127)
if i > 0
--i
ser.tx(8)
'send(fmt.nl(),"i:",fmt.unsdec(i)," ") 'debug
elseif (c == 13) or (c == 10)
ser.tx(13)
ser.tx(10)
quit
elseif (i == STRING_SIZE)
'send(fmt.nl(),"i:",fmt.unsdec(i)," ") 'debug
next
else
if (c > 47) and (c < 58)
str[i++] := c
send(fmt.nl(),"i:",fmt.unsdec(i)," ") 'debug ' UNCOMMENT THIS to disable DEBUG !!!
ser.tx(c)
str[i] := 0
Comments
getnumber(number_str) should be getnumber(@number_str)
I couldn't run your code because I don't have ers_fmt.spin2, but I've written similar code many times. This works:
pub get_number(p_str, maxlen) : len | c bytefill(p_str, 0, maxlen+1) ' clear buffer repeat c := term.rx() ' wait for character case c "0".."9" : ' digit? if (len < maxlen) ' room? byte[p_str][len++] := c ' yes, add to string 8, 127 : ' backspace if (len > 0) ' and not at beginning byte[p_str][--len] := 0 ' yes, delete last 13 : return ' and exit
Keep in mind that string routines need a terminating zero. In the code that I used to test the above method, I had this:
con BUF_SIZE = 8 var byte nbuf[BUF_SIZE+1]
This allows your buffer to hold as many characters as you need, plus the terminating zero.
Here's my test loop that prints the length of the string and its contents
repeat term.str(string("Enter a number", 13)) x := get_number(@nbuf, BUF_SIZE) term.fstr2(string("-- (%d) : %s\r\r"), x, @nbuf)
Dave made a good catch on the missing @, but given the code, I wonder if even that would correct it. The offending loop uses str[] instead of byte[str][] which would probably stuff characters (as longs) into the address holding str, ultimately causing things to go horribly wrong. No?
Looking at your version I see you're echoing input to the terminal. Here's a version that also does that.
pub get_number(p_str, maxlen) : len | c bytefill(p_str, 0, maxlen+1) ' clear buffer repeat c := term.rx() ' wait for character case c "0".."9" : ' digit? if (len < maxlen) ' room? byte[p_str][len++] := c ' yes, add to string term.tx(c) 8, 127 : ' backspace if (len > 0) ' and not at beginning byte[p_str][--len] := 0 ' yes, delete last term.tx(8) 13 : term.tx(13) return ' and exit
And just for giggles, this version will show you the width of the input field.
pub get_number(p_str, maxlen) : len | c bytefill(p_str, 0, maxlen+1) ' clear buffer term.txn("_", maxlen) ' show width of field term.txn(term.CRSR_LF, maxlen) ' backup to beginning repeat c := term.rx() ' wait for character case c "0".."9" : ' digit? if (len < maxlen) ' room? byte[p_str][len++] := c ' yes, add to string term.tx(c) 8, 127 : ' backspace if (len > 0) ' and not at beginning byte[p_str][--len] := 0 ' yes, delete last term.tx(8) term.tx("_") term.tx(term.CRSR_LF) 13 : term.tx(13) return ' and exit
Thank you! Yes, all those things mentioned solved the problems I had.
- missing @ : I though that It was only used for DAT an for method pointers, learned that is also for VAR. - [BUF_SIZE+1] : Yes, I was writing out of the array - byte[str][] : This was the worst, I totally corrupted the code, no wonder didn't worked.
You're welcome.
@ provides the run-time address of (a pointer to) any object. In my programs I always preface a variable that is intended to hold a pointer with p_, so the name p_str means "pass a pointer to a string." In many cases, I will prefix the name of a predefined string (in a dat section) with s_ -- this is just a reminder to me that the object is a string and needs @ to determine its run-time address. So, you might see something like this in my programs:
if (condition) term.str(@s_Warning)