修改分流场算法(c ++)

时间:2013-06-01 21:42:54

标签: c++ shunting-yard

我有一个正常工作顺序的调车场算法,但我注意到一个特殊的怪癖:

1 + ( 3 * ( 4 + 5 ) )

正确解析

1 3 4 5 + * +,

但是

1 + (3 * (4 + 5))
失败,并解析为

1 * + 5)) +

我想让它正确解析第二个问题,以便结果与第一个问题相同。我怎么能做到这一点?

注意: 我从维基百科中导出了我的算法: http://en.wikipedia.org/wiki/Shunting-yard_algorithm#The_algorithm_in_detail

我的算法代码是:

string switchingYard(string input)
{
stringstream io(input);
ProcessStack switch_stack;
vector<string> out;
while(io.good())
{
    string token;
    io >> token;
    if(isdigit(token[0]) || (token[0] == '.' && isdigit(token[1]))
        || ( (token[0] == '-' && isdigit(token[1])) || (token[0] == '-' && token[1] == '.' && isdigit(token[2])) ) )
    {
        out.push_back(token);
    }


    if(isFunctionToken(token))
    {
        switch_stack.pushNode(token);
    }

    if(isArgSeparator(token[0]))
    {
        bool mismatch_parens = false;
        do{
            if(switch_stack.length() == 1)
            {
                if(switch_stack.peekChar() != '(')
                {
                    mismatch_parens = true;
                    break;
                }
            }
            string opPop = switch_stack.popNode();
            out.push_back(opPop);
        }while(switch_stack.peekChar() != '(');
        if(mismatch_parens)
            return "MISMATCH_ERROR";
    }

    if(isOperator(token[0]))
    {
        while(  isOperator(switch_stack.peekChar()) &&
                ((left_assoc(token[0]) && (op_preced(token[0]) == op_preced(switch_stack.peekChar()) )) || (op_preced(token[0]) < op_preced(switch_stack.peekChar())) ) )
        {
            string popped = switch_stack.popNode();
            out.push_back(popped);
        }
        switch_stack.pushNode(token);
    }

    if(token == "(")
        switch_stack.pushNode(token);

    if(token == ")")
    {
        bool mismatch_parens = false;
        while(switch_stack.peekChar() != '(')
        {
            if(switch_stack.length() == 0 || (switch_stack.length() == 1 && switch_stack.peekChar() != '('))
            {
                mismatch_parens = true;
                break;
            }
            string opPop = switch_stack.popNode();
            out.push_back(opPop);
        }
        if(mismatch_parens)
            return "MISMATCH_ERROR";
        string parensPop = switch_stack.popNode();
        if(isFunctionToken(switch_stack.peek()))
        {
            string funcPop = switch_stack.popNode();
            out.push_back(funcPop);
        }

    }
}
while(switch_stack.length() > 0)
{
    if(switch_stack.peekChar() == '(' || switch_stack.peekChar() == ')')
        return "MISMATCH_ERROR";
    string opPop = switch_stack.popNode();
    out.push_back(opPop);
}
string ret;
for(int i = 0; (unsigned)i < out.size(); i++)
{
    ret += out[i];
    if((unsigned)i < out.size()-1)
        ret += " ";
}
cout << "returning:\n" << ret << endl;
return ret;
}

编辑:好的,所以我有了一个主意。因此,当解析器遇到'(3'标记时,否则它会将两个字符视为一个,并丢弃整个事物,但是如果我以递归方式调用函数,则传入该字符串的子字符串输入字符串以'3'字符开头?我只需要将分流字符串添加到输出向量,并在字符串流上调用ignore! 我正在谈论做出这些改变:

string switchingYard(string input)

变     

string switchingYard(string input, int depth)
和     
if((token[0] == '(' || token[0] == ')') && (isdigit(token[1]) || token[1] == '.' || isOperator(token[1]))
            {
                string shunted_recur = out.push_back(switchingYard(input.substr(io.tellg()+1),depth+1));
            }
被添加到while循环的末尾。想法?

1 个答案:

答案 0 :(得分:1)

您的问题是解析器使用以下函数读取字符串:

io >> token;

在我看来,简单的解决方案是一次只读一个角色。例如。

char ch;

io >> ch;

我实际上会编写一个读取令牌的函数 - 它会知道诸如“数字序列是一个数字”之类的东西,并将运算符,括号等分开。它将返回一个持有的对象(类或结构类型) “元素类型”和“值(如果相关) - 所以它可以是”数字“类型和值”4711“,或者键入”运算符“,值”+“。

你的tokeniser需要一个“状态”,其中包括一个“lookahead”字符(一个字符应该足够),这样当你超过一个数字的末尾就可以停止,然后拿起下次“停止成为号码”的角色。