【问题标题】:Lua-Pattern - Evaluate conditional expressionLua-Pattern - 评估条件表达式
【发布时间】:2019-03-16 12:08:58
【问题描述】:

我要评估一个条件表达式字符串,我定义如下BNF:

X     ::= <value>    
COND  ::= X | X '==' X | '!{' COND '}' | '{' COND '&&' COND '}' | '{' COND '||' COND '}'

基于这个结构,我写了这个评估函数,返回一个布尔值:

-- Bedingung auswerten
  function eval(exp, valueTab, loopValue)
  -- !{COND} - Negierung
    if string.find(exp, '^!{(.+)}$') then
      return not eval(string.gsub(exp, '^!{(.+)}$', '%1'))
  -- {COND&&COND} - AND
    elseif string.find(exp, '^{(.+)&&(.+)}$') then
      return (eval(string.gsub(exp, '^{(.+)&&(.+)}$', '%1')) and eval(string.gsub(exp, '^{(.+)&&(.+)}$', '%2')))
  -- {COND||COND} - OR
    elseif string.find(exp, '^{(.+)||(.+)}$') then
      return (eval(string.gsub(exp, '^{(.+)||(.+)}$', '%1')) or eval(string.gsub(exp, '^{(.+)||(.+)}$', '%2')))
  -- X==X - Gleichheit -> true/false
    elseif string.find(exp, '^(.+)==(.+)$') then
      return (getValue(string.gsub(exp, '^(.+)==(.+)$', '%1'), valueTab, loopValue) == getValue(string.gsub(exp, '^(.+)==(.+)$', '%2'), valueTab, loopValue))
  -- X -> false wenn X nil/false auswertet ansonsten true
    else
      return (getValue(exp, valueTab, loopValue) and true or false)
    end
  end

但它不适用于某些嵌套条件,例如

exp = '{{1||boolean:false}&&{boolean:true&&!{boolean:false}}}'

第一个递归步骤将表达式拆分为

eval('{1||boolean:false}&&{boolean:true') and
eval('!{boolean:false}}'

知道如何检查“{”的数量是否等于“}”的数量?它应该像

那样拆分表达式
eval('{1||boolean:false}') and
eval('{boolean:true&&!{boolean:false}}')

希望您能理解我的问题,如果您还有其他问题,请告诉我。 如果你有更好的主意,我也愿意改变我的语法。但应支持否定、AND- 和 OR-从句。

【问题讨论】:

  • 解析表达式需要合适的解析器。但是尝试模式%b{},它匹配平衡{}
  • '^{(!?%b{})&amp;&amp;(!?%b{})}$' 看起来不错,但我没有获取值。知道如何在不编辑 BNF 语法的情况下获得它们吗? (例如'!'? '{' X }''!'? '{'X '==' X'}'
  • 无论如何,感谢您的提示。我会发布解决方案。

标签: lua lua-patterns


【解决方案1】:

解决方案

解析表达式需要合适的解析器。但是尝试模式%b{},它匹配平衡{}

我是这样做的:

  1. 编辑 BNF

    COND  ::= '{' (X|X '==' X|COND '&&' COND|COND '||' COND) '}'|'!' COND
    
  2. 编辑图案

    -- Bedingung auswerten
      function eval(exp, valueTab, loopValue)
      -- !{COND} - Negierung
        if string.find(exp, '^!(%b{})$') then
          return not eval(string.gsub(exp, '^!(%b{})$', '%1'))
      -- {COND&&COND} - AND
        elseif string.find(exp, '^{(!?%b{})&&(!?%b{})}$') then
          return (eval(string.gsub(exp, '^{(!?%b{})&&(!?%b{})}$', '%1')) and eval(string.gsub(exp, '^{(!?%b{})&&(!?%b{})}$', '%2')))
      -- {COND||COND} - OR
        elseif string.find(exp, '^{(!?%b{})||(!?%b{})}$') then
          return (eval(string.gsub(exp, '^{(!?%b{})||(!?%b{})}$', '%1')) or eval(string.gsub(exp, '^{(!?%b{})||(!?%b{})}$', '%2')))
      -- X==X - Gleichheit -> true/false
        elseif string.find(exp, '^{(.+)==(.+)}$') then
          return (getValue(string.gsub(exp, '^{(.+)==(.+)}$', '%1'), valueTab, loopValue) == getValue(string.gsub(exp, '^{(.+)==(.+)}$', '%2'), valueTab, loopValue))
      -- X -> false wenn X nil/false auswertet ansonsten true
        elseif string.find(exp, '^{(.+)}$') then
          return (getValue(string.gsub(exp, '^{(.+)}$', '%1'), valueTab, loopValue) and true or false)
        else
          print('wrong syntax')
          return
        end
      end
    

【讨论】:

    【解决方案2】:

    语法非常简单,LPEG 基本上可以让您几乎逐字复制语法,加上一些语义动作,它就可以工作了™。

    如果你想了解更多关于 LPEG 和解析表达式语法的知识,我推荐这个教程:http://leafo.net/guides/parsing-expression-grammars.html

    local lpeg = require"lpeg"
    local P, V = lpeg.P, lpeg.V
    
    local True = function() return true end
    local False = function() return false end
    local Not = function(a) return not a end
    local Eq = function(a,b) return a == b end
    local And = function(a,b) return a and b end
    local Or = function(a,b) return a or b end
    
    local grammar = P{
        "cond",
        cond = (V"x")
             + (V"x" * "==" * V"x") / Eq
             + (P"!{" * V"cond" * P"}") / Not
             + (P"{" * V"cond" * P"&&" * V"cond" * P"}") / And
             + (P"{" * V"cond" * P"||" * V"cond" * P"}") / Or,
        x = P"1" / True
          + P"0" / False
          + P"boolean:true" / True
          + P"boolean:false" / False
    }
    
    local eval = function(exp)
        return grammar:match(exp)
    end
    
    print(eval('{{1||boolean:false}&&{boolean:true&&!{boolean:false}}}'))
    

    【讨论】:

      猜你喜欢
      • 2015-02-22
      • 2010-11-12
      • 2023-01-12
      • 1970-01-01
      • 1970-01-01
      • 2020-11-24
      • 2013-12-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多