Skip to content
10 changes: 7 additions & 3 deletions solver/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ repositories {

dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-cli:0.3.5")
implementation("com.fasterxml.jackson.core:jackson-core:2.14.0")
implementation("com.fasterxml.jackson.core:jackson-databind:2.14.0")
implementation ("io.github.oshai:kotlin-logging-jvm:5.1.0")
//needed for .dot parsing
implementation("org.antlr:antlr4:4.13.1")
// https://mvnrepository.com/artifact/org.slf4j/slf4j-api
//needed for kotlin-logging
implementation("org.slf4j:slf4j-api:2.0.17")
implementation("ch.qos.logback:logback-classic:1.5.18")

testImplementation(kotlin("test"))
testImplementation("org.junit.jupiter:junit-jupiter:5.8.1")
implementation("org.antlr:antlr4:4.13.1")
}

kotlin { jvmToolchain(11) }
Expand Down
14 changes: 13 additions & 1 deletion solver/src/main/kotlin/org/ucfs/descriptors/Descriptor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,17 @@ data class Descriptor<InputNodeType>(
*/
val sppfNode: RangeSppfNode<InputNodeType>,

)

) {
// debug only property
val id = lastId++
override fun toString(): String {
return "${id}\t;" +
"${inputPosition}\t;" +
"${rsmState.id}\t;" +
"(${gssNode.inputPosition}, ${gssNode.rsm.id})\t;" +
"sppf: ${sppfNode.id} "
}
}

var lastId = 0
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package org.ucfs.descriptors

import io.github.oshai.kotlinlogging.KotlinLogging
import org.ucfs.parser.ParsingException

