Introduction to Scala Parser And Combinators

Table of contents
Reading Time: 2 minutes

Scala parser combinators are a Powerful way to build parsers that can be used in everyday programs. But it’s hard to understand the plumbing pieces and how to get started. After you get the first couple of samples to compile and work, the plumbing starts to make sense,this is very easy way to design your own programming language, using its parser library

so lets get started first thing is that we need to extend the regex parser

to use scala parser combinators you need to add following dependencies in your build.sbt

libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.5"

sbt version is 2.11.3

EBNF grammar for this language would look something like this:

def symbol: Parser[Any] = "+" | "-" | "*"

def number: Parser[Int] = """(0|[1-9]\d*)""".r ^^ { _.toInt }

symbol is our parser of type any that state that it will contain either the +,-, * symbol using | operator

number is parser of type int looking at it you might get confused ,it states that it will evaluate a regular expression of type int,then you might  think what is is  ^^ symbol is doing it denotes the operation that needs to be performed when the left hand side expression is evaluated so here it is converting this expression value to integer

def expression = {
  number ~ symbol ~ number ^^ { case firstOperand ~ operator ~ secondOperand =>
    validateAndExtractFirstValue(firstOperand) + validateAndExtractSecondValue(secondOperand)
  }

now what is this method is doing

~ symbol in scala parser is used to seperate out the token in scala,it will parse the expression if the expression contain a number followed by a symbol followed by another number,then it simply add those two numbers

to be more concise here is the full code

import scala.util.Try
import scala.util.parsing.combinator.RegexParsers

class ScalaParser extends RegexParsers {

  def expression = {
    number ~ symbol ~ number ^^ { case firstOperand ~ operator ~ secondOperand =>
      validateAndExtractFirstValue(firstOperand) + validateAndExtractSecondValue(secondOperand)
    }
  }

  def symbol: Parser[Any] = "+" | "-" | "*"

  def number: Parser[Int] = """(0|[1-9]\d*)""".r ^^ { _.toInt }

  def validateAndExtractFirstValue(firstOperand: Any): Int = {
    val firstValue: Try[Int] = Try(firstOperand.toString.toInt)
    firstValue match {
      case util.Success(value) => value
      case util.Failure(exception) => throw new Exception("can not convert values to integer")
    }
  }

  def validateAndExtractSecondValue(secondOperand: Any): Int = {
    val secondValue = Try(secondOperand.toString.toInt)
    secondValue match {
      case util.Success(value) => value
      case util.Failure(exception) => throw new Exception("can not convert values to integer")
    }
  }
}

object TestSimpleParser extends ScalaParser {
  def main(args: Array[String]) = {
    parse(expression, "5 + 4") match {
      case Success(result, _) => println(result)
      case Failure(msg, _) => println("FAILURE: " + msg)
      case Error(msg, _) => println("ERROR: " + msg)
    }

  }
}

to be clear to call the parser you have to call the parse method it takes two arguments one is type of parser and second one is statement to be parsed

i think this blog will help to getting started with scala parser and combinators

KNOLDUS-advt-sticker

Discover more from Knoldus Blogs

Subscribe now to keep reading and get access to the full archive.

Continue reading