помогите создать парсер peg.js - PullRequest
6 голосов
/ 09 марта 2011

Я хочу создать синтаксический анализатор и синтаксис выражения в peg.js, который позволил бы мне делать эти вещи

В основном я хочу передать маску и получить вывод числа.

маска обладает этими способностями.

1) генерирует случайное число между 0-9 (символ n для выражения?)
2) генерирует случайное число между x и y ((x,y) для выражения?)
3) допустимы литеральные числа (надеюсь, для выражения ничего не нужно?)
4) повторять предыдущее выражение x раз ({x} для выражения?)
5) повторять предыдущее выражение междуx и y раз ({x, y} для выражения?)

, поэтому примером выражения может быть

027n(5,9){4}n12{2,8}(2,4)

, предложенный выше синтаксис выражения является только примером, это может измениться.

Может ли кто-нибудь оказать помощь в создании парсера для этого в peg.js ?

1 Ответ

17 голосов
/ 09 марта 2011

Идея состоит в том, чтобы заставить ее генерировать функцию JavaScript, которая при выполнении будет возвращать случайную строку в соответствии с маской.

Литеральным числом является любой символ от 0 до 9, поэтому заставьте его сгенерироватьфункция, которая возвращает себя.

literal_number
 = num:[0-9]
 { return function() {
     return num;
 }; }

Тогда n для случайного числа.Опять же, это генерирует функцию для возврата случайного числа.Я добавил + '', чтобы преобразовать его в строку перед возвратом.

random_number
 = "n"
 { return function() {
     return Math.floor(Math.random() * 10) + '';
 }; }

В синтаксисе (a,b) a и b - это числа, поэтому нам нужно заставить его разобрать и вернутьчисло.Используя объявление из примера калькулятора:

number
 = digits:[0-9]+ { return parseInt(digits.join(""), 10); }

Затем мы можем перейти к созданию правила для синтаксиса (a,b).

random_number_between
 = "(" a:number "," b:number ")"
 { return function() {
     return a + Math.floor(Math.random() * (b - a + 1)) + ''
 }; }

Итак, эти 3 вещи (literal_number, random_number), random_number_between) объединяется в одно выражение, которое генерирует допустимую функцию.

single_expression
 = random_number
 / random_number_between
 / literal_number

Одно выражение, за которым следуют {n} или {a,b}, образует повторяющееся выражение.Отдельное выражение также является повторяющимся выражением, повторяемым один раз.

Идея повторного выражения состоит в том, чтобы при заданной функции возвращать функцию, которая вызывает функцию ввода N раз, собирать результат и возвращать его.

repeated_expression
 = ex:single_expression "{" n:number "}" {
       return function() {
           var result = '';
           for (var i = 0; i < n; i ++) {
               result += ex();
           }
           return result;
       };
   }
 / ex:single_expression "{" a:number "," b:number "}" {
       return function() {
           var result = '';
           var n = a + Math.floor(Math.random() * (b - a + 1))
           for (var i = 0; i < n; i ++) {
               result += ex();
           }
           return result;
       };
   }
 / ex:single_expression

Наконец, повторяющиеся выражения могут быть помещены рядом друг с другом для объединения.

expression
 = list:repeated_expression* {
       return function() {
           var result = '';
           for (var i = 0; i < list.length; i ++) {
               result += list[i]();
           }
           return result;
       };
   }

Наконец, вам нужна начальная точка, которая определяет маску.Этот последний бит сканирует выражение, которое возвращает a, генерирует функцию и вызывает ее. Поместите следующее в верхнюю часть , и когда вы попробуете это онлайн, он сгенерирует строку чисел в соответствии с вашей маской.

mask
 = ex:expression
 { return ex() }

Пример выполнения: 027n(5,9){4}n12{2,8}(2,4) дает 0271568891222224.

...