问题
For languages with keywords, some special trickery needs to happen to prevent for example "if" from being interpreted as an identifier and "ifSomeVariableName" from becoming keyword "if" followed by identifier "SomeVariableName" in the token stream.
For recursive descent and Lex/Yacc, I've simply taken the approach (as per helpful instruction) of transforming the token stream between the lexer and the parser.
However, FParsec doesn't really seem do a separate lexer step, so I'm wondering what the best way to deal with this is. Speaking of, it seems like Haskell's Parsec supports a lexer layer, but FParsec does not?
回答1:
I think, this problem is very simple. The answer is that you have to:
- Parse out an entire word (
[a-z]+
), lower case only; - Check if it belongs to a dictionary; if so, return a
keyword
; otherwise, the parser will fall back; - Parse
identifier
separately;
E.g. (just a hypothetical code, not tested):
let keyWordSet =
System.Collections.Generic.HashSet<_>(
[|"while"; "begin"; "end"; "do"; "if"; "then"; "else"; "print"|]
)
let pKeyword =
(many1Satisfy isLower .>> nonAlphaNumeric) // [a-z]+
>>= (fun s -> if keyWordSet.Contains(s) then (preturn x) else fail "not a keyword")
let pContent =
pLineComment <|> pOperator <|> pNumeral <|> pKeyword <|> pIdentifier
The code above will parse a keyword or an identifier twice. To fix it, alternatively, you may:
- Parse out an entire word (
[a-z][A-Z]+[a-z][A-Z][0-9]+
), e.g. everything alphanumeric; - Check if it's a keyword or an identifier (lower case and belonging to a dictionary) and either
- Return a keyword
- Return an identifier
P.S. Don't forget to order "cheaper" parsers first, if it does not ruin the logic.
回答2:
You can define a parser for whitespace and check if keyword or identifier is followed by it. For example some generic whitespace parser will look like
let pWhiteSpace = pLineComment <|> pMultilineComment <|> pSpaces
this will require at least one whitespace
let ws1 = skipMany1 pWhiteSpace
then if will look like
let pIf = pstring "if" .>> ws1
来源:https://stackoverflow.com/questions/9763942/fparsec-identifiers-vs-keywords