package myscala15
import myscala.Element.elem
import myscala.Element

sealed abstract class Expr
case class Var(name: String) extends Expr
case class Number(num: Double) extends Expr
case class UnOp(operator: String, arg: Expr) extends Expr
case class BinOp(operator: String,
  left: Expr, right: Expr) extends Expr

class ExprFormatter {
  //包含了递增优先级的组中的操作符
  private val opGroups =
    Array(
        Set("|", "||"),
        Set("&", "&&"),
        Set("^"),
        Set("==", "!="),
        Set("<", "<=", ">", ">="),
        Set("+", "-"),
        Set("*", "%")
        )
  //操作符优先级映射
  private val precedence = {
    val assocs =
      for {
        i <- 0 until opGroups.length
        op <- opGroups(i)
      } yield op -> i
      Map() ++ assocs    
  }
  private val unaryPrecedence = opGroups.length
  private val fractionPrecedence = -1
 
  private def format(e: Expr, enclPrec: Int): Element =
    e match {
    case Var(name) =>
      elem(name)
    case Number(num) =>
      def stripDot(s: String) =
        if(s endsWith ".0") s.substring(0, s.length - 2)
        else s
        elem(stripDot(num.toString))
    case UnOp(op, arg) =>
      elem(op) beside format(arg, unaryPrecedence)
    case BinOp("/", left, right) =>
      val top = format(left, fractionPrecedence)
      val bot = format(right, fractionPrecedence)
      val line = elem('-', top.width max bot.width, 1)
      val frac = top above line above bot
      if (enclPrec != fractionPrecedence) frac
      else elem(" ") beside frac beside elem(" ")
    case BinOp(op, left, right) =>
      val opPrec = precedence(op)
      val l = format(left, opPrec)
      val r = format(right, opPrec + 1)
      val oper = l beside elem(" "+ op +" ") beside r
      if (enclPrec <= opPrec)oper
      else elem("(") beside oper beside elem(")")
  }
  def format(e: Expr): Element = format(e, 0)
}

object Express extends App {
  val f = new ExprFormatter
  val e1 = BinOp("*", BinOp("/", Number(1), Number(2)),
       BinOp("+", Var("x"), Number(1)))
  val e2 = BinOp("+", BinOp("/", Var("x"), Number(2)),
       BinOp("/", Number(1.5), Var("x")))
  val e3 = BinOp("/", e1, e2)
  def show(e: Expr) = println(f.format(e)+ "\n\n")
//  for (val e <- Array(e1, e2, e3)) show(e) 显示出错可做如下等价修改

Array(e1, e2, e3).foreach(e => show(e))
}

scala编程第15章的更多相关文章

  1. scala编程第16章学习笔记(3)——List类的高阶方法

    列表间映射:map.flatMap和foreach 1.xs map f 操作返回把函数f应用在xs的每个列表元素之后由此组成的新列表.如: scala> List(1, 2, 3) map ( ...

  2. scala编程第17章学习笔记(1)——集合类型

    列表 列表的初始化及对其首尾的访问: scala> val colors = List("red", "blue", "green") ...

  3. scala编程第16章学习笔记(2)

    转换列表:toIterator, toArray,copyToArray List类的toArray方法将递归存放的列表转换为连续存放的数组 Array类的toList方法将连续存放的数组转换为递归存 ...

  4. scala编程第16章学习笔记(1)

    List列表的基本操作 head方法获得列表的第一个元素 tail方法获得列表除第一个元素之外的其它元素 isEmpty:判断列表是否为空,空的话返回真 last:获得列表最后一个元素 init:获得 ...

  5. scala编程第19章学习笔记(1)——类型参数化

    一.queues函数式队列 函数式队列是一种具有以下三种操作方式的数据结构: head 返回队列的第一个元素. tail 返回除第一个元素之外的队列. scala> import scala.c ...

  6. scala编程第18章学习笔记——有状态的对象

    银行账号的简化实现: scala> class BankAccount{ | private var bal: Int = 0 | def balance: Int = bal | def de ...

  7. scala编程第17章学习笔记(4)——元组

    元组可以把固定数量的条目组合在一起以便于作为整体传送.不像数组或列表,元组可以保存不同类型的对象. 元组常用来返回方法的多个值.例如,下面的方法找到集合中的最长单词并返回它的索引: scala> ...

  8. scala编程第17章学习笔记(3)

    可变(mutable)集合与不可变(immutable)集合 为了更易于完成不可变集合到可变集合的转换,或者反向转换,Scala提供了一些语法糖.纵使不可变集和映射并不支持真正的+=方法,Scala还 ...

  9. scala编程第17章学习笔记(2)——集和映射

    默认情况下在使用“Set”或“Map”的时候,获得的都是不可变对象.如果需要的是可变版本,需要先写明引用. 如果同一个源文件中既要用到可变版本,也要用到不可变版本的集合或映射,方法之一是引用包含了可变 ...

随机推荐

  1. 如何在Ubuntu 18.04上安装和配置Apache 2 Web服务器(转)

    如何在Ubuntu 18.04上安装和配置Apache 2 Web服务器 什么是Apache Web Server? Apache或Apache HTTP服务器是一个免费的开源Web服务器,由Apac ...

  2. Cookie安全漫谈(转)

    add by zhj: 我也同意作者的观点,JavaScript 操作 Cookie 是一种不正常的做法:可以用 JavaScript 操作 Cookie 完成的功能,一样可以在服务端来完成. js操 ...

  3. SpringBoot详细研究-04部署测试与监控

    这部分的内容实际就是devops的主要工作内容,当然一名合格的程序要也需要掌握这部分的知识. 热部署 简单来说,在开发时,修改了任何的代码,IDE将自动编译运行及发布:在发布时,当前发布不影响线上服务 ...

  4. UML类图之间的关系

    1. 泛化(Generalization) [泛化关系]:是一种继承关系,表示一般与特殊的关系,它指定了子类如何特化父类的所有特征和行为.例如:老虎是动物的一种,即有老虎的特性也有动物的共性. [箭头 ...

  5. MySql 时间戳存char还是存int?

    一次小事故,让我对时间戳存char还是存int有了深刻的印象. 生产环境的sql条件涉及到时间戳字段的大小比较(between and),当时设计的时间戳类型是char(10),结果当数据量达到200 ...

  6. Go语言笔记:struct结构遍历

    package main import ( "fmt" "reflect" ) type User struct { Id int Name string // ...

  7. 洛谷.3381.[模板]最小费用最大流(zkw)

    题目链接 Update:我好像刚知道多路增广就是zkw费用流.. //1314ms 2.66MB 本题优化明显 #include <queue> #include <cstdio&g ...

  8. FTP传输一定要注意使用二进制模式

    一个问题困扰了我一下午,刚刚才解决.我要上传一个PHP程序,其中用了sqlite数据库,没想到上传完以后无论如何也不能用,总是数据库查询失败.我登录上SSH,把几乎每个php都调试了一遍,还是没法解决 ...

  9. git指南目录

    git指南目录 发表回复 蓝色表示未阅读,棕色表示阅读过,绿色表示阅读过但不太理解 1. 起步 1.1 关于版本控制 1.2 Git 简史 1.3 Git 基础 1.4 安装 Git 1.5 初次运行 ...

  10. 什么是 "use strict"? 使用它的好处和坏处分别是什么?

    ECMAscript 5添加了第二种运行模式:"严格模式"(strict mode).顾名思义,这种模式使得Javascript在更严格的条件下运行. 设立"严格模式&q ...