摘要
回憶一下我們的英雄所處的困境
● 二進制加/減/乘/除運算符
● 一元反運算符
● 數值
它背後的執行引擎知道如何執行那些操作
最後的 代碼 是這樣的
清單
package com
{
private[calcdsl] abstract class Expr
private[calcdsl] case class Variable(name : String) extends Expr
private[calcdsl] case class Number(value : Double) extends Expr
private[calcdsl] case class UnaryOp(operator : String
private[calcdsl] case class BinaryOp(operator : String
extends Expr
object Calc
{
/**
* Function to simplify (a la mathematic terms) expressions
*/
def simplify(e : Expr) : Expr =
{
e match {
// Double negation returns the original value
case UnaryOp(
// Positive returns the original value
case UnaryOp(
// Multiplying x by
case BinaryOp(
// Multiplying
case BinaryOp(
// Multiplying x by
case BinaryOp(
// Multiplying
case BinaryOp(
// Dividing x by
case BinaryOp(
// Dividing x by x returns
case BinaryOp(
// Adding x to
case BinaryOp(
// Adding
case BinaryOp(
// Anything else cannot (yet) be simplified
case _ => e
}
}
def evaluate(e : Expr) : Double =
{
simplify(e) match {
case Number(x) => x
case UnaryOp(
case BinaryOp(
case BinaryOp(
case BinaryOp(
case BinaryOp(
}
}
}
}
前一篇文章的讀者應該還記得
清單
/*
* Lex
*/
def simplify(e: Expr): Expr = {
// first simplify the subexpressions
val simpSubs = e match {
// Ask each side to simplify
case BinaryOp(op
// Ask the operand to simplify
case UnaryOp(op
// Anything else doesn
case _ => e
}
// now simplify at the top
def simplifyTop(x: Expr) = x match {
// Double negation returns the original value
case UnaryOp(
// Positive returns the original value
case UnaryOp(
// Multiplying x by
case BinaryOp(
// Multiplying
case BinaryOp(
// Multiplying x by
case BinaryOp(
// Multiplying
case BinaryOp(
// Dividing x by
case BinaryOp(
// Dividing x by x returns
case BinaryOp(
// Adding x to
case BinaryOp(
// Adding
case BinaryOp(
// Anything else cannot (yet) be simplified
case e => e
}
simplifyTop(simpSubs)
}
在此對 Lex 表示感謝
解析
現在是構建 DSL 的另一半工作
以往
● 手工構建一個解析器
● 通過工具生成解析器
我們可以試著手工構建這個解析器
除了手工編寫解析器外
由於這是 Computer Science
同時
解析器組合子
了解 Becker
清單
input ::= ws expr ws eoi;
expr ::= ws powterm [{ws
powterm ::= ws factor [{ws (
factor ::= ws term [{ws (
term ::=
number ::= {dgt} [
dgt ::=
ws ::= [{
語句左邊的每個元素是可能的輸入的集合的名稱
用 BNF 形式來表達語言的強大之處在於
清單
expr ::= term {
term ::= factor {
factor ::= floatingPointNumber |
其中花括號({})表明內容可能重復(
在這裡
清單
package com
{
object Calc
{
//
import scbinator
object ArithParser extends JavaTokenParsers
{
def expr: Parser[Any] = term ~ rep(
def term : Parser[Any] = factor ~ rep(
def factor : Parser[Any] = floatingPointNumber |
def parse(text : String) =
{
parseAll(expr
}
}
def parse(text : String) =
{
val results = ArithParser
System
+ results
}
//
}
}
BNF 實際上被一些解析器組合子語法元素替換
從兩個方面可以看到這種方法的強大之處
這種特定的(一個中綴計算器的)語法很容易使用(這也是在那麼多演示稿和文章中看到它的原因)
解析器組合子概念入門
為了理解其中的原理
清單
type Elem
type Input = Reader[Elem]
type Parser[T] = Input => ParseResult[T]
sealed abstract class ParseResult[+T]
case class Success[T](result: T
case class Failure(msg: String
換句話說
顯然
我們還沒有完成
我們仍然沒有完成
清單
package com
{
class CalcTest
{
import org
//
@Test def parseNumber =
{
assertEquals(Number(
assertEquals(Number(
}
}
}
這次測試會在運行時失敗
相反
假設這是一次成功的解析
清單
package com
{
object Calc
{
//
import scbinator
object ArithParser extends JavaTokenParsers
{
def expr: Parser[Any] = term ~ rep(
def term : Parser[Any] = factor ~ rep(
def factor : Parser[Any] = floatingPointNumber |
def parse(text : String) =
{
parseAll(expr
}
}
def parse(text : String) =
{
val results = ArithParser
System
+ results
results
}
//
}
}
成功了!真的嗎?
對不起
確實有另外一種方法
在下一期中
結束語
顯然
對於那些想領先一步的讀者
當然
參考資料
● 您可以參閱本文在 developerWorks 全球網站上的 英文原文
●
○
○
○
○
○
○
○
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26082.html