/****************************************************************************
*BasicCompiler: reads commands from a supplied text file containing
* lo resolution instructions written for the old Apple II
* BASIC interpreter and outputs a new java source file that
* can be compiled to form a new java class that can be used
* to view a "translated" version of the BASIC commands in an
* Applet window.
*
*Date Completed: May 7, 1999
*
*Purpose: to bridge the gap between old and modern computing, allowing old
* Apple II BASIC programs to run under within a Java context.
*
*Usage: invoke an instantiation of this class from another containing a main
* method that supplies the name of the file to be tranlated as an
* argument.
*
*References: tested RGB color codes for Color methods using applet at
* http://www.creativityunlimited.com/colortest.html
*
*Revision History: created April 24, 1999; finished Parse method April 27
* and early April 28; finished load/graphics methods;
* April 28, inserted greaterChar and lesserChar methods May 4.
* inserted makeString method May 4 (all of these made as
* methods to insure that their objects are destroyed once
* they have outlived their usefulness). First clean compile
* May 4, 1999 (without makeCode method). (following
* debugging). Added makeCode method May 4 - 5.
* Cleanly compiled after this. Added html file writing
* ability to the makeCode method May 6.
*
*Error Handling: Supported somewhat; though errors (except IOException)
* do not cause the program to cease functioning.
* Restriction: throws null Pointer exception in load method if
* a line number is not present.
*****************************************************************************/
import java.io.*; //needed for file reading activities
import java.util.Vector; //needed for newJCmnds Vector calls
import java.awt.Color; //needed for Calls to color class
/**
class BasicCompiler
*********************************METHODS*************************************
parse() => extracts commands and data from the BASIC
commands and makes the appropriate method
call from this class
makeCode() => used to write the new Java source file
load() => loads the commands from a file into
a linear linked list for "execution."
vLin(int a, int b, int c) => outputs a call to a paint method that
makes vertical lines by filled rectangles
color(int col) => outputs a call to a paint method that
sets color based upon the BASIC code.
hLin(int a, int b, int c) => outputs a call to a paint method that
makes horizontal lines by filled rectangles
plot(int a, int b) => outputs a call to a paint method that
makes plotted points by filled rectangles
*********************************CONSTRUCTOR*********************************
BasicCompiler(String file) => creates a new instance of this class
setting the file name to be parsed to the
String variable file.
*********************************EXCEPTIONS**********************************
IOException => thrown when problems reading and
writing from the disk are encountered
*****************************************************************************
*/
public class BasicCompiler {
/******************************** DATA MEMBERS ******************************/
public String file; //the name of the file to be "compiled"
private ListNode current; //the list node with containing the
//command to be executed
private String newFile; //name of Java source file generated
public Vector newJCmnds = new Vector();
//temporary storage place containing
//instructions for the new paint method
private int atNumber; //stores where parser leaves off in a
//string after getting the command word
List master = new List(); //the list of commands for "memory"
/********************************CONSTRUCTOR*********************************/
public BasicCompiler(String f) { //creates new object and sets variable
file = f;
}
/********************************* ACCESSORS ********************************/
/**
parse - assesses the BASIC command given on each line, extracting the data
necessary from it and passes this on to the appropriate method call
@param None
@return None
@exception None
*/
public void parse() {
String subject = (String)current.data;
//local constant to simplify this code
String command = null; //local variable to store BASIC call
char tmp; //character to hold a temporary value
boolean gotWord = false; //local variable to tell whether
//command has been obtained yet
int i = 0; //all-purpose loop control variable
int tooMuch = 0; //specifies a range of subject to check
while (subject != "stop") {
tmp = subject.charAt(i); //start with the first
//character in the line
tooMuch = subject.length();
//range in which to check
while ((i < tooMuch) && !gotWord) {
if((greaterChar(tmp, 65)) && (lesserChar(tmp, 122))) {
//condition that determines a letter
//has been encountered, includes
//capital A through lowercase z
//IGNORES LINE NUMBERS
gotWord = true; //once out, command is obtained
while ((greaterChar(tmp, 65)) && (lesserChar(tmp, 122))
&& (i < tooMuch)) {
//loop that gets the word;
//CANNOT EXCEED END OF A LINE
if (command == null)
//provide for all cases
command = makeString(tmp);
else
command = command.concat(makeString(tmp));
atNumber = i; //add this character to the string
//store the number for use in next loop
//DEFINITELY GOT IT
i = i + 1; //increment the counter variable
if (i < tooMuch) {
tmp = subject.charAt(i);
}
//if not exceeding range, get next char
//increment the character variable
} //end inner while
} //end if - done gotWord is true - get out of outer loop
else { //just increment character
i = i + 1; //and counter variables
if (i < tooMuch)
tmp = subject.charAt(i);
else
gotWord = true; //get out of this loop - line is empty
} //end else
} //end outer while
/*Now String variable contains the complete
command from the currrent memory node */
/*COLOR*/
if (command.equalsIgnoreCase("COLOR")) {
String tempNum = null; //holds the number to be obtained from
//a line before it is converted into
//a primitive type.
boolean numOn = false; //specifies whether reading a number
/*SAME AS OTHER EVALUATIONS OF COMMANDS*/
i = atNumber; //initialize counter variable to start
while (i < tooMuch) {
tmp = subject.charAt(i);
//store subject character - provided
//it is not greater than the range
if ((greaterChar(tmp, 48)) && (lesserChar(tmp, 57))) {
numOn = true; //reading a number now
while ((greaterChar(tmp, 48)) && (lesserChar(tmp, 57))
&& (i < tooMuch)) {
if (tempNum == null)
tempNum = makeString(tmp);
else
tempNum = tempNum.concat(makeString(tmp));
i = i + 1; //increment the counter variable
if (i < tooMuch)
tmp = subject.charAt(i);
//get the next one if condition is met;
//otherwise loop terminates on next pass
} //end while - number obtained
} //end number on if
/*CALL THE COLOR METHOD*/
if (numOn) {
color(makeInt(tempNum));
//convert the integer and...
//CALL THE COLOR METHOD
numOn = false; //back from method call (completeness)
i = tooMuch; //back from method call
//terminate while loop if it
//wasn't going to already
} //end numOn "if"
i = i + 1; //increment the counter by default
} //end while loop
} //end call to COLOR method
/*VLIN and HLIN*/
if ((command.equalsIgnoreCase("VLIN")) ||
(command.equalsIgnoreCase("HLIN"))) {
/*INITIALIZE ALL VARIABLES*/
//program must get the same types of
//data if this statement is true
int num1 = 0; //local variables to be
int num2 = 0; //used for purposes of auxillary
int num3 = 0; //method in this class
boolean ok1 = false; //specifies when #1 is gotten
boolean ok2 = false; //specifies when #2 is gotten
boolean ok3 = false; //specifies when #3 is gotten
boolean numOn = false; //specifies whether reading a number
String tempNum = null; //holds each number to be obtained
//from a line before it is converted
//into a primitive type
i = atNumber; //initialize counter variable
while (i < tooMuch) {
tmp = subject.charAt(i);
//store subject character - provided
//it is not greater than the range
if ((greaterChar(tmp, 48)) && (lesserChar(tmp, 57))) {
numOn = true; //reading a number now
while ((greaterChar(tmp, 48)) && (lesserChar(tmp, 57))
&& (i < tooMuch)) {
if (tempNum == null)
tempNum = makeString(tmp);
else
tempNum = tempNum.concat(makeString(tmp));
i = i + 1; //increment the counter variable
if (i < tooMuch)
tmp = subject.charAt(i);
//get the next one if condition is met;
//otherwise loop terminates on next pass
} //end while - number obtained
} //end number on if
/*Ifs to store the numbers and call appropriate auxillary method */
if (!ok1 && numOn) {
num1 = makeInt(tempNum);
//store the first number
tempNum = null; //reset this temp variable
ok1 = true; //don't set number 1 again;
numOn = false; //done with this number
} //end first if
if (!ok2 && numOn) {
num2 = makeInt(tempNum);
//store the second number
tempNum = null; //reset this temp variable
ok2 = true; //don't set number 1
numOn = false; //done with this number
} //end second if
if (!ok3 && numOn) {
num3 = makeInt(tempNum);
//store the third number
tempNum = null; //reset the temp variable (completeness)
ok3 = true; //reset the temp variable (completeness)
/*NOW CALL THE APPROPRIATE DRAWING METHOD*/
if (command.equalsIgnoreCase("VLIN")) {
vLIN(num1, num2, num3); }
//CALL THE vLIN method
else
hLIN(num1, num2, num3);
//CALL THE hLIN method
numOn = false; //done with this number (completeness)
i = tooMuch;
//terminate this for loop on return
} //end third if
i = i + 1; //increment the counter by default
} //end main while loop
} //end call to VLIN or HLIN
/*PLOT*/
if (command.equalsIgnoreCase("PLOT")) {
/*INITIALIZE ALL VARIABLES*/
//program must get the same types of
//data if this statement is true
int num1 = 0; //local variables to be
int num2 = 0; //used for purposes of auxillary
boolean ok1 = false; //specifies when #1 is gotten
boolean ok2 = false; //specifies when #2 is gotten
boolean numOn = false; //specifies whether reading a number
String tempNum = null; //holds each number to be obtained
//from a line before it is converted
//into a primitive type
i = atNumber; //initialize counter variable
while (i < tooMuch) {
tmp = subject.charAt(i);
//store subject character - provided
//it is not greater than the range
if ((greaterChar(tmp, 48)) && (lesserChar(tmp, 57))) {
numOn = true; //reading a number now
while ((greaterChar(tmp, 48)) && (lesserChar(tmp, 57))
&& (i < tooMuch)) {
if (tempNum == null)
tempNum = makeString(tmp);
else
tempNum = tempNum.concat(makeString(tmp));
i = i + 1; //increment the counter variable
if (i < tooMuch)
tmp = subject.charAt(i);
//get the next one if condition is met;
//otherwise loop terminates on next pass
} //end while - number obtained
} //end number on if
/*Ifs to store the numbers and call auxillary method */
if (!ok1 && numOn) {
num1 = makeInt(tempNum);
//store the first number
tempNum = null; //reset this temp variable
ok1 = true; //don't set number 1 again;
numOn = false; //done with this number
} //end first if
if (!ok2 && numOn) {
num2 = makeInt(tempNum);
//store the second number
tempNum = null; //reset this temp variable
ok2 = true; //don't set number 1
numOn = false; //done with this number (completeness)
i = tooMuch;
//terminate this for loop on return
/*NOW CALL THE PLOT DRAWING METHOD*/
plot(num1, num2);
} //end second if
i = i + 1; //increment the counter by default
} //end main while loop
} //end call to PLOT
/*IF NOT ONE OF THESE, GET NEXT LINE OF COMMAND*/
command = null; //reinitialize
gotWord = false; //variables
current = current.next; //get next list node
subject = (String)current.data;
//set next line for parsing
i = 0; //reinitalize univeral counter
//variable in this method
} //END BIG CONTROLLING WHILE
} //END PARSE METHOD
/**
makeCode - used to write the contents of of the new JCmnds Vector into a
source Java file
Inspired by CopyFile.java example
@param None
@return None
@exception IOException - problem writing to the disk
*/
public void makeCode() throws IOException {
String compiled = file + ".java";
//the name of the new file to write
char EOL = '\n'; //End of line Character for convenience
File writeOut = new File(compiled);
//the file object for writing to disk
FileWriter outFile = null; //output stream
try {
outFile = new FileWriter(writeOut);
outFile.write("/*--->Generated Java file by M. Scehovic's " +
"BasicCompiler" + EOL);
outFile.write("Java Translation of Apple II BASIC code for " +
file + " */" + EOL + EOL);
outFile.write("import java.awt.*;" + EOL);
outFile.write("import java.applet.Applet;" + EOL + EOL);
outFile.write("public class " + file + " extends Applet {" + EOL);
outFile.write(" public void paint(Graphics g) {" + EOL);
outFile.write("//--> DEFINE CUSTOM COLORS!" + EOL);
outFile.write(" Color lavender = new Color" +
"(225, 150, 250);" + EOL);
outFile.write(" Color darkGreen = new Color" +
"(50, 90, 50);" + EOL);
outFile.write(" Color aquamarine = new Color" +
"(50, 175, 225);" + EOL);
outFile.write(" Color lightBlue = new Color" +
"(100, 175, 255);" + EOL);
outFile.write(" Color brown = new Color" +
"(125, 75, 50);" + EOL);
outFile.write(" Color greenish = new Color" +
"(100, 255, 200);" + EOL);
outFile.write("//--> CREATE BACKGROUND like Apple II's" + EOL);
outFile.write(" g.setColor(Color.black);" + EOL);
outFile.write(" g.fillRect(0,0,410,410);" + EOL);
outFile.write("//--> NOW PLACE THE COMMANDS..." + EOL);
while (!(newJCmnds.isEmpty())) {
//loop to unload commands from the
//vector newJCmnds into the new file
outFile.write(" " + ((String)newJCmnds.elementAt(0)) +
EOL); //write the command and unload it
newJCmnds.removeElementAt(0);
} //end while loop
outFile.write(" } //end paint method" + EOL + "} //end " +
"generated class " + file);
} catch(IOException e)
{ System.err.println("Cannot write \"" + file + ".java" + "\""); }
outFile.close(); //done - close the output stream
/* NOW CREATE THE ACCOMPANYING HTML FILE -- Redefine necessary variables*/
String html = file + ".html";
//the name of the new file to write
writeOut = new File(html);
//the file object for writing to disk
outFile = null; //output stream
try {
outFile = new FileWriter(writeOut);
outFile.write("<html>" + EOL + "<head>" + EOL);
outFile.write("<title>Class " + file + " </title>" + EOL +
"</head>" + EOL);
outFile.write("<body><H3>Note this file generated M. Scehovic's " +
"BasicToJava program" + EOL + "(Java class). </H3>"
+ EOL);
outFile.write("<applet code=" + '\"' + file + ".class" + '\"' +
" width=410 height=410>" + EOL);
outFile.write("</applet>" + EOL + "</body>" + EOL + "</html>");
} catch(IOException e)
{ System.err.println("Cannot write \"" + file + ".java" + "\""); }
outFile.close(); //done - close the output stream
} //end method makeCode
/******************************STARTER METHOD******************************/
/**
load - loads the commands from the file into "memory,"
a linear linked listfor subsequent execution.
CopyFile.java example
@param None
@return None
@exception IOException - problem reading from the disk
*/
public void load() throws IOException {
File dataFile = new File(file);
//institute a new file object
FileReader infile = null; //input stream
BufferedReader iStream = null; //buffered input stream
String aLine = null; //string which will hold each line
String label = null; //to hold the label for
//each node of the new list
boolean gotLabel = false; //states whether the label has been
//gotten yet
int i = 0; //increment counter variable
char test; //temporary character variable
char EOL = '\n'; //convenience end of line character
try { //set input streams for reading
infile = new FileReader(dataFile);
iStream = new BufferedReader(infile);
while (((aLine = iStream.readLine()) != null)) {
//null indicates reached end of file
if (aLine.length() > 1) {
while (!gotLabel) {
//MAKE THE LABEL FOR NEW NODE
test = aLine.charAt(i);
//convert for necessary comparison
if ((greaterChar(test, 48)) && (lesserChar(test, 57))) {
//assign line number as the label -
//guaranteed to be unique
if (label == null)
label = makeString(aLine.charAt(i));
else
label = label.concat(makeString(aLine.charAt(i)));
i = i + 1; //now increment to get the next one
} //end if
else if (label.length() >= 1)
//make sure a label exists before exit
//will not leave until a character
//other than a number is encountered
gotLabel = true;
else
i = i + 1; //get the next character - line
//number must be moved over by one
} //end first while statement - got label
master.insertNode(label);
//insert a new containing node to memory
master.current.data = aLine;
//now place the data from the line in it
gotLabel = false; //reset these variables
label = null; //to prepare for the next pass
i = 0; //set the increment counter to 0
} //end EOL-if
} //end iStream while
} catch(IOException e)
{ System.err.println("Cannot read \"" + file + "\""); }
master.insertNode("Terminating");
master.current.data = "stop"; //the end node; signalling upcoming
//termination of the list
current = master.first; //set the first node for the parser
infile.close(); //done - close the input stream
} //END LOAD METHOD
/************************AUXILLARY INTERNAL METHODS*************************/
/**
vLIN - translates a call to the BASIC COMPILER to create
a vertical lines into a java paint method for a 400x400 grid.
@param starting y coordinate on a 40x40 pixel grid
@param ending y coordinate on a 40x40 pixel grid
@param x coordinate on a 40x40 pixel grid
@return None
*/
private void vLIN(/*IN*/ int a, /*IN*/ int b, /*IN*/ int c) {
String theCommand;
theCommand = ("g.fillRect(" + c*10 + ", " + a*10 + ", " + 10 + ", " +
(((b+1)*10) - a*10) + ");");
//draw the new vertical rectangle
//x1, y1, width, height
newJCmnds.addElement(theCommand);
//add it to the Vector
} //end method vLIN
/**
hLIN - translates a call to the BASIC COMPILER to create
a horizontal lines into a java paint method for a 400x400 grid.
@param starting x coordinate on a 40x40 pixel grid
@param ending x coordinate on a 40x40 pixel grid
@param y coordinate on a 40x40 pixel grid
@return None
*/
private void hLIN(/*IN*/ int a, /*IN*/ int b, /*IN*/ int c) {
String theCommand;
theCommand = ("g.fillRect(" + a*10 + ", " + c*10 + ", " +
(((b+1)*10) - a*10) + ", " + 10 + ");");
//draw the new horizontal rectangle
//x1, y1, width, height
newJCmnds.addElement(theCommand);
//add it to the Vector
} //end method hLIN
/**
color- translates a call to the BASIC COMPILER which specifies
a painting color within the Java graphical environment.
@param an integer indicating the color code with with to paint
@return None
Note: improves contrast between colors represented in Apple BASIC interpreter
none or invalid color specified yields an error on the System screen.
*/
private void color(/*IN*/ int a) {
//non-defined colors defined in RGB values
Color lavender = new Color(225, 150, 250);
Color darkGreen = new Color(50, 90, 50);
Color aquamarine = new Color(50, 175, 225);
Color lightBlue = new Color(100, 175, 255);
Color brown = new Color(125, 75, 50);
Color greenish = new Color(100, 255, 200);
switch(a) {
case 0:
newJCmnds.addElement("g.setColor(Color.black);");
break;
case 1:
newJCmnds.addElement("g.setColor(Color.red);");
break;
case 2:
newJCmnds.addElement("g.setColor(Color.blue);");
break;
case 3:
newJCmnds.addElement("g.setColor(lavender);");
break;
case 4:
newJCmnds.addElement("g.setColor(darkGreen);");
break;
case 5:
newJCmnds.addElement("g.setColor(Color.darkGray);");
break;
case 6:
newJCmnds.addElement("g.setColor(aquamarine);");
break;
case 7:
newJCmnds.addElement("g.setColor(lightBlue);");
break;
case 8:
newJCmnds.addElement("g.setColor(brown);");
break;
case 9:
newJCmnds.addElement("g.setColor(Color.orange);");
break;
case 10:
newJCmnds.addElement("g.setColor(Color.lightGray);");
break;
case 11:
newJCmnds.addElement("g.setColor(Color.pink);");
break;
case 12:
newJCmnds.addElement("g.setColor(Color.green);");
break;
case 13:
newJCmnds.addElement("g.setColor(Color.yellow);");
break;
case 14:
newJCmnds.addElement("g.setColor(greenish);");
break;
case 15:
newJCmnds.addElement("g.setColor(Color.white);");
break;
default:
System.out.println("No color specified in " +
current.toString());
} //end switch
} //end method color
/**
plot - translates a call to the BASIC COMPILER to create
a square point into a java paint method for a 400x400 grid.
@param indicating the x coordinate on a 40x40 pixel grid
@param indicating the y coordinate on a 40x40 pixel grid
@return None
*/
private void plot(/*IN*/ int a, /*IN*/ int b) {
String theCommand;
theCommand = ("g.fillRect(" + a*10 + "," + b*10 + ", 10, 10);");
//draw the new horizontal rectangle
//x1, y1, width, height
newJCmnds.addElement(theCommand);
//add it to the Vector
} //end method plot
/***************************SUPPORT INTERNAL METHODS*************************/
/**
greaterChar - decides whether a given character's unicode value
is greater than a given integer value.
@param the primitive character to be compared against
@param integer value of which it must be greater
@return true or false whether character value is greater than given integer
*/
private boolean greaterChar(/*IN*/ char a, /*IN*/ int b) {
Character determiner = new Character(a);
//instantiate the new object
if (determiner.charValue() >= b)
return true; //the condition
else
return false;
} //end method greaterChar
/**
lesserChar - decides whether a given character's unicode value
is lesser than a given integer value.
@param the primitive character to be compared against
@param integer value of which it must be greater
@return true or false whether character value is greater than given integer
*/
private boolean lesserChar(/*IN*/ char c, /*IN*/ int d) {
Character determiner = new Character(c);
//instantiate the new object
if (determiner.charValue() <= d)
return true; //the condition
else
return false;
} //end method lesserChar
/**
makeString - converts a primitive character type into a string object.
@param the primitive character to be converted to an object
@return a String value representing this primitive type
*/
private String makeString(/*IN*/ char a) {
Character newOne = new Character(a);
//make the new character object
return newOne.toString(); //give it back as a string
} //end method makeString
/**
makeInt - converts a Strig object to an integer object and returns its
primitive type value
@param the String object to be converted
@return the value of the primitive type equal to the original string - an int
*/
private int makeInt(/*IN*/ String t) {
Integer treasure = new Integer(t);
//make the new integer object
return treasure.intValue(); //give it back as a primitive type
} //end method makeInt
} //end class BasicCompiler!
/****************************************************************************
*BasicToJava: program to translate old low resolution graphical code for the
* Apple II BASIC interpreter into Java source code that can be
* viewed from within a Java Applet.
*
*Date: Created May 5, 1999
*
*Purpose: to fulfill the final project requirements for CMSC230 for Spring
* 1999 at The College of New Jersey in creating a program that
* utilizes data structures to perform an interesting function.
*
*Usage: calls methods from the accompanying worker class BasicCompiler to
* translate specific calls to the Apple II BASIC Interpreter into
* Java graphical statements. Requires the user to specify the name
* of the file to be translated as a command line argument.
*
*References: utilizes class ListNode and class List (which extends utilizes
* class ListNode to create a template for using a linear linked
* list data structure. These two classes, the supporting worker
* class BasicCompiler, and the files containing the native Apple
* II code must reside within the same directory (for usual use).
*
*Revision History: created May 5, 1999 (utilized smartHash.java - another
* Java method containing a Main method as a template for
* the creation of this file.
*
*Error Handling: returns an error if no command line argument is given
****************************************************************************/
import java.io.*; //needed for IOExceptions
/**
class BasicToJava
*********************************METHOD**************************************
main(String args[]) => calls for the instantiation of a new
BasicCompiler object and calls methods
load,parse, and makeCode within for this
object to initiate the translation of code
specified in a designated source file
containing native Apple II instructions
*********************************CONSTRUCTOR*********************************
None
*********************************EXCEPTIONS**********************************
IOException => thrown by load method from BasicCompiler
class if a problem is encountered
reading the file specified by the first
command line argument to this class
*****************************************************************************
*/
public class BasicToJava {
/********************************METHOD - Main*******************************/
/**
Main -- responsible for calling all the methods and actions relevant to
translating a specified file containing Apple II low resolution
graphical instructions into Java source code. Suggests the
compilation of this new file following creation of it.
@param integer command line argument
@return None
@Exception called method throws (IOException e) if difficulty is encountered
while attempting to read a file from the disk.
*/
public static void main (/*IN*/ String args[]) throws IOException {
/********************************DATA MEMBERS********************************/
boolean ok = true; //assumes command line argument exists
/********************************ROUTINE************************************/
//Check the argument for validity - Test 1: Is it there?
if (args.length == 0) {
System.out.println("Nope! This class requires a file name as " +
"an argument!!");
ok = false; //don't use this argument
} //end Test
if (ok == true) { //argument passes the test, use it
BasicCompiler translator = new BasicCompiler(args[0]);
//instantiate new object of type
//BasicCompiler
translator.load(); //load commands into the linear linked
//list for "execution" i.e. translation
translator.parse(); //parse the list and translate cmnds
translator.makeCode(); //write the translated commands out
//to the new Java file
System.out.println('\n'); //linefeed one line
System.out.println("-->" + translator.file + ".java created. Try "
+ "the new product by typing: javac " + translator.file + ".java" +
'\n' + " and then appletviewer: " + translator.file + ".html");
//provide the user with instructions
} //end if statement
} //end main method
} //end class BasicToJava