This repository has been archived on 2025-09-23. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
2025LogProg-project-GhentPr.../src/parser/grammars/TermsGrammar.kt
2025-05-08 17:47:13 +02:00

142 lines
7.2 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.lists.List
import prolog.ast.terms.*
import prolog.builtins.Dynamic
import prolog.ast.lists.List.Empty
import prolog.ast.lists.List.Cons
/**
* Precedence is based on the following table:
*
* | Precedence | Type | Operators |
* |------------|------|-----------------------------------------------------------------------------------------------|
* | 1200 | xfx | --\>, :-, =\>, ==\> |
* | 1200 | fx | :-, ?- |
* | 1150 | fx | dynamic |
* | 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 | $ |
*
* It is very easy to extend this grammar to support more operators. Just add them at the appropriate rule or create a
* new rule and chain it to the existing ones.
*
* @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 or anonymousVariableToken) use { Variable(text) }
protected val simpleAtom: Parser<Atom> by (nameToken or exclamation) 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()) }
protected val functor: Parser<String> by (nameToken * divide * int) use { "${t1.text}${t2.text}$t3" }
// Base terms (atoms, compounds, variables, numbers)
protected val baseTerm: Parser<Term> by (dummy
or (-leftParenthesis * parser(::term) * -rightParenthesis)
or parser(::list)
or compound
or atom
or variable
or float
or int
)
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)
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)) }
}
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)) }
}
protected val op700: Parser<String> by (univOp or equivalent or notEquivalent or equals or notEquals or isOp) 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))
}
protected val op1000: Parser<String> by (comma) use { text }
protected val term1000: Parser<Term> by (term700 * zeroOrMore(op1000 * term700)) use {
t2.fold(t1) { acc, (op, term) -> CompoundTerm(Atom(op), listOf(acc, term)) }
}
protected val op1100: Parser<String> by (semicolon) use { text }
protected val term1100: Parser<Term> by (term1000 * zeroOrMore(op1100 * term1000)) use {
t2.fold(t1) { acc, (op, term) -> CompoundTerm(Atom(op), listOf(acc, term)) }
}
protected val dynamic: Parser<Term> by (dynamicOp * functor) use {
CompoundTerm( Atom(t1.text), listOf(Atom(t2)) )
}
protected val term1150: Parser<Term> by (dynamic or term1100) use { this }
protected val op1200: Parser<String> by (neck) use { text }
protected val term1200: Parser<Term> by (term1150 * zeroOrMore(op1200 * term1100)) use {
t2.fold(t1) { acc, (op, term) -> CompoundTerm(Atom(op), listOf(acc, term)) }
}
// Lists
protected val list: Parser<List> by (-leftBracket * separated(
parser(::termNoConjunction),
comma,
acceptZero = true
) * -rightBracket) use {
var list: List = Empty
// Construct the list in reverse order
for (term in this.terms.reversed()) {
list = Cons(term, list)
}
list
}
// Term - highest level expression
protected val term: Parser<Term> by term1200
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
}