5

对于具有关键字的语言,需要发生一些特殊的技巧来防止例如“if”被解释为标识符,以及“ifSomeVariableName”在令牌流中成为关键字“if”后跟标识符“SomeVariableName”。

对于递归下降和 Lex/Yacc,我只是采用了在词法分析器和解析器之间转换令牌流的方法(根据有用的指令)。

但是,FParsec 似乎并没有真正做一个单独的词法分析器步骤,所以我想知道处理这个问题的最佳方法是什么。说到这里,Haskell 的 Parsec 似乎支持词法分析器层,但 FParsec 不支持?

4

2 回答 2

6

我想,这个问题很简单。答案是你必须:

  1. 解析出整个单词 ( [a-z]+),仅小写;
  2. 检查它是否属于字典;如果是,则返回一个keyword;否则,解析器将退回;
  3. 分别解析identifier

例如(只是一个假设的代码,未经测试):

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

上面的代码将解析关键字或标识符两次。要修复它,或者,您可以:

  1. 解析出整个单词 ( [a-z][A-Z]+[a-z][A-Z][0-9]+),例如所有字母数字;
  2. 检查它是关键字还是标识符(小写并属于字典),或者
    1. 返回一个关键字
    2. 返回一个标识符

PS不要忘记先订购“更便宜”的解析器,如果它不破坏逻辑的话。

于 2012-12-19T11:48:08.890 回答
0

您可以为空格定义解析器并检查关键字或标识符是否跟在它后面。例如,一些通用的空白解析器看起来像

let pWhiteSpace = pLineComment <|> pMultilineComment <|> pSpaces

这将需要至少一个空格

let ws1 = skipMany1 pWhiteSpace

那么如果看起来像

let pIf = pstring "if" .>> ws1
于 2012-04-11T05:09:53.943 回答