progs/matcher/re1.sc
changeset 981 14e5ae1fb541
parent 965 94f5cce73a4f
--- a/progs/matcher/re1.sc	Mon Feb 03 13:25:59 2025 +0000
+++ b/progs/matcher/re1.sc	Fri Sep 05 16:59:48 2025 +0100
@@ -10,15 +10,16 @@
 //
 
  
-// regular expressions
-abstract class Rexp
-case object ZERO extends Rexp                    // matches nothing
-case object ONE extends Rexp                     // matches an empty string
-case class CHAR(c: Char) extends Rexp            // matches a character c
-case class ALT(r1: Rexp, r2: Rexp) extends Rexp  // alternative
-case class SEQ(r1: Rexp, r2: Rexp) extends Rexp  // sequence
-case class STAR(r: Rexp) extends Rexp            // star
-
+// regular expressions (as enum in Scala 3)
+enum Rexp {
+  case ZERO                     // matches nothing
+  case ONE                      // matches an empty string
+  case CHAR(c: Char)            // matches a character c
+  case ALT(r1: Rexp, r2: Rexp)  // alternative
+  case SEQ(r1: Rexp, r2: Rexp)  // sequence
+  case STAR(r: Rexp)            // star
+}
+import Rexp._
 
 // nullable function: tests whether a regular 
 // expression can recognise the empty string  
@@ -172,9 +173,74 @@
   }
 }
 
+
+
+// Some code for pretty printing regexes as trees
+
+def implode(ss: Seq[String]) = ss.mkString("\n")
+def explode(s: String) = s.split("\n").toList
+
+def lst(s: String) : String = explode(s) match {
+  case hd :: tl => implode(" └" ++ hd :: tl.map("  " ++ _))
+  case Nil => ""
+}
+
+def mid(s: String) : String = explode(s) match {
+  case hd :: tl => implode(" ├" ++ hd :: tl.map(" │" ++ _))
+  case Nil => ""
+}
+
+def indent(ss: Seq[String]) : String = ss match {
+  case init :+ last => implode(init.map(mid) :+ lst(last))
+  case _ => ""
+}
+
+def pp(e: Rexp) : String = e match {
+  case ZERO => "0\n"
+  case ONE => "1\n"
+  case CHAR(c) => s"$c\n"
+  case ALT(r1, r2) => "ALT\n" ++ pps(r1, r2)
+  case SEQ(r1, r2) => "SEQ\n" ++ pps(r1, r2)
+  case STAR(r) => "STAR\n" ++ pps(r)
+}
+def pps(es: Rexp*) = indent(es.map(pp))
+
+
 @main
-def all() = { test1(); test2() ; test3() } 
+def test4() = {
+  println(pp(r2))
+  println(pp(ders("x".toList, r2)))
+  println(pp(ders("xy".toList, r2)))
+  println(pp(ders("xyz".toList, r2)))
+}
+
+@main
+def all() = { test1(); test2() ; test3() ; test4() } 
 
 
 
 
+
+// partial derivatives produce a set of regular expressions
+def pder(c: Char, r: Rexp) : Set[Rexp] = r match {
+  case ZERO => Set()
+  case ONE => Set()
+  case CHAR(d) => if (c == d) Set(ONE) else Set()
+  case ALT(r1, r2) => pder(c, r1) ++ pder(c, r2)
+  case SEQ(r1, r2) => {
+    (for (pr1 <- pder(c, r1)) yield SEQ(pr1, r2)) ++
+    (if (nullable(r1)) pder(c, r2) else Set())
+  }
+  case STAR(r1) => {
+    for (pr1 <- pder(c, r1)) yield SEQ(pr1, STAR(r1))
+  }
+}
+
+def pders(s: List[Char], rs: Set[Rexp]) : Set[Rexp] = s match {
+  case Nil => rs
+  case c::s => pders(s, rs.flatMap(pder(c, _)))
+}
+
+def pders1(s: String, r: Rexp) = pders(s.toList, Set(r))
+
+