Java homework

profilea1103929875
MP3.docx

Write a Java program, in file Logic.java that meets all of the requirements for MP2 and also supports the following gate types:

and

or

Each gate has inputs named in1 and in2 and one output named out.

not

Each gate has one input named in and one output named out.

const

This has outputs named true and false and no inputs

Wires may connect outputs to inputs. Each output may be connected to zero or more inputs, with each connection made by a distinct wire. Exactly one wire must connect to each input. Any attempt to connect inputs or outputs with names that are not supported by that kind of gate must be detected as an error.

In addition to checking the above correctness criteria, your program must be resiliant in the face of input errors of the sort that MP2 was expected to handle, and because you now have access to a ScanSupport class, it your code should work better than your code for MP2.

As with MP2, your program should generate either error messages to standard error or output a reconstruction of the circuit to standard output. All error messages should reasonably document the error.

Grading criteria: No credit will be given to programs that do not represent a substantial attempt at meeting the requirements of this assignment. Your program must:

· Begin with a header comment giving the source file name.

· Contain appropriate Javadoc or other comments claiming authorship and declaring the version to be MP3.

· Be cleanly and readably indented.

· Use appropriate variable names.

· Respond appropriately to errors in the input.

· Not demonstrate any unhandled or mishandled exceptions.

· Properly reconstruct the correct part of the input.

Note that MP4 will involve extending MP3 to simulate the behavior of gates, so planning for this, while not part of this assignment, may simplify the next.

Note that the requirements for header comments in the file header are absolute. Your name must appear in the form that it appears on your ID card. The TAs will not waste their time doing detective work to attempt to figure out who submitted what code.

Submission: Your solution should consist of a single file named Logic.java, with a public method, main. (We will chop the file into smaller more managable pieces later, as it grows.)

import java.util.regex.Pattern;

import java.util.LinkedList;

import java.io.File;

import java.io.FileNotFoundException;

import java.util.Scanner;

/** Error reporting package

* provides standard prefix and behavior for messages

*/

class Errors {

// error messages are counted.

private static int errorCount = 0;

/** Allow public read-only access to the count of error messages

* @return the count

*/

public static int count() {

return errorCount;

}

/** Report nonfatal errors, output a message and return

* @arg message the message to output

*/

public static void warn( String message ) {

System.err.println( "Logic: " + message );

errorCount = errorCount + 1;

}

/** Report fatal errors, output a message and exit, never to return

* @arg message the message to output

*/

public static void fatal( String message ) {

warn( message );

System.exit( 1 );

}

}

/** Support methods for scanning

* @see Errors

*/

class ScanSupport {

// patterns needed for scanning

private static final Pattern name = Pattern.compile(

"[a-zA-Z0-9_]*"

);

private static final Pattern number = Pattern.compile(

"[0-9][0-9]*\\.?[0-9]*|\\.[0-9][0-9]*|"

);

private static final Pattern whitespace = Pattern.compile(

"[ \t]*" // no newlines in this pattern

);

/** Interface used for error messages

* Messages are typically formulated as string-valued lambda expressions

* so that any concatenations they contain are only computed if the

* message is needed.

*/

public static interface ErrorMessage {

public String myString();

}

/** Get next name without skipping to next line (unlike sc.next())

* @param sc the scanner from which end of line is scanned

* @param message the message to output if there was no name

* @return the name, if there was one, or an empty string

*/

public static String nextName( Scanner sc, ErrorMessage message ) {

sc.skip( whitespace );

sc.skip( name );

String s = sc.match().group();

if ("".equals( s )) {

Errors.warn( "Name expected: " + message.myString() );

sc.nextLine();

}

return s;

}

/** Get next float without skipping to next line (unlike sc.nextFloat())

* @param sc the scanner from which end of line is scanned

* @param message the message to output if there was no float

* @return the value, if there was one, or NaN if not

*/

public static float nextFloat( Scanner sc, ErrorMessage message ) {

sc.skip( whitespace );

sc.skip( number );

String s = sc.match().group();

if ("".equals( s )) {

Errors.warn( "Float expected: " + message.myString() );

sc.nextLine();

return Float.NaN;

}

// now, s is guaranteed to hold a legal float

return Float.parseFloat( s );

}

/** Advance to next line and complain if is junk at the line end

* @see Errors

* @param sc the scanner from which end of line is scanned

* @param message gives a prefix to give context to error messages

* This version supports comments starting with --

*/

public static void lineEnd( Scanner sc, ErrorMessage message ) {

sc.skip( whitespace );

String lineEnd = sc.nextLine();

if ( (!lineEnd.equals( "" ))

&& (!lineEnd.startsWith( "--" )) ) {

Errors.warn(

message.myString() +

" followed unexpected by '" + lineEnd + "'"

);

}

}

}

