3

私は元々 Perl で構築したミニ言語をやり直しています ( github の Chessa# を参照) が、セマンティクスを適用するときに多くの問題に直面しています。

文法は次のとおりです。

(* integers *)
DEC = /([1-9][0-9]*|0+)/;
int = /(0b[01]+|0o[0-7]+|0x[0-9a-fA-F]+)/ | DEC;
(* floats *)
pointfloat = /([0-9]*\.[0-9]+|[0-9]+\.)/;
expfloat = /([0-9]+\.?|[0-9]*\.)[eE][+-]?[0-9]+/;
float = pointfloat | expfloat;
list = '[' @+:atom {',' @+:atom}* ']';
(* atoms *)
identifier = /[_a-zA-Z][_a-zA-Z0-9]*/;
symbol = int        |
         float      |
         identifier |
         list;
(* functions *)
arglist = @+:atom {',' @+:atom}*;
function = identifier '(' [arglist] ')';
atom = function | symbol;
prec8 = '(' atom ')' | atom;
prec7 = [('+' | '-' | '~')] prec8;
prec6 = prec7 ['!'];
prec5 = [prec6 '**'] prec6;
prec4 = [prec5 ('*' | '/' | '%' | 'd')] prec5;
prec3 = [prec4 ('+' | '-')] prec4;
(* <| and >| are rotate-left and rotate-right, respectively. They assume the nearest C size. *)
prec2 = [prec3 ('<<' | '>>' | '<|' | '>|')] prec3;
prec1 = [prec2 ('&' | '|' | '^')] prec2;
expr = prec1 $;

私が直面している問題はd、演算子と後続の英数字文字列の間に空白が存在しない場合、演算子が識別子ルールに引き込まれていることです。文法自体はLL(2)なのですが、どこが問題なのかわかりません。

たとえば、は識別子4d6として解釈されているため、パーサーを停止します。起こるべきことは、 が演算子であると解釈されることです。LL パーサーでは、これが実際に当てはまります。4 d6d64 d 6d

考えられる解決策はd、識別子の開始を禁止することですが、これにより、関数などのdrop名前をそのように指定することが許可されなくなります。

4

2 に答える 2

3

Perl では、一般的な BNF パーサーであるMarpaを使用できます。これは、そのままで結合性 (およびその他の多く) を備えた一般化された優先順位をサポートします。たとえば、

:start ::= Script
Script ::= Expression+ separator => comma
comma ~ [,]
Expression ::=
    Number bless => primary
    | '(' Expression ')' bless => paren assoc => group
   || Expression '**' Expression bless => exponentiate assoc => right
   || Expression '*' Expression bless => multiply
    | Expression '/' Expression bless => divide
   || Expression '+' Expression bless => add
    | Expression '-' Expression bless => subtract

完全な作業例はこちらです。プログラミング言語に関しては、Marpa ベースの C パーサーがあります。

お役に立てれば。

于 2014-09-26T16:44:56.280 に答える