112 lines
5.8 KiB
Kotlin
112 lines
5.8 KiB
Kotlin
package parser.grammars
|
|
|
|
import com.github.h0tk3y.betterParse.combinators.*
|
|
import com.github.h0tk3y.betterParse.grammar.parser
|
|
import com.github.h0tk3y.betterParse.parser.Parser
|
|
import prolog.ast.arithmetic.Float
|
|
import prolog.ast.arithmetic.Integer
|
|
import prolog.ast.terms.*
|
|
|
|
/**
|
|
* Precedence is based on the following table:
|
|
*
|
|
* | Precedence | Type | Operators |
|
|
* |------------|------|-----------------------------------------------------------------------------------------------|
|
|
* | 1200 | xfx | --\>, :-, =\>, ==\> |
|
|
* | 1200 | fx | :-, ?- |
|
|
* | 1105 | xfy | \| |
|
|
* | 1100 | xfy | ; |
|
|
* | 1050 | xfy | -\>, \*-\> |
|
|
* | 1000 | xfy | , |
|
|
* | 990 | xfx | := |
|
|
* | 900 | fy | \\+ |
|
|
* | 700 | xfx | \<, =, =.., =:=, =\<, ==, =\\=, \>, \>=, \\=, \\==, as, is, \>:\<, :\< |
|
|
* | 600 | xfy | : |
|
|
* | 500 | yfx | +, -, /\\, \\/, xor |
|
|
* | 500 | fx | ? |
|
|
* | 400 | yfx | \*, /, //, div, rdiv, \<\<, \>\>, mod, rem |
|
|
* | 200 | xfx | \*\* |
|
|
* | 200 | xfy | ^ |
|
|
* | 200 | fy | +, -, \\ |
|
|
* | 100 | yfx | . |
|
|
* | 1 | fx | $ |
|
|
*
|
|
* @see [SWI-Prolog Predicate op/3](https://www.swi-prolog.org/pldoc/man?predicate=op/3)
|
|
*/
|
|
open class TermsGrammar : Tokens() {
|
|
|
|
// Basic named terms
|
|
protected val variable: Parser<Variable> by variableToken use { Variable(text) }
|
|
protected val simpleAtom: Parser<Atom> by nameToken use { Atom(text) }
|
|
protected val quotedAtom: Parser<Atom> by (dummy
|
|
or ticked
|
|
or doubleTicked
|
|
or backTicked
|
|
) use { Atom(text.substring(1, text.length - 1)) }
|
|
protected val atom: Parser<Atom> by (quotedAtom or simpleAtom)
|
|
protected val compound: Parser<Structure> by (atom * -leftParenthesis * separated(
|
|
parser(::termNoConjunction),
|
|
comma,
|
|
acceptZero = true
|
|
) * -rightParenthesis) use {
|
|
Structure(t1, t2.terms)
|
|
}
|
|
|
|
// Basic arithmetic
|
|
protected val int: Parser<Integer> by integerToken use { Integer(text.toInt()) }
|
|
protected val float: Parser<Float> by floatToken use { Float(text.toFloat()) }
|
|
|
|
// Base terms (atoms, compounds, variables, numbers)
|
|
protected val baseTerm: Parser<Term> by (dummy
|
|
or (-leftParenthesis * parser(::term) * -rightParenthesis)
|
|
or compound
|
|
or atom
|
|
or variable
|
|
or float
|
|
or int
|
|
)
|
|
|
|
// Level 200 - prefix operators (+, -, \)
|
|
protected val op200: Parser<CompoundTerm> by ((plus or minus) * parser(::term200)) use {
|
|
CompoundTerm(Atom(t1.text), listOf(t2))
|
|
}
|
|
protected val term200: Parser<Term> by (op200 or baseTerm)
|
|
|
|
// Level 400 - multiplication, division
|
|
protected val op400: Parser<String> by (multiply or divide) use { text }
|
|
protected val term400: Parser<Term> by (term200 * zeroOrMore(op400 * term200)) use {
|
|
t2.fold(t1) { acc, (op, term) -> CompoundTerm(Atom(op), listOf(acc, term)) }
|
|
}
|
|
|
|
// Level 500 - addition, subtraction
|
|
protected val op500: Parser<String> by (plus or minus) use { text }
|
|
protected val term500: Parser<Term> by (term400 * zeroOrMore(op500 * term400)) use {
|
|
t2.fold(t1) { acc, (op, term) -> CompoundTerm(Atom(op), listOf(acc, term)) }
|
|
}
|
|
|
|
// Level 700 - comparison operators
|
|
protected val op700: Parser<String> by (equals or notEquals) use { text }
|
|
protected val term700: Parser<Term> by (term500 * optional(op700 * term500)) use {
|
|
if (t2 == null) t1 else CompoundTerm(Atom(t2!!.t1), listOf(t1, t2!!.t2))
|
|
}
|
|
|
|
// Level 1000 - conjunction (,)
|
|
protected val term1000: Parser<Term> by (term700 * zeroOrMore(comma * term700)) use {
|
|
t2.fold(t1) { acc, (_, term) -> CompoundTerm(Atom(","), listOf(acc, term)) }
|
|
}
|
|
|
|
// Level 1100 - disjunction (;)
|
|
protected val term1100: Parser<Term> by (term1000 * zeroOrMore(semicolon * term1000)) use {
|
|
t2.fold(t1) { acc, (_, term) -> CompoundTerm(Atom(";"), listOf(acc, term)) }
|
|
}
|
|
|
|
// Term - highest level expression
|
|
protected val term: Parser<Term> by term1100
|
|
protected val termNoConjunction: Parser<Term> by term700
|
|
|
|
// Parts for clauses
|
|
protected val head: Parser<Head> by (compound or atom)
|
|
protected val body: Parser<Body> by term use { this as Body }
|
|
|
|
override val rootParser: Parser<Any> by term
|
|
}
|