#
#  File: code.k3
#  Defines all actual code generation routines.
#
#  Copyright 2005 Radboud 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 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: code.k3,v 1.71 2006/08/09 11:13:08 marcs Exp $"
#
MODULE code = SUSPENDED TEXT_TYPE INT_TYPE CHOICE_COUNT DEBUGINFOS.

DEFINES ACTION generate code.

USES globals, io, rule, id, transduction, intermediate, instructions,
     set, affix, optimize, properties, parser, textstorage.

PRELUDE init code:
  init todo list,
    init debuginfos,
    [ -1 -> INT_TYPE ],
    [ -2 -> TEXT_TYPE ],
    [ 0 -> CHOICE_COUNT ].

TEXT_TYPE, INT_TYPE = INT.
CHOICE_COUNT = INT.

ACTION get new choice number (INT>):
  [ CHOICE_COUNT -> INT ],
    [ INT + 1 -> CHOICE_COUNT ].

FUNCTION get number of choices (INT>):
  [ CHOICE_COUNT -> INT ].

#
# The root of the code generation
#
ACTION generate code:
  open code file,
    generate prelude,
    get agfl version (TEXT),
    generate agfl version (TEXT),
    code start rule,
    get number of syntax nonterminals (INT),
    generate code (INT),
    resume suspends,
    generate postlude,
    generate runtime interface,
    generate debuginfo,
    end of code generation,
    close code file.

#
# Start rule code generation:
#
ACTION code start rule:
  get start nonterminal (NONTERMINAL),
    export "root",
    create root stack frame (0, 1, 1),
    get root nonterminal (NONTERMINAL1),
    new fail LABEL1,
    new call LABEL9 for NONTERMINAL1,
    convert NONTERMINAL1 to INT,
    generate start call to rule INT at LABEL9 failing to LABEL1,
    maybe generate eos match (LABEL3),
    new fail LABEL2,
    generate success and fail to LABEL2,
    generate second pass for root (NONTERMINAL, NONTERMINAL1),
    generate undo success,
    generate undo LABEL2,
    maybe generate undo eos match (LABEL3),
    generate undo call (0),
    generate undo LABEL1,
    generate end instruction (0, 1).

ACTION generate start call to rule >INT at >LABEL9 failing to >LABEL1:
  if positive memo option,
    generate posmemo call to rule INT at LABEL9 failing to LABEL1;
  generate call to rule INT at LABEL9 failing to LABEL1.

ACTION maybe generate eos match (LABEL>):
  if generative grammar option, empty LABEL;
  if segment mode option, empty LABEL;
  get eos terminal (ID), new fail LABEL,
    convert id to syntax terminal (ID, INT1),
    generate match terminal INT1 using 0 targeting -1 failing to LABEL.

ACTION maybe generate undo eos match (>LABEL):
  if generative grammar option;
  if segment mode option;
    generate unmatch terminal targeting -1,
    generate undo LABEL.

ACTION generate second pass for root (>NONTERMINAL, >NONTERMINAL1):
  empty ALTNO,
    new trans LABEL1 for NONTERMINAL at ALTNO,
    new tree LABEL2 for NONTERMINAL at ALTNO,
    generate second pass call (LABEL1, LABEL2),
    [ NONTERMINAL1 son 1 -> SON ],
    [ print SON -> TRACT ],
    [ TRACT nil -> TRACTS ],
    [ LABEL1 ALTNO TRACTS -> SPCODE1 ],
    [ LABEL2 ALTNO TRACTS -> SPCODE2 ],
    [ nil -> EXPRS ],
    suspend SPCODE1 and SPCODE2 for NONTERMINAL with params EXPRS.

#
# Generate code for syntax rules:
#
ACTION generate code (>INT):
  [ INT -> 0 ];
  [ INT - 1 -> INT ],
    generate code (INT),
    convert INT to NONTERMINAL,
    generate code for nonterminal (NONTERMINAL).

FRLEN = INT.

ACTION generate code for nonterminal (>NONTERMINAL):
  ic says it is unused (NONTERMINAL);
  get ic rule (NONTERMINAL, ICRULE),
    generate heading (NONTERMINAL, ICRULE, FRLEN, LABEL2, LABEL3),
    get ICDEFS from ICRULE,
    new fail LABEL,
    get NR_FORMALS and NR_LOCALS from ICRULE,
    maybe generate choice (ICDEFS, INT1),
    generate code (ICDEFS, LABEL, NONTERMINAL, FRLEN, NR_FORMALS),
    maybe generate undo choice (INT1),
    generate footing (NONTERMINAL, LABEL, LABEL2, LABEL3).

ACTION generate heading (>NONTERMINAL, >ICRULE, FRLEN>, LABEL2>, LABEL3>):
  announce rule (NONTERMINAL),
    new call LABEL for NONTERMINAL,
    new fail LABEL2 for NONTERMINAL,
    generate call LABEL,
    get NR_FORMALS and NR_LOCALS from ICRULE,
    convert NR_FORMALS to INT1,
    convert NR_LOCALS to INT2,
    get nr sons INT3 from ICRULE,
    [ INT1 + INT2 + INT3 -> FRLEN ],
    create stack frame (INT1, INT2, INT3, LABEL2),
    may be generate mark lrec (NONTERMINAL, LABEL3).

ACTION generate footing (>NONTERMINAL, >LABEL, >LABEL2, >LABEL3):
  generate undo LABEL,
    may be generate umark lrec (NONTERMINAL, LABEL3),
    generate LABEL2,
    generate fail instruction,
    denounce rule (NONTERMINAL).

ACTION may be generate mark lrec (>NONTERMINAL, LABEL>):
  is left recursive (NONTERMINAL),
    new lrec LABEL,
    generate mark lrec (LABEL),
    generate LABEL;
  empty LABEL.

ACTION may be generate umark lrec (>NONTERMINAL, >LABEL):
  is left recursive (NONTERMINAL),
    generate umark lrec (LABEL);
  +.

ACTION maybe generate choice (>ICDEFS, INT1>):
  if generative grammar option,
    get new choice number (INT1),
    count (ICDEFS, INT2),
    generate choice (INT1, INT2);
  [ -1 -> INT1 ].

ACTION maybe generate undo choice (>INT):
  if generative grammar option,
    generate undo choice (INT);
  +.

