Цель reservedOp
- создать парсер (который вы назвали m_reservedOp
), который анализирует заданную строку символов оператора, при этом гарантируя, что это , а не префикс более длинной строки операторских символов. Это можно увидеть из определения reservedOp
в источнике:
reservedOp name =
lexeme $ try $
do{ _ <- string name
; notFollowedBy (opLetter languageDef) <?> ("end of " ++ show name)
}
Обратите внимание, что поставляемый name
анализируется, только если за ним не следуют никакие символы opLetter
.
В вашем случае строка "--2"
не может быть проанализирована с помощью m_reservedOp "-"
, потому что, даже если она начинается с действительного оператора "-"
, эта строка встречается как префикс более длинного действительного оператора "--"
.
В языке с односимвольными операторами вы, вероятно, вообще не хотите использовать reservedOp
, если только вы не хотите запретить смежные операторы без пробелов. Просто используйте symbol "-"
, который всегда будет анализировать "-"
, независимо от того, что следует (и использовать следующие пробелы, если они есть). Кроме того, на языке с фиксированным набором операторов (т. Е. Без пользовательских операторов) вы, вероятно, не будете использовать синтаксический анализатор operator
, поэтому вам не понадобится opStart
или reservedOpNames
. Без reservedOp
или operator
синтаксический анализатор opLetter
не используется, так что вы также можете его удалить.
Это, вероятно, довольно запутанно, а документация Parsec
объясняет ужасную работу как должен работать «зарезервированный» механизм. Вот пример:
Давайте начнем с идентификаторов, а не операторов. В типичном языке, который допускает определяемые пользователем идентификаторы (т. Е. Практически любой язык, поскольку «переменные» и «функции» имеют определяемые пользователем имена), а также может иметь некоторые зарезервированные слова, которые не допускаются в качестве идентификаторов, соответствующие настройки в GenLanguageDef
входят:
identStart -- parser for first character of valid identifier
identLetter -- second and following characters of valid identifier
reservedNames -- list of reserved names not allowed as identifiers
Лексемы (поглощающие пробелы), созданные с использованием объекта GenTokenParser
:
identifier
- анализирует неизвестное, определяемый пользователем идентификатор. Он анализирует символ от identStart
с последующим нулем или более identLetter
с до первого не identLetter
. (Он никогда не анализирует частичный идентификатор, поэтому он никогда не оставит больше identLetter
s в таблице.) Кроме того, он проверяет, что идентификатора нет в списке reservedNames
. symbol
- Разбирает заданную строку. Если строка является зарезервированным словом, не выполняется проверка того, что она не является частью большего допустимого идентификатора. Таким образом, symbol "for"
будет соответствовать началу foreground = "black"
, что редко является тем, что вы хотите. Обратите внимание, что symbol
не использует identStart
, identLetter
или reservedNames
. reserved
- анализирует данную строку, а затем гарантирует, что за ней не следует identLetter
. Итак, m_reserved "for"
будет анализировать for (i=1; ...
, но не анализировать foreground = "black"
. Обычно предоставленная строка будет допустимым идентификатором, но проверка не выполняется, поэтому вы можете написать m_reserved "15"
, если хотите - на языке с обычными типами идентификаторов alphanumeri c, это будет анализировать "15"
при условии, что за ним не следует ни письмо, ни другое git. Также, что может быть несколько удивительно, не выполняется проверка того, что поставляемая строка находится в reservedNames
.
Если это имеет смысл для вас, тогда настройки оператора следуют точно такой же схеме. Соответствующие настройки:
opStart -- parser for first character of valid operator
opLetter -- valid second and following operator chars, for multichar operators
reservedOpNames -- list of reserved operator names not allowed as user-defined operators
и соответствующие анализаторы:
operator
- анализирует неизвестный пользовательский оператор, начинающийся с opStart
и сопровождаемый ноль или более opLetter
с до первого не opLetter
. Таким образом, operator
, примененный к строке "--2"
, всегда будет принимать весь оператор "--"
, а не только префикс "-"
. Дополнительная проверка выполняется, что результирующий оператор не в списке reservedOpNames
. symbol
- точно так же, как для идентификаторов. Он анализирует строку без проверок или ссылок на opStart
, opLetter
или reservedOpNames
, поэтому symbol "-"
будет анализировать первый символ строки "--"
очень хорошо, оставляя второй символ "-"
для позже парсер. reservedOp
- анализирует данную строку, следя за тем, чтобы за ней не следовал opLetter
. Таким образом, m_reservedOp "-"
будет анализировать начало "-x"
, но не "--2"
, предполагая, что -
соответствует opLetter
. Как и прежде, не выполняется проверка того, что строка находится в reservedOpNames
.