QT Spim Mips programming - inputting a character into a string - qt

How would I add on a letter into a string. For instance, I have:
str: .asciiz "abcdefghijklmnopqrstuvwxyz"
I want to add the letter a to the end of the string to make it display "abcdefghijklmnopqrstuvwxyza" when I print out the string.
I've tried
la $t0, str
lb $t1, 0($t0)
add $t0, $t0, 25
sb $t2, 1($t0) # assume that $t2 contains the character a
Any help is greatly appreciated!

You can't just grow a string without having space for it to grow into. In this case you'd be overwriting the NULL terminator with an 'a', which can cause all sorts of problems later on.
You could allocate some extra space following the string:
str: .asciiz "abcdefghijklmnopqrstuvwxyz"
extra_space: .space 32
And then adding an 'a' at the end could be done like so:
la $t0,str+26
li $t1,'a'
sb $t1,($t0) # append an 'a' to the string
sb $zero,1($t0) # add a NULL terminator after the 'a'

Related

Counting instances of a character in a string

I need to be able to count the instances of a period in a string. (I need to capture the decimal point in a number, but discard the other periods in the name or title.) I know NUM-ENTRIES essentially counts the number of entries around that character, but I want to do the opposite. My broader problem is to parse a decimal number out of a string, where occasionally the string has other periods in the string.
What syntax can I use to determine the number of periods in this string? See my pretend "NUM-PERIODDS" pretend Progess function below.
Erin L. Halpin (33.333%)
Mr. Thomas Q. Smith 66.6%
I have an algorith to take everything in front of the "%" sign, then I process through all the numbers, but if I find a second "." then I need to skip that character. (If there are better ways to do my algorithm, would love suggestions on that, too.)
//takes in the full joint name and sees if there is a percentage value in it
//then finds whatever is in front of the % sign
IF INDEX (full_name_percentage, "%") GT 0 THEN DO:
cBeforePercentageStr=
SUBSTRING(full_name_percentage,1,INDEX(full_name_percentage,"%") - 1).
IF LENGTH (cBeforePercentageStr) GT 0 THEN DO:
//MESSAGE full_name_percentage VIEW-AS ALERT-BOX.
cThisChar = "".
DO iTemp = 1 TO LENGTH(cBeforePercentageStr):
cThisChar = SUBSTRING(cBeforePercentageStr,iTemp,1).
IF fnIsNumericOrPeriod(cThisChar) THEN
cPercentage = cPercentage + cThisChar.
END.
//need to account for if there are two decimal points
IF **NUM-PERIODS** (cPercentage, ".") GT 1 THEN DO:
MESSAGE "cPercentage value " + cPercentage VIEW-AS ALERT-BOX.
cPercentage = SUBSTRING(cPercentage,2,LENGTH(cPercentage)).
END.
dPercent = TRUNCAT (DECIMAL(cPercentage),2).
END.
END.
There is no need for loops. The number of characters in a string is equal to the length of the string minus the length of that same string without those characters.
define variable p as integer no-undo.
define variable myString as character no-undo.
myString = 'Erin L. Halpin (33.333%) Mr. Thomas Q. Smith 66.6%'.
p = length( myString )
- length( replace( myString, '.', '' ) )
.
message 'there are' p 'periods in the string'.
Golfing on you can also just return the number of entries with "." as delimiter minus one but with a floor of 0.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE VARIABLE cStr AS CHARACTER NO-UNDO.
cStr = 'Erin L. Halpin (33.333%) Mr. Thomas Q. Smith 66.6%'.
i = MAX(NUM-ENTRIES(cStr, ".") - 1,0) .
MESSAGE SUBSTITUTE("There are &1 periods in the string", i) VIEW-AS ALERT-BOX.
I like Stefan's idea (and it's pretty foolproof) but for a bit of code golf fun, you can loop without looping all the characters ...
DEFINE VARIABLE str AS CHARACTER NO-UNDO.
DEFINE VARIABLE findChr AS CHARACTER NO-UNDO.
DEFINE VARIABLE cnt AS INTEGER NO-UNDO.
DEFINE VARIABLE pos AS INTEGER NO-UNDO.
DEFINE VARIABLE startPos AS INTEGER NO-UNDO.
str = "Erin L. Halpin (33.333%) Mr. Thomas Q. Smith 66.6%".
findChr = ".".
startPos = 1.
pos = INDEX(str, findChr, startPos).
DO while pos > 0:
cnt = cnt + 1.
startpos = pos + 1.
pos = INDEX(str, findChr, startPos).
eND.
MESSAGE
cnt
VIEW-AS ALERT-BOX.
This is kind of crude and ugly but it should work just fine:
define variable i as integer no-undo.
define variable n as integer no-undo.
define variable p as integer no-undo.
define variable myString as character no-undo.
myString = "Erin L. Halpin (33.333%) Mr. Thomas Q. Smith 66.6%".
n = length( myString ).
do i = 1 to n:
if substring( myString, i, 1 ) = "." then p = p + 1.
end.
message "there are" p "periods in the string".