/** Wires join Gates

* @see Gate

*/

class Wire {

// constructors may throw this when an error prevents construction

public static class ConstructorFailure extends Exception {}

// fields of a gate

private final float delay; // measured in seconds

private final Gate source; // where this wire comes from, never null

private final String srcPin; // what pin of source, never null

private final Gate destination; // where this wire goes, never null

private final String dstPin; // what pin of the destination, never null

// name of a wire is source-srcpin-destination-dstpin

/** construct a new wire by scanning its description from the source file

*/

public Wire( Scanner sc ) throws ConstructorFailure {

String sourceName = ScanSupport.nextName(

sc, ()-> "wire ???"

);

if ("".equals( sourceName )) throw new ConstructorFailure();

srcPin = ScanSupport.nextName(

sc, ()->"wire " + sourceName + " ???"

);

if ("".equals( srcPin )) throw new ConstructorFailure();

String dstName = ScanSupport.nextName(

sc, ()->"wire " + " " + srcPin + " ???"

);

if ("".equals( dstName )) throw new ConstructorFailure();

dstPin = ScanSupport.nextName(

sc, ()->"wire " + " " + srcPin + " " + dstName + " ???"

);

if ("".equals( dstPin )) throw new ConstructorFailure();

source = Logic.findGate( sourceName );

destination = Logic.findGate( dstName );

if (source == null) {

Errors.warn( "No such source gate: wire "

+ sourceName + " " + srcPin + " "

+ dstName + " " + dstPin

);

sc.nextLine();

throw new ConstructorFailure();

}

if (destination == null) {

Errors.warn( "No such destination gate: wire "

+ sourceName + " " + srcPin + " "

+ dstName + " " + dstPin

);

sc.nextLine();

throw new ConstructorFailure();

}

// take care of source and destination pins

// Bug: This is a start, but in the long run, it might not be right

source.registerOutput( srcPin );

destination.registerInput( dstPin );

delay = ScanSupport.nextFloat(

sc, ()->"wire "

+ sourceName + " " + srcPin + " "

+ dstName + " " + dstPin + " ???"

);

if (Float.isNaN( delay )) throw new ConstructorFailure();

if (delay < 0.0F) Errors.warn( "Negative delay: " + this.toString() );

ScanSupport.lineEnd( sc, ()->this.toString() );

}

/** output the wire in a form like that used for input

* @return the textual form

*/

public String toString() {

return "wire "

+ source.name + " "

+ srcPin + " "

+ destination.name + " "

+ dstPin + " "

+ delay;

}

}

/** Gates process inputs from Wires and deliver outputs to Wires

* @see Wire

*/

