C++ 关于调车场的基本问题

C++ 关于调车场的基本问题,c++,algorithm,shunting-yard,C++,Algorithm,Shunting Yard,我已经完成了调车场算法的实现,但是有一些问题: 该算法如何验证输入是否合法,换句话说,它如何检测a++b是否合法(确保不合法) 我应该做的第二步是什么?调车场将1+2转换为1+2 关于1的更新: 经过一些尝试后,我认为它是这样的,例如,以a++b为例,它将是a+b+,然后当我计算它时,我将取a+then+,但因为我手头只有一个变量,这是一个错误 对于无效表达式总是这样吗?让我们看看是否可以为您细分。调车场算法通过打破中缀符号执行以下操作之一: In a simple description

我已经完成了
调车场
算法的实现,但是有一些问题:

  • 该算法如何验证输入是否合法,换句话说,它如何检测a++b是否合法(确保不合法)

  • 我应该做的第二步是什么?调车场将
    1+2
    转换为
    1+2


  • 关于1的更新:

    经过一些尝试后,我认为它是这样的,例如,以
    a++b
    为例,它将是
    a+b+
    ,然后当我计算它时,我将取a+then+,但因为我手头只有一个变量,这是一个错误


    对于无效表达式总是这样吗?让我们看看是否可以为您细分。调车场算法通过打破中缀符号执行以下操作之一:

    In a simple description:
        (1) Infix: A + B
            Postfix: A B +
        (2) Infix: A + B * C
            Postfix: A B C * +
    
  • 或者生成后缀符号字符串(也称为反向波兰符号)
  • 或抽象语法树
  • 在你的例子中,它是后缀符号

    [注:我希望您了解后缀符号,如果不了解,请阅读。]

    现在,后缀符号使计算数学表达式变得非常容易。我将向您展示如何计算后缀符号:

    In a simple description:
        (1) Infix: A + B
            Postfix: A B +
        (2) Infix: A + B * C
            Postfix: A B C * +
    
    我希望,你们已经理解了,调车场将帮助你们把中缀转换成后缀,然后,你们可以很容易地计算后缀符号

    现在的问题是如何检测
    a++b
    错误

    现在,观察a、+、+、b令牌的情况(如您在注释中所述:
    a++b
    是标记化的a、+、+、b令牌):

    我从维基百科上获取了伪代码(变得懒惰,不想自己编写):

    考虑到这一点:a、+、+、b将在输出队列中采用以下形式:

    a, b, +, +
    
    a,b,+,+
    完全是错误的,因为根据后缀评估规则,会发生以下情况:

    1. [a] // output queue is now [b, +, +]
    2. [a, b] // output queue is now [+, +]
    3. [r1] // output queue is now [+]
    4. error // cause: notice there's still one '+' operator left in queue
    // but, only one number 'r1' left in the 'stack'
    // so, error
    
    我希望你现在明白了……

    1。语法错误 这取决于您如何准确地实现该算法,但在通常通过互联网搜索找到的版本中,无法保证调车场算法会正确拒绝不符合语法的表达式。许多不正确的表达式将产生不正确的后缀字符串(如您所注意的),甚至是正确的后缀字符串。特别是,如果有一元运算符,则算法(通常显示)无法真正区分前缀使用(运算符位于操作数之前)和后缀使用(运算符位于操作数之后)

    如果目标语言中的运算符可以用作前缀或后缀运算符,并且具有不同的语义(例如C系列的
    ++
    --
    运算符),那么这将是一个严重的问题。由于算法没有区分这两种情况,因此语义差异丢失

    运算符也有一个类似的更常见的问题,它既可以用作二进制中缀运算符,也可以用作前缀运算符,例如
    -
    运算符。除非区分这两种用法,否则后缀输出将无法解释,因为当到达
    -
    时,计算器无法知道它是应用于一个操作数还是两个操作数。(此外,一元减号运算符的处理优先级可能不正确,因为所需的一元减号优先级高于乘法和除法。但是,对于大多数算术表达式,使用不正确的优先级不会更改结果的数值,因为
    -(x*y)
    (-x)*y
    具有完全相同的值。如果实现模运算符,则会出现不正确的结果。)

    调车场算法将检测不平衡圆括号,因为不平衡圆括号将导致分析堆栈被覆盖或在分析结束时有太多值

    使用一个非常小的状态机来扩充调车场算法相对容易,该状态机足以对具有多个语法意义的运算符的不同明确用法进行分类;该状态机还足以检测上面提到的其他语法错误:运算符放置不正确或完全丢失

    因为在实际应用中必须正确区分一元否定和二元否定;前缀和后缀运算符的不同含义;括号的不同使用(分组与函数调用),使用分流码的生产解析器将包括一些额外的语法机制,这些机制也将检测语法错误。可以找到这种算法的一个例子


    2.RPN作为中间步骤 绝对没有必要使用RPN作为中间结果;调车场算法可用于

    • 直接计算算术表达式(如果表达式不包括条件或循环构造)

    • 为堆栈机器编译器输出可执行代码(或者为更真实的机器输出三地址代码),或者更一般

    • 生成表示已解析表达式的语法树,可用于上述任何目的和其他语义分析任务

    要生成语法树,需要将操作数推送到解析器堆栈上,而不是直接将它们输出到输出流。此外,当您将运算符推送到堆栈上时,实际上是推送表示该运算符应用程序的语法节点:对于二进制运算符,它与堆栈顶部的两个插槽组合。(对于具有顶部堆栈插槽的一元运算符。)如果要使用调车场作为直接求值器,则使用相同的策略,但将运算符推到堆栈上会导致该运算符及其操作数的求值,以相同的方式标识

    RPN中间表示法实际上没有提供任何价值。我没有我
    else if the token is an operator then:
            while ((there is a operator at the top of the operator stack)
                  and ((the operator at the top of the operator stack has greater precedence)
                   or (the operator at the top of the operator stack has equal precedence and the token is left associative))
                  and (the operator at the top of the operator stack is not a left parenthesis)):
                pop operators from the operator stack onto the output queue.
            push it onto the operator stack.
    
    a, b, +, +
    
    1. [a] // output queue is now [b, +, +]
    2. [a, b] // output queue is now [+, +]
    3. [r1] // output queue is now [+]
    4. error // cause: notice there's still one '+' operator left in queue
    // but, only one number 'r1' left in the 'stack'
    // so, error