import key Token token = in.readToken(); if (token ==

import*;import java.util.*;class Parser {    private Lexer in;    KeyWord if_key;    KeyWord then_key;    KeyWord else_key;    KeyWord let_key;    KeyWord in_key;    KeyWord map_key;    KeyWord to_key;    KeyWord set_key;    Parser(Lexer i) {        in = i;        initParser();    }    Parser(Reader r) {        this(new Lexer(r));    }    Parser(String fileName) throws IOException {        this(new FileReader(fileName));    }    private void initParser() {        if_key = (KeyWord)in.wordTable.get(“if”);        then_key = (KeyWord)in.wordTable.get(“then”);        else_key = (KeyWord)in.wordTable.get(“else”);        let_key = (KeyWord)in.wordTable.get(“let”);        in_key = (KeyWord)in.wordTable.get(“in”);        map_key = (KeyWord)in.wordTable.get(“map”);        to_key = (KeyWord)in.wordTable.get(“to”);        set_key = (KeyWord)in.wordTable.get(“:=”);    }    public AST parse() throws ParseException{        AST tree = parseExp();        return tree;    }    private AST parseExp() {        //read token and check for if/let/map key        Token token = in.readToken();        if (token == if_key) {            return parseIf();        }        if (token == let_key) {            return parseLet();        }        if (token == map_key) {            return parseMap();        }        //else we can expect a term        else{            //parse the term and peek            AST term = parseTerm(token);            Token peek = in.peek();            //if term followed by an operator we can expect a binop            if (peek instanceof Op) {                Op operation = (Op)peek;                if (!(operation.isBinOp())) {                    throw new ParseException(“Expected binary operation, got: ” + peek);                }                //parse RHS of the operation                in.readToken();                AST expression = parseExp();                return new BinOpApp(operation, term, expression);            }            //otherwise just return the parsed term            return term;        }    }    private AST parseTerm(Token token) {        AST factor;        //Check for instance of constant, unary op, left paren, prim, or var        if (token instanceof Constant) {            return (Constant)token;        }        else if (token instanceof Op) {            Op operation = (Op)token;            //if unop parse the following term and return as UnOp            if (operation.isUnOp()){                AST term = parseTerm(in.readToken());                return new UnOpApp(operation, term);            }            else {                throw new ParseException(“Expected Unary operation, got ” + token);            }        }        if (token == LeftParen.ONLY) {            //get expression in parenthesis and ensure it is followed by a closed parenthesis            AST expression = parseExp();            token = in.readToken();            if (token != RightParen.ONLY) {                throw new ParseException(“Expected close parenthesis, got: ” + token);            }            factor =  expression;        }        else if ((token instanceof PrimFun) || (token instanceof Variable)){            factor = (Term)token;        }        //throw exception if factor wasn’t parsed successfully        else {            throw new ParseException(“Expected open parenthesis, primitive, variable, constant or unop, got: ” + token);        }        //peek next token, if its a left parenthesis we can expect another expression        Token peek = in.peek();        if (peek == LeftParen.ONLY) {            //pull left parenthesis from reader and initialize a list for our expressions            in.readToken();            ArrayList explist = new ArrayList();            peek = in.peek();            if (peek == RightParen.ONLY) {                in.readToken();                return new App(factor, new AST0);            }            //parse current expression and append to list while next token is a comma            AST exp = parseExp();            explist.add(exp);            peek = in.readToken();            while(peek==Comma.ONLY){                exp = parseExp();                explist.add(exp);                peek = in.readToken();            }            //exp list must end with close parenthesis            if (peek != RightParen.ONLY) {                throw new ParseException(“Expected a comma or close parenthesis, got: ” + peek);            }            //return  Factor { ( ExpList ) }            return new App(factor, explist.toArray(new AST0));        }        return factor;    }    private AST parseIf() {        //parse if         AST if_exp = parseExp();        Token token = in.readToken();        if (token != then_key) {            throw new ParseException(“Expected then, got: ” + token);        }        //parse then        AST then_exp = parseExp();        token = in.readToken();        if (token != else_key) {            throw new ParseException(“Expected else, got: ” + token);        }        //parse else        AST else_exp = parseExp();        return new If(if_exp, then_exp, else_exp);    }    private AST parseLet() {        Token token = in.readToken();        ArrayList deflist = new ArrayList();        while (token != in_key){            //throw error if token isn’t a var            if (!(token instanceof Variable)) {                throw new ParseException(“Expected variable, got: ” + token);            }            //same here if next token isn’t the assignment operator            Token next = in.readToken();            if (next != set_key) {                throw new ParseException(“Expected :=, got: ” + next);            }            //get expression and do the same if the assignment doesnt end with ;            AST exp = parseExp();            next = in.readToken();            if (next != SemiColon.ONLY) {                throw new ParseException(“Expected semicolon, got: ” + next);            }            //add def to the list and get the next variable or in_key            Def def = new Def((Variable)token, exp);            deflist.add(def);            token = in.readToken();        }        return new Let(deflist.toArray(new Def0), parseExp());    }    private AST parseMap() {        Token token = in.readToken();        ArrayList varlist = new ArrayList();        //if we’ve already encountered the to key, return the single var mapped to the parsed expression        if (token == to_key) {            return new Map(new Variable0, parseExp());        }        //else we keep reading vars until we reach the to key        while(1==1){            if (!(token instanceof Variable)) {                throw new ParseException(“Expected variable, got: ” + token);            }            //gathering all vars on LHS of the map            varlist.add((Variable)token);            token = in.readToken();            //we’ve gathered all the vars once we hit the to key            if (token == to_key) {                break;            }            //if we didn’t break already and the var isn’t followed by a comma, theres an error            if (token != Comma.ONLY) {                throw new ParseException(“Expected to or a comma, got: ” + token);            }            //get the next var or to key            token = in.readToken();        }        //return the array of vars mapped to the parsed RHS of the expression        return new Map(varlist.toArray(new Variable0), parseExp());    }}