PEGjs:如果浮点规则失败,则回退(回溯?)到字符串

时间:2013-04-18 11:29:59

标签: node.js grammar peg pegjs

我有一个atom规则尝试先将所有内容解析为数字或带引号的字符串,如果失败,则将该事物视为字符串。

除了一个非常特殊的字符串的特殊情况外,所有内容都解析得很好:

DUD 123abc

无法解析Expected " ", "." or [0-9] but "a" found.错误。

我的期望:它应该成功解析并返回字符串“123abc”作为字符串原子。您可以在下面的语法内容中看到我的一些不成功的尝试。

任何帮助/提示/指示/建议赞赏!


您可以在online PEG.js version上尝试语法。我正在使用节点v0.8.23和pegjs 0.7.0

正确解析的数字:

  • `123
  • `0
  • `0。
  • `1。
  • `0.23
  • `0.23
  • `1.23
  • `0.000
  • .< --- as string,not number and not error

我想将123abc解析为字符串,这可能吗?


这是我的整个语法文件:

start = lines:line+ { return lines; }

// --------------------- LINE STRUCTURE
line = command:command eol { return command; }

command = action:atom args:(sep atom)*
{
  var i = 0, len = 0;

  for (var i = 0, len = args.length; i < len; i++) {
    // discard parsed separator tokens
    args[i] = args[i][1];
  }

  return [action, args];
}

sep = ' '+
eol = "\r" / "\n" / "\r\n"

atom = num:number { return num; }
     / str:string_quoted { return str; }
     / str:string { return str; }

// --------------------- COMMANDS

// TODO:

// --------------------- STRINGS
string = chars:([^" \r\n]+) { return chars.join(''); }

string_quoted = '"' chars:quoted_chars* '"' { return chars.join(''); }
quoted_chars = '\\"' { return '"'; }
             / char:[^"\r\n] { return char; }

// --------------------- NUMBERS
number = integral:('0' / [1-9][0-9]*) fraction:("." [0-9]*)?
{
  if (fraction && fraction.length) {
    fraction = fraction[0] + fraction[1].join('');
  } else {
    fraction = '';
  }

  integral = integral instanceof Array ?
    integral[0] + integral[1].join('') :
    '0';

  return parseFloat(integral + fraction);
}
        / ("." / "0.") fraction:[0-9]+
{
  return parseFloat("0." + fraction.join(''));
}

/*
float = integral:integer? fraction:fraction { return integral + fraction; }

fraction = '.' digits:[0-9]* { return parseFloat('0.' + digits.join('')); }

integer = digits:('0' / [1-9][0-9]*)
{
  if (digits === '0') return 0;
  return parseInt(digits[0] + digits[1].join(''), 10);
}

*/

2 个答案:

答案 0 :(得分:3)

通过添加!([0-9\.]+[^0-9\.])来解决此问题,numberatom规则的前瞻性。

我知道number规则会匹配,所以它实际上会使number = !([0-9\.]+[^0-9\.]) integral:('0' / [1-9][0-9]*) fraction:("." [0-9]*)?规则更快地失败。希望这可以帮助将来处理模糊案例的人。

现在数字规则变为:

{{1}}

答案 1 :(得分:1)

我认为检查字符尾部number是一个数字分隔符(而不是一个字母)也会起作用,而且更便宜。

number = integral:('0' / [1-9][0-9]*) fraction:("." [0-9]*)? !([0-9A-Za-z])