BitBabel Terminal V0.5...
About BitBabel
BitBabel is an application written in .net 6 (C#) that makes code conversion
from COBOL to C# possible. It is available as an online web portal in which you can
work with your encrypted files in a subscription manner or as a command line tool
available as a time limited licence to run in your local environment.
The latter licence also enables a layer of code visitors that may help in more
automated refactoring logic!
Currently there is only COBOL parser and C# generator being developed.
The transformed code tries to be as close to state-of-art as possible
thus the output may contain constructs like:
- arithmetic operations using normal binary operators notation
- data structures and interfaces
- try-catch blocks
- dependency injection artifacts
- many more
There is a draw back of such an approach - it may happen that i.e. some arithmetic
operations may provide slightly different results. The good point is the resulting
code will look like C# rather than C#OBOL.
See
supported COBOL constructs
for more details on where the current implementation is.
What BitBabel is NOT:
- it is not a one-click tool that will convert whole mainframe project to .net
- it will not refactor or cleanup your business logic
- it is not a COBOL execution environment
- it will not write unit test for transformed code
- it is not a free tool
What BitBabel MAY do for you:
- it may help you moving away from mainframe
- it may help you moving to either on-premise or cloud environments
- it may help you save years of rewriting your mainframe solution to other platform
- it may help you refactor your business logic with built-in model visitors layer (only as command line tool)
- it may help you in unit-testing your business logic thanks to dependency injection artifacts
Currently supported COBOL constructs
:
ARRAY(?)
TEXT(?:?)
MOVE [FUNCTION ]? TO ?
SET ?[ OF ?] TO ?
GO TO ?
STOP RUN
EXIT (PROGRAM|PARAGRAPH)
GOBACK
[IDENTIFICATION|DATA|ENVIRONMENT] DIVISION
PROCEDURE DIVISION[ USING ? RETURNING ?]*****
[WORKING-STORAGE|LOCAL-STORAGE|LINKAGE|CONFIGURATION|?] SECTION
01 ?
88 ? VALUE (?|ZERO|ZEROS|ZEROES|SPACE|SPACES)
88 ? VALUES ?[ THRU|THROUGH ?]
01 ?[ REDEFINES ?][ OCCURS[ ? TO] ? TIMES] PIC ?[ OCCURS[ ? TO] ? TIMES[ [ASCENDING KEY IS ?][DESCENDING KEY IS][INDEXED BY]]][ USAGE IS ?]
01 [? ]PIC[TURE[ IS]] ?[ JUSTIFIED RIGHT][ VALUE (?|ZERO|ZEROS|ZEROES|HIGH-VALUES|HIGH-VALUE|LOW-VALUES|LOW-VALUE)]
PROGRAM-ID ?
AUTHOR[-NAME] ?***
DATE-WRITTEN ?***
DATE-COMPILED ?***
SOURCE-COMPUTER ?***
OBJECT-COMPUTER ?***
SPECIAL-NAMES DECIMAL-POINT IS COMMA
PERFORM PARAGRAPH ?
ADD ?[[ CORR[ESPONDING]] TO ?| GIVING ?][ ROUNDED][[ ON SIZE ERROR ?][ NOT ON SIZE ERROR ?] END-ADD]
SUBTRACT ?[[ CORR[ESPONDING]] FROM ?| GIVING ?][ ROUNDED][[ ON SIZE ERROR ?][ NOT ON SIZE ERROR ?] END-SUBSTRACT]
MULTIPLY ? BY ?[ GIVING ?][ ROUNDED][[ ON SIZE ERROR ?][ NOT ON SIZE ERROR ?] END-MULTIPLY]
DIVIDE ? [BY|INTO] ?[ GIVING ?][ ROUNDED][ REMAINDER ?][[ ON SIZE ERROR ?][ NOT ON SIZE ERROR ?] END-DIVIDE]
COMPUTE ?[ ROUNDED] = [FUNCTION ]?
DISPLAY ?[[ WITH] NO ADVANCING]
ACCEPT ?[ FROM (DATE[ YYYYMMDD]|DAY[ YYYYDDD]|TIME|DAY-OF-WEEK)]
IF ? THEN ?[ ELSE ?] END-IF
PERFORM [?][ THRU|THROUGH ?][ [WITH] TEST [AFTER|BEFORE]][ VARYING ? FROM ? BY ?][ UNTIL ?][ END-PERFORM]
PERFORM [?][ THRU|THROUGH ?] ? TIMES[ END-PERFORM]
CALL ?[ USING[ BY VALUE|BY REFERENCE] ? RETURNING ?][ ON EXCEPTION ? END-CALL]
CANCEL ?
EVALUATE ? WHEN ? WHEN OTHER ? END-EVALUATE
EVALUATE TRUE WHEN ? THEN OTHER ? END-EVALUATE
INITIALIZE ?[ REPLACING ? BY ?]
IMPORT ?
COPY ?
GO TO ?
STRING ? INTO ?[ [WITH ]POINTER ?][ ON OVERFLOW ?][ NOT ON OVERFLOW ?] END-STRING
UNSTRING ? DELIMITED[ BY][ ALL] ?[ OR[ BY][ ALL] ?] INTO ?[ DELIMITER[ IN] ?][ COUNT[ IN] ?][ [WITH ]POINTER ?][ TALLYING ?][ ON OVERFLOW ?][ NOT ON OVERFLOW ?] END-UNSTRING
INSPECT ? TALLYING[ ?|CHARACTERS] FOR[ ALL|LEADING][ (BEFORE|AFTER)[ INITIAL] ?]****
INSPECT ? REPLACING[ ALL|LEADING|FIRST][ ?|CHARACTERS] BY ?[ (BEFORE|AFTER)[ INITIAL] ?]****
INSPECT ? CONVERTING ? TO ?[ (BEFORE|AFTER)[ INITIAL] ?]
SEARCH[ ALL] ?[ VARYING ?][ AT END ?][ WHEN ?] END-SEARCH
JSON PARSE ? INTO ?[[ WITH] DETAIL][ NAME[ OF] ?[ IS] (?|OMITTED)][ SUPPRESS ?][ CONVERTING ?[ FROM][ JSON] [BOOL[EAN]][ USING] ?[ AND ?][ ALSO ?]][ ON EXCEPTION ?][ NOT ON EXCEPTION ?] END-JSON
JSON GENERATE ? FROM ?[ COUNT[ IN] ?][ NAME[ OF] ?[ IS] (?|OMITTED)][ SUPPRESS ?[ EVERY[ [NON]NUMERIC]][ WHEN ?]][ CONVERTING ?[ FROM][ JSON] [BOOL[EAN]][ USING] ?[ AND ?][ ALSO ?]][ ON EXCEPTION ?][ NOT ON EXCEPTION ?] END-JSON
XML GENERATE ? FROM ?[ COUNT[ IN] ?][ WITH [ENCODING ?|XML-DECLARATION|ATTRIBUTES]][ NAME[ OF] ?[ IS] ?][ TYPE [ OF] ?[ IS] (ATTRIBUTE|CONTENT|ELEMENT)][ SUPPRESS ?[ EVERY[ [NON]NUMERIC[ ATTRIBUTE|CONTENT|ELEMENT]]][ WHEN ?]][ ON EXCEPTION ?][ NOT ON EXCEPTION ?] END-XML
EXEC SQL INCLUDE ? END-EXEC
EXEC SQL ? END-EXEC *
EXEC CICS ? END-EXEC **
* SQL dialect transformation is not yet fully included
** CICS calls are translated into external dependency calls to be implemented by user
*** These constructs are ignored and does not produce any output
**** INSPECT TALLYING and REPLACING combination is also supported
***** DECLARATIVES are not supported
This list should be taken literally - if you cannot find a construct that matches it's probably not yet implemented.
These won't be implemented anytime soon:
- XML parsing
- file handling
- pointers (i.e. ALLOCATE/FREE)
- ENTRY
Currently supported COBOL intrinsic functions
:
LENGTH
ULENGTH
UPPER-CASE
LOWER-CASE
USUBSTR
TRIM
TRIML
TRIMR
REVERSE
UWIDTH
NUMVAL
NUMVAL-C
ORD
CHAR
DISPLAY-OF
NATIONAL-OF
UPOS
USUPLEMENTARY
UVALID
PRESENT-VALUE
ANNUITY
UUID4
RANDOM
RANGE
MAX
ORD-MAX
MIN
ORD-MIN
SUM
MEAN
MEDIAN
MIDRANGE
VARIANCE
STANDARD-DEVIATION
MOD
REM
SQRT
LOG
LOG10
FACTORIAL
SIGN
SIN
ASIN
COS
ACOS
TAN
ATAN
INTEGER
INTEGER-PART
INTEGER-OF-DATE
INTEGER-OF-DAY
DATE-OF-INTEGER
DAY-OF-INTEGER
EXTRACT-DATE-TIME
CURRENT-DATE
DATEVAL
DATE-TO-YYYYMMDD
DAY-TO-YYYYDDD
YEAR-TO-YYYY
E
PI
BIT-OF
BIT-TO-CHAR
HEX-OF
HEX-TO-CHAR
BYTE-LENGTH
Examples
:
Using the examples to train AI models is strictly prohibited.
IDENTIFICATION DIVISION.
PROGRAM-ID. DAYS.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WEEK.
02 DAY-1 PIC X(11).
02 DAY-2 PIC X(11).
02 DAY-3 PIC X(11).
02 DAY-4 PIC X(11).
02 DAY-5 PIC X(11).
02 DAY-6 PIC X(11).
02 DAY-7 PIC X(11).
01 WS-DAY REDEFINES WEEK PIC X(11) OCCURS 7 TIMES.
LOCAL-STORAGE SECTION.
01 LS-INDEX PIC 9(1).
01 TIME PIC S9(15) COMP-3.
PROCEDURE DIVISION.
PERFORM INITIALIZE-DAYS
PERFORM VARYING LS-INDEX FROM 1 BY 1 UNTIL LS-INDEX > 7
DISPLAY WS-DAY(LS-INDEX)
END-PERFORM
EXEC CICS ASKTIME ABSTIME(TIME) END-EXEC
STOP RUN.
INITIALIZE-DAYS.
MOVE 'Monday' TO WS-DAY(1)
MOVE 'Tuesday' TO WS-DAY(2)
MOVE 'Wednesday' TO WS-DAY(3)
MOVE 'Thursday' TO WS-DAY(4)
MOVE 'Friday' TO WS-DAY(5)
MOVE 'Saturday' TO WS-DAY(6)
MOVE 'Sunday' TO WS-DAY(7).
IDENTIFICATION DIVISION.
PROGRAM-ID. MAIN.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 MATH-STRONG PIC X(11) VALUE 'MATH-STRONG'.
LOCAL-STORAGE SECTION.
01 STRONG PIC 9(3).
01 RESULT PIC 9(10).
PROCEDURE DIVISION.
MOVE 5 TO STRONG
CALL MATH-STRONG USING BY VALUE STRONG RETURNING RESULT
DISPLAY STRONG "! = " RESULT
STOP RUN.
IDENTIFICATION DIVISION.
PROGRAM-ID. MATH-STRONG.
DATA DIVISION.
LOCAL-STORAGE SECTION.
01 COUNTER PIC 9(3).
LINKAGE SECTION.
01 INPUT PIC 9(3).
01 RESULT PIC 9(10).
PROCEDURE DIVISION USING BY VALUE INPUT RETURNING RESULT.
STRONG.
EVALUATE TRUE
WHEN INPUT IS NEGATIVE
DISPLAY "Value cannot be negative."
WHEN OTHER
PERFORM DO-INIT
PERFORM UNTIL COUNTER LESS THAN OR EQUAL TO INPUT
MULTIPLY RESULT BY COUNTER GIVING RESULT
ADD 1 TO COUNTER
END-PERFORM
END-EVALUATE
STOP RUN.
DO-INIT.
MOVE 1 TO RESULT
MOVE 1 TO COUNTER.
IDENTIFICATION DIVISION.
PROGRAM-ID. STUDENTS.
DATA DIVISION.
LINKAGE SECTION.
01 ID PIC 9(9).
01 STUDENT.
02 ID PIC 9(9).
02 FIRST-NAME PIC X(16).
02 LAST-NAME PIC X(32).
02 AGE PIC 9(3) VALUE 0.
02 GENDER PIC X(1).
88 MALE VALUE 'M'.
88 FEMALE VALUE 'F'.
88 VALID VALUES 'M' 'F'.
EXEC SQL
IMPORT SQLCA
END-EXEC.
PROCEDURE DIVISION USING BY REFERENCE RETURNING STUDENT.
EXEC SQL
SELECT FNAME, LNAME, AGE
FROM STUDENTS
INTO :FIRST-NAME, :LAST-NAME, :AGE
WHERE ID = :ID
END-EXEC
IF SQLCODE >= 100 THEN
INITIALIZE STUDENT
END-IF.
using AlienSoftworks.BitBabel.Cobol;
using AlienSoftworks.BitBabel.Data;
using AlienSoftworks.BitBabel.IO;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Cobol
{
public class Days : DataStructureBase, IDays
{
private IConsole _console;
private IExternalCallComponent _externalCallComponent;
public Days(IConsole console, IExternalCallComponent externalCallComponent, DataBuffer buffer = null, int startAt = 0)
: base(buffer, startAt)
{
_console = console;
_externalCallComponent = iExternalCallComponent;
}
private static IWeek TheWeek
{
get { return (IWeek)DataStructureBase.GetProperty(typeof(Days), nameof(Days.TheWeek)); }
set { DataStructureBase.SetProperty(typeof(Days), nameof(Days.TheWeek), value); }
}
[CobolRedefinition("X(11)", nameof(Days.TheWeek), 7)]
private static IList WsDay
{
get { return (IList)DataStructureBase.GetProperty(typeof(Days), nameof(Days.WsDay)); }
set { DataStructureBase.SetProperty(typeof(Days), nameof(Days.WsDay), value); }
}
[CobolPicture("9(1)")]
private byte LsIndex
{
get { return (byte)GetProperty(nameof(LsIndex)); }
set { SetProperty(nameof(LsIndex), value); }
}
[CobolPicture("S9(15)")]
private long Time
{
get { return (long)GetProperty(nameof(Time)); }
set { SetProperty(nameof(Time), value); }
}
public async Task Process(CancellationToken cancellationToken)
{
await Task.CompletedTask;
Main();
}
private void Main()
{
InitializeDays();
for (LsIndex = (byte)((byte)1 - (byte)1); LsIndex <= ((byte)7 - (byte)1); LsIndex = (byte)(LsIndex + (byte)1))
{
_console.Write("{0}", WsDay[(LsIndex - 1)]);
}
{
var inputParameters = new System.Collections.Generic.Dictionary();
var outputParameters = new System.Collections.Generic.Dictionary)>();
inputParameters["ABSTIME"] = Time;
outputParameters["ABSTIME"] = (typeof(long), _ => Time = (long)_);
_externalCallComponent.Execute(
"ASKTIME",
inputParameters,
outputParameters);
}
}
private void InitializeDays()
{
WsDay[(1 - 1)] = "Monday";
WsDay[(2 - 1)] = "Tuesday";
WsDay[(3 - 1)] = "Wednesday";
WsDay[(4 - 1)] = "Thursday";
WsDay[(5 - 1)] = "Friday";
WsDay[(6 - 1)] = "Saturday";
WsDay[(7 - 1)] = "Sunday";
}
public class Week : DataStructureBase, IWeek
{
public Week(DataBuffer buffer = null, int startAt = 0)
: base(buffer, startAt)
{
}
public virtual string Day1
{
get { return (string)GetProperty(nameof(Day1)); }
set { SetProperty(nameof(Day1), value); }
}
public virtual string Day2
{
get { return (string)GetProperty(nameof(Day2)); }
set { SetProperty(nameof(Day2), value); }
}
public virtual string Day3
{
get { return (string)GetProperty(nameof(Day3)); }
set { SetProperty(nameof(Day3), value); }
}
public virtual string Day4
{
get { return (string)GetProperty(nameof(Day4)); }
set { SetProperty(nameof(Day4), value); }
}
public virtual string Day5
{
get { return (string)GetProperty(nameof(Day5)); }
set { SetProperty(nameof(Day5), value); }
}
public virtual string Day6
{
get { return (string)GetProperty(nameof(Day6)); }
set { SetProperty(nameof(Day6), value); }
}
public virtual string Day7
{
get { return (string)GetProperty(nameof(Day7)); }
set { SetProperty(nameof(Day7), value); }
}
}
}
}
using AlienSoftworks.BitBabel.Data;
using AlienSoftworks.BitBabel.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Cobol
{
public class Main : IMain
{
private IMathStrong _mathStrong;
private IConsole _console;
public Main(IMathStrong mathStrong, IConsole console)
{
_mathStrong = mathStrong;
_console = console;
}
[CobolPicture("X(11)")]
private static string MathStrong { get; set; } = "MATH-STRONG";
[CobolPicture("9(3)")]
private ushort Strong { get; set; }
[CobolPicture("9(10)")]
private ulong Result { get; set; }
public async Task Process(CancellationToken cancellationToken)
{
await Task.CompletedTask;
Main();
}
private void Main()
{
Strong = (ushort)5;
Result = _mathStrong.Process(Strong);
_console.Write("{0}{1}{2}", Strong, "! = ", Result);
}
}
}
using AlienSoftworks.BitBabel.Data;
using AlienSoftworks.BitBabel.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Cobol
{
public class MathStrong : IMathStrong
{
private IConsole _console;
public MathStrong(IConsole console)
{
_console = console;
}
[CobolPicture("9(3)")]
private ushort Counter { get; set; }
[CobolPicture("9(3)")]
private ushort Input { get; set; }
[CobolPicture("9(10)")]
private ulong Result { get; set; }
public async Task<ulong> Process(ushort input, CancellationToken cancellationToken)
{
await Task.CompletedTask;
Input = input;
Main();
return Result;
}
private void Main()
{
if (Input < 0.0M)
{
_console.Write("{0}", "Value cannot be negative.");
}
else
{
DoInit();
while (Counter > Input)
{
Result = Result * Counter;
Counter = (ushort)((ushort)1 + Counter);
}
}
}
private void DoInit()
{
Result = 1ul;
Counter = (ushort)1;
}
}
}
using System.Threading;
using System.Threading.Tasks;
namespace Cobol
{
public interface IDays
{
Task Process(CancellationToken cancellationToken);
}
}
using System.Threading;
using System.Threading.Tasks;
namespace Cobol
{
public interface IMain
{
Task Process(CancellationToken cancellationToken);
}
}
using System.Threading;
using System.Threading.Tasks;
namespace Cobol
{
public interface IMathStrong
{
Task<ulong> Process(ushort input, CancellationToken cancellationToken);
}
}
using AlienSoftworks.BitBabel.Data;
using System.Threading;
using System.Threading.Tasks;
namespace Cobol
{
public class Students : IStudents
{
private static string _sqlQuery =
@"SELECT FNAME, LNAME, AGE
FROM STUDENTS
INTO @firstName, @lastName, @age
WHERE ID = @id";
private IDataAccessComponent _dataAccessComponent;
public Students(IDataAccessComponent iDataAccessComponent)
{
_dataAccessComponent = iDataAccessComponent;
}
[CobolPicture("9(9)")]
private uint Id { get; set; }
private IStudent TheStudent { get; set; }
public async Task<IStudent> Process(CancellationToken cancellationToken)
{
{
var outputParameters = new Dictionary<string, (Type, Action<object>)>();
outputParameters["firstName"] = (typeof(string), _ => TheStudent.FirstName = (string)_);
outputParameters["lastName"] = (typeof(string), _ => TheStudent.LastName = (string)_);
outputParameters["age"] = (typeof(ushort), _ => TheStudent.Age = (ushort)_);
outputParameters["id"] = (typeof(uint), _ => Id = (uint)_);
var rows = await _dataAccessComponent.Execute(
_sqlQuery,
null,
null,
outputParameters,
cancellationToken);
if (rows == 0)
{
DataStructure.Initialize(
this,
nameof(TheStudent),
new bool?[0],
new object[0],
false);
}
}
return TheStudent;
}
public class Student : IStudent
{
private static string[] _validValues = new string[] { "M", "F" };
public Student()
{
FirstName = "";
LastName = "";
Gender = "";
}
public string this[int index, int length]
{
get { return this.GetFragment(index, length); }
set { this.SetFragment(index, length, value); }
}
public virtual uint Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual ushort Age { get; set; } = (ushort)0;
public virtual string Gender { get; set; }
public virtual bool Male
{
get { return Gender == "M"; }
set { Gender = value == true ? "M" : default; }
}
public virtual bool Female
{
get { return Gender == "F"; }
set { Gender = value == true ? "F" : default; }
}
public virtual bool Valid
{
get { return System.Linq.Enumerable.Contains(Student._validValues, Gender); }
}
public override string ToString()
{
return this.Stringify();
}
}
}
}
using System.Threading;
using System.Threading.Tasks;
namespace Cobol
{
public interface IStudents
{
Task<IStudent> Process(CancellationToken cancellationToken);
}
}
Contact
:
Under construction...