// this is the parser of a model debugging file
// the format of a debugging file is
// debugFile : (action)* ;
// action : test id-list #END
// | #FILE <filename>
// ;
// test : #TRUE
// | #FALSE
// | #INCOMPLETE
// | #COMPLETE
// ;
// id-list: (IDENTIFIER)+ ;
import java.io.*;
import java.util.*;
import Jakarta.util.*;
class dparser {
static final String fileToken;
static final int fileTokenLength;
static final String falseToken;
static final int falseTokenLength;
static final String trueToken;
static final int trueTokenLength;
static final String endToken;
static final int endTokenLength;
static final String incompleteToken;
static final int incompleteTokenLength;
static final String completeToken;
static final int completeTokenLength;
static final String comment;
static {
fileToken = "#file";
fileTokenLength = fileToken.length();
falseToken = "#false";
falseTokenLength = falseToken.length();
trueToken = "#true";
trueTokenLength = trueToken.length();
endToken = "#end";
endTokenLength = endToken.length();
incompleteToken = "#incomplete";
incompleteTokenLength = incompleteToken.length();
completeToken = "#complete";
completeTokenLength = completeToken.length();
comment = "#";
}
Stack stack; // stack of filenames to process
String filename; // name current file being processed
int lineno; // line# in current file
LineNumberReader l; // handle to file being processed
dparser( String fname ) throws dparseException {
stack = new Stack();
filename = fname;
lineno = 0;
try {
l = new LineNumberReader( new FileReader( filename ) );
}
catch ( Exception e ) {
throw new dparseException( e.getMessage() );
}
}
// returns the next SATtest, else null (when at end of debug files)
//
public SATtest getNextTest() throws dparseException {
String tmpstr;
String s;
SATtest current = null;
try {
while ( true ) {
// Step 1: read in line
//
lineno = l.getLineNumber();
s = l.readLine();
// Step 2: if at end of file, then process the next file on stack
// else, return null as processing is finished.
if ( s == null ) {
l.close();
if ( stack.empty() )
return null;
filename = ( String ) stack.pop();
l = new LineNumberReader( new FileReader( filename ) );
continue;
}
// In the following, we'll define actions per line of
// a debug file.
//
// Step 3: process fileToken if present
//
if ( s.startsWith( fileToken ) ) {
// fileToken cannot appear inside a test-end pair
//
if ( current != null ) {
throw new dparseException( "Parse error at " + filename + ":" +
lineno + " " + current.name + " not ended properly. " +
fileToken + " appears inside its definition" );
}
// else push name on file stack for later processing
//
stack.push( ( s.substring( fileTokenLength ) ).trim() );
continue;
}
// Step 4: process true/false/complete/incomplete statement if present
//
if ( s.startsWith( trueToken ) || s.startsWith( falseToken ) ||
s.startsWith( completeToken ) || s.startsWith( incompleteToken ) ) {
// if we are inside a t/f/c/i statement (i.e. a SAT test)
// then this is an error
//
if ( current == null ) {
if ( s.startsWith( trueToken ) ) {
tmpstr = ( s.substring( trueTokenLength ) ).trim();
current = new SATtest( tmpstr, true, false );
}
if ( s.startsWith( falseToken ) ) {
tmpstr = ( s.substring( falseTokenLength ) ).trim();
current = new SATtest( tmpstr, false, false );
}
if ( s.startsWith( completeToken ) ) {
tmpstr = ( s.substring( completeTokenLength ) ).trim();
current = new SATtest( tmpstr, true, true );
}
if ( s.startsWith( incompleteToken ) ) {
tmpstr = ( s.substring( incompleteTokenLength ) ).trim();
current = new SATtest( tmpstr, false, true );
}
}
else {
throw new dparseException( "Parse error at " + filename + ":" +
lineno + " " + current.name + " not ended properly." );
}
continue;
}
// Step 5: process end token
//
if ( s.startsWith( endToken ) ) {
// if an end token appears without a prior true/false
// token, this is an error
//
if ( current == null ) {
throw new dparseException( "Parse error at " + filename + ":" +
lineno + " unmatched " + endToken );
}
// if not, then we've finished reading a SAT test
//
else {
return current;
}
}
// Step 6: ignore comments (lines beginning with #)
//
if ( s.startsWith( comment ) )
continue;
// Step 7: if we're reading a SAT test, parse identifiers
// and add to test
//
if ( current != null ) {
tokenizeLine( s, current );
continue;
}
// Step 8: otherwise, only blank lines are ignored. We'll
// complain otherwise
//
if ( ! ( s.trim().equals( "" ) ) )
throw new dparseException( "Ignoring " + filename +
":" + lineno + " " + s );
}
}
catch ( Exception e ) {
throw new dparseException( e.getMessage() );
}
}
// method takes a line and adds its tokens (feature names) to the
// provided SATtest
//
void tokenizeLine( String line, SATtest t ) throws dparseException {
StringTokenizer st = new StringTokenizer( line );
while ( st.hasMoreTokens() ) {
String tok = st.nextToken();
if ( tok.equals( "-" ) ) {
throw new dparseException( "minus (-) cannot be a " +
" separate token at " + filename + ":" + lineno );
}
if (t.isComplete() && tok.startsWith("-"))
throw new dparseException( "minus (-) cannot be used " +
" in a complete test at " + filename + ":" + lineno );
t.add( tok );
}
}
}