Assignment 5, due Feb 15

Solutions

Part of the homework for CS:2820, Spring 2019
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science

  1. Background: We have been using Java's Scanner class and its methods hasNext() and next() to pick apart the input to our road-network and logic simulators. We have designed our input data in terms of lines of text, for example:
    gate a xor 6.7
    gate b threshold 1 3.6
    wire a 3.2 b
    wire b 1.5 a 1.8 a
    

    There is a serious mismatch here that makes it difficult for our code to recover from errors in the input file. The problem is, the scanner services treat newlines as just another form of space, while our input format wants newlines to be significant. We can fix this, to some extent, by using the nextLine method of Java's Scanner class.

    a) Where, in the code for the constructors for Road(), Intersection() Gate(), or Wire() should the call to the nextLine() method be put? (0.5 points)

    Since the intent of our input format is that each of these items begin on a new line, processing one of them should finish by consuming the remainder of the line. Therefore, the short answer is: Call nextLine() at the end.

    b) If you wanted to detect and complain about extraneous text after the definition of one of the objects mentioned above, what would you check for in the value returned by nextLine()? (0.5 points)

    nextLine() returns a string holding the text if finds between the current position in the input scanner and the following newline. So, an adequate short answer would be: Check that nextLine() returns the empty string and complain if not.

    If you do this, you might notice that your code complains about trailing blanks. A better answer might check that the string contains nothing but blanks and tabs, but that's hard work.

    An even better solution would force the scanner to skip blanks and tabs before calling nextLine(), but this gets into obscure parts of Java's class Scanner.

  2. Background: At the end of the notes for Lecture 12, the Bourne (and Bash) shell's if command is discussed. This can be used to test the exit status of any application launched from the shell. In the Feb. 8 lecture, we constructed a little shell script
    # test script for road network
    java RoadNetwork
    echo "that should complain about a missing parameter"
    java RoadNetwork "no such file"
    echo "that should complain it can't open 'no such file'"
    java RoadNetwork "no such file" "and more junk"
    echo "that should complain that there is 'and more junk' and about the file"
    

    a) Fix the first (non-comment) line of the script so that it uses the if command to test the exit status of RoadNetwork so that the script outputs FAILURE, it should have failed if RoadNetwork exited normally. (0.5 points)

    if java RoadNetwork
            then echo "FAILURE, it should have failed"
    fi
    

    b) Modify your answer to part a so that, in addition to testing the exit status, it also tests RoadNetwork's output to standard output and standard error. Specifically, if the program fails as it should under this test, your script should complain FAILURE, there was output to standard output if there was, and FAILURE, there was no output to standard error if there was not.

    If you need an empty file to compare with, use the shell command touch emptyfile at the start of your script to create it and rm -f emptyfile at the end of your script to delete it. (0.5 points)

    if java RoadNetwork > testoutput 2> erroroutput
            then echo "FAILURE, it should have failed"
    fi
    touch emptyfile
    if ! diff testoutput emptyfile
    	then echo "FAILURE, there was output to standard output"
    fi
    if diff testoutput erroroutput
    	then echo "FAILURE, there was no output to standard error"
    fi
    rm -f testoutput erroroutput emptyfile
    

  3. Background: The code we've studied up to this point uses the scanner methods hasNext() and next() to pick up gate and intersection names. This has the annoying consequence that syntax errors in the input file lead to delays being read as gate or intersection names. Here, we consider two ways of dealing with this problem.

    a) Our first solution involves a new boolean utility method, hasNextName(sc). This returns true if the next token in the scanner's input stream exists and is not a legal float. Give code for hasNextName(sc) using only hasNext() and hasNextFloat(). (0.5 points)

    public static boolean hasNextName( Scanner sc ) {
        if hasNextFloat( sc ) return false;
        return hasNext( sc );
    }
    

    b) Explore the documentation for Java's scanner class and identify methods offered by the scanner that can be used to build very specific hasNext() and next() methods that will only scan specific and arbitrarily described types of tokens. Identify the candidate methods. (Later, we will explore using them; they are complex enough that we'll defer actually using them to solve this problem right now.) (0.5 points)

    There are hasNext( Pattern pattern ) and next( Pattern pattern ) which look promising, if there is a way to build a pattern that matches text that is not a legal float but is a legal name for a gate or intersection.

    While hunting for this, I also found skip( Pattern pattern ) that can be used to solve the "skip trailing blanks but not newlines" problem mentioned in the note at the end of the answer to problem 1b above.