/******************************************************************************
* Module    :   Lexical Analyzer --- Process the input text file into tokens
*               that the configuration file parser can understand.
*
* Routines  :   Lex()   - Return the next token from the file.
*               OpenPrg - Open the back up program script file.
*
* Author    :   John W. M. Stevens
******************************************************************************/

#include    "compiler.h"

#include    "lex.h"

/* Type definitions for this file.  */
typedef struct  key_st  {
    char    c;
    TKNS    val;
    struct  key_st  *branch;
} KEY;

/* Constants local to this file.    */
#define     NOT_FND     -2

/* Object Data. */
static  char    word[80];   /* Last string analyzed.                        */
static  int     LnNo = 0;   /* The current line number reading the script.  */
static  FILE    *PrgFl;     /* Pointer to the ASCII file that contains the
                            *   backup program script.
                            */

/* Trie data structure containing all the keywords and punctuation marks for
*   the backup language.
*/
static
KEY T8[2] = {
    {   ' ',                  2,    NULL                    },
    {   'e',        T_ALTERNATE,    NULL                    }
};

static
KEY T7[2] = {
    {   ' ',                  2,    NULL                    },
    {   't',                  0,    T8                      }
};

static
KEY T6[2] = {
    {   ' ',                  2,    NULL                    },
    {   'a',                  0,    T7                      }
};

static
KEY T5[2] = {
    {   ' ',                  2,    NULL                    },
    {   'n',                  0,    T6                      }
};

static
KEY T4[2] = {
    {   ' ',                  2,    NULL                    },
     {   'r',                  0,    T5                      }
};

static
KEY T3[2] = {
    {   ' ',                  2,    NULL                    },
    {   'e',                  0,    T4                      }
};

static
KEY T2[2] = {
    {   ' ',                  2,    NULL                    },
    {   't',                  0,    T3                      }
};

static
KEY T1[2] = {
    {   ' ',                  2,    NULL                    },
    {   'l',                  0,    T2                      }
};

static
KEY Tb[2] = {
    {   ' ',                  2,    NULL                    },
    {   'y',             T_BODY,    NULL                    }
};

static
KEY Ta[2] = {
    {   ' ',                  2,    NULL                    },
    {   'd',                  0,    Tb                      }
};

static
KEY T9[2] = {
    {   ' ',                  2,    NULL                    },
    {   'o',                  0,    Ta                      }
};

static
KEY Te[2] = {
    {   ' ',                  2,    NULL                    },
    {   'e',             T_CASE,    NULL                    }
};

static
KEY Td[2] = {
    {   ' ',                  2,    NULL                    },
    {   's',                  0,    Te                      }
};

static
KEY Tc[2] = {
    {   ' ',                  2,    NULL                    },
    {   'a',                  0,    Td                      }
};

static
KEY T13[2] = {
    {   ' ',                  2,    NULL                    },
    {   'r',           T_HEADER,    NULL                    }
};

static
KEY T12[2] = {
    {   ' ',                  2,    NULL                    },
     {   'e',                  0,    T13                     }
};

static
KEY T11[2] = {
    {   ' ',                  2,    NULL                    },
    {   'd',                  0,    T12                     }
};

static
KEY T10[2] = {
    {   ' ',                  2,    NULL                    },
    {   'a',                  0,    T11                     }
};

static
KEY Tf[2] = {
    {   ' ',                  2,    NULL                    },
    {   'e',                  0,    T10                     }
};

static
KEY T18[2] = {
    {   ' ',                  2,    NULL                    },
    {   'e',           T_IGNORE,    NULL                    }
};

static
KEY T17[2] = {
    {   ' ',                  2,    NULL                    },
    {   'r',                  0,    T18                     }
};

static
KEY T16[2] = {
    {   ' ',                  2,    NULL                    },
    {   'o',                  0,    T17                     }
};

static
KEY T15[2] = {
    {   ' ',                  2,    NULL                    },
    {   'n',                  0,    T16                     }
};

static
KEY T14[3] = {
    {   ' ',                  3,    NULL                    },
    {   'd',               T_ID,    NULL                    },
    {   'g',                  0,    T15                     }
};

static
KEY T1d[2] = {
    {   ' ',                  2,    NULL                    },
    {   'r',           T_NUMBER,    NULL                    }
};

static
KEY T1c[2] = {
    {   ' ',                  2,    NULL                    },
    {   'e',                  0,    T1d                     }
};

static
KEY T1b[2] = {
     {   ' ',                  2,    NULL                    },
    {   'b',                  0,    T1c                     }
};

static
KEY T1a[2] = {
    {   ' ',                  2,    NULL                    },
    {   'm',                  0,    T1b                     }
};

static
KEY T19[2] = {
    {   ' ',                  2,    NULL                    },
    {   'u',                  0,    T1a                     }
};

static
KEY T20[2] = {
    {   ' ',                  2,    NULL                    },
    {   't',             T_PART,    NULL                    }
};