#
# Rule bodies:
#
ACTION generate code (>ICDEFS, >LABEL, >NONTERMINAL, >FRLEN, >NR_FORMALS):
  [ ICDEFS -> ICDEF ICDEFS ],
    generate code (ICDEF, LABEL, NONTERMINAL, FRLEN, NR_FORMALS),
    generate code (ICDEFS, LABEL, NONTERMINAL, FRLEN, NR_FORMALS);
  [ ICDEFS -> nil ];
  ?.

ACTION generate code (>ICDEF, >LABEL, >NONTERMINAL, >FRLEN, >NR_FORMALS):
  [ ICDEF -> lhs ICACTS rhs ICALTS ],
    announce start lhs,
    generate code (ICACTS, ICALTS, LABEL, NONTERMINAL, FRLEN, NR_FORMALS).

ACTION generate code (>ICACTS, >ICALTS, >LABEL, >NONTERMINAL, >FRLEN, >NR_FORMALS):
  [ ICACTS -> nil ],
    denounce start lhs,
    maybe generate choice (ICALTS, INT),
    generate code (ICALTS, LABEL, NONTERMINAL, FRLEN, NR_FORMALS),
    maybe generate undo choice (INT);
  [ ICACTS -> ICACT ICACTS ],
    new fail LABEL1,
    generate do code (ICACT, NONTERMINAL, NR_FORMALS, LABEL1),
    generate code (ICACTS, ICALTS, LABEL, NONTERMINAL, FRLEN, NR_FORMALS),
    generate undo code (ICACT, NR_FORMALS, LABEL1);
  ?.

ACTION generate code (>ICALTS, >LABEL, >NONTERMINAL, >FRLEN, >NR_FORMALS):
  [ ICALTS -> nil ];
  [ ICALTS -> ICALT ICALTS ],
    generate code (ICALT, LABEL, NONTERMINAL, FRLEN, NR_FORMALS),
    generate code (ICALTS, LABEL, NONTERMINAL, FRLEN, NR_FORMALS);
  ?.

ACTION maybe generate choice (>ICALTS, INT1>):
  if generative grammar option,
    get new choice number (INT1),
    count (ICALTS, INT2),
    generate choice (INT1, INT2);
  [ -1 -> INT1 ].

#
# Alternative generation:
#
ACTION generate code (>ICALT, >LABEL, >NONTERMINAL, >FRLEN, >NR_FORMALS):
  [ ICALT -> ALTNO ICACTS COMMITED ],
    announce alt (ALTNO),
    maybe generate clear (FRLEN),
    generate code (ICACTS, NONTERMINAL, NR_FORMALS),
    maybe generate commit (COMMITED, LABEL),
    denounce alt (ALTNO).

ACTION maybe generate clear (>FRLEN):
  [ FRLEN -> -1 ];
  generate clear instruction (FRLEN).

ACTION generate code (>ICACTS, >NONTERMINAL, >NR_FORMALS):
  [ ICACTS -> nil ];
  [ ICACTS -> ICACT ICACTS ],
    new fail LABEL1,
    generate do code (ICACT, NONTERMINAL, NR_FORMALS, LABEL1),
    generate code (ICACTS, NONTERMINAL, NR_FORMALS),
    generate undo code (ICACT, NR_FORMALS, LABEL1);
  ?.

ACTION maybe generate commit (>COMMITED, >LABEL):
  [ COMMITED -> true ],
    generate commit to LABEL;
  +.

#
# Action generation (do and undo parts):
#
ACTION generate do code (>ICACT, >NONTERMINAL, >NR_FORMALS, >LABEL):
  [ ICACT -> init formal INT to VALUE ],
    generate code for init INT to VALUE;
  [ ICACT -> init local INT to VALUE ],
    calculate local offset INT1 from INT using NR_FORMALS,
    generate code for init INT1 to VALUE;
  [ ICACT -> match lexicon NONTERMINAL ],
    convert NONTERMINAL to number INT,
    generate lexmatch for INT failing to LABEL;
  [ ICACT -> group ICALTS ],
    generate code (ICALTS, LABEL, NONTERMINAL, -1, NR_FORMALS);
  [ ICACT -> call NONTERMINAL ],
    new call LABEL1 for NONTERMINAL,
    convert NONTERMINAL to INT,
    generate call to rule INT at LABEL1 failing to LABEL;
  [ ICACT -> penalty INT ],
    generate penalty of INT failing to LABEL;
  [ ICACT -> match terminal ID using local INT targeting ICVAR ],
    convert id to syntax terminal (ID, INT1),
    calculate local offset INT2 from INT using NR_FORMALS,
    calculate local offset INT3 for ICVAR using NR_FORMALS,
    generate match terminal INT1 using INT2 targeting INT3 failing to LABEL;
  [ ICACT -> skip ID using local INT targeting ICVAR ],
    convert id to regexp skip (ID, INT1),
    calculate local offset INT2 from INT using NR_FORMALS,
    calculate local offset INT3 for ICVAR using NR_FORMALS,
    generate regexp skip INT1 using INT2 targeting INT3 failing to LABEL;
  [ ICACT -> match ID using local INT targeting ICVAR ],
    convert id to regexp match (ID, INT1),
    calculate local offset INT2 from INT using NR_FORMALS,
    calculate local offset INT3 for ICVAR using NR_FORMALS,
    generate regexp match INT1 using INT2 targeting INT3 failing to LABEL;
  [ ICACT -> other using local INT targeting ICVAR ],
    calculate local offset INT1 from INT using NR_FORMALS,
    calculate local offset INT2 for ICVAR using NR_FORMALS,
    generate match other using INT1 targeting INT2 failing to LABEL;
  [ ICACT -> input pos using local INT targeting ICVAR ],
    calculate local offset INT1 from INT using NR_FORMALS,
    calculate local offset INT2 for ICVAR using NR_FORMALS,
    generate input pos using INT1 targeting INT2 failing to LABEL;
  [ ICACT -> restrict local INT to VALUE ],
    calculate local offset INT1 from INT using NR_FORMALS,
    generate restrict INT1 to VALUE failing to LABEL;
  [ ICACT -> restrict formal INT to VALUE ],
    generate restrict INT to VALUE failing to LABEL;
  [ ICACT -> adjust integer formal INT1 to output param INT2 ],
    generate adjust integer for INT1 to param INT2 failing to LABEL;
  [ ICACT -> adjust set formal INT1 to output param INT2 ],
    generate adjust set for INT1 to param INT2 failing to LABEL;
  [ ICACT -> adjust text formal INT1 to output param INT2 ],
    generate adjust text for INT1 to param INT2 failing to LABEL;
  [ ICACT -> adjust integer local INT1 to output param INT2],
    calculate local offset INT3 from INT1 using NR_FORMALS,
    generate adjust integer for INT3 to param INT2 failing to LABEL;
  [ ICACT -> adjust set local INT1 to output param INT2],
    calculate local offset INT3 from INT1 using NR_FORMALS,
    generate adjust set for INT3 to param INT2 failing to LABEL;
  [ ICACT -> adjust text local INT1 to output param INT2],
    calculate local offset INT3 from INT1 using NR_FORMALS,
    generate adjust text for INT3 to param INT2 failing to LABEL;
  [ ICACT -> continuation trans TRANSDUCTION1 and tree TRANSDUCTION2 and params EXPRS ],
    [ TRANSDUCTION1 -> ALTNO1 with TRACTS1 ],
    [ TRANSDUCTION2 -> ALTNO2 with TRACTS2 ],
    new trans LABEL1 for NONTERMINAL at ALTNO1,
    new tree LABEL2 for NONTERMINAL at ALTNO2,
    generate continuation (LABEL1, LABEL2),
    [ LABEL1 ALTNO1 TRACTS1 -> SPCODE1 ],
    [ LABEL2 ALTNO2 TRACTS2 -> SPCODE2 ],
    suspend SPCODE1 and SPCODE2 for NONTERMINAL with params EXPRS;
  [ ICACT -> director test DIR_MEMO ],
    convert DIR_MEMO to INT,
    generate director test for memo INT failing to LABEL;
  [ ICACT -> negative memo test MEMO ],
    convert MEMO to INT,
    generate negative memo test (INT, LABEL);
  [ ICACT -> negative memo set succeeded MEMO ],
    convert MEMO to INT,
    generate negative memo set succeeded (INT);
  [ ICACT -> alt marker ],
    generate alternative marker (LABEL);
  [ ICACT -> trace DEBUGINFO ],
    postpone DEBUGINFO at LABEL1,
    generate trace instruction (LABEL1);
  [ ICACT -> position INT ],
    generate position instruction (INT);
  ?.

