У меня есть еще один вопрос, связанный с как расширить пример арифметики 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, но это не помогло в любом случае.