better-parse icon indicating copy to clipboard operation
better-parse copied to clipboard

Advanced rules

Open barsan-md opened this issue 8 years ago • 4 comments

I wonder if there is it possible to implement advanced rules, something like if(condition), then(this rule can be applied).

I'm new to both kotlin and parser combinators so maybe my understanding of the problem is completely wrong.

As a concrete example what I want to do is very similar to the aritmetic evaluator example: https://github.com/h0tk3y/better-parse/blob/master/demo/src/main/kotlin/com/example/ArithmeticsEvaluator.kt except I have many different levels of precedece on operators (not just 3: sum, sub < mul, div < pow). (Small note here: exponentiation is right associative, not left (a^b^c = a^(b^c))) Suppose, instead of collectiong the same level operations into the same rule (like the example), a general single rule is the only way possible, to be more general and open to the addition of new operator.

val digits by token("\\d+")
val plus by token("+")
val minus
// val ...
val operator = plus or minus or ...
// this won't work because it will match addition before others
val operation: Parser<Tree> = digits and operator and digits
// it must match an operation that has the maximum value in the chain
val operation: Parser<Tree> = not(operator with higher precedence) and digits and operator and digits and not(operator with higher precedence)
// or you must associate the digits with the operator having higher precedence
val assignLeft: Parser<Tree> = (operator with higher precedence) and digits and (operator with lower precedence)
val rightAssign: Parser<Tree> = (operator with lower precedence) and digits and (operator with higher precedence)

Is it possible or does this approach make sense? PS: this library is awesome and the infix notation makes the rules very readable when compared with other libraries and languages. Good job, thank you!

barsan-md avatar Sep 04 '17 15:09 barsan-md

@barsan-ds I'm not quite sure I understand your use case. Is it similar to the operator table in jparsec? If not, could you please provide a more concrete example with operators and maybe the input that should be parsed?

h0tk3y avatar Sep 12 '17 14:09 h0tk3y

From what I could understand from the example, that seems to be the case. Does anything like that exist in better-parse?

barsan-md avatar Sep 13 '17 14:09 barsan-md

Not yet. There's no built-in features that allow defining operator rules like this. Though I considered adding something like that (and especially with support for left recursion removal), and I might add this among other features in future.

You can define combinators in your project according to your needs, and I'll be grateful if you come up with an example implementation of the operator table.

h0tk3y avatar Sep 13 '17 14:09 h0tk3y

hey there, this sounds like a nice feature and I prototyped a lightweight solution for this. With it the ArithmeticEvaluator could be simplified to this:

// ... tokens as usual
val number by num use { text.toInt() }
val term: Parser<Int> by number or
        (skip(minus) and parser(::term) map { -it }) or
        (skip(lpar) and parser(::rootParser) and skip(rpar))

// subSumchain, divMulChain, powChain can be merged to this:
override val rootParser: Parser<Int> by operatorTable(term)
    .infixl(pow) { a, _, b -> a.toDouble().pow(b.toDouble()).toInt() } // highest priority first
    .infixl(div or mul use {type }) { a, op, b -> if (op == div) a / b else a * b }
    .infixl(plus or minus use { type }) { a, op, b -> if (op == plus) a + b else a - b } // lowest priority last

the operator table provides these helpers:

  • infixl leftAssociative infix operation
  • infixr rightAssociative infix operation
  • prefix prefix operation
  • postfix postfix operation

I can create a PullRequest if you think this might be a good fit for your lib

InfectedBytes avatar Apr 19 '22 21:04 InfectedBytes