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

时间:2014-12-01 23:14:53

标签: javascript boolean-logic peg

经过几个小时试图让它发挥作用后,头痛得厉害。 我正在使用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")

真正复杂的东西开始了,混合不同的水平:

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

这根本不起作用。 我能找到的所有例子都是左或右关联的。 我认为两者都没有完全被要求。

您是否知道如何解决此问题?

1 个答案:

答案 0 :(得分:0)

我只是想通了。希望它可以帮助某人:

{
  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]*