#
# File: id.k3
# Handles identifiers
#
# Copyright 2005, University of Nijmegen.
#
# 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 Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# CVS ID: "$Id: id.k3,v 1.35 2005/10/26 13:36:55 marcs Exp $"
#
MODULE id =
	EOS_ID DEFAULT_REGEXP_ID TEXT_AFFIX_ID INT_AFFIX_ID START_NONT
	ID_INFOS{}
	ANONYMOUS_COUNT
	LEX_NONT_COUNT
        IS_ANON_GROUP_NONT{}
	NONT_TO_INFO{}		NONT_COUNT
	AFFIX_TO_ID{}		AFFIX_COUNT
	AFFIX_TERM_TO_ID{}	AFFIX_TERM_COUNT
	AFFIX_NONT_TO_ID{}	AFFIX_NONT_COUNT
	AFFIX_INT_TO_ID{}	AFFIX_INT_COUNT
	AFFIX_TEXT_TO_ID{}	AFFIX_TEXT_COUNT
	TERM_TO_ID{}		TERM_COUNT
	SKIP_TO_ID{}		SKIP_COUNT
	MATCH_TO_ID{}		MATCH_COUNT
	TEXT_TO_ID{}		TEXT_COUNT
	INTERNAL_INSTANCE_COUNT.

DEFINES ARITY,

	NONTERMINAL,
        FUNCTION assert valid >NONTERMINAL,
        TEST is anonymous group >NONTERMINAL,
        ACTION mark >NONTERMINAL as anonymous group,

	RULENR,
	WEIGHT,

	ACTION initialize identification info (>ID),
	ACTION create anonymous id (ID>),
	ACTION create predefined ids,
        ACTION create start nonterminal,

	ACTION create internal instance (INT>),
	ACTION create duplicate internal id with instance (>ID, ID1>, INT>),

	FUNCTION get start nonterminal (NONTERMINAL>),
	FUNCTION get text affix (ID>),
	FUNCTION get integer affix (ID>),
	FUNCTION get eos terminal (ID>),
	FUNCTION get default regexp (ID>),

	ACTION mark id as anonymous affix nonterminal (>ID),
	ACTION mark id as anonymous integer affix (>ID),
	ACTION mark id as anonymous text affix (>ID),
	ACTION mark id as invalid affix (>ID),
	ACTION mark id as unknown affix (>ID),
	PRED mark id as unknown affix nonterminal (>ID),
	PRED mark id as untyped affix nonterminal (>ID),
	PRED mark id as set affix nonterminal (>ID),
	PRED mark id as integer affix (>ID),
	PRED mark id as text affix (>ID),

        ACTION create dummy nonterminal (NONTERMINAL>),
	ACTION mark id as lexicon nonterminal (>ID, >ARITY, NONTERMINAL>),
	ACTION mark id as anonymous nonterminal (>ID, >ARITY, NONTERMINAL>),
	ACTION mark id as syntax nonterminal (>ID, >ARITY, NONTERMINAL>),
	ACTION mark id as syntax terminal (>ID),
	ACTION mark id as regexp match (>ID),
	ACTION mark id as regexp skip (>ID),
	ACTION mark id as text constant (>ID),

	TEST id is user variable (>ID),
        TEST id is user affix terminal (>ID),
	TEST id is affix nonterminal (>ID),
	TEST id is anonymous affix (>ID),
	TEST id is lexicon affix (>ID),
	TEST id is lexicon affix terminal (>ID),
	TEST id is set affix (>ID),
	TEST id is text affix (>ID),
	TEST id is integer affix (>ID),
	TEST id is untyped affix (>ID),
	TEST id is invalid affix (>ID),
	TEST id is anonymous (>ID),

	TEST is lexicon nonterminal (>NONTERMINAL),
	TEST is user nonterminal (>NONTERMINAL),
	TEST is anonymous nonterminal (>NONTERMINAL),
	TEST is start nonterminal (>NONTERMINAL),
        TEST is dummy nonterminal (>NONTERMINAL),

	FUNCTION get number of affixes (INT>),
	FUNCTION get number of affix terminals (INT>),
	FUNCTION get number of affix nonterminals (INT>),
	FUNCTION get number of integer affixes (INT>),
	FUNCTION get number of text affixes (INT>),
	FUNCTION get number of lexicon nonterminals (INT>),
	FUNCTION get number of syntax nonterminals (INT>),
	FUNCTION get number of syntax terminals (INT>),
	FUNCTION get number of regexp matches (INT>),
	FUNCTION get number of regexp skips (INT>),
	FUNCTION get number of text constants (INT>),

	FUNCTION convert id to affix (>ID, INT>),
	FUNCTION convert id to syntax terminal (>ID, INT>),
	FUNCTION convert id to regexp match (>ID, INT>),
	FUNCTION convert id to regexp skip (>ID, INT>),
	FUNCTION convert id to text constant (>ID, INT>),

	FUNCTION convert affix to id (>INT, ID>),
	FUNCTION convert text affix to id (>INT, ID>),
	FUNCTION convert integer affix to id (>INT, ID>),
	FUNCTION convert affix terminal to id (>INT, ID>),
	FUNCTION convert affix nonterminal to id (>INT, ID>),
	FUNCTION convert syntax terminal to id (>INT, ID>),
	FUNCTION convert regexp match to id (>INT, ID>),
	FUNCTION convert regexp skip to id (>INT, ID>),
	FUNCTION convert text constant to id (>INT, ID>),

	FUNCTION convert >INT to NONTERMINAL>,
	FUNCTION convert >NONTERMINAL to INT>,
        FUNCTION convert >NONTERMINAL to number INT>,
	FUNCTION convert >NONTERMINAL to ID> and ARITY>,
	FUNCTION convert >NONTERMINAL to TEXT>,
	FUNCTION convert >ARITY to INT>,
	FUNCTION convert >ARITY to TEXT>,
        FUNCTION convert >INT to ARITY>,
	FUNCTION convert >RULENR to TEXT>,

	FUNCTION get pragmats (>NONTERMINAL, PRAGMATS>),
        FUNCTION get arity (>NONTERMINAL, ARITY>),
	FUNCTION get set info (>ID, SET>),
	FUNCTION get affix weight (>ID, WEIGHT>),
	TEST     get affix rule number (>ID, RULENR>),
	FUNCTION get affix number (>ID, INT>),
	ACTION store pragmats (>NONTERMINAL, >PRAGMATS),
	ACTION store set info (>ID, >SET),
	ACTION store affix weight (>ID, >WEIGHT),
	ACTION store affix rule number (>ID, >RULENR),

	ACTION mark unknown affix ids,
	ACTION warn for hybrid ids,
	ACTION dump ids.

