diff --git a/src/main/net/podkopaev/cpsComb.kt b/src/main/net/podkopaev/cpsComb.kt
index c1cd46a..48070ba 100644
--- a/src/main/net/podkopaev/cpsComb.kt
+++ b/src/main/net/podkopaev/cpsComb.kt
@@ -338,7 +338,7 @@ fun many1(parser: Recognizer): Recognizer> =
fun char(c: Char): Recognizer = satp { it == c }
val space : Recognizer =
- char(' ') / char('\n') / char('\t') /
+ char(' ') / char('\n') / char('\t') / char('\n') /
transp(terminal("\r\n")) { '\n' }
val spaces: Recognizer = fix { s -> space / transp(seq(space, s), {' '}) }
@@ -357,12 +357,12 @@ val alpha: Recognizer = satp {
val alphaOrDigit: Recognizer = alpha / digit
val number: Recognizer = (digit map {it-> it.toString().toInt()}) / (many1(digit) map { it.toStr().toInt() })
val word : Recognizer = many1(alpha) map { it.toStr() }
-val symbol: Recognizer = seq(alpha, many0(alphaOrDigit)) map {
+val symbol: Recognizer = (seq(alpha, many0(alphaOrDigit)) map {
val sb = StringBuilder()
sb.append(it.first)
it.second.forEach { sb.append(it) }
sb.toString()
- }
+ }) / (alpha map { t -> t.toString() })
fun leftAssocp(opp: Recognizer, elemp: Recognizer,
f: (String, A, A) -> A): Recognizer {
val rightp = opp + elemp
diff --git a/src/main/net/podkopaev/grammar/HairpinGrammar.kt b/src/main/net/podkopaev/grammar/HairpinGrammar.kt
new file mode 100644
index 0000000..48f3b49
--- /dev/null
+++ b/src/main/net/podkopaev/grammar/HairpinGrammar.kt
@@ -0,0 +1,30 @@
+package net.podkopaev.grammar.HairpinGrammar
+
+import net.podkopaev.cpsComb.*
+/**
+ * A context-free grammar for an RNA stem loop.
+ * S -> aW1u | cW1g | gW1c | uW1a
+ * W1 -> aW2u | cW2g | gW2c | uW2a
+ * W2 -> aW3u | cW3g | gW3c | uW3a
+ * W3 -> gaaa | gcaa
+ *
+ */
+
+val a = terminal("a") map { 1 }
+val u = terminal("u") map { 1 }
+val c = terminal("c") map { 1 }
+val g = terminal("g") map { 1 }
+
+val pl = { t:Pair, Int> -> t.first.second + 2 }
+
+val pW3: Recognizer = (seq(seq(seq(g, a), a), a) map { t -> t.first.first.second + 3 }) /
+ (seq(seq(seq(g, c), a), a) map { t -> t.first.first.second + 3 })
+
+val pW2: Recognizer = (seq(seq(a, pW3), u) map pl) / (seq(seq(c, pW3), g) map pl) /
+ (seq(seq(g, pW3), c) map pl) / (seq(seq(u, pW3), a) map pl)
+
+val pW1: Recognizer = (seq(seq(a, pW2), u) map pl) / (seq(seq(c, pW2), g) map pl) /
+ (seq(seq(g, pW2), c) map pl) / (seq(seq(u, pW2), a) map pl)
+
+val pS: Recognizer = (seq(seq(a, pW1), u) map pl) / (seq(seq(c, pW1), g) map pl) /
+ (seq(seq(g, pW1), c) map pl) / (seq(seq(u, pW1), a) map pl)
diff --git a/src/main/net/podkopaev/grammar/PseudoknotsGrammar.kt b/src/main/net/podkopaev/grammar/PseudoknotsGrammar.kt
new file mode 100644
index 0000000..8696c0d
--- /dev/null
+++ b/src/main/net/podkopaev/grammar/PseudoknotsGrammar.kt
@@ -0,0 +1,37 @@
+package net.podkopaev.grammar.PseudoknotsGrammar
+
+import net.podkopaev.cpsComb.*
+
+/**
+ * L2 = { [^i (^j ]^i )^j | i, j > 0 }
+ * S -> S1 & S5
+ * p1 -> [
+ * p2 -> ]
+ * p3 -> (
+ * p4 -> )
+ *
+ * S1 -> S2 S3
+ * S2 -> p1 S2 p2 | S4
+ * S4 -> p3 S4 | eps
+ * S3 -> p4 S3 | eps
+ *
+ * S5 -> S6 S7
+ * S6 -> p1 S6 | eps
+ * S7 -> p3 S7 p4 | S8
+ * S8 -> p2 S8 | eps
+ */
+
+val p1 = terminal("[") map { 1 }
+val p2 = terminal("]") map { 1 }
+val p3 = terminal("(") map { 1 }
+val p4 = terminal(")") map { 1 }
+
+val pS3: Recognizer = fix { S3 -> (seq(p4, S3) map { t -> 1 + t.second }) / p4 }
+val pS4: Recognizer = fix { S4 -> (seq(p3, S4) map { t -> 1 + t.second }) / p3 }
+val pS2: Recognizer = fix { S2 -> (seq(seq(p1, S2), p2) map { t -> 1 + t.first.second }) / pS4 }
+
+val pS6: Recognizer = fix { S6 -> (seq(p1, S6) map { t -> 1 + t.second }) / p1 }
+val pS8: Recognizer = fix { S8 -> (seq(p2, S8) map { t -> 1 + t.second }) / p2 }
+val pS7: Recognizer = fix { S7 -> (seq(seq(p3, S7), p4) map { t -> 1 + t.first.second }) / pS8 }
+
+val grParser = and(seq(pS2, pS3), seq(pS6, pS7)) map { t -> t.first.first * 2 }
\ No newline at end of file
diff --git a/src/main/net/podkopaev/whileParser/cpsParser.kt b/src/main/net/podkopaev/whileParser/cpsParser.kt
new file mode 100644
index 0000000..776a390
--- /dev/null
+++ b/src/main/net/podkopaev/whileParser/cpsParser.kt
@@ -0,0 +1,52 @@
+package net.podkopaev.cpsParser
+
+import net.podkopaev.cpsComb.*
+import net.podkopaev.whileParser.Expr
+import net.podkopaev.whileParser.Stmt
+
+fun generateExprParser(): Recognizer = fix {
+ val corep = (number map { Expr.Con(it) as Expr }) /
+ (symbol map { Expr.Var(it) as Expr }) /
+ paren( sp(it) )
+ val op1p = rightAssocp(sp(terminal("^")), corep) { l, op, r -> Expr.Binop(l, op, r) }
+ val op2p = rightAssocp(sp(terminal("*") / terminal("/") / terminal("%")), op1p) {
+ op, e1, e2 ->
+ Expr.Binop(op, e1, e2)
+ }
+ val op3p = assocp (sp(terminal("+") / terminal("-")), op2p) {
+ op, e1, e2 ->
+ Expr.Binop(op, e1, e2)
+ }
+ return@fix op3p
+}
+val exprParser: Recognizer = generateExprParser()
+
+fun generateStmtParser(): Recognizer = fix {
+ val readp : Recognizer = terminal("read" ) seqr spaces seqr paren(sp(symbol)) map { Stmt.Read (it) as Stmt }
+ val writep : Recognizer = terminal("write") seqr spaces seqr paren(sp(exprParser)) map { Stmt.Write(it) as Stmt }
+ val assignp: Recognizer = ((symbol seql spaces seql terminal(":=") seql spaces) + exprParser) map { nameexpr ->
+ Stmt.Assign(nameexpr.first, nameexpr.second) as Stmt
+ }
+ val ifp = (terminal("if" ) seqr spaces seqr paren(sp(exprParser)) seql spaces) +
+ (terminal("then") seqr spaces seqr it seql spaces) +
+ (terminal("else") seqr spaces seqr it seql spaces) - terminal("fi") map {
+ ete -> Stmt.If(ete.first.first, ete.first.second, ete.second) as Stmt
+ }
+ val whilep = (terminal("while") seqr spaces seqr exprParser seql spaces) +
+ (terminal("do" ) seqr spaces seqr it seql spaces) -
+ terminal("od") map {
+ eb -> Stmt.While(eb.first, eb.second) as Stmt
+ }
+ val corepp: Recognizer = readp / writep / assignp / ifp / whilep
+ val parser = assocp(terminal(";"), corepp) {
+ op, s1, s2 ->
+ Stmt.Seq(s1, s2)
+ }
+ return@fix parser
+}
+val stmtParser = generateStmtParser()
+
+fun assocp(opp: Recognizer, elemp: Recognizer,
+ f: (String, A, A) -> A): Recognizer = fix { P ->
+ elemp / ((elemp + opp + P) map { f(it.first.second, it.first.first, it.second) })
+}
\ No newline at end of file
diff --git a/src/test/net/podkopaev/LCpsParserTest.kt b/src/test/net/podkopaev/LCpsParserTest.kt
new file mode 100644
index 0000000..685e552
--- /dev/null
+++ b/src/test/net/podkopaev/LCpsParserTest.kt
@@ -0,0 +1,106 @@
+package net.podkopaev.whileParser.cpsParser
+
+import net.podkopaev.cpsParser.*
+import net.podkopaev.whileParser.Expr
+
+
+import org.junit.Assert
+import org.junit.Test
+
+class LCpsParserTest {
+ @Test fun test0() {
+ val parser = exprParser
+ Assert.assertEquals(Expr.Con(123), parser.parse("123", parser))
+ }
+
+ @Test fun test01() {
+ val parser = exprParser
+ Assert.assertEquals(Expr.Con(123), parser.parse("( 123 )", parser))
+ }
+ @Test fun test1() {
+ val parser = exprParser
+ val result = parser.parse("abc0", parser)
+ Assert.assertEquals(Expr.Var("abc0"), result)
+ }
+ @Test fun test2() {
+ val parser = exprParser
+ val result = parser.parse("1 ^ 2 ^ 3", parser)
+ Assert.assertEquals(Expr.Binop("^", Expr.Con(1),
+ Expr.Binop("^", Expr.Con(2), Expr.Con(3))),
+ result)
+ }
+ @Test fun test03() {
+ val parser = exprParser
+ val result = parser.parse("1 + 2", parser)
+ Assert.assertEquals(Expr.Binop("+", Expr.Con(1), Expr.Con(2)),
+ result)
+ }
+
+ @Test fun test4() {
+ val parser = exprParser
+ val result = parser.parse("1 + 2 + 3", parser)
+ Assert.assertEquals(6, result?.calc(hashMapOf()))
+ }
+
+ @Test fun test5() {
+ val parser = exprParser
+ val result = parser.parse("1 + 2 * 3", parser)
+ Assert.assertEquals(7, result?.calc(hashMapOf()))
+ }
+
+ @Test fun test7() {
+ val parser = stmtParser
+ val result = parser.parse("write ( 5 )", parser)
+ Assert.assertEquals(listOf(5), result?.interpret(listOf()))
+ }
+
+ @Test fun test8() {
+ val parser = stmtParser
+ val result = parser.parse("x0 := 8 - 2;write ( x0 )", parser)
+ Assert.assertEquals(listOf(6), result?.interpret(listOf()))
+ }
+
+ @Test fun test9() {
+ val parser = stmtParser
+ val result = parser.parse("write ( 5 + 8 );write ( 5 )", parser)
+ Assert.assertEquals(listOf(13,5), result?.interpret(listOf()))
+ }
+
+ @Test fun test10() {
+ val parser = stmtParser
+ val result = parser.parse("x := 3;write ( 5 );write ( 10 )", parser)
+ Assert.assertEquals(listOf(5, 10), result?.interpret(listOf()))
+ }
+
+ @Test fun test11() {
+ val parser = stmtParser
+ val result = parser.parse("x := 3", parser)
+ Assert.assertEquals(listOf(), result?.interpret(listOf()))
+ }
+ @Test fun test12() {
+ val program = "read ( n )"
+ val parser = stmtParser
+ val result = parser.parse(program, parser)
+ Assert.assertEquals(listOf(), result?.interpret(listOf(2)))
+ }
+ @Test fun test13() {
+ val program = "read ( n );read ( k )"
+ val parser = stmtParser
+ val result = parser.parse(program, parser)
+ Assert.assertEquals(listOf(), result?.interpret(listOf(2, 5)))
+ }
+
+ val logpowProgram =
+ """read ( n );read ( k );r := 1;while k do
+ if ( k % 2 ) then
+ r := ( r * n );k := ( k - 1 )
+ else
+ n := ( n * n );k := ( k / 2 )
+ fi od;write ( r )"""
+
+ @Test fun test14() {
+ val parser = stmtParser
+ val result = parser.parse(logpowProgram, parser)
+ Assert.assertEquals(listOf(32), result?.interpret(listOf(2, 5)))
+ }
+}
\ No newline at end of file
diff --git a/src/test/net/podkopaev/grammar/HairpinGrammarTest.kt b/src/test/net/podkopaev/grammar/HairpinGrammarTest.kt
new file mode 100644
index 0000000..4122524
--- /dev/null
+++ b/src/test/net/podkopaev/grammar/HairpinGrammarTest.kt
@@ -0,0 +1,32 @@
+package net.podkopaev.grammar.HairpinGrammar
+
+import org.junit.Assert
+import org.junit.Test
+
+class HairpinGrammarTest {
+ @Test fun test1() {
+ val p = pS
+ val inp = "aaagaaauuu"
+ Assert.assertEquals(inp.length, p.parse(inp, p))
+ }
+ @Test fun test2() {
+ val p = pS
+ val inp = "cacgaaagug"
+ Assert.assertEquals(inp.length, p.parse(inp, p))
+ }
+ @Test fun test3() {
+ val p = pS
+ val inp = "guagcaauac"
+ Assert.assertEquals(inp.length, p.parse(inp, p))
+ }
+ @Test fun test4() {
+ val p = pS
+ val inp = "uuugcaaaaa"
+ Assert.assertEquals(inp.length, p.parse(inp, p))
+ }
+ @Test fun test5() {
+ val p = pS
+ val inp = "aucgaaagau"
+ Assert.assertEquals(inp.length, p.parse(inp, p))
+ }
+}
diff --git a/src/test/net/podkopaev/grammar/PseudoknotsGrammarTest.kt b/src/test/net/podkopaev/grammar/PseudoknotsGrammarTest.kt
new file mode 100644
index 0000000..8d75a37
--- /dev/null
+++ b/src/test/net/podkopaev/grammar/PseudoknotsGrammarTest.kt
@@ -0,0 +1,47 @@
+package net.podkopaev.grammar.PseudoknotsGrammar
+
+import org.junit.Assert
+import org.junit.Test
+
+class PseudoknotsGrammarTest {
+ @Test fun test0() {
+ val inp = "[(])"
+ val p = grParser
+ Assert.assertEquals(inp.length, p.parse(inp, p))
+ }
+ @Test fun test1() {
+ val inp = "[[((]]))"
+ val p = grParser
+ Assert.assertEquals(inp.length, p.parse(inp, p))
+ }
+ @Test fun test2() {
+ val inp = "[((]))"
+ val p = grParser
+ Assert.assertEquals(inp.length, p.parse(inp, p))
+ }
+ @Test fun test8() {
+ val inp = "[[((((]]))))"
+ val p = grParser
+ Assert.assertEquals(inp.length, p.parse(inp, p))
+ }
+ @Test fun test4() {
+ val inp = "[".repeat(50) + "(".repeat(100) + "]".repeat(50) + ")".repeat(100)
+ val p = grParser
+ Assert.assertEquals(inp.length, p.parse(inp, p))
+ }
+ @Test fun test5() {
+ val inp = "[(((((])))))"
+ val p = grParser
+ Assert.assertEquals(inp.length, p.parse(inp, p))
+ }
+ @Test fun test6() {
+ val inp = "[[[[[[[(]]]]]]])"
+ val p = grParser
+ Assert.assertEquals(inp.length, p.parse(inp, p))
+ }
+ @Test fun test7() {
+ val inp = "[[[(((]]])))"
+ val p = grParser
+ Assert.assertEquals(inp.length, p.parse(inp, p))
+ }
+}
\ No newline at end of file