/* * Parser.java * * Parses a MIPS64 source code and fills the symbol table and the memory. * * (c) 2006 mancausoft, Vanni * * This file is part of the EduMIPS64 project, and is released under the GNU * General Public License. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** Parses a MIPS64 source code and fills the symbol table and the memory. * @author mancausoft, Vanni */ package org.edumips64.core; import org.edumips64.core.fpu.FPInstructionUtils; import org.edumips64.core.fpu.FPOverflowException; import org.edumips64.core.fpu.FPUnderflowException; import org.edumips64.core.is.Instruction; import org.edumips64.core.is.InstructionBuilder; import org.edumips64.utils.Converter; import org.edumips64.utils.IrregularStringOfBitsException; import org.edumips64.utils.IrregularStringOfHexException; import org.edumips64.utils.io.FileUtils; import org.edumips64.utils.io.ReadException; import java.util.LinkedList; import java.util.List; import java.util.Stack; import java.util.logging.Logger; class VoidJump { Instruction instr; String label; int row; int column; int instrCount; String line; boolean isBranch = false; } public class Parser { /** Instance variables */ private static final Logger logger = Logger.getLogger(Parser.class.getName()); private final Memory mem; private enum AliasRegister {zero, at, v0, v1, a0, a1, a2, a3, t0, t1, t2, t3, t4, t5, t6, t7, s0, s1, s2, s3, s4, s5, s6, s7, t8, t9, k0, k1, gp, sp, fp, ra} private static final String deprecateInstruction[] = {"BNEZ", "BEQZ", "HALT", "DADDUI", "L.D", "S.D"}; private ParserMultiException error; /** Base basePath to use for further #include directives. */ private String basePath; private int numError; private enum FileSection {NONE, DATA, TEXT} private FileSection section; /** File to be parsed */ private int memoryCount; private String filename; private SymbolTable symTab; private FileUtils fileUtils; private InstructionBuilder instructionBuilder; private FPInstructionUtils fpInstructionUtils; /** Accessible only because of unit tests. * The Parser needs an FCSR register only because the core FP functions of the simulator * are coupled too tightly with the actual implementation of the FPU, and therefore they assume * that there is an FCSR register and use it to decide whether to throw an exception or not. * * The Parser uses the FP functions to parse, and as a result it needs to have an FCSR. Not ideal. */ private FCSRRegister fcsr; FCSRRegister getFCSR() { return fcsr; } /** Public methods */ public Parser(FileUtils utils, SymbolTable symTab, Memory memory, InstructionBuilder instructionBuilder) { this.symTab = symTab; this.fileUtils = utils; this.mem = memory; this.instructionBuilder = instructionBuilder; this.fcsr = new FCSRRegister(); fcsr.setFPExceptions(CPU.FPExceptions.INVALID_OPERATION, true); fcsr.setFPExceptions(CPU.FPExceptions.OVERFLOW, true); fcsr.setFPExceptions(CPU.FPExceptions.UNDERFLOW, true); fcsr.setFPExceptions(CPU.FPExceptions.DIVIDE_BY_ZERO, true); fpInstructionUtils = new FPInstructionUtils(this.fcsr); } /** Loading from File * @param filename A String with the system-dependent file name. It should be an absolute file name. * @throws SecurityException if a security manager exists and its checkRead method denies read access to the file. */ public void parse(String filename) throws ParserMultiException, ReadException { logger.info("About to parse " + filename); this.filename = filename; basePath = fileUtils.GetBasePath(filename); String code = preprocessor(filename); doParsing(code); logger.info(filename + " correctly parsed."); } /** Replace all Tabulator with space * @param text the string to replace * @return a new String */ static String replaceTab(String text) { return text.replace("\t", " "); } /** Private methods */ private String fileToString(String filename) throws ReadException { return fileUtils.ReadFile(filename); } private void checkLoop(String data, Stack<String> included) throws ParserMultiException, ReadException { int i = 0; do { i = data.indexOf("#include ", i); if (i != -1) { int end = data.indexOf("\n", i); if (end == -1) { end = data.length(); } int a = included.search(data.substring(i + 9, end).trim()); if (a != -1) { error = new ParserMultiException(); error.add("INCLUDE_LOOP", 0, 0, "#include " + data.substring(i + 9, end).trim()); throw error; } String filename = data.substring(i + 9, end).split(";") [0].trim(); if (!fileUtils.isAbsolute(filename)) { filename = basePath + filename; } String filetmp = fileToString(filename); checkLoop(filetmp , included); i ++; } } while (i != -1); } /** Process the #include (Syntax #include file.ext ) */ private String preprocessor(String filename) throws ParserMultiException, ReadException { String filetmp; filetmp = fileToString(filename); int i = 0; //check loop Stack<String> included = new Stack<>(); included.push(this.filename); checkLoop(filetmp, included); // include do { i = filetmp.indexOf("#include ", i); if (i != -1) { int end = filetmp.indexOf("\n", i); if (end == -1) { end = filetmp.length(); } logger.info("Open by #include: " + filetmp.substring(i + 9, end).trim()); String includedFilename = filetmp.substring(i + 9, end).split(";") [0].trim(); if (!fileUtils.isAbsolute(includedFilename)) { includedFilename = basePath + includedFilename; } String fileContents = fileToString(includedFilename); filetmp = filetmp.substring(0, i) + fileContents + filetmp.substring(end); } } while (i != -1); return filetmp; } public void doParsing(String code) throws ParserMultiException { boolean isFirstOutOfInstructionMemory = true; boolean isFirstOutOfMemory = true; boolean halt = false; int row = 0; numError = 0; int numWarning = 0; int instrCount = -4; // Hack fituso by Andrea error = new ParserMultiException(); ParserMultiWarningException warning = new ParserMultiWarningException(); LinkedList<VoidJump> voidJump = new LinkedList<>(); memoryCount = 0; String lastLabel = ""; code = code.replaceAll("\r\n", "\n"); for (String line : code.split("\n")) { row++; logger.info("-- Processing line " + row); for (int i = 0; i < line.length(); i++) { if (line.charAt(i) == ';') { //comments break; } if (line.charAt(i) == ' ' || line.charAt(i) == '\t') { continue; } int tab = line.indexOf('\t', i); int space = line.indexOf(' ', i); if (tab == -1) { tab = line.length(); } if (space == -1) { space = line.length(); } int end = Math.min(tab, space) - 1; String instr = line.substring(i, end + 1); String parameters; try { if (line.charAt(i) == '.') { logger.info("Processing " + instr); if (instr.compareToIgnoreCase(".DATA") == 0) { section = FileSection.DATA; } else if (instr.compareToIgnoreCase(".TEXT") == 0 || instr.compareToIgnoreCase(".CODE") == 0) { section = FileSection.TEXT; } else { String name = instr.substring(1); // The name, without the dot. if (section != FileSection.DATA) { numError++; error.add(name.toUpperCase() + "INCODE", row, i + 1, line); i = line.length(); continue; } try { if (!((instr.compareToIgnoreCase(".ASCII") == 0) || instr.compareToIgnoreCase(".ASCIIZ") == 0)) { // We don't want strings to be uppercase, do we? parameters = cleanFormat(line.substring(end + 2)); parameters = parameters.toUpperCase(); parameters = parameters.split(";") [0]; logger.info("parameters: " + parameters); } else { parameters = line.substring(end + 2); } parameters = parameters.split(";") [0].trim(); logger.info("parameters: " + parameters); } catch (StringIndexOutOfBoundsException e) { numWarning++; warning.add("VALUE_MISS", row, i + 1, line); error.addWarning("VALUE_MISS", row, i + 1, line); memoryCount++; i = line.length(); continue; } if (instr == null) { numWarning++; warning.add("VALUE_MISS", row, i + 1, line); error.addWarning("VALUE_MISS", row, i + 1, line); memoryCount++; i = line.length(); continue; } MemoryElement tmpMem; tmpMem = mem.getCellByIndex(memoryCount); logger.info("line: " + line); String[] comment = (line.substring(i)).split(";", 2); if (comment.length == 2) { logger.info("found comments: " + comment[1]); tmpMem.setComment(comment[1]); } tmpMem.setCode(comment[0]); if (instr.compareToIgnoreCase(".ASCII") == 0 || instr.compareToIgnoreCase(".ASCIIZ") == 0) { logger.info(".ascii(z): parameters = " + parameters); boolean auto_terminate = false; if (instr.compareToIgnoreCase(".ASCIIZ") == 0) { auto_terminate = true; } try { List<String> pList = splitStringParameters(parameters, auto_terminate); for (String current_string : pList) { logger.info("Current string: [" + current_string + "]"); logger.info(".ascii(z): requested new memory cell (" + memoryCount + ")"); tmpMem = mem.getCellByIndex(memoryCount); memoryCount++; int posInWord = 0; // TODO: Controllo sui parametri (es. virgolette?) int num = current_string.length(); boolean escape = false; boolean placeholder = false; int escaped = 0; // to avoid escape sequences to count as two bytes for (int tmpi = 0; tmpi < num; tmpi++) { if ((tmpi - escaped) % 8 == 0 && (tmpi - escaped) != 0 && !escape) { logger.info(".ascii(z): requested new memory cell (" + memoryCount + ")"); tmpMem = mem.getCellByIndex(memoryCount); memoryCount++; posInWord = 0; } char c = current_string.charAt(tmpi); int to_write = (int) c; logger.info("Char: " + c + " (" + to_write + ") [" + Integer.toHexString(to_write) + "]"); if (escape) { switch (c) { case '0': to_write = 0; break; case 'n': to_write = 10; break; case 't': to_write = 9; break; case '\\': to_write = 92; break; case '"': to_write = 34; break; default: throw new StringFormatException(); } logger.info("(escaped to [" + Integer.toHexString(to_write) + "])"); escape = false; c = 0; // to avoid re-entering the escape if branch. } if (placeholder) { if (c != '%' && c != 's' && c != 'd' && c != 'i') { logger.info("Invalid placeholder: %" + c); // Invalid placeholder throw new StringFormatException(); } placeholder = false; } else if (c == '%') { logger.info("Expecting on next step a valid placeholder..."); placeholder = true; } if (c == '\\') { escape = true; escaped++; continue; } tmpMem.writeByte(to_write, posInWord++); } } } catch (StringFormatException ex) { logger.info("Badly formed string list"); numError++; // TODO: more descriptive error message error.add("INVALIDVALUE", row, 0, line); } end = line.length(); } else if (instr.compareToIgnoreCase(".SPACE") == 0) { int posInWord = 0; //position of byte to write into a doubleword memoryCount++; try { if (isHexNumber(parameters)) { parameters = Converter.hexToLong(parameters); } if (isNumber(parameters)) { int num = Integer.parseInt(parameters); for (int tmpi = 0; tmpi < num; tmpi++) { if (tmpi % 8 == 0 && tmpi != 0) { tmpMem = mem.getCellByIndex(memoryCount); memoryCount++; posInWord = 0; } tmpMem.writeByte(0, posInWord++); } } else { throw new NumberFormatException(); } } catch (NumberFormatException ex) { numError++; error.add("INVALIDVALUE", row, i + 1, line); continue; } catch (IrregularStringOfHexException ex) { numError++; error.add("INVALIDVALUE", row, i + 1, line); continue; } posInWord ++; end = line.length(); } else if (instr.compareToIgnoreCase(".WORD") == 0 || instr.compareToIgnoreCase(".WORD64") == 0) { logger.info("pamword: " + parameters); writeIntegerInMemory(row, i, line, parameters, 64, "WORD"); end = line.length(); } else if (instr.compareToIgnoreCase(".WORD32") == 0) { writeIntegerInMemory(row, i, line, parameters, 32, "WORD32"); end = line.length(); } else if (instr.compareToIgnoreCase(".BYTE") == 0) { writeIntegerInMemory(row, i, line, parameters, 8, "BYTE"); end = line.length(); } else if (instr.compareToIgnoreCase(".WORD16") == 0) { writeIntegerInMemory(row, i, line, parameters, 16 , "WORD16"); end = line.length(); } else if (instr.compareToIgnoreCase(".DOUBLE") == 0) { writeDoubleInMemory(row, i, line, parameters); end = line.length(); } else { numError++; error.add("INVALIDCODEFORDATA", row, i + 1, line); i = line.length(); continue; } } } else if (line.charAt(end) == ':') { String label = line.substring(i, end); logger.info("Processing label " + label); if (section == FileSection.DATA) { logger.info("in .data section"); try { symTab.setCellLabel(memoryCount * 8, label); } catch (SameLabelsException e) { // TODO: errore del parser logger.warning("Label " + label + " is already assigned"); } } else if (section == FileSection.TEXT) { logger.info("in .text section"); lastLabel = label; } logger.info("done"); } else { if (section != FileSection.TEXT) { numError++; error.add("INVALIDCODEFORDATA", row, i + 1, line); i = line.length(); continue; } else if (section == FileSection.TEXT) { boolean doPack = true; end++; Instruction tmpInst; // Check for halt-like instructions String temp = cleanFormat(line.substring(i)).toUpperCase(); if (temp.equals("HALT") || temp.equals("SYSCALL 0") || temp.equals("TRAP 0")) { halt = true; } //timmy for (int timmy = 0; timmy < deprecateInstruction.length; timmy++) { if (deprecateInstruction[timmy].toUpperCase().equals(line.substring(i, end).toUpperCase())) { warning.add("WINMIPS64_NOT_MIPS64", row, i + 1, line); error.addWarning("WINMIPS64_NOT_MIPS64", row, i + 1, line); numWarning++; } } tmpInst = instructionBuilder.buildInstruction(line.substring(i, end).toUpperCase()); if (tmpInst == null) { numError++; error.add("INVALIDCODE", row, i + 1, line); i = line.length(); continue; } String syntax = tmpInst.getSyntax(); instrCount += 4; if (syntax.compareTo("") != 0 && (line.length() < end + 1)) { numError++; error.add("UNKNOWNSYNTAX", row, end, line); i = line.length(); continue; } if (syntax.compareTo("") != 0) { String param = cleanFormat(line.substring(end + 1)); param = param.toUpperCase(); param = param.split(";") [0].trim(); logger.info("param: " + param); int indPar = 0; for (int z = 0; z < syntax.length(); z++) { if (syntax.charAt(z) == '%') { z++; if (syntax.charAt(z) == 'R') { //register int endPar; if (z != syntax.length() - 1) { endPar = param.indexOf(syntax.charAt(++z), indPar); } else { endPar = param.length(); } if (endPar == -1) { numError++; error.add("SEPARATORMISS", row, indPar, line); i = line.length(); tmpInst.getParams().add(0); continue; } int reg; if ((reg = isRegister(param.substring(indPar, endPar).trim())) >= 0) { tmpInst.getParams().add(reg); indPar = endPar + 1; } else { numError++; error.add("INVALIDREGISTER", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); tmpInst.getParams().add(0); i = line.length(); continue; } } else if (syntax.charAt(z) == 'F') { //floating point register int endPar; if (z != syntax.length() - 1) { endPar = param.indexOf(syntax.charAt(++z), indPar); } else { endPar = param.length(); } if (endPar == -1) { numError++; error.add("SEPARATORMISS", row, indPar, line); i = line.length(); tmpInst.getParams().add(0); continue; } int reg; if ((reg = isRegisterFP(param.substring(indPar, endPar).trim())) >= 0) { tmpInst.getParams().add(reg); indPar = endPar + 1; } else { numError++; error.add("INVALIDREGISTER", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); tmpInst.getParams().add(0); i = line.length(); continue; } } else if (syntax.charAt(z) == 'I') { //immediate int endPar; if (z != syntax.length() - 1) { endPar = param.indexOf(syntax.charAt(++z), indPar); } else { endPar = param.length(); } if (endPar == -1) { numError++; error.add("SEPARATORMISS", row, indPar, line); i = line.length(); tmpInst.getParams().add(0); continue; } int imm; if (isImmediate(param.substring(indPar, endPar))) { if (param.charAt(indPar) == '#') { indPar++; } if (isNumber(param.substring(indPar, endPar))) { try { imm = Integer.parseInt(param.substring(indPar, endPar)); if (imm < -32768 || imm > 32767) { throw new NumberFormatException(); } } catch (NumberFormatException ex) { imm = 0; numError++; error.add("IMMEDIATE_TOO_LARGE", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); } tmpInst.getParams().add(imm); indPar = endPar + 1; } else if (isHexNumber(param.substring(indPar, endPar))) { try { try { imm = (int) Long.parseLong(Converter.hexToShort(param.substring(indPar, endPar))); logger.info("imm = " + imm); if (imm < -32768 || imm > 32767) { throw new NumberFormatException(); } } catch (NumberFormatException ex) { imm = 0; numError++; error.add("IMMEDIATE_TOO_LARGE", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); } tmpInst.getParams().add(imm); indPar = endPar + 1; } catch (IrregularStringOfHexException ex) { //non ci dovrebbe mai arrivare } } } else { try { int cc; MemoryElement tmpMem; cc = param.indexOf("+", indPar); if (cc != -1) { tmpMem = symTab.getCell(param.substring(indPar, cc).trim()); if (isNumber(param.substring(cc + 1, endPar))) { try { imm = Integer.parseInt(param.substring(indPar, endPar)); if (imm < -32768 || imm > 32767) { throw new NumberFormatException(); } } catch (NumberFormatException ex) { imm = 0; numError++; error.add("IMMEDIATE_TOO_LARGE", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); } tmpInst.getParams().add(tmpMem.getAddress() + imm); indPar = endPar + 1; } else if (isHexNumber(param.substring(cc + 1, endPar))) { try { try { imm = (int) Long.parseLong(Converter.hexToLong(param.substring(indPar, endPar))); if (imm < -32768 || imm > 32767) { throw new NumberFormatException(); } } catch (NumberFormatException ex) { imm = 0; numError++; error.add("IMMEDIATE_TOO_LARGE", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); } tmpInst.getParams().add(tmpMem.getAddress() + imm); indPar = endPar + 1; } catch (IrregularStringOfHexException ex) { logger.severe("Irregular string of bits: " + ex.getMessage()); } } else { MemoryElement tmpMem1 = symTab.getCell(param.substring(cc + 1, endPar).trim()); tmpInst.getParams().add(tmpMem.getAddress() + tmpMem1.getAddress()); } } else { cc = param.indexOf("-", indPar); if (cc != -1) { tmpMem = symTab.getCell(param.substring(indPar, cc).trim()); if (isNumber(param.substring(cc + 1, endPar))) { try { imm = Integer.parseInt(param.substring(indPar, endPar)); if (imm < -32768 || imm > 32767) { throw new NumberFormatException(); } } catch (NumberFormatException ex) { imm = 0; numError++; error.add("IMMEDIATE_TOO_LARGE", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); } tmpInst.getParams().add(tmpMem.getAddress() - imm); indPar = endPar + 1; } else if (isHexNumber(param.substring(cc + 1, endPar))) { try { try { imm = (int) Long.parseLong(Converter.hexToLong(param.substring(indPar, endPar))); if (imm < -32768 || imm > 32767) { throw new NumberFormatException(); } } catch (NumberFormatException ex) { imm = 0; numError++; error.add("IMMEDIATE_TOO_LARGE", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); } tmpInst.getParams().add(tmpMem.getAddress() - imm); indPar = endPar + 1; } catch (IrregularStringOfHexException ex) { //non ci dovrebbe mai arrivare } } else { MemoryElement tmpMem1 = symTab.getCell(param.substring(cc + 1, endPar).trim()); tmpInst.getParams().add(tmpMem.getAddress() - tmpMem1.getAddress()); } } else { tmpMem = symTab.getCell(param.substring(indPar, endPar).trim()); tmpInst.getParams().add(tmpMem.getAddress()); } } } catch (MemoryElementNotFoundException ex) { numError++; error.add("INVALIDIMMEDIATE", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); i = line.length(); tmpInst.getParams().add(0); continue; } } } else if (syntax.charAt(z) == 'U') { //Unsigned Immediate (5 bit) int endPar; if (z != syntax.length() - 1) { endPar = param.indexOf(syntax.charAt(++z), indPar); } else { endPar = param.length(); } if (endPar == -1) { numError++; error.add("SEPARATORMISS", row, indPar, line); i = line.length(); tmpInst.getParams().add(0); continue; } int imm; if (isImmediate(param.substring(indPar, endPar))) { if (param.charAt(indPar) == '#') { indPar++; } if (isNumber(param.substring(indPar, endPar))) { try { imm = Integer.parseInt(param.substring(indPar, endPar).trim()); if (imm < 0) { numError++; error.add("VALUEISNOTUNSIGNED", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); i = line.length(); tmpInst.getParams().add(0); continue; } if (imm < 0 || imm > 31) { throw new NumberFormatException(); } } catch (NumberFormatException ex) { imm = 0; numError++; error.add("5BIT_IMMEDIATE_TOO_LARGE", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); } tmpInst.getParams().add(imm); indPar = endPar + 1; } else if (isHexNumber(param.substring(indPar, endPar).trim())) { try { imm = (int) Long.parseLong(Converter.hexToLong(param.substring(indPar, endPar))); if (imm < 0) { numError++; error.add("VALUEISNOTUNSIGNED", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); i = line.length(); tmpInst.getParams().add(0); continue; } tmpInst.getParams().add(imm); indPar = endPar + 1; if (imm < 0 || imm > 31) { throw new NumberFormatException(); } } catch (NumberFormatException ex) { imm = 0; numError++; error.add("5BIT_IMMEDIATE_TOO_LARGE", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); tmpInst.getParams().add(imm); indPar = endPar + 1; } catch (IrregularStringOfHexException ex) { //non ci dovrebbe mai arrivare } } } else { numError++; error.add("INVALIDIMMEDIATE", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); i = line.length(); tmpInst.getParams().add(0); continue; } } else if (syntax.charAt(z) == 'C') { //Unsigned Immediate (3 bit) int endPar; if (z != syntax.length() - 1) { endPar = param.indexOf(syntax.charAt(++z), indPar); } else { endPar = param.length(); } if (endPar == -1) { numError++; error.add("SEPARATORMISS", row, indPar, line); i = line.length(); tmpInst.getParams().add(0); continue; } int imm; if (isImmediate(param.substring(indPar, endPar))) { if (param.charAt(indPar) == '#') { indPar++; } if (isNumber(param.substring(indPar, endPar))) { try { imm = Integer.parseInt(param.substring(indPar, endPar).trim()); if (imm < 0) { numError++; error.add("VALUEISNOTUNSIGNED", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); i = line.length(); tmpInst.getParams().add(0); continue; } if (imm < 0 || imm > 7) { throw new NumberFormatException(); } } catch (NumberFormatException ex) { imm = 0; numError++; error.add("3BIT_IMMEDIATE_TOO_LARGE", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); } tmpInst.getParams().add(imm); indPar = endPar + 1; } else if (isHexNumber(param.substring(indPar, endPar).trim())) { try { imm = (int) Long.parseLong(Converter.hexToLong(param.substring(indPar, endPar))); if (imm < 0) { numError++; error.add("VALUEISNOTUNSIGNED", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); i = line.length(); tmpInst.getParams().add(0); continue; } tmpInst.getParams().add(imm); indPar = endPar + 1; if (imm < 0 || imm > 31) { throw new NumberFormatException(); } } catch (NumberFormatException ex) { imm = 0; numError++; error.add("3BIT_IMMEDIATE_TOO_LARGE", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); tmpInst.getParams().add(imm); indPar = endPar + 1; } catch (IrregularStringOfHexException ex) { //non ci dovrebbe mai arrivare } } } else { numError++; error.add("INVALIDIMMEDIATE", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); i = line.length(); tmpInst.getParams().add(0); continue; } } else if (syntax.charAt(z) == 'L') { //Memory Label int endPar; if (z != syntax.length() - 1) { endPar = param.indexOf(syntax.charAt(++z), indPar); } else { endPar = param.length(); } if (endPar == -1) { numError++; error.add("SEPARATORMISS", row, indPar, line); i = line.length(); tmpInst.getParams().add(0); continue; } try { MemoryElement tmpMem; if (param.substring(indPar, endPar).equals("")) { tmpInst.getParams().add(0); } else if (isNumber(param.substring(indPar, endPar).trim())) { int tmp = Integer.parseInt(param.substring(indPar, endPar).trim()); //if (tmp<0 || tmp%2!=0 || tmp > org.edumips64.core.CPU.DATALIMIT) if (tmp < 0 || tmp > org.edumips64.core.CPU.DATALIMIT) { numError++; String er = "LABELADDRESSINVALID"; if (tmp > org.edumips64.core.CPU.DATALIMIT) { er = "LABELTOOLARGE"; } error.add(er, row, line.indexOf(param.substring(indPar, endPar)) + 1, line); i = line.length(); indPar = endPar + 1; tmpInst.getParams().add(0); continue; } tmpInst.getParams().add(tmp); } else { tmpMem = symTab.getCell(param.substring(indPar, endPar).trim()); tmpInst.getParams().add(tmpMem.getAddress()); } indPar = endPar + 1; } catch (MemoryElementNotFoundException e) { numError++; error.add("LABELNOTFOUND", row, line.indexOf(param.substring(indPar, endPar)) + 1, line); i = line.length(); indPar = endPar + 1; tmpInst.getParams().add(0); continue; } } else if (syntax.charAt(z) == 'E') { //Instruction Label int endPar; if (z != syntax.length() - 1) { endPar = param.indexOf(syntax.charAt(++z), indPar); } else { endPar = param.length(); } if (endPar == -1) { numError++; error.add("SEPARATORMISS", row, indPar, line); i = line.length(); tmpInst.getParams().add(0); continue; } String label = param.substring(indPar, endPar).trim(); Integer labelAddr = symTab.getInstructionAddress(label); logger.info("Label " + label + " at address " + labelAddr); if (labelAddr != null) { tmpInst.getParams().add(labelAddr); } else { VoidJump tmpVoid = new VoidJump(); tmpVoid.instr = tmpInst; tmpVoid.row = row; tmpVoid.line = line; tmpVoid.column = indPar; tmpVoid.label = label; voidJump.add(tmpVoid); doPack = false; } } else if (syntax.charAt(z) == 'B') { //Instruction Label for branch int endPar; if (z != syntax.length() - 1) { endPar = param.indexOf(syntax.charAt(++z), indPar); } else { endPar = param.length(); } if (endPar == -1) { numError++; error.add("SEPARATORMISS", row, indPar, line); i = line.length(); tmpInst.getParams().add(0); continue; } Integer labelAddr = symTab.getInstructionAddress(param.substring(indPar, endPar).trim()); if (labelAddr != null) { labelAddr -= instrCount + 4; tmpInst.getParams().add(labelAddr); } else { VoidJump tmpVoid = new VoidJump(); tmpVoid.instr = tmpInst; tmpVoid.row = row; tmpVoid.line = line; tmpVoid.column = indPar; tmpVoid.label = param.substring(indPar, endPar); tmpVoid.instrCount = instrCount; tmpVoid.isBranch = true; voidJump.add(tmpVoid); doPack = false; } } else { numError++; error.add("UNKNOWNSYNTAX", row, 1, line); i = line.length(); tmpInst.getParams().add(0); continue; } } else { if (syntax.charAt(z) != param.charAt(indPar++)) { numError++; error.add("UNKNOWNSYNTAX", row, 1, line); i = line.length(); tmpInst.getParams().add(0); continue; } } } if (i == line.length()) { continue; } try { if (doPack) { tmpInst.pack(); } } catch (IrregularStringOfBitsException ex) { logger.severe("Irregular string of bits: " + ex.getMessage()); } } else { try { tmpInst.pack(); } catch (IrregularStringOfBitsException e) { logger.severe("Irregular string of bits: " + e.getMessage()); } } logger.info("row: " + line); String comment[] = line.split(";", 2); tmpInst.setFullName(replaceTab(comment[0].substring(i))); tmpInst.setFullName(replaceTab(comment[0].substring(i))); tmpInst.setFullName(replaceTab(comment[0].substring(i))); tmpInst.setFullName(replaceTab(comment[0].substring(i))); if (comment.length == 2) { tmpInst.setComment(comment[1]); } try { mem.addInstruction(tmpInst, instrCount); if (lastLabel != null && !lastLabel.equals("")) { logger.info("About to add label: " + lastLabel); symTab.setInstructionLabel(instrCount, lastLabel.toUpperCase()); } } catch (SymbolTableOverflowException ex) { if (isFirstOutOfInstructionMemory) { //is first out of memory? isFirstOutOfInstructionMemory = false; numError++; error.add("OUTOFINSTRUCTIONMEMORY", row, i + 1, line); i = line.length(); continue; } } catch (SameLabelsException ex) { numError++; error.add("SAMELABEL", row, 1, line); i = line.length(); } // Il finally e' totalmente inutile, ma Ú bello utilizzarlo per la // prima volta in un programma ;) finally { lastLabel = ""; } end = line.length(); } } i = end; } catch (MemoryElementNotFoundException ex) { if (isFirstOutOfMemory) { //is first out of memory? isFirstOutOfMemory = false; numError++; error.add("OUTOFMEMORY", row, i + 1, line); i = line.length(); continue; } } catch (IrregularWriteOperationException ex) { numError++; error.add("INVALIDVALUE", row, i + 1, line); break; } } } for (int i = 0; i < voidJump.size(); i++) { Integer labelAddr = symTab.getInstructionAddress(voidJump.get(i).label.trim()); if (labelAddr != null) { if (voidJump.get(i).isBranch) { labelAddr -= voidJump.get(i).instrCount + 4; } voidJump.get(i).instr.getParams().add(labelAddr); try { voidJump.get(i).instr.pack(); } catch (IrregularStringOfBitsException ex) { logger.severe("Irregular string of bits: " + ex.getMessage()); } } else { numError++; error.add("LABELNOTFOUND", voidJump.get(i).row, voidJump.get(i).column , voidJump.get(i).line); continue; } } if (!halt) { //if Halt is not present in code numWarning++; warning.add("HALT_NOT_PRESENT", row, 0, ""); error.addWarning("HALT_NOT_PRESENT", row, 0, ""); try { logger.warning("No terminating instruction detected, adding one."); Instruction tmpInst = instructionBuilder.buildInstruction("SYSCALL"); tmpInst.getParams().add(0); tmpInst.setFullName("SYSCALL 0"); try { tmpInst.pack(); } catch (IrregularStringOfBitsException ex) { logger.severe("Irregular string of bits: " + ex.getMessage()); } mem.addInstruction(tmpInst, (instrCount + 4)); symTab.setInstructionLabel((instrCount + 4), ""); } catch (SymbolTableOverflowException ex) { if (isFirstOutOfInstructionMemory) { //is first out of memory? numError++; error.add("OUTOFINSTRUCTIONMEMORY", row, 0, "Halt"); } } catch (SameLabelsException ex) { logger.severe("Same labels: " + ex); } // impossible } if (numError > 0) { throw error; } else if (numWarning > 0) { throw warning; } } /** Clean multiple tab or spaces in a bad format String //and converts this String to upper case * @param s the bad format String * @return the cleaned String */ private String cleanFormat(String s) { if (s.length() > 0 && s.charAt(0) != ';' && s.charAt(0) != '\n') { //String[] nocomment=s.split(";"); //s=nocomment[0];//.toUpperCase(); s = s.trim(); s = s.replace("\t", " "); while (s.contains(" ")) { s = s.replace(" ", " "); } s = s.replace(", ", ","); s = s.replace(" ,", ","); if (s.length() > 0) { return s; } } return null; } /** Check if is a valid string for a register * @param reg the string to validate * @return -1 if reg isn't a valid register, else a number of register */ private int isRegister(String reg) { try { int num; if (reg.charAt(0) == 'r' || reg.charAt(0) == 'R' || reg.charAt(0) == '$') //ci sono altri modi di scrivere un registro??? if (isNumber(reg.substring(1))) { num = Integer.parseInt(reg.substring(1)); if (num < 32 && num >= 0) { return num; } } if (reg.charAt(0) == '$' && (num = isAlias(reg.substring(1))) != -1) { return num; } } catch (Exception ignored) {} return -1; } /** Check if is a valid string for a floating point register * @param reg the string to validate * @return -1 if reg isn't a valid register, else a number of register */ private int isRegisterFP(String reg) { try { int num; if (reg.charAt(0) == 'f' || reg.charAt(0) == 'F' || reg.charAt(0) == '$') if (isNumber(reg.substring(1))) { num = Integer.parseInt(reg.substring(1)); if (num < 32 && num >= 0) { return num; } } if (reg.charAt(0) == '$' && (num = isAlias(reg.substring(1))) != -1) { return num; } } catch (Exception ignored) {} return -1; } /** Check if the parameter is a valid string for an alias-register * @param reg the string to validate * @return -1 if reg isn't a valid alias-register, else a number of register */ private int isAlias(String reg) { for (AliasRegister x : AliasRegister.values()) { if (reg.equalsIgnoreCase(x.name())) { return x.ordinal(); } } return -1; } /** Check if a string is a number * @param num the string to validate * @return true if num is a number, else false */ private boolean isNumber(String num) { if (num.charAt(0) == '+' || num.charAt(0) == '-') { num = num.substring(1); } for (int i = 0; i < num.length(); i++) if (num.charAt(i) < '0' || num.charAt(i) > '9') { return false; } return true; } /** Check if a string is a Hex number * @param num the string to validate * @return true if num is a number, else false */ private boolean isHexNumber(String num) { try { if (num.substring(0, 2).compareToIgnoreCase("0X") != 0) { return false; } for (int i = 2; i < num.length(); i++) if ((num.charAt(i) < '0' || num.charAt(i) > '9') && (num.charAt(i) < 'A' || num.charAt(i) > 'F')) { return false; } return true; } catch (Exception e) { return false; } } /** Check if is a valid string for a register * @param imm the string to validate * @return false if imm isn't a valid immediate, else true */ private boolean isImmediate(String imm) { try { if (imm.charAt(0) == '#') { imm = imm.substring(1); } if (isNumber(imm)) { return true; } else if (isHexNumber(imm)) { if (imm.length() <= 6) { return true; } } return false; } catch (Exception e) { return false; } } /** Write a double in memory * @param row number of row * @param i * @param line the line of code * @param instr params */ private void writeDoubleInMemory(int row, int i, String line, String instr) throws MemoryElementNotFoundException { String value[] = instr.split(","); MemoryElement tmpMem; for (String aValue : value) { tmpMem = mem.getCellByIndex(memoryCount); memoryCount++; // TODO(andrea): unit tests for those 3 cases. try { tmpMem.setBits(fpInstructionUtils.doubleToBin(aValue.trim()), 0); } catch (FPOverflowException ex) { numError++; //error.add("DOUBLE_TOO_LARGE",row,i+1,line); error.add("FP_OVERFLOW", row, i + 1, line); } catch (FPUnderflowException ex) { numError++; error.add("FP_UNDERFLOW", row, i + 1, line); } catch (IrregularStringOfBitsException e) { numError++; error.add("INVALIDVALUE", row, i + 1, line); i = line.length(); } } } /** Write an integer in memory * @param row number of row * @param i * @param line the line of code * @param instr * @param numBit * @param name type of data */ private void writeIntegerInMemory(int row, int i, String line, String instr, int numBit, String name) throws MemoryElementNotFoundException { int posInWord = 0; //position of byte to write into a doubleword String value[] = instr.split(","); MemoryElement tmpMem = null; for (int j = 0; j < value.length; j++) { if (j % (64 / numBit) == 0) { posInWord = 0; tmpMem = mem.getCellByIndex(memoryCount); memoryCount++; } String val = value[j].trim(); if(val.isEmpty()) { numError++; error.add("INVALIDVALUE", row, i + 1, line); i = line.length(); continue; } if (isHexNumber(val)) { try { val = Converter.hexToLong(val); } catch (IrregularStringOfHexException e) { numError++; error.add("INVALIDVALUE", row, i + 1, line); i = line.length(); continue; } } try { // Convert the integer to a long, and then check for overflow. long num = Long.parseLong(val); if ((num < - (Converter.powLong(2, numBit - 1)) || num > (Converter.powLong(2, numBit - 1) - 1)) && numBit != 64) { throw new NumberFormatException(); } if (numBit == 8) { tmpMem.writeByte((int) num, posInWord); } else if (numBit == 16) { tmpMem.writeHalf((int) num, posInWord); } else if (numBit == 32) { tmpMem.writeWord(num, posInWord); } else if (numBit == 64) { tmpMem.writeDoubleWord(num); } } catch (NumberFormatException ex) { numError++; error.add(name.toUpperCase() + "_TOO_LARGE", row, i + 1, line); continue; } catch (IrregularWriteOperationException | NotAlignException e) { e.printStackTrace(); numError++; error.add("INVALIDVALUE", row, i + 1, line); i = line.length(); continue; } posInWord += numBit / 8; } } private List<String> splitStringParameters(String params, boolean auto_terminate) throws StringFormatException { List<String> pList = new LinkedList<>(); StringBuilder temp = new StringBuilder(); logger.info("Params: " + params); params = params.trim(); logger.info("After trimming: " + params); int length = params.length(); boolean in_string = false; boolean escaping = false; boolean comma = false; for (int i = 0; i < length; ++i) { char c = params.charAt(i); if (!in_string) { switch (c) { case '"': if ((!comma && pList.size() != 0) || i == length - 1) { throw new StringFormatException(); } in_string = true; comma = false; break; case ' ': case '\t': break; case ',': if (comma || i == 0 || i == length - 1) { throw new StringFormatException(); } comma = true; break; default: throw new StringFormatException(); } } else { if (!escaping && c == '\\') { escaping = true; } else if (!escaping && c == '"') { if (temp.length() > 0) { if (auto_terminate) { logger.info("Behaving like .asciiz."); temp.append((char) 0); } logger.info("Added to pList string " + temp.toString()); pList.add(temp.toString()); temp.setLength(0); } in_string = false; } else { if (escaping) { escaping = false; temp.append('\\'); } temp.append(c); } } } if (pList.size() == 0 && in_string) // TODO: Unterminated string literal { throw new StringFormatException(); } return pList; } }