我试图实现一个
输入:
~1^(2~&3)|1 69 11111 -12
输出:
[whatever NOT 69 XOR (11111 NAND -12) OR 69 equals]
所有按位运算符具有相同的优先级,从左到右求值我正在构造的算法基本上是
Get number n1 (or evaluation of expression in parenthesis)
Set result = n1
Get operator o1
Get number n2 (or evaluation of expression in parenthesis)
Set result = result op n2
Get operator o2
Get number n3 (or evaluation of expression in paranthesis)
Set result = result o2 n3
Etcetera
我还没有完全完成,但我至少应该能够评估
((1)) 69
会导致
69
我已经测试过了
(1) 69
结果
69
这意味着我只需要找出嵌套括号的问题所在。
我的代码的相关部分,很好的注释,是…在这里忍受我。。。
private static long? EvalInner ( string eqtn, Tuple<int,int> eqtnBnds, Dictionary<int,long> eqtnArgs)
{
// eqtn: Equation to be parsed
// eqtnBnds: Bounds that define sub-equation being evaluated.
// eqtnargs: Equation arguments
// Parses and returns the evaluation of the equation eqtn in the bounds [eqtnBands.Item1, eqtnBnds.Item2)
// Handle case of empty sub-equation:
if (eqtnBnds.Item1 == eqtnBnds.Item2) throw new Exception(String.Format("Encountered empty equation at index {0}", eqtnBnds.Item1));
long? result = null;
char? lastop = null; // last operator found
bool negateNextNum = false;
PARSEMODE CURMODE = PARSEMODE.NUM; // beginning of equation should be a number since the form of the equation is
// <NUM><OPER><NUM><OPER>...<OPER><NUM>
int curidx = eqtnBnds.Item1, offend = eqtnBnds.Item2;
while ( curidx < offend )
{
switch ( CURMODE )
{
case PARSEMODE.NUM: // Expecting character at current index to be the beginning of a
{
if ( eqtn[curidx] >= '0' && eqtn[curidx] <= '9' ) // beginning of the int corresponding to the argument index
{
int begidx = curidx;
// Increment curidx to one after the last digit or the end of the subequation
while ( ++curidx < offend && eqtn[curidx] >= '0' && eqtn[curidx] <= '9' );
// Try to get an integer representation of the argument. If an error is encountered in that parsing,
// throw an error. If the argument is one within the range of arguments given in the command line,
// get its value and update result accordingly. If not, throw an error.
int argnum;
if ( Int32.TryParse(eqtn.Substring(begidx, curidx - begidx), out argnum) )
{
if (eqtnArgs.ContainsKey(argnum))
{
result = (result != null ? BinOpEval(result, lastop, eqtnArgs[argnum]) : eqtnArgs[argnum]);
if (negateNextNum)
{
result = ~result;
negateNextNum = false;
}
}
else
throw new Exception(String.Format("Argument {0} found in the equation beginning at index {1} is out-of-bounds",
argnum,
begidx)
);
}
else
{
throw new Exception(String.Format("Trouble parsing argument number that begins at index {0}",
begidx)
);
}
CURMODE = PARSEMODE.OPER;
}
else if ( eqtn[curidx] == Calculator.OPENPAREN ) // beginning of subequation in paranthesis
{
int begidx = curidx, netparens = 1;
while ( ++curidx < offend && netparens != 0 )
{
if ( eqtn[curidx] == Calculator.OPENPAREN ) ++netparens;
else if ( eqtn[curidx] == Calculator.CLOSEPAREN ) --netparens;
}
if ( netparens != 0 ) // didn't find closing parenthesis
throw new Exception(String.Format("Couldn't find closing paranthesis for opening paranthesis at index {0}",
begidx)
);
long? presult = null; // to be the result of the evaluated subequation between the set of parenthesis
try { presult = EvalInner(eqtn,new Tuple<int, int>(++begidx, curidx - begidx),eqtnArgs); }
catch ( Exception e ) { throw e; }
result = (result != null ? BinOpEval(result,lastop,presult) : presult);
if (negateNextNum)
{
result = ~result;
negateNextNum = false;
}
// Upon leaving this else-if block, curidx should be 1 after the closing paranthesis
// Expect operate to following closing paranthesis
CURMODE = PARSEMODE.OPER; // expecting operator after parens
}
else if ( eqtn[curidx] == Calculator.NOT ) // NOT symbol preceding number
{
negateNextNum = !negateNextNum;
++curidx;
// CURMODE stays as num
}
else // unexpected character where beginning of number expected
{
throw new Exception(String.Format("Expected beginning of number at index {0}, instead got {1}",
curidx,
eqtn[curidx])
);
}
break;
}
case PARSEMODE.OPER:
{
// ...
我想弄清楚为什么
((1)) 69
正在打印错误
Error: Encountered empty equation at index 2
让我来看看我的逻辑:
首先是
curidx = 0
,eqtn[curidx] = '('
和CURMODE = PARSEMODE.NUM
。那会让我们进入街区 else if ( eqtn[curidx] == Calculator.OPENPAREN ) // beginning of subequation in paranthesis
{
// ...
}
在街区的尽头
int begidx = curidx, netparens = 1;
while ( ++curidx < offend && netparens != 0 )
{
if ( eqtn[curidx] == Calculator.OPENPAREN ) ++netparens;
else if ( eqtn[curidx] == Calculator.CLOSEPAREN ) --netparens;
}
之后
begidx
是0
并且curidx
是5
(右括号后的索引)。因此,++begidx
是1
并且curidx - begidx
(在++begidx
之后评估)是4
因此,打电话后EvalInner(eqtn,new Tuple<int, int>(++begidx, curidx - begidx),eqtnArgs); }
我们最后回到街区
else if ( eqtn[curidx] == Calculator.OPENPAREN ) // beginning of subequation in paranthesis
{
int begidx = curidx, netparens = 1;
while ( ++curidx < offend && netparens != 0 )
{
if ( eqtn[curidx] == Calculator.OPENPAREN ) ++netparens;
else if ( eqtn[curidx] == Calculator.CLOSEPAREN ) --netparens;
}
在上述
begidx = 1
和curidx = 4
之后(索引在右括号之后)。然后++begidx = 2
以后curidx - begidx = 2
当我们重新进入EvalInner
时,我们有eqtn[curidx] = '1'
,导致我们进入这个区块 if ( eqtn[curidx] >= '0' && eqtn[curidx] <= '9' ) // beginning of the int corresponding to the argument index
{
// ...
}
很明显,在这之后,我们用桨划过了
1
,将它与参数69
关联起来,并通过调用堆栈返回到输出。我哪里做错了?
最佳答案
元组的第二个元素是子方程的长度还是它的上界?
presult = EvalInner(eqtn,new Tuple<int, int>(++begidx, curidx - begidx),eqtnArgs);
简单地使用两个明确的命名参数可能会更有帮助,但是根据您在递归调用之前的使用情况,它看起来好像是上界,但是您传递的是一个长度。
也许这是唯一的问题?不确定。