Hi Pete,
When you insert a P-spec in your program, you're telling the compiler "I
want to start a subprocedure". If you're not familiar with
subprocedures, you can think of them like a subroutine, except that they
can contain parameters and have their own private variables.
Basically, a subroutine in steroids!
But, anyway... you have this code:
D Main PR
D 8A
D*********************************************************
D*Main Procedure
D*********************************************************
P Main B
D PI
D MyParm 8A
This P-psec (P Main, above) tells it you're done with the main part of
yoru program, and you're starting a subprocedure. Because of the RPG
cycle, the main part of your program will be an infinite loop, and run
forever. There's no code that ever calls the subprocedure.
Since you say you're familiar with RPG III... let's say you did this:
C MAIN BEGSR
C ... CODE HERE....
C ENDSR
Assuming that this was your ENTIRE program, what would happen when you
called it? There's no EXSR for the subroutine, so it wouldn't run. The
RPG cycle would run the input specs, calcs and output specs in a loop --
but since there are none of them, and no way for *INLR to ever get set
on, you'd have an endless loop that does nothing.
That's exactly what your example with the P-spec does. You have a
subprocedure, but it's never called, and never run.
To eliminate your *ENTRY PLIST, you do NOT want to create a subprocedure
with a P-spec. Instead, you want to add a PI (procedure interface)
D-spec for the main procedure of your program.
When I say "main procedure", I do NOT mean a procedure that's named
"main" (like you had). Instead, I mean the PRIMARY procedure of your
program, which in RPG terminology is the "main procedure".
The main procedure is the "normal" part of your program. It's the part
that's called when you call your program with the CALL command. It's
the "mainline" of your program. It's the ONLY part of your program that
existed in OPM versions of RPG. If you've never written a subprocedure
in your life, everything you've written has been in the main procedure.
The system determines the end of the main procedure, and the start of a
subprocedure by looking for a 'P' spec. If you have no P-specs, you
only have a main procedure.
Hopefully that clears up the difference between a main procedure and a
subprocedure.
Anyway.. what you want to do is add a PI (and corresponding PR) to your
main procedure. That means you put PI at the top of your main procedure
like this (this assumes your module is named ACC001):
D ACC001 PI
D MyParm 8A
As soon as you have a PI, the compiler will also require a PR, so you
have to put that, too.
D ACC001 PR
D MyParm 8A
D ACC001 PI
D MyParm 8A
Technically speaking, a PR (prototype) is used to make a CALL, and a PI
(procedure interface) is used to receive parameters. So the PI is what
acts like the *ENTRY PLIST. The compiler forces you to code a PR that
matches the PI, even if you never use it to call anything.
The idea is that your PR *must* match your PI. Therefore, anything that
uses the PR to make a call will pass the parameters properly, since you
know the PR matches the PI. That's the theory, anyway.
When coding the PR for a *program* (as opposed to a bound module, or
subprocedure) most people prefer to code EXTPGM, so that the prototype
would be valid for a program call (though, it's not necessary, strictly
speaking, unless you actually use the prototype to make the call)
D ACC001 PR EXTPGM('ACC001')
D MyParm 8A
As long as ACC001 matches the main procedure name (which is usually also
the module name) you don't need this EXTPGM unless you want to use the
prototype to call the program. But most people like to code it since it
makes the intent clearer: This is to be called as an external program.
Another reason for the EXTPGM is that the compiler will let you name the
PR and PI differently from the actual main procedure name. So you can do
this:
D Main PR EXTPGM('FOO')
D MyParm 8A
D Main PI
D MyParm 8A
This way, even if your module is NOT named 'Main', you can still use
this PR/PI to receive parameters. It's a weird feature. Technically,
you're 'tricking' the compiler by coding this, you're making the
compiler skip it's validity checking. But, a lot of people do it
because, I guess, they find it more intuitive to use a name like 'MAIN'
even though the program/procedure can't be called by that name. Not
sure why.
Pete Helgren wrote:
I was feeling pretty comfortable with my transition from RPGIII to RPGLE
and /free until I needed to write a program from scratch that wasn't
using *ENTRY to pass parms to the program. I must not understand the
differences between the way RPGIII passed parameters and the way RPGLE
operates.
What I have been doing (cheating) was to have a short, initial non-free
calculation section like this:
C *ENTRY PLIST
C PARM MyParm
C/free
What I want to do is to do it "correctly". So after poking around the
Internet I thought I came up with the solution:
D Main PR
D 8A
D*********************************************************
D*Main Procedure
D*********************************************************
P Main B
D PI
D MyParm 8A
C/free
// Body of the program here
It wouldn't compile until I used dftactgrp(*no) actgrp(*caller) on the H
specs.
Although it compiles, when I run it in debug mode, the program is
invoked but "hangs" at the command line, it never progresses to the
first statement of the program which is where I have my breakpoint set.
So the question is: What is the correct way to write a simple program
in RPGLE that takes parameters? What do I do with the *ENTRY PLIST
method of passing parameters? I could go back to using the *ENTRY PLIST
approach but I'd like to use the "correct" way, if there is such a thing...
Thanks,
Pete Helgren
As an Amazon Associate we earn from qualifying purchases.