C Inference (Part 3 of 4)

TOOLS tools at raybed2.UUCP
Tue Jan 28 03:12:19 AEST 1986


As requested by the author we are reposting the source and documentation of
a C inference engine. Address all questions to George Hageman at:
UUCP: {asgb!benish}!hageman
MAIL:	George W. Hageman
	P.O. Box 11234
	Boulder, Colorado  80301
NOTE: RAYTHEON Inc. is not reponsible for the contents and/or consequences
of use of this software. This software is totally the work of George Hageman
and is being reposted as per his request (see following message). Address all
questions, comments, etc. to him.
=========================================================================
>From linus!decvax!seismo!hao!asgb!benish!hageman Fri Jan 24 07:31:04 1986
>Subject: Re:  C inference engine
>
>	... it seems that
>	the probability of getting somthing out to net.and is
>	inversely proportional to the number of hops it has to go.
>
>	I'll send you all of the shars (inference rulecompiler and 
>	the storm expert).  If you could make sure that they are
>	available at your site either by reposting them from your
>	end or by some other means it would be appreciated.
>
>	Thanks,
>
>George [Hageman]
=========================================================================
____Cut for rulecomp.sh______
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	expert.h
#	infer.h
#	inferenc.h
#	keywords.h
#	routine.h
#	getkeywo.c
#	putstrin.c
#	rulecomp.c
#	README.TO
#	makercom
#	rulecomp.str
# This archive created: Sun Jan 12 16:13:31 1986
export PATH; PATH=/bin:$PATH
if test -f 'expert.h'
then
	echo shar: will not over-write existing file "'expert.h'"
else
cat << \SHAR_EOF > 'expert.h'

/*************************************************************************
**									**
**	The software contained in this distribution is copyright (C)	**
**	by George Hageman 1985 and is released into the public 		**
**	domain with the following restrictions:	 			**
**									**
**		(1)  This software is intended for non-commertial	**
**			usage.						**
**		(2)  I am held save from damages resulting from		**
**			its use, and					**
**		(3)  The following concepts and legal jargon are	**
**			agreed to by the user of this software.		**
**									**
**	User-supported software concept: 				**
**									**	
**	IF    you find use for this software				**
**	ANDIF it saves you some development time			**
**	THEN        send me $10.00					**
**	ANDTHENHYP  you will feel good!					**
**									**
**									**
**	This source code is provided on an "as is" basis without	**
**	warranty of any kind, expressed or implied, including but	**
**	not limited to the implied warranties of merchantability	**
**	and fitness for a particular purpose.  The entire risk as	**
**	to quality and performance of this software is with you. 	**
**	Should the software prove defective, you assume the entire	**
**	cost of all necessary repair, servicing, or correction.  In	**
**	no event will the author be liable to you for any damages,	**
**	including any lost profits, lost savings, or other		**
**	incidental or consequential damages arising out of the  use	**
**	of inability to use this software.  In short my friends, I	**
**	have done  a reasonable ammount of work in debugging this	**
**	software and I think it is pretty good but, as you know,	**
**	there is always some chance that a bug is still lurking 	**
**	around. If you should happen to be lucky enough to  find one,	**
**	please let me know so I	can make an attempt to fix it.		**
**									**
**				Thanks,					**
**									**
**				George Hageman				**
**				P.O. Box 11234				**
**				Boulder, Colorado 80302			**
**									**
*************************************************************************/


/*
**	These are the structures of the rulebase which will
**	be used to compile the rules into.  
*/

#define FALSE 			0 
#define TRUE  			-1 
#define MAX_STRING_BUFF 	5000
#define MAX_STR_LEN		100
#define MAX_RULE_STATEMENTS 	500
#define MAX_HYPS		250 
#define ANTECEDENT 		1
#define CONSEQUENT 		2
#define COMMENT_CHAR		'!'
#define	BLANK 			0x20
#define EOL			0x0a

#define KEY_EOF			-2 
#define LINE_ERROR		-3
#define KEY_WORD_ERROR		-4
#define ERROR		 	-5	
#define STR_LEN_ERROR		-6

/*
**	Other definitions of key words
*/

