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