Institute of Computer Science
  1. Courses
  2. 2020/21 fall
  3. Programming Languages (MTAT.03.006)
ET
Log in

Programming Languages 2020/21 fall

  • Info
  • Õppekava
  • Moodle
  • Loengud & Praksid
  • Lisamaterjalid
  • Küsi abi! (Fleep)

KalaParser Scalas

AKT-s oli korduvaks näiteks niinimetatud KalaParser. See tegeles näiteks sellise sisendi parsimisega mingiteks abstraktse süntaksipuu klassideks: (kala, (x,y , null, (), (kala,()) )).

AKT-s tehti selle parsimist kas täiesti käsitsi või ANTLR-iga grammatikast genereeritud parseri abil. scala-parser-combinators võimaldab põhimõtteliselt sama grammatika kirja panna otse Scala koodis, kasutades selleks hulka eeldefineeritud infiksoperaatoreid ja funktsioone (Scala on väga hea DSL'ide defineerimiseks ja kasutamiseks). Lisaks saab sealsamas defineerida ka, mida eduka parsimise korral teha/tagastada, mis võimaldab konstrueerida näiteks avaldise puu.

Järgnevas koodis ongi kogu KalaParser ülesanne lahendatud, aga nüüd Scalas. Defineeritud on vastava puu klassid, toodud kaks erineva keerukusega viisi scala-parser-combinators abil sisendsõne parsida ning näidatud, kuidas parserit käivitada ja selle tulemust kasutada. Lisaks on niisama defineeritud funktsioon nende kala avaldiste "väärtustamiseks".

KalaParser.scala

package kala

import scala.util.parsing.combinator.RegexParsers

// Kala AST klassid
sealed trait KalaNode

case object KalaNull extends KalaNode
case class KalaIdent(name: String) extends KalaNode
case class KalaList(args: List[KalaNode]) extends KalaNode


object KalaParser extends RegexParsers { // RegexParsers annab kõik parsimiseks vajaliku
  // pikem, detailsem ja lihtsam variant
  // grammatika reegel 'kala' on parser, mille tulemuseks on KalaNode
  def kala: Parser[KalaNode] = (
    "null" ^^ { case "null" => KalaNull } // reeglis võib esineda String, ^^-ga defineeritakse parsimise tulemuseks olev väärtus
  | "[a-z]+".r ^^ { case name => KalaIdent(name) } // reeglis võib esineda Regex, ^^ annab parsitud sõne argumendina
  | "(" ~ kalaArgs ~ ")" ^^ { case "(" ~ args ~ ")" => KalaList(args) } // reeglis saab kasutada teisi reegleid ning osi ~-ga järjestada, ^^ all saab ~ kasutada ka mustrisobituses
  ) // alternatiivid on eraldatud |-ga

  // grammatika reegel 'kalaArgs' on parser, mille tulemuseks on List[KalaNode]
  def kalaArgs: Parser[List[KalaNode]] = (
    kala ~ "," ~ kalaArgs ^^ { case node ~ "," ~ args => node :: args }
  | kala ^^ { case node => node :: Nil }
  | "" ^^ { case "" => Nil }
  ) // alternatiivide järjekord on siin väga oluline

  // lühem, kavalam ja keerukam variant
  // keerukamad konstruktsioonid võimaldavad ülaldefineeritu kirjutada palju kompaktsemalt
  def kalaLyhem: Parser[KalaNode] = (
    "null" ^^^ KalaNull // ^^^-ga defineeritakse tulemuseks konstantne väärtus
  | "[a-z]+".r ^^ KalaIdent // KalaIdent konstruktorit kasutatakse kui funktsiooni otse
  | "(" ~> repsep(kalaLyhem, ",") <~ ")" ^^ KalaList // repsep parsib komadega eraldatud jada ise List-iks, ~> ja <~ ignoreerivad tulemuse defineerimisel fikseeritud literaale
  )

  // RegexParsers vaikimisi ignoreerib tühikuid

  // funktsioon, mis kala AST-iga töötab
  def kalaSum(node: KalaNode)(implicit env: Map[String, Int]): Int = node match {
    case KalaNull => 0
    case KalaIdent(name) => env(name)
    case KalaList(args) => args.map(kalaSum).sum // implicit väldib env-i käsitsi edasi andmist
  }

  def main(args: Array[String]): Unit = {
    // terve String-i parsimine käib RegexParsers-ist tuleva parseAll funktsiooni abil, esimeseks argumendiks on Parser (parsitav grammatikareegel)
    parseAll(kalaLyhem, "(kala, (x,y , null, (), (kala,()) ))") match {
      case Success(result, next) => // parsimine õnnestus
        println(result)

        val env = Map("kala" -> 1, "x" -> 2, "y" -> 3)
        println(kalaSum(result)(env)) // 7

      case NoSuccess(msg, next) => println(s"Viga: $msg") // parsimine ebaõnnestus
    }
  }
}
  • Institute of Computer Science
  • Faculty of Science and Technology
  • University of Tartu
In case of technical problems or questions write to:

Contact the course organizers with the organizational and course content questions.
The proprietary copyrights of educational materials belong to the University of Tartu. The use of educational materials is permitted for the purposes and under the conditions provided for in the copyright law for the free use of a work. When using educational materials, the user is obligated to give credit to the author of the educational materials.
The use of educational materials for other purposes is allowed only with the prior written consent of the University of Tartu.
Terms of use for the Courses environment