2016-01-10 2 views
2

Я хотел бы получить конечную позицию маркера во время разбора с Parsec.Получить конечную позицию с помощью Parsec

Например, если я использую identifier комбинатор следующим образом:

test = do 
    start <- getPosition 
    result <- identifier 
    end <- getPosition 

end не будет указывать на конец идентификатора. Он будет указывать на следующий токен (пробелы пробела).

Я мог бы написать свой собственный комбинатор identifier, чтобы получить конечную позицию перед пропуском пробелов, но мне интересно, есть ли что-то уже в этом случае в Parsec.

Есть ли способ получить конечную позицию комбинатора с Parsec?

+0

Разве это не просто «начало» плюс длина «результата»? –

+0

Ну, в данном случае, да. Но в более сложных случаях (многострочные строки или определения функций) сложнее вычислить конечную позицию. – antoyo

ответ

1

Если вы имеете в виду 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) как часть «пользовательского состояния», а затем пропустить пробелы, как обычно. Затем вы можете получить конечную позицию из пользовательского состояния.

Смежные вопросы