繁体   English   中英

具有PEG.js的访问控制字符串(ACS)解析器/解释器

[英]Access Control String (ACS) Parser/Interpreter with PEG.js

前言

我正在努力创建一个带有PEG.js的A ccess C ontrol S tring(或S ystem)(ACS)字符串解析器/解释器。 ACS字符串通常用于公告板系统(BBS),以检查对电路板特定区域的访问权限。 例如,请参阅Renegade的ACS文档

示例ACS字符串

以下是一些简化的字符串及其英文翻译,用于说明:

// Has GM123 OR NOT GM456
GM123|!GM456

// Has GM123 OR NOT (GM456 AND GM789) (note: AND is implied in this grammar if not specified)
GM123|!(GM456GM789)

// Has GM123 AND NOT GM456 OR has GM789
GM123!GM456|GM789

// Has GM1 OR (NOT GM2 OR GM3)
GM1|(!GM2|GM3) 

我想要实现的目标

我想在这里做的是解析解释(或“运行”)ACS字符串,最终得到一个最终的布尔值。

语法到目前为止

下面是我到目前为止所学的PEG.js语法。 请注意,ACS字符串本身比上面的示例复杂一点(我允许例如GM ['abc','def'])但我认为到目前为止它是相当自我解释的。

{   
  function checkAccessSingle(acsName, arg) {
    return true;
  }

  function checkAccessMulti(acsName, args, anyMatch) {
    return true;
  }

  function makeNot(not, x) {
    return not ? !x : x;
  }
}

start
  = acsString


whitespaceChar
  = ' '

ws
  = whitespaceChar*

lineTerminatorChar
  = [\r\n\u2028\u2029]

decimalDigit
  = [0-9]

integer
  = decimalDigit+ { return parseInt(text(), 10); }

asciiPrintableChar
  = [ -~]

singleAsciiStringChar
  = !("'") asciiPrintableChar { return text(); }

doubleAsciiStringChar
  = !('"') asciiPrintableChar { return text(); }

nonEmptyStringLiteral
  = "'" chars:singleAsciiStringChar+ "'" { return chars.join(''); }
  / '"' chars:doubleAsciiStringChar+ '"' { return chars.join(''); }

AND
  = '&'

OR
  = '|'

NOT
  = '!'

acsName
  = n:([A-Z][A-Z]) { return n.join(''); }

acsArg
  = nonEmptyStringLiteral
  / integer

acsArgs
  = first:acsArg rest:(ws ',' ws a:acsArg { return a; })* {
      var args = [ first ];
      for(var i = 0; i < rest.length; ++i) {
        args.push(rest[i]);
      }
      return args;
    }

singleAcsCheck
  = not:NOT? n:acsName a:acsArg* {
    return function() {
      makeNot(not, checkAccessSingle(n, a));
      }
    }
  / not:NOT? n:acsName '[' a:acsArgs ']' {
    return function() {
      return makeNot(not, checkAccessMulti(n, a, false));
      }
    }
  / not:NOT? n:acsName '{' a:acsArgs '}' {
    return function() {
      return makeNot(not, checkAccessMulti(n, a, true));
      }
    }

multiAcsCheck
  = singleAcsCheck+

acsString = multiAcsCheck

我需要帮助的地方

我遇到的主要问题(如果不是其他我还没有遇到过!)是使用()和OR子句处理优先级。 这可能是一件简单的事情,但我已经为此工作了好几天并且做了一些简短的事情。 同样,我最终试图在这里实现的是输入ACS字符串并输出最终的布尔结果。 各种ACS“命令”(例如上例中的“GM”)应该进行方法调用以执行脏工作。

这是一个快速演示,可以正确解析您的示例输入,并展示如何动态评估表达式(将返回一个布尔值):

{
  function check(name, value) {
    // Dummy implementation: returns true when the name starts with 'A'
    return name.charAt(0) == 'A';
  }
}

start
 = expr

expr
 = or_expr

or_expr
 = left:and_expr '|' right:expr { return left || right; }
 / and_expr

and_expr
 = left:not_expr '&'? right:expr { return left && right; }
 / not_expr

not_expr
 = '!' value:atom { return !value; }
 / atom

atom
 = acs_check
 / '(' value:expr ')' { return value; }

acs_check
 = n:name a:arg { return check(n, a); }

name
 = c:([A-Z][A-Z]) { return c.join(''); }

arg
 = c:[A-Z]+ { return c.join(''); }
 / d:[0-9]+ { return d.join(''); }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM