Skip to content

Instantly share code, notes, and snippets.

@dfinke
Created January 26, 2026 13:06
Show Gist options
  • Select an option

  • Save dfinke/0ffeeee010f6cf2058c85b7c7ae52a9e to your computer and use it in GitHub Desktop.

Select an option

Save dfinke/0ffeeee010f6cf2058c85b7c7ae52a9e to your computer and use it in GitHub Desktop.
Reads and parses ISPF panel syntax from ISPFPanel.txt
# ParseISPF.ps1 - Reads and parses ISPF panel syntax from ISPFPanel.txt
# Then generates a PowerShell script that creates a WinForm based on the layout
$panelFile = "ISPFPanel.txt"
$content = Get-Content $panelFile -Raw
# Split into sections
$sections = @{}
$currentSection = $null
$lines = $content -split "`n"
foreach ($line in $lines) {
$line = $line.Trim()
$match = $line | Select-String '^\)(\w+)'
if ($match) {
$currentSection = $match.Matches[0].Groups[1].Value
$sections[$currentSection] = @()
}
elseif ($currentSection -and $line) {
$sections[$currentSection] += $line
}
}
# Parse ATTR section
$attrs = @{}
if ($sections.ContainsKey('ATTR')) {
foreach ($line in $sections['ATTR']) {
$match = $line | Select-String '^\s*(\w)\s+(.+)'
if ($match) {
$char = $match.Matches[0].Groups[1].Value
$attrStr = $match.Matches[0].Groups[2].Value
$attrs[$char] = @{}
# Parse attributes like TYPE(INPUT) CAPS(OFF)
$attrParts = $attrStr -split '\s+'
foreach ($part in $attrParts) {
$match = $part | Select-String '(\w+)\(([^)]*)\)'
if ($match) {
$key = $match.Matches[0].Groups[1].Value
$value = $match.Matches[0].Groups[2].Value
$attrs[$char][$key] = $value
}
}
}
}
}
# Parse BODY section
$bodyLines = @()
if ($sections.ContainsKey('BODY')) {
foreach ($line in $sections['BODY']) {
if ($line -notmatch '^WINDOW') {
$bodyLines += $line
}
}
}
# Collect all variables from BODY
$variables = @()
foreach ($line in $bodyLines) {
$varMatches = [regex]::Matches($line, '&(\w+)')
foreach ($match in $varMatches) {
$var = $match.Groups[1].Value
if ($var -notin $variables) {
$variables += $var
}
}
}
# Generate WinForm script
$winFormScript = @"
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
`$form = New-Object System.Windows.Forms.Form
`$form.Text = 'ISPF Panel Simulation'
`$form.Size = New-Object System.Drawing.Size(500, 400)
`$form.StartPosition = 'CenterScreen'
`$y = 20
`$x = 20
"@
# Calculate a shared input column based on max label width
$maxLabelWidth = 0
foreach ($line in $bodyLines) {
$match = $line | Select-String '^\s*(.)(.*)'
if ($match) {
$text = $match.Matches[0].Groups[2].Value
$labelText = [regex]::Replace($text, '&\w+', '')
$labelText = $labelText.TrimEnd()
if ($labelText.Length -gt $maxLabelWidth) {
$maxLabelWidth = $labelText.Length
}
}
}
$inputColumnX = 20 + ($maxLabelWidth * 8) + 20
foreach ($line in $bodyLines) {
$match = $line | Select-String '^\s*(.)(.*)'
if ($match) {
$attrChar = $match.Matches[0].Groups[1].Value
$text = $match.Matches[0].Groups[2].Value
# Split the line into parts: text and &variables
$parts = @()
$regex = [regex]'(&\w+)|([^&]+)'
$regexMatches = $regex.Matches($text)
foreach ($match in $regexMatches) {
if ($match.Groups[1].Success) {
$parts += $match.Groups[1].Value
}
elseif ($match.Groups[2].Success) {
$parts += $match.Groups[2].Value
}
}
$lineX = 20
foreach ($part in $parts) {
$partMatch = [regex]::Match($part, '^&(\w+)')
if ($partMatch.Success) {
$var = $partMatch.Groups[1].Value
# Create TextBox for input
$winFormScript += @"
`$textBox$var = New-Object System.Windows.Forms.TextBox
`$textBox$var.Location = New-Object System.Drawing.Point($inputColumnX, `$y)
`$textBox$var.Size = New-Object System.Drawing.Size(150, 20)
`$form.Controls.Add(`$textBox$var)
"@
$winFormScript += "`n"
$lineX = $inputColumnX + 160
}
elseif ($part.Trim()) {
# Create Label for text
$escapedPart = $part -replace "'", "''"
$winFormScript += @"
`$label = New-Object System.Windows.Forms.Label
`$label.Text = '$escapedPart'
`$label.Location = New-Object System.Drawing.Point($lineX, `$y)
`$label.AutoSize = `$true
`$form.Controls.Add(`$label)
"@
$winFormScript += "`n"
$lineX += ($part.Length * 8) # Rough estimate for width
}
}
$winFormScript += "`n`$y += 30`n"
}
}
# Add OK button
$winFormScript += @"
`$okButton = New-Object System.Windows.Forms.Button
`$okButton.Text = 'OK'
`$okButton.Location = New-Object System.Drawing.Point(200, `$y)
`$okButton.Size = New-Object System.Drawing.Size(75, 23)
`$okButton.Add_Click({
`$result = @{}
"@
$winFormScript += "`n"
foreach ($var in $variables) {
$winFormScript += " `$result['$var'] = `$textBox$var.Text`n"
}
$winFormScript += @"
Write-Host "Captured Data:"
`$result.GetEnumerator() | ForEach-Object { Write-Host ("{0}: {1}" -f `$_.Key, `$_.Value) }
`$form.DialogResult = [System.Windows.Forms.DialogResult]::OK
`$form.Close()
})
`$form.Controls.Add(`$okButton)
`$form.ShowDialog()
"@
# Output the generated script to a file
$outputFile = "GeneratedWinForm.ps1"
Set-Content -Path $outputFile -Value $winFormScript -Encoding UTF8
Write-Host "Generated WinForm script: $outputFile"
@dfinke
Copy link
Author

dfinke commented Jan 26, 2026

image


image

@dfinke
Copy link
Author

dfinke commented Jan 26, 2026

GeneratedWinForm.ps1

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$form = New-Object System.Windows.Forms.Form
$form.Text = 'ISPF Panel Simulation'
$form.Size = New-Object System.Drawing.Size(500, 400)
$form.StartPosition = 'CenterScreen'

$y = 20
$x = 20
$label = New-Object System.Windows.Forms.Label
$label.Text = 'First Name: '
$label.Location = New-Object System.Drawing.Point(20, $y)
$label.AutoSize = $true
$form.Controls.Add($label)

$textBoxFIRST = New-Object System.Windows.Forms.TextBox
$textBoxFIRST.Location = New-Object System.Drawing.Point(128, $y)
$textBoxFIRST.Size = New-Object System.Drawing.Size(150, 20)
$form.Controls.Add($textBoxFIRST)

$y += 30

$label = New-Object System.Windows.Forms.Label
$label.Text = 'Last Name: '
$label.Location = New-Object System.Drawing.Point(20, $y)
$label.AutoSize = $true
$form.Controls.Add($label)

$textBoxLAST = New-Object System.Windows.Forms.TextBox
$textBoxLAST.Location = New-Object System.Drawing.Point(128, $y)
$textBoxLAST.Size = New-Object System.Drawing.Size(150, 20)
$form.Controls.Add($textBoxLAST)

$y += 30

$label = New-Object System.Windows.Forms.Label
$label.Text = 'City: '
$label.Location = New-Object System.Drawing.Point(20, $y)
$label.AutoSize = $true
$form.Controls.Add($label)

$textBoxCITY = New-Object System.Windows.Forms.TextBox
$textBoxCITY.Location = New-Object System.Drawing.Point(128, $y)
$textBoxCITY.Size = New-Object System.Drawing.Size(150, 20)
$form.Controls.Add($textBoxCITY)

$y += 30

$label = New-Object System.Windows.Forms.Label
$label.Text = 'State: '
$label.Location = New-Object System.Drawing.Point(20, $y)
$label.AutoSize = $true
$form.Controls.Add($label)

$textBoxSTATE = New-Object System.Windows.Forms.TextBox
$textBoxSTATE.Location = New-Object System.Drawing.Point(128, $y)
$textBoxSTATE.Size = New-Object System.Drawing.Size(150, 20)
$form.Controls.Add($textBoxSTATE)

$y += 30

$label = New-Object System.Windows.Forms.Label
$label.Text = 'Zip: '
$label.Location = New-Object System.Drawing.Point(20, $y)
$label.AutoSize = $true
$form.Controls.Add($label)

$textBoxZIP = New-Object System.Windows.Forms.TextBox
$textBoxZIP.Location = New-Object System.Drawing.Point(128, $y)
$textBoxZIP.Size = New-Object System.Drawing.Size(150, 20)
$form.Controls.Add($textBoxZIP)

$y += 30

$okButton = New-Object System.Windows.Forms.Button
$okButton.Text = 'OK'
$okButton.Location = New-Object System.Drawing.Point(200, $y)
$okButton.Size = New-Object System.Drawing.Size(75, 23)
$okButton.Add_Click({
    $result = @{}
    $result['FIRST'] = $textBoxFIRST.Text
    $result['LAST'] = $textBoxLAST.Text
    $result['CITY'] = $textBoxCITY.Text
    $result['STATE'] = $textBoxSTATE.Text
    $result['ZIP'] = $textBoxZIP.Text
    Write-Host "Captured Data:"
    $result.GetEnumerator() | ForEach-Object { Write-Host ("{0}: {1}" -f $_.Key, $_.Value) }
    $form.DialogResult = [System.Windows.Forms.DialogResult]::OK
    $form.Close()
})
$form.Controls.Add($okButton)

$form.ShowDialog()
```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment