import java.util.Scanner; import java.util.ArrayList; import java.io.*; public class Jive { private static Scanner keys = new Scanner( System.in ); private static Scanner input; private static PrintWriter output; private static PrintWriter output2; // "global" info --- applies across entire program // ------------------------------------------------ // holds the vpl code as it is produced private static ArrayList vpl = new ArrayList(); // holds the name and starting index of all functions private static ArrayList funcStart = new ArrayList(); // string at given index is name of function called at hole -index private static ArrayList callHoles = new ArrayList(); // stores for entire program the start label assigned to each // given function name private static ArrayList callInfo = new ArrayList(); // little info for actual globals in VPL: // ---------------------------------------- // holds all the global variables for entire program private static ArrayList globsList; // "local" info --- used separately for each function // -------------------------------------------------- // holds the local variables and literals temporarily for each function private static ArrayList locsList = new ArrayList(); // once have a locsList for a function, store it in allLocs for output2 private static ArrayList allLocs = new ArrayList(); // holds the locations of the holes and the corresponding labels in current function private static ArrayList labelHoles = new ArrayList(); // holds the label and corresponding index for all labels in current function private static ArrayList labelInfo = new ArrayList(); public static void main(String[] args) throws Exception { if (args.length != 1) { System.out.println("Usage: java Jive "); System.exit(1); } String fileName = args[0]; input = new Scanner( new File( fileName ) ); output = new PrintWriter( new File( fileName + ".vpl" ) ); output2 = new PrintWriter( new File( fileName + ".doc" ) ); // scan Jive file one word at a time // (line breaks mean nothing more than a space) // start anonymous "main" function // since human readability is not a big issue, go ahead // and treat the "main" function like all others, even // though the label at the top is meaningless, since it // can't be called // (all other functions do these things when "Def" is encountered) vpl.add( 1 ); vpl.add( nextLabel(true) ); // all functions start with a 1 command // note index where command 4 will be inserted // (can change if there's a Globs command) funcStart.add( new StringIntPair( "?", 2 ) ); // note label for start of the function callInfo.add( new StringIntPair( "?", currentLabel ) ); // make scratch cell (local cell 0) for scratch space for main locsList.add( "-" ); int scratch = 0; String rememberWord = "huh?"; // used a little to pass word to next state callHoles.add("---"); // waste spot 0 so call holes -1, -2, -3, .. // match nicely to positions in list int state = 1; while ( input.hasNext() ) { String word = input.next(); System.out.println("--------------------->>>" + "\nIn state " + state + " processing [" + word + "]" ); if ( state == 1 ) { if ( word.equals("/*") ) { state = 2; } else if ( word.equals("Halt") ) { vpl.add( 26 ); state = 1; } else if ( word.equals("NL") ) { vpl.add( 29 ); state = 1; } else if ( word.equals("Def") ) {// starting a function definition // stuff to do when see Def, also when see end of input file finishFunctionDef(); // initialize things for the upcoming function definition locsList = new ArrayList(); labelHoles = new ArrayList(); labelInfo = new ArrayList(); // move on to see the function name state = 3; } else if ( isLabel( word ) ) {// process a label int label = nextLabel(false); labelInfo.add( new StringIntPair( word, label ) ); vpl.add( 1 ); vpl.add( label ); state = 1; } else if ( word.equals("Globs") ) {// global declarations section // global declarations must be first command in program, if there at all if ( vpl.size() == 2 ) {// have only put in the command 1 for "main" // so still at start vpl.add( 0, 32 ); globsList = new ArrayList(); state = 6; } else { error( "Globals declaration must occur at very beginning of a Jive program"); } } else if ( word.equals("Jmp") ) { vpl.add( 7 ); state = 7; } else if ( findBIF2( word ) >= 0 ) {// is built-in function with 2 args // cheaply get opcode corresponding to word int op; if ( word.equals("Get") ) { op = 24; } else { op = findBIF2(word) + 9; } vpl.add( op ); // the binary op vpl.add( scratch ); // where to put the result state = 8; } else if ( findBIF1( word ) >= 0 ) {// is built-in function with 1 arg if ( word.equals( "Not" ) ) vpl.add( 20 ); else if ( word.equals( "Opp" ) ) vpl.add( 21 ); else if ( word.equals( "New" ) ) vpl.add( 31 ); else error("[" + word + "] is not a valid one argument built-in function"); vpl.add( scratch ); state = 11; } else if ( word.equals("Keys") ) {// is built-in function with 0 args vpl.add( 27 ); state = 13; } else if ( word.equals("Fet") ) {// have to look for built-in Fet before user-def state = 16; } else if ( isFuncName( word ) ) { rememberWord = word; state = 14; } else if ( isVar( word ) ) { // can put in entire part 1 code here vpl.add( 23 ); vpl.add( scratch ); vpl.add( processVar( word, locsList ) ); state = 15; } }// state 1 else if ( state == 2 ) { if ( word.equals("*/") ) {// reached end of comment state = 1; // start a new command } else {// part of comment // consume the word and stay in state 2 } } else if ( state == 3 ) { if ( ! isFuncName( word ) ) { error( "[" + word + "] is not a valid function name"); } vpl.add( 1 ); vpl.add( nextLabel(true) ); // all functions start with a 1 command // note index where command 4 will be inserted funcStart.add( new StringIntPair( word, vpl.size() ) ); // note label for start of the function callInfo.add( new StringIntPair( word, currentLabel ) ); state = 5; } // state 4 lost in change from f ( a b c ) to f a b c . else if ( state == 5 ) { if ( word.equals( "." ) ) { // make scratch cell for this function after params cells locsList.add( "-" ); scratch = locsList.size()-1; state = 1; // go on to body of function } else if ( isParam( word ) ) { // note another parameter locsList.add( word ); // loop back to stay in state 5 } } else if ( state == 6 ) { if ( word.equals( "." ) ) { // done creating list of globals, generate VPL code for command 32 vpl.add( 1, globsList.size() ); // adjust start index of "main" to be 2 farther funcStart.get( 0 ).x += 2; state = 1; } else if ( isParam( word ) ) { // add global globsList.add( word ); // stay in state 6 } else { error("[" + word + "] is not a valid global variable name"); } } else if ( state == 7 ) { if ( isLabel( word ) ) { // add the hole vpl.add( -1 ); labelHoles.add( new StringIntPair( word, vpl.size()-1 ) ); state = 1; } else { error( "[" + word + "] is not a valid label"); } } else if ( state == 8 ) { if ( isVar( word ) ) { vpl.add( processVar( word, locsList ) ); // first arg state = 9; } else { error( "[" + word + "] is not a valid variable or literal"); } } else if ( state == 9 ) { if ( isVar( word ) ) { vpl.add( processVar( word, locsList ) ); // second arg state = 10; } else { error( "[" + word + "] is not a valid variable or literal"); } } else if ( state == 10 ) { if ( word.equals("->") ) { state = 100; } else { error("a part 1 must be followed by ->"); } } else if ( state == 11 ) { if ( isVar( word ) ) { vpl.add( processVar( word, locsList ) ); state = 12; } else { error( "[" + word + "] is not a valid variable or literal"); } } else if ( state == 12 ) { if ( word.equals("->") ) { state = 100; } else { error("a part 1 must be followed by ->"); } } else if ( state == 13 ) { if ( word.equals("->") ) { vpl.add( scratch ); state = 100; } else { error("a part 1 must be followed by ->"); } } else if ( state == 14 ) { if ( isVar( word ) ) { vpl.add( 3 ); vpl.add( processVar( word, locsList ) ); // state loops to 14 } else if ( word.equals("->") ) { // done with function call, send out the vpl code vpl.add( 2 ); vpl.add( - nextCallHole() ); // leave a hole callHoles.add( rememberWord ); // followed by command 6 for when return from doing called function vpl.add( 6 ); vpl.add( scratch ); state = 100; } else { error("a part 1 must be followed by ->"); } } else if ( state == 15 ) { if ( word.equals("->") ) { state = 100; } else { error("a part 1 must be followed by ->"); } } else if ( state == 16 ) { if ( isParam( word ) ) { vpl.add( 34 ); vpl.add( scratch ); vpl.add( processVar( word, globsList ) ); state = 17; } else { error("[" + word + "] is not a valid argument for Fet"); } } else if ( state == 17 ) { if ( word.equals("->") ) { state = 100; } else { error("a part 1 must be followed by ->"); } } // end of part 1 states // begin part 2 states else if ( state == 100 ) {// start state for part 2 if ( word.equals(".") ) { // do nothing with the value in scratch cell from part 1 state = 1; } else if ( word.equals("Prt") ) { // generate code to print the value in the scratch cell vpl.add( 28 ); vpl.add( scratch ); state = 1; } else if ( word.equals("Sym") ) { // generate code to print the value in the scratch cell vpl.add( 30 ); vpl.add( scratch ); state = 1; } else if ( word.equals("Ret") ) { // generate code to return the value in scratch cell vpl.add( 5 ); vpl.add( scratch ); state = 1; } else if ( isParam( word ) ) { vpl.add( 23 ); vpl.add( processVar( word, locsList ) ); vpl.add( scratch ); state = 1; } else if ( word.equals("Jmp") ) { state = 101; } else if ( word.equals("Put") ) { state = 102; } else if ( word.equals("Sto") ) { state = 104; } else {// unknown first word in a part 2 error("[" + word + "] is invalid as start of a part 2"); } }// start state for part 2 (100) else if ( state == 101 ) { if ( isLabel( word ) ) { vpl.add( 8 ); vpl.add( -1 ); // hole for target of jump labelHoles.add( new StringIntPair( word, vpl.size()-1 ) ); vpl.add( scratch ); state = 1; } else { error("[" + word + "] is not a valid label to use after conditional Jmp"); } } else if ( state == 102 ) {// processing first for Put if ( isVar( word ) ) {// have valid first argument vpl.add( 25 ); vpl.add( processVar( word, locsList ) ); state = 103; } else { error("[" + word + "] is not a valid first argument for Put"); } } else if ( state == 103 ) {// processing second for Put if ( isVar( word ) ) {// have valid second argument vpl.add( processVar( word, locsList ) ); vpl.add( scratch ); state = 1; } else { error("[" + word + "] is not a valid first argument for Put"); } } else if ( state == 104 ) { if ( isParam( word ) ) {// valid argument for Sto // generate VPL code 33 n a vpl.add( 33 ); vpl.add( processVar( word, globsList ) ); vpl.add( scratch ); state = 1; } else { error("[" + word + "] is not a valid argument for Sto"); } } }// loop to scan all words in Jive source file // finish off last function definition finishFunctionDef(); System.out.println("vpl before filling call holes:"); for ( int k=0; k list ) { for (int k=0; k list ) { for (int k=0; k