From c5c6d4a8ce75993d2dcd80f6360b45de534a3f41 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Tue, 17 Jul 2007 20:49:24 +0000 Subject: updated examples to new combinator library --- docs/examples/Parsers.scala | 108 ------------------------ docs/examples/parsers1.scala | 122 --------------------------- docs/examples/parsers2.scala | 69 --------------- docs/examples/parsing/ArithmeticParser.scala | 57 +++++++++++++ docs/examples/parsing/ListParser.scala | 33 ++++++++ 5 files changed, 90 insertions(+), 299 deletions(-) delete mode 100644 docs/examples/Parsers.scala delete mode 100644 docs/examples/parsers1.scala delete mode 100644 docs/examples/parsers2.scala create mode 100644 docs/examples/parsing/ArithmeticParser.scala create mode 100644 docs/examples/parsing/ListParser.scala (limited to 'docs/examples') diff --git a/docs/examples/Parsers.scala b/docs/examples/Parsers.scala deleted file mode 100644 index 4129edca2d..0000000000 --- a/docs/examples/Parsers.scala +++ /dev/null @@ -1,108 +0,0 @@ -package examples - -abstract class Parsers { - - type inputType - - trait Parser[a] { - - type Result = Option[Pair[a, inputType]]; - - def apply(in: inputType): Result; - - def filter(pred: a => boolean) = new Parser[a] { - def apply(in: inputType): Result = Parser.this.apply(in) match { - case None => None - case Some(Pair(x, in1)) => if (pred(x)) Some(Pair(x, in1)) else None - } - } - - def map[b](f: a => b) = new Parser[b] { - def apply(in: inputType): Result = Parser.this.apply(in) match { - case None => None - case Some(Pair(x, in1)) => Some(Pair(f(x), in1)) - } - } - - def flatMap[b](f: a => Parser[b]) = new Parser[b] { - def apply(in: inputType): Result = Parser.this.apply(in) match { - case None => None - case Some(Pair(x, in1)) => f(x).apply(in1) - } - } - - def ||| (p: => Parser[a]) = new Parser[a] { - def apply(in: inputType): Result = Parser.this.apply(in) match { - case None => p(in) - case s => s - } - } - - def &&& [b](p: => Parser[b]): Parser[b] = - for (_ <- this; x <- p) yield x - } - - def succeed[a](x: a) = new Parser[a] { - def apply(in: inputType): Result = Some(Pair(x, in)) - } - - def rep[a](p: Parser[a]): Parser[List[a]] = - rep1(p) ||| succeed(List()) - - def rep1[a](p: Parser[a]): Parser[List[a]] = - for (x <- p; xs <- rep(p)) yield x :: xs - - def opt[a](p: Parser[a]): Parser[List[a]] = - (for (x <- p) yield List(x)) ||| succeed(List()) -} - -class Tokenizer(in: Iterator[char], delimiters: String) extends Iterator[String] { - - val EOI: char = 0 - - def nextChar() = - if (in.hasNext) in.next else EOI - - private var ch = nextChar(); - - def isDelimiter(ch: Char) = { - var i = 0 - while (i < delimiters.length() && delimiters.charAt(i) != ch) { i += 1 } - i < delimiters.length() - } - - def hasNext: boolean = ch != EOI - - private val buf = new StringBuffer - - def next: String = { - while (ch <= ' ' && ch != EOI) nextChar() - if (ch == EOI) "" - else { - if (isDelimiter(ch)) ch.toString() - else { - buf.setLength(0); buf append ch - while (ch > ' ' && ch != EOI && !isDelimiter(ch)) { - buf append ch; nextChar(); - } - buf.toString() - } - } - } -} - -trait TokenParsers extends Parsers { - type inputType = Stream[String] - def nextToken() = new Parser[String] { - def apply(in: inputType): Result = - if (in.isEmpty) None else Some(Pair(in.head, in.tail)) - } -} - -trait CharParsers extends Parsers { - def any: Parser[char] - def chr(ch: char) = - for (c <- any if c == ch) yield c - def chr(p: char => boolean) = - for (c <- any if p(c)) yield c -} diff --git a/docs/examples/parsers1.scala b/docs/examples/parsers1.scala deleted file mode 100644 index e4aeea3613..0000000000 --- a/docs/examples/parsers1.scala +++ /dev/null @@ -1,122 +0,0 @@ -package examples - -object parsers1 { - - abstract class Parsers { - - type inputType; - - abstract class Parser { - - type Result = Option[inputType] - - def apply(in: inputType): Result - - /*** p &&& q applies first p, and if that succeeds, then q - */ - def &&& (q: => Parser) = new Parser { - def apply(in: inputType): Result = Parser.this.apply(in) match { - case None => None - case Some(in1) => q(in1) - } - } - - /*** p ||| q applies first p, and, if that fails, then q. - */ - def ||| (q: => Parser) = new Parser { - def apply(in: inputType): Result = Parser.this.apply(in) match { - case None => q(in) - case s => s - } - } - } - - val empty = new Parser { - def apply(in: inputType): Result = Some(in) - } - - val fail = new Parser { - def apply(in: inputType): Result = None - } - - def opt(p: Parser): Parser = p ||| empty // p? = (p | ) - def rep(p: Parser): Parser = opt(rep1(p)) // p* = [p+] - def rep1(p: Parser): Parser = p &&& rep(p) // p+ = p p* - } - - trait ListParsers extends Parsers { - def chr(p: char => boolean): Parser - def chr(c: char): Parser = chr((d: char) => d == c) - - def letter : Parser = chr((c: char) => Character.isLetter(c)) - def digit : Parser = chr((c: char) => Character.isDigit(c)) - - def ident : Parser = letter &&& rep(letter ||| digit) - def number : Parser = digit &&& rep(digit) - def list : Parser = chr('(') &&& listElems &&& chr(')') - def listElems : Parser = expr &&& (chr(',') &&& listElems ||| empty) - def expr : Parser = ident ||| number ||| list - } - - trait ExprParsers extends Parsers { - def chr(p: char => boolean): Parser - def chr(c: char): Parser = chr((d: char) => d == c) - - def digit : Parser = chr((c: char) => Character.isDigit(c)) - def number : Parser = digit &&& rep(digit) - def summand : Parser = number ||| chr('(') &&& expr &&& chr(')') - def expr : Parser = summand &&& rep(chr('+') &&& summand) - } - - class ParseString(s: String) extends Parsers { - type inputType = Int - val input = 0 - def chr(p: char => boolean) = new Parser { - def apply(in: int): Parser#Result = - if (in < s.length() && p(s charAt in)) Some(in + 1) - else None - } - } - - object TestList { - def main(args: Array[String]) { - Console.println( - if (args.length == 1) { - val ps = new ParseString(args(0)) with ListParsers - ps.expr(ps.input) match { - case Some(n) => - "parsed: " + args(0).substring(0, n) - case None => - "nothing parsed" - } - } - else - "usage: java examples.TestList " - ) - } - } - - object TestExpr { - def main(args: Array[String]) { - Console.println( - if (args.length == 1) { - val ps = new ParseString(args(0)) with ExprParsers - ps.expr(ps.input) match { - case Some(n) => - "parsed: " + args(0).substring(0, n) - case None => - "nothing parsed" - } - } - else - "usage: java examples.TestExpr " - ) - } - } - - def main(args: Array[String]) { - TestList.main(Array("(a,b,(1,2))")) - TestExpr.main(Array("2+3+(4+1)")) - } - -} diff --git a/docs/examples/parsers2.scala b/docs/examples/parsers2.scala deleted file mode 100644 index 71ece15552..0000000000 --- a/docs/examples/parsers2.scala +++ /dev/null @@ -1,69 +0,0 @@ -package examples - -object parsers2 { - - abstract class Tree - case class Id(s: String) extends Tree - case class Num(n: int) extends Tree - case class Lst(elems: List[Tree]) extends Tree - - def isLetter = (c: char) => Character.isLetter(c) - def isLetterOrDigit: char => boolean = Character.isLetterOrDigit - def isDigit: char => boolean = Character.isDigit - - trait ListParsers extends CharParsers { - - def ident: Parser[Tree] = - for ( - c: char <- chr(isLetter); - cs: List[char] <- rep(chr(isLetterOrDigit)) - ) yield Id((c :: cs).mkString("", "", "")) - - def number: Parser[Tree] = - for ( - d: char <- chr(isDigit); - ds: List[char] <- rep(chr(isDigit)) - ) yield Num(((d - '0') /: ds) ((x, digit) => x * 10 + digit - '0')) - - def list: Parser[Tree] = - for ( - _ <- chr('('); - es <- listElems ||| succeed(List()); - _ <- chr(')') - ) yield Lst(es) - - def listElems: Parser[List[Tree]] = - for ( - x <- expr; - xs <- chr(',') &&& listElems ||| succeed(List()) - ) yield x :: xs - - def expr: Parser[Tree] = - list ||| ident ||| number - - } - - class ParseString(s: String) extends Parsers { - type inputType = int - val input = 0 - def any = new Parser[char] { - def apply(in: int): Parser[char]#Result = - if (in < s.length()) Some(Pair(s charAt in, in + 1)) else None - } - } - - def main(args: Array[String]) { - Console.println( - if (args.length == 1) { - val ps = new ParseString(args(0)) with ListParsers - ps.expr(ps.input) match { - case Some(Pair(list, _)) => "parsed: " + list - case None => "nothing parsed" - } - } - else - "usage: scala examples.parsers2 " - ) - } - -} diff --git a/docs/examples/parsing/ArithmeticParser.scala b/docs/examples/parsing/ArithmeticParser.scala new file mode 100644 index 0000000000..2aac4b6f6c --- /dev/null +++ b/docs/examples/parsing/ArithmeticParser.scala @@ -0,0 +1,57 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2007, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package examples.parsing + +import scala.util.parsing.combinator.lexical.StdLexical +import scala.util.parsing.combinator.syntactical.StdTokenParsers + +/** Parse and evaluate a numeric expression as a sequence of terms, separated by + or - + * a term is a sequence of factors, separated by * or / + * a factor is a parenthesized expression or a number + * + * @author Adriaan Moors + */ +object arithmeticParser extends StdTokenParsers { + type Tokens = StdLexical ; val lexical = new StdLexical + lexical.delimiters ++= List("(", ")", "+", "-", "*", "/") + + lazy val expr = term*("+" ^^ {(x: int, y: int) => x + y} | "-" ^^ {(x: int, y: int) => x - y}) + lazy val term = factor*("*" ^^ {(x: int, y: int) => x * y} | "/" ^^ {(x: int, y: int) => x / y}) + lazy val factor: Parser[int] = "(" ~ expr ~ ")" | numericLit ^^ (_.toInt) + + def main(args: Array[String]) { + println( + if (args.length == 1) { + expr(new lexical.Scanner(args(0))) + } + else + "usage: scala examples.parsing.arithmeticParser " + ) + } +} + + +object arithmeticParserDesugared extends StdTokenParsers { + type Tokens = StdLexical ; val lexical = new StdLexical + lexical.delimiters ++= List("(", ")", "+", "-", "*", "/") + + lazy val expr = chainl1(term, (keyword("+").^^{(x: int, y: int) => x + y}).|(keyword("-").^^{(x: int, y: int) => x - y})) + lazy val term = chainl1(factor, (keyword("*").^^{(x: int, y: int) => x * y}).|(keyword("/").^^{(x: int, y: int) => x / y})) + lazy val factor: Parser[int] = keyword("(").~(expr.~(keyword(")"))).|(numericLit.^^(x => x.toInt)) + + def main(args: Array[String]) { + println( + if (args.length == 1) { + expr(new lexical.Scanner(args(0))) + } + else + "usage: scala examples.parsing.arithmeticParser " + ) + } +} \ No newline at end of file diff --git a/docs/examples/parsing/ListParser.scala b/docs/examples/parsing/ListParser.scala new file mode 100644 index 0000000000..65354482f3 --- /dev/null +++ b/docs/examples/parsing/ListParser.scala @@ -0,0 +1,33 @@ +package examples.parsing + +import scala.util.parsing.combinator.{Parsers, ImplicitConversions, ~, mkTilde} +import scala.util.parsing.input.CharArrayReader + +object listParser { + abstract class Tree + case class Id(s: String) extends Tree + case class Num(n: Int) extends Tree + case class Lst(elems: List[Tree]) extends Tree + + import Character.{isLetter, isLetterOrDigit, isDigit} + def mkString(cs: List[Any]) = cs.mkString("") + + class ListParsers extends Parsers { + type Elem = Char + + lazy val ident = rep1(elem("letter", isLetter), elem("letter or digit", isLetterOrDigit)) ^^ {cs => Id(mkString(cs))} + lazy val number = chainl1(elem("digit", isDigit) ^^ (_ - '0'), success ^^ {(accum: Int, d: Int) => accum * 10 + d}) ^^ Num + lazy val list = '(' ~ repsep(expr, ',') ~ ')' ^^ Lst + lazy val expr: Parser[Tree] = list | ident | number + } + + def main(args: Array[String]) { + println( + if (args.length == 1) { + (new ListParsers).expr(new CharArrayReader(args(0).toCharArray())) + } + else + "usage: scala examples.parsing.listParser " + ) + } +} -- cgit v1.2.3