I'm trying to convert this Java code (Evaluates arithmetic expressions using Dijkstra's two-stack algorithm) to C# :
using System;
using System.Collections.Generic;
using System.IO;
public class Evaluate
{
public double Eval(string expression)
{
Stack<string> ops = new Stack<string>();
Stack<double> vals = new Stack<double>();
string s = expression;
while (!s.Equals(""))
{
if (s.Equals("(")) ;
if (s.Equals("+")) ops.Push(s);
else if (s.Equals("-")) ops.Push(s);
else if (s.Equals("*")) ops.Push(s);
else if (s.Equals("/")) ops.Push(s);
else if (s.Equals("sqrt")) ops.Push(s);
else if (s.Equals(")"))
{
string op = ops.Pop();
double v = vals.Pop();
if (op.Equals("+")) v = vals.Pop() + v;
else if (op.Equals("-")) v = vals.Pop() - v;
else if (op.Equals("*")) v = vals.Pop() * v;
else if (op.Equals("/")) v = vals.Pop() / v;
else if (op.Equals("sqrt")) v = Math.Sqrt(v);
vals.Push(v);
}
else vals.Push(double.Parse(s));
}
return vals.Pop();
}
}
But Unity stop working when I'm try to test it. What have I done wrong?
Your code is behaving as expected. You did not translate the Java code to C# well. I can spot one problem for now but I don't know if there is more of them when you fix this one.
The Java original code exits the while loop if input is empty . Below is what the Java code looks like:
while (!StdIn.isEmpty()) {
String s = StdIn.readString();
......
......
}
It uses the input to break out of the while loop. Exits if input is empty.
Your C# code:
while (!s.Equals(""))
{
......
......
}
It uses s to break out of the while loop but s is not being changed any where in the loop. So the loop keeps going.This leads to infinite loop and infinite loop in Unity = Lock/Freeze with few Exceptions.
Fix #1 . Call Eval in another Thread. Not recommended for a beginner.
Fix #2 . Use Coroutine .
My solution is with Coroutine.
Change your function return type from double
to Coroutine
then put yield return null;
inside the while
loop. To call the function, use StartCoroutine(Eval("Your Expression"));
. The use of yield return null;
will prevent Unity from crashing.
Even when you do this, you code still won't exit when you pass in a value that is not empty but it wont Lock / Freeze anymore.
To fix this and replicate the code from Java, you should find a way to exit the program with an input.
Go to GameObject -> UI -> Input Field and Rename that GameObject to EvalInput ;
Now use the Input field and the code below to make the C# code look and function more like the Java Code. The final result is stored in the global evalResult
variable.
InputField evalInput;
void Start()
{
StartCoroutine(Eval("Your Expression"));
evalInput = GameObject.Find("EvalInput").GetComponent<InputField>();
}
double evalResult = 0;
public IEnumerator Eval(string expression)
{
Stack<string> ops = new Stack<string>();
Stack<double> vals = new Stack<double>();
string s = expression;
while (!s.Equals(""))
{
s = evalInput.text; //Modify the string here (Empty string == Exit)
if (s.Equals("(")) ;
if (s.Equals("+")) ops.Push(s);
else if (s.Equals("-")) ops.Push(s);
else if (s.Equals("*")) ops.Push(s);
else if (s.Equals("/")) ops.Push(s);
else if (s.Equals("sqrt")) ops.Push(s);
else if (s.Equals(")"))
{
string op = ops.Pop();
double v = vals.Pop();
if (op.Equals("+")) v = vals.Pop() + v;
else if (op.Equals("-")) v = vals.Pop() - v;
else if (op.Equals("*")) v = vals.Pop() * v;
else if (op.Equals("/")) v = vals.Pop() / v;
else if (op.Equals("sqrt")) v = System.Math.Sqrt(v);
vals.Push(v);
}
else vals.Push(double.Parse(s));
yield return null;
}
evalResult = vals.Pop();
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.