Skip to content

Commit

Permalink
Improved yasm in response to feedback from Azurethi (working on ISAN).
Browse files Browse the repository at this point in the history
 - Added comments
 - Better error messages
 - Error out when too many substitutions are made (instead of freezing forever)
 - Added braces which get removed from compiled output
  • Loading branch information
martindevans committed May 6, 2021
1 parent 9c6f9d4 commit fd051dd
Show file tree
Hide file tree
Showing 23 changed files with 356 additions and 93 deletions.
20 changes: 16 additions & 4 deletions YololAssembler/Grammar/AST/BaseDefine.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
using YololAssembler.Grammar.Errors;

namespace YololAssembler.Grammar.AST
{
Expand All @@ -15,9 +16,9 @@ public string Apply(string input)
var r = Replace(match.Groups["body"].Value);
r = Other.Trim(r);

var v = input.Substring(0, match.Index)
var v = input[..match.Index]
+ r
+ input.Substring(0 + match.Index + match.Length);
+ input[(0 + match.Index + match.Length)..];
return v;
}

Expand All @@ -31,8 +32,11 @@ public string Apply(string input)
/// <param name="block"></param>
/// <param name="defines"></param>
/// <returns></returns>
internal static string Apply(string block, IEnumerable<BaseDefine> defines)
internal static string Apply(string block, IReadOnlyList<BaseDefine> defines)
{
var original = block;
var matches = 0;

var changed = true;
while (changed)
{
Expand All @@ -41,8 +45,16 @@ internal static string Apply(string block, IEnumerable<BaseDefine> defines)
{
var input = block;
block = item.Apply(input);
changed |= !block.Equals(input);

if (!block.Equals(input))
{
changed = true;
matches++;
}
}

if (matches >= 100)
throw new TooManySubstitutions(original, block, matches);
}

return block;
Expand Down
13 changes: 13 additions & 0 deletions YololAssembler/Grammar/AST/Comment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace YololAssembler.Grammar.AST
{
internal class Comment
: BaseStatement
{
public string Value { get; }

public Comment(string value)
{
Value = value;
}
}
}
2 changes: 1 addition & 1 deletion YololAssembler/Grammar/AST/EvalReplacement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal class EvalReplacement
protected override string Replace(string part)
{
// Convert the floating expression into a statement assigning a variable;
const string name = "_95efe616";
const string name = "eval";
var stmtCode = $"{name}={part}";

// Try to parse this tiny little program
Expand Down
3 changes: 1 addition & 2 deletions YololAssembler/Grammar/AST/FunctionDefine.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using YololAssembler.Grammar.Errors;

Expand Down
15 changes: 14 additions & 1 deletion YololAssembler/Grammar/AST/Other.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,30 @@ internal class Other
public Other(string content)
{
Content = content;

// Find comments and trim them out
var idx = Content.IndexOf("##", StringComparison.OrdinalIgnoreCase);
if (idx != -1)
{
// Remove the comment
Content = Content.Substring(0, idx);

// If there was space trailing the line leading up to the comment, remove it
Content = Content.TrimEnd(' ');
}
}

internal static string Trim(string input)
{
return string.Join("",
var trimmed = string.Join("",
input
.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.RemoveEmptyEntries)
.Select(l => l.TrimStart(' '))
.Select(l => l.TrimStart('\t'))
.Select(l => l.Replace(";", " "))
);

return trimmed;
}
}
}
41 changes: 14 additions & 27 deletions YololAssembler/Grammar/AST/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Linq;
using System.Net;
using YololAssembler.Grammar.Errors;
using Result = Yolol.Grammar.Parser.Result<string, Yolol.Grammar.Parser.ParseError>;

namespace YololAssembler.Grammar.AST
{
Expand All @@ -17,32 +16,25 @@ public Program(IEnumerable<BaseStatement> statements)
Statements = statements.ToArray();
}

