• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Include C Utilities in Your Developer Library: Evaluating a Mathematical String Expression

    March 24, 2010 Michael Sansoterra

    Most i programmers have a library of RPG or COBOL utilities they’ve written or filched from another source. Having a library of samples and pre-built code is a great productivity booster. However, have you ever considered adding C and C++ code to your library? You don’t know C? Big deal. If you have the C compiler loaded on your i, there’s an abundance of C and C++ code out there on the internet just waiting for you to discover. Plus, if you’re well versed in ILE concepts, you may be further along the C path than you think.

    Consider this scenario: every once in a while I find myself working on a project that requires the run-time evaluation of a mathematical expression contained in a string. Writing a versatile mathematical expression evaluator in RPG would be a huge chore. A while back, I published a tip on how to use SQL as a dynamic expression evaluator. While SQL can evaluate a string expression dynamically, it is relatively slow, so for this one particular project I found myself looking for a faster solution. I hopped online and found a program called eval.c (from a Web site called The SNIPPETS C Source Code Archives), which is written in C. It was a great solution that has served its purpose well.

    For a little more background, this one particular project involved executing a large number of calculations based on formulas that were constantly subject to change by the users. My desire was to remove these hard-coded formulas from the RPG program and soft code them so that developers wouldn’t have to spend a lot of time changing source, compiling, and testing. For the purpose of this discussion, a formula could be as simple as: “QTY * UNITPRICE”. At run time I would substitute numerical values in place of the variable names (for example, “8 * 7.50”) and then evaluate and store the results.

    Once I had the C code compiled, it could be invoked using a prototype in RPG like this:

    MyResult = Eval('8 * 7.50')
    

    In SQL, the C code can also be invoked as a user-defined function:

    Select Eval('8 * 7.50') As MyResult From SysIBM.SysDummy1
    

    Of course, both of these calls return the result of 60. If you’d like to know exactly how this code was compiled and accessed by SQL and RPG, see the section titled “Instructions: How To Create the “eval.c” Program on the System i/iSeries/AS/400/I” at the end of this tip.

    Since many of us IBM “i” folk don’t know C (or don’t know it very well–I last did C in the late ’80s on my Commodore 128), here are a few notes to get you started:

    • Use FTP, the IBM System i Access File Transfer, WDSc/RDi RSE, or some other utility to get the Web code to your IBM i.
    • Storage for C source code typically goes in source physical file QCSRC with a member type of C.
    • Source for C++ code typically goes in source file QCPPSRC with a member type of CPP.
    • “Include” files typically go in a source file called H with a member type of H. In the C world, an include file is similar to an RPG /COPY member.
    • If your organization allows production source code to be stored on the IFS, C source files can be placed on the IFS instead of in source members (saving you the trouble of converting them to source members). In addition to source members, the C/C++ compiler commands allow programs to be compiled directly from stream files that reside on the IFS.
    • From the early days, C programmers were writing code in reusable chunks. Don’t be surprised if, in addition to the main source code, you have to download many additional source files before you have everything you need. For the eval.c program discussed here, I had to download a total of nine additional source files!
    • The basic OS/400 and i/OS compile commands for C and C++ objects are:
      * CRTBNDC–Create Bound ILE C Program
      * CRTBNDCPP–Create Bound ILE C++ Program
      * CRTCMOD–Create ILE C Module
      * CRTCPPMOD–Create ILE C++ Module
      * CRTSQLCI–Create SQL ILE C Object
      * CRTSQLCPPI–Create SQL ILE C++ Object
    • A function in C is similar to an RPG subprocedure.
    • Similar to RPG, a collection of C functions (procedures) should be compiled as a module and bound within a service program. A C program that contains the “main” function (and is intended to be run with a definitive start and end) should be created as a program object–just like RPG.
    • When creating a C++ based service program, specify public function names in the binder source instead of using the EXPORT(*ALL) option. When using EXPORT(*ALL), the function names will have some additional characters appended.
    • Once the C source files are on your system, you may need to add a small wrapper of some kind to the code in order to easily access it from an ILE or SQL interface. For instance, in the case of eval.c, I opted to write a function wrapper that would return a value directly (because the original function returned its value as an output parameter).
    • The default compiler setting will not generate a source listing, which makes it difficult for new C developers to work with! Specify the OUTPUT(*PRINT) parameter when compiling to remedy this.
    • If the C source file has a long name, you will need to shorten the program object name to 10 characters or less, a limitation of i/OS and OS/400. (Remember you can compile a long source file name from the IFS but you’ll need to specify a shorter program name.)
    • When debugging a program using the ILE debugger, you often want to view the content of a variable. In C, you generally have to know something about the type of variables you’re debugging in order to specify the correct suffix for the debugger’s eval command. Without the right suffix, you may get something like a memory address! Look in the ILE debugger help under eval to find out about these options. For example, you’ll need to suffix your variable name with “:s” if you want to display the contents of string variable “MyString”:
    eval MyString:s
    

    Because I don’t know C very well, I frequently have to review a few concepts from one of the many free C, C++ tutorials on the Web. As already mentioned, it is often necessary to write a little additional “wrapper” code that allows the C routines to be accessed from RPG or SQL. Here are a few of the C reference sites I found useful:

    • http://www.iu.hio.no/~mark/CTutorial/CTutorial.html
    • http://www.codersource.net/codersource_cppprogramming.html
    • http://www.exforsys.com/tutorials/c-language/c-programming-an-overview.html

    Also, since you’ll likely be using the C/C++ code you download from an RPG program, you’ll need to know how to access the C code from within RPG. To do this, you’ll need to create a prototype in RPG to call the C program or function. This means you’ll have to know how to deal with pointers and translate data type differences between the two languages. There are already many good tips on how to prototype C calls in RPG on the Internet. IBM’s Barbara Morris wrote one such article, which you can see here.

    In a prior tip, I exhorted DB2 SQL developers to find existing SQL code from other database platforms and convert it to DB2 where needed in order to save time and leverage someone else’s expertise. This tip is urging the same concept–expand your horizons to include C. When code samples aren’t available in your “native” programming languages, expanding your search to include other languages can pay big dividends. While you may stumble a bit getting out of the gate, the time investment will be worth it. Leverage existing code, get things done quicker (and often better) and be more productive. In this economy, increased productivity is golden–you’re bound to get a raise (or at least a little more appreciation)!

    Instructions: How To Create the “eval.c” Program on the System i/iSeries/AS/400/i

    Step 1: After identifying the source code I needed, I downloaded the following nine files and placed them (both C source and include (“copy”) source files) on the IFS in the folder /tmp/c_files.

    1. http://c.snippets.org/code/rmallws.c
    2. http://c.snippets.org/code/sniptype.h
    3. http://c.snippets.org/code/snip_str.h
    4. http://c.snippets.org/code/snipmath.h
    5. http://c.snippets.org/code/numcnvrt.h
    6. http://c.snippets.org/code/extkword.h
    7. http://c.snippets.org/code/round.h
    8. http://c.snippets.org/code/pi.h
    9. http://c.snippets.org/code/strupr.c

    For simplicity, the compilation commands assume all source and include files are placed in the /tmp/c_files folder, although normally these would be placed in source members or, if your organization’s policy allows, in a folder on the IFS intended for storing source.

    Step 2: Compile the supporting modules that eval.c requires.

    CRTCMOD MODULE(XXXXX/RMALLWS)
            SRCSTMF('/tmp/c_files/rmallws.c')
            OUTPUT(*PRINT)
    
    CRTCMOD MODULE(XXXXX/STRUPR)
            SRCSTMF('/tmp/c_files/strupr.c')
            OUTPUT(*PRINT
    

    For the record, it was trial and error that revealed I had to do this. I originally tried to compile the eval.c program and found I had some unresolved external reference errors that forced me to go back and look for more source and additional instructions. However, already being comfortable with RPG modules and service programs, I had little trouble working through these same issues in a different language.

    Step 3: I wasn’t happy with how an ILE program or SQL function would interact with this program as coded by the original author (because his function returned its result as an output parameter), so I decided to add a function of my own to return the result to ILE programs and SQL (as a scalar function).

    Edit the eval.c source file (or source member) and append the following “eval” function to the end:

    double eval(char *formula)    
    {
          int retval;
          double val;
          retval = evaluate(formula, &val);
          return val;
    }

    This function will now make it easy to access the evaluator’s logic from both ILE and DB2 for i SQL environments. Keep in mind that the program will be named EVAL and the function within the program will also be called eval (lower case).

    Step 4: Now that the source code is changed and ready to compile, it’s time to create the program. Because the eval function is the only function that will be accessed from other programs, I chose to create it as a service program. Compile the eval.c program as a module:

    CRTCMOD MODULE(XXXXX/EVAL)
            SRCSTMF('/tmp/c_files/eval.c')
            OUTPUT(*PRINT)
    

    Create a service program based on the eval module and the two modules that were previously compiled:

    CRTSRVPGM SRVPGM(XXXXX/EVAL)
              MODULE(EVAL RMALLWS STRUPR)
              EXPORT(*ALL)
              TEXT('Eval Math Expression')
    

    The service program will simply be called EVAL and the function to be accessed by the outside world is called eval (in lowercase). Remember, in C the function names are case sensitive.

    In this case I didn’t use binding source but rather chose the EXPORT(*ALL) option. In most cases, you’ll want to use binding source to specify your own signature for the service program.

    If you’re acquainted with the concept of ILE modules, programs, and service programs in a language like RPG, then you already understand how they work in the C world.

    Step 5: If necessary, add your newly created EVAL service program to a binding directory of your choice.

    ADDBNDDIRE BNDDIR(XXXXX/MYBNDDIR) OBJ((XXXXX/EVAL))
    

    Step 6: The eval function can be accessed by RPG using the following prototype:

    DEval             PR             8F   ExtProc('eval')
    D Formula                         *   Value Options(*String)
    

    Here is a complete RPG program showing the use of eval:

    HDftActGrp(*No) ActGrp(*Caller) BndDir('XXXXX/MYBNDDIR')
    DEval             PR             8F   ExtProc('eval')
    D Formula                         *   Value Options(*String)
    
    DTestData         S             35
    
     /Free
         TestData=%Char(Eval('34 + 7 * 2'));
         Dsply TestData '' *InLR;
         Return;
     /End-Free
    

    Step 7: If you want to use this C function as an SQL user-defined function, simply register the function in DB2 with the following CREATE FUNCTION statement:

    Create Function XXXXX/EVAL(Formula VarChar(64))
    Returns Double
    Language C
    External Name 'XXXXX/EVAL(eval)'
    Parameter Style General
    No SQL
    Deterministic
    Returns Null On Null Input
    Not Fenced
    

    Notice the external name specified includes the service program name (EVAL) and the function name to be invoked (eval) within parenthesis. Don’t forget that function names are case sensitive. Exported RPG subprocedure names are always converted to uppercase, but this consistency will not be present with C.

    Michael Sansoterra is a DBA for Broadway Systems in Grand Rapids, Michigan. Send your questions or comments for Mike via the IT Jungle Contact page.

    RELATED STORIES

    SQL Cross Platform Interoperability: The Proper Function

    Executing Dynamic Calculations with Embedded SQL



                         Post this story to del.icio.us
                   Post this story to Digg
        Post this story to Slashdot

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags:

    Sponsored by
    Raz-Lee Security

    iSecurity Multi Factor Authentication (MFA) helps organizations meet compliance standards and improve the existing security environment on IBM i. It requires a user to verify his identity with two or more credentials.

    Key Features:

    • iSecurity provides Multi Factor Authentication as part of the user’s initial program
    • Works with every Authenticator App available in the Market.

    Contact us at https://www.razlee.com/isecurity-multi-factor-authentication/

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Sponsored Links

    Help/Systems:  Robot/CONSOLE monitors System i resources automatically
    Northeast User Groups Conference:  20th Annual Conference, April 12 - 14, Framingham, MA
    COMMON:  Join us at the annual 2010 conference, May 3 - 6, in Orlando, Florida

    IT Jungle Store Top Book Picks

    Easy Steps to Internet Programming for AS/400, iSeries, and System i: List Price, $49.95
    The iSeries Express Web Implementer's Guide: List Price, $49.95
    The System i RPG & RPG IV Tutorial and Lab Exercises: List Price, $59.95
    The System i Pocket RPG & RPG IV Guide: List Price, $69.95
    The iSeries Pocket Database Guide: List Price, $59.00
    The iSeries Pocket SQL Guide: List Price, $59.00
    The iSeries Pocket Query Guide: List Price, $49.00
    The iSeries Pocket WebFacing Primer: List Price, $39.00
    Migrating to WebSphere Express for iSeries: List Price, $49.00
    Getting Started With WebSphere Development Studio Client for iSeries: List Price, $89.00
    Getting Started with WebSphere Express for iSeries: List Price, $49.00
    Can the AS/400 Survive IBM?: List Price, $49.00
    Chip Wars: List Price, $29.95

    Construction App from CGC Gets a Web Portal Source Technologies Now Supports System i with MICR Printer

    One thought on “Include C Utilities in Your Developer Library: Evaluating a Mathematical String Expression”

    • Andy Warren says:
      February 23, 2017 at 6:05 am

      The Snippet site in the article is defunct. They are preserved on GitHub: https://github.com/vonj/snippets

      Reply

    Leave a Reply Cancel reply

Volume 10, Number 11 -- March 24, 2010
THIS ISSUE SPONSORED BY:

SEQUEL Software
Northeast User Groups Conference
Twin Data Corporation

Table of Contents

  • Using UNION for Data Analysis
  • Include C Utilities in Your Developer Library: Evaluating a Mathematical String Expression
  • Internet Explorer 8 Doesn’t Support HMC V7. . . or Does It?

Content archive

  • The Four Hundred
  • Four Hundred Stuff
  • Four Hundred Guru

Recent Posts

  • IBM Tweaks Some Power Systems Prices Down, Others Up
  • Disaster Recovery: From OS/400 V5R3 To IBM i 7.4 In 36 Hours
  • The Disconnect In Modernization Planning And Execution
  • Superior Support: One Of The Reasons You Pay The Power Systems Premium
  • IBM i PTF Guide, Volume 25, Number 13
  • IBM i Has a Future ‘If Kept Up To Date,’ IDC Says
  • When You Need Us, We Are Ready To Do Grunt Work
  • Generative AI: Coming to an ERP Near You
  • Four Hundred Monitor, March 22
  • IBM i PTF Guide, Volume 25, Number 12

Subscribe

To get news from IT Jungle sent to your inbox every week, subscribe to our newsletter.

Pages

  • About Us
  • Contact
  • Contributors
  • Four Hundred Monitor
  • IBM i PTF Guide
  • Media Kit
  • Subscribe

Search

Copyright © 2023 IT Jungle