/******************************************************************************
* 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