/**
* Collection of default descriptors
* @param VertexType - type of vertex in input graph
*/
open class DescriptorsStorage<VertexType> {
private val logger = KotlinLogging.logger {}

/**
* Collection of already handled descriptors, accessible via descriptor's hashcode
*/
Expand All @@ -31,10 +34,12 @@ open class DescriptorsStorage<VertexType> {
}

fun add(descriptor: Descriptor<VertexType>) {
if(!handledDescriptors.contains(descriptor)){
logger.debug { "+d:${descriptor.id}" }
if (!handledDescriptors.contains(descriptor)) {
descriptorsToHandle.addLast(descriptor)
}
}

/**
* Gets next descriptor to handle
* @return default descriptor if there is available one, null otherwise
Expand Down
11 changes: 4 additions & 7 deletions solver/src/main/kotlin/org/ucfs/grammar/combinator/Grammar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ open class Grammar {
val nonTerms = ArrayList<Nt>()

private lateinit var startNt: Nt
private lateinit var fictitiousStartNt: Nt

private var _rsm: RsmState? = null
val rsm: RsmState
Expand All @@ -22,12 +23,6 @@ open class Grammar {
return _rsm!!
}

fun setStart(expr: Regexp) {
if (expr is Nt) {
startNt = expr
} else throw IllegalArgumentException("Only NT object can be start state for Grammar")
}

fun Nt.asStart(): Nt {
if (this@Grammar::startNt.isInitialized) {
throw Exception("Nonterminal ${nonterm.name} is already initialized")
Expand All @@ -43,6 +38,8 @@ open class Grammar {
private fun buildRsm(): RsmState {
nonTerms.forEach { it.buildRsmBox() }
//if nonterminal not initialized -- it will be checked in buildRsmBox()
return startNt.nonterm.startState
fictitiousStartNt = Nt(startNt, "fictiveStart")
fictitiousStartNt.buildRsmBox()
return fictitiousStartNt.nonterm.startState
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ open class Nt() : DerivedSymbol {
constructor(lhs: Regexp) : this() {
rsmDescription = lhs
}
constructor(lhs: Regexp, name: String) : this() {
rsmDescription = lhs
this.nonterm = Nonterminal(name)
}


lateinit var nonterm: Nonterminal
private set
Expand Down
55 changes: 36 additions & 19 deletions solver/src/main/kotlin/org/ucfs/parser/Gll.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.ucfs.parser

import io.github.oshai.kotlinlogging.KotlinLogging
import org.ucfs.descriptors.Descriptor
import org.ucfs.gss.GssEdge
import org.ucfs.input.IInputGraph
Expand All @@ -18,6 +19,7 @@ import org.ucfs.sppf.node.*
class Gll<VertexType, LabelType : ILabel> private constructor(
override var ctx: Context<VertexType, LabelType>, private val engine: IIntersectionEngine
) : IGll<VertexType, LabelType> {
val logger = KotlinLogging.logger {}

companion object {
/**
Expand All @@ -29,7 +31,8 @@ class Gll<VertexType, LabelType : ILabel> private constructor(
fun <VertexType, LabelType : ILabel> gll(
startState: RsmState, inputGraph: IInputGraph<VertexType, LabelType>
): Gll<VertexType, LabelType> {
return Gll(Context(startState, inputGraph), IntersectionEngine)
val finalState = startState.outgoingEdges[0].destinationState
return Gll(Context(startState, finalState, inputGraph), IntersectionEngine)
}
}

Expand Down Expand Up @@ -66,33 +69,47 @@ class Gll<VertexType, LabelType : ILabel> private constructor(
ctx.descriptors.add(newDescriptor)
}

private fun isParseResult(matchedRange: RangeSppfNode<VertexType>): Boolean {
return matchedRange.inputRange!!.from in ctx.input.getInputStartVertices()
&& matchedRange.rsmRange!!.from == ctx.fictiveStartState
&& matchedRange.rsmRange.to == ctx.fictiveFinalState
}

/**
* Processes descriptor
* @param descriptor - descriptor to process
*/
override fun handleDescriptor(descriptor: Descriptor<VertexType>) {
ctx.descriptors.addToHandled(descriptor)
logger.debug { "\n${descriptor}\t" }
if (descriptor.rsmState.isFinal) {
val matchedRange = if (descriptor.sppfNode.type is EmptyType) {
val node = getEpsilonRange(descriptor)
//TODO fix
// dirty hack: in fact it's equivavelnt descriptors
// but only initial was added in handlet set
ctx.descriptors.addToHandled(Descriptor(descriptor.inputPosition,
descriptor.gssNode, descriptor.rsmState, node))
node
} else {
descriptor.sppfNode
}
for (poppedEdge in ctx.gss.pop(descriptor, matchedRange)) {
handlePoppedGssEdge(poppedEdge, descriptor, matchedRange)
}
if (descriptor.gssNode.outgoingEdges.isEmpty() && descriptor.gssNode.rsm.isStart) {
ctx.parseResult = matchedRange
}
handleTerminalRsmState(descriptor)
}

engine.handleEdges(this, descriptor)
}

private fun handleTerminalRsmState(descriptor: Descriptor<VertexType>) {
val matchedRange = if (descriptor.sppfNode.type is EmptyType) {
val node = getEpsilonRange(descriptor)
//TODO fix
// dirty hack: in fact it's equivavelnt descriptors
// but only initial was added in handled set
ctx.descriptors.addToHandled(
Descriptor(
descriptor.inputPosition,
descriptor.gssNode, descriptor.rsmState, node
)
)
node
} else {
descriptor.sppfNode
}
for (poppedEdge in ctx.gss.pop(descriptor, matchedRange)) {
handlePoppedGssEdge(poppedEdge, descriptor, matchedRange)
}
if (isParseResult(matchedRange)) {
ctx.parseResults.add(matchedRange)
}
}
}

22 changes: 11 additions & 11 deletions solver/src/main/kotlin/org/ucfs/parser/IGll.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ interface IGll<InputNodeType, LabelType : ILabel> {
* Main parsing loop. Iterates over available descriptors and processes them
* @return Pair of derivation tree root and collection of reachability pairs
*/
fun parse(): RangeSppfNode<InputNodeType>? {
ctx.parseResult = null
fun parse(): Set<RangeSppfNode<InputNodeType>> {
ctx.parseResults = HashSet()
initDescriptors(ctx.input)

var curDescriptor = ctx.descriptors.nextToHandle()
Expand All @@ -36,7 +36,7 @@ interface IGll<InputNodeType, LabelType : ILabel> {
curDescriptor = ctx.descriptors.nextToHandle()
}

return ctx.parseResult
return ctx.parseResults
}

/**
Expand All @@ -52,9 +52,9 @@ interface IGll<InputNodeType, LabelType : ILabel> {
fun initDescriptors(input: IInputGraph<InputNodeType, LabelType>) {
for (startVertex in input.getInputStartVertices()) {

val gssNode = ctx.gss.getOrCreateNode(startVertex, ctx.startState)
val gssNode = ctx.gss.getOrCreateNode(startVertex, ctx.fictiveStartState)
val startDescriptor = Descriptor(
startVertex, gssNode, ctx.startState, getEmptyRange()
startVertex, gssNode, ctx.fictiveStartState, getEmptyRange()
)
ctx.descriptors.add(startDescriptor)
}
Expand All @@ -76,16 +76,16 @@ interface IGll<InputNodeType, LabelType : ILabel> {
for (rangeToPop in positionToPops) {
val leftSubRange = descriptor.sppfNode
val rightSubRange = ctx.sppfStorage.addNonterminalNode(
rangeToPop.inputRange!!, RsmRange(
descriptor.rsmState, destinationRsmState
), rsmStartState
)
rangeToPop.inputRange!!, RsmRange(
descriptor.rsmState, destinationRsmState
), rsmStartState
)

val newSppfNode = ctx.sppfStorage.addIntermediateNode(leftSubRange, rightSubRange)

//TODO why these parameters???
newDescriptor = Descriptor(
rangeToPop.inputRange!!.to, descriptor.gssNode, destinationRsmState, newSppfNode
rangeToPop.inputRange.to, descriptor.gssNode, destinationRsmState, newSppfNode
)
ctx.descriptors.add(newDescriptor)
}
Expand All @@ -98,7 +98,7 @@ interface IGll<InputNodeType, LabelType : ILabel> {
destinationRsmState: RsmState,
terminal: ITerminal
) {
var terminalSppfNode = ctx.sppfStorage.addNode(
val terminalSppfNode = ctx.sppfStorage.addNode(
InputRange(
descriptor.inputPosition,
inputEdge.targetVertex,
Expand Down
10 changes: 5 additions & 5 deletions solver/src/main/kotlin/org/ucfs/parser/context/Context.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.ucfs.parser.context

import org.ucfs.descriptors.Descriptor
import org.ucfs.descriptors.DescriptorsStorage
import org.ucfs.gss.GraphStructuredStack
import org.ucfs.input.IInputGraph
Expand All @@ -14,11 +13,12 @@ import org.ucfs.sppf.node.RangeSppfNode
* @param InputNodeType - type of vertex in input graph
* @param LabelType - type of label on edges in input graph
*/
class Context<InputNodeType, LabelType : ILabel> (
class Context<InputNodeType, LabelType : ILabel>(
/**
* Starting state of accepting Nonterminal in RSM
*/
val startState: RsmState,
val fictiveStartState: RsmState,
val fictiveFinalState: RsmState,
val input: IInputGraph<InputNodeType, LabelType>


Expand All @@ -33,8 +33,8 @@ class Context<InputNodeType, LabelType : ILabel> (
* Derivation trees storage
*/
val sppfStorage: SppfStorage<InputNodeType> = SppfStorage()

val gss: GraphStructuredStack<InputNodeType> = GraphStructuredStack()

var parseResult: RangeSppfNode<InputNodeType>? = null
var parseResults = HashSet<RangeSppfNode<InputNodeType>>()
}
2 changes: 1 addition & 1 deletion solver/src/main/kotlin/org/ucfs/rsm/RsmWrite.kt
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ fun writeRsmToTxt(startState: RsmState, pathToTXT: String) {
}

fun writeRsmToDot(startState: RsmState, filePath: String) {
val states = getAllStates(startState)
val states = getAllStates((startState.outgoingEdges.get(0).symbol as Nonterminal).startState)
val boxes: HashMap<Nonterminal, HashSet<RsmState>> = HashMap()

for (state in states) {
Expand Down
15 changes: 11 additions & 4 deletions solver/src/main/kotlin/org/ucfs/sppf/SppfStorage.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.ucfs.sppf

import io.github.oshai.kotlinlogging.KotlinLogging
import org.ucfs.rsm.RsmState
import org.ucfs.rsm.symbol.ITerminal
import org.ucfs.sppf.node.*
Expand All @@ -8,14 +9,19 @@ import org.ucfs.sppf.node.*
* @param InputEdgeType - type of vertex in input graph
*/
open class SppfStorage<InputEdgeType> {
private val logger = KotlinLogging.logger {}

/**
* Collection of created sppfNodes with access and search in O(1) time
*/
private val createdSppfNodes: HashMap<RangeSppfNode<InputEdgeType>, RangeSppfNode<InputEdgeType>> = HashMap()


private fun addNode(node: RangeSppfNode<InputEdgeType>): RangeSppfNode<InputEdgeType> {
return createdSppfNodes.getOrPut(node, { node })

val sppfNode = createdSppfNodes.getOrPut(node) { node }
logger.debug{"+sppf:${sppfNode.id}, "}
return sppfNode
}

/**
Expand All @@ -37,7 +43,8 @@ open class SppfStorage<InputEdgeType> {
rsmState: RsmState
): RangeSppfNode<InputEdgeType> {
return addNode(
input, rsmRange, EpsilonNonterminalType(rsmState))
input, rsmRange, EpsilonNonterminalType(rsmState)
)
}

/**
Expand Down Expand Up @@ -79,8 +86,8 @@ open class SppfStorage<InputEdgeType> {
if (!rangeNode.children.contains(valueNode)) {
rangeNode.children.add(valueNode)
}
for(child in children){
if (!valueNode.children.contains(child)){
for (child in children) {
if (!valueNode.children.contains(child)) {
valueNode.children.add(child)
}
}
Expand Down
Loading
Loading