/tmp/duangsuse.sock
23 subscribers
303 photos
3 videos
92 files
337 links
从 duangsuse::Echo (@dsuse) 跟进出来的分支,将在作者恢复原帐号访问的时候合并删除。
Download Telegram
Calc.kt
7.1 KB
#Kotlin #code 这是 jison 里部分代码的第二次重写,以后有机会我用 jison org.parserkt 里原有的测试来验证一下它们
fun <T: Any> Feed<T>.takeWhile(predicate: Predicate<T>): Sequence<T> = generateSequence {
peek.takeIf(predicate)?.let { runCatching(::consume).getOrNull() }
}

fun <T> Feed<T>.takeWhile(predicate: Predicate<T>): Sequence<T> = sequence {
while (true)
if (predicate(peek)) yield(runCatching(::consume).getOrNull() ?: break)
else break
}


#Kotlin sequences 好棒棒呀,一个 or 的逻辑从三行简化到了一行。
Calc.kt
12.5 KB
#Kotlin #code 又写了许多,已经开始觉得没必要了
Calc.kt
15.3 KB
#Kotlin #code 终于完成了字典树
Calc.kt
15.4 KB
#Kotlin #code 简化了一下字典树
其实对缩进布局的解析根本不需要抛 exception,子布局返回的数据里放终止嵌套层次就可以做到级联收尾了。
忍不住想起之前的 NumEqualize.kt
不知道现在的 seq, or, repeat 相对于之前函数+then contextual 的版本是简单了还是复杂了
Repeat 现在需要 override fun show(write: Consumer<T>, item: R?)
因为 Fold 只能完成 from,并不能完成 to。

至于现在的 Tuple+read/show 和之前的 Fold+then/contextual 孰优孰劣,还没有定数
但现在规范化了解析失败的时候有 clamUntil,还是比较好的

其实 Seq, Or, Repeat 也完全可以在 read 的时候 try catch 一下,给异常添加更多信息传下去,不过我觉得镇静模式就很好。
有了关键的 TriePattern 和 InfixPattern,加上 LayoutPattern 就可以实现 Python 解析器了(跑)
Literate Kotlin 可以教小白了解自己的实现,但写起来很冗长,emmm……
回看那篇
为了输入数据结构兼容性,每次要弄什么 Input("", SliceFeeder(slice("emmm")))
/tmp/duangsuse.sock
Calc.kt
提问!如何编写一个十进制解析器?

我们先来看看上一个版本怎么做:
class DecimalRead(mzero: Int): Monoid<Int>(mzero, { i -> this*10 + i })
object HexRead: Monoid<Int>(0, { i -> this*16 + i })

private val oneNine = element('1'..'9') then { it-'0' }
private val zero = item('0') const 0
private val digit = or(oneNine, zero)
private fun digitsCtx(zero: Int, optional: Boolean): CParser<Int>
= repeat(DecimalRead(zero), digit, if (optional) MAYBE else SOME)
val digits = digitsCtx(0, optional = false)
val digitsNoLeadingZero: CParser<Int> = or(digit.single(), oneNine contextual { digitsCtx(it, optional = true) })
private val hexDigit: CParser<Int> = or(digit, element('A'..'F') then { it-'A'+10 }, element('a'..'f') then { it-'a'+10 })

那么, 如何不允许前置 '0'?

不知道,好像不得不引入 contextual 解析器…… 其实也不一定需要…… 但是最好要有……

class DecimalRead(zero: Int): Monoid<Int>(zero, { this*10 + it })
object Digit: Convert<Char, Char, Int>(RangeElement('0'..'9'), {it-'0'}, {'0'+it})
object Decimal: Repeat<Char, Int, Int>(DecimalRead(0), Digit) {
override fun show(write: Consumer<Char>, item: Int?) { item?.toString()?.forEach(write) }
}
>>> val s=CharInput("",InputStreamFeed(System.`in`))
>>> s.takeWhile { it in '0'..'9' || it == '\n' }.toList()
12313
432
res17: kotlin.collections.List<kotlin.Char> = [
, 1, 2, 3, 1, 3,
, 4, 3, 2,
]

修好了 InputStreamFeed
Parser.kt
17.7 KB
class DecimalRead(zero: Int): Monoid<Int>(zero, { this*10 + it })
object Digit: Convert<Char, Char, Int>(RangeElement('0'..'9'), {it-'0'}, {'0'+it})
object Decimal: Repeat<Char, Int, Int>(DecimalRead(0), Digit) {
override fun show(write: Consumer<Char>, item: Int?) { item?.toString()?.forEach(write) }
}
总之就是可以用,但怎么用呢…… 明天再看 #Kotlin #code