//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA). All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
package gov.nasa.jpf.vm;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.HashMap;
import gov.nasa.jpf.JPFException;
/**
* a little helper class that is used to replay previously stored traces
* (which are little more than just a list of ChoiceGenerator classnames and
* choice indexes stored in a previous run)
*/
public class ChoicePoint {
String cgClassName;
int choice;
ChoicePoint next, prev;
ChoicePoint (String cgClassName, int choice, ChoicePoint prev) {
this.cgClassName = cgClassName;
this.choice = choice;
if (prev != null) {
this.prev = prev;
prev.next = this;
}
}
public String getCgClassName() {
return cgClassName;
}
public int getChoice() {
return choice;
}
public ChoicePoint getNext() {
return next;
}
public ChoicePoint getPrevious() {
return prev;
}
public static void storeTrace (String fileName,
String sutName, String comment,
ChoiceGenerator<?>[] trace, boolean verbose) {
int i;
if (fileName != null) {
try {
FileWriter fw = new FileWriter(fileName);
PrintWriter pw = new PrintWriter(fw);
if (comment != null){ // might be multi-line
pw.print("/* ");
pw.print(comment);
pw.println(" */");
}
// store the main app class and args here, so that we can do at least some checking
pw.print( "application: ");
pw.println( sutName);
// keep a String->id map so that we don't have to store thousands of redundant strings
HashMap<String,Integer> map = new HashMap<String,Integer>();
int clsId = 0;
for (i=0; i<trace.length; i++) {
String cgClsName = trace[i].getClass().getName();
pw.print('[');
pw.print(i);
pw.print("] ");
Integer ref = map.get(cgClsName);
if (ref == null) {
pw.print(cgClsName);
map.put(cgClsName, clsId++);
} else { // us the numeric id instead
pw.print('#');
pw.print(ref.intValue());
}
pw.print(" ");
pw.print( trace[i].getProcessedNumberOfChoices());
if (verbose){
pw.print(" // ");
pw.print(trace[i]);
}
pw.println();
}
pw.close();
fw.close();
} catch (Throwable t) {
throw new JPFException(t);
}
}
}
static StreamTokenizer createScanner (String fileName) {
StreamTokenizer scanner = null;
if (fileName == null) {
return null;
}
File f = new File(fileName);
if (f.exists()) {
try {
FileReader fr = new FileReader(f);
scanner = new StreamTokenizer(fr);
scanner.slashSlashComments(true);
scanner.slashStarComments(true);
// how silly - there is no better way to turn off parseNumbers()
scanner.resetSyntax();
scanner.wordChars('a', 'z');
scanner.wordChars('A', 'Z');
scanner.wordChars(128 + 32, 255);
scanner.whitespaceChars(0, ' ');
//scanner.commentChar('/');
scanner.quoteChar('"');
scanner.quoteChar('\'');
scanner.wordChars('0','9');
scanner.wordChars(':', ':');
scanner.wordChars('.', '.');
scanner.wordChars('#', '#');
scanner.nextToken();
} catch (IOException iox) {
throw new JPFException("cannot read tracefile: " + fileName);
}
return scanner;
} else {
return null;
}
}
static void match (StreamTokenizer scanner, String s) throws IOException {
if ((scanner.ttype == StreamTokenizer.TT_WORD) && (scanner.sval.equals(s))) {
scanner.nextToken();
} else {
throw new JPFException ("tracefile error - expected " + s + ", got: " + scanner.sval);
}
}
static String matchString (StreamTokenizer scanner) throws IOException {
if (scanner.ttype == StreamTokenizer.TT_WORD) {
String s = scanner.sval;
if (s.length() == 0) {
throw new JPFException ("tracefile error - non-empty string expected");
}
scanner.nextToken();
return s;
} else {
throw new JPFException ("tracefile error - word expected, got: " + scanner.sval);
}
}
static void matchChar (StreamTokenizer scanner, char c) throws IOException {
if (scanner.ttype == (int) c) {
scanner.nextToken();
} else {
throw new JPFException ("tracefile error - char '"
+ c + "' expected, got: " + scanner.sval);
}
}
static int matchNumber (StreamTokenizer scanner) throws IOException {
try {
if (scanner.ttype == StreamTokenizer.TT_WORD) {
int n = Integer.parseInt(scanner.sval);
scanner.nextToken();
return n;
}
} catch (NumberFormatException nfx) {}
throw new JPFException ("tracefile error - number expected, got: " + scanner.sval);
}
/**
* "application:" appName
* {arg}
* "["searchLevel"]" (choiceGeneratorName | '#'cgID) nChoice
*/
public static ChoicePoint readTrace (String fileName, String sutName) {
ChoicePoint firstCp = null, cp = null;
StreamTokenizer scanner = createScanner(fileName);
if (scanner == null) {
return null;
}
try {
match(scanner, "application:");
match(scanner, sutName);
HashMap<String,String> map = new HashMap<String,String>();
int clsId = 0;
while (scanner.ttype != StreamTokenizer.TT_EOF) {
matchChar(scanner, '[');
matchNumber(scanner);
matchChar(scanner, ']');
String cpClass = matchString(scanner);
if (cpClass.charAt(0) == '#') { // it's a CG class id
cpClass = map.get(cpClass);
if (cpClass == null) {
throw new JPFException("tracefile error - unknown ChoicePoint class id: " + cpClass);
}
} else {
String id = "#" + clsId++;
map.put(id, cpClass);
}
int choiceIndex = matchNumber(scanner) -1;
cp = new ChoicePoint(cpClass, choiceIndex, cp);
if (firstCp == null) {
firstCp = cp;
}
}
} catch (IOException iox) {
throw new JPFException("tracefile read error: " + iox.getMessage());
}
return firstCp;
}
}