From 699c74c3b041690f9996982d79cc4ed7ec6a3d5b Mon Sep 17 00:00:00 2001 From: Quazi Irfan GD Date: Sun, 23 Oct 2016 03:34:33 -0500 Subject: [PATCH] Initial Error Handling --- src/Assembler/Main.java | 79 +++++++++++ src/Assembler/Utility.java | 25 ++++ src/Main.java | 48 ------- src/OperandPkg/Literal.java | 15 +- src/OperandPkg/Operand.java | 21 ++- src/OperandPkg/OperandUtility.java | 214 ++++++++++++++++++++++++----- src/OperandPkg/Token.java | 64 +++++++++ src/SymbolPkg/BinaryTree.java | 16 +-- src/SymbolPkg/Node.java | 11 +- src/SymbolPkg/SymbolTable.java | 16 +-- 10 files changed, 394 insertions(+), 115 deletions(-) create mode 100644 src/Assembler/Main.java create mode 100644 src/Assembler/Utility.java delete mode 100644 src/Main.java diff --git a/src/Assembler/Main.java b/src/Assembler/Main.java new file mode 100644 index 0000000..955a7c0 --- /dev/null +++ b/src/Assembler/Main.java @@ -0,0 +1,79 @@ +package Assembler; + +import OperandPkg.Literal; +import OperandPkg.OperandUtility; +import SymbolPkg.*; + +import java.io.*; +import java.util.LinkedList; + +// NAME : Quazi Irfan +// CLASS : CSc 354 +// ASSIGNMENT : 2 +// DUE DATE : 10/5/16 +// INSTRUCTOR : Dr. Hamer +// DESCRIPTION : Assignment 2 : Expressions + +/** + * Assembler.Main is the Entry point Assignment 2 : Expressions + * + * Thic class checks if two arguments were supplied, or it prompts the user to enter them. + * If <2 arguments were supplied then it terminates the execution. + * The user has to reload the program to try again. + * + * After setting the input file, the program calls static methods to, + * 1. Populate the Symbol Table + * 2. Evaluate and print all valid expressions + * 3. Print the literals + * + */ +public class Main { + public static void main(String[] args) throws IOException{ + SymbolTable symbolTable = new SymbolTable(); + LinkedList literalLnkdLst = new LinkedList<>(); + + // Set input files + String symbolFile, operandFile; + if(args.length < 2){ + System.out.println("Missing command like argument."); + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + System.out.print("Enter Symbol File : "); + symbolFile = reader.readLine(); + System.out.print("Enter Expressions File : "); + operandFile = reader.readLine(); + } else { + symbolFile = args[0]; + operandFile = args[1]; + } + + // Check the existence of both symbol and operand file + File f = new File(symbolFile); + if(!f.exists()) { + System.out.println(symbolFile + " not found. Please rerun the program to try again."); + return; + } + + f = new File(operandFile); + if(!f.exists()) { + System.out.println(operandFile + " not found. Please rerun the program to try again."); + return; + } + + // Populate Symbol Table + SymbolUtility.populateSymbolTable(symbolTable, symbolFile); + System.out.println("*** SYMBOL TABLE ***\nSymbol\t Value\t rflag\t iflag\t mflag\t"); + symbolTable.view(); + + // Evaluate and print Expressions + System.out.println("\n*** EXPRESSIONS ***\nExpresion\t Value\t Relocatable n i x"); + OperandUtility.evaluateOperand(symbolTable, literalLnkdLst, operandFile); + + // Print contents of the literal table + System.out.println("\n*** LITERAL TABLE ***\nName\t\t Value\t\t Size\t Address"); + for(Object o : literalLnkdLst){ + System.out.println(o); + } + } + + +} diff --git a/src/Assembler/Utility.java b/src/Assembler/Utility.java new file mode 100644 index 0000000..0470d0c --- /dev/null +++ b/src/Assembler/Utility.java @@ -0,0 +1,25 @@ +package Assembler; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * This Utility class is meant for temporary code segments that doesn't fit in other classes. + * + */ + +public class Utility { + /** + * This method prompts the user the press Enter to continue. + */ + public static void enterToContinue(){ + System.out.print(" *** Press Enter to continue..."); + try{ + BufferedReader tempHalt = new BufferedReader(new InputStreamReader(System.in)); + tempHalt.readLine(); + } catch (IOException e){ + System.out.println(e); + } + } +} diff --git a/src/Main.java b/src/Main.java deleted file mode 100644 index 8a7e24a..0000000 --- a/src/Main.java +++ /dev/null @@ -1,48 +0,0 @@ -import OperandPkg.Literal; -import OperandPkg.Operand; -import OperandPkg.OperandUtility; -import SymbolPkg.*; - - -import java.io.*; -import java.util.Arrays; -import java.util.LinkedList; - - -// NAME : Quazi Irfan -// CLASS : CSc 354 -// ASSIGNMENT : 1 -// DUE DATE : 9/14/16 -// INSTRUCTOR : Dr. Hamer -// DESCRIPTION : Assignment 1 : Symbol Table - - -/** - * Main class of Assignment 1. This class is within SymbolTable package. - * - * Currently everything is contained within static Main method. - * Three stages are labeled as Stage X. This code mostly read the file and - * delegates responsibilities to other classes. - * - */ -public class Main { - public static void main(String[] args) throws IOException{ - SymbolTable symbolTable = new SymbolTable(); - LinkedList literalLnkdLst = new LinkedList<>(); - - if(args.length < 2){ - System.out.println("Please use command \"javac Main labels.txt operands.txt\""); - return; - } - - String symbolFile = args[0]; - SymbolUtility.populateSymbolTable(symbolTable, symbolFile); - - String operandFile = args[1]; - OperandUtility.evaluateOperand(symbolTable, literalLnkdLst, operandFile); - - // print the literal linked list -// System.out.println(literalLnkdLst); - } - -} diff --git a/src/OperandPkg/Literal.java b/src/OperandPkg/Literal.java index 02c77d0..58a3080 100644 --- a/src/OperandPkg/Literal.java +++ b/src/OperandPkg/Literal.java @@ -1,13 +1,26 @@ package OperandPkg; +/** + * Each literal is an entry to the Literal Table + * + * Literals are addressed 1,2...n. The starting address is a static number, + * and upon each successful entry to the literal table the static int is increased. + * + * Other attributes of literal are public. + */ public class Literal { public static int staticAddress = 1; String name, value; int length, address; + /** + * Helper method that returns formatted attributes of a Literal + */ public String toString() { - return name + " " + value + " " + length + " " + address; + String output = String.format("%1$-12s %2$-16s %3$-7d %4$d", name, value, length, address); + + return output; } } diff --git a/src/OperandPkg/Operand.java b/src/OperandPkg/Operand.java index d652b88..9c8d275 100644 --- a/src/OperandPkg/Operand.java +++ b/src/OperandPkg/Operand.java @@ -1,16 +1,25 @@ package OperandPkg; +/** + * Each Operand is a processed non-literal Expression + */ public class Operand { public String expression; public int value; public boolean relocability, nbit, ibit, xbit; + /* + * This method returns a formatted operand attribute + */ public String toString() { - return expression + " " + - value + " " + - (relocability ? "Relative":"Absolute") + " " + - (nbit? "1":"0") + " " + - (ibit? "1":"0") + " " + - (xbit? "1":"0"); + String output = String.format("%1$-16s %2$-7d %3$-11s %4$s %5$s %6$s", + expression, + value, + (relocability ? "Relative":"Absolute"), + (nbit? "1":"0"), + (ibit? "1":"0"), + (xbit? "1":"0")); + + return output; } } diff --git a/src/OperandPkg/OperandUtility.java b/src/OperandPkg/OperandUtility.java index c5fbf67..b9a1212 100644 --- a/src/OperandPkg/OperandUtility.java +++ b/src/OperandPkg/OperandUtility.java @@ -1,5 +1,6 @@ package OperandPkg; +import Assembler.Utility; import SymbolPkg.SymbolTable; import java.io.BufferedReader; @@ -8,64 +9,108 @@ import java.util.LinkedList; import java.util.StringTokenizer; +/** + * This class holds the static method to process Expressions. + */ public class OperandUtility{ + private static String original; + + /** + * This method does the initial Expression evalution. + * + * @param symbolTable Take the symbol table to compare the Exparesions with + * @param literalLnkdLst Holds the Linked link populated with literals + * @param operandFile Source file to read the Expressions from + */ public static void evaluateOperand(SymbolTable symbolTable, LinkedList literalLnkdLst, String operandFile) throws IOException{ BufferedReader reader = new BufferedReader(new FileReader(operandFile)); String expression = reader.readLine(); - while(expression != null){ + while(expression != null && expression.length() > 0){ + + original = expression; if(expression.charAt(0) != '=') { // Handle non-Literal Operand operand = new Operand(); - operand.expression = expression; expression = expression.toUpperCase(); + operand.expression = expression; + // operand n,i anx x bits are 0 by default if (expression.charAt(0) == '#') { + // for #expression operand.ibit = true; expression = expression.substring(1); } else if (expression.charAt(0) == '@') { + // for @expression operand.nbit = true; expression = expression.substring(1); - } else if (Character.isDigit(expression.charAt(0))) { + } else if (Character.isDigit(expression.charAt(0)) & !(expression.contains("+") | expression.contains("-"))) { + // for 6 + operand.nbit = false; + operand.ibit = true; + } else if ((expression.charAt(0) == '+' | expression.charAt(0) == '-') & Character.isDigit(expression.charAt(1))){ + // for +6 or -6 operand.nbit = false; operand.ibit = true; } else { + // for expression OR expression+expression operand.nbit = true; operand.ibit = true; } + // handles expression,X if (expression.length() >= 3 && expression.substring(expression.length() - 2, expression.length()).equals(",X")) { - if (operand.nbit & !operand.ibit) { - System.out.println("@ or # can't be mixed with ,X"); - return; + // Check if mixing @ or # with ,X + if (original.contains("@") | original.contains("#") ) { + System.out.println(original + " (Error : @ or # can't be mixed with ,X)"); + expression = reader.readLine(); + continue; } + + // We have valid expression,X operand.xbit = true; expression = expression.substring(0, expression.length() - 2); } - validateExp(expression, operand, symbolTable); + // evaluate the expression + String expressionStatus = validateExp(expression, operand, symbolTable); + if(!expressionStatus.equals("valid")){ + System.out.println(expressionStatus); + expression = reader.readLine(); + continue; + }; -// print(operand); System.out.println(operand); expression = reader.readLine(); } else { // Handle Literal Literal literal = new Literal(); - literal.name = expression; + String tempValue = ""; expression = expression.substring(1); if(expression.charAt(0) == 'C' | expression.charAt(0) == 'c'){ // Handle Character Literal + StringBuilder strbld = new StringBuilder(expression); + strbld.setCharAt(0, 'C'); + expression = strbld.toString(); + literal.name = expression; + + if(expression.charAt(1) != '\'' & expression.charAt(expression.length()-1) != '\''){ + System.out.println(original + " (Error : Character literal must be enclosed with \' and \' character)"); + expression = reader.readLine(); + continue; + } + expression = expression.substring(2, expression.length()-1); for(int i =0;i } else if(expression.charAt(0) == 'X' | expression.charAt(0) == 'x'){ // Handle Hex Literal + expression = expression.toUpperCase(); + literal.name = expression; + + if(expression.charAt(1) != '\'' & expression.charAt(expression.length()-1) != '\''){ + System.out.println(original + " (Error : Character string must be enclosed with \' and \' character)"); + expression = reader.readLine(); + continue; + } + expression = expression.substring(2, expression.length()-1); + + try{ + Integer.parseInt(expression, 16); + }catch (NumberFormatException e){ + System.out.println(original + " (Error : Invalid Hex value)"); + expression = reader.readLine(); + continue; + } + if(expression.length() % 2 != 0){ - // Hex literal length must divisible by 2 + System.out.println(original + " (Error : Hex literal value lengh must be a multipel of 2)"); + expression = reader.readLine(); + continue; } literal.length = expression.length()/2; @@ -88,7 +153,7 @@ public static void evaluateOperand(SymbolTable symbolTable, LinkedList if(literalLnkdLst.isEmpty()){ literalLnkdLst.add(literal); Literal.staticAddress++; - System.out.println(literal); +// System.out.println(literal); } else { for(int i =0; i if(!literal.name.equals(literalLnkdLst.get(i).name) && i+1 == literalLnkdLst.size()){ literalLnkdLst.add(literal); Literal.staticAddress++; - System.out.println(literal); +// System.out.println(literal); break; } } @@ -109,53 +174,120 @@ public static void evaluateOperand(SymbolTable symbolTable, LinkedList } } - private static void validateExp(String expression, Operand operand, SymbolTable symbolTable){ - if(expression.indexOf('+') >= 0 || expression.indexOf('-') >= 0){ - // Symbol+Symbol - StringTokenizer tokenizer = new StringTokenizer(expression, "+-"); + /** + * After striping the expression of off @,# and = the remaining expression is evaluated in thie method. + * Example Expression to be processed: Symbol+Symbol, Symbol+literal, literal+literal + * + * @param expression The expression to be processed + * @param operand The operand we are working with. The Value of the expression will be set as the value of this operand. + * @param symbolTable see if the symbols are in the symbol table + * @return If no error is found, "valid" string is returned, otherwise description of the error is returned. + * The method is terminated upon an error. + */ + private static String validateExp(String expression, Operand operand, SymbolTable symbolTable){ + StringTokenizer tokenizer = new StringTokenizer(expression, "+-"); + + if((expression.contains("+") || expression.contains("-")) & tokenizer.countTokens() > 1){ + // handles Symbol+Symbol, Symbol+literal + + String token1 = tokenizer.nextToken(); + + int token1Value = Token.getTokenValue(token1, symbolTable); + if(token1Value == -1) { + return token1 + " (Error : Symbol Not found on Symbol Table)"; + } else if(token1Value == -2){ + return token1 + " (Error : Invalid Symbol)"; + } + boolean token1rflag = Token.getTokenRflag(token1, symbolTable); + + String token2 = tokenizer.nextToken(); + int token2Value = Token.getTokenValue(token2, symbolTable); + if(token2Value == -1) { + return token2 + " (Error : Symbol Not found on Symbol Table)"; + } else if(token2Value == -2){ + return token2 + " (Error : Invalid Symbol)"; + } + boolean token2rflag = Token.getTokenRflag(token2, symbolTable); - String temp = tokenizer.nextToken(); - int token1Value = Token.getTokenValue(temp, symbolTable); - boolean token1rflag = Token.getTokenRflag(temp, symbolTable); + if(isInteger(token1) & isInteger(token2) & original.contains("@")) + return original + " (Error : @Literal or #Literal is not illegal)"; - temp = tokenizer.nextToken(); - int token2Value = Token.getTokenValue(temp, symbolTable); - boolean token2rflag = Token.getTokenRflag(temp, symbolTable); + if(isInteger(token1) & isInteger(token2)) + operand.nbit = false; - // set operands value, and flag + // Set the value and flag of Operand if(expression.indexOf('+') >= 0) operand.value = token1Value + token2Value; else operand.value = token1Value - token2Value; - if(evaluateRelocability(token1rflag, token2rflag, expression).equals("true")) + String relocability = evaluateRelocability(token1rflag, token2rflag, expression); + if(relocability.equals("true")) operand.relocability = true; - else + else if(relocability.equals("false")) operand.relocability = false; + else{ + return original + " (Error : " + relocability + ")"; + } + } else { - // Symbol - operand.value = Token.getTokenValue(expression, symbolTable); - operand.relocability = Token.getTokenRflag(expression, symbolTable); + // Symbol / single literal + + String token = expression; + + // Check for @literal + if(original.contains("@") & isInteger(token)){ + return original + " (Error : @Literal or #Literal is not legal)"; + } + + // Set the value and flag of Operand + if(isInteger(token)) { + // for Numeric token + operand.value = Integer.parseInt(token); + } else { + // for symbolic token + operand.value = Token.getTokenValue(token, symbolTable); + + if(operand.value == -1) { + return token + " (Error : Symbol Not found on Symbol Table)"; + } else if(operand.value == -2){ + return token + " (Error : Invalid Symbol)"; + } + } + + + operand.relocability = Token.getTokenRflag(token, symbolTable); } + + return "valid"; } + /** + * Given two flags this method calculates the relocability. + * + * @param token1rflag rflag of first token + * @param token2rflag rflag of second token + * @param expression check if the tokens are seperated with + or - character + * @return returns the calculated the rflag + */ private static String evaluateRelocability(boolean token1rflag, boolean token2rflag, String expression){ + // true is absolute; false is relative if(expression.indexOf('+') >= 0){ - if(!token1rflag & !token2rflag) + if(!token1rflag & !token2rflag) // absolute + absolute return "false"; if(!token1rflag & token2rflag) return "true"; if(token1rflag & !token2rflag) return "true"; if(token1rflag & token2rflag) - return "error"; + return "Relative + Relative = Error"; } else if(expression.indexOf('-') >= 0){ - if(!token1rflag& !token2rflag) - return "false"; if(!token1rflag & !token2rflag) - return "error"; - if(token1rflag & !token2rflag) + return "false"; + if(!token1rflag & token2rflag) + return "Absolute - Relative = Error"; + if(token1rflag & !token2rflag) // relative - absolute return "true"; if(token1rflag & token2rflag) return "false"; @@ -163,5 +295,17 @@ private static String evaluateRelocability(boolean token1rflag, boolean token2rf return null; } + + public static boolean isInteger(String s) { + try { + Integer.parseInt(s); + } catch(NumberFormatException e) { + return false; + } catch(NullPointerException e) { + return false; + } + // only got here if we didn't return false + return true; + } } diff --git a/src/OperandPkg/Token.java b/src/OperandPkg/Token.java index 56d13aa..f89d25c 100644 --- a/src/OperandPkg/Token.java +++ b/src/OperandPkg/Token.java @@ -3,7 +3,19 @@ import SymbolPkg.Node; import SymbolPkg.SymbolTable; +/** + * Token is an smallest elements on an Expression. For example, in @Red+Red expression, Red is a token. + * + * This class holds some static method to check the validity of the token against the symbol table and get it's value. + */ class Token{ + /** + * Get the rflag of the given token + * + * @param token String value of the token + * @param symbolTable Check against this symbol table + * @return returns true is the token is a valid symbol on the symbol table, false otherwise. + */ public static boolean getTokenRflag(String token, SymbolTable symbolTable){ boolean operantRflag = false; @@ -30,6 +42,16 @@ public static boolean getTokenRflag(String token, SymbolTable symbolTable){ return operantRflag; } + /** + * This method returns the value of the token. + * @param token String value of the token + * @param symbolTable Check against this symbol table + * @return Returns the value from the symbol table if the token is a valid symbol. + * Returns -1 if the token is a valid symbol, but isn't in the symbol table. + * Returns -2 if the token is not a valid symbol. + * TODO : Returns other values to explain why it's no a valid symbol + */ + public static Integer getTokenValue(String token, SymbolTable symbolTable){ Integer operandValue = null; @@ -43,9 +65,16 @@ public static Integer getTokenValue(String token, SymbolTable symbolTable){ if(tokenValue == null){ // Symbol is not a number + if(!validateSymbol(token).equals("valid")) { + operandValue = -2; + return operandValue; + } + node = symbolTable.search(token); if(node != null){ operandValue = node.getValue(); + } else { + operandValue = -1; } } else { // Symbol is a number @@ -54,4 +83,39 @@ public static Integer getTokenValue(String token, SymbolTable symbolTable){ return operandValue; } + + /** + * DUPLICATE CODE : REMOVE IT + * + * Function to check the validity of a symbol. It performes 3 checks. + * The first check is if the symbol is longer then 10 characters. + * Second check is if the symbol starts with numeric character. + * Third check is if any character on the symbol is anything other than alphabate, number or underscore. + * + * + * @param symbol Symbol string to check + * @return if symbol is valid "valid" string is returned, otherwise "invalid" string is returned. + */ + private static String validateSymbol(String symbol) { + // check if symbol lenth exceeds 10 characters + if(symbol.length() > 10){ + return "Symbol length must be less than 10 characters."; + } + + // check if symbol doesn't start with letters + if(!Character.isAlphabetic(symbol.charAt(0))){ + return "Symbol must start with letters(A...Z or a...z)"; + } + + // check for alphabetic, digits and underscore + for(int i = 1; i