听起来您正在做一个 lex-then-parse 样式的解析器,您需要在词法分析器中使用一个简单的状态机,以便为一元和二进制减号获取单独的标记。(在 PEG 解析器中,这不是您必须担心的事情。)
在 JavaCC 中,您将有一个DEFAULT
状态,您将在其中将-
字符视为UNARY_MINUS
. 当您标记主表达式的结尾时(根据您提供的示例,可以是右括号或整数),然后您将切换到INFIX
将-
被视为INFIX_MINUS
. 一旦遇到任何中缀运算符,您就会返回到该DEFAULT
状态。
如果您自己滚动,它可能会比这更简单一些。看看这个Python 代码,寻找一种聪明的方法。基本上,当您遇到 a 时-
,您只需检查前一个标记是否是中缀运算符。该示例使用字符串"-u"
来表示一元减标记,这便于进行非正式标记化。最好我能说的是,Python 示例确实无法处理 a-
跟随开放括号或出现在输入开头的情况。这些也应该被认为是一元的。
为了在调车场算法本身中正确处理一元减号,它需要具有比任何中缀运算符更高的优先级,并且需要标记为右关联。(确保您处理右关联性。您可能已将其排除在外,因为其余的运算符都是左关联的。)这在 Python 代码中很清楚(尽管我会使用某种结构而不是两个单独的映射) .
当需要计算时,您需要稍微不同地处理一元运算符,因为您只需从堆栈中弹出一个数字,而不是两个。根据您的实现的样子,只需浏览列表并将每次出现的地方替换为"-u"
with可能会更容易[-1, "*"]
。
如果您完全可以使用 Python,那么您应该能够在我链接到的示例中看到我正在谈论的所有内容。我发现代码比其他人提到的 C 版本更容易阅读。另外,如果你很好奇,我不久前写了一篇关于在 Ruby 中使用 shutting-yard 的文章,但我将一元运算符作为单独的非终结符处理,因此没有显示它们。