#define	AND_N       	 0
#define	ANDIF_N     	 1
#define	ANDIFRUN_N  	 2
#define	ANDNOT_N    	 3	
#define	ANDNOTRUN_N 	 4
#define	ANDRUN_N    	 5
#define	ANDTHEN_N   	 6 
#define ANDTHENHYP       7
#define	ANDTHENRUN_N	 8
#define	ANDTHENRUNHYP_N  9
#define	IF_N        	10
#define	IFNOT_N     	11
#define	IFNOTRUN_N  	12
#define	IFRUN_N     	13
#define	THEN_N      	14
#define	THENHYP_N     	15  
#define THENRUN_N	16
#define THENRUNHYP_N    17
		
/*
**	Flag definitions:
*/

#define	STRING_TRUE	 1
#define	STRING_FALSE	 2
#define	ROUTINE_TRUE	 3
#define ROUTINE_FALSE	 4
#define STRING_TRUE_HYP  5
#define ROUTINE_TRUE_HYP 6

#define NUM_KEYWORDS	18

struct	rule_statement_r
		{
		int flag ;   /* logical flag for inference engine */
		int string ; /* offset into string buffer */
		};


/* 
**	rules are compiled into the array rules in the folloiwng form:
**
**	antecedent-group consequent-group 
**	... 
**	antecedent-group consequent-group
**	end-group
**
**	Each group of consequences and antecedents
**	are compiled in a group like the following:
**
**	flag pointer flag pointer ... flag pointer 0-flag 0-pointer
**
**	The end-group is merely:
**
**	0-flag 0-pointer 0-flag 0-pointer 0-flag 0-pointer
**
**	flags are used by the inference engine to determine what to
**	do with the following string pointer.  
**	string pointers are merely offsets into the string array.
**	The pointers may either point
**	to a string which is a rule statement such as "the animal has wings"
**	or is a UNIX pathname for a particular routine which is to be
**	executed such as "/g1/hageman/Diagnostics/Disk1diag".   This
**	routine will then be executed and will return either a true or
**	false indication.  Latter versions of the inference engin may be
**	capable of returning more than this via some pipe-line mechanism or
**	other.
**
**	Once an anicedent whether string or routine is verified it is placed
**	in either a known-true or known-false stack for later verification 
**	in other rules which use them.  In short they only have to be verified
**	once.
**
**	Examples of a rule structure are:
**
**	IFNOT the animal is a bird
**	AND the animal has wings
**	ANDNOT the animal lives in caves
**	AND the animal is nocternal
**	THEN the animal is a bat
**	IF the animal is a bat
**	ANDRUN /g1/hageman/Src/Expert/speed_of_bat
**	THENHYP the bat is out of hell
**	IF the animal is a bat
**	ANDNOTRUN /g1/hageman/Src/Expert/speed_of_bat
**	THENHYP the bat is out of cave
**
*/
SHAR_EOF
fi # end of overwriting check
if test -f 'infer.h'
then
	echo shar: will not over-write existing file "'infer.h'"
else
cat << \SHAR_EOF > 'infer.h'


/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*
**	the following are the global common variables which
**	are used in the inference engine...
**
**	all routines except inference.c should have this
**	file included.
*/

#define	MAX_KNOWN	500

int	numHypot, hypStack[MAX_HYPS],strBuffOfst ;
char	strBuff[MAX_STRING_BUFF] ;
int	ruleBuffOfst ;
int	knownTrue[MAX_KNOWN], knownFalse[MAX_KNOWN] ;
int	numTrue, numFalse ;
struct  rule_statement_r ruleBuff[MAX_RULE_STATEMENTS] ;

SHAR_EOF
fi # end of overwriting check
if test -f 'inferenc.h'
then
	echo shar: will not over-write existing file "'inferenc.h'"
else
cat << \SHAR_EOF > 'inferenc.h'