public Result Compile(bool compress = true)
public string Compile()
{
// Apply replacements to all blocks of `Other`
var lines = Apply(Defines().ToArray(), Others().ToArray()).ToArray();
var lines = Apply(Defines(), Others().ToArray()).ToArray();

// Replace line labels
lines = Apply(Labels().ToArray(), lines.ToArray()).ToArray();
lines = Apply(Labels(), lines.ToArray()).ToArray();

// Replace implicit line labels
lines = ApplyImplicitLabels(lines).ToArray();

// Remove all of the {} characters now that substitutions are done
lines = lines.Select(l => l.Replace("{", "").Replace("}", "")).ToArray();

// Run all `eval` replacements
lines = Apply(new[] { new EvalReplacement() }, lines).ToArray();

// Early out if compression should not be applied
var yolol = string.Join("\n", lines);
if (!compress)
return new Result(yolol);

// Parse as yolol to apply compression
var parsedYolol = Yolol.Grammar.Parser.ParseProgram(yolol);
if (!parsedYolol.IsOk)
return new Result(parsedYolol.Err);

// remove unnecessary spaces from the program
return new Result(Compress(parsedYolol.Ok));
// Return compiled program
return string.Join("\n", lines);
}

private static IEnumerable<string> ApplyImplicitLabels(IEnumerable<string> lines)
Expand All @@ -55,38 +47,33 @@ private static IEnumerable<string> ApplyImplicitLabels(IEnumerable<string> lines
}
}

private static string Compress(Yolol.Grammar.AST.Program yolol)
{
//todo: compress
return yolol.ToString();
}

private static IEnumerable<string> Apply(IReadOnlyList<BaseDefine> defines, IReadOnlyList<string> blocks)
{
foreach (var block in blocks)
yield return BaseDefine.Apply(block, defines);
}

private IEnumerable<BaseDefine> Labels()
private IReadOnlyList<BaseDefine> Labels()
{
return Statements
.OfType<LineLabel>()
.Select((s, i) => (s.Name, (i + 1).ToString()))
.Select(a => new FindAndReplace(a.Name, a.Item2));
.Select(a => new FindAndReplace(a.Name, a.Item2))
.ToArray();
}

private IEnumerable<BaseDefine> Defines()
private IReadOnlyList<BaseDefine> Defines()
{
// Find all things defined in this file
var defines = Statements.OfType<BaseDefine>();

// Resolve imports
var imports = Statements.OfType<Import>().SelectMany(Resolve);

return defines.Concat(imports);
return defines.Concat(imports).ToArray();
}

private static IEnumerable<BaseDefine> Resolve(Import import)
private static IReadOnlyList<BaseDefine> Resolve(Import import)
{
string Fetch()
{
Expand Down
5 changes: 5 additions & 0 deletions YololAssembler/Grammar/Errors/BaseCompileException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,10 @@ public BaseCompileException(string message)
: base(message)
{
}

public override string ToString()
{
return Message;
}
}
}
2 changes: 1 addition & 1 deletion YololAssembler/Grammar/Errors/CannotParseEval.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class CannotParseEval
public Yolol.Grammar.Parser.ParseError ParseError { get; }