Why does my vector have 2 additional elements?

I'm taking input from stdin() and splitting it into a Vec<char>
For some reason there are 2 elements at the end of my vector. Can anyone tell me why they are there and how to get rid of them?
This is where I split the input into a Vec<char>:
// Splits regEx into vector of chars
let mut reg_ex: Vec<char> = input.chars().collect();
This is the code iterating through the Vec:
let mut i = 0;
for character in &reg_ex {
println!("{} {}", i, character);
i = i + 1;
}
And this is the output I get with 2 extra elements at the end:
User input required:
aaa
0 a
1 a
2 a
3
4
Assuming you are on Windows these are likely the newline characters \r\n.
You can get rid of them by calling .trim_end() on input. Note that this would also strip any whitespace at the end of your line, if you wanted to keep that.

How to convert A00073 value to 9973 in progress 4gl

i have column having multiple value like A0045 ,A00065 . i want to convert it 9945, 9965.
Need to remove all 0 and character value and add 99 before that value.. Please help..
This can be done in many ways. Here is one way (may not be the best). As I don't have a database, I created a temp table.
def temp-table tt
field val as char.
create tt.
tt.val = "A0045".
create tt.
tt.val = "A00065".
for each tt:
run filter_zero(input-output val).
val = replace(val,"A","99").
DISP val.
end.
procedure filter_zero:
define input-output parameter val as character.
// remvoe all zeroes
repeat while val matches("*0*"):
val = replace(val,"0","").
end.
end procedure.
The code below removes the uppercase (A-Z) and lowercase letter (a-z) and "0" as well :
DEF TEMP-TABLE test
FIELD str1 AS CHAR.
DEF VAR newStr AS CHAR NO-UNDO.
DEF VAR i AS INT NO-UNDO.
CREATE test.
ASSIGN test.str1 = "A0045".
CREATE test.
ASSIGN test.str1 = "A00065".
FOR EACH test:
DO i = 65 TO 90: /* A - Z */
IF SUBSTR(test.str1, 1, 1) EQ CHR(i) THEN
DO:
test.str1 = REPLACE(test.str1, CHR(i), "").
END.
END.
DO i = 97 TO 122: /* a - z */
IF SUBSTR(test.str1, 1, 1) EQ CHR(i) THEN
DO:
test.str1 = REPLACE(test.str1, CHR(i), "").
END.
END.
/* Removes all 0 and add 99 before the value */
test.str1 = REPLACE(test.str1, "0", "").
ASSIGN test.str1 = "99" + test.str1.
DISP test.
END.
define variable word as character no-undo.
define variable i as integer no-undo.
assign word = "A00065".
/*******To Remove all the zero********/
word = replace(word,substring(word,index(word,"0"),(r-index(word,"0") - 1)),"").
do i = 65 to 90:
if substring(word,1,1) = chr(i) then
do:
word = replace(word,substring(word,1,1),"99").
leave.
end.
end.
display word.
DEFINE VARIABLE word AS CHARACTER NO-UNDO.
SET word.
word = REPLACE(word,SUBSTRING(word,1,R-INDEX(word,"0")),"99").
/* If you want to remove all words before last zero
(including last zero also) * /
MESSAGE word
VIEW-AS ALERT-BOX INFORMATION BUTTONS OK.
Please do let me know if this works for you, Progress not installed so couldn't compile and test.
/* A0045 -> 9945
A00065 -> 9965 */
DEFINE VARIABLE v_RawData AS CHARACTER NO-UNDO.
DEFINE VARIABLE v_InpData AS CHARACTER NO-UNDO.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE VARIABLE j AS INTEGER NO-UNDO.
ASSIGN v_RawData = "A0045,A00065".
DO i =1 TO NUM-ENTRIES(v_RawData):
ASSIGN v_InpData = ENTRY(i,v_RawData).
DO j = 1 TO LENGTH(v_InpData):
IF ASC(SUBSTRING(v_InpData,j,1)) > 48 AND
ASC(SUBSTRING(v_InpData,j,1)) < 58 THEN
DO:
LEAVE.
END.
END.
MESSAGE REPLACE(v_InpData,SUBSTRING(v_InpData,1,j - 1),"99").
END.

Remove Duplicate Characters from String r

