5

そのため、1 行のステートメントに対して非常に単純な文法を実装しようとしています。

# Grammar

   c         : Character c        [a-z0-9-]
  (v)        : Vowel              (= [a,e,u,i,o])
  (c)        : Consonant
  (?)        : Any character (incl. number)
  (l)        : Any alpha char     (= [a-z])
  (n)        : Any integer        (= [0-9])
  (c1-c2)    : Range from char c1 to char c2
  (c1,c2,c3) : List including chars c1, c2 and c3

  Examples:
  h(v)(c)no(l)(l)jj-k(n)
  h(v)(c)no(l)(l)(a)(a)(n)
  h(e-g)allo
  h(e,f,g)allo
  h(x,y,z)uul
  h(x,y,z)(x,y,z)(x,y,z)(x,y,z)uul

Happy パーサー ジェネレーター (http://www.haskell.org/happy/) を使用していますが、何らかの理由であいまいな問題があるようです。

エラーメッセージは次のとおりです。「シフト/競合の削減: 1」

あいまいさは次の 2 行にあると思います。

  | lBracket char rBracket              { (\c -> case c of
                                                 'v' -> TVowel
                                                 'c' -> TConsonant
                                                 'l' -> TLetter
                                                 'n' -> TNumber) $2 }
  | lBracket char hyphen char rBracket  { TRange $2 $4              }

例: "(a)" vs "(az)"

lexer は、2 つのケースに対して次のようになります。

(a)   : [CLBracket, CChar 'a', CRBracket]
(a-z) : [CLBracket, CChar 'a', CHyphen, CChar 'z', CRBracket]

私が理解していないのは、これが LL[2] パーサーでどのように曖昧になるかということです。

ここで役立つ場合は、ハッピー文法の定義全体を次に示します。

{

module XHappyParser where

import Data.Char
import Prelude   hiding (lex)
import XLexer
import XString

}

%name parse
%tokentype { Character  }
%error     { parseError }

%token
    lBracket                  { CLBracket   }
    rBracket                  { CRBracket   }
    hyphen                    { CHyphen     }
    question                  { CQuestion   }
    comma                     { CComma      }
    char                      { CChar $$    }

%%

xstring : tokens                            { XString (reverse $1)       }

tokens : token                              { [$1]                       }
       | tokens token                       { $2 : $1                    }

token : char                                { TLiteral $1                }
      | hyphen                              { TLiteral '-'               }
      | lBracket char rBracket              { (\c -> case c of
                                                     'v' -> TVowel
                                                     'c' -> TConsonant
                                                     'l' -> TLetter
                                                     'n' -> TNumber) $2 }
      | lBracket question rBracket          { TAny                      }
      | lBracket char hyphen char rBracket  { TRange $2 $4              }
      | lBracket listitems rBracket         { TList $2                  }

listitems : char                            { [$1]                      }
          | listitems comma char            { $1 ++ [$3]                }

{

parseError :: [Character] -> a
parseError _ = error "parse error"

}

ありがとうございました!

4

2 に答える 2

4

あいまいさは次のとおりです。

token : [...]
      | lBracket char rBracket
      | [...] 
      | lBracket listitems rBracket

listitems : char
          | [...]

パーサーは、式に欠落している文字は言うまでもなく、との(v)両方として受け入れることができます。TString [TVowel]TString [TList ['v']]case

それを解決する1つの可能な方法は、リストが少なくとも2つの項目になるように文法を変更するか、母音、子音などの表記法を変えることです.

于 2011-06-27T22:31:14.440 に答える
3

問題は次のようです。

| lBracket char rBracket
...
| lBracket listitems rBracket

またはよりクリーンな構文で:

(c)

TVowel、TConsonant、TLetter、TNumber (ご存じのとおり)、またはシングルトン TList のいずれかです。

幸せなマニュアルが言うように、通常、シフトを減らすことは問題ではありません。必要に応じて、優先順位を付けて動作を強制したり、警告を削除したりできます。

于 2011-06-27T22:30:05.257 に答える