Text.Parsec many синтаксический анализатор не будет полностью анализировать пользовательский синтаксический анализатор

#parsing #haskell #eval

#синтаксический анализ #haskell #оценка

Вопрос:

У меня возникла проблема, из-за которой мой анализатор для блоков if (и блоков Do-While, потому что проблема одна и та же) не завершается при разборе строки «fi». If-блок принимает форму:

 if P -> p
[] Q -> q
fi
 

Если я использую Text.Parsec анализатор строк для синтаксического "fi" анализа, как я использовал его для синтаксического "if" анализа, чтобы даже войти в цикл, программа останавливается. Когда я распечатываю то, что должно быть оценено, его даже нет, поэтому программа даже не вводит If-блок, когда он заканчивается "fi" .

Однако, когда я удаляю синтаксический анализатор, который анализирует "fi" , происходит то, что программа может запускаться, и оценка If-блока выполняется так, как ожидалось, но я должен завершить блок тем же числом "fi" (или любой строкой), что и выражения внутри самого блока. Если я не завершу блок с тем же числом "fi" ‘s, произойдет любое утверждение после того, как блок будет оцениваться бесконечно. Например, блок, который добавляет единицу к текущему итогу, если переменная четная, будет выглядеть так:

 if ((x mod 2) = 0)-> r := r   1
[] ((x mod 2) = 1)-> r := r   0
fi
fi
 

И если бы был один "fi" , и я напечатал значение r после блока, оно печатало бы r бесконечно

 if ((x mod 2) = 0)-> r := r   1
[] ((x mod 2) = 1)-> r := r   0
fi

print(r)

./Main prog
1
1
1
1
1
...
 

Проблема, вероятно, в неправильном использовании spaces функции, но, похоже, я не могу правильно выполнить синтаксический анализ, даже когда я удаляю все экземпляры пробелов, чтобы все было в одной строке, объединенной вместе. Даже когда я это сделаю, он не будет принят "fi" в коде синтаксического анализатора, но он примет его, если это то же число, что и выражения при его удалении.

 parseIf :: Parser HStatement
parseIf = do
        try (string "if") <|> try (string "[]")
        spaces
        string "("
        cond  <- parseVals
        string ")->"
        spaces
        expr  <- many1 $ parseStatements
        spaces
        return $ If (cond, expr)


parseSelection :: Parser HStatement
parseSelection = do
        selection <- many1 parseIf
        spaces
        --try (string "fi")
        return $ Selection selection

parseStatements :: Parser HStatement
parseStatements = try (parseDo) <* spaces <|> try (parseSelection) <|> try (parsePrint) <|> try (parseEvalHVal)
 

Комментарии:

1. Это не рабочий пример, поэтому я не могу его протестировать, но мое первое предположение заключается в том, что что-то не работает с пробелами. В частности, когда вы выполняете синтаксический many $ try parseStatements анализ, не похоже, что вы заботитесь о пробелах между несколькими операторами.

2. Как говорит @DDub, parseStatements я бы проанализировал что-то вроде x := x 1 , но вы хотите проанализировать <many space>x := x 1 . Я думаю, что что-то в линии many $ try (optional spaces >> parseStatements) shoud работает.

3. Правильно, поэтому я изменил many $ try parseStatements many $ (spaces *> parseStatements <* spaces) и добавил spaces после каждой строки в каждом анализаторе, например, я добавил его перед x in parseArith , и поведение по-прежнему сохраняется

4. Поведение странное, потому что я пытался many $ try (optional spaces >> parseStatements) , и поведение осталось прежним, но дело в том, что я могу выполнять выражения, подобные x := x 1 in sequence, без цикла, без проблем

5. @JiangShi ты можешь попробовать без отступов внутри Do-Od ? просто чтобы проверить, не в этом ли проблема. Другое дело spaces , что не включено Text.Parsec , как это определяется?