
/************************************************************************************************/
/************************************************************************************************/
/**                                                **/
/**       |--------------------------------------|                         **/
/**       | JoshJava to MARIE Assembler Compiler |                         **/
/**       |--------------------------------------|                         **/
/**                                                **/
/** This is a complier/parser to translate from JoshJava to MARIE.                 **/
/** It has a procedure GetT for each (most) non-terminal T. The                **/
/** pre-condition/post-condition contract for these will be as follows.            **/
/**                                                **/
/** Parse:                                             **/
/**   For each nonterminal T, the routine GetT parses the longest substring            **/
/**   of the code from the indicated starting pothat is a valid T.             **/
/**                                                **/
/** Output:                                            **/
/**   The output consists of the parsing.                              **/
/**   For Compile, it is MARIE assembly code that will mirror the actions              **/
/**   taken in the block of JoshJava code being parsed.                    **/
/**                                                **/
/** token:                                             **/
/**   The global variable token initially contains the next token                  **/
/**   to be processed, ie the first token in T.                        **/
/**   When GetT returns the global variable token will be changed to the next          **/
/**   token to be processes which is the first token after this parsed T.              **/
/**                                                **/
/** Memory Address m:                                      **/
/**   GetExp, GetTerm, and GetFact is passed an address m of physical              **/
/**   memory. The result of the assembly code produced is to evaluate the              **/
/**   Exp, Term, or Factor and store the result in this memory cell.               **/
/**                                                **/
/** nextLabel:                                         **/
/**   The global variable nextLabel is an integer indicating what the next             **/
/**   label in the assembly code should be. For example, if nextLabel is 5             **/
/**   then the next label will be "Label5".                            **/
/**                                                **/
/** r:                                             **/
/**   A parameter integer r is passed to each routine indicating the depth             **/
/**   of the parse tree. For example, when GetProgram will have a value of             **/
/**   0. When it calls GetMainProcedure it will have 1. When it calls List             **/
/**   Code it will have 2. And so one. The purpose of this is to indent the            **/
/**   MARIE code based on this value.                              **/
/**                                                **/
/** MARIE comments:                                        **/
/**   This compiler also comments the MARIE instructions to tell which             **/
/**   procedure and which rule produced the instruction.                       **/
/**                                                **/
/************************************************************************************************/
/************************************************************************************************/


import java.io.BufferedReader
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.FileReader
import java.io.IOException
import java.io.PrintStream
import java.io.StreamTokenizer

public class Compiler {
    StreamTokenizer code               // This Java object keeps track of where in the file the tokenizer is
    // and the command code.nextToken() returns the next token,
    // converting it to an string, character, or real as needed. 
    token                      // Contains the next token to process. 
    nextL                      // The next MARIE label will be L037 when nextL=37
    FileOutputStream fileOutputStream      // MARIE code streamed out here.
    PrintStream fps                        // MARIE code streamed out here.
    boolean debug = true               // Whether to output debugging statements.
    boolean ascii = true                   // Whether to output in ascii or ints.
    String[] ss = new String[16]       // Routines at depth r will be indented by ss[r] = tab + 2r blanks
    String procedureName = new String("globalVars")   // The name of the current routine being compiled.
    // The label for the end will be one bigger.

    algorithm init(String fileName, boolean a, boolean d) throws IOException {
        ascii=a
        debug=d
        HandleFiles(fileName)
        nextToken()              // GetT requires first token to have been read
        GetProgram(0)
        CompleteCode()
    }