ACTION generate continuation (>LABEL1, >LABEL2):
  generate normal continuation (LABEL1, LABEL2).

ACTION generate undo code (>ICACT, >NR_FORMALS, >LABEL):
  [ ICACT -> init formal INT to VALUE ];
  [ ICACT -> init local INT to VALUE ];
  [ ICACT -> match lexicon NONTERMINAL ],
    convert NONTERMINAL to number INT,
    generate undo lexmatch for INT,
    generate undo LABEL;
  [ ICACT -> group ICALTS ],
    generate undo LABEL;
  [ ICACT -> call NONTERMINAL ],
    convert NONTERMINAL to ID and ARITY,
    convert ARITY to INT,
    generate undo call (INT),
    generate undo LABEL;
  [ ICACT -> penalty INT ],
    generate undo penalty of INT,
    generate undo LABEL;
  [ ICACT -> match terminal ID using local INT targeting ICVAR ],
    calculate local offset INT2 for ICVAR using NR_FORMALS,
    generate unmatch terminal targeting INT2,
    generate undo LABEL;
  [ ICACT -> skip ID using local INT targeting ICVAR ],
    calculate local offset INT2 for ICVAR using NR_FORMALS,
    generate unmatch regexp targeting INT2,
    generate undo LABEL;
  [ ICACT -> match ID using local INT targeting ICVAR ],
    calculate local offset INT2 for ICVAR using NR_FORMALS,
    generate unmatch regexp targeting INT2,
    generate undo LABEL;
  [ ICACT -> other using local INT targeting ICVAR ],
    calculate local offset INT2 for ICVAR using NR_FORMALS,
    generate unmatch other targeting INT2,
    generate undo LABEL;
  [ ICACT -> input pos using local INT targeting ICVAR ],
    calculate local offset INT1 from INT using NR_FORMALS,
    calculate local offset INT2 for ICVAR using NR_FORMALS,
    generate uinput pos using INT1 targeting INT2,
    generate undo LABEL;
  [ ICACT -> restrict local INT to VALUE ],
    calculate local offset INT1 from INT using NR_FORMALS,
    generate undo restrict INT1 for VALUE,
    generate undo LABEL;
  [ ICACT -> restrict formal INT to VALUE ],
    generate undo restrict INT for VALUE,
    generate undo LABEL;
  [ ICACT -> adjust integer formal INT1 to output param INT2 ],
    generate undo adjust integer for INT1 to param INT2,
    generate undo LABEL;
  [ ICACT -> adjust set formal INT1 to output param INT2 ],
    generate undo adjust set for INT1 to param INT2,
    generate undo LABEL;
  [ ICACT -> adjust text formal INT1 to output param INT2 ],
    generate undo adjust text for INT1 to param INT2,
    generate undo LABEL;
  [ ICACT -> adjust integer local INT1 to output param INT2 ],
    calculate local offset INT3 from INT1 using NR_FORMALS,
    generate undo adjust integer for INT3 to param INT2,
    generate undo LABEL;
  [ ICACT -> adjust set local INT1 to output param INT2 ],
    calculate local offset INT3 from INT1 using NR_FORMALS,
    generate undo adjust set for INT3 to param INT2,
    generate undo LABEL;
  [ ICACT -> adjust text local INT1 to output param INT2 ],
    calculate local offset INT3 from INT1 using NR_FORMALS,
    generate undo adjust text for INT3 to param INT2,
    generate undo LABEL;
  [ ICACT -> continuation trans TRANSDUCTION1 and tree TRANSDUCTION2 and params EXPRS ];
  [ ICACT -> director test DIR_MEMO ],
    generate undo LABEL;
  [ ICACT -> negative memo test MEMO ],
    generate undo LABEL;
  [ ICACT -> negative memo set succeeded MEMO ];
  [ ICACT -> alt marker ],
    generate undo alternative marker,
    generate undo LABEL;
  [ ICACT -> trace DEBUGINFO ];
  [ ICACT -> position INT ];
  ?.

