home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / os2 / pgen_2 / pgen.doc < prev    next >
Encoding:
Text File  |  1993-06-08  |  54.4 KB  |  1,248 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.                                  PGEN
  10.  
  11.                            Parser GENerator
  12.  
  13.                                 (v2.0)
  14.  
  15.  
  16.  
  17.  
  18.                           Copyright (C) 1992
  19.  
  20.                                   by
  21.  
  22.                           Keith L. Robertson
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32. PGEN accepts a description of a context-free grammar and its semantic
  33. actions.  It can output C language code for tables used to parse
  34. sentences in the described language and to interpret them via the
  35. semantic actions.  The C language 'parse()' program that uses the
  36. tables is included with PGEN.
  37.  
  38.  
  39.  
  40. PGEN is NOT public domain or free software.  It is distributed as
  41. Shareware.  Okay, folks.  You're experienced enough to know what that
  42. means:
  43.  
  44.         You get to try it for free.
  45.         If you like it and use it, buy it;
  46.             keep the author in business.
  47.         If not, burn it (your copies, not mine).
  48.  
  49. See the section LEGALESE for licensing terms.
  50.  
  51.  
  52.  
  53.                                                                      1
  54. PACKING LIST (Shareware):
  55.  
  56. This is what you should have with the shareware version of PGEN:
  57.         PGEN parser generator:
  58. PGEN.DOC        This file.  The documentation for PGEN and the files
  59.                 that come bundled with it.
  60. PGEN.EXE        The parser generator program.  Execute it with no
  61.                 arguments for brief usage instructions.
  62. ORDER.FRM       Print this for a PGEN order form.
  63. TYPES.H         Public domain header file with some convenient
  64.                 declarations. Put this in your INCLUDE directory.
  65. PG_PARSE.H      Header file for types, globals, and procedures needed
  66.                 by the parser, parse tables, and semantic actions.
  67. PG_PARSE.C      Source code of the parser.
  68.  
  69.         Included with the parser is the source code for EXPR, a simple
  70.         expression evaluator used to demonstrate usage of the PGEN
  71.         parser generator.  It uses PG_PARSE.H and PG_PARSE.C.
  72. MAKEFILE        EXPR's makefile.  Compilation instructions are for
  73.                 'ztc', the Zortech compiler.  Easily modified for
  74.                 other compilers.
  75. EXPR_LEX.H      EXPR's lexical analyzer header.  Defines LEX_INFO,
  76.                 used by the parser.
  77. EXPR_LEX.C      EXPR's lexical analyzer implementation.
  78. EXPR_PAR.PGN    EXPR's grammar file for PGEN.  Used to produce parsing
  79.                 tables.   PGEN -C EXPR_PAR.PGN >EXPR_PAR.C
  80. EXPR_SEM.H      EXPR's semantic actions header.  Declares the semantic
  81.                 action routines used in EXPR_PAR.PGN and the resulting
  82.                 EXPR_PAR.C.
  83. EXPR_SEM.C      EXPR's semantic actions implementation and the
  84.                 'main()' program.
  85.  
  86.         Bundled with PGEN shareware are three useful utility programs. 
  87.         All of these print usage instructions when executed with no
  88.         arguments.
  89. PPRINT.EXE      Pretty print text files, with headings and (optional)
  90.                 line numbers.  Uses Epson-compatible printer codes. 
  91.                 The source code (received with commercial version
  92.                 registration) is easily modified for other printers.
  93. TAIL.EXE        Prints the last lines of the given file or of the
  94.                 standard input stream.
  95. TEE.EXE         Sends standard input to the given file and to standard
  96.                 output.
  97.  
  98.  
  99. NOTE:   When you received the shareware version of PGEN, you probably
  100. received it in a self-extracting archive, PGEN_xxx.EXE, where xxx is
  101. the version number.  On the same disk, there may also be these files: 
  102. PGEN_xxx.EX2, PGEN_xxx.EX3, and PGEN_xxx.EX4.  These are merely copies
  103. of PGEN_xxx.EXE.  If the .EXE should be unreadable due to a sector
  104. gone bad, any of the other three may be renamed with a .EXE extension
  105. and executed to extract the same files.  If your .EXE is okay, the
  106. others are not needed.
  107.  
  108.  
  109.  
  110.                                                                      2
  111. PACKING LIST (Commercial):
  112.  
  113. This is what you receive with the commercial version of PGEN:
  114.         All of the above, except with the following change:
  115. PGEN.EXE        Employs a sophisticated table reduction algorithm. 
  116.                 The EXPR 'action_list' table shrinks from 101 to 73
  117.                 elements (28%).  A larger application decreased from
  118.                 963 to 577 elements (40%).  The nonterminal and
  119.                 production tables will also have unused entries
  120.                 removed, although the gain is not as great.
  121.  
  122.         You will additionally receive the following utilities:
  123. CAT.EXE         Prints in sequence (concatenates) to standard output
  124.                 the given file(s).
  125. CHOPCRLF.EXE    Chops <CR,LF> off the end of a text file.
  126. CMDLINE.EXE     Simply echoes the arguments given with wildcard
  127.                 replacement, so you can see what the other programs
  128.                 are receiving.
  129. CP.EXE          Copies one file to another or several to a directory.
  130. MV.EXE          Moves one file to another or several to a directory.
  131. RM.EXE          Removes one or more files or directories.
  132. HSPLIT.EXE      Breaks a long text file into several smaller text
  133.                 files.  Useful when you have a file bigger than your
  134.                 editor can handle (like "PGEN -L" output for a large
  135.                 grammar).
  136. VSPLIT.EXE      Breaks a wide text file (like "PGEN -A" output for a
  137.                 large grammar) into several others for printing.
  138. NCSL.EXE        Reads a C or C++ source file, categorizing each line
  139.                 into one of four categories: Blank, Comment, Bracket,
  140.                 or Code.
  141. DIFF.EXE        Compares two text files and prints their differences.
  142. DIRDIFF.EXE     Compares two directory structures and prints the files
  143.                 unique to each.  Useful for comparing working and
  144.                 backup directories.
  145.         Each of the above prints usage instructions when executed
  146.         without arguments.
  147.  
  148.         And best of all, commented source code:
  149. MAKEFILE, 8 header files, and 8 implementation files in C++ for PGEN.
  150. MAKEFILE and source files (mostly C, some C++) for all the above
  151. utilities.
  152.  
  153.         Registered users will also receive notice of any updates,
  154.         which will be provided for no more than $5.00, plus non-
  155.         U.S. Mail mailing costs (see REGISTRATION PROCEDURES below).
  156.  
  157.  
  158.  
  159.                                                                      3
  160. REGISTRATION PROCEDURES:
  161.  
  162. Simple, just print the file ORDER.FRM and fill in the requested
  163. information.  Currently, IBM DOS (& compatible OS) only.
  164.  
  165. Make a check payable to "Keith L. Robertson" for the following amount:
  166.         $ 20.00 (U.S.)  per copy (TX residents add 8% sales tax)
  167.         $  1.00         per copy for 3 1/2"-1.44M (high density) disks
  168.  
  169. Orders are shipped via U.S. Mail at no extra cost.  Otherwise, add:
  170.         $  3.00         for UPS shipment
  171.         $  5.00         for shipment outside the U.S.A.
  172.  
  173. Students using PGEN for coursework ONLY may register PGEN for $10.00
  174. per copy.  Gets commercial PGEN.EXE and utilities but not source code. 
  175. Please include photocopy of validated Student I.D.  For personal or
  176. commercial project use, please register for the full $20.00.
  177.  
  178. Mail the above to:
  179.         Keith L. Robertson
  180.         11857 Gloger Street
  181.         Houston, TX  77039-6309         (U.S.A.)
  182.  
  183. Customer support is currently by mail only, to the same address. 
  184. Unregistered users please include SASE if not ordering at the same
  185. time.  PGEN is not a program for the masses; I must keep my costs low
  186. to offer it and support it at the requested price.
  187.  
  188.  
  189. LEGALESE (Licensing terms):
  190. (Sorry, but we have to go thru this.)
  191.  
  192. In the following, reference to "PGEN" includes the parser generator
  193. and all source code and other utility programs that come with the
  194. shareware version.  (Exception:  TYPES.H is public domain.)
  195.  
  196. (1)     Unregistered users may copy PGEN and use it for two weeks
  197.         solely for the purpose of determining if it suits their needs. 
  198.         If PGEN is used to create parsing tables for a programming
  199.         project, whether for commercial or private use, continuing use
  200.         of those tables (and therefore of PG_PARSE.H and PG_PARSE.C)
  201.         within that project constitutes use of PGEN and requires
  202.         registration, even if PGEN itself is never executed again.
  203.  
  204. (2)     A user may register as given above in REGISTRATION PROCEDURES.
  205.  
  206. (3)     A registered user may use PGEN on one computer per copy
  207.         registered at any given time.  If other people use PGEN
  208.         routinely, even on the same computer, they must become
  209.         registered users themselves.
  210.  
  211. (4)     A company using PGEN may have one or more employees using the
  212.         same copy of PGEN.  In this case, the registered user is the
  213.         company, not the employee.  However, if PGEN is available for
  214.         use on more than one computer at a time, one copy must be
  215.         registered for each such computer.
  216.  
  217.                                                                      4
  218. (5)     Anyone -- electronic BBS sysops, commercial data networks,
  219.         shareware distribution houses, users, etc. -- may distribute
  220.         the shareware version of PGEN, as long as there is no charge
  221.         for the program itself, all files in the shareware package are
  222.         distributed complete and unmodified, and no files from the
  223.         commercial package are included.  There may be a charge for
  224.         normal connect time, or for disk copying and mailing costs, as
  225.         long as this charge does not exceed $7.00 per disk; PGEN
  226.         shareware must fit on one disk.  The distributor or vendor
  227.         must make it clear that it is charging for distribution costs
  228.         and not for the software itself.
  229.  
  230. (6)     PGEN may not be bundled with any other commercial product
  231.         without the express written consent of the author.
  232.  
  233. (7)     The commercial version of PGEN, sent to registered users, and
  234.         all source code and utility programs bundled with it, are for
  235.         the private use of the registrant.  They may not be copied or
  236.         distributed in any form.
  237.  
  238. (8)     Any products made using properly registered copies of PGEN are
  239.         entirely the property of their creators.  There are no
  240.         royalties nor run-time license fees required by the author of
  241.         PGEN for the creation and distribution of these products.
  242.  
  243. (9)     PGEN may be ported to other operating systems (I expect very
  244.         easily), using the source code with the commercial version,
  245.         only with written permission from the author.  The ported
  246.         version will be subject to the same licensing terms under the
  247.         target platform.  Once the author's permission has been
  248.         obtained, a shareware version may be distributed for that
  249.         platform, as long as it contains all files and only those
  250.         files listed in the shareware packing list.
  251.  
  252. Any usage of any part of the PGEN shareware or commercial packages,
  253. including source code or utility programs constitutes legal acceptance
  254. of the above licensing terms.  A user must be registered to use any of
  255. the source code or utility programs that come with PGEN beyond the
  256. evaluation period.  If you use ANY of these, you must be registered
  257. for the entire PGEN package.
  258.  
  259. THIS SOFTWARE IS SOLD "AS-IS" WITHOUT WARRANTY OF ANY KIND, EITHER
  260. EXPRESS OR IMPLIED, RESPECTING THE FITNESS OF MERCHANTABILITY OF THIS
  261. SOFTWARE FOR ANY USE.  THE AUTHOR SHALL NOT BE LIABLE TO THE
  262. PURCHASER, USER, OR ANY OTHER PERSON OR ENTITY WITH RESPECT TO ANY
  263. LIABILITY, LOSS, OR DAMAGE CAUSED OR ALLEGED TO BE CAUSED DIRECTLY OR
  264. INDIRECTLY BY THIS SOFTWARE.
  265.  
  266. The user is especially cautioned on the use of the "RM -R" feature of
  267. the "RM" remove files utility.
  268.  
  269.  
  270. Trademark Acknowledgements:
  271.    Epson is a trademark of Epson Corporation.
  272.    IBM is a trademark of International Business Machines Corporation.
  273.    Zortech and Symantec are trademarks of Symantec Corporation.
  274.  
  275.  
  276.  
  277.                                                                      5
  278.                               USING PGEN
  279.  
  280.  
  281. INTRODUCTION:
  282.  
  283. A parser generator is a rather advanced programming tool which can be
  284. used in the creation of compilers, interpreters, structured editors,
  285. text formatters, command line parsers (e.g. for an adventure game),
  286. etc.  This document is therefore written for the advanced programmer
  287. with knowledge of the principles of parser generation.  If you don't
  288. know what is a token (or terminal), nonterminal, production, or
  289. semantic action, chances are you don't need a parser generator.  For
  290. those interested in the topic, read
  291.  
  292.         Aho, A.V., R.Sethi, and J.D.Ullman,
  293.                 "Compilers, principles, techniques, and tools",
  294.                 1986, Addison-Wesley, Reading, Mass.
  295.  
  296. known as "the dragon book" in academia for the red dragon on its
  297. cover, which represents "complexity of compiler design".  An LALR
  298. parser generator, like PGEN, is shown as the knight's sword used to
  299. slay the dragon.
  300.  
  301. I created PGEN because I wanted to write a compiler, I didn't have
  302. access to YACC (Dragon book pp.257-266), and I couldn't find a public
  303. domain or shareware parser generator in the ShW/PD libraries.  Because
  304. of this, I don't know how PGEN compares with other parser generators
  305. in execution speed, nor in size and speed of the parser generated (if
  306. anyone wants to compare PGEN with any other and send me the results, I
  307. would welcome the feedback).  I do know I have used PGEN to create a
  308. working parser (I haven't finished the whole compiler; been working on
  309. PGEN!).  I find it very useful and others may as well.
  310.  
  311. Terminology:
  312.         stdin   = the standard input stream
  313.         stdout  = the standard output stream
  314.         stderr  = the standard error stream
  315.  
  316.  
  317.  
  318. PGEN COMMAND LINE:
  319.  
  320. Usage:          PGEN  [-I] [-TNFDPSKLWQAGCX]  <grammar file>
  321.  
  322. PGEN reads the given grammar file and prints its results to stdout,
  323. which is usually redirected to a file.  Options can be given together
  324. or separately ("PGEN -IC x" == "PGEN -I -C x") in any order, but must
  325. precede the grammar file name.  During its operation, PGEN prints some
  326. progress information to stderr, which will print to the screen even
  327. when stdout is redirected (as it should).
  328.  
  329.  
  330.  
  331.                                                                      6
  332. PGEN GRAMMAR FILE FORMAT:
  333.  
  334. The grammar file has a format similar to that expected for YACC, but
  335. there are significant differences.  The format is as follows:
  336.  
  337.  
  338. /*      C language code that will appear at the beginning of the
  339.         C code parse table output.  Everything up to the first line
  340.         beginning with an open bracket ('[') is emitted unmodified.
  341.         Usually header comments, includes, and defines.
  342.         No line in this section can begin with '['.
  343. */
  344. #include "lexer.h"      /* Get defns of token identifier names. */
  345. #define         STACK_INC       10
  346.  
  347. [   # Token definitions begin with a bracket, which must begin the
  348.     # line.  Comments begin with '#' and last to the end of the line.
  349.         TOKEN1,         # Token definitions are separated by commas.
  350.                         #  The parser must return 0 for end-of-stream,
  351.                         #  1 for the first token (TOKEN1 here), etc.
  352.         IDENTIFIER,     # A token name can be an identifier, beginning
  353.         NUMBER,         #  with a letter, followed by letters, numbers
  354.                         #  & underscores, up to 128 characters.  Case
  355.                         #  is significant, although all upper case is
  356.                         #  recommended for tokens.
  357.         "%",            # A token can also be a string, enclosed in
  358.                         #  single or double quotes.  Tokens must
  359.                         #  appear in productions exactly as in the
  360.                         #  definition including the quote characters.
  361.         T  ALT_NAME,    # A token may be given an alternate name,
  362.                         #  which will be used when printing the parse
  363.                         #  table C code.  It must be an identifier.
  364.         ','  COMMA,     #  An alternate name is usually used with
  365.         '(' LP, ')' RP, #  string tokens, since the string name is not
  366.                         #  valid for the C output tables.
  367.         '='  1R,        # A token may be given a precedence number,
  368.                         #  which can resolve some ambiguities (Dragon
  369.                         #  p.261).  A 'L' or 'R' giving associativity
  370.                         #  can immediately follow the precedence.
  371.         '+'  2,         # Left associative is the default.
  372.         '-'  2,         # All operators with the same precedence
  373.                         #  should be given the same associativity.
  374.         '*'  TIMES  3L, # When all three are present, the correct
  375.                         #  order is "primary name", "alternate name",
  376.                         #  "precedence/assoc".
  377. ]   # Token defs end with a close bracket.  Productions follow.
  378.  
  379. # The first nonterminal defined is always the start symbol.
  380. #  Each nonterminal must be defined exactly once but may have
  381. #  multiple productions in the definition.
  382. Expr_list               # Recommended style is initial capital.
  383.     # Each production is introduced with a '|' or ':' and is defined
  384.     #  by a sequence of zero or more symbols (tokens and nonterminals)
  385.     #  on the right-hand-side.  I recommend introducing all
  386.     #  productions with '|'.
  387.                                                                      7
  388.     # Nonterminals can be used before they are defined.
  389.         | Rep1_expr_list
  390.         |               # Empty productions are sometimes necessary.
  391.         | error         # Error prod's as in YACC (see ERROR HANDLING)
  392.         ;               # List of productions is ended with ';'.
  393. Rep1_expr_list
  394.     # Productions may be directly or indirectly recursive, although
  395.     #  left recursion, as shown here, is preferable.
  396.         | Rep1_expr_list ',' Expr
  397.         | Expr
  398.         ;
  399. Expr
  400.     # Productions can have a priority also.  The first token with a
  401.     #  priority gives its priority to the production.  Alternately,
  402.     #  the priority can be given explicitly.  Although this grammar is
  403.     #  ambiguous, the priority and associativity designations resolve
  404.     #  the ambiguity.
  405.         | Expr '*' Expr                 # Implicit priority 3
  406.         | 2 Expr Add_op Expr            # Explicit priority 2
  407.     # A production may end with a semantic action name introduced by
  408.     #  an at sign ('@').  This identifier is the name of the C
  409.     #  procedure to be called when the production is reduced.
  410.     #  It must be a simple identifier, not C code.
  411.         | IDENTIFIER '=' Expr   @ do_assign     # Recommend lower case
  412.         | '(' Expr ')'          @ do_paren
  413.         | Add_op  Expr          @ do_unary
  414.         | IDENTIFIER [Fn_args]  # Any single symbol may be enclosed in
  415.                                 #  brackets to make it optional.
  416.         ;
  417. Fn_args
  418.         | '(' Expr_list_2 ')'
  419.         ;
  420. Expr_list_2
  421.         | { Expr ',' ... }      # A production can be defined by two
  422.                                 # symbols in braces to specify a list.
  423.         ;
  424. Add_op  | '+'   | '-'   ;
  425. #--------------------------- End of File ---------------------------#
  426.  
  427. The grammar above is not terribly useful as-is.  See EXPR_PAR.PGN for
  428. a working example.
  429.  
  430. For readability, I recommend that a nonterminal being defined sits on
  431. a line by itself, followed by its productions indented beneath, each
  432. production beginning a new line, and the terminating semicolon
  433. indented on a line by itself.  (I don't entirely follow this
  434. convention in this document's examples for reasons of length.)
  435.  
  436. For users of versions prior to 2.0, note that "{ sem }" has been
  437. changed to "@ sem" for semantic actions.  If it were needed, I would
  438. have included a converter, but any decent text editor will have a
  439. search and replace operation that will allow you to selectively
  440. replace '{' with '@' and remove '}'.  Braces were originally used to
  441. enclose the semantic action name for similarity to YACC, but they were
  442. made to enclose the repetition construct instead for similarity to
  443. EBNF (Extended Backus-Naur Formalism).
  444.  
  445.  
  446.  
  447.                                                                      8
  448. PGEN COMMAND LINE OPTIONS:
  449.  
  450. Once again, the usage line is
  451. Usage:          PGEN  [-I] [-TNFDPSKLWQAGCX]  <grammar file>
  452. PGEN has many options, although all but one are print options.
  453.  
  454. -I      Inline productions.  If this option is given, PGEN will
  455.         substitute productions where possible.  See PRODUCTION
  456.         INLINING below.
  457.  
  458. The remaining options tell PGEN what to print to stdout.
  459.  
  460. -T      Print tokens.  The format is "Sequence number", "Priority",
  461.         "Associativity", "Primary name".  The alternate name is not
  462.         printed. '#E_O_S#' (end of stream) is always the first token,
  463.         and 'error' is always the last.
  464. -N      Print nonterminals.  The format is "Sequence number", "Number
  465.         of the first production which defines the nonterminal",
  466.         "Number of productions defining this nonterminal", "Number of
  467.         uses on the right-hand-side of any production", "Stack size
  468.         needed to parse this nonterminal", "Recursion mark", "Name". 
  469.         The first line gives a stack size and recursion mark for the
  470.         entire grammar.  These are explained later.  A dummy start
  471.         symbol '$_Start_$' is always the first nonterminal.
  472. -F      Print the "first symbols in productions" for each nonterminal.
  473. -D      Print the "first symbols in derivations" for each nonterminal.
  474.         -F and -D were primarily useful for debugging PGEN itself, so
  475.         the meaning of these is documented in the source file
  476.         PGEN_SYM.CPP.
  477. -P      Print productions.  "Sequence number", "Number of the first
  478.         SLR item for this production", "Production priority",
  479.         "Production".  The grammar is always augmented with the
  480.         production
  481.                 $_Start_$ --> <the first defined nonterminal>.
  482. -S      Print the SLR items.  "Sequence number", "SLR item".  The dot
  483.         location is shown as '<>'.
  484. -K      Print the item set kernels.
  485. -L      Print the item set LALR closures.
  486.         -K and -L are very useful in debugging grammars, especially in
  487.         finding and resolving parsing conflicts.
  488. -W      Modifies the printing of -K and -L to print the item sets
  489.         (W)ith its goto list.  This list shows what state the parser
  490.         will go to for each symbol (both tokens and nonterminals). 
  491.         Symbols not listed are errors if seen.
  492. -Q      Print parsing action conflicts to stdout instead of stderr.
  493. -A      Print a table showing the parsing actions for each state and
  494.         token.
  495. -G      Print the goto table for each state and nonterminal.
  496.         -A and -G combined give the type of information shown in the
  497.         Dragon book Figs 4.31 (p.219), 4.40 (p.236), and 4.47 (p.250).
  498. -C      Print the C language code for the generated parsing tables. 
  499.         (Our goal.)
  500. -X      Print ALL of the above except -W and -Q (which you may specify
  501.         separately).  This will get REALLY BIG for a grammar of any
  502.         size, and was mostly useful in debugging PGEN.
  503.  
  504.  
  505.  
  506.                                                                      9
  507. PRODUCTION INLINING:
  508.  
  509. Consider the following:
  510.  
  511.         Lhn | Rhn ;     # This production has one nonterminal and no
  512.                         #  semantic action. Lhn may have other prod's.
  513.         Rhn | ... ;     # Rhn is defined by one production, which
  514.                         #  may or may not have a semantic action.
  515.  
  516. PGEN will substitute for Rhn, resulting in:
  517.  
  518.         Lhn | ... ;     # Rhn's production and semantic action.
  519.  
  520. This will increase the parser's speed slightly, since it won't have to
  521. reduce by  "Lhn --> Rhn".  The rationale for this option is so we can
  522. write productions like
  523.  
  524.         Statement
  525.                 | For_statement
  526.                 | While_statement
  527.                 | If_statement
  528.                 # etc.
  529.                 ;
  530.         For_statement
  531.                 | FOR IDENT ':=' Expr To_ Expr DO Statement @ for_st ;
  532.         # etc.
  533.  
  534. without any unnecessary overhead, rather than having to write
  535.  
  536.         Statement
  537.                 | FOR IDENT ':=' Expr To_ Expr DO Statement @ for_st ;
  538.                 # etc.
  539.  
  540. which will be much less readable.  This optimization often results in
  541. inlining and optimizing many productions that weren't expected.
  542.  
  543.  
  544.  
  545. STACK SIZE AND RECURSIVE MARK:
  546.  
  547. Two of the things printed on the "PGEN -N" option are the stack size
  548. and recursive mark for each nonterminal and for the entire grammar. 
  549. The stack size needed to parse the grammar is simply that for the
  550. augmented start symbol '$_Start_$' plus one.  The recursion mark for
  551. the grammar is the sum of that for all nonterminals.
  552.  
  553. The stack size for a nonterminal is the worst-case size of the parsing
  554. stack needed to parse a sequence of tokens, starting at that
  555. nonterminal, barring any recursion other than left recursion.  Left
  556. recursion, as with Rep1_expr_list above, causes no problems, and is
  557. not considered recursion for purposes of the mark or this discussion. 
  558. Other recursion, as with both of these productions,
  559.  
  560.         Expr    | '('  Expr  ')'
  561.                 | IDENTIFIER '=' Expr   ;       # Right associative
  562.  
  563.                                                                     10
  564. would require an infinite stack size to be guaranteed to parse any
  565. sequence of tokens that match the grammar's definition of an Expr. 
  566. For example, the following is a valid Expr:
  567.  
  568.         ((((((((((((((((((((((((((( zebra )))))))))))))))))))))))))))
  569.  
  570. Indeed, how many parentheses should we allow?  A million?  Since an
  571. infinite stack is impossible in any real computer, PGEN computes the
  572. stack size as if there were no such recursion, and informs the
  573. programmer in its -N and -C output if the grammar is recursive.
  574.  
  575. The recursive mark for a nonterminal increases each time (non-left)
  576. recursion through the nonterminal is detected.  Its main relevance,
  577. however, is whether or not it is zero, not the actual number.  If the
  578. mark is nonzero, the nonterminal or grammar is recursive.
  579.  
  580. The programmer may deal with a recursive grammar by deciding how much
  581. nesting to allow and setting an amount to increase the stack size in
  582. the "PGEN -C" output.  This is done by defining the macro 'STACK_INC'
  583. in the C code part of the grammar file.  For example,
  584.  
  585.         #define         STACK_INC       10
  586.  
  587. will allow at least 10 nested '(' or at least 5 nested "IDENT '='"
  588. (or six '(' and two "IDENT '='", etc.)  without stack overflow, even
  589. in the worst case.
  590.  
  591. The parser may still be asked to parse a string of tokens which is
  592. valid for the language, but which its stack cannot handle.  It will
  593. not by default check if the parse stack overflows, and in this case
  594. the program will probably crash.  Fortunately, with just a little
  595. leeway, stack overflow is rare in practice unless you are really
  596. trying.  To get the parser to check for overflow, set STACK_SIZE in
  597. PG_PARSE.C to the actual stack size.  The actual stack size is set by
  598. the  "#define STACK_SIZE"  in the "PGEN -C" output.
  599.  
  600.  
  601.  
  602. FOLLOWING ALONG WITH PGEN:
  603.  
  604. While executing, PGEN prints progress messages.  As they are read, it
  605. prints the number of tokens, nonterminals, and productions taken from
  606. the input file.  PGEN then checks that all nonterminals are properly
  607. defined and used.  The number of SLR items is computed and printed.
  608.  
  609. As the item sets are constructed, PGEN prints a running tab of two
  610. numbers.  The first number is the item set PGEN is currently
  611. examining; the second is the total number of item sets created so far. 
  612. Initially, there is only one item set, number 0.  As each set is
  613. examined, zero, one, or many new item sets may be added.  PGEN is done
  614. when the first number becomes equal to the second.
  615.  
  616. Then, lookahead symbols are propagated from all item sets.  PGEN
  617. prints the item set currently being examined.  When it finishes the
  618. last item set, it may need to backtrack to an earlier set several
  619. times.
  620.  
  621.                                                                     11
  622. Next, PGEN constructs a table of actions for each <state, token> pair. 
  623. If any parsing conflicts are found (see PARSING ACTION CONFLICTS),
  624. they are printed during this phase.
  625.  
  626. Finally, PGEN converts the tables to action lists which reduces the
  627. storage requirement (Dragon book p.244-247).  In the commercial
  628. version, PGEN merges similar action lists as they are added, further
  629. reducing the needed storage.  The lists then need to be sorted into
  630. the order they will be printed in the final C code output.
  631.  
  632.  
  633.  
  634. CREATING A LEXICAL ANALYZER:
  635.  
  636. The parser requires an associated lexical analyzer (lexer). 
  637. Fortunately, it is not very difficult to create an efficient, robust
  638. lexer by hand.  EXPR_LEX.C is easily modified to recognize a different
  639. set of tokens and to accept its input from other than stdin.
  640.  
  641. The header file for the lexer must declare all token identifier names
  642. and any types, global data, or routines needed by the parser and
  643. semantic actions.  These are the items it must declare:
  644.  
  645. 1)      The type  'LEX_INFO'
  646. The type of objects on the parse stack.  Defines attribute information
  647. relevant to token lexemes and nonterminal symbols.
  648.  
  649. 2)      The extern variable  'lexeme'  of type  'LEX_INFO'
  650. Location where the lexer function 'get_token()' returns information
  651. related to the last token it read from the input stream.  READ ONLY!
  652.  
  653. 3)      The extern variable  'last_token'  of type  'USHORT'
  654. Token number returned by the last call to 'get_token()'.  READ ONLY!
  655.  
  656. 4)      Function  'USHORT  get_token()'
  657. Reads the input stream, returns the number of the token it saw
  658. directly and in 'last_token', and places related information in
  659. 'lexeme'.
  660.  
  661. 5)      Procedure  'VOID  log_error (USHORT etype,  CSTRING desc)'
  662. Prints an error message based on the given error type and description. 
  663. See EXPR_LEX.H for a description.
  664.  
  665. 6)      Operations  'set_jumped' and 'was_jumped'  on type 'LEX_INFO'
  666.         #define         set_jumped(lex,val)
  667.         #define         was_jumped(lex)
  668. The macro 'set_jumped()' marks 'lex' as jumped if 'val' is true and as
  669. not jumped if 'val' is false; 'was_jumped()' returns true if and only
  670. if 'lex' is marked as jumped.
  671.  
  672. The type 'USHORT' above is defined in TYPES.H as "unsigned short". 
  673. You may alternately use any integer type.
  674.  
  675. Finally, if the parser is to stop parsing on something in the input
  676. stream other than the end-of-file, the lexer merely needs to return
  677. the end-of-stream token (token 0) for that thing.
  678.  
  679.  
  680.  
  681.                                                                     12
  682. SEMANTIC ACTIONS:
  683.  
  684. When the parser reduces by a production, its corresponding semantic
  685. action (after '@'), if any, is executed.  Semantic actions must be
  686. written as individual C procedures which take no arguments and return
  687. no value.
  688.  
  689. When a semantic action is called, a global pointer 'attr' points to an
  690. array of objects of type LEX_INFO representing the symbols of the
  691. associated production, beginning with 0.  The semantic action returns
  692. attribute information in attr[0].  For example, in the EXPR example we
  693. have a production
  694.  
  695.         Expression | IDENTIFIER '=' Expression  @ expr_assign ;
  696.  
  697. In the code of 'expr_assign()', the identifier is represented by
  698. attr[0].  The lexer returned the string for token IDENTIFIER in its
  699. 'name' field.  The '=' is attr[1].  The lexer did not return the token
  700. string, as all relevant information was carried by the token type
  701. EQUAL.  In fact, that the parser saw '=' when it did is contained in
  702. the parse state, so 'expr_assign()' doesn't even consult attr[1]. 
  703. Finally, the attributes for the received Expression is in attr[2], of
  704. which only the field 't.fvalue' is relevant.
  705.  
  706. A semantic action returns its attribute information in attr[0].  Note
  707. that the first production symbol and the return symbol use the same
  708. attribute object, attr[0].  Make sure the writes for the return
  709. information don't affect the attribute reads from the first symbol
  710. information.  This is easy to ensure in practice.  Also, if the return
  711. attributes are identical to the attr[0] input and no side effects are
  712. required, no semantic action is needed.  This is the case for Binary1,
  713. Binary2, and Unary in EXPR_PAR.PGN.
  714.  
  715. In EXPR, 'expr_assign()' is mostly useful for its side effect, saving
  716. the IDENTIFIER name and its assigned value in a symbol table.  Since
  717. an assignment is also an Expression, the value is copied to
  718. attr[0].t.fvalue.
  719.  
  720. It is an error for a semantic action to access or modify attr[n] where
  721. (n < 0) or ("the number of production symbols" <= n).
  722.  
  723.  
  724.  
  725. OPTIONAL SYMBOLS:
  726.  
  727. Any single symbol on the right-hand-side of a production can be made
  728. optional simply by enclosing it in brackets.  Prior to version 2.0,
  729. you would usually need to clutter your grammar with the following:
  730.  
  731.         Nonterm         | ... Opt_symbol ...  @ p1_action ;
  732.         Opt_symbol      | Symbol
  733.                         | ;
  734.  
  735. This also adds inefficiency.  Time: When Symbol is parsed, we must
  736. needlessly reduce it to an Opt_symbol.  Space: The above introduces
  737. one nonterminal and two productions which must appear in the final
  738.                                                                     13
  739. parse table output.  The only time that you wouldn't need this is if
  740. Symbol is a nonterminal that is optional in ALL its uses.  Then it
  741. just needs an empty production:
  742.  
  743.         Symbol  | ... all its other productions
  744.                 | ;
  745.  
  746. Now, it doesn't matter if Symbol is a token or nonterminal or if it is
  747. not optional in other uses.  You may write
  748.  
  749.         Nonterm         | ... [Symbol] ...      @ p1_action ;
  750.  
  751. When appropriate, Symbol will be jumped (skipped) with no semantic
  752. action taken.
  753.  
  754. This introduces a potential problem.  How does a semantic action like
  755. 'p1_action()' determine if one of its optional symbols appeared in the
  756. input stream or was jumped?  It tests "was_jumped (attr [sym_num])",
  757. where 'sym_num' corresponds to the Symbol.  As previously noted (in
  758. CREATING A LEXICAL ANALYZER), the lexer header is required to provide
  759. this macro.
  760.  
  761. The lexer must ensure "was_jumped (lexeme)" is false, because any
  762. token it returns was seen, not jumped.  The parser sometimes needs to
  763. mark stack symbols (pointed to by attr) as jumped or not, so the macro
  764. 'set_jumped()' must also appear in the lexer header.
  765.  
  766.  
  767.  
  768. LISTS,LISTS,LISTS:
  769.  
  770. A construct that may repeat entirely was always easy to write.
  771.  
  772.         List    | List  <all repeating symbols>
  773.                 |                               # for 0-or-more, *OR*
  774.                 | <all repeating symbols>       # for 1-or-more.
  775.                 ;
  776.         # e.g. (empty)  C;      C;C;    C;C;C;  C;C;C;C;  (etc.)
  777.         # Here, <all repeating symbols> derives  "C;"
  778.  
  779. Optional symbols make the 1-or-more list even easier
  780.  
  781.         List    | [List] <all repeating symbols> ;
  782.  
  783. However, a list of items and separators is more verbose to express
  784. without optional symbols, especially in the 0-or-more case:
  785.  
  786.         List_0  | List_1                        # 0-or-more
  787.                 |               ;
  788.         List_1  | List_1 Separator Item         # 1-or-more
  789.                 | Item          ;
  790.         # e.g. (empty)  A       A,A     A,A,A   A,A,A,A   (etc.)
  791.         # Here, Item derives "A" and Separator derives ","
  792.  
  793.                                                                     14
  794. Optional symbols remove the need for nonterminal List_0 and its
  795. productions, but you must make your list optional in all its uses
  796. EXCEPT in the 1-or-more list.
  797.  
  798.         List_0_use      | ... [List_0] ... ;
  799.         List_0  | List_0 Separator Item         # Really a 1-or-more
  800.                 | Item          ;
  801.  
  802. This is error prone; you might forget to make a usage optional. 
  803. Computers are supposed to do the rote work for us, right?
  804.  
  805. PGEN version 2.0 adds the following constructs:
  806.  
  807.         List_0  | { Item Separator ... }  ;     # 0-or-more list
  808.         List_1  | { Item Separator ... }+ ;     # 1-or-more list
  809.  
  810. There must be exactly the two symbols, the item and the separator, and
  811. no others in the production.  The ellipse ('...') is optional but
  812. highly recommended.  For example:
  813.  
  814.         A_list  | { A ',' ... }  ;      # Add '+' to exclude (empty)
  815.  
  816. PGEN converts both constructs to a 1-or-more list, turning the one
  817. production into two.  For a 0-or-more list, it automatically scans all
  818. past and future productions, and makes optional all uses of the
  819. defined nonterminal.  The "PGEN -P" output shows the productions after
  820. these translations.
  821.  
  822. What about semantic actions?  This production
  823.  
  824.         List    | { Item Separator ... }        @ bld_item_list ;
  825.  
  826. and the similar 1-or-more list both become
  827.  
  828.         List    | List Separator Item           @ bld_item_list
  829.                 | Item                          @ bld_item_list1 ;
  830.  
  831. Note that two semantic actions are needed by a list.  The first to
  832. execute will have the semantic action name with the character '1'
  833. appended ('bld_item_list1').  It must convert a single item to a list
  834. with one item.  Successive iterations will call the unmodified
  835. semantic action name ('bld_item_list'), which adds a single item to
  836. the list.
  837.  
  838. WARNING!!  There are two potential pitfalls the PGEN parser programmer
  839. must particularly pay heed to!  (Oooh, love the alliteration.)
  840.  
  841. 1)      In the unchanged semantic action name (e.g. 'bld_item_list'),
  842.         the List nonterminal is at attr[0], the Item at attr[2], and
  843.         of course, the Separator at attr[1].  This is not obvious from
  844.         the original list construct where the Item appears before the
  845.         Separator, and the List doesn't appear at all.
  846.  
  847. 2)      In the usage of a 0-or-more list, an empty list results in a
  848.         jumped symbol, NOT in an empty list.  Be sure to check for
  849.         this in semantic actions that use a 0-or-more list.
  850.  
  851.                                                                     15
  852. Your test for the day:
  853.  
  854.         [ ALPHA, BETA, SEP, END ]       # Tokens
  855.         Start   | List END              @ start ;
  856.         List    | { Item SEP ... }      @ list ;
  857.         Item    | ALPHA
  858.                 | BETA          ;
  859.         # Item derives ALPHA or BETA.  The Separator is SEP.
  860.  
  861. Implement semantic actions for the above grammar so that the number of
  862. ALPHA tokens found in the input stream is printed.  Assume structure
  863. LEX_INFO has an integer field 'token' filled by the lexer with the
  864. appropriate token value and an integer field 'count' available for
  865. your use.  Also, 'ALPHA', 'BETA', etc. are macro defined constants
  866. with the correct token values.  See THAT'S ALL, FOLKS! for an answer.
  867.  
  868.  
  869.  
  870. ERROR HANDLING:
  871.  
  872. Error handling is done similarly as with YACC (Dragon book p.264-266),
  873. by deciding on a set of "major" nonterminals to have error recovery
  874. and giving those nonterminals an error production of the form
  875.  
  876.         Nonterminal     | error         @ nonterminal_error ;
  877.  
  878. The error token must be the ONLY symbol in the production, and it must
  879. appear in lower case.
  880.  
  881. When an unexpected token is detected in the input stream, 0 or more
  882. states are popped off the stack until the topmost state defines an
  883. action on the 'error' token (the state contains an item of the form
  884. "Nonterminal --> <> error").  The error token is shifted onto the
  885. stack, and the error production's semantic action is called when the
  886. error production is reduced.  If the stack becomes empty and no such
  887. state is found, the parser aborts with a fatal error.
  888.  
  889. The error semantic action routine is responsible for printing any
  890. needed error message and for skipping tokens until the parser can
  891. resume.  Procedure 'log_error()' in EXPR_LEX.C provides the former
  892. facility for EXPR.  PG_PARSE.C provides routines 'skip_to_token()' and
  893. 'skip_to_bittok()' for skipping to a particular token, or to one of a
  894. set of tokens given as a bitmap.  (See the file EXPR_SEM.C for example
  895. usages of these.)  The matching token is not consumed from the input
  896. stream by these procedures.
  897.  
  898.  
  899.  
  900. THE JUMP ACTION:
  901.  
  902. You already should be familiar with the quaternion of actions
  903. performed by bottom-up parsers -- shift, reduce, accept, and error. 
  904. PGEN includes a fifth action, jump, which was added to accommodate
  905. optional symbols.  Like the shift action, the jump action specifies
  906. which state to "shift" onto the stack.  Unlike 'shift', it does not
  907. consume a token from the input stream.  The LEX_INFO structure pushed
  908.                                                                     16
  909. represents the symbol being jumped.  Its contents are undefined,
  910. except that 'was_jumped()' will return a true value when given that
  911. structure as its argument.  The jump action, with all its consequences
  912. and solutions, is entirely this author's original invention.
  913.  
  914. The parser also uses the jump action when it would otherwise reduce by
  915. an empty production with no semantic action.  In fact, such a
  916. production is eliminated, and all uses of the nonterminal on its
  917. right-hand-side are made optional.  This will appear in the "PGEN -P"
  918. output.  The contents of the LEX_INFO structure representing the
  919. result of such a production would otherwise be completely undefined,
  920. but now you can test it with 'was_jumped()'.
  921.  
  922. I could have implemented optional symbols by converting the grammar to
  923. an equivalent form without optional symbols, but that would mean
  924. adding extra nonterminals and productions just for this purpose, which
  925. would have increased the size of the resulting tables.  The jump
  926. action is also slightly faster.
  927.  
  928. This is how PGEN determines when it should use the jump action. 
  929. Assume state 's' contains an LR(1) item of the following form:
  930.  
  931.     Nonterm --> ... <> [Opt_sym] <follow_string>, [{follow_tokens}]
  932.  
  933. If token 't' is a member of FIRST(<follow_string>) or if
  934. <follow_string> derives the empty string and 't' is a member of
  935. {follow_tokens}, then action [s,t] == "jump goto (s, [Opt_sym])".
  936.  
  937. Whoa!  You know that "goto (s, Symbol)" is the state the parser goes
  938. to (pushes on the stack) when it is in state 's' and it sees 'Symbol'. 
  939. (I consider the item set, "I sub s" to be equivalent to state 's'.) 
  940. But what is "goto (s, [Symbol])"?  It is the state the parser goes to
  941. when it jumps 'Symbol'.  This may or may not be the same as
  942. "goto (s, Symbol)".  Consider a state with the following items:
  943.  
  944.         SET a:  Xn --> ... <>  Symbol  ...
  945.                 Yn --> ... <> [Symbol] ...
  946.  
  947. The parser can either see a Symbol or jump it.  If seen, both items
  948. should be in the resulting state.
  949.  
  950.         SET b:  Xn --> ...  Symbol  <> ...
  951.                 Yn --> ... [Symbol] <> ...
  952.  
  953. If jumped, however, only the items where 'Symbol' is optional should
  954. appear in the resulting state.
  955.  
  956.         SET c:  Yn --> ... [Symbol] <> ...
  957.  
  958. Here, "goto (a, Symbol) = b" and "goto (a, [Symbol]) = c".  In the
  959. "PGEN -KW" output under set 'a', both will appear:
  960.  
  961.         SET a:  ...
  962.                 Symbol   b              [Symbol]   c
  963.  
  964. While the jump action reduces size and time, it invites three new
  965. potential conflicts.  See PARSING ACTION CONFLICTS.
  966.  
  967.  
  968.                                                                     17
  969. PARSING ACTION CONFLICTS:
  970.  
  971. While generating the parsing actions for each <state, token> pair,
  972. PGEN may encounter parsing action conflicts (Dragon p.228-230), which
  973. occur when a pair is defined by two or more actions.  These conflicts
  974. are printed to stderr as they are found.  When they occur, the
  975. programmer should consult the "PGEN -K" or "PGEN -L" output for the
  976. same grammar to determine if the conflicts need to be resolved. 
  977. Parsing conflicts don't always need to be eliminated; the default
  978. choice made by PGEN usually produces the intended result, and
  979. eliminating the conflict may add complexity to the grammar.
  980.  
  981. A reduce/reduce conflict arises when the same state has two or more
  982. items that call for a reduction on the same token.  For example:
  983.  
  984.         Sign  --> '+' <>, [INTEGER REAL]
  985.         Unary --> '+' <>, [INTEGER REAL]
  986.  
  987. PGEN will reduce by the production that appeared first in the grammar
  988. file.  In this case, "Sign --> '+'" is the production we wanted to
  989. reduce by, so we just make the definition of Sign appear before Unary
  990. in the grammar file.
  991.  
  992. A shift/reduce conflict occurs when the same state has items that call
  993. for a shift action and an item that calls for a reduce on the same
  994. token.  Example:
  995.  
  996.         Expr --> Expr '*' Expr <>, ['+' '-' '*' '/' '^' ')']
  997.         Expr --> Expr <> '*' Expr, ['+' '-' '*' '/' '^' ')']
  998.  
  999. The first item calls for reduce by production "Expr --> Expr '*' Expr"
  1000. on token '*' (among others), while the second calls for a shift on
  1001. '*'.  This kind of conflict is best resolved by giving each of the
  1002. symbol tokens the appropriate priority and associativity.
  1003.  
  1004. Not all shift/reduce conflicts are appropriately resolved with
  1005. associativity.  Consider a state containing the following two LR(1)
  1006. items (among others):
  1007.  
  1008.         Statement --> IF Expr THEN Statement <>,  [ELSE ...]
  1009.         Statement --> IF Expr THEN Statement <> ELSE Statement, [...]
  1010.  
  1011. The first item indicates that an IF Statement can potentially be
  1012. reduced when ELSE is seen.  The second item requires a shift.  In this
  1013. case and many like it, the shift is needed (we match each ELSE with
  1014. the closest IF).  If not, the grammar needs to be rearranged.  PGEN
  1015. always chooses shift when there is a shift/reduce conflict.
  1016.  
  1017.                                                                     18
  1018. The shift/jump conflict arises in states containing items similar to
  1019. the following,
  1020.  
  1021.         # Opt_sym can represent either a token or a nonterminal
  1022.         Nt1 --> ... <> [Opt_sym] ..., [token_set]
  1023.         Nt2 --> ... <> TOKEN ...
  1024.  
  1025. where TOKEN can follow the Opt_sym in the first production.  (If TOKEN
  1026. is a member of FIRST(Opt_sym), this conflict will invariably result.) 
  1027. PGEN must choose to make the parser shift the TOKEN or jump Opt_sym. 
  1028. It always chooses the shift action.
  1029.  
  1030. The reduce/jump conflict results from the similar situation where a
  1031. state contains items like the following:
  1032.  
  1033.         Nt1 --> ... <> [Opt_sym] ..., [token_set]
  1034.         Nt2 --> ... <>,  [ ... TOKEN ... ]
  1035.  
  1036. Again, TOKEN can follow Opt_sym in the first production.  In this
  1037. case, the second production specifies a reduce action on TOKEN.  PGEN
  1038. chooses the reduce.  The parser can still jump Opt_sym after the
  1039. reduce action if appropriate.
  1040.  
  1041. Finally, a jump/jump conflict occurs when two or more different
  1042. symbols could be jumped.
  1043.  
  1044.         Nt1 --> ... <> [Opt_sym1] ..., [token_set]
  1045.         Nt2 --> ... <> [Opt_sym2] ..., [token_set]
  1046.  
  1047. Here, TOKEN can follow either Opt_sym1 or Opt_sym2, producing jump
  1048. actions to two different states on the same token.  PGEN chooses to
  1049. jump the optional symbol in the first such item in the item set,
  1050. Opt_sym1 in this case.
  1051.  
  1052.  
  1053.  
  1054. PUTTING IT ALL TOGETHER:
  1055.  
  1056. As in the EXPR example, your parser will need a lexical analyzer, a
  1057. PGEN file to create the parsing table, the 'parse()' driver routine in
  1058. PG_PARSE.C, the associated semantic actions, and a 'main()' startup
  1059. procedure.  How these are assembled into a working unit is not as
  1060. easily explained in prose as it is to learn by example.  Reading the
  1061. EXPR*.* and PG_PARSE.? program text files is the best source for
  1062. learning PGEN usage.  That's why I created and included the EXPR
  1063. example.
  1064.  
  1065. A few things to notice:
  1066.  
  1067. (1)     The token definitions in the lexer header file parallel the
  1068.         definitions in the grammar file.  The lexer header includes an
  1069.         end-of-stream token as token 0 and uses only identifiers,
  1070.         which are the alternate names for the grammar file tokens that
  1071.         are symbols.
  1072.  
  1073.                                                                     19
  1074. (2)     The grammar file needs #includes at the top to include the
  1075.         token definitions from the lexer header and the semantic
  1076.         action names from the semantic action header.
  1077.  
  1078. (3)     The lexer and semantic actions are written to work in concert
  1079.         where each makes assumptions about the other.  In EXPR, the
  1080.         lexer returns the lexeme string only for certain tokens.  The
  1081.         semantic actions are responsible for utilizing or freeing the
  1082.         memory used.  This is normal and is required for efficiency.
  1083.  
  1084. (4)     To the contrary, the parser driver makes no assumptions about
  1085.         the format or content of the LEX_INFO structure.  It does
  1086.         expect 'set_jumped()' and 'was_jumped()' to be available as
  1087.         previously mentioned.
  1088.  
  1089. (5)     PG_PARSE.C needs to be modified slightly to include your lexer
  1090.         header.  If your application needs it, as when parsing a
  1091.         programming language, either your lexer must skip comments or
  1092.         you will need to modify the parser to do so.  For extremely
  1093.         large grammars PG_PARSE.H may need modification.  See the file
  1094.         \PSOURCE\OVERVIEW (with registered copy) for information.
  1095.  
  1096.  
  1097.  
  1098. THAT'S ALL, FOLKS!
  1099.  
  1100. Here is an answer to your test in LISTS,LISTS,LISTS.
  1101.  
  1102. void    list1 ()
  1103.   /* If Item (pos 0) is ALPHA, init List with count of 1. */
  1104.   /* 0 otherwise. */
  1105. {   attr [0].count = (attr [0].token == ALPHA);
  1106. }
  1107.  
  1108. void    list ()
  1109.   /* If Item (pos 2) is ALPHA, increment List (pos 0) count. */
  1110. {   if  (attr [2].token == ALPHA)  { attr [0].count += 1; }
  1111. }
  1112.  
  1113. void    start ()
  1114.   /* Check for empty (jumped) list, and print the count. */
  1115. {   if  (was_jumped (attr [0]))  { attr [0].count = 0; }
  1116.     printf ("%d\n",  attr [0].count);
  1117. }
  1118.  
  1119.  
  1120. That's all I can think of to say about PGEN.  I appreciate all
  1121. feedback -- likes, dislikes, suggested improvements, etc.  I would
  1122. especially like to hear from people who have used it.  What extra
  1123. information would you have liked to see in the documentation file and
  1124. in the source code comments?  Also, I'm always interested in others'
  1125. applications for PGEN.  If you care to tell me, please write and let
  1126. me know what you are programming.
  1127.  
  1128. I'll conclude with the usage instructions for all the included
  1129. programmer's utilities:
  1130.  
  1131.  
  1132.                                                                     20
  1133. Usage:  PPRINT  [-SPBN] [-L<lines>] [-C<cols>] [-T<tabs>]  <filepatrn>  ...
  1134.         Pretty prints text files with headings and optional line numbers.
  1135. Options:
  1136.   S     Send output to standard out.    (default: standard printer)
  1137.   P     Print in current type size.     (def: modify for output width)
  1138.   B     Print in boldface type.         (def: use current printer setting)
  1139.   N     Do not print line numbers.      (def: print line numbers)
  1140.   L     Set lines per page.             (def: 66)
  1141.   C     Set columns per line (incl. line numbers).  (def: stdprn-96, stdout-79)
  1142.   T     Set tab stop width.        (def: 8)
  1143.  
  1144.  
  1145. Usage:  command | TAIL  [-<nlines>]
  1146.    or:  TAIL  [-<nlines>]  <input file>
  1147.         Prints the last <nlines> lines (default is 10 if not given) from
  1148.         standard output from the piped command (form 1 above) or from
  1149.         the given input file (form 2 above).
  1150.         Use instead [+<nlines>] to print all but the first <nlines> lines.
  1151. Ex:     DIR | TAIL -5           Print the last 5 lines of the DIR listing.
  1152.         TAIL +20 TEST           Print all but the first 20 lines of file TEST.
  1153.  
  1154.  
  1155. Usage:  command | TEE  <file>
  1156.         Sends text output by the command to the file and to standard output.
  1157.         Does not work with interactive commands under DOS.
  1158.  
  1159.  
  1160. Usage:  CAT  <file pattern> ...
  1161.         Prints in sequence (conCATenates) all requested files.
  1162.  
  1163.  
  1164. Usage:  CHOPCRLF  <text file>  ...
  1165.         Removes the terminating carriage return/line feed
  1166.         from the end of text files.
  1167.  
  1168.  
  1169. Usage:  CHOPLL  <text file>  ...
  1170.         Removes all blank lines from the end of text files.
  1171.  
  1172.  
  1173. Usage:  CMDLINE  <file pattern>  ...
  1174.         Prints command line arguments with pattern substitution.
  1175.  
  1176.  
  1177. Usage:  CP  [-VQ]  <source file> <dest name>
  1178.    or:  CP  [-VQ]  <file pattern> ...  <dest directory>
  1179.         Copies source file to dest file, or a set of files to a directory.
  1180. Options:
  1181.   V     Verbose.  Report what is being copied.
  1182.   Q     Query user before copying.
  1183.  
  1184.  
  1185. Usage:  MV  [-VQ]  <source file> <dest name>
  1186.    or:  MV  [-VQ]  <file pattern> ...  <dest directory>
  1187.         Moves source file to dest file, or a set of files to a directory.
  1188. Options:
  1189.   V     Verbose.  Report what is being moved.
  1190.   Q     Query user before moving.
  1191.  
  1192.                                                                     21
  1193. Usage:  RM  [-RVQ]  <file pattern> ...
  1194.         Removes all files matching the given file patterns.
  1195. Options:
  1196.   R     Remove all directory contents recursively.
  1197.   V     Verbose.  Report what is being deleted.
  1198.   Q     Query user before deleting.
  1199.  
  1200.  
  1201. Usage:  HSPLIT  <num>  <infile.ext>
  1202.         Breaks a long text file into <num> shorter text files where each output
  1203.         file is a horizontal piece of the input file, approx equal in size.
  1204.         Output is to files:     infile.H00 .. infile.H<num-1>
  1205. <num> must be in the range 2 - 100.
  1206.  
  1207.  
  1208. Usage:  VSPLIT  [-T<tab>] [-L<len>]  <infile.ext>
  1209.         Breaks a wide text file into several thinner text files where each
  1210.         output file is a vertical strip of the input file.
  1211.         Output is to files:     infile.V00 .. infile.V<num-1>
  1212.         where <num> is the largest input line length divided by <len>.
  1213. <tab> is tab size (2-32, default 8).
  1214. <len> is max line length for output files (16-256, default 80).
  1215. <len> must be a multiple of <tab>
  1216.  
  1217.  
  1218. Usage:  NCSL  <C/C++ source file pattern> ...
  1219.         Reads the requested C/C++ source files and categorizes each line as
  1220.         Blank, Comment, 1 Brace, or Code.  The name comes from the industry
  1221.         metric for source code size, "Non-Commentary Source Lines".
  1222. Commentary:
  1223.   Blank   --    Lines with only whitespace; no comments or text
  1224.   Comment --    Lines containing only // or /* */ comments and whitespace.
  1225.                 Includes blank lines within /* */ comments.
  1226. Non-commentary:
  1227.   1 Brace --    Lines with only a single { or } brace, whitespace and comments.
  1228.   Code    --    All other lines (should be program code).
  1229.  
  1230.  
  1231. Usage:  DIFF  [-B]  <old text>  <new text>
  1232.         Compares the contents of two text files and prints their differences.
  1233.     If -B is specified, a tab character is prepended to the output lines.
  1234.  
  1235.  
  1236. Usage:  DIRDIFF  dir1[\patrn]  dir2
  1237.         Compares the two directories for files matching the pattern
  1238.         and prints the matching files unique to each directory.
  1239.         Matching subdirectories are also compared recursively.
  1240.         This is useful for keeping working and archive directories consistent.
  1241. The first argument is a directory or filename pattern.
  1242. Ex:  C:\DIR\*.C,  DIR (patrn=*.*),  *.EXE (dir=.)
  1243. The second argument is a directory name.
  1244.  
  1245.  
  1246. DIFF and DIRDIFF are written in C++.  The others are in C.
  1247.  
  1248.