PEG.JS解析逻辑变量名称,其操作数和值

PEG.JS parsing logical variable names, its operand and value

本文关键字:操作数 变量名 JS PEG      更新时间:2023-09-26

在试图让它工作数小时后感到非常头疼。我正在使用 PEG.js解析来将输入查询解析为数组。现在我正在尽力使用这个克默。操作数和连接器是静态的,由应用生成。

start = start:(statement)
statement = statement:block_statement* { return statement; }
block_statement = OPENPAREN block:block+ CLOSEPAREN connector:CONNECTOR block2:(block_statement+ / block+) { return [block, block2]; }
                / OPENPAREN block:block+ CLOSEPAREN connector:CONNECTOR* !(block_statement / block) { return block; }
                / block:block
block = control:atom operand:OPERAND atom:atom connector:CONNECTOR* { return { control: control, operand: operand, value: atom, connector: connector[0] || false }; }
atom = _ QUOTE "#"*atom:(word)* QUOTE _ { return atom.toString(); }
OPERAND     = _ operand:("=" / "in") _      { return operand.toString(); }
CONNECTOR   = _ connector:("or" / "and") _  { return connector.toString(); }
word = w:char+ { return w.join(""); }
char = c:[^'r'n't'"]
OPENPAREN = _ '(' _
CLOSEPAREN = _ ')' _
QUOTE = _ quote:("'"" / """ / "'xA0") _
_ = [ 'r'n't]*

假设我有以下输入:

"#CTL 1" = "VAL 1" or "#CTL 2" = "VAL 2"

这被解析为 - 检查/工作。

[
  {
      "control": "CTL 1",
      "operand": "=",
      "value": "VAL 1",
      "connector": "or"
  },
  {
      "control": "CTL 2",
      "operand": "=",
      "value": "VAL 2",
      "connector": false
  }

]

这个应该导致相同的输出数组 - 检查/工作。

("#CTL 1" = "VAL 1" or "#CTL 2" = "VAL 2")

这个半途而废:

("#CTL 1" = "VAL 1" or "#CTL 2" = "VAL 2") and "#CTL 3" = "VAL 3"

输出如下所示:

[
   [
      [
         {
            "control": "CTL 1",
            "operand": "=",
            "value": "VAL 1",
            "connector": "or"
         },
         {
            "control": "CTL 2",
            "operand": "=",
            "value": "VAL 2",
            "connector": false
         }
      ],
      [
         {
            "control": "CTL 3",
            "operand": "=",
            "value": "VAL 3",
            "connector": false
         }
      ]
   ]
]

CTL 2 上的连接器应为"AND"。所以需要有某种展望(我猜)。与此相同:

("#CTL 1" = "VAL 1" or "#CTL 2" = "VAL 2") and ("#CTL 3" = "VAL 3" or "#CTL 4" = "VAL 4")

真正复杂的东西开始了,wenn将不同的关卡相互混合:

("#CTL 1" = "VAL 1" or ("#CTL 2" = "VAL 2" and "#CTL 3" = "VAL 3")) or ("#CTL 4" = "VAL 4" or "#CTL 5" = "VAL 5")

这根本行不通。我能找到的所有例子都是左关联或右关联。我认为两者都不是完全需要的。

您对如何解决此问题有线索吗?

我刚刚想通了。希望它对某人有所帮助:

{
  function findFirstLeftStatement(arr) {
    if ( Array.isArray(arr) ) {
      return findFirstLeftStatement(arr[0]["left"]);
    } else if ( typeof arr === "object" ) {
        return arr;
    }
  }
  function inject(arr, connector) {
    findFirstLeftStatement(arr)["connector"] = connector;
    return arr;
  }
}
Start
  = Statement*
Statement
  = left:Block connector:Connector right:Statement 
    { return { left: left, right: inject(right, connector) }; }
  / left: Block 
    { return left; }
Block
  = pOpen block:Statement* pClose
    { return block; }
  / block:Assignment
    { return block; }
Assignment
  = control:ControlAtom operand:Operand value:ValueAtom
    { return { control: control, operand: operand, value: value }; }
ControlAtom
  = _ Quote "#"atom:(Word)* Quote _ 
    { return atom.toString(); }
ValueAtom 
  = _ Quote atom:(Word)* Quote _ 
    { return atom.toString(); }
Operand
  = _ operand:("=" / "in") _
    { return operand.toString(); }
Connector
    = _ connector:("or" / "and") _
      { return connector.toString(); }
Word
  = w:Character+ { return w.join(""); }
Character 
  = c:[^'r'n't'"]
pOpen
  = _ '(' _
pClose
  = _ ')' _
Quote 
  = _ quote:("'"" / """ / "'xA0") _
_
  = [ 'r'n't]*