$title('TOKEN module for GENDEF')
token:
do;
$include (:f1:glit.plb)

declare
    cr lit '0dh';

/* token tables given below are each addressed by tokadr(length), and
each start with the number of items in the table of that particular
length.  the tables are in sorted order so that they could be searched
with a binary search algorithm (sequential is used at this time) */

declare
    /* tokens are not listed for length 0,1 */
    tok0 (*) byte data(0), tok1 (*) byte data(0),
    /* single character tokens are given by their ascii representation */
    tok2 (*) byte data
    (0),
    tok3 (*) byte data
    (0),
    tok4 (*) byte data
    (0),
    tok5 (*) byte data
    (2,'DISKS','ENDEF'),
    tok6 (*) byte data
    (1,'MACLIB'),
    tok7 (*) byte data
    (1,'DISKDEF');

declare
    /* index to base address of each table */
    tokadr (*) address data
    (.tok0,.tok1,.tok2,.tok3,.tok4,.tok5,.tok6,.tok7),

    /* starting token number for each length */
    tokbas (*) byte data
    (0,0,token2,token3,token4,token5,token6,token7);

/* external declarations */
declare
    nextc      byte external,   /* next char (lookahead) */
    token      byte external,   /* current token */
    continue   byte external,   /* true for long idents, strings */
    acclen     byte external,   /* accumulator length */
    accum(32)  byte external;   /* actual characters scanned */

gnt: procedure external;
    /* produces token = tiden, tnumb, tstrng, or tspecl */
    end gnt;

scan: procedure public;
    /* scan produces the actual token number for each item returned by
    gnt (get next token).  in the case of identifiers and special chars,
    the token tables are searched before returning the token number */

    nextchar: procedure(lookchr) byte;
        declare lookchr byte;
        /* nextchar is used to look ahead for special two character
        sequences.  if 'lookchr' is found, then nextc is zeroed and true is
        returned from the call */
        declare tf byte;
        if (tf := nextc = lookchr) then nextc = 0;
        return tf;
        end nextchar;

    declare /* local variables for the token matching */
        ta address,       /* set to beginning of string of symbols */
        tokstr based ta (tokenm) byte, /* string template at ta */
        n byte,           /* number of symbols remaining to scan in string */
        i byte;           /* index used while matching characters */

    call gnt; /* sets external variables */
    if token = tstrng or token = tnumb then return;

    /* otherwise token = tspecl or token = tiden */

    if token = tspecl then
        do;
        /* may be a comment */
        if accum(0) = ';' then
            do while accum(0) <> cr;
            call gnt;
            end;
        token = accum(0);
        return;
        end;

    if acclen > tokenm then
        /* cannot be a reserved word */
        return;

    ta = tokadr(acclen);  /* ta is set to the base string to match */
    n  = tokstr(0);   /* n is the number of symbols in the string */

    /* token must be set to tiden at this point */
    token  = tokbas(acclen);  /* base token number */

        do while n > 0; /* more match attempts */
        n = n - 1;  i = acclen;
            do while i > 0 and accum(i-1) = tokstr(i);
            /* one more character has been matched */
            i = i - 1;
            end;
        if i = 0 then /* a complete match was found */
            return;
        /* current token does not match, try again */
        token = token + 1; /* move to next token in sequence */
        ta = ta + acclen; /* base address advanced to next item */
        end;
    /* cannot find the token, leave 'token' set to tiden */
    token = tiden;
    return;
    end scan;
end;
