2017-06-11 2 views
0

Im Verlauf für nach dem Tutorial Write yourself a Scheme in 48 hours, ich versuche, meinen Parsing-Code zu verbessern Unterstützung für hexadezimal, oktal, binär und dezimal Literale zu erstellen.Designing Parsing Code Parsec

import Text.ParserCombinators.Parsec hiding (spaces) 
import Control.Monad 
import Numeric 

hexChar :: Parser Char 
hexChar = ... 

octChar :: Parser Char 
octChar = ... 

hexNumber :: Parser Integer 
hexNumber = do 
    char '#' 
    char 'x' 
    s <- many1 hexChar 
    return $ (fst . head) readHex s 


octNumber :: Parser Integer 
octNumber = do 
    char '#' 
    char 'o' 
    s <- many1 hexChar 
    return $ (fst . head) readOct s 

Wenn wir in dieser Diskussion über Dezimal- und Binärzahlen vergessen:

parseNumber :: Parse Integer 
parseNumber = hexNumber <|> octNumber 

Dann wird dieser Parser nicht Oktalzahlen erkennen. Dies scheint die Anzahl der Look-Ahead-Zeichen bezogen werden erforderlich auseinander und Oktal von hexadezimalen Zahlen sagen (wenn wir das führende ‚#‘ in der Syntax fallen, dann wird der Parser funktioniert). Daher scheint es, wir den Code und ‚factorize‘ die führenden ‚#‘ sozusagen gezwungen sind, zu überdenken, indem die char '#' in den einzelnen Parser fallen und definieren:

parseNumber = char '#' >> (hexNumber <|> octNumber) 

Das ist in Ordnung, aber ich finde den Code weniger angenehm. Irgendwie, wenn ich eine Funktion namens haben hexNumber Ich würde erwarten, dass es #xffff zu erkennen (die Syntax richtige Schema ist) und nicht xffff. Ist das etwas, mit dem ich leben muss, oder gibt es Möglichkeiten, diese "erzwungene Faktorisierung" der Hauptfigur # zu umgehen?

Antwort

1

Wenn das erste Argument von (<|>) fehlschlägt, nachdem eine Eingabe verbraucht hat, dann schlägt es sofort, ohne die zweite Alternative zu versuchen. Wenn ein Fehler im ersten Argument zu einem erneuten Versuch mit dem zweiten Argument führen sollte, können Sie try verwenden, um Eingaben zu vermeiden. In hexNumber müssen Sie '#' nur verbrauchen, wenn das folgende Zeichen 'x' entspricht.

hexNumber :: Parser Integer 
hexNumber = do 
    try $ char '#' >> char 'x' 
    s <- many1 hexChar 
    return $ (fst . head) readHex s 


octNumber :: Parser Integer 
octNumber = do 
    try $ char '#' >> char 'o' 
    s <- many1 hexChar 
    return $ (fst . head) readOct s 

Beachten Sie, dass dies etwas ist ineffizient, da Sie '#' zweimal analysieren, und es wird noch schlimmer als das gemeinsame Präfix länger und komplexer wird.

+0

Das ist großartig vielen Dank! –