mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-05 11:18:18 +02:00
969 lines
29 KiB
ObjectPascal
969 lines
29 KiB
ObjectPascal
{
|
|
This module collects the various tables used by the Yacc program:
|
|
- the symbol table
|
|
- the rule table
|
|
- the precedence table
|
|
- the closure table
|
|
- the LALR state, item, transition and reduction table
|
|
Note: All tables are allocated dynamically (at initialization time)
|
|
because of the 64KB static data limit. *)
|
|
|
|
|
|
Copyright (c) 1990-92 Albert Graef <ag@muwiinfa.geschichte.uni-mainz.de>
|
|
Copyright (C) 1996 Berend de Boer <berend@pobox.com>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
$Revision: 1.3 $
|
|
$Modtime: 96-07-31 21:15 $
|
|
|
|
$History: YACCTABL.PAS $
|
|
*
|
|
* ***************** Version 2 *****************
|
|
* User: Berend Date: 96-10-10 Time: 21:16
|
|
* Updated in $/Lex and Yacc/tply
|
|
* Updated for protected mode, windows and Delphi 1.X and 2.X.
|
|
|
|
}
|
|
|
|
|
|
unit YaccTabl;
|
|
|
|
interface
|
|
|
|
uses
|
|
YaccBase;
|
|
|
|
|
|
const
|
|
|
|
(* Maximum table sizes: *)
|
|
|
|
max_keys = 997; (* size of hash symbol table (prime number!) *)
|
|
{$IFDEF MsDos}
|
|
max_nts = 300; (* maximum number of nonterminals *)
|
|
max_lits = 556; (* number of literals (300+256) *)
|
|
max_rules = 301; (* number of rules (300+1) *)
|
|
max_types = 100; (* number of type tags *)
|
|
max_prec = 50; (* maximum precedence level *)
|
|
max_states = 600; (* number of LR(0) states *)
|
|
max_items = 2400; (* number of items *)
|
|
max_trans = 2400; (* number of transitions *)
|
|
max_redns = 1200; (* number of reductions *)
|
|
{$ELSE}
|
|
max_nts = 900; (* maximum number of nonterminals *)
|
|
max_lits = max_nts+256; (* number of literals (300+256) *)
|
|
max_rules = max_nts+1; (* number of rules (300+1) *)
|
|
max_types = 100; (* number of type tags *)
|
|
max_prec = 50; (* maximum precedence level *)
|
|
{$IFDEF Windows}
|
|
max_states = 3000; (* number of LR(0) states *)
|
|
{$ELSE}
|
|
max_states = 3000; (* number of LR(0) states *)
|
|
{$ENDIF}
|
|
max_items = 40000; (* number of items *)
|
|
max_trans = 40000; (* number of transitions *)
|
|
max_redns = 9600; (* number of reductions *)
|
|
{$ENDIF}
|
|
|
|
{$IFDEF MsDos}
|
|
max_rule_len = 64; (* maximum length of rules *)
|
|
max_set_items = 64; (* maximum number of items in an item set *)
|
|
{$ELSE}
|
|
max_rule_len = 64; (* maximum length of rules *)
|
|
max_set_items = 9600; (* maximum number of items in an item set *)
|
|
{$ENDIF}
|
|
|
|
var
|
|
|
|
(* Actual table sizes: *)
|
|
|
|
n_nts : Integer;
|
|
n_lits : Integer;
|
|
n_rules : Integer;
|
|
n_types : Integer;
|
|
n_prec : Integer;
|
|
n_states : Integer;
|
|
n_items : Integer;
|
|
n_trans : Integer;
|
|
n_redns : Integer;
|
|
|
|
type
|
|
|
|
(* Table data structures: *)
|
|
|
|
(* Symbol table: The symbol table consists of a hash table which stores
|
|
print names and internal symbol numbers, and a key table which stores,
|
|
for each internal symbol number, the corresponding hash key. *)
|
|
|
|
SymRec = record
|
|
pname : StrPtr;
|
|
(* print name; empty entries are denoted by pname=nil *)
|
|
deff : Boolean;
|
|
(* flag denoting whether symbol is already defined *)
|
|
sym : Integer;
|
|
(* internal symbol number (0 or positive: literal symbols
|
|
(literal characters have symbol numbers 1 thru 255);
|
|
negative: nonterminal symbols; 0 denotes endmarker,
|
|
-1 augmented start nonterminal, 256 is reserved for
|
|
error token; note that the predefined symbols except
|
|
the error literal are not actually stored in the symbol
|
|
table; the error symbol is entered at initialization
|
|
s.t. it always has number 256) *)
|
|
end;
|
|
|
|
SymTable = array [1..max_keys] of SymRec;
|
|
|
|
SymKeyTable = array [-max_nts..max_lits-1] of Integer;
|
|
(* hash keys for nonterminal and literal symbols *)
|
|
|
|
(* Rule table: the rule table consists of an array storing the rules
|
|
sequentially in the order in which they appear in the source grammar;
|
|
a rule no.s table which is used to sort rules w.r.t. left-hand side
|
|
nonterminals (after the rule table has been constructed and sorted, all
|
|
references to rules are done indirectly via the rule_no array s.t. the
|
|
rules for each nonterminal can be accessed easily); and an offset table
|
|
which stores, for each nonterminal, the corresponding first and last
|
|
index in the rule no.s table. *)
|
|
|
|
RuleRec = record
|
|
lhs_sym : Integer; (* lhs nonterminal *)
|
|
rhs_len : Integer; (* length of rhs *)
|
|
rhs_sym : array [1..max_rule_len] of Integer;
|
|
(* rhs symbols *)
|
|
end;
|
|
|
|
RuleRecPtr = ^RuleRec;
|
|
|
|
RuleTable = array [1..max_rules] of RuleRecPtr;
|
|
|
|
RuleNoTable = array [1..max_rules] of Integer;
|
|
|
|
RuleOffsRec = record
|
|
rule_lo, rule_hi : Integer;
|
|
end;
|
|
|
|
RuleOffsTable = array [1..max_nts] of RuleOffsRec;
|
|
|
|
(* Symbol type table: The symbol type table stores the types associated
|
|
with the nonterminal and terminal grammar symbols (0 if none). *)
|
|
|
|
TypeTable = array [1..max_types] of Integer;
|
|
(* types declared in the definitions section *)
|
|
|
|
SymTypeTable = array [-max_nts..max_lits-1] of Integer;
|
|
(* symbol types *)
|
|
|
|
(* Precedence table: The precedence table stores the type of each
|
|
precedence level (left, right, nonassoc) and, for each literal
|
|
symbol and grammar rule, the assigned precedence level (precedence
|
|
level 0 if none). *)
|
|
|
|
PrecType = ( left, right, nonassoc );
|
|
|
|
PrecTable = array [1..max_prec] of PrecType;
|
|
|
|
SymPrecTable = array [0..max_lits-1] of Integer;
|
|
|
|
RulePrecTable = array [1..max_rules] of Integer;
|
|
|
|
(* Closure and first symbols table: The closure table stores, for each
|
|
nonterminal X, the set of those nonterminals Y for which there is a
|
|
rightmost derivation X =>+ Y ... . Similarly, the first set table
|
|
stores, for each nonterminal X, the set of literals a for which there
|
|
is a derivation X =>+ a ... . Both tables are of type SymSetTable.
|
|
|
|
The nullable table stores, for each nonterminal, a flag denoting whether
|
|
the nonterminal is nullable (i.e. may be derived to the empty string).
|
|
|
|
These tables are constructed by the routines in the YaccClosure unit,
|
|
and are used by the LALR parser construction algorithms in YaccLR0 and
|
|
YaccLookaheads. *)
|
|
|
|
SymSetTable = array [1..max_nts] of IntSetPtr;
|
|
|
|
NullableTable = array [1..max_nts] of Boolean;
|
|
|
|
(* State table:
|
|
|
|
Each state stores the first and last index of the kernel items,
|
|
transitions and reductions belonging to it, and a hash key determined
|
|
from the kernel items which is used to speed up searches for existing
|
|
states.
|
|
|
|
The items table stores the individual kernel items in the LR(0) set.
|
|
Each entry consists of a rule number together with the item position,
|
|
and a "next" field indicating the associated item in the successor state
|
|
(0 if there is none). The ItemSet type is used to retrieve and manipulate
|
|
individual item sets from the item table.
|
|
|
|
The transition table stores the shift and goto transitions in each state
|
|
(each transition is denoted by a (symbol, next_state) pair). Similarly,
|
|
the reductions table stores the reductions in each state, where each
|
|
action is denoted by a (symbolset, ruleno) pair. *)
|
|
|
|
StateRec = record
|
|
item_lo, item_hi : Integer;
|
|
trans_lo, trans_hi : Integer;
|
|
redns_lo, redns_hi : Integer;
|
|
key : Integer;
|
|
end;
|
|
|
|
StateTable = array [0..max_states-1] of StateRec;
|
|
|
|
ItemRec = record
|
|
rule_no, pos_no : Integer;
|
|
next : Integer;
|
|
end;
|
|
|
|
ItemSet = record
|
|
n_items : Integer;
|
|
item : array [1..max_set_items] of ItemRec;
|
|
end;
|
|
|
|
ItemTable = array [1..max_items] of ItemRec;
|
|
|
|
TransRec = record
|
|
sym, next_state : Integer;
|
|
end;
|
|
|
|
TransTable = array [1..max_trans] of TransRec;
|
|
|
|
RednRec = record
|
|
symset : IntSetPtr;
|
|
rule_no : Integer;
|
|
end;
|
|
|
|
RednTable = array [1..max_redns] of RednRec;
|
|
|
|
(* Lookaheads table: This table stores, for each kernel item, the
|
|
corresponding LALR(1) lookahead symbol sets. *)
|
|
|
|
LookaheadTable = array [1..max_items] of IntSetPtr;
|
|
|
|
(* The propagation table is used to keep track of how lookaheads are
|
|
propagated from kernel items to other lookahead sets. *)
|
|
|
|
PropList = ^PropEntry;
|
|
|
|
PropEntry = record
|
|
symset : IntSetPtr;
|
|
next : PropList;
|
|
end;
|
|
|
|
PropTable = array [1..max_items] of PropList;
|
|
|
|
|
|
var
|
|
|
|
verbose : Boolean; (* status of the verbose option *)
|
|
debug : Boolean; (* status of the debug option *)
|
|
startnt : Integer; (* start nonterminal of grammar
|
|
(0 if undefined) *)
|
|
sym_table : ^SymTable; (* symbol table *)
|
|
sym_key : ^SymKeyTable; (* symbol keys *)
|
|
rule_table : ^RuleTable; (* rule table *)
|
|
type_table : ^TypeTable; (* type table *)
|
|
sym_type : ^SymTypeTable; (* symbol types *)
|
|
prec_table : ^PrecTable; (* precedence table *)
|
|
sym_prec : ^SymPrecTable; (* literal symbols precedence *)
|
|
rule_prec : ^RulePrecTable; (* rules precedence *)
|
|
rule_no : ^RuleNoTable; (* rule no table *)
|
|
rule_offs : ^RuleOffsTable; (* rule offset table *)
|
|
closure_table : ^SymSetTable; (* closure table *)
|
|
first_set_table : ^SymSetTable; (* first set table *)
|
|
nullable : ^NullableTable; (* nullable flags table *)
|
|
state_table : ^StateTable; (* LR(0) state table *)
|
|
item_table : ^ItemTable; (* LR(0) kernel item table *)
|
|
trans_table : ^TransTable; (* transition table *)
|
|
redn_table : ^RednTable; (* reduction table *)
|
|
lookahead_table : ^LookaheadTable; (* LALR lookaheads table *)
|
|
prop_table : ^PropTable; (* lookahead propagation table *)
|
|
|
|
|
|
(* Operations: *)
|
|
|
|
(* Symbol table routines: *)
|
|
|
|
function new_nt : Integer;
|
|
(* returns a new nonterminal number (<-1) *)
|
|
|
|
function new_lit : Integer;
|
|
(* returns a new literal number above 256 *)
|
|
|
|
procedure add_lit ( sym : Integer );
|
|
(* this routine allows to add a user-defined literal symbol;
|
|
the current literal symbols count is adjusted accordingly *)
|
|
|
|
function get_key ( symbol : String ) : Integer;
|
|
(* returns a hash key for symbol *)
|
|
|
|
procedure def_key ( k : Integer; sym : Integer );
|
|
(* defines k to be a new symbol with internal symbol number sym *)
|
|
|
|
function is_def_key ( k : Integer; var sym : Integer ) : Boolean;
|
|
(* checks whether symbol denoted by symbol table key k is already
|
|
defined; if so, returns the corresponding symbol number *)
|
|
|
|
function pname ( sym : Integer ) : String;
|
|
(* returns the print name of an internal symbol (`$end' for
|
|
symbol 0, `$accept' for nonterminal -1, and a single quoted
|
|
character for literals 1..255) *)
|
|
|
|
(* Rule table routines: *)
|
|
|
|
function newRuleRec ( r : RuleRec ) : RuleRecPtr;
|
|
(* obtains a dynamic copy of r (only the number of bytes actually
|
|
needed is allocated) *)
|
|
|
|
procedure add_rule ( r : RuleRecPtr );
|
|
(* add a rule to the rule table *)
|
|
|
|
procedure sort_rules;
|
|
(* sorts rules w.r.t. left-hand sides into the rule no table *)
|
|
|
|
procedure rule_offsets;
|
|
(* computes rule offsets after rules have been sorted *)
|
|
|
|
function n_nt_rules ( sym : Integer ) : Integer;
|
|
(* returns number of rules for nonterminal sym *)
|
|
|
|
(* Type Table routines: *)
|
|
|
|
procedure add_type ( k : Integer );
|
|
(* add a type identifier to the table *)
|
|
|
|
procedure sort_types;
|
|
(* sort the type table alphabetically, eliminate dups *)
|
|
|
|
function search_type ( symbol : String ) : Boolean;
|
|
(* search the sorted types table for the given type symbol *)
|
|
|
|
(* Precedence table routines: *)
|
|
|
|
function new_prec_level ( prec_type : PrecType ) : Integer;
|
|
(* adds a new precedence level of the denoted type; returns: the new
|
|
level *)
|
|
|
|
(* State table routines: *)
|
|
|
|
var act_state : Integer; (* state currently considered *)
|
|
|
|
procedure new_state;
|
|
(* build a new state *)
|
|
|
|
procedure add_item ( rule_no, pos_no : Integer );
|
|
(* add an item to the new state (initialize its next field to 0) *)
|
|
|
|
function add_state : Integer;
|
|
(* add the new state to the state table; if an equivalent state is already
|
|
in the table, dispose the new state, and return the existing state
|
|
number, otherwise return the new state number *)
|
|
|
|
procedure start_trans;
|
|
(* starts building transitions of the active state *)
|
|
|
|
procedure add_trans ( sym, next_state : Integer );
|
|
(* adds a transition to the active state *)
|
|
|
|
procedure end_trans;
|
|
(* ends transitions of the active state *)
|
|
|
|
procedure start_redns;
|
|
(* starts building reduction actions of the active state *)
|
|
|
|
procedure add_redn ( symset : IntSetPtr; rule_no : Integer );
|
|
(* adds a reduction to the active state *)
|
|
|
|
procedure end_redns;
|
|
(* ends reduction actions of the active state *)
|
|
|
|
function n_state_items ( s : Integer ) : Integer;
|
|
function n_state_trans ( s : Integer ) : Integer;
|
|
function n_state_redns ( s : Integer ) : Integer;
|
|
(* return the number of kernel items, transitions and reductions in state
|
|
s, respectively *)
|
|
|
|
function find_item( s : Integer; rule_no, pos_no : Integer ) : Integer;
|
|
(* find item (rule_no, pos_no) in state s; returns: the item number *)
|
|
|
|
(* Item set routines: *)
|
|
|
|
procedure empty_item_set ( var item_set : ItemSet );
|
|
(* initializes an empty item set *)
|
|
|
|
procedure include_item_set ( var item_set : ItemSet;
|
|
rule_no, pos_no : Integer);
|
|
(* add the denoted item to the given item set *)
|
|
|
|
procedure get_item_set ( s : Integer; var item_set : ItemSet);
|
|
(* obtain the item set of state s from the item table *)
|
|
|
|
procedure closure ( var item_set : ItemSet );
|
|
(* compute the closure of item_set (using the closure table) *)
|
|
|
|
procedure sort_item_set ( var item_set : ItemSet );
|
|
(* sorts an item set w.r.t. position and rule numbers (higher positions,
|
|
lower rules first) *)
|
|
|
|
implementation
|
|
|
|
uses YaccMsgs;
|
|
|
|
(* Symbol table routines: *)
|
|
|
|
function new_nt : Integer;
|
|
begin
|
|
inc(n_nts);
|
|
if n_nts>max_nts then fatal(nt_table_overflow);
|
|
sym_type^[-n_nts] := 0;
|
|
new_nt := -n_nts;
|
|
end(*new_nt*);
|
|
|
|
function new_lit : Integer;
|
|
begin
|
|
inc(n_lits);
|
|
if n_lits>max_lits then fatal(lit_table_overflow);
|
|
sym_type^[n_lits-1] := 0;
|
|
sym_prec^[n_lits-1] := 0;
|
|
new_lit := n_lits-1;
|
|
end(*new_lit*);
|
|
|
|
procedure add_lit ( sym : Integer );
|
|
begin
|
|
if sym>n_lits then n_lits := sym;
|
|
if n_lits>max_lits then fatal(lit_table_overflow);
|
|
sym_type^[sym] := 0;
|
|
sym_prec^[sym] := 0;
|
|
end(*add_lit*);
|
|
|
|
{$ifndef fpc}{$F+}{$endif}
|
|
function lookup(k : Integer) : String;
|
|
{$ifndef fpc}{$F-}{$endif}
|
|
(* print name of symbol no. k *)
|
|
begin
|
|
with sym_table^[k] do
|
|
if pname=nil then
|
|
lookup := ''
|
|
else
|
|
lookup := pname^
|
|
end(*lookup*);
|
|
|
|
{$ifndef fpc}{$F+}{$endif}
|
|
procedure entry(k : Integer; symbol : String);
|
|
{$ifndef fpc}{$F-}{$endif}
|
|
(* enter symbol into table *)
|
|
begin
|
|
sym_table^[k].pname := newStr(symbol);
|
|
end(*entry*);
|
|
|
|
function get_key ( symbol : String ) : Integer;
|
|
begin
|
|
get_key := key(symbol, max_keys, {$ifdef fpc}@{$endif}lookup,
|
|
{$ifdef fpc}@{$endif}entry);
|
|
end(*get_key*);
|
|
|
|
procedure def_key ( k : Integer; sym : Integer );
|
|
begin
|
|
sym_key^[sym] := k;
|
|
sym_table^[k].deff := true;
|
|
sym_table^[k].sym := sym;
|
|
end(*def_key*);
|
|
|
|
function is_def_key ( k : Integer; var sym : Integer ) : Boolean;
|
|
begin
|
|
if sym_table^[k].deff then
|
|
begin
|
|
sym := sym_table^[k].sym;
|
|
is_def_key := true;
|
|
end
|
|
else
|
|
is_def_key := false
|
|
end(*is_def_key*);
|
|
|
|
function pname ( sym : Integer ) : String;
|
|
begin
|
|
case sym of
|
|
1..255 : pname := singleQuoteStr(chr(sym));
|
|
0 : pname := '$end';
|
|
-1 : pname := '$accept';
|
|
else begin
|
|
if sym_table^[sym_key^[sym]].pname^[1]=''''
|
|
then begin
|
|
pname := singleQuoteStr(
|
|
copy( sym_table^[sym_key^[sym]].pname^,
|
|
2,
|
|
length(sym_table^[sym_key^[sym]].pname^)-2)
|
|
)
|
|
end
|
|
else begin
|
|
pname := sym_table^[sym_key^[sym]].pname^;
|
|
end;
|
|
end;
|
|
end;
|
|
end(*pname*);
|
|
|
|
(* Rule table: *)
|
|
|
|
function newRuleRec ( r : RuleRec ) : RuleRecPtr;
|
|
var rp : RuleRecPtr;
|
|
begin
|
|
getmem(rp, 2*sizeOf(Integer)+r.rhs_len*sizeOf(Integer));
|
|
move(r, rp^, 2*sizeOf(Integer)+r.rhs_len*sizeOf(Integer));
|
|
newRuleRec := rp;
|
|
end(*newRuleRec*);
|
|
|
|
procedure add_rule ( r : RuleRecPtr );
|
|
begin
|
|
inc(n_rules);
|
|
if n_rules>max_rules then fatal(rule_table_overflow);
|
|
rule_table^[n_rules] := r;
|
|
end(*add_rule*);
|
|
|
|
{$ifndef fpc}{$F+}{$endif}
|
|
function rule_less ( i, j : Integer ) : Boolean;
|
|
{$ifndef fpc}{$F-}{$endif}
|
|
begin
|
|
if rule_table^[rule_no^[i]]^.lhs_sym =
|
|
rule_table^[rule_no^[j]]^.lhs_sym then
|
|
rule_less := rule_no^[i] < rule_no^[j]
|
|
else
|
|
rule_less := rule_table^[rule_no^[i]]^.lhs_sym >
|
|
rule_table^[rule_no^[j]]^.lhs_sym
|
|
end(*rule_less*);
|
|
|
|
{$ifndef fpc}{$F+}{$endif}
|
|
procedure rule_swap ( i, j : Integer );
|
|
{$ifndef fpc}{$F-}{$endif}
|
|
var x : Integer;
|
|
begin
|
|
x := rule_no^[i]; rule_no^[i] := rule_no^[j]; rule_no^[j] := x;
|
|
end(*rule_swap*);
|
|
|
|
procedure sort_rules;
|
|
var i : Integer;
|
|
begin
|
|
for i := 1 to n_rules do rule_no^[i] := i;
|
|
quicksort ( 1, n_rules, {$ifdef fpc}@{$endif}rule_less,
|
|
{$ifdef fpc}@{$endif}rule_swap );
|
|
end(*sort_rules*);
|
|
|
|
procedure rule_offsets;
|
|
var i, sym : Integer;
|
|
begin
|
|
for sym := 1 to n_nts do with rule_offs^[sym] do
|
|
begin
|
|
rule_lo := 1; rule_hi := 0;
|
|
end;
|
|
i := 1;
|
|
while (i<=n_rules) do
|
|
begin
|
|
sym := rule_table^[rule_no^[i]]^.lhs_sym;
|
|
rule_offs^[-sym].rule_lo := i;
|
|
inc(i);
|
|
while (i<=n_rules) and
|
|
(rule_table^[rule_no^[i]]^.lhs_sym=sym) do
|
|
inc(i);
|
|
rule_offs^[-sym].rule_hi := i-1;
|
|
end;
|
|
end(*rule_offsets*);
|
|
|
|
function n_nt_rules ( sym : Integer ) : Integer;
|
|
begin
|
|
with rule_offs^[-sym] do
|
|
n_nt_rules := rule_hi-rule_lo+1
|
|
end(*n_nt_rules*);
|
|
|
|
(* Type Table routines: *)
|
|
|
|
procedure add_type ( k : Integer );
|
|
begin
|
|
inc(n_types);
|
|
if n_types>max_types then fatal(type_table_overflow);
|
|
type_table^[n_types] := k;
|
|
end(*add_type*);
|
|
|
|
(* Routines to sort type identifiers alphabetically: *)
|
|
|
|
{$ifndef fpc}{$F+}{$endif}
|
|
function type_less ( i, j : Integer ) : Boolean;
|
|
{$ifndef fpc}{$F-}{$endif}
|
|
begin
|
|
type_less := sym_table^[type_table^[i]].pname^<
|
|
sym_table^[type_table^[j]].pname^
|
|
end(*type_less*);
|
|
|
|
{$ifndef fpc}{$F+}{$endif}
|
|
procedure type_swap ( i, j : Integer );
|
|
{$ifndef fpc}{$F-}{$endif}
|
|
var x : Integer;
|
|
begin
|
|
x := type_table^[i];
|
|
type_table^[i] := type_table^[j];
|
|
type_table^[j] := x;
|
|
end(*type_swap*);
|
|
|
|
procedure sort_types;
|
|
var i, j, count : Integer;
|
|
begin
|
|
(* sort: *)
|
|
quicksort(1, n_types, {$ifdef fpc}@{$endif}type_less,
|
|
{$ifdef fpc}@{$endif}type_swap);
|
|
(* eliminate dups: *)
|
|
i := 1; j := 1; count := 0;
|
|
while i<=n_types do
|
|
begin
|
|
if i<>j then type_table^[j] := type_table^[i];
|
|
while (i<n_types) and (type_table^[i+1]=type_table^[i]) do
|
|
begin
|
|
inc(i); inc(count);
|
|
end;
|
|
inc(i); inc(j);
|
|
end;
|
|
dec(n_types, count);
|
|
end(*sort_types*);
|
|
|
|
function search_type ( symbol : String ) : Boolean;
|
|
var l, r, k : Integer;
|
|
begin
|
|
(* binary search: *)
|
|
l := 1; r := n_types;
|
|
k := l + (r-l) div 2;
|
|
while (l<r) and (sym_table^[type_table^[k]].pname^<>symbol) do
|
|
begin
|
|
if sym_table^[type_table^[k]].pname^<symbol then
|
|
l := succ(k)
|
|
else
|
|
r := pred(k);
|
|
k := l + (r-l) div 2;
|
|
end;
|
|
search_type := (k<=n_types) and (sym_table^[type_table^[k]].pname^=symbol);
|
|
end(*search_type*);
|
|
|
|
(* Precedence table routines: *)
|
|
|
|
function new_prec_level ( prec_type : PrecType ) : Integer;
|
|
begin
|
|
inc(n_prec);
|
|
if n_prec>max_prec then fatal(prec_table_overflow);
|
|
prec_table^[n_prec] := prec_type;
|
|
new_prec_level := n_prec;
|
|
end(*new_prec_level*);
|
|
|
|
(* State table: *)
|
|
|
|
procedure new_state;
|
|
begin
|
|
inc(n_states);
|
|
if n_states>max_states then fatal(state_table_overflow);
|
|
state_table^[n_states-1].item_lo := n_items+1;
|
|
end(*new_state*);
|
|
|
|
procedure add_item ( rule_no, pos_no : Integer );
|
|
begin
|
|
inc(n_items);
|
|
if n_items>max_items then fatal(item_table_overflow);
|
|
item_table^[n_items].rule_no := rule_no;
|
|
item_table^[n_items].pos_no := pos_no;
|
|
item_table^[n_items].next := 0;
|
|
end(*add_item*);
|
|
|
|
function add_state : Integer;
|
|
function state_key ( s : Integer ) : Integer;
|
|
(* determines a hash key for state s *)
|
|
const max_key = 4001;
|
|
(* should be prime number s.t. hash keys are distributed
|
|
evenly *)
|
|
var i, k : Integer;
|
|
begin
|
|
with state_table^[s] do
|
|
begin
|
|
k := 0;
|
|
for i := item_lo to item_hi do
|
|
with item_table^[i] do
|
|
inc(k, rule_no+pos_no);
|
|
state_key := k mod max_key;
|
|
end;
|
|
end(*state_key*);
|
|
function search_state ( s, lo, hi : Integer; var t : Integer ) : Boolean;
|
|
(* searches the range lo..hi in the state table for a state with the
|
|
same kernel items as s; returns true if found, and then the
|
|
corresponding state number in t *)
|
|
function eq_items(s, t : Integer) : Boolean;
|
|
(* compares kernel item sets of states s and t *)
|
|
var i, i_s, i_t : Integer;
|
|
begin
|
|
if n_state_items(s)<>n_state_items(t) then
|
|
eq_items := false
|
|
else
|
|
begin
|
|
i_s := state_table^[s].item_lo;
|
|
i_t := state_table^[t].item_lo;
|
|
for i := 0 to n_state_items(s)-1 do
|
|
if (item_table^[i_s+i].rule_no<>item_table^[i_t+i].rule_no) or
|
|
(item_table^[i_s+i].pos_no<>item_table^[i_t+i].pos_no) then
|
|
begin
|
|
eq_items := false;
|
|
exit;
|
|
end;
|
|
eq_items := true;
|
|
end
|
|
end(*eq_items*);
|
|
var t1 : Integer;
|
|
begin
|
|
with state_table^[s] do
|
|
for t1 := lo to hi do
|
|
if (key=state_table^[t1].key) and
|
|
eq_items(s, t1) then
|
|
begin
|
|
search_state := true;
|
|
t := t1;
|
|
exit;
|
|
end;
|
|
search_state := false;
|
|
end(*search_state*);
|
|
var s : Integer;
|
|
begin
|
|
with state_table^[n_states-1] do
|
|
begin
|
|
item_hi := n_items;
|
|
key := state_key(n_states-1);
|
|
if search_state(n_states-1, 0, n_states-2, s) then
|
|
begin
|
|
n_items := item_lo;
|
|
dec(n_states);
|
|
add_state := s;
|
|
end
|
|
else
|
|
add_state := n_states-1;
|
|
end;
|
|
end(*add_state*);
|
|
|
|
procedure start_trans;
|
|
begin
|
|
state_table^[act_state].trans_lo := n_trans+1;
|
|
end(*start_trans*);
|
|
|
|
procedure add_trans ( sym, next_state : Integer );
|
|
begin
|
|
inc(n_trans);
|
|
if n_trans>max_trans then fatal(trans_table_overflow);
|
|
trans_table^[n_trans].sym := sym;
|
|
trans_table^[n_trans].next_state := next_state;
|
|
end(*add_trans*);
|
|
|
|
procedure end_trans;
|
|
begin
|
|
state_table^[act_state].trans_hi := n_trans;
|
|
end(*end_trans*);
|
|
|
|
procedure start_redns;
|
|
begin
|
|
state_table^[act_state].redns_lo := n_redns+1;
|
|
end(*start_redns*);
|
|
|
|
procedure add_redn ( symset : IntSetPtr; rule_no : Integer );
|
|
begin
|
|
inc(n_redns);
|
|
if n_redns>max_redns then fatal(redn_table_overflow);
|
|
redn_table^[n_redns].symset := symset;
|
|
redn_table^[n_redns].rule_no := rule_no;
|
|
end(*add_redn*);
|
|
|
|
procedure end_redns;
|
|
begin
|
|
state_table^[act_state].redns_hi := n_redns;
|
|
end(*end_redns*);
|
|
|
|
function n_state_items ( s : Integer ) : Integer;
|
|
begin
|
|
with state_table^[s] do
|
|
n_state_items := item_hi-item_lo+1
|
|
end(*n_state_items*);
|
|
|
|
function n_state_trans ( s : Integer ) : Integer;
|
|
begin
|
|
with state_table^[s] do
|
|
n_state_trans := trans_hi-trans_lo+1
|
|
end(*n_state_trans*);
|
|
|
|
function n_state_redns ( s : Integer ) : Integer;
|
|
begin
|
|
with state_table^[s] do
|
|
n_state_redns := redns_hi-redns_lo+1
|
|
end(*n_state_redns*);
|
|
|
|
function find_item( s : Integer; rule_no, pos_no : Integer ) : Integer;
|
|
var i : Integer;
|
|
begin
|
|
with state_table^[s] do
|
|
for i := item_lo to item_hi do
|
|
if (item_table^[i].rule_no=rule_no) and
|
|
(item_table^[i].pos_no=pos_no) then
|
|
begin
|
|
find_item := i;
|
|
exit;
|
|
end;
|
|
find_item := 0;
|
|
end(*find_item*);
|
|
|
|
(* Item set routines: *)
|
|
|
|
procedure empty_item_set ( var item_set : ItemSet );
|
|
begin
|
|
item_set.n_items := 0;
|
|
end(*empty_item_set*);
|
|
|
|
procedure include_item_set ( var item_set : ItemSet;
|
|
rule_no, pos_no : Integer);
|
|
begin
|
|
with item_set do
|
|
begin
|
|
inc(n_items);
|
|
if n_items>max_set_items then fatal(item_table_overflow);
|
|
item[n_items].rule_no := rule_no;
|
|
item[n_items].pos_no := pos_no;
|
|
end;
|
|
end(*include_item_set*);
|
|
|
|
procedure get_item_set ( s : Integer; var item_set : ItemSet);
|
|
begin
|
|
with state_table^[s], item_set do
|
|
begin
|
|
n_items := n_state_items(s);
|
|
move(item_table^[item_lo], item, n_items*sizeOf(ItemRec));
|
|
end
|
|
end(*get_item_set*);
|
|
|
|
procedure closure ( var item_set : ItemSet );
|
|
var i, j : Integer;
|
|
nt_syms0, nt_syms : IntSet;
|
|
begin
|
|
with item_set do
|
|
begin
|
|
(* get the nonterminals at current positions in items: *)
|
|
empty(nt_syms0);
|
|
for i := 1 to n_items do
|
|
with item[i], rule_table^[rule_no]^ do
|
|
if (pos_no<=rhs_len) and (rhs_sym[pos_no]<0) then
|
|
include(nt_syms0, rhs_sym[pos_no]);
|
|
nt_syms := nt_syms0;
|
|
(* add closure symbols: *)
|
|
for i := 1 to size(nt_syms0) do
|
|
setunion(nt_syms, closure_table^[-nt_syms0[i]]^);
|
|
(* add the nonkernel items for the nonterminal symbols: *)
|
|
for i := 1 to size(nt_syms) do
|
|
with rule_offs^[-nt_syms[i]] do
|
|
for j := rule_lo to rule_hi do
|
|
include_item_set(item_set, rule_no^[j], 1);
|
|
end;
|
|
end(*closure*);
|
|
|
|
var sort_items : ItemSet;
|
|
|
|
(* comparison and swap routines for sort_item_set: *)
|
|
|
|
{$ifndef fpc}{$F+}{$endif}
|
|
function items_less ( i, j : Integer ) : Boolean;
|
|
{$ifndef fpc}{$F-}{$endif}
|
|
begin
|
|
with sort_items do
|
|
if item[i].pos_no=item[j].pos_no then
|
|
items_less := item[i].rule_no<item[j].rule_no
|
|
else
|
|
items_less := item[i].pos_no>item[j].pos_no
|
|
end(*items_less*);
|
|
|
|
{$ifndef fpc}{$F+}{$endif}
|
|
procedure items_swap ( i, j : Integer );
|
|
{$ifndef fpc}{$F-}{$endif}
|
|
var x : ItemRec;
|
|
begin
|
|
with sort_items do
|
|
begin
|
|
x := item[i]; item[i] := item[j]; item[j] := x;
|
|
end
|
|
end(*items_swap*);
|
|
|
|
procedure sort_item_set ( var item_set : ItemSet );
|
|
begin
|
|
sort_items := item_set;
|
|
quicksort(1, sort_items.n_items, {$ifdef fpc}@{$endif}items_less,
|
|
{$ifdef fpc}@{$endif}items_swap);
|
|
item_set := sort_items;
|
|
end(*sort_item_set*);
|
|
|
|
var i : Integer;
|
|
|
|
begin
|
|
|
|
verbose := false;
|
|
debug := false;
|
|
startnt := 0;
|
|
|
|
n_nts := 1;
|
|
n_lits := 257;
|
|
n_rules := 0;
|
|
n_types := 0;
|
|
n_prec := 0;
|
|
n_states := 0;
|
|
n_items := 0;
|
|
n_trans := 0;
|
|
n_redns := 0;
|
|
|
|
(* allocate tables: *)
|
|
|
|
new(sym_table);
|
|
new(sym_key);
|
|
new(rule_table);
|
|
new(rule_no);
|
|
new(rule_offs);
|
|
new(type_table);
|
|
new(sym_type);
|
|
new(prec_table);
|
|
new(sym_prec);
|
|
new(rule_prec);
|
|
new(closure_table);
|
|
new(first_set_table);
|
|
new(nullable);
|
|
new(state_table);
|
|
new(item_table);
|
|
new(trans_table);
|
|
new(redn_table);
|
|
new(lookahead_table);
|
|
new(prop_table);
|
|
|
|
(* initialize symbol table: *)
|
|
|
|
for i := 1 to max_keys do
|
|
with sym_table^[i] do
|
|
begin
|
|
pname := nil;
|
|
deff := false;
|
|
end;
|
|
|
|
(* enter predefined error symbol into symbol table: *)
|
|
|
|
def_key(get_key('error'), 256);
|
|
|
|
(* initialize type and precedence tables: *)
|
|
|
|
for i := -max_nts to max_lits-1 do sym_type^[i] := 0;
|
|
for i := 0 to max_lits-1 do sym_prec^[i] := 0;
|
|
for i := 1 to max_rules do rule_prec^[i] := 0;
|
|
|
|
end(*YaccTables*).
|