FUNCTION calculate local offset INT2> from >INT1 using >NR_FORMALS:
  convert NR_FORMALS to INT, [ INT + INT1 -> INT2 ].

FUNCTION calculate local offset INT> for >ICVAR using >NR_FORMALS:
  [ ICVAR -> none ], [ -1 -> INT ];
  [ ICVAR -> formal INT ];
  [ ICVAR -> local INT ], convert NR_FORMALS to INT2, [ INT + INT2 -> INT ];
  ?.

ACTION generate code for init >INT to >VALUE:
  [ VALUE -> top text ],
    get top text value (LABEL),
    generate text init INT to LABEL;
  [ VALUE -> top integer ],
    get top integer value (INT1),
    generate integer init INT to INT1;
  [ VALUE -> set ID ],
    get set info (ID, SET),
    generate set init INT to SET;
  [ VALUE -> text const ID ],
    convert name ID to LABEL,
    generate text init INT to LABEL;
  [ VALUE -> integer const INT1 ],
    generate integer init INT to INT1;
  ?.

FUNCTION get top text value (LABEL>):
  [ "0" -> TEXT ], convert TEXT to LABEL.

#
# The integer bottom value is -MAXINT - 1
# For the moment we assume that ints are 32 bits wide
#
FUNCTION get top integer value (INT>):
  [ 1 << 31 -> INT ].

ACTION generate restrict >INT to >VALUE failing to >LABEL:
  [ VALUE -> top text ];
  [ VALUE -> top integer ];
  [ VALUE -> set ID ],
    get set info (ID, SET),
    generate set restrict INT to SET failing to LABEL;
  [ VALUE -> text const ID ],
    convert name ID to LABEL,
    generate text restrict INT to LABEL failing to LABEL;
  [ VALUE -> integer const INT1 ],
    generate integer restrict INT to INT1 failing to LABEL;
  ?.

ACTION generate undo restrict >INT for >VALUE:
  [VALUE -> top text];
  [VALUE -> top integer];
  [VALUE -> set ID],
    generate undo restrict set (INT);
  [VALUE -> text const ID],
    generate undo restrict text (INT);
  [VALUE -> integer const INT1],
    generate undo restrict integer (INT);
  ?.


#########################
#                       #
#  Suspended animation  #
#                       #
#########################

### Global variable:

SUSPENDED = TODO_LIST.

ACTION init todo list:
  [nil -> SUSPENDED].

ACTION suspend >TODO_ITEM:
  add TODO_ITEM to SUSPENDED.


### TODO_LIST handling:

TODO_LIST :: TODO_ITEM TODO_LIST;
             nil.

FUNCTION add >TODO_ITEM to >TODO_LIST>:
  [TODO_ITEM TODO_LIST -> TODO_LIST].


### TODO_ITEM:

TODO_ITEM :: SECONDPASS_ITEM.


### SECONDPASS_ITEMs:

SECONDPASS_ITEM :: trans SPCODE tree SPCODE for NONTERMINAL with params EXPRS.

SPCODE :: LABEL ALTNO TRACTS.

ACTION suspend >SPCODE1 and >SPCODE2 for >NONTERMINAL with params >EXPRS:
  [trans SPCODE1 tree SPCODE2 for NONTERMINAL with params EXPRS -> SECONDPASS_ITEM],
    suspend SECONDPASS_ITEM.

ACTION resume suspends:
  resume suspended (SUSPENDED).

ACTION resume suspended (>TODO_LIST):
  [TODO_LIST -> nil];
  [TODO_LIST -> TODO_ITEM TODO_LIST],
    resume suspended (TODO_LIST),
    resume suspended (TODO_ITEM);
  ?.

ACTION resume suspended (>TODO_ITEM):
  [TODO_ITEM -> SECONDPASS_ITEM],
    [SECONDPASS_ITEM -> trans SPCODE1 tree SPCODE2 for NONTERMINAL with params EXPRS],
    generate trans code (SPCODE1, NONTERMINAL),
    generate tree code (SPCODE2, NONTERMINAL, EXPRS).

IS_TRANSDUCTION = BOOL.

ACTION generate trans code (>SPCODE, >NONTERMINAL):
  [SPCODE -> LABEL ALTNO TRACTS],
    announce trans (NONTERMINAL, ALTNO, LABEL),
    generate code (TRACTS, true),
    denounce trans (NONTERMINAL, ALTNO).

ACTION generate tree code (>SPCODE, >NONTERMINAL, >EXPRS):
  [SPCODE -> LABEL ALTNO TRACTS],
    announce tree (NONTERMINAL, ALTNO, LABEL, LABEL1),
    maybe generate nonterminal printing (NONTERMINAL),
    maybe generate begin alternative (NONTERMINAL, LABEL1),
    generate code (TRACTS, false),
    maybe generate end alternative (NONTERMINAL),
    denounce tree (NONTERMINAL, ALTNO).

ACTION maybe generate nonterminal printing (>NONTERMINAL):
  is invisible in tree (NONTERMINAL);
  generate nonterminal printing (NONTERMINAL).

ACTION maybe generate begin alternative (>NONTERMINAL, >LABEL):
  is invisible in tree (NONTERMINAL);
  generate begin alternative (LABEL).

ACTION maybe generate end alternative (>NONTERMINAL):
  is invisible in tree (NONTERMINAL);
  generate end alternative.

ACTION generate nonterminal printing (>NONTERMINAL):
  convert NONTERMINAL to ID and ARITY,
    get formal specification (NONTERMINAL, FSPEC),
    [FSPEC -> SPEC],
    convert ARITY to INT,
    ([INT -> 0];
     generate begin param pack,
       generate param pack params (INT, SPEC),
       generate end param pack).

ACTION generate param pack params (>INT, >SPEC):
  [INT -> 1],
    generate param pack param (INT, SPEC);
  generate param pack params (INT - 1, SPEC),
    generate param pack seperator,
    generate param pack param (INT, SPEC).

ACTION generate param pack param (>INT, >SPEC):
  get param id (SPEC, INT, ID),
    (id is set affix (ID),
       convert id to affix (ID, INT1),
       generate print set affix formal (INT - 1, INT1);
     id is text affix (ID),
       generate print text affix formal (INT - 1);
     id is integer affix (ID),
       generate print integer affix formal (INT - 1);
     ?).

