私は現在、Ironyを使用して簡単な表現言語を作成する方法を学んでいます。関数のシグネチャを定義する最良の方法を見つけ出し、それらの関数への入力を検証するのが誰の責任であるかを判断するのに少し問題があります。
これまでのところ、私の言語の基本的な要素を定義する簡単な文法があります。これには、少数の二項演算子、括弧、数値、識別子、および関数呼び出しが含まれます。私の文法のBNFは次のようになります。
<expression> ::= <number> | <parenexp> | <binexp> | <fncall> | <identifier>
<parenexp> ::= ( <expression> )
<fncall> ::= <identifier> ( <argumentlist> )
<binexp> ::= <expression> <binop> <expression>
<binop> ::= + - * / %
... the rest of the grammar definition
Ironyパーサーを使用して、さまざまな入力文字列の構文を検証し、それらがこの文法に準拠していることを確認できます。
x + y / z * AVG(a + b, p) -> Valid Syntax
x +/ AVG(x -> Invalid Syntax
それはすべてうまくいっていますが、今度はさらに一歩進んで、各関数に必要なパラメーターの数とともに、使用可能な関数を定義したいと思います。たとえば、 1つのパラメーターを受け入れ、2つのパラメーターをFOO
受け入れる関数が必要です。BAR
FOO(a + b) * BAR(x + y, p + q) -> Valid
FOO(a + b, 13) -> Invalid
2番目のステートメントが解析されるときに、この関数の予想される入力を認識しているエラーメッセージを出力できるようにしたいと思います。
Too many arguments specified for function 'FOO'
これらのステートメントを実際に評価する必要はありません。ステートメントの構文を検証し、それらが有効な式であるかどうかを判断するだけです。
これをどの程度正確に行う必要がありますか?技術的には、次のように関数を文法に追加するだけでよいことを知っています。
<foofncall> ::= FOO( <expression> )
<barfncall> ::= BAR( <expression>, <expression> )
しかし、これについての何かは完全に正しく感じられません。私には、文法はジェネリック関数呼び出しのみを定義する必要があり、言語で使用可能なすべての関数を定義する必要はないようです。
- これは通常、他の言語でどのように達成されますか?
- 言語文法の基本的な構文と関数定義のようなより具体的な要素を分析する責任を処理する必要があると呼ばれるコンポーネントは何ですか?両方の責任を同じコンポーネントで処理する必要がありますか?