static
KEY T1f[2] = {
    {   ' ',                  2,    NULL                    },
    {   'r',                  0,    T20                     }
};

static
KEY T1e[2] = {
    {   ' ',                  2,    NULL                    },
    {   'a',                  0,    T1f                     }
};

static
KEY T27[2] = {
    {   ' ',                  2,    NULL                    },
    {   's',         T_SEGMENTS,    NULL                    }
};

static
KEY T26[2] = {
    {   ' ',                  2,    NULL                    },
    {   't',          T_SEGMENT,    T27                     }
};

static
KEY T25[2] = {
    {   ' ',                  2,    NULL                    },
    {   'n',                  0,    T26                     }
};

static
KEY T24[2] = {
    {   ' ',                  2,    NULL                    },
    {   'e',                  0,    T25                     }
};

static
KEY T23[2] = {
    {   ' ',                  2,    NULL                    },
    {   'm',                  0,    T24                     }
};

static
KEY T2d[2] = {
     {   ' ',                  2,    NULL                    },
    {   'e',        T_SENSITIVE,    NULL                    }
};

static
KEY T2c[2] = {
    {   ' ',                  2,    NULL                    },
    {   'v',                  0,    T2d                     }
};

static
KEY T2b[2] = {
    {   ' ',                  2,    NULL                    },
    {   'i',                  0,    T2c                     }
};

static
KEY T2a[2] = {
    {   ' ',                  2,    NULL                    },
    {   't',                  0,    T2b                     }
};

static
KEY T29[2] = {
    {   ' ',                  2,    NULL                    },
    {   'i',                  0,    T2a                     }
};

static
KEY T28[2] = {
    {   ' ',                  2,    NULL                    },
    {   's',                  0,    T29                     }
};

static
KEY T22[3] = {
    {   ' ',                  3,    NULL                    },
    {   'g',                  0,    T23                     },
    {   'n',                  0,    T28                     }
};

static
KEY T31[2] = {
    {   ' ',                  2,    NULL                    },
    {   'g',           T_STRING,    NULL                    }
};

static
KEY T30[2] = {
    {   ' ',                  2,    NULL                    },
    {   'n',                  0,    T31                     }
};

static
KEY T2f[2] = {
    {   ' ',                  2,    NULL                    },
    {   'i',                  0,    T30                     }
};

static
KEY T2e[2] = {
    {   ' ',                  2,    NULL                    },
    {   'r',                  0,    T2f                     }
};

static
KEY  T21[3] = {
    {   ' ',                  3,    NULL                    },
    {   'e',                  0,    T22                     },
    {   't',                  0,    T2e                     }
};

static
KEY T35[2] = {
    {   ' ',                  2,    NULL                    },
    {   'l',            T_TOTAL,    NULL                    }
};

static
KEY T34[2] = {
    {   ' ',                  2,    NULL                    },
    {   'a',                  0,    T35                     }
};

static
KEY T33[2] = {
    {   ' ',                  2,    NULL                    },
    {   't',                  0,    T34                     }
};

static
KEY T32[2] = {
    {   ' ',                  2,    NULL                    },
    {   'o',                  0,    T33                     }
};

static
KEY T0[12] = {
    {   ' ',                 12,    NULL                    },
    {   'a',                  0,    T1                      },
    {   'b',                  0,    T9                      },
    {   'c',                  0,    Tc                      },
    {   'h',                  0,    Tf                      },
    {   'i',                  0,    T14                     },
    {   'n',                  0,    T19                     },
    {   'p',                  0,    T1e                     },
    {   's',                  0,    T21                     },
    {   't',                  0,    T32                     },
    {   '{',          T_L_BRACE,    NULL                    },
    {   '}',          T_R_BRACE,    NULL                    }
};

/*-----------------------------------------------------------------------------
| Routine   :   TrieSrch() --- Search the trie for a token.
|
| Inputs    :   Keys    - The trie level pointer.
|               ch      - The current character to search for.
|               WordPtr - The pointer to the current byte of the word buffer.
| Outputs   :   The token number or TKN_NOT_FND for not found.
-----------------------------------------------------------------------------*/