ACTION generate code (>TRACTS, >IS_TRANSDUCTION):
  [TRACTS -> TRACT TRACTS],
    generate code (TRACT, IS_TRANSDUCTION),
    generate code (TRACTS, IS_TRANSDUCTION);
  [TRACTS -> nil];
  ?.

ACTION generate code (>TRACT, >IS_TRANSDUCTION):
  [TRACT -> print text ID],
    convert name ID to LABEL,
    generate print text (LABEL);
  [TRACT -> print terminal ID using local INT],
    generate print terminal (INT);
  [TRACT -> push formal INT],
    generate push formal (INT);
  [TRACT -> push local INT],
    generate push local (INT);
  [TRACT -> print SON],
    convert SON to INT,
    (if SON is lexicon nonterminal, ?;
     generate print son (INT - 1));
  [TRACT -> print lexicon SON with param TRACTS],
    generate print lexicon nonterminal (SON, TRACTS, IS_TRANSDUCTION);
  [TRACT -> print regexp using local INT],
    generate print regexp (INT);
  [TRACT -> print other using local INT],
    generate print other (INT);
  [TRACT -> print input pos using local INT],
    generate print input pos (INT);
  [TRACT -> print penalty INT],
    generate print penalty (INT);
  [TRACT -> print affix ID using formal INT],
    (id is set affix (ID),
       convert id to affix (ID, INT1),
       generate print set affix formal (INT, INT1);
     id is text affix (ID),
       generate print text affix formal (INT);
     id is integer affix (ID),
       generate print integer affix formal (INT);
     ?);
  [TRACT -> print affix ID using local INT],
    (id is set affix (ID),
       convert id to affix (ID, INT1),
       generate print set affix local (INT, INT1);
     id is text affix (ID),
       generate print text affix local (INT);
     id is integer affix (ID),
       generate print integer affix local (INT);
     ?);
  ?.


### Special actions for lexicon nonterminal printing:

ACTION generate print lexicon nonterminal (>SON, >TRACTS, >IS_TRANSDUCTION):
  [IS_TRANSDUCTION -> true],
    convert SON to INT,
    generate print lexicon nonterminal (INT - 1);
  convert SON to nonterminal ID,
    generate print lexicon nonterminal name (ID),
    maybe generate param pack (TRACTS, IS_TRANSDUCTION),
#    generate begin lexicon alternative,
    convert SON to INT,
    generate print lexicon nonterminal (INT - 1),
#    generate end alternative.
    +.

ACTION maybe generate param pack (>TRACTS, >IS_TRANSDUCTION):
  [TRACTS -> nil];
  [TRACTS -> TRACT TRACTS],
    generate begin param pack,
    generate code (TRACT, IS_TRANSDUCTION),
    generate rest param pack (TRACTS, IS_TRANSDUCTION),
    generate end param pack;
  ?.

ACTION generate rest param pack (>TRACTS, >IS_TRANSDUCTION):
  [TRACTS -> nil];
  [TRACTS -> TRACT TRACTS],
    generate param pack seperator,
    generate code (TRACT, IS_TRANSDUCTION),
    generate rest param pack (TRACTS, IS_TRANSDUCTION);
  ?.


#######################
#                     #
#  Runtime interface  #
#                     #
#######################
ACTION generate runtime interface:
  generate grammar version,
    generate runtime info,
    generate run time options,
    code affix table,
    code nonterminal domains,
    code memo directors table,
    code memo enable table,
    code name table,
    code id names,
    code alternatives profile table.

ACTION generate grammar version:
  get grammar version (INT),
    generate grammar version (INT).

ACTION generate runtime info:
  get number of lexicon nonterminals (INT),
#
# (FIXME) HACK ALERT! The "+ 1" is probably not correct!
#
    generate number of lexicon nonterminals (INT + 1),

    get number of syntax terminals (INT),
    generate number of syntax terminals (INT),

    get number of regexp matches (INT),
    generate number of regexp matches (INT),

    get number of regexp skips (INT),
    generate number of regexp skips (INT),

    get number of syntax nonterminals (INT),
    generate number of syntax nonterminals (INT),

    get number of memos (INT),
    generate number of memos (INT),

    get number of choices (INT),
    generate number of choices (INT),

    get number of positions (INT),
    generate number of positions (INT),

    get eos terminal (ID),
    convert id to syntax terminal (ID, INT),
    generate eos terminal (INT).

ACTION generate run time options:
  generate comment ("Run time options"),
    generate lexicon use,
    generate negative memo identification,
    generate positive memo identification,
    generate directors identification,
    generate log option identification,
    generate counters option identification,
    generate profile option,
    generate trace option,
    generate labelled bracket option,
    generate suppress output option,
    generate transduce option,
    generate generate option,
    generate echo unparsed sentence option,
    generate translate option,
    generate word terminators,
    generate invisible characters,
    generate graph option,
    generate client option,
    generate verbose parser option,
    generate segment mode option.

ACTION generate lexicon use:
  export ("use_lexicon"),
    (if lexicon used,
       generate long (1);
     generate long (0)).

ACTION generate negative memo identification:
  export ("neg_memo_option"),
    (if negative memo option,
       generate long (1);		# used in rtsopt.c 
     generate long (0)).

ACTION generate positive memo identification:
  export ("pos_memo_option"),
    (if positive memo option,
       generate long (1);		# used in rtsopt.c 
     generate long (0)).

ACTION generate directors identification:
  export ("directors_option"),
    (if directors option,
       generate long (1);
     generate long (0)).

ACTION generate log option identification:
  export ("log_option"),
    (if log option,
       generate long (1);
     generate long (0)).

ACTION generate counters option identification:
  export ("counters_option"),
    (if counters option,
       generate long (1);
     generate long (0)).

ACTION generate trace option:
  export "trace_option",
    (if trace option,
       generate long (1);
     generate long (0)).

ACTION generate profile option:
  export ("profile_option"),
    (if profile option,
       generate long (1);
     generate long (0)).

ACTION generate labelled bracket option:
  export "label_bracket",
    (if labelled bracket option,
       generate long (1);
     generate long (0)).

ACTION generate suppress output option:
  export "no_output",
    (if suppress output option,
       generate long (1);
     generate long (0)).

