Skip to main content

Copybook and Cross-File Dependencies

Production RPG lives in libraries of programs linked by /COPY and /INCLUDE, external CALL targets, and shared DDS. For a best-effort sketch of copybook edges you can walk CopyStatement and IncludeStatement on each AST. For resolved, codebase-wide graphs, use symbol resolution and the analyzer.

When to use this pattern

ApproachGood for
Walk COPY / INCLUDE directivesQuick inventory of include sites from a single file
rpgCodebase + resolveSymbolsForRPGLoading copybooks and DDS into a shared symbol table
RPGAnalyzer.dependencyGraph()File- and behavior-level edges (CopyInclude, CallProgram, InvokeSubroutine, …)

Add Dependencies

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

dependencies {
implementation(files("deps/rpgparser-2.2.0-all.jar"))
}

Extract COPY / INCLUDE targets from one file

Each copy/include statement wraps a directive with memberName, optional fileName, and optional libraryName:

import com.strumenta.kolasu.commercial.LicenseManager
import com.strumenta.kolasu.traversing.walkDescendants
import com.strumenta.rpgparser.RPGKolasuParser
import com.strumenta.rpgparser.model.CopyStatement
import com.strumenta.rpgparser.model.IncludeStatement
import java.io.File

data class IncludeEdge(val kind: String, val member: String, val file: String?, val library: String?)

fun copyIncludeEdges(rpgFile: File, license: File): List<IncludeEdge> {
LicenseManager.registerLicense(license)
val root = RPGKolasuParser.parserFromExtension(rpgFile).parse(rpgFile).root ?: return emptyList()
val edges = mutableListOf<IncludeEdge>()

root.walkDescendants(CopyStatement::class).forEach { copy ->
val d = copy.copyDirective
edges += IncludeEdge("COPY", d.memberName, d.fileName, d.libraryName)
}
root.walkDescendants(IncludeStatement::class).forEach { include ->
val d = include.includeDirective
edges += IncludeEdge("INCLUDE", d.memberName, d.fileName, d.libraryName)
}
return edges
}

Next steps