When a parser generator is required, some famous parsers that cross our mind are:
Yacc and
Bison for parsers written in C and ANTLR for parsers written in Java but they are designed to run for specific programming languages. This shortens the scope of use of parsers. However, Scala provides a unique and helpful alternative. Instead of using the standalone domain specific language of a parser generator, one can use an internal domain specific language (internal DSL for short). The internal DSL will consist of a library of parser combinators—functions and operators defined in Scala that will serve as building blocks for parsers.
In order to understand this content, one must have basic knowledge of compilers and must understand regular and context free languages.
The first step is always to write down a grammar for the language to be parsed.
Expression : Every expression (represented by expr) is a term which can be followed by a sequence of '+' or '-' operators and further terms.
Term : A term is a factor, possibly followed by a sequence of '*' or '/' operators and further factors.
Factor: A factor is either a numeric literal or an expression in parentheses.
Example for arithmetic expression parser:
expr ::= term {"+" term | "-" term}.
term ::= factor {"*" factor | "/" factor}.
factor ::= ?FloatingPointNumber | "(" expr ")".
| denotes alternative productions
{ ... } denotes repetition (zero or more times)
Scala code for above example:
Scala
import scala.util.parsing.combinator._
class Arith extends JavaTokenParsers
{
def expr: Parser[Any] = term~rep("+"~term | "-"~term)
def term: Parser[Any] = factor~rep("*"~factor | "/"~factor)
def factor: Parser[Any] = floatingPointNumber | "("~expr~")"
}
The parsers for arithmetic expressions are contained in a class that inherits from the trait JavaTokenParsers.
Steps for converting Context free grammar into code:
- Every production becomes a method, hence add a prefix 'def'.
- The result type of each method is Parser[Any], so we need to change the ::= symbol to ": Parser[Any] =".
- In the grammar, sequential composition was implicit, but in the program it is expressed by an explicit operator: ~. So we need to insert a '~' between every two consecutive symbols of a production.
- Repetition is expressed rep( ... ) instead of { ... }.
- The period(.) at the end of each production is omitted, however one can use semicolons(;) too.
Test whether your parser works or not with the code below!
Scala
object ParseExpr extends Arith
{
def main(args: Array[String])
{
println("input : "+ args(0))
println(parseAll(expr, args(0)))
}
}
The ParseExpr object defines a main method that parses the first command line argument passed to it. Parsing is done by the expression: parseAll(expr, input)
We can run the arithmetic parser with the following command:
$ scala ParseExpr "4 * (5 + 7)"
input: 4 * (5 + 7)
[1.12] parsed: ((4~List((*~(((~((5~List())~List((+ ~(7~List())))))~)))))~List())
The output tells us that the parser successfully analyzed the input string up to position[1.12]. That means the first line and the twelfth column or we can say the whole input string was parsed.
We could also check whether the parser works for wrong input and gives an error or not.
Example:
$ scala ParseExpr "2 * (3 + 7))"
input: 2 * (3 + 7))
[1.12] failure: `-' expected but `)' found
2 * (3 + 7)) ˆ
The expr parser parsed everything except the final closing parenthesis which does not form part of the arithmetic expression. The 'parseAll' method then issued an error message, saying that it expected a operator at the point of the closing parenthesis.
Similar Reads
Iterators in Scala
An iterator is a way to access elements of a collection one-by-one. It resembles to a collection in terms of syntax but works differently in terms of functionality. An iterator defined for any collection does not load the entire collection into the memory but loads elements one after the other. Ther
5 min read
Scala For Comprehensions
Comprehensions have the structure for (enumerators) yield e, wherever enumerators refers to a semicolon-separated list of enumerators. Enumerator is either a generator that introduces new variables, or it's a filter. A comprehension evaluates the body e for every binding generated by the enumerators
3 min read
Monads in Scala
In Scala, Monads is a construction which performs successive calculations. It is an object which covers the other object. It is worth noting that here, the output of an operation at some step is an input to another computations, which is a parent to the recent step of the program stated. Monad is ne
4 min read
Concatenate Two Maps in Scala
The concatenation of Scala map is obtained by utilizing ++ operator. Syntax : def ++(xs: Map[(A, B)]): Map[A, B] Return Type: It returns a single map by concatenating two maps but it separates the identical keys. Example #1: Scala // Scala program of concatenating // two maps // Creating object obje
2 min read
Scala | reduce() Function
The reduce() method is a higher-order function that takes all the elements in a collection (Array, List, etc) and combines them using a binary operation to produce a single value. It is necessary to make sure that operations are commutative and associative. Anonymous functions are passed as paramete
3 min read
Scala Iterator count() method with example
The count() method belongs to the concrete value members of the class Abstract Iterator. It is defined in the class IterableOnceOps. It counts the number of elements in the stated collection which satisfy the given predicate. Method Definition : def count(p: (A) => Boolean): Int Where, p is the p
1 min read
Program to convert Java list to an iterator in Scala
A java list can be converted to an iterator in Scala by utilizing toIterator method of Java in Scala. Here, we need to import Scalaâs JavaConversions object in order to make this conversions work else an error will occur. Now, lets see some examples and then discuss how it works in details. Example:
3 min read
ListMap in Scala
Immutable maps Implemented by using a list-based data structure. The Scala List class holds a sequenced, linear list of items. We must import scala.collection.mutable.ListMap for ListMap. ListMap collection used only for a small number of elements.Syntax: var listMapName = ListMap("k1"->"v1", "k2
3 min read
How to create partition in scala?
In the world of big data, processing efficiency is key, and data partitioning emerges as a vital tool for optimizing performance. By strategically dividing large datasets into smaller subsets, partitioning enables parallel processing, significantly accelerating data manipulation tasks. In Scala, ach
2 min read
Scala | Methods to Call Option
The Option in Scala is referred to a carrier of single or no element for a stated type. When a method returns a value which can even be null then Option is utilized i.e, the method defined returns an instance of an Option, in place of returning a single object or a null. There are a few methods that
5 min read