Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/main/net/podkopaev/cpsComb.kt
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ fun <A> many1(parser: Recognizer<A>): Recognizer<List<A>> =

fun char(c: Char): Recognizer<Char> = satp { it == c }
val space : Recognizer<Char> =
char(' ') / char('\n') / char('\t') /
char(' ') / char('\n') / char('\t') / char('\n') /
transp(terminal("\r\n")) { '\n' }
val spaces: Recognizer<Char> = fix { s -> space / transp(seq(space, s), {' '}) }

Expand All @@ -357,12 +357,12 @@ val alpha: Recognizer<Char> = satp {
val alphaOrDigit: Recognizer<Char> = alpha / digit
val number: Recognizer<Int> = (digit map {it-> it.toString().toInt()}) / (many1(digit) map { it.toStr().toInt() })
val word : Recognizer<String> = many1(alpha) map { it.toStr() }
val symbol: Recognizer<String> = seq(alpha, many0(alphaOrDigit)) map {
val symbol: Recognizer<String> = (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 <A> leftAssocp(opp: Recognizer<String>, elemp: Recognizer<A>,
f: (String, A, A) -> A): Recognizer<A> {
val rightp = opp + elemp
Expand Down
30 changes: 30 additions & 0 deletions src/main/net/podkopaev/grammar/HairpinGrammar.kt
Original file line number Diff line number Diff line change
@@ -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<Pair<Int, Int>, Int> -> t.first.second + 2 }

val pW3: Recognizer<Int> = (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<Int> = (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<Int> = (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<Int> = (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)
37 changes: 37 additions & 0 deletions src/main/net/podkopaev/grammar/PseudoknotsGrammar.kt
Original file line number Diff line number Diff line change
@@ -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<Int> = fix { S3 -> (seq(p4, S3) map { t -> 1 + t.second }) / p4 }
val pS4: Recognizer<Int> = fix { S4 -> (seq(p3, S4) map { t -> 1 + t.second }) / p3 }
val pS2: Recognizer<Int> = fix { S2 -> (seq(seq(p1, S2), p2) map { t -> 1 + t.first.second }) / pS4 }

val pS6: Recognizer<Int> = fix { S6 -> (seq(p1, S6) map { t -> 1 + t.second }) / p1 }
val pS8: Recognizer<Int> = fix { S8 -> (seq(p2, S8) map { t -> 1 + t.second }) / p2 }
val pS7: Recognizer<Int> = 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 }
52 changes: 52 additions & 0 deletions src/main/net/podkopaev/whileParser/cpsParser.kt
Original file line number Diff line number Diff line change
@@ -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<Expr> = 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<Expr> = generateExprParser()

fun generateStmtParser(): Recognizer<Stmt> = fix {
val readp : Recognizer<Stmt> = terminal("read" ) seqr spaces seqr paren(sp(symbol)) map { Stmt.Read (it) as Stmt }
val writep : Recognizer<Stmt> = terminal("write") seqr spaces seqr paren(sp(exprParser)) map { Stmt.Write(it) as Stmt }
val assignp: Recognizer<Stmt> = ((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<Stmt> = readp / writep / assignp / ifp / whilep
val parser = assocp(terminal(";"), corepp) {
op, s1, s2 ->
Stmt.Seq(s1, s2)
}
return@fix parser
}
val stmtParser = generateStmtParser()

fun <A> assocp(opp: Recognizer<String>, elemp: Recognizer<A>,
f: (String, A, A) -> A): Recognizer<A> = fix { P ->
elemp / ((elemp + opp + P) map { f(it.first.second, it.first.first, it.second) })
}
106 changes: 106 additions & 0 deletions src/test/net/podkopaev/LCpsParserTest.kt
Original file line number Diff line number Diff line change
@@ -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<Int>(), result?.interpret(listOf()))
}
@Test fun test12() {
val program = "read ( n )"
val parser = stmtParser
val result = parser.parse(program, parser)
Assert.assertEquals(listOf<Int>(), 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<Int>(), 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)))
}
}
32 changes: 32 additions & 0 deletions src/test/net/podkopaev/grammar/HairpinGrammarTest.kt
Original file line number Diff line number Diff line change
@@ -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))
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А тесты по-больше?

Copy link
Collaborator Author

@onewhl onewhl May 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это маленький примерчик, увидела в книжке -- добавила, он не особо показателен. Распознаем шпильки (hairpin) с длиной спирали 3 и последовательностью в петле gaaa и gcaa. В языке, порождаемым этой грамматикой, строки всегда одной длины (10 символов).

}
47 changes: 47 additions & 0 deletions src/test/net/podkopaev/grammar/PseudoknotsGrammarTest.kt
Original file line number Diff line number Diff line change
@@ -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))
}
}