/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*************************************************************************
**									**
**	The software contained in this distribution is copyright (C)	**
**	by George Hageman 1985 and is released into the public 		**
**	domain with the following restrictions:	 			**
**									**
**		(1)  This software is intended for non-commertial	**
**			usage.						**
**		(2)  I am held save from damages resulting from		**
**			its use, and					**
**		(3)  The following concepts and legal jargon are	**
**			agreed to by the user of this software.		**
**									**
**	User-supported software concept: 				**
**									**	
**	IF    you find use for this software				**
**	ANDIF it saves you some development time			**
**	THEN        send me $10.00					**
**	ANDTHENHYP  you will feel good!					**
**									**
**									**
**	This source code is provided on an "as is" basis without	**
**	warranty of any kind, expressed or implied, including but	**
**	not limited to the implied warranties of merchantability	**
**	and fitness for a particular purpose.  The entire risk as	**
**	to quality and performance of this software is with you. 	**
**	Should the software prove defective, you assume the entire	**
**	cost of all necessary repair, servicing, or correction.  In	**
**	no event will the author be liable to you for any damages,	**
**	including any lost profits, lost savings, or other		**
**	incidental or consequential damages arising out of the  use	**
**	of inability to use this software.  In short my friends, I	**
**	have done  a reasonable ammount of work in debugging this	**
**	software and I think it is pretty good but, as you know,	**
**	there is always some chance that a bug is still lurking 	**
**	around. If you should happen to be lucky enough to  find one,	**
**	please let me know so I	can make an attempt to fix it.		**
**									**
**				Thanks,					**
**									**
**				George Hageman				**
**				P.O. Box 11234				**
**				Boulder, Colorado 80302			**
**									**
*************************************************************************/


/*
Expert system inference engine

This inference engine is backwards-chaining only and features the
running of binary files if:

	1) they are antecedents associated with a particuar consequent
	   being proved, or
	2) they are consequents which have been proven true by verify().
	   their actual predicate value will be determined by their returned
	   result after running.

This inference engine is designed with diagnostics in mind and so will probably
be best suited for this application.  Later revisons will include 
forward-chaining so that the user will have the opportunity to give pre-existant
conditons, or that these my be supplied by the calling process.

(If you cant tell by the above description -- I am very excited about the 
possibilties presented in this form of computer control of the diagnostic
process... Geo.)

See structure design for details of operation,  but basically the 

inference reads in all of the compiled information as produced by the
    rule compiler.
    
it proceeds to attempt to prove each consequent by proving the truth
	or falseness of any antecedent associated with this consequent.
if any antecedent of a consequent turns out to be a consequent itself, then
        the inference engine will recursively attempt to prove this consequent.

the process is complete when all of the predicate values of the consequents has
	been determined.
	
Additional features which I may put in at a later time is the abiltiy for
the inference engine to expalin itself to the user when the user asks why
the inference engine needs to know the predicate value of a particular
antecedent.   This will be done by forward and backward chaining of predicat
clauses, the truth of each will be displayed.
*/
#define	MAX_ANTECEDENTS		25

extern 	int	numHypot, hypStack[],strBuffOfst ;
extern 	char	strBuff[] ;
extern	int	ruleBuffOfst ;
extern	int	knownTrue[], knownFalse[] ;
extern	int	numTrue, numFalse ;
extern	struct  rule_statement_r ruleBuff[] ;
SHAR_EOF
fi # end of overwriting check
if test -f 'keywords.h'
then
	echo shar: will not over-write existing file "'keywords.h'"
else
cat << \SHAR_EOF > 'keywords.h'

char	*keyWords[NUM_KEYWORDS] =
	{
	"AND           ",
	"ANDIF         ",
	"ANDIFRUN      ",
	"ANDNOT        ",
	"ANDNOTRUN     ",
	"ANDRUN        ",
	"ANDTHEN       ", 
	"ANDTHENHYP    ",
	"ANDTHENRUN    ",
	"ANDTHENRUNHYP ",
	"IF            ",
	"IFNOT         ",
	"IFNOTRUN      ",
	"IFRUN         ",
	"THEN          ",
	"THENHYP       ",
	"THENRUN       ",
	"THENRUNHYP    "
	} ;

SHAR_EOF
fi # end of overwriting check
if test -f 'routine.h'
then
	echo shar: will not over-write existing file "'routine.h'"
else
cat << \SHAR_EOF > 'routine.h'


/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*
**	these are the two return values
**	which must be returned as the exit
**	value.  Any other will result in
**	an assumption that the result is true
**	or that some sort of error occured.
*/

#define RETURN_ROUTINE_TRUE	254
#define RETURN_ROUTINE_FALSE	255

SHAR_EOF
fi # end of overwriting check
if test -f 'getkeywo.c'
then
	echo shar: will not over-write existing file "'getkeywo.c'"
else
cat << \SHAR_EOF > 'getkeywo.c'

#include <stdio.h>
#include <string.h>
#include "expert.h"


/******************************************************************
**
**
**		GET KEYWORD
**
**
******************************************************************/

/*
**
**	getKeyWord(infile,keyWords,lineNum) ;
**
**	returns either KEY_EOF, or number of keyword, or indications
**		that keyword was not first word on line.
**
*/

