0

これとシフト削減の問題を理解するのに苦労しています。

';' の追加 言語を変更できないため、最後まで問題を解決できません。次の例のようにする必要があります。先行オペランドは機能しますか?

例は次のとおりです。

変数は次のように宣言できます: ポインターとして、または整数として int として、したがって、これは両方とも有効です:

<int> a = 0
int a = 1

コードは次のとおりです。

%left '<'

declaration: variable
           | declaration variable

variable : type tNAME '=' expr
         | type tNAME

type : '<' type '>'
     | tINT

expr : tINTEGER
     | expr '<' expr

それは明らかに式の後にシフト/リデュースの問題を引き起こします。「less」演算子のexprにシフトするか、別の変数宣言にreduceできるためです。

変数宣言に優先順位を付けたいのですが、%nonassoc prec_aux を作成して '<' type '>' %prec prec_aux と type tNAME の後に配置しようとしましたが、問題は解決しません:S

どうすればこれを解決できますか?

出力は次のとおりです。

返信時に改行とコードを投稿する方法を理解することはできません...だから、ここに出力があります:

35: shift/reduce conflict (shift 47, reduce 7) on '<'
state 35
    variable : type tNAME '=' expr .  (7)
    expr : expr . '+' expr  (26)
    expr : expr . '-' expr  (27)
    expr : expr . '*' expr  (28)
    expr : expr . '/' expr  (29)
    expr : expr . '%' expr  (30)
    expr : expr . '<' expr  (31)
    expr : expr . '>' expr  (32)

    '>'  shift 46
    '<'  shift 47
    '+'  shift 48
    '-'  shift 49
    '*'  shift 50
    '/'  shift 51
    '%'  shift 52
    $end  reduce 7
    tINT  reduce 7

それが出力であり、エラーは私が言及したもののようです。


実際にはオプションではない言語に新しい端末を追加する以外に、別の解決策を知っている人はいますか?

解決策は、文法を書き直して、何らかの方法で先読みして、「<」の後の型または式であるかどうかを確認できるようにすることだと思いますが、方法がわかりません。

同じキャラクターなので、優先順位が機能する可能性は低いです。定義した型を優先する方法はありますか? 宣言など?

前もって感謝します

4

3 に答える 3

2

あなたの文法は、次のようなテキストで混乱します。

int a = b
<int> c

2 行目の「<」は、最初の宣言の式の一部である可能性があります。それを見つけるには、さらに先を見据える必要があります。

これが、ほとんどの言語にステートメント ターミネータがある理由です。これにより競合は発生しません。

%%

%token tNAME;
%token tINT;
%token tINTEGER;
%token tTERM;

%left '<';

declaration: variable
           | declaration variable

variable : type tNAME '=' expr tTERM
         | type tNAME tTERM

type : '<' type '>'
     | tINT

expr : tINTEGER
     | expr '<' expr

パーサーを作成するときに、起こりうる競合を排除するために文法を設計する方法を知っておくと役立ちます。そのためには、パーサーがどのように機能するかを理解する必要がありますが、これはこの回答の範囲外です:)

于 2012-04-16T19:05:43.740 に答える
1

ここでの基本的な問題は、yacc/bison で取得する 1 つのトークンよりも多くの先読みが必要なことです。パーサーが a を見たとき、<それが前の宣言で完了し、角かっこで囲まれた型の先頭を見ているのかどうか、またはこれがより小演算子であるかどうかを判断する方法がありません。ここでできる基本的なことは 2 つあります。

  • bison の%glr-parserオプションやbtyaccなど、非 LR(1) 文法を処理できる解析方法を使用します。

  • lexer を使用して追加の先読みを行い、曖昧さを解消するトークンを返す

後者の場合、レクサーは「<」の後に追加の先読みを行い、その後に型のように見える何かが続く場合は別のトークンを返します。最も簡単な方法は、flex の/先読み演算子を使用することです。例えば:

"<"/[ \t\n\r]*"<"    return OPEN_ANGLE;
"<"/[ \t\n\r]*"int"  return OPEN_ANGLE;
"<"                  return '<';

OPEN_ANGLE次に、 bison ルールを変更して、 の代わりに型を期待するようにし<ます。

type : OPEN_ANGLE type '>'
     | tINT

expr : tINTEGER
     | expr '<' expr

より複雑な問題については、フレックス開始状態を使用するか、レクサーとパーサーの間にトークン フィルター/変換パス全体を挿入することもできます。

于 2012-04-17T22:48:01.203 に答える
0

これが修正ですが、完全に満足できるものではありません。

%{
%}

%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) 

より強力な解析方法またはハックなしでは、これを修正する方法はありません。

%nonassocbeforeを移動して、%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)
于 2012-04-17T21:52:11.800 に答える