    /************************************************************************************************/
    /** Routine GetProgram produces MARIE code that executes the following JoshJava statements:    **/
    /**                                                **/
    /** Program     ==>    ProgramBlock                            **/
    /**            ProgramBlock                            **/
    /**              ...                                   **/
    /**            ProgramBlock                            **/
    /**                                                **/
    /** ProgramBlock    ==>    GListVarDec                     (begins with "int") **/
    /**         ==>    MainProcedure                               **/
    /**         ==>    Procedure                               **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetProgram(r) {
        while( true ) {
            if(token!=StreamTokenizer.TT_WORD)
                break
            if( code.sval.equals("") ) 
                GetListVarDec(r,true)
            else if( code.sval.equals("public") ) 
                GetProcedure(r)
            else
                break
        }
    }
    
    /************************************************************************************************/
    /** Routine GetProcedure produces MARIE code that executes the following JoshJava statements:  **/
    /**                                                **/
    /** MainProcedure   ==>    algorithm main (String[] args) {                 **/
    /**              LListVarDec                               **/
    /**              ListCode                              **/
    /**            }                                   **/
    /**                                                **/
    /** Procedure       ==>    public  ProcedureName( LVarName, LVarName, ...) {       **/
    /**              LListVarDec                               **/
    /**              ListCode                              **/
    /**            }                                   **/
    /**                                                **/
    /** ProcedureName   ==>    any string starting with a letter                   **/
    /** LVarName    ==>    any string starting with a small letter                 **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetProcedure(r) {
        nextToken()
        nextToken()
        nextToken()            // void or int
        if( token!=StreamTokenizer.TT_WORD )
            System.out.format("* Error: GetListVarDec: Expected ProcedureName")
        procedureName = new String(code.sval)  // Save the ProcedureName
        nextToken()
        
        Output("/**********************************************************************")    
        Output("/** %s",procedureName)              
        Output("/**********************************************************************")    
        Output("%s,","B_"+procedureName)       
        Output("JnS %s       /Mark the beginning of the data to copy to recursive stack","B_"+procedureName)
        Output("         /and contains its own address")
        Output("%s,","J_"+procedureName)           
        Output("Hex 0    /Beginning of procedure.") 
        Output("         /JnS store here the address to Jump back to")
        Output("         /Note this too needs to be copied to the recursive stack")
        
        nextToken()
        if( token==StreamTokenizer.TT_WORD && code.sval.equals("String") ) {
            nextToken()
            nextToken()
            nextToken()
            nextToken()              
        }
        else
            GetListVarInputDec(r+1)
        nextToken()')
        nextToken()
        GetListVarDec(r+1,false)
        GetListCode(r+1)
        nextToken()
        Output("Halt")        
    }
    

    
    /************************************************************************************************/
    /** Routine GetListVarInputDec produces MARIE code that executes the following         **/
    /**    JoshJava statements:                                    **/
    /**                                                **/
    /** GetListVarInputDec    ==>    LVarName, LVarName, ..., LVarName         **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetListVarInputDec(r) {
        for( i=0 i<16 ++i ) {
            nextToken()
            if( token!=StreamTokenizer.TT_WORD )
                System.out.format("* Error: GetListVarDec: Expected string")
            String varName = new String(code.sval) // Save the variable name
            varName = GlobalLocalVar(varName)      // Concatenate with procedure name
            nextToken()         // move token past the VarName

            Output("Jump L%03d    /Jump over data", nextL)            
            Output("%s,",varName)              // The varName acts as the label of the memory cell.
            Output("Dec 0")
            Output("L%03d,",nextL)     
            Output("Load input%x  /Copy in input", i)
            Output("Store %s", varName)
            ++nextL                            
            
            if( token!=',' )
                break
            nextToken()
        }
    }

    /************************************************************************************************/
    /** Routine GetListVarDec produces MARIE code that executes the following JoshJava statements: **/
    /**                                                **/
    /** GListVarDec     ==>    GVarDec                                 **/
    /**            GVarDec                                 **/
    /**              ...                                   **/
    /**            GVarDec                                 **/
    /**                                                **/
    /** GVarDec     ==>     GVarName                              **/
    /**         ==>     GVarName = Int                        **/
    /**         ==>     int[] GVarName = new int[Int]                     **/
    /**                                                **/
    /** GVarName    ==>    any string starting with a capital letter               **/
    /**                                                **/
    /** LListVarDec     ==>    LVarDec                                 **/
    /**            LVarDec                                 **/
    /**              ...                                   **/
    /**            LVarDec                                 **/
    /**                                                **/
    /** LVarDec     ==>    LVarName                               **/
    /**         ==>    LVarName = Int                         **/
    /**         ==>    int[] LVarName = new int[Int]                      **/
    /**                                                **/
    /** LVarName    ==>    any string starting with a small letter                 **/
    /**                                                **/
    /**     isGlobal indicates whether processing GlistVarDec or LlistVarDec               **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetListVarDec(r, boolean isGlobal) {
        boolean isArray
        arraySize=0
        initialValue=0
        if( isGlobal ) {
            Output("/**********************************************************************")    
            Output("/** Global Variable Declarations")              
            Output("/**********************************************************************")    
        }
        else {
            Output("Jump %s   /Jump over data", "S_"+procedureName)   
        }
        while( token==StreamTokenizer.TT_WORD && (code.sval.equals("") || code.sval.equals("int") )) {
            if( isGlobal ) 
                nextToken()
            nextToken()
            if( token=='[') {
                isArray = true
                nextToken()
                nextToken()
            }
            else
                isArray = false
            if( token!=StreamTokenizer.TT_WORD )
                System.out.format("* Error: GetListVarDec: Expected string")
            String varName = new String(code.sval) // Save the variable name
            nextToken()         // move token past the VarName
            if( !isArray ) {
                if( token=='=') {
                    nextToken()
                    if( token!=StreamTokenizer.TT_NUMBER )
                        System.out.format("* Error: GetListVarDec: Expected an integer")
                    initialValue = (int) code.nval
                    nextToken()
                }
                else
                    initialValue = 0
            }
            else {                                  // isArray
                nextToken()
                nextToken()
                nextToken()
                nextToken()
                if( token!=StreamTokenizer.TT_NUMBER )
                    System.out.format("* Error: GetListVarDec: Expected an integer")
                arraySize = (int) code.nval
                nextToken()
                nextToken()
            }
            nextToken()
            if( isGlobal && !( varName.charAt(0)>='A' && varName.charAt(0)<='Z') ) 
                System.out.format("* Error: GetListVarDec: Global variable must start with a capital letter")
            if( !isGlobal && !( varName.charAt(0)>='a' && varName.charAt(0)<='z') ) 
                System.out.format("* Error: GetListVarDec: Local variable must start with a small letter")
            if( !isGlobal )
                varName = GlobalLocalVar(varName)      // Concatenate with procedure name
            if( !isArray ) {
                Output("%s,",varName)     // The varName acts as the label of the memory cell.
                Output("Dec %03d", initialValue)
            }
            else {
                Output("%s,",varName)     // The varName acts as the label of the memory cell.
                Output("JnS L%03d    /Address of %s[0]", nextL,varName)
                Output("L%03d,",nextL)     // Memory cell for 
                Output(ss[r+1]+"Hex 0     /Memory cell for %s[0]", varName)
                nextL += 1
                for( i=1 i<= arraySize-1 ++i ) 
                    Output(ss[r+1]+"Hex 0")
            }
        }
        if( !isGlobal ) {
            Output("%s,","E_"+procedureName)               
            Output(ss[r-1]+"JnS %s    /Mark the end of the ListVarDec and contains its own address","E_"+procedureName)
            Output("%s,","L_"+procedureName)               
            Output(ss[r-1]+"Hex 0     /Lenght of the ListVarDec")
            Output("%s,","S_"+procedureName)               
            Output("Load %s     /Address one after ListVarDec","E_"+procedureName)
            Output("Subt %s     /Address one before ListVarDec","B_"+procedureName)
            Output("Subt One    /Lenght of ListVarDec")
            Output("Store %s","L_"+procedureName)
            Output("/Beginning of Code")
        }
    }

    /************************************************************************************************/
    /** Routine GetBlockCode produces MARIE code that executes the following JoshJava statements:  **/
    /**                                                **/
    /** BlockCode       ==>    LineCode                                **/
    /**         ==>    { ListCode }                            **/
    /************************************************************************************************/

