当我学到一些DSL时,我意识到Rebol中的Parse方言可以成为一个伟大的词法分析器和解析器。 the Parse tutorial有一个很好的例子:
expr: [term ["+" | "-"] expr | term]
term: [factor ["*" | "/"] term | factor]
factor: [primary "**" factor | primary]
primary: [some digit | "(" expr ")"]
digit: charset "0123456789"
probe parse "4/5+3**2-(5*6+1)" expr
;will output true
上面的代码验证表达式是否符合上面定义的“语法”。我的问题是:
答案 0 :(得分:2)
Boyko Bantchev修改版code:
arith-eval: funct [
a-exp [string!]
] [
op-stack: copy []
num-stack: copy []
pop: func [stk /local t] [t: last stk remove back tail stk t]
do.op: func [/local op x y] [
op: to-word pop op-stack
y: pop num-stack
x: pop num-stack
append num-stack do reduce [x op y]
]
num: op: none
expr: [term any [copy op [{+} | {-}] (append op-stack op) term (do.op)]]
term: [prim any [copy op [{*} | {/}] (append op-stack op) prim (do.op)]]
prim: [copy num some digit (append num-stack to-decimal num) | {(} expr {)}]
digit: charset {0123456789}
; whitespace is not allowed between tokens
either parse a-exp expr [num-stack/1] [{wrong expression}]
]
>> arith-eval "12+34*56-89/2"
== 1871.5
>>
答案 1 :(得分:1)
1,您生成字符串或更好的块,例如with collect,你可以用do评估。
2,Gabriele Santilli on rebol.org中有一个带有运算符优先级的旧示例方言。
答案 2 :(得分:1)
请参阅下文,了解良好的订购解析规则。
REBOL []
math-expression?: func
[ {Returns a block of rebol code for a given mathematical expression string,
or none if mathematical expression is not correct.
>> e: math-expression? "1-2**3*6"
== [subtract 1.0 multiply power 2.0 3.0 6.0]
>> do e
== -47.0
>> x: 0
== 0
>> e: math-expression? "sqrt(1+1)/(1-x)**3"
== [divide square-root add 1.0 1.0 power subtract 1.0 x 3.0]
>> do e
== 1.4142135623731
}
Amath-expression {The mathematical expression to convert to REBOL code.}
/trace 'Rtrace {Set Rtrace from the syntax error to the mathematical expression end.}
/local
exprs fx expr text
digit number parameter primary factor term expression
]
[ exprs: copy []
fx: copy []
append/only exprs expr: copy []
digit: charset "0123456789"
number: [some digit]
parameter: charset "abcdefghijklmnopqrstuvwxyz"
primary:
[ opt
[ trace: "abs" (fx: copy [abs])
| trace: "acos" (fx: copy [arccosine/radians])
| trace: "arccos" (fx: copy [arccosine/radians])
| trace: "arcsin" (fx: copy [arcsine/radians])
| trace: "arctan" (fx: copy [arctangent/radians])
| trace: "asin" (fx: copy [arcsine/radians])
| trace: "atan" (fx: copy [arctangent/radians])
| trace: "cos" (fx: copy [cosine/radians])
| trace: "exp" (fx: copy [exp])
| trace: "ln" (fx: copy [log-e])
| trace: "log2" (fx: copy [log-2])
| trace: "log10" (fx: copy [log-10])
| trace: "sin" (fx: copy [sine/radians])
| trace: "sqrt" (fx: copy [square-root])
| trace: "tan" (fx: copy [tangent/radians])
]
trace: "("
( append/only expr fx
fx: copy []
append/only exprs expr: copy []
)
expression
trace: ")"
( insert head expr last second-to-last exprs
remove back tail second-to-last exprs
temp: tail second-to-last exprs
expr: append second-to-last exprs head expr
remove back tail exprs
expr: temp
)
| trace: "+" expression
| trace: "-" (append expr 'negate) expression
| trace: copy text number (append expr to decimal! trim/all text) ; (probe head exprs)
| trace: copy text parameter (append expr to word! trim/all text)
]
factor:
[ primary any
[ [ trace: "**" (insert expr 'power)
| trace: "^^" (insert expr 'power)
| trace: "//" (insert expr 'remainder)
]
primary
]
]
term:
[ factor any
[ [ trace: "*" (insert expr 'multiply)
| trace: "/" (insert expr 'divide)
]
factor
]
]
expression:
[ term any
[ [ trace: "+" (expr: tail insert head expr 'add)
| trace: "-" (expr: tail insert head expr 'subtract)
]
term
]
]
either parse Amath-expression expression
[ first exprs
]
[ if Rtrace [set Rtrace copy back trace]
none
]
]
a: b: i: x: y: 0
foreach e
[ "1 * (2 * (3 - sqrt(4 * sqrt(16)) + 5))"
"-1"
"+1"
"1 + 2 + 3"
"1 + 2 * 3"
"1 * 2 + 4 * 5"
"(1 + 2) * 3"
"-((1 + 2) * 3)"
"3 * (1 + 2)"
"SQRT(1-x**2)/(1-x)**3"
"3*(3+x)**sin(2-i)+cos((3*y)**3*(a-b))+1"
"+(1+-x)**-sqrt(-1--x)"
"3-2+1"
"4/2*2"
"2**3*6"
"1-2**3*6"
"4/5+3**2-(5*6+1)"
"sqrt(3*3)"
"1-x**3"
"(1-x)**3"
"(1+1)/(1-x)**3"
"sqrt(1+1)/(1-x)**3"
"-(1+1)/(1-x)**3"
"+(1+2)/-(1-2)"
"1 - 2"
"-(1 + 2)"
"-1/2"
"(-1)/2"
"-(1)/2"
]
[ print ""
print e
probe e: math-expression? e
prin "= "probe either error? err: try [e: first reduce e] [disarm err] [e]
; break
]
print ""
probe m: "2*(1*1+1))"
probe math-expression? m
probe math-expression?/trace m t: copy ""
probe t
probe m: "1+abs(-1"
probe math-expression? m
probe math-expression?/trace m t: copy ""
probe t
probe m: "1+2+"
probe math-expression? m
probe math-expression?/trace m t: copy ""
probe t