REF LR_PARSER Robert Duncan, November 1992
COPYRIGHT University of Sussex 1992. All Rights Reserved.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<< AN LALR(1) >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<< PARSER GENERATOR >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
This file describes an LALR(1) parser generator library for Pop-11. It
assumes a working knowledge of what such a parser generator can do and
what it's good for: useful background information can be found in the
file HELP * LR_PARSER.
CONTENTS - (Use <ENTER> g to access required sections)
1 Introductory Note
2 The Basic Library
3 Generating a Parser
4 Running the Parser
5 Running the Parser in Trace Mode
6 Saving the Parser to a File
7 The Parser Report File
8 Investigating the Parser States
--------------------
1 Introductory Note
--------------------
Most Pop-11 programmers will find the syntactic interface to the library
described in HELP * DEFINE_PARSER of more immediate use. The features
described here are more likely to be useful to programmers using other
languages or who need to generate parsers dynamically.
--------------------
2 The Basic Library
--------------------
None of the identifiers described in this file are autoloadable. In
order to use the library at all, you must first include in your program
the line:
uses lr_parser;
This adds the LR_PARSER library directory to popuseslist and defines
some basic utility procedures. Libraries defining specific features can
then be loaded individually as required. Each of the sections which
follow is introduced with the name of the library you need to load to
access the identifiers described in that section.
In the context of this library, a PARSER is a recordclass object which
encodes the LALR(1) parsing tables for the grammar from which it was
constructed. A parser is created initially by the procedure lr_build and
then interpreted (i.e. made to parse) by the procedure lr_parse.
The procedure lr_parser maintains a global property table which maps
grammar names to their associated parsers. Whenever a parser is
constructed using lr_build it can optionally be added into this
property, after which the grammar name can be used interchangeably with
the parser structure itself. Throughout this file, the argument name
PARSER is used to stand for any item which lr_parser would map to a
parser structure, i.e. it can be either the parser structure itself, or
a grammar name recorded in the lr_parser property.
lr_parser(item) -> parser [procedure]
false -> lr_parser(item)
A recogniser for parsers built by the library. If item is an
LALR(1) parser structure generated by a previous call to
lr_build or if item is the name of such a parser which was built
with the KEEP argument <true>, then the parser is returned;
otherwise <false> is returned. Uses a property table to maintain
the mapping from names to parsers. You can assign <false> to the
updater to clear the property entry for a particular name.
LR_PARSER_DIR -> string [constant]
The root of the LR_PARSER directory tree containing standard
sub-directories such as:
auto
lib
The lib directory is added by the library to popuseslist and the
auto directory to popautolist.
----------------------
3 Generating a Parser
----------------------
LIB * LR_BUILD defines the LALR(1) parser generator which constructs a
set of parsing tables from the symbolic description of a grammar. The
library should be loaded using:
uses lr_build;
lr_build(name, tokens, symbols, start_symbol, rules, [procedure]
resolve_p, keep) -> parser
Constructs the LALR(1) parsing tables for the grammar described
by the arguments:
name
The grammar name: this can be any item and plays no role
other than to identify the resulting parser.
tokens
The set of terminal symbols (tokens). This may be a list
or vector. Any item can be used as a token, but tokens
are always compared for equality using the "=="
operator, so wherever a particular token occurs (e.g. in
a grammar rule) it must always be represented by the
identical item. In principle the tokens set should be a
true set, containing no duplicates, but this is not
checked: subsequent occurrences of the same item are
ignored.
symbols
The set of nonterminal symbols. This may be a list or
vector. The comments above relating to terminal symbols
apply equally to nonterminal symbols, with one extra
condition: no item from the tokens set can appear in the
symbols set (i.e. no item can be both a terminal and a
nonterminal symbol of the same grammar).
start_symbol
The start symbol of the grammar: this must be an item
from the symbols set.
rules
The set of productions (grammar rules). This may be a
list or vector. A grammar rule is a non-empty list or
vector of symbols. The first item in a rule must be a
nonterminal symbol and stands for the left-hand-side of
the rule; the remaining items make up the
right-hand-side of the rule. A rule containing just a
single item (the left-hand-side) stands for a null
production. A rule cannot contain any item which does
not occur in either the tokens or symbols sets.
The resulting parser is a record structure encoding the LALR(1)
parsing tables for the input grammar. If the grammar is not
LALR(1) then the tables will contain conflicts: the number of
conflicts can be determined with the procedures
lr_parser_sr_conflicts and lr_parser_rr_conflicts. The parser
also retains the symbolic information about the grammar from
which it was constructed: the name, tokens symbols and rules.
These can be recovered using the procedures described below.
The remaining arguments to lr_build are optional:
resolve_p
A procedure used for resolving conflicts arising from
grammars which are not properly LALR(1). It has the call
form:
resolve_p(ITEM_1, ITEM_2) -> ITEM
The two arguments represent a single conflict in the
parser. For a shift/reduce conflict, ITEM_1 is a
terminal symbol standing for the possible shift action
and ITEM_2 is a rule standing for the possible
reduction; for a reduce/reduce conflict, both items are
rules standing for the alternative reductions, ordered
such that ITEM_1 always precedes ITEM_2 in the rules
set. The result ITEM can be either ITEM_1 or ITEM_2 to
indicate a successful resolution of the conflict or else
<false> to indicate no resolution. Conflicts
successfully resolved are not counted in the parser. For
each conflict not resolved, and for every conflict if
the resolve_p argument is omitted, a default strategy is
applied: in a shift/reduce conflict the shift is chosen,
and in a reduce/reduce conflict the rule which occurs
first in the rules set is chosen (this is the only case
where the order of items in the input is significant).
This is functionally equivalent to providing a value of
erase for resolve_p, except that conflicts resolved
using resolve_p are not counted.
keep
A boolean: if <true> the result parser is added to the
lr_parser property keyed under the grammar name. The
name can then be used everywhere in place of the parser
structure. The default value is <false>.
The following example constructs the parsing tables for a simple
grammar describing expressions in the Lambda calculus.
uses lr_parser;
uses lr_build;
lr_build(
"Lambda", ;;; name
{ VAR \ . ( ) }, ;;; tokens
{ exp }, ;;; symbols
"exp", ;;; start_symbol
{{ exp VAR } ;;; rules
{ exp exp exp }
{ exp \ VAR . exp }
{ exp ( exp ) }},
true, ;;; keep
) =>
** <parser Lambda>
This grammar is ambiguous and hence not LALR(1), so the
resulting parser has conflicts. See HELP * LR_PARSER for an
alternative formulation of the grammar.
lr_parser_name(parser) -> item [procedure]
lr_parser_terminal_symbols(parser) -> vec [procedure]
lr_parser_nonterminal_symbols(parser) -> vec [procedure]
lr_parser_start_symbol(parser) -> item [procedure]
lr_parser_rules(parser) -> vec [procedure]
Return the components of the grammar from which the parser was
built. Note that the tokens, symbols and rules components are
always returned as vectors for faster indexing, regardless of
the format of the original arguments to lr_build, but the order
of items within the vectors is identical with the original
input. For example:
lr_parser_name("Lambda") =>
** Lambda
lr_parser_nonterminal_symbols("Lambda") =>
** {exp}
lr_parser_sr_conflicts(parser) -> n [procedure]
lr_parser_rr_conflicts(parser) -> n [procedure]
Return the number of shift/reduce and reduce/reduce conflicts in
the parser. A properly LALR(1) parser will return 0 for both.
However, conflicts resolved by an explicit RESOLVE_P argument to
lr_build are not counted, so a parser may appear to have no
conflicts even though the grammar was not strictly LALR(1). For
example:
lr_parser_sr_conflicts("Lambda") =>
** 6
lr_parser_rr_conflicts("Lambda") =>
** 0
lr_strip(parser) [procedure]
lr_strip(parser, bool)
Removes symbolic information from the parser structure. This can
considerably reduce the size of the parser, but necessarily
means that certain features of the library will no longer work.
By default, the parser is only partially stripped to remove the
rules, states and conflict information. This recovers the
majority of the available space, but also means that the
following procedures will mishap if applied to the parser:
# lr_trace
# lr_report
# lr_state_items
In addition, the procedures
# lr_parser_rules
# lr_parser_sr_conflicts
# lr_parser_rr_conflicts
will no longer return sensible values.
If the optional bool argument is given <true> then the parser is
fully stripped, which removes (in addition to the above) the
vectors of terminal and non-terminal symbols. This makes the
parser as small as it possibly can be, but also means that none
of the LR_STATE procedures can be expected to work, and the
procedures
# lr_parser_terminal_symbols
# lr_parser_nonterminal_symbols
# lr_parser_start_symbol
will all return <false>.
---------------------
4 Running the Parser
---------------------
LIB * LR_PARSE defines an implementation of the LR(1) parsing algorithm
which interprets the PARSER tables generated by lr_build. Load the
library using:
uses lr_parse;
lr_parse(input_p, reduce_p, parser) [procedure]
Interprets the parser tables to parse a stream of items
generated by input_p, using reduce_p to perform the semantic
actions appropriate to each reduction.
The input procedure is called each time the parser needs to read
an item. It has the call form:
input_p() -> (ITEM, TOKEN_N)
where ITEM is some arbitrary item, and TOKEN_N is an integer
number identifying to which terminal symbol the ITEM
corresponds. Terminal symbols are numbered from 1 according to
their order in the vector
lr_parser_terminal_symbols(parser)
A value of 0 is a special case used to stand for the end of
input; any other value is taken to indicate some input error. If
the token read leads to a shift action, then ITEM is pushed onto
the user stack.
The reduction procedure is called immediately prior to every
reduce action. It has the call form:
reduce_p(RULE_N)
where RULE_N is the integer number of the rule being reduced:
rules are numbered from 1 according to their order in the vector
lr_parser_rules(parser)
The reduction procedure would typically do a go_on to select an
action appropriate to the rule. There are no restrictions on the
actions which can be performed, except that the procedure should
be prepared to take account of any terminal symbols from the
right-hand-side of the rule which will have been previously
shifted onto the user stack. If the parse terminates
successfully, then any results computed by reduce_p are left
untouched on the stack.
If the parse fails, either because of an input error or because
the input is not well-formed, the redefinable procedure
lr_parse_error is called.
The procedure lr_parse is the default class_apply of the parser
structure, allowing a parser to be applied directly:
parser(input_p, reduce_p)
lr_parse_error(item, token_n, state_n) [procedure variable]
Called by lr_parse on a parsing error. item and token_n are as
returned by the last call to INPUT_P and state_n is an integer
identifying the current parsing state. For an error to arise,
either token_n must be an invalid token number, or else there is
no action for that token in the current state. The default
behaviour of lr_parse_error is to call
mishap(item, 1, 'PARSE ERROR')
but the procedure can be redefined to give a more informative
error report.
-----------------------------------
5 Running the Parser in Trace Mode
-----------------------------------
LIB * LR_TRACE defines an alternative implementation of the LR(1)
parsing algorithm which provides a trace of its actions in a VED buffer,
useful for debugging. This library cannot be used with a parser which
has been stripped. Load it using:
uses lr_trace;
lr_trace(input, parser) -> parse_tree [procedure]
lr_trace(input_p, reduce_p, parser)
Parses the input according to the tables encoded in the parser
structure, displaying a trace of its actions.
The tracer has two call forms. In the first form, input is a
list (possibly dynamic) of items drawn from the parser's TOKENS
set. If the input makes up a sentence of the language which the
parser recognises, then lr_trace returns a parse tree describing
its derivation, otherwise it returns <false>. The parse_tree for
a successful parse has the input tokens at its leaves and one
interior node for each reduction which the parser performed.
These interior nodes are constructed by the redefinable
procedure lr_trace_constree. Its default action is to construct
a list representing the rule being reduced: the head is the
nonterminal symbol from the left-hand-side of the rule, and the
tail is a list of sub-trees, one for each symbol on the
right-hand-side. For example:
uses lr_trace;
lr_trace([ \ VAR . VAR VAR ], "Lambda") =>
** [exp \ VAR . [exp [exp VAR] [exp VAR]]]
Such a tree can be displayed graphically within VED using the
procedure showtree:
uses showtree;
showtree(lr_trace([ \ VAR . VAR VAR ], "Lambda"));
See HELP * SHOWTREE.
In its second call form, lr_trace takes two procedure arguments
input_p and reduce_p which provide an input source and a
reduction procedure for the parser. In this mode, lr_trace
simulates the behaviour of lr_parse. This means that the results
(if any) returned by the parse are determined exclusively by
reduce_p, and a parsing error would normally cause a mishap
rather than returning <false>. Refer to the previous section for
more details.
In either case, lr_trace displays a trace of its actions in a
VED buffer. The trace output takes the form of a table headed as
follows:
State| Stack | Input | Action
-----+----------------+----------+-------
One row is added to the table for each step in the parse. The
columns of the table have the following interpretations:
Column Meaning
------ -------
State the current state
Stack the top of the parser's symbol stack: the topmost
item is always at the right-hand end of the field
Input the current input item: a blank entry here means
that the parser's choice of action is independent of
the input
Action the action chosen for the current state/input
combination
The trace generated from the previous example would look
something like the following:
State| Stack | Input | Action
-----+-----------------+-------+-------
1| | \ | SHIFT 3
3| \ | VAR | SHIFT 10
10| \ VAR | . | SHIFT 11
11| \ VAR . | VAR | SHIFT 2
2| \ VAR . VAR | | REDUCE exp --> VAR
12| \ VAR . exp | VAR | CONFLICT [SHIFT 2]
2| \ VAR . exp VAR | | REDUCE exp --> VAR
7| \ VAR . exp exp | $end$ | REDUCE exp --> exp exp
12| \ VAR . exp | $end$ | REDUCE exp --> \ VAR . exp
5| exp | $end$ | SHIFT 6
6| exp $end$ | | ACCEPT
The parser always begins in state 1 with nothing on the stack.
The first input item is the token "\" which causes a shift to
state 3. The second row of t he table thus shows the parser in
state 3, with "\" on the stack. The next three items ("VAR", "."
and "VAR") are also shifted: note how items cross from the Input
to the Stack field as they are consumed. At row 5 (state 2) the
parser performs a reduction by the rule
exp --> VAR
which replaces the topmost "VAR" token on the stack with the
symbol "exp". This is the default action for state 2 activated
for any input item, hence the empty Input column. Each REDUCE
action in the trace corresponds to one interior node in the
resulting parse tree:
[exp \ VAR . ;;; REDUCE exp --> \ VAR . exp
[exp ;;; REDUCE exp --> exp exp
[exp VAR] ;;; REDUCE exp --> VAR
[exp VAR]]] ;;; REDUCE exp --> VAR
Once a parse has run to completion, the last action in the table
will either be ACCEPT for a successful outcome, or ERROR
otherwise.
Loading the LR_TRACE library also generalises the class_apply of
the parser structure to call lr_trace where possible, but with
the trace output disabled. This allows calls such as:
lr_parser("Lambda")([ \ VAR . VAR VAR ]) =>
** [exp \ VAR . [exp [exp VAR] [exp VAR]]]
lr_parser("Lambda")([ \ VAR VAR VAR ]) =>
** <false>
lr_trace_tracing -> bool [variable]
bool -> lr_trace_tracing
Determines whether lr_trace should produce any trace output. The
default value is <true>; setting it <false> means that lr_trace
will still parse but without tracing.
lr_trace_file -> string [variable]
string -> lr_trace_file
Name of the file to which trace output should be sent: the
default is 'lr_trace'.
lr_trace_file_writeable -> bool [variable]
bool -> lr_trace_file_writeable
Controls whether the trace output file should be writeable: the
default value is <false>.
lr_trace_state_width -> n [variable]
n -> lr_trace_state_width
lr_trace_stack_width -> n [variable]
n -> lr_trace_stack_width
lr_trace_input_width -> n [variable]
n -> lr_trace_input_width
Determine the sizes of the fields in the trace output diagram:
lr_trace_state_width is the number of columns used for the State
field, lr_trace_stack_width is the number of columns used for
the Stack field and lr_trace_input_width is the number of
columns used for the Input field. The default value is <false>
for each, meaning that the sizes are determined dynamically
depending on the width of the trace output file: the wider the
window, the more informative the output. Setting any of these
variables to 0 or less means that the corresponding field is not
shown in the trace output. The Action field always extends as
far to the right as necessary and cannot be suppressed.
lr_trace_constree(symbol, n) -> tree [procedure variable]
Used for constructing interior nodes in the parse tree built by
lr_trace. Called once for each reduction, symbol is the
left-hand-side symbol of the rule being reduced and n is the
number of symbols on the right-hand-side. The default definition
is:
define vars lr_trace_constree(symbol, n) -> tree;
lvars symbol, n, tree = conslist(n);
symbol :: tree -> tree;
enddefine;
If redefined, the procedure should consume n items from the
stack and return some object representing the parse tree. For
example, the procedure prolog_maketerm would be a suitable
alternative value, using Prolog terms to represent trees.
------------------------------
6 Saving the Parser to a File
------------------------------
LIB * LR_OUTPUT writes a program to regenerate a parser structure
without using the LR_BUILD library. Load using:
uses lr_output;
lr_output(decl_list, word, parser, output) [procedure]
Writes to the given output a Pop-11 program to reconstruct the
parser structure and bind it to word. decl_list provides an
appropriate declaration for word. The resulting program can only
be loaded after the LR_PARSER library, but is otherwise
self-contained; in particular, it does not need the LR_BUILD
library.
output can be any valid output destination: a file name, a
character consumer or an output device. A named file will be
opened afresh using discout; if the name is a word, it will have
the extension '.p' appended automatically.
The resulting program has the form:
<declaration> word = <parser> ;
where <declaration> is generated from the argument decl_list by
the call:
applist(decl_list, spr);
It is expected that decl_list should be some meaningful list of
declaration syntax words (such as "global", "constant",
"lconstant" etc.) but this is not checked. If decl_list is nil,
then a default declaration of "vars" is assumed.
For example, the sequence:
uses lr_output;
lr_output([global vars], "lambdaParser", "Lambda", "Lambda")
creates a file called 'Lambda.p' in the current directory,
containing a program of the form:
global vars lambdaParser = <expression> ;
where <expression> recreates the Lambda parser without the use
of the LR_BUILD library.
The full symbolic information in the parser is too complex to be
written out reliably, so is ignored. This means that a parser
recreated from a program generated by lr_output will always be
at least partially stripped (regardless of whether the original
was stripped or not) and so cannot be used for tracing (see
lr_strip above).
The program does preserve the parser's terminal and non-terminal
symbols if these are present in the original. This in itself
poses a problem, in that symbols can in principal be arbitrary
items which may not have a suitable printing representation. For
this reason, the symbols are written out using the redefinable
procedure lr_output_pr which must be defined in such a way that
its output can be read back in successfully by the compiler.
lr_output_pr(item) [procedure variable]
Writes an expression to the current output which would recreate
item if compiled by the Pop-11 compiler. Used by lr_output to
write out a parser's terminal and nonterminal symbols which can
be arbitrary items. The generated expressions are enclosed in
evaluating vector brackets:
{% ... %}
separated by commas, and must be evaluable in that context.
The default version of this procedure handles words, strings and
integral numbers. It should be redefined for symbols of any
other type. The procedure is always called in a context where
pop_pr_quotes has the value <false> and pr has the value
sys_syspr.
-------------------------
7 The Parser Report File
-------------------------
LIB * LR_REPORT generates a written description of the parsing tables.
This is essential for understanding conflicts in a parser, and can also
be useful when planning error reporting. Information from the report can
also be determined dynamically using the procedures from LIB * LR_STATE
(see below). This library cannot be used with a parser which has been
stripped. Load the library with:
uses lr_report;
lr_report(parser, output) [procedure]
Writes a summary report on the parser to the specified output.
The output can be any valid output destination: a file name, a
character consumer or an output device. A file name can be given
as a word or a string; on VMS systems, a word will have the
extension '.lis' appended automatically. For all but the
smallest of grammars, the report can get very large -- up to
thousands of lines -- so it's generally best to send the report
to a file rather than to the screen.
The layout of the report is best described with reference to an
example. If you have compiled the "Lambda" example above, you
can generate the report for the parser by doing:
uses lr_report;
lr_report("Lambda", 'report');
The report starts with a brief header which includes the parser
name, the number of states and the number of conflicts. For the
Lambda parser, this looks like:
Parser Lambda
12 states
6 shift/reduce conflicts
0 reduce/reduce conflicts
The remainder of the file is taken up with a description of each
of the parser states. State number 12 of the Lambda parser
demonstrates most of the relevant features: you can view this by
doing
<ENTER> pved report
<ENTER> /@aState 12/
The state description is in three parts:
1) the set of LR(0) items from which the state was
constructed
2) the action table
3) the goto table
For Lambda state 12, these appear as follows:
1) The LR(0) items
[2] exp --> exp <.> exp
[3] exp --> \ VAR . exp <.>
There are two items, generated from production numbers 2
and 3. These numbers cross-reference with the reduce
actions in the action table. The special symbol <.>
indicates the "dot" position within each item.
2) The action table
! VAR shift 2
! VAR reduce 3
! \ shift 3
! \ reduce 3
! ( shift 4
! ( reduce 3
$default$ reduce 3
This lists the tokens which are valid in the state and
shows the action associated with each: an action
shift <N>
means a shift to state <N> and
reduce <N>
means a reduction by rule <N>. For each reduction, the
associated rule must appear in the item set with the dot
at the right-hand end. The special token "$default$" is
a default action to be taken for any token not listed
explicitly: this will always be a reduction. Not all
states have a default action in which case any token not
listed will cause a parsing error. The `!` character in
the first column of the table indicates a conflict, i.e,
where the associated token has more than one possible
action in the state (in this particular state, all the
valid tokens have conflicts). You can locate conflicts
within VED by doing
<ENTER> /@a!
The table is organised such that the first action
associated with any token is the one the parser will
choose.
3) The goto table
exp goto 7
This lists the nonterminal symbols which are valid in
the state and their associated goto transitions. Some
states may have no goto transitions, and there is no
concept of a default transition.
A final point to note from the report is that lr_build always
adds an additional rule to the grammar RULES set of the form:
$begin$ --> START_SYMBOL $end$
where "$begin$" and "$end$" are special tokens. This rule is
assigned number [0]; the state constructed from the item
[0] $begin$ --> START_SYMBOL $end$ <.>
is the terminal state of the parser.
----------------------------------
8 Investigating the Parser States
----------------------------------
LIB * LR_STATE makes available from procedure calls all the information
in the parser report file. This is useful for presenting the report in
an alternative way (e.g. with a graphical display) or else for
dynamically generating error reports. This library cannot be used with a
parser which has been stripped. Load with:
uses lr_state;
lr_state_max(parser) -> n [procedure]
Returns the largest valid state number for the parser. States
are numbered sequentially from 1, so this is also the number of
states within the parser.
lr_state_tokens(n, parser) -> (token_list, default) [procedure]
Returns a list of tokens for which there are explicit actions
defined in state n of the parser. The boolean default is <true>
if there is also a default action in this state, implying that
any token is valid in the state, but that all tokens not
occurring explicitly in the token_list share some common,
default action: this will always be a reduction. If default is
<false> then there is no default action: only the tokens in
token_list are valid in this state, and any other token would
cause an error. It follows that in an error state (e.g. in a
call to lr_parse_error) default will always be <false>.
The special value lr_state_end_token is included in token_list
if the end-of-input marker ("$end$") is valid in state n.
lr_state_actions(token, n, parser) -> (shift, reductions) [procedure]
Returns the ACTION table entry (or entries) for a token in state
n of the parser: in a properly LALR(1) parser there will never
be more than one action for any token, but there may be multiple
actions in the presence of conflicts. The result shift is the
next state number if token has a shift action, or <false>
otherwise. reductions is a list of the rule numbers for which
token has reduce actions. A rule number of 0 stands for the
ACCEPT action, indicating that state n must be the terminal
state of the parser.
In a parser which has been partially stripped, all conflict
information will have been removed, so this procedure will never
return more than one action.
lr_state_shift(token, n, parser) -> shift [procedure]
Returns the shift result returned by lr_state_actions.
lr_state_reduce(token, n, parser) -> reduction [procedure]
Returns the first rule number from the list of REDUCTIONS
returned by lr_state_actions, or <false> if the list is empty.
lr_state_end_token -> item [variable]
item -> lr_state_end_token
Special value used to stand for the end-of-input marker (i.e.
the "$end$" symbol from the report file). The default is
<termin>.
lr_state_symbols(n, parser) -> symbol_list [procedure]
Returns a list of the nonterminal symbols for which there are
GOTO table entries in state n of the parser. The list may be
empty.
lr_state_goto(symbol, n, parser) -> m [procedure]
Returns the GOTO table entry for a nonterminal symbol in state n
of the parser: this will be the next state number or <false> for
a blank entry.
lr_state_items(n, parser) -> list [procedure]
Returns a list of the LR(0) items from which the parser state n
was constructed. An item is represented by a pair of integers:
the front of the pair is the item rule number and the back of
the pair is the "dot" position within the rule. The dot position
is an index into the rule with the interpretation that the dot
occurs after the indexed symbol. Because the first symbol of the
rule is always the left-hand-side symbol, a dot position of 1
implies that the dot is at the start of the right-hand-side,
while a dot position equal to the length of the rule implies
that the dot is at the end.
For example:
uses lr_state;
lr_state_items(12, "Lambda") =>
** [[2|2] [3|5]]
This result corresponds to the extract from the report file
shown above:
[2] exp --> exp <.> exp
[3] exp --> \ VAR . exp <.>
This procedure will mishap if the parser has been even partially
stripped.
--- C.all/ref/lr_parser
--- Copyright University of Sussex 1992. All rights reserved.Author: Robert Duncan, November 1992