演算子のオーバーロードを実装する+
(plus)は、二項演算子であることがわかっていれば、それほど難しくはありません。 expression
+
expression
しかし、プログラマーが+
は、2進数、単項(接頭辞/接尾辞)、3項の一部、またはその他のものですか?例えば。
.. ? .. : ..
..²
.. | .. | .. | .. | ..
.. 大 .. 小 ..
不 ..
問題は、解析時にアリティが認識されるべきであるということのようですが、そうではなく、コンパイル/トランスパイル全体の後でのみ認識されます。
いくつかのアイデア:
ひどくない方法はありますか?
解析フェーズで演算子を他の識別子と区別できると仮定することで、より可能になりますか(たとえば、他の識別子は英数字です)?
言語がユーザー定義の演算子をサポートしている場合(既存の演算子のオーバーロードとは対照的)、言語は通常、構文解析時にアリティ、連想性、および優先順位がわかるように構造化されています。
もちろん、これにより、一般的なパーサジェネレータを使用できなくなりますが、別の方法もあります(パーサを手動で作成するなど)。
演算子は宣言する必要があります前使用されます。これは、C/C++関数を呼び出す前に宣言する必要がある方法と似ています。
例:Haskell。ここでは、許可された文字のセットから演算子を自由に宣言できます。 _infixr 5 **
_のような宣言を使用して、結合性、アリティ、および優先順位レベルを指定できます。それ以外の場合、演算子は通常の関数のように宣言されます。 _(++) a b = concat a b
_。演算子が括弧で片側または両側に囲まれている場合、それらはアリティを失います。同等に_a + b
_、_(a +) b
_、_(+ b) a
_、_(+) a b
_と書くことができます。
例:Scala。 In Scala演算子は通常のメソッドであり、メソッドをドット表記で呼び出す必要はありません。したがって、a.m(b)
は_a m b
_と同等です。 _++
_というメソッドを定義します。_a ++ b
_と書くことができます。一部の演算子はより特殊で、特別な名前のメソッドでのみオーバーロードできます。たとえば、apply()
メソッドを使用した関数呼び出し演算子です。演算子の優先順位レベルは、演算子の最初の文字によって決定されます。したがって、演算子_+
_、_+*
_、および_+|
_はすべて同じ優先順位を持ちます。
例:Perl6。 Perl6言語には、強力な文法エンジンが含まれています。たとえば、サブルーチンを演算子として宣言することにより、新しいルールをその場で文法に追加できます。演算子は常にアリティで宣言されるため、multi sub prefix:<++>($x)
、multi sub infix:<++>($x, $y)
、およびmulti sub postfix:<++>($x)
は異なる演算子として共存できます。演算子は記号に限定されず、文字も含めることができます。全体として、この言語のオペレーターシステムは非常に複雑で柔軟性があります。
あなたはその言語について言及しませんでした。
Swiftには、最初に演算子となる文字シーケンスの構文があります。たとえば、「+」は、言語に組み込まれているためではなく、標準ライブラリの一部として実装されているため、演算子です。
次に、演算子が単項演算子か二項演算子かを決定する構文があります。 A + BまたはA + Bでは「+」は2項演算子、A * + Bでは単項演算子です。 (A * + Bには二項演算子* +があります)。
この構文を使用すると、演算子が見つかり、関数呼び出しのように扱われます。演算子が見つからない場合は、未定義の関数名の関数呼び出し構文と同じです。 (演算子ごとに定義されている演算子の優先順位と左または右の結合性を省略しました)。
したがって、たとえば単項演算子* +と二項演算子* +を簡単に定義でき、コンパイラーはそれらを別々に保持しても問題ありません。 (Swiftの初心者は、a + bまたはa + bがコンパイルされないことにしばしば驚かされます)。