Неоднозначность грамматики: почему?(проблема: "(а)" против "(аз)") - PullRequest
5 голосов
/ 28 июня 2011

Итак, я пытаюсь реализовать довольно простую грамматику для однострочных операторов:

# 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»

Я думаю, что двусмысленность заключается в этих двух строках:

  | 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 "(a-z)"

Лексер дал бы следующее для двух случаев:

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

Я не понимаю, как это может быть неоднозначно с анализатором LL [2].

Если это поможет, вот полное определение грамматики Happy:

{

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"

}

Спасибо!

Ответы [ 2 ]

4 голосов
/ 28 июня 2011

Вот двусмысленность:

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

listitems : char
          | [...]

Ваш анализатор может принять (v) как TString [TVowel], так и TString [TList ['v']], не говоря уже о пропущенных символах в этом выражении case.

Один из возможных способов решения этой проблемы - изменить грамматику так, чтобы списки представляли собой как минимум два элемента или имели разные обозначения для гласных, согласных и т. Д.

3 голосов
/ 28 июня 2011

Кажется, проблема в следующем:

| lBracket char rBracket
...
| lBracket listitems rBracket

или в более чистом синтаксисе:

(c)

Может быть TVowel, TConsonant, TLetter, TNumber (как вы знаете) или синглтонTList.

Как говорится в счастливом руководстве, уменьшение смены обычно не является проблемой.Вы можете использовать приоритет для принудительного поведения / удаления предупреждения, если хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...