How to make a scala parser

so i have something like this:

class MyParser extends JavaTokenParsers { var m = new HashMap[String,String] def store = ("var" ~> ident "=") ~ ident ^^ { case k ~ v => m += k -> v } def stored_val = ident ^^ { case k => m(k) } } 

And my problem is that what I really want to do is that parser stored_val fails so that other parsers have the ability to match the input. But now what happens is that the card throws when it cannot find the value.

I tried implementing stored_val as follows:

 def stored_val = ident => { case k => if (m.contains(k)) m(k) else failure("identifier not found") } 

But the problem with this is that failure returns a Parser [Nothing], which is different from String.

+8
scala
source share
2 answers

If you want to check the contents of characters outside the regular expression, you can check the StandardTokenParser . In particular,

 def elem (kind: String, p: (Elem) β‡’ Boolean) : Parser[Elem] 

Parser input elements that satisfy the given predicate elem(kind, p) are successful if the input starts with element e' for which p(e) true.

Edit : For examples of a standard token token, check out Jim McBath’s article on Scala Parser Combiners. I did a quick modification of the first example to demonstrate elem . This is a simple parser that only accepts the sum of odd numbers:

 import scala.util.parsing.combinator.syntactical._ import scala.util.parsing.combinator._ trait Expression case class EConstant(value: Int) extends Expression case class EAdd(lhs: Expression, rhs: Expression) extends Expression object ExpressionParser extends StandardTokenParsers { lexical.delimiters ++= List("+") def oddValue = elem("odd", { x => x.toString.toInt % 2 == 1 }) ^^ { x => EConstant(x.toString.toInt) } def value = numericLit ^^ { x => EConstant(x.toInt) } def sum = oddValue ~ "+" ~ oddValue ^^ { case left ~ "+" ~ right => EAdd(left, right) } def expr = ( sum | value ) def parse(s:String) = { val tokens = new lexical.Scanner(s) phrase(expr)(tokens) } def apply(s:String): Expression = parse(s) match { case Success(tree, _) => tree case e: NoSuccess => throw new IllegalArgumentException("Bad syntax: "+s) } } 

Save the above as ExpressionParser.scala and load it into the REPL as follows:

 scala> :l ExpressionParser.scala Loading ExpressionParser.scala... import scala.util.parsing.combinator.syntactical._ import scala.util.parsing.combinator._ defined trait Expression defined class EConstant defined class EAdd defined module ExpressionParser scala> ExpressionParser("2 + 2") java.lang.IllegalArgumentException: Bad syntax: 2 + 2 at ExpressionParser$.apply(<console>:42) at .<init>(<console>:24) at .<clinit>(<console>) at RequestResult$.<init>(<console>:9) at RequestResult$.<clinit>(<console>) at RequestResult$scala_repl_result(<console>) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988) at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988) at scala.util.con... scala> ExpressionParser("1 + 1") res3: Expression = EAdd(EConstant(1),EConstant(1)) 
+3
source share

Can you use combinator ^? which accepts a partial function ( Scaladoc ):

 def stored_val: Parser[String] = ident ^? { case k if m.contains(k) => m(k) } 

I clicked the full example using tests on Github.

+8
source share

All Articles