diff -r 0c491eff5b01 -r 14e5ae1fb541 progs/matcher/re1.sc --- 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)) + +