ID:1542053
 
(See the best response by Koshigia.)
Code:
proc
runProgram(var/list/L, a as num, b as num) // runs the program
world << "RUNNING runProgram(list of length [length(L)], [a], [b])"
var/list/stack = new/list() // initialize stack
world << "STACK INITIALIZED"
var/pos = 0 // initialize position
world << "POS INITIALIZED"
for(var/i=1, i<=L.len, i++) // initialize program loop
world << "PERFORMING OPERATION [L[i]]"
if(isnum(L[i])) // if the operation is #
stack.Add(L[i]) // push # into stack
pos++ // increment position of end of stack
else // if the operation is not #
switch(L[i]) // find operation
if("A") // add
if(pos == 0)
// do nothing, cannot perform operations without operands
else if(pos==1)
// do nothing, cannot add with only one operand
else
stack[pos-1] += stack[pos] // add the last two numbers in the stack together
stack.Remove(stack[pos]) // pop the stack
pos--
if("D") // divide
if(pos == 0)
// do nothing, cannot perform operations without operands
else if(pos==1)
// do nothing, cannot divide with only one operand
else
if(stack[pos] != 0)
stack[pos-1] /= stack[pos] // divide the last two numbers in the stack together
stack.Remove(stack[pos]) // pop the stack
pos--
else
// do nothing, cannot divide by zero
if("M") // multiply
if(pos == 0)
// do nothing, cannot perform operations without operands
else if(pos==1)
// do nothing, cannot divide with only one operand
else
stack[pos-1] *= stack[pos] // divide the last two numbers in the stack together
stack.Remove(stack[pos]) // pop the stack
pos--
if("S") // subtract
if(pos == 0)
// do nothing, cannot perform operations without operands
else if(pos==1)
// do nothing, cannot divide with only one operand
else
stack[pos-1] -= stack[pos] // divide the last two numbers in the stack together
stack.Remove(stack[pos]) // pop the stack
pos--
if("a") // push a
stack.Add(a)
pos++
if("b") // push b
stack.Add(b)
pos++
if("P") // pop, discard
if(pos == 0)
// do nothing, cannot pop a stack with no data
else
stack.Remove(stack[pos]) // pop the stack
pos--
return stack[pos]

client
var/list/program
verb
test()
program = list("A","M","S",1,"P")
world << runProgram(program,1,2)


Problem description:

When I run it, I get this output:

runtime error: list index out of bounds
proc name: runProgram (/proc/runProgram)
usr: Guest-116658514 (/mob)
src: null
call stack:
runProgram(/list (/list), 1, 2)
Guest-116658514 (/client): test()
RUNNING runProgram(list of length 5, 1, 2)
STACK INITIALIZED
POS INITIALIZED
PERFORMING OPERATION A
PERFORMING OPERATION M
PERFORMING OPERATION S
PERFORMING OPERATION 1
PERFORMING OPERATION P


and it doesn't return the last data in the stack.

However, if I change the program to (1,M,S,1,P), I get this output:

RUNNING runProgram(list of length 5, 1, 2)
STACK INITIALIZED
POS INITIALIZED
PERFORMING OPERATION 1
PERFORMING OPERATION M
PERFORMING OPERATION S
PERFORMING OPERATION 1
PERFORMING OPERATION P
1


and it returns the last data in the stack.

There's plenty of other random configurations where it will give me a "list index out of bounds" error right as runProgram() is called (e.g. (b,a,M,P,D), (D,P,0,P,M), (A,3,S,P,A), (M,P,6,S,P), I'm literally just telling it to generate random programs and writing down the ones which give an error), and I can't find any reason why.

At first I thought it was the "P" operation that caused it, but then I ran (1,M,S,1,P) and it ran fine. I'm at a loss. Can anyone see what's going wrong?
Best response
It's not so strange. If you run the program the first way, you end up with a position of 0, which is not a valid index to your stack list. Whenever your list becomes empty, your last iteration is going to produce that error, barring any cases where your position isn't decremented properly as the stack is popped

change the last bit to...

        if(pos>0) return stack[pos]
else
world << "Pos = [pos]"
world << "stack.len = [stack.len]"
Thank you. The way it gave me all the output after the error confused me.
No problem =)