abstract class Gate {

// constructors may throw this when an error prevents construction

public static class ConstructorFailure extends Exception {}

// fields of a gate

public final String name; // textual name of gate, never null!

protected final float delay; // the delay of this gate, in seconds

private LinkedList <Wire> outgoing; // set of all wires out of this gate

private LinkedList <Wire> incoming; // set of all wires in to this gate

// Bug: Is incoming really needed?

// Bug: When are the above ever set to anything?

/** The constructor used only from within subclasses

* @param name used to initialize the final field

* @param delay used to initialize the final field

*/

protected Gate( String name, float delay ) {

this.name = name;

this.delay = delay;

}

/** The public use this factory to construct gates

* @param sc the scanner from which the gate description is read

* @return the newly constructed gate

*/

public static Gate factory( Scanner sc ) throws ConstructorFailure {

String name = ScanSupport.nextName( sc, ()->"gate ???" );

if ("".equals( name )) throw new ConstructorFailure();

String kind = ScanSupport.nextName( sc, ()->"gate " + name + " ???" );

if ("".equals( kind )) throw new ConstructorFailure();

if (Logic.findGate( name ) != null) {

Errors.warn( "Redefinition: gate " + name + " " + kind );

sc.nextLine();

throw new ConstructorFailure();

}

final float delay = ScanSupport.nextFloat(

sc, ()->"gate " + name + " " + kind + " ???"

);

if (Float.isNaN( delay )) throw new ConstructorFailure();

if (delay < 0.0F) Errors.warn(

"Negative delay: " + "gate " + name + " " + kind + " " + delay

);

final Gate newGate; // initialized by one of the alternatives below

if ("and".equals( kind )) {

newGate = new AndGate( name, delay );

} else if ("or".equals( kind )) {

newGate = new OrGate( name, delay );

} else if ("not".equals( kind )) {

newGate = new NotGate( name, delay );

} else if ("const".equals( kind )) {

newGate = new ConstGate( name, delay );

} else {

Errors.warn( "Unknown gate kind: gate " + name + " " + kind );

sc.nextLine();

throw new ConstructorFailure();

}

ScanSupport.lineEnd( sc, ()->newGate.toString() );

return newGate;

}

/** tell the gate that one of its input pins is in use

* @param pinName

*/

public abstract void registerInput( String pinName );

/** tell the gate that one of its output pins is in use

* @param pinName

*/

public abstract void registerOutput( String pinName );

/** check the sanity of this gate's connections

*/

public abstract void checkSanity();

} // class Gate

class AndGate extends Gate {

// usage records for inputs

private boolean in1used = false;

private boolean in2used = false;

/** The constructor used only from within class Gate

* @param name used to initialize the final field

* @param delay used to initialize the final field

*/

protected AndGate( String name, float delay ) {

super( name, delay );

}

/** tell the gate that one of its input pins is in use

* @param pinName

*/

public void registerInput( String pinName ) {

if ("in1".equals( pinName )) {

if (in1used) Errors.warn(

"Multiple uses of input pin: " + name + " in1"

);

in1used = true;

} else if ("in2".equals( pinName )) {

if (in2used) Errors.warn(

"Multiple uses of input pin: " + name + " in2"

);

in2used = true;

} else {

Errors.warn( "Illegal input pin: " + name + " " + pinName );

}

}

/** tell the gate that one of its output pins is in use

* @param pinName

*/

public void registerOutput( String pinName ) {

if ("out".equals( pinName )) {

// Bug: Do we do anything?

} else {

Errors.warn( "Illegal output pin: " + name + " " + pinName );

}

}

/** check the sanity of this gate's connections

*/

public void checkSanity() {

if (!in1used) Errors.warn( "Unused input pin: " + name + " in1" );

if (!in2used) Errors.warn( "Unused input pin: " + name + " in2" );

}

/** reconstruct the textual description of this gate

* @return the textual description

*/

public String toString() {

return "gate " + name + " and " + delay;

}

} // class AndGate

class OrGate extends Gate {

// usage records for inputs

private boolean in1used = false;

private boolean in2used = false;

/** The constructor used only from within class Gate

* @param name used to initialize the final field

* @param delay used to initialize the final field

*/

protected OrGate( String name, float delay ) {

super( name, delay );

}

/** tell the gate that one of its input pins is in use

* @param pinName

*/

public void registerInput( String pinName ) {

if ("in1".equals( pinName )) {

if (in1used) Errors.warn(

"Multiple uses of input pin: " + name + " in1"

);

in1used = true;

} else if ("in2".equals( pinName )) {

if (in2used) Errors.warn(

"Multiple uses of input pin: " + name + " in2"

);

in2used = true;

} else {

Errors.warn( "Illegal input pin: " + name + " " + pinName );

}

}

/** tell the gate that one of its output pins is in use

* @param pinName

*/

public void registerOutput( String pinName ) {

if ("out".equals( pinName )) {

// Bug: Do we do anything?

} else {

Errors.warn( "Illegal output pin: " + name + " " + pinName );

}

}

/** check the sanity of this gate's connections

*/

public void checkSanity() {

if (!in1used) Errors.warn( "Unused input pin: " + name + " in1" );

if (!in2used) Errors.warn( "Unused input pin: " + name + " in2" );

}

/** reconstruct the textual description of this gate

* @return the textual description

*/

public String toString() {

return "gate " + name + " or " + delay;

}

} // class OrGate