    algorithm GetBlockCode(r) {
        if(token=='{') {
            nextToken() // move token past the '{' in "{ ListCode }"
            GetListCode(r)
            nextToken() // move token past the '}' in "{ ListCode }"
        }
        else
            GetLineCode(r)
    }

    /************************************************************************************************/
    /** Routine GetListCode produces MARIE code that executes the following JoshJava statements:  **/
    /**                                                **/
    /** ListCode    ==>    LineCode                                **/
    /**            LineCode                                **/
    /**              ...                                   **/
    /**            LineCode                      (ends with '}')       **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetListCode(r) {
        while( token==StreamTokenizer.TT_WORD ) // Lines beginning with a string and not with a }
            GetLineCode(r)
    }

    /************************************************************************************************/
    /** Routine GetLineCode produces MARIE code that executes the following JoshJava statements:   **/
    /**                                                **/
    /** LineCode    ==>    Assignmentv                   (begins with 'string')    **/
    /**         ==>    Assignmenta                   (begins with 'string[')   **/
    /**         ==>    IfStatement                   (begins with 'if')    **/
    /**         ==>    WhileStatement                (begins with 'while')     **/
    /**         ==>    ProcedureCall                 (begins with "string(")   **/
    /**         ==>    Return                    (begins with 'return')    **/
    /**         ==>    Out                       (begins with 'System...') **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetLineCode(r) {
        if(code.sval.equals("if"))
            GetIfStatement(r+1)
        else if(code.sval.equals("while"))
            GetWhileStatement(r+1)
        else if(code.sval.equals("return"))
            GetReturn(r+1)
        else if(code.sval.equals("System.out.print") || code.sval.equals("System.out.println"))
            GetOutPut(r+1)
        else if(code.sval.equals("int"))
            System.out.format("* Error: GetLineCode: All variable declarations must be at the top of procedure - Sorry")
        else {
            String varName = new String(code.sval) // Save the variable name
            nextToken()         // move token past the variable in "var = Exp"
            if(token=='[') 
                GetAssignmenta(r+1,varName)
            else if(token=='(') {
                GetProcedureCall(0,varName)
                nextToken() // move token past the '' in "p(2)"
            }
            else
                GetAssignmentv(r+1,varName)
        }
    }

    /************************************************************************************************/
    /** Routine GetAsignmentv produces MARIE code that executes the following JoshJava statements: **/
    /**                                                **/
    /** Assignmentv     ==>    VarName = Exp                              **/
    /**      The VarName is in varName and '=' is in token                     **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetAssignmentv(r, String varName) {
        varName = GlobalLocalVar(varName)      // Concatenate with procedure name
        nextToken()   // move token past the '=' in "vi = Exp"
        GetExp(0)                          // Evaluate Exp and store it in cell0
        Output("Load cell0")
        Output("Store %s",varName)
        nextToken() // move token past the '' in "vi = Exp"
    }

    /************************************************************************************************/
    /** Routine GetAssignmenta produces MARIE code that executes the following JoshJava statements:**/
    /**                                                **/
    /** Assignmenta     ==>    VarName[Exp] = Exp                         **/
    /**      The VarName is in varName and '[' is in token                     **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetAssignmenta(r, String varName) {
        varName = GlobalLocalVar(varName)      // Concatenate with procedure name
        nextToken()    // move token past the '['
        GetExp(0)                  // Evaluate first Exp in "a[Exp]=Exp" and store it in cell0
        nextToken()   // move token past the '['
        nextToken()   // move token past the '='
        GetExp(1)                          // Evaluate second Exp in "a[Exp]=Exp" and store it in cell1
        Output("Load %s",varName)       // Load a   (or b)
        Output("JnS StoreInArray")
        nextToken() // move token past the '' in "a[Exp] = Exp"
    }

    /************************************************************************************************/
    /** Routine GlobalLocalVar determines if a variable name is local or global            **/
    /**       and makes unique if local                                **/
    /************************************************************************************************/

    public  String GlobalLocalVar(String varName) {
        if(varName.charAt(0) >= 'a' && varName.charAt(0) <= 'z' )  // Local if begins with small letter
            return varName.concat("_"+procedureName)
        else
            return varName
    }

    /****************************************************************************/
    /** Routine GetExp produces MARIE code that                                **/
    /**     evaluates an expression Exp and stores it in cellm                 **/
    /**                                                                        **/
    /** Exp             ==>    Term                                            **/
    /**                 ==>    Term +|- Term +|- ... +|- Term                  **/
    /**                                                                        **/
    /****************************************************************************/
    algorithm GetExp(m) {
        GetTerm(m)                      // MARIE code that evaluates a term and stores 
                                        // its value in memory cell indexed by m 
        while( true ){
            if(token=='+')              // Token after the term
                nextToken()             // move token past the '+'
                GetTerm(m+1)            // MARIE code that evaluates a term and stores 
                                        // its value in memory cell indexed by m+1 
                Output("Load cell",m)   // cellm = cellm + cell(m+1)
                Output("Add  cell",m+1)
                Output("Store cell",m)
            elseif(token=='-') ...                      
            else exit
        }
    }

