2

为了使用 实现不区分大小写的中缀运算符OperatorPrecedenceParser,我正在预处理输入,将其解析为由字符串文字分隔的文本。然后在文本部分搜索需要大写的中缀运算符(以符合 已知的运算符OPP)。然后进行实际的解析。

我的问题是,这两个阶段可以组合成一个解析器吗?我试过

// preprocess: Parser<string,_>
// scalarExpr: Parser<ScalarExpr,_>
let filter = (preprocess .>> eof) >>. (scalarExpr .>> eof)

但它在输入结束时失败,似乎期待一个scalarExpr. 输入可以独立地解析preprocessscalarExpr所以我猜这是一个问题eof,但我似乎无法正确理解。这可能吗?

这是其他解析器供参考。

let stringLiteral = 
  let subString = manySatisfy ((<>) '"')
  let escapedQuote = stringReturn "\"\"" "\""
  (between (pstring "\"") (pstring "\"") (stringsSepBy subString escapedQuote)) 

let canonicalizeKeywords =
  let keywords = 
    [
      "OR"
      "AND"
      "CONTAINS"
      "STARTSWITH"
      "ENDSWITH"
    ]
  let caseInsensitiveKeywords = HashSet(keywords, StringComparer.InvariantCultureIgnoreCase)
  fun text ->
    let re = Regex(@"([\w][\w']*\w)")
    re.Replace(text, MatchEvaluator(fun m ->
      if caseInsensitiveKeywords.Contains(m.Value) then m.Value.ToUpperInvariant()
      else m.Value))

let preprocess = 
  stringsSepBy 
    ((manySatisfy ((<>) '"')) |>> canonicalizeKeywords) 
    (stringLiteral |>> (fun s -> "\"" + s + "\"")) 
4

1 回答 1

1

使用 FParsec 的OperatorPrecedenceParser解析不区分大小写的运算符的最简单方法是为要支持的每个大小写添加运算符定义。如果您只需要支持短运算符名称,例如“and”或“or”,您可以简单地添加所有可能的大小写组合。如果您想使用对于这种方法来说太长的运算符名称,您可能会考虑仅支持正常的大小写,即小写、大写、驼峰式和 PascalCase。当您想要支持多个套管时,通常可以方便地编写一个辅助函数,该函数会自动为您从标准套管生成所有需要的套管。

如果你有很长的操作符名字并且你真的想支持所有的大小写,那么OperatorPrecedenceParser的动态可配置性也允许使用以下方法,这应该比转换输入更容易和更有效:

  1. 在输入中搜索所有不区分大小写的受支持运算符。此搜索不应遗漏任何事件,但如果在函数名称或字符串文字中使用运算符名称等情况下发现误报,也没有问题。
  2. 将您在步骤 1 中找到的所有独特外壳添加到OperatorPrecedenceParser. (通常不会有很多同一个算子的套管。)
  3. 使用配置的OperatorPrecedenceParser.

当您解析多个输入时,您可以保留OperatorPrecedenceParser实例并在需要时懒惰地添加新的运算符外壳。

于 2013-05-15T18:04:09.290 回答