F# FParsec标识符与关键字
对于具有关键字的语言,需要进行一些特殊的欺骗,以防止例如“if”被解释为标识符,“ifSomeVariableName”在令牌流中变成关键字“if”,后跟标识符“SomeVariableName” 对于递归下降和Lex/Yacc,我只是采用了在lexer和解析器之间转换令牌流的方法(根据有用的指令)F# FParsec标识符与关键字,f#,parser-combinators,fparsec,F#,Parser Combinators,Fparsec,对于具有关键字的语言,需要进行一些特殊的欺骗,以防止例如“if”被解释为标识符,“ifSomeVariableName”在令牌流中变成关键字“if”,后跟标识符“SomeVariableName” 对于递归下降和Lex/Yacc,我只是采用了在lexer和解析器之间转换令牌流的方法(根据有用的指令) 然而,FParsec似乎并没有真正做一个单独的lexer步骤,所以我想知道处理这个问题的最佳方法是什么。说到这里,Haskell的Parsec似乎支持lexer层,但FParsec不支持?您可以为空
然而,FParsec似乎并没有真正做一个单独的lexer步骤,所以我想知道处理这个问题的最佳方法是什么。说到这里,Haskell的Parsec似乎支持lexer层,但FParsec不支持?您可以为空白定义一个解析器,并检查它后面是否跟有关键字或标识符。 例如,一些通用的空白解析器如下所示
let pWhiteSpace = pLineComment <|> pMultilineComment <|> pSpaces
let pIf = pstring "if" .>> ws1
那么如果你看起来像
let pWhiteSpace = pLineComment <|> pMultilineComment <|> pSpaces
let pIf = pstring "if" .>> ws1
我觉得这个问题很简单。答案是你必须:
[a-z]+
),仅小写李>
关键字
;否则,解析器将后退李>
标识符
李>
例如(只是一个假设代码,未经测试):
let关键字集=
System.Collections.Generic.HashSet(
[|“while”;“begin”;“end”;“do”;“if”;“then”;“else”;“print”|]
)
让我来说说=
(多数情况下为非对数)/[a-z]+
>>=(乐趣->如果关键字集.Contains,则(预返回x)否则失败“不是关键字”)
让P内容=
pLineComment pOperator PNUMAL pKeyword pIdentifier
上面的代码将解析关键字或标识符两次。要解决此问题,您也可以:
[a-z][a-z]+[a-z][a-z][0-9]+
),例如所有字母数字李>
另外,如果不会破坏逻辑,请不要忘记先订购“更便宜”的解析器。“如果”(“不会以这种方式匹配。我喜欢你的第二个进程。它基本上与lexer后处理器技巧相同,但只是内联。20/20后见之明,这是最明显的解决方案:)。谢谢上面答案中的
pKeyword
的定义让我困惑。我的类型推断表明它是一个解析器
,它不是(IMHO)你想要的-你想要返回一个解析器
,或者一个包含在回复
类型中的失败,我看不出如何使用|>
操作符来实现这一点,谢谢你指出这一点。我已经更新了守卫规则。根据域的具体情况,可能还需要将解析器包装到trunt
中。希望这有帮助。