[Joanju Logo]
    Proparse API Quick Start Joanju Software

 Home


 Products
      Proparse
      Analyst


 Prices/Licenses
 Purchase
 Services
 Support
 Forum


 White Papers Etc.


 Projects, Utils,
 and Contributors



 Site History
 Contact us
 About Joanju
 Privacy

The purpose of this article is to provide enough background information about Proparse so that we are able to talk about more interesting things, namely, applications of the parser like Prolint.

Proparse is a DLL (or shared library on Unix). There is a 4GL interface to Proparse which makes it easy to use from the 4GL.

Here's the basic three lines necessary for using Proparse:

  DEFINE VARIABLE parserHandle AS HANDLE NO-UNDO.
  RUN proparse/api/proparse.p PERSISTENT SET parserHandle.
  {proparse/api/proparse.i parserHandle}

Once we've run proparse.p persistent, we're pretty much done with parserHandle. We now refer to all of Proparse's API via functions which are declared in proparse.i. Those function names all begin with "parser".

Now to parse a program file:

  IF parserParse("hello.p") = FALSE THEN DO:
    /* error handling here */
  END.

Note that in order for Proparse to successfully parse a program, that program must be compilable. If it is not compilable, then there's no way to build a sensible and complete syntax tree. (There are ways to work with non-compilable files, but I won't get into that here.)

Now let's ask the parser for a node handle. Proparse will create a node handle, and we will refer to that handle with an integer handle number.

  DEFINE VARIABLE myHandle AS INTEGER NO-UNDO.
  myHandle = parserGetHandle().

Pretty straightforward, I think. Proparse creates a handle, and returns the handle number, so that we have something to refer to it by.

Now let's do something with that handle. We'll ask Proparse to point that handle at the very topmost node in the syntax tree that it built when it parsed "hello.p".

  parserNodeTop(myHandle).

Let's have a look at a trivial output from the parser for the following program:

run test.
procedure test:
  disp "hello world".
end procedure.

And here's the output from the parser, which gives an idea of the shape of the tree. Each of the following lines represents a node in the tree:

Program_root    
    RUN    run
        FILENAME    test
        PERIOD    .
    PROCEDURE    procedure
        ID    test
        LEXCOLON    :
        Code_block    
            DISPLAY    disp
                Form_item    
                    QSTRING    "hello world"
                PERIOD    .
        END    end
            PROCEDURE    procedure
        PERIOD    .
    Program_tail    

Now we're ready to start examining the syntax tree. Let's ask Proparse to create a query for all DISPLAY nodes within the tree:

  DEFINE VARIABLE numResults AS INTEGER NO-UNDO.
  numResults = parserQueryCreate(myHandle, "myQuery":U, "DISPLAY":U).

The first parameter is the handle where we want the query to start. Sometimes we want the query to start at the very top of the entire tree, sometimes (quite often, actually) we only want the query to start at the top of some branch - maybe a block branch or a statement branch.

Because we may be working with many queries at once, we give them names so that we can refer to them later. That's the second parameter.

Finally, for the third parameter, we tell it what type of nodes we're looking for.

The query returns the number of results that it found.

Now let's use the query:

  DEFINE VARIABLE count AS INTEGER NO-UNDO.
  REPEAT count = 1 TO numResults:
    parserQueryGetResult("myQuery":U, count, myHandle).
    DISPLAY
      parserGetNodeType(myHandle)
      parserGetNodeText(myHandle)
      .
  END.

For each result in the query, we ask Proparse to change our handle so that it points to the same node in the syntax tree as the one found by the query. Next, we display the node type, which will be "DISPLAY" which is not surprising because that's what we asked for in our query. But, in my program "hello.p", I had the following line:
  disp "hello world".
and the string returned by parserGetNodeText is, of course, "disp" rather than "DISPLAY".

We've scratched the surface of Proparse. There are many other node attributes, other ways to navigate the syntax tree, and other features of Proparse in general. However, these basics should be enough for you to start reading and making sense of Prolint rules.