对于带有关键字的语言,需要一些特殊的技巧来防止例如“if”被解释为标识符而“ifSomeVariableName”变成关键字“if”后跟标识符流中的标识符“SomeVariableName”。
对于递归下降和Lex / Yacc,我只是采用了在词法分析器和解析器之间转换令牌流的方法(根据有用的指示)。
然而,FParsec似乎并没有真正做一个单独的词法分析器步骤,所以我想知道处理这个问题的最佳方法是什么。说到,似乎Haskell的Parsec支持lexer层,但FParsec不支持?
答案 0 :(得分:5)
我认为,这个问题非常简单。答案是你必须:
[a-z]+
),仅限小写; keyword
;否则,解析器将退回; identifier
; E.g。 (只是一个假设的代码,没有经过测试):
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
上面的代码将解析关键字或标识符两次。或者,要修复它,您可以:
[a-z][A-Z]+[a-z][A-Z][0-9]+
),例如一切字母数字; P.S。如果它不破坏逻辑,不要忘记首先订购“更便宜”的解析器。
答案 1 :(得分:0)
您可以为空格定义解析器,并检查是否后跟关键字或标识符。 例如,一些通用的空白解析器看起来像
let pWhiteSpace = pLineComment <|> pMultilineComment <|> pSpaces
这将需要至少一个空格
let ws1 = skipMany1 pWhiteSpace
然后如果看起来像
let pIf = pstring "if" .>> ws1