public CannotParseEval(string expression, Yolol.Grammar.Parser.ParseError parseError)
: base($"Cannot parse expression pass to eval `{expression}`.")
: base($"Cannot parse expression as Yolol in `Eval({expression})`.\n\n{parseError}")
{
Expression = expression;
ParseError = parseError;
Expand Down
2 changes: 1 addition & 1 deletion YololAssembler/Grammar/Errors/CannotParseImport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class CannotParseImport
public Yolol.Grammar.Parser.ParseError ParseError { get; }

public CannotParseImport(string path, Yolol.Grammar.Parser.ParseError parseError)
: base($"Cannot parse file import from `{path}`.")
: base($"Cannot parse file import from `{path}` as YASM.")
{
Path = path;
ParseError = parseError;
Expand Down
4 changes: 2 additions & 2 deletions YololAssembler/Grammar/Errors/CannotResolveImport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
public class CannotResolveImport
: BaseCompileException
{
public CannotResolveImport(string message)
: base($"Cannot interpret imported path `{message}` as a file path or a Uri")
public CannotResolveImport(string path)
: base($"Cannot interpret imported path `{path}` as a file path or a Uri")
{
}
}
Expand Down
2 changes: 1 addition & 1 deletion YololAssembler/Grammar/Errors/EvalNotConst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public class EvalNotConst
public Yolol.Grammar.AST.Expressions.BaseExpression Expression { get; }

public EvalNotConst(Yolol.Grammar.AST.Expressions.BaseExpression expression)
: base($"Expression pass to eval is not constant `{expression}`.")
: base($"Attempted to evaluate a non-constant expression: `Eval({expression})`")
{
Expression = expression;
}
Expand Down
11 changes: 11 additions & 0 deletions YololAssembler/Grammar/Errors/TooManySubstitutions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace YololAssembler.Grammar.Errors
{
public class TooManySubstitutions
: BaseCompileException
{
internal TooManySubstitutions(string original, string result, int matches)
: base($"Too many substitutions made while processing input:\n\n\t`{original}`\n\nResult after {matches} substitutions:\n\n\t`{result}`")
{
}
}
}
9 changes: 7 additions & 2 deletions YololAssembler/Grammar/YololAssembler.pegasus
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,20 @@ program <Program>

statement <BaseStatement>
= line_label
/ line_nolabel
/ define
/ import
/ comment
/ other

line_label <LineLabel>
= "@" i:identifier ":" { new LineLabel(i) }

//comment <Comment>
// = "#" c:(!newline .)* { new Comment(string.Concat(c)) }
line_nolabel <LineLabel>
= "@:" { new LineLabel(Guid.NewGuid().ToString()) }

comment <Comment>
= _ "##" c:(!newline .)* { new Comment(string.Concat(c)) }

import <Import>
= "#import" _ p:(!newline .)* { new Import(string.Concat(p)) }
Expand Down
27 changes: 9 additions & 18 deletions YololAssembler/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ private class Options

[Option('w', "watch", HelpText = "If set, the assembler will automatically run every time the input file changes", Required = false)]
public bool Watch { get; set; }

[Option('c', "compress", HelpText = "If set, the assembler will automatically compress the output code", Required = false)]
public bool Compress { get; set; }
// ReSharper restore UnusedAutoPropertyAccessor.Local
}

Expand All @@ -36,7 +33,7 @@ private static void Run(Options options)
var input = options.InputFile!;
var output = options.OutputFile!;

ProcessFile(options.InputFile!, options.OutputFile!, options.Compress);
ProcessFile(options.InputFile!, options.OutputFile!);

if (options.Watch)
{
Expand All @@ -52,7 +49,7 @@ private static void Run(Options options)
void OnChanged(object sender, FileSystemEventArgs fileSystemEventArgs)
{
Thread.Sleep(100);
ProcessFile(input, output, options.Compress);
ProcessFile(input, output);
}

// Add event handlers.
Expand All @@ -68,12 +65,12 @@ void OnChanged(object sender, FileSystemEventArgs fileSystemEventArgs)
while (Console.ReadKey(true).Key != ConsoleKey.Q && File.Exists(options.InputFile))
{
Thread.Sleep(100);
ProcessFile(input, output, options.Compress);
ProcessFile(input, output);
}
}
}

private static void ProcessFile(string inputPath, string outputPath, bool compress)
private static void ProcessFile(string inputPath, string outputPath)
{
var timer = new Stopwatch();
timer.Start();
Expand All @@ -89,22 +86,13 @@ private static void ProcessFile(string inputPath, string outputPath, bool compre
var parseResult = Grammar.Parser.ParseProgram(File.ReadAllText(inputPath));
if (!parseResult.IsOk)
{
Console.WriteLine("# yasm parse error");
Console.WriteLine("# Yasm Parse Error");
Console.WriteLine("------------------");
Console.WriteLine(parseResult.Err.ToString());
break;
}

var compileResult = parseResult.Ok.Compile(compress);
if (!compileResult.IsOk)
{
Console.WriteLine("# yolol parse error");
Console.WriteLine("-------------------");
Console.WriteLine(compileResult.Err.ToString());
break;
}

var yolol = compileResult.Ok;
var yolol = parseResult.Ok.Compile();
yolol += "\n\n";
yolol += "// <-------------- this line is 70 characters long ------------------>";

Expand All @@ -117,7 +105,10 @@ private static void ProcessFile(string inputPath, string outputPath, bool compre
}
catch (BaseCompileException e)
{
Console.WriteLine("# YASM Compiler Error");
Console.WriteLine("---------------------");
Console.WriteLine(e);
Console.WriteLine();
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion YololAssembler/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"profiles": {
"YololAssembler": {
"commandName": "Project",
"commandLineArgs": "-i Persistence.yasm -o Persistence.yolol --watch",
"commandLineArgs": "-i IsanDemo/isan.yasm -o IsanDemo/isan.yolol --watch",
"workingDirectory": "C:\\Users\\Martin\\Documents\\dotnet\\YololEmulator\\YololAssembler\\Scripts"
}
}
Expand Down
Loading

0 comments on commit fd051dd

Please sign in to comment.