blob: c9029ffb11384efdbb0ed2819a936a5caa6766b0 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
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 | <empty>)
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]): Unit =
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 <expr-string>"
)
}
object TestExpr {
def main(args: Array[String]): unit =
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 <expr-string>"
)
}
def main(args: Array[String]): Unit = {
TestList.main(Array("(a,b,(1,2))"))
TestExpr.main(Array("2+3+(4+1)"))
}
}
|