3

私はどこでも例を見つけようとしてきましたが、それは無駄でした。

基本的なRubyインタープリターを書こうとしています。このために、トークン認識文を含むフレックスレキシカルファイルと文法ファイルを作成しました。

文法にセマンティックタイプチェックが含まれていることを望みます。

私の文法ファイルには、たとえば次のものが含まれています。

arg : arg '+' arg 

これは、整数と浮動小数点数の有効なルールである必要があります。

私が読んだことによると、argなどの非終端記号のタイプを次のように指定できます。

%type <intval> arg

ここで、「intval」は型共用体であり、intC型に対応します。

しかし、これは整数の場合のみです。たとえば、floatに対してルールを有効にする方法がわかりません。私は2つの異なるルールを持つことを考えました。1つはint用、もう1つはfloat用です。

argint : argint '+' argint
argfloat : argfloat '+' argfloat

しかし、この残虐行為では、floatとintの間に追加を許可するルールが必要になるため、これを行うにははるかに優れた方法があると確信しています。

私が見つけたすべての例には、1つのタイプしかありません(通常、電卓のような例では整数)。

加算などのルールが引数としてintとfloatを持つことができるように指定するにはどうすればよいですか?

どうもありがとうございます。

4

1 に答える 1

5

これはあなたが望んでいる答えではありません。必要な例が見当たらない理由は、文法ファイル(.y)に入力規則を適用するのは非現実的だからだと思います。むしろ、開発者は手続き型の.cまたは.cppコードでこれを実現します。一般に、とにかく解析された入力の分析を行う必要があるため、そうするときにセマンティックルールを適用することは副産物です。

余談ですが、質問で再現する文法の断片を考えると、式をどのように解析しているのかよくわかりません。

これが私がそれが非現実的であると主張する理由です。(1)タイプ情報は、文法の非終端記号全体に浸透する必要があります。(2)さらに悪いことに、それは変数名に反映されなければなりません。

識別子、数値定数、および4つの卓上電卓演算子を使用できる単純な代入ステートメントを解析するこのおもちゃの例を考えてみてください。NUMBERトークンは、42のような整数または3.14のような浮動小数点数にすることができます。そして、識別子が1文字のAZであるとしましょう。

%token IDENTIFIER NUMBER

%%

stmt : IDENTIFIER '=' expr
     ;

expr : expr '+' term
     | expr '-' term
     | term
     ;

term : term '*' factor
     | term '/' factor
     | factor
     ;

factor : '(' expr ')'
       | '-' factor
       | NUMBER
       | IDENTIFIER
       ;

それでは、タイピングルールを紹介してみましょう。NUMBERトークンをFLT_NUMBERとINT_NUMBERに分けます。、、および非終端記号も2つexprに分割されます。termfactor

%token IDENTIFIER FLT_NUMBER INT_NUMBER

stmt : IDENTIFIER '=' int_expr
     | IDENTIFIER '=' flt_expr
     ;

int_expr : int_expr '+' int_term
         | int_expr '-' int_term
         | int_term
         ;

flt_expr : flt_expr '+' flt_term
         | flt_expr '-' flt_term
         | flt_term
         ;

int_term : int_term '*' int_factor
         | int_term '/' int_factor
         | int_factor
         ;

flt_term : flt_term '*' flt_factor
         | flt_term '/' flt_factor
         | flt_factor
         ;

int_factor : '(' int_expr ')'
           | '-' int_factor
           | INT_NUMBER
           | int_identifier
           ;

flt_factor : '(' flt_expr ')'
           | '-' flt_factor
           | FLT_NUMBER
           | flt_identifier
           ;

int_identifier : IDENTIFIER ;

flt_identifier : IDENTIFIER ;

私たちの文法はこの時点で立っているので、矛盾があります。パーサーはIDENTIFIERをaint_identifierまたは。として認識するかどうかを判断できませんflt_identifierA = Bしたがって、 asIDENTIFIER = int_exprまたはを減らすかどうかはわかりませんIDENTIFIER = flt_expr

(ここで、Rubyについての私の理解は少しソフトです:) Ruby(ほとんどの言語のように)は、識別子の数値タイプを決定するための語彙レベルの方法を提供しません。これを古い学校のBASICと比較してください。ここで、Aは数値を示し、A$は文字列を示します。言い換えれば、たとえば、A#が整数を表し、A @が浮動小数点数を表す言語を発明した場合、これを機能させることができます。

のような限定された混合型の式を許可したい場合int_term '*' flt_factor、文法はさらに複雑になります。

これらの問題を回避する方法があるかもしれません。yacc/bison以外のテクノロジーで構築されたパーサーを使用すると簡単になる場合があります。少なくとも、私のスケッチはあなたにさらに追求するためのいくつかのアイデアを与えるでしょう。

于 2012-06-27T02:03:17.230 に答える