Звучит так, будто вы делаете парсер стиля lex-then-parse, где вам понадобится простой конечный автомат в лексере, чтобы получить отдельные токены для унарного и двоичного минуса. (В PEG-парсере вам не о чем беспокоиться.)
В JavaCC у вас будет состояние DEFAULT
, где вы будете считать символ -
UNARY_MINUS
. Когда вы токенизируете конец первичного выражения (или закрывающее слово, или целое число, основываясь на приведенных вами примерах), вы переключаетесь в состояние INFIX
, где -
будет считаться INFIX_MINUS
. Когда вы встретите какой-нибудь инфиксный оператор, вы вернетесь в состояние DEFAULT
.
Если вы катаетесь самостоятельно, это может быть немного проще, чем это. Посмотрите на этот код Python , чтобы узнать, как это сделать. По сути, когда вы встречаете -
, вы просто проверяете, был ли предыдущий токен инфиксным оператором. В этом примере используется строка "-u"
для представления унарного минусового токена, что удобно для неформального токенизации. Насколько я могу судить, пример Python не справляется со случаем, когда -
следует за открытым паренем или идет в начале ввода. Они также должны считаться одинарными.
Для того чтобы унарный минус был правильно обработан в самом алгоритме маневрового двора, он должен иметь более высокий приоритет, чем любой из инфиксных операторов, и он должен быть помечен как правоассоциативный. (Убедитесь, что вы обрабатываете ассоциативность справа. Возможно, вы не указали ее, поскольку остальные ваши операторы левоассоциативны.) Это достаточно ясно в коде Python (хотя я бы использовал некоторую структуру, а не две отдельные карты) .
Когда придет время оценивать, вам нужно будет обрабатывать унарные операторы немного по-другому, так как вам нужно всего лишь вытолкнуть одно число из стека, а не два. В зависимости от того, как выглядит ваша реализация, может быть проще просмотреть список и заменить каждое вхождение "-u"
на [-1, "*"]
.
Если вы вообще можете следовать Python, вы сможете увидеть все, о чем я говорю, в примере, на который я ссылаюсь. Я считаю, что код немного проще для чтения, чем версия C, о которой кто-то упоминал. Кроме того, если вам интересно, я некоторое время назад немного писал об использовании shunting-yard в Ruby , но я рассматривал унарные операторы как отдельный нетерминал, поэтому они не отображаются.