; Пресмятане на аритметичен израз, образуван от цели числа, действия събиране (+), ; изваждане (-), умножение (*) и делене (/) и скоби. Образуваните от действията стойности ; не са непременно цели. Не се допуска изразът да съдържа шпации. ; За синтактичен анализ на израза се използва сложната форма на функцията parse, при която ; вторият аргумент е блок – правило за разпознаване. В случая това правило е в рекурентна ; връзка с две други, с които заедно задават граматиката на израз съгласно схемата ; израз :: събираемо | събираемо {‘+’ | ‘-’} събираемо ; събираемо :: множител | множител {‘*’ | ‘/’} множител ; множител :: цяло | ‘(’ израз ‘)’ ; Правилото expr отговаря на израз като цяло и най-напред чрез цитиране на правилото addend ; разпознава събираемо. Ако следва + или - разпознава следващо събираемо и т.н. Аналогично ; addend най-напред чрез цитиране на правилото multpr разпознава множител и ако следва * или ; / разпознава следващ множител и т.н. Правилото multpr разпознава число (редица от цифри) ; или израз в скоби – в първия случай непосредствено, а във втория чрез цитиране на expr. ; Думите any и some тук са от диалекта на parse, т.е. обозначават нейни действия – за ; разпознаване съответно на коя да е от известен брой възможности и на какъв да е брой поредни ; повторения на дадена конструкция. Така в частност се постига повторност в expr и addend. ; Успоредно с разпознаването пресмятаме стойностите на съответните (под)изрази. За разлика от ; рекурсивни процедури обаче тук за различните рекурентни цитирания на правилата не можем да ; имаме отделни локални променливи, в които да съхраняваме стойностите на вече разпознатите и ; пресметнати подизрази. Затова организираме два глобални спрямо правилата стека (блокове) – ; vs от числа и ps от показалци към места в низа-израз. В правилата expr и addend местата на ; съответните операции се запомнят в ps. При пресмятане на операция тя се извлича чрез ps, а ; стойностите на аргументите ѝ се вземат от vs, където след това се съхранява и резултатът. ; Така разпознаването на израз е рекурсивно, но пресмятането му – не. Всъщност разпознаването ; служи за превръщане на израза в суфиксна форма, в която и става пресмятането. Превръщането ; и пресмятането се редуват, следвайки йерархичния строеж на израза: всеки подизраз се пресмята ; веднага след като бъде разпознат и превърнат. ; При успешно разпознаване и пресмятане на израз стойността му е единственото число във vs. ; За неправилно образуван израз повикването „parse низ expr“ дава стойност none. Rebol [Title: {Пресмятане на аритметичен израз}] ; Извличане на елемент от редицата stk, ползвана като стек. ; Прилага се за vs и ps. pop: func [stk /local t] [t: last stk remove back tail stk t] ; Пресмятане на операция от стека ps с аргументи от стека vs. Резултатът отива във vs. do.op: func [/local p x y] [ p: pop ps y: pop vs x: pop vs append vs do reform [x p/-1 y] ] expr: [addend any [[{+} | {-}] p: (append ps p) addend (do.op)]] addend: [multpr any [[{*} | {/}] p: (append ps p) multpr (do.op)]] multpr: [p1: some digit p2: (append vs to-decimal copy/part p1 p2) | {(} expr {)}] digit: charset {0123456789} ; разпознава цифра, коя да е от низа-аргумент на charset ; Пример за използване: четене и анализ на редове до срещане на празен. while [not empty? s: trim input] [ print do [ps: copy [] vs: copy [] either parse s expr [vs/1] [{неправилен израз}]] ]