ACTION generate transduce option:
  export "transduce_option",
    (if transduce option,
       generate long (1);
     generate long (0)).

ACTION generate generate option:
  export ("generate_option"),
    (if generative grammar option,
       generate long (1);
     generate long (0)).

ACTION generate echo unparsed sentence option:
  export ("echo_unparsed_option"),
    # TODO: real option with pragmat
    generate long (0).

ACTION generate translate option:
  export ("alphabet_file"),
    ( if translate option (TEXT),
         convert "Lalphabet" to LABEL,
         generate applied LABEL,
         generate LABEL,
         strip quotes (TEXT),
         generate byte_string (TEXT),
         generate align;
      generate long (0)
    ).

ACTION generate word terminators:
  export ("word_terminator_chars"),
    convert "Lwsep" to LABEL,
    generate applied LABEL,
    generate LABEL,
      (if word terminators option (TEXT),
         strip quotes (TEXT),
         convert control codes (TEXT),
         generate byte string (TEXT),
         generate align;
       generate byte string (" \t\n\015,.?;:()!\""),
         generate align).
       

ACTION generate invisible characters:
  export ("invisible_chars"),
    convert "Linvchar" to LABEL,
    generate applied LABEL,
    generate LABEL,
      (if invisible characters option (TEXT),
         strip quotes (TEXT),
         convert control codes (TEXT),
         generate byte string (TEXT),
         generate align;
       generate byte string (" \t\n\015"),
         generate align).

ACTION generate graph option:
  export "graph_option",
    (if graph option,
       generate long (1);
     generate long (0)).

ACTION generate client option:
  export "client_option",
    (if client option,
       generate long (1);
     generate long (0)).

ACTION generate verbose parser option:
  export "verbose",
    (if verbose parser option (INT),
       generate long (INT);
     generate long (0)).

ACTION generate segment mode option:
  export ("segment_mode"),
    (if segment mode option,
       generate long (1);
     generate long(0)).


###############
#             #
#   Affixes   #
#             #
###############

ACTION code affix table:
  get number of affixes (INT),  
    generate comment ("Affix domains"),
    export ("affix_domains"),
    code affix domains (INT),
    generate comment ("Affix weights"),
    export ("affix_weights"),
    code affix weights (INT),
    display time ("coded affix table").

ACTION code affix domains (>INT):
  [INT -> 0];
  [INT - 1 -> INT],
    code affix domains (INT),
    code affix domain (INT).

ACTION code affix domain (>INT):
  convert affix to id (INT, ID),
    (id is set affix (ID),
       get set info (ID, SET),
       generate set (SET);
     generate long (0)).

ACTION code affix weights (>INT):
  code weight pointers (INT),
    code weights (INT).

ACTION code weight pointers (>INT):
  [INT -> 0];
  [INT - 1 -> INT],
    code weight pointers (INT),
    code weight pointer (INT).

ACTION code weight pointer (>INT):
  convert affix to id (INT, ID),
    (id is integer affix (ID),
       generate long (0);
     id is text affix (ID),
       generate long (0);  
     convert weight INT to LABEL,
       generate applied LABEL).

ACTION code weights (>INT):
  [INT -> 0];
  [INT - 1 -> INT],
    code weight (INT),
    code weights (INT).

# FIXME! Sometimes it happens that "code weight pointer" codes a pointer
# but "code weight" doesn't code the (label and the) weight.  So
# something is then not an integer, text or set affix??  As a workaround
# for this apparent bug, generate the label anyway, or the poor user
# gets a link error and no clue what is going on, or how to fix it.
#
# In the case I have seen, the domain was not actually used in any
# PRINT_SL or PRINT_SF instructions, so the origins were quite
# untraceable.

ACTION code weight (>INT):
  convert affix to id (INT, ID),
    (id is set affix (ID),
       convert weight INT to LABEL,
       generate LABEL,
       code full domain (INT, ID),
       get affix weight (ID, WEIGHT),
       code affixes with weights (WEIGHT, INT),
       generate long (-1);
     id is integer affix (ID);
     id is text affix (ID);
    # unforseen:
     convert weight INT to LABEL,
       generate LABEL,
       convert id to name (ID, TEXT),
       generate comment ("orphaned domain: " + TEXT),
       warning ("orphaned domain: " + TEXT),
       generate long (-1)).

# TODO: check this!

ACTION code full domain (>INT, >ID):
  id is anonymous affix (ID);
  id is affix nonterminal (ID),
    generate long (INT);
  +.

ACTION code affixes with weights (>WEIGHT, >INT):
  [WEIGHT -> -1];
  code affixes with weight (WEIGHT, INT),
    code affixes with weights (WEIGHT - 1, INT).

ACTION code affixes with weight (>WEIGHT, >INT):
  get number of affixes (INT2),
    code affixes with weight (INT2, WEIGHT, INT).

ACTION code affixes with weight (>INT2, >WEIGHT, >INT):
  [INT2 -> 0];
  [INT2 - 1 -> INT2],
    code affix with weight (INT2, WEIGHT, INT),
    code affixes with weight (INT2, WEIGHT, INT).

ACTION code affix with weight (>INT2, >WEIGHT, >INT):
  matrix test (INT, INT2),	# TODO: abstraction
    convert affix to id (INT2, ID),
      (id is anonymous affix (ID);
       get affix weight (ID, WEIGHT2),
         ([WEIGHT2 = WEIGHT],
             generate long (INT2);
          +));
  +.

###########################
#                         #
#   Nonterminal domains   #
#                         #
###########################

# Nonterminal domains are encoded for displaying the lexical graph,
# and for determining domain types when restricting formals to shadows.
# Note that we assume that the lexicon system and agfl compiler use the
# same numbering for nonterminals.

ACTION code nonterminal domains:
  get number of syntax nonterminals (INT),
    generate comment ("Nonterminal domains"),
    export ("nont_domains"),
    code nonterminal domain pointers (INT),
    code nonterminal domains (INT).

ACTION code nonterminal domain pointers (>INT):
  [INT -> 0];
  [INT - 1 -> INT],
    code nonterminal domain pointers (INT),
    code nonterminal domain pointer (INT).

ACTION code nonterminal domain pointer (>INT):
  convert domain INT to LABEL,
    generate applied LABEL.