I've got a vector of strings which is being read in, but every entry has garbage characters at the start and end of the string that I want to remove. My problem is that I don't know which characters are the garbage until they appear in each entry.
ie:
Vector contains:
nRsp ;A810SS-Q1D-01 "
nRsp ;C5A19A60WESD04 "
nRsp ;461961 "
in this case, nRsp ; is the garbage at the beginning and " is the end garbage. The garbage values should occur at the same place relative to the start and end of the vector, but I need some way to first find them and then remove them.
Thanks!!
If you want to find the characters that all elements of your vector have in common both at the beginning and at the end before removing them, you could do:
library(purrr)
## Replicating the data
v = c("nRsp ;A810SS-Q1D-01 \"","nRsp ;C5A19A60WESD04 \"","nRsp ;461961 \"")
## Split each string into a vector
l = strsplit(v,"")
## Find the common parts at the start and end of all elements in the list
start = 1
while(every(l,function(x) sum(x[1:start]==l[[1]][1:start])==start)){start=start+1}
end = 1
while(every(l,function(x) sum(rev(x)[1:end]==rev(l[[1]])[1:end])==end)){end=end+1}
## Remove the common 'garbage' from each element of the list
v2 = sapply(l,function(x) paste(x[start:(length(x)-end+1)],collapse=""))
This returns:
[1] "A810SS-Q1D-01" "C5A19A60WESD04" "461961"

Recursion in MIPS with arrays

