# You may have to edit this file to delete header lines produced by
# mailers or news systems from this file (all lines before these shell
# comments you are currently reading).
# Shell archive made by dwjones on Thu Apr 20 16:17:19 CDT 2017
# To install this software on a UNIX system:
# 1) create a directory (e.g. with the shell command mkdir stuff)
# 2) change to that directory (e.g. with the command cd stuff),
# 3) direct the remainder of this text to sh (e.g. sh < ../thisfile).
# This will make sh create files in the new directory; it will do
# nothing else (if you're paranoid, you should scan the following text
# to verify this before you follow these directions). Then read README
# in the new directory for additional instructions.
cat > README <<\xxxxxxxxxx
README
a ternary logic simulator with graphical output in the style required by MP5.
Note that only the file Gate.java is specifically a solution to MP5; the
rest of this distribution is merely scaffolding to permit that code to run.
Contents:
README -- this file
classes -- a list of all the class.java files in this program
*.java -- the source code
testfile -- a file of input formatted for this code
To build this project, use the following command line:
javac @classes
To run this project on the test file use this command line:
java TernaryLogic testfile 1 16
xxxxxxxxxx
cat > classes <<\xxxxxxxxxx
Errors.java
ScanSupport.java
Simulation.java
Wire.java
Gate.java
MaxGate.java
MinGate.java
NegGate.java
IsFGate.java
IsTGate.java
IsUGate.java
TernaryLogic.java
xxxxxxxxxx
cat > Errors.java <<\xxxxxxxxxx
/* Errors.java -- error reporting support package */
/** Utility package for error handling.
*
* General purpose error reporting package for command-line applications.
* It allows reporting fatal errors and warnings to the user.
*
* @author Douglas Jones
* @version 2017-04-05
* this code is ripped from RoadNetwork.java version 2017-03-31.
*/
public class Errors {
private Errors(){}; // you may never instantiate this class
private static int count = 0; // warning count, really public read only
/** Provide public read only access to the count of warnings.
* @return the count of the non-fatal warnings
*/
public static int count() {
return count;
}
/** Warn of non fatal errors with a message on system.err
* @param message the string to output as an error message.
*/
public static void warn( String message ) {
System.err.println( "Warning: " + message );
count = count + 1;
}
/** Report fatal errors with a message on system.err
* and then exit the application.
* @param message the string to output as an error message.
*/
public static void fatal( String message ) {
System.err.println( "Fatal error: " + message );
System.exit( -1 );
}
}
xxxxxxxxxx
cat > Gate.java <<\xxxxxxxxxx
/* Gate.java -- abstract class defining generic properties of logic gates */
import java.util.LinkedList;
import java.util.Scanner;
/** Gates are linked by wires.
* Each specific type of gate must extend this abstract class.
*
* @author Douglas Jones
* @version 2017-04-17
* The logic used to simulate a gate is largely lifted from the
* posted solution to Homework 8.
*
* @see Wire
* @see MinGate
* @see MaxGate
* @see NegGate
* @see IsTGate
* @see IsFGate
* @see IsUGate
* @see TernaryLogic#findGate(String)
*/
public abstract class Gate {
private final LinkedList outgoing = new LinkedList ();
/** setter method to add outgoing wires to this gate
* @param w the wire that connects from this gate
*/
public void addOutgoing( Wire w ) {
outgoing.add( w );
}
private int incount = 0; // how many inputs are connected?
/** setter method to add incoming wires to this gate
* @param w the wire that connects to this gate
*/
public void addIncoming( Wire w ) {
// actually, we don't need w, but the public doesn't know that
incount = incount + 1;
}
public final String name; // the name of the gate
// Gripe: We'd like to declare the following as final, but can't
// because they're set by the subclass constructor
public int inputs; // the type of the gate
public float delay; // the type of the gate
/** constructor needed by subclasses to set the final fields of gate
* @param n the name of the new gate
*/
protected Gate( String n ) {
name = n;
}
/** factory method scans and processes one gate definition
* @param sc The scanner from which input is read to build the gate.
* @return the newly constructed gate.
*/
public static Gate newGate( Scanner sc ) {
String myName = ScanSupport.nextName( sc );
if ("".equals( myName )) {
Errors.warn(
"gate has no name"
);
sc.nextLine();
return null;
}
if (TernaryLogic.findGate( myName ) != null) {
Errors.warn(
"Gate '" + myName +
"' redefined."
);
sc.nextLine();
return null;
}
String myType = ScanSupport.nextName( sc );
if ("min".equals( myType )) {
return new MinGate( sc, myName );
} else if ("max".equals( myType )) {
return new MaxGate( sc, myName );
} else if ("neg".equals( myType )) {
return new NegGate( sc, myName );
} else if ("isfalse".equals( myType )) {
return new IsFGate( sc, myName );
} else if ("istrue".equals( myType )) {
return new IsTGate( sc, myName );
} else if ("isunknown".equals( myType )) {
return new IsUGate( sc, myName );
} else {
Errors.warn(
"Gate '" + myName +
"' '" + myType +
"' has an illegal type."
);
sc.nextLine();
return null;
}
}
/** Scan gate's delay and line end to finish initialization;
* this is always called at the end of the subclass constructor.
* @param sc The scanner from which input is read to build the gate.
*/
protected final void finishGate( Scanner sc ) {
delay = sc.nextFloat();
if (delay != delay) { // really asks if delay == NaN
Errors.warn(
this.myString() + " -- has no delay"
);
} else if (delay < 0.0f) {
Errors.warn(
this.myString() + " -- has negative delay."
);
}
ScanSupport.lineEnd( sc, () -> this.myString() );
}
/** Get the representation of this Gate in the format of the input file.
* It would have been nice to use toString here,
* but Java does not permit that to be protected.
* @return the string representation of this gate.
*/
protected String myString() {
return(
"gate " + name
);
}
// ***** Logic Simulation *****
// for logic values, inputCount[v] shows how many inputs have that value
int inputCounts[] = new int[3];
// all of the following are initially set to unknown
int output = 1; // this gate's most recently computed output value
int current = 1; // this gate's current output for printing
int previous = 1; // this gate's previously printed output
/** Sanity check for gates */
public void check() {
if (incount < inputs) {
Errors.warn(
this.myString() + " -- has missing inputs."
);
} else if (incount > inputs) {
Errors.warn(
this.myString() + " -- has too many inputs."
);
}
// initially, all the inputs are unknown
inputCounts[0] = 0;
inputCounts[1] = inputs;
inputCounts[2] = 0;
// and initially, the output is unknown
output = 1;
// some subclasses will add to this behavior
}
/** The textual print value for this gate as required by MP5.
* The first array index is the old value,
* the second array index is the new value.
*/
private static final String[][] printValues = {
{ "| ", "|_ ", "|___ " },
{ " _| ", " | ", " |_ " },
{ " ___|", " _|", " |" }
};
/** Get the graphical display of this gate's output since the last
* time this gate was checked.
* @return The string to be displayed.
*/
public String printValue() {
String r = printValues[previous][current];
previous = current;
return r;
}
/** Every subclass must define this function;
* @return the new logic value, a function of inputCounts;
*/
protected abstract int logicValue();
/** Event service routine called when the input to a gate changes
* @param time the time at which the input changes
* @param oldv the previous logic value carried over this input
* @param newv the new logic value carried over this input
*/
public void inputChangeEvent( float time, int oldv, int newv ) {
inputCounts[oldv]--;
inputCounts[newv]++;
final int newOut = logicValue();
if (output != newOut) {
final int old = output;
Simulation.schedule(
time + delay,
(float t) -> outputChangeEvent( t, old, newOut )
);
output = newOut;
}
};
/** Event service routine called when the output of a gate changes
* @param time the time at which the output changes
* @param oldv the previous logic value of this gate's output
* @param newv the new logic value of this gate's output
*/
public void outputChangeEvent( float time, int oldv, int newv ) {
// send the new value out to all the outgoing wires
for ( Wire w: outgoing ) {
// this is optimized, we could have scheduled an event
w.inputChangeEvent( time, oldv, newv );
}
// record the new output value in case it needs to be printed
current = newv;
};
}
xxxxxxxxxx
cat > IsFGate.java <<\xxxxxxxxxx
/* IsFGate.java -- implements the is-false subclass of gates */
import java.util.Scanner;
/** the is-false gate, a kind of gate.
* @author Douglas Jones
* @version 2017-04-20
* This code is largely ripped from Version 2017-04-06, with comment changes.
* @see Gate
*/
public class IsFGate extends Gate {
/** initializer scans and processes one is-false gate
* @param sc the Scanner from which gate description is read
* @param myName the value to be put in the name field
*/
IsFGate( Scanner sc, String myName ) {
// the text "gate myName min" has already been scanned
super( myName );
inputs = 1; // it is a one-input gate
this.finishGate( sc );
}
/** get a representation for this Gate in the form used for input
* @return the representation as a string
*/
public String toString() {
return(
this.myString() + " isfalse " + delay
);
}
// ***** Logic Simulation for IsFGate *****
/** Sanity check for IsFGate */
public void check() {
super.check();
// now change the output from unknown to false
Simulation.schedule(
delay,
(float t) -> this.outputChangeEvent( t, 1, 0 )
);
output = 0;
}
/** Return the new logic value, false unless the input is false.
* Every subclass of gate must define this.
* @return the new logic value, a function of inputCounts;
*/
protected int logicValue() {
int newOutput = 0;
if (inputCounts[0] != 0) newOutput = 2;
return newOutput;
}
}
xxxxxxxxxx
cat > IsTGate.java <<\xxxxxxxxxx
/* IsTGate.java -- implements the is-true subclass of gates */
import java.util.Scanner;
/** the is-true gate, a kind of gate
* @author Douglas Jones
* @version 2017-04-20
* This code is largely ripped from Version 2017-04-06, with comment changes.
* @see Gate
*/
public class IsTGate extends Gate {
/** initializer scans and processes one is-true gate
* @parame sc Scanner from which gate description is read
* @param myName the value to be put in the name field
*/
IsTGate( Scanner sc, String myName ) {
// the text "gate myName min" has already been scanned
super( myName );
inputs = 1; // it is a one-input gate
this.finishGate( sc );
}
/** get a representation for this Gate in the form used for input
* @return the representation as a string
*/
public String toString() {
return(
this.myString() + " istrue " + delay
);
}
// ***** Logic Simulation for IsTGate *****
/** Sanity check for IsTGate */
public void check() {
super.check();
// now change the output from unknown to false
Simulation.schedule(
delay,
(float t) -> this.outputChangeEvent( t, 1, 0 )
);
output = 0;
}
/** Return the new logic value, false unless the input is true.
* Every subclass of gate must define this.
* @return the new logic value, a function of inputCounts;
*/
protected int logicValue() {
int newOutput = 0;
if (inputCounts[2] != 0) newOutput = 2;
return newOutput;
}
}
xxxxxxxxxx
cat > IsUGate.java <<\xxxxxxxxxx
/* IsUGate.java -- implements the is-undefined subclass of gates */
import java.util.Scanner;
/** the is-undefined gate, a kind of gate.
* @author Douglas Jones
* @version 2017-04-20
* This code is largely ripped from Version 2017-04-06, with comment changes.
* @see Gate
*/
public class IsUGate extends Gate {
/** initializer scans and processes one is-undefined gate
* @param sc Scanner from which gate description is read
* @param myName the value to be put in the name field
*/
IsUGate( Scanner sc, String myName ) {
// the text "gate myName min" has already been scanned
super( myName );
inputs = 1; // it is a one-input gate
this.finishGate( sc );
}
/** get a representation for this Gate in the form used for input
* @return the representation as a string
*/
public String toString() {
return(
this.myString() + " isundefined " + delay
);
}
// ***** Logic Simulation for IsUGate *****
/** Sanity check for IsUGate */
public void check() {
super.check();
// now change the output from unknown to true
Simulation.schedule(
delay,
(float t) -> this.outputChangeEvent( t, 1, 2 )
);
output = 2;
}
/** Return the new logic value, false unless the input is undefined.
* Every subclass of gate must define this.
* @return the new logic value, a function of inputCounts;
*/
protected int logicValue() {
int newOutput = 0;
if (inputCounts[1] != 0) newOutput = 2;
return newOutput;
}
}
xxxxxxxxxx
cat > MaxGate.java <<\xxxxxxxxxx
/* MaxGate.java -- a subclass of gates that computes the max of its inputs */
import java.util.Scanner;
/** the max operator, a fundamental kind of ternary logic gate.
* @author Douglas Jones
* @version 2017-04-20
* This code is largely ripped from Version 2017-04-06, with comment changes.
* @see Gate
*/
public class MaxGate extends Gate {
/** initializer scans and processes one max gate
* @param sc Scanner from which gate description is read
* @param myName the value to be put in the name field
*/
MaxGate( Scanner sc, String myName ) {
// the text "gate myName min" has already been scanned
super( myName );
// get inputs
if (sc.hasNextInt()) {
inputs = sc.nextInt();
} else {
Errors.warn(
this.myString() + " max -- has no input count"
);
}
this.finishGate( sc );
}
/** get a representation for this Gate in the form used for input
* @return the representation as a string
*/
public String toString() {
return(
this.myString() + " max " + inputs + " " + delay
);
}
// ***** Logic Simulation for MaxGate *****
/** Return the new logic value, the max of the input values.
* Every subclass of gate must define this.
* @return the new logic value, a function of inputCounts;
*/
protected int logicValue() {
// find the maximum of all the inputs
int newOutput = 2;
while (inputCounts[newOutput] == 0) newOutput--;
return newOutput;
}
}
xxxxxxxxxx
cat > MinGate.java <<\xxxxxxxxxx
/* MinGate.java -- a subclass of gates that computes the min of its inputs */
import java.util.Scanner;
/** the min operator, a fundamental kind of ternary logic gate.
* @author Douglas Jones
* @version 2017-04-20
* This code is largely ripped from Version 2017-04-06, with comment changes.
* @see Gate
*/
public class MinGate extends Gate {
/** initializer scans and processes one min gate
* @param sc Scanner from which gate description is read
* @param myName the value to be put in the name field
*/
MinGate( Scanner sc, String myName ) {
// the text "gate myName min" has already been scanned
super( myName );
// get inputs
if (sc.hasNextInt()) {
inputs = sc.nextInt();
} else {
Errors.warn(
this.myString() +
" min -- has no input count"
);
}
this.finishGate( sc );
}
/** get a representation for this Gate in the form used for input
* @return the representation as a string
*/
public String toString() {
return(
this.myString() + " min " + inputs + " " + delay
);
}
// ***** Logic Simulation for MinGate *****
/** Return the new logic value, the min of the input values.
* Every subclass of gate must define this.
* @return the new logic value, a function of inputCounts;
*/
protected int logicValue() {
// find the minimum of all the inputs
int newOutput = 0;
while (inputCounts[newOutput] == 0) newOutput++;
return newOutput;
}
}
xxxxxxxxxx
cat > NegGate.java <<\xxxxxxxxxx
/* NegGate.java -- implements logical negation gates, a ternary operator */
import java.util.Scanner;
/** the negate gate, a fundamental ternary logic gate.
* @author Douglas Jones
* @version 2017-04-20
* This code is largely ripped from Version 2017-04-06, with comment changes.
* @see Gate
*/
public class NegGate extends Gate {
/** initializer scans and processes one neg gate
* @param sc Scanner from which gate description is read
* @param myName the value to be put in the name field
*/
NegGate( Scanner sc, String myName ) {
// the text "gate myName min" has already been scanned
super( myName );
inputs = 1; // it is a one-input gate
this.finishGate( sc );
}
/** get a representation for this Gate in the form used for input
* @return the representation as a string
*/
public String toString() {
return(
this.myString() + " neg " + " " + delay
);
}
// ***** Logic Simulation for NegGate *****
/** Return the new logic value, 2 minus the input value.
* Every subclass of gate must define this.
* @return the new logic value, a function of inputCounts;
*/
protected int logicValue() {
// Warning this is mildly tricky code
int newOutput = 2;
while (inputCounts[2 - newOutput] == 0) newOutput--;
return newOutput;
}
}
xxxxxxxxxx
cat > ScanSupport.java <<\xxxxxxxxxx
/* ScanSupport.java -- package of support methods for scanning */
import java.util.Scanner;
import java.util.regex.Pattern;
/** Support methods for scanning input files.
* @author Douglas Jones
* @version 2017-04-05
* This is ripped from RoadNetwork.java version 2017-03-31 with a change:
* nextFloat method is added based on the homework and the comments are
* somewhat improved.
* @see Errors
*/
public class ScanSupport {
/** Pattern for recognizing identifers
*/
public static final Pattern name // letter followed by alphanumeric
= Pattern.compile( "[a-zA-Z][a-zA-Z0-9_]*|" );
/** Pattern for recognizing floating point numbers
*/
public static final Pattern numb // Digits.Digits or .Digits or nothing
= Pattern.compile( "[0-9]+\\.?[0-9]*|\\.[0-9]+|" );
/** Pattern for recognzing whitespace excluding newlines
*/
public static final Pattern whitespace
= Pattern.compile( "[ \t]*" );
/** Get next name without skipping to next line (unlike sc.Next()).
* @param sc the scanner from which end of line is scanned.
* @return the name, if there was one, or an empty string.
*/
public static String nextName( Scanner sc ) {
sc.skip( whitespace );
// the following is weird code, it skips the name
// and then returns the string that matched what was skipped
sc.skip( name );
return sc.match().group();
}
/** Get next float without skipping lines (unlike sc.nextFloat()).
* @param sc the scanner from which end of line is scanned.
* @return the name, if there was one, or NaN if not.
*/
public static Float nextFloat( Scanner sc ) {
sc.skip( whitespace );
// the following is weird code, it skips the name
// and then returns the string that matched what was skipped
sc.skip( numb );
String f = sc.match().group();
// now convert what we can or return NaN
if (!"".equals( f )) {
return Float.parseFloat( f );
} else {
return Float.NaN;
}
}
/** Class used only for deferred evaluation of lambda expressions
* passed to lineEnd
.
*/
public interface EndMessage {
/** Method to compute the error message text
* @return the text the error message
*/
public abstract String myString();
}
/** Advance to next line and complain if there is junk at the line end;
* call this when all useful content has been consumed from the line
* it skips optional line-end comments and complains about anything
* it finds while advancing to the next line.
* @see Errors
* @see EndMessage
* @param sc the scanner from which end of line is scanned.
* @param message will be evaluated only when there is an error;
* it is typically passed as a lambda expression, for example,
* {@code ScanSupport.lineEnd( sc, () -> "this " + x + " that" );}
*/
public static void lineEnd( Scanner sc, EndMessage message ) {
sc.skip( whitespace );
String lineEnd = sc.nextLine();
if ( (!lineEnd.equals( "" ))
&& (!lineEnd.startsWith( "--" )) ) {
Errors.warn(
"" + message.myString() +
" followed unexpected by '" + lineEnd + "'"
);
}
}
}
xxxxxxxxxx
cat > Simulation.java <<\xxxxxxxxxx
/* Simulation.java -- discrete event simulation framework */
import java.util.PriorityQueue;
/** Discrete event simulation support framework
* @author Douglas Jones
* @version 2017-04-10
* this code is ripped from RoadNetwork.java version 2017-03-31
*/
class Simulation {
/** Interface allowing actions to be passed as lambda expressions.
*/
public interface Action {
void trigger( float time );
}
/** Events are the core of the control structure of the simulation.
*/
private static class Event {
/** Each event has a time */
float time;
/** Each event has an action */
Action act;
/** Construct and initialize a new Event
.
* @param t the time
of the event.
* @param a the act
to be triggered then.
*/
Event( float t, Action a ) {
time = t;
act = a;
};
/** Trigger the event's act
at the indicated
* time.
*/
void trigger() {
act.trigger( time );
}
}
/** Events are queued for {@code run} retrieve in chronological order.
*/
private static PriorityQueue eventSet =
new PriorityQueue (
(Event e1, Event e2)->Float.compare( e1.time, e2.time )
);
/** Users call schedule to schedule one action at some time,
* usually a later time but possibly the current time.
*
* @param time specifies when the event should occur.
* @param act specifies what to do at that time.
* Typically, {@code act} is a lambda expression,
* so a call to schedule could look like this:
*
* {@code
* Simulation.schedule( t, (float t)->object.method( params, t ) )
* }
*/
public static void schedule( float time, Action act ) {
eventSet.add( new Event( time, act ) );
}
/** the main program should build the model,
* this inolves scheduling some initial events
* and then, just once, it should call {@code run}.
*/
public static void run() {
while (!eventSet.isEmpty()) {
Event e = eventSet.remove();
e.trigger();
}
}
}
xxxxxxxxxx
cat > TernaryLogic.java <<\xxxxxxxxxx
/* TernaryLogic.java -- main class of a ternary logic simulator */
import java.util.LinkedList;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
/** TernaryLogic -- The main class of a ternary logic simulator.
*
* This reads a description of a ternary logic circuit, builds a model,
* and if that model passes sanity checks, runs a simulation of that
* circuit.
*
* It runs from the command line, with three command line arguments,
* the input file name, the interval between successive outputs, and the
* total duration of the simulation.
*
* @author Douglas Jones
* @version 2017-04-20
* This code is largely ripped from Version 2017-04-06, with comment changes.
*
* @see Wire
* @see Gate
* @see Errors
* @see Simulation
* @see ScanSupport
* @see #main
*/
public class TernaryLogic {
// lists of roads and intersectins
static LinkedList wires
= new LinkedList ();
static LinkedList gates
= new LinkedList ();
/** utility method to look up an gate by name
* @param s is the name of the gate, a string
* @return is the Gate object with that name
*/
public static Gate findGate( String s ) {
for ( Gate g: gates ) {
if (g.name.equals( s )) return g;
}
return null;
}
/** read a ternary logic system.
* @param sc the scanner from which the system is read.
*/
public static void initializeTernary( Scanner sc ) {
while (sc.hasNext()) {
// until we hit the end of the file
String command = ScanSupport.nextName( sc );
if ("gate".equals( command )) {
Gate g = Gate.newGate( sc );
if (g != null) gates.add( g );
} else if ("wire".equals( command )) {
wires.add( new Wire( sc ) );
} else if ("".equals( command )) { // blank or comment
// line holding -- ends up here!
ScanSupport.lineEnd( sc, () -> "Line" );
} else {
Errors.warn(
"Command '" + command +
"' is not gate or wire"
);
sc.nextLine(); // skip the rest of the error
}
}
}
/** Check the sanity of the network.
* @see Gate#check
*/
public static void checkNetwork() {
for ( Gate g: gates ) {
g.check();
}
// we could also go through the wires,
// but there's nothing to check there.
}
/** write out a ternary logic system
*/
public static void writeTernary() {
for ( Gate g: gates ) {
System.out.println( g.toString() );
}
for ( Wire w: wires ) {
System.out.println( w.toString() );
}
}
/** logic output interval */
private static float printInterval;
/** output headline for logic output
* @param i the interval between successive outputs
*/
public static void initPrint( float i ) {
printInterval = i;
Simulation.schedule(
0.0f,
(float t) -> printGates( t )
);
for( Gate g: gates ) {
System.out.print( " " + g.name );
}
System.out.println();
}
/** output event service routine
* @see printInterval
*/
private static void printGates( float time ) {
for( Gate g: gates ) {
System.out.print( " " + g.printValue() );
}
System.out.println();
Simulation.schedule(
time + printInterval,
(float t) -> printGates( t )
);
}
/** main program that reads and writes a road network
* @param args the command line arguments must hold one file name
*/
public static void main( String[] args ) {
// verify that the argument exists.
if (args.length < 1) {
Errors.fatal( "Missing file name on command line" );
} else if (args.length < 2) {
Errors.fatal( "Missing interval on command line" );
} else if (args.length < 3) {
Errors.fatal( "Missing time limit on command line" );
} else if (args.length > 3) {
Errors.fatal( "Unexpected command line args" );
} else try {
initializeTernary( new Scanner( new File( args[0] ) ) );
checkNetwork();
if (Errors.count() > 0) {
writeTernary();
} else try {
initPrint( Float.parseFloat( args[1] ) );
Simulation.schedule(
Float.parseFloat( args[2] ),
(float t) -> System.exit( 0 )
);
Simulation.run();
} catch (NumberFormatException e) {
// Bug: The error message is wrong for args[2]
Errors.fatal(
"'" + args[1] +
"' is not an floating print interval"
);
}
} catch (FileNotFoundException e) {
Errors.fatal( "Could not read '" + args[0] + "'" );
}
}
}
xxxxxxxxxx
cat > Wire.java <<\xxxxxxxxxx
/* Wire.java -- class defining the properties of wires */
import java.util.Scanner;
/** Wires are link by gates.
*
* @author Douglas Jones
* @version 2017-04-17
*
* @see Gate
* @see Errors
* @see TernaryLogic#findGate(String)
*/
class Wire {
private final float delay; // time delay of this wire
private final Gate destination; // where wire goes, or null
private final Gate source; // source of wire, or null
// Wire name is the source-destination names
/** Initializer scans and processes one wire definition.
* @param sc The scanner from which the definition is read.
*/
public Wire( Scanner sc ) {
// textual names of source and dest
String srcName = ScanSupport.nextName( sc );
String dstName = ScanSupport.nextName( sc );
// if there are no next names on this line, these are ""
// therefore, the findGate calls below will fail
// lookup names of source and dest
source = TernaryLogic.findGate( srcName );
if (source == null) {
Errors.warn(
"Wire '" + srcName +
"' '" + dstName +
"' source undefined."
);
}
destination = TernaryLogic.findGate( dstName );
if (destination == null) {
Errors.warn(
"Wire '" + srcName +
"' '" + dstName +
"' destination undefined."
);
}
delay = ScanSupport.nextFloat( sc );
if (delay != delay) { // really asks if delay == NaN
Errors.warn(
"Wire '" + srcName +
"' '" + dstName +
"' has no delay."
);
} else if (delay < 0.0f) {
Errors.warn(
"Wire '" + srcName +
"' '" + dstName +
"' '" + delay +
"' has negative delay."
);
}
ScanSupport.lineEnd( sc, () -> this.toString() );
// Now, tell the gates that they've been wired together
if (destination != null) destination.addIncoming( this );
if (source != null) source.addOutgoing( this );
}
/** Convert this wire to a format like that used for input
* @return The textual description of the wire
*/
public String toString() {
String srcName;
String dstName;
if (source == null) {
srcName = "???";
} else {
srcName = source.name;
}
if (destination == null) {
dstName = "???";
} else {
dstName = destination.name;
}
return(
"wire " +
srcName + " " +
dstName + " " +
delay
);
}
// ***** Logic Simulation *****
/** Event service routine called when the input to a wire changes
* @param time the time at which the input changes
* @param old the previous logic value carried over this wire
* @param new the new logic value carried over this wire
*/
public void inputChangeEvent( float time, int oldv, int newv ) {
Simulation.schedule(
time + delay,
(float t) -> outputChangeEvent( t, oldv, newv )
);
};
/** Event service routine called when the output of a wire changes
* @param time the time at which the output changes
* @param old the previous logic value carried over this wire
* @param new the new logic value carried over this wire
*/
public void outputChangeEvent( float time, int oldv, int newv ) {
// this version is optimized, we could have scheduled an event
destination.inputChangeEvent( time, oldv, newv );
};
}
xxxxxxxxxx
cat > testfile <<\xxxxxxxxxx
gate TIMER istrue 9.0
wire TIMER TIMER 1.0
gate ENABLE isunknown 1.0
wire TIMER ENABLE 1.0
gate CLOCK isfalse 0.5
gate CONTROL min 2 0.5
wire CLOCK CONTROL 0.5
wire CONTROL CLOCK 0.5
wire ENABLE CONTROL 0.5
gate FLIP neg 0.5
gate MIX max 2 0.5
wire TIMER FLIP 1.0
wire FLIP MIX 1.0
wire MIX MIX 1.0
xxxxxxxxxx