Resolve Symbols Across a Codebase
Single-file parsing gives you syntax. The symbol-resolution module builds a shared symbol repository over an entire project directory — RPGLE, copybooks, DDS/PF/LF/DSPF, and DDL — then resolves links and maps prototypes to their implementing procedures.
Add Dependencies
You need the core parser JAR plus the symbol-resolution module.
- Kotlin
- Java
repositories {
mavenLocal()
mavenCentral()
flatDir {
dirs("deps")
}
}
dependencies {
implementation(files("deps/rpgparser-2.2.0-all.jar"))
implementation(files("deps/rpgparser-symbol-resolution-2.2.0.jar"))
implementation("com.strumenta.kolasu:kolasu-codebase:1.5.107")
implementation("com.strumenta.kolasu:kolasu-semantics:1.5.107")
}
repositories {
mavenLocal()
mavenCentral()
flatDir {
dirs("deps")
}
}
dependencies {
implementation(files("deps/rpgparser-2.2.0-all.jar"))
implementation(files("deps/rpgparser-symbol-resolution-2.2.0.jar"))
implementation "com.strumenta.kolasu:kolasu-javalib:1.5.107"
implementation "com.strumenta.kolasu:kolasu-codebase:1.5.107"
implementation "com.strumenta.kolasu:kolasu-semantics:1.5.107"
}
Maven coordinates for the module are com.strumenta:rpg-parser-symbol-resolution when consuming from a repository instead of flat files.
Build a codebase and resolve
rpgCodebase(baseDir, licenseFile) walks the directory for RPG-related extensions and parses each file. resolveSymbolsForRPG() runs the semantics engine over every compilation unit.
- Kotlin
- Java
import com.strumenta.kolasu.traversing.walkDescendants
import com.strumenta.rpgparser.model.Prototype
import com.strumenta.rpgparser.symbolresolution.rpgCodebase
import com.strumenta.rpgparser.symbolresolution.resolveSymbolsForRPG
import java.io.File
fun resolveProject(projectDir: File, license: File) {
val codebase = rpgCodebase(projectDir, license)
println("Files in codebase: ${codebase.files().count()}")
val resolved = codebase.resolveSymbolsForRPG()
resolved.files.forEach { file ->
file.ast.walkDescendants(Prototype::class).forEach { proto ->
val impl = resolved.correspondingDefinition(proto)
println(
"${proto.name} in ${file.relativePath} → " +
(impl?.let { "procedure ${it.name}" } ?: "unresolved")
)
}
}
}
import com.strumenta.kolasu.ids.CommonNodeIdProvider;
import com.strumenta.kolasu.javalib.Traversing;
import com.strumenta.rpgparser.model.Prototype;
import com.strumenta.rpgparser.symbolresolution.RPGSemanticsAnalysisResult;
import com.strumenta.rpgparser.symbolresolution.SemanticsOverCodebaseKt;
import com.strumenta.rpgparser.symbolresolution.UtilsKt;
import java.io.File;
import kotlin.sequences.SequencesKt;
public class SymbolResolution {
public static void resolveProject(File projectDir, File license) {
var codebase = UtilsKt.rpgCodebase(projectDir, license, "UnnamedCodebase");
System.out.println("Files in codebase: " + SequencesKt.count(codebase.files()));
RPGSemanticsAnalysisResult resolved =
SemanticsOverCodebaseKt.resolveSymbolsForRPG(
codebase, new CommonNodeIdProvider());
SequencesKt.forEach(resolved.getFiles(), file -> {
Traversing.walkDescendantsBreadthFirst(file.getAst(), Prototype.class).forEach(proto -> {
var impl = resolved.correspondingDefinition(proto);
System.out.println(proto.getName() + " in " + file.getRelativePath()
+ " → " + (impl != null ? "procedure " + impl.getName() : "unresolved"));
});
return null;
});
}
}
Kotlin call sites are the documented API (rpgCodebase, resolveSymbolsForRPG). From Java the same functions appear as static methods on the generated *Kt facade classes; prefer Kotlin for multi-file semantic work when possible.
What gets indexed
During construction, RPGSemantics loads:
| Source | Contribution |
|---|---|
| RPGLE / RPGLEM | Data definitions, file specifications, procedures, prototypes |
| CPY / CPYBK | Copybook symbols |
| DDS / PF / LF / DSPF / PRTF | Record formats and fields |
| DDL | Converted into RPG RecordFormat symbols via the DB2 parser |
| Standard library | Built-in and platform function / variable prototypes |
Find usages of a definition
After resolution, RPGSemanticsAnalysisResult.usages maps each referred definition node to the nodes that reference it:
val resolved = codebase.resolveSymbolsForRPG()
resolved.usages.forEach { (definition, refs) ->
println("${definition.simpleNodeType}: ${refs.size} usage(s)")
}
Next steps
Feed the RPGSemanticsAnalysisResult into RPGAnalyzer to obtain dependency graphs and PlantUML sequence diagrams.