    /****************************************************************************/
    /** Routine GetTerm produces MARIE code that                               **/
    /**     evaluates an expression Term and stores it in cellm                **/
    /**                                                                        **/
    /** Term            ==>    Factor                                          **/
    /**                 ==>    Factor *|/ Factor *|/ ... *|/ Factor            **/
    /**                                                                        **/
    /****************************************************************************/
    algorithm GetTerm(m) {
        GetFact(m)                      // MARIE code that evaluates a factor and stores 
                                        // its value in memory cell indexed by m 
        while( true ){
            if(token=='*')              // Token after the factor
                nextToken()             // move token past the '*'
                GetFact(m+1)            // MARIE code that evaluates a factor and stores 
                                        // its value in memory cell indexed by m+1 
                Output("Load cell",m)   // cellm = cellm * cell(m+1)
                Output("... call routine to Mult cell",m+1)
                Output("Store cell",m)
            elseif(token=='/') ...                      
            else exit
        }
    }

    /****************************************************************************/
    /** Routine GetFact produces MARIE code that                               **/
    /**     evaluates an expression Fact and stores it in cellm                **/
    /**                                                                        **/
    /** Factor          ==>    Int                                             **/
    /**                 ==>    ( Exp )                                         **/
    /**                 ==>    VarName                                         **/
    /**                 ==>    VarName[Exp]                                    **/
    /**                 ==>    readInt()                                       **/
    /**                 ==>    ProcedureCall                                   **/
    /**                                                                        **/
    /****************************************************************************/

        /************************************************************************************************/
        /** Routine GetFact produces MARIE code that evaluates a factor Factor                         **/
        /** and stores it in ExpSm                                                                     **/
        /**                                                                                            **/
        /** Factor ==>    Int              begins with '0' .. '9'     **/
        /**        ==>    ( Exp )          begins with '('            **/
        /**        ==>    VarName          begins with "string"       **/
        /**        ==>    VarName[Exp]     begins with "string["      **/
        /**        ==>    readInt()        begins with "readInt()"     **/
        /**        ==>    ProcedureCall    begins with "string("      **/
        /**                                                                                            **/
        /************************************************************************************************/


    algorithm GetFact(m) {
        switch (token) { 
        case StreamTokenizer.TT_NUMBER:                 // A number was found                 
            GetFactInt(m,r)
            return
        case '(': 
            GetFactExp(m,r)
            return
        case StreamTokenizer.TT_WORD: 
            if(code.sval.equals("in.nextInt"))          // in.nextInt
                GetFactInput(m,r)
            else {
                String varName = new String(code.sval) // Save the variable name
                nextToken()         // move token past the variable name
                if(token=='[')                          // a[Exp] 
                    GetFactArray(m,r,varName)
                else if(token=='(')                     // ProcedureCall(5)
                    GetProcedureCall(m,r,varName)
                else 
                    GetFactVar(m,r,varName)
            }
            return
        default:
            nextToken()              // Will pran Error (Unless starts with F)
            return
        }
    }

    /************************************************************************************************/
    /** Routine GetFactInt MARIE code that evaluates a factor Factor that is an integer   **/
    /** and stores it in cellm                                     **/
    /**                                                **/
    /** Factor      ==>                                    **/
    /**         ==>    5                                   **/
    /**                                                **/
    /************************************************************************************************/
    algorithm GetFactInt(m) {
        switch ((int) code.nval) {              // A number was found the value is in code.nval 
        case 0: 
            Output("Clear")
            break
        case 1: 
            Output("Load One")
            break
        default:
            Output("Jump L%03d   /Jump over data line", nextL+1)
            Output("L%03d,",nextL)
            Output("Dec %d       /Store constant", (int) code.nval)
            Output("L%03d,",nextL+1)
            Output("Load L%03d   /Save constant", nextL)
            nextL+=2
            break
        }               
        Output("Store cell", m)
        nextToken()        // move token past the integer
    }

    /************************************************************************************************/
    /** Routine GetFactExp produces MARIE code that evaluates a factor of the form ( Exp )     **/
    /** and stores it in cellm                                     **/
    /**                                                **/
    /** Factor      ==>    ( Exp )                                 **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetFactExp(m) {
        nextToken()            // move token past the '('
        GetExp(m)                          // Evaluate Exp and store in cellm
        nextToken()')           // move token past the ')'
    }

    /************************************************************************************************/
    /** Routine GetFactInput produces MARIE code that evaluates a factor of the form in.next   **/
    /** and stores it in cellm                                     **/
    /**                                                **/
    /** Factor      ==>    in.next                             **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetFactInput(m) {
        Output("Input")
        Output("Store cell%x /Save it", m)
        nextToken()   // move past the "in.nextInt"
    }       

    /************************************************************************************************/
    /** Routine GetFactArray produces MARIE code that evaluates a factor of the form VarName[Exp]  **/
    /** and stores it in cellm               
    /**                                      
    /** Factor  ==>  VarName[Exp]      
    /**                                      
    /************************************************************************************************/

    algorithm GetFactArray(m) {
        varName = procedurename + token  // Concatenate variable name with procedure name
        nextToken()                      // move token past variable name
        nextToken()                      // move token past the '[' in "varName[Exp]"
        GetExp(m+1)                      // MARIE code that evaluates Exp and stores 
                                         // its value in memory cell indexed by m+1
        nextToken()                      // move token past the ']' in "varName[Exp]"
        Output("Load ",varNam  )         // Load address of varName[0]
        Output("Add cell",m+1 )          // Add Exp to address of varName[0] for address of varName[Exp]
        Output("Store Temp0")
        Output("LoadI Temp0")            // Load the value of varName[Exp]
        Output("Store cell",m)           // Store value in cellm
    }

