Интерпретатор арифметики на OMeta

предыдущая серия

Расширение грамматики семантикой также достаточно просто. Правила разбора, которые надо наполнить семантическим содержанием, дополняются конструкцией «-> {выражение}», и значение этого выражения и будет по сути возвращаться исполнительной системой.

Таким образом, наш язык интерпретации арифметических выражений окончательно запишется так:

ometa OMetaSharp.Examples.Calculator<char, int> : Parser<char> {
dig = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9',
num = dig+:n -> {n},
fac = fac:x '*' num:y -> {x*y}
| fac:x '/' num:y -> {x/y}
| num,
exp = exp:x '+' fac:y -> {x+y}
| exp:x '-' fac:y -> {x-y}
| fac
}

Для числа мы возвращаем число, для арифметической операции — ее значение.

Пересоберём наш проект, вызовем

var result = Parse<string>("1+3*2-4/2", x => x.exp);

и получим в result результат 5. Как видно, приоритеты соблюдаются корректно.

Полезный шаг — дополнение языка скобками. Для примера приведу стандартный вариант, входящий в набор примеров — теперь он будет полностью понятен:

ometa OMetaSharp.Examples.Calculator<char, int> : Parser<char> {
Digit   ^= Super(Digit):d           -> { d },
Number  ^= Number:n Digit:d         -> { n * 10 + d }
| Digit,
AddExpr  = AddExpr:x '+' MulExpr:y  -> { x + y }
| AddExpr:x '-' MulExpr:y  -> { x - y }
| MulExpr,
MulExpr  = MulExpr:x '*' PrimExpr:y -> { x * y }
| MulExpr:x '/' PrimExpr:y -> { x / y }
| PrimExpr,
PrimExpr = '(' Expr:x ')'           -> { x }
| Number,
Expr     = AddExpr
}

Соответственно,

var result = Parse<string>("(1+(3*(2-(4)))-2)", x => x.Expr);

вернёт -7. Наш интерпретатор работает отлично!

Далее мы построим транслятор нашего арифметического языка в конкатенативный код.

Поделиться статьей ...Share on Facebook0Share on Google+0Tweet about this on TwitterShare on LinkedIn0Share on VKPrint this page

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *