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
- Kotlin
- Java
repositories {
mavenLocal()
mavenCentral()
flatDir {
dirs("deps")
}
}
dependencies {
implementation(files("deps/clparser-with-dependencies-1.0.1-all.jar"))
}
repositories {
mavenLocal()
mavenCentral()
flatDir {
dirs("deps")
}
}
dependencies {
implementation(files("deps/clparser-with-dependencies-1.0.1-all.jar"))
implementation "com.strumenta.kolasu:kolasu-javalib:1.5.107"
}
Print an inventory
CLCompilationUnit exposes procedures, top-level commands, and subroutines. Nested commands live under each Procedure and Subroutine. Walk descendants for declarations and command-type histograms.
- Kotlin
- Java
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")
}
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.javalib.Traversing;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class ProgramInventory {
public static void printInventory(File clFile, File license) {
LicenseManager.INSTANCE.registerLicense(license);
CLCompilationUnit root = new CLKolasuParser().parse(clFile).getRoot();
if (root == null) return;
System.out.println("File: " + clFile.getName());
System.out.println("Procedures: " + root.getProcedures().size());
int i = 0;
for (Procedure proc : root.getProcedures()) {
System.out.println(" [" + (i++) + "] " + proc.getParameters().size()
+ " parm(s), " + proc.getCommands().size() + " command(s), "
+ proc.getSubroutines().size() + " subroutine(s)");
}
System.out.println("Subroutines:");
Traversing.walkDescendantsBreadthFirst(root, Subroutine.class,
sub -> System.out.println(" " + sub.getName()));
System.out.println("DCL variables:");
Traversing.walkDescendantsBreadthFirst(root, DeclareVariableCommand.class,
dcl -> System.out.println(" " + dcl.getName() + ": " + dcl.getType()));
Map<String, Integer> byType = new HashMap<>();
Traversing.walkDescendantsBreadthFirst(root, CLCommand.class, cmd ->
byType.merge(cmd.getClass().getSimpleName(), 1, Integer::sum));
System.out.println("Command types: " + byType);
int[] generics = {0};
Traversing.walkDescendantsBreadthFirst(root, GenericCommand.class, g -> generics[0]++);
if (generics[0] > 0) {
System.out.println("GenericCommand (unmapped/custom): " + generics[0]);
}
}
}
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.