I'm a beginner user of MARS for programming in MIPS language. I started to study the recursion and I wrote a little method in java that take in input an array and an index, and make a recursive sum of all its elements. But I don't know how to write it in mips language, someone can help me?
public int recursiveSum(int i, int[] array)
{
if(i == array.length-1)
return array[i];
return array[i]+recursiveSum(i+1, array);
}
When you create a recursive function in mips, you need to save the return address (register $ra) on a stack frame you create for the function call's duration, restoring it upon exit (and removing/popping the frame).
Simple functions can get by minimally with just the save/restore of $ra, but, for recursive functions they typically have to save/restore some of their arguments as well.
Aside from the mips instruction set reference, one of the things you'll want to consult is the mips ABI document as it lays out which registers get used in which context for which purpose. This is particularly important when writing recursive code.
Here's a program that implements your function with unit tests. It has two different recursive function implementations to help illustrate some of the tricks you do [can do] in asm.
Notice in the top comment block your original function and a modified one that removes the "non-standard" return statement. That is, when using a high level language as pseudo-code for asm, just have a single return statement as that's how the asm gets implemented. It's important to keep things simple in the HLL. The simpler it is, the more literal the translation to the asm.
Also, there are some things you can do in asm [mips in particular] that can't be done/modeled in an HLL. mips has 32 registers. Imagine putting invariant values [such as the address of your array] in "global" registers that are preserved across all calls. The address is in a register and not on the stack or global memory, so it's very fast.
There is no HLL equivalent for this. BTW, if you know C, I'd do the pseudo-code in that rather than java. C has pointers [and explicit memory addresses], whereas java does not, and pointers are the lifeblood of asm.
Anyway, here's the code. It is well annotated, so, hopefully, it's easy to read:
# recursive sum
#
##+
# // original function:
# public int recursiveSum(int i, int[] array)
# {
#
# if (i == (array.length - 1))
# return array[i];
#
# return array[i] + recursiveSum(i + 1,array);
# }
#
# // function as it could be implemented:
# public int recursiveSum(int i, int[] array)
# {
# int ret;
#
# if (i == (array.length - 1))
# ret = 0;
# else
# ret = recursiveSum(i + 1,array);
#
# return array[i] + ret;
# }
#
# // function as it _was_ be implemented:
# public int[] array; // in a global register
#
# public int recursiveSum(int i)
# {
# int ret;
#
# if (i == (array.length - 1))
# ret = 0;
# else
# ret = recursiveSum(i + 1);
#
# return array[i] + ret;
# }
##-
.data
sdata:
array:
.word 1,2,3,4,5,6,7,8,9,10
.word 11,12,13,14,15,16,17,18,19,20
.word 11,22,23,24,25,26,27,28,29,30
arrend:
msg_simple: .asciiz "simple sum is: "
msg_recur1: .asciiz "recursive sum (method 1) is: "
msg_recur2: .asciiz "recursive sum (method 2) is: "
msg_match: .asciiz "difference is: "
msg_nl: .asciiz "\n"
.text
.globl main
# main -- main program
#
# registers:
# s0 -- array count (i.e. number of integers/words)
# s1 -- array pointer
# s2 -- array count - 1
#
# s3 -- simple sum
# s4 -- recursive sum
main:
la $s1,array # get array address
la $s0,arrend # get address of array end
subu $s0,$s0,$s1 # get byte length of array
srl $s0,$s0,2 # count = len / 4
subi $s2,$s0,1 # save count - 1
# get simple sum for reference
jal sumsimple # get simple sum
move $s3,$v0 # save for compare
# show the simple sum results
la $a0,msg_simple
move $a1,$v0
jal showsum
# get recursive sum (method 1)
li $a0,0 # i = 0
jal sumrecurs1 # get recursive sum
move $s4,$v0 # save for compare
# show the recursive sum results
la $a0,msg_recur1
move $a1,$v0
jal showsum
# get recursive sum (method 2)
li $a0,0 # i = 0
jal sumrecurs2 # get recursive sum
# show the recursive sum results
la $a0,msg_recur2
move $a1,$v0
jal showsum
# show the difference in values between simple and method 1
subu $a1,$s4,$s3 # difference of values
la $a0,msg_match
jal showsum
# exit the program
li $v0,10
syscall
# sumsimple -- compute simple sum by looping through array
#
# RETURNS:
# v0 -- sum
#
# registers:
# t0 -- array count
# t1 -- array pointer
sumsimple:
move $t0,$s0 # get array count
move $t1,$s1 # get array address
li $v0,0 # sum = 0
j sumsimple_test
sumsimple_loop:
lw $t2,0($t1) # get array[i]
add $v0,$v0,$t2 # sum += array[i]
addi $t1,$t1,4 # advance pointer to array[i + 1]
subi $t0,$t0,1 # decrement count
sumsimple_test:
bgtz $t0,sumsimple_loop # are we done? if no, loop
jr $ra # return
# sumrecurs1 -- compute recursive sum
#
# RETURNS:
# v0 -- sum
#
# arguments:
# a0 -- array index (i)
# s1 -- array pointer
#
# NOTES:
# (1) in the mips ABI, the second argument is normally passed in a1 [which can
# be trashed] but we are using s1 as a "global" register
# (2) this saves an extra [and unnecessary push/pop to stack] as s1 _must_ be
# preserved
# (3) we do, however, preserve the array index (a0) on the stack
sumrecurs1:
# save return address and argument on a stack frame we setup
subiu $sp,$sp,8
sw $ra,0($sp)
sw $a0,4($sp)
blt $a0,$s2,sumrecurs1_call # at the end? if no, fly
li $v0,0 # yes, simulate call return of 0
j sumrecurs1_done # skip to function epilog
sumrecurs1_call:
addi $a0,$a0,1 # bump up the index
jal sumrecurs1 # recursive call
# get back the index we were called with from our stack frame
# NOTES:
# (1) while we _could_ just subtract one from a0 here because of the way
# sumrecurs is implemented, we _don't_ because, in general, under the
# standard mips ABI the called function is at liberty to _trash_ it
# (2) the index value restored in the epilog of our recursive function
# call is _not_ _our_ value "i", but "i + 1", so we need to get our
# "i" value from _our_ stack frame
# (3) see sumrecurs2 for the faster method where we "cheat" and violate
# the ABI
lw $a0,4($sp)
sumrecurs1_done:
sll $t2,$a0,2 # get byte offset for index i
add $t2,$s1,$t2 # get address of array[i]
lw $t2,0($t2) # fetch array[i]
add $v0,$t2,$v0 # sum our value and callee's
# restore return address from stack
lw $ra,0($sp)
lw $a0,4($sp)
addiu $sp,$sp,8
jr $ra
# sumrecurs2 -- compute recursive sum
#
# RETURNS:
# v0 -- sum
#
# arguments:
# a0 -- array index (i)
# s1 -- array pointer
#
# NOTES:
# (1) in the mips ABI, the second argument is normally passed in a1 [which can
# be trashed] but we are using s1 as a "global" register
# (2) this saves an extra [and unnecessary push/pop to stack] as s1 _must_ be
# preserved
# (3) we do, however, preserve the array index (a0) on the stack
sumrecurs2:
# save _only_ return address on a stack frame we setup
subiu $sp,$sp,4
sw $ra,0($sp)
blt $a0,$s2,sumrecurs2_call # at the end? if no, fly
li $v0,0 # yes, simulate call return of 0
j sumrecurs2_done # skip to function epilog
sumrecurs2_call:
addi $a0,$a0,1 # bump up the index
jal sumrecurs2 # recursive call
subi $a0,$a0,1 # bump down the index
sumrecurs2_done:
sll $t2,$a0,2 # get byte offset for index i
add $t2,$s1,$t2 # get address of array[i]
lw $t2,0($t2) # fetch array[i]
add $v0,$t2,$v0 # sum our value and callee's
# restore return address from stack
lw $ra,0($sp)
addiu $sp,$sp,4
jr $ra
# showsum -- output a message
#
# arguments:
# a0 -- message
# a1 -- number value
showsum:
li $v0,4 # puts
syscall
move $a0,$a1 # get number to print
li $v0,1 # prtint
syscall
la $a0,msg_nl
li $v0,4 # puts
syscall
jr $ra

Resources