USES globals, set, io, rule, properties, textstorage.

INTERNAL_INSTANCE_COUNT,
NONT_COUNT,
LEX_NONT_COUNT,
ANONYMOUS_COUNT = INT.

EOS_ID,
DEFAULT_REGEXP_ID,
TEXT_AFFIX_ID,
INT_AFFIX_ID = ID.
START_NONT = NONTERMINAL.

### For each ID we store its usages.

ID_INFOS :: ID_INFO.
ID_INFO  :: FIRST and SECOND and OTHER.

### First level (syntax)

# At the first level, we have:
# - nonterminal classes (different arity, same id)
# - syntax terminals
# - regexp matches
# - regexp skips
# Ids of nonterminal classes and terminals/skips/matches are disjoint due
# to double qoutes around identifiers for terminals/skips/matches.

FIRST :: empty;
         TERMINAL and SKIP and MATCH;
         NONT_CLASSES.

NONT_CLASSES :: NONTERMINAL with ARITY and NONT_CLASSES;
                nil.

NONTERMINAL :: nonterminal INT.
ARITY       :: arity INT.
TERMINAL    :: terminal INT.
SKIP        :: skip INT.
MATCH       :: match INT.

FUNCTION empty (TERMINAL>):
  [terminal (-1) -> TERMINAL].

TEST is empty (>TERMINAL):
  [TERMINAL -> terminal (-1)].

FUNCTION empty (SKIP>):
  [skip (-1) -> SKIP].

TEST is empty (>SKIP>):
  [SKIP -> skip (-1)].

FUNCTION empty (MATCH>):
  [match (-1) -> MATCH].

TEST is empty (>MATCH):
  [MATCH -> match (-1)].

### Second level (affix)

# At the second level we have affixes with the following types:
# - definition type: user/lexicon/anonymous
# - domain type: set/int/text
# - categorie: /nonterminal/terminal

SECOND :: empty;
          unknown affix;
          unknown affix nonterminal;
          affix INT with DEFTYPE and DOMTYPE and RULENR.

DEFTYPE :: anonymous;
           user;
           lexicon;
           property dummy.

DOMTYPE :: erroneous;
           untyped nonterminal;
           set nonterminal with WEIGHT and SET;
           set terminal with WEIGHT and SET;
           integer;
           text.

WEIGHT :: INT.
RULENR :: INT.

FUNCTION undefined (RULENR>):
  [-1 -> RULENR].

TEST is defined (>RULENR):
  [RULENR -> INT],
    greatereq (INT, 0).

FUNCTION untyped (DOMTYPE>):
  [untyped nonterminal -> DOMTYPE].

FUNCTION empty set nonterminal domain (DOMTYPE>):
  empty (WEIGHT),
    empty (SET),
    [set nonterminal with WEIGHT and SET -> DOMTYPE].

FUNCTION empty set terminal domain (DOMTYPE>):
  empty (WEIGHT),
    empty (SET),
    [set terminal with WEIGHT and SET -> DOMTYPE].

FUNCTION empty (WEIGHT>):
  [0 -> WEIGHT].

TEST is empty (>WEIGHT):
  [WEIGHT -> 0].

### Other usages (text constants)

OTHER :: text constant INT;
         empty.

### Array counters (point to objects)

AFFIX_COUNT,
AFFIX_TERM_COUNT,
AFFIX_NONT_COUNT,
AFFIX_INT_COUNT,
AFFIX_TEXT_COUNT,
TEXT_COUNT,
TERM_COUNT,
SKIP_COUNT,
MATCH_COUNT  = INT.

### Base types for arrays

AFFIX_TO_ID,
AFFIX_TERM_TO_ID,
AFFIX_NONT_TO_ID,
AFFIX_INT_TO_ID,
AFFIX_TEXT_TO_ID,
TERM_TO_ID,
SKIP_TO_ID,
MATCH_TO_ID,
TEXT_TO_ID :: ID.

NONT_TO_INFO :: NONT_INFO.
NONT_INFO    :: ID with ARITY and DEFTYPE and PRAGMATS.

#############################
#                           #
#   Module initialization   #
#                           #
#############################

PRELUDE init id:
  [0 -> ANONYMOUS_COUNT],
  [0 -> LEX_NONT_COUNT],
  [0 -> NONT_COUNT],
  [0 -> AFFIX_COUNT],
  [0 -> AFFIX_TERM_COUNT],
  [0 -> AFFIX_NONT_COUNT],
  [0 -> AFFIX_INT_COUNT],
  [0 -> AFFIX_TEXT_COUNT],
  [0 -> TERM_COUNT],
  [0 -> SKIP_COUNT],
  [0 -> MATCH_COUNT],
  [0 -> TEXT_COUNT],
  [0 -> INTERNAL_INSTANCE_COUNT].

###########
#         #
#   Ids   #
#         #
###########

ACTION initialize identification info (>ID):
  [empty and empty and empty -> ID_INFOS{ID}].

# Ids are created for system objects (anonymous ids) and user defined
# objects. These categories are disjoint, since user identifiers may
# not contain digits.

ACTION create anonymous id (ID>):
  convert ANONYMOUS_COUNT to TEXT,
    [ANONYMOUS_COUNT + 1 -> ANONYMOUS_COUNT],
    create new id ("_a_" + TEXT, ID),
    initialize identification info (ID).

TEST id is anonymous (>ID):
  convert id to name (ID, TEXT),
    extract (TEXT, 0, 3, TEXT2),
    [TEXT2 -> "_a_"].

