Skip to main content
Version: Next

Program Inventory

Before refactoring or migrating CL, teams need a high-level map of each member: procedures (PGM…ENDPGM), subroutines, DCL variables, and a count of typed commands. The parser turns source files into a structured inventory you can print, export to CSV, or feed into a dashboard.

Add Dependencies​

repositories {
mavenLocal()
mavenCentral()
flatDir {
dirs("deps")
}
}

dependencies {
implementation(files("deps/clparser-with-dependencies-1.0.1-all.jar"))
}

CLCompilationUnit exposes procedures, top-level commands, and subroutines. Nested commands live under each Procedure and Subroutine. Walk descendants for declarations and command-type histograms.

import com.strumenta.cl.model.CLCommand
import com.strumenta.cl.model.CLCompilationUnit
import com.strumenta.cl.model.DeclareVariableCommand
import com.strumenta.cl.model.GenericCommand
import com.strumenta.cl.model.Procedure
import com.strumenta.cl.model.Subroutine
import com.strumenta.cl.parser.CLKolasuParser
import com.strumenta.kolasu.commercial.LicenseManager
import com.strumenta.kolasu.traversing.walkDescendants
import java.io.File

fun printInventory(clFile: File, license: File) {
LicenseManager.registerLicense(license)
val root = CLKolasuParser().parse(clFile).root ?: return

println("File: ${clFile.name}")
println("Procedures: ${root.procedures.size}")
root.procedures.forEachIndexed { i, proc: Procedure ->
println(" [$i] ${proc.parameters.size} parm(s), ${proc.commands.size} command(s), " +
"${proc.subroutines.size} subroutine(s)")
}

val subroutines = root.walkDescendants(Subroutine::class).toList()
println("Subroutines: ${subroutines.size}")
subroutines.forEach { println(" ${it.name}") }

val variables = root.walkDescendants(DeclareVariableCommand::class).toList()
println("DCL variables: ${variables.size}")
variables.forEach { println(" ${it.name}: ${it.type}") }

val byType = root.walkDescendants(CLCommand::class)
.groupingBy { it::class.simpleName ?: "?" }
.eachCount()
.toList()
.sortedByDescending { it.second }
println("Top command types:")
byType.take(15).forEach { (name, count) -> println(" $name: $count") }

val generics = root.walkDescendants(GenericCommand::class).count()
if (generics > 0) println("GenericCommand (unmapped/custom): $generics")
}

For program and procedure calls, see Call graph. For DCLF / OVRDBF / OPNDBF, see File and database operations. For binding &VAR and label references, see symbol resolution.