class NotGate extends Gate {

// usage records for inputs

private boolean inUsed = false;

/** The constructor used only from within class Gate

* @param name used to initialize the final field

* @param delay used to initialize the final field

*/

protected NotGate( String name, float delay ) {

super( name, delay );

}

/** tell the gate that one of its input pins is in use

* @param pinName

*/

public void registerInput( String pinName ) {

if ("in".equals( pinName )) {

if (inUsed) Errors.warn(

"Multiple uses of input pin: " + name + " in"

);

inUsed = true;

} else {

Errors.warn( "Illegal input pin: " + name + " " + pinName );

}

}

/** tell the gate that one of its output pins is in use

* @param pinName

*/

public void registerOutput( String pinName ) {

if ("out".equals( pinName )) {

// Bug: Do we do anything?

} else {

Errors.warn( "Illegal output pin: " + name + " " + pinName );

}

}

/** check the sanity of this gate's connections

*/

public void checkSanity() {

if (!inUsed) Errors.warn( "Unused input pin: " + name + " in" );

}

/** reconstruct the textual description of this gate

* @return the textual description

*/

public String toString() {

return "gate " + name + " not " + delay;

}

} // class NotGate

class ConstGate extends Gate {

/** The constructor used only from within class Gate

* @param name used to initialize the final field

* @param delay used to initialize the final field

*/

protected ConstGate( String name, float delay ) {

super( name, delay );

}

/** tell the gate that one of its input pins is in use

* @param pinName

*/

public void registerInput( String pinName ) {

Errors.warn( "Illegal input pin: " + name + " " + pinName );

}

/** tell the gate that one of its output pins is in use

* @param pinName

*/

public void registerOutput( String pinName ) {

if ("true".equals( pinName )) {

// Bug: Do we do anything?

} else if ("false".equals( pinName )) {

// Bug: Do we do anything?

} else {

Errors.warn( "Illegal output pin: " + name + " " + pinName );

}

}

/** check the sanity of this gate's connections

*/

public void checkSanity() {

// no sanity check; there are no input pins to check

}

/** reconstruct the textual description of this gate

* @return the textual description

*/

public String toString() {

return "gate " + name + " const " + delay;

}

} // class ConstGate

public class Logic {

// the sets of all wires and all gates

private static LinkedList <Wire> wires

= new LinkedList <Wire> ();

private static LinkedList <Gate> gates

= new LinkedList <Gate> ();

/** Find a gate by textual name in the set gates

* @param s name of a gate

* @return the gate named s or null if none

*/

public static Gate findGate( String s ) {

// quick and dirty implementation

for (Gate i: gates) {

if (i.name.equals( s )) {

return i;

}

}

return null;

}

/** Initialize this logic circuit by scanning its description

*/

private static void readCircuit( Scanner sc ) {

while (sc.hasNext()) {

String command = sc.next();

if ("gate".equals( command )) {

try {

gates.add( Gate.factory( sc ) );

} catch (Gate.ConstructorFailure e) {

// do nothing, the constructor already reported the error

}

} else if ("wire".equals( command )) {

try {

wires.add( new Wire( sc ) );

} catch (Wire.ConstructorFailure e) {

// do nothing, the constructor already reported the error

}

} else if ("--".equals( command )) {

sc.nextLine();

} else {

Errors.warn( "unknown command: " + command );

sc.nextLine();

}

}

}

/** Check that a circuit is properly constructed

*/

private static void sanityCheck() {

for (Gate i: gates) i.checkSanity();

// Bug: Are there any sensible sanity checks on wires?

}

/** Print out the wire network to system.out

*/

private static void printCircuit() {

for (Gate i: gates) {

System.out.println( i.toString() );

}

for (Wire r: wires) {

System.out.println( r.toString() );

}

}

/** Main program

*/

public static void main( String[] args ) {

if (args.length < 1) {

Errors.fatal( "Missing file name argument" );

} else if (args.length > 1) {

Errors.fatal( "Too many arguments" );

} else try {

readCircuit( new Scanner( new File( args[0] ) ) );

sanityCheck();

if (Errors.count() == 0) printCircuit();

} catch (FileNotFoundException e) {

Errors.fatal( "Can't open the file" );

}

}

}