    /************************************************************************************************/
    /** Routine GetFactVar produces MARIE code that evaluates a factor of the form VarName     **/
    /** and stores it in cellm                                     **/
    /**                                                **/
    /** Factor      ==>    VarName                                 **/
    /**      The VarName is in varName and token has moved one past it.                **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetFactVar(m, String varName) {
        varName = GlobalLocalVar(varName)          // Concatenate with procedure name
        Output("Load %s ", varName)
        Output("Store cell", m)
    }

    /************************************************************************************************/
    /** Routine GetBooleanExp produces MARIE code that that evaluates a BooleanExp         **/
    /** and stores it in cellm                                     **/
    /**                                                **/
    /** BooleanExp      ==> BooleanTerm                                **/
    /**         ==> BooleanTerm || ... || BooleanTerm                      **/
    /**                                                **/
    /**  (Note && has higher order of operations just like * does                  **/
    /**   true || true && false  = true || (true && false)                     **/
    /**             not   (true || true) && false  )                       **/
    /**                                                **/
    /** true        ==>    positive integer                            **/
    /** false       ==>    zero                                **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetBooleanExp(m) {
        GetBooleanTerm(m)                          // Read first Term and put it in cellm
        while( true ){
            if(token=='|') {                            // Token after the term
                nextToken()         // move token past the '|'
                nextToken()    // move token past the second '|'
                GetBooleanTerm(m+1)                // Read next BooleanTerm and put it in cell(m+1)
                Output("Load cell",m)
                Output("Add  cell",m+1)
                Output("SkipCond 400",m)
                Output("Jump L%03d   /Jump over data line", nextL)
                Output("Clear")
                Output("Jump L%03d   /Jump over data line", nextL+1)
                Output("L%03d,", nextL)
                Output("Load One")
                Output("L%03d,", nextL+1)
                Output("Store cell",m)
                nextL+=2
            }
            else
                return
        }
    }

    /************************************************************************************************/
    /** Routine GetBooleanTerm produces MARIE code that that evaluates a BooleanTerm           **/
    /** and stores it in cellm                                     **/
    /**                                                **/
    /** BooleanTerm     ==> BooleanFactor                              **/
    /**         ==> BooleanFactor && ... && BooleanFactor                  **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetBooleanTerm(m) {
        GetBooleanFact(m)                          // Read first Fact and put it in cellm
        while( true ){
            if(token=='&') {                            // Token after the Fact
                nextToken()        // move token past the '&'
                nextToken()   // move token past the second '&'
                GetBooleanFact(m+1)                // Read next BooleanFact and put it in cell(m+1)
                Output("Load cell",m)
                Output("Add  cell",m+1)
                Output("Subt One")
                Output("Subt One")
                Output("SkipCond 400",m)
                Output("Jump L%03d   /Jump over data line", nextL)
                Output("Load One")
                Output("Jump L%03d   /Jump over data line", nextL+1)
                Output("L%03d,", nextL)
                Output("Clear")
                Output("L%03d,", nextL+1)
                Output("Store cell",m)
                nextL+=2
            }
            else
                return
        }
    }

    /************************************************************************************************/
    /** Routine GetBooleanFactor produces MARIE code that that evaluates a BooleanFactor       **/
    /** and stores it in cellm                                     **/
    /**                                                **/
    /** BooleanFactor   ==> true|false                                 **/
    /**         ==> BooleanStatement                               **/
    /**         ==> (BooleanExp)                               **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetBooleanFact(m) {
        switch (token) { 
        case '(': 
            nextToken()",'(')          // move token past the '('
            GetBooleanExp(m)                           // Evaluate Exp and store in cellm
            nextToken()",')')         // move token past the ')'
            return
        case StreamTokenizer.TT_WORD: 
            switch (code.sval.charAt(0)){
            case 't':                                           // code.sval is the token true.
                Output("Load One")
                Output("Store cell%x", m)
                nextToken()     // move token past the true
                return
            case 'f':                                           // code.sval is the token true.
                Output("Clear")
                Output("Store cell%x", m)
                nextToken()   // move token past the true
                return
            default:
                GetBooleanStatement(m) 
                return
            }
        default:
            GetBooleanStatement(m) 
            return
        }
    }

    /************************************************************************************************/
    /** Routine GetBooleanStatement produces MARIE code that that evaluates a BooleanStatement     **/
    /** and stores it in cellm                                     **/
    /**                                                **/
    /** BooleanStatement  ==> Exp ==|!=|<|<=|>|>=  Exp                         **/
    /**                                                **/
    /** true        ==>    positive integer                            **/
    /** false       ==>    zero                                **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetBooleanStatement(m) {
        boolean eq = false
        GetExp(m, r+1)
        switch (token){
        case '=':
            nextToken()
            nextToken()
            GetExp(m+1)
            Output("Load cell",m)
            Output("Subt cell",m+1)
            Output("SkipCond 400",m)
            Output("Jump L%03d   /Jump over data line", nextL)
            Output("Load One")
            Output("Jump L%03d   /Jump over data line", nextL+1)
            Output("L%03d,", nextL)
            Output("Clear")
            Output("L%03d,", nextL+1)
            Output("Store cell",m)
            nextL+=2
            return
        case '!':
            nextToken()
            nextToken()
            GetExp(m+1)
            Output("Load cell%x  /cell%x = Test(cell%x - cell%x = 0)",m,m,m,m+1)
            Output("Subt cell",m+1)
            Output("SkipCond 400",m)
            Output("Jump L%03d   /Jump over data line", nextL)
            Output("Clear")
            Output("Jump L%03d   /Jump over data line", nextL+1)
            Output("L%03d,", nextL)
            Output("Load One")
            Output("L%03d,", nextL+1)
            Output("Store cell",m)
            nextL+=2
            return
        case '<':
            nextToken()
            if (token=='='){
                eq = true
                nextToken()
            }
            GetExp(m+1, r+1)
            if (!eq) {
                Output("Load cell%x   /cell%x = Test(cell%x - cell%x < 0)",m,m,m,m+1)
                Output("Subt cell",m+1)
            }
            else {
                Output("Load cell%x   /cell%x = Test(cell%x - cell%x <= 0)",m,m,m,m+1)
                Output("Subt cell",m+1)
                Output("Subt One")                
            }           
            Output("SkipCond 000",m)
            Output("Jump L%03d   /Jump over data line", nextL)
            Output("Load One")
            Output("Jump L%03d   /Jump over data line", nextL+1)
            Output("L%03d,", nextL)
            Output("Clear")
            Output("L%03d,", nextL+1)
            Output("Store cell",m)
            nextL+=2
            return
        case '>':
            nextToken()
            if (token=='='){
                eq = true
                nextToken()
            }
            GetExp(m+1, r+1)
            if (!eq) {
                Output("Load cell%x   /cell%x = Test(cell%x - cell%x > 0)",m,m,m,m+1)
                Output("Subt cell",m+1)
            }
            else {
                Output("Load cell%x   /cell%x = Test(cell%x - cell%x >= 0)",m,m,m,m+1)
                Output("Subt cell",m+1)
                Output("Add  One")             
            }           
            Output("SkipCond 800",m)
            Output("Jump L%03d   /Jump over data line", nextL)
            Output("Load One")
            Output("Jump L%03d   /Jump over data line", nextL+1)
            Output("L%03d,", nextL)
            Output("Clear")
            Output("L%03d,", nextL+1)
            Output("Store cell",m)
            nextL+=2
            return
        }
    }

    /****************************************************************************/
    /** Routine GetIfStatement produces MARIE code that                        **/
    /**     that executes the following JoshJava statements:                   **/
    /**                                                                        **/
    /** IfStatement     ==>    if( BooleanExp )                                **/
    /**                          BlockCode                                     **/
    /**                 ==>    if( BooleanExp )                                **/
    /**                          BlockCode                                     **/
    /**                        else                                            **/
    /**                          BlockCode                                     **/
    /**                                                                        **/
    /****************************************************************************/