ACTION code nonterminal domains (>INT):
  [INT -> 0];
  [INT - 1 -> INT],
    code nonterminal domain (INT),
    code nonterminal domains (INT).

ACTION code nonterminal domain (>INT):
  convert domain INT to LABEL,
    generate LABEL,
    convert INT to NONTERMINAL,
    code domain (NONTERMINAL).

# Also encode domains of unreachable nonterminals, otherwise
# printing of lexical graph may not work.

ACTION code domain (>NONTERMINAL):
  get formal specification (NONTERMINAL, FSPEC),
    [FSPEC -> SPEC],
    code domain (SPEC).

ACTION code domain (>SPEC):
  [SPEC -> empty]; # specification not collected (unused anon nonterminal)
  code collected domain (SPEC).

ACTION code collected domain (>SPEC):
  [SPEC -> nil];
  [SPEC -> OIDS SPEC1],
    code collected domain (OIDS),
    code collected domain (SPEC1);
  ?.

ACTION code collected domain (>OIDS):
  [OIDS -> collected ID],
    (id is text affix (ID),
       generate long (TEXT_TYPE);
     id is integer affix (ID),
       generate long (INT_TYPE);
     convert id to affix (ID, INT),
       generate long (INT));
  ?.


################
#              #
#   ID Names   #
#              #
################

ACTION code id names:
  generate comment ("ID Names"),
    get number of ids (INT),
    code id names (INT),
    display time ("coded id names").

ACTION code id names (>INT):
  [INT -> 0];
  [INT - 1 -> INT],
    code id name (INT),
    code id names (INT).


# No brief comments are generated for id's, as this breaks the generated code
# when a string contains something like */ (like regexps)

ACTION code id name (>ID):
  convert name ID to LABEL,
    generate align,
    generate LABEL,
    convert id to name (ID, TEXT),
    strip quotes (TEXT),
    convert control codes (TEXT),
    generate byte string (TEXT),
    generate align.


# Assemblers may apply different quoting mechanisms to backslashes in
# regular expressions. Therefore the string is codes as bytes.

ACTION generate byte string (>TEXT):
  length (TEXT, INT),
    generate byte string (0, INT, TEXT).

ACTION generate byte string (>INT1, >INT2, >TEXT):
  [INT1 = INT2],
    generate byte (0);
  asciicode (TEXT, INT1, INT3),
    generate byte (INT3),
    generate byte string (INT1 + 1, INT2, TEXT);
  ?.

###################
#                 #
#   Name tables   #
#                 #
###################

ACTION code name table:
  generate comment ("Name table"),
    code affix name table,
    code terminal name table,
    code nonterminal name table,
    code regexp name tables,
    display time ("coded name table").

  
### Affix names

ACTION code affix name table:
  export ("affix_names"),
    get number of affixes (INT),
    code affix name pointers (INT).

ACTION code affix name pointers (>INT):
  [INT -> 0];
  [INT - 1 -> INT],
    code affix name pointers (INT),
    code affix name pointer (INT).

ACTION code affix name pointer (>INT):
  convert affix to id (INT, ID),
    (id is anonymous (ID),
       generate long (0);
     convert name ID to LABEL,
       generate applied LABEL).

### Terminal names

ACTION code terminal name table:
  export ("term_names"),
    get number of syntax terminals (INT),
    code terminal name pointers (INT).

ACTION code terminal name pointers (>INT):
  [INT -> 0];
  [INT - 1 -> INT],
    code terminal name pointers (INT),
    code terminal name pointer (INT).

ACTION code terminal name pointer (>INT):
  convert syntax terminal to id (INT, ID),
    convert name ID to LABEL,
    generate applied LABEL.


### Nonterminal names

ACTION code nonterminal name table:
  export ("nonterm_names"),
    get number of syntax nonterminals (INT),
    code nonterminal name pointers (INT).

ACTION code nonterminal name pointers (>INT):
  [INT -> 0];
  [INT - 1 -> INT],
    code nonterminal name pointers (INT),
    code nonterminal name pointer (INT).

ACTION code nonterminal name pointer (>INT):
  convert INT to NONTERMINAL,
    convert NONTERMINAL to ID and ARITY,
    convert name ID to LABEL,
    generate applied LABEL.


### Regular expression names

ACTION code regexp name tables:
  code regexp match name table,
    code regexp skip name table.

ACTION code regexp match name table:
  export ("match_regexp_names"),
    get number of regexp matches (INT),
    code regexp match name pointers (INT).

ACTION code regexp match name pointers (>INT):
  [INT -> 0];
  [INT - 1 -> INT],
    code regexp match name pointers (INT),
    code regexp match name pointer (INT).

ACTION code regexp match name pointer (>INT):
  convert regexp match to id (INT, ID),
    convert name ID to LABEL,
    generate applied LABEL.

ACTION code regexp skip name table:
  export ("skip_regexp_names"),
    get number of regexp skips (INT),
    code regexp skip name pointers (INT).

ACTION code regexp skip name pointers (>INT):
  [INT -> 0];
  [INT - 1 -> INT],
    code regexp skip name pointers (INT),
    code regexp skip name pointer (INT).

ACTION code regexp skip name pointer (>INT):
  convert regexp skip to id (INT, ID),
    convert name ID to LABEL,
    generate applied LABEL.


######################
#                    #
#   Memo directors   #
#                    #
######################

ACTION code memo directors table:
  generate comment ("Memo directors"),
    (if directors option,
       code memo director pointers,
       code memo directors,
       display time ("coded memo directors");
     export ("term_memo_dir"),
       export ("skip_memo_dir"),
       export ("match_memo_dir"),
       export ("lex_memo_dir")).

ACTION code memo director pointers:
  code terminal memo director pointers,
    code regexp skip memo director pointers,
    code regexp match memo director pointers,
    code lexicon memo director pointers.

ACTION code terminal memo director pointers:
  export ("term_memo_dir"),
    get number of syntax terminals (INT),
    code memo director pointers (terminal, INT).

ACTION code regexp skip memo director pointers:
  export ("skip_memo_dir"),
    get number of regexp skips (INT),
    code memo director pointers (regexp skip, INT).

ACTION code regexp match memo director pointers:
  export ("match_memo_dir"),
    get number of regexp matches (INT),
    code memo director pointers (regexp match, INT).

