Есть два разных случая для рассмотрения, в зависимости от синтаксиса вашего языка. Если ваш язык использует скобки для обозначения приложения функции (например f(2+1)
), то приоритет не имеет значения. Функция должна быть помещена в стек и выдана после (для примера выше, результат равен 2 1 + f
). В качестве альтернативы вы можете рассматривать функцию как значение и выводить ее немедленно и выводить операцию вызова функции после закрывающей круглой скобки (которая в противном случае должна обрабатываться так же, как любая другая скобка), например f 2 1 + $
, где $
находится операция вызова функции.
Если ваш язык, однако, не использует круглые скобки для обозначения вызова функции, а вместо этого помещает аргумент непосредственно после функции без какой-либо специальной пунктуации (например f 2 + 1
), как это, очевидно, имеет место в примере из Википедии, тогда все немного сложнее. Обратите внимание, что выражение, которое я только что привел в качестве примера, неоднозначно: применяется ли f к 2 и 1, добавляется к результату, или мы добавляем 2 и 1 вместе, а затем вызываем f с результатом?
Опять же, есть два подхода. Вы можете просто поместить функцию в стек операторов, когда встретите ее, и назначить ей любой приоритет, какой захотите. Это самый простой подход, и, очевидно, это то, что сделал приведенный пример. Однако есть практические проблемы. Во-первых, как вы определяете функцию? Если у вас есть конечный набор, это легко, но если у вас есть определенные пользователем функции, это означает, что вашему анализатору требуется слишком обратная связь с вашей средой, которая может быстро запутаться. А как вы обрабатываете функции с несколькими аргументами?
Мне кажется, что для этого стиля синтаксиса использование функций в качестве значений, которые более удобны для оператора приложения функции, имеет гораздо больше смысла. Затем вы можете просто ввести оператор приложения всякий раз, когда вы читаете значение, и последнее, что вы прочитали, было также значением, поэтому вам не требуется особый способ сообщить, какие идентификаторы являются функциями. Вы также можете работать с выражениями, которые возвращают функции (что сложно или невозможно со стилем «функция как операция»). А это означает, что вы можете использовать каррирование для обработки функций с несколькими аргументами, что является огромным упрощением по сравнению с попыткой обрабатывать их напрямую.
Тогда единственное, что вам нужно решить - это приоритет применения функций. Выбор за вами, но на каждом используемом мной языке, который работает подобным образом, он был наиболее сильным обязательным оператором в языке и был правильно ассоциативным. (Единственный интересный вариант - это Haskell, который, помимо описанной версии с сильной привязкой, также имеет синоним для него с символом, $
который является наиболее слабой связывающей операцией в языке, позволяя выражениям типа f 2 + 1
применять f к 2 и f $ 2 + 1
применять это ко всему остальному выражению)
sin( max( 2 3) / 3 * 3.1415)