Disabled external gits
This commit is contained in:
11
cs452-fos/fos-assignments/1-arithmetic/.gitignore
vendored
Normal file
11
cs452-fos/fos-assignments/1-arithmetic/.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
.bsp
|
||||
.idea/
|
||||
project/project/
|
||||
project/target/
|
||||
target/ .bsp/
|
||||
.idea/
|
||||
project/project/
|
||||
project/target/
|
||||
target/
|
||||
.metals/
|
||||
.vscode/
|
4
cs452-fos/fos-assignments/1-arithmetic/build.sbt
Normal file
4
cs452-fos/fos-assignments/1-arithmetic/build.sbt
Normal file
@@ -0,0 +1,4 @@
|
||||
scalaVersion := "3.0.2"
|
||||
|
||||
libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "2.0.0"
|
||||
|
@@ -0,0 +1 @@
|
||||
sbt.version=1.5.5
|
@@ -0,0 +1,136 @@
|
||||
package fos
|
||||
|
||||
import scala.util.parsing.combinator.syntactical.StandardTokenParsers
|
||||
import scala.util.parsing.input.*
|
||||
|
||||
/** This object implements a parser and evaluator for the NB
|
||||
* language of booleans and numbers found in Chapter 3 of
|
||||
* the TAPL book.
|
||||
*/
|
||||
object Arithmetic extends StandardTokenParsers {
|
||||
lexical.reserved ++= List("true", "false", "if", "then", "else", "succ", "pred", "iszero")
|
||||
|
||||
import lexical.NumericLit
|
||||
|
||||
/** term ::= 'true'
|
||||
| 'false'
|
||||
| 'if' term 'then' term 'else' term
|
||||
| numericLit
|
||||
| 'succ' term
|
||||
| 'pred' term
|
||||
| 'iszero' term
|
||||
*/
|
||||
|
||||
def NumericRec(c:Int,s:Term): (Int,Term) = {
|
||||
if(c<=0){
|
||||
(0,s)
|
||||
}else{
|
||||
NumericRec(c-1,Succ(s))
|
||||
}
|
||||
}
|
||||
|
||||
def term: Parser[Term] = {
|
||||
"true" ^^^ True |
|
||||
"false" ^^^ False |
|
||||
("if" ~> term) ~ ("then" ~> term) ~ ("else" ~> term) ^^ { case cond ~ t1 ~ t2 => If(cond, t1, t2) } |
|
||||
numericLit ^^ { case v if (v.toInt >=0) => NumericRec(v.toInt,Zero)._2} |
|
||||
("succ" ~> term) ^^ { Succ(_) } |
|
||||
("pred" ~> term) ^^ { Pred(_) } |
|
||||
("iszero" ~> term) ^^ { IsZero(_) } |
|
||||
failure("Unknown Term")
|
||||
}
|
||||
|
||||
case class NoReductionPossible(t: Term) extends Exception(t.toString)
|
||||
|
||||
/** Return a list of at most n terms, each being one step of reduction. */
|
||||
def path(t: Term, n: Int = 64): List[Term] =
|
||||
if (n <= 0) Nil
|
||||
else
|
||||
t :: {
|
||||
try {
|
||||
path(reduce(t), n - 1)
|
||||
} catch {
|
||||
case NoReductionPossible(t1) =>
|
||||
Nil
|
||||
}
|
||||
}
|
||||
|
||||
def isNumeric(t: Term): Boolean = t match {
|
||||
case Zero => true
|
||||
case Pred(v) => isNumeric(v)
|
||||
case Succ(v) => isNumeric(v)
|
||||
case _ => false;
|
||||
}
|
||||
/** Perform one step of reduction, when possible.
|
||||
* If reduction is not possible NoReductionPossible exception
|
||||
* with corresponding irreducible term should be thrown.
|
||||
*/
|
||||
def reduce(t: Term): Term = t match {
|
||||
case If(cond, t1, t2) => if(cond == True) t1 else if (cond == False) t2 else If(reduce(cond), t1, t2)
|
||||
case IsZero(z) => z match {
|
||||
case Zero => True
|
||||
case Succ(_) => False
|
||||
case other => IsZero(reduce(other))
|
||||
}
|
||||
case Succ(s) => s match {
|
||||
case Zero => throw NoReductionPossible(Zero)
|
||||
case other => Succ(reduce(other))
|
||||
}
|
||||
case Pred(p) => p match {
|
||||
case Zero => Zero
|
||||
case Succ(nv) if (isNumeric(nv)) => nv
|
||||
case other => Pred(reduce(other))
|
||||
}
|
||||
case other => throw NoReductionPossible(other)
|
||||
}
|
||||
|
||||
case class TermIsStuck(t: Term) extends Exception(t.toString)
|
||||
|
||||
/** Perform big step evaluation (result is always a value.)
|
||||
* If evaluation is not possible TermIsStuck exception with
|
||||
* corresponding inner irreducible term should be thrown.
|
||||
*/
|
||||
def eval(t: Term): Term = t match {
|
||||
case True => True
|
||||
case False => False
|
||||
case If(cond, t1, t2) => eval(cond) match {
|
||||
case True => eval(t1)
|
||||
case False => eval(t2)
|
||||
case _ => throw TermIsStuck(t)
|
||||
}
|
||||
case Zero => Zero
|
||||
case Succ(v) => eval(v) match {
|
||||
case Zero => Zero
|
||||
case Pred(nv) => eval(nv)
|
||||
case _ => throw TermIsStuck(t)
|
||||
}
|
||||
case Pred(v) => eval(v) match {
|
||||
case Zero => Zero
|
||||
case Succ(nv) => eval(nv)
|
||||
case _ => throw TermIsStuck(t)
|
||||
}
|
||||
case IsZero(v) => eval(v) match {
|
||||
case Zero => True
|
||||
case Succ(nv) => False
|
||||
case _ => throw TermIsStuck(t)
|
||||
}
|
||||
}
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
val stdin = new java.io.BufferedReader(new java.io.InputStreamReader(System.in))
|
||||
val tokens = new lexical.Scanner(stdin.readLine())
|
||||
phrase(term)(tokens) match {
|
||||
case Success(trees, _) =>
|
||||
for (t <- path(trees))
|
||||
println(t)
|
||||
try {
|
||||
print("Big step: ")
|
||||
println(eval(trees))
|
||||
} catch {
|
||||
case TermIsStuck(t) => println("Stuck term: " + t)
|
||||
}
|
||||
case e =>
|
||||
println(e)
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
package fos
|
||||
|
||||
import scala.util.parsing.input.Positional
|
||||
|
||||
/** Abstract Syntax Trees for terms. */
|
||||
sealed abstract class Term extends Positional
|
||||
case object True extends Term
|
||||
case object False extends Term
|
||||
case class If(cond: Term, t1: Term, t2: Term) extends Term
|
||||
case object Zero extends Term
|
||||
case class Succ(t: Term) extends Term
|
||||
case class Pred(t: Term) extends Term
|
||||
case class IsZero(t: Term) extends Term
|
Reference in New Issue
Block a user