ACTION code lexicon memo director pointers:
  export ("lex_memo_dir"),
    get number of lexicon nonterminals (INT),
#
# (FIXME) HACK ALERT! The "+ 1" is probably not correct!
#
    code memo director pointers (lexicon nonterminal, INT + 1).

ACTION code memo director pointers (>MEMO_OBJECT, >INT):
  [INT -> 0];
  [INT - 1 -> INT],
  code memo director pointers (MEMO_OBJECT, INT),
    code memo director pointer (MEMO_OBJECT, INT).

ACTION code memo director pointer (>MEMO_OBJECT, >INT):
  convert MEMO_OBJECT memo INT to LABEL,
    generate applied LABEL.

FUNCTION convert >MEMO_OBJECT memo >INT to LABEL>:
  bindec (INT, TEXT),
    ([MEMO_OBJECT -> terminal],
       ["Lterm_memo" + TEXT -> TEXT],
       convert TEXT to LABEL;
     [MEMO_OBJECT -> regexp skip],
       ["Lskip_memo" + TEXT -> TEXT],
       convert TEXT to LABEL;
     [MEMO_OBJECT -> regexp match],
       ["Lmatch_memo" + TEXT -> TEXT],
       convert TEXT to LABEL;
     [MEMO_OBJECT -> lexicon nonterminal],
       ["Llex_memo" + TEXT -> TEXT],
       convert TEXT to LABEL;
     ?).


ACTION code memo directors:
  code terminal memo directors,
    code regexp skip memo directors,
    code regexp match memo directors,
    code lexicon memo directors.

ACTION code terminal memo directors:
  get number of syntax terminals (INT),
    code memo directors (terminal, INT).

ACTION code regexp skip memo directors:
  get number of regexp skips (INT),
    code memo directors (regexp skip, INT).

ACTION code regexp match memo directors:
  get number of regexp matches (INT),
    code memo directors (regexp match, INT).

ACTION code lexicon memo directors:
  get number of lexicon nonterminals (INT),
#
# (FIXME) HACK ALERT! The "+ 1" is probably not correct!
#
    code memo directors (lexicon nonterminal, INT + 1).

ACTION code memo directors (>MEMO_OBJECT, >INT):
  [INT -> 0];
  [INT - 1 -> INT],
    code memo vector (MEMO_OBJECT, INT),
    code memo directors (MEMO_OBJECT, INT).

# All memo bitvectors of type MEMO_OBJECT are encoded in a single array.
# Let l be the vector length. The bitvector for memo i ranges from
# index l*i .. l*i + i-1

ACTION code memo vector (>MEMO_OBJECT, >INT):
  convert MEMO_OBJECT memo INT to LABEL,
    generate LABEL,
    get memo vector size (INT1),
    code memo vector (MEMO_OBJECT, INT * INT1, INT1).

ACTION code memo vector (>MEMO_OBJECT, >INT1, >INT2):
  [INT2 -> 0];
  get memo slice (MEMO_OBJECT, INT1, INT),
    generate long (INT),
    code memo vector (MEMO_OBJECT, INT1 + 1, INT2 - 1).

#
# Memo enable table generation
#
ACTION code memo enable table:
  get number of syntax nonterminals (INT),
    generate comment ("memo enable table"),
    export ("memo_enable_table"),
    code memo enable table (INT).

ACTION code memo enable table (>INT):
  [INT -> 0];
  [INT - 1 -> INT],
    code memo enable table (INT),
    convert INT to NONTERMINAL,
    code memo enable table entry (NONTERMINAL).

ACTION code memo enable table entry (>NONTERMINAL):
  computed rule type is cond (NONTERMINAL),
    generate long (1);
  generate long (1).


# Alternatives profile table

ACTION code alternatives profile table:
  get number of positions (INT),
  generate comment ("Alternatives profile table"),
    export ("alternatives_profile_table"),
    code alternative profile entries (INT).

ACTION code alternative profile entries (>INT):
  [INT -> 0];
  [INT-1 -> INT],
    code alternative profile entries (INT),
    code alternative profile entry (INT).

ACTION code alternative profile entry (>INT):
  convert syntax terminal to id (INT, ID),
    generate long (0).


################
#              #
#  Debug info  #
#              #
################

DEBUGINFO_ENTRY :: DEBUGINFO at debug LABEL.
DEBUGINFO_LIST :: DEBUGINFO_ENTRY DEBUGINFO_LIST;
                  nil.

DEBUGINFOS = DEBUGINFO_LIST.

ACTION init debuginfos:
  [nil -> DEBUGINFOS].

ACTION postpone >DEBUGINFO at LABEL>:
  new debuginfo LABEL,
    [DEBUGINFO at debug LABEL -> DEBUGINFO_ENTRY],
    [DEBUGINFO_ENTRY DEBUGINFOS -> DEBUGINFOS].

ACTION generate debuginfo:
  generate debuginfo (DEBUGINFOS).

ACTION generate debuginfo (>DEBUGINFO_LIST):
  [DEBUGINFO_LIST -> nil];
  [DEBUGINFO_LIST -> DEBUGINFO_ENTRY DEBUGINFO_LIST],
    [DEBUGINFO_ENTRY -> DEBUGINFO at debug LABEL],
    generate LABEL with DEBUGINFO,
    generate debuginfo (DEBUGINFO_LIST);
  ?.

ACTION generate >LABEL with >DEBUGINFO:
  [DEBUGINFO -> guard],
    generate LABEL,
    generate long (0);
  [DEBUGINFO -> terminal ID],
    generate LABEL,
    generate long (ID);
  [DEBUGINFO -> call NONTERMINAL],
    convert NONTERMINAL to INT,
    generate LABEL,
    generate long (INT);
  [DEBUGINFO -> option call NONTERMINAL],
    convert NONTERMINAL to INT,
    generate LABEL,
    generate long (INT);
  [DEBUGINFO -> penalty INT],
    generate LABEL,
    generate long (INT);
  [DEBUGINFO -> skip ID],
    generate LABEL,
    generate long (ID);
  [DEBUGINFO -> match ID],
    generate LABEL,
    generate long (ID);
  [DEBUGINFO -> director INT],
    generate LABEL,
    generate long (INT);
  [DEBUGINFO -> empty],
    generate LABEL,
    generate long (0);
  ?.

