/******************************************************************************
* Module : Parse Configuration File --- Build the regular expression
* hierarchy tree by reading data from a configuration file.
*
* Notes : Configuration file grammar:
*
* CONFIG_FILE ::= SEGMENT <EOF>
* | SEGMENT CONFIG_FILE
*
* SEGMENT ::= 'segment' STRING '{' ID_LINES '}'
*
* ID_LINES ::= 'header' '{' PREFIXES '}'
* 'body' '{' PREFIXES '}'
*
* PREFIXES ::= PREFIX
* | PREFIX PREFIXES
*
* PREFIX ::= STRING '{' ID_PARTS '}'
*
* ID_PARTS ::= ID_PART_RE
* | ID_PART_RE ID_PARTS
*
* ID_PART_RE := STRING '{'
* 'id' NUMBER
* 'segment' 'number' NUMBER
* 'segments' NUMBER
* 'alternate' 'id' NUMBER
* 'case' CASE_TYPE
* '}'
*
* CASE_TYPE ::= 'sensitive'
* | 'ignore'
*
* STRING ::= '"' [ -~]* '"'
*
* NUMBER ::= [0-9]+
*
* Author : John W. M. Stevens
******************************************************************************/
#include "compiler.h"
#include "unpost.h"
#include "lex.h"
#include "list.h"
#include "parse.h"
#include "regexp.h"
#include "config.h"
#include "utils.h"
typedef enum {
ID_SUB_EXPR,
SEG_NO_SUB_EXPR,
NO_SEGS_SUB_EXPR,
ALT_ID_SUB_EXPR,
CASE_SENSITIVITY
} ID_PARTS_IDX;
static char ReStr[512];
/*-----------------------------------------------------------------------------
| Routine : ParseParts() --- Parse the ID line part number blocks.
|
| Returns : A pointer to the root of the ID part regular expression tree.
-----------------------------------------------------------------------------*/
static
PART_RE *ParseParts(void)
{
register int i;
auto TOKEN sym;
auto int tkn;
auto int Elements[5];
auto char *tp;
auto PART_RE NewPart;
auto LIST *PartList;
/* Create ID list. */
PartList = CrtList( sizeof( PART_RE ) );
/* Get list of part extraction regular expressions. */
while ((tkn = Lex( &sym )) == T_DBL_QUOTE)
{
/* Initialize new part re structure. */
NewPart.IDStr = 0;
NewPart.SegNo = 0;
NewPart.NoSegs = 0;
NewPart.AltIDStr = 0;
NewPart.Case = IGN_CASE;
/* Get IDENT line part regular expression string. */
for (tp = ReStr; ; tp = ReStr + strlen( ReStr ))
{
/* Copy string from token structure to buffer. */
strcpy(tp, sym.str);
/* Get next token. */
if ((tkn = Lex( &sym )) != T_DBL_QUOTE)
break;
}
/* Create ID prefix regular expression string. */
NewPart.ReExpStr = StrDup( ReStr );
/* Check for opening curly brace. */
if (tkn != T_L_BRACE)
{
ParseErr("expecting '{' to open ID part block.");
exit( 1 );
}
/* Process components in ANY order. */
for (i = ID_SUB_EXPR; i <= CASE_SENSITIVITY; i++)
Elements[i] = 0;
for (i = ID_SUB_EXPR; i <= CASE_SENSITIVITY; i++)
{
/* Get a token. */
if ((tkn = Lex( &sym )) == T_R_BRACE)
break;
/* Select parse action based on token. */
switch ( tkn )
{
case T_ID:
/* Check for duplication. */
if (Elements[ID_SUB_EXPR] != 0)
{
ParseErr("duplicate sub-expression numbers.");
exit( 1 );
}
/* Get the sub-expression number for the ID sub-string. */
if ((tkn = Lex( &sym )) != T_INT_NO)
{
ParseErr("missing sub-expression number.");
exit( 1 );
}
NewPart.IDStr = sym.no;
Elements[ID_SUB_EXPR] = 1;
break;
case T_SEGMENT:
/* Check for duplication. */
if (Elements[SEG_NO_SUB_EXPR] != 0)
{
ParseErr("duplicate sub-expression numbers.");
exit( 1 );
}
/* Get next token. */
if ((tkn = Lex( &sym )) != T_NUMBER)
{
ParseErr("missing 'number' after 'segment'.");
exit( 1 );
}
/* Get sub-expression number for the segment number
* sub-string.
*/
if ((tkn = Lex( &sym )) != T_INT_NO)
{
ParseErr("missing sub-expression number.");
exit( 1 );
}
NewPart.SegNo = sym.no;
Elements[SEG_NO_SUB_EXPR] = 1;
break;
case T_SEGMENTS:
/* Check for duplication. */
if (Elements[NO_SEGS_SUB_EXPR] != 0)
{
ParseErr("duplicate sub-expression numbers.");
exit( 1 );
}
/* Get number of segments sub-expression number. */
if ((tkn = Lex( &sym )) != T_INT_NO)
{
ParseErr("missing sub-expression number.");
exit( 1 );
}
NewPart.NoSegs = sym.no;
Elements[NO_SEGS_SUB_EXPR] = 1;
break;
case T_ALTERNATE:
/* Check for duplication. */
if (Elements[ALT_ID_SUB_EXPR] != 0)
{
ParseErr("duplicate sub-expression numbers.");
exit( 1 );
}
/* Get next token. */
if ((tkn = Lex( &sym )) != T_ID)
{
ParseErr("missing 'id' after 'alternate'.");
exit( 1 );
}
/* Get alternate ID string sub-expression number. */
if ((tkn = Lex( &sym )) != T_INT_NO)
{
ParseErr("missing sub-expression number.");
exit( 1 );
}
NewPart.AltIDStr = sym.no;
Elements[ALT_ID_SUB_EXPR] = 1;
break;
case T_CASE:
/* Check for duplication. */
if (Elements[CASE_SENSITIVITY] != 0)
{
ParseErr("duplicate sub-expression numbers.");
exit( 1 );
}
/* Get case sensitivity type. */
if ((tkn = Lex( &sym )) == T_SENSITIVE)
NewPart.Case = CASE_SENSITIVE;
else if (tkn == T_IGNORE)
NewPart.Case = IGN_CASE;
else
{
ParseErr("expected case sensitivity type after 'case'.");
exit( 1 );
}
Elements[CASE_SENSITIVITY] = 1;
break;
default:
ParseErr( "Unexpected token in ID part block" );
break;
}
}
/* Compile string and save pointer to expression tree in
* structure, then save structure in segment list.
*/
NewPart.ReExpr = ReCompile( NewPart.ReExpStr );
PartList = AppList(PartList, &NewPart);
/* Get closing token. */
if (tkn != T_R_BRACE)
{
/* Get and discard the right brace. */
if ((tkn = Lex( &sym )) != T_R_BRACE)
{
ParseErr("expecting '}' to close ID part block.");
exit( 1 );
}
}
}
/* Check closing token. */
if (tkn != T_R_BRACE)
{
ParseErr("expecting '}' to close ID prefix block.");
exit( 1 );
}
/* Append a null record. */
memset(&NewPart, 0, sizeof( PART_RE ));
PartList = AppList(PartList, &NewPart);
/* Return pointer to list. */
MemCopy(PartList,
PartList->List,
sizeof( PART_RE ) * PartList->NoElems);
/* Return pointer to list. */
return( (PART_RE *) PartList );
}
/*-----------------------------------------------------------------------------
| Routine : ParseIDs() --- Parse the ID blocks.
|
| Returns : A pointer to the root of the ID regular expression tree.
-----------------------------------------------------------------------------*/
static
IDENT *ParseIDs(void)
{
auto TOKEN sym;
auto int tkn;
auto char *tp;
auto IDENT NewID;
auto LIST *PreFixList;
/* Create ID list. */
PreFixList = CrtList( sizeof( IDENT ) );
/* Get regular expression source string. */
while ((tkn = Lex( &sym )) == T_DBL_QUOTE)
{
/* Get IDENT line regular expression string. */
for (tp = ReStr; ; tp = ReStr + strlen( ReStr ))
{
/* Copy string from token structure to buffer. */
strcpy(tp, sym.str);
/* Get next token. */
if ((tkn = Lex( &sym )) != T_DBL_QUOTE)
break;
}
/* Check for opening curly brace. */
if (tkn != T_L_BRACE)
{
ParseErr("expecting '{' after ID prefix regular expression.");
exit( 1 );
}
/* Create ID prefix regular expression string. */
NewID.ReExprStr = StrDup( ReStr );
/* Parse header regular expression configuration block. */
NewID.IdParts = ParseParts();
/* Compile string and save pointer to expression tree in
* structure, then save structure in segment list.
*/
NewID.ReExpr = ReCompile( NewID.ReExprStr );
PreFixList = AppList(PreFixList, &NewID);
}
/* Check closing token. */
if (tkn != T_R_BRACE)
{
ParseErr("expecting '}' to close ID block.");
exit( 1 );
}
/* Append a null record. */
memset(&NewID, 0, sizeof( IDENT ));
PreFixList = AppList(PreFixList, &NewID);
/* Return pointer to list. */
MemCopy(PreFixList,
PreFixList->List,
sizeof( IDENT ) * PreFixList->NoElems);
/* Return pointer to list. */
return( (IDENT *) PreFixList );
}
/*-----------------------------------------------------------------------------
| Routine : ReadConfig() --- Read the configuration file.
|
| Inputs : CfgFlNm - Name of configuration file name.
|
| Returns : A pointer to the root of the SEGMENT regular expression tree.
-----------------------------------------------------------------------------*/
SEGMENT *ReadConfig(char *CfgFlNm)
{
auto TOKEN sym;
auto int tkn;
auto char *tp;
auto SEGMENT NewSeg;
auto LIST *SegList;
/* Open the configuration file. */
OpenCfg( CfgFlNm );
/* Get token. */
if ((tkn = Lex( &sym )) != T_SEGMENT)
{
ParseErr("expecting SEGMENT token.");
exit( 1 );
}
/* Create segment list. */
SegList = CrtList( sizeof( SEGMENT ) );
/* Process multiple SEGMENT begin line blocks. */
while (tkn == T_SEGMENT)
{
/* Get regular expression source string. */
if ((tkn = Lex( &sym )) != T_DBL_QUOTE)
{
ParseErr("expecting regular expression source string.");
exit( 1 );
}
/* Get SEGMENT begin line regular expression string. */
for (tp = ReStr; ; tp = ReStr + strlen( ReStr ))
{
/* Copy string from token structure to buffer. */
strcpy(tp, sym.str);
/* Get next token. */
if ((tkn = Lex( &sym )) != T_DBL_QUOTE)
break;
}
/* Check for opening curly brace. */
if (tkn != T_L_BRACE)
{
ParseErr("expecting '{' to open SEGMENT block.");
exit( 1 );
}
/* Create SEGMENT regular expression string. */
NewSeg.ReExprStr = StrDup( ReStr );
/* Get header block prefix. */
if ((tkn = Lex( &sym )) != T_HEADER)
{
ParseErr("expecting 'header' in SEGMENT block.");
exit( 1 );
}
/* Get open curly brace. */
if ((tkn = Lex( &sym )) != T_L_BRACE)
{
ParseErr("expecting '{' to open HEADER block.");
exit( 1 );
}
/* Get header block. */
NewSeg.Header = ParseIDs();
/* Get body block prefix. */
if ((tkn = Lex( &sym )) != T_BODY)
{
ParseErr("expecting 'body' in SEGMENT block.");
exit( 1 );
}
/* Get open curly brace. */
if ((tkn = Lex( &sym )) != T_L_BRACE)
{
ParseErr("expecting '{' to open BODY block.");
exit( 1 );
}
/* Parse body ID block. */
NewSeg.Body = ParseIDs();
/* Compile string and save pointer to expression tree in
* structure, then save structure in SEGMENT begin line list.
*/
NewSeg.ReExpr = ReCompile( NewSeg.ReExprStr );
SegList = AppList(SegList, &NewSeg);
/* Get closing token. */
if ((tkn = Lex( &sym )) != T_R_BRACE)
{
ParseErr("expecting '}' to close SEGMENT block.");
exit( 1 );
}
/* Get next token. */
if ((tkn = Lex( &sym )) == EOF)
break;
}
/* Append a null record. */
memset(&NewSeg, 0, sizeof( SEGMENT ));
SegList = AppList(SegList, &NewSeg);
/* Return pointer to list. */
MemCopy(SegList,
SegList->List,
sizeof( SEGMENT ) * SegList->NoElems);
/* Close the configuration file and return a pointer to the new
* configuration tree.
*/
CloseCfg();
return( (SEGMENT *) SegList );
}
syntax highlighted by Code2HTML, v. 0.9.1