    algorithm GetIfStatement() {
        nextToken()               // Move past "if"
        nextToken()               // Move past "("
        GetBooleanExp(0)          // MARIE code to evaluate expression and store in AC
        nextToken()               // Move past ")"
        Output("SkipCond 800")    // If(true) Skip to 1st block of code
        Output("Jump ElseCode")   // Else Jump to ElseCode
        GetBlockCode()            // MARIE code exicuting 1st block of code.
        Output("Jump EndIf")      // Jump to EndIf
        Output("ElseCode: )
        if (token=="else") 
            nextToken()           // Moving past the "else"
            GetBlockCode()        // MARIE code exicuting 2nd block of code.
        Output("EndIf:) 
    }


Java Code:
  if( a=b )
    BlockCode1
  else
    BlockCode2

MARIE Code
            ... code to set AC=1 iff a=b
            SkipCond 800      // If(true) Skip to 1st block of code
            Jump ElseCode     // Else Jump to ElseCode
            ... MARIE code exicuting 1st block of code.
            Jump EndIf        // Jump to EndIf
  ElseCode:
            ... MARIE code exicuting 2nd block of code.
  EndIf:



    /************************************************************************************************/
    /** Routine GetWhileStatement produces MARIE code                          **/
    /**     that executes the following JoshJava statements:                       **/
    /**                                                **/
    /** WhileStatement  ==>    while( BooleanExp )                         **/
    /**              BlockCode                             **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetWhileStatement(r) {
        currentL = nextL
        nextL+=2
        nextToken()
        nextToken()
        Output("L%03d,", currentL+1)
        Output("Clear    /TopWhile")  
        GetBooleanExp(0)
        nextToken()')
        Output("SkipCond 800 /If(true) Skip to code in while")
        Output("Jump L%03d   /Else Jump to EndWhile", currentL)
        GetBlockCode(r+1)
        Output("Jump L%03d   /Jump back to TopWhile", currentL+1)
        Output("L%03d,", currentL)
        Output("Clear       /EndWhile")  
    }

    /************************************************************************************************/
    /** Routine GetOut produces MARIE code that executes the following JoshJava statements:    **/
    /**                                                **/
    /** OutPut      ==>    System.out.println(Factor+"Hello World"+Factor)            **/
    /**         ==>    System.out.print("Hello\nWorld"+Factor)                **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetOutPut(r) {
        boolean println = false

        if(code.sval.equals("System.out.println"))
            println = true
        nextToken()
        nextToken()
        while(true) {
            if (token == '"') {
                if( ascii ) 
                    OutPutString(r+1)
                nextToken()
            }
            else {
                Output(ss[r+1]+"/Output Factor")
                GetFact(0,r+2)
                Output(ss[r+1]+"Load cell%x",0)
                if( ascii ) {
                    Output(ss[r+1]+"Store Mx")
                    Output(ss[r+1]+"JnS PrintDec")
                }
                else
                    Output(ss[r+1]+"Output")
            }
            if(token == ')') 
                break
            nextToken()
        }
        nextToken()')
        nextToken()
        if(println && ascii) {
            Output("Load AsciiCR /Output a return character")
            Output("Output")
        }
    }

    /************************************************************************************************/
    /** Routine OutPutString produces MARIE code that outputs a string                 **/
    /************************************************************************************************/

    algorithm OutPutString(r) {
        Output("Load L%03d   /Get command for loading first char",nextL+2)
        Output("Store L%03d  /Store it where it will be executed for loading next char",nextL)
        Output("Load L%03d   /Get number of characters to print",nextL+3)
        Output("Store L%03d  /Store it in the number left to print",nextL+4)
        Output("L%03d,", nextL)
        Output("Hex 0    /Command for loading next char")
        Output("Output       /Output next char")
        Output("Load L%03d   /Incrementing command, increments the cell address that is being loaded from",nextL)
        Output("Add  One")
        Output("Store L%03d ",nextL)
        Output("Load L%03d   /Decrementing number of chars left to print",nextL+4)
        Output("Subt One")
        Output("Store L%03d ",nextL+4)
        Output("Skipcond 400 /Skip if number of chars left to pris zero",nextL+4)
        Output("Jump L%03d ",nextL)
        Output("Jump L%03d   /Jump over String Data",nextL+5)
        Output("L%03d,", nextL+1)
        for( i=0 i< code.sval.length() i++ ) {
            c = (int) code.sval.charAt(i)
            if( c== 10 )  
                c= 13 // Change New Line to Carriage Return
            if( c== 32 )  
                c= 95 // Change Space to Under Score
            Output("Hex %x      /%c", c, (char) c )
        }
        Output("L%03d,", nextL+2)
        Output("Load L%03d   /Give command for loading first char",nextL+1)
        Output("L%03d,", nextL+3)
        Output("Dec %d       /Number of chars to print",code.sval.length())
        Output("L%03d,", nextL+4)
        Output("Dec 0       /Number of chars left to print",code.sval.length() )
        Output("L%03d,", nextL+5)
        Output("Clear       /End of String Data")
        nextL += 6
    }


    /************************************************************************************************/
    /** Routine Procedure produces MARIE code that executes the following JoshJava statements:     **/
    /** and stores it in cellm                                     **/
    /**                                                **/
    /** Procedure       ==>    ProcedureName( Exp, Exp, Exp, ..., Exp )                **/
    /**      The VarName is in varName and '(' is in token                     **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetProcedureCall(m, String CalledProcedure) {
        nextToken() 
        for( i=0 token!=')' ++i ) {
            GetExp(m)                          // Evaluate Exp and store it in cell0
            Output("Load cell",m)
            Output("Store input%x  /Copy out to input", i)
            if( token==',' )
                nextToken()
        }
        nextToken()')         
        PushOnStack(r+1,"B_cell","L_cell")
        PushOnStack(r+1,"B_"+procedureName,"L_"+procedureName)
        Output("JnS %s   /Jump to routine","J_"+CalledProcedure)
        PopOffStack(r+1,"B_"+procedureName,"L_"+procedureName)
        PopOffStack(r+1,"B_cell","L_cell")
        Output("Load Return")
        Output("Store cell",m)
    }
    
    /************************************************************************************************/
    /** Routine PushOnStack produces MARIE code that copies a block of data onto the recursion     **/
    /** stack                                              **/
    /**                                                **/
    /** B_label: label of cell containing the address one before the block to copy         **/
    /** L_label: label of cell containing length of the block to copy                  **/
    /**                                                **/
    /************************************************************************************************/

    algorithm PushOnStack( r, String B_label, String L_label ) {
        Output("Load %s     /Address one before block to copy",B_label)
        Output("Add  One     /Address of beginning of block to copy")
        Output("Store CopyA     /Argument for Copy program")
        Output("Load %s     /Lenght of the block to copy",L_label)
        Output("Store CopyL     /Argument for Copy program")
        Output("Load StackP     /End of Stack")
        Output("Store CopyB     /Argument for Copy program")
        Output("Add  CopyL       /Move End of Stack")
        Output("Store StackP    /End of Stack")
        Output("JnS Copy    /Jump to Copy routine")
    }

    /************************************************************************************************/
    /** Routine PopOffStack produces MARIE code that copies a block of data off the recursion      **/
    /** stack                                              **/
    /**                                                **/
    /** B_label: label of cell containing the address one before the block to receive data     **/
    /** L_label: label of cell containing length of the block to copy                  **/
    /**                                                **/
    /************************************************************************************************/

    algorithm PopOffStack( r, String B_label, String L_label ) {
        Output("Load %s     /Address one before block to copy to",B_label)
        Output("Add One     /Address of beginning of block to copy to")
        Output("Store CopyB     /Argument for Copy program")
        Output("Load %s     /Lenght of the block to copy",L_label)
        Output("Store CopyL     /Argument for Copy program")
        Output("Load StackP     /End of Stack")
        Output("Subt CopyL      /Move End of Stack")          
        Output("Store CopyA     /Argument for Copy program")
        Output("Store StackP    /End of Stack")
        Output("JnS Copy    /Jump to Copy routine")
    }
    
    /************************************************************************************************/
    /** Routine GetReturn produces MARIE code that executes the following JoshJava statements:     **/
    /**                                                **/
    /** Return      ==>    return                                 **/
    /**         ==>    return Exp                             **/
    /**                                                **/
    /************************************************************************************************/

    algorithm GetReturn(r) {
        nextToken() 
        if( token == '') 
            Output("Clear")       // Returns zero when not specified
        else {
            GetExp(0)                      // Evaluate Exp and store it in cell0
            Output("Load cell0")
        }
        Output("Store Return")
        Output("JumpI %s   /Return to calling program", "J_"+procedureName)           
        nextToken()        // move token past the '' in "return Exp"
    }

    /************************************************************************************************/
    /** Routine CompleteCode produces the MARIE code required at the end of the program        **/
    /**    for setting up the Stack Frame Stack                            **/
    /**                                                **/
    /************************************************************************************************/

    algorithm CompleteCode() {
        Output("/**********************************************************************")    
        Output("/** Recursion Stack begins here")               
        Output("/**********************************************************************")    
        Output("B_Stack, Hex 0    / The address of beginning the recursion stackframe")
        fileOutputStream.close()
    }

    /************************************************************************************************/
    /************************************************************************************************/
    /**                                                **/
    /**         File and Error Routines                            **/
    /**        -------------------------                               **/
    /**                                                **/
    /************************************************************************************************/
    /************************************************************************************************/

    /************************************************************************************************/
    /** Routine nextToken gets the next token                              **/
    /**    S = name of GetT procedure                                  **/
    /**    c = the expected current token                              **/
    /**    Gets the next token and puts it in token                        **/
    /**    If(debugging) Prints string S, previous token, and next token found             **/
    /************************************************************************************************/
    algorithm nextToken() {
        token = code.nextToken()
        if( debug ) {
            System.out.format("%-15s: moving past %c: Token is ",S,c)
            printToken()
        }
    }

    /************************************************************************************************/
    /** Routine nextTokenCheck checks the current token and gets the next token            **/
    /**    S = name of GetT procedure                                  **/
    /**    c = the expected current token                              **/
    /**    If( current token is not c ) Gives Error message                    **/
    /**    Gets the next token and puts it in token                        **/
    /**    If(debugging) Prints string S, previous token, and next token found             **/
    /************************************************************************************************/
    algorithm nextToken() {
        if(token!=c) {      
            System.out.format("* Error: %s: Expected %c: Token is ",S,c)
            printToken()
            System.in.read()
            // while( token != StreamTokenizer.TT_EOF && token!='' ) nextToken() // move token past non ''
            return
        }
        nextToken() 
    }       

    /************************************************************************************************/
    /** Routine nextTokenCheckString checks the current token and gets the next token          **/
    /**    S = name of GetT procedure                                  **/
    /**    T = the expected current token                              **/
    /**    If( current token is not T ) Gives Error message                    **/
    /**    Gets the next token and puts it in token                        **/
    /**    If(debugging) Prints string S, previous token, and next token found             **/
    /************************************************************************************************/
    algorithm nextToken() {
        if(!code.sval.equals(T)) {          
            System.out.format("* Error: %s: Expected %s: Token is ",S,T)
            printToken()
            System.in.read()
            while( token != StreamTokenizer.TT_EOF && token!='' ) nextToken() // move token past non ''
            return
        }
        nextToken       
    }       

    /************************************************************************************************/
    /** Prtoken                                                                                **/
    /************************************************************************************************/
    algorithm printToken() {
        switch (token) { 
        case StreamTokenizer.TT_NUMBER: // A number was found the value is in nval double num = code.nval 
            System.out.println(code.nval)
            break 
        case StreamTokenizer.TT_WORD:   // A word was found the value is in sval String word = code.sval 
            System.out.println(code.sval)
            break 
        case '"': // A string like "Hello World" was found the value is in sval String word = code.sval 
            System.out.println(code.sval)
            break 
        default: // A regular character was found the value is the token itself char ch = (char)code.ttype 
            System.out.println((char) token)
            break 
        }
    }

    /************************************************************************************************/
    /**    Set up Input and Output Files                                                           **/
    /************************************************************************************************/
    algorithm HandleFiles(String filename) {
        String joshFileName   = filename+".jj"
        String marieFileName  = filename+".mas"
        String memorycodeName = "memorycode.txt"
        String subroutinesName= "subroutines.txt"
        String s
        BufferedReader fbr

        // Open MARIE Output file.
        fileOutputStream = new FileOutputStream(marieFileName)
        fps = new PrintStream(fileOutputStream)

        // Copies file memorycode containing all the MARIE data structures into code            
        fbr = new BufferedReader(new FileReader(memorycodeName))
        while ((s=fbr.readLine()) != null)
            fps.println(s)
        fbr.close()

        // for(i=0040 to 008F)  Hex i  Used for a,b,Multa,Multb,DecStr
        for(i=3*16 i<6*16 ++i )
            Output("    Hex %x",i)      

        // Copies file subroutines containing all the MARIE subroutines into code           
        fbr = new BufferedReader(new FileReader(subroutinesName))
        while ((s=fbr.readLine()) != null)
            fps.println(s)
        fbr.close()

        // Copies in a copy of JoshJava code as a comment.
        fps.println("")        
        fps.println("   /********************* JoshJava Code to Compile ****************************/")        
        fbr = new BufferedReader(new FileReader(joshFileName))
        while ((s=fbr.readLine()) != null)
            fps.println("   /** "+s)
        fps.println("   /***************************************************************************/")        
        fps.println("")        
        fbr.close()

        // Opens JoshJava code to be tokenized.
        FileReader rd = null
        try {
            rd = new FileReader(joshFileName)
        } catch (FileNotFoundException e1) {
            System.out.println("file not found")
        }
        code = new StreamTokenizer(rd)
        code.ordinaryChar('-')     // Tells tokenizer to parse -3 as two tokens.
        code.ordinaryChar('/')     // Tells tokenizer to parse 5/10 as three tokens.
        code.eolIsSignificant(false)   // Tells tokenizer to ignore the end of the line
        code.slashSlashComments(true)  // Tells tokenizer to ignore // comments 
        code.slashStarComments(true)   // Tells tokenizer to ignore /* comments */

        ss[0] = "       "                      // Routines at depth r will be indented by ss[r] = tab + 2r blanks
        for(i=1 i<16 i++ ) 
            ss[i] = ss[i-1]+"  "
    }
}

