diff --git a/src/com/bytezone/diskbrowser/applefile/ApplesoftBasicProgram.java b/src/com/bytezone/diskbrowser/applefile/ApplesoftBasicProgram.java index 2dbd376..7abe924 100644 --- a/src/com/bytezone/diskbrowser/applefile/ApplesoftBasicProgram.java +++ b/src/com/bytezone/diskbrowser/applefile/ApplesoftBasicProgram.java @@ -22,6 +22,8 @@ public class ApplesoftBasicProgram extends BasicProgram final Map> gosubLines = new TreeMap<> (); final Map> callLines = new TreeMap<> (); private final Map> symbolLines = new TreeMap<> (); + private final Map> functionLines = new TreeMap<> (); + private final Map> arrayLines = new TreeMap<> (); private final Map> uniqueSymbols = new TreeMap<> (); final List stringsLine = new ArrayList<> (); @@ -52,6 +54,10 @@ public class ApplesoftBasicProgram extends BasicProgram { for (String symbol : subline.getSymbols ()) checkVar (symbol, line.lineNumber); + for (String symbol : subline.getArrays ()) + checkArray (symbol, line.lineNumber); + for (String symbol : subline.getFunctions ()) + checkFunction (symbol, line.lineNumber); for (int targetLine : subline.getGosubLines ()) addXref (line.lineNumber, targetLine, gosubLines); for (int targetLine : subline.getGotoLines ()) @@ -73,6 +79,7 @@ public class ApplesoftBasicProgram extends BasicProgram lines = new ArrayList<> (); symbolLines.put (var, lines); } + if (lines.size () == 0) lines.add (lineNumber); else @@ -81,9 +88,56 @@ public class ApplesoftBasicProgram extends BasicProgram if (lastLine != lineNumber) lines.add (lineNumber); } + checkUniqueName (var); } + // ---------------------------------------------------------------------------------// + void checkArray (String var, int lineNumber) + // ---------------------------------------------------------------------------------// + { + List lines = arrayLines.get (var); + if (lines == null) + { + lines = new ArrayList<> (); + arrayLines.put (var, lines); + } + + if (lines.size () == 0) + lines.add (lineNumber); + else + { + int lastLine = lines.get (lines.size () - 1); + if (lastLine != lineNumber) + lines.add (lineNumber); + } + + checkUniqueName (var); + } + + // ---------------------------------------------------------------------------------// + void checkFunction (String var, int lineNumber) + // ---------------------------------------------------------------------------------// + { + List lines = functionLines.get (var); + if (lines == null) + { + lines = new ArrayList<> (); + functionLines.put (var, lines); + } + + if (lines.size () == 0) + lines.add (lineNumber); + else + { + int lastLine = lines.get (lines.size () - 1); + if (lastLine != lineNumber) + lines.add (lineNumber); + } + + // checkUniqueName (var); + } + // ---------------------------------------------------------------------------------// private void addXref (int sourceLine, int targetLine, Map> map) // ---------------------------------------------------------------------------------// @@ -290,34 +344,14 @@ public class ApplesoftBasicProgram extends BasicProgram fullText.append ("\n"); } - if (basicPreferences.showXref && !gosubLines.isEmpty ()) - showIntegerLines (fullText, gosubLines, " GOSUB"); - - if (basicPreferences.showXref && !gotoLines.isEmpty ()) - showIntegerLines (fullText, gotoLines, " GOTO"); - - if (basicPreferences.showCalls && !callLines.isEmpty ()) - showStringLines (fullText, callLines, " CALL"); - if (basicPreferences.showSymbols && !symbolLines.isEmpty ()) - { - heading (fullText, "Symbol "); + showSymbols (fullText, symbolLines, "Var "); - int longestVarName = getLongestVarName (); - String format = - longestVarName > 6 ? "%-" + longestVarName + "s %s%n" : "%-6s %s%n"; + if (basicPreferences.showSymbols && !arrayLines.isEmpty ()) + showSymbols (fullText, arrayLines, "Array "); - for (String symbol : symbolLines.keySet ()) - { - String line = symbolLines.get (symbol).toString (); - line = line.substring (1, line.length () - 1); - for (String s : splitXref (line, 90, ' ')) - { - fullText.append (String.format (format, symbol, s)); - symbol = ""; - } - } - } + if (basicPreferences.showFunctions && !functionLines.isEmpty ()) + showSymbols (fullText, functionLines, "Fnction"); if (basicPreferences.showDuplicateSymbols && !uniqueSymbols.isEmpty ()) { @@ -347,6 +381,15 @@ public class ApplesoftBasicProgram extends BasicProgram String.format (" %6s %s%n", stringsLine.get (i), stringsText.get (i))); } + if (basicPreferences.showXref && !gosubLines.isEmpty ()) + showIntegerLines (fullText, gosubLines, " GOSUB"); + + if (basicPreferences.showXref && !gotoLines.isEmpty ()) + showIntegerLines (fullText, gotoLines, " GOTO"); + + if (basicPreferences.showCalls && !callLines.isEmpty ()) + showStringLines (fullText, callLines, " CALL"); + if (fullText.length () > 0) while (fullText.charAt (fullText.length () - 1) == '\n') fullText.deleteCharAt (fullText.length () - 1); // remove trailing newlines @@ -376,6 +419,7 @@ public class ApplesoftBasicProgram extends BasicProgram // ---------------------------------------------------------------------------------// { heading (fullText, heading); + for (Integer line : lines.keySet ()) { String list = lines.get (line).toString (); @@ -390,22 +434,67 @@ public class ApplesoftBasicProgram extends BasicProgram // ---------------------------------------------------------------------------------// { heading (fullText, heading); + for (String target : lines.keySet ()) { - String list = lines.get (target).toString (); - list = list.substring (1, list.length () - 1); - fullText.append (String.format (" %6s %s%n", target, list)); + String line = lines.get (target).toString (); + // String line = numToString (lines.get (target)); + line = line.substring (1, line.length () - 1); + + for (String s : splitXref (line, 90, ' ')) + { + fullText.append (String.format (" %6s %s%n", target, s)); + target = ""; + } } } // ---------------------------------------------------------------------------------// - private int getLongestVarName () + private String numToString (List numbers) + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder ("."); + + for (int number : numbers) + text.append (String.format ("%5d, ", number)); + text.deleteCharAt (text.length () - 1); + + return text.toString (); + } + + // ---------------------------------------------------------------------------------// + private void showSymbols (StringBuilder fullText, Map> map, + String heading) + // ---------------------------------------------------------------------------------// + { + heading (fullText, heading); + + int longestVarName = getLongestName (map); + String format = longestVarName > 7 ? "%-" + longestVarName + "s %s%n" : "%-7s %s%n"; + + for (String symbol : map.keySet ()) + { + String line = map.get (symbol).toString (); + // String line = numToString (map.get (symbol)); + line = line.substring (1, line.length () - 1); + for (String s : splitXref (line, 90, ' ')) + { + fullText.append (String.format (format, symbol, s)); + symbol = ""; + } + } + } + + // ---------------------------------------------------------------------------------// + private int getLongestName (Map> map) // ---------------------------------------------------------------------------------// { int longestName = 0; - for (String symbol : symbolLines.keySet ()) + + for (String symbol : map.keySet ()) if (symbol.length () > longestName) longestName = symbol.length (); + return longestName; } diff --git a/src/com/bytezone/diskbrowser/applefile/ApplesoftConstants.java b/src/com/bytezone/diskbrowser/applefile/ApplesoftConstants.java index 1fb5230..16fd851 100755 --- a/src/com/bytezone/diskbrowser/applefile/ApplesoftConstants.java +++ b/src/com/bytezone/diskbrowser/applefile/ApplesoftConstants.java @@ -54,7 +54,9 @@ public interface ApplesoftConstants static final byte TOKEN_RETURN = (byte) 0xB1; static final byte TOKEN_REM = (byte) 0xB2; static final byte TOKEN_ON = (byte) 0xB4; + static final byte TOKEN_DEF = (byte) 0xB8; static final byte TOKEN_PRINT = (byte) 0xBA; + static final byte TOKEN_FN = (byte) 0xC2; static final byte TOKEN_THEN = (byte) 0xC4; static final byte TOKEN_EQUALS = (byte) 0xD0; diff --git a/src/com/bytezone/diskbrowser/applefile/SubLine.java b/src/com/bytezone/diskbrowser/applefile/SubLine.java index d2acc18..9f9bd54 100644 --- a/src/com/bytezone/diskbrowser/applefile/SubLine.java +++ b/src/com/bytezone/diskbrowser/applefile/SubLine.java @@ -17,11 +17,16 @@ public class SubLine String callTarget; String forVariable = ""; int equalsPosition; // used for aligning the equals sign + String functionArgument; + String functionName; + boolean isDefine = false; byte[] buffer; private final List gotoLines = new ArrayList<> (); private final List gosubLines = new ArrayList<> (); private final List symbols = new ArrayList<> (); + private final List functions = new ArrayList<> (); + private final List arrays = new ArrayList<> (); // ---------------------------------------------------------------------------------// SubLine (SourceLine parent, int startPtr, int length) @@ -46,22 +51,63 @@ public class SubLine return; int ptr = startPtr; - length--; String var = ""; boolean inQuote = false; + boolean inFunction = false; + boolean inDefine = false; - while (length-- > 0) + int max = startPtr + length - 1; + // System.out.printf ("%02X%n", buffer[max]); + if (buffer[max] == 0) + --max; + // System.out.printf ("%02X%n", buffer[max]); + if (buffer[max] == Utility.ASCII_COLON) + --max; + // System.out.printf ("%02X%n", buffer[max]); + + while (ptr <= max) { + // System.out.printf ("%02X%n", buffer[ptr]); byte b = buffer[ptr++]; + if (b == ApplesoftConstants.TOKEN_DEF) + { + inDefine = true; + isDefine = true; + continue; + } + + if (inDefine) // ignore the name and argument + { + if (b == ApplesoftConstants.TOKEN_EQUALS) + inDefine = false; + + continue; + } + if (inQuote && b != Utility.ASCII_QUOTE) continue; + if (inFunction && b == Utility.ASCII_RIGHT_BRACKET) + { + inFunction = false; + continue; + } + + if (b == ApplesoftConstants.TOKEN_FN) + { + inFunction = true; + continue; + } + if (Utility.isPossibleVariable (b)) var += (char) b; else { - checkVar (var, b); + if (inFunction) + checkFunction (var, b); + else + checkVar (var, b); var = ""; if (b == Utility.ASCII_QUOTE) @@ -71,6 +117,16 @@ public class SubLine checkVar (var, (byte) 0); } + // ---------------------------------------------------------------------------------// + private void checkFunction (String var, byte terminator) + // ---------------------------------------------------------------------------------// + { + assert terminator == Utility.ASCII_LEFT_BRACKET; + // System.out.printf ("checking function: %6d %s%n", parent.lineNumber, var); + if (!functions.contains (var)) + functions.add (var); + } + // ---------------------------------------------------------------------------------// private void checkVar (String var, byte terminator) // ---------------------------------------------------------------------------------// @@ -78,10 +134,20 @@ public class SubLine if (var.length () == 0) return; - if (terminator == Utility.ASCII_LEFT_BRACKET) - var += "("; + if (!Utility.isLetter ((byte) var.charAt (0))) + return; - if (Utility.isLetter ((byte) var.charAt (0)) && !symbols.contains (var)) + if (isDefine && (var.equals (functionName) || var.equals (functionArgument))) + return; + + if (terminator == Utility.ASCII_LEFT_BRACKET) + { + // var += "("; + if (!arrays.contains (var)) + arrays.add (var); + + } + else if (!symbols.contains (var)) symbols.add (var); } @@ -92,6 +158,20 @@ public class SubLine return symbols; } + // ---------------------------------------------------------------------------------// + List getFunctions () + // ---------------------------------------------------------------------------------// + { + return functions; + } + + // ---------------------------------------------------------------------------------// + List getArrays () + // ---------------------------------------------------------------------------------// + { + return arrays; + } + // ---------------------------------------------------------------------------------// List getGotoLines () // ---------------------------------------------------------------------------------// @@ -175,16 +255,41 @@ public class SubLine break; case ApplesoftConstants.TOKEN_CALL: - byte[] buffer = getBuffer (); + byte[] lineBuffer = getBuffer (); - if (buffer[0] == (byte) 0xC9) // negative - callTarget = "-" + new String (buffer, 1, buffer.length - 1); + if (lineBuffer[0] == (byte) 0xC9) // negative + callTarget = "-" + new String (lineBuffer, 1, lineBuffer.length - 1); else - callTarget = new String (buffer, 0, buffer.length); + callTarget = new String (lineBuffer, 0, lineBuffer.length); + break; + + case ApplesoftConstants.TOKEN_DEF: + lineBuffer = getBuffer (); + assert lineBuffer[0] == ApplesoftConstants.TOKEN_FN; + + int leftBracket = getPosition (lineBuffer, 1, Utility.ASCII_LEFT_BRACKET); + int rightBracket = + getPosition (lineBuffer, leftBracket + 1, Utility.ASCII_RIGHT_BRACKET); + + functionName = new String (lineBuffer, 1, leftBracket - 1); + functionArgument = + new String (lineBuffer, leftBracket + 1, rightBracket - leftBracket - 1); + functions.add (functionName); + break; } } + // ---------------------------------------------------------------------------------// + private int getPosition (byte[] buffer, int start, byte value) + // ---------------------------------------------------------------------------------// + { + for (int i = start; i < buffer.length; i++) + if (buffer[i] == value) + return i; + return -1; + } + // ---------------------------------------------------------------------------------// private void doDigit () // ---------------------------------------------------------------------------------// diff --git a/src/com/bytezone/diskbrowser/gui/BasicPreferences.java b/src/com/bytezone/diskbrowser/gui/BasicPreferences.java index f28d26d..ef871bc 100644 --- a/src/com/bytezone/diskbrowser/gui/BasicPreferences.java +++ b/src/com/bytezone/diskbrowser/gui/BasicPreferences.java @@ -18,6 +18,7 @@ public class BasicPreferences public boolean showXref = false; public boolean showCalls = false; public boolean showSymbols = false; + public boolean showFunctions = false; public boolean showDuplicateSymbols = false; public boolean splitDim = false; public int wrapPrintAt = 0; @@ -42,6 +43,7 @@ public class BasicPreferences text.append (String.format ("Show Xref ................ %s%n", showXref)); text.append (String.format ("Show CALL ................ %s%n", showCalls)); text.append (String.format ("Show symbols ............. %s%n", showSymbols)); + text.append (String.format ("Show functions ........... %s%n", showFunctions)); text.append (String.format ("Show duplicate symbols ... %s%n", showDuplicateSymbols)); text.append (String.format ("List strings ............. %s%n", listStrings)); text.append (String.format ("Blank after RETURN ....... %s%n", blankAfterReturn)); diff --git a/src/com/bytezone/diskbrowser/gui/DiskBrowser.java b/src/com/bytezone/diskbrowser/gui/DiskBrowser.java index d39386a..03db840 100755 --- a/src/com/bytezone/diskbrowser/gui/DiskBrowser.java +++ b/src/com/bytezone/diskbrowser/gui/DiskBrowser.java @@ -161,8 +161,8 @@ public class DiskBrowser extends JFrame implements DiskSelectionListener, QuitLi if (desktop.isSupported (Desktop.Action.APP_QUIT_HANDLER)) desktop.setQuitHandler ( (e, r) -> fireQuitEvent ()); - else - setQuitHandler (); + // else + setQuitHandler (); } else { diff --git a/src/com/bytezone/diskbrowser/gui/MenuHandler.java b/src/com/bytezone/diskbrowser/gui/MenuHandler.java index 77e07c5..5d279d8 100755 --- a/src/com/bytezone/diskbrowser/gui/MenuHandler.java +++ b/src/com/bytezone/diskbrowser/gui/MenuHandler.java @@ -53,6 +53,7 @@ class MenuHandler implements DiskSelectionListener, FileSelectionListener, QuitL private static final String PREFS_SHOW_XREF = "showXref"; private static final String PREFS_SHOW_CALLS = "showCalls"; private static final String PREFS_SHOW_SYMBOLS = "showSymbols"; + private static final String PREFS_SHOW_FUNCTIONS = "showFunctions"; private static final String PREFS_SHOW_DUPLICATE_SYMBOLS = "showDuplicateSymbols"; private static final String PREFS_LIST_STRINGS = "listStrings"; private static final String PREFS_BLANK_AFTER_RETURN = "blankAfterReturn"; @@ -146,6 +147,7 @@ class MenuHandler implements DiskSelectionListener, FileSelectionListener, QuitL final JMenuItem showXrefItem = new JCheckBoxMenuItem ("List GOSUB/GOTO"); final JMenuItem showCallsItem = new JCheckBoxMenuItem ("List CALLs"); final JMenuItem showSymbolsItem = new JCheckBoxMenuItem ("List variables"); + final JMenuItem showFunctionsItem = new JCheckBoxMenuItem ("List functions"); final JMenuItem showDuplicateSymbolsItem = new JCheckBoxMenuItem ("List duplicate variables"); final JMenuItem listStringsItem = new JCheckBoxMenuItem ("List strings"); @@ -256,6 +258,7 @@ class MenuHandler implements DiskSelectionListener, FileSelectionListener, QuitL applesoftMenu.add (showXrefItem); applesoftMenu.add (showCallsItem); applesoftMenu.add (showSymbolsItem); + applesoftMenu.add (showFunctionsItem); applesoftMenu.add (showDuplicateSymbolsItem); applesoftMenu.add (listStringsItem); @@ -319,6 +322,7 @@ class MenuHandler implements DiskSelectionListener, FileSelectionListener, QuitL showXrefItem.addActionListener (basicPreferencesAction); showCallsItem.addActionListener (basicPreferencesAction); showSymbolsItem.addActionListener (basicPreferencesAction); + showFunctionsItem.addActionListener (basicPreferencesAction); showDuplicateSymbolsItem.addActionListener (basicPreferencesAction); listStringsItem.addActionListener (basicPreferencesAction); blankAfterReturn.addActionListener (basicPreferencesAction); @@ -371,6 +375,7 @@ class MenuHandler implements DiskSelectionListener, FileSelectionListener, QuitL basicPreferences.showXref = showXrefItem.isSelected (); basicPreferences.showCalls = showCallsItem.isSelected (); basicPreferences.showSymbols = showSymbolsItem.isSelected (); + basicPreferences.showFunctions = showFunctionsItem.isSelected (); basicPreferences.showDuplicateSymbols = showDuplicateSymbolsItem.isSelected (); basicPreferences.listStrings = listStringsItem.isSelected (); basicPreferences.blankAfterReturn = blankAfterReturn.isSelected (); @@ -533,6 +538,7 @@ class MenuHandler implements DiskSelectionListener, FileSelectionListener, QuitL prefs.putBoolean (PREFS_SHOW_XREF, showXrefItem.isSelected ()); prefs.putBoolean (PREFS_SHOW_CALLS, showCallsItem.isSelected ()); prefs.putBoolean (PREFS_SHOW_SYMBOLS, showSymbolsItem.isSelected ()); + prefs.putBoolean (PREFS_SHOW_FUNCTIONS, showFunctionsItem.isSelected ()); prefs.putBoolean (PREFS_SHOW_DUPLICATE_SYMBOLS, showDuplicateSymbolsItem.isSelected ()); prefs.putBoolean (PREFS_LIST_STRINGS, listStringsItem.isSelected ()); @@ -589,6 +595,7 @@ class MenuHandler implements DiskSelectionListener, FileSelectionListener, QuitL showXrefItem.setSelected (prefs.getBoolean (PREFS_SHOW_XREF, false)); showCallsItem.setSelected (prefs.getBoolean (PREFS_SHOW_CALLS, false)); showSymbolsItem.setSelected (prefs.getBoolean (PREFS_SHOW_SYMBOLS, false)); + showFunctionsItem.setSelected (prefs.getBoolean (PREFS_SHOW_FUNCTIONS, false)); showDuplicateSymbolsItem .setSelected (prefs.getBoolean (PREFS_SHOW_DUPLICATE_SYMBOLS, false)); listStringsItem.setSelected (prefs.getBoolean (PREFS_LIST_STRINGS, false)); diff --git a/src/com/bytezone/diskbrowser/utilities/Utility.java b/src/com/bytezone/diskbrowser/utilities/Utility.java index e4dbc71..031ed32 100644 --- a/src/com/bytezone/diskbrowser/utilities/Utility.java +++ b/src/com/bytezone/diskbrowser/utilities/Utility.java @@ -23,8 +23,10 @@ public class Utility public static final byte ASCII_DOLLAR = 0x24; public static final byte ASCII_PERCENT = 0x25; public static final byte ASCII_LEFT_BRACKET = 0x28; + public static final byte ASCII_RIGHT_BRACKET = 0x29; public static final byte ASCII_COLON = 0x3A; public static final byte ASCII_SEMI_COLON = 0x3B; + public static final byte ASCII_EQUALS = 0x3D; public static final byte ASCII_CARET = 0x5E; public static final List suffixes = Arrays.asList ("po", "dsk", "do", "hdv",