COBOL

COBOL

COBOL

COBOL is responsible for the efficient, reliable, secure, and unseen day-to-day operations of the world's economy.


#Programminglanguages
 View Only
  • 1.  Easy COBOL Migrator - Desktop transpiler converting COBOL to C++, Java, C#, Python, Rust and Go; Looking for feedback

    Posted 03/16/26 05:36 PM
    Edited by Lorraine Rizzuto 03/17/26 09:24 AM

    Hello everyone,

    I'm Norbert, a software developer and security consultant based in London. For the past six months I've been building a desktop COBOL transpiler called Easy COBOL Migrator and I'd like to share it with this community for feedback.

    The tool converts COBOL source code to six modern languages: C++ 17, Java 17, C# 12, Python 3, Rust and Go. It uses a full compiler pipeline, not AI or pattern matching.

    Building a parser for COBOL was one of the most challenging projects I've taken on. The language has depth that I didn't fully appreciate before starting. PIC clause parsing alone took weeks. Handling the interaction between level numbers, REDEFINES, OCCURS DEPENDING ON and group item nesting required multiple rewrites before I got the data structure generation right. PERFORM THRU with paragraph fall-through semantics was another area where I had to rethink my approach several times.

    The pipeline has five stages:

    • COPY Preprocessor - Resolves COPY and REPLACE directives with nested copybook support up to 10 levels and circular-include detection
    • Lexer - Tokenizes source with auto-detection of fixed-format and free-format, handles 220+ keywords, column 7 indicators and continuation lines
    • Parser - Recursive descent parser covering 36 statement types, builds a complete AST with expression trees, conditions and hierarchical data structures
    • Semantic Analyzer - Symbol table construction, ambiguous name detection, OF/IN qualification resolution, paragraph/section existence checks, level 88 validation and type checking
    • Code Generators - Six separate generators, each producing idiomatic output for the target language

    Here is a small example. This COBOL:

           IDENTIFICATION DIVISION.
           PROGRAM-ID. PAYROLL-CALC.
    
           DATA DIVISION.
           WORKING-STORAGE SECTION.
    
           01  WS-EMPLOYEE.
               05  WS-NAME            PIC X(25).
               05  WS-HOURS           PIC 9(3)V99.
               05  WS-RATE            PIC 9(3)V99.
               05  WS-GROSS-PAY       PIC 9(5)V99.
               05  WS-TAX             PIC 9(5)V99.
               05  WS-NET-PAY         PIC 9(5)V99.
    
           01  WS-TAX-RATE            PIC V99 VALUE 0.20.
           01  WS-OVERTIME-MULT       PIC 9V9 VALUE 1.5.
           01  WS-OVERTIME-THRESHOLD  PIC 9(3) VALUE 40.
           01  WS-OVERTIME-HOURS      PIC 9(3)V99 VALUE 0.
           01  WS-REGULAR-HOURS       PIC 9(3)V99 VALUE 0.
           01  WS-COUNTER             PIC 9(2) VALUE 0.
    
           01  WS-PAY-GRADE           PIC 9 VALUE 0.
               88  JUNIOR             VALUE 1.
               88  SENIOR             VALUE 2.
               88  MANAGER            VALUE 3.
    
           PROCEDURE DIVISION.
           MAIN-PROGRAM.
               MOVE "Alice Johnson" TO WS-NAME
               MOVE 45.00 TO WS-HOURS
               MOVE 32.50 TO WS-RATE
               MOVE 2 TO WS-PAY-GRADE
    
               PERFORM CALCULATE-PAY
               PERFORM DISPLAY-PAYSLIP
               PERFORM DISPLAY-GRADE
    
               STOP RUN.
    
           CALCULATE-PAY.
               IF WS-HOURS > WS-OVERTIME-THRESHOLD
                   COMPUTE WS-REGULAR-HOURS =
                       WS-OVERTIME-THRESHOLD
                   SUBTRACT WS-OVERTIME-THRESHOLD FROM WS-HOURS
                       GIVING WS-OVERTIME-HOURS
                   COMPUTE WS-GROSS-PAY =
                       (WS-REGULAR-HOURS * WS-RATE) +
                       (WS-OVERTIME-HOURS * WS-RATE *
                        WS-OVERTIME-MULT)
               ELSE
                   COMPUTE WS-GROSS-PAY =
                       WS-HOURS * WS-RATE
               END-IF
    
               MULTIPLY WS-GROSS-PAY BY WS-TAX-RATE
                   GIVING WS-TAX ROUNDED
    
               SUBTRACT WS-TAX FROM WS-GROSS-PAY
                   GIVING WS-NET-PAY.
    
           DISPLAY-PAYSLIP.
               DISPLAY "================================"
               DISPLAY "  PAYROLL SUMMARY"
               DISPLAY "================================"
               DISPLAY "Employee:  " WS-NAME
               DISPLAY "Hours:     " WS-HOURS
               DISPLAY "Rate:      " WS-RATE
               DISPLAY "Gross Pay: " WS-GROSS-PAY
               DISPLAY "Tax (20%): " WS-TAX
               DISPLAY "Net Pay:   " WS-NET-PAY
               DISPLAY "================================".
    
           DISPLAY-GRADE.
               EVALUATE TRUE
                   WHEN JUNIOR
                       DISPLAY "Grade: Junior"
                   WHEN SENIOR
                       DISPLAY "Grade: Senior"
                   WHEN MANAGER
                       DISPLAY "Grade: Manager"
                   WHEN OTHER
                       DISPLAY "Grade: Unknown"
               END-EVALUATE.

    Produces this C++:

    // Transpiled from COBOL program: PAYROLL-CALC
    // Generated by Easy COBOL Migrator on 2026-03-16 07:09:47
    
    #include <iostream>
    #include <string>
    #include <cmath>
    #include <cstdlib>
    #include <cstdint>
    
    // COBOL string move helper: truncate or right-pad to field width
    inline std::string cobolMove(const std::string& src, int len) {
        std::string r = src; r.resize(len, ' '); return r;
    }
    
    // COBOL string comparison: pad shorter operand with spaces
    inline int cobolCmp(const std::string& a, const std::string& b) {
        size_t len = std::max(a.size(), b.size());
        std::string la = a, lb = b;
        la.resize(len, ' '); lb.resize(len, ' ');
        return la.compare(lb);
    }
    
    void main_program();
    void calculate_pay();
    void display_payslip();
    void display_grade();
    
    // WORKING-STORAGE variables
    struct {
        std::string ws_name = std::string(25, ' ');
        double ws_hours = 0.0;
        double ws_rate = 0.0;
        double ws_gross_pay = 0.0;
        double ws_tax = 0.0;
        double ws_net_pay = 0.0;
    } ws_employee;
    double ws_tax_rate = 0.20;
    double ws_overtime_mult = 1.5;
    int ws_overtime_threshold = 40;
    double ws_overtime_hours = 0;
    double ws_regular_hours = 0;
    int ws_counter = 0;
    int ws_pay_grade = 0;
    inline bool junior() { return ws_pay_grade == 1; }
    inline bool senior() { return ws_pay_grade == 2; }
    inline bool manager() { return ws_pay_grade == 3; }
    
    int64_t return_code = 0;
    
    void main_program() {
        ws_employee.ws_name = cobolMove("Alice Johnson", 25);
        ws_employee.ws_hours = 45.00;
        ws_employee.ws_rate = 32.50;
        ws_pay_grade = 2;
        calculate_pay();
        display_payslip();
        display_grade();
        exit(0);
    }
    
    void calculate_pay() {
        if (ws_employee.ws_hours > ws_overtime_threshold) {
            ws_regular_hours = ws_overtime_threshold;
            ws_overtime_hours = ws_employee.ws_hours - (ws_overtime_threshold);
            ws_employee.ws_gross_pay = ((ws_regular_hours * ws_employee.ws_rate) + ((ws_overtime_hours * ws_employee.ws_rate) * ws_overtime_mult));
        } else {
            ws_employee.ws_gross_pay = (ws_employee.ws_hours * ws_employee.ws_rate);
        }
        ws_employee.ws_tax = std::round((ws_employee.ws_gross_pay * ws_tax_rate) * 100.0) / 100.0;
        ws_employee.ws_net_pay = ws_employee.ws_gross_pay - (ws_employee.ws_tax);
    }
    
    void display_payslip() {
        std::cout << "================================" << std::endl;
        std::cout << "  PAYROLL SUMMARY" << std::endl;
        std::cout << "================================" << std::endl;
        std::cout << "Employee:  " << ws_employee.ws_name << std::endl;
        std::cout << "Hours:     " << ws_employee.ws_hours << std::endl;
        std::cout << "Rate:      " << ws_employee.ws_rate << std::endl;
        std::cout << "Gross Pay: " << ws_employee.ws_gross_pay << std::endl;
        std::cout << "Tax (20%): " << ws_employee.ws_tax << std::endl;
        std::cout << "Net Pay:   " << ws_employee.ws_net_pay << std::endl;
        std::cout << "================================" << std::endl;
    }
    
    void display_grade() {
        if (junior()) {
            std::cout << "Grade: Junior" << std::endl;
        } else if (senior()) {
            std::cout << "Grade: Senior" << std::endl;
        } else if (manager()) {
            std::cout << "Grade: Manager" << std::endl;
        } else {
            std::cout << "Grade: Unknown" << std::endl;
        }
    }
    
    int main() {
        main_program();
        return 0;
    }

    The group item becomes an anonymous struct with typed fields. PIC 9(3)V99 maps to double with std::round for ROUNDED arithmetic. The level 88 conditions JUNIOR, SENIOR and MANAGER resolve to inline bool functions checking their parent variable WS-PAY-GRADE.

    Coverage includes:

    • All four divisions with full DATA DIVISION support (levels 01-88, all PIC/USAGE variants including COMP-3, OCCURS, REDEFINES, RENAMES, FILLER)
    • LINKAGE SECTION transpilation with CALL BY REFERENCE, BY CONTENT and BY VALUE
    • File I/O with OPEN/CLOSE/READ/WRITE/REWRITE/DELETE/START, record packing/unpacking and seek-based in-place update
    • SORT/MERGE with key-field extraction supporting multi-key comparators with ascending/descending order
    • COPY/REPLACE preprocessing with pseudo-text substitution and nested copybooks
    • STRING/UNSTRING/INSPECT with full clause support
    • SEARCH and SEARCH ALL for table operations
    • 40+ intrinsic functions mapped to native equivalents in all 6 languages
    • EXEC SQL, EXEC CICS and EXEC DLI blocks preserved as comments with migration notes
    • IBM Enterprise COBOL, Micro Focus, GnuCOBOL, COBOL-85/2002/2014 dialect support
    • Fixed-format and free-format with auto-detection

    Known limitations: Report Writer and Screen Section are not supported. Indexed/relative file random access converts to sequential with a migration note recommending database replacement.

    The tool is backed by 498 automated tests across all six target languages and has been validated against the NIST CCVS85 standard test suite.

    There is a free demo available that converts single files up to 500 lines to C++ output: https://mecanik.dev/en/products/easy-cobol-migrator/

    I would genuinely appreciate feedback from this community, especially:

    • Are there Enterprise COBOL patterns or extensions that you think would be challenging for the parser? I want to know what real production code looks like beyond test suites.
    • How heavily do your codebases rely on EXEC SQL and EXEC CICS? Currently the tool preserves these as comments with migration notes. Would generated scaffolding code (JDBC stubs for Java, ADO.NET stubs for C#) be more useful?
    • Which target language is most relevant for your migration projects? Most of the industry seems to target Java but I'm curious what this community's experience has been.

    I'm happy to test any COBOL samples you'd like to share (non-confidential of course) and report back on how the tool handles them.

    Thank you for your time.



    ------------------------------
    Norbert Elemer Boros
    Software Developer & Security Consultant
    Mecanik Dev Ltd
    London
    ------------------------------



  • 2.  RE: Easy COBOL Migrator - Desktop transpiler converting COBOL to C++, Java, C#, Python, Rust and Go; Looking for feedback

    Posted 03/23/26 01:17 AM

    I've just released v1.0.1 with several fixes and improvements driven by testing and technical feedback over the past week.

    Highlights:

    • ON SIZE ERROR now correctly detects arithmetic overflow against the target variable's PIC capacity across all 6 target languages. Previously only division-by-zero was caught. ADD, SUBTRACT, MULTIPLY and COMPUTE overflows were silently ignored. So PIC 999 with 995 + 6 now properly triggers the SIZE ERROR handler.
    • COMP-3/packed decimal DISPLAY now formats output with correct sign prefix, zero-padded digits and exact decimal places matching the PIC clause. All 6 languages.
    • Edited numeric fields (PIC with Z, *, $, +, -) are now mapped to string types instead of integer types. MOVE applies full PIC edit mask formatting via a new cobolEditFmt helper.
    • REDEFINES fields now share storage with their base fields via init-time sync code. When the base field has a VALUE clause, the generated program builds a storage string from the base value and extracts substrings for each child of the redefining group.
    • ADD...TO...GIVING and SUBTRACT...FROM...GIVING now correctly include the TO/FROM operands in the expression for Python, Rust and Go. Previously ADD A TO B GIVING C computed C = A instead of C = A + B.
    • COPY REPLACING with pseudo-text delimiters now works correctly. The preprocessor was not receiving the source file path, so it could never locate copybook files.
    • SET condition-name TO TRUE for level 88 conditions inside group structures now generates correctly qualified parent variable references in all 6 languages.

    Full changelog at https://mecanik.dev/en/products/easy-cobol-migrator/

    Free demo updated. Same 500-line limit, C++ output. If anyone wants to throw COBOL at it and tell me what breaks, I'm all ears.

    Sample screenshot (COMP-3/packed) to Java (had to edit the namespace a bit):

    Example conversion of COMP-3/packed COBOL to Java
    Many thanks to https://www.onlinegdb.com/ for offering this very easy way to compile COBOL and other languages.


    ------------------------------
    Norbert Elemer Boros
    Software Developer & Security Consultant
    Mecanik Dev Ltd
    London
    ------------------------------



  • 3.  RE: Easy COBOL Migrator - Desktop transpiler converting COBOL to C++, Java, C#, Python, Rust and Go; Looking for feedback

    Posted 03/31/26 12:56 PM

    Hi Norbert,

    I am very interested in using this to convert to Python.

    I'll let you know how it does with a complex program I'm working on now.

    Best,

    Ross Burnett



    ------------------------------
    Ross Burnett
    ------------------------------



  • 4.  RE: Easy COBOL Migrator - Desktop transpiler converting COBOL to C++, Java, C#, Python, Rust and Go; Looking for feedback

    Posted 03/31/26 02:31 PM

    Hi Ross,

    Sounds good, love a challenge!

    Post a sample here or send me via email if confidential and I will show you an example output with the latest version.

    Thanks



    ------------------------------
    Norbert Elemer Boros
    Software Developer & Security Consultant
    Mecanik Dev Ltd
    London
    ------------------------------



  • 5.  RE: Easy COBOL Migrator - Desktop transpiler converting COBOL to C++, Java, C#, Python, Rust and Go; Looking for feedback

    Posted 03/31/26 11:32 PM

    Hi Ross,

    Looking at the code you sent me, it's missing the standard COBOL COPY header block that the *++INCLUDE statements reference. The *++INCLUDE UW006 is missing its copybook content (used for UW006-RTN-CD). Additionally, I have no way of replying to your private message; not entirely sure why and how this forum is working. So send it via email to contact@mecanik.dev

    Can you please send me the full working code without missing pieces? The transpiler cannot guess or invent missing functions, it converts what is provided.

    Thanks



    ------------------------------
    Norbert Elemer Boros
    Software Developer & Security Consultant
    Mecanik Dev Ltd
    London
    ------------------------------



  • 6.  RE: Easy COBOL Migrator - Desktop transpiler converting COBOL to C++, Java, C#, Python, Rust and Go; Looking for feedback

    Posted 04/08/26 04:06 AM
      |   view attached

    Hi Ross,

    Thank you for the exercise, it was fun.

    The running Python code and all six language outputs are in this repository: https://github.com/Mecanik-Dev/MRFLCL-Exercise

    Thanks,

    Norbert



    ------------------------------
    Norbert Elemer Boros
    Software Developer & Security Consultant
    Mecanik Dev Ltd
    London
    ------------------------------