# Used by making affixes in calls derived parameters:
ACTION create internal instance (INT>):
  [INTERNAL_INSTANCE_COUNT + 1 -> INTERNAL_INSTANCE_COUNT],
  [0 - INTERNAL_INSTANCE_COUNT -> INT].

ACTION create duplicate internal id with instance (>ID, ID1>, INT>):
  id is user variable (ID),
    [ID -> ID1],
    create internal instance (INT);
  id is affix nonterminal (ID),
    [ID -> ID1],
    create internal instance (INT);
  id is anonymous affix (ID),
    [ID -> ID1],
    create internal instance (INT);
  id is lexicon affix (ID),
    [ID -> ID1],
    create internal instance (INT);
#  id is lexicon affix terminal (ID),
  id is set affix (ID),
    create anonymous id (ID1),
    (mark id as set affix nonterminal (ID1),
       get set info (ID, SET),
       store set info (ID1, SET),
       create internal instance (INT);
     ?);
  id is text affix (ID),
    create anonymous id (ID1),
    (mark id as text affix (ID1),
       create internal instance (INT);
     ?);
  id is integer affix (ID),
    create anonymous id (ID1),
    (mark id as integer affix (ID1),
       create internal instance (INT);
     ?);
  id is untyped affix (ID),
    [ID -> ID1],
    create internal instance (INT);
  convert id to name (ID, TEXT),
    system error ("Can't duplicate ID \""+TEXT+"\"!"),
    ?.

#---
# TODO: 'create predefined ids' from 'init id'. Now invoked before
# reading lexicon, in order to prevent numbering problems within lexgen.
# "create start nonterminal" s called thereafter, to prevent a
# nonterminal numbering problem with lexgen.

ACTION create predefined ids:
  create eos terminal (EOS_ID),
    create default regexp (DEFAULT_REGEXP_ID),
    create text affix (TEXT_AFFIX_ID),
    create integer affix (INT_AFFIX_ID).

ACTION create start nonterminal:
  create start nonterminal (START_NONT).
#---

ACTION create start nonterminal (NONTERMINAL>):
  create new id ("$start$", ID),
    initialize identification info (ID),
    mark id as anonymous nonterminal (ID, arity 0, NONTERMINAL),
    [NONTERMINAL -> START_NONT].

# The user cannot define the eos id herself because user terminals
# are enclosed between double quotes.

ACTION create eos terminal (ID>):
  create new id ("$end of sentence$", ID),
    initialize identification info (ID),
    mark id as syntax terminal (ID).

ACTION create default regexp (ID>):
  create new id ("\".*\"", ID),
    initialize identification info (ID).  # marked by parser as skip or match

ACTION create text affix (ID>):
  create new id ("TEXT", ID),
    initialize identification info (ID),
    mark id as anonymous text affix (ID).

ACTION create integer affix (ID>):
  create new id ("INT", ID),
    initialize identification info (ID),
    mark id as anonymous integer affix (ID).

FUNCTION get eos terminal (ID>):
  [EOS_ID -> ID].

FUNCTION get default regexp (ID>):
  [DEFAULT_REGEXP_ID -> ID].

FUNCTION get text affix (ID>):
  [TEXT_AFFIX_ID -> ID].

FUNCTION get integer affix (ID>):
  [INT_AFFIX_ID -> ID].

FUNCTION get start nonterminal (NONTERMINAL>):
  [START_NONT -> NONTERMINAL].

######################
#                    #
#   Marking of ids   #
#                    #
######################

### Untyped affixes

# Untyped affix nonterminals result from chain affix rules, e.g. `A :: B.',
# with unknown type. Therefore, an untyped affix nonterminal is created.

