これが修正ですが、完全に満足できるものではありません。
%{
%}
%token tNAME tINT tINTEGER
%left '<'
%left '+'
%nonassoc '=' /* <-- LOOK */
%%
declaration: variable
| declaration variable
variable : type tNAME '=' expr
| type tNAME
type : '<' type '>'
| tINT
expr : tINTEGER
| expr '<' expr
| expr '+' expr
;
この問題は、次の 2 つの LR アイテム間の競合です: ドット ファイナル:
variable : type tNAME '=' expr_no_less .
そしてこれ:
expr : expr . '<' expr
これら 2 つの演算子は異なることに注意してください。ご想像のとおり、'<' 演算子を含む異なるプロダクション間の競合ではありません。
=
優先順位に追加することで、競合の診断がなくなるという意味で問題を修正します。
=
優先順位が高いことに注意してください。これにより、reduce が優先されて競合が解決されます。これは、「<」式を初期化子として使用できないことを意味します。
int name = 4 < 3 // syntax error
< が見られるとき、int name = 4
欲求は減らされ、生産<
の一部として、次の宣言の開始でなければならないという考えです。type
関係式を初期化子として使用できるよう<
にするには、括弧のサポートを式の文法に追加します。次に、ユーザーは括弧を付けることができます:
int foo = (4 < 3) <int> bar = (2 < 1)
より強力な解析方法またはハックなしでは、これを修正する方法はありません。
%nonassoc
beforeを移動して、%left '<'
優先順位を低くするとどうなるでしょうか? その後、シフトが優先されます。<int>
残念ながら、宣言の後に別の宣言を書くことはできません。
int foo = 3 <int> bar = 4
^ // error: the machine shifted and is now doing: expr '<' . expr.
したがって、それは競合を解決するための間違った方法です。そのような宣言を複数記述できるようにする必要があります。
別の注意:
私の TXR 言語は、Parse Expression Grammars と同等のものを実装しており、この文法を適切に処理します。これは本質的に LL(infinite) であり、LALR(1) よりも優れています。
別の語彙アナライザーとパーサーを用意する必要さえありません! これは、1 シンボル先読みの制限と、1970 年代のハードウェアでの最大限の効率の必要性によって必要になったものです。
dl
シェル コマンド ラインからの出力例。変数(宣言リスト)にバインドされた Lisp のような抽象構文ツリーへの変換による解析を示します。したがって、これはセマンティック アクションで完了し、TXR Lisp でさらに処理できる出力が得られます。識別子は への呼び出しを介して Lisp シンボルに変換されintern
、数値は数値オブジェクトにも変換されます。
$ txr -l type.txr -
int x = 3 < 4 int y
(dl (decl x int (< 3 4)) (decl y int nil))
$ txr -l type.txr -
< int > x = 3 < 4 < int > y
(dl (decl x (pointer int) (< 3 4)) (decl y (pointer int) nil))
$ txr -l type.txr -
int x = 3 + 4 < 9 < int > y < int > z = 4 + 3 int w
(dl (decl x int (+ 3 (< 4 9))) (decl y (pointer int) nil)
(decl z (pointer int) (+ 4 3)) (decl w int nil))
$ txr -l type.txr -
<<<int>>>x=42
(dl (decl x (pointer (pointer (pointer int))) 42))
( ) のソース コードtype.txr
:
@(define ws)@/[ \t]*/@(end)
@(define int)@(ws)int@(ws)@(end)
@(define num (n))@(ws)@{n /[0-9]+/}@(ws)@(filter :tonumber n)@(end)
@(define id (id))@\
@(ws)@{id /[A-Za-z_][A-Za-z_0-9]*/}@(ws)@\
@(set id @(intern id))@\
@(end)
@(define type (ty))@\
@(local l)@\
@(cases)@\
@(int)@\
@(bind ty @(progn 'int))@\
@(or)@\
<@(type l)>@\
@(bind ty @(progn '(pointer ,l)))@\
@(end)@\
@(end)
@(define expr (e))@\
@(local e1 op e2)@\
@(cases)@\
@(additive e1)@{op /[<>]/}@(expr e2)@\
@(bind e @(progn '(,(intern op) ,e1 ,e2)))@\
@(or)@\
@(additive e)@\
@(end)@\
@(end)
@(define additive (e))@\
@(local e1 op e2)@\
@(cases)@\
@(num e1)@{op /[+\-]/}@(expr e2)@\
@(bind e @(progn '(,(intern op) ,e1 ,e2)))@\
@(or)@\
@(num e)@\
@(end)@\
@(end)
@(define decl (d))@\
@(local type id expr)@\
@(type type)@(id id)@\
@(maybe)=@(expr expr)@(or)@(bind expr nil)@(end)@\
@(bind d @(progn '(decl ,id ,type ,expr)))@\
@(end)
@(define decls (dl))@\
@(coll :gap 0)@(decl dl)@(end)@\
@(end)
@(freeform)
@(decls dl)