Завершение списка выражений в PEG.js

У меня есть еще один вопрос, связанный с как расширить пример арифметики PEG.js по умолчанию, чтобы разрешить несколько выражений, а не одно?

У меня есть эта грамматика:

start = code:statements {
    return {
      "type": "Program",
      "body": code
    };
 }

statements = head:(if / expression_statement) tail:(_ (if / expression_statement))* {
    return [head].concat(tail.map(function(element) {
      return element[1];
    })); 
  }

expression_statement = expression:expression {
    return  {
      "type": "ExpressionStatement",
      "expression": expression
    };
}


if = "if" _ expression:(comparison / expression) _ "then" body:(statements / _) "end" {
   return {
     "type": "IfStatement",
     "test": expression,
     "consequent": {
        "type": "BlockStatement",
        "body": body
     },
     "alternate": null
   };
}

expression = expression:(arithmetic / literal) { return expression; }

literal = value:(string / Integer) {
   return {"type": "Literal", "value": value };
}

variable = variable:name {
  return {
    "type": "Identifier",
    "name": variable
  }
}

name = [A-Z_a-z][A-Z_a-z0-9]* { return text(); }

comparison = _ left:expression _ "==" _ right:expression _ {
   return {
        "type": "BinaryExpression",
        "operator": "==",
        "left": left,
        "right": right
   };
}

string = "\"" ([^"] / "\\\\\"")*  "\"" {
  return JSON.parse(text());
}

arithmetic
  = head:term tail:(_ ("+" / "-") _ term)* {
      return tail.reduce(function(result, element) {
          return {
            "type": "BinaryExpression",
            "operator": element[1],
            "left": result,
            "right": element[3]
          };
      }, head);
    }

term
  = head:factor tail:(_ ("*" / "/") _ factor)* {
      return tail.reduce(function(result, element) {
          return {
            "type": "BinaryExpression",
            "operator": element[1],
            "left": result,
            "right": element[3]
          };
      }, head);
    }

factor
  = "(" _ expr:arithmetic _ ")" { return expr; }
  / literal

Integer "integer"
  = _ [0-9]+ { return parseInt(text(), 10); }

_ "whitespace"
  = [ \t\n\r]* {
   return [];
}

Парсер предназначен для создания JavaScript AST (с использованием структуры объекта Esprima).

Я пытался разобрать рубин как операторы if:

Это отлично работает, он создает пустой if:

if "foo" == "bar" then

end

но это не удается разобрать:

if "foo" == "bar" then
10 + 10
end

Он не работает с ошибкой:

Parse Error: Expected "(", "*", "+", "-", "/", "\"", "if", or integer but "e" found.

Error in line 3
end
^

Я также хочу, чтобы он работал с более чем одной строкой:

if "foo" == "bar" then
10 + 10
10 * 10
end

Я думаю, что я должен добавить конец как тип вперед, но я не уверен, где.

Изменить: я пытался это:

statements = head:(if / expression_statement)  tail:(_ &"end" / (if / expression_statement)*) {
    return [head].concat(tail.map(function(element) {
      if (element) {
        return element[2];
      }
    }).filter(Boolean)); 
  }

но это не работает для двух строк выражения, и если я использую * в конце

tail:(_ &"end" / (if / expression_statement))*

У меня ошибка синтаксического анализатора бесконечного цикла. Я также пробовал несколько комбинаций &end, но они не работают. Я также нашел эту проблему на GitHub pegjs/pegjs#57, но это не помогло в любом случае.


person jcubic    schedule 26.03.2021    source источник


Ответы (1)


Я решил проблему с этим кодом:

statements = head:(if / expression_statement)  tail:( (!"end" _  (if / expression_statement) .)*) {
    return [head].concat(tail.map(function(element) {
      if (element) {
        return element[2];
      }
    }).filter(Boolean)); 
  }
person jcubic    schedule 27.03.2021