PRED mark id as untyped affix nonterminal (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([SECOND -> empty],
       create untyped affix nonterminal (user, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [SECOND -> unknown affix],
       create untyped affix nonterminal (user, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [SECOND -> unknown affix nonterminal],
       create untyped affix nonterminal (user, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     is affix nonterminal (SECOND)).

### Anonymous affixes

# Anonymous affix nonterminals result from set denotations, and from
# collecting specifications. In the latter case, the type of the rule
# is not known yet, and therefore an untyped affix nonterminal is created.

ACTION mark id as anonymous affix nonterminal (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([SECOND -> empty],
       create untyped affix nonterminal (anonymous, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     ?).

ACTION mark id as anonymous integer affix (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([SECOND -> empty],
       create integer affix (anonymous, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     ?).

ACTION mark id as anonymous text affix (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([SECOND -> empty],
       create text affix (anonymous, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     ?).

### Unknown affixes

ACTION mark id as unknown affix (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([SECOND -> empty],
       [unknown affix -> SECOND],
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     +).

PRED mark id as unknown affix nonterminal (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([SECOND -> empty],
       [unknown affix nonterminal -> SECOND],
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [SECOND -> unknown affix],
       [unknown affix nonterminal -> SECOND],
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [SECOND -> unknown affix nonterminal];
     is affix nonterminal (SECOND)).

### Set affixes

PRED mark id as set affix nonterminal (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([SECOND -> empty],
       create set affix nonterminal (user, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [SECOND -> unknown affix],
       create set affix nonterminal (user, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [SECOND -> unknown affix nonterminal],
       create set affix nonterminal (user, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
       (mark as set affix nonterminal (DOMTYPE),
          [affix INT with DEFTYPE and DOMTYPE and RULENR -> SECOND],
          [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
        -);
     ?).

TEST mark as set affix nonterminal (>DOMTYPE>):
  [DOMTYPE -> untyped nonterminal],
    empty set nonterminal domain (DOMTYPE);
  [DOMTYPE -> set nonterminal with WEIGHT and SET].

### Text affixes

PRED mark id as text affix (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([SECOND -> empty],
       create text affix (user, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [SECOND -> unknown affix],
       create text affix (user, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [SECOND -> unknown affix nonterminal],
       create text affix (user, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
       (mark as text affix (DOMTYPE),
          [affix INT with DEFTYPE and DOMTYPE and RULENR -> SECOND],
          [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
        -);
     ?).

TEST mark as text affix (>DOMTYPE>):
  [DOMTYPE -> untyped nonterminal],
    [text -> DOMTYPE];
  [DOMTYPE -> text].

### Integer affixes

PRED mark id as integer affix (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([SECOND -> empty],
       create integer affix (user, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [SECOND -> unknown affix],
       create integer affix (user, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [SECOND -> unknown affix nonterminal],
       create integer affix (user, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
       (mark as integer affix (DOMTYPE),
          [affix INT with DEFTYPE and DOMTYPE and RULENR -> SECOND],
          [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
        -);
     ?).

TEST mark as integer affix (>DOMTYPE>):
  [DOMTYPE -> untyped nonterminal],
    [integer -> DOMTYPE];
  [DOMTYPE -> integer].

### Invalid affixes

ACTION mark id as invalid affix (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    mark as invalid affix (SECOND),
    [FIRST and SECOND and OTHER -> ID_INFOS{ID}].

FUNCTION mark as invalid affix (>SECOND>):
  [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
    [erroneous -> DOMTYPE],
    [affix INT with DEFTYPE and DOMTYPE and RULENR -> SECOND];
  ?.

### Nonterminals

ACTION mark id as lexicon nonterminal (>ID, >ARITY, NONTERMINAL>):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([FIRST -> empty],
       enter lexicon nonterminal (ID, ARITY, nil|NONT_CLASSES, NONTERMINAL),
       [NONT_CLASSES -> FIRST],
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [FIRST -> NONT_CLASSES],
       enter lexicon nonterminal (ID, ARITY, NONT_CLASSES, NONTERMINAL),
       [NONT_CLASSES -> FIRST],
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     ?).

ACTION mark id as syntax nonterminal (>ID, >ARITY, NONTERMINAL>):
  mark id as nonterminal (ID, ARITY, user, NONTERMINAL).

ACTION mark id as anonymous nonterminal (>ID, >ARITY, NONTERMINAL>):
  mark id as nonterminal (ID, ARITY, anonymous, NONTERMINAL).

ACTION mark id as nonterminal (>ID, >ARITY, >DEFTYPE, NONTERMINAL>):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([FIRST -> empty],
       enter nonterminal (ID, ARITY, DEFTYPE, nil|NONT_CLASSES, NONTERMINAL),
       [NONT_CLASSES -> FIRST],
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [FIRST -> NONT_CLASSES],
       enter nonterminal (ID, ARITY, DEFTYPE, NONT_CLASSES, NONTERMINAL),
       [NONT_CLASSES -> FIRST],
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     ?).

IS_ANON_GROUP_NONT = BOOL.

ACTION mark >NONTERMINAL as anonymous group:
  [NONTERMINAL -> nonterminal INT],
    [true -> IS_ANON_GROUP_NONT{INT}].

ACTION init anonymous group >NONTERMINAL admin:
  [NONTERMINAL -> nonterminal INT],
    [false -> IS_ANON_GROUP_NONT{INT}].

TEST is anonymous group >NONTERMINAL:
  [NONTERMINAL -> nonterminal INT],
    [IS_ANON_GROUP_NONT{INT} -> true].


### Syntax terminals

ACTION mark id as syntax terminal (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([FIRST -> empty],
       create syntax terminal (ID, TERMINAL),
       empty (SKIP),
       empty (MATCH),
       [TERMINAL and SKIP and MATCH -> FIRST],
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [FIRST -> TERMINAL and SKIP and MATCH],
       (is empty (TERMINAL),
          create syntax terminal (ID, TERMINAL),
          [TERMINAL and SKIP and MATCH -> FIRST],
          [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
        +);
     ?).

### Regexp matches

ACTION mark id as regexp match (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([FIRST -> empty],
       create regexp match (ID, MATCH),
       empty (TERMINAL),
       empty (SKIP),
       [TERMINAL and SKIP and MATCH -> FIRST],
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [FIRST -> TERMINAL and SKIP and MATCH],
       (is empty (MATCH),
          create regexp match (ID, MATCH),
          [TERMINAL and SKIP and MATCH -> FIRST],
          [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
        +);
     ?).

### Regexp skips

ACTION mark id as regexp skip (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([FIRST -> empty],
       create regexp skip (ID, SKIP),
       empty (TERMINAL),
       empty (MATCH),
       [TERMINAL and SKIP and MATCH -> FIRST],
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [FIRST -> TERMINAL and SKIP and MATCH],
       (is empty (SKIP),
          create regexp skip (ID, SKIP),
          [TERMINAL and SKIP and MATCH -> FIRST],
          [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
        +);
     ?).

### Text constants

ACTION mark id as text constant (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([OTHER -> empty],
       create text constant (ID, OTHER),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     +).

###########################
#                         #
#   Creation of objects   #
#                         #
###########################

### Untyped affixes

ACTION create untyped affix nonterminal (>DEFTYPE, >ID, SECOND>):
  untyped (DOMTYPE),
    undefined (RULENR),
    [affix AFFIX_COUNT with DEFTYPE and DOMTYPE and RULENR -> SECOND],
    [ID -> AFFIX_NONT_TO_ID{AFFIX_NONT_COUNT}],
    [ID -> AFFIX_TO_ID{AFFIX_COUNT}],
    [AFFIX_NONT_COUNT + 1 -> AFFIX_NONT_COUNT],
    [AFFIX_COUNT + 1 -> AFFIX_COUNT].

### Set affixes

ACTION create set affix nonterminal (>DEFTYPE, >ID, SECOND>):
  empty set nonterminal domain (DOMTYPE),
    undefined (RULENR),
    [affix AFFIX_COUNT with DEFTYPE and DOMTYPE and RULENR -> SECOND],
    [ID -> AFFIX_NONT_TO_ID{AFFIX_NONT_COUNT}],
    [ID -> AFFIX_TO_ID{AFFIX_COUNT}],
    [AFFIX_NONT_COUNT + 1 -> AFFIX_NONT_COUNT],
    [AFFIX_COUNT + 1 -> AFFIX_COUNT].

ACTION create set affix terminal (>DEFTYPE, >ID, SECOND>):
  empty set terminal domain (DOMTYPE),
    undefined (RULENR),
    [affix AFFIX_COUNT with DEFTYPE and DOMTYPE and RULENR -> SECOND],
    [ID -> AFFIX_TERM_TO_ID{AFFIX_TERM_COUNT}],
    [ID -> AFFIX_TO_ID{AFFIX_COUNT}],
    [AFFIX_TERM_COUNT + 1 -> AFFIX_TERM_COUNT],
    [AFFIX_COUNT + 1 -> AFFIX_COUNT].

### Text affixes

ACTION create text affix (>DEFTYPE, >ID, SECOND>):
  [text -> DOMTYPE],
    undefined (RULENR),
    [affix AFFIX_COUNT with DEFTYPE and DOMTYPE and RULENR -> SECOND],
    [ID -> AFFIX_TEXT_TO_ID{AFFIX_TEXT_COUNT}],
    [ID -> AFFIX_TO_ID{AFFIX_COUNT}],
    [ID -> AFFIX_NONT_TO_ID{AFFIX_NONT_COUNT}],
    [AFFIX_TEXT_COUNT + 1 -> AFFIX_TEXT_COUNT],
    [AFFIX_COUNT + 1 -> AFFIX_COUNT],
    [AFFIX_NONT_COUNT + 1 -> AFFIX_NONT_COUNT].

### Integer affixes

ACTION create integer affix (>DEFTYPE, >ID, SECOND>):
  [integer -> DOMTYPE],
    undefined (RULENR),
    [affix AFFIX_COUNT with DEFTYPE and DOMTYPE and RULENR -> SECOND],
    [ID -> AFFIX_INT_TO_ID{AFFIX_INT_COUNT}],
    [ID -> AFFIX_TO_ID{AFFIX_COUNT}],
    [ID -> AFFIX_NONT_TO_ID{AFFIX_NONT_COUNT}],
    [AFFIX_INT_COUNT + 1 -> AFFIX_INT_COUNT],
    [AFFIX_COUNT + 1 -> AFFIX_COUNT],
    [AFFIX_NONT_COUNT + 1 -> AFFIX_NONT_COUNT].

### Syntax terminals

ACTION create syntax terminal (>ID, TERMINAL>):
  [ID -> TERM_TO_ID{TERM_COUNT}],
    [terminal TERM_COUNT -> TERMINAL],
    [TERM_COUNT + 1 -> TERM_COUNT].

### Regexp matches

ACTION create regexp match (>ID, MATCH>):
  [ID -> MATCH_TO_ID{MATCH_COUNT}],
    [match MATCH_COUNT -> MATCH],
    [MATCH_COUNT + 1 -> MATCH_COUNT].

### Regexp skips

ACTION create regexp skip (>ID, SKIP>):
  [ID -> SKIP_TO_ID{SKIP_COUNT}],
    [skip SKIP_COUNT -> SKIP],
    [SKIP_COUNT + 1 -> SKIP_COUNT].

### Text constants

ACTION create text constant (>ID, OTHER>):
  [text constant TEXT_COUNT -> OTHER],
    [ID -> TEXT_TO_ID{TEXT_COUNT}],
    [TEXT_COUNT + 1 -> TEXT_COUNT].

### Syntax nonterminals

ACTION enter nonterminal (>ID, >ARITY, >DEFTYPE, >NONT_CLASSES>, NONTERMINAL>):
  where ARITY identifies NONTERMINAL in NONT_CLASSES;
  create nonterminal (ID, ARITY, DEFTYPE, NONTERMINAL),
    [NONTERMINAL with ARITY and NONT_CLASSES -> NONT_CLASSES].

ACTION enter lexicon nonterminal (>ID, >ARITY, >NONT_CLASSES>, NONTERMINAL>):
# shouldnt happen, lexgen2 isn't doing this anymore
#
#  where ARITY identifies NONTERMINAL1 in NONT_CLASSES,
#    ([NONTERMINAL = NONTERMINAL1];
#     ?); ## inconsistent LexGen
  create lexicon nonterminal (ID, ARITY, NONTERMINAL),
    [NONTERMINAL with ARITY and NONT_CLASSES -> NONT_CLASSES].

TEST where >ARITY identifies NONTERMINAL> in >NONT_CLASSES:
  [NONT_CLASSES -> NONTERMINAL with ARITY1 and NONT_CLASSES1],
    ([ARITY = ARITY1];
     where ARITY identifies NONTERMINAL in NONT_CLASSES1).

FUNCTION assert valid >NONTERMINAL:
  convert NONTERMINAL to INT,
    ( lesseq (0, INT), less (INT, NONT_COUNT);
      bindec (INT, TEXT),
         abort ("assert valid nonterminal number " + TEXT + "failed")
    ).

ACTION create nonterminal (>ID, >ARITY, >DEFTYPE, NONTERMINAL>):
  [nonterminal NONT_COUNT -> NONTERMINAL],
    [NONT_COUNT + 1 -> NONT_COUNT],
    notify properties of newly created NONTERMINAL,
    empty (PRAGMATS),
    [ID with ARITY and DEFTYPE and PRAGMATS -> NONT_INFO],
    store nonterminal info (NONTERMINAL, NONT_INFO),
    init nonterminal (NONTERMINAL).

ACTION create dummy nonterminal (NONTERMINAL>):
  create anonymous id (ID),
    [nonterminal NONT_COUNT -> NONTERMINAL],
    [NONT_COUNT + 1 -> NONT_COUNT],
    notify properties of newly created NONTERMINAL,
    empty (PRAGMATS),
    [property dummy -> DEFTYPE],
    [arity 0 -> ARITY],
    [ID with ARITY and DEFTYPE and PRAGMATS -> NONT_INFO],
    store nonterminal info (NONTERMINAL, NONT_INFO),
    init nonterminal (NONTERMINAL).

ACTION create lexicon nonterminal (>ID, >ARITY, NONTERMINAL>):
  [nonterminal NONT_COUNT -> NONTERMINAL],
    [NONT_COUNT + 1 -> NONT_COUNT],
    notify properties of newly created NONTERMINAL,
    [LEX_NONT_COUNT + 1 -> LEX_NONT_COUNT],
    empty (PRAGMATS),
    [lexicon -> DEFTYPE],
    [ID with ARITY and DEFTYPE and PRAGMATS -> NONT_INFO],
    store nonterminal info (NONTERMINAL, NONT_INFO),
    init nonterminal (NONTERMINAL).

ACTION init nonterminal (>NONTERMINAL):
  init properties (NONTERMINAL),
    init syntax rule (NONTERMINAL),
    init anonymous group NONTERMINAL admin.

FUNCTION get nonterminal info (>NONTERMINAL, NONT_INFO>):
  convert NONTERMINAL to INT,
    [NONT_TO_INFO{INT} -> NONT_INFO].

ACTION store nonterminal info (>NONTERMINAL, >NONT_INFO):
  convert NONTERMINAL to INT,
    [NONT_INFO -> NONT_TO_INFO{INT}].

######################
#                    #
#   Testing of ids   #
#                    #
######################

### Lexicon affixes

TEST id is lexicon affix (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
      [DEFTYPE -> lexicon].
  
TEST id is lexicon affix terminal (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
      [DEFTYPE -> lexicon],
        [DOMTYPE -> set terminal with WEIGHT and SET].

### Anonymous affixes

TEST id is anonymous affix (>ID):
 [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
   [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
     [DEFTYPE -> anonymous].

### Nonterminal affixes

TEST id is affix nonterminal (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    is affix nonterminal (SECOND).

TEST is affix nonterminal (>SECOND):
  [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
    is affix nonterminal (DOMTYPE).

TEST is affix nonterminal (>DOMTYPE):
  [DOMTYPE -> untyped nonterminal];
  [DOMTYPE -> set nonterminal with WEIGHT and SET];
  [DOMTYPE -> integer];
  [DOMTYPE -> text].

TEST id is user variable (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    is user variable (SECOND).

TEST is user variable (>SECOND):
  [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
    ([DEFTYPE -> anonymous],
       (is predefined (DOMTYPE);
        -);
     is affix nonterminal (DOMTYPE)).

TEST is predefined (>DOMTYPE):
  [DOMTYPE -> integer];
  [DOMTYPE -> text].

### Set affixes

TEST id is set affix (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    is set affix (SECOND).

TEST is set affix (>SECOND):
  [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
    ([DOMTYPE -> set nonterminal with WEIGHT and SET];
     [DOMTYPE -> set terminal with WEIGHT and SET]).

TEST id is user affix terminal (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
      [DEFTYPE -> user],
        [DOMTYPE -> set terminal with WEIGHT and SET].


### Text affixes

TEST id is text affix (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    is text affix (SECOND).

TEST is text affix (>SECOND):
  [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
    [DOMTYPE -> text].

### Integer affixes

TEST id is integer affix (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    is integer affix (SECOND).

TEST is integer affix (>SECOND):
  [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
    [DOMTYPE -> integer].

### Untyped affixes

TEST id is untyped affix (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
      [DOMTYPE -> untyped nonterminal].

### Invalid affixes

TEST id is invalid affix (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
      [DOMTYPE -> erroneous].

### Nonterminals

TEST is start nonterminal (>NONTERMINAL):
  [START_NONT -> NONTERMINAL2],
    [NONTERMINAL = NONTERMINAL2].

TEST is user nonterminal (>NONTERMINAL):
  get nonterminal info (NONTERMINAL, NONT_INFO),
    [NONT_INFO -> ID with ARITY and DEFTYPE and PRAGMATS],
    [DEFTYPE -> user].

TEST is lexicon nonterminal (>NONTERMINAL):
  get nonterminal info (NONTERMINAL, NONT_INFO),
    [NONT_INFO -> ID with ARITY and DEFTYPE and PRAGMATS],
    [DEFTYPE -> lexicon].

TEST is anonymous nonterminal (>NONTERMINAL):
  get nonterminal info (NONTERMINAL, NONT_INFO),
    [NONT_INFO -> ID with ARITY and DEFTYPE and PRAGMATS],
    [DEFTYPE -> anonymous].

TEST is dummy nonterminal (>NONTERMINAL):
  get nonterminal info (NONTERMINAL, NONT_INFO),
    [NONT_INFO -> ID with ARITY and DEFTYPE and PRAGMATS],
    [DEFTYPE -> property dummy].

##################
#                #
#  Unknown Ids   #
#                #
##################

# Unknown ids are assumed to be set affixes and marked as such.

ACTION mark unknown affix ids:
  get number of ids (ID),
    mark unknown affix ids (ID).

ACTION mark unknown affix ids (>ID):
  [ID -> 0];
  [ID - 1 -> ID],
    mark unknown affix id (ID),
    mark unknown affix ids (ID).

ACTION mark unknown affix id (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([SECOND -> unknown affix nonterminal],
       create set affix nonterminal (user, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     [SECOND -> unknown affix],
       create set affix terminal (user, ID, SECOND),
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     +).

##################
#                #
#   Hybrid ids   #
#                #
##################

ACTION warn for hybrid ids:
  get number of ids (ID),
    warn for hybrid ids (ID).

ACTION warn for hybrid ids (>ID):
  [ID -> 0];
  [ID - 1 -> ID],
    warn for hybrid id (ID),
    warn for hybrid ids (ID).

ACTION warn for hybrid id (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([FIRST -> empty];
     [SECOND -> empty];
     report hybrid id (ID)).

ACTION report hybrid id (>ID):
  convert id to name (ID, TEXT),
    warning ("identifier '" + TEXT + "' is used on both levels").

################
#              #
#   Counters   #
#              #
################

FUNCTION get number of affixes (INT>):
  [AFFIX_COUNT -> INT].

FUNCTION get number of integer affixes (INT>):
  [AFFIX_INT_COUNT -> INT].

FUNCTION get number of text affixes (INT>):
  [AFFIX_TEXT_COUNT -> INT].

FUNCTION get number of affix terminals (INT>):
  [AFFIX_TERM_COUNT -> INT].

FUNCTION get number of affix nonterminals (INT>):
  [AFFIX_NONT_COUNT -> INT].

FUNCTION get number of lexicon nonterminals (INT>):
  [LEX_NONT_COUNT -> INT].

FUNCTION get number of syntax nonterminals (INT>):
  [NONT_COUNT -> INT].

FUNCTION get number of syntax terminals (INT>):
  [TERM_COUNT -> INT].

FUNCTION get number of regexp skips (INT>):
  [SKIP_COUNT -> INT].

FUNCTION get number of regexp matches (INT>):
  [MATCH_COUNT -> INT].

FUNCTION get number of text constants (INT>):
  [TEXT_COUNT -> INT].

###################
#                 #
#   Conversions   #
#                 #
###################

### Object to index

FUNCTION convert id to affix (>ID, INT>):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR];
     convert id to name (ID, TEXT),
       abort ("convert id to affix: unknown affix " + TEXT),
       ?).

FUNCTION convert id to syntax terminal (>ID, INT>):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([FIRST -> TERMINAL and SKIP and MATCH],
       convert TERMINAL to INT;
     ?).

FUNCTION convert >TERMINAL to INT>:
  is empty (TERMINAL), ?;
  [TERMINAL -> terminal INT].

FUNCTION convert id to regexp skip (>ID, INT>):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([FIRST -> TERMINAL and SKIP and MATCH],
       convert SKIP to INT;
     ?).

FUNCTION convert >SKIP to INT>:
  is empty (SKIP), ?;
  [SKIP -> skip INT].

FUNCTION convert id to regexp match (>ID, INT>):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([FIRST -> TERMINAL and SKIP and MATCH],
       convert MATCH to INT;
     ?).

FUNCTION convert >MATCH to INT>:
  is empty (MATCH), ?;
  [MATCH -> match INT].

FUNCTION convert id to text constant (>ID, INT>):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([OTHER -> text constant INT];
     ?).

### Index to object

FUNCTION convert affix nonterminal to id (>INT, ID>):
  [AFFIX_NONT_TO_ID{INT} -> ID].

FUNCTION convert affix terminal to id (>INT, ID>):
  [AFFIX_TERM_TO_ID{INT} -> ID].

FUNCTION convert affix to id (>INT, ID>):
  [AFFIX_TO_ID{INT} -> ID].

FUNCTION convert integer affix to id (>INT, ID>):
  [AFFIX_INT_TO_ID{INT} -> ID].

FUNCTION convert text affix to id (>INT, ID>):
  [AFFIX_TEXT_TO_ID{INT} -> ID].

FUNCTION convert syntax terminal to id (>INT, ID>):
  [TERM_TO_ID{INT} -> ID].

FUNCTION convert regexp skip to id (>INT, ID>):
  [SKIP_TO_ID{INT} -> ID].

FUNCTION convert regexp match to id (>INT, ID>):
  [MATCH_TO_ID{INT} -> ID].

FUNCTION convert text constant to id (>INT, ID>):
  [TEXT_TO_ID{INT} -> ID].

### Nonterminals

FUNCTION convert >INT to NONTERMINAL>:
  [nonterminal INT -> NONTERMINAL].

FUNCTION convert >NONTERMINAL to INT>:
  [NONTERMINAL -> nonterminal INT].

FUNCTION convert >NONTERMINAL to ID> and ARITY>:
  get nonterminal info (NONTERMINAL, NONT_INFO),
    [NONT_INFO -> ID with ARITY and DEFTYPE and PRAGMATS].

FUNCTION get arity (>NONTERMINAL, ARITY>):
  convert NONTERMINAL to ID and ARITY.

FUNCTION convert >NONTERMINAL to TEXT>:
  convert NONTERMINAL to ID and ARITY,
    convert id to name (ID, TEXT1),
    convert ARITY to TEXT2,
    [TEXT1 + "/" + TEXT2 -> TEXT].

FUNCTION convert >ARITY to TEXT>:
  convert ARITY to INT,
    convert INT to TEXT.

FUNCTION convert >ARITY to INT>:
  [ARITY -> arity INT].

FUNCTION convert >INT to ARITY>:
  [arity INT -> ARITY].

FUNCTION convert >RULENR to TEXT>:
  is defined (RULENR),
    [RULENR -> INT],
    convert INT to TEXT;
  ["*undefined*" -> TEXT].

FUNCTION convert >NONTERMINAL to number INT>:
  convert NONTERMINAL to ID and ARITY,
    convert NONTERMINAL to INT1,
    convert ARITY to INT2,
    [(INT1 << 8) + INT2 -> INT].


#######################
#                     #
#   Access routines   #
#                     #
#######################

### Set infos

ACTION store set info (>ID, >SET):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
    store set info (SET, DOMTYPE),
    [affix INT with DEFTYPE and DOMTYPE and RULENR -> SECOND],
    [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
  ?.

FUNCTION store set info (>SET, >DOMTYPE>):
  [DOMTYPE -> set nonterminal with WEIGHT and SET1],
    may replace SET1 with SET,
    [set nonterminal with WEIGHT and SET -> DOMTYPE];
  [DOMTYPE -> set terminal with WEIGHT and SET1],
    may replace SET1 with SET,
    [set terminal with WEIGHT and SET -> DOMTYPE];
  ?.

FUNCTION may replace >SET1 with >SET2:
  [SET1 -> empty];
  [SET1 = SET2];
  convert SET1 to TEXT1,
    convert SET2 to TEXT2,
    system error ("LexGen and AGFL disagree on "+TEXT1+" and "+TEXT2),
    ?.	# LexGen and AGFL disagree.

FUNCTION get set info (>ID, SET>):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
       convert id to name (ID, TEXT),
       get set info (TEXT, DOMTYPE, SET);
     ?).

FUNCTION get set info (>TEXT, >DOMTYPE, SET>):
  [DOMTYPE -> set nonterminal with WEIGHT and SET];
  [DOMTYPE -> set terminal with WEIGHT and SET];
  system error ("set info for \""+TEXT+"\" is not yet known"),?.

### Affix weights

ACTION store affix weight (>ID, >WEIGHT):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
       store affix weight (WEIGHT, DOMTYPE),
       [affix INT with DEFTYPE and DOMTYPE and RULENR -> SECOND],
       [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
     ?).

FUNCTION store affix weight (>WEIGHT, >DOMTYPE>):
  [DOMTYPE -> set nonterminal with WEIGHT1 and SET],
    may replace WEIGHT1 with WEIGHT,
    [set nonterminal with WEIGHT and SET -> DOMTYPE];
  [DOMTYPE -> set terminal with WEIGHT1 and SET],
    may replace WEIGHT1 with WEIGHT,
    [set terminal with WEIGHT and SET -> DOMTYPE];
  ?.

FUNCTION may replace >WEIGHT1 with >WEIGHT2:
  is empty (WEIGHT1);
  [WEIGHT1 = WEIGHT2];
  ?.	# LexGen and AGFL disagree.

FUNCTION get affix weight (>ID, WEIGHT>):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    ([SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
       get affix weight (DOMTYPE, WEIGHT);
     ?).

FUNCTION get affix weight (>DOMTYPE, WEIGHT>):
  [DOMTYPE -> set nonterminal with WEIGHT and SET];
  [DOMTYPE -> set terminal with WEIGHT and SET];
  ?.

### Affix rule numbers

ACTION store affix rule number (>ID, >RULENR):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR1],
      [affix INT with DEFTYPE and DOMTYPE and RULENR -> SECOND],
      [FIRST and SECOND and OTHER -> ID_INFOS{ID}];
  ?.

TEST get affix rule number (>ID, RULENR>):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
      is defined (RULENR).

### Pragmats

FUNCTION get pragmats (>NONTERMINAL, PRAGMATS>):
  get nonterminal info (NONTERMINAL, NONT_INFO),
    [NONT_INFO -> ID with ARITY and DEFTYPE and PRAGMATS].

ACTION store pragmats (>NONTERMINAL, >PRAGMATS):
  get nonterminal info (NONTERMINAL, NONT_INFO),
    [NONT_INFO -> ID with ARITY and DEFTYPE and PRAGMATS1],
    add (PRAGMATS1, PRAGMATS),
    [ID with ARITY and DEFTYPE and PRAGMATS1 -> NONT_INFO],
    store nonterminal info (NONTERMINAL, NONT_INFO).

###############
#             #
#   Dumping   #
#             #
###############

ACTION dump ids:
  log ("Id table"),
    get number of ids (ID),
    dump ids (ID).

ACTION dump ids (>ID):
  [ID -> 0];
  [ID - 1 -> ID],
    dump id (ID),
    dump ids (ID).

ACTION dump id (>ID):
  convert  ID to  TEXT1,
    convert id to name (ID, TEXT2),
    log ("Id " + TEXT1 + ": " + TEXT2),
    dump id info (ID).

ACTION dump id info (>ID):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    dump id first (FIRST),
    dump id second (SECOND),
    dump id other (OTHER).

ACTION dump id first (>FIRST):
  [FIRST -> empty];
  [FIRST -> TERMINAL and SKIP and MATCH],
    dump id (TERMINAL),
    dump id (SKIP),
    dump id (MATCH);
  [FIRST -> NONT_CLASSES],
    log ("    nonterminal class:"),
    dump nonterminal class (NONT_CLASSES);
  ?.

ACTION dump id (>TERMINAL):
  is empty (TERMINAL);
  convert TERMINAL to INT,
    convert INT to TEXT,
    log ("    syntax terminal number " + TEXT).

ACTION dump id (>SKIP):
  is empty (SKIP);
  convert SKIP to INT,
    convert INT to TEXT,
    log ("    syntax terminal number " + TEXT).

ACTION dump id (>MATCH):
  is empty (MATCH);
  convert MATCH to INT,
    convert INT to TEXT,
    log ("    syntax terminal number " + TEXT).

ACTION dump nonterminal class (>NONT_CLASSES):
  [NONT_CLASSES -> nil];
  [NONT_CLASSES -> NONTERMINAL with ARITY and NONT_CLASSES1],
    dump syntax nonterminal (NONTERMINAL),
    dump nonterminal class (NONT_CLASSES1);
  ?.

ACTION dump id second (>SECOND):
  [SECOND -> empty];
  [SECOND -> unknown affix],
    log ("    unknown affix");
  [SECOND -> unknown affix nonterminal],
    log ("    unknown affix nonterminal");
  [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR],
    convert INT to TEXT1,
    convert DEFTYPE to TEXT2,
    convert DOMTYPE to TEXT3,
    convert RULENR to TEXT4,
    log ("    " + TEXT2 + " " + TEXT3 + "\n    with affix number " + TEXT1 +
         " and rulenr " + TEXT4);
  ?.

FUNCTION get affix number (>ID, INT>):
  [ID_INFOS{ID} -> FIRST and SECOND and OTHER],
    [SECOND -> affix INT with DEFTYPE and DOMTYPE and RULENR];
  ?.

FUNCTION convert >DEFTYPE to TEXT>:
  [DEFTYPE -> user],
    ["user" -> TEXT];
  [DEFTYPE -> lexicon],
    ["lexicon" -> TEXT];
  [DEFTYPE -> anonymous],
    ["anonymous" -> TEXT];
  ?.

FUNCTION convert >DOMTYPE to TEXT>:
  [DOMTYPE -> set nonterminal with WEIGHT and SET],
    convert WEIGHT to TEXT1,
    convert SET to TEXT2,
    ["set affix nonterminal with weight " + TEXT1 + " and set " + TEXT2 ->TEXT];
  [DOMTYPE -> set terminal with WEIGHT and SET],
    convert WEIGHT to TEXT1,
    convert SET to TEXT2,
    ["set affix terminal with weight " + TEXT1 + " and set " + TEXT2 -> TEXT];
  [DOMTYPE -> integer],
    ["integer affix" -> TEXT];
  [DOMTYPE -> text],
    ["text affix" -> TEXT];
  [DOMTYPE -> erroneous],
    ["erroneous" -> TEXT];
  [DOMTYPE -> untyped nonterminal],
    ["untyped nonterminal" -> TEXT];
  ?.

FUNCTION convert >WEIGHT to TEXT>:
  [WEIGHT -> INT],
    convert INT to TEXT.

ACTION dump id other (>OTHER):
  [OTHER -> empty];
  [OTHER -> text constant INT],
    convert INT to TEXT,
    log ("    text constant " + TEXT);
  ?.
