Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
states[0] = new State(new int[]{28,27,8,31,9,35,10,39,11,43,12,47,13,51,14,55,15,59,16,63,17,67,18,71,19,75,20,79,21,83,22,87,23,91,24,95,25,99,26,103,3,108,4,109,5,110,6,112,7,113,39,114,32,116,31,118},new int[]{-1,1,-3,3,-4,30,-5,107,-6,111});
states[1] = new State(new int[]{2,2});
states[2] = new State(-1);
Левая рекурсия
PEG фактически описывает нисходящий рекурсивный парсер с откатами. Этот тип парсеров имеет одно ограничение. Без специальной доработки (негативно влияющей на производительность и сильно усложняющей парсер) парсеры этого типа не могут разбирать леворекурсивные грамматики.
Леворекурсивной грамматикой называют грамматику, которая имеет леворекурсивные правила (прямые или нет). Например, следующая грамматика имеет левую рекурсию:
X = X '+' 1 / 1
…
Научно доказано, что любое леворекурсивное правило можно переписать без левой рекурсии. Например, приведенное выше правило можно переписать так:
X = 1 ('+' 1)*
expr : expr ('*'|'/') expr # MulDiv
| expr ('+'|'-') expr # AddSub
| INT # int
| '(' expr ')' # parens
;
@namespace MyProject
@classname ExpressionParser
additive <decimal> -memoize
= left:additive "+" right:multiplicative { left + right }
/ left:additive "-" right:multiplicative { left - right }
/ multiplicative
multiplicative <decimal> -memoize
= left:multiplicative "*" right:primary { left * right }
/ left:multiplicative "/" right:primary { left / right }
/ primary
primary <decimal>
= decimal
/ "(" additive:additive ")" { additive }
decimal <decimal>
= value:([0-9]+ ("." [0-9]+)?) { decimal.Parse(value) }
grammar Calculator;
/*
* Parser Rules
*/
prog: expr+ ;
expr : left = expr op=('*'|'/') right = expr # MulDiv
| left = expr op=('+'|'-') right = expr # AddSub
| INT # int
| '(' expr ')' # parens
;
/*
* Lexer Rules
*/
INT : [0-9]+;
ADD : '+';
MUL : '*';
WS
: (' ' | '\r' | '\n') -> channel(HIDDEN)
;
grammar Calculator;
prog: expr+ ;
expr : expr ('*'|'/') expr # MulDiv
| expr ('+'|'-') expr # AddSub
| INT # int
| '(' expr ')' # parens
;
INT : [0-9]+;
WS
: (' ' | '\r' | '\n') -> channel(HIDDEN)
;
Ещё одно средство распознавания языков 4