static
int     TrieSrch(KEY    *Keys,
                 int    ch,
                 char   *WordPtr)
{
    register    int     mid;        /* Mid point of array piece.            */
    register    TKNS    ret;        /* Return value of comparison.          */

    auto        int     cmp;        /* Comparison.                          */
    auto        int     lo;         /* Limits of current array piece.       */
    auto        int     hi;

     /* Make sure that input is lower case.  */
    ch = tolower( ch );

    /* Search for a token.  */
    hi = Keys[0].val - 1;
    lo = 1;
    do
    {
        /* Find mid point of current array piece.   */
        mid = (lo + hi) >> 1;

        /* Do character comparison. */
        cmp = ch - Keys[mid].c;

        /* Fix the array limits.    */
        if (cmp <= 0)
            hi = mid - 1;
        if (cmp >= 0)
            lo = mid + 1;

    }  while (hi >= lo);

    /*  If the character matches one of the entries in this level and this
    *   entry has a child, recurse.  If a match is found but the matching
    *   entry has no child, return the token value associated with the
    *   match.  If the return value from the recursive call indicates that
    *   no match was found at a lower level, return the token value
    *   associated with the match at this level of the trie.
    */
    if (cmp == 0)
    {
        /* Save the current character.  */
        *WordPtr++ = ch;

        /* Is this the last character in the string?    */
        if ( Keys[mid].branch )
        {
            /* Get the next character.  */
            if ((ch = fgetc( PrgFl )) == EOF)
                return( EOF );

            /* Search next level.   */
            if ((ret = TrieSrch(Keys[mid].branch, ch, WordPtr)) == T_NOT_FND)
            {
                ungetc(ch, PrgFl);
                return( Keys[mid].val );
            }
            return( ret );
        }
        else
        {
            *WordPtr = '\0';
            return( Keys[mid].val );
        }
    }

    /* Return not found.    */
    *WordPtr = '\0';
    return( T_NOT_FND );
}

/*-----------------------------------------------------------------------------
| Routine   :   Lex() --- Get the next key word from the input file.
|
| Outputs   :   sym - The symbolic data read from the file.
|
| Return :   Returns the token read or EOF.
-----------------------------------------------------------------------------*/

int     Lex(TOKEN   *sym)
{
    register    int     tkn;
    auto        int     ch;
    extern      FILE    *ErrFile;

    /* Strip comments and white space.  If the character read is a '#',
    *   every thing to the end of the line is a comment.
    */
    ch = fgetc( PrgFl );
    while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#')
    {
        /* Process the special characters '#' and '\n'.     */
        if (ch == '\n')
            LnNo++;
        else if (ch == '#')
        {
            while (fgetc( PrgFl ) != '\n')
                ;
            LnNo++;
        }

        /* Get the next character.  */
        ch = fgetc( PrgFl );
    }

    /* Get strings, etc.    */
    if (ch == '"')
    {
        auto    char    *bf;

        /* Get contents of string.  */
        bf = sym->str;
        while ((ch = fgetc( PrgFl )) != '"' && ch != EOF)
            *bf++ = ch;
        *bf = '\0';

        /* Return string token. */
        return( T_DBL_QUOTE );
    }
    else if (ch >= '0' && ch <= '9')
    {
        /* Get the number.  */
        sym->no = 0;
        do
        {
            sym->no = sym->no * 10 + (ch - '0');
        }  while ((ch = fgetc( PrgFl )) >= '0' && ch <= '9');

        /* Return the unused character. */
        ungetc(ch, PrgFl);
        return( T_INT_NO );
    }
    else if (ch == EOF)
        return( EOF );

    /* Call the trie search routine to return the next token, EOF
    *   or NOT_FND.  If not found, print an error and quit.
    */
    if ((tkn = TrieSrch(T0, ch, word)) == T_NOT_FND || tkn == 0)
    {
        fprintf(ErrFile,
                "%s %d : Error - cannot identify string '%s' ",
                 __FILE__,
                __LINE__,
                word);
        fprintf(ErrFile,
                "in line %d\n",
                LnNo + 1);
        exit( 1 );
    }

    /* Return the token found.  */
    return( tkn );
}

/*-----------------------------------------------------------------------------
| Routine   :   OpenCfg() --- Open the ASCII text file that contains the
|               configuration data.
-----------------------------------------------------------------------------*/

void    OpenCfg(char    *FileNm)
{
    extern  FILE    *ErrFile;

    /* Open the program script file.    */
    if ((PrgFl = fopen(FileNm, TXT_READ)) == NULL)
    {
        fprintf(ErrFile,
                "%s %d : Error - %s\n",
                __FILE__,
                __LINE__,
                strerror( errno ));
        fprintf(ErrFile,
                "\tFile Name: '%s'\n",
                FileNm);
        exit( 1 );
    }
}

/*-----------------------------------------------------------------------------
| Routine   :   CloseCfg() --- Close the ASCII text file that contains the
|               configuration data.
-----------------------------------------------------------------------------*/

void    CloseCfg(void)
{
    fclose( PrgFl );
}

/*-----------------------------------------------------------------------------
| Routine   :   ParseErr() --- Report a parse error.
|
| Inputs    :   ErrStr  - The error string.
-----------------------------------------------------------------------------*/

void    ParseErr(char   *ErrStr)
{
    extern  FILE    *ErrFile;

    fprintf(ErrFile,
            "%s %d : Error - %s\n",
            __FILE__,
            __LINE__,
            ErrStr);
    fprintf(ErrFile,
            "\tLine %d, word '%s'\n",
            LnNo + 1,
            word);
    exit( 1 );
}


syntax highlighted by Code2HTML, v. 0.9.1