Commit ff6b82e4 authored by Jesse McGrew's avatar Jesse McGrew
Browse files

Use AbbrevFinder for the initial frequent words file instead of a placeholder. [ZILF-201]

parent ea6e02444000
...@@ -140,5 +140,17 @@ namespace Zapf.Parsing.Instructions ...@@ -140,5 +140,17 @@ namespace Zapf.Parsing.Instructions
return result; return result;
} }
public bool HasStringOperand([NotNullWhen(true)] out string? str)
{
if (Operands.Count >= 1 && Operands[0] is StringLiteral lit)
{
str = lit.Text;
return true;
}
str = null;
return false;
}
} }
} }
\ No newline at end of file
...@@ -72,10 +72,12 @@ namespace Zilf.Common.StringEncoding ...@@ -72,10 +72,12 @@ namespace Zilf.Common.StringEncoding
/// <returns>A sequence of abbreviations, in descending order of overall savings.</returns> /// <returns>A sequence of abbreviations, in descending order of overall savings.</returns>
public IEnumerable<Result> GetResults(int max) public IEnumerable<Result> GetResults(int max)
{ {
#if DEBUG_ABBREV
Console.Error.WriteLine("Indexing {0} strings", allTexts.Count); Console.Error.WriteLine("Indexing {0} strings", allTexts.Count);
var outerStopw = new Stopwatch(); var outerStopw = new Stopwatch();
outerStopw.Start(); outerStopw.Start();
#endif
var isc = new IndexedStringCollection(allTexts); var isc = new IndexedStringCollection(allTexts);
var charsetMap = encoder.GetCharsetMap(); var charsetMap = encoder.GetCharsetMap();
...@@ -151,8 +153,10 @@ namespace Zilf.Common.StringEncoding ...@@ -151,8 +153,10 @@ namespace Zilf.Common.StringEncoding
#endif #endif
} }
#if DEBUG_ABBREV
outerStopw.Stop(); outerStopw.Stop();
Console.Error.WriteLine("Abbreviation search finished in {0}", outerStopw.Elapsed); Console.Error.WriteLine("Abbreviation search finished in {0}", outerStopw.Elapsed);
#endif
} }
} }
} }
...@@ -384,7 +384,7 @@ namespace Zilf.Emit ...@@ -384,7 +384,7 @@ namespace Zilf.Emit
/// </description></item> /// </description></item>
/// <item><description>Instruction types may be toggled between /// <item><description>Instruction types may be toggled between
/// <see cref="PeepholeLineType.BranchNegative"/> and /// <see cref="PeepholeLineType.BranchNegative"/> and
/// <see cref="PeepholeLineType.BranchPositive"/>.) /// <see cref="PeepholeLineType.BranchPositive"/>.
/// </description></item> /// </description></item>
/// </list> /// </list>
/// </remarks> /// </remarks>
......
...@@ -26,6 +26,14 @@ using Zilf.Common.StringEncoding; ...@@ -26,6 +26,14 @@ using Zilf.Common.StringEncoding;
namespace Zilf.Emit.Zap namespace Zilf.Emit.Zap
{ {
[Flags]
public enum GameBuilderOptions
{
None = 0,
WantDebugInfo = 1,
WantFrequentWords = 2,
}
public sealed class GameBuilder : IGameBuilder public sealed class GameBuilder : IGameBuilder
{ {
const string INDENT = "\t"; const string INDENT = "\t";
...@@ -54,6 +62,7 @@ namespace Zilf.Emit.Zap ...@@ -54,6 +62,7 @@ namespace Zilf.Emit.Zap
readonly IZapStreamFactory streamFactory; readonly IZapStreamFactory streamFactory;
internal readonly int zversion; internal readonly int zversion;
internal readonly DebugFileBuilder? debug; internal readonly DebugFileBuilder? debug;
internal readonly AbbrevFinder? abbrevs;
readonly GameOptions options; readonly GameOptions options;
IRoutineBuilder? entryRoutine; IRoutineBuilder? entryRoutine;
...@@ -62,9 +71,9 @@ namespace Zilf.Emit.Zap ...@@ -62,9 +71,9 @@ namespace Zilf.Emit.Zap
TextWriter writer; TextWriter writer;
/// <exception cref="ArgumentOutOfRangeException"><paramref name="zversion"/> is not a supported Z-machine version.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="zversion"/> is not a supported Z-machine version.</exception>
/// <exception cref="ArgumentException"><paramref name="options"/> is the wrong type for this Z-machine version.</exception> /// <exception cref="ArgumentException"><paramref name="gameOptions"/> is the wrong type for this Z-machine version.</exception>
public GameBuilder(int zversion, IZapStreamFactory streamFactory, bool wantDebugInfo, public GameBuilder(int zversion, IZapStreamFactory streamFactory, GameBuilderOptions builderOptions = GameBuilderOptions.None,
GameOptions? options = null) GameOptions? gameOptions = null)
{ {
if (!IsSupportedZversion(zversion)) if (!IsSupportedZversion(zversion))
throw new ArgumentOutOfRangeException(nameof(zversion), "Unsupported Z-machine version"); throw new ArgumentOutOfRangeException(nameof(zversion), "Unsupported Z-machine version");
...@@ -72,17 +81,17 @@ namespace Zilf.Emit.Zap ...@@ -72,17 +81,17 @@ namespace Zilf.Emit.Zap
this.streamFactory = streamFactory ?? throw new ArgumentNullException(nameof(streamFactory)); this.streamFactory = streamFactory ?? throw new ArgumentNullException(nameof(streamFactory));
GetOptionsTypeForZVersion(zversion, out var requiredOptionsType, out var concreteOptionsType); GetOptionsTypeForZVersion(zversion, out var requiredOptionsType, out var concreteOptionsType);
if (options != null) if (gameOptions != null)
{ {
const string SOptionsNotCompatible = "Options not compatible with this Z-machine version"; const string SOptionsNotCompatible = "Options not compatible with this Z-machine version";
if (requiredOptionsType.IsInstanceOfType(options)) if (requiredOptionsType.IsInstanceOfType(gameOptions))
{ {
this.options = options; this.options = gameOptions;
} }
else else
{ {
throw new ArgumentException(SOptionsNotCompatible, nameof(options)); throw new ArgumentException(SOptionsNotCompatible, nameof(gameOptions));
} }
} }
else else
...@@ -91,7 +100,8 @@ namespace Zilf.Emit.Zap ...@@ -91,7 +100,8 @@ namespace Zilf.Emit.Zap
?? throw new InvalidOperationException("Failed to construct options"); ?? throw new InvalidOperationException("Failed to construct options");
} }
debug = wantDebugInfo ? new DebugFileBuilder() : null; debug = builderOptions.HasFlag(GameBuilderOptions.WantDebugInfo) ? new DebugFileBuilder() : null;
abbrevs = builderOptions.HasFlag(GameBuilderOptions.WantFrequentWords) ? new AbbrevFinder() : null;
stream = streamFactory.CreateMainStream(); stream = streamFactory.CreateMainStream();
writer = new StreamWriter(stream); writer = new StreamWriter(stream);
...@@ -540,18 +550,36 @@ namespace Zilf.Emit.Zap ...@@ -540,18 +550,36 @@ namespace Zilf.Emit.Zap
writer.Close(); writer.Close();
// write frequent words file if necessary // write frequent words file if necessary
if (!streamFactory.FrequentWordsFileExists) if (abbrevs != null)
{ {
stream = streamFactory.CreateFrequentWordsStream(); stream = streamFactory.CreateFrequentWordsStream();
writer = new StreamWriter(stream); writer = new StreamWriter(stream);
writer.WriteLine(INDENT + "; Dummy frequent words file for {0}", streamFactory.GetMainFileName(true)); const int maxAbbrevs = 96;
writer.WriteLine(INDENT + ".FSTR FSTR?DUMMY,\"\""); writer.WriteLine(INDENT + "; Frequent words file for {0}", streamFactory.GetMainFileName(true));
writer.WriteLine();
int num = 1, totalSavings = 0;
foreach (var r in abbrevs.GetResults(maxAbbrevs))
{
writer.WriteLine(INDENT + ".FSTR FSTR?{0},\"{1}\"\t\t; {2}x, saved {3}",
num++, SanitizeString(r.Text), r.Count, r.Score);
totalSavings += r.Score;
}
if (num < maxAbbrevs)
writer.WriteLine(INDENT + ".FSTR FSTR?DUMMY,\"\"");
writer.WriteLine("WORDS::"); writer.WriteLine("WORDS::");
for (int i = 0; i < 96; i++) for (int i = 1; i < num; i++)
writer.WriteLine(INDENT + "FSTR?{0}", i);
for (int i = num; i < maxAbbrevs; i++)
writer.WriteLine(INDENT + "FSTR?DUMMY"); writer.WriteLine(INDENT + "FSTR?DUMMY");
writer.WriteLine();
writer.WriteLine(INDENT + ".ENDI"); writer.WriteLine(INDENT + ".ENDI");
writer.WriteLine(INDENT + "; Total savings: {0} Z-chars (~{1} bytes)",
totalSavings, totalSavings * 2 / 3);
writer.Close(); writer.Close();
} }
...@@ -704,6 +732,8 @@ namespace Zilf.Emit.Zap ...@@ -704,6 +732,8 @@ namespace Zilf.Emit.Zap
// property tables // property tables
foreach (var ob in objects) foreach (var ob in objects)
{ {
abbrevs?.AddText(ob.DescriptiveName);
writer.WriteLine(); writer.WriteLine();
writer.WriteLine("?PTBL?{0}:: .TABLE", ob.SymbolicName); writer.WriteLine("?PTBL?{0}:: .TABLE", ob.SymbolicName);
ob.WriteProperties(writer); ob.WriteProperties(writer);
...@@ -833,8 +863,11 @@ namespace Zilf.Emit.Zap ...@@ -833,8 +863,11 @@ namespace Zilf.Emit.Zap
if (stringPool.Count > 0) if (stringPool.Count > 0)
writer.WriteLine(); writer.WriteLine();
foreach (var pair in stringPool.OrderBy(p => p.Key)) foreach (var (text, symbol) in stringPool.OrderBy(p => p.Key))
writer.WriteLine(INDENT + ".GSTR {0},\"{1}\"", pair.Value, SanitizeString(pair.Key)); {
abbrevs?.AddText(text);
writer.WriteLine(INDENT + ".GSTR {0},\"{1}\"", symbol, SanitizeString(text));
}
} }
internal void WriteOutput(string str) internal void WriteOutput(string str)
......
...@@ -593,20 +593,6 @@ namespace Zilf.Emit.Zap ...@@ -593,20 +593,6 @@ namespace Zilf.Emit.Zap
public void EmitScanTable(IOperand value, IOperand table, IOperand length, IOperand? form, public void EmitScanTable(IOperand value, IOperand table, IOperand length, IOperand? form,
IVariable result, ILabel label, bool polarity) IVariable result, ILabel label, bool polarity)
{ {
var sb = new StringBuilder("INTBL? ");
sb.Append(value);
sb.Append(',');
sb.Append(table);
sb.Append(',');
sb.Append(length);
if (form != null)
{
sb.Append(',');
sb.Append(form);
}
sb.Append(" >");
sb.Append(result);
var inst = new Instruction("INTBL?", value.ToAsmExpr(), table.ToAsmExpr(), length.ToAsmExpr()) var inst = new Instruction("INTBL?", value.ToAsmExpr(), table.ToAsmExpr(), length.ToAsmExpr())
{ {
StoreTarget = result.ToString() StoreTarget = result.ToString()
...@@ -1017,6 +1003,9 @@ namespace Zilf.Emit.Zap ...@@ -1017,6 +1003,9 @@ namespace Zilf.Emit.Zap
} }
game.WriteOutput(sb.ToString()); game.WriteOutput(sb.ToString());
if (game.abbrevs != null && code.Instruction.HasStringOperand(out var str))
game.abbrevs.AddText(str);
}); });
if (game.debug != null) if (game.debug != null)
......
...@@ -220,9 +220,13 @@ namespace Zilf.Compiler ...@@ -220,9 +220,13 @@ namespace Zilf.Compiler
{ {
var zversion = ctx.ZEnvironment.ZVersion; var zversion = ctx.ZEnvironment.ZVersion;
var streamFactory = new ZapStreamFactory(this, outputFileName); var streamFactory = new ZapStreamFactory(this, outputFileName);
var options = MakeGameOptions(ctx); var gameOptions = MakeGameOptions(ctx);
using var gameBuilder = new GameBuilder(zversion, streamFactory, wantDebugInfo, options); var builderOptions = wantDebugInfo ? GameBuilderOptions.WantDebugInfo : GameBuilderOptions.None;
if (!streamFactory.FrequentWordsFileExists)
builderOptions |= GameBuilderOptions.WantFrequentWords;
using var gameBuilder = new GameBuilder(zversion, streamFactory, builderOptions, gameOptions);
Compilation.Compile(ctx, gameBuilder); Compilation.Compile(ctx, gameBuilder);
} }
catch (ZilErrorBase ex) // catch fatals too catch (ZilErrorBase ex) // catch fatals too
......
...@@ -47,14 +47,14 @@ namespace Zilf.Emit.Tests ...@@ -47,14 +47,14 @@ namespace Zilf.Emit.Tests
[ExpectedException(typeof(ArgumentOutOfRangeException), "zversion 0 should be rejected")] [ExpectedException(typeof(ArgumentOutOfRangeException), "zversion 0 should be rejected")]
public void Ctor_Should_Reject_Low_Zversion() public void Ctor_Should_Reject_Low_Zversion()
{ {
_ = new GameBuilder(0, mockStreamFactory.Object, false); _ = new GameBuilder(0, mockStreamFactory.Object);
} }
[TestMethod] [TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException), "zversion 9 should be rejected")] [ExpectedException(typeof(ArgumentOutOfRangeException), "zversion 9 should be rejected")]
public void Ctor_Should_Reject_High_Zversion() public void Ctor_Should_Reject_High_Zversion()
{ {
_ = new GameBuilder(9, mockStreamFactory.Object, false); _ = new GameBuilder(9, mockStreamFactory.Object);
} }
[TestMethod] [TestMethod]
...@@ -62,7 +62,7 @@ namespace Zilf.Emit.Tests ...@@ -62,7 +62,7 @@ namespace Zilf.Emit.Tests
public void Ctor_Should_Reject_Null_StreamFactory() public void Ctor_Should_Reject_Null_StreamFactory()
{ {
// ReSharper disable once AssignNullToNotNullAttribute // ReSharper disable once AssignNullToNotNullAttribute
_ = new GameBuilder(5, null, false); _ = new GameBuilder(5, null);
} }
} }
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment