commonMain.piacenti.dslmaker.structures.derivationgraph.DerivationGraph.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dsl-maker-js Show documentation
Show all versions of dsl-maker-js Show documentation
Kotlin multiplatform library to facilitate creation of DSLs with ANTLR or a simple built in parser
package piacenti.dslmaker.structures.derivationgraph
import piacenti.dslmaker.abstraction.ProductionStep
import piacenti.dslmaker.pop
import piacenti.dslmaker.structures.Grammar
import piacenti.dslmaker.structures.Production
/**
* @param
* @author Piacenti
*/
class DerivationGraph(private val grammar: Grammar<*>) {
private var roots: MutableList = mutableListOf()
private var subGraphs: MutableMap = HashMap()
private val leftRecursionRemover = LeftRecursionRemover()
init {
try {
leftRecursionRemover.removeLeftRecursion(grammar)
} catch (e: Exception) {
println(e.message)
}
buildDerivationTree()
roots.forEach { it.fixTreeLinks() }
}
/**
* @return
*/
fun getSubGraphs(): Map {
return subGraphs
}
private fun buildDerivationTree() {
subGraphs = HashMap()
roots = ArrayList()
//Algorithm
//simply build graphs for each production
for ((key, value) in grammar.productions) {
buildSubTree(key, value)
}
mergeTwins()
}
private fun buildSubTree(key: ProductionStep, production: Production) {
val localRoot = DerivationNode(key, true)
roots.add(localRoot)
//go over productions and append each subgroups to root
val expressions = production.expressions
for (expression in expressions) {
var parent = localRoot
val steps = expression.steps
for (step in steps) {
val derivationNode = DerivationNode(step)
derivationNode.parent=parent
parent.children.add(derivationNode)
parent = parent.children.last()
}
}
subGraphs[localRoot.step] = localRoot
}
private fun mergeTwins() {
for ((_, value) in subGraphs) {
//put all nodes into a list after traversal
val traversalNodes = getTraveraslNodes(value)
//remove root since it doesn't have twins
traversalNodes.removeAt(0)
while (traversalNodes.isNotEmpty()) {
val current = traversalNodes[0]
val twinList = ArrayList()
twinList.add(current)
for (i in 1 until traversalNodes.size) {
if (current.step === traversalNodes[i].step && current.parent === traversalNodes[i].parent) {
twinList.add(traversalNodes[i])
}
}
mergeTwins(twinList)
traversalNodes.removeAll(twinList)
}
}
}
private fun getTraveraslNodes(value: DerivationNode): MutableList {
val result = ArrayList()
val stack = mutableListOf()
stack.add(value)
while (stack.isNotEmpty()) {
val current = stack.pop()
result.add(current)
//add only children that are not looping back to root
stack.addAll(current.children.filter { child -> child !== value })
}
result.reverse()
return result
}
private fun mergeTwins(twinList: List) {
//pick the first as the one to remain
val keep = twinList[0]
//add the children of all the others to keep one and make it their parent
for (i in 1 until twinList.size) {
//if either of them don't have a child add a null to account for the end of match, must be added at end of
//list so that DFS traversal starting on left go over longer branches before going over the ones that end with null
if (keep.children.isEmpty() || twinList[i].children.isEmpty()) {
if (!(keep.children.isEmpty() && twinList[i].children.isEmpty())) {
keep.isLeaf = true
}
}
keep.children.addAll(twinList[i].children)
//remove them from their parent
keep.parent!!.children.remove(twinList[i])
if (twinList[i].children.isNotEmpty()) {
for (child in twinList[i].children) {
child.parent = keep
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy