Если вы имеете в виду identifier
от Text.Parsec.Token
, я не думаю, что это будет легко. identifier
определяется с помощью lexeme
:
identifier =
lexeme $ try $
do{ name <- ident
; if (isReservedName name)
then unexpected ("reserved word " ++ show name)
else return name
}
и lexeme
потребляют пропуска:
lexeme p
= do{ x <- p; whiteSpace; return x }
что означает, к тому времени, вы получите результат от identifier
, конечного положения идентификатора теряется.
Я не думаю, что есть изящное решение. Уродливым является копирование определения makeTokenParser
от Text.Parsec.Token
и изменение его определения lexeme
так, чтобы оно не пропускало пробелы. Тогда вы можете иметь это:
myMakeTokenParser :: (Stream s m Char)
=> GenLanguageDef s u m -> GenTokenParser s u m
myMakeTokenParser languageDef
= TokenParser{ identifier = identifier
, reserved = reserved
...
lexeme p = p
...
}
lexer = myMakeTokenParser haskellDef
identifier' = identifier lexer
test = do
start <- getPosition
result <- identifier'
end <- getPosition
return (result, (start, end))
main = parseTest test "abc def "
> :main
("abc",((line 1, column 1),(line 1, column 4)))
Конечно, теперь вы должны быть осторожны, потому что парсеры не будет пропускать пробелы больше. Альтернативой было бы сделать lexeme
запись положения конца внутреннего синтаксического анализатора (например, identifier
) как часть «пользовательского состояния», а затем пропустить пробелы, как обычно. Затем вы можете получить конечную позицию из пользовательского состояния.
Разве это не просто «начало» плюс длина «результата»? –
Ну, в данном случае, да. Но в более сложных случаях (многострочные строки или определения функций) сложнее вычислить конечную позицию. – antoyo