Lua-Pattern - оценка условного выражения - PullRequest
0 голосов
/ 11 октября 2018

Я хочу оценить строку условного выражения, я определил следующее 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-предложения должны поддерживаться.

Ответы [ 2 ]

0 голосов
/ 12 октября 2018

Грамматика довольно проста, а 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}}}'))
0 голосов
/ 11 октября 2018

Решение

Для синтаксического анализа выражений требуется правильный синтаксический анализатор.Но попробуйте шаблон %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
    
...