简体   繁体   English

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

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

Preface 前言

I'm working on creating a A ccess C ontrol S tring (or S ystem) (ACS) string Parser/Interpreter with PEG.js. 我正在努力创建一个带有PEG.js的A ccess C ontrol S tring(或S ystem)(ACS)字符串解析器/解释器。 ACS strings are commonly used on Bulletin Board Systems (BBSs) to check access rights to particular areas of the board. ACS字符串通常用于公告板系统(BBS),以检查对电路板特定区域的访问权限。 For example, see Renegade's ACS documentation . 例如,请参阅Renegade的ACS文档

Example ACS Strings 示例ACS字符串

Below are some simplified strings and their English translations for illustration: 以下是一些简化的字符串及其英文翻译,用于说明:

// 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) 

What I'm Trying to Achieve 我想要实现的目标

What I would like to do here is parse and interpret (or "run") the ACS string and ultimately end up with a final boolean. 我想在这里做的是解析解释(或“运行”)ACS字符串,最终得到一个最终的布尔值。

Grammar So Far 语法到目前为止

Below is the PEG.js grammer I've some up with so far. 下面是我到目前为止所学的PEG.js语法。 Note that the ACS strings themselves are a bit more complex than the examples above (I allow for example GM['abc','def']) but I think up to this point it's fairly self explanatory. 请注意,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

Where I Need Help 我需要帮助的地方

The main issue I'm having (if not others I haven't run into yet!) is handling precedence with () and the OR clauses. 我遇到的主要问题(如果不是其他我还没有遇到过!)是使用()和OR子句处理优先级。 This may be something simple, but I've worked on this for days and have some up short. 这可能是一件简单的事情,但我已经为此工作了好几天并且做了一些简短的事情。 Again, what I'm ultimately attempting to achieve here is to feed in an ACS string and output a final boolean result. 同样,我最终试图在这里实现的是输入ACS字符串并输出最终的布尔结果。 The various ACS "commands" (eg 'GM' in the above example) should make method calls that do the dirty work. 各种ACS“命令”(例如上例中的“GM”)应该进行方法调用以执行脏工作。

Here's a quick demo that parses your example input properly and shows how you could go about evaluating the expressions on the fly (which will return a boolean): 这是一个快速演示,可以正确解析您的示例输入,并展示如何动态评估表达式(将返回一个布尔值):

{
  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