Как мне написать Nanoparse c парсеры? - PullRequest
2 голосов
/ 04 мая 2020

Я работаю через Стивена Дила * Пишу тебе Haskell, и я только что начал нанопарсетную часть c. Я понимаю, как синтаксические анализаторы могут использоваться для синтаксического анализа любого заданного ввода, но как мне составить их для анализа композитного ввода?

Задача c, которую я пытаюсь решить, состоит в том, как составить анализатор строк из список анализаторов символов. Пример в статье такой:

satisfy :: (Char -> Bool) -> Parser Char
satisfy p = item `bind` \c ->
  if p c
  then unit c
  else (Parser (\cs -> []))

char :: Char -> Parser Char
char c = satisfy (c ==)

string :: String -> Parser String
string [] = return []
string (c:cs) = do { char c; string cs; return (c:cs)}

Как эта строка возвращает строку?

string (c:cs) = do { char c; string cs; return (c:cs)}

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

string (c:cs) = do { char c; string cs; return (c:cs)}
string (c:cs) = do { char c; 
                 do { char c; 
                  do { char c; string cs; return (c:cs)}
                 return (c:cs)}
               return (c:cs)}

et c, et c. Как это на самом деле работает?

1 Ответ

2 голосов
/ 04 мая 2020

A char «потребляет» символ, если он совпадает. Так что, если мы используем char 'a', а следующий символ для разбора - это действительно 'a', мы «перемещаем курсор» на одну позицию дальше и возвращаем 'a'.

string, чтобы выполнить то же самое, но для списка Char с, поэтому [Char] или эквивалентного String. Он делает это, глядя на String. Если String пусто, то ничего не нужно делать, мы можем просто вернуть пустой список (String).

В случае, если строка содержит хотя бы один элемент, мы вызываем char c на сначала символе этой строки, а затем мы рекурсивно на хвосте строки, в конце концов мы возвращаем (c:cs) (строка, которую мы уже передали в качестве параметра функции string) , Мы не принимаем во внимание результат самого синтаксического анализатора, мы просто возвращаем заданную строку, , если парсер действительно соответствует строке.

Таким образом, это делается с помощью последовательность char вызывает, что каждая проверка действительно ли тот символ, который нам нужен, и если это так, мы продолжаем перемещать курсор и проверять следующий символ.

Если мы, таким образом, выполняем string "foo", это эквивалентно:

string "foo" = char 'f' >> char 'o' >> char 'o' >> return "foo"

Если, однако, в середине символ не совпадает, синтаксический анализатор не будет перемещать курсор назад. Поэтому следующий синтаксический анализ завершится неудачно:

Prelude Parsec Control.Applicative> Parsec.parse (Parsec.string "faa" <|> Parsec.string "foo") "" "foo"
Left (line 1, column 1):
unexpected "o"
expecting "faa"

Так как "faa" пробуется первым, и это уже будет соответствовать первому символу 'f', что означает, что курсор переместился, передал 'f'.

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