BitBabel Terminal V0.5...

About BitBabel Examples Contact

About BitBabel


BitBabel is an application written in .net 6 (C#) that makes code conversion from COBOL to other languages 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 per-seat 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 are COBOL to C# and Java and JCL to PowerShell transformations available.
The transformed code tries to be as close to state-of-the-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#BOL or J-BOL and easier to maintain in future.
See supported COBOL constructs and supported JCL 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 or Java
- 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 platforms
- 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

Menu

Currently supported JCL constructs

:
JOB ? PROC
PEND
EXEC (PGM=?[ DD (PARAM=?|*?/*)]|PROC=?[,PARAM=?])*
IF ? THEN ?[ ELSE ?] ENDIF
COND=(EVEN|ONLY|?, (LT|GT|LE|GE|EQ|NE)[,?])
RESTART=?
[?.[?.[?]]]RC
[?.[?.[?]]][!]ABEND
[?.[?.[?]]][!]RUN
* - procedure step modification is not supported
About

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 **
INTRINSIC FUNCTIONS

* 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
About

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
Supported COBOL constructs
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.
                Back
                
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();
            }
        }
    }
}
                Back
                
using System.Threading;
using System.Threading.Tasks;

namespace Cobol
{
    public interface IStudents
    {
        Task<IStudent> Process(CancellationToken cancellationToken);
    }
}
                Back
                
package cobol;

import java.util.function.Consumer;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import javafx.util.Pair;
import net.bitbabel.data.CobolName;
import net.bitbabel.data.CobolPicture;
import net.bitbabel.data.DataAccessComponent;
import net.bitbabel.data.DataStructure;
import net.bitbabel.reflect.Order;
import net.bitbabel.util.ArrayOf;
import static net.bitbabel.ObjectExtensions.fromString;
import static net.bitbabel.ObjectExtensions.stringify;
import static net.bitbabel.reflect.Part.getFragment;
import static net.bitbabel.reflect.Part.setFragment;
import static net.bitbabel.util.stream.StreamHelper.toStream;

public class StudentsImpl implements Students {
    private static String[] validValues = new String[] { "M", "F" };
    private static String sqlQuery =
        "SELECT FNAME, LNAME, AGE\nFROM STUDENTS\nINTO firstName, lastName, age\nWHERE ID = id";

    private final DataAccessComponent dataAccessComponent;

    public StudentsImpl(DataAccessComponent dataAccessComponent) {
        resetLocalStorage();
        this.dataAccessComponent = dataAccessComponent;
    }

    private int _id;

    @Order(0)
    @CobolPicture("9(9)")
    @CobolName("ID")
    private int getId() {
        return _id;
    }

    @Order(0)
    @CobolPicture("9(9)")
    @CobolName("ID")
    private int setId(int value) {
        return _id = value;
    }

    private StudentsStudent _theStudent;

    @Order(1)
    @CobolName("STUDENT")
    private StudentsStudent getTheStudent() {
        return _theStudent;
    }

    @Order(1)
    @CobolName("STUDENT")
    private StudentsStudent setTheStudent(StudentsStudent value) {
        return _theStudent = value;
    }

    public static Student asStudent(String value) {
        return fromString(new StudentsImpl(null).new Student(), value);
    }

    public void reset() {
        resetLocalStorage();
    }

    public StudentsStudent process() {
        {
            Map<String, Pair<Class<?>, Consumer<Object>>> outputParameters = new HashMap<>();
            outputParameters.put("firstName", new Pair<Class<?>, Consumer<Object>>(String.class, x -> getTheStudent().setFirstName((String)x)));
            outputParameters.put("lastName", new Pair<Class<?>, Consumer<Object>>>String.class, x -> getTheStudent().setLastName((String)x)));
            outputParameters.put("age", new Pair<Class<?>, Consumer<Object>>(Short.class, x -> getTheStudent().setAge((short)x)));
            outputParameters.put("id", new Pair<Class<?>, Consumer<Object>>(Integer.class, x -> setId((int)x)));
            int rows = dataAccessComponent.execute(
                sqlQuery,
                null,
                null,
                outputParameters);
            if (rows == 0)
            {
                DataStructure.initialize(
                    this,
                    "TheStudent",
                    (Optional<Boolean>[])ArrayOf.values(Optional.class, 0),
                    new Object[0],
                    false);
            }
        }
        return getTheStudent();
    }

    private void resetLocalStorage() {
        setTheStudent(new StudentsImpl(null).new Student());
    }

    public class Student implements StudentsStudent {
        public Student() {
            this._firstName = "";
            this._lastName = "";
            this._gender = "";
        }

        public String get(int index, int length) {
            return getFragment(this, index, length);
        }

        public String put(int index, int length, String value) {
            setFragment(this, index, length, value);
            return this.get(index, length);
        }

        private int _id;

        public int getId() {
            return _id;
        }

        public int setId(int value) {
            return _id = value;
        }

        private String _firstName;

        public String getFirstName() {
            return _firstName;
        }

        public String setFirstName(String value) {
            return _firstName = value;
        }

        private String _lastName;

        public String getLastName() {
            return _lastName;
        }

        public String setLastName(String value) {
            return _lastName = value;
        }

        private short _age = 0;

        public short getAge() {
            return _age;
        }

        public short setAge(short value) {
            return _age = value;
        }

        private String _gender;

        public String getGender() {
            return _gender;
        }

        public String setGender(String value) {
            return _gender = value;
        }

        public boolean isMale() {
            return getGender() == "M";
        }

        public boolean isMale(boolean value) {
            setGender(value == true ? "M" : null);
            return isMale();
        }

        public boolean isFemale() {
            return getGender() == "F";
        }

        public boolean isFemale(boolean value) {
            setGender(value == true ? "F" : null);
            return isFemale();
        }

        public boolean isValid() {
            return toStream(StudentsImpl.validValues).anyMatch(x -> Objects.equals(x, getGender()));
        }

        @Override
        public String toString() {
            return stringify(this);
        }
    }
}
                Back
                
package cobol;

import net.bitbabel.Program;

public interface Students extends Program {
    StudentsStudent process();
}
                Back
                
//CATLPROC PROC PROG=,BASELB=MYCOBOL.BASE.LIB1
//*
//PROC1     EXEC PGM=&PROG
//STEPLIB   DD DSN=&BASELB,DISP=SHR
//IN1       DD DSN=&DSNAME,DISP=SHR
//OUT1      DD SYSOUT=*
//SYSOUT    DD SYSOUT=*
//SYSIN     DD DSN=&DATAC
//*
                Back
                
using namespace System.Linq;

class Catlproc
{
    static [int] $proc1 = -1;

    static [bool] getReturnCode()
    {
        return [Enumerable]::Max(@([Catlproc]::$proc1));
    }

    static [void] Process([string] $prog, [string] $baselb, [string] $dsname, [string] $datac)
    {
        if ($prog -eq $null)
        {
            $prog = "";
        }

        if ($baselb -eq $null)
        {
            $baselb = "MYCOBOL.BASE.LIB1";
        }

        if ([Catlproc]::getReturnCode() -le 0)
        {
            [Catlproc]::Proc1($prog, $baselb, $dsname, $datac);
        }
    }

    static [void] Proc1([string] $prog, [string] $baselb, [string] $dsname, [string] $datac)
    {
        & $prog `
            -STEPLIB DSN=$baselb,DISP=SHR `
            -IN1 DSN=$dsname,DISP=SHR `
            -OUT1 SYSOUT=* `
            -SYSOUT SYSOUT=* `
            -SYSIN DSN=$datac;
        [Catlproc]::$proc1 = $LastExitCode;
    }
}
                Back
                

Contact

:
Under construction...

Menu