int	getKeyWord (infile,keyWords,lineNum)

FILE	*infile ;
char	*keyWords[] ;
int	*lineNum ;

{
int	firstc,c,i,j ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-GET_KEYWORD") ;
#endif

/*
**	get first non blank character
*/

i = 0 ;
while( TRUE )
	{
	c = getc(infile);
	putchar(c) ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-GET_KEYWORD character= %c,%x",c,c) ;
#endif
	if( c == EOF )
		return (KEY_EOF) ;
	if( (i == 0) && (c == COMMENT_CHAR) )	/* ignore comment line */
		{
		while(  c != EOL )
			{
#ifdef DEBUG
	fprintf(stdout,"\nDEBUG-GET_KEYWORD (delete comment) character=%c,%x",c,c);
#endif
			c = getc(infile) ;
			if( c == EOF)
				return (KEY_EOF) ;
			putchar(c) ;
			} 
		printf("%04d  ",*lineNum) ;
		*lineNum += 1 ;
		i = 0 ;
		}
	else
		{
		i = 1 ;
		if( c != BLANK )
			{
			if(c == EOF)
				return(KEY_EOF) ;
			break ;
			}
		}
	}

/*
**	locate first keyword with matching first character
*/

for( i = 0 ; i < NUM_KEYWORDS ; i++ )
	{
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-GET_KEYWORD i=%d, keyword=%c",i,*(keyWords[i])) ;
#endif
	if ( *(keyWords[i]) == c )
		break ;
	}
if( i == NUM_KEYWORDS )
	return (KEY_WORD_ERROR)  ;

/*
**	find the key word if there
**
**	Note that this search algrorithm is very dependant on having
**	the keyWord file being in strict alphabetical order!!!
**
*/

j=0 ; 		
firstc = c ;

while( i < NUM_KEYWORDS  )
	{
	if( (c=getc(infile)) == *(keyWords[i]+(++j)) )
		{
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-GET_KEYWORD char=%c,keyword=%c",c,*((keyWords[i])+j)) ;
#endif
		putchar(c) ;
		if( c == BLANK )
			return (i) ;
		if( c == EOF )
			return(KEY_EOF) ;
		}
/*
**	increment the keyWord pointer to be tested
**	decrement the character pointer in keyWord
**	and put the last character tested back.
*/

/*
**	since the keyWord array is alphabetical, testing
**	for a first character change would indicate that
**	the possible keywords have been exhausted.
*/

	else
		{
		i++ ;
		j-- ;
		ungetc(c,infile) ;
		if( c == EOF )
			return (KEY_EOF) ;
		if( firstc != *(keyWords[i]))
			return (KEY_WORD_ERROR) ;
		}
	}

/*
**	no keywords were found because we exhausted the keyWord array
*/

return (KEY_WORD_ERROR)  ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'putstrin.c'
then
	echo shar: will not over-write existing file "'putstrin.c'"
else
cat << \SHAR_EOF > 'putstrin.c'

#include <stdio.h>
#include <string.h>
#include "expert.h"


/*****************************************************************
**
**	PUT STRING
**
**	looks for string on rule line and
**	    either returns the offset into the
**		string buffer if found or places
**		it into the string buffer and returns
**		the offset to it.
**	strBuffOfst is the pointer to the offset to
**		the last used location in the string buffer
**
**
*****************************************************************/

int	putString (infile,strBuff,strBuffOfst) 

	FILE	*infile ;
	char	*strBuff ;
	int	*strBuffOfst ;

{
int	i,offSet,strLen,c,newline ;
char	buff[MAX_STR_LEN] ;

#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-PUTSTRING strBuffOfst= %d",*strBuffOfst) ;
#endif

/*
**
**	get file positioned to first non blank character (after keyword)
**
*/

while( ( c=getc(infile)) == BLANK )
	putchar(c) ;
if( c == EOL )
	{
	putchar(c) ;
	return (LINE_ERROR) ;
	}
if( c == EOF )
	return (KEY_EOF) ;
ungetc(c,infile);

#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-PUTSTRING c = %c", c) ;
#endif
/*
**
** 	load the string on the line into the string buffer for 
**	later comparison to strings in the line buffer.
**
*/
newline = FALSE ;
for( i = 0 ; i < (MAX_STR_LEN-1) ; i++ )
	{
	buff[i]=c=getc(infile) ;

#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-PUTSTRING c =%c, i = %d -- ", c,i) ;
#endif
	putchar(c) ;
	if(c == '\\')
		{
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-PUTSTRING newline is TRUE");
#endif
		newline = TRUE ;
		continue ;
		}
	if( newline == TRUE )
		{
		if( c == 'n' ) 
			{
			i -= 1 ;
			buff[i] = '\n' ;
			}
#ifdef	DEBUG
		fprintf(stdout,"\nDEBUG-PUTSTRING newline is FALSE");
#endif
		newline = FALSE ;
		continue ;
		}
	if(c == EOL)
		{
		buff[i]=0 ;
		break ;
		}
	if(c == EOF)
		{
		buff[i]=0 ;
		ungetc(c,infile) ;
		break ;
		}
	}

/*
**	remove trailing blanks in the buffer 
**
*/
for( --i ; i > -1 ; i-- )
	{
	if( buff[i] != BLANK )
		break ;
	buff[i]=0 ;
	}	
if(i <= 0)
	return(STR_LEN_ERROR) ;
strLen = i ;

buff[MAX_STR_LEN-1] = 0 ;

/*
**	at this point strLen should be the offset to the last character
**	in the string and is also, therefore, the length of the string -1
**
**	search for the string in the string buffer
**	return offset to string if found else put the string
**	in the string buffer and uptate buffer offset returning
**	pointer to new string
**
*/

offSet = 0 ;
while( offSet < *strBuffOfst )
	{
	if( strcmp(&strBuff[offSet], buff) == 0 )
		return(offSet) ;
	while( strBuff[++offSet] ) ;   	/* look for end of null trmntd string */
	++offSet ;			/* move past the null to next string  */
	}
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-PUTSTRING strBuffOfst= %d",*strBuffOfst) ;
	fprintf(stdout,"\nDEBUG-PUTSTRING offSet = %d",offSet) ;
	fprintf(stdout,"\nDEBUG-PUTSTRING strBuff= %s",&strBuff[offSet]);
	fprintf(stdout,"\nDEBUG-PUTSTRING buff   = %s",buff) ;
#endif
strcpy(&strBuff[*strBuffOfst],buff) ;
if(*strBuffOfst == 0 )
	{
	*strBuffOfst += strLen + 2 ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-PUTSTRING strBuffOfst= %d",*strBuffOfst) ;
#endif
	return(0) ;
	}
else
	{
	offSet = *strBuffOfst ;
	*strBuffOfst += strLen + 2 ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-PUTSTRING strBuffOfst= %d",*strBuffOfst) ;
#endif
	return(offSet) ;
	}
}
SHAR_EOF
fi # end of overwriting check
if test -f 'rulecomp.c'
then
	echo shar: will not over-write existing file "'rulecomp.c'"
else
cat << \SHAR_EOF > 'rulecomp.c'

/*****************************************************************
**								**
**	  Inference -- (C) Copyright 1985 George Hageman	**
**								**
**	    user-supported software:				**
**								**
**		    George Hageman				**
**		    P.O. Box 11234				**
**		    Boulder, Colorado 80302			**
**								**
*****************************************************************/

/*****************************************************************
**	Expert system rule compiler
**
**	This compiler produces a file of the form:
**
**	Number_of_bytes_in_hypstack_section
**	Hypstack_section
**	Number_of_bytes_in_rule_section
**	Rule base section
**	Number_of_bytes_in_string_section
**	String section
**	EOF
**	
**	The rule section consits of integer flags and long-integer
**	pointers to strings in the string section.
**	
**	All strings in the string section will be unique nomatter how
**	many times they are repeated in the rules which are compiled
**	into the rule base by this compiler.
**
**
**	Usage:
**
**	rulecomp rule.file object.file
**
*****************************************************************/

/*****************************************************************
**
**	rule compiler main routine
**
*******************************************************************/

#include <stdio.h>
#include <string.h>

#include "expert.h"
#include "keywords.h"

int	main(argc,argv)
int argc ;
char **argv ;

{
char	strBuff[MAX_STRING_BUFF] ;
int	i ;
int	state ;
int	strAddr;
int	numHypot, hypStack[MAX_HYPS],strBuffOfst ;
int	c ;
int	ruleBuffOfst ;
int	keyWrdNum ;
int	getKewWord() ;
int	putString() ;
int	lineNum ;

struct  rule_statement_r ruleBuff[MAX_RULE_STATEMENTS] ;

int	done ;
FILE	*infile, *outfile ;

for( done = 0; done < MAX_STRING_BUFF; done ++ )
	strBuff[done] = 0 ;
for( done = 0; done < MAX_HYPS ; done++ )
	hypStack[done]=0 ;
done = FALSE ;

#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP argc=%d ",argc) ;
#endif

if(argc != 3 )
	{
	fprintf(stdout, "\n\n Usage: rulecomp in.file out.file\n\n" ) ;
	exit() ;
	}
infile = fopen( argv[1], "r" );
if(infile == NULL)
	{
	fprintf(stdout,"\n\n Cannot open input file %s ", argv[1]);
	exit() ;
	}
outfile = fopen(argv[2], "wb" ) ;
if(outfile == NULL)
	{
	fprintf(stdout,"\n\n Cannot open output file %s ",argv[2]);
	exit() ;
	}
done = FALSE ;

numHypot = 0 ;				/* number of hypothesis is zero */
strBuffOfst = 0 ;			/* pointer in buffer is zero */
ruleBuffOfst = 0 ;			/* rule buffer offset is zero */


state = ANTECEDENT ;

/* Compilation states:
**
**	Antecedent group in progress -- 1
**	Consequent group in progress -- 2
**
**	If state 1 and you get a consequent then output group barrier.
**		change state to 2.
**	If state 2 and you get an antecedent then output group barrier.
**		change state to 1.
*/
lineNum = 1 ;
printf("\n") ;
while( !done )
	{

/*
**   	get the key word number from the
**	input file
*/
	printf("%04d  ",lineNum++) ;
	keyWrdNum = getKeyWord(infile,keyWords,&lineNum);
/*
**	error occured on line clear the line and
**	start over.
*/
	if(keyWrdNum == KEY_EOF)
		{
		done = TRUE ;
		continue ;
		}
	if(keyWrdNum == KEY_WORD_ERROR)
		{
		while( ( (c = getc(infile))) != EOL && (c != EOF) )
			putchar(c) ;
		fprintf(stdout," **** KEY WORD not found on line " );
		if(c == EOF)
			{
			done = TRUE ;
			break ;
			}
		putchar(c) ;
		continue;
		}
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP keyWrdNum = %d",keyWrdNum ) ;
#endif
/*
**	based on the key Word build the
**	rule files
*/

	switch(keyWrdNum)
		{
		case AND_N :
		case ANDIF_N :
		case IF_N :
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case AND_N, ANDIF_N, IF_N ") ;
#endif
			if(state == CONSEQUENT)
				{
				state = ANTECEDENT ;
				ruleBuff[ruleBuffOfst].flag = NULL ;
				ruleBuff[ruleBuffOfst++].string = NULL ;
				}
			ruleBuff[ruleBuffOfst].flag = STRING_TRUE ;
			strAddr=putString(infile,strBuff,&strBuffOfst) ;
			ruleBuff[ruleBuffOfst++].string = strAddr ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP strAddr= %d",strAddr ) ;
#endif
			break ;
		case ANDRUN_N :
		case ANDIFRUN_N :
		case IFRUN_N :
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case AND_N, ANDIF_N, IF_N ") ;
#endif
			if(state == CONSEQUENT)
				{
				state = ANTECEDENT ;
				ruleBuff[ruleBuffOfst].flag = NULL ;
				ruleBuff[ruleBuffOfst++].string = NULL ;
				}
			ruleBuff[ruleBuffOfst].flag = ROUTINE_TRUE ;
			strAddr=putString(infile,strBuff,&strBuffOfst) ;
			ruleBuff[ruleBuffOfst++].string = strAddr ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP strAddr= %d",strAddr ) ;
#endif
			break ;
		case ANDNOT_N :
		case IFNOT_N  :
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case ANDNOT_N, IFNOT_N    ") ;
#endif
			if(state == CONSEQUENT)
				{
				state = ANTECEDENT ;
				ruleBuff[ruleBuffOfst].flag = NULL ;
				ruleBuff[ruleBuffOfst++].string = NULL ;
				}
			ruleBuff[ruleBuffOfst].flag = STRING_FALSE ;
			strAddr=putString(infile,strBuff,&strBuffOfst) ;
			ruleBuff[ruleBuffOfst++].string = strAddr ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP strAddr=%d",strAddr) ;
#endif
			break ;
		case ANDNOTRUN_N :
		case IFNOTRUN_N  :
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case ANDNOT_N, IFNOT_N    ") ;
#endif
			if(state == CONSEQUENT)
				{
				state = ANTECEDENT ;
				ruleBuff[ruleBuffOfst].flag = NULL ;
				ruleBuff[ruleBuffOfst++].string = NULL ;
				}
			ruleBuff[ruleBuffOfst].flag = ROUTINE_FALSE ;
			strAddr=putString(infile,strBuff,&strBuffOfst) ;
			ruleBuff[ruleBuffOfst++].string = strAddr ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP strAddr=%d",strAddr) ;
#endif
			break ;
		case ANDTHEN_N :
		case THEN_N :
		case THENHYP_N :
		case ANDTHENHYP :
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case ANDTHEN_N,THEN_N,THENHYP_N");
#endif
			if(state == ANTECEDENT)
				{
				state = CONSEQUENT ;
				ruleBuff[ruleBuffOfst].flag = NULL ;
				ruleBuff[ruleBuffOfst++].string = NULL ;
				}

			if( (keyWrdNum == THENHYP_N) || (keyWrdNum == ANDTHENHYP) )
				ruleBuff[ruleBuffOfst].flag = STRING_TRUE_HYP ;
			else
				ruleBuff[ruleBuffOfst].flag = STRING_TRUE ;

			strAddr=putString(infile,strBuff,&strBuffOfst) ;
			hypStack[numHypot++] = ruleBuffOfst ;
			ruleBuff[ruleBuffOfst++].string = strAddr ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP strAddr=%d",strAddr) ;
#endif
			break ;
		case ANDTHENRUN_N :
		case THENRUN_N :
		case THENRUNHYP_N :
		case ANDTHENRUNHYP_N :
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case ANDTHEN_N,THEN_N,THENHYP_N");
#endif
			if(state == ANTECEDENT)
				{
				state = CONSEQUENT ;
				ruleBuff[ruleBuffOfst].flag = NULL ;
				ruleBuff[ruleBuffOfst++].string = NULL ;
				}

			if( (keyWrdNum == THENRUNHYP_N ) || (keyWrdNum == ANDTHENRUNHYP_N) )
				ruleBuff[ruleBuffOfst].flag = ROUTINE_TRUE_HYP ;
			else
				ruleBuff[ruleBuffOfst].flag = ROUTINE_TRUE ;

			strAddr=putString(infile,strBuff,&strBuffOfst) ;
			hypStack[numHypot++] = ruleBuffOfst ;
			ruleBuff[ruleBuffOfst++].string = strAddr ;
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP strAddr=%d",strAddr) ;
#endif
			break ;
		case KEY_EOF :
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case KEY_EOF ") ;
#endif
			done = TRUE ;
			break ;
		default:
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP case DEFAULT "  ) ;
#endif
			fprintf(stdout, " \n\n illegal keyword number found " );
		}
	}

/* 
**	set up some blank space at the end of the rule file 
*/

ruleBuff[ruleBuffOfst].flag = NULL ;
ruleBuff[ruleBuffOfst++].string = NULL ;
ruleBuff[ruleBuffOfst].flag = NULL ;
ruleBuff[ruleBuffOfst++].string = NULL ;
ruleBuff[ruleBuffOfst].flag = NULL ;
ruleBuff[ruleBuffOfst++].string = NULL ;
if(ruleBuffOfst%2 == 0 )
	{
	ruleBuff[ruleBuffOfst].flag = NULL ;
	ruleBuff[ruleBuffOfst++].string = NULL ;
	}
#ifdef	DEBUG
	fprintf(stdout,"\nDEBUG-RULECOMP ruleBoffOfst=%d", ruleBuffOfst ) ;
#endif
/*
**	ruleBuffOfst -3 is the number of rule statements processed 
*/

/*
**
**	Write out all of the compiled information as follows:
**
**		numHypot*2	Number_of_bytes_in_hypstack_section
**		hypStack	Hypstack_section
**		ruleBuffOfst	Number_of_bytes_in_rule_section
**		ruleBuff	Rule base section
**		strBuffOfst	Number_of_bytes_in_string_section
**		strBuff		String section
**		EOF
**
*/
#ifdef DEBUG

	fprintf(stdout,"\nDEBUG numHypot=%d",numHypot ) ;

	for(i=0;i<numHypot;i++)
		fprintf(stdout,"\nDEBUG     hypStack=%d",hypStack[i] ) ;

	fprintf(stdout,"\nDEBUG ruleBuffOfst=%d  ",ruleBuffOfst ) ;

	for(i=0;i<ruleBuffOfst;i++)
		{
		fprintf(stdout,"\nDEBUG ruleBuff[%d].flag=%d ",i,ruleBuff[i].flag ) ;
		fprintf(stdout,"\nDEBUG ruleBuff[%d].string=%d ",i,ruleBuff[i].string ) ;
		}

	fprintf(stdout,"\nDEBUG strBuffOfst=%d",strBuffOfst ) ;

	for(i=0;i<strBuffOfst;i++)
		fprintf(stdout,"\nDEBUG strBuff[%d]=%d(d),%c(c)",i,strBuff[i],strBuff[i] ) ;
#endif
fwrite(&numHypot,sizeof(int),1,outfile) ;
fwrite(hypStack,sizeof(int),numHypot,outfile) ;
fwrite(&ruleBuffOfst,sizeof(int),1,outfile) ;
fwrite(ruleBuff,2*sizeof(int),ruleBuffOfst,outfile) ;
fwrite(&strBuffOfst,sizeof(int),1,outfile) ;
fwrite(strBuff,1,strBuffOfst,outfile) ;
fclose(infile);
fclose(outfile);
#ifdef DEBUG
	fclose(stdout) ;
#endif
printf("\n\n") ;
exit(0) ;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'README.TO'
then
	echo shar: will not over-write existing file "'README.TO'"
else
cat << \SHAR_EOF > 'README.TO'
To compile:

cc *.c -DUNIXSV -orulecomp


No other command is necessary..

Geo.


SHAR_EOF
fi # end of overwriting check
if test -f 'makercom'
then
	echo shar: will not over-write existing file "'makercom'"
else
cat << \SHAR_EOF > 'makercom'
#
# 	Makefile 
# 

# debug the file and do a 80286 model

#CFLAGS = /DDEBUG /G0 /Zd /Od /Fc

CFLAGS = /G0

# All object modules

rulecomp.obj : rulecomp.c expert.h keywords.h
	msc $(CFLAGS) rulecomp.c ;

getkeywo.obj : getkeywo.c expert.h
	msc $(CFLAGS) getkeywo.c ;

putstrin.obj : putstrin.c expert.h
	msc $(CFLAGS) putstrin.c ;


# 	rulecomp.exe -- main target
#
rulecomp.exe : rulecomp.obj getkeywo.obj putstrin.obj 
	link rulecomp.obj getkeywo.obj putstrin.obj ,rulecomp.exe,/STACK:15000 ;
#	link rulecomp.obj getkeywo.obj putstrin.obj ,rulecomp.exe,/MAP/LINE/STACK:15000 ;
#
#	mapsym rulecomp
#
SHAR_EOF
fi # end of overwriting check
if test -f 'rulecomp.str'
then
	echo shar: will not over-write existing file "'rulecomp.str'"
else
cat << \SHAR_EOF > 'rulecomp.str'

/*
Pseudo code for the rule compiler :

compile_rules(rule_file,output_compile_file)
{
OPEN rule_file ;
WHILE ( EOF in rule_file NOT reached )
	{
	locate keyword
	IF ( keyword not located on line and line not blank )
		{
		OUTPUT error message to user telling of problem
		}
	place flag associated with keyword into rule section
	IF (following string is in string section)
		{
		place the address of the string into the rule section
		}
	ELSE
		{
		place the string into the string section (0 delimit)
		place the address of the string into the rule section
		}
	IF ( the keyword is a THEN or THENHYP )
		{
		place and additional IF flag and a zeroed 
		    pointer in the rule section 
		place address of hypothesis or then clause into
		    hypstack section
		}
	}
IF (last keyword not of a "HYP" type )
	{
	OUTPUT warning to user about this being a problem
	}
place  two successive IF flags - zeroed pointer into the rule section
    to mark the end of the rules section.
CLOSE rule_file 
OPEN compile_output_file 
OUTPUT number of bytes in rule section to compile_output_file
COPY rule section to compile_output_file
OUTPUT number of bytes in string section to compile_output_file
COPY string section to compile_output_file
CLOSE compile_output_file
}
*/
